summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Config.in36
-rw-r--r--drivers/char/Makefile208
-rw-r--r--drivers/char/README.computone195
-rw-r--r--drivers/char/adbmouse.c296
-rw-r--r--drivers/char/amigamouse.c203
-rw-r--r--drivers/char/amikeyb.c7
-rw-r--r--drivers/char/applicom.c842
-rw-r--r--drivers/char/applicom.h85
-rw-r--r--drivers/char/atarimouse.c132
-rw-r--r--drivers/char/atixlmouse.c142
-rw-r--r--drivers/char/bttv.c773
-rw-r--r--drivers/char/bttv.h1
-rw-r--r--drivers/char/busmouse.c612
-rw-r--r--drivers/char/busmouse.h28
-rw-r--r--drivers/char/buz.c13
-rw-r--r--drivers/char/bw-qcam.c26
-rw-r--r--drivers/char/bw-qcam.h1
-rw-r--r--drivers/char/c-qcam.c12
-rw-r--r--drivers/char/console.c8
-rw-r--r--drivers/char/cyclades.c1738
-rw-r--r--drivers/char/defkeymap.c26
-rw-r--r--drivers/char/dn_keyb.c9
-rw-r--r--drivers/char/drm/.cvsignore2
-rw-r--r--drivers/char/drm/Makefile27
-rw-r--r--drivers/char/drm/README.drm39
-rw-r--r--drivers/char/drm/auth.c161
-rw-r--r--drivers/char/drm/bufs.c527
-rw-r--r--drivers/char/drm/context.c308
-rw-r--r--drivers/char/drm/dma.c530
-rw-r--r--drivers/char/drm/drawable.c50
-rw-r--r--drivers/char/drm/drm.h277
-rw-r--r--drivers/char/drm/drmP.h584
-rw-r--r--drivers/char/drm/fops.c204
-rw-r--r--drivers/char/drm/gamma_dma.c802
-rw-r--r--drivers/char/drm/gamma_drv.c525
-rw-r--r--drivers/char/drm/gamma_drv.h58
-rw-r--r--drivers/char/drm/init.c99
-rw-r--r--drivers/char/drm/ioctl.c91
-rw-r--r--drivers/char/drm/lists.c252
-rw-r--r--drivers/char/drm/lock.c227
-rw-r--r--drivers/char/drm/memory.c320
-rw-r--r--drivers/char/drm/proc.c568
-rw-r--r--drivers/char/drm/sigio.c82
-rw-r--r--drivers/char/drm/vm.c264
-rw-r--r--drivers/char/dsp56k.c2
-rw-r--r--drivers/char/epca.c46
-rw-r--r--drivers/char/esp.c2
-rw-r--r--drivers/char/ftape/lowlevel/ftape-io.c8
-rw-r--r--drivers/char/ftape/lowlevel/ftape-setup.c14
-rw-r--r--drivers/char/generic_serial.c1074
-rw-r--r--drivers/char/generic_serial.h101
-rw-r--r--drivers/char/hfmodem/Config.in6
-rw-r--r--drivers/char/hfmodem/Makefile37
-rw-r--r--drivers/char/hfmodem/gentbl.c69
-rw-r--r--drivers/char/hfmodem/main.c734
-rw-r--r--drivers/char/hfmodem/modem.c792
-rw-r--r--drivers/char/hfmodem/refclock.c154
-rw-r--r--drivers/char/hfmodem/sbc.c741
-rw-r--r--drivers/char/hfmodem/wss.c437
-rw-r--r--drivers/char/i2c-parport.c2
-rw-r--r--drivers/char/ip2.c72
-rw-r--r--drivers/char/ip2/.cvsignore2
-rw-r--r--drivers/char/ip2/Makefile12
-rw-r--r--drivers/char/ip2/fip_firm.h2149
-rw-r--r--drivers/char/ip2/i2cmd.c264
-rw-r--r--drivers/char/ip2/i2cmd.h660
-rw-r--r--drivers/char/ip2/i2ellis.c1470
-rw-r--r--drivers/char/ip2/i2ellis.h609
-rw-r--r--drivers/char/ip2/i2hw.h648
-rw-r--r--drivers/char/ip2/i2lib.c2253
-rw-r--r--drivers/char/ip2/i2lib.h350
-rw-r--r--drivers/char/ip2/i2os.h145
-rw-r--r--drivers/char/ip2/i2pack.h364
-rw-r--r--drivers/char/ip2/ip2.h109
-rw-r--r--drivers/char/ip2/ip2ioctl.h35
-rw-r--r--drivers/char/ip2/ip2trace.h43
-rw-r--r--drivers/char/ip2/ip2types.h54
-rw-r--r--drivers/char/ip2main.c3235
-rw-r--r--drivers/char/isicom.c275
-rw-r--r--drivers/char/istallion.c21
-rw-r--r--drivers/char/joystick/joystick.c5
-rw-r--r--drivers/char/keyboard.c5
-rw-r--r--drivers/char/logibusmouse.c157
-rw-r--r--drivers/char/lp.c63
-rw-r--r--drivers/char/lp_intern.c364
-rw-r--r--drivers/char/lp_m68k.c556
-rw-r--r--drivers/char/mem.c22
-rw-r--r--drivers/char/misc.c59
-rw-r--r--drivers/char/msbusmouse.c145
-rw-r--r--drivers/char/msp3400.c13
-rw-r--r--drivers/char/n_r3964.c1488
-rw-r--r--drivers/char/n_tty.c4
-rw-r--r--drivers/char/nvram.c8
-rw-r--r--drivers/char/pc_keyb.c11
-rw-r--r--drivers/char/pcwd.c38
-rw-r--r--drivers/char/pcxx.c11
-rw-r--r--drivers/char/planb.c7
-rw-r--r--drivers/char/ppdev.c349
-rw-r--r--drivers/char/ppdev.h9
-rw-r--r--drivers/char/pty.c2
-rw-r--r--drivers/char/q40_keyb.c454
-rw-r--r--drivers/char/qpmouse.c2
-rw-r--r--drivers/char/radio-aimslab.c47
-rw-r--r--drivers/char/radio-aztech.c33
-rw-r--r--drivers/char/radio-gemtek.c38
-rw-r--r--drivers/char/radio-miropcm20.c16
-rw-r--r--drivers/char/radio-rtrack2.c17
-rw-r--r--drivers/char/radio-sf16fmi.c15
-rw-r--r--drivers/char/radio-terratec.c12
-rw-r--r--drivers/char/radio-trust.c354
-rw-r--r--drivers/char/radio-zoltrix.c29
-rw-r--r--drivers/char/random.c1262
-rw-r--r--drivers/char/raw.c394
-rw-r--r--drivers/char/riscom8.c10
-rw-r--r--drivers/char/rocket.c22
-rw-r--r--drivers/char/rtc.c4
-rw-r--r--drivers/char/saa5249.c10
-rw-r--r--drivers/char/selection.c2
-rw-r--r--drivers/char/serial.c1083
-rw-r--r--drivers/char/serial167.c4
-rw-r--r--drivers/char/softdog.c11
-rw-r--r--drivers/char/specialix.c4
-rw-r--r--drivers/char/stallion.c36
-rw-r--r--drivers/char/sx.c2684
-rw-r--r--drivers/char/sx.h180
-rw-r--r--drivers/char/sxboards.h181
-rw-r--r--drivers/char/sxwindow.h393
-rw-r--r--drivers/char/synclink.c4
-rw-r--r--drivers/char/sysrq.c2
-rw-r--r--drivers/char/tty_io.c23
-rw-r--r--drivers/char/tty_ioctl.c2
-rw-r--r--drivers/char/tuner.c15
-rw-r--r--drivers/char/vc_screen.c2
-rw-r--r--drivers/char/videodev.c57
-rw-r--r--drivers/char/vino.c5
-rw-r--r--drivers/char/vt.c6
-rw-r--r--drivers/char/wdt.c4
137 files changed, 31361 insertions, 7751 deletions
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 8aa4d68a9..1ae10a544 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -37,10 +37,12 @@ if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
fi
tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8
+ tristate 'Computone IntelliPort Plus serial support' CONFIG_COMPUTONE
tristate 'Specialix IO8+ card support' CONFIG_SPECIALIX
if [ "$CONFIG_SPECIALIX" != "n" ]; then
bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
fi
+ tristate 'Specialix SX (and SI) card support' CONFIG_SX
tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m
@@ -60,18 +62,25 @@ if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
fi
-bool 'Mouse Support (not serial mice)' CONFIG_MOUSE
-if [ "$CONFIG_MOUSE" = "y" ]; then
- mainmenu_option next_comment
- comment 'Mice'
- tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE
- tristate 'Logitech busmouse support' CONFIG_BUSMOUSE
- tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE
+mainmenu_option next_comment
+comment 'Mice'
+tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
+if [ "$CONFIG_BUSMOUSE" != "n" ]; then
+ dep_tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
+ dep_tristate 'Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
+ dep_tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
+ if [ "$CONFIG_PPC" = "y" ] ; then
+ dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
+ fi
+fi
+
+tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE
+if [ "$CONFIG_MOUSE" != "n" ]; then
bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
tristate 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
tristate 'PC110 digitizer pad support' CONFIG_PC110_PAD
- endmenu
fi
+endmenu
tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
@@ -85,7 +94,6 @@ if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
fi
dep_tristate 'Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV
dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
- dep_tristate ' Include support for LML33' CONFIG_VIDEO_LML33 $CONFIG_VIDEO_ZORAN
fi
bool 'Watchdog Timer Support' CONFIG_WATCHDOG
@@ -191,6 +199,9 @@ endmenu
tristate 'Double Talk PC internal speech card support' CONFIG_DTLK
+tristate 'Siemens R3964 line discipline' CONFIG_R3964
+tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM
+
mainmenu_option next_comment
comment 'Ftape, the floppy tape device driver'
tristate 'Ftape (QIC-80/Travan) support' CONFIG_FTAPE
@@ -199,4 +210,11 @@ if [ "$CONFIG_FTAPE" != "n" ]; then
fi
endmenu
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
+ if [ "$CONFIG_DRM" = "y" ]; then
+ dep_tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA m
+ fi
+fi
+
endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 9ac5bc5ab..b9d58b64c 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -18,14 +18,14 @@ ALL_SUB_DIRS := $(SUB_DIRS) ftape joystick
#
FONTMAPFILE = cp437.uni
-L_TARGET := char.a
+O_TARGET := char.o
M_OBJS :=
-L_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o
-LX_OBJS := pty.o misc.o
+O_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o raw.o
+OX_OBJS := pty.o misc.o
ifdef CONFIG_VT
-L_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o
-LX_OBJS += console.o selection.o
+O_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o
+OX_OBJS += console.o selection.o
endif
ifeq ($(CONFIG_SERIAL),y)
@@ -33,7 +33,7 @@ ifeq ($(CONFIG_SERIAL),y)
ifeq ($(CONFIG_SGI_SERIAL),)
ifeq ($(CONFIG_DECSTATION),)
ifeq ($(CONFIG_BAGET_MIPS),)
- LX_OBJS += serial.o
+ OX_OBJS += serial.o
endif
endif
endif
@@ -56,26 +56,26 @@ ifndef CONFIG_SUN_KEYBOARD
ifndef CONFIG_DECSTATION
ifndef CONFIG_BAGET_MIPS
ifdef CONFIG_VT
-LX_OBJS += keyboard.o
+OX_OBJS += keyboard.o
endif
ifneq ($(ARCH),m68k)
- L_OBJS += pc_keyb.o defkeymap.o
+ O_OBJS += pc_keyb.o defkeymap.o
endif
else
ifdef CONFIG_PCI
-L_OBJS += defkeymap.o
-LX_OBJS += keyboard.o
+O_OBJS += defkeymap.o
+OX_OBJS += keyboard.o
endif
endif
ifdef CONFIG_MAGIC_SYSRQ
-LX_OBJS += sysrq.o
+OX_OBJS += sysrq.o
endif
endif
endif
ifeq ($(CONFIG_ATARI_DSP56K),y)
-L_OBJS += dsp56k.o
+O_OBJS += dsp56k.o
S = y
else
ifeq ($(CONFIG_ATARI_DSP56K),m)
@@ -85,7 +85,7 @@ else
endif
ifeq ($(CONFIG_ROCKETPORT),y)
-L_OBJS += rocket.o
+O_OBJS += rocket.o
else
ifeq ($(CONFIG_ROCKETPORT),m)
M_OBJS += rocket.o
@@ -93,7 +93,7 @@ else
endif
ifeq ($(CONFIG_DIGI),y)
-L_OBJS += pcxx.o
+O_OBJS += pcxx.o
else
ifeq ($(CONFIG_DIGI),m)
M_OBJS += pcxx.o
@@ -101,7 +101,7 @@ else
endif
ifeq ($(CONFIG_DIGIEPCA),y)
-L_OBJS += epca.o
+O_OBJS += epca.o
else
ifeq ($(CONFIG_DIGIEPCA),m)
M_OBJS += epca.o
@@ -109,7 +109,7 @@ else
endif
ifeq ($(CONFIG_CYCLADES),y)
-L_OBJS += cyclades.o
+O_OBJS += cyclades.o
else
ifeq ($(CONFIG_CYCLADES),m)
M_OBJS += cyclades.o
@@ -117,7 +117,7 @@ else
endif
ifeq ($(CONFIG_STALLION),y)
-L_OBJS += stallion.o
+O_OBJS += stallion.o
else
ifeq ($(CONFIG_STALLION),m)
M_OBJS += stallion.o
@@ -125,15 +125,23 @@ else
endif
ifeq ($(CONFIG_ISTALLION),y)
-L_OBJS += istallion.o
+O_OBJS += istallion.o
else
ifeq ($(CONFIG_ISTALLION),m)
M_OBJS += istallion.o
endif
endif
+ifeq ($(CONFIG_COMPUTONE),y)
+L_OBJS += ip2.o ip2main.o
+else
+ ifeq ($(CONFIG_COMPUTONE),m)
+ M_OBJS += ip2.o ip2main.o
+ endif
+endif
+
ifeq ($(CONFIG_RISCOM8),y)
-L_OBJS += riscom8.o
+O_OBJS += riscom8.o
else
ifeq ($(CONFIG_RISCOM8),m)
M_OBJS += riscom8.o
@@ -141,7 +149,7 @@ else
endif
ifeq ($(CONFIG_ISI),y)
-L_OBJS += isicom.o
+O_OBJS += isicom.o
else
ifeq ($(CONFIG_ISI),m)
M_OBJS += isicom.o
@@ -149,7 +157,7 @@ else
endif
ifeq ($(CONFIG_ESPSERIAL),y)
-L_OBJS += esp.o
+O_OBJS += esp.o
else
ifeq ($(CONFIG_ESPSERIAL),m)
M_OBJS += esp.o
@@ -165,31 +173,39 @@ ifeq ($(CONFIG_N_HDLC),m)
endif
ifeq ($(CONFIG_SPECIALIX),y)
-L_OBJS += specialix.o
+O_OBJS += specialix.o
else
ifeq ($(CONFIG_SPECIALIX),m)
M_OBJS += specialix.o
endif
endif
+ifeq ($(CONFIG_SX),y)
+L_OBJS += sx.o generic_serial.o
+else
+ ifeq ($(CONFIG_SX),m)
+ M_OBJS += sx.o
+ endif
+endif
+
ifeq ($(CONFIG_ATIXL_BUSMOUSE),y)
-L_OBJS += atixlmouse.o
+O_OBJS += atixlmouse.o
else
ifeq ($(CONFIG_ATIXL_BUSMOUSE),m)
M_OBJS += atixlmouse.o
endif
endif
-ifeq ($(CONFIG_BUSMOUSE),y)
-L_OBJS += busmouse.o
+ifeq ($(CONFIG_LOGIBUSMOUSE),y)
+O_OBJS += logibusmouse.o
else
- ifeq ($(CONFIG_BUSMOUSE),m)
- M_OBJS += busmouse.o
+ ifeq ($(CONFIG_LOGIBUSMOUSE),m)
+ M_OBJS += logibusmouse.o
endif
endif
ifeq ($(CONFIG_PRINTER),y)
-L_OBJS += lp.o
+O_OBJS += lp.o
else
ifeq ($(CONFIG_PRINTER),m)
M_OBJS += lp.o
@@ -197,7 +213,7 @@ else
endif
ifeq ($(CONFIG_JOYSTICK),y)
-L_OBJS += joystick/js.o
+O_OBJS += joystick/js.o
SUB_DIRS += joystick
MOD_SUB_DIRS += joystick
else
@@ -206,16 +222,42 @@ else
endif
endif
+ifeq ($(CONFIG_BUSMOUSE),y)
+M = y
+OX_OBJS += busmouse.o
+else
+ ifeq ($(CONFIG_BUSMOUSE),m)
+ MM = m
+ MX_OBJS += busmouse.o
+ endif
+endif
+
ifeq ($(CONFIG_DTLK),y)
-L_OBJS += dtlk.o
+O_OBJS += dtlk.o
else
ifeq ($(CONFIG_DTLK),m)
M_OBJS += dtlk.o
endif
endif
+ifeq ($(CONFIG_R3964),y)
+O_OBJS += n_r3964.o
+else
+ ifeq ($(CONFIG_R3964),m)
+ M_OBJS += n_r3964.o
+ endif
+endif
+
+ifeq ($(CONFIG_APPLICOM),y)
+O_OBJS += applicom.o
+else
+ ifeq ($(CONFIG_APPLICOM),m)
+ M_OBJS += applicom.o
+ endif
+endif
+
ifeq ($(CONFIG_MS_BUSMOUSE),y)
-L_OBJS += msbusmouse.o
+O_OBJS += msbusmouse.o
else
ifeq ($(CONFIG_MS_BUSMOUSE),m)
M_OBJS += msbusmouse.o
@@ -223,7 +265,7 @@ else
endif
ifeq ($(CONFIG_82C710_MOUSE),y)
-L_OBJS += qpmouse.o
+O_OBJS += qpmouse.o
else
ifeq ($(CONFIG_82C710_MOUSE),m)
M_OBJS += qpmouse.o
@@ -231,7 +273,7 @@ else
endif
ifeq ($(CONFIG_SOFT_WATCHDOG),y)
-L_OBJS += softdog.o
+O_OBJS += softdog.o
else
ifeq ($(CONFIG_SOFT_WATCHDOG),m)
M_OBJS += softdog.o
@@ -239,7 +281,7 @@ else
endif
ifeq ($(CONFIG_PCWATCHDOG),y)
-L_OBJS += pcwd.o
+O_OBJS += pcwd.o
else
ifeq ($(CONFIG_PCWATCHDOG),m)
M_OBJS += pcwd.o
@@ -247,7 +289,7 @@ else
endif
ifeq ($(CONFIG_ACQUIRE_WDT),y)
-L_OBJS += acquirewdt.o
+O_OBJS += acquirewdt.o
else
ifeq ($(CONFIG_ACQUIRE_WDT),m)
M_OBJS += acquirewdt.o
@@ -255,7 +297,7 @@ else
endif
ifeq ($(CONFIG_AMIGAMOUSE),y)
-L_OBJS += amigamouse.o
+O_OBJS += amigamouse.o
else
ifeq ($(CONFIG_AMIGAMOUSE),m)
M_OBJS += amigamouse.o
@@ -263,7 +305,7 @@ else
endif
ifeq ($(CONFIG_ATARIMOUSE),y)
-L_OBJS += atarimouse.o
+O_OBJS += atarimouse.o
else
ifeq ($(CONFIG_ATARIMOUSE),m)
M_OBJS += atarimouse.o
@@ -271,7 +313,7 @@ else
endif
ifeq ($(CONFIG_ADBMOUSE),y)
-L_OBJS += adbmouse.o
+O_OBJS += adbmouse.o
else
ifeq ($(CONFIG_ADBMOUSE),m)
M_OBJS += adbmouse.o
@@ -279,7 +321,7 @@ else
endif
ifeq ($(CONFIG_PC110_PAD),y)
-L_OBJS += pc110pad.o
+O_OBJS += pc110pad.o
else
ifeq ($(CONFIG_PC110_PAD),m)
M_OBJS += pc110pad.o
@@ -287,7 +329,7 @@ else
endif
ifeq ($(CONFIG_WDT),y)
-L_OBJS += wdt.o
+O_OBJS += wdt.o
else
ifeq ($(CONFIG_WDT),m)
M_OBJS += wdt.o
@@ -295,12 +337,12 @@ else
endif
ifeq ($(CONFIG_RTC),y)
-L_OBJS += rtc.o
+O_OBJS += rtc.o
endif
ifeq ($(CONFIG_NVRAM),y)
ifeq ($(CONFIG_PPC),)
- L_OBJS += nvram.o
+ O_OBJS += nvram.o
endif
else
ifeq ($(CONFIG_NVRAM),m)
@@ -311,7 +353,7 @@ else
endif
ifeq ($(CONFIG_VIDEO_DEV),y)
-LX_OBJS += videodev.o
+OX_OBJS += videodev.o
else
ifeq ($(CONFIG_VIDEO_DEV),m)
MX_OBJS += videodev.o
@@ -327,7 +369,7 @@ else
endif
ifeq ($(CONFIG_VIDEO_BT848),y)
-L_OBJS += bttv.o msp3400.o tuner.o
+O_OBJS += bttv.o msp3400.o tuner.o
L_I2C=y
else
ifeq ($(CONFIG_VIDEO_BT848),m)
@@ -337,7 +379,7 @@ else
endif
ifeq ($(CONFIG_VIDEO_SAA5249),y)
-L_OBJS += saa5249.o
+O_OBJS += saa5249.o
L_I2C=y
else
ifeq ($(CONFIG_VIDEO_SAA5249),m)
@@ -347,7 +389,7 @@ else
endif
ifeq ($(CONFIG_I2C_PARPORT),y)
-L_OBJS += i2c-parport.o
+O_OBJS += i2c-parport.o
L_I2C = y
else
ifeq ($(CONFIG_I2C_PARPORT),m)
@@ -357,7 +399,7 @@ else
endif
ifeq ($(CONFIG_VIDEO_BWQCAM),y)
-L_OBJS += bw-qcam.o
+O_OBJS += bw-qcam.o
else
ifeq ($(CONFIG_VIDEO_BWQCAM),m)
M_OBJS += bw-qcam.o
@@ -365,7 +407,7 @@ else
endif
ifeq ($(CONFIG_VIDEO_CQCAM),y)
-L_OBJS += c-qcam.o
+O_OBJS += c-qcam.o
else
ifeq ($(CONFIG_VIDEO_CQCAM),m)
M_OBJS += c-qcam.o
@@ -373,15 +415,15 @@ else
endif
ifeq ($(CONFIG_VIDEO_ZORAN),y)
-L_OBJS += buz.o
+O_OBJS += buz.o
else
- ifeq ($(CONFIG_VIDEO_LML33),m)
+ ifeq ($(CONFIG_VIDEO_ZORAN),m)
M_OBJS += buz.o
endif
endif
ifeq ($(CONFIG_VIDEO_LML33),y)
-L_OBJS += bt856.o bt819.o
+O_OBJS += bt856.o bt819.o
else
ifeq ($(CONFIG_VIDEO_LML33),m)
M_OBJS += bt856.o bt819.o
@@ -389,7 +431,7 @@ else
endif
ifeq ($(CONFIG_VIDEO_BUZ),y)
-L_OBJS += saa7111.o saa7185.o
+O_OBJS += saa7111.o saa7185.o
else
ifeq ($(CONFIG_VIDEO_BUZ),m)
M_OBJS += saa7111.o saa7185.o
@@ -397,7 +439,7 @@ else
endif
ifeq ($(CONFIG_VIDEO_PMS),y)
-L_OBJS += pms.o
+O_OBJS += pms.o
else
ifeq ($(CONFIG_VIDEO_PMS),m)
M_OBJS += pms.o
@@ -405,7 +447,7 @@ else
endif
ifeq ($(CONFIG_VIDEO_PLANB),y)
-L_OBJS += planb.o
+O_OBJS += planb.o
else
ifeq ($(CONFIG_VIDEO_PLANB),m)
M_OBJS += planb.o
@@ -413,15 +455,7 @@ else
endif
ifeq ($(CONFIG_VIDEO_VINO),y)
-L_OBJS += vino.o
-else
- ifeq ($(CONFIG_VIDEO_VINO),m)
- M_OBJS += vino.o
- endif
-endif
-
-ifeq ($(CONFIG_VIDEO_VINO),y)
-L_OBJS += vino.o
+O_OBJS += vino.o
else
ifeq ($(CONFIG_VIDEO_VINO),m)
M_OBJS += vino.o
@@ -429,7 +463,7 @@ else
endif
ifeq ($(CONFIG_RADIO_AZTECH),y)
-L_OBJS += radio-aztech.o
+O_OBJS += radio-aztech.o
else
ifeq ($(CONFIG_RADIO_AZTECH),m)
M_OBJS += radio-aztech.o
@@ -437,7 +471,7 @@ else
endif
ifeq ($(CONFIG_RADIO_SF16FMI),y)
-L_OBJS += radio-sf16fmi.o
+O_OBJS += radio-sf16fmi.o
else
ifeq ($(CONFIG_RADIO_SF16FMI),m)
M_OBJS += radio-sf16fmi.o
@@ -445,7 +479,7 @@ else
endif
ifeq ($(CONFIG_RADIO_RTRACK),y)
-L_OBJS += radio-aimslab.o
+O_OBJS += radio-aimslab.o
else
ifeq ($(CONFIG_RADIO_RTRACK),m)
M_OBJS += radio-aimslab.o
@@ -453,7 +487,7 @@ else
endif
ifeq ($(CONFIG_RADIO_RTRACK2),y)
-L_OBJS += radio-rtrack2.o
+O_OBJS += radio-rtrack2.o
else
ifeq ($(CONFIG_RADIO_RTRACK2),m)
M_OBJS += radio-rtrack2.o
@@ -461,7 +495,7 @@ else
endif
ifeq ($(CONFIG_RADIO_TYPHOON),y)
-L_OBJS += radio-typhoon.o
+O_OBJS += radio-typhoon.o
else
ifeq ($(CONFIG_RADIO_TYPHOON),m)
M_OBJS += radio-typhoon.o
@@ -469,7 +503,7 @@ else
endif
ifeq ($(CONFIG_RADIO_ZOLTRIX),y)
-L_OBJS += radio-zoltrix.o
+O_OBJS += radio-zoltrix.o
else
ifeq ($(CONFIG_RADIO_ZOLTRIX),m)
M_OBJS += radio-zoltrix.o
@@ -477,7 +511,7 @@ else
endif
ifeq ($(CONFIG_RADIO_CADET),y)
-L_OBJS += radio-cadet.o
+O_OBJS += radio-cadet.o
else
ifeq ($(CONFIG_RADIO_CADET),m)
M_OBJS += radio-cadet.o
@@ -485,7 +519,7 @@ else
endif
ifeq ($(CONFIG_RADIO_MIROPCM20),y)
-L_OBJS += radio-miropcm20.o
+O_OBJS += radio-miropcm20.o
else
ifeq ($(CONFIG_RADIO_MIROPCM20),m)
M_OBJS += radio-miropcm20.o
@@ -493,7 +527,7 @@ else
endif
ifeq ($(CONFIG_RADIO_GEMTEK),y)
-L_OBJS += radio-gemtek.o
+O_OBJS += radio-gemtek.o
else
ifeq ($(CONFIG_RADIO_GEMTEK),m)
M_OBJS += radio-gemtek.o
@@ -501,7 +535,7 @@ else
endif
ifeq ($(CONFIG_RADIO_TERRATEC),y)
-L_OBJS += radio-terratec.o
+O_OBJS += radio-terratec.o
else
ifeq ($(CONFIG_RADIO_TERRATEC),m)
M_OBJS += radio-terratec.o
@@ -509,7 +543,7 @@ else
endif
ifeq ($(CONFIG_QIC02_TAPE),y)
-L_OBJS += tpqic02.o
+O_OBJS += tpqic02.o
else
ifeq ($(CONFIG_QIC02_TAPE),m)
M_OBJS += tpqic02.o
@@ -517,7 +551,7 @@ else
endif
ifeq ($(CONFIG_FTAPE),y)
-L_OBJS += ftape/ftape.o
+O_OBJS += ftape/ftape.o
SUB_DIRS += ftape
ifneq ($(CONFIG_ZFTAPE),n)
MOD_SUB_DIRS += ftape
@@ -529,11 +563,11 @@ else
endif
ifdef CONFIG_H8
-LX_OBJS += h8.o
+OX_OBJS += h8.o
endif
ifeq ($(CONFIG_PPDEV),y)
-L_OBJS += ppdev.o
+O_OBJS += ppdev.o
else
ifeq ($(CONFIG_PPDEV),m)
M_OBJS += ppdev.o
@@ -541,30 +575,22 @@ else
endif
ifeq ($(L_I2C),y)
-LX_OBJS += i2c.o
+OX_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
-L_OBJS += hfmodem/hfmodem.o
-else
- ifeq ($(CONFIG_HFMODEM),m)
- ALL_SUB_DIRS += hfmodem
- MOD_SUB_DIRS += hfmodem
- endif
-
-endif
-
ifeq ($(CONFIG_DZ),y)
L_OBJS += dz.o
endif
+ifeq ($(CONFIG_DRM),y)
+ ALL_SUB_DIRS += drm
+ MOD_SUB_DIRS += drm
+endif
+
include $(TOPDIR)/Rules.make
fastdep:
diff --git a/drivers/char/README.computone b/drivers/char/README.computone
new file mode 100644
index 000000000..51c3666b6
--- /dev/null
+++ b/drivers/char/README.computone
@@ -0,0 +1,195 @@
+
+Computone Intelliport II/Plus Multiport Serial Driver
+-----------------------------------------------------
+
+Release Notes For Linux Kernel 2.2
+These notes have been tested on Linux kernels 2.0 and 2.2.
+
+
+Version: 1.2.4
+Date: 08/04/99
+Fixes and Updates: Doug McNash
+Historical Author: Andrew Manison
+
+1. INTRODUCTION
+
+This driver supports the entire family of Intelliport II/Plus controllers
+with the exception of the MicroChannel controllers.
+
+This driver was developed on the v2.0.x Linux source tree and has been
+tested up to v2.2.10; it will probably not work with earlier v1.X kernels,
+and has not yet been tested on the v2.1.x tree. The most likely problems
+will be in patching the kernel sources to support the driver. For this
+reason there are 2 different patch files for 2.0.XX and 2.2.XX kernels.
+Make sure you use the right one!
+Someday soon it should be included in the 2.3.XX tree.
+
+2. QUICK INSTALLATION
+
+Hardware - If you have an ISA card, find a free interrupt and io port.
+ List those in use with `cat /proc/interrupts` and
+ `cat /proc/ioports`. Set the card dip switches to that free
+ address. You may need to configure your BIOS to reserve the
+ irq for the ISA card. PCI and EISA parameters are set
+ automagically and need no attention. Insert card into
+ computer with the power off before or after driver installation.
+
+Software -
+
+Module installation:
+
+a) Obtain driver-kernel patch file
+b) Copy to the linux source tree root, Run ip2build (if not patch)
+c) Determine free irq/address to use if any (configure BIOS if need be)
+d) Run "make config" or "make menuconfig" or "make xconfig"
+ Select (m) module for CONFIG_COMPUTONE under character
+ devices. CONFIG_PCI and CONFIG_MODULES also may need to be set.
+e) Set address on ISA cards then:
+ edit /usr/src/linux/drivers/char/ip2/ip2.h if needed
+ or
+ edit /etc/conf.modules (or /etc/modules.conf) if needed (module).
+ or both to match this setting.
+f) Run "make dep"
+g) Run "make modules"
+h) Run "make modules_install"
+i) Run "/sbin/depmod -a"
+i) install driver using `modprobe ip2 <options>` (options listed below)
+j) run mkip2dev
+
+
+Kernel installation:
+
+a) Obtain driver-kernel patch file
+b) Copy to the linux source tree root, Run ip2build (if not patch)
+c) Determine free irq/address to use if any (configure BIOS if need be)
+d) Run "make config" or "make menuconfig" or "make xconfig"
+ Select (y) kernel for CONFIG_COMPUTONE under character
+ devices. CONFIG_PCI may need to be set if you have PCI bus.
+e) Set address on ISA cards then:
+ edit /usr/src/linux/drivers/char/ip2/ip2.h
+f) Run "make dep"
+g) Run "make zImage" or whatever target you prefer.
+h) mv /usr/src/linux/arch/i386/boot/zImage to /boot.
+i) add new config for this kernel into /etc/lilo.conf, run "lilo"
+j) reboot using this kernel
+k) make and run ip2/mkip2dev
+
+3. INSTALLATION
+
+Previously, the driver sources were packaged with a set of patch files
+to update the character drivers' makefile and configuration file, and other
+kernel source files. A build script (ip2build) was included which applies
+the patches if needed, and build any utilities needed.
+What you recieve may be a single patch file in conventional kernel
+patch format build script. That form can also be applied by
+running patch -p1 < ThePatchFile. Otherwise run ip2build.
+
+The driver can be installed as a module (recommended) or built into the
+kernel. This is selected as for other drivers through the `make config`
+command from the root of the Linux source tree. If the driver is built
+into the kernel you will need to edit the file ip2.h to match the boards
+you are installing. See that file for instructions. If the driver is
+installed as a module the configuration can also be specified on the
+modprobe command line as follows:
+
+ modprobe ip2 irq=irq1,irq2,irq3,irq4 io=addr1,addr2,addr3,addr4
+
+where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11,
+12,15) and addr1-4 are the base addresses for up to four controllers. If
+the irqs are not specified the driver uses the default in ip2/ip2.h (which
+selects polled mode). If no base addresses are specified the defaults in
+ip2.h are used. If you are autoloading the driver module with kerneld or
+kmod the base addresses and interrupt number must also be set in ip2/ip2.h
+and recompile or just insert and options line in /etc/modules.conf or both.
+The options line is equivalent to the command line and takes precidence over
+what is in ip2.h.
+
+/etc/modules.conf sample:
+ options ip2 io=1,0x328 irq=1,10
+ alias char-major-71 ip2
+ alias char-major-72 ip2
+ alias char-major-73 ip2
+
+equivelant ip2.h:
+static ip2config_t ip2config =
+{
+ {1,10,0,0},
+ {
+ 0x0001, // Board 0, ttyF0 - ttyF63 /* PCI card */
+ 0x0328, // Board 1, ttyF64 - ttyF127 /* ISA card */
+ 0x0000, // Board 2, ttyF128 - ttyF191 /* empty */
+ 0x0000 // Board 3, ttyF192 - ttyF255 /* empty */
+ }
+};
+
+Specifying an invalid or in-use irq will default the driver into
+running in polled mode for that card. If all irq entries are 0 then
+all cards will operate in polled mode.
+
+Tarball Install:
+
+The whole tarfile should be untarred in the /usr/src/linux/drivers/char/
+directory. Most files required for the driver are placed in the ip2
+subdirectory. Then execute the script
+
+ ip2build
+
+which will patch the files.
+
+Kernel Patch Install:
+
+ cd to the Linux source root, run patch -p1 < ThePatchFile.
+
+Now return to the root directory of the Linux
+source tree and run make config or make menuconfig. You will be prompted
+for the Computone drivers, either as a module or part of the kernel.
+If you have a PCI card you many need to select PCI bios support (CONFIG_PCI)
+if not enabled already. Ditto for CONFIG_MODULES if you use modules.
+
+If you select the driver as part of the kernel run :
+
+ make depend
+ make zlilo (or whatever you do to create a bootable kernel)
+
+If you selected a module run :
+
+ make modules && make modules_install
+
+The utility ip2mkdev creates all the device nodes required by the driver.
+For a device to be created it must be configured in the driver and the
+board must be installed. Only devices corresponding to real IntelliPort II
+ports are created. With multiple boards and expansion boxes this will
+leave gaps in the sequence of device names. ip2mkdev uses Linux tty naming
+conventions: ttyF0 - ttyF255 for normal devices, and cuf0 - cuf255 for
+callout devices.
+
+4. USING THE DRIVERS
+
+As noted above, the driver implements the ports in accordance with Linux
+conventions, and the devices should be interchangeable with the standard
+serial devices. (This is a key point for problem reporting: please make
+sure that what you are trying do works on the ttySx/cuax ports first; then
+tell us what went wrong with the ip2 ports!)
+
+Higher speeds can be obtained using the setserial utility which remaps
+38,400 bps (extb) to 57,600 bps, 115,200 bps, or a custom speed.
+Intelliport II installations using the PowerPort expansion module can
+use the custom speed setting to select the highest speeds: 153,600 bps,
+230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for
+custom baud rate configuration is fixed at 921,600 for cards/expantion
+modules with ST654's and 115200 for those with Cirrus CD1400's. This
+corresponds to the maximum bit rates those chips are capable.
+For example if the baud base is 921600 and the baud divisor is 18 then
+the custom rate is 921600/18 = 51200 bps. See the setserial man page for
+complete details. Of course if stty accepts the higher rates now you can
+use that as well as the standard ioctls().
+
+5. NOTES
+
+This is a release version of the driver, but it is impossible to test it
+in all configurations of Linux. If there is any anomalous behaviour that
+does not match the standard serial port's behaviour please let us know.
+
+Author: dmcnash@computine.com
+Testing: larryg@computone.com
+Spport: support@computone.com
diff --git a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c
index 24ed4d9d9..eaf1a8357 100644
--- a/drivers/char/adbmouse.c
+++ b/drivers/char/adbmouse.c
@@ -21,6 +21,9 @@
* 1996/02/11 Andreas Schwab
* Module support
* Allow multiple open's
+ *
+ * Converted to use new generic busmouse code. 11 July 1998
+ * Russell King <rmk@arm.uk.linux.org>
*/
#include <linux/module.h>
@@ -34,233 +37,136 @@
#include <linux/init.h>
#include <asm/adb_mouse.h>
-#include <asm/uaccess.h>
#ifdef __powerpc__
#include <asm/processor.h>
#endif
+#if defined(__mc68000__) || defined(MODULE)
#include <asm/setup.h>
+#endif
+
+#include "busmouse.h"
-static struct mouse_status mouse;
+static int msedev;
static unsigned char adb_mouse_buttons[16];
extern void (*adb_mouse_interrupt_hook)(unsigned char *, int);
extern int adb_emulate_buttons;
extern int adb_button2_keycode;
extern int adb_button3_keycode;
-
extern int console_loglevel;
/*
- * XXX: need to figure out what ADB mouse packets mean ...
- * This is the stuff stolen from the Atari driver ...
+ * XXX: need to figure out what ADB mouse packets mean ...
+ * This is the stuff stolen from the Atari driver ...
*/
static void adb_mouse_interrupt(unsigned char *buf, int nb)
{
- int buttons, id;
+ int buttons, id;
+ char dx, dy;
-/*
- 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] = dddd 1100 ADB command: Talk, register 0, for device dddd.
- data[1] = bxxx xxxx First button and x-axis motion.
- data[2] = byyy yyyy Second button and y-axis motion.
-
- 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] = dddd 1100 ADB command: Talk, register 0, for device dddd.
- data[1] = bxxx xxxx Left button and x-axis motion.
- data[2] = byyy yyyy Second button and y-axis motion.
- data[3] = byyy bxxx Third button and fourth button.
- Y is additional high bits of y-axis motion.
- X is additional high bits of x-axis motion.
-
- This procedure also gets called from the keyboard code if we
- are emulating mouse buttons with keys. In this case data[0] == 0
- (data[0] cannot be 0 for a real ADB packet).
-
- 'buttons' here means 'button down' states!
- Button 1 (left) : bit 2, busmouse button 3
- Button 2 (middle): bit 1, busmouse button 2
- Button 3 (right) : bit 0, busmouse button 1
-*/
-
- /* x/y and buttons swapped */
-
- if (console_loglevel >= 8)
- printk("KERN_DEBUG adb_mouse: %s data; ", buf[0]? "real": "fake");
-
- id = (buf[0] >> 4) & 0xf;
- buttons = adb_mouse_buttons[id];
-
- /* button 1 (left, bit 2) */
- 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 ! */
- if (nb >= 4)
- buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
-
- add_mouse_randomness(((~buttons&7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
-
- adb_mouse_buttons[id] = buttons;
- /* a button is down if it is down on any mouse */
- for (id = 0; id < 16; ++id)
- buttons &= adb_mouse_buttons[id];
-
- mouse.buttons = buttons;
- 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);
-}
+ /*
+ Handler 1 -- 100cpi original Apple mouse protocol.
+ Handler 2 -- 200cpi original Apple mouse protocol.
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
- int retval;
+ For Apple's standard one-button mouse protocol the data array will
+ contain the following values:
- retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
- if (retval < 0)
- return retval;
- return 0;
-}
+ BITS COMMENTS
+ data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+ data[1] = bxxx xxxx First button and x-axis motion.
+ data[2] = byyy yyyy Second button and y-axis motion.
-static int release_mouse(struct inode *inode, struct file *file)
-{
- fasync_mouse(-1, file, 0);
- if (--mouse.active)
- return 0;
+ Handler 4 -- Apple Extended mouse protocol.
- adb_mouse_interrupt_hook = NULL;
- MOD_DEC_USE_COUNT;
- return 0;
-}
+ For Apple's 3-button mouse protocol the data array will contain the
+ following values:
-static int open_mouse(struct inode *inode, struct file *file)
-{
- int id;
+ BITS COMMENTS
+ data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+ data[1] = bxxx xxxx Left button and x-axis motion.
+ data[2] = byyy yyyy Second button and y-axis motion.
+ data[3] = 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.
- if (mouse.active++)
- return 0;
-
- mouse.ready = 0;
-
- mouse.dx = mouse.dy = 0;
- for (id = 0; id < 16; ++id)
- adb_mouse_buttons[id] = 7; /* all buttons up */
- MOD_INC_USE_COUNT;
- adb_mouse_interrupt_hook = adb_mouse_interrupt;
- return 0;
-}
+ '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
+ */
-static ssize_t write_mouse(struct file *file, const char *buffer,
- size_t count, loff_t *ppos)
-{
- return -EINVAL;
+ /* x/y and buttons swapped */
+
+ id = (buf[0] >> 4) & 0xf;
+
+ buttons = adb_mouse_buttons[id];
+
+ /* button 1 (left, bit 2) */
+ 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 ! */
+ if (nb >= 4)
+ buttons = (buttons & 6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
+
+ adb_mouse_buttons[id] = buttons;
+
+ /* a button is down if it is down on any mouse */
+ for (id = 0; id < 16; ++id)
+ buttons &= adb_mouse_buttons[id];
+
+ dx = ((buf[2] & 0x7f) < 64 ? (buf[2] & 0x7f) : (buf[2] & 0x7f) - 128);
+ dy = ((buf[1] & 0x7f) < 64 ? (buf[1] & 0x7f) : (buf[1] & 0x7f) - 128);
+ busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
+
+ if (console_loglevel >= 8)
+ printk(" %X %X %X dx %d dy %d \n",
+ buf[1], buf[2], buf[3], dx, dy);
}
-static ssize_t read_mouse(struct file *file, char *buffer, size_t count,
- loff_t *ppos)
+static int release_mouse(struct inode *inode, struct file *file)
{
- 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;
+ adb_mouse_interrupt_hook = NULL;
+ MOD_DEC_USE_COUNT;
+ return 0;
}
-static unsigned int mouse_poll(struct file *file, poll_table *wait)
+static int open_mouse(struct inode *inode, struct file *file)
{
- poll_wait(file, &mouse.wait, wait);
- if (mouse.ready)
- return POLLIN | POLLRDNORM;
+ MOD_INC_USE_COUNT;
+ adb_mouse_interrupt_hook = adb_mouse_interrupt;
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,
- NULL, /* flush */
- release_mouse,
- NULL,
- fasync_mouse,
-};
-
-#define ADB_MOUSE_MINOR 10
-
-static struct miscdevice adb_mouse = {
- ADB_MOUSE_MINOR, "adbmouse", &adb_mouse_fops
+static struct busmouse adb_mouse =
+{
+ ADB_MOUSE_MINOR, "adbmouse", open_mouse, release_mouse, 7
};
int __init adb_mouse_init(void)
{
- mouse.active = 0;
- mouse.ready = 0;
- init_waitqueue_head(&mouse.wait);
-
#ifdef __powerpc__
- if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
- return -ENODEV;
+ if ((_machine != _MACH_chrp) && (_machine != _MACH_Pmac))
+ return -ENODEV;
#endif
#ifdef __mc68000__
- if (!MACH_IS_MAC)
- return -ENODEV;
+ if (!MACH_IS_MAC)
+ return -ENODEV;
#endif
- printk(KERN_INFO "Macintosh ADB mouse driver installed.\n");
- misc_register(&adb_mouse);
- return 0;
-}
+ msedev = register_busmouse(&adb_mouse);
+ if (msedev < 0)
+ printk(KERN_WARNING "Unable to register ADB mouse driver.\n");
+ else
+ printk(KERN_INFO "Macintosh ADB mouse driver installed.\n");
+
+ return msedev < 0 ? msedev : 0;
+}
/*
* XXX this function is misnamed.
@@ -268,26 +174,32 @@ int __init adb_mouse_init(void)
* option, which is about using ADB keyboard buttons to emulate
* mouse buttons. -- paulus
*/
-void __init adb_mouse_setup(char *str, int *ints)
+static int __init adb_mouse_setup(char *str)
{
+ int ints[4];
+
+ str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] >= 1) {
- adb_emulate_buttons = ints[1] > 0;
- if (ints[1] > 1)
- adb_button2_keycode = ints[1];
+ adb_emulate_buttons = ints[1];
if (ints[0] >= 2)
- adb_button3_keycode = ints[2];
+ adb_button2_keycode = ints[2];
+ if (ints[0] >= 3)
+ adb_button3_keycode = ints[3];
}
+ return 1;
}
-#ifdef MODULE
+__setup("adb_buttons=", adb_mouse_setup);
+#ifdef MODULE
int init_module(void)
{
- return adb_mouse_init();
+ return adb_mouse_init();
}
void cleanup_module(void)
{
- misc_deregister(&adb_mouse);
+ unregister_busmouse(msedev);
}
+
#endif
diff --git a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c
index 70e20b887..f3f0b372d 100644
--- a/drivers/char/amigamouse.c
+++ b/drivers/char/amigamouse.c
@@ -30,6 +30,9 @@
* Moved the isr-allocation to the mouse_{open,close} calls, as there
* is no reason to service the mouse in the vertical blank isr if
* the mouse is not in use. Jes Sorensen
+ *
+ * Converted to use new generic busmouse code. 5 Apr 1998
+ * Russell King <rmk@arm.uk.linux.org>
*/
#include <linux/module.h>
@@ -44,7 +47,7 @@
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
-#include <linux/busmouse.h>
+#include <linux/logibusmouse.h>
#include <asm/setup.h>
#include <asm/system.h>
@@ -53,13 +56,15 @@
#include <asm/amigahw.h>
#include <asm/amigaints.h>
+#include "busmouse.h"
+
+#if AMIGA_OLD_INT
#define AMI_MSE_INT_ON() mouseint_allowed = 1
#define AMI_MSE_INT_OFF() mouseint_allowed = 0
-
-
-static struct mouse_status mouse;
-
static int mouseint_allowed;
+#endif
+
+static int msedev;
static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
@@ -70,9 +75,11 @@ static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
unsigned short joy0dat, potgor;
+#if AMIGA_OLD_INT
if(!mouseint_allowed)
return;
AMI_MSE_INT_OFF();
+#endif
/*
* This routine assumes, just like Kickstart, that the mouse
@@ -128,44 +135,10 @@ static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
(potgor & 0x0400 ? 1 : 0); /* right button */
- if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
- add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
- mouse.buttons = buttons;
- mouse.dx += dx;
- mouse.dy -= dy;
- mouse.ready = 1;
- wake_up_interruptible(&mouse.wait);
-
- /*
- * keep dx/dy reasonable, but still able to track when X (or
- * whatever) must page or is busy (i.e. long waits between
- * reads)
- */
- if (mouse.dx < -2048)
- mouse.dx = -2048;
- else
- if (mouse.dx > 2048)
- mouse.dx = 2048;
-
- if (mouse.dy < -2048)
- mouse.dy = -2048;
- else
- if (mouse.dy > 2048)
- mouse.dy = 2048;
-
- if (mouse.fasyncptr)
- kill_fasync(mouse.fasyncptr, SIGIO);
- }
+ busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
+#if AMIGA_OLD_INT
AMI_MSE_INT_ON();
-}
-
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
- int retval;
- retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
- if (retval < 0)
- return retval;
- return 0;
+#endif
}
/*
@@ -174,11 +147,10 @@ static int fasync_mouse(int fd, struct file *filp, int on)
static int release_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(-1, file, 0);
- if (--mouse.active)
- return 0;
free_irq(IRQ_AMIGA_VERTB, mouse_interrupt);
+#if AMIGA_OLD_INT
AMI_MSE_INT_OFF();
+#endif
MOD_DEC_USE_COUNT;
return 0;
}
@@ -190,123 +162,25 @@ static int release_mouse(struct inode * inode, struct file * file)
static int open_mouse(struct inode * inode, struct file * file)
{
- if (!mouse.present)
- return -EINVAL;
- if (mouse.active++)
- return 0;
/*
* use VBL to poll mouse deltas
*/
if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0,
"Amiga mouse", mouse_interrupt)) {
- mouse.present = 0;
printk(KERN_INFO "Installing Amiga mouse failed.\n");
return -EIO;
}
- mouse.ready = 0;
- mouse.dx = 0;
- mouse.dy = 0;
- mouse.buttons = 0x87;
- mouse.active = 1;
MOD_INC_USE_COUNT;
+#if AMIGA_OLD_INT
AMI_MSE_INT_ON();
+#endif
return 0;
}
-/*
- * writes are disallowed
- */
-
-static ssize_t write_mouse(struct file * file, const char * buffer,
- size_t count, loff_t *ppos)
-{
- return -EINVAL;
-}
-
-/*
- * read mouse data. Currently never blocks.
- */
-
-static ssize_t read_mouse(struct file * file, char * buffer,
- size_t count, loff_t *ppos)
-{
- int dx;
- int dy;
- unsigned char buttons;
-
- if (count < 3)
- return -EINVAL;
- if (!mouse.ready)
- return -EAGAIN;
-
- /*
- * Obtain the current mouse parameters and limit as appropriate for
- * the return data format. Interrupts are only disabled while
- * obtaining the parameters, NOT during the puts_user() calls,
- * so paging in put_user() does not effect mouse tracking.
- */
-
- AMI_MSE_INT_OFF();
- dx = mouse.dx;
- dy = mouse.dy;
- if (dx < -127)
- dx = -127;
- else
- if (dx > 127)
- dx = 127;
- if (dy < -127)
- dy = -127;
- else
- if (dy > 127)
- dy = 127;
- buttons = mouse.buttons;
- mouse.dx -= dx;
- mouse.dy -= dy;
- mouse.ready = 0;
- AMI_MSE_INT_ON();
-
- if (put_user(buttons | 0x80, buffer++) ||
- put_user((char)dx, buffer++) ||
- put_user((char)dy, buffer++))
- return -EINVAL;
-
- if (count > 3)
- if (clear_user(buffer, count - 3))
- return -EFAULT;
- return count;
-}
-
-/*
- * poll for mouse input
- */
-
-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 amiga_mouse_fops = {
- NULL, /* mouse_seek */
- read_mouse,
- write_mouse,
- NULL, /* mouse_readdir */
- mouse_poll, /* mouse_poll */
- NULL, /* mouse_ioctl */
- NULL, /* mouse_mmap */
- open_mouse,
- NULL, /* flush */
- release_mouse,
- NULL,
- fasync_mouse,
-};
-
-static struct miscdevice amiga_mouse = {
- AMIGAMOUSE_MINOR, "amigamouse", &amiga_mouse_fops
+static struct busmouse amigamouse = {
+ AMIGAMOUSE_MINOR, "amigamouse", open_mouse, release_mouse, 7
};
int __init amiga_mouse_init(void)
@@ -315,32 +189,23 @@ int __init amiga_mouse_init(void)
return -ENODEV;
custom.joytest = 0; /* reset counters */
-
+#if AMIGA_OLD_INT
AMI_MSE_INT_OFF();
-
- mouse.active = 0;
- mouse.ready = 0;
- mouse.buttons = 0x87;
- mouse.dx = 0;
- mouse.dy = 0;
- mouse.wait = NULL;
-
- mouse.present = 1;
-
- printk(KERN_INFO "Amiga mouse installed.\n");
- misc_register(&amiga_mouse);
- return 0;
+#endif
+ msedev = register_busmouse(&amigamouse);
+ if (msedev < 0)
+ printk(KERN_WARNING "Unable to install Amiga mouse driver.\n");
+ else
+ printk(KERN_INFO "Amiga mouse installed.\n");
+ return msedev < 0 ? msedev : 0;
}
-#ifdef MODULE
-
-int init_module(void)
+void __exit amiga_mouse_exit(void)
{
- return amiga_mouse_init();
+ unregister_busmouse(msedev);
}
-void cleanup_module(void)
-{
- misc_deregister(&amiga_mouse);
-}
+#ifdef MODULE
+module_init(amiga_mouse_init)
+module_exit(amiga_mouse_exit)
#endif
diff --git a/drivers/char/amikeyb.c b/drivers/char/amikeyb.c
index d9ebd1084..42e1ea7c8 100644
--- a/drivers/char/amikeyb.c
+++ b/drivers/char/amikeyb.c
@@ -257,7 +257,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
add_timer(&amikeyb_rep_timer);
}
- handle_scancode(scancode, !break_flag);
+ handle_scancode(keycode, !break_flag);
} else
switch (keycode) {
case 0x78:
@@ -341,8 +341,3 @@ int amiga_kbdrate( struct kbd_repeat *k )
return( 0 );
}
-
-/* for "kbd-reset" cmdline param */
-void __init amiga_kbd_reset_setup(char *str, int *ints)
-{
-}
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
new file mode 100644
index 000000000..c311e58cd
--- /dev/null
+++ b/drivers/char/applicom.c
@@ -0,0 +1,842 @@
+/* Derived from Applicom driver ac.c for SCO Unix */
+/* Ported by David Woodhouse, Axiom (Cambridge) Ltd. */
+/* Dave@mvhi.com 30/8/98 */
+/* $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $ */
+/* This module is for Linux 2.1 and 2.2 series kernels. */
+/*****************************************************************************/
+/* J PAGET 18/02/94 passage V2.4.2 ioctl avec code 2 reset to les interrupt */
+/* ceci pour reseter correctement apres une sortie sauvage */
+/* J PAGET 02/05/94 passage V2.4.3 dans le traitement de d'interruption, */
+/* LoopCount n'etait pas initialise a 0. */
+/* F LAFORSE 04/07/95 version V2.6.0 lecture bidon apres acces a une carte */
+/* pour liberer le bus */
+/* J.PAGET 19/11/95 version V2.6.1 Nombre, addresse,irq n'est plus configure */
+/* et passe en argument a acinit, mais est scrute sur le bus pour s'adapter */
+/* au nombre de cartes presentes sur le bus. IOCL code 6 affichait V2.4.3 */
+/* F.LAFORSE 28/11/95 creation de fichiers acXX.o avec les differentes */
+/* adresses de base des cartes, IOCTL 6 plus complet */
+/* J.PAGET le 19/08/96 copie de la version V2.6 en V2.8.0 sans modification */
+/* de code autre que le texte V2.6.1 en V2.8.0 */
+/*****************************************************************************/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+#include <linux/init.h>
+#include "applicom.h"
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#undef DEBUG
+#define DEVPRIO PZERO+8
+#define FALSE 0
+#define TRUE ~FALSE
+#define MAX_BOARD 8 /* maximum of pc board possible */
+#define MAX_ISA_BOARD 4
+#define LEN_RAM_IO 0x800
+#define AC_MINOR 157
+
+#ifndef PCI_VENDOR_ID_APPLICOM
+#define PCI_VENDOR_ID_APPLICOM 0x1389
+#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001
+#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002
+#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003
+#define MAX_PCI_DEVICE_NUM 3
+#endif
+
+static char *applicom_pci_devnames[]={
+ "PCI board", "PCI2000IBS / PCI2000CAN", "PCI2000PFB"};
+
+MODULE_AUTHOR("David Woodhouse & Applicom International");
+MODULE_DESCRIPTION("Driver for Applicom Profibus card");
+MODULE_PARM(irq, "i");
+MODULE_PARM_DESC(irq, "IRQ of the Applicom board");
+MODULE_PARM(mem,"i");
+MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board");
+
+MODULE_SUPPORTED_DEVICE("ac");
+
+
+struct applicom_board {
+ unsigned long PhysIO;
+ unsigned long RamIO;
+#if LINUX_VERSION_CODE > 0x20300
+ wait_queue_head_t FlagSleepSend;
+#else
+ struct wait_queue *FlagSleepSend;
+#endif
+ long irq;
+} apbs[MAX_BOARD];
+
+static unsigned int irq=0; /* interrupt number IRQ */
+static unsigned long mem=0; /* physical segment of board */
+
+static unsigned int numboards; /* number of installed boards */
+static volatile unsigned char Dummy;
+#if LINUX_VERSION_CODE > 0x20300
+static DECLARE_WAIT_QUEUE_HEAD (FlagSleepRec);
+#else
+static struct wait_queue *FlagSleepRec;
+#endif
+static unsigned int WriteErrorCount; /* number of write error */
+static unsigned int ReadErrorCount; /* number of read error */
+static unsigned int DeviceErrorCount; /* number of device error */
+
+static loff_t ac_llseek(struct file *file, loff_t offset, int origin);
+static int ac_open(struct inode *inode, struct file *filp);
+static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr);
+static ssize_t ac_write (struct file *file, const char *buf, size_t count, loff_t *ppos);
+static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int ac_release(struct inode *inode, struct file *file);
+static void ac_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+
+struct file_operations ac_fops={
+ ac_llseek, /* llseek */
+ ac_read, /* read */
+ ac_write, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ ac_ioctl, /* ioctl */
+ NULL, /* mmap */
+ ac_open, /* open */
+ NULL, /* flush */
+ ac_release, /* release */
+ NULL /* fsync */
+};
+
+struct miscdevice ac_miscdev={
+ AC_MINOR,
+ "ac",
+ &ac_fops
+};
+
+int ac_register_board(unsigned long physloc, unsigned long loc,
+ unsigned char boardno)
+{
+ volatile unsigned char byte_reset_it;
+
+ if((readb(loc + CONF_END_TEST) != 0x00) ||
+ (readb(loc + CONF_END_TEST + 1) != 0x55) ||
+ (readb(loc + CONF_END_TEST + 2) != 0xAA) ||
+ (readb(loc + CONF_END_TEST + 3) != 0xFF))
+ return 0;
+
+
+ if (!boardno)
+ boardno = readb(loc + NUMCARD_OWNER_TO_PC);
+
+ if (!boardno && boardno > MAX_BOARD)
+ {
+ printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n",boardno, physloc, MAX_BOARD);
+ return 0;
+ }
+
+ if (apbs[boardno-1].RamIO)
+ {
+ printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n",
+ boardno, physloc, boardno, apbs[boardno-1].PhysIO);
+ return 0;
+ }
+
+ boardno--;
+
+ apbs[boardno].PhysIO = physloc;
+ apbs[boardno].RamIO = loc;
+#if LINUX_VERSION_CODE > 0x20300
+ init_waitqueue_head(&apbs[boardno].FlagSleepSend);
+#else
+ apbs[boardno].FlagSleepSend = NULL;
+#endif
+ byte_reset_it = readb(loc + RAM_IT_TO_PC);
+
+ numboards++;
+ return boardno+1;
+}
+
+#ifdef MODULE
+
+#define applicom_init init_module
+
+void cleanup_module(void)
+{
+ int i;
+
+ misc_deregister(&ac_miscdev);
+ for (i=0; i< MAX_BOARD; i++)
+ {
+ if (!apbs[i].RamIO)
+ continue;
+ iounmap((void *)apbs[i].RamIO);
+ if (apbs[i].irq)
+ free_irq(apbs[i].irq,&ac_open);
+ }
+ // printk("Removing Applicom module\n");
+}
+
+#endif /* MODULE */
+
+int __init applicom_init(void)
+{
+ int i, numisa=0;
+ struct pci_dev *dev = NULL;
+ void *RamIO;
+ int boardno;
+#if LINUX_VERSION_CODE > 0x20300
+#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
+#else
+#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
+#endif
+
+ printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $\n");
+
+ /* No mem and irq given - check for a PCI card */
+
+ while ( (dev = pci_find_device(PCI_VENDOR_ID_APPLICOM, 1, dev)))
+ {
+ // mem = dev->base_address[0];
+ // irq = dev->irq;
+
+ RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO);
+
+ if (!RamIO) {
+ printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev));
+ return -EIO;
+ }
+
+ printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n",
+ applicom_pci_devnames[dev->device-1], PCI_BASE_ADDRESS(dev),
+ dev->irq);
+
+ if (!(boardno = ac_register_board(PCI_BASE_ADDRESS(dev),
+ (unsigned long)RamIO,0)))
+ {
+ printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n");
+ iounmap(RamIO);
+ continue;
+ }
+
+ if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open))
+ {
+ printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
+ iounmap(RamIO);
+ apbs[boardno-1].RamIO = 0;
+ continue;
+ }
+
+ /* Enable interrupts. */
+
+ writeb(0x40, apbs[boardno-1].RamIO + RAM_IT_FROM_PC);
+
+ apbs[boardno-1].irq = dev->irq;
+ }
+
+ /* Finished with PCI cards. If none registered,
+ * and there was no mem/irq specified, exit */
+
+ if (!mem || !irq)
+ {
+ if (numboards)
+ goto fin;
+ else
+ {
+ printk(KERN_INFO "ac.o: No PCI boards found.\n");
+ printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n");
+ return -ENXIO;
+ }
+ }
+
+ /* Now try the specified ISA cards */
+
+ RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD);
+
+ if (!RamIO) {
+ printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n",mem);
+ }
+
+ for (i=0; i< MAX_ISA_BOARD; i++)
+ {
+ RamIO = ioremap(mem+ (LEN_RAM_IO*i), LEN_RAM_IO);
+
+ if (!RamIO) {
+ printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n",i+1);
+ continue;
+ }
+
+ if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i),
+ (unsigned long)RamIO,i+1))) {
+ iounmap(RamIO);
+ continue;
+ }
+
+ printk("Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq);
+
+ if (!numisa)
+ {
+ if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &ac_open))
+ {
+ printk("Could not allocate IRQ %d for ISA Applicom device.\n", irq);
+ iounmap((void *)RamIO);
+ apbs[boardno-1].RamIO = 0;
+ }
+ apbs[boardno-1].irq=irq;
+ }
+ else
+ apbs[boardno-1].irq=0;
+
+ numisa++;
+ }
+
+ if (!numisa)
+ printk("ac.o: No valid ISA Applicom boards found at mem 0x%lx\n",mem);
+
+#if LINUX_VERSION_CODE > 0x20300
+ init_waitqueue_head(&FlagSleepRec);
+#else
+ FlagSleepRec = NULL;
+#endif
+ WriteErrorCount = 0;
+ ReadErrorCount = 0;
+ DeviceErrorCount = 0;
+
+fin:
+ if (numboards)
+ {
+ misc_register (&ac_miscdev);
+ for (i=0; i<MAX_BOARD; i++)
+ {
+ int serial;
+ char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
+
+ if (!apbs[i].RamIO)
+ continue;
+
+ for(serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
+ boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
+ boardname[serial]=0;
+
+
+ printk("Applicom board %d: %s, PROM V%d.%d",
+ i+1, boardname,
+ (int)(readb(apbs[i].RamIO + VERS) >> 4),
+ (int)(readb(apbs[i].RamIO + VERS) & 0xF));
+
+ serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) +
+ (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) +
+ (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) );
+
+ if (serial != 0)
+ printk (" S/N %d\n", serial);
+ else
+ printk("\n");
+ }
+ return 0;
+ }
+
+ else
+ return -ENXIO;
+}
+
+
+#ifndef MODULE
+__initcall (applicom_init);
+#endif
+
+static loff_t ac_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static int ac_open(struct inode *inode, struct file *filp)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int ac_release(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+
+static ssize_t ac_write (struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+ unsigned int NumCard; /* Board number 1 -> 8 */
+ unsigned int IndexCard; /* Index board number 0 -> 7 */
+ unsigned char TicCard; /* Board TIC to send */
+ unsigned long flags; /* Current priority */
+ struct st_ram_io st_loc;
+ struct mailbox tmpmailbox;
+
+ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
+ printk("Hmmm. write() of Applicom card, length %d != expected %d\n",count,sizeof(struct st_ram_io) + sizeof(struct mailbox));
+ return -EINVAL;
+ }
+
+ if(copy_from_user (&st_loc, buf, sizeof(struct st_ram_io))) {
+ return -EFAULT;
+ }
+ if(copy_from_user (&tmpmailbox, &buf[sizeof(struct st_ram_io)], sizeof(struct mailbox))) {
+ return -EFAULT;
+ }
+
+ NumCard = st_loc.num_card; /* board number to send */
+ TicCard = st_loc.tic_des_from_pc; /* tic number to send */
+ IndexCard = NumCard -1;
+ if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO)
+ { /* User board number not OK */
+ // printk("Write to invalid Applicom board %d\n", NumCard);
+ return -EINVAL; /* Return error code user buffer */
+ }
+
+#ifdef DEBUG
+ {
+ int c;
+
+ printk("Write to applicom card #%d. struct st_ram_io follows:",NumCard);
+
+
+
+ for (c=0; c< sizeof(struct st_ram_io);)
+ {
+ printk("\n%5.5X: %2.2X",c,((unsigned char *)&st_loc)[c]);
+
+ for (c++ ; c%8 && c<sizeof(struct st_ram_io); c++)
+ {
+ printk(" %2.2X",((unsigned char *)&st_loc)[c]);
+ }
+ }
+
+ printk("\nstruct mailbox follows:");
+
+ for (c=0; c< sizeof(struct mailbox);)
+ {
+ printk("\n%5.5X: %2.2X",c,((unsigned char *)&tmpmailbox)[c]);
+
+ for (c++ ; c%8 && c<sizeof(struct mailbox); c++)
+ {
+ printk(" %2.2X",((unsigned char *)&tmpmailbox)[c]);
+ }
+ }
+
+ printk("\n");
+ }
+
+#endif
+
+ save_flags (flags);
+ cli(); /* disable interrupt */
+
+ if(readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) /* Test octet ready correct */
+ {
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
+ printk("APPLICOM driver write error board %d, DataFromPcReady = %d\n",
+ IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY));
+ DeviceErrorCount++;
+ return -EIO;
+ }
+ while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0)
+ {
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
+ interruptible_sleep_on (&apbs[IndexCard].FlagSleepSend);
+ if (signal_pending(current))
+ return -EINTR;
+ save_flags(flags);
+ cli();
+ }
+ writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+
+ // memcpy_toio ((void *)apbs[IndexCard].PtrRamFromPc, (void *)&tmpmailbox, sizeof(struct mailbox));
+ {
+ unsigned char *from = (unsigned char *)&tmpmailbox;
+ unsigned long to = (unsigned long)apbs[IndexCard].RamIO + RAM_FROM_PC;
+ int c;
+
+ for (c=0; c<sizeof(struct mailbox) ; c++)
+ writeb(*(from++), to++);
+ }
+ writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC);
+ writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC);
+ writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC);
+ writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
+ writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+ writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags (flags);
+ return 0;
+}
+
+static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr)
+{
+ unsigned int NumCard; /* board number 1 -> 8 */
+ unsigned int IndexCard; /* index board number 0 -> 7 */
+ unsigned long flags;
+ unsigned int i;
+ unsigned char tmp=0;
+ struct st_ram_io st_loc;
+ struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */
+
+
+ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
+ printk("Hmmm. read() of Applicom card, length %d != expected %d\n",count,sizeof(struct st_ram_io) + sizeof(struct mailbox));
+ return -EINVAL;
+ }
+
+ save_flags(flags);
+ cli();
+
+ i = 0;
+
+ while (tmp != 2)
+ {
+ for (i=0; i < MAX_BOARD; i++)
+ {
+ if (!apbs[i].RamIO)
+ continue;
+
+ tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY);
+
+ if (tmp == 2)
+ break;
+
+ if (tmp > 2) /* Test octet ready correct */
+ {
+ Dummy = readb(apbs[i].RamIO + VERS);
+ restore_flags(flags);
+ printk("APPLICOM driver read error board %d, DataToPcReady = %d\n",
+ i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY));
+ DeviceErrorCount++;
+ return -EIO;
+ }
+ Dummy = readb(apbs[i].RamIO + VERS);
+
+ }
+ if (tmp != 2)
+ {
+ restore_flags(flags);
+ interruptible_sleep_on (&FlagSleepRec);
+ if (signal_pending(current))
+ return -EINTR;
+ save_flags(flags);
+ cli();
+ }
+ }
+
+ IndexCard = i;
+ NumCard = i+1;
+ st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC);
+ st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
+
+
+ // memcpy_fromio(&tmpmailbox, apbs[IndexCard].PtrRamToPc, sizeof(struct mailbox));
+ {
+ unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC;
+ unsigned char *to = (unsigned char *)&tmpmailbox;
+ int c;
+
+ for (c=0; c<sizeof(struct mailbox) ; c++)
+ *(to++) = readb(from++);
+ }
+ writeb(1,apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
+ writeb(1,apbs[IndexCard].RamIO + TYP_ACK_FROM_PC);
+ writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
+ writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC),
+ apbs[IndexCard].RamIO + TIC_ACK_FROM_PC);
+ writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
+ writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY);
+ writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
+
+#ifdef DEBUG
+ { int c;
+
+ printk("Read from applicom card #%d. struct st_ram_io follows:",NumCard);
+
+ for (c=0; c< sizeof(struct st_ram_io);)
+ {
+ printk("\n%5.5X: %2.2X",c,((unsigned char *)&st_loc)[c]);
+
+ for (c++ ; c%8 && c<sizeof(struct st_ram_io); c++)
+ {
+ printk(" %2.2X",((unsigned char *)&st_loc)[c]);
+ }
+ }
+
+ printk("\nstruct mailbox follows:");
+
+ for (c=0; c< sizeof(struct mailbox);)
+ {
+ printk("\n%5.5X: %2.2X",c,((unsigned char *)&tmpmailbox)[c]);
+
+ for (c++ ; c%8 && c<sizeof(struct mailbox); c++)
+ {
+ printk(" %2.2X",((unsigned char *)&tmpmailbox)[c]);
+ }
+ }
+ printk("\n");
+
+ }
+#endif
+
+
+ /* Je suis stupide. DW. */
+
+ if(copy_to_user (buf, &st_loc, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ if(copy_to_user (&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static void ac_interrupt(int vec, void *dev_instance, struct pt_regs *regs)
+{
+ unsigned int i;
+ unsigned int FlagInt;
+ unsigned int LoopCount;
+ // volatile unsigned char ResetIntBoard;
+
+ // printk("Applicom interrupt on IRQ %d occurred\n", vec);
+
+ LoopCount = 0;
+ // for(i=boardno;i<MAX_BOARD;i++) /* loop for not configured board */
+ // if (apbs[i].RamIO)
+ // ResetIntBoard = *apbs[i].PtrRamItToPc; /* reset interrupt of unused boards */
+
+ do
+ {
+ FlagInt = FALSE;
+ for(i=0;i<MAX_BOARD;i++)
+ {
+ if (!apbs[i].RamIO)
+ continue;
+
+ if(readb(apbs[i].RamIO + RAM_IT_TO_PC) != 0)
+ FlagInt = TRUE;
+ writeb(0, apbs[i].RamIO + RAM_IT_TO_PC);
+
+ if(readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2)
+ {
+ printk("APPLICOM driver interrupt err board %d, DataToPcReady = %d\n",
+ i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY));
+ DeviceErrorCount++;
+ }
+ if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) &&
+ (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6))
+ {
+ printk("APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n",
+ i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY));
+ DeviceErrorCount++;
+ }
+ if(readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) /* mailbox sent by the card ? */
+ {
+ wake_up_interruptible(&FlagSleepRec);
+ }
+ if(readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) /* ram i/o free for write by pc ? */
+ {
+ if(waitqueue_active(&apbs[i].FlagSleepSend)) /* process sleep during read ? */
+ {
+ wake_up_interruptible(&apbs[i].FlagSleepSend);
+ }
+ }
+ Dummy = readb(apbs[i].RamIO + VERS);
+
+ if(readb(apbs[i].RamIO + RAM_IT_TO_PC))
+ i--; /* There's another int waiting on this card */
+ }
+ if(FlagInt) LoopCount = 0;
+ else LoopCount++;
+ }
+ while(LoopCount < 2);
+}
+
+
+static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+
+{ /* @ ADG ou ATO selon le cas */
+ int i;
+ unsigned char IndexCard;
+ unsigned long pmem ;
+ volatile unsigned char byte_reset_it;
+ struct st_ram_io adgl ;
+ unsigned char TmpRamIo[sizeof(struct st_ram_io)];
+
+
+ if (copy_from_user (&adgl, (void *)arg,sizeof(struct st_ram_io)))
+ return -EFAULT;
+
+ IndexCard = adgl.num_card-1;
+ if(cmd != 0 && cmd != 6 &&
+ ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO))
+ {
+ printk("APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
+ printk("apbs[%d].RamIO = %lx\n",IndexCard, apbs[IndexCard].RamIO);
+ return -EINVAL;
+ }
+
+ switch( cmd )
+ {
+ case 0 :
+ pmem = apbs[IndexCard].RamIO;
+ for(i=0;i<sizeof(struct st_ram_io);i++)TmpRamIo[i]=readb(pmem++);
+ if (copy_to_user((void *)arg, TmpRamIo, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ break;
+ case 1 :
+ pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
+ for (i=0;i<4;i++)
+ adgl.conf_end_test[i] = readb(pmem++);
+ for (i=0;i<2;i++)
+ adgl.error_code[i] = readb(pmem++);
+ for (i=0;i<4;i++)
+ adgl.parameter_error[i] = readb(pmem++);
+ pmem = apbs[IndexCard].RamIO + VERS;
+ adgl.vers = readb(pmem);
+ pmem = apbs[IndexCard].RamIO + TYPE_CARD;
+ for (i=0;i<20;i++)
+ adgl.reserv1[i] = readb(pmem++);
+ *(int *)&adgl.reserv1[20] =
+ (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) +
+ (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) +
+ (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2) );
+
+ if (copy_to_user ((void *)arg, &adgl, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ break;
+ case 2 :
+ pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
+ for (i=0;i<10;i++)
+ writeb(0xff, pmem++);
+ writeb(adgl.data_from_pc_ready,
+ apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+
+ writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+#if LINUX_VERSION_CODE > 0x20300
+ init_waitqueue_head (&FlagSleepRec);
+#else
+ FlagSleepRec = NULL;
+#endif
+ for (i=0;i<MAX_BOARD;i++)
+ {
+ if (apbs[i].RamIO)
+ {
+#if LINUX_VERSION_CODE > 0x20300
+ init_waitqueue_head (&apbs[i].FlagSleepSend);
+#else
+ apbs[i].FlagSleepSend = NULL;
+#endif
+ byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC);
+ }
+ }
+ break ;
+ case 3 :
+ pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC;
+ writeb(adgl.tic_des_from_pc, pmem);
+ break;
+ case 4 :
+ pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC;
+ adgl.tic_owner_to_pc = readb(pmem++);
+ adgl.numcard_owner_to_pc = readb(pmem);
+ if (copy_to_user ((void *)arg, &adgl,sizeof(struct st_ram_io)))
+ return -EFAULT;
+ break;
+ case 5 :
+ writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
+ writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
+ writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
+ writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+ writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+ break ;
+ case 6 :
+ printk("APPLICOM driver release .... V2.8.0\n");
+ printk("Number of installed boards . %d\n",(int)numboards);
+ printk("Segment of board ........... %X\n",(int)mem);
+ printk("Interrupt IRQ number ....... %d\n",(int)irq);
+ for(i=0;i<MAX_BOARD;i++)
+ {
+ int serial;
+ char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
+
+ if (!apbs[i].RamIO)
+ continue;
+
+
+ for(serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
+ boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
+ boardname[serial]=0;
+
+
+ printk("Prom version board %d ....... V%d.%d %s",
+ i+1,
+ (int)(readb(apbs[IndexCard].RamIO + VERS) >> 4),
+ (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF),
+ boardname);
+
+
+ serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) +
+ (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) +
+ (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) );
+
+ if (serial != 0)
+ printk (" S/N %d\n", serial);
+ else
+ printk("\n");
+ }
+ if(DeviceErrorCount != 0)
+ printk("DeviceErrorCount ........... %d\n",DeviceErrorCount);
+ if(ReadErrorCount != 0)
+ printk("ReadErrorCount ............. %d\n",ReadErrorCount);
+ if(WriteErrorCount != 0)
+ printk("WriteErrorCount ............ %d\n",WriteErrorCount);
+ if(waitqueue_active(&FlagSleepRec))
+ printk("Process in read pending\n");
+ for(i=0;i<MAX_BOARD;i++)
+ {
+ if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend))
+ printk("Process in write pending board %d\n",i+1);
+ }
+ break;
+ default :
+ printk("APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
+ return -EINVAL;
+ break;
+ }
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ return 0;
+}
+
+#ifndef MODULE
+static int __init applicom_setup(char *str)
+{
+ int ints[4];
+
+ (void)get_options(str, 4, ints);
+
+ if (ints[0] > 2) {
+ printk(KERN_WARNING "Too many arguments to 'applicom=', expected mem,irq only.\n");
+ }
+
+ if (ints[0] < 2) {
+ printk("applicom numargs: %d\n", ints[0]);
+ return 0;
+ }
+
+ mem=ints[1];
+ irq=ints[2];
+ return 1;
+}
+#if LINUX_VERSION_CODE > 0x20300
+__setup("applicom=", applicom_setup);
+#endif
+#endif /* MODULE */
+
diff --git a/drivers/char/applicom.h b/drivers/char/applicom.h
new file mode 100644
index 000000000..35530b3d9
--- /dev/null
+++ b/drivers/char/applicom.h
@@ -0,0 +1,85 @@
+/* $Id: applicom.h,v 1.2 1999/08/28 15:09:49 dwmw2 Exp $ */
+
+
+#ifndef __LINUX_APPLICOM_H__
+#define __LINUX_APPLICOM_H__
+
+
+#define DATA_TO_PC_READY 0x00
+#define TIC_OWNER_TO_PC 0x01
+#define NUMCARD_OWNER_TO_PC 0x02
+#define TIC_DES_TO_PC 0x03
+#define NUMCARD_DES_TO_PC 0x04
+#define DATA_FROM_PC_READY 0x05
+#define TIC_OWNER_FROM_PC 0x06
+#define NUMCARD_OWNER_FROM_PC 0x07
+#define TIC_DES_FROM_PC 0x08
+#define NUMCARD_DES_FROM_PC 0x09
+#define ACK_FROM_PC_READY 0x0E
+#define TIC_ACK_FROM_PC 0x0F
+#define NUMCARD_ACK_FROM_PC 0x010
+#define TYP_ACK_FROM_PC 0x011
+#define CONF_END_TEST 0x012
+#define ERROR_CODE 0x016
+#define PARAMETER_ERROR 0x018
+#define VERS 0x01E
+#define RAM_TO_PC 0x040
+#define RAM_FROM_PC 0x0170
+#define TYPE_CARD 0x03C0
+#define SERIAL_NUMBER 0x03DA
+#define RAM_IT_FROM_PC 0x03FE
+#define RAM_IT_TO_PC 0x03FF
+
+struct mailbox{
+ u16 stjb_codef; /* offset 00 */
+ s16 stjb_status; /* offset 02 */
+ u16 stjb_ticuser_root; /* offset 04 */
+ u8 stjb_piduser[4]; /* offset 06 */
+ u16 stjb_mode; /* offset 0A */
+ u16 stjb_time; /* offset 0C */
+ u16 stjb_stop; /* offset 0E */
+ u16 stjb_nfonc; /* offset 10 */
+ u16 stjb_ncard; /* offset 12 */
+ u16 stjb_nchan; /* offset 14 */
+ u16 stjb_nes; /* offset 16 */
+ u16 stjb_nb; /* offset 18 */
+ u16 stjb_typvar; /* offset 1A */
+ u32 stjb_adr; /* offset 1C */
+ u16 stjb_ticuser_dispcyc; /* offset 20 */
+ u16 stjb_ticuser_protocol; /* offset 22 */
+ u8 stjb_filler[12]; /* offset 24 */
+ u8 stjb_data[256]; /* offset 30 */
+ };
+
+struct st_ram_io
+{
+ unsigned char data_to_pc_ready;
+ unsigned char tic_owner_to_pc;
+ unsigned char numcard_owner_to_pc;
+ unsigned char tic_des_to_pc;
+ unsigned char numcard_des_to_pc;
+ unsigned char data_from_pc_ready;
+ unsigned char tic_owner_from_pc;
+ unsigned char numcard_owner_from_pc;
+ unsigned char tic_des_from_pc;
+ unsigned char numcard_des_from_pc;
+ unsigned char ack_to_pc_ready;
+ unsigned char tic_ack_to_pc;
+ unsigned char numcard_ack_to_pc;
+ unsigned char typ_ack_to_pc;
+ unsigned char ack_from_pc_ready;
+ unsigned char tic_ack_from_pc;
+ unsigned char numcard_ack_from_pc;
+ unsigned char typ_ack_from_pc;
+ unsigned char conf_end_test[4];
+ unsigned char error_code[2];
+ unsigned char parameter_error[4];
+ unsigned char time_base;
+ unsigned char nul_inc;
+ unsigned char vers;
+ unsigned char num_card;
+ unsigned char reserv1[32];
+};
+
+
+#endif /* __LINUX_APPLICOM_H__ */
diff --git a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c
index b813510eb..b831bd49c 100644
--- a/drivers/char/atarimouse.c
+++ b/drivers/char/atarimouse.c
@@ -10,6 +10,9 @@
* 1996/02/11 Andreas Schwab
* Module support
* Allow multiple open's
+ *
+ * Converted to use new generic busmouse code. 5 Apr 1998
+ * Russell King <rmk@arm.uk.linux.org>
*/
#include <linux/module.h>
@@ -21,13 +24,15 @@
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
-#include <linux/busmouse.h>
+#include <linux/logibusmouse.h>
#include <asm/setup.h>
#include <asm/atarikb.h>
#include <asm/uaccess.h>
-static struct mouse_status mouse;
+#include "busmouse.h"
+
+static int msedev;
static int mouse_threshold[2] = {2,2};
MODULE_PARM(mouse_threshold, "2i");
extern int atari_mouse_buttons;
@@ -38,36 +43,17 @@ static void atari_mouse_interrupt(char *buf)
/* ikbd_mouse_disable(); */
- buttons = ((buf[0] & 1 ? 1 : 0)
- | (buf[0] & 2 ? 4 : 0)
+ buttons = ((buf[0] & 1)
+ | ((buf[0] & 2) << 1)
| (atari_mouse_buttons & 2));
atari_mouse_buttons = buttons;
- add_mouse_randomness((buttons << 16) + (buf[2] << 8) + buf[1]);
- mouse.buttons = ~buttons & 7;
- mouse.dx += buf[1];
- mouse.dy -= buf[2];
- mouse.ready = 1;
- wake_up_interruptible(&mouse.wait);
- if (mouse.fasyncptr)
- kill_fasync(mouse.fasyncptr, SIGIO);
+ busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons ^ 7);
/* ikbd_mouse_rel_pos(); */
}
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
- int retval;
- retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
- if (retval < 0)
- return retval;
- return 0;
-}
-
static int release_mouse(struct inode *inode, struct file *file)
{
- fasync_mouse(-1, file, 0);
- if (--mouse.active)
- return 0;
ikbd_mouse_disable();
atari_mouse_interrupt_hook = NULL;
@@ -77,10 +63,6 @@ static int release_mouse(struct inode *inode, struct file *file)
static int open_mouse(struct inode *inode, struct file *file)
{
- if (mouse.active++)
- return 0;
- mouse.ready = 0;
- mouse.dx = mouse.dy = 0;
atari_mouse_buttons = 0;
ikbd_mouse_y0_top ();
ikbd_mouse_thresh (mouse_threshold[0], mouse_threshold[1]);
@@ -90,92 +72,20 @@ static int open_mouse(struct inode *inode, struct file *file)
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;
- /* ikbd_mouse_disable */
- 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;
- /* ikbd_mouse_rel_pos(); */
- 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 atari_mouse_fops = {
- NULL, /* mouse_seek */
- read_mouse,
- write_mouse,
- NULL, /* mouse_readdir */
- mouse_poll,
- NULL, /* mouse_ioctl */
- NULL, /* mouse_mmap */
- open_mouse,
- NULL, /* flush */
- release_mouse,
- NULL,
- fasync_mouse,
-};
-
-static struct miscdevice atari_mouse = {
- ATARIMOUSE_MINOR, "atarimouse", &atari_mouse_fops
+static struct busmouse atarimouse = {
+ ATARIMOUSE_MINOR, "atarimouse", open_mouse, release_mouse, 0
};
int __init atari_mouse_init(void)
{
- int r;
-
- 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;
+ if (!MACH_IS_ATARI)
+ return -ENODEV;
+ msedev = register_busmouse(&atarimouse);
+ if (msedev < 0)
+ printk(KERN_WARNING "Unable to register Atari mouse driver.\n");
+ else
+ printk(KERN_INFO "Atari mouse installed.\n");
+ return msedev < 0 ? msedev : 0;
}
@@ -215,6 +125,6 @@ int init_module(void)
void cleanup_module(void)
{
- misc_deregister(&atari_mouse);
+ unregister_busmouse(msedev);
}
#endif
diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c
index ecddff26c..1ab9a211f 100644
--- a/drivers/char/atixlmouse.c
+++ b/drivers/char/atixlmouse.c
@@ -7,6 +7,9 @@
* Modified by Chris Colohan (colohan@eecg.toronto.edu)
* Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
*
+ * Converted to use new generic busmouse code. 5 Apr 1998
+ * Russell King <rmk@arm.uk.linux.org>
+ *
* version 0.3a
*/
@@ -26,6 +29,8 @@
#include <asm/system.h>
#include <asm/irq.h>
+#include "busmouse.h"
+
#define ATIXL_MOUSE_IRQ 5 /* H/W interrupt # set up on ATIXL board */
#define ATIXL_BUSMOUSE 3 /* Minor device # (mknod c 10 3 /dev/bm) */
@@ -59,17 +64,7 @@
/* Same general mouse structure */
-static struct mouse_status {
- char buttons;
- char latch_buttons;
- int dx;
- int dy;
- int present;
- int ready;
- int active;
- wait_queue_head_t wait;
- struct fasync_struct *fasync;
-} mouse;
+static int msedev;
void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
@@ -82,35 +77,13 @@ void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
dy = inb( ATIXL_MSE_DATA_PORT);
outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */
buttons = inb( ATIXL_MSE_DATA_PORT);
- if (dx != 0 || dy != 0 || buttons != mouse.latch_buttons) {
- add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
- mouse.latch_buttons |= buttons;
- mouse.dx += dx;
- mouse.dy += dy;
- mouse.ready = 1;
- wake_up_interruptible(&mouse.wait);
- if (mouse.fasync)
- kill_fasync(mouse.fasync, SIGIO);
- }
+ busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
ATIXL_MSE_ENABLE_UPDATE();
}
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
- int retval;
- retval = fasync_helper(fd, filp, on, &mouse.fasync);
- if (retval < 0)
- return retval;
- return 0;
-}
-
static int release_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(-1, file, 0);
- if (--mouse.active)
- return 0;
ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
- mouse.ready = 0;
free_irq(ATIXL_MOUSE_IRQ, NULL);
MOD_DEC_USE_COUNT;
return 0;
@@ -118,90 +91,17 @@ static int release_mouse(struct inode * inode, struct file * file)
static int open_mouse(struct inode * inode, struct file * file)
{
- if (!mouse.present)
- return -EINVAL;
- if (mouse.active++)
- return 0;
- if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL)) {
- mouse.active--;
+ if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL))
return -EBUSY;
- }
- mouse.ready = 0;
- mouse.dx = 0;
- mouse.dy = 0;
- mouse.buttons = mouse.latch_buttons = 0;
ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
MOD_INC_USE_COUNT;
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)
-{
- ssize_t i;
-
- if (count < 3)
- return -EINVAL;
- if (!mouse.ready)
- return -EAGAIN;
- ATIXL_MSE_DISABLE_UPDATE();
- /* Allowed interrupts to occur during data gathering - shouldn't hurt */
- put_user((char)(~mouse.latch_buttons&7) | 0x80 , buffer);
- if (mouse.dx < -127)
- mouse.dx = -127;
- if (mouse.dx > 127)
- mouse.dx = 127;
- put_user((char)mouse.dx, buffer + 1);
- if (mouse.dy < -127)
- mouse.dy = -127;
- if (mouse.dy > 127)
- mouse.dy = 127;
- put_user((char)-mouse.dy, buffer + 2);
- for(i = 3; i < count; i++)
- put_user(0x00, buffer + i);
- mouse.dx = 0;
- mouse.dy = 0;
- mouse.latch_buttons = mouse.buttons;
- mouse.ready = 0;
- ATIXL_MSE_ENABLE_UPDATE();
- return i; /* i data bytes returned */
-}
-
-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 atixl_busmouse_fops = {
- NULL, /* mouse_seek */
- read_mouse,
- write_mouse,
- NULL, /* mouse_readdir */
- mouse_poll, /* mouse_poll */
- NULL, /* mouse_ioctl */
- NULL, /* mouse_mmap */
- open_mouse,
- NULL, /* flush */
- release_mouse,
- NULL,
- fasync_mouse,
+static struct busmouse atixlmouse = {
+ ATIXL_BUSMOUSE, "atixl", open_mouse, release_mouse, 0
};
-static struct miscdevice atixl_mouse = {
- ATIXL_BUSMOUSE, "atixl", &atixl_busmouse_fops
-};
-
-
int __init atixl_busmouse_init(void)
{
unsigned char a,b,c;
@@ -211,22 +111,18 @@ int __init atixl_busmouse_init(void)
c = inb( ATIXL_MSE_SIGNATURE_PORT );
if (( a != b ) && ( a == c ))
printk(KERN_INFO "\nATI Inport ");
- else{
- mouse.present = 0;
+ else
return -EIO;
- }
outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */
outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */
outb(0x0a, ATIXL_MSE_DATA_PORT); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */
- mouse.present = 1;
- mouse.active = 0;
- mouse.ready = 0;
- mouse.buttons = mouse.latch_buttons = 0;
- mouse.dx = mouse.dy = 0;
- init_waitqueue_head(&mouse.wait);
- printk("Bus mouse detected and installed.\n");
- misc_register(&atixl_mouse);
- return 0;
+
+ msedev = register_busmouse(&atixlmouse);
+ if (msedev < 0)
+ printk("Bus mouse initialisation error.\n");
+ else
+ printk("Bus mouse detected and installed.\n");
+ return msedev < 0 ? msedev : 0;
}
#ifdef MODULE
@@ -238,6 +134,6 @@ int init_module(void)
void cleanup_module(void)
{
- misc_deregister(&atixl_mouse);
+ unregister_busmouse(msedev);
}
#endif
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index c24d96b27..a177e7de6 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -29,9 +29,7 @@
#include <linux/major.h>
#include <linux/malloc.h>
#include <linux/mm.h>
-#if LINUX_VERSION_CODE >= 0x020100
#include <linux/poll.h>
-#endif
#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
@@ -44,36 +42,8 @@
#include <linux/wrapper.h>
#include <linux/interrupt.h>
-#if LINUX_VERSION_CODE >= 0x020100
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
-#else
-#include <linux/bios32.h>
-#define mdelay(x) udelay((x)*1000)
-#define signal_pending(current) (current->signal & ~current->blocked)
-#define sigfillset(set)
-
-static inline int time_before(unsigned long a, unsigned long b)
-{
- return((long)((a) - (b)) < 0L);
-}
-
-static inline unsigned long
-copy_to_user(void *to, const void *from, unsigned long n)
-{
- memcpy_tofs(to,from,n);
- return 0;
-}
-
-static inline unsigned long
-copy_from_user(void *to, const void *from, unsigned long n)
-{
- memcpy_fromfs(to,from,n);
- return 0;
-}
-#define ioremap vremap
-#define iounmap vfree
-#endif
#include <linux/videodev.h>
#include <linux/i2c.h>
@@ -83,19 +53,10 @@ copy_from_user(void *to, const void *from, unsigned long n)
#define DEBUG(x) /* Debug driver */
#define IDEBUG(x) /* Debug interrupt handler */
-#if LINUX_VERSION_CODE >= 0x020117
-MODULE_PARM(vidmem,"i");
-MODULE_PARM(triton1,"i");
-MODULE_PARM(remap,"1-4i");
-MODULE_PARM(radio,"1-4i");
-MODULE_PARM(card,"1-4i");
-MODULE_PARM(pll,"1-4i");
-#endif
/* Anybody who uses more than four? */
#define BTTV_MAX 4
-static int find_vga(void);
static void bt848_set_risc_jmps(struct bttv *btv);
static unsigned int vidmem=0; /* manually set video mem address */
@@ -243,6 +204,12 @@ static void rvfree(void * mem, unsigned long size)
}
}
+MODULE_PARM(vidmem,"i");
+MODULE_PARM(triton1,"i");
+MODULE_PARM(remap,"1-4i");
+MODULE_PARM(radio,"1-4i");
+MODULE_PARM(card,"1-4i");
+MODULE_PARM(pll,"1-4i");
/*
@@ -403,7 +370,7 @@ static void writeee(struct i2c_bus *bus, unsigned char *eedata)
}
}
-void attach_inform(struct i2c_bus *bus, int id)
+static void attach_inform(struct i2c_bus *bus, int id)
{
struct bttv *btv = (struct bttv*)bus->data;
@@ -422,7 +389,7 @@ void attach_inform(struct i2c_bus *bus, int id)
}
}
-void detach_inform(struct i2c_bus *bus, int id)
+static void detach_inform(struct i2c_bus *bus, int id)
{
struct bttv *btv = (struct bttv*)bus->data;
@@ -576,6 +543,8 @@ static struct tvcard tvcards[] =
{ 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}},
/* AVEC Intercapture */
{ 3, 2, 0, 2, 0, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0}},
+ /* LifeView FlyKit w/o Tuner */
+ { 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}}
};
#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
@@ -1286,7 +1255,7 @@ static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc,
}
-static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
+static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt, int pllset)
{
u16 vscale, hscale;
u32 xsf, sr;
@@ -1295,9 +1264,13 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
u16 inter;
u8 crop, vtc;
struct tvnorm *tvn;
+ unsigned long flags;
if (!width || !height)
return;
+
+ save_flags(flags);
+ cli();
tvn=&tvnorms[btv->win.norm];
@@ -1322,7 +1295,8 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
btwrite(1, BT848_VBI_PACK_DEL);
btv->pll.pll_ofreq = tvn->Fsc;
- set_pll(btv);
+ if(pllset)
+ set_pll(btv);
btwrite(fmt, BT848_COLOR_FMT);
#ifdef __sparc__
@@ -1370,6 +1344,8 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
hdelay, vdelay, crop);
bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive,
hdelay, vdelay, crop);
+
+ restore_flags(flags);
}
@@ -1398,7 +1374,7 @@ static void bt848_set_winsize(struct bttv *btv)
else
btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
- bt848_set_geo(btv, btv->win.width, btv->win.height, format);
+ bt848_set_geo(btv, btv->win.width, btv->win.height, format, 1);
}
/*
@@ -1582,20 +1558,18 @@ static long bttv_read(struct video_device *v, char *buf, unsigned long count, in
static int bttv_open(struct video_device *dev, int flags)
{
struct bttv *btv = (struct bttv *)dev;
- int users, i;
-
+ int i, ret;
+
+ ret = -EBUSY;
+ down(&btv->lock);
if (btv->user)
- return -EBUSY;
- audio(btv, AUDIO_UNMUTE);
- for (i=users=0; i<bttv_num; i++)
- users+=bttvs[i].user;
- if (users==1)
- find_vga();
- btv->fbuffer=NULL;
- if (!btv->fbuffer)
- btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
+ goto out_unlock;
+
+ btv->fbuffer= (unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
+ ret = -ENOMEM;
if (!btv->fbuffer)
- return -EINVAL;
+ goto out_unlock;
+ audio(btv, AUDIO_UNMUTE);
btv->grabbing = 0;
btv->grab = 0;
btv->lastgrab = 0;
@@ -1603,14 +1577,20 @@ static int bttv_open(struct video_device *dev, int flags)
btv->frame_stat[i] = GBUFFER_UNUSED;
btv->user++;
+ up(&btv->lock);
MOD_INC_USE_COUNT;
return 0;
+
+ out_unlock:
+ up(&btv->lock);
+ return ret;
}
static void bttv_close(struct video_device *dev)
{
struct bttv *btv=(struct bttv *)dev;
-
+
+ down(&btv->lock);
btv->user--;
audio(btv, AUDIO_INTERN);
btv->cap&=~3;
@@ -1640,6 +1620,7 @@ static void bttv_close(struct video_device *dev)
if(btv->fbuffer)
rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF);
btv->fbuffer=0;
+ up(&btv->lock);
MOD_DEC_USE_COUNT;
}
@@ -1760,14 +1741,16 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (v.channel>tvcards[btv->type].video_inputs)
return -EINVAL;
- bt848_muxsel(btv, v.channel);
if(v.norm!=VIDEO_MODE_PAL&&v.norm!=VIDEO_MODE_NTSC
&&v.norm!=VIDEO_MODE_SECAM)
return -EOPNOTSUPP;
+ down(&btv->lock);
+ bt848_muxsel(btv, v.channel);
btv->win.norm = v.norm;
make_vbitab(btv);
bt848_set_winsize(btv);
btv->channel=v.channel;
+ up(&btv->lock);
return 0;
}
case VIDIOCGTUNER:
@@ -1812,7 +1795,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
&&v.mode!=VIDEO_MODE_SECAM)
return -EOPNOTSUPP;
btv->win.norm = v.mode;
+ down(&btv->lock);
bt848_set_winsize(btv);
+ up(&btv->lock);
return 0;
}
case VIDIOCGPICT:
@@ -1839,6 +1824,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
int format;
if(copy_from_user(&p, arg,sizeof(p)))
return -EFAULT;
+ down(&btv->lock);
/* We want -128 to 127 we get 0-65535 */
bt848_bright(btv, (p.brightness>>8)-128);
/* 0-511 for the colour */
@@ -1856,6 +1842,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (fmtbppx2[format&0x0f]/2 == btv->win.bpp)
btv->win.color_fmt = format;
}
+ up(&btv->lock);
return 0;
}
case VIDIOCSWIN:
@@ -1869,7 +1856,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(vw.flags || vw.width < 16 || vw.height < 16)
{
+ down(&btv->lock);
bt848_cap(btv,0);
+ up(&btv->lock);
return -EINVAL;
}
if (btv->win.bpp < 4)
@@ -1879,6 +1868,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
i = vw.x - i;
vw.width -= i;
}
+
+ down(&btv->lock);
btv->win.x=vw.x;
btv->win.y=vw.y;
btv->win.width=vw.width;
@@ -1893,6 +1884,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
bt848_cap(btv,0);
bt848_set_winsize(btv);
+
+ up(&btv->lock);
/*
* Do any clips.
@@ -1916,11 +1909,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EFAULT;
}
}
+ down(&btv->lock);
make_clip_tab(btv, vcp, vw.clipcount);
if (vw.clipcount != 0)
vfree(vcp);
if(on && btv->win.vidadr!=0)
bt848_cap(btv,1);
+ up(&btv->lock);
return 0;
}
case VIDIOCGWIN:
@@ -1944,17 +1939,17 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
int v;
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
+ if(v!=0 && (btv->win.vidadr==0 || btv->win.width==0
+ || btv->win.height==0))
+ return -EINVAL;
+
+ down(&btv->lock);
if(v==0)
- {
bt848_cap(btv,0);
- }
else
- {
- if(btv->win.vidadr==0 || btv->win.width==0
- || btv->win.height==0)
- return -EINVAL;
bt848_cap(btv,1);
- }
+ up(&btv->lock);
+
return 0;
}
case VIDIOCGFBUF:
@@ -1974,7 +1969,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct video_buffer v;
#if LINUX_VERSION_CODE >= 0x020100
- if(!capable(CAP_SYS_ADMIN))
+ if(!capable(CAP_SYS_ADMIN)
+ && !capable(CAP_SYS_RAWIO))
#else
if(!suser())
#endif
@@ -1985,13 +1981,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.depth!=24 && v.depth!=32 && v.width > 16 &&
v.height > 16 && v.bytesperline > 16)
return -EINVAL;
+ down(&btv->lock);
if (v.base)
- {
- if ((unsigned long)v.base&1)
- btv->win.vidadr=(unsigned long)(PAGE_OFFSET|uvirt_to_bus((unsigned long)v.base));
- else
- btv->win.vidadr=(unsigned long)v.base;
- }
+ btv->win.vidadr=(unsigned long)v.base;
btv->win.sheight=v.height;
btv->win.swidth=v.width;
btv->win.bpp=((v.depth+7)&0x38)/8;
@@ -2001,6 +1993,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
v.base, v.width,v.height, btv->win.bpp, btv->win.bpl));
bt848_set_winsize(btv);
+ up(&btv->lock);
return 0;
}
case VIDIOCKEY:
@@ -2067,13 +2060,17 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
struct video_audio v;
if(copy_from_user(&v,arg, sizeof(v)))
return -EFAULT;
+ down(&btv->lock);
if(v.flags&VIDEO_AUDIO_MUTE)
audio(btv, AUDIO_MUTE);
/* One audio source per tuner */
/* if(v.audio!=0) */
/* ADSTech TV card has more than one */
if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs)
+ {
+ up(&btv->lock);
return -EINVAL;
+ }
bt848_muxsel(btv,v.audio);
if(!(v.flags&VIDEO_AUDIO_MUTE))
audio(btv, AUDIO_UNMUTE);
@@ -2137,6 +2134,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
MSP_SET_STEREO,&(v.mode));
}
btv->audio_dev=v;
+ up(&btv->lock);
return 0;
}
@@ -2163,25 +2161,21 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return 0;
case BTTV_WRITEE:
-#if LINUX_VERSION_CODE >= 0x020100
if(!capable(CAP_SYS_ADMIN))
-#else
- if(!suser())
-#endif
return -EPERM;
if(copy_from_user((void *) eedata, (void *) arg, 256))
return -EFAULT;
+ down(&btv->lock);
writeee(&(btv->i2c), eedata);
+ up(&btv->lock);
return 0;
case BTTV_READEE:
-#if LINUX_VERSION_CODE >= 0x020100
if(!capable(CAP_SYS_ADMIN))
-#else
- if(!suser())
-#endif
return -EPERM;
+ down(&btv->lock);
readee(&(btv->i2c), eedata);
+ up(&btv->lock);
if(copy_to_user((void *) arg, (void *) eedata, 256))
return -EFAULT;
break;
@@ -2194,28 +2188,29 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case BTTV_PLLSET: {
struct bttv_pll_info p;
-#if LINUX_VERSION_CODE >= 0x020100
if(!capable(CAP_SYS_ADMIN))
-#else
- if(!suser())
-#endif
return -EPERM;
if(copy_from_user(&p , (void *) arg, sizeof(btv->pll)))
return -EFAULT;
+ down(&btv->lock);
btv->pll.pll_ifreq = p.pll_ifreq;
btv->pll.pll_ofreq = p.pll_ofreq;
btv->pll.pll_crystal = p.pll_crystal;
-
+ up(&btv->lock);
break;
}
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
+ int v;
if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
return -EFAULT;
if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING)
return -EBUSY;
- return vgrab(btv, &vm);
+ down(&btv->lock);
+ v=vgrab(btv, &vm);
+ up(&btv->lock);
+ return v;
}
case VIDIOCGMBUF:
@@ -2297,9 +2292,8 @@ static int bttv_init_done(struct video_device *dev)
* But e.g. pte_alloc() does not work in modules ... :-(
*/
-static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size)
+static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size)
{
- struct bttv *btv=(struct bttv *)dev;
unsigned long start=(unsigned long) adr;
unsigned long page,pos;
@@ -2323,6 +2317,17 @@ static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long si
return 0;
}
+static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+ struct bttv *btv=(struct bttv *)dev;
+ int r;
+
+ down(&btv->lock);
+ r=do_bttv_mmap(btv, adr, size);
+ up(&btv->lock);
+ return r;
+}
+
static struct video_device bttv_template=
{
"UNSET",
@@ -2388,7 +2393,6 @@ static long vbi_read(struct video_device *v, char *buf, unsigned long count,
return count;
}
-#if LINUX_VERSION_CODE >= 0x020100
static unsigned int vbi_poll(struct video_device *dev, struct file *file,
poll_table *wait)
{
@@ -2402,15 +2406,16 @@ static unsigned int vbi_poll(struct video_device *dev, struct file *file,
return mask;
}
-#endif
static int vbi_open(struct video_device *dev, int flags)
{
struct bttv *btv=(struct bttv *)(dev-2);
+ down(&btv->lock);
btv->vbip=VBIBUF_SIZE;
btv->cap|=0x0c;
bt848_set_risc_jmps(btv);
+ up(&btv->lock);
MOD_INC_USE_COUNT;
return 0;
@@ -2419,9 +2424,11 @@ static int vbi_open(struct video_device *dev, int flags)
static void vbi_close(struct video_device *dev)
{
struct bttv *btv=(struct bttv *)(dev-2);
-
+
+ down(&btv->lock);
btv->cap&=~0x0c;
bt848_set_risc_jmps(btv);
+ up(&btv->lock);
MOD_DEC_USE_COUNT;
}
@@ -2457,25 +2464,34 @@ static int radio_open(struct video_device *dev, int flags)
{
struct bttv *btv = (struct bttv *)(dev-1);
+ down(&btv->lock);
if (btv->user)
- return -EBUSY;
+ goto busy_unlock;
btv->user++;
+
set_freq(btv,400*16);
btv->radio = 1;
bt848_muxsel(btv,0);
audio(btv, AUDIO_UNMUTE);
+ up(&btv->lock);
MOD_INC_USE_COUNT;
return 0;
+
+ busy_unlock:
+ up(&btv->lock);
+ return -EBUSY;
}
static void radio_close(struct video_device *dev)
{
struct bttv *btv=(struct bttv *)(dev-1);
+ down(&btv->lock);
btv->user--;
btv->radio = 0;
/*audio(btv, AUDIO_MUTE);*/
+ up(&btv->lock);
MOD_DEC_USE_COUNT;
}
@@ -2565,233 +2581,6 @@ static struct video_device radio_template=
};
-struct vidbases
-{
- unsigned short vendor, device;
- char *name;
- uint badr;
-};
-
-static struct vidbases vbs[] = {
- { PCI_VENDOR_ID_ALLIANCE, PCI_DEVICE_ID_ALLIANCE_AT3D,
- "Alliance AT3D", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215CT222,
- "ATI MACH64 CT", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_210888GX,
- "ATI MACH64 Winturbo", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215GT,
- "ATI MACH64 GT", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_CIRRUS, 0, "Cirrus Logic", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA,
- "DEC DC21030", PCI_BASE_ADDRESS_0},
- { 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_MATROX, 0x0521, "Matrox G200", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128,
- "Number Nine Imagine 128", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128_2,
- "Number Nine Imagine 128 Series 2", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_S3, 0, "S3", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_TSENG, 0, "TSENG", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128,
- "Riva128", PCI_BASE_ADDRESS_1},
-};
-
-
-/* DEC TGA offsets stolen from XFree-3.2 */
-
-static uint dec_offsets[4] = {
- 0x200000,
- 0x804000,
- 0,
- 0x1004000
-};
-
-#define NR_CARDS (sizeof(vbs)/sizeof(struct vidbases))
-
-/* Scan for PCI display adapter
- if more than one card is present the last one is used for now */
-
-#if LINUX_VERSION_CODE >= 0x020100
-
-static int find_vga(void)
-{
- unsigned short badr;
- int found = 0, i, tga_type;
- unsigned int vidadr=0;
- struct pci_dev *dev;
-
-
- for (dev = pci_devices; dev != NULL; dev = dev->next)
- {
- if (dev->class != PCI_CLASS_NOT_DEFINED_VGA &&
- ((dev->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
- {
- continue;
- }
- if (PCI_FUNC(dev->devfn) != 0)
- continue;
-
- badr=0;
- printk(KERN_INFO "bttv: PCI display adapter: ");
- for (i=0; i<NR_CARDS; i++)
- {
- if (dev->vendor == vbs[i].vendor)
- {
- if (vbs[i].device)
- if (vbs[i].device!=dev->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;
- }
- 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)
- {
- printk(KERN_ERR "bttv: TGA type (0x%x) unrecognized!\n", tga_type);
- found--;
- }
- vidadr+=dec_offsets[tga_type];
- }
- DEBUG(printk(KERN_DEBUG "bttv: memory @ 0x%08x, ", vidadr));
- DEBUG(printk(KERN_DEBUG "devfn: 0x%04x.\n", dev->devfn));
- found++;
- }
-
- if (vidmem)
- {
- vidadr=vidmem<<20;
- printk(KERN_INFO "bttv: Video memory override: 0x%08x\n", vidadr);
- found=1;
- }
- for (i=0; i<BTTV_MAX; i++)
- bttvs[i].win.vidadr=vidadr;
-
- return found;
-}
-
-#else
-static int find_vga(void)
-{
- unsigned int devfn, class, vendev;
- unsigned short vendor, device, badr;
- int found=0, bus=0, i, tga_type;
- unsigned int vidadr=0;
-
-
- for (devfn = 0; devfn < 0xff; devfn++)
- {
- if (PCI_FUNC(devfn) != 0)
- continue;
- pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &vendev);
- if (vendev == 0xffffffff || vendev == 0x00000000)
- continue;
- pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &device);
- pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class);
- class = class >> 16;
-/* if (class == PCI_CLASS_DISPLAY_VGA) {*/
- if ((class>>8) == PCI_BASE_CLASS_DISPLAY ||
- /* Number 9 GXE64Pro needs this */
- class == PCI_CLASS_NOT_DEFINED_VGA)
- {
- badr=0;
- printk(KERN_INFO "bttv: PCI display adapter: ");
- for (i=0; i<NR_CARDS; i++)
- {
- if (vendor==vbs[i].vendor)
- {
- if (vbs[i].device)
- if (vbs[i].device!=device)
- continue;
- printk("%s.\n", vbs[i].name);
- badr=vbs[i].badr;
- break;
- }
- }
- if (NR_CARDS == i)
- printk("UNKNOWN.\n");
- if (!badr)
- {
- printk(KERN_ERR "bttv: Unknown video memory base address.\n");
- continue;
- }
- pcibios_read_config_dword(bus, devfn, badr, &vidadr);
- if (vidadr & PCI_BASE_ADDRESS_SPACE_IO)
- {
- printk(KERN_ERR "bttv: Memory seems to be I/O memory.\n");
- printk(KERN_ERR "bttv: Check entry for your card type in bttv.c vidbases struct.\n");
- continue;
- }
- vidadr &= PCI_BASE_ADDRESS_MEM_MASK;
- if (!vidadr)
- {
- printk(KERN_ERR "bttv: Memory @ 0, must be something wrong!\n");
- continue;
- }
-
- if (vendor==PCI_VENDOR_ID_DEC)
- if (device==PCI_DEVICE_ID_DEC_TGA)
- {
- tga_type = (readl((unsigned long)vidadr) >> 12) & 0x0f;
- if (tga_type != 0 && tga_type != 1 && tga_type != 3)
- {
- printk(KERN_ERR "bttv: TGA type (0x%x) unrecognized!\n", tga_type);
- found--;
- }
- vidadr+=dec_offsets[tga_type];
- }
-
- DEBUG(printk(KERN_DEBUG "bttv: memory @ 0x%08x, ", vidadr));
- DEBUG(printk(KERN_DEBUG "devfn: 0x%04x.\n", devfn));
- found++;
- }
- }
-
- if (vidmem)
- {
- if (vidmem < 0x1000)
- vidadr=vidmem<<20;
- else
- vidadr=vidmem;
- printk(KERN_INFO "bttv: Video memory override: 0x%08x\n", vidadr);
- found=1;
- }
- for (i=0; i<BTTV_MAX; i++)
- bttvs[i].win.vidadr=vidadr;
-
- return found;
-}
-#endif
-
#define TRITON_PCON 0x50
#define TRITON_BUS_CONCURRENCY (1<<0)
@@ -2800,8 +2589,6 @@ static int find_vga(void)
#define TRITON_PEER_CONCURRENCY (1<<3)
-#if LINUX_VERSION_CODE >= 0x020100
-
static void handle_chipset(void)
{
struct pci_dev *dev = NULL;
@@ -2833,110 +2620,8 @@ static void handle_chipset(void)
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 */
-
- 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)
- {
- pci_write_config_byte(dev, TRITON_PCON, b);
- printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b);
- }
-#endif
- }
-}
-#else
-static void handle_chipset(void)
-{
- int index;
-
- for (index = 0; index < 8; index++)
- {
- unsigned char bus, devfn;
- unsigned char b;
-
- /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */
-
- if (!pcibios_find_device(PCI_VENDOR_ID_SI,
- PCI_DEVICE_ID_SI_496,
- index, &bus, &devfn))
- {
- printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n");
- }
-
- if (!pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82441,
- index, &bus, &devfn))
- {
- pcibios_read_config_byte(bus, devfn, 0x53, &b);
- DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "));
- DEBUG(printk("bufcon=0x%02x\n",b));
- }
-
- if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437,
- index, &bus, &devfn))
- {
- printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n");
- triton1=BT848_INT_ETBF;
-
-#if 0
- /* The ETBF bit SHOULD make all this unnecessary */
- /* 430FX (Triton I) freezes with bus concurrency on -> switch it off */
- {
- unsigned char bo;
-
- pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b);
- bo=b;
- DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b));
-
- if(!(b & TRITON_BUS_CONCURRENCY))
- {
- printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n");
- b |= TRITON_BUS_CONCURRENCY;
- }
-
- if(b & TRITON_PEER_CONCURRENCY)
- {
- printk(KERN_WARNING "bttv: 82437FX: disabling peer concurrency\n");
- b &= ~TRITON_PEER_CONCURRENCY;
- }
- if(!(b & TRITON_STREAMING))
- {
- printk(KERN_WARNING "bttv: 82437FX: disabling streaming\n");
- b |= TRITON_STREAMING;
- }
-
- if (b!=bo)
- {
- pcibios_write_config_byte(bus, devfn, TRITON_PCON, b);
- printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b);
- }
- }
-#endif
- }
}
}
-#endif
static void init_tea6300(struct i2c_bus *bus)
{
@@ -2950,14 +2635,14 @@ static void init_tea6300(struct i2c_bus *bus)
static void init_tea6320(struct i2c_bus *bus)
{
- I2CWrite(bus, I2C_TEA6300, TEA6320_V, 0x28, 1); /* master volume */
- I2CWrite(bus, I2C_TEA6300, TEA6320_FFL, 0x28, 1); /* volume left 0dB */
- I2CWrite(bus, I2C_TEA6300, TEA6320_FFR, 0x28, 1); /* volume right 0dB */
- I2CWrite(bus, I2C_TEA6300, TEA6320_FRL, 0x28, 1); /* volume rear left 0dB */
- I2CWrite(bus, I2C_TEA6300, TEA6320_FRR, 0x28, 1); /* volume rear right 0dB */
- I2CWrite(bus, I2C_TEA6300, TEA6320_BA, 0x11, 1); /* bass 0dB */
- I2CWrite(bus, I2C_TEA6300, TEA6320_TR, 0x11, 1); /* treble 0dB */
- I2CWrite(bus, I2C_TEA6300, TEA6320_S, TEA6320_S_GMU, 1); /* mute off input A */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_V, 0x28, 1); /* master volume */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_FFL, 0x28, 1); /* volume left 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_FFR, 0x28, 1); /* volume right 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_FRL, 0x28, 1); /* volume rear left 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_FRR, 0x28, 1); /* volume rear right 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_BA, 0x11, 1); /* bass 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_TR, 0x11, 1); /* treble 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_S, TEA6320_S_GMU, 1); /* mute off input A */
}
static void init_tda8425(struct i2c_bus *bus)
@@ -3087,16 +2772,16 @@ static void idcard(int i)
if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0)
{
- if(btv->type==BTTV_AVEC_INTERCAP)
- {
- printk(KERN_INFO "bttv%d: fader chip: TEA6320\n",btv->nr);
- btv->audio_chip = TEA6320;
- init_tea6320(&(btv->i2c));
- } else {
- printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr);
- btv->audio_chip = TEA6300;
- init_tea6300(&(btv->i2c));
- }
+ if(btv->type==BTTV_AVEC_INTERCAP)
+ {
+ printk(KERN_INFO "bttv%d: fader chip: TEA6320\n",btv->nr);
+ btv->audio_chip = TEA6320;
+ init_tea6320(&(btv->i2c));
+ } else {
+ printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr);
+ btv->audio_chip = TEA6300;
+ init_tea6300(&(btv->i2c));
+ }
} else
printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr);
@@ -3145,7 +2830,7 @@ static void idcard(int i)
break;
}
printk("%s\n",btv->video_dev.name);
- audio(btv, AUDIO_MUTE);
+ audio(btv, AUDIO_INTERN);
}
@@ -3207,6 +2892,8 @@ static int init_bt848(int i)
struct bttv *btv = &bttvs[i];
btv->user=0;
+
+ init_MUTEX(&btv->lock);
/* reset the bt848 */
btwrite(0, BT848_SRESET);
@@ -3435,14 +3122,14 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btv->risc_jmp[11]=cpu_to_le32(btv->gre);
bt848_set_geo(btv, btv->gwidth,
btv->gheight,
- btv->gfmt);
+ btv->gfmt, 0);
} else {
bt848_set_risc_jmps(btv);
btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
bt848_set_geo(btv, btv->win.width,
btv->win.height,
- btv->win.color_fmt);
+ btv->win.color_fmt, 0);
}
wake_up_interruptible(&btv->capq);
break;
@@ -3453,7 +3140,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btv->risc_jmp[11]=cpu_to_le32(btv->gre);
btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
bt848_set_geo(btv, btv->gwidth, btv->gheight,
- btv->gfmt);
+ btv->gfmt, 0);
}
}
if (astat&BT848_INT_OCERR)
@@ -3515,7 +3202,6 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
* Scan for a Bt848 card, request the irq and map the io memory
*/
-#if LINUX_VERSION_CODE >= 0x020100
int configure_bt848(struct pci_dev *dev, int bttv_num)
{
int result;
@@ -3538,27 +3224,12 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
btv->id=dev->device;
btv->irq=dev->irq;
- btv->bt848_adr=dev->base_address[0];
+ btv->bt848_adr=dev->resource[0].start;
if (btv->id >= 878)
btv->i2c_command = 0x83;
else
btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
- if (remap[bttv_num])
- {
- unsigned int dw = btv->bt848_adr;
-
- if (remap[bttv_num] < 0x1000)
- remap[bttv_num]<<=20;
- remap[bttv_num]&=PCI_BASE_ADDRESS_MEM_MASK;
- printk(KERN_INFO "bttv%d: remapping to : 0x%lx.\n",
- bttv_num,remap[bttv_num]);
- remap[bttv_num]|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, remap[bttv_num]);
- pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dw);
- btv->dev->base_address[0] = btv->bt848_adr;
- }
- btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ",
bttv_num,btv->id, btv->revision);
@@ -3588,11 +3259,7 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
}
}
-#ifdef __sparc__
- btv->bt848_mem=(unsigned char *)btv->bt848_adr;
-#else
- btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
-#endif
+ btv->bt848_mem = ioremap(btv->bt848_adr, 0x1000);
/* clear interrupt mask */
btwrite(0, BT848_INT_MASK);
@@ -3657,170 +3324,6 @@ static int find_bt848(void)
printk(KERN_INFO "bttv: %d Bt8xx card(s) found.\n", bttv_num);
return bttv_num;
}
-#else
-static int find_bt848(void)
-{
- short pci_index;
- unsigned char command, latency;
- int result;
- unsigned char bus, devfn;
- struct bttv *btv;
-
- bttv_num=0;
-
- if (!pcibios_present())
- {
- DEBUG(printk(KERN_DEBUG "bttv%d: PCI-BIOS not present or not accessable!\n",bttv_num));
- return 0;
- }
-
- for (pci_index = 0;
- !pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
- pci_index, &bus, &devfn)
- ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
- pci_index, &bus, &devfn)
- ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
- pci_index, &bus, &devfn)
- ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
- pci_index, &bus, &devfn);
- ++pci_index)
- {
- btv=&bttvs[bttv_num];
- btv->nr = bttv_num;
- btv->bus=bus;
- btv->devfn=devfn;
- btv->bt848_mem=NULL;
- btv->vbibuf=NULL;
- btv->risc_jmp=NULL;
- btv->vbi_odd=NULL;
- btv->vbi_even=NULL;
- btv->vbiq=NULL;
- btv->capq=NULL;
- btv->capqo=NULL;
- btv->capqe=NULL;
-
- btv->vbip=VBIBUF_SIZE;
-
- pcibios_read_config_word(btv->bus, btv->devfn, PCI_DEVICE_ID,
- &btv->id);
- pcibios_read_config_byte(btv->bus, btv->devfn,
- PCI_INTERRUPT_LINE, &btv->irq);
- pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
- &btv->bt848_adr);
- if (btv->id >= 878)
- btv->i2c_command = 0x83;
- else
- btv->i2c_command=
- (I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
-
- if (remap[bttv_num])
- {
- if (remap[bttv_num] < 0x1000)
- remap[bttv_num]<<=20;
- remap[bttv_num]&=PCI_BASE_ADDRESS_MEM_MASK;
- printk(KERN_INFO "bttv%d: remapping to : 0x%08x.\n",
- bttv_num,remap[bttv_num]);
- remap[bttv_num]|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
- pcibios_write_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
- remap[bttv_num]);
- pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
- &btv->bt848_adr);
- }
-
- btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
- pcibios_read_config_byte(btv->bus, btv->devfn, PCI_CLASS_REVISION,
- &btv->revision);
- printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ",
- bttv_num,btv->id, btv->revision);
- printk("bus: %d, devfn: %d, ",
- btv->bus, btv->devfn);
- printk("irq: %d, ",btv->irq);
- printk("memory: 0x%08x.\n", btv->bt848_adr);
-
- btv->pll.pll_crystal = 0;
- btv->pll.pll_ifreq = 0;
- btv->pll.pll_ofreq = 0;
- btv->pll.pll_current = 0;
- if (!(btv->id==848 && btv->revision==0x11)) {
- switch (pll[btv->nr]) {
- case 0:
- /* off */
- break;
- case 1:
- /* 28 MHz crystal installed */
- btv->pll.pll_ifreq=28636363;
- btv->pll.pll_crystal=BT848_IFORM_XT0;
- break;
- case 2:
- /* 35 MHz crystal installed */
- btv->pll.pll_ifreq=35468950;
- btv->pll.pll_crystal=BT848_IFORM_XT1;
- break;
- }
- }
-
- btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
-
- result = request_irq(btv->irq, bttv_irq,
- SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv);
- if (result==-EINVAL)
- {
- printk(KERN_ERR "bttv%d: Bad irq number or handler\n",
- bttv_num);
- return -EINVAL;
- }
- if (result==-EBUSY)
- {
- printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq);
- return result;
- }
- if (result < 0)
- return result;
-
- /* Enable bus-mastering */
- pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
- command|=PCI_COMMAND_MASTER;
- pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command);
- pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
- if (!(command&PCI_COMMAND_MASTER))
- {
- printk(KERN_ERR "bttv%d: PCI bus-mastering could not be enabled\n",bttv_num);
- return -1;
- }
- pcibios_read_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER,
- &latency);
- if (!latency)
- {
- latency=32;
- pcibios_write_config_byte(btv->bus, btv->devfn,
- PCI_LATENCY_TIMER, latency);
- }
- DEBUG(printk(KERN_DEBUG "bttv%d: latency: %02x\n",
- bttv_num, latency));
-
- btv->triton1=triton1 ? BT848_INT_ETBF : 0;
- if (triton1 && btv->id >= 878)
- {
- triton1 = 0;
- printk("bttv: Enabling 430FX compatibilty for bt878\n");
- pcibios_read_config_byte(btv->bus, btv->devfn, BT878_DEVCTRL, &command);
- command|=BT878_EN_TBFX;
- pcibios_write_config_byte(btv->bus, btv->devfn, BT878_DEVCTRL, command);
- pcibios_read_config_byte(btv->bus, btv->devfn, BT878_DEVCTRL, &command);
- if (!(command&BT878_EN_TBFX))
- {
- printk("bttv: 430FX compatibility could not be enabled\n");
- return -1;
- }
- }
-
- bttv_num++;
- }
- if(bttv_num)
- printk(KERN_INFO "bttv: %d Bt8xx card(s) found.\n", bttv_num);
- return bttv_num;
-}
-#endif
static void release_bttv(void)
{
@@ -3845,17 +3348,11 @@ static void release_bttv(void)
i2c_unregister_bus((&btv->i2c));
/* disable PCI bus-mastering */
-#if LINUX_VERSION_CODE >= 0x020100
+
pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
/* Should this be &=~ ?? */
command&=~PCI_COMMAND_MASTER;
pci_write_config_byte(btv->dev, PCI_COMMAND, command);
-#else
- pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
- command&=~PCI_COMMAND_MASTER;
- pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command);
-
-#endif
/* unmap and free memory */
if (btv->grisc)
diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h
index 847336116..83c9f1e8f 100644
--- a/drivers/char/bttv.h
+++ b/drivers/char/bttv.h
@@ -84,6 +84,7 @@ struct bttv
struct video_picture picture; /* Current picture params */
struct video_audio audio_dev; /* Current audio params */
+ struct semaphore lock;
int user;
int capuser;
struct device_open open_data[MAX_OPENS];
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index 70b75ecc1..4620a3d60 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -1,299 +1,485 @@
/*
- * Logitech Bus Mouse Driver for Linux
- * by James Banks
+ * linux/drivers/char/mouse.c
*
- * Mods by Matthew Dillon
- * calls verify_area()
- * tracks better when X is busy or paging
+ * Copyright (C) 1995 - 1998 Russell King
+ * Protocol taken from busmouse.c
+ * read() waiting taken from psaux.c
*
- * Heavily modified by David Giller
- * changed from queue- to counter- driven
- * hacked out a (probably incorrect) mouse_select
+ * Medium-level interface for quadrature or bus mice.
*
- * Modified again by Nathan Laredo to interface with
- * 0.96c-pl1 IRQ handling changes (13JUL92)
- * didn't bother touching select code.
+ * Currently, the majority of kernel busmice drivers in the
+ * kernel common code to talk to userspace. This driver
+ * attempts to rectify this situation by presenting a
+ * simple and safe interface to the mice and user.
*
- * Modified the select() code blindly to conform to the VFS
- * requirements. 92.07.14 - Linus. Somebody should test it out.
- *
- * Modified by Johan Myreen to make room for other mice (9AUG92)
- * removed assignment chr_fops[10] = &mouse_fops; see mouse.c
- * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
- * renamed this file mouse.c => busmouse.c
- *
- * Minor addition by Cliff Matthews
- * added fasync support
- *
- * Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
- *
- * Replaced dumb busy loop with udelay() 16 Nov 95
- * Nathan Laredo <laredo@gnu.ai.mit.edu>
- *
- * Track I/O ports with request_region(). 12 Dec 95 Philip Blundell
+ * This driver:
+ * - is SMP safe
+ * - handles multiple opens
+ * - handles the wakeups and locking
+ * - has optional blocking reads
*/
#include <linux/module.h>
-
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/busmouse.h>
#include <linux/signal.h>
+#include <linux/malloc.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
#include <linux/init.h>
-#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
-#include <asm/irq.h>
+#include <asm/io.h>
-static struct mouse_status mouse;
-static int mouse_irq = MOUSE_IRQ;
+#include "busmouse.h"
-#ifdef MODULE
-MODULE_PARM(mouse_irq, "i");
-#endif
+/* Uncomment this if your mouse drivers expect the kernel to
+ * return with EAGAIN if the mouse does not have any events
+ * available, even if the mouse is opened in nonblocking mode.
+ *
+ * Should this be on a per-mouse basis? If so, add an entry to
+ * the struct busmouse structure and add the relevent flag to
+ * the drivers.
+ */
+/*#define BROKEN_MOUSE*/
+
+extern int adb_mouse_init(void);
+extern int logi_busmouse_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 sun_mouse_init(void);
+extern void mouse_rpc_init (void);
+
+struct busmouse_data {
+ struct miscdevice miscdev;
+ struct busmouse *ops;
+ spinlock_t lock;
+
+ wait_queue_head_t wait;
+ struct fasync_struct *fasyncptr;
+ char active;
+ char buttons;
+ char latch_buttons;
+ char ready;
+ int dxpos;
+ int dypos;
+};
+
+#define NR_MICE 15
+#define FIRST_MOUSE 0
+#define DEV_TO_MOUSE(dev) MINOR_TO_MOUSE(MINOR(dev))
+#define MINOR_TO_MOUSE(minor) ((minor) - FIRST_MOUSE)
+
+static struct busmouse_data *busmouse_data[NR_MICE];
-void __init bmouse_setup(char *str, int *ints)
+/* a mouse driver just has to interface with these functions
+ * These are !!!OLD!!! Do not use!!!
+ */
+void add_mouse_movement(int dx, int dy)
+{
+ struct busmouse_data *mse = busmouse_data[MINOR_TO_MOUSE(6)];
+
+ mse->dxpos += dx;
+ mse->dypos += dy;
+ mse->ready = 1;
+ wake_up(&mse->wait);
+}
+
+int add_mouse_buttonchange(int set, int value)
{
- if (ints[0] > 0)
- mouse_irq=ints[1];
+ struct busmouse_data *mse = busmouse_data[MINOR_TO_MOUSE(6)];
+
+ mse->buttons = (mse->buttons & ~set) ^ value;
+ mse->ready = 1;
+ wake_up(&mse->wait);
+ return mse->buttons;
}
-static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+/* New interface. !!! Use this one !!!
+ * These routines will most probably be called from interrupt.
+ */
+void
+busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
{
- char dx, dy;
- unsigned char buttons;
-
- outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
- dx = (inb(MSE_DATA_PORT) & 0xf);
- outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
- dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
- outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
- dy = (inb(MSE_DATA_PORT) & 0xf);
- outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
- buttons = inb(MSE_DATA_PORT);
- dy |= (buttons & 0xf) << 4;
- buttons = ((buttons >> 5) & 0x07);
- if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
- add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
- mouse.buttons = buttons;
- mouse.dx += dx;
- mouse.dy -= dy;
- mouse.ready = 1;
- wake_up_interruptible(&mouse.wait);
-
- /*
- * keep dx/dy reasonable, but still able to track when X (or
- * whatever) must page or is busy (i.e. long waits between
- * reads)
- */
- if (mouse.dx < -2048)
- mouse.dx = -2048;
- if (mouse.dx > 2048)
- mouse.dx = 2048;
-
- if (mouse.dy < -2048)
- mouse.dy = -2048;
- if (mouse.dy > 2048)
- mouse.dy = 2048;
-
- if (mouse.fasyncptr)
- kill_fasync(mouse.fasyncptr, SIGIO);
+ struct busmouse_data *mse = busmouse_data[mousedev];
+ int changed;
+
+ spin_lock(&mse->lock);
+ changed = (dx != 0 || dy != 0 || mse->buttons != buttons);
+
+ if (changed) {
+ add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
+
+ mse->buttons = buttons;
+// mse->latch_buttons |= buttons;
+ mse->dxpos += dx;
+ mse->dypos += dy;
+ mse->ready = 1;
+
+ /*
+ * keep dx/dy reasonable, but still able to track when X (or
+ * whatever) must page or is busy (i.e. long waits between
+ * reads)
+ */
+ if (mse->dxpos < -2048)
+ mse->dxpos = -2048;
+ if (mse->dxpos > 2048)
+ mse->dxpos = 2048;
+ if (mse->dypos < -2048)
+ mse->dypos = -2048;
+ if (mse->dypos > 2048)
+ mse->dypos = 2048;
}
- MSE_INT_ON();
+
+ spin_unlock(&mse->lock);
+
+ if (changed) {
+ wake_up(&mse->wait);
+
+ if (mse->fasyncptr)
+ kill_fasync(mse->fasyncptr, SIGIO);
+ }
+}
+
+void
+busmouse_add_movement(int mousedev, int dx, int dy)
+{
+ struct busmouse_data *mse = busmouse_data[mousedev];
+
+ busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);
}
-static int fasync_mouse(int fd, struct file *filp, int on)
+void
+busmouse_add_buttons(int mousedev, int clear, int eor)
{
+ struct busmouse_data *mse = busmouse_data[mousedev];
+
+ busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor);
+}
+
+static int
+busmouse_fasync(int fd, struct file *filp, int on)
+{
+ struct busmouse_data *mse = (struct busmouse_data *)filp->private_data;
int retval;
- retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mse->fasyncptr);
if (retval < 0)
return retval;
return 0;
}
-/*
- * close access to the mouse
- */
-
-static int close_mouse(struct inode * inode, struct file * file)
+static int
+busmouse_release(struct inode *inode, struct file *file)
{
- fasync_mouse(-1, file, 0);
- if (--mouse.active)
- return 0;
- MSE_INT_OFF();
- free_irq(mouse_irq, NULL);
- MOD_DEC_USE_COUNT;
- return 0;
-}
+ struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
+ int ret = 0;
-/*
- * open access to the mouse
- */
+ busmouse_fasync(-1, file, 0);
-static int open_mouse(struct inode * inode, struct file * file)
+ if (--mse->active == 0) {
+ if (mse->ops &&
+ mse->ops->release)
+ ret = mse->ops->release(inode, file);
+
+ mse->ready = 0;
+
+ MOD_DEC_USE_COUNT;
+ }
+
+ return ret;
+}
+
+static int
+busmouse_open(struct inode *inode, struct file *file)
{
- if (!mouse.present)
+ struct busmouse_data *mse;
+ unsigned long flags;
+ unsigned int mousedev;
+ int ret = 0;
+
+ mousedev = DEV_TO_MOUSE(inode->i_rdev);
+ if (mousedev >= NR_MICE)
return -EINVAL;
- if (mouse.active++)
+ mse = busmouse_data[mousedev];
+ if (!mse)
+ /* shouldn't happen, but... */
+ return -ENODEV;
+
+ if (mse->ops &&
+ mse->ops->open)
+ ret = mse->ops->open(inode, file);
+
+ if (ret)
+ return ret;
+
+ file->private_data = mse;
+
+ if (mse->active++)
return 0;
- if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL)) {
- mouse.active--;
- return -EBUSY;
- }
- mouse.ready = 0;
- mouse.dx = 0;
- mouse.dy = 0;
- mouse.buttons = 0x87;
+
MOD_INC_USE_COUNT;
- MSE_INT_ON();
+
+ spin_lock_irqsave(&mse->lock, flags);
+
+ mse->ready = 0;
+ mse->dxpos = 0;
+ mse->dypos = 0;
+ if (mse->ops)
+ mse->buttons = mse->ops->init_button_state;
+ else
+ mse->buttons = 7;
+
+ spin_unlock_irqrestore(&mse->lock, flags);
+
return 0;
}
-/*
- * writes are disallowed
- */
-
-static ssize_t write_mouse(struct file * file,
- const char * buffer, size_t count, loff_t *ppos)
+static ssize_t
+busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
return -EINVAL;
}
-/*
- * read mouse data. Currently never blocks.
- */
-
-static ssize_t read_mouse(struct file * file,
- char * buffer, size_t count, loff_t *ppos)
+static ssize_t
+busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
- int r;
- int dx;
- int dy;
- unsigned char buttons;
- /* long flags; */
+ struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int dxpos, dypos, buttons;
if (count < 3)
return -EINVAL;
- if ((r = verify_area(VERIFY_WRITE, buffer, count)))
- return r;
- if (!mouse.ready)
+
+ spin_lock_irqsave(&mse->lock, flags);
+
+ if (!mse->ready) {
+#ifdef BROKEN_MOUSE
+ spin_unlock_irqrestore(&mse->lock, flags);
return -EAGAIN;
+#else
+ if (file->f_flags & O_NONBLOCK) {
+ spin_unlock_irqrestore(&mse->lock, flags);
+ return -EAGAIN;
+ }
+
+ add_wait_queue(&mse->wait, &wait);
+repeat:
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!mse->ready && !signal_pending(current)) {
+ spin_unlock_irqrestore(&mse->lock, flags);
+ schedule();
+ spin_lock_irqsave(&mse->lock, flags);
+ goto repeat;
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&mse->wait, &wait);
+
+ if (signal_pending(current)) {
+ spin_unlock_irqrestore(&mse->lock, flags);
+ return -ERESTARTSYS;
+ }
+#endif
+ }
- /*
- * Obtain the current mouse parameters and limit as appropriate for
- * the return data format. Interrupts are only disabled while
- * obtaining the parameters, NOT during the puts_fs_byte() calls,
- * so paging in put_user() does not effect mouse tracking.
+ dxpos = mse->dxpos;
+ dypos = mse->dypos;
+ buttons = mse->buttons;
+// mse->latch_buttons = mse->buttons;
+
+ if (dxpos < -127)
+ dxpos =- 127;
+ if (dxpos > 127)
+ dxpos = 127;
+ if (dypos < -127)
+ dypos =- 127;
+ if (dypos > 127)
+ dypos = 127;
+
+ mse->dxpos -= dxpos;
+ mse->dypos -= dypos;
+
+ /* This is something that many drivers have apparantly
+ * forgotten... If the X and Y positions still contain
+ * information, we still have some info ready for the
+ * user program...
*/
+ mse->ready = mse->dxpos || mse->dypos;
+
+ spin_unlock_irqrestore(&mse->lock, flags);
+
+ /* Write out data to the user. Format is:
+ * byte 0 - identifer (0x80) and (inverted) mouse buttons
+ * byte 1 - X delta position +/- 127
+ * byte 2 - Y delta position +/- 127
+ */
+ if (put_user((char)buttons | 128, buffer) ||
+ put_user((char)dxpos, buffer + 1) ||
+ put_user((char)dypos, buffer + 2))
+ return -EFAULT;
+
+ if (count > 3 && clear_user(buffer + 3, count - 3))
+ return -EFAULT;
- /* save_flags(flags); cli(); */
- disable_irq(mouse_irq);
- dx = mouse.dx;
- dy = mouse.dy;
- if (dx < -127)
- dx = -127;
- if (dx > 127)
- dx = 127;
- if (dy < -127)
- dy = -127;
- if (dy > 127)
- dy = 127;
- buttons = mouse.buttons;
- mouse.dx -= dx;
- mouse.dy -= dy;
- mouse.ready = 0;
- enable_irq(mouse_irq);
- /* restore_flags(flags); */
-
- put_user(buttons | 0x80, buffer);
- put_user((char)dx, buffer + 1);
- put_user((char)dy, buffer + 2);
- for (r = 3; r < count; r++)
- put_user(0x00, buffer + r);
- return r;
+ file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+
+ return count;
}
-/*
- * poll for mouse input
- */
-static unsigned int mouse_poll(struct file *file, poll_table * wait)
+static unsigned int
+busmouse_poll(struct file *file, poll_table *wait)
{
- poll_wait(file, &mouse.wait, wait);
- if (mouse.ready)
+ struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
+
+ poll_wait(file, &mse->wait, wait);
+
+ if (mse->ready)
return POLLIN | POLLRDNORM;
+
return 0;
}
-struct file_operations bus_mouse_fops = {
- NULL, /* mouse_seek */
- read_mouse,
- write_mouse,
- NULL, /* mouse_readdir */
- mouse_poll, /* mouse_poll */
- NULL, /* mouse_ioctl */
- NULL, /* mouse_mmap */
- open_mouse,
- NULL, /* flush */
- close_mouse,
+struct file_operations busmouse_fops=
+{
+ NULL, /* busmouse_seek */
+ busmouse_read,
+ busmouse_write,
+ NULL, /* busmouse_readdir */
+ busmouse_poll,
+ NULL, /* busmouse_ioctl */
+ NULL, /* busmouse_mmap */
+ busmouse_open,
+ NULL, /* busmouse_flush */
+ busmouse_release,
NULL,
- fasync_mouse,
+ busmouse_fasync,
};
-static struct miscdevice bus_mouse = {
- LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops
-};
+int
+register_busmouse(struct busmouse *ops)
+{
+ unsigned int msedev = MINOR_TO_MOUSE(ops->minor);
+ struct busmouse_data *mse;
+ int ret;
+
+ if (msedev >= NR_MICE) {
+ printk(KERN_ERR "busmouse: trying to allocate mouse on minor %d\n",
+ ops->minor);
+ return -EINVAL;
+ }
+
+ if (busmouse_data[msedev])
+ return -EBUSY;
+
+ mse = kmalloc(sizeof(*mse), GFP_KERNEL);
+ if (!mse)
+ return -ENOMEM;
-int __init bus_mouse_init(void)
+ memset(mse, 0, sizeof(*mse));
+
+ mse->miscdev.minor = ops->minor;
+ mse->miscdev.name = ops->name;
+ mse->miscdev.fops = &busmouse_fops;
+ mse->ops = ops;
+ mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
+ init_waitqueue_head(&mse->wait);
+
+ busmouse_data[msedev] = mse;
+
+ ret = misc_register(&mse->miscdev);
+ if (!ret)
+ ret = msedev;
+
+ return ret;
+}
+
+int
+unregister_busmouse(int mousedev)
{
- if (check_region(LOGIBM_BASE, LOGIBM_EXTENT)) {
- mouse.present = 0;
- return -EIO;
+ if (mousedev < 0)
+ return 0;
+ if (mousedev >= NR_MICE) {
+ printk(KERN_ERR "busmouse: trying to free mouse on"
+ " mousedev %d\n", mousedev);
+ return -EINVAL;
}
- outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
- outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
- udelay(100L); /* wait for reply from mouse */
- if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
- mouse.present = 0;
- return -EIO;
+ if (!busmouse_data[mousedev]) {
+ printk(KERN_WARNING "busmouse: trying to free free mouse"
+ " on mousedev %d\n", mousedev);
+ return -EINVAL;
+ }
+
+ if (busmouse_data[mousedev]->active) {
+ printk(KERN_ERR "busmouse: trying to free active mouse"
+ " on mousedev %d\n", mousedev);
+ return -EINVAL;
}
- outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
- MSE_INT_OFF();
-
- request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse");
-
- mouse.present = 1;
- mouse.active = 0;
- mouse.ready = 0;
- mouse.buttons = 0x87;
- mouse.dx = 0;
- mouse.dy = 0;
- init_waitqueue_head(&mouse.wait);
- printk(KERN_INFO "Logitech bus mouse detected, using IRQ %d.\n",
- mouse_irq);
- misc_register(&bus_mouse);
+
+ misc_deregister(&busmouse_data[mousedev]->miscdev);
+
+ kfree(busmouse_data[mousedev]);
+ busmouse_data[mousedev] = NULL;
return 0;
}
-#ifdef MODULE
+int __init
+bus_mouse_init(void)
+{
+#ifdef CONFIG_LOGIBUSMOUSE
+ logi_busmouse_init();
+#endif
+#ifdef CONFIG_MS_BUSMOUSE
+ ms_bus_mouse_init();
+#endif
+#ifdef CONFIG_ATIXL_BUSMOUSE
+ atixl_busmouse_init();
+#endif
+#ifdef CONFIG_AMIGAMOUSE
+ amiga_mouse_init();
+#endif
+#ifdef CONFIG_ATARIMOUSE
+ atari_mouse_init();
+#endif
+#ifdef CONFIG_MAC_MOUSE
+ mac_mouse_init();
+#endif
+#ifdef CONFIG_SUN_MOUSE
+ sun_mouse_init();
+#endif
+#ifdef CONFIG_ADBMOUSE
+ adb_mouse_init();
+#endif
+#ifdef CONFIG_RPCMOUSE
+ mouse_rpc_init();
+#endif
+ return 0;
+}
+
+EXPORT_SYMBOL(busmouse_add_movementbuttons);
+EXPORT_SYMBOL(busmouse_add_movement);
+EXPORT_SYMBOL(busmouse_add_buttons);
+EXPORT_SYMBOL(register_busmouse);
+EXPORT_SYMBOL(unregister_busmouse);
-int init_module(void)
+#ifdef MODULE
+int
+init_module(void)
{
return bus_mouse_init();
}
-void cleanup_module(void)
+void
+cleanup_module(void)
{
- misc_deregister(&bus_mouse);
- release_region(LOGIBM_BASE, LOGIBM_EXTENT);
}
#endif
diff --git a/drivers/char/busmouse.h b/drivers/char/busmouse.h
new file mode 100644
index 000000000..3626334d9
--- /dev/null
+++ b/drivers/char/busmouse.h
@@ -0,0 +1,28 @@
+/*
+ * linux/drivers/char/mouse.h
+ *
+ * Copyright (C) 1995 - 1998 Russell King
+ *
+ * Prototypes for generic busmouse interface
+ */
+#ifndef MOUSE_H
+#define MOUSE_H
+
+struct busmouse {
+ int minor;
+ const char *name;
+ int (*open)(struct inode * inode, struct file * file);
+ int (*release)(struct inode * inode, struct file * file);
+ int init_button_state;
+};
+
+extern void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons);
+extern void busmouse_add_movement(int mousedev, int dx, int dy);
+extern void busmouse_add_buttons(int mousedev, int clear, int eor);
+
+extern int register_busmouse(struct busmouse *ops);
+extern int unregister_busmouse(int mousedev);
+
+extern int bus_mouse_init(void);
+
+#endif
diff --git a/drivers/char/buz.c b/drivers/char/buz.c
index 1a37e2944..b535ac05e 100644
--- a/drivers/char/buz.c
+++ b/drivers/char/buz.c
@@ -47,7 +47,7 @@
#include <asm/segment.h>
#include <linux/types.h>
#include <linux/wrapper.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
#include <linux/videodev.h>
@@ -374,13 +374,13 @@ static int i2c_getdataline(struct i2c_bus *bus)
return (btread(ZR36057_I2CBR) >> 1) & 1;
}
-void attach_inform(struct i2c_bus *bus, int id)
+static void attach_inform(struct i2c_bus *bus, int id)
{
DEBUG(struct zoran *zr = (struct zoran *) bus->data);
DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id));
}
-void detach_inform(struct i2c_bus *bus, int id)
+static void detach_inform(struct i2c_bus *bus, int id)
{
DEBUG(struct zoran *zr = (struct zoran *) bus->data);
DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id));
@@ -2650,7 +2650,8 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct video_buffer v;
- if (!capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN)
+ || !capable(CAP_SYS_RAWIO))
return -EPERM;
if (copy_from_user(&v, arg, sizeof(v)))
@@ -3219,7 +3220,7 @@ static int zr36057_init(int i)
}
/* i2c */
memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus));
- sprintf(zr->i2c.name, "zoran%u%u", zr->id);
+ sprintf(zr->i2c.name, "zoran%u", zr->id);
zr->i2c.data = zr;
if (i2c_register_bus(&zr->i2c) < 0) {
kfree((void *) zr->stat_com);
@@ -3327,7 +3328,7 @@ static int find_zr36057(void)
spin_lock_init(&zr->lock);
- zr->zr36057_adr = zr->pci_dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
+ zr->zr36057_adr = zr->pci_dev->resource[0].start;
pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
if (zr->revision < 2) {
printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
diff --git a/drivers/char/bw-qcam.c b/drivers/char/bw-qcam.c
index 29cdac314..17f7d25dc 100644
--- a/drivers/char/bw-qcam.c
+++ b/drivers/char/bw-qcam.c
@@ -76,18 +76,19 @@ OTHER DEALINGS IN THE SOFTWARE.
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/videodev.h>
+#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include "bw-qcam.h"
+static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */
+static unsigned int yieldlines=4; /* Yield after this many during capture */
+
#if LINUX_VERSION_CODE >= 0x020117
MODULE_PARM(maxpoll,"i");
MODULE_PARM(yieldlines,"i");
#endif
-static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */
-static unsigned int yieldlines=4; /* Yield after this many during capture */
-
extern __inline__ int read_lpstatus(struct qcam_device *q)
{
return parport_read_status(q->pport);
@@ -174,6 +175,8 @@ static struct qcam_device *qcam_init(struct parport *port)
}
memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
+
+ init_MUTEX(&q->lock);
q->port_mode = (QC_ANY | QC_NOTSET);
q->width = 320;
@@ -817,14 +820,12 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
qcam->contrast = p.contrast>>8;
qcam->whitebal = p.whiteness>>8;
qcam->bpp = p.depth;
-
+
+ down(&qcam->lock);
qc_setscanmode(qcam);
+ up(&qcam->lock);
qcam->status |= QC_PARAM_CHANGE;
-/* parport_claim_or_block(qcam->pdev);
- qc_set(qcam);
- parport_release(qcam->pdev);
-*/
return 0;
}
case VIDIOCSWIN:
@@ -855,7 +856,9 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
qcam->height = 240;
qcam->transfer_scale = 1;
}
+ down(&qcam->lock);
qc_setscanmode(qcam);
+ up(&qcam->lock);
/* We must update the camera before we grab. We could
just have changed the grab size */
@@ -904,7 +907,9 @@ static long qcam_read(struct video_device *v, char *buf, unsigned long count, i
struct qcam_device *qcam=(struct qcam_device *)v;
int len;
parport_claim_or_block(qcam->pdev);
- /* Probably should have a semaphore against multiple users */
+
+ down(&qcam->lock);
+
qc_reset(qcam);
/* Update the camera parameters if we need to */
@@ -912,6 +917,9 @@ static long qcam_read(struct video_device *v, char *buf, unsigned long count, i
qc_set(qcam);
len=qc_capture(qcam, buf,count);
+
+ up(&qcam->lock);
+
parport_release(qcam->pdev);
return len;
}
diff --git a/drivers/char/bw-qcam.h b/drivers/char/bw-qcam.h
index bb49cde10..723e8ad9e 100644
--- a/drivers/char/bw-qcam.h
+++ b/drivers/char/bw-qcam.h
@@ -55,6 +55,7 @@ struct qcam_device {
struct video_device vdev;
struct pardevice *pdev;
struct parport *pport;
+ struct semaphore lock;
int width, height;
int bpp;
int mode;
diff --git a/drivers/char/c-qcam.c b/drivers/char/c-qcam.c
index 3c7cc317a..90eb5405d 100644
--- a/drivers/char/c-qcam.c
+++ b/drivers/char/c-qcam.c
@@ -16,6 +16,7 @@
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/videodev.h>
+#include <asm/semaphore.h>
#include <asm/uaccess.h>
struct qcam_device {
@@ -28,6 +29,7 @@ struct qcam_device {
int contrast, brightness, whitebal;
int top, left;
unsigned int bidirectional;
+ struct semaphore lock;
};
/* The three possible QuickCam modes */
@@ -516,10 +518,12 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
qcam->brightness = p.brightness>>8;
qcam->contrast = p.contrast>>8;
qcam->whitebal = p.whiteness>>8;
-
+
+ down(&qcam->lock);
parport_claim_or_block(qcam->pdev);
qc_setup(qcam);
parport_release(qcam->pdev);
+ up(&qcam->lock);
return 0;
}
case VIDIOCSWIN:
@@ -564,9 +568,11 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
#endif
/* Ok we figured out what to use from our
wide choice */
+ down(&qcam->lock);
parport_claim_or_block(qcam->pdev);
qc_setup(qcam);
parport_release(qcam->pdev);
+ up(&qcam->lock);
return 0;
}
case VIDIOCGWIN:
@@ -608,10 +614,13 @@ static long qcam_read(struct video_device *v, char *buf, unsigned long count, i
{
struct qcam_device *qcam=(struct qcam_device *)v;
int len;
+
+ down(&qcam->lock);
parport_claim_or_block(qcam->pdev);
/* Probably should have a semaphore against multiple users */
len = qc_capture(qcam, buf,count);
parport_release(qcam->pdev);
+ up(&qcam->lock);
return len;
}
@@ -660,6 +669,7 @@ static struct qcam_device *qcam_init(struct parport *port)
memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
+ init_MUTEX(&q->lock);
q->width = q->ccd_width = 320;
q->height = q->ccd_height = 240;
q->mode = QC_MILLIONS | QC_DECIMATION_1;
diff --git a/drivers/char/console.c b/drivers/char/console.c
index db165915c..d0503cdcb 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -33,7 +33,7 @@
* 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.
+ * <geert@linux-m68k.org>, Jan 1997.
*
* Original m68k console driver modifications by
*
@@ -1984,7 +1984,7 @@ void vt_console_print(struct console *co, const char * b, unsigned count)
static unsigned long printing = 0;
const ushort *start;
ushort cnt = 0;
- ushort myx = x;
+ ushort myx;
/* console busy or not yet initialized */
if (!printable || test_and_set_bit(0, &printing))
@@ -1993,6 +1993,10 @@ void vt_console_print(struct console *co, const char * b, unsigned count)
if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
currcons = kmsg_redirect - 1;
+ /* read `x' only after setting currecons properly (otherwise
+ the `x' macro will read the x of the foreground console). */
+ myx = x;
+
if (!vc_cons_allocated(currcons)) {
/* impossible */
printk("vt_console_print: tty %d not allocated ??\n", currcons+1);
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index cae9bb818..f795f96bb 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1,7 +1,7 @@
-#define BLOCKMOVE
+#undef BLOCKMOVE
#define Z_WAKE
static char rcsid[] =
-"$Revision: 2.2.2.3 $$Date: 1999/06/28 11:13:29 $";
+"$Revision: 2.3.2.2 $$Date: 1999/10/01 11:27:43 $";
/*
* linux/drivers/char/cyclades.c
@@ -9,9 +9,8 @@ static char rcsid[] =
* This file contains the driver for the Cyclades Cyclom-Y multiport
* serial boards.
*
- * Maintained by Ivan Passos (ivan@cyclades.com),
- * Marcio Saito (marcio@cyclades.com) and
- * Randolph Bentson (bentson@grieg.seaslug.org).
+ * Initially written by Randolph Bentson (bentson@grieg.seaslug.org).
+ * Maintained by Ivan Passos (ivan@cyclades.com).
*
* For Technical support and installation problems, please send e-mail
* to support@cyclades.com.
@@ -31,6 +30,39 @@ static char rcsid[] =
* void cleanup_module(void);
*
* $Log: cyclades.c,v $
+ * Revision 2.3.2.2 1999/10/01 11:27:43 ivan
+ * Fixed bug in cyz_poll that would make all ports but port 0
+ * unable to transmit/receive data (Cyclades-Z only);
+ * Implemented logic to prevent the RX buffer from being stuck with
+ * due to a driver / firmware race condition in interrupt op mode
+ * (Cyclades-Z only);
+ * Fixed bug in block_til_ready logic that would lead to a system crash;
+ * Revisited cy_close spinlock usage;
+ *
+ * Revision 2.3.2.1 1999/09/28 11:01:22 ivan
+ * Revisited CONFIG_PCI conditional compilation for PCI board support;
+ * Implemented TIOCGICOUNT and TIOCMIWAIT ioctl support;
+ * _Major_ cleanup on the Cyclades-Z interrupt support code / logic;
+ * Removed CTS handling from the driver -- this is now completely handled
+ * by the firmware (Cyclades-Z only);
+ * Flush RX on-board buffers on a port open (Cyclades-Z only);
+ * Fixed handling of ASYNC_SPD_* TTY flags;
+ * Module unload now unmaps all memory area allocated by ioremap;
+ *
+ * Revision 2.3.1.1 1999/07/15 16:45:53 ivan
+ * Removed CY_PROC conditional compilation;
+ * Implemented SMP-awareness for the driver;
+ * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
+ * functions;
+ * The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs
+ * (irq=NN) as parameters (only for ISA boards);
+ * Fixed bug in set_line_char that would prevent the Cyclades-Z
+ * ports from being configured at speeds above 115.2Kbps;
+ * Fixed bug in cy_set_termios that would prevent XON/XOFF flow control
+ * switching from working properly;
+ * The driver now only prints IRQ info for the Cyclades-Z if it's
+ * configured to work in interrupt mode;
+ *
* Revision 2.2.2.3 1999/06/28 11:13:29 ivan
* Added support for interrupt mode operation for the Z cards;
* Removed the driver inactivity control for the Z;
@@ -165,7 +197,7 @@ static char rcsid[] =
* Change queue_task_irq_off to queue_task_irq.
* The inline function queue_task_irq_off (tqueue.h)
* was removed from latest releases of 2.1.x kernel.
- * Use of macro __initfunc to mark the initialization
+ * Use of macro __init to mark the initialization
* routines, so memory can be reused.
* Also incorporate implementation of critical region
* in function cleanup_module() created by anonymous
@@ -557,7 +589,6 @@ static char rcsid[] =
#undef CY_16Y_HACK
#undef CY_ENABLE_MONITORING
#undef CY_PCI_DEBUG
-#undef CY_PROC
#if 0
#define PAUSE __asm__("nop");
@@ -606,6 +637,7 @@ static char rcsid[] =
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/spinlock.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -613,6 +645,16 @@ static char rcsid[] =
#include <asm/uaccess.h>
#include <asm/bitops.h>
+#define CY_LOCK(info,flags) \
+ do { \
+ spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \
+ } while (0)
+
+#define CY_UNLOCK(info,flags) \
+ do { \
+ spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \
+ } while (0)
+
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -631,7 +673,8 @@ static char rcsid[] =
#define cy_put_user put_user
-static unsigned long cy_get_user(unsigned long *addr)
+static unsigned long
+cy_get_user(unsigned long *addr)
{
unsigned long result = 0;
int error = get_user (result, addr);
@@ -668,11 +711,6 @@ static struct tty_driver cy_serial_driver, cy_callout_driver;
static int serial_refcount;
#ifndef CONFIG_COBALT_27
-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
@@ -695,6 +733,14 @@ static unsigned char *cy_isa_addresses[] = {
};
#define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
+#ifdef MODULE
+static int maddr[NR_CARDS] = { 0, };
+static int irq[NR_CARDS] = { 0, };
+
+MODULE_PARM(maddr, "1-" __MODULE_STRING(NR_CARDS) "l");
+MODULE_PARM(irq, "1-" __MODULE_STRING(NR_CARDS) "i");
+#endif
+
#endif /* CONFIG_COBALT_27 */
/* This is the per-card data structure containing address, irq, number of
@@ -802,6 +848,7 @@ static int cy_chip_offset [] =
static unsigned short cy_pci_nboard = 0;
static unsigned short cy_isa_nboard = 0;
static unsigned short cy_nboard = 0;
+#ifdef CONFIG_PCI
static unsigned short cy_pci_dev_id[] = {
PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */
PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */
@@ -813,12 +860,13 @@ static unsigned short cy_pci_dev_id[] = {
PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */
0 /* end of table */
};
-
+#endif
static void cy_start(struct tty_struct *);
static void set_line_char(struct cyclades_port *);
+static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong);
#ifndef CONFIG_COBALT_27
-static void cy_probe(int, void *, struct pt_regs *);
+static unsigned detect_isa_irq (volatile ucchar *);
#endif /* CONFIG_COBALT_27 */
#ifdef CYCLOM_SHOW_STATUS
static void show_status(int);
@@ -837,6 +885,9 @@ static struct timer_list
cyz_timerlist = {
NULL, NULL, 0, 0, cyz_poll
};
+#else /* CONFIG_CYZ_INTR */
+static void cyz_rx_restart(unsigned long);
+static struct timer_list cyz_rx_full_timer[NR_PORTS];
#endif /* CONFIG_CYZ_INTR */
/**************************************************
@@ -941,6 +992,17 @@ do_softint(void *private_)
if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
wake_up_interruptible(&info->open_wait);
}
+#ifdef CONFIG_CYZ_INTR
+ if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) {
+ cyz_rx_full_timer[info->line].expires = jiffies + 1;
+ cyz_rx_full_timer[info->line].function = cyz_rx_restart;
+ cyz_rx_full_timer[info->line].data = (unsigned long)info;
+ add_timer(&cyz_rx_full_timer[info->line]);
+ }
+#endif
+ if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) {
+ wake_up_interruptible(&info->delta_msr_wait);
+ }
if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
&& tty->ldisc.write_wakeup){
@@ -963,226 +1025,80 @@ do_softint(void *private_)
command to the Cirrus chip to complete and then issues the
new command. An error is returned if the previous command
didn't finish within the time limit.
+
+ This function is only called from inside spinlock-protected code.
*/
static int
cyy_issue_cmd(volatile ucchar *base_addr, u_char cmd, int index)
{
- unsigned long flags;
volatile int i;
- save_flags(flags); cli();
- /* Check to see that the previous command has completed */
- for(i = 0 ; i < 100 ; i++){
- if (cy_readb(base_addr+(CyCCR<<index)) == 0){
- break;
- }
- udelay(10L);
- }
- /* if the CCR never cleared, the previous command
- didn't finish within the "reasonable time" */
- if ( i == 100 ) {
- restore_flags(flags);
- return (-1);
- }
+ /* Check to see that the previous command has completed */
+ for(i = 0 ; i < 100 ; i++){
+ if (cy_readb(base_addr+(CyCCR<<index)) == 0){
+ break;
+ }
+ udelay(10L);
+ }
+ /* if the CCR never cleared, the previous command
+ didn't finish within the "reasonable time" */
+ if (i == 100) return (-1);
+
+ /* Issue the new command */
+ cy_writeb((u_long)base_addr+(CyCCR<<index), cmd);
- /* Issue the new command */
- cy_writeb((u_long)base_addr+(CyCCR<<index), cmd);
- restore_flags(flags);
return(0);
} /* cyy_issue_cmd */
#ifndef CONFIG_COBALT_27 /* ISA interrupt detection code */
-
-static int probe_ready;
-
-/*
- * Grab all interrupts in preparation for doing an automatic irq
- * detection. dontgrab is a mask of irq's _not_ to grab. Returns a
- * mask of irq's which were grabbed and should therefore be freed
- * using free_all_interrupts().
- */
-static int
-grab_all_interrupts(int dontgrab)
+static unsigned
+detect_isa_irq (volatile ucchar *address)
{
- int irq_lines = 0;
- int i, mask;
-
- for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
- if (!(mask & dontgrab)
- && !request_irq(i, cy_probe,
- SA_INTERRUPT, "serial probe", NULL)) {
- irq_lines |= mask;
- }
- }
- return irq_lines;
-} /* grab_all_interrupts */
+ int irq;
+ unsigned long irqs, flags;
+ int save_xir, save_car;
+ int index = 0; /* IRQ probing is only for ISA */
-/*
- * Release all interrupts grabbed by grab_all_interrupts
- */
-static void
-free_all_interrupts(int irq_lines)
-{
- int i;
-
- for (i = 0; i < 16; i++) {
- if (irq_lines & (1 << i)) {
- free_irq(i,NULL);
- }
- }
-} /* free_all_interrupts */
+ /* forget possible initially masked and pending IRQ */
+ irq = probe_irq_off(probe_irq_on());
-/*
- * This routine returns a bitfield of "wild interrupts". Basically,
- * any unclaimed interrupts which is flapping around.
- */
-static int
-check_wild_interrupts(void)
-{
- int i, mask;
- int wild_interrupts = 0;
- int irq_lines;
- unsigned long timeout;
- unsigned long flags;
-
- /*Turn on interrupts (they may be off) */
- save_flags(flags); sti();
+ /* Clear interrupts on the board first */
+ cy_writeb((u_long)address + (Cy_ClrIntr<<index), 0);
+ /* Cy_ClrIntr is 0x1800 */
- irq_lines = grab_all_interrupts(0);
-
- /*
- * Delay for 0.1 seconds -- we use a busy loop since this may
- * occur during the bootup sequence
- */
- timeout = jiffies+(HZ/10);
- while (time_after_eq(timeout, jiffies))
- ;
-
- cy_triggered = 0; /* Reset after letting things settle */
-
- timeout = jiffies+(HZ/10);
- while (time_after_eq(timeout, jiffies))
- ;
-
- for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
- if ((cy_triggered & (1 << i)) &&
- (irq_lines & (1 << i))) {
- wild_interrupts |= mask;
- }
- }
- free_all_interrupts(irq_lines);
- restore_flags(flags);
- return wild_interrupts;
-} /* check_wild_interrupts */
+ irqs = probe_irq_on();
+ /* Wait ... */
+ udelay(5000L);
-/*
- * This routine is called by do_auto_irq(); it attempts to determine
- * which interrupt a serial port is configured to use. It is not
- * fool-proof, but it works a large part of the time.
- */
-static int
-get_auto_irq(volatile ucchar *address)
-{
- unsigned long timeout;
- volatile ucchar *base_addr;
- int index;
- unsigned long flags;
-
- index = 0; /* IRQ probing is only for ISA */
- base_addr = address;
- intr_base_addr = address;
-
- /*
- * Enable interrupts and see who answers
- */
- cy_irq_triggered = 0;
+ /* Enable the Tx interrupts on the CD1400 */
save_flags(flags); cli();
- cy_writeb((u_long)base_addr+(CyCAR<<index), 0);
- cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
- cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
- probe_ready = 1;
- restore_flags(flags);
-
- timeout = jiffies+(HZ/50);
- while (time_after_eq(timeout, jiffies)) {
- if (cy_irq_triggered)
- break;
- }
- probe_ready = 0;
- return(cy_irq_triggered);
-} /* get_auto_irq */
-
-/*
- * Calls get_auto_irq() multiple times, to make sure we don't get
- * faked out by random interrupts
- */
-static int
-do_auto_irq(volatile ucchar *address)
-{
- int irq_lines = 0;
- int irq_try_1 = 0, irq_try_2 = 0;
- int retries;
- unsigned long flags;
-
- /* Turn on interrupts (they may be off) */
- save_flags(flags); sti();
+ cy_writeb((u_long)address + (CyCAR<<index), 0);
+ cyy_issue_cmd(address, CyCHAN_CTL|CyENB_XMTR, index);
- probe_ready = 0;
-
- cy_wild_int_mask = check_wild_interrupts();
-
- irq_lines = grab_all_interrupts(cy_wild_int_mask);
-
- for (retries = 0; retries < 5; retries++) {
- if (!irq_try_1)
- irq_try_1 = get_auto_irq(address);
- if (!irq_try_2)
- irq_try_2 = get_auto_irq(address);
- if (irq_try_1 && irq_try_2) {
- if (irq_try_1 == irq_try_2)
- break;
- irq_try_1 = irq_try_2 = 0;
- }
- }
+ cy_writeb((u_long)address + (CyCAR<<index), 0);
+ cy_writeb((u_long)address + (CySRER<<index),
+ cy_readb(address + (CySRER<<index)) | CyTxMpty);
restore_flags(flags);
- free_all_interrupts(irq_lines);
- return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
-} /* do_auto_irq */
+ /* Wait ... */
+ udelay(5000L);
-/*
- * This interrupt routine is used
- * while we are probing for submarines.
- */
-static void
-cy_probe(int irq, void *dev_id, struct pt_regs *regs)
-{
- int save_xir, save_car;
- int index = 0; /* probing interrupts is only for ISA */
-
- if (!probe_ready) {
- cy_writeb((u_long)intr_base_addr+(Cy_ClrIntr<<index), 0);
- return;
- }
+ /* Check which interrupt is in use */
+ irq = probe_irq_off(irqs);
- cy_irq_triggered = irq;
- cy_triggered |= 1 << irq;
-
- 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));
- 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);
- cy_writeb((u_long)intr_base_addr+(CyTIR<<index), (save_xir & 0x3f));
- cy_writeb((u_long)intr_base_addr+(CyCAR<<index), (save_car));
- }
- cy_writeb((u_long)intr_base_addr+(Cy_ClrIntr<<index), 0);
- /* Cy_ClrIntr is 0x1800 */
- return;
-} /* cy_probe */
+ /* Clean up */
+ save_xir = (u_char) cy_readb(address + (CyTIR<<index));
+ save_car = cy_readb(address + (CyCAR<<index));
+ cy_writeb((u_long)address + (CyCAR<<index), (save_xir & 0x3));
+ cy_writeb((u_long)address + (CySRER<<index),
+ cy_readb(address + (CySRER<<index)) & ~CyTxMpty);
+ cy_writeb((u_long)address + (CyTIR<<index), (save_xir & 0x3f));
+ cy_writeb((u_long)address + (CyCAR<<index), (save_car));
+ cy_writeb((u_long)address + (Cy_ClrIntr<<index), 0);
+ /* Cy_ClrIntr is 0x1800 */
+ return (irq > 0)? irq : 0;
+}
#endif /* CONFIG_COBALT_27 */
/* The real interrupt service routine is called
@@ -1245,6 +1161,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
#endif
/* determine the channel & change to that context */
+ spin_lock(&cinfo->card_lock);
save_xir = (u_char) cy_readb(base_addr+(CyRIR<<index));
channel = (u_short ) (save_xir & CyIRChannel);
i = channel + chip * 4 + cinfo->first_line;
@@ -1252,6 +1169,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
info->last_active = jiffies;
save_car = cy_readb(base_addr+(CyCAR<<index));
cy_writeb((u_long)base_addr+(CyCAR<<index), save_xir);
+ spin_unlock(&cinfo->card_lock);
/* if there is nowhere to put the data, discard it */
if(info->tty == 0){
@@ -1269,7 +1187,19 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask);
if ( j == CyIVRRxEx ) { /* exception */
data = cy_readb(base_addr+(CyRDSR<<index));
+
+ /* For statistics only */
+ if (data & CyBREAK)
+ info->icount.brk++;
+ else if(data & CyFRAME)
+ info->icount.frame++;
+ else if(data & CyPARITY)
+ info->icount.parity++;
+ else if(data & CyOVERRUN)
+ info->icount.overrun++;
+
if(data & info->ignore_status_mask){
+ info->icount.rx++;
continue;
}
if (tty->flip.count < TTY_FLIPBUF_SIZE){
@@ -1277,9 +1207,10 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (data & info->read_status_mask){
if(data & CyBREAK){
*tty->flip.flag_buf_ptr++ =
- TTY_BREAK;
+ TTY_BREAK;
*tty->flip.char_buf_ptr++ =
cy_readb(base_addr+(CyRDSR<<index));
+ info->icount.rx++;
if (info->flags & ASYNC_SAK){
do_SAK(tty);
}
@@ -1288,17 +1219,20 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
TTY_FRAME;
*tty->flip.char_buf_ptr++ =
cy_readb(base_addr+(CyRDSR<<index));
+ info->icount.rx++;
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->icount.rx++;
info->idle_stats.parity_errs++;
}else if(data & CyOVERRUN){
*tty->flip.flag_buf_ptr++ =
TTY_OVERRUN;
*tty->flip.char_buf_ptr++ = 0;
+ info->icount.rx++;
/* If the flip buffer itself is
overflowing, we still lose
the next incoming character.
@@ -1310,6 +1244,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
TTY_NORMAL;
*tty->flip.char_buf_ptr++ =
cy_readb(base_addr+(CyRDSR<<index));
+ info->icount.rx++;
}
info->idle_stats.overruns++;
/* These two conditions may imply */
@@ -1319,15 +1254,18 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}else{
*tty->flip.flag_buf_ptr++ = 0;
*tty->flip.char_buf_ptr++ = 0;
+ info->icount.rx++;
}
}else{
*tty->flip.flag_buf_ptr++ = 0;
*tty->flip.char_buf_ptr++ = 0;
+ info->icount.rx++;
}
}else{
/* there was a software buffer
overrun and nothing could be
done about it!!! */
+ info->icount.buf_overrun++;
info->idle_stats.overruns++;
}
} else { /* normal character reception */
@@ -1351,6 +1289,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
data = cy_readb(base_addr+(CyRDSR<<index));
*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
*tty->flip.char_buf_ptr++ = data;
+ info->icount.rx++;
#ifdef CY_16Y_HACK
udelay(10L);
#endif
@@ -1359,8 +1298,10 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
queue_task(&tty->flip.tqueue, &tq_timer);
}
/* end of service */
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CyRIR<<index), (save_xir & 0x3f));
cy_writeb((u_long)base_addr+(CyCAR<<index), (save_car));
+ spin_unlock(&cinfo->card_lock);
}
@@ -1373,34 +1314,40 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#endif
/* determine the channel & change to that context */
+ spin_lock(&cinfo->card_lock);
save_xir = (u_char) cy_readb(base_addr+(CyTIR<<index));
channel = (u_short ) (save_xir & CyIRChannel);
i = channel + chip * 4 + cinfo->first_line;
save_car = cy_readb(base_addr+(CyCAR<<index));
cy_writeb((u_long)base_addr+(CyCAR<<index), save_xir);
+ spin_unlock(&cinfo->card_lock);
/* validate the port# (as configured and open) */
if( (i < 0) || (NR_PORTS <= i) ){
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+ spin_unlock(&cinfo->card_lock);
goto txend;
}
info = &cy_port[i];
info->last_active = jiffies;
if(info->tty == 0){
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+ spin_unlock(&cinfo->card_lock);
goto txdone;
}
/* load the on-chip space for outbound data */
char_count = info->xmit_fifo_size;
-
if(info->x_char) { /* send special char */
outch = info->x_char;
cy_writeb((u_long)base_addr+(CyTDR<<index), outch);
char_count--;
+ info->icount.tx++;
info->x_char = 0;
}
@@ -1421,21 +1368,27 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
while (char_count-- > 0){
if (!info->xmit_cnt){
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) &
~CyTxMpty);
+ spin_unlock(&cinfo->card_lock);
goto txdone;
}
if (info->xmit_buf == 0){
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) &
~CyTxMpty);
+ spin_unlock(&cinfo->card_lock);
goto txdone;
}
if (info->tty->stopped || info->tty->hw_stopped){
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) &
~CyTxMpty);
+ spin_unlock(&cinfo->card_lock);
goto txdone;
}
/* Because the Embedded Transmit Commands have
@@ -1455,6 +1408,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
info->xmit_tail = (info->xmit_tail + 1)
& (SERIAL_XMIT_SIZE - 1);
cy_writeb((u_long)base_addr+(CyTDR<<index), outch);
+ info->icount.tx++;
}else{
if(char_count > 1){
info->xmit_cnt--;
@@ -1463,6 +1417,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
cy_writeb((u_long)base_addr+(CyTDR<<index),
outch);
cy_writeb((u_long)base_addr+(CyTDR<<index), 0);
+ info->icount.tx++;
char_count--;
}else{
}
@@ -1475,14 +1430,17 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
txend:
/* end of service */
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CyTIR<<index),
(save_xir & 0x3f));
cy_writeb((u_long)base_addr+(CyCAR<<index), (save_car));
+ spin_unlock(&cinfo->card_lock);
}
if (status & CySRModem) { /* modem interrupt */
/* determine the channel & change to that context */
+ spin_lock(&cinfo->card_lock);
save_xir = (u_char) cy_readb(base_addr+(CyMIR<<index));
channel = (u_short ) (save_xir & CyIRChannel);
info = &cy_port[channel + chip * 4
@@ -1493,10 +1451,21 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
mdm_change = cy_readb(base_addr+(CyMISR<<index));
mdm_status = cy_readb(base_addr+(CyMSVR1<<index));
+ spin_unlock(&cinfo->card_lock);
if(info->tty == 0){/* no place for data, ignore it*/
;
}else{
+ if (mdm_change & CyANY_DELTA) {
+ /* For statistics only */
+ if (mdm_change & CyDCD) info->icount.dcd++;
+ if (mdm_change & CyCTS) info->icount.cts++;
+ if (mdm_change & CyDSR) info->icount.dsr++;
+ if (mdm_change & CyRI) info->icount.rng++;
+
+ cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
+ }
+
if((mdm_change & CyDCD)
&& (info->flags & ASYNC_CHECK_CD)){
if(mdm_status & CyDCD){
@@ -1517,9 +1486,11 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* cy_start isn't used
because... !!! */
info->tty->hw_stopped = 0;
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) |
CyTxMpty);
+ spin_unlock(&cinfo->card_lock);
cy_sched_event(info,
Cy_EVENT_WRITE_WAKEUP);
}
@@ -1528,29 +1499,35 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* cy_stop isn't used
because ... !!! */
info->tty->hw_stopped = 1;
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) &
~CyTxMpty);
+ spin_unlock(&cinfo->card_lock);
}
}
}
- if(mdm_status & CyDSR){
+ if(mdm_change & CyDSR){
}
- if(mdm_status & CyRI){
+ if(mdm_change & CyRI){
}
}
/* end of service */
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CyMIR<<index),
(save_xir & 0x3f));
cy_writeb((u_long)base_addr+(CyCAR<<index), save_car);
+ spin_unlock(&cinfo->card_lock);
}
} /* end while status != 0 */
} /* end loop for chips... */
} while(had_work);
/* clear interrupts */
+ spin_lock(&cinfo->card_lock);
cy_writeb((u_long)card_base_addr + (Cy_ClrIntr<<index), 0);
/* Cy_ClrIntr is 0x1800 */
+ spin_unlock(&cinfo->card_lock);
} /* cyy_interrupt */
/***********************************************************/
@@ -1589,7 +1566,6 @@ cyz_fetch_msg( struct cyclades_card *cinfo,
return 0;
} /* cyz_fetch_msg */
-
static int
cyz_issue_cmd( struct cyclades_card *cinfo,
uclong channel, ucchar cmd, uclong param)
@@ -1624,37 +1600,184 @@ cyz_issue_cmd( struct cyclades_card *cinfo,
return(0);
} /* cyz_issue_cmd */
+static void
+cyz_handle_rx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
+{
+ struct cyclades_card *cinfo = &cy_card[info->card];
+ struct tty_struct *tty = info->tty;
+ volatile int char_count;
+#ifdef BLOCKMOVE
+ int small_count;
+#else
+ char data;
+#endif
+ volatile uclong rx_put, rx_get, rx_bufsize;
-#if 0
-static int
-cyz_update_channel( struct cyclades_card *cinfo,
- u_long channel, u_char mode, u_char cmd)
-{
- struct FIRM_ID *firm_id =
- (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
- struct ZFW_CTRL *zfw_ctrl;
- struct CH_CTRL *ch_ctrl;
+/* Removed due to compilation problems in Alpha systems */
+// if ((char_count = CHARS_IN_BUF(buf_ctrl))){
- if (!ISZLOADED(*cinfo)){
- return (-1);
+ rx_get = cy_readl(&buf_ctrl->rx_get);
+ rx_put = cy_readl(&buf_ctrl->rx_put);
+ rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
+ if (rx_put >= rx_get)
+ char_count = rx_put - rx_get;
+ else
+ char_count = rx_put - rx_get + rx_bufsize;
+
+ if ( char_count ) {
+ info->last_active = jiffies;
+ info->jiffies[1] = jiffies;
+
+#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
+ if(tty == 0){
+ /* flush received characters */
+ rx_get = (rx_get + char_count) & (rx_bufsize - 1);
+ info->rflush_count++;
+ }else{
+#ifdef BLOCKMOVE
+ /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
+ for performance, but because of buffer boundaries, there
+ may be several steps to the operation */
+ while(0 < (small_count =
+ cy_min((rx_bufsize - rx_get),
+ cy_min((TTY_FLIPBUF_SIZE - tty->flip.count), char_count))
+ )) {
+ memcpy_fromio(tty->flip.char_buf_ptr,
+ (char *)(cinfo->base_addr
+ + cy_readl(&buf_ctrl->rx_bufaddr)
+ + rx_get),
+ small_count);
+
+ tty->flip.char_buf_ptr += small_count;
+ memset(tty->flip.flag_buf_ptr, TTY_NORMAL, small_count);
+ tty->flip.flag_buf_ptr += small_count;
+ rx_get = (rx_get + small_count) & (rx_bufsize - 1);
+ char_count -= small_count;
+ info->icount.rx += small_count;
+ info->idle_stats.recv_bytes += small_count;
+ tty->flip.count += small_count;
+ }
+#else
+ while(char_count--){
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE){
+#ifdef CONFIG_CYZ_INTR
+ cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
+#endif
+ break;
+ }
+ data = cy_readb(cinfo->base_addr +
+ cy_readl(&buf_ctrl->rx_bufaddr) + rx_get);
+ rx_get = (rx_get + 1) & (rx_bufsize - 1);
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+ *tty->flip.char_buf_ptr++ = data;
+ info->idle_stats.recv_bytes++;
+ info->icount.rx++;
+ }
+#endif
+ info->idle_stats.recv_idle = jiffies;
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ }
+ /* Update rx_get */
+ cy_writel(&buf_ctrl->rx_get, rx_get);
}
- zfw_ctrl = (struct ZFW_CTRL *)
- (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
- ch_ctrl = zfw_ctrl->ch_ctrl;
+}
- cy_writel(&ch_ctrl[channel].op_mode, (uclong)mode);
+static void
+cyz_handle_tx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
+{
+ struct cyclades_card *cinfo = &cy_card[info->card];
+ struct tty_struct *tty = info->tty;
+ char data;
+ volatile int char_count;
+#ifdef BLOCKMOVE
+ int small_count;
+#endif
+ volatile uclong tx_put, tx_get, tx_bufsize;
- return cyz_issue_cmd(cinfo, channel, cmd, 0L);
+/* Removed due to compilation problems in Alpha systems */
+// if ((char_count = SPACE_IN_BUF(buf_ctrl))){
-} /* cyz_update_channel */
+ tx_get = cy_readl(&buf_ctrl->tx_get);
+ tx_put = cy_readl(&buf_ctrl->tx_put);
+ tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+ if (tx_put >= tx_get)
+ char_count = tx_get - tx_put - 1 + tx_bufsize;
+ else
+ char_count = tx_get - tx_put - 1;
+
+ if ( char_count ) {
+
+ if( tty == 0 ){
+ goto ztxdone;
+ }
+
+ if(info->x_char) { /* send special char */
+ data = info->x_char;
+
+ cy_writeb((cinfo->base_addr +
+ cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), data);
+ tx_put = (tx_put + 1) & (tx_bufsize - 1);
+ info->x_char = 0;
+ char_count--;
+ info->icount.tx++;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
+#ifdef BLOCKMOVE
+ while(0 < (small_count =
+ cy_min((tx_bufsize - tx_put),
+ cy_min ((SERIAL_XMIT_SIZE - info->xmit_tail),
+ cy_min(info->xmit_cnt, char_count))))){
+
+ memcpy_toio((char *)(cinfo->base_addr
+ + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put),
+ &info->xmit_buf[info->xmit_tail],
+ small_count);
+
+ tx_put = (tx_put + small_count) & (tx_bufsize - 1);
+ char_count -= small_count;
+ info->icount.tx += small_count;
+ info->xmit_cnt -= small_count;
+ info->xmit_tail =
+ (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1);
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
+#else
+ while (info->xmit_cnt && char_count){
+ data = info->xmit_buf[info->xmit_tail];
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
+
+ cy_writeb(cinfo->base_addr +
+ cy_readl(&buf_ctrl->tx_bufaddr) + tx_put, data);
+ tx_put = (tx_put + 1) & (tx_bufsize - 1);
+ char_count--;
+ info->icount.tx++;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
#endif
+ ztxdone:
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
+ /* Update tx_put */
+ cy_writel(&buf_ctrl->tx_put, tx_put);
+ }
+}
-#ifdef CONFIG_CYZ_INTR
static void
-cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+cyz_handle_cmd(struct cyclades_card *cinfo)
{
struct tty_struct *tty;
- struct cyclades_card *cinfo;
struct cyclades_port *info;
static volatile struct FIRM_ID *firm_id;
static volatile struct ZFW_CTRL *zfw_ctrl;
@@ -1665,541 +1788,200 @@ cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ucchar cmd;
uclong param;
uclong hw_ver, fw_ver;
- char data;
- volatile int char_count, special_count;
-#ifdef BLOCKMOVE
- int small_count;
-#endif
- volatile uclong tx_put, tx_get, tx_bufsize;
- volatile uclong rx_put, rx_get, rx_bufsize;
-
- if((cinfo = (struct cyclades_card *)dev_id) == 0){
-#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
-#endif
- return; /* spurious interrupt */
- }
+ int special_count;
+ int delta_count;
- firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
- if (!ISZLOADED(*cinfo)) {
-#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: board not yet loaded (INT %d).\n\r", irq);
-#endif
- return;
+ firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+ zfw_ctrl = (struct ZFW_CTRL *)
+ (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
+ board_ctrl = &(zfw_ctrl->board_ctrl);
+ fw_ver = cy_readl(&board_ctrl->fw_version);
+ hw_ver = cy_readl(&((struct RUNTIME_9060 *)(cinfo->ctl_addr))->mail_box_0);
+
+ while(cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
+ special_count = 0;
+ delta_count = 0;
+ info = &cy_port[channel + cinfo->first_line];
+ if((tty = info->tty) == 0) {
+ continue;
}
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
- zfw_ctrl = (struct ZFW_CTRL *)
- (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
- board_ctrl = &(zfw_ctrl->board_ctrl);
- fw_ver = cy_readl(&board_ctrl->fw_version);
- hw_ver = cy_readl(&((struct RUNTIME_9060 *)
- (cinfo->ctl_addr))->mail_box_0);
-
- while(cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
- special_count = 0;
- info = &cy_port[channel + cinfo->first_line];
- if((tty = info->tty) == 0) continue;
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
-
- switch(cmd){
+ switch(cmd) {
case C_CM_PR_ERROR:
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_PARITY;
*tty->flip.char_buf_ptr++ = 0;
+ info->icount.rx++;
special_count++;
- break;
+ break;
case C_CM_FR_ERROR:
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_FRAME;
*tty->flip.char_buf_ptr++ = 0;
+ info->icount.rx++;
special_count++;
- break;
+ break;
case C_CM_RXBRK:
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_BREAK;
*tty->flip.char_buf_ptr++ = 0;
+ info->icount.rx++;
special_count++;
- break;
+ break;
case C_CM_MDCD:
+ info->icount.dcd++;
+ delta_count++;
if (info->flags & ASYNC_CHECK_CD){
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);
+ ((u_long)param) :
+ cy_readl(&ch_ctrl->rs_status)) & C_RS_DCD) {
+ cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
+ }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE)
+ &&(info->flags & ASYNC_CALLOUT_NOHUP))){
+ cy_sched_event(info, Cy_EVENT_HANGUP);
}
}
- break;
+ break;
case C_CM_MCTS:
- if (info->flags & ASYNC_CTS_FLOW) {
- if(info->tty->hw_stopped){
- 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);
- }
- }else{
- 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"); */
- }
- }
- }
- break;
+ info->icount.cts++;
+ delta_count++;
+ break;
case C_CM_MRI:
- break;
+ info->icount.rng++;
+ delta_count++;
+ break;
case C_CM_MDSR:
- break;
+ info->icount.dsr++;
+ delta_count++;
+ break;
#ifdef Z_WAKE
case C_CM_IOCTLW:
cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
- break;
+ break;
#endif
+#ifdef CONFIG_CYZ_INTR
case C_CM_RXHIWM:
case C_CM_RXNNDT:
+ case C_CM_INTBACK2:
/* Reception Interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: rcvd intr, card %d, port %ld\n\r",
- info->card, channel);
+ printk("cyz_interrupt: rcvd intr, card %d, port %ld\n\r",
+ info->card, channel);
#endif
-
- rx_get = cy_readl(&buf_ctrl->rx_get);
- rx_put = cy_readl(&buf_ctrl->rx_put);
- rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
- if (rx_put >= rx_get)
- char_count = rx_put - rx_get;
- else
- char_count = rx_put - rx_get + rx_bufsize;
-
- if ( char_count ){
-
-#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
- /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
- for performance, but because of buffer boundaries, there
- may be several steps to the operation */
- while(0 < (small_count
- = cy_min((rx_bufsize - rx_get),
- cy_min((TTY_FLIPBUF_SIZE - tty->flip.count),
- char_count)))){
-
- memcpy_fromio(tty->flip.char_buf_ptr,
- (char *)(cinfo->base_addr
- + cy_readl(&buf_ctrl->rx_bufaddr)
- + rx_get),
- small_count);
-
- tty->flip.char_buf_ptr += small_count;
- memset(tty->flip.flag_buf_ptr,
- TTY_NORMAL,
- small_count);
- tty->flip.flag_buf_ptr += small_count;
- rx_get = (rx_get + small_count) & (rx_bufsize - 1);
- char_count -= small_count;
- tty->flip.count += small_count;
- }
-#else
- while(char_count--){
- if (tty->flip.count >= TTY_FLIPBUF_SIZE){
- break;
- }
- data = cy_readb(cinfo->base_addr +
- cy_readl(&buf_ctrl->rx_bufaddr) + rx_get);
- rx_get = (rx_get + 1) & (rx_bufsize - 1);
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = data;
- }
-#endif
- queue_task(&tty->flip.tqueue, &tq_timer);
- }
- /* Update rx_get */
- cy_writel(&buf_ctrl->rx_get, rx_get);
- }
+ cyz_handle_rx(info, buf_ctrl);
break;
case C_CM_TXBEMPTY:
case C_CM_TXLOWWM:
case C_CM_INTBACK:
/* Transmission Interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: xmit intr, card %d, port %ld\n\r",
- info->card, channel);
+ printk("cyz_interrupt: xmit intr, card %d, port %ld\n\r",
+ info->card, channel);
#endif
-
- tx_get = cy_readl(&buf_ctrl->tx_get);
- tx_put = cy_readl(&buf_ctrl->tx_put);
- tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
- if (tx_put >= tx_get)
- char_count = tx_get - tx_put - 1 + tx_bufsize;
- else
- char_count = tx_get - tx_put - 1;
-
- if ( char_count ){
-
- if( tty == 0 ){
- goto ztxdone;
- }
-
- if(info->x_char) { /* send special char */
- data = info->x_char;
-
- cy_writeb((cinfo->base_addr +
- cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), data);
- tx_put = (tx_put + 1) & (tx_bufsize - 1);
- info->x_char = 0;
- char_count--;
- }
-#ifdef BLOCKMOVE
- while(0 < (small_count
- = cy_min((tx_bufsize - tx_put),
- cy_min ((SERIAL_XMIT_SIZE - info->xmit_tail),
- cy_min(info->xmit_cnt, char_count))))){
-
- memcpy_toio((char *)(cinfo->base_addr
- + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put),
- &info->xmit_buf[info->xmit_tail],
- small_count);
-
- tx_put = (tx_put + small_count) & (tx_bufsize - 1);
- char_count -= small_count;
- info->xmit_cnt -= small_count;
- info->xmit_tail =
- (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1);
- }
-#else
- while (info->xmit_cnt && char_count){
- data = info->xmit_buf[info->xmit_tail];
- info->xmit_cnt--;
- info->xmit_tail =
- (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
-
- cy_writeb(cinfo->base_addr +
- cy_readl(&buf_ctrl->tx_bufaddr) + tx_put,
- data);
- tx_put = (tx_put + 1) & (tx_bufsize - 1);
- char_count--;
- }
-
-#endif
- ztxdone:
- if (info->xmit_cnt < WAKEUP_CHARS) {
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
- }
- /* Update tx_put */
- cy_writel(&buf_ctrl->tx_put, tx_put);
- }
+ cyz_handle_tx(info, buf_ctrl);
break;
+#endif /* CONFIG_CYZ_INTR */
case C_CM_FATAL:
/* should do something with this !!! */
- break;
- }
- if(special_count){
- queue_task(&tty->flip.tqueue, &tq_timer);
- }
+ break;
+ default:
+ break;
}
+ if(delta_count)
+ cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
+ if(special_count)
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ }
+}
+
+#ifdef CONFIG_CYZ_INTR
+static void
+cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct cyclades_card *cinfo;
+
+ if((cinfo = (struct cyclades_card *)dev_id) == 0){
+#ifdef CY_DEBUG_INTERRUPTS
+ printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
+#endif
+ return; /* spurious interrupt */
+ }
+
+ if (!ISZLOADED(*cinfo)) {
+#ifdef CY_DEBUG_INTERRUPTS
+ printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq);
+#endif
+ return;
+ }
+
+ /* Handle the interrupts */
+ cyz_handle_cmd(cinfo);
return;
} /* cyz_interrupt */
+static void
+cyz_rx_restart(unsigned long arg)
+{
+ struct cyclades_port *info = (struct cyclades_port *)arg;
+ int retval;
+ int card = info->card;
+ uclong channel = (info->line) - (cy_card[card].first_line);
+
+ cyz_rx_full_timer[info->card].expires = jiffies + HZ;
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L);
+ if (retval != 0){
+ printk("cyc:cyz_rx_restart retval was %x\n", retval);
+ }
+}
+
#else /* CONFIG_CYZ_INTR */
static void
cyz_poll(unsigned long arg)
{
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info;
+ struct tty_struct *tty;
static volatile struct FIRM_ID *firm_id;
static volatile struct ZFW_CTRL *zfw_ctrl;
static volatile struct BOARD_CTRL *board_ctrl;
static volatile struct CH_CTRL *ch_ctrl;
static volatile struct BUF_CTRL *buf_ctrl;
- struct cyclades_card *cinfo;
- struct cyclades_port *info;
- struct tty_struct *tty;
int card, port;
- int char_count;
-#ifdef BLOCKMOVE
- int small_count;
-#endif
- char data;
- uclong channel;
- ucchar cmd;
- uclong param;
- uclong hw_ver, fw_ver;
- volatile uclong tx_put, tx_get, tx_bufsize;
- volatile uclong rx_put, rx_get, rx_bufsize;
cyz_timerlist.expires = jiffies + (HZ);
for (card = 0 ; card < NR_CARDS ; card++){
cinfo = &cy_card[card];
- if (!IS_CYC_Z(*cinfo)) continue;
+ if (!IS_CYC_Z(*cinfo)) continue;
+ if (!ISZLOADED(*cinfo)) continue;
- firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
- if (!ISZLOADED(*cinfo)) {
+ /* Skip first polling cycle to avoid racing conditions with the FW */
+ if (!cinfo->intr_enabled) {
+ cinfo->intr_enabled = 1;
continue;
}
+ firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
zfw_ctrl = (struct ZFW_CTRL *)
- (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
+ (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
board_ctrl = &(zfw_ctrl->board_ctrl);
- fw_ver = cy_readl(&board_ctrl->fw_version);
- hw_ver = cy_readl(&((struct RUNTIME_9060 *)
- (cinfo->ctl_addr))->mail_box_0);
-
- while(cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1){
- char_count = 0;
- info = &cy_port[ channel + cinfo->first_line ];
- if((tty = info->tty) == 0) continue;
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
- info->jiffies[0] = jiffies;
-
- switch(cmd){
- case C_CM_PR_ERROR:
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
- *tty->flip.char_buf_ptr++ = 0;
- char_count++;
- break;
- case C_CM_FR_ERROR:
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
- *tty->flip.char_buf_ptr++ = 0;
- char_count++;
- break;
- case C_CM_RXBRK:
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
- *tty->flip.char_buf_ptr++ = 0;
- char_count++;
- break;
- case C_CM_MDCD:
- if (info->flags & ASYNC_CHECK_CD){
- if ((fw_ver > 241 ?
- ((u_long)param) :
- cy_readl(&ch_ctrl[channel].rs_status)) & C_RS_DCD) {
- cy_sched_event(info,
- Cy_EVENT_OPEN_WAKEUP);
- }else if(!((info->flags
- & ASYNC_CALLOUT_ACTIVE)
- &&(info->flags
- & ASYNC_CALLOUT_NOHUP))){
- cy_sched_event(info,
- Cy_EVENT_HANGUP);
- }
- }
- break;
- case C_CM_MCTS:
- if (info->flags & ASYNC_CTS_FLOW) {
- if(info->tty->hw_stopped){
- if( cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD){
- /* cy_start isn't used because...
- HW flow is handled by the board */
- cy_sched_event(info,
- Cy_EVENT_WRITE_WAKEUP);
- }
- }else{
- if(!(cy_readl(&ch_ctrl[channel].rs_status) & C_RS_CTS)){
- /* cy_stop isn't used because
- HW flow is handled by the board */
- }
- }
- }
- break;
- case C_CM_MRI:
- break;
- case C_CM_MDSR:
- break;
-#ifdef Z_WAKE
- case C_CM_IOCTLW:
- cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
- break;
-#endif
- case C_CM_FATAL:
- /* should do something with this !!! */
- break;
- }
- if(char_count){
- queue_task(&tty->flip.tqueue, &tq_timer);
- }
- }
+
+ cyz_handle_cmd(cinfo);
+
for (port = 0; port < cy_readl(&board_ctrl->n_channel); port++){
info = &cy_port[ port + cinfo->first_line ];
tty = info->tty;
ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
-/* Removed due to compilation problems in Alpha systems */
-// if ((char_count = CHARS_IN_BUF(buf_ctrl))){
-
- rx_get = cy_readl(&buf_ctrl->rx_get);
- rx_put = cy_readl(&buf_ctrl->rx_put);
- rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
- if (rx_put >= rx_get)
- char_count = rx_put - rx_get;
- else
- char_count = rx_put - rx_get + rx_bufsize;
-
- if ( char_count ){
-
- info->last_active = jiffies;
- info->jiffies[1] = jiffies;
-
-#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);
- info->rflush_count++;
- }else{
-#ifdef BLOCKMOVE
- /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
- for performance, but because of buffer boundaries, there
- may be several steps to the operation */
- while(0 < (small_count
- = cy_min((rx_bufsize - rx_get),
- cy_min((TTY_FLIPBUF_SIZE - tty->flip.count),
- char_count)))){
-
- memcpy_fromio(tty->flip.char_buf_ptr,
- (char *)(cinfo->base_addr
- + cy_readl(&buf_ctrl->rx_bufaddr)
- + rx_get),
- small_count);
-
- tty->flip.char_buf_ptr += small_count;
- memset(tty->flip.flag_buf_ptr,
- TTY_NORMAL,
- small_count);
- tty->flip.flag_buf_ptr += small_count;
- rx_get = (rx_get + small_count) & (rx_bufsize - 1);
- char_count -= small_count;
- tty->flip.count += small_count;
- }
-#else
- while(char_count--){
- if (tty->flip.count >= TTY_FLIPBUF_SIZE){
- break;
- }
- data = cy_readb(cinfo->base_addr +
- cy_readl(&buf_ctrl->rx_bufaddr) + rx_get);
- rx_get = (rx_get + 1) & (rx_bufsize - 1);
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = data;
- }
-#endif
- queue_task(&tty->flip.tqueue, &tq_timer);
- }
- /* Update rx_get */
- cy_writel(&buf_ctrl->rx_get, rx_get);
- }
-
-/* Removed due to compilation problems in Alpha systems */
-// if ((char_count = SPACE_IN_BUF(buf_ctrl))){
-
- tx_get = cy_readl(&buf_ctrl->tx_get);
- tx_put = cy_readl(&buf_ctrl->tx_put);
- tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
- if (tx_put >= tx_get)
- char_count = tx_get - tx_put - 1 + tx_bufsize;
- else
- char_count = tx_get - tx_put - 1;
-
- if ( char_count ){
-
- if( tty == 0 ){
- goto ztxdone;
- }
-
- if(info->x_char) { /* send special char */
- data = info->x_char;
-
- cy_writeb((cinfo->base_addr +
- cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), data);
- tx_put = (tx_put + 1) & (tx_bufsize - 1);
- info->x_char = 0;
- char_count--;
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
- }
-#ifdef BLOCKMOVE
- while(0 < (small_count
- = cy_min((tx_bufsize - tx_put),
- cy_min ((SERIAL_XMIT_SIZE - info->xmit_tail),
- cy_min(info->xmit_cnt, char_count))))){
-
- memcpy_toio((char *)(cinfo->base_addr
- + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put),
- &info->xmit_buf[info->xmit_tail],
- small_count);
-
- tx_put = (tx_put + small_count) & (tx_bufsize - 1);
- char_count -= small_count;
- info->xmit_cnt -= small_count;
- info->xmit_tail =
- (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1);
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
- }
-#else
- while (info->xmit_cnt && char_count){
- data = info->xmit_buf[info->xmit_tail];
- info->xmit_cnt--;
- info->xmit_tail =
- (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
-
- cy_writeb(cinfo->base_addr +
- cy_readl(&buf_ctrl->tx_bufaddr) + tx_put,
- data);
- tx_put = (tx_put + 1) & (tx_bufsize - 1);
- char_count--;
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
- }
-
-#endif
- ztxdone:
- if (info->xmit_cnt < WAKEUP_CHARS) {
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
- }
- /* Update tx_put */
- cy_writel(&buf_ctrl->tx_put, tx_put);
- }
+ cyz_handle_rx(info, buf_ctrl);
+ cyz_handle_tx(info, buf_ctrl);
}
- /* poll every 40 ms */
+ /* poll every 'cyz_polling_cycle' period */
cyz_timerlist.expires = jiffies + cyz_polling_cycle;
}
add_timer(&cyz_timerlist);
@@ -2225,11 +2007,14 @@ startup(struct cyclades_port * info)
int card,chip,channel,index;
unsigned long page;
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+
page = get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
if (info->flags & ASYNC_INITIALIZED){
free_page(page);
@@ -2249,10 +2034,10 @@ startup(struct cyclades_port * info)
else
info->xmit_buf = (unsigned char *) page;
+ CY_UNLOCK(info, flags);
+
set_line_char(info);
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
if (!IS_CYC_Z(cy_card[card])) {
chip = channel>>2;
channel &= 0x03;
@@ -2265,6 +2050,8 @@ startup(struct cyclades_port * info)
card, chip, channel, (long)base_addr);/**/
#endif
+ CY_LOCK(info, flags);
+
cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
cy_writeb((ulong)base_addr+(CyRTPR<<index), (info->default_timeout
@@ -2297,7 +2084,7 @@ startup(struct cyclades_port * info)
info->idle_stats.recv_idle =
info->idle_stats.xmit_idle = jiffies;
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
} else {
struct FIRM_ID *firm_id;
@@ -2306,8 +2093,6 @@ startup(struct cyclades_port * info)
struct CH_CTRL *ch_ctrl;
int retval;
- restore_flags(flags);
-
base_addr = (unsigned char*) (cy_card[card].base_addr);
firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
@@ -2326,35 +2111,42 @@ startup(struct cyclades_port * info)
card, channel, (long)base_addr);/**/
#endif
+ CY_LOCK(info, flags);
+
cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
#ifdef Z_WAKE
#ifdef CONFIG_CYZ_INTR
cy_writel(&ch_ctrl[channel].intr_enable,
C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT|
C_IN_IOCTLW|
- C_IN_MDCD|C_IN_MCTS);
+ C_IN_MDCD);
#else
cy_writel(&ch_ctrl[channel].intr_enable,
C_IN_IOCTLW|
- C_IN_MDCD|C_IN_MCTS);
+ C_IN_MDCD);
#endif /* CONFIG_CYZ_INTR */
#else
#ifdef CONFIG_CYZ_INTR
cy_writel(&ch_ctrl[channel].intr_enable,
C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT|
- C_IN_MDCD|C_IN_MCTS);
+ C_IN_MDCD);
#else
cy_writel(&ch_ctrl[channel].intr_enable,
- C_IN_MDCD|C_IN_MCTS);
+ C_IN_MDCD);
#endif /* CONFIG_CYZ_INTR */
#endif /* Z_WAKE */
- retval = cyz_issue_cmd( &cy_card[card],
- channel, C_CM_IOCTL, 0L); /* was C_CM_RESET */
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
if (retval != 0){
printk("cyc:startup(1) retval was %x\n", retval);
}
+ /* Flush RX buffers before raising DTR and RTS */
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX, 0L);
+ if (retval != 0){
+ printk("cyc:startup(2) retval was %x\n", retval);
+ }
+
/* set timeout !!! */
/* set RTS and DTR !!! */
cy_writel(&ch_ctrl[channel].rs_control,
@@ -2362,7 +2154,7 @@ startup(struct cyclades_port * info)
retval = cyz_issue_cmd(&cy_card[info->card],
channel, C_CM_IOCTLM, 0L);
if (retval != 0){
- printk("cyc:startup(2) retval was %x\n", retval);
+ printk("cyc:startup(3) retval was %x\n", retval);
}
#ifdef CY_DEBUG_DTR
printk("cyc:startup raising Z DTR\n");
@@ -2380,6 +2172,8 @@ startup(struct cyclades_port * info)
info->idle_stats.in_use =
info->idle_stats.recv_idle =
info->idle_stats.xmit_idle = jiffies;
+
+ CY_UNLOCK(info, flags);
}
#ifdef CY_DEBUG_OPEN
@@ -2388,7 +2182,7 @@ startup(struct cyclades_port * info)
return 0;
errout:
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
return retval;
} /* startup */
@@ -2410,21 +2204,21 @@ start_xmit( struct cyclades_port *info )
(cy_card[card].base_addr
+ (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), channel);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
} else {
#ifdef CONFIG_CYZ_INTR
int retval;
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK, 0L);
if (retval != 0){
printk("cyc:start_xmit retval was %x\n", retval);
}
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
#else /* CONFIG_CYZ_INTR */
/* Don't have to do anything at this time */
#endif /* CONFIG_CYZ_INTR */
@@ -2461,7 +2255,10 @@ shutdown(struct cyclades_port * info)
card, chip, channel, (long)base_addr);
#endif
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
+
+ /* Clear delta_msr_wait queue to avoid mem leaks. */
+ wake_up_interruptible(&info->delta_msr_wait);
if (info->xmit_buf){
unsigned char * temp;
@@ -2488,7 +2285,7 @@ shutdown(struct cyclades_port * info)
set_bit(TTY_IO_ERROR, &info->tty->flags);
}
info->flags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
} else {
struct FIRM_ID *firm_id;
struct ZFW_CTRL *zfw_ctrl;
@@ -2513,7 +2310,7 @@ shutdown(struct cyclades_port * info)
board_ctrl = &(zfw_ctrl->board_ctrl);
ch_ctrl = zfw_ctrl->ch_ctrl;
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
if (info->xmit_buf){
unsigned char * temp;
@@ -2529,7 +2326,7 @@ shutdown(struct cyclades_port * info)
retval = cyz_issue_cmd(&cy_card[info->card],
channel, C_CM_IOCTLM, 0L);
if (retval != 0){
- printk("cyc:shutdown retval (2) was %x\n", retval);
+ printk("cyc:shutdown retval was %x\n", retval);
}
#ifdef CY_DEBUG_DTR
printk("cyc:shutdown dropping Z DTR\n");
@@ -2541,7 +2338,7 @@ shutdown(struct cyclades_port * info)
}
info->flags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
}
#ifdef CY_DEBUG_OPEN
@@ -2568,6 +2365,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
int retval;
char *base_addr;
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+
/*
* If the device is in the middle of being closed, then block
* until it's done, and then try again.
@@ -2627,18 +2427,16 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
if (!tty_hung_up_p(filp))
info->count--;
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
#ifdef CY_DEBUG_COUNT
printk("cyc block_til_ready: (%d): decrementing count to %d\n",
current->pid, info->count);
#endif
info->blocked_open++;
- cinfo = &cy_card[info->card];
- channel = info->line - cinfo->first_line;
if (!IS_CYC_Z(*cinfo)) {
chip = channel>>2;
channel &= 0x03;
@@ -2647,7 +2445,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
+ (cy_chip_offset[chip]<<index));
while (1) {
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
(tty->termios->c_cflag & CBAUD)){
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
@@ -2660,24 +2458,27 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
cy_readb(base_addr+(CyMSVR2<<index)));
#endif
}
- restore_flags(flags);
- current->state = TASK_INTERRUPTIBLE;
+ CY_UNLOCK(info, flags);
+
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp)
|| !(info->flags & ASYNC_INITIALIZED) ){
- return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
break;
}
- save_flags(flags); cli();
+
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
&& !(info->flags & ASYNC_CLOSING)
&& (C_CLOCAL(tty)
|| (cy_readb(base_addr+(CyMSVR1<<index)) & CyDCD))) {
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
break;
}
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
+
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
@@ -2720,10 +2521,10 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
printk("cyc:block_til_ready raising Z DTR\n");
#endif
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp)
|| !(info->flags & ASYNC_INITIALIZED) ){
- return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
break;
}
@@ -2813,6 +2614,10 @@ cy_open(struct tty_struct *tty, struct file * filp)
interrupts should be enabled as soon as the first open happens
to one of its ports. */
if (!cy_card[info->card].intr_enabled) {
+ /* Enable interrupts on the PLX chip */
+ cy_writew(cy_card[info->card].ctl_addr+0x68,
+ cy_readw(cy_card[info->card].ctl_addr+0x68)|0x0900);
+ /* Enable interrupts on the FW */
retval = cyz_issue_cmd(&cy_card[info->card],
0, C_CM_IRQ_ENBL, 0L);
if (retval != 0){
@@ -2897,7 +2702,8 @@ 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)
+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;
@@ -2979,9 +2785,9 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
* This routine is called when a particular tty device is closed.
*/
static void
-cy_close(struct tty_struct * tty, struct file * filp)
+cy_close(struct tty_struct *tty, struct file *filp)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
@@ -2992,12 +2798,11 @@ cy_close(struct tty_struct * tty, struct file * filp)
return;
}
- save_flags(flags); cli();
-
+ CY_LOCK(info, flags);
/* If the TTY is being hung up, nothing to do */
if (tty_hung_up_p(filp)) {
MOD_DEC_USE_COUNT;
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
return;
}
@@ -3028,7 +2833,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
}
if (info->count) {
MOD_DEC_USE_COUNT;
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
return;
}
info->flags |= ASYNC_CLOSING;
@@ -3046,9 +2851,11 @@ cy_close(struct tty_struct * tty, struct file * filp)
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
+ CY_UNLOCK(info, flags);
if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
tty_wait_until_sent(tty, info->closing_wait);
}
+ CY_LOCK(info, flags);
if (!IS_CYC_Z(cy_card[info->card])) {
int channel = info->line - cy_card[info->card].first_line;
@@ -3064,7 +2871,9 @@ cy_close(struct tty_struct * tty, struct file * filp)
if (info->flags & ASYNC_INITIALIZED) {
/* Waiting for on-board buffers to be empty before closing
the port */
+ CY_UNLOCK(info, flags);
cy_wait_until_sent(tty, info->timeout);
+ CY_LOCK(info, flags);
}
} else {
#ifdef Z_WAKE
@@ -3082,27 +2891,34 @@ cy_close(struct tty_struct * tty, struct file * filp)
retval = cyz_issue_cmd(&cy_card[info->card], channel,
C_CM_IOCTLW, 0L);
if (retval != 0){
- printk("cyc:shutdown retval (1) was %x\n", retval);
+ printk("cyc:cy_close retval was %x\n", retval);
}
+ CY_UNLOCK(info, flags);
interruptible_sleep_on(&info->shutdown_wait);
+ CY_LOCK(info, flags);
}
#endif
}
+ CY_UNLOCK(info, flags);
shutdown(info);
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
+ CY_LOCK(info, flags);
+
tty->closing = 0;
info->event = 0;
info->tty = 0;
if (info->blocked_open) {
+ CY_UNLOCK(info, flags);
if (info->close_delay) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(info->close_delay);
}
wake_up_interruptible(&info->open_wait);
+ CY_LOCK(info, flags);
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
ASYNC_CLOSING);
@@ -3113,7 +2929,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
#endif
MOD_DEC_USE_COUNT;
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
return;
} /* cy_close */
@@ -3151,8 +2967,7 @@ cy_write(struct tty_struct * tty, int from_user,
return 0;
}
- save_flags(flags);
-
+ CY_LOCK(info, flags);
if (from_user) {
down(&tmp_buf_sem);
while (1) {
@@ -3168,13 +2983,11 @@ cy_write(struct tty_struct * tty, int from_user,
}
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;
@@ -3182,22 +2995,20 @@ cy_write(struct tty_struct * tty, int from_user,
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;
}
}
+ CY_UNLOCK(info, flags);
info->idle_stats.xmit_bytes += ret;
info->idle_stats.xmit_idle = jiffies;
@@ -3232,9 +3043,9 @@ cy_put_char(struct tty_struct *tty, unsigned char ch)
if (!tty || !info->xmit_buf)
return;
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
return;
}
@@ -3243,7 +3054,7 @@ cy_put_char(struct tty_struct *tty, unsigned char ch)
info->xmit_cnt++;
info->idle_stats.xmit_bytes++;
info->idle_stats.xmit_idle = jiffies;
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
} /* cy_put_char */
@@ -3255,9 +3066,6 @@ static void
cy_flush_chars(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- unsigned char *base_addr;
- int card,chip,channel,index;
#ifdef CY_DEBUG_IO
printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
@@ -3270,25 +3078,7 @@ cy_flush_chars(struct tty_struct *tty)
|| tty->hw_stopped || !info->xmit_buf)
return;
- 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));
-
- save_flags(flags); cli();
- cy_writeb((u_long)base_addr+(CyCAR<<index), channel);
- cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
- restore_flags(flags);
- } else {
- /* Since polling is already in place,
- nothing further need be done. */
- }
+ start_xmit(info);
} /* cy_flush_chars */
@@ -3397,6 +3187,20 @@ set_line_char(struct cyclades_port * info)
cflag = info->tty->termios->c_cflag;
iflag = info->tty->termios->c_iflag;
+ /*
+ * 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;
+ }
+
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
chip_number = channel / 4;
@@ -3406,7 +3210,11 @@ set_line_char(struct cyclades_port * info)
index = cy_card[card].bus_index;
/* baud rate */
- baud = tty_get_baud_rate(info->tty);
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
+ baud = info->baud;
+ } else {
+ baud = tty_get_baud_rate(info->tty);
+ }
if (baud > CD1400_MAX_SPEED) {
baud = CD1400_MAX_SPEED;
}
@@ -3509,7 +3317,7 @@ set_line_char(struct cyclades_port * info)
(cy_card[card].base_addr
+ (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
/* tx and rx baud rate */
@@ -3599,14 +3407,15 @@ set_line_char(struct cyclades_port * info)
if (info->tty){
clear_bit(TTY_IO_ERROR, &info->tty->flags);
}
+ CY_UNLOCK(info, flags);
- restore_flags(flags);
} else {
struct FIRM_ID *firm_id;
struct ZFW_CTRL *zfw_ctrl;
struct BOARD_CTRL *board_ctrl;
struct CH_CTRL *ch_ctrl;
struct BUF_CTRL *buf_ctrl;
+ uclong sw_flow;
int retval;
firm_id = (struct FIRM_ID *)
@@ -3622,9 +3431,13 @@ set_line_char(struct cyclades_port * info)
buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
/* baud rate */
- baud = tty_get_baud_rate(info->tty);
- if (baud > CD1400_MAX_SPEED) {
- baud = CD1400_MAX_SPEED;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
+ baud = info->baud;
+ } else {
+ baud = tty_get_baud_rate(info->tty);
+ }
+ if (baud > CYZ_MAX_SPEED) {
+ baud = CYZ_MAX_SPEED;
}
cy_writel(&ch_ctrl->comm_baud , baud);
@@ -3664,14 +3477,24 @@ set_line_char(struct cyclades_port * info)
/* CTS flow control flag */
if (cflag & CRTSCTS){
- info->flags |= ASYNC_CTS_FLOW;
cy_writel(&ch_ctrl->hw_flow,
cy_readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
}else{
- info->flags &= ~ASYNC_CTS_FLOW;
cy_writel(&ch_ctrl->hw_flow,
cy_readl(&ch_ctrl->hw_flow) & ~(C_RS_CTS | C_RS_RTS));
}
+ /* As the HW flow control is done in firmware, the driver doesn't
+ need to care about it */
+ info->flags &= ~ASYNC_CTS_FLOW;
+
+ /* XON/XOFF/XANY flow control flags */
+ sw_flow = 0;
+ if (iflag & IXON){
+ sw_flow |= C_FL_OXX;
+ if (iflag & IXANY)
+ sw_flow |= C_FL_OIXANY;
+ }
+ cy_writel(&ch_ctrl->sw_flow, sw_flow);
retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
if (retval != 0){
@@ -3686,14 +3509,6 @@ set_line_char(struct cyclades_port * info)
info->flags |= ASYNC_CHECK_CD;
}
- if (iflag & IXON){
- cy_writel(&ch_ctrl->sw_flow,
- cy_readl(&ch_ctrl->sw_flow) | C_FL_OXX);
- } else {
- cy_writel(&ch_ctrl->sw_flow,
- cy_readl(&ch_ctrl->sw_flow) & ~C_FL_OXX);
- }
-
if(baud == 0){ /* baud rate is zero, turn off line */
cy_writel(&ch_ctrl->rs_control,
cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
@@ -3719,20 +3534,6 @@ 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 */
@@ -3829,12 +3630,11 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
(cy_card[card].base_addr
+ (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
status = cy_readb(base_addr+(CyMSVR1<<index));
status |= cy_readb(base_addr+(CyMSVR2<<index));
- restore_flags(flags);
-
+ CY_UNLOCK(info, flags);
if (info->rtsdtr_inv) {
result = ((status & CyRTS) ? TIOCM_DTR : 0)
@@ -3874,7 +3674,7 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
}
}
- return cy_put_user(result,(unsigned long *) value);
+ return cy_put_user(result, value);
} /* get_modem_info */
@@ -3905,17 +3705,17 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
switch (cmd) {
case TIOCMBIS:
if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (info->rtsdtr_inv) {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
} else {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
}
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
}
if (arg & TIOCM_DTR){
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (info->rtsdtr_inv) {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
@@ -3928,12 +3728,12 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
cy_readb(base_addr+(CyMSVR1<<index)),
cy_readb(base_addr+(CyMSVR2<<index)));
#endif
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
}
break;
case TIOCMBIC:
if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index),
(u_char)channel);
if (info->rtsdtr_inv) {
@@ -3941,10 +3741,10 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
} else {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
}
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
}
if (arg & TIOCM_DTR){
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (info->rtsdtr_inv) {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
@@ -3957,31 +3757,31 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
cy_readb(base_addr+(CyMSVR1<<index)),
cy_readb(base_addr+(CyMSVR2<<index)));
#endif
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
}
break;
case TIOCMSET:
if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (info->rtsdtr_inv) {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
} else {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
}
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
}else{
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (info->rtsdtr_inv) {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
} else {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
}
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
}
if (arg & TIOCM_DTR){
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (info->rtsdtr_inv) {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
@@ -3994,9 +3794,9 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
cy_readb(base_addr+(CyMSVR1<<index)),
cy_readb(base_addr+(CyMSVR2<<index)));
#endif
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
}else{
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (info->rtsdtr_inv) {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
@@ -4010,7 +3810,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
cy_readb(base_addr+(CyMSVR1<<index)),
cy_readb(base_addr+(CyMSVR2<<index)));
#endif
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
}
break;
default:
@@ -4030,50 +3830,66 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
switch (cmd) {
case TIOCMBIS:
if (arg & TIOCM_RTS){
+ CY_LOCK(info, flags);
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS);
+ CY_UNLOCK(info, flags);
}
if (arg & TIOCM_DTR){
+ CY_LOCK(info, flags);
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info raising Z DTR\n");
#endif
+ CY_UNLOCK(info, flags);
}
break;
case TIOCMBIC:
if (arg & TIOCM_RTS){
+ CY_LOCK(info, flags);
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS);
+ CY_UNLOCK(info, flags);
}
if (arg & TIOCM_DTR){
+ CY_LOCK(info, flags);
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info clearing Z DTR\n");
#endif
+ CY_UNLOCK(info, flags);
}
break;
case TIOCMSET:
if (arg & TIOCM_RTS){
+ CY_LOCK(info, flags);
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS);
+ CY_UNLOCK(info, flags);
}else{
+ CY_LOCK(info, flags);
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS);
+ CY_UNLOCK(info, flags);
}
if (arg & TIOCM_DTR){
+ CY_LOCK(info, flags);
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info raising Z DTR\n");
#endif
+ CY_UNLOCK(info, flags);
}else{
+ CY_LOCK(info, flags);
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info clearing Z DTR\n");
#endif
+ CY_UNLOCK(info, flags);
}
break;
default:
@@ -4082,12 +3898,14 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
}else{
return -ENODEV;
}
+ CY_LOCK(info, flags);
retval = cyz_issue_cmd(&cy_card[info->card],
channel, C_CM_IOCTLM,0L);
if (retval != 0){
printk("cyc:set_modem_info retval at %d was %x\n",
__LINE__, retval);
}
+ CY_UNLOCK(info, flags);
}
return 0;
} /* set_modem_info */
@@ -4104,7 +3922,7 @@ cy_break(struct tty_struct *tty, int break_state)
if (serial_paranoia_check(info, tty->device, "cy_break"))
return;
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
if (!IS_CYC_Z(cy_card[info->card])) {
/* Let the transmit ISR take care of this (since it
requires stuffing characters into the output stream).
@@ -4113,14 +3931,18 @@ cy_break(struct tty_struct *tty, int break_state)
if (!info->breakon) {
info->breakon = 1;
if (!info->xmit_cnt) {
+ CY_UNLOCK(info, flags);
start_xmit(info);
+ CY_LOCK(info, flags);
}
}
} else {
if (!info->breakoff) {
info->breakoff = 1;
if (!info->xmit_cnt) {
+ CY_UNLOCK(info, flags);
start_xmit(info);
+ CY_LOCK(info, flags);
}
}
}
@@ -4145,8 +3967,7 @@ cy_break(struct tty_struct *tty, int break_state)
}
}
}
- restore_flags(flags);
-
+ CY_UNLOCK(info, flags);
} /* cy_break */
static int
@@ -4168,6 +3989,7 @@ set_threshold(struct cyclades_port * info, unsigned long value)
{
unsigned char *base_addr;
int card,channel,chip,index;
+ unsigned long flags;
card = info->card;
channel = info->line - cy_card[card].first_line;
@@ -4181,8 +4003,11 @@ set_threshold(struct cyclades_port * info, unsigned long value)
info->cor3 &= ~CyREC_FIFO;
info->cor3 |= value & CyREC_FIFO;
- cy_writeb((u_long)base_addr+(CyCOR3<<index), info->cor3);
- cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
+
+ CY_LOCK(info, flags);
+ cy_writeb((u_long)base_addr+(CyCOR3<<index), info->cor3);
+ cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
+ CY_UNLOCK(info, flags);
} else {
// Nothing to do!
}
@@ -4236,6 +4061,7 @@ set_timeout(struct cyclades_port * info, unsigned long value)
{
unsigned char *base_addr;
int card,channel,chip,index;
+ unsigned long flags;
card = info->card;
channel = info->line - cy_card[card].first_line;
@@ -4247,7 +4073,9 @@ set_timeout(struct cyclades_port * info, unsigned long value)
(cy_card[card].base_addr
+ (cy_chip_offset[chip]<<index));
- cy_writeb((u_long)base_addr+(CyRTPR<<index), value & 0xff);
+ CY_LOCK(info, flags);
+ cy_writeb((u_long)base_addr+(CyRTPR<<index), value & 0xff);
+ CY_UNLOCK(info, flags);
} else {
// Nothing to do!
}
@@ -4305,7 +4133,10 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct *p_cuser; /* user space */
int ret_val = 0;
+ unsigned long flags;
if (serial_paranoia_check(info, tty->device, "cy_ioctl"))
return -ENODEV;
@@ -4361,6 +4192,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
if (copy_to_user((void *)arg, (void *)&cy_card[info->card],
sizeof (struct cyclades_card))) {
ret_val = -EFAULT;
+ break;
}
ret_val = 0;
break;
@@ -4397,6 +4229,77 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
case TIOCSSERIAL:
ret_val = set_serial_info(info, (struct serial_struct *) arg);
break;
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ CY_LOCK(info, flags);
+ /* note the counters on entry */
+ cprev = info->icount;
+ CY_UNLOCK(info, flags);
+ while (1) {
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current)) {
+ return -ERESTARTSYS;
+ }
+
+ CY_LOCK(info, flags);
+ cnow = info->icount; /* atomic copy */
+ CY_UNLOCK(info, flags);
+
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+ return -EIO; /* no change => error */
+ }
+ if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+ return 0;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ CY_LOCK(info, flags);
+ cnow = info->icount;
+ CY_UNLOCK(info, flags);
+ p_cuser = (struct serial_icounter_struct *) arg;
+ ret_val = put_user(cnow.cts, &p_cuser->cts);
+ if (ret_val) return ret_val;
+ ret_val = put_user(cnow.dsr, &p_cuser->dsr);
+ if (ret_val) return ret_val;
+ ret_val = put_user(cnow.rng, &p_cuser->rng);
+ if (ret_val) return ret_val;
+ ret_val = put_user(cnow.dcd, &p_cuser->dcd);
+ if (ret_val) return ret_val;
+ ret_val = put_user(cnow.rx, &p_cuser->rx);
+ if (ret_val) return ret_val;
+ ret_val = put_user(cnow.tx, &p_cuser->tx);
+ if (ret_val) return ret_val;
+ ret_val = put_user(cnow.frame, &p_cuser->frame);
+ if (ret_val) return ret_val;
+ ret_val = put_user(cnow.overrun, &p_cuser->overrun);
+ if (ret_val) return ret_val;
+ ret_val = put_user(cnow.parity, &p_cuser->parity);
+ if (ret_val) return ret_val;
+ ret_val = put_user(cnow.brk, &p_cuser->brk);
+ if (ret_val) return ret_val;
+ ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
+ if (ret_val) return ret_val;
+ ret_val = 0;
+ break;
default:
ret_val = -ENOIOCTLCMD;
}
@@ -4424,7 +4327,9 @@ cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
printk("cyc:cy_set_termios ttyC%d\n", info->line);
#endif
- if (tty->termios->c_cflag == old_termios->c_cflag)
+ if ((tty->termios->c_cflag == old_termios->c_cflag) &&
+ ((tty->termios->c_iflag & (IXON|IXANY)) ==
+ (old_termios->c_iflag & (IXON|IXANY))))
return;
set_line_char(info);
@@ -4487,14 +4392,14 @@ cy_throttle(struct tty_struct * tty)
(cy_card[card].base_addr
+ (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (info->rtsdtr_inv) {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
} else {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
}
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
} else {
// Nothing to do!
}
@@ -4546,14 +4451,14 @@ cy_unthrottle(struct tty_struct * tty)
(cy_card[card].base_addr
+ (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (info->rtsdtr_inv) {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
} else {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
}
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
}else{
// Nothing to do!
}
@@ -4591,12 +4496,12 @@ cy_stop(struct tty_struct *tty)
(cy_card[info->card].base_addr
+ (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index),
(u_char)(channel & 0x0003)); /* index channel */
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
} else {
// Nothing to do!
}
@@ -4631,12 +4536,12 @@ cy_start(struct tty_struct *tty)
(cy_card[info->card].base_addr
+ (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
cy_writeb((u_long)base_addr+(CyCAR<<index),
(u_char)(channel & 0x0003)); /* index channel */
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
} else {
// Nothing to do!
}
@@ -4658,19 +4563,22 @@ cy_flush_buffer(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
return;
- save_flags(flags); cli();
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- restore_flags(flags);
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
+ CY_LOCK(info, flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ CY_UNLOCK(info, flags);
+
if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board
buffers as well */
+ CY_LOCK(info, flags);
retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
if (retval != 0) {
printk("cyc: flush_buffer retval was %x\n", retval);
}
+ CY_UNLOCK(info, flags);
}
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
@@ -4717,7 +4625,7 @@ cy_hangup(struct tty_struct *tty)
/* initialize chips on Cyclom-Y card -- return number of valid
chips (which is number of ports/4) */
-static unsigned short __init
+static unsigned short __init
cyy_init_card(volatile ucchar *true_base_addr,int index)
{
unsigned int chip_number;
@@ -4803,14 +4711,30 @@ cyy_init_card(volatile ucchar *true_base_addr,int index)
* sets global variables and return the number of ISA boards found.
* ---------------------------------------------------------------------
*/
-static int __init cy_detect_isa(void)
+static int __init
+cy_detect_isa(void)
{
unsigned short cy_isa_irq,nboard;
volatile ucchar *cy_isa_address;
unsigned short i,j,cy_isa_nchan;
+#ifdef MODULE
+ int isparam = 0;
+#endif
nboard = 0;
+#ifdef MODULE
+ /* Check for module parameters */
+ for(i = 0 ; i < NR_CARDS; i++) {
+ if (maddr[i] || i) {
+ isparam = 1;
+ cy_isa_addresses[i] = (ucchar *)maddr[i];
+ }
+ if (!maddr[i])
+ break;
+ }
+#endif
+
/* scan the address table probing for Cyclom-Y/ISA boards */
for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
cy_isa_address = cy_isa_addresses[i];
@@ -4829,8 +4753,13 @@ static int __init cy_detect_isa(void)
continue;
}
+#ifdef MODULE
+ if (isparam && irq[i])
+ cy_isa_irq = irq[i];
+ else
+#endif
/* find out the board's irq by probing */
- cy_isa_irq = do_auto_irq(cy_isa_address);
+ cy_isa_irq = detect_isa_irq(cy_isa_address);
if (cy_isa_irq == 0) {
printk("Cyclom-Y/ISA found at 0x%lx ",
(unsigned long) cy_isa_address);
@@ -4891,7 +4820,8 @@ static int __init cy_detect_isa(void)
} /* cy_detect_isa */
#endif /* CONFIG_COBALT_27 */
-static void plx_init(uclong addr, uclong initctl)
+static void
+plx_init(uclong addr, uclong initctl)
{
/* Reset PLX */
cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
@@ -4910,7 +4840,7 @@ static void plx_init(uclong addr, uclong initctl)
* sets global variables and return the number of PCI boards found.
* ---------------------------------------------------------------------
*/
-static int __init
+static int __init
cy_detect_pci(void)
{
#ifdef CONFIG_PCI
@@ -4923,6 +4853,7 @@ cy_detect_pci(void)
unsigned short device_id,dev_index = 0;
uclong mailbox;
uclong Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
+ unsigned char Ze_irq[NR_CARDS];
if(pci_present() == 0) { /* PCI bus not present */
return(0);
@@ -4943,9 +4874,9 @@ cy_detect_pci(void)
/* read PCI configuration area */
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];
+ cy_pci_addr0 = pdev->resource[0].start;
+ cy_pci_addr1 = pdev->resource[1].start;
+ cy_pci_addr2 = pdev->resource[2].start;
pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
device_id &= ~PCI_DEVICE_ID_MASK;
@@ -4960,13 +4891,11 @@ cy_detect_pci(void)
printk("Cyclom-Y/PCI:found winaddr=0x%lx ctladdr=0x%lx\n",
(ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
#endif
- cy_pci_addr0 &= PCI_BASE_ADDRESS_MEM_MASK;
- cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
- if (cy_pci_addr2 & ~PCI_BASE_ADDRESS_IO_MASK) {
+ if (pdev->resource[2].flags & ~PCI_BASE_ADDRESS_IO_MASK) {
printk(" Warning: PCI I/O bit incorrectly set. "
"Ignoring it...\n");
- cy_pci_addr2 &= PCI_BASE_ADDRESS_IO_MASK;
+ pdev->resource[2].flags &= PCI_BASE_ADDRESS_IO_MASK;
}
#if defined(__alpha__)
@@ -5054,6 +4983,11 @@ cy_detect_pci(void)
default: /* Old boards, use PLX_9060 */
plx_init(cy_pci_addr0, 0x6c);
+ /* For some yet unknown reason, once the PLX9060 reloads
+ the EEPROM, the IRQ is lost and, thus, we have to
+ re-write it to the PCI config. registers.
+ This will remain here until we find a permanent fix. */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, cy_pci_irq);
cy_writew(cy_pci_addr0+0x68,
cy_readw(cy_pci_addr0+0x68)|0x0900);
@@ -5089,21 +5023,28 @@ cy_detect_pci(void)
printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
(ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
#endif
- cy_pci_addr0 &= PCI_BASE_ADDRESS_MEM_MASK;
#if !defined(__alpha__)
cy_pci_addr0 = (ulong)ioremap(cy_pci_addr0, CyPCI_Zctl);
#endif
+ /* Disable interrupts on the PLX before resetting it */
+ cy_writew(cy_pci_addr0+0x68,
+ cy_readw(cy_pci_addr0+0x68) & ~0x0900);
+
plx_init(cy_pci_addr0, 0x6c);
+ /* For some yet unknown reason, once the PLX9060 reloads
+ the EEPROM, the IRQ is lost and, thus, we have to
+ re-write it to the PCI config. registers.
+ This will remain here until we find a permanent fix. */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, cy_pci_irq);
mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *)
cy_pci_addr0)->mail_box_0);
- cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
- if (cy_pci_addr2 & ~PCI_BASE_ADDRESS_IO_MASK) {
+ if (pdev->resource[2].flags & ~PCI_BASE_ADDRESS_IO_MASK) {
printk(" Warning: PCI I/O bit incorrectly set. "
"Ignoring it...\n");
- cy_pci_addr2 &= PCI_BASE_ADDRESS_IO_MASK;
+ pdev->resource[2].flags &= PCI_BASE_ADDRESS_IO_MASK;
}
if (mailbox == ZE_V1) {
#if !defined(__alpha__)
@@ -5117,6 +5058,7 @@ cy_detect_pci(void)
} else {
Ze_addr0[ZeIndex] = cy_pci_addr0;
Ze_addr2[ZeIndex] = cy_pci_addr2;
+ Ze_irq[ZeIndex] = cy_pci_irq;
ZeIndex++;
}
i--;
@@ -5203,24 +5145,21 @@ cy_detect_pci(void)
cy_card[j].num_chips = -1;
/* print message */
+#ifdef CONFIG_CYZ_INTR
/* don't report IRQ if board is no IRQ */
- if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
+ if( (cy_pci_irq != 0) && (cy_pci_irq != 255) )
printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
j+1,(ulong)cy_pci_addr2,
(ulong)(cy_pci_addr2 + CyPCI_Zwin - 1),
(int)cy_pci_irq);
- }else{
+ else
+#endif /* CONFIG_CYZ_INTR */
printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
j+1,(ulong)cy_pci_addr2,
(ulong)(cy_pci_addr2 + CyPCI_Zwin - 1));
- }
+
printk("%d channels starting from port %d.\n",
cy_pci_nchan,cy_next_channel);
-#ifdef CONFIG_CYZ_INTR
- /* Enable interrupts on the PLX chip */
- cy_writew(cy_pci_addr0+0x68,
- cy_readw(cy_pci_addr0+0x68)|0x0900);
-#endif /* CONFIG_CYZ_INTR */
cy_next_channel += cy_pci_nchan;
}
}
@@ -5228,9 +5167,11 @@ cy_detect_pci(void)
for (; ZeIndex != 0 && i < NR_CARDS; i++) {
cy_pci_addr0 = Ze_addr0[0];
cy_pci_addr2 = Ze_addr2[0];
+ cy_pci_irq = Ze_irq[0];
for (j = 0 ; j < ZeIndex-1 ; j++) {
Ze_addr0[j] = Ze_addr0[j+1];
Ze_addr2[j] = Ze_addr2[j+1];
+ Ze_irq[j] = Ze_irq[j+1];
}
ZeIndex--;
mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *)
@@ -5288,24 +5229,21 @@ cy_detect_pci(void)
cy_card[j].num_chips = -1;
/* print message */
+#ifdef CONFIG_CYZ_INTR
/* don't report IRQ if board is no IRQ */
- if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
+ if( (cy_pci_irq != 0) && (cy_pci_irq != 255) )
printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
j+1,(ulong)cy_pci_addr2,
(ulong)(cy_pci_addr2 + CyPCI_Ze_win - 1),
(int)cy_pci_irq);
- }else{
+ else
+#endif /* CONFIG_CYZ_INTR */
printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
j+1,(ulong)cy_pci_addr2,
(ulong)(cy_pci_addr2 + CyPCI_Ze_win - 1));
- }
+
printk("%d channels starting from port %d.\n",
cy_pci_nchan,cy_next_channel);
-#ifdef CONFIG_CYZ_INTR
- /* Enable interrupts on the PLX chip */
- cy_writew(cy_pci_addr0+0x68,
- cy_readw(cy_pci_addr0+0x68)|0x0900);
-#endif /* CONFIG_CYZ_INTR */
cy_next_channel += cy_pci_nchan;
}
if (ZeIndex != 0) {
@@ -5414,7 +5352,7 @@ done:
extra ports are ignored.
*/
-int __init
+int __init
cy_init(void)
{
struct cyclades_port *info;
@@ -5424,9 +5362,6 @@ cy_init(void)
unsigned long mailbox;
unsigned short chip_number;
int nports;
-#ifdef CY_PROC
- struct proc_dir_entry *ent;
-#endif
init_bh(CYCLADES_BH, do_cyclades_bh);
@@ -5530,12 +5465,13 @@ 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);
nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
cinfo->intr_enabled = 0;
+ spin_lock_init(&cinfo->card_lock);
for (port = cinfo->first_line ;
port < cinfo->first_line + nports;
port++)
@@ -5563,6 +5499,11 @@ cy_init(void)
info->rco = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = CLOSING_WAIT_DELAY;
+ info->icount.cts = info->icount.dsr =
+ info->icount.rng = info->icount.dcd = 0;
+ info->icount.rx = info->icount.tx = 0;
+ info->icount.frame = info->icount.parity = 0;
+ info->icount.overrun = info->icount.brk = 0;
info->x_char = 0;
info->event = 0;
info->count = 0;
@@ -5578,9 +5519,10 @@ cy_init(void)
cy_callout_driver.init_termios;
info->normal_termios =
cy_serial_driver.init_termios;
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->shutdown_wait);
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->shutdown_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
/* info->session */
/* info->pgrp */
info->read_status_mask = 0;
@@ -5594,6 +5536,7 @@ cy_init(void)
continue;
}else{ /* Cyclom-Y of some kind*/
index = cinfo->bus_index;
+ spin_lock_init(&cinfo->card_lock);
for (port = cinfo->first_line ;
port < cinfo->first_line + 4*cinfo->num_chips ;
port++)
@@ -5613,6 +5556,11 @@ cy_init(void)
info->cor5 = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = CLOSING_WAIT_DELAY;
+ info->icount.cts = info->icount.dsr =
+ info->icount.rng = info->icount.dcd = 0;
+ info->icount.rx = info->icount.tx = 0;
+ info->icount.frame = info->icount.parity = 0;
+ info->icount.overrun = info->icount.brk = 0;
chip_number = (port - cinfo->first_line) / 4;
if ((info->chip_rev = cy_readb(cinfo->base_addr +
(cy_chip_offset[chip_number]<<index) +
@@ -5647,9 +5595,10 @@ cy_init(void)
cy_callout_driver.init_termios;
info->normal_termios =
cy_serial_driver.init_termios;
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->shutdown_wait);
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->shutdown_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
/* info->session */
/* info->pgrp */
info->read_status_mask =
@@ -5671,11 +5620,6 @@ cy_init(void)
}
#endif /* CONFIG_CYZ_INTR */
-#ifdef CY_PROC
- ent = create_proc_entry("cyclades", S_IFREG | S_IRUGO, 0);
- ent->read_proc = cyclades_get_proc_info;
-#endif
-
return 0;
} /* cy_init */
@@ -5716,23 +5660,22 @@ cleanup_module(void)
restore_flags(flags);
for (i = 0; i < NR_CARDS; i++) {
- if (cy_card[i].base_addr != 0
+ if (cy_card[i].base_addr != 0) {
+ iounmap((void *)cy_card[i].base_addr);
+ if (cy_card[i].ctl_addr != 0)
+ iounmap((void *)cy_card[i].ctl_addr);
+ if (cy_card[i].irq
#ifndef CONFIG_CYZ_INTR
- && cy_card[i].num_chips != -1 /* not a Z card */
+ && cy_card[i].num_chips != -1 /* not a Z card */
#endif /* CONFIG_CYZ_INTR */
- && cy_card[i].irq)
- {
- free_irq(cy_card[i].irq, &cy_card[i]);
+ )
+ free_irq(cy_card[i].irq, &cy_card[i]);
}
}
if (tmp_buf) {
free_page((unsigned long) tmp_buf);
tmp_buf = NULL;
}
-#ifdef CY_PROC
- remove_proc_entry("cyclades", 0);
-#endif
-
} /* cleanup_module */
#else
/* called by linux/init/main.c to parse command line options */
@@ -5796,8 +5739,7 @@ show_status(int line_num)
printk(" session pgrp open_wait = %lx %lx %lx\n",
info->session, info->pgrp, (long)info->open_wait);
-
- save_flags(flags); cli();
+ CY_LOCK(info, flags);
base_addr = (unsigned char*)
(cy_card[card].base_addr
@@ -5854,7 +5796,7 @@ show_status(int line_num)
printk(" CyTBPR %x\n", cy_readb(base_addr + CyTBPR<<index));
printk(" CyTCOR %x\n", cy_readb(base_addr + CyTCOR<<index));
- restore_flags(flags);
+ CY_UNLOCK(info, flags);
} /* show_status */
#endif
diff --git a/drivers/char/defkeymap.c b/drivers/char/defkeymap.c
index 5d8b98e55..42fae3568 100644
--- a/drivers/char/defkeymap.c
+++ b/drivers/char/defkeymap.c
@@ -1,4 +1,3 @@
-
/* Do not edit this file! It was automatically generated by */
/* loadkeys --mktable defkeymap.map > defkeymap.c */
@@ -25,7 +24,7 @@ u_short plain_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
};
-static u_short shift_map[NR_KEYS] = {
+u_short shift_map[NR_KEYS] = {
0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009,
0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
@@ -38,13 +37,13 @@ static u_short shift_map[NR_KEYS] = {
0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a,
0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116,
0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
};
-static u_short altgr_map[NR_KEYS] = {
+u_short altgr_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
@@ -57,13 +56,13 @@ static u_short altgr_map[NR_KEYS] = {
0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b,
0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516,
0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
};
-static u_short ctrl_map[NR_KEYS] = {
+u_short ctrl_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
@@ -82,7 +81,7 @@ static u_short ctrl_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
};
-static u_short shift_ctrl_map[NR_KEYS] = {
+u_short shift_ctrl_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
@@ -95,13 +94,13 @@ static u_short shift_ctrl_map[NR_KEYS] = {
0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
};
-static u_short alt_map[NR_KEYS] = {
+u_short alt_map[NR_KEYS] = {
0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809,
0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
@@ -120,7 +119,7 @@ static u_short alt_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
};
-static u_short ctrl_alt_map[NR_KEYS] = {
+u_short ctrl_alt_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
@@ -133,7 +132,7 @@ static u_short ctrl_alt_map[NR_KEYS] = {
0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a,
0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c,
0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
@@ -148,7 +147,6 @@ ushort *key_maps[MAX_NR_KEYMAPS] = {
unsigned int keymap_count = 7;
-
/*
* Philosophy: most people do not define more strings, but they who do
* often want quite a lot of string space. So, we statically allocate
@@ -186,7 +184,6 @@ char func_buf[] = {
'\033', '[', 'P', 0,
};
-
char *funcbufptr = func_buf;
int funcbufsize = sizeof(func_buf);
int funcbufleft = 0; /* space left */
@@ -236,6 +233,7 @@ struct kbdiacr accent_table[MAX_DIACR] = {
{'A', 'A', '\305'}, {'a', 'a', '\345'},
{'A', 'E', '\306'}, {'a', 'e', '\346'},
{',', 'C', '\307'}, {',', 'c', '\347'},
+ {'\'', 'C', '\307'}, {'\'', 'c', '\347'},
{'`', 'E', '\310'}, {'`', 'e', '\350'},
{'\'', 'E', '\311'}, {'\'', 'e', '\351'},
{'^', 'E', '\312'}, {'^', 'e', '\352'},
@@ -262,4 +260,4 @@ struct kbdiacr accent_table[MAX_DIACR] = {
{'s', 'z', '\337'}, {'i', 'j', '\377'},
};
-unsigned int accent_table_size = 68;
+unsigned int accent_table_size = 70;
diff --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c
index eceb50f6c..97b237ca3 100644
--- a/drivers/char/dn_keyb.c
+++ b/drivers/char/dn_keyb.c
@@ -55,7 +55,8 @@ static void debug_keyb_timer_handler(unsigned long ignored);
static u_char debug_buf1[4096],debug_buf2[4096],*debug_buf=&debug_buf1[0];
static u_char *shadow_buf=&debug_buf2[0];
static short debug_buf_count=0;
-static int debug_buf_overrun=0,debug_timer_running=0,debug_buffer_updated=0;
+static int debug_buf_overrun=0,debug_timer_running=0;
+static unsigned long debug_buffer_updated=0;
static struct timer_list debug_keyb_timer = { NULL, NULL, 0, 0,
debug_keyb_timer_handler };
#endif
@@ -280,7 +281,7 @@ static void debug_keyb_timer_handler(unsigned long ignored) {
u_char *swap;
short length,i;
- if((jiffies-debug_buffer_updated) > 100) {
+ if (time_after(jiffies, debug_buffer_updated + 100)) {
save_flags(flags);
cli();
length=debug_buf_count;
@@ -422,7 +423,7 @@ static void dn_keyb_process_key_event(unsigned char scancode) {
!(prev_scancode==DNKEY_CTRL || prev_scancode==DNKEY_LSHIFT ||
prev_scancode==DNKEY_RSHIFT || prev_scancode==DNKEY_REPT ||
prev_scancode==DNKEY_LALT || prev_scancode==DNKEY_RALT)) {
- if(jiffies-lastkeypress > DNKEY_REPEAT_DELAY) {
+ if (time_after(jiffies, lastkeypress + DNKEY_REPEAT_DELAY)) {
/* printk("handle_scancode: %02x\n",prev_scancode); */
handle_scancode(prev_scancode, 1);
}
@@ -491,8 +492,8 @@ static void dn_keyb_int(int irq, void *dummy, struct pt_regs *fp) {
debug_buf[debug_buf_count++]=data;
debug_buffer_updated=jiffies;
if(!debug_timer_running) {
- add_timer(&debug_keyb_timer);
debug_keyb_timer.expires=jiffies+10;
+ add_timer(&debug_keyb_timer);
debug_timer_running=1;
}
}
diff --git a/drivers/char/drm/.cvsignore b/drivers/char/drm/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/char/drm/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
new file mode 100644
index 000000000..d72b726c0
--- /dev/null
+++ b/drivers/char/drm/Makefile
@@ -0,0 +1,27 @@
+#
+# Makefile for the drm device driver. This driver provides support for
+# the Direct Rendering Infrastructure (DRI) in XFree86 4.x.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+
+L_TARGET := libdrm.a
+
+L_OBJS := init.o memory.o proc.o auth.o context.o drawable.o bufs.o \
+ lists.o lock.o ioctl.o fops.o vm.o dma.o
+
+M_OBJS :=
+
+ifdef CONFIG_DRM_GAMMA
+M_OBJS += gamma.o
+endif
+
+include $(TOPDIR)/Rules.make
+
+gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET)
+ $(LD) $(LD_RFLAG) -r -o $@ gamma_drv.o gamma_dma.o -L. -ldrm
diff --git a/drivers/char/drm/README.drm b/drivers/char/drm/README.drm
new file mode 100644
index 000000000..fc3c680e1
--- /dev/null
+++ b/drivers/char/drm/README.drm
@@ -0,0 +1,39 @@
+
+The Direct Rendering Manager (drm) is a device-independent kernel-level
+device driver that provides support for the XFree86 Direct Rendering
+Infrastructure (DRI).
+
+The DRM supports the Direct Rendering Infrastructure (DRI) in four major
+ways:
+
+ 1. The DRM provides synchronized access to the graphics hardware via
+ the use of an optimized two-tiered lock.
+
+ 2. The DRM enforces the DRI security policy for access to the graphics
+ hardware by only allowing authenticated X11 clients access to
+ restricted regions of memory.
+
+ 3. The DRM provides a generic DMA engine, complete with multiple
+ queues and the ability to detect the need for an OpenGL context
+ switch.
+
+ 4. The DRM is extensible via the use of small device-specific modules
+ that rely extensively on the API exported by the DRM module.
+
+
+Documentation on the DRI is available from:
+ http://precisioninsight.com/piinsights.html
+
+For specific information about kernel-level support, see:
+
+ The Direct Rendering Manager, Kernel Support for the Direct Rendering
+ Infrastructure
+ http://precisioninsight.com/dr/drm.html
+
+ Hardware Locking for the Direct Rendering Infrastructure
+ http://precisioninsight.com/dr/locking.html
+
+ A Security Analysis of the Direct Rendering Infrastructure
+ http://precisioninsight.com/dr/security.html
+
+
diff --git a/drivers/char/drm/auth.c b/drivers/char/drm/auth.c
new file mode 100644
index 000000000..2561264ff
--- /dev/null
+++ b/drivers/char/drm/auth.c
@@ -0,0 +1,161 @@
+/* auth.c -- IOCTLs for authentication -*- linux-c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:48 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/auth.c,v 1.4 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gen_ioctl.c,v 1.2 1999/06/27 14:08:27 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int drm_hash_magic(drm_magic_t magic)
+{
+ return magic & (DRM_HASH_SIZE-1);
+}
+
+static drm_file_t *drm_find_file(drm_device_t *dev, drm_magic_t magic)
+{
+ drm_file_t *retval = NULL;
+ drm_magic_entry_t *pt;
+ int hash = drm_hash_magic(magic);
+
+ down(&dev->struct_sem);
+ for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
+ if (pt->priv->authenticated) continue;
+ if (pt->magic == magic) {
+ retval = pt->priv;
+ break;
+ }
+ }
+ up(&dev->struct_sem);
+ return retval;
+}
+
+int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
+{
+ int hash;
+ drm_magic_entry_t *entry;
+
+ DRM_DEBUG("%d\n", magic);
+
+ hash = drm_hash_magic(magic);
+ entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
+ if (!entry) return -ENOMEM;
+ entry->magic = magic;
+ entry->priv = priv;
+ entry->next = NULL;
+
+ down(&dev->struct_sem);
+ if (dev->magiclist[hash].tail) {
+ dev->magiclist[hash].tail->next = entry;
+ dev->magiclist[hash].tail = entry;
+ } else {
+ dev->magiclist[hash].head = entry;
+ dev->magiclist[hash].tail = entry;
+ }
+ up(&dev->struct_sem);
+
+ return 0;
+}
+
+int drm_remove_magic(drm_device_t *dev, drm_magic_t magic)
+{
+ drm_magic_entry_t *prev = NULL;
+ drm_magic_entry_t *pt;
+ int hash;
+
+ DRM_DEBUG("%d\n", magic);
+ hash = drm_hash_magic(magic);
+
+ down(&dev->struct_sem);
+ for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
+ if (pt->magic == magic) {
+ if (dev->magiclist[hash].head == pt) {
+ dev->magiclist[hash].head = pt->next;
+ }
+ if (dev->magiclist[hash].tail == pt) {
+ dev->magiclist[hash].tail = prev;
+ }
+ if (prev) {
+ prev->next = pt->next;
+ }
+ up(&dev->struct_sem);
+ return 0;
+ }
+ }
+ up(&dev->struct_sem);
+
+ drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+
+ return -EINVAL;
+}
+
+int drm_getmagic(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ static drm_magic_t sequence = 0;
+ static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_auth_t auth;
+
+ /* Find unique magic */
+ if (priv->magic) {
+ auth.magic = priv->magic;
+ } else {
+ spin_lock(&lock);
+ do {
+ if (!sequence) ++sequence; /* reserve 0 */
+ auth.magic = sequence++;
+ } while (drm_find_file(dev, auth.magic));
+ spin_unlock(&lock);
+ priv->magic = auth.magic;
+ drm_add_magic(dev, priv, auth.magic);
+ }
+
+ DRM_DEBUG("%u\n", auth.magic);
+ copy_to_user_ret((drm_auth_t *)arg, &auth, sizeof(auth), -EFAULT);
+ return 0;
+}
+
+int drm_authmagic(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_auth_t auth;
+ drm_file_t *file;
+
+ copy_from_user_ret(&auth, (drm_auth_t *)arg, sizeof(auth), -EFAULT);
+ DRM_DEBUG("%u\n", auth.magic);
+ if ((file = drm_find_file(dev, auth.magic))) {
+ file->authenticated = 1;
+ drm_remove_magic(dev, auth.magic);
+ return 0;
+ }
+ return -EINVAL;
+}
diff --git a/drivers/char/drm/bufs.c b/drivers/char/drm/bufs.c
new file mode 100644
index 000000000..32469a83a
--- /dev/null
+++ b/drivers/char/drm/bufs.c
@@ -0,0 +1,527 @@
+/* bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 22:48:10 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/bufs.c,v 1.8 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "linux/un.h"
+
+ /* Compute order. Can be made faster. */
+int drm_order(unsigned long size)
+{
+ int order;
+ unsigned long tmp;
+
+ for (order = 0, tmp = size; tmp >>= 1; ++order);
+ if (size & ~(1 << order)) ++order;
+ return order;
+}
+
+int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_map_t *map;
+
+ if (!(filp->f_mode & 3)) return -EACCES; /* Require read/write */
+
+ map = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
+ if (!map) return -ENOMEM;
+ if (copy_from_user(map, (drm_map_t *)arg, sizeof(*map))) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EFAULT;
+ }
+
+ DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
+ map->offset, map->size, map->type);
+ if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EINVAL;
+ }
+ map->mtrr = -1;
+ map->handle = 0;
+
+ switch (map->type) {
+ case _DRM_REGISTERS:
+ case _DRM_FRAME_BUFFER:
+ if (map->offset + map->size < map->offset
+ || map->offset < virt_to_phys(high_memory)) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EINVAL;
+ }
+#ifdef CONFIG_MTRR
+ if (map->type == _DRM_FRAME_BUFFER
+ || (map->flags & _DRM_WRITE_COMBINING)) {
+ map->mtrr = mtrr_add(map->offset, map->size,
+ MTRR_TYPE_WRCOMB, 1);
+ }
+#endif
+ map->handle = drm_ioremap(map->offset, map->size);
+ break;
+
+
+ case _DRM_SHM:
+ DRM_DEBUG("%ld %d\n", map->size, drm_order(map->size));
+ map->handle = (void *)drm_alloc_pages(drm_order(map->size)
+ - PAGE_SHIFT,
+ DRM_MEM_SAREA);
+ if (!map->handle) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -ENOMEM;
+ }
+ map->offset = (unsigned long)map->handle;
+ if (map->flags & _DRM_CONTAINS_LOCK) {
+ dev->lock.hw_lock = map->handle; /* Pointer to lock */
+ }
+ break;
+ default:
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EINVAL;
+ }
+
+ down(&dev->struct_sem);
+ if (dev->maplist) {
+ ++dev->map_count;
+ dev->maplist = drm_realloc(dev->maplist,
+ (dev->map_count-1)
+ * sizeof(*dev->maplist),
+ dev->map_count
+ * sizeof(*dev->maplist),
+ DRM_MEM_MAPS);
+ } else {
+ dev->map_count = 1;
+ dev->maplist = drm_alloc(dev->map_count*sizeof(*dev->maplist),
+ DRM_MEM_MAPS);
+ }
+ dev->maplist[dev->map_count-1] = map;
+ up(&dev->struct_sem);
+
+ copy_to_user_ret((drm_map_t *)arg, map, sizeof(*map), -EFAULT);
+ if (map->type != _DRM_SHM) {
+ copy_to_user_ret(&((drm_map_t *)arg)->handle,
+ &map->offset,
+ sizeof(map->offset),
+ -EFAULT);
+ }
+ return 0;
+}
+
+int drm_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_desc_t request;
+ int count;
+ int order;
+ int size;
+ int total;
+ int page_order;
+ drm_buf_entry_t *entry;
+ unsigned long page;
+ drm_buf_t *buf;
+ int alignment;
+ unsigned long offset;
+ int i;
+ int byte_count;
+ int page_count;
+
+ if (!dma) return -EINVAL;
+
+ copy_from_user_ret(&request,
+ (drm_buf_desc_t *)arg,
+ sizeof(request),
+ -EFAULT);
+
+ count = request.count;
+ order = drm_order(request.size);
+ size = 1 << order;
+
+ DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n",
+ request.count, request.size, size, order, dev->queue_count);
+
+ if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+ if (dev->queue_count) return -EBUSY; /* Not while in use */
+
+ alignment = (request.flags & DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size;
+ page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+ total = PAGE_SIZE << page_order;
+
+ spin_lock(&dev->count_lock);
+ if (dev->buf_use) {
+ spin_unlock(&dev->count_lock);
+ return -EBUSY;
+ }
+ atomic_inc(&dev->buf_alloc);
+ spin_unlock(&dev->count_lock);
+
+ down(&dev->struct_sem);
+ entry = &dma->bufs[order];
+ if (entry->buf_count) {
+ up(&dev->struct_sem);
+ atomic_dec(&dev->buf_alloc);
+ return -ENOMEM; /* May only call once for each order */
+ }
+
+ entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+ DRM_MEM_BUFS);
+ if (!entry->buflist) {
+ up(&dev->struct_sem);
+ atomic_dec(&dev->buf_alloc);
+ return -ENOMEM;
+ }
+ memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+
+ entry->seglist = drm_alloc(count * sizeof(*entry->seglist),
+ DRM_MEM_SEGS);
+ if (!entry->seglist) {
+ drm_free(entry->buflist,
+ count * sizeof(*entry->buflist),
+ DRM_MEM_BUFS);
+ up(&dev->struct_sem);
+ atomic_dec(&dev->buf_alloc);
+ return -ENOMEM;
+ }
+ memset(entry->seglist, 0, count * sizeof(*entry->seglist));
+
+ dma->pagelist = drm_realloc(dma->pagelist,
+ dma->page_count * sizeof(*dma->pagelist),
+ (dma->page_count + (count << page_order))
+ * sizeof(*dma->pagelist),
+ DRM_MEM_PAGES);
+ DRM_DEBUG("pagelist: %d entries\n",
+ dma->page_count + (count << page_order));
+
+
+ entry->buf_size = size;
+ entry->page_order = page_order;
+ byte_count = 0;
+ page_count = 0;
+ while (entry->buf_count < count) {
+ if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break;
+ entry->seglist[entry->seg_count++] = page;
+ for (i = 0; i < (1 << page_order); i++) {
+ DRM_DEBUG("page %d @ 0x%08lx\n",
+ dma->page_count + page_count,
+ page + PAGE_SIZE * i);
+ dma->pagelist[dma->page_count + page_count++]
+ = page + PAGE_SIZE * i;
+ }
+ for (offset = 0;
+ offset + size <= total && entry->buf_count < count;
+ offset += alignment, ++entry->buf_count) {
+ buf = &entry->buflist[entry->buf_count];
+ buf->idx = dma->buf_count + entry->buf_count;
+ buf->total = alignment;
+ buf->order = order;
+ buf->used = 0;
+ buf->offset = (dma->byte_count + byte_count + offset);
+ buf->address = (void *)(page + offset);
+ buf->next = NULL;
+ buf->waiting = 0;
+ buf->pending = 0;
+ init_waitqueue_head(&buf->dma_wait);
+ buf->pid = 0;
+#if DRM_DMA_HISTOGRAM
+ buf->time_queued = 0;
+ buf->time_dispatched = 0;
+ buf->time_completed = 0;
+ buf->time_freed = 0;
+#endif
+ DRM_DEBUG("buffer %d @ %p\n",
+ entry->buf_count, buf->address);
+ }
+ byte_count += PAGE_SIZE << page_order;
+ }
+
+ dma->buflist = drm_realloc(dma->buflist,
+ dma->buf_count * sizeof(*dma->buflist),
+ (dma->buf_count + entry->buf_count)
+ * sizeof(*dma->buflist),
+ DRM_MEM_BUFS);
+ for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+ dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+
+ dma->buf_count += entry->buf_count;
+ dma->seg_count += entry->seg_count;
+ dma->page_count += entry->seg_count << page_order;
+ dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
+
+ drm_freelist_create(&entry->freelist, entry->buf_count);
+ for (i = 0; i < entry->buf_count; i++) {
+ drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+ }
+
+ up(&dev->struct_sem);
+
+ request.count = entry->buf_count;
+ request.size = size;
+
+ copy_to_user_ret((drm_buf_desc_t *)arg,
+ &request,
+ sizeof(request),
+ -EFAULT);
+
+ atomic_dec(&dev->buf_alloc);
+ return 0;
+}
+
+int drm_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_info_t request;
+ int i;
+ int count;
+
+ if (!dma) return -EINVAL;
+
+ spin_lock(&dev->count_lock);
+ if (atomic_read(&dev->buf_alloc)) {
+ spin_unlock(&dev->count_lock);
+ return -EBUSY;
+ }
+ ++dev->buf_use; /* Can't allocate more after this call */
+ spin_unlock(&dev->count_lock);
+
+ copy_from_user_ret(&request,
+ (drm_buf_info_t *)arg,
+ sizeof(request),
+ -EFAULT);
+
+ for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+ if (dma->bufs[i].buf_count) ++count;
+ }
+
+ DRM_DEBUG("count = %d\n", count);
+
+ if (request.count >= count) {
+ for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+ if (dma->bufs[i].buf_count) {
+ copy_to_user_ret(&request.list[count].count,
+ &dma->bufs[i].buf_count,
+ sizeof(dma->bufs[0]
+ .buf_count),
+ -EFAULT);
+ copy_to_user_ret(&request.list[count].size,
+ &dma->bufs[i].buf_size,
+ sizeof(dma->bufs[0].buf_size),
+ -EFAULT);
+ copy_to_user_ret(&request.list[count].low_mark,
+ &dma->bufs[i]
+ .freelist.low_mark,
+ sizeof(dma->bufs[0]
+ .freelist.low_mark),
+ -EFAULT);
+ copy_to_user_ret(&request.list[count]
+ .high_mark,
+ &dma->bufs[i]
+ .freelist.high_mark,
+ sizeof(dma->bufs[0]
+ .freelist.high_mark),
+ -EFAULT);
+ DRM_DEBUG("%d %d %d %d %d\n",
+ i,
+ dma->bufs[i].buf_count,
+ dma->bufs[i].buf_size,
+ dma->bufs[i].freelist.low_mark,
+ dma->bufs[i].freelist.high_mark);
+ ++count;
+ }
+ }
+ }
+ request.count = count;
+
+ copy_to_user_ret((drm_buf_info_t *)arg,
+ &request,
+ sizeof(request),
+ -EFAULT);
+
+ return 0;
+}
+
+int drm_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_desc_t request;
+ int order;
+ drm_buf_entry_t *entry;
+
+ if (!dma) return -EINVAL;
+
+ copy_from_user_ret(&request,
+ (drm_buf_desc_t *)arg,
+ sizeof(request),
+ -EFAULT);
+
+ DRM_DEBUG("%d, %d, %d\n",
+ request.size, request.low_mark, request.high_mark);
+ order = drm_order(request.size);
+ if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+ entry = &dma->bufs[order];
+
+ if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+ return -EINVAL;
+ if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+ return -EINVAL;
+
+ entry->freelist.low_mark = request.low_mark;
+ entry->freelist.high_mark = request.high_mark;
+
+ return 0;
+}
+
+int drm_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_free_t request;
+ int i;
+ int idx;
+ drm_buf_t *buf;
+
+ if (!dma) return -EINVAL;
+
+ copy_from_user_ret(&request,
+ (drm_buf_free_t *)arg,
+ sizeof(request),
+ -EFAULT);
+
+ DRM_DEBUG("%d\n", request.count);
+ for (i = 0; i < request.count; i++) {
+ copy_from_user_ret(&idx,
+ &request.list[i],
+ sizeof(idx),
+ -EFAULT);
+ if (idx < 0 || idx >= dma->buf_count) {
+ DRM_ERROR("Index %d (of %d max)\n",
+ idx, dma->buf_count - 1);
+ return -EINVAL;
+ }
+ buf = dma->buflist[idx];
+ if (buf->pid != current->pid) {
+ DRM_ERROR("Process %d freeing buffer owned by %d\n",
+ current->pid, buf->pid);
+ return -EINVAL;
+ }
+ drm_free_buffer(dev, buf);
+ }
+
+ return 0;
+}
+
+int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ int retcode = 0;
+ const int zero = 0;
+ unsigned long virtual;
+ unsigned long address;
+ drm_buf_map_t request;
+ int i;
+
+ if (!dma) return -EINVAL;
+
+ DRM_DEBUG("\n");
+
+ spin_lock(&dev->count_lock);
+ if (atomic_read(&dev->buf_alloc)) {
+ spin_unlock(&dev->count_lock);
+ return -EBUSY;
+ }
+ ++dev->buf_use; /* Can't allocate more after this call */
+ spin_unlock(&dev->count_lock);
+
+ copy_from_user_ret(&request,
+ (drm_buf_map_t *)arg,
+ sizeof(request),
+ -EFAULT);
+
+ if (request.count >= dma->buf_count) {
+ virtual = do_mmap(filp, 0, dma->byte_count,
+ PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+ if (virtual > -1024UL) {
+ /* Real error */
+ retcode = (signed long)virtual;
+ goto done;
+ }
+ request.virtual = (void *)virtual;
+
+ for (i = 0; i < dma->buf_count; i++) {
+ if (copy_to_user(&request.list[i].idx,
+ &dma->buflist[i]->idx,
+ sizeof(request.list[0].idx))) {
+ retcode = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user(&request.list[i].total,
+ &dma->buflist[i]->total,
+ sizeof(request.list[0].total))) {
+ retcode = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user(&request.list[i].used,
+ &zero,
+ sizeof(zero))) {
+ retcode = -EFAULT;
+ goto done;
+ }
+ address = virtual + dma->buflist[i]->offset;
+ if (copy_to_user(&request.list[i].address,
+ &address,
+ sizeof(address))) {
+ retcode = -EFAULT;
+ goto done;
+ }
+ }
+ }
+done:
+ request.count = dma->buf_count;
+ DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
+
+ copy_to_user_ret((drm_buf_map_t *)arg,
+ &request,
+ sizeof(request),
+ -EFAULT);
+
+ return retcode;
+}
diff --git a/drivers/char/drm/context.c b/drivers/char/drm/context.c
new file mode 100644
index 000000000..b85aed606
--- /dev/null
+++ b/drivers/char/drm/context.c
@@ -0,0 +1,308 @@
+/* context.c -- IOCTLs for contexts and DMA queues -*- linux-c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:32:09 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/context.c,v 1.5 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gen_ioctl.c,v 1.2 1999/06/27 14:08:27 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int drm_init_queue(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx)
+{
+ DRM_DEBUG("\n");
+
+ if (atomic_read(&q->use_count) != 1
+ || atomic_read(&q->finalization)
+ || atomic_read(&q->block_count)) {
+ DRM_ERROR("New queue is already in use: u%d f%d b%d\n",
+ atomic_read(&q->use_count),
+ atomic_read(&q->finalization),
+ atomic_read(&q->block_count));
+ }
+
+ atomic_set(&q->finalization, 0);
+ atomic_set(&q->block_count, 0);
+ atomic_set(&q->block_read, 0);
+ atomic_set(&q->block_write, 0);
+ atomic_set(&q->total_queued, 0);
+ atomic_set(&q->total_flushed, 0);
+ atomic_set(&q->total_locks, 0);
+
+ init_waitqueue_head(&q->write_queue);
+ init_waitqueue_head(&q->read_queue);
+ init_waitqueue_head(&q->flush_queue);
+
+ q->flags = ctx->flags;
+
+ drm_waitlist_create(&q->waitlist, dev->dma->buf_count);
+
+ return 0;
+}
+
+
+/* drm_alloc_queue:
+PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not
+ disappear (so all deallocation must be done after IOCTLs are off)
+ 2) dev->queue_count < dev->queue_slots
+ 3) dev->queuelist[i].use_count == 0 and
+ dev->queuelist[i].finalization == 0 if i not in use
+POST: 1) dev->queuelist[i].use_count == 1
+ 2) dev->queue_count < dev->queue_slots */
+
+static int drm_alloc_queue(drm_device_t *dev)
+{
+ int i;
+ drm_queue_t *queue;
+ int oldslots;
+ int newslots;
+ /* Check for a free queue */
+ for (i = 0; i < dev->queue_count; i++) {
+ atomic_inc(&dev->queuelist[i]->use_count);
+ if (atomic_read(&dev->queuelist[i]->use_count) == 1
+ && !atomic_read(&dev->queuelist[i]->finalization)) {
+ DRM_DEBUG("%d (free)\n", i);
+ return i;
+ }
+ atomic_dec(&dev->queuelist[i]->use_count);
+ }
+ /* Allocate a new queue */
+ down(&dev->struct_sem);
+
+ queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES);
+ memset(queue, 0, sizeof(*queue));
+ atomic_set(&queue->use_count, 1);
+
+ ++dev->queue_count;
+ if (dev->queue_count >= dev->queue_slots) {
+ oldslots = dev->queue_slots * sizeof(*dev->queuelist);
+ if (!dev->queue_slots) dev->queue_slots = 1;
+ dev->queue_slots *= 2;
+ newslots = dev->queue_slots * sizeof(*dev->queuelist);
+
+ dev->queuelist = drm_realloc(dev->queuelist,
+ oldslots,
+ newslots,
+ DRM_MEM_QUEUES);
+ if (!dev->queuelist) {
+ up(&dev->struct_sem);
+ DRM_DEBUG("out of memory\n");
+ return -ENOMEM;
+ }
+ }
+ dev->queuelist[dev->queue_count-1] = queue;
+
+ up(&dev->struct_sem);
+ DRM_DEBUG("%d (new)\n", dev->queue_count - 1);
+ return dev->queue_count - 1;
+}
+
+int drm_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_ctx_res_t res;
+ drm_ctx_t ctx;
+ int i;
+
+ DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+ copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+ if (res.count >= DRM_RESERVED_CONTEXTS) {
+ memset(&ctx, 0, sizeof(ctx));
+ for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+ ctx.handle = i;
+ copy_to_user_ret(&res.contexts[i],
+ &i,
+ sizeof(i),
+ -EFAULT);
+ }
+ }
+ res.count = DRM_RESERVED_CONTEXTS;
+ copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+ return 0;
+}
+
+
+int drm_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if ((ctx.handle = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
+ /* Init kernel's context and get a new one. */
+ drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
+ ctx.handle = drm_alloc_queue(dev);
+ }
+ drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
+ DRM_DEBUG("%d\n", ctx.handle);
+ copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+ return 0;
+}
+
+int drm_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+ drm_queue_t *q;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+
+ DRM_DEBUG("%d\n", ctx.handle);
+
+ if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL;
+ q = dev->queuelist[ctx.handle];
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) == 1) {
+ /* No longer in use */
+ atomic_dec(&q->use_count);
+ return -EINVAL;
+ }
+
+ if (DRM_BUFCOUNT(&q->waitlist)) {
+ atomic_dec(&q->use_count);
+ return -EBUSY;
+ }
+
+ q->flags = ctx.flags;
+
+ atomic_dec(&q->use_count);
+ return 0;
+}
+
+int drm_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+ drm_queue_t *q;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+
+ DRM_DEBUG("%d\n", ctx.handle);
+
+ if (ctx.handle >= dev->queue_count) return -EINVAL;
+ q = dev->queuelist[ctx.handle];
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) == 1) {
+ /* No longer in use */
+ atomic_dec(&q->use_count);
+ return -EINVAL;
+ }
+
+ ctx.flags = q->flags;
+ atomic_dec(&q->use_count);
+
+ copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+
+ return 0;
+}
+
+int drm_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ DRM_DEBUG("%d\n", ctx.handle);
+ return drm_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int drm_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ DRM_DEBUG("%d\n", ctx.handle);
+ drm_context_switch_complete(dev, ctx.handle);
+
+ return 0;
+}
+
+int drm_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+ drm_queue_t *q;
+ drm_buf_t *buf;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ DRM_DEBUG("%d\n", ctx.handle);
+
+ if (ctx.handle >= dev->queue_count) return -EINVAL;
+ q = dev->queuelist[ctx.handle];
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) == 1) {
+ /* No longer in use */
+ atomic_dec(&q->use_count);
+ return -EINVAL;
+ }
+
+ atomic_inc(&q->finalization); /* Mark queue in finalization state */
+ atomic_sub(2, &q->use_count); /* Mark queue as unused (pending
+ finalization) */
+
+ while (test_and_set_bit(0, &dev->interrupt_flag)) {
+ schedule();
+ if (signal_pending(current)) {
+ clear_bit(0, &dev->interrupt_flag);
+ return -EINTR;
+ }
+ }
+ /* Remove queued buffers */
+ while ((buf = drm_waitlist_get(&q->waitlist))) {
+ drm_free_buffer(dev, buf);
+ }
+ clear_bit(0, &dev->interrupt_flag);
+
+ /* Wakeup blocked processes */
+ wake_up_interruptible(&q->read_queue);
+ wake_up_interruptible(&q->write_queue);
+ wake_up_interruptible(&q->flush_queue);
+
+ /* Finalization over. Queue is made
+ available when both use_count and
+ finalization become 0, which won't
+ happen until all the waiting processes
+ stop waiting. */
+ atomic_dec(&q->finalization);
+ return 0;
+}
diff --git a/drivers/char/drm/dma.c b/drivers/char/drm/dma.c
new file mode 100644
index 000000000..0ccbfc146
--- /dev/null
+++ b/drivers/char/drm/dma.c
@@ -0,0 +1,530 @@
+/* dma.c -- DMA IOCTL and function support -*- linux-c -*-
+ * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 13:06:51 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/dma.c,v 1.6 1999/08/20 20:00:53 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+#include <linux/interrupt.h> /* For task queue support */
+
+void drm_dma_setup(drm_device_t *dev)
+{
+ int i;
+
+ dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER);
+ memset(dev->dma, 0, sizeof(*dev->dma));
+ for (i = 0; i <= DRM_MAX_ORDER; i++)
+ memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
+}
+
+void drm_dma_takedown(drm_device_t *dev)
+{
+ drm_device_dma_t *dma = dev->dma;
+ int i, j;
+
+ if (!dma) return;
+
+ /* Clear dma buffers */
+ for (i = 0; i <= DRM_MAX_ORDER; i++) {
+ if (dma->bufs[i].seg_count) {
+ DRM_DEBUG("order %d: buf_count = %d,"
+ " seg_count = %d\n",
+ i,
+ dma->bufs[i].buf_count,
+ dma->bufs[i].seg_count);
+ for (j = 0; j < dma->bufs[i].seg_count; j++) {
+ drm_free_pages(dma->bufs[i].seglist[j],
+ dma->bufs[i].page_order,
+ DRM_MEM_DMA);
+ }
+ drm_free(dma->bufs[i].buflist,
+ dma->buf_count
+ * sizeof(*dma->bufs[0].buflist),
+ DRM_MEM_BUFS);
+ drm_free(dma->bufs[i].seglist,
+ dma->buf_count
+ * sizeof(*dma->bufs[0].seglist),
+ DRM_MEM_SEGS);
+ drm_freelist_destroy(&dma->bufs[i].freelist);
+ }
+ }
+
+ if (dma->buflist) {
+ drm_free(dma->buflist,
+ dma->buf_count * sizeof(*dma->buflist),
+ DRM_MEM_BUFS);
+ }
+
+ if (dma->pagelist) {
+ drm_free(dma->pagelist,
+ dma->page_count * sizeof(*dma->pagelist),
+ DRM_MEM_PAGES);
+ }
+ drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER);
+ dev->dma = NULL;
+}
+
+#if DRM_DMA_HISTOGRAM
+/* This is slow, but is useful for debugging. */
+int drm_histogram_slot(unsigned long count)
+{
+ int value = DRM_DMA_HISTOGRAM_INITIAL;
+ int slot;
+
+ for (slot = 0;
+ slot < DRM_DMA_HISTOGRAM_SLOTS;
+ ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) {
+ if (count < value) return slot;
+ }
+ return DRM_DMA_HISTOGRAM_SLOTS - 1;
+}
+
+void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf)
+{
+ cycles_t queued_to_dispatched;
+ cycles_t dispatched_to_completed;
+ cycles_t completed_to_freed;
+ int q2d, d2c, c2f, q2c, q2f;
+
+ if (buf->time_queued) {
+ queued_to_dispatched = (buf->time_dispatched
+ - buf->time_queued);
+ dispatched_to_completed = (buf->time_completed
+ - buf->time_dispatched);
+ completed_to_freed = (buf->time_freed
+ - buf->time_completed);
+
+ q2d = drm_histogram_slot(queued_to_dispatched);
+ d2c = drm_histogram_slot(dispatched_to_completed);
+ c2f = drm_histogram_slot(completed_to_freed);
+
+ q2c = drm_histogram_slot(queued_to_dispatched
+ + dispatched_to_completed);
+ q2f = drm_histogram_slot(queued_to_dispatched
+ + dispatched_to_completed
+ + completed_to_freed);
+
+ atomic_inc(&dev->histo.total);
+ atomic_inc(&dev->histo.queued_to_dispatched[q2d]);
+ atomic_inc(&dev->histo.dispatched_to_completed[d2c]);
+ atomic_inc(&dev->histo.completed_to_freed[c2f]);
+
+ atomic_inc(&dev->histo.queued_to_completed[q2c]);
+ atomic_inc(&dev->histo.queued_to_freed[q2f]);
+
+ }
+ buf->time_queued = 0;
+ buf->time_dispatched = 0;
+ buf->time_completed = 0;
+ buf->time_freed = 0;
+}
+#endif
+
+void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf)
+{
+ drm_device_dma_t *dma = dev->dma;
+
+ if (!buf) return;
+
+ buf->waiting = 0;
+ buf->pending = 0;
+ buf->pid = 0;
+ buf->used = 0;
+#if DRM_DMA_HISTOGRAM
+ buf->time_completed = get_cycles();
+#endif
+ if (waitqueue_active(&buf->dma_wait)) {
+ wake_up_interruptible(&buf->dma_wait);
+ } else {
+ /* If processes are waiting, the last one
+ to wake will put the buffer on the free
+ list. If no processes are waiting, we
+ put the buffer on the freelist here. */
+ drm_freelist_put(dev, &dma->bufs[buf->order].freelist, buf);
+ }
+}
+
+void drm_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+
+ for (i = 0; i < dma->buf_count; i++) {
+ if (dma->buflist[i]->pid == pid) {
+ switch (dma->buflist[i]->list) {
+ case DRM_LIST_NONE:
+ drm_free_buffer(dev, dma->buflist[i]);
+ break;
+ case DRM_LIST_WAIT:
+ dma->buflist[i]->list = DRM_LIST_RECLAIM;
+ break;
+ default:
+ /* Buffer already on hardware. */
+ break;
+ }
+ }
+ }
+}
+
+int drm_context_switch(drm_device_t *dev, int old, int new)
+{
+ char buf[64];
+ drm_queue_t *q;
+
+ atomic_inc(&dev->total_ctx);
+
+ if (test_and_set_bit(0, &dev->context_flag)) {
+ DRM_ERROR("Reentering -- FIXME\n");
+ return -EBUSY;
+ }
+
+#if DRM_DMA_HISTOGRAM
+ dev->ctx_start = get_cycles();
+#endif
+
+ DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+ if (new >= dev->queue_count) {
+ clear_bit(0, &dev->context_flag);
+ return -EINVAL;
+ }
+
+ if (new == dev->last_context) {
+ clear_bit(0, &dev->context_flag);
+ return 0;
+ }
+
+ q = dev->queuelist[new];
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) == 1) {
+ atomic_dec(&q->use_count);
+ clear_bit(0, &dev->context_flag);
+ return -EINVAL;
+ }
+
+ if (drm_flags & DRM_FLAG_NOCTX) {
+ drm_context_switch_complete(dev, new);
+ } else {
+ sprintf(buf, "C %d %d\n", old, new);
+ drm_write_string(dev, buf);
+ }
+
+ atomic_dec(&q->use_count);
+
+ return 0;
+}
+
+int drm_context_switch_complete(drm_device_t *dev, int new)
+{
+ drm_device_dma_t *dma = dev->dma;
+
+ dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
+ dev->last_switch = jiffies;
+
+ if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("Lock isn't held after context switch\n");
+ }
+
+ if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) {
+ if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ DRM_ERROR("Cannot free lock\n");
+ }
+ }
+
+#if DRM_DMA_HISTOGRAM
+ atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+ - dev->ctx_start)]);
+
+#endif
+ clear_bit(0, &dev->context_flag);
+ wake_up_interruptible(&dev->context_wait);
+
+ return 0;
+}
+
+void drm_clear_next_buffer(drm_device_t *dev)
+{
+ drm_device_dma_t *dma = dev->dma;
+
+ dma->next_buffer = NULL;
+ if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) {
+ wake_up_interruptible(&dma->next_queue->flush_queue);
+ }
+ dma->next_queue = NULL;
+}
+
+
+int drm_select_queue(drm_device_t *dev, void (*wrapper)(unsigned long))
+{
+ int i;
+ int candidate = -1;
+ int j = jiffies;
+
+ if (!dev) {
+ DRM_ERROR("No device\n");
+ return -1;
+ }
+ if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) {
+ /* This only happens between the time the
+ interrupt is initialized and the time
+ the queues are initialized. */
+ return -1;
+ }
+
+ /* Doing "while locked" DMA? */
+ if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) {
+ return DRM_KERNEL_CONTEXT;
+ }
+
+ /* If there are buffers on the last_context
+ queue, and we have not been executing
+ this context very long, continue to
+ execute this context. */
+ if (dev->last_switch <= j
+ && dev->last_switch + DRM_TIME_SLICE > j
+ && DRM_WAITCOUNT(dev, dev->last_context)) {
+ return dev->last_context;
+ }
+
+ /* Otherwise, find a candidate */
+ for (i = dev->last_checked + 1; i < dev->queue_count; i++) {
+ if (DRM_WAITCOUNT(dev, i)) {
+ candidate = dev->last_checked = i;
+ break;
+ }
+ }
+
+ if (candidate < 0) {
+ for (i = 0; i < dev->queue_count; i++) {
+ if (DRM_WAITCOUNT(dev, i)) {
+ candidate = dev->last_checked = i;
+ break;
+ }
+ }
+ }
+
+ if (wrapper
+ && candidate >= 0
+ && candidate != dev->last_context
+ && dev->last_switch <= j
+ && dev->last_switch + DRM_TIME_SLICE > j) {
+ if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) {
+ del_timer(&dev->timer);
+ dev->timer.function = wrapper;
+ dev->timer.data = (unsigned long)dev;
+ dev->timer.expires = dev->last_switch+DRM_TIME_SLICE;
+ add_timer(&dev->timer);
+ }
+ return -1;
+ }
+
+ return candidate;
+}
+
+
+int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d)
+{
+ int i;
+ drm_queue_t *q;
+ drm_buf_t *buf;
+ int idx;
+ int while_locked = 0;
+ drm_device_dma_t *dma = dev->dma;
+ DECLARE_WAITQUEUE(entry, current);
+
+ DRM_DEBUG("%d\n", d->send_count);
+
+ if (d->flags & _DRM_DMA_WHILE_LOCKED) {
+ int context = dev->lock.hw_lock->lock;
+
+ if (!_DRM_LOCK_IS_HELD(context)) {
+ DRM_ERROR("No lock held during \"while locked\""
+ " request\n");
+ return -EINVAL;
+ }
+ if (d->context != _DRM_LOCKING_CONTEXT(context)
+ && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Lock held by %d while %d makes"
+ " \"while locked\" request\n",
+ _DRM_LOCKING_CONTEXT(context),
+ d->context);
+ return -EINVAL;
+ }
+ q = dev->queuelist[DRM_KERNEL_CONTEXT];
+ while_locked = 1;
+ } else {
+ q = dev->queuelist[d->context];
+ }
+
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->block_write)) {
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&q->write_queue, &entry);
+ atomic_inc(&q->block_count);
+ for (;;) {
+ if (!atomic_read(&q->block_write)) break;
+ schedule();
+ if (signal_pending(current)) {
+ atomic_dec(&q->use_count);
+ return -EINTR;
+ }
+ }
+ atomic_dec(&q->block_count);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&q->write_queue, &entry);
+ }
+
+ for (i = 0; i < d->send_count; i++) {
+ idx = d->send_indices[i];
+ if (idx < 0 || idx >= dma->buf_count) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Index %d (of %d max)\n",
+ d->send_indices[i], dma->buf_count - 1);
+ return -EINVAL;
+ }
+ buf = dma->buflist[ idx ];
+ if (buf->pid != current->pid) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Process %d using buffer owned by %d\n",
+ current->pid, buf->pid);
+ return -EINVAL;
+ }
+ if (buf->list != DRM_LIST_NONE) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Process %d using buffer %d on list %d\n",
+ current->pid, buf->idx, buf->list);
+ }
+ buf->used = d->send_sizes[i];
+ buf->while_locked = while_locked;
+ buf->context = d->context;
+ if (!buf->used) {
+ DRM_ERROR("Queueing 0 length buffer\n");
+ }
+ if (buf->pending) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Queueing pending buffer:"
+ " buffer %d, offset %d\n",
+ d->send_indices[i], i);
+ return -EINVAL;
+ }
+ if (buf->waiting) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Queueing waiting buffer:"
+ " buffer %d, offset %d\n",
+ d->send_indices[i], i);
+ return -EINVAL;
+ }
+ buf->waiting = 1;
+ if (atomic_read(&q->use_count) == 1
+ || atomic_read(&q->finalization)) {
+ drm_free_buffer(dev, buf);
+ } else {
+ drm_waitlist_put(&q->waitlist, buf);
+ atomic_inc(&q->total_queued);
+ }
+ }
+ atomic_dec(&q->use_count);
+
+ return 0;
+}
+
+static int drm_dma_get_buffers_of_order(drm_device_t *dev, drm_dma_t *d,
+ int order)
+{
+ int i;
+ drm_buf_t *buf;
+ drm_device_dma_t *dma = dev->dma;
+
+ for (i = d->granted_count; i < d->request_count; i++) {
+ buf = drm_freelist_get(&dma->bufs[order].freelist,
+ d->flags & _DRM_DMA_WAIT);
+ if (!buf) break;
+ if (buf->pending || buf->waiting) {
+ DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n",
+ buf->idx,
+ buf->pid,
+ buf->waiting,
+ buf->pending);
+ }
+ buf->pid = current->pid;
+ copy_to_user_ret(&d->request_indices[i],
+ &buf->idx,
+ sizeof(buf->idx),
+ -EFAULT);
+ copy_to_user_ret(&d->request_sizes[i],
+ &buf->total,
+ sizeof(buf->total),
+ -EFAULT);
+ ++d->granted_count;
+ }
+ return 0;
+}
+
+
+int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma)
+{
+ int order;
+ int retcode = 0;
+ int tmp_order;
+
+ order = drm_order(dma->request_size);
+
+ dma->granted_count = 0;
+ retcode = drm_dma_get_buffers_of_order(dev, dma, order);
+
+ if (dma->granted_count < dma->request_count
+ && (dma->flags & _DRM_DMA_SMALLER_OK)) {
+ for (tmp_order = order - 1;
+ !retcode
+ && dma->granted_count < dma->request_count
+ && tmp_order >= DRM_MIN_ORDER;
+ --tmp_order) {
+
+ retcode = drm_dma_get_buffers_of_order(dev, dma,
+ tmp_order);
+ }
+ }
+
+ if (dma->granted_count < dma->request_count
+ && (dma->flags & _DRM_DMA_LARGER_OK)) {
+ for (tmp_order = order + 1;
+ !retcode
+ && dma->granted_count < dma->request_count
+ && tmp_order <= DRM_MAX_ORDER;
+ ++tmp_order) {
+
+ retcode = drm_dma_get_buffers_of_order(dev, dma,
+ tmp_order);
+ }
+ }
+ return 0;
+}
diff --git a/drivers/char/drm/drawable.c b/drivers/char/drm/drawable.c
new file mode 100644
index 000000000..6a8fc753a
--- /dev/null
+++ b/drivers/char/drm/drawable.c
@@ -0,0 +1,50 @@
+/* drawable.c -- IOCTLs for drawables -*- linux-c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:03 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drawable.c,v 1.3 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_adddraw(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_draw_t draw;
+
+ draw.handle = 0; /* NOOP */
+ DRM_DEBUG("%d\n", draw.handle);
+ copy_to_user_ret((drm_draw_t *)arg, &draw, sizeof(draw), -EFAULT);
+ return 0;
+}
+
+int drm_rmdraw(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ return 0; /* NOOP */
+}
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
new file mode 100644
index 000000000..2251462e8
--- /dev/null
+++ b/drivers/char/drm/drm.h
@@ -0,0 +1,277 @@
+/* drm.h -- Header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 13:08:18 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drm.h,v 1.46 1999/08/20 20:00:53 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drm.h,v 1.2 1999/06/27 14:08:21 dawes Exp $
+ *
+ */
+
+#ifndef _DRM_H_
+#define _DRM_H_
+
+#include <asm/ioctl.h> /* For _IO* macros */
+
+#define DRM_PROC_DEVICES "/proc/devices"
+#define DRM_PROC_MISC "/proc/misc"
+#define DRM_PROC_DRM "/proc/drm"
+#define DRM_DEV_DRM "/dev/drm"
+#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
+#define DRM_DEV_UID 0
+#define DRM_DEV_GID 0
+
+
+#define DRM_NAME "drm" /* Name in kernel, /dev, and /proc */
+#define DRM_MIN_ORDER 5 /* At least 2^5 bytes = 32 bytes */
+#define DRM_MAX_ORDER 22 /* Up to 2^22 bytes = 4MB */
+#define DRM_RAM_PERCENT 10 /* How much system ram can we lock? */
+
+#define _DRM_LOCK_HELD 0x80000000 /* Hardware lock is held */
+#define _DRM_LOCK_CONT 0x40000000 /* Hardware lock is contended */
+#define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD)
+#define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT)
+#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
+
+typedef unsigned long drm_handle_t;
+typedef unsigned int drm_context_t;
+typedef unsigned int drm_drawable_t;
+typedef unsigned int drm_magic_t;
+
+
+typedef struct drm_version {
+ int version_major; /* Major version */
+ int version_minor; /* Minor version */
+ int version_patchlevel;/* Patch level */
+ size_t name_len; /* Length of name buffer */
+ char *name; /* Name of driver */
+ size_t date_len; /* Length of date buffer */
+ char *date; /* User-space buffer to hold date */
+ size_t desc_len; /* Length of desc buffer */
+ char *desc; /* User-space buffer to hold desc */
+} drm_version_t;
+
+typedef struct drm_unique {
+ size_t unique_len; /* Length of unique */
+ char *unique; /* Unique name for driver instantiation */
+} drm_unique_t;
+
+typedef struct drm_list {
+ int count; /* Length of user-space structures */
+ drm_version_t *version;
+} drm_list_t;
+
+typedef struct drm_block {
+ int unused;
+} drm_block_t;
+
+typedef struct drm_control {
+ enum {
+ DRM_ADD_COMMAND,
+ DRM_RM_COMMAND,
+ DRM_INST_HANDLER,
+ DRM_UNINST_HANDLER
+ } func;
+ int irq;
+} drm_control_t;
+
+typedef enum drm_map_type {
+ _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */
+ _DRM_REGISTERS = 1, /* no caching, no core dump */
+ _DRM_SHM = 2 /* shared, cached */
+} drm_map_type_t;
+
+typedef enum drm_map_flags {
+ _DRM_RESTRICTED = 0x01, /* Cannot be mapped to user-virtual */
+ _DRM_READ_ONLY = 0x02,
+ _DRM_LOCKED = 0x04, /* shared, cached, locked */
+ _DRM_KERNEL = 0x08, /* kernel requires access */
+ _DRM_WRITE_COMBINING = 0x10, /* use write-combining if available */
+ _DRM_CONTAINS_LOCK = 0x20 /* SHM page that contains lock */
+} drm_map_flags_t;
+
+typedef struct drm_map {
+ unsigned long offset; /* Requested physical address (0 for SAREA)*/
+ unsigned long size; /* Requested physical size (bytes) */
+ drm_map_type_t type; /* Type of memory to map */
+ drm_map_flags_t flags; /* Flags */
+ void *handle; /* User-space: "Handle" to pass to mmap */
+ /* Kernel-space: kernel-virtual address */
+ int mtrr; /* MTRR slot used */
+ /* Private data */
+} drm_map_t;
+
+typedef enum drm_lock_flags {
+ _DRM_LOCK_READY = 0x01, /* Wait until hardware is ready for DMA */
+ _DRM_LOCK_QUIESCENT = 0x02, /* Wait until hardware quiescent */
+ _DRM_LOCK_FLUSH = 0x04, /* Flush this context's DMA queue first */
+ _DRM_LOCK_FLUSH_ALL = 0x08, /* Flush all DMA queues first */
+ /* These *HALT* flags aren't supported yet
+ -- they will be used to support the
+ full-screen DGA-like mode. */
+ _DRM_HALT_ALL_QUEUES = 0x10, /* Halt all current and future queues */
+ _DRM_HALT_CUR_QUEUES = 0x20 /* Halt all current queues */
+} drm_lock_flags_t;
+
+typedef struct drm_lock {
+ int context;
+ drm_lock_flags_t flags;
+} drm_lock_t;
+
+typedef enum drm_dma_flags { /* These values *MUST* match xf86drm.h */
+ /* Flags for DMA buffer dispatch */
+ _DRM_DMA_BLOCK = 0x01, /* Block until buffer dispatched.
+ Note, the buffer may not yet have
+ been processed by the hardware --
+ getting a hardware lock with the
+ hardware quiescent will ensure
+ that the buffer has been
+ processed. */
+ _DRM_DMA_WHILE_LOCKED = 0x02, /* Dispatch while lock held */
+ _DRM_DMA_PRIORITY = 0x04, /* High priority dispatch */
+
+ /* Flags for DMA buffer request */
+ _DRM_DMA_WAIT = 0x10, /* Wait for free buffers */
+ _DRM_DMA_SMALLER_OK = 0x20, /* Smaller-than-requested buffers ok */
+ _DRM_DMA_LARGER_OK = 0x40 /* Larger-than-requested buffers ok */
+} drm_dma_flags_t;
+
+typedef struct drm_buf_desc {
+ int count; /* Number of buffers of this size */
+ int size; /* Size in bytes */
+ int low_mark; /* Low water mark */
+ int high_mark; /* High water mark */
+ enum {
+ DRM_PAGE_ALIGN = 0x01 /* Align on page boundaries for DMA */
+ } flags;
+} drm_buf_desc_t;
+
+typedef struct drm_buf_info {
+ int count; /* Entries in list */
+ drm_buf_desc_t *list;
+} drm_buf_info_t;
+
+typedef struct drm_buf_free {
+ int count;
+ int *list;
+} drm_buf_free_t;
+
+typedef struct drm_buf_pub {
+ int idx; /* Index into master buflist */
+ int total; /* Buffer size */
+ int used; /* Amount of buffer in use (for DMA) */
+ void *address; /* Address of buffer */
+} drm_buf_pub_t;
+
+typedef struct drm_buf_map {
+ int count; /* Length of buflist */
+ void *virtual; /* Mmaped area in user-virtual */
+ drm_buf_pub_t *list; /* Buffer information */
+} drm_buf_map_t;
+
+typedef struct drm_dma {
+ /* Indices here refer to the offset into
+ buflist in drm_buf_get_t. */
+ int context; /* Context handle */
+ int send_count; /* Number of buffers to send */
+ int *send_indices; /* List of handles to buffers */
+ int *send_sizes; /* Lengths of data to send */
+ drm_dma_flags_t flags; /* Flags */
+ int request_count; /* Number of buffers requested */
+ int request_size; /* Desired size for buffers */
+ int *request_indices; /* Buffer information */
+ int *request_sizes;
+ int granted_count; /* Number of buffers granted */
+} drm_dma_t;
+
+typedef enum {
+ _DRM_CONTEXT_PRESERVED = 0x01,
+ _DRM_CONTEXT_2DONLY = 0x02
+} drm_ctx_flags_t;
+
+typedef struct drm_ctx {
+ drm_context_t handle;
+ drm_ctx_flags_t flags;
+} drm_ctx_t;
+
+typedef struct drm_ctx_res {
+ int count;
+ drm_ctx_t *contexts;
+} drm_ctx_res_t;
+
+typedef struct drm_draw {
+ drm_drawable_t handle;
+} drm_draw_t;
+
+typedef struct drm_auth {
+ drm_magic_t magic;
+} drm_auth_t;
+
+typedef struct drm_irq_busid {
+ int irq;
+ int busnum;
+ int devnum;
+ int funcnum;
+} drm_irq_busid_t;
+
+#define DRM_IOCTL_BASE 'd'
+#define DRM_IOCTL_NR(n) _IOC_NR(n)
+#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr)
+#define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size)
+#define DRM_IOW(nr,size) _IOW(DRM_IOCTL_BASE,nr,size)
+#define DRM_IOWR(nr,size) _IOWR(DRM_IOCTL_BASE,nr,size)
+
+
+#define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t)
+#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t)
+#define DRM_IOCTL_GET_MAGIC DRM_IOW( 0x02, drm_auth_t)
+#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t)
+
+#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t)
+#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t)
+#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, drm_block_t)
+#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, drm_block_t)
+#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, drm_control_t)
+#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, drm_map_t)
+#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, drm_buf_desc_t)
+#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, drm_buf_desc_t)
+#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm_buf_info_t)
+#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm_buf_map_t)
+#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm_buf_free_t)
+
+#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, drm_ctx_t)
+#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, drm_ctx_t)
+#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, drm_ctx_t)
+#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, drm_ctx_t)
+#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t)
+#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, drm_ctx_t)
+#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t)
+#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, drm_draw_t)
+#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, drm_draw_t)
+#define DRM_IOCTL_DMA DRM_IOWR(0x29, drm_dma_t)
+#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t)
+#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t)
+#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t)
+
+#endif
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
new file mode 100644
index 000000000..75103b074
--- /dev/null
+++ b/drivers/char/drm/drmP.h
@@ -0,0 +1,584 @@
+/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 13:04:33 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drmP.h,v 1.58 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drmP.h,v 1.2 1999/06/27 14:08:24 dawes Exp $
+ *
+ */
+
+#ifndef _DRM_P_H_
+#define _DRM_P_H_
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/pci.h>
+#include <linux/wrapper.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#include "drm.h"
+
+#define DRM_DEBUG_CODE 2 /* Include debugging code (if > 1, then
+ also include looping detection. */
+#define DRM_DMA_HISTOGRAM 1 /* Make histogram of DMA latency. */
+
+#define DRM_HASH_SIZE 16 /* Size of key hash table */
+#define DRM_KERNEL_CONTEXT 0 /* Change drm_resctx if changed */
+#define DRM_RESERVED_CONTEXTS 1 /* Change drm_resctx if changed */
+#define DRM_LOOPING_LIMIT 5000000
+#define DRM_BSZ 1024 /* Buffer size for /dev/drm? output */
+#define DRM_TIME_SLICE (HZ/20) /* Time slice for GLXContexts */
+#define DRM_LOCK_SLICE 1 /* Time slice for lock, in jiffies */
+
+#define DRM_FLAG_DEBUG 0x01
+#define DRM_FLAG_NOCTX 0x02
+
+#define DRM_MEM_DMA 0
+#define DRM_MEM_SAREA 1
+#define DRM_MEM_DRIVER 2
+#define DRM_MEM_MAGIC 3
+#define DRM_MEM_IOCTLS 4
+#define DRM_MEM_MAPS 5
+#define DRM_MEM_VMAS 6
+#define DRM_MEM_BUFS 7
+#define DRM_MEM_SEGS 8
+#define DRM_MEM_PAGES 9
+#define DRM_MEM_FILES 10
+#define DRM_MEM_QUEUES 11
+#define DRM_MEM_CMDS 12
+#define DRM_MEM_MAPPINGS 13
+#define DRM_MEM_BUFLISTS 14
+
+ /* Backward compatibility section */
+#ifndef _PAGE_PWT
+ /* The name of _PAGE_WT was changed to
+ _PAGE_PWT in Linux 2.2.6 */
+#define _PAGE_PWT _PAGE_WT
+#endif
+ /* Wait queue declarations changes in 2.3.1 */
+#ifndef DECLARE_WAITQUEUE
+#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = { c, NULL }
+typedef struct wait_queue *wait_queue_head_t;
+#define init_waitqueue_head(q) *q = NULL;
+#endif
+
+#define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock)
+#define _DRM_CAS(lock,old,new,__ret) \
+ do { \
+ int __dummy; /* Can't mark eax as clobbered */ \
+ __asm__ __volatile__( \
+ "lock ; cmpxchg %4,%1\n\t" \
+ "setnz %0" \
+ : "=d" (__ret), \
+ "=m" (__drm_dummy_lock(lock)), \
+ "=a" (__dummy) \
+ : "2" (old), \
+ "r" (new)); \
+ } while (0)
+
+
+
+ /* Macros to make printk easier */
+#define DRM_ERROR(fmt, arg...) \
+ printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ "] *ERROR* " fmt , ##arg)
+#define DRM_MEM_ERROR(area, fmt, arg...) \
+ printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ ":%s] *ERROR* " fmt , \
+ drm_mem_stats[area].name , ##arg)
+#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
+
+#if DRM_DEBUG_CODE
+#define DRM_DEBUG(fmt, arg...) \
+ do { \
+ if (drm_flags&DRM_FLAG_DEBUG) \
+ printk(KERN_DEBUG \
+ "[" DRM_NAME ":" __FUNCTION__ "] " fmt , \
+ ##arg); \
+ } while (0)
+#else
+#define DRM_DEBUG(fmt, arg...) do { } while (0)
+#endif
+
+#define DRM_PROC_LIMIT (PAGE_SIZE-80)
+
+#define DRM_PROC_PRINT(fmt, arg...) \
+ len += sprintf(&buf[len], fmt , ##arg); \
+ if (len > DRM_PROC_LIMIT) return len;
+
+#define DRM_PROC_PRINT_RET(ret, fmt, arg...) \
+ len += sprintf(&buf[len], fmt , ##arg); \
+ if (len > DRM_PROC_LIMIT) { ret; return len; }
+
+ /* Internal types and structures */
+#define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define DRM_MIN(a,b) ((a)<(b)?(a):(b))
+#define DRM_MAX(a,b) ((a)>(b)?(a):(b))
+
+#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1))
+#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
+#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist)
+
+typedef int drm_ioctl_t(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+typedef struct drm_ioctl_desc {
+ drm_ioctl_t *func;
+ int auth_needed;
+ int root_only;
+} drm_ioctl_desc_t;
+
+typedef struct drm_devstate {
+ pid_t owner; /* X server pid holding x_lock */
+
+} drm_devstate_t;
+
+typedef struct drm_magic_entry {
+ drm_magic_t magic;
+ struct drm_file *priv;
+ struct drm_magic_entry *next;
+} drm_magic_entry_t;
+
+typedef struct drm_magic_head {
+ struct drm_magic_entry *head;
+ struct drm_magic_entry *tail;
+} drm_magic_head_t;
+
+typedef struct drm_vma_entry {
+ struct vm_area_struct *vma;
+ struct drm_vma_entry *next;
+ pid_t pid;
+} drm_vma_entry_t;
+
+typedef struct drm_buf {
+ int idx; /* Index into master buflist */
+ int total; /* Buffer size */
+ int order; /* log-base-2(total) */
+ int used; /* Amount of buffer in use (for DMA) */
+ unsigned long offset; /* Byte offset (used internally) */
+ void *address; /* Address of buffer */
+ struct drm_buf *next; /* Kernel-only: used for free list */
+ __volatile__ int waiting; /* On kernel DMA queue */
+ __volatile__ int pending; /* On hardware DMA queue */
+ wait_queue_head_t dma_wait; /* Processes waiting */
+ pid_t pid; /* PID of holding process */
+ int context; /* Kernel queue for this buffer */
+ int while_locked;/* Dispatch this buffer while locked */
+ enum {
+ DRM_LIST_NONE = 0,
+ DRM_LIST_FREE = 1,
+ DRM_LIST_WAIT = 2,
+ DRM_LIST_PEND = 3,
+ DRM_LIST_PRIO = 4,
+ DRM_LIST_RECLAIM = 5
+ } list; /* Which list we're on */
+#if DRM_DMA_HISTOGRAM
+ cycles_t time_queued; /* Queued to kernel DMA queue */
+ cycles_t time_dispatched; /* Dispatched to hardware */
+ cycles_t time_completed; /* Completed by hardware */
+ cycles_t time_freed; /* Back on freelist */
+#endif
+} drm_buf_t;
+
+#if DRM_DMA_HISTOGRAM
+#define DRM_DMA_HISTOGRAM_SLOTS 9
+#define DRM_DMA_HISTOGRAM_INITIAL 10
+#define DRM_DMA_HISTOGRAM_NEXT(current) ((current)*10)
+typedef struct drm_histogram {
+ atomic_t total;
+
+ atomic_t queued_to_dispatched[DRM_DMA_HISTOGRAM_SLOTS];
+ atomic_t dispatched_to_completed[DRM_DMA_HISTOGRAM_SLOTS];
+ atomic_t completed_to_freed[DRM_DMA_HISTOGRAM_SLOTS];
+
+ atomic_t queued_to_completed[DRM_DMA_HISTOGRAM_SLOTS];
+ atomic_t queued_to_freed[DRM_DMA_HISTOGRAM_SLOTS];
+
+ atomic_t dma[DRM_DMA_HISTOGRAM_SLOTS];
+ atomic_t schedule[DRM_DMA_HISTOGRAM_SLOTS];
+ atomic_t ctx[DRM_DMA_HISTOGRAM_SLOTS];
+ atomic_t lacq[DRM_DMA_HISTOGRAM_SLOTS];
+ atomic_t lhld[DRM_DMA_HISTOGRAM_SLOTS];
+} drm_histogram_t;
+#endif
+
+ /* bufs is one longer than it has to be */
+typedef struct drm_waitlist {
+ int count; /* Number of possible buffers */
+ drm_buf_t **bufs; /* List of pointers to buffers */
+ drm_buf_t **rp; /* Read pointer */
+ drm_buf_t **wp; /* Write pointer */
+ drm_buf_t **end; /* End pointer */
+ spinlock_t read_lock;
+ spinlock_t write_lock;
+} drm_waitlist_t;
+
+typedef struct drm_freelist {
+ int initialized; /* Freelist in use */
+ atomic_t count; /* Number of free buffers */
+ drm_buf_t *next; /* End pointer */
+
+ wait_queue_head_t waiting; /* Processes waiting on free bufs */
+ int low_mark; /* Low water mark */
+ int high_mark; /* High water mark */
+ atomic_t wfh; /* If waiting for high mark */
+} drm_freelist_t;
+
+typedef struct drm_buf_entry {
+ int buf_size;
+ int buf_count;
+ drm_buf_t *buflist;
+ int seg_count;
+ int page_order;
+ unsigned long *seglist;
+
+ drm_freelist_t freelist;
+} drm_buf_entry_t;
+
+typedef struct drm_hw_lock {
+ __volatile__ unsigned int lock;
+ char padding[60]; /* Pad to cache line */
+} drm_hw_lock_t;
+
+typedef struct drm_file {
+ int authenticated;
+ int minor;
+ pid_t pid;
+ uid_t uid;
+ drm_magic_t magic;
+ unsigned long ioctl_count;
+ struct drm_file *next;
+ struct drm_file *prev;
+ struct drm_device *dev;
+} drm_file_t;
+
+
+typedef struct drm_queue {
+ atomic_t use_count; /* Outstanding uses (+1) */
+ atomic_t finalization; /* Finalization in progress */
+ atomic_t block_count; /* Count of processes waiting */
+ atomic_t block_read; /* Queue blocked for reads */
+ wait_queue_head_t read_queue; /* Processes waiting on block_read */
+ atomic_t block_write; /* Queue blocked for writes */
+ wait_queue_head_t write_queue; /* Processes waiting on block_write */
+ atomic_t total_queued; /* Total queued statistic */
+ atomic_t total_flushed;/* Total flushes statistic */
+ atomic_t total_locks; /* Total locks statistics */
+ drm_ctx_flags_t flags; /* Context preserving and 2D-only */
+ drm_waitlist_t waitlist; /* Pending buffers */
+ wait_queue_head_t flush_queue; /* Processes waiting until flush */
+} drm_queue_t;
+
+typedef struct drm_lock_data {
+ drm_hw_lock_t *hw_lock; /* Hardware lock */
+ pid_t pid; /* PID of lock holder (0=kernel) */
+ wait_queue_head_t lock_queue; /* Queue of blocked processes */
+ unsigned long lock_time; /* Time of last lock in jiffies */
+} drm_lock_data_t;
+
+typedef struct drm_device_dma {
+ /* Performance Counters */
+ atomic_t total_prio; /* Total DRM_DMA_PRIORITY */
+ atomic_t total_bytes; /* Total bytes DMA'd */
+ atomic_t total_dmas; /* Total DMA buffers dispatched */
+
+ atomic_t total_missed_dma; /* Missed drm_do_dma */
+ atomic_t total_missed_lock; /* Missed lock in drm_do_dma */
+ atomic_t total_missed_free; /* Missed drm_free_this_buffer */
+ atomic_t total_missed_sched;/* Missed drm_dma_schedule */
+
+ atomic_t total_tried; /* Tried next_buffer */
+ atomic_t total_hit; /* Sent next_buffer */
+ atomic_t total_lost; /* Lost interrupt */
+
+ drm_buf_entry_t bufs[DRM_MAX_ORDER+1];
+ int buf_count;
+ drm_buf_t **buflist; /* Vector of pointers info bufs */
+ int seg_count;
+ int page_count;
+ unsigned long *pagelist;
+ unsigned long byte_count;
+
+ /* DMA support */
+ drm_buf_t *this_buffer; /* Buffer being sent */
+ drm_buf_t *next_buffer; /* Selected buffer to send */
+ drm_queue_t *next_queue; /* Queue from which buffer selected*/
+ wait_queue_head_t waiting; /* Processes waiting on free bufs */
+} drm_device_dma_t;
+
+typedef struct drm_device {
+ const char *name; /* Simple driver name */
+ char *unique; /* Unique identifier: e.g., busid */
+ int unique_len; /* Length of unique field */
+ dev_t device; /* Device number for mknod */
+ char *devname; /* For /proc/interrupts */
+
+ int blocked; /* Blocked due to VC switch? */
+ struct proc_dir_entry *root; /* Root for this device's entries */
+
+ /* Locks */
+ spinlock_t count_lock; /* For inuse, open_count, buf_use */
+ struct semaphore struct_sem; /* For others */
+
+ /* Usage Counters */
+ int open_count; /* Outstanding files open */
+ atomic_t ioctl_count; /* Outstanding IOCTLs pending */
+ atomic_t vma_count; /* Outstanding vma areas open */
+ int buf_use; /* Buffers in use -- cannot alloc */
+ atomic_t buf_alloc; /* Buffer allocation in progress */
+
+ /* Performance Counters */
+ atomic_t total_open;
+ atomic_t total_close;
+ atomic_t total_ioctl;
+ atomic_t total_irq; /* Total interruptions */
+ atomic_t total_ctx; /* Total context switches */
+
+ atomic_t total_locks;
+ atomic_t total_unlocks;
+ atomic_t total_contends;
+ atomic_t total_sleeps;
+
+ /* Authentication */
+ drm_file_t *file_first;
+ drm_file_t *file_last;
+ drm_magic_head_t magiclist[DRM_HASH_SIZE];
+
+ /* Memory management */
+ drm_map_t **maplist; /* Vector of pointers to regions */
+ int map_count; /* Number of mappable regions */
+
+ drm_vma_entry_t *vmalist; /* List of vmas (for debugging) */
+ drm_lock_data_t lock; /* Information on hardware lock */
+
+ /* DMA queues (contexts) */
+ int queue_count; /* Number of active DMA queues */
+ int queue_reserved; /* Number of reserved DMA queues */
+ int queue_slots; /* Actual length of queuelist */
+ drm_queue_t **queuelist; /* Vector of pointers to DMA queues */
+ drm_device_dma_t *dma; /* Optional pointer for DMA support */
+
+ /* Context support */
+ int irq; /* Interrupt used by board */
+ __volatile__ int context_flag; /* Context swapping flag */
+ __volatile__ int interrupt_flag;/* Interruption handler flag */
+ __volatile__ int dma_flag; /* DMA dispatch flag */
+ struct timer_list timer; /* Timer for delaying ctx switch */
+ wait_queue_head_t context_wait; /* Processes waiting on ctx switch */
+ int last_checked; /* Last context checked for DMA */
+ int last_context; /* Last current context */
+ unsigned long last_switch; /* jiffies at last context switch */
+ struct tq_struct tq;
+ cycles_t ctx_start;
+ cycles_t lck_start;
+#if DRM_DMA_HISTOGRAM
+ drm_histogram_t histo;
+#endif
+
+ /* Callback to X server for context switch
+ and for heavy-handed reset. */
+ char buf[DRM_BSZ]; /* Output buffer */
+ char *buf_rp; /* Read pointer */
+ char *buf_wp; /* Write pointer */
+ char *buf_end; /* End pointer */
+ struct fasync_struct *buf_async;/* Processes waiting for SIGIO */
+ wait_queue_head_t buf_readers; /* Processes waiting to read */
+ wait_queue_head_t buf_writers; /* Processes waiting to ctx switch */
+} drm_device_t;
+
+
+ /* Internal function definitions */
+
+ /* Misc. support (init.c) */
+extern int drm_flags;
+extern void drm_parse_options(char *s);
+
+
+ /* Device support (fops.c) */
+extern int drm_open_helper(struct inode *inode, struct file *filp,
+ drm_device_t *dev);
+extern int drm_flush(struct file *filp);
+extern int drm_release(struct inode *inode, struct file *filp);
+extern int drm_fasync(int fd, struct file *filp, int on);
+extern ssize_t drm_read(struct file *filp, char *buf, size_t count,
+ loff_t *off);
+extern int drm_write_string(drm_device_t *dev, const char *s);
+
+ /* Mapping support (vm.c) */
+extern unsigned long drm_vm_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access);
+extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access);
+extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access);
+extern void drm_vm_open(struct vm_area_struct *vma);
+extern void drm_vm_close(struct vm_area_struct *vma);
+extern int drm_mmap_dma(struct file *filp,
+ struct vm_area_struct *vma);
+extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
+
+
+ /* Proc support (proc.c) */
+extern int drm_proc_init(drm_device_t *dev);
+extern int drm_proc_cleanup(void);
+
+ /* Memory management support (memory.c) */
+extern void drm_mem_init(void);
+extern int drm_mem_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+extern void *drm_alloc(size_t size, int area);
+extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size,
+ int area);
+extern char *drm_strdup(const char *s, int area);
+extern void drm_strfree(const char *s, int area);
+extern void drm_free(void *pt, size_t size, int area);
+extern unsigned long drm_alloc_pages(int order, int area);
+extern void drm_free_pages(unsigned long address, int order,
+ int area);
+extern void *drm_ioremap(unsigned long offset, unsigned long size);
+extern void drm_ioremapfree(void *pt, unsigned long size);
+
+ /* Buffer management support (bufs.c) */
+extern int drm_order(unsigned long size);
+extern int drm_addmap(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_addbufs(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_infobufs(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_markbufs(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_freebufs(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_mapbufs(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+
+ /* Buffer list management support (lists.c) */
+extern int drm_waitlist_create(drm_waitlist_t *bl, int count);
+extern int drm_waitlist_destroy(drm_waitlist_t *bl);
+extern int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf);
+extern drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl);
+
+extern int drm_freelist_create(drm_freelist_t *bl, int count);
+extern int drm_freelist_destroy(drm_freelist_t *bl);
+extern int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl,
+ drm_buf_t *buf);
+extern drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block);
+
+ /* DMA support (gen_dma.c) */
+extern void drm_dma_setup(drm_device_t *dev);
+extern void drm_dma_takedown(drm_device_t *dev);
+extern void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf);
+extern void drm_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern int drm_context_switch(drm_device_t *dev, int old, int new);
+extern int drm_context_switch_complete(drm_device_t *dev, int new);
+extern void drm_wakeup(drm_device_t *dev, drm_buf_t *buf);
+extern void drm_clear_next_buffer(drm_device_t *dev);
+extern int drm_select_queue(drm_device_t *dev,
+ void (*wrapper)(unsigned long));
+extern int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *dma);
+extern int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma);
+#if DRM_DMA_HISTOGRAM
+extern int drm_histogram_slot(unsigned long count);
+extern void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf);
+#endif
+
+
+ /* Misc. IOCTL support (ioctl.c) */
+extern int drm_irq_busid(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_getunique(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_setunique(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+
+ /* Context IOCTL support (context.c) */
+extern int drm_resctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_addctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_modctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_getctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_switchctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_newctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_rmctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+
+ /* Drawable IOCTL support (drawable.c) */
+extern int drm_adddraw(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_rmdraw(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+
+ /* Authentication IOCTL support (auth.c) */
+extern int drm_add_magic(drm_device_t *dev, drm_file_t *priv,
+ drm_magic_t magic);
+extern int drm_remove_magic(drm_device_t *dev, drm_magic_t magic);
+extern int drm_getmagic(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_authmagic(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+
+ /* Locking IOCTL support (lock.c) */
+extern int drm_block(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_unblock(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_lock_take(__volatile__ unsigned int *lock,
+ unsigned int context);
+extern int drm_lock_transfer(__volatile__ unsigned int *lock,
+ unsigned int context);
+extern int drm_lock_free(drm_device_t *dev,
+ __volatile__ unsigned int *lock,
+ unsigned int context);
+extern int drm_finish(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_flush_unblock(drm_device_t *dev, int context,
+ drm_lock_flags_t flags);
+extern int drm_flush_block_and_flush(drm_device_t *dev, int context,
+ drm_lock_flags_t flags);
+#endif
+#endif
diff --git a/drivers/char/drm/fops.c b/drivers/char/drm/fops.c
new file mode 100644
index 000000000..12ab4d628
--- /dev/null
+++ b/drivers/char/drm/fops.c
@@ -0,0 +1,204 @@
+/* fops.c -- File operations for DRM -*- linux-c -*-
+ * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:46 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/fops.c,v 1.3 1999/08/20 15:36:45 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+/* drm_open is called whenever a process opens /dev/drm. */
+
+int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev)
+{
+ kdev_t minor = MINOR(inode->i_rdev);
+ drm_file_t *priv;
+
+ if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */
+
+ DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor);
+
+ priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
+ memset(priv, 0, sizeof(*priv));
+ filp->private_data = priv;
+ priv->uid = current->euid;
+ priv->pid = current->pid;
+ priv->minor = minor;
+ priv->dev = dev;
+ priv->ioctl_count = 0;
+ priv->authenticated = capable(CAP_SYS_ADMIN);
+
+ down(&dev->struct_sem);
+ if (!dev->file_last) {
+ priv->next = NULL;
+ priv->prev = NULL;
+ dev->file_first = priv;
+ dev->file_last = priv;
+ } else {
+ priv->next = NULL;
+ priv->prev = dev->file_last;
+ dev->file_last->next = priv;
+ dev->file_last = priv;
+ }
+ up(&dev->struct_sem);
+
+ return 0;
+}
+
+int drm_flush(struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+
+ DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d, f_count = %d\n",
+ current->pid, dev->device, dev->open_count, atomic_read(&filp->f_count));
+ return 0;
+}
+
+/* drm_release is called whenever a process closes /dev/drm*. Linux calls
+ this only if any mappings have been closed. */
+
+int drm_release(struct inode *inode, struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+
+ DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+ current->pid, dev->device, dev->open_count);
+
+ drm_reclaim_buffers(dev, priv->pid);
+
+ drm_fasync(-1, filp, 0);
+
+ down(&dev->struct_sem);
+ if (priv->prev) priv->prev->next = priv->next;
+ else dev->file_first = priv->next;
+ if (priv->next) priv->next->prev = priv->prev;
+ else dev->file_last = priv->prev;
+ up(&dev->struct_sem);
+
+ drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+
+ return 0;
+}
+
+int drm_fasync(int fd, struct file *filp, int on)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int retcode;
+
+ DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device);
+ retcode = fasync_helper(fd, filp, on, &dev->buf_async);
+ if (retcode < 0) return retcode;
+ return 0;
+}
+
+
+/* The drm_read and drm_write_string code (especially that which manages
+ the circular buffer), is based on Alessandro Rubini's LINUX DEVICE
+ DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */
+
+ssize_t drm_read(struct file *filp, char *buf, size_t count, loff_t *off)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int left;
+ int avail;
+ int send;
+ int cur;
+
+ DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
+
+ while (dev->buf_rp == dev->buf_wp) {
+ DRM_DEBUG(" sleeping\n");
+ if (filp->f_flags & O_NONBLOCK) {
+ return -EAGAIN;
+ }
+ interruptible_sleep_on(&dev->buf_readers);
+ if (signal_pending(current)) {
+ DRM_DEBUG(" interrupted\n");
+ return -ERESTARTSYS;
+ }
+ DRM_DEBUG(" awake\n");
+ }
+
+ left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+ avail = DRM_BSZ - left;
+ send = DRM_MIN(avail, count);
+
+ while (send) {
+ if (dev->buf_wp > dev->buf_rp) {
+ cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp);
+ } else {
+ cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
+ }
+ copy_to_user_ret(buf, dev->buf_rp, cur, -EINVAL);
+ dev->buf_rp += cur;
+ if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf;
+ send -= cur;
+ }
+
+ wake_up_interruptible(&dev->buf_writers);
+ return DRM_MIN(avail, count);;
+}
+
+int drm_write_string(drm_device_t *dev, const char *s)
+{
+ int left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+ int send = strlen(s);
+ int count;
+
+ DRM_DEBUG("%d left, %d to send (%p, %p)\n",
+ left, send, dev->buf_rp, dev->buf_wp);
+
+ if (left == 1 || dev->buf_wp != dev->buf_rp) {
+ DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n",
+ left,
+ dev->buf_wp,
+ dev->buf_rp);
+ }
+
+ while (send) {
+ if (dev->buf_wp >= dev->buf_rp) {
+ count = DRM_MIN(send, dev->buf_end - dev->buf_wp);
+ if (count == left) --count; /* Leave a hole */
+ } else {
+ count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1);
+ }
+ strncpy(dev->buf_wp, s, count);
+ dev->buf_wp += count;
+ if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf;
+ send -= count;
+ }
+
+ if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
+ DRM_DEBUG("waking\n");
+ wake_up_interruptible(&dev->buf_readers);
+ return 0;
+}
diff --git a/drivers/char/drm/gamma_dma.c b/drivers/char/drm/gamma_dma.c
new file mode 100644
index 000000000..66d828a71
--- /dev/null
+++ b/drivers/char/drm/gamma_dma.c
@@ -0,0 +1,802 @@
+/* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*-
+ * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:45 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_dma.c,v 1.8 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "gamma_drv.h"
+
+#include <linux/interrupt.h> /* For task queue support */
+
+
+/* WARNING!!! MAGIC NUMBER!!! The number of regions already added to the
+ kernel must be specified here. Currently, the number is 2. This must
+ match the order the X server uses for instantiating register regions ,
+ or must be passed in a new ioctl. */
+#define GAMMA_REG(reg) \
+ (2 \
+ + ((reg < 0x1000) \
+ ? 0 \
+ : ((reg < 0x10000) ? 1 : ((reg < 0x11000) ? 2 : 3))))
+
+#define GAMMA_OFF(reg) \
+ ((reg < 0x1000) \
+ ? reg \
+ : ((reg < 0x10000) \
+ ? (reg - 0x1000) \
+ : ((reg < 0x11000) \
+ ? (reg - 0x10000) \
+ : (reg - 0x11000))))
+
+#define GAMMA_BASE(reg) ((unsigned long)dev->maplist[GAMMA_REG(reg)]->handle)
+#define GAMMA_ADDR(reg) (GAMMA_BASE(reg) + GAMMA_OFF(reg))
+#define GAMMA_DEREF(reg) *(__volatile__ int *)GAMMA_ADDR(reg)
+#define GAMMA_READ(reg) GAMMA_DEREF(reg)
+#define GAMMA_WRITE(reg,val) do { GAMMA_DEREF(reg) = val; } while (0)
+
+#define GAMMA_BROADCASTMASK 0x9378
+#define GAMMA_COMMANDINTENABLE 0x0c48
+#define GAMMA_DMAADDRESS 0x0028
+#define GAMMA_DMACOUNT 0x0030
+#define GAMMA_FILTERMODE 0x8c00
+#define GAMMA_GCOMMANDINTFLAGS 0x0c50
+#define GAMMA_GCOMMANDMODE 0x0c40
+#define GAMMA_GCOMMANDSTATUS 0x0c60
+#define GAMMA_GDELAYTIMER 0x0c38
+#define GAMMA_GDMACONTROL 0x0060
+#define GAMMA_GINTENABLE 0x0808
+#define GAMMA_GINTFLAGS 0x0810
+#define GAMMA_INFIFOSPACE 0x0018
+#define GAMMA_OUTFIFOWORDS 0x0020
+#define GAMMA_OUTPUTFIFO 0x2000
+#define GAMMA_SYNC 0x8c40
+#define GAMMA_SYNC_TAG 0x0188
+
+static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address,
+ unsigned long length)
+{
+ GAMMA_WRITE(GAMMA_DMAADDRESS, virt_to_phys((void *)address));
+ while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4)
+ ;
+ GAMMA_WRITE(GAMMA_DMACOUNT, length / 4);
+}
+
+static inline void gamma_dma_quiescent(drm_device_t *dev)
+{
+ while (GAMMA_READ(GAMMA_DMACOUNT))
+ ;
+ while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
+ ;
+ GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
+ GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
+ GAMMA_WRITE(GAMMA_SYNC, 0);
+
+ /* Read from first MX */
+ do {
+ while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
+ ;
+ } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
+
+
+ /* Read from second MX */
+ do {
+ while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000))
+ ;
+ } while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
+}
+
+static inline void gamma_dma_ready(drm_device_t *dev)
+{
+ while (GAMMA_READ(GAMMA_DMACOUNT))
+ ;
+}
+
+static inline int gamma_dma_is_ready(drm_device_t *dev)
+{
+ return !GAMMA_READ(GAMMA_DMACOUNT);
+}
+
+static void gamma_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+ drm_device_t *dev = (drm_device_t *)device;
+ drm_device_dma_t *dma = dev->dma;
+
+ atomic_inc(&dev->total_irq);
+ GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */
+ GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8);
+ GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001);
+ if (gamma_dma_is_ready(dev)) {
+ /* Free previous buffer */
+ if (test_and_set_bit(0, &dev->dma_flag)) {
+ atomic_inc(&dma->total_missed_free);
+ return;
+ }
+ if (dma->this_buffer) {
+ drm_free_buffer(dev, dma->this_buffer);
+ dma->this_buffer = NULL;
+ }
+ clear_bit(0, &dev->dma_flag);
+
+ /* Dispatch new buffer */
+ queue_task(&dev->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+}
+
+/* Only called by gamma_dma_schedule. */
+static int gamma_do_dma(drm_device_t *dev, int locked)
+{
+ unsigned long address;
+ unsigned long length;
+ drm_buf_t *buf;
+ int retcode = 0;
+ drm_device_dma_t *dma = dev->dma;
+#if DRM_DMA_HISTOGRAM
+ cycles_t dma_start, dma_stop;
+#endif
+
+ if (test_and_set_bit(0, &dev->dma_flag)) {
+ atomic_inc(&dma->total_missed_dma);
+ return -EBUSY;
+ }
+
+#if DRM_DMA_HISTOGRAM
+ dma_start = get_cycles();
+#endif
+
+ if (!dma->next_buffer) {
+ DRM_ERROR("No next_buffer\n");
+ clear_bit(0, &dev->dma_flag);
+ return -EINVAL;
+ }
+
+ buf = dma->next_buffer;
+ address = (unsigned long)buf->address;
+ length = buf->used;
+
+ DRM_DEBUG("context %d, buffer %d (%ld bytes)\n",
+ buf->context, buf->idx, length);
+
+ if (buf->list == DRM_LIST_RECLAIM) {
+ drm_clear_next_buffer(dev);
+ drm_free_buffer(dev, buf);
+ clear_bit(0, &dev->dma_flag);
+ return -EINVAL;
+ }
+
+ if (!length) {
+ DRM_ERROR("0 length buffer\n");
+ drm_clear_next_buffer(dev);
+ drm_free_buffer(dev, buf);
+ clear_bit(0, &dev->dma_flag);
+ return 0;
+ }
+
+ if (!gamma_dma_is_ready(dev)) {
+ clear_bit(0, &dev->dma_flag);
+ return -EBUSY;
+ }
+
+ if (buf->while_locked) {
+ if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("Dispatching buffer %d from pid %d"
+ " \"while locked\", but no lock held\n",
+ buf->idx, buf->pid);
+ }
+ } else {
+ if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ atomic_inc(&dma->total_missed_lock);
+ clear_bit(0, &dev->dma_flag);
+ return -EBUSY;
+ }
+ }
+
+ if (dev->last_context != buf->context
+ && !(dev->queuelist[buf->context]->flags
+ & _DRM_CONTEXT_PRESERVED)) {
+ /* PRE: dev->last_context != buf->context */
+ if (drm_context_switch(dev, dev->last_context, buf->context)) {
+ drm_clear_next_buffer(dev);
+ drm_free_buffer(dev, buf);
+ }
+ retcode = -EBUSY;
+ goto cleanup;
+
+ /* POST: we will wait for the context
+ switch and will dispatch on a later call
+ when dev->last_context == buf->context.
+ NOTE WE HOLD THE LOCK THROUGHOUT THIS
+ TIME! */
+ }
+
+ drm_clear_next_buffer(dev);
+ buf->pending = 1;
+ buf->waiting = 0;
+ buf->list = DRM_LIST_PEND;
+#if DRM_DMA_HISTOGRAM
+ buf->time_dispatched = get_cycles();
+#endif
+
+ gamma_dma_dispatch(dev, address, length);
+ drm_free_buffer(dev, dma->this_buffer);
+ dma->this_buffer = buf;
+
+ atomic_add(length, &dma->total_bytes);
+ atomic_inc(&dma->total_dmas);
+
+ if (!buf->while_locked && !dev->context_flag && !locked) {
+ if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ DRM_ERROR("\n");
+ }
+ }
+cleanup:
+
+ clear_bit(0, &dev->dma_flag);
+
+#if DRM_DMA_HISTOGRAM
+ dma_stop = get_cycles();
+ atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]);
+#endif
+
+ return retcode;
+}
+
+static void gamma_dma_schedule_timer_wrapper(unsigned long dev)
+{
+ gamma_dma_schedule((drm_device_t *)dev, 0);
+}
+
+static void gamma_dma_schedule_tq_wrapper(void *dev)
+{
+ gamma_dma_schedule(dev, 0);
+}
+
+int gamma_dma_schedule(drm_device_t *dev, int locked)
+{
+ int next;
+ drm_queue_t *q;
+ drm_buf_t *buf;
+ int retcode = 0;
+ int processed = 0;
+ int missed;
+ int expire = 20;
+ drm_device_dma_t *dma = dev->dma;
+#if DRM_DMA_HISTOGRAM
+ cycles_t schedule_start;
+#endif
+
+ if (test_and_set_bit(0, &dev->interrupt_flag)) {
+ /* Not reentrant */
+ atomic_inc(&dma->total_missed_sched);
+ return -EBUSY;
+ }
+ missed = atomic_read(&dma->total_missed_sched);
+
+#if DRM_DMA_HISTOGRAM
+ schedule_start = get_cycles();
+#endif
+
+again:
+ if (dev->context_flag) {
+ clear_bit(0, &dev->interrupt_flag);
+ return -EBUSY;
+ }
+ if (dma->next_buffer) {
+ /* Unsent buffer that was previously
+ selected, but that couldn't be sent
+ because the lock could not be obtained
+ or the DMA engine wasn't ready. Try
+ again. */
+ atomic_inc(&dma->total_tried);
+ if (!(retcode = gamma_do_dma(dev, locked))) {
+ atomic_inc(&dma->total_hit);
+ ++processed;
+ }
+ } else {
+ do {
+ next = drm_select_queue(dev,
+ gamma_dma_schedule_timer_wrapper);
+ if (next >= 0) {
+ q = dev->queuelist[next];
+ buf = drm_waitlist_get(&q->waitlist);
+ dma->next_buffer = buf;
+ dma->next_queue = q;
+ if (buf && buf->list == DRM_LIST_RECLAIM) {
+ drm_clear_next_buffer(dev);
+ drm_free_buffer(dev, buf);
+ }
+ }
+ } while (next >= 0 && !dma->next_buffer);
+ if (dma->next_buffer) {
+ if (!(retcode = gamma_do_dma(dev, locked))) {
+ ++processed;
+ }
+ }
+ }
+
+ if (--expire) {
+ if (missed != atomic_read(&dma->total_missed_sched)) {
+ atomic_inc(&dma->total_lost);
+ if (gamma_dma_is_ready(dev)) goto again;
+ }
+ if (processed && gamma_dma_is_ready(dev)) {
+ atomic_inc(&dma->total_lost);
+ processed = 0;
+ goto again;
+ }
+ }
+
+ clear_bit(0, &dev->interrupt_flag);
+
+#if DRM_DMA_HISTOGRAM
+ atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles()
+ - schedule_start)]);
+#endif
+ return retcode;
+}
+
+static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d)
+{
+ unsigned long address;
+ unsigned long length;
+ int must_free = 0;
+ int retcode = 0;
+ int i;
+ int idx;
+ drm_buf_t *buf;
+ drm_buf_t *last_buf = NULL;
+ drm_device_dma_t *dma = dev->dma;
+ DECLARE_WAITQUEUE(entry, current);
+
+ /* Turn off interrupt handling */
+ while (test_and_set_bit(0, &dev->interrupt_flag)) {
+ schedule();
+ if (signal_pending(current)) return -EINTR;
+ }
+ if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) {
+ while (!drm_lock_take(&dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ schedule();
+ if (signal_pending(current)) {
+ clear_bit(0, &dev->interrupt_flag);
+ return -EINTR;
+ }
+ }
+ ++must_free;
+ }
+ atomic_inc(&dma->total_prio);
+
+ for (i = 0; i < d->send_count; i++) {
+ idx = d->send_indices[i];
+ if (idx < 0 || idx >= dma->buf_count) {
+ DRM_ERROR("Index %d (of %d max)\n",
+ d->send_indices[i], dma->buf_count - 1);
+ continue;
+ }
+ buf = dma->buflist[ idx ];
+ if (buf->pid != current->pid) {
+ DRM_ERROR("Process %d using buffer owned by %d\n",
+ current->pid, buf->pid);
+ retcode = -EINVAL;
+ goto cleanup;
+ }
+ if (buf->list != DRM_LIST_NONE) {
+ DRM_ERROR("Process %d using %d's buffer on list %d\n",
+ current->pid, buf->pid, buf->list);
+ retcode = -EINVAL;
+ goto cleanup;
+ }
+ /* This isn't a race condition on
+ buf->list, since our concern is the
+ buffer reclaim during the time the
+ process closes the /dev/drm? handle, so
+ it can't also be doing DMA. */
+ buf->list = DRM_LIST_PRIO;
+ buf->used = d->send_sizes[i];
+ buf->context = d->context;
+ buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;
+ address = (unsigned long)buf->address;
+ length = buf->used;
+ if (!length) {
+ DRM_ERROR("0 length buffer\n");
+ }
+ if (buf->pending) {
+ DRM_ERROR("Sending pending buffer:"
+ " buffer %d, offset %d\n",
+ d->send_indices[i], i);
+ retcode = -EINVAL;
+ goto cleanup;
+ }
+ if (buf->waiting) {
+ DRM_ERROR("Sending waiting buffer:"
+ " buffer %d, offset %d\n",
+ d->send_indices[i], i);
+ retcode = -EINVAL;
+ goto cleanup;
+ }
+ buf->pending = 1;
+
+ if (dev->last_context != buf->context
+ && !(dev->queuelist[buf->context]->flags
+ & _DRM_CONTEXT_PRESERVED)) {
+ add_wait_queue(&dev->context_wait, &entry);
+ current->state = TASK_INTERRUPTIBLE;
+ /* PRE: dev->last_context != buf->context */
+ drm_context_switch(dev, dev->last_context,
+ buf->context);
+ /* POST: we will wait for the context
+ switch and will dispatch on a later call
+ when dev->last_context == buf->context.
+ NOTE WE HOLD THE LOCK THROUGHOUT THIS
+ TIME! */
+ schedule();
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev->context_wait, &entry);
+ if (signal_pending(current)) {
+ retcode = -EINTR;
+ goto cleanup;
+ }
+ if (dev->last_context != buf->context) {
+ DRM_ERROR("Context mismatch: %d %d\n",
+ dev->last_context,
+ buf->context);
+ }
+ }
+
+#if DRM_DMA_HISTOGRAM
+ buf->time_queued = get_cycles();
+ buf->time_dispatched = buf->time_queued;
+#endif
+ gamma_dma_dispatch(dev, address, length);
+ atomic_add(length, &dma->total_bytes);
+ atomic_inc(&dma->total_dmas);
+
+ if (last_buf) {
+ drm_free_buffer(dev, last_buf);
+ }
+ last_buf = buf;
+ }
+
+
+cleanup:
+ if (last_buf) {
+ gamma_dma_ready(dev);
+ drm_free_buffer(dev, last_buf);
+ }
+
+ if (must_free && !dev->context_flag) {
+ if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ DRM_ERROR("\n");
+ }
+ }
+ clear_bit(0, &dev->interrupt_flag);
+ return retcode;
+}
+
+static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d)
+{
+ DECLARE_WAITQUEUE(entry, current);
+ drm_buf_t *last_buf = NULL;
+ int retcode = 0;
+ drm_device_dma_t *dma = dev->dma;
+
+ if (d->flags & _DRM_DMA_BLOCK) {
+ last_buf = dma->buflist[d->send_indices[d->send_count-1]];
+ add_wait_queue(&last_buf->dma_wait, &entry);
+ }
+
+ if ((retcode = drm_dma_enqueue(dev, d))) {
+ if (d->flags & _DRM_DMA_BLOCK)
+ remove_wait_queue(&last_buf->dma_wait, &entry);
+ return retcode;
+ }
+
+ gamma_dma_schedule(dev, 0);
+
+ if (d->flags & _DRM_DMA_BLOCK) {
+ DRM_DEBUG("%d waiting\n", current->pid);
+ current->state = TASK_INTERRUPTIBLE;
+ for (;;) {
+ if (!last_buf->waiting
+ && !last_buf->pending)
+ break; /* finished */
+ schedule();
+ if (signal_pending(current)) {
+ retcode = -EINTR; /* Can't restart */
+ break;
+ }
+ }
+ current->state = TASK_RUNNING;
+ DRM_DEBUG("%d running\n", current->pid);
+ remove_wait_queue(&last_buf->dma_wait, &entry);
+ if (!retcode
+ || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) {
+ if (!waitqueue_active(&last_buf->dma_wait)) {
+ drm_free_buffer(dev, last_buf);
+ }
+ }
+ if (retcode) {
+ DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n",
+ d->context,
+ last_buf->waiting,
+ last_buf->pending,
+ DRM_WAITCOUNT(dev, d->context),
+ last_buf->idx,
+ last_buf->list,
+ last_buf->pid,
+ current->pid);
+ }
+ }
+ return retcode;
+}
+
+int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ int retcode = 0;
+ drm_dma_t d;
+
+ copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT);
+ DRM_DEBUG("%d %d: %d send, %d req\n",
+ current->pid, d.context, d.send_count, d.request_count);
+
+ if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) {
+ DRM_ERROR("Process %d using context %d\n",
+ current->pid, d.context);
+ return -EINVAL;
+ }
+ if (d.send_count < 0 || d.send_count > dma->buf_count) {
+ DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
+ current->pid, d.send_count, dma->buf_count);
+ return -EINVAL;
+ }
+ if (d.request_count < 0 || d.request_count > dma->buf_count) {
+ DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+ current->pid, d.request_count, dma->buf_count);
+ return -EINVAL;
+ }
+
+ if (d.send_count) {
+ if (d.flags & _DRM_DMA_PRIORITY)
+ retcode = gamma_dma_priority(dev, &d);
+ else
+ retcode = gamma_dma_send_buffers(dev, &d);
+ }
+
+ d.granted_count = 0;
+
+ if (!retcode && d.request_count) {
+ retcode = drm_dma_get_buffers(dev, &d);
+ }
+
+ DRM_DEBUG("%d returning, granted = %d\n",
+ current->pid, d.granted_count);
+ copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
+
+ return retcode;
+}
+
+int gamma_irq_install(drm_device_t *dev, int irq)
+{
+ int retcode;
+
+ if (!irq) return -EINVAL;
+
+ down(&dev->struct_sem);
+ if (dev->irq) {
+ up(&dev->struct_sem);
+ return -EBUSY;
+ }
+ dev->irq = irq;
+ up(&dev->struct_sem);
+
+ DRM_DEBUG("%d\n", irq);
+
+ dev->context_flag = 0;
+ dev->interrupt_flag = 0;
+ dev->dma_flag = 0;
+
+ dev->dma->next_buffer = NULL;
+ dev->dma->next_queue = NULL;
+ dev->dma->this_buffer = NULL;
+
+ dev->tq.next = NULL;
+ dev->tq.sync = 0;
+ dev->tq.routine = gamma_dma_schedule_tq_wrapper;
+ dev->tq.data = dev;
+
+
+ /* Before installing handler */
+ GAMMA_WRITE(GAMMA_GCOMMANDMODE, 0);
+ GAMMA_WRITE(GAMMA_GDMACONTROL, 0);
+
+ /* Install handler */
+ if ((retcode = request_irq(dev->irq,
+ gamma_dma_service,
+ 0,
+ dev->devname,
+ dev))) {
+ down(&dev->struct_sem);
+ dev->irq = 0;
+ up(&dev->struct_sem);
+ return retcode;
+ }
+
+ /* After installing handler */
+ GAMMA_WRITE(GAMMA_GINTENABLE, 0x2001);
+ GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0x0008);
+ GAMMA_WRITE(GAMMA_GDELAYTIMER, 0x39090);
+
+ return 0;
+}
+
+int gamma_irq_uninstall(drm_device_t *dev)
+{
+ int irq;
+
+ down(&dev->struct_sem);
+ irq = dev->irq;
+ dev->irq = 0;
+ up(&dev->struct_sem);
+
+ if (!irq) return -EINVAL;
+
+ DRM_DEBUG("%d\n", irq);
+
+ GAMMA_WRITE(GAMMA_GDELAYTIMER, 0);
+ GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0);
+ GAMMA_WRITE(GAMMA_GINTENABLE, 0);
+ free_irq(irq, dev);
+
+ return 0;
+}
+
+
+int gamma_control(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_control_t ctl;
+ int retcode;
+
+ copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT);
+
+ switch (ctl.func) {
+ case DRM_INST_HANDLER:
+ if ((retcode = gamma_irq_install(dev, ctl.irq)))
+ return retcode;
+ break;
+ case DRM_UNINST_HANDLER:
+ if ((retcode = gamma_irq_uninstall(dev)))
+ return retcode;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int gamma_lock(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ DECLARE_WAITQUEUE(entry, current);
+ int ret = 0;
+ drm_lock_t lock;
+ drm_queue_t *q;
+#if DRM_DMA_HISTOGRAM
+ cycles_t start;
+
+ dev->lck_start = start = get_cycles();
+#endif
+
+ copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+ if (lock.context == DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Process %d using kernel context %d\n",
+ current->pid, lock.context);
+ return -EINVAL;
+ }
+
+ DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+ lock.context, current->pid, dev->lock.hw_lock->lock,
+ lock.flags);
+
+ if (lock.context < 0 || lock.context >= dev->queue_count)
+ return -EINVAL;
+ q = dev->queuelist[lock.context];
+
+ ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+
+ if (!ret) {
+ if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+ != lock.context) {
+ long j = jiffies - dev->lock.lock_time;
+
+ if (j > 0 && j <= DRM_LOCK_SLICE) {
+ /* Can't take lock if we just had it and
+ there is contention. */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(j);
+ }
+ }
+ add_wait_queue(&dev->lock.lock_queue, &entry);
+ for (;;) {
+ if (!dev->lock.hw_lock) {
+ /* Device has been unregistered */
+ ret = -EINTR;
+ break;
+ }
+ if (drm_lock_take(&dev->lock.hw_lock->lock,
+ lock.context)) {
+ dev->lock.pid = current->pid;
+ dev->lock.lock_time = jiffies;
+ atomic_inc(&dev->total_locks);
+ atomic_inc(&q->total_locks);
+ break; /* Got lock */
+ }
+
+ /* Contention */
+ atomic_inc(&dev->total_sleeps);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev->lock.lock_queue, &entry);
+ }
+
+ drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */
+
+ if (!ret) {
+ if (lock.flags & _DRM_LOCK_READY)
+ gamma_dma_ready(dev);
+ if (lock.flags & _DRM_LOCK_QUIESCENT)
+ gamma_dma_quiescent(dev);
+ }
+ DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+#if DRM_DMA_HISTOGRAM
+ atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
+#endif
+
+ return ret;
+}
diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c
new file mode 100644
index 000000000..d83c98ef9
--- /dev/null
+++ b/drivers/char/drm/gamma_drv.c
@@ -0,0 +1,525 @@
+/* gamma.c -- 3dlabs GMX 2000 driver -*- linux-c -*-
+ * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 22:48:11 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_drv.c,v 1.17 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define EXPORT_SYMTAB
+#include "drmP.h"
+#include "gamma_drv.h"
+EXPORT_SYMBOL(gamma_init);
+EXPORT_SYMBOL(gamma_cleanup);
+
+#define GAMMA_NAME "gamma"
+#define GAMMA_DESC "3dlabs GMX 2000"
+#define GAMMA_DATE "19990830"
+#define GAMMA_MAJOR 0
+#define GAMMA_MINOR 0
+#define GAMMA_PATCHLEVEL 5
+
+static drm_device_t gamma_device;
+
+static struct file_operations gamma_fops = {
+ open: gamma_open,
+ flush: drm_flush,
+ release: gamma_release,
+ ioctl: gamma_ioctl,
+ mmap: drm_mmap,
+ read: drm_read,
+ fasync: drm_fasync,
+};
+
+static struct miscdevice gamma_misc = {
+ minor: MISC_DYNAMIC_MINOR,
+ name: GAMMA_NAME,
+ fops: &gamma_fops,
+};
+
+static drm_ioctl_desc_t gamma_ioctls[] = {
+ [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { gamma_version, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 },
+
+ [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { gamma_control, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { drm_addbufs, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { drm_markbufs, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_infobufs, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { drm_mapbufs, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_freebufs, 1, 0 },
+
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { drm_addctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { drm_rmctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { drm_modctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { drm_getctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { drm_newctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { drm_resctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { gamma_dma, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { gamma_lock, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { gamma_unlock, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 },
+};
+#define GAMMA_IOCTL_COUNT DRM_ARRAY_SIZE(gamma_ioctls)
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+static char *gamma = NULL;
+
+MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas.");
+MODULE_DESCRIPTION("3dlabs GMX 2000");
+MODULE_PARM(gamma, "s");
+
+/* init_module is called when insmod is used to load the module */
+
+int init_module(void)
+{
+ return gamma_init();
+}
+
+/* cleanup_module is called when rmmod is used to unload the module */
+
+void cleanup_module(void)
+{
+ gamma_cleanup();
+}
+#endif
+
+#ifndef MODULE
+/* gamma_setup is called by the kernel to parse command-line options passed
+ * via the boot-loader (e.g., LILO). It calls the insmod option routine,
+ * drm_parse_drm.
+ *
+ * This is not currently supported, since it requires changes to
+ * linux/init/main.c. */
+
+
+void __init gamma_setup(char *str, int *ints)
+{
+ if (ints[0] != 0) {
+ DRM_ERROR("Illegal command line format, ignored\n");
+ return;
+ }
+ drm_parse_options(str);
+}
+#endif
+
+static int gamma_setup(drm_device_t *dev)
+{
+ int i;
+
+ atomic_set(&dev->ioctl_count, 0);
+ atomic_set(&dev->vma_count, 0);
+ dev->buf_use = 0;
+ atomic_set(&dev->buf_alloc, 0);
+
+ drm_dma_setup(dev);
+
+ atomic_set(&dev->total_open, 0);
+ atomic_set(&dev->total_close, 0);
+ atomic_set(&dev->total_ioctl, 0);
+ atomic_set(&dev->total_irq, 0);
+ atomic_set(&dev->total_ctx, 0);
+ atomic_set(&dev->total_locks, 0);
+ atomic_set(&dev->total_unlocks, 0);
+ atomic_set(&dev->total_contends, 0);
+ atomic_set(&dev->total_sleeps, 0);
+
+ for (i = 0; i < DRM_HASH_SIZE; i++) {
+ dev->magiclist[i].head = NULL;
+ dev->magiclist[i].tail = NULL;
+ }
+ dev->maplist = NULL;
+ dev->map_count = 0;
+ dev->vmalist = NULL;
+ dev->lock.hw_lock = NULL;
+ init_waitqueue_head(&dev->lock.lock_queue);
+ dev->queue_count = 0;
+ dev->queue_reserved = 0;
+ dev->queue_slots = 0;
+ dev->queuelist = NULL;
+ dev->irq = 0;
+ dev->context_flag = 0;
+ dev->interrupt_flag = 0;
+ dev->dma_flag = 0;
+ dev->last_context = 0;
+ dev->last_switch = 0;
+ dev->last_checked = 0;
+ init_timer(&dev->timer);
+ init_waitqueue_head(&dev->context_wait);
+#if DRM_DMA_HISTO
+ memset(&dev->histo, 0, sizeof(dev->histo));
+#endif
+ dev->ctx_start = 0;
+ dev->lck_start = 0;
+
+ dev->buf_rp = dev->buf;
+ dev->buf_wp = dev->buf;
+ dev->buf_end = dev->buf + DRM_BSZ;
+ dev->buf_async = NULL;
+ init_waitqueue_head(&dev->buf_readers);
+ init_waitqueue_head(&dev->buf_writers);
+
+ DRM_DEBUG("\n");
+
+ /* The kernel's context could be created here, but is now created
+ in drm_dma_enqueue. This is more resource-efficient for
+ hardware that does not do DMA, but may mean that
+ drm_select_queue fails between the time the interrupt is
+ initialized and the time the queues are initialized. */
+
+ return 0;
+}
+
+
+static int gamma_takedown(drm_device_t *dev)
+{
+ int i;
+ drm_magic_entry_t *pt, *next;
+ drm_map_t *map;
+ drm_vma_entry_t *vma, *vma_next;
+
+ DRM_DEBUG("\n");
+
+ if (dev->irq) gamma_irq_uninstall(dev);
+
+ down(&dev->struct_sem);
+ del_timer(&dev->timer);
+
+ if (dev->devname) {
+ drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+ dev->devname = NULL;
+ }
+
+ if (dev->unique) {
+ drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+ dev->unique = NULL;
+ dev->unique_len = 0;
+ }
+ /* Clear pid list */
+ for (i = 0; i < DRM_HASH_SIZE; i++) {
+ for (pt = dev->magiclist[i].head; pt; pt = next) {
+ next = pt->next;
+ drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+ }
+ dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+ }
+
+ /* Clear vma list (only built for debugging) */
+ if (dev->vmalist) {
+ for (vma = dev->vmalist; vma; vma = vma_next) {
+ vma_next = vma->next;
+ drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+ }
+ dev->vmalist = NULL;
+ }
+
+ /* Clear map area and mtrr information */
+ if (dev->maplist) {
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ switch (map->type) {
+ case _DRM_REGISTERS:
+ case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+ if (map->mtrr >= 0) {
+ int retcode;
+ retcode = mtrr_del(map->mtrr,
+ map->offset,
+ map->size);
+ DRM_DEBUG("mtrr_del = %d\n", retcode);
+ }
+#endif
+ drm_ioremapfree(map->handle, map->size);
+ break;
+ case _DRM_SHM:
+ drm_free_pages((unsigned long)map->handle,
+ drm_order(map->size)
+ - PAGE_SHIFT,
+ DRM_MEM_SAREA);
+ break;
+ }
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ }
+ drm_free(dev->maplist,
+ dev->map_count * sizeof(*dev->maplist),
+ DRM_MEM_MAPS);
+ dev->maplist = NULL;
+ dev->map_count = 0;
+ }
+
+ if (dev->queuelist) {
+ for (i = 0; i < dev->queue_count; i++) {
+ drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
+ if (dev->queuelist[i]) {
+ drm_free(dev->queuelist[i],
+ sizeof(*dev->queuelist[0]),
+ DRM_MEM_QUEUES);
+ dev->queuelist[i] = NULL;
+ }
+ }
+ drm_free(dev->queuelist,
+ dev->queue_slots * sizeof(*dev->queuelist),
+ DRM_MEM_QUEUES);
+ dev->queuelist = NULL;
+ }
+
+ drm_dma_takedown(dev);
+
+ dev->queue_count = 0;
+ if (dev->lock.hw_lock) {
+ dev->lock.hw_lock = NULL; /* SHM removed */
+ dev->lock.pid = 0;
+ wake_up_interruptible(&dev->lock.lock_queue);
+ }
+ up(&dev->struct_sem);
+
+ return 0;
+}
+
+/* gamma_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+int gamma_init(void)
+{
+ int retcode;
+ drm_device_t *dev = &gamma_device;
+
+ DRM_DEBUG("\n");
+
+ memset((void *)dev, 0, sizeof(*dev));
+ dev->count_lock = SPIN_LOCK_UNLOCKED;
+ sema_init(&dev->struct_sem, 1);
+
+#ifdef MODULE
+ drm_parse_options(gamma);
+#endif
+
+ if ((retcode = misc_register(&gamma_misc))) {
+ DRM_ERROR("Cannot register \"%s\"\n", GAMMA_NAME);
+ return retcode;
+ }
+ dev->device = MKDEV(MISC_MAJOR, gamma_misc.minor);
+ dev->name = GAMMA_NAME;
+
+ drm_mem_init();
+ drm_proc_init(dev);
+
+ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+ GAMMA_NAME,
+ GAMMA_MAJOR,
+ GAMMA_MINOR,
+ GAMMA_PATCHLEVEL,
+ GAMMA_DATE,
+ gamma_misc.minor);
+
+ return 0;
+}
+
+/* gamma_cleanup is called via cleanup_module at module unload time. */
+
+void gamma_cleanup(void)
+{
+ drm_device_t *dev = &gamma_device;
+
+ DRM_DEBUG("\n");
+
+ drm_proc_cleanup();
+ if (misc_deregister(&gamma_misc)) {
+ DRM_ERROR("Cannot unload module\n");
+ } else {
+ DRM_INFO("Module unloaded\n");
+ }
+ gamma_takedown(dev);
+}
+
+int gamma_version(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_version_t version;
+ int len;
+
+ copy_from_user_ret(&version,
+ (drm_version_t *)arg,
+ sizeof(version),
+ -EFAULT);
+
+#define DRM_COPY(name,value) \
+ len = strlen(value); \
+ if (len > name##_len) len = name##_len; \
+ name##_len = strlen(value); \
+ if (len && name) { \
+ copy_to_user_ret(name, value, len, -EFAULT); \
+ }
+
+ version.version_major = GAMMA_MAJOR;
+ version.version_minor = GAMMA_MINOR;
+ version.version_patchlevel = GAMMA_PATCHLEVEL;
+
+ DRM_COPY(version.name, GAMMA_NAME);
+ DRM_COPY(version.date, GAMMA_DATE);
+ DRM_COPY(version.desc, GAMMA_DESC);
+
+ copy_to_user_ret((drm_version_t *)arg,
+ &version,
+ sizeof(version),
+ -EFAULT);
+ return 0;
+}
+
+int gamma_open(struct inode *inode, struct file *filp)
+{
+ drm_device_t *dev = &gamma_device;
+ int retcode = 0;
+
+ DRM_DEBUG("open_count = %d\n", dev->open_count);
+ if (!(retcode = drm_open_helper(inode, filp, dev))) {
+ MOD_INC_USE_COUNT;
+ atomic_inc(&dev->total_open);
+ spin_lock(&dev->count_lock);
+ if (!dev->open_count++) {
+ spin_unlock(&dev->count_lock);
+ return gamma_setup(dev);
+ }
+ spin_unlock(&dev->count_lock);
+ }
+ return retcode;
+}
+
+int gamma_release(struct inode *inode, struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int retcode = 0;
+
+ DRM_DEBUG("open_count = %d\n", dev->open_count);
+ if (!(retcode = drm_release(inode, filp))) {
+ MOD_DEC_USE_COUNT;
+ atomic_inc(&dev->total_close);
+ spin_lock(&dev->count_lock);
+ if (!--dev->open_count) {
+ if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+ DRM_ERROR("Device busy: %d %d\n",
+ atomic_read(&dev->ioctl_count),
+ dev->blocked);
+ spin_unlock(&dev->count_lock);
+ return -EBUSY;
+ }
+ spin_unlock(&dev->count_lock);
+ return gamma_takedown(dev);
+ }
+ spin_unlock(&dev->count_lock);
+ }
+ return retcode;
+}
+
+/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int gamma_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int nr = DRM_IOCTL_NR(cmd);
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int retcode = 0;
+ drm_ioctl_desc_t *ioctl;
+ drm_ioctl_t *func;
+
+ atomic_inc(&dev->ioctl_count);
+ atomic_inc(&dev->total_ioctl);
+ ++priv->ioctl_count;
+
+ DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+ current->pid, cmd, nr, dev->device, priv->authenticated);
+
+ if (nr >= GAMMA_IOCTL_COUNT) {
+ retcode = -EINVAL;
+ } else {
+ ioctl = &gamma_ioctls[nr];
+ func = ioctl->func;
+
+ if (!func) {
+ DRM_DEBUG("no function\n");
+ retcode = -EINVAL;
+ } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+ || (ioctl->auth_needed && !priv->authenticated)) {
+ retcode = -EACCES;
+ } else {
+ retcode = (func)(inode, filp, cmd, arg);
+ }
+ }
+
+ atomic_dec(&dev->ioctl_count);
+ return retcode;
+}
+
+
+int gamma_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_lock_t lock;
+
+ copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+ if (lock.context == DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Process %d using kernel context %d\n",
+ current->pid, lock.context);
+ return -EINVAL;
+ }
+
+ DRM_DEBUG("%d frees lock (%d holds)\n",
+ lock.context,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+ atomic_inc(&dev->total_unlocks);
+ if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+ atomic_inc(&dev->total_contends);
+ drm_lock_transfer(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+ gamma_dma_schedule(dev, 1);
+ if (!dev->context_flag) {
+ if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ DRM_ERROR("\n");
+ }
+ }
+#if DRM_DMA_HISTOGRAM
+ atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles()
+ - dev->lck_start)]);
+#endif
+
+ return 0;
+}
diff --git a/drivers/char/drm/gamma_drv.h b/drivers/char/drm/gamma_drv.h
new file mode 100644
index 000000000..d91526a98
--- /dev/null
+++ b/drivers/char/drm/gamma_drv.h
@@ -0,0 +1,58 @@
+/* gamma_drv.h -- Private header for 3dlabs GMX 2000 driver -*- linux-c -*-
+ * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:24:27 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_drv.h,v 1.4 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#ifndef _GAMMA_DRV_H_
+#define _GAMMA_DRV_H_
+
+ /* gamma_drv.c */
+extern int gamma_init(void);
+extern void gamma_cleanup(void);
+extern int gamma_version(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int gamma_open(struct inode *inode, struct file *filp);
+extern int gamma_release(struct inode *inode, struct file *filp);
+extern int gamma_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int gamma_lock(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int gamma_unlock(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+ /* gamma_dma.c */
+extern int gamma_dma_schedule(drm_device_t *dev, int locked);
+extern int gamma_dma(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int gamma_irq_install(drm_device_t *dev, int irq);
+extern int gamma_irq_uninstall(drm_device_t *dev);
+extern int gamma_control(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+#endif
diff --git a/drivers/char/drm/init.c b/drivers/char/drm/init.c
new file mode 100644
index 000000000..ecdf62e7c
--- /dev/null
+++ b/drivers/char/drm/init.c
@@ -0,0 +1,99 @@
+/* init.c -- Setup/Cleanup for DRM -*- linux-c -*-
+ * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:02 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/init.c,v 1.3 1999/08/20 15:07:01 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_flags = 0;
+
+/* drm_parse_option parses a single option. See description for
+ drm_parse_drm for details. */
+
+static void drm_parse_option(char *s)
+{
+ char *c, *r;
+
+ DRM_DEBUG("\"%s\"\n", s);
+ if (!s || !*s) return;
+ for (c = s; *c && *c != ':'; c++); /* find : or \0 */
+ if (*c) r = c + 1; else r = NULL; /* remember remainder */
+ *c = '\0'; /* terminate */
+ if (!strcmp(s, "noctx")) {
+ drm_flags |= DRM_FLAG_NOCTX;
+ DRM_INFO("Server-mediated context switching OFF\n");
+ return;
+ }
+ if (!strcmp(s, "debug")) {
+ drm_flags |= DRM_FLAG_DEBUG;
+ DRM_INFO("Debug messages ON\n");
+ return;
+ }
+ DRM_ERROR("\"%s\" is not a valid option\n", s);
+ return;
+}
+
+/* drm_parse_options parse the insmod "drm=" options, or the command-line
+ * options passed to the kernel via LILO. The grammar of the format is as
+ * follows:
+ *
+ * drm ::= 'drm=' option_list
+ * option_list ::= option [ ';' option_list ]
+ * option ::= 'device:' major
+ * | 'debug'
+ * | 'noctx'
+ * major ::= INTEGER
+ *
+ * Note that 's' contains option_list without the 'drm=' part.
+ *
+ * device=major,minor specifies the device number used for /dev/drm
+ * if major == 0 then the misc device is used
+ * if major == 0 and minor == 0 then dynamic misc allocation is used
+ * debug=on specifies that debugging messages will be printk'd
+ * debug=trace specifies that each function call will be logged via printk
+ * debug=off turns off all debugging options
+ *
+ */
+
+void drm_parse_options(char *s)
+{
+ char *h, *t, *n;
+
+ DRM_DEBUG("\"%s\"\n", s ?: "");
+ if (!s || !*s) return;
+
+ for (h = t = n = s; h && *h; h = n) {
+ for (; *t && *t != ';'; t++); /* find ; or \0 */
+ if (*t) n = t + 1; else n = NULL; /* remember next */
+ *t = '\0'; /* terminate */
+ drm_parse_option(h); /* parse */
+ }
+}
+
diff --git a/drivers/char/drm/ioctl.c b/drivers/char/drm/ioctl.c
new file mode 100644
index 000000000..e5bfd6953
--- /dev/null
+++ b/drivers/char/drm/ioctl.c
@@ -0,0 +1,91 @@
+/* ioctl.c -- IOCTL processing for DRM -*- linux-c -*-
+ * Created: Fri Jan 8 09:01:26 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:02 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/ioctl.c,v 1.3 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_irq_busid(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_irq_busid_t p;
+ struct pci_dev *dev;
+
+ copy_from_user_ret(&p, (drm_irq_busid_t *)arg, sizeof(p), -EFAULT);
+ dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
+ if (dev) p.irq = dev->irq;
+ else p.irq = 0;
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+ p.busnum, p.devnum, p.funcnum, p.irq);
+ copy_to_user_ret((drm_irq_busid_t *)arg, &p, sizeof(p), -EFAULT);
+ return 0;
+}
+
+int drm_getunique(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_unique_t u;
+
+ copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT);
+ if (u.unique_len >= dev->unique_len) {
+ copy_to_user_ret(u.unique, dev->unique, dev->unique_len,
+ -EFAULT);
+ }
+ u.unique_len = dev->unique_len;
+ copy_to_user_ret((drm_unique_t *)arg, &u, sizeof(u), -EFAULT);
+ return 0;
+}
+
+int drm_setunique(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_unique_t u;
+
+ if (dev->unique_len || dev->unique) return -EBUSY;
+
+ copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT);
+ if (!u.unique_len) return -EINVAL;
+
+ dev->unique_len = u.unique_len;
+ dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER);
+ copy_from_user_ret(dev->unique, u.unique, dev->unique_len,
+ -EFAULT);
+ dev->unique[dev->unique_len] = '\0';
+
+ dev->devname = drm_alloc(strlen(dev->name) + strlen(dev->unique) + 2,
+ DRM_MEM_DRIVER);
+ sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
+
+ return 0;
+}
diff --git a/drivers/char/drm/lists.c b/drivers/char/drm/lists.c
new file mode 100644
index 000000000..062631f98
--- /dev/null
+++ b/drivers/char/drm/lists.c
@@ -0,0 +1,252 @@
+/* lists.c -- Buffer list handling routines -*- linux-c -*-
+ * Created: Mon Apr 19 20:54:22 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:01 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/lists.c,v 1.3 1999/08/20 15:07:02 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_waitlist_create(drm_waitlist_t *bl, int count)
+{
+ DRM_DEBUG("%d\n", count);
+ if (bl->count) return -EINVAL;
+
+ bl->count = count;
+ bl->bufs = drm_alloc((bl->count + 2) * sizeof(*bl->bufs),
+ DRM_MEM_BUFLISTS);
+ bl->rp = bl->bufs;
+ bl->wp = bl->bufs;
+ bl->end = &bl->bufs[bl->count+1];
+ bl->write_lock = SPIN_LOCK_UNLOCKED;
+ bl->read_lock = SPIN_LOCK_UNLOCKED;
+ return 0;
+}
+
+int drm_waitlist_destroy(drm_waitlist_t *bl)
+{
+ DRM_DEBUG("\n");
+ if (bl->rp != bl->wp) return -EINVAL;
+ if (bl->bufs) drm_free(bl->bufs,
+ (bl->count + 2) * sizeof(*bl->bufs),
+ DRM_MEM_BUFLISTS);
+ bl->count = 0;
+ bl->bufs = NULL;
+ bl->rp = NULL;
+ bl->wp = NULL;
+ bl->end = NULL;
+ return 0;
+}
+
+int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf)
+{
+ int left;
+ unsigned long flags;
+
+ left = DRM_LEFTCOUNT(bl);
+ DRM_DEBUG("put %d (%d left, rp = %p, wp = %p)\n",
+ buf->idx, left, bl->rp, bl->wp);
+ if (!left) {
+ DRM_ERROR("Overflow while adding buffer %d from pid %d\n",
+ buf->idx, buf->pid);
+ return -EINVAL;
+ }
+#if DRM_DMA_HISTOGRAM
+ buf->time_queued = get_cycles();
+#endif
+ buf->list = DRM_LIST_WAIT;
+
+ spin_lock_irqsave(&bl->write_lock, flags);
+ *bl->wp = buf;
+ if (++bl->wp >= bl->end) bl->wp = bl->bufs;
+ spin_unlock_irqrestore(&bl->write_lock, flags);
+
+ return 0;
+}
+
+drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl)
+{
+ drm_buf_t *buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bl->read_lock, flags);
+ buf = *bl->rp;
+ if (bl->rp == bl->wp) {
+ spin_unlock_irqrestore(&bl->read_lock, flags);
+ return NULL;
+ }
+ if (++bl->rp >= bl->end) bl->rp = bl->bufs;
+ spin_unlock_irqrestore(&bl->read_lock, flags);
+
+ DRM_DEBUG("get %d\n", buf->idx);
+ return buf;
+}
+
+int drm_freelist_create(drm_freelist_t *bl, int count)
+{
+ DRM_DEBUG("\n");
+ atomic_set(&bl->count, 0);
+ bl->next = NULL;
+ init_waitqueue_head(&bl->waiting);
+ bl->low_mark = 0;
+ bl->high_mark = 0;
+ atomic_set(&bl->wfh, 0);
+ ++bl->initialized;
+ return 0;
+}
+
+int drm_freelist_destroy(drm_freelist_t *bl)
+{
+ DRM_DEBUG("\n");
+ atomic_set(&bl->count, 0);
+ bl->next = NULL;
+ return 0;
+}
+
+int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf)
+{
+ unsigned int old;
+ unsigned int new;
+ char failed;
+ int count = 0;
+ drm_device_dma_t *dma = dev->dma;
+
+ if (!dma) {
+ DRM_ERROR("No DMA support\n");
+ return 1;
+ }
+
+ if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) {
+ DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n",
+ buf->idx, buf->waiting, buf->pending, buf->list);
+ }
+ DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n",
+ buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh),
+ buf->waiting, buf->pending);
+ if (!bl) return 1;
+#if DRM_DMA_HISTOGRAM
+ buf->time_freed = get_cycles();
+ drm_histogram_compute(dev, buf);
+#endif
+ buf->list = DRM_LIST_FREE;
+ do {
+ old = (unsigned long)bl->next;
+ buf->next = (void *)old;
+ new = (unsigned long)buf;
+ _DRM_CAS(&bl->next, old, new, failed);
+ if (++count > DRM_LOOPING_LIMIT) {
+ DRM_ERROR("Looping\n");
+ return 1;
+ }
+ } while (failed);
+ atomic_inc(&bl->count);
+ if (atomic_read(&bl->count) > dma->buf_count) {
+ DRM_ERROR("%d of %d buffers free after addition of %d\n",
+ atomic_read(&bl->count), dma->buf_count, buf->idx);
+ return 1;
+ }
+ /* Check for high water mark */
+ if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) {
+ atomic_set(&bl->wfh, 0);
+ wake_up_interruptible(&bl->waiting);
+ }
+ return 0;
+}
+
+static drm_buf_t *drm_freelist_try(drm_freelist_t *bl)
+{
+ unsigned int old;
+ unsigned int new;
+ char failed;
+ drm_buf_t *buf;
+ int count = 0;
+
+ if (!bl) return NULL;
+
+ /* Get buffer */
+ do {
+ old = (unsigned int)bl->next;
+ if (!old) {
+ return NULL;
+ }
+ new = (unsigned long)bl->next->next;
+ _DRM_CAS(&bl->next, old, new, failed);
+ if (++count > DRM_LOOPING_LIMIT) {
+ DRM_ERROR("Looping\n");
+ return NULL;
+ }
+ } while (failed);
+ atomic_dec(&bl->count);
+
+ buf = (drm_buf_t *)old;
+ buf->next = NULL;
+ buf->list = DRM_LIST_NONE;
+ DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n",
+ buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh),
+ buf->waiting, buf->pending);
+ if (buf->waiting || buf->pending) {
+ DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n",
+ buf->idx, buf->waiting, buf->pending, buf->list);
+ }
+
+ return buf;
+}
+
+drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block)
+{
+ drm_buf_t *buf = NULL;
+ DECLARE_WAITQUEUE(entry, current);
+
+ if (!bl || !bl->initialized) return NULL;
+
+ /* Check for low water mark */
+ if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */
+ atomic_set(&bl->wfh, 1);
+ if (atomic_read(&bl->wfh)) {
+ DRM_DEBUG("Block = %d, count = %d, wfh = %d\n",
+ block, atomic_read(&bl->count),
+ atomic_read(&bl->wfh));
+ if (block) {
+ add_wait_queue(&bl->waiting, &entry);
+ current->state = TASK_INTERRUPTIBLE;
+ for (;;) {
+ if (!atomic_read(&bl->wfh)
+ && (buf = drm_freelist_try(bl))) break;
+ schedule();
+ if (signal_pending(current)) break;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&bl->waiting, &entry);
+ }
+ return buf;
+ }
+
+ DRM_DEBUG("Count = %d, wfh = %d\n",
+ atomic_read(&bl->count), atomic_read(&bl->wfh));
+ return drm_freelist_try(bl);
+}
diff --git a/drivers/char/drm/lock.c b/drivers/char/drm/lock.c
new file mode 100644
index 000000000..03931acc3
--- /dev/null
+++ b/drivers/char/drm/lock.c
@@ -0,0 +1,227 @@
+/* lock.c -- IOCTLs for locking -*- linux-c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:01 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/lock.c,v 1.5 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_block(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ DRM_DEBUG("\n");
+ return 0;
+}
+
+int drm_unblock(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ DRM_DEBUG("\n");
+ return 0;
+}
+
+int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
+{
+ unsigned int old;
+ unsigned int new;
+ char failed;
+
+ DRM_DEBUG("%d attempts\n", context);
+ do {
+ old = *lock;
+ if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
+ else new = context | _DRM_LOCK_HELD;
+ _DRM_CAS(lock, old, new, failed);
+ } while (failed);
+ if (_DRM_LOCKING_CONTEXT(old) == context) {
+ if (old & _DRM_LOCK_HELD) {
+ if (context != DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("%d holds heavyweight lock\n",
+ context);
+ }
+ return 0;
+ }
+ }
+ if (new == (context | _DRM_LOCK_HELD)) {
+ /* Have lock */
+ DRM_DEBUG("%d\n", context);
+ return 1;
+ }
+ DRM_DEBUG("%d unable to get lock held by %d\n",
+ context, _DRM_LOCKING_CONTEXT(old));
+ return 0;
+}
+
+/* This takes a lock forcibly and hands it to context. Should ONLY be used
+ inside *_unlock to give lock to kernel before calling *_dma_schedule. */
+int drm_lock_transfer(__volatile__ unsigned int *lock, unsigned int context)
+{
+ unsigned int old;
+ unsigned int new;
+ char failed;
+
+ do {
+ old = *lock;
+ new = context | _DRM_LOCK_HELD;
+ _DRM_CAS(lock, old, new, failed);
+ } while (failed);
+ DRM_DEBUG("%d => %d\n", _DRM_LOCKING_CONTEXT(old), context);
+ return 1;
+}
+
+int drm_lock_free(drm_device_t *dev,
+ __volatile__ unsigned int *lock, unsigned int context)
+{
+ unsigned int old;
+ unsigned int new;
+ char failed;
+
+ DRM_DEBUG("%d\n", context);
+ do {
+ old = *lock;
+ new = 0;
+ _DRM_CAS(lock, old, new, failed);
+ } while (failed);
+ if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
+ DRM_ERROR("%d freed heavyweight lock held by %d\n",
+ context,
+ _DRM_LOCKING_CONTEXT(old));
+ return 1;
+ }
+ dev->lock.pid = 0;
+ wake_up_interruptible(&dev->lock.lock_queue);
+ return 0;
+}
+
+static int drm_flush_queue(drm_device_t *dev, int context)
+{
+ DECLARE_WAITQUEUE(entry, current);
+ int ret = 0;
+ drm_queue_t *q = dev->queuelist[context];
+
+ DRM_DEBUG("\n");
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) > 1) {
+ atomic_inc(&q->block_write);
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&q->flush_queue, &entry);
+ atomic_inc(&q->block_count);
+ for (;;) {
+ if (!DRM_BUFCOUNT(&q->waitlist)) break;
+ schedule();
+ if (signal_pending(current)) {
+ ret = -EINTR; /* Can't restart */
+ break;
+ }
+ }
+ atomic_dec(&q->block_count);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&q->flush_queue, &entry);
+ }
+ atomic_dec(&q->use_count);
+ atomic_inc(&q->total_flushed);
+
+ /* NOTE: block_write is still incremented!
+ Use drm_flush_unlock_queue to decrement. */
+ return ret;
+}
+
+static int drm_flush_unblock_queue(drm_device_t *dev, int context)
+{
+ drm_queue_t *q = dev->queuelist[context];
+
+ DRM_DEBUG("\n");
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) > 1) {
+ if (atomic_read(&q->block_write)) {
+ atomic_dec(&q->block_write);
+ wake_up_interruptible(&q->write_queue);
+ }
+ }
+ atomic_dec(&q->use_count);
+ return 0;
+}
+
+int drm_flush_block_and_flush(drm_device_t *dev, int context,
+ drm_lock_flags_t flags)
+{
+ int ret = 0;
+ int i;
+
+ DRM_DEBUG("\n");
+
+ if (flags & _DRM_LOCK_FLUSH) {
+ ret = drm_flush_queue(dev, DRM_KERNEL_CONTEXT);
+ if (!ret) ret = drm_flush_queue(dev, context);
+ }
+ if (flags & _DRM_LOCK_FLUSH_ALL) {
+ for (i = 0; !ret && i < dev->queue_count; i++) {
+ ret = drm_flush_queue(dev, i);
+ }
+ }
+ return ret;
+}
+
+int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags)
+{
+ int ret = 0;
+ int i;
+
+ DRM_DEBUG("\n");
+
+ if (flags & _DRM_LOCK_FLUSH) {
+ ret = drm_flush_unblock_queue(dev, DRM_KERNEL_CONTEXT);
+ if (!ret) ret = drm_flush_unblock_queue(dev, context);
+ }
+ if (flags & _DRM_LOCK_FLUSH_ALL) {
+ for (i = 0; !ret && i < dev->queue_count; i++) {
+ ret = drm_flush_unblock_queue(dev, i);
+ }
+ }
+
+ return ret;
+}
+
+int drm_finish(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int ret = 0;
+ drm_lock_t lock;
+
+ DRM_DEBUG("\n");
+
+ copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+ ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+ drm_flush_unblock(dev, lock.context, lock.flags);
+ return ret;
+}
diff --git a/drivers/char/drm/memory.c b/drivers/char/drm/memory.c
new file mode 100644
index 000000000..f7b5335a5
--- /dev/null
+++ b/drivers/char/drm/memory.c
@@ -0,0 +1,320 @@
+/* memory.c -- Memory management wrappers for DRM -*- linux-c -*-
+ * Created: Thu Feb 4 14:00:34 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 13:04:33 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/memory.c,v 1.4 1999/08/20 20:00:53 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+typedef struct drm_mem_stats {
+ const char *name;
+ int succeed_count;
+ int free_count;
+ int fail_count;
+ unsigned long bytes_allocated;
+ unsigned long bytes_freed;
+} drm_mem_stats_t;
+
+static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long drm_ram_available = 0;
+static unsigned long drm_ram_used = 0;
+static drm_mem_stats_t drm_mem_stats[] = {
+ [DRM_MEM_DMA] = { "dmabufs" },
+ [DRM_MEM_SAREA] = { "sareas" },
+ [DRM_MEM_DRIVER] = { "driver" },
+ [DRM_MEM_MAGIC] = { "magic" },
+ [DRM_MEM_IOCTLS] = { "ioctltab" },
+ [DRM_MEM_MAPS] = { "maplist" },
+ [DRM_MEM_VMAS] = { "vmalist" },
+ [DRM_MEM_BUFS] = { "buflist" },
+ [DRM_MEM_SEGS] = { "seglist" },
+ [DRM_MEM_PAGES] = { "pagelist" },
+ [DRM_MEM_FILES] = { "files" },
+ [DRM_MEM_QUEUES] = { "queues" },
+ [DRM_MEM_CMDS] = { "commands" },
+ [DRM_MEM_MAPPINGS] = { "mappings" },
+ [DRM_MEM_BUFLISTS] = { "buflists" },
+ { NULL, 0, } /* Last entry must be null */
+};
+
+void drm_mem_init(void)
+{
+ drm_mem_stats_t *mem;
+ struct sysinfo si;
+
+ for (mem = drm_mem_stats; mem->name; ++mem) {
+ mem->succeed_count = 0;
+ mem->free_count = 0;
+ mem->fail_count = 0;
+ mem->bytes_allocated = 0;
+ mem->bytes_freed = 0;
+ }
+
+ si_meminfo(&si);
+ drm_ram_available = si.totalram;
+ drm_ram_used = 0;
+}
+
+/* drm_mem_info is called whenever a process reads /dev/drm/mem. */
+
+static int _drm_mem_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_mem_stats_t *pt;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT(" total counts "
+ " | outstanding \n");
+ DRM_PROC_PRINT("type alloc freed fail bytes freed"
+ " | allocs bytes\n\n");
+ DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu |\n",
+ "system", 0, 0, 0, drm_ram_available);
+ DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu |\n",
+ "locked", 0, 0, 0, drm_ram_used);
+ DRM_PROC_PRINT("\n");
+ for (pt = drm_mem_stats; pt->name; pt++) {
+ DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n",
+ pt->name,
+ pt->succeed_count,
+ pt->free_count,
+ pt->fail_count,
+ pt->bytes_allocated,
+ pt->bytes_freed,
+ pt->succeed_count - pt->free_count,
+ (long)pt->bytes_allocated
+ - (long)pt->bytes_freed);
+ }
+
+ return len;
+}
+
+int drm_mem_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ int ret;
+
+ spin_lock(&drm_mem_lock);
+ ret = _drm_mem_info(buf, start, offset, len, eof, data);
+ spin_unlock(&drm_mem_lock);
+ return ret;
+}
+
+void *drm_alloc(size_t size, int area)
+{
+ void *pt;
+
+ if (!size) {
+ DRM_MEM_ERROR(area, "Allocating 0 bytes\n");
+ return NULL;
+ }
+
+ if (!(pt = kmalloc(size, GFP_KERNEL))) {
+ spin_lock(&drm_mem_lock);
+ ++drm_mem_stats[area].fail_count;
+ spin_unlock(&drm_mem_lock);
+ return NULL;
+ }
+ spin_lock(&drm_mem_lock);
+ ++drm_mem_stats[area].succeed_count;
+ drm_mem_stats[area].bytes_allocated += size;
+ spin_unlock(&drm_mem_lock);
+ return pt;
+}
+
+void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
+{
+ void *pt;
+
+ if (!(pt = drm_alloc(size, area))) return NULL;
+ if (oldpt && oldsize) {
+ memcpy(pt, oldpt, oldsize);
+ drm_free(oldpt, oldsize, area);
+ }
+ return pt;
+}
+
+char *drm_strdup(const char *s, int area)
+{
+ char *pt;
+ int length = s ? strlen(s) : 0;
+
+ if (!(pt = drm_alloc(length+1, area))) return NULL;
+ strcpy(pt, s);
+ return pt;
+}
+
+void drm_strfree(const char *s, int area)
+{
+ unsigned int size;
+
+ if (!s) return;
+
+ size = 1 + (s ? strlen(s) : 0);
+ drm_free((void *)s, size, area);
+}
+
+void drm_free(void *pt, size_t size, int area)
+{
+ int alloc_count;
+ int free_count;
+
+ if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n");
+ else kfree_s(pt, size);
+ spin_lock(&drm_mem_lock);
+ drm_mem_stats[area].bytes_freed += size;
+ free_count = ++drm_mem_stats[area].free_count;
+ alloc_count = drm_mem_stats[area].succeed_count;
+ spin_unlock(&drm_mem_lock);
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+}
+
+unsigned long drm_alloc_pages(int order, int area)
+{
+ unsigned long address;
+ unsigned long bytes = PAGE_SIZE << order;
+ unsigned long addr;
+ unsigned int sz;
+
+ spin_lock(&drm_mem_lock);
+ if (drm_ram_used > +(DRM_RAM_PERCENT * drm_ram_available) / 100) {
+ spin_unlock(&drm_mem_lock);
+ return 0;
+ }
+ spin_unlock(&drm_mem_lock);
+
+ address = __get_free_pages(GFP_KERNEL, order);
+ if (!address) {
+ spin_lock(&drm_mem_lock);
+ ++drm_mem_stats[area].fail_count;
+ spin_unlock(&drm_mem_lock);
+ return 0;
+ }
+ spin_lock(&drm_mem_lock);
+ ++drm_mem_stats[area].succeed_count;
+ drm_mem_stats[area].bytes_allocated += bytes;
+ drm_ram_used += bytes;
+ spin_unlock(&drm_mem_lock);
+
+
+ /* Zero outside the lock */
+ memset((void *)address, 0, bytes);
+
+ /* Reserve */
+ for (addr = address, sz = bytes;
+ sz > 0;
+ addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+ mem_map_reserve(MAP_NR(addr));
+ }
+
+ return address;
+}
+
+void drm_free_pages(unsigned long address, int order, int area)
+{
+ unsigned long bytes = PAGE_SIZE << order;
+ int alloc_count;
+ int free_count;
+ unsigned long addr;
+ unsigned int sz;
+
+ if (!address) {
+ DRM_MEM_ERROR(area, "Attempt to free address 0\n");
+ } else {
+ /* Unreserve */
+ for (addr = address, sz = bytes;
+ sz > 0;
+ addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+ mem_map_unreserve(MAP_NR(addr));
+ }
+ free_pages(address, order);
+ }
+
+ spin_lock(&drm_mem_lock);
+ free_count = ++drm_mem_stats[area].free_count;
+ alloc_count = drm_mem_stats[area].succeed_count;
+ drm_mem_stats[area].bytes_freed += bytes;
+ drm_ram_used -= bytes;
+ spin_unlock(&drm_mem_lock);
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(area,
+ "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+}
+
+void *drm_ioremap(unsigned long offset, unsigned long size)
+{
+ void *pt;
+
+ if (!size) {
+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+ "Mapping 0 bytes at 0x%08lx\n", offset);
+ return NULL;
+ }
+
+ if (!(pt = ioremap(offset, size))) {
+ spin_lock(&drm_mem_lock);
+ ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
+ spin_unlock(&drm_mem_lock);
+ return NULL;
+ }
+ spin_lock(&drm_mem_lock);
+ ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
+ drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
+ spin_unlock(&drm_mem_lock);
+ return pt;
+}
+
+void drm_ioremapfree(void *pt, unsigned long size)
+{
+ int alloc_count;
+ int free_count;
+
+ if (!pt)
+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+ "Attempt to free NULL pointer\n");
+ else
+ iounmap(pt);
+
+ spin_lock(&drm_mem_lock);
+ drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
+ free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
+ alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
+ spin_unlock(&drm_mem_lock);
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+ "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+}
diff --git a/drivers/char/drm/proc.c b/drivers/char/drm/proc.c
new file mode 100644
index 000000000..7db90aea8
--- /dev/null
+++ b/drivers/char/drm/proc.c
@@ -0,0 +1,568 @@
+/* proc.c -- /proc support for DRM -*- linux-c -*-
+ * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:48 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/proc.c,v 1.4 1999/08/20 15:36:46 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static struct proc_dir_entry *drm_root = NULL;
+static struct proc_dir_entry *drm_dev_root = NULL;
+static char drm_slot_name[64];
+
+static int drm_name_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+static int drm_vm_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+static int drm_clients_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+static int drm_queues_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+static int drm_bufs_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+#if DRM_DEBUG_CODE
+static int drm_vma_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+#endif
+#if DRM_DMA_HISTOGRAM
+static int drm_histo_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+#endif
+
+struct drm_proc_list {
+ const char *name;
+ int (*f)(char *, char **, off_t, int, int *, void *);
+} drm_proc_list[] = {
+ { "name", drm_name_info },
+ { "mem", drm_mem_info },
+ { "vm", drm_vm_info },
+ { "clients", drm_clients_info },
+ { "queues", drm_queues_info },
+ { "bufs", drm_bufs_info },
+#if DRM_DEBUG_CODE
+ { "vma", drm_vma_info },
+#endif
+#if DRM_DMA_HISTOGRAM
+ { "histo", drm_histo_info },
+#endif
+};
+#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
+
+int drm_proc_init(drm_device_t *dev)
+{
+ struct proc_dir_entry *ent;
+ int i, j;
+
+ drm_root = create_proc_entry("video", S_IFDIR, NULL);
+ if (!drm_root) {
+ DRM_ERROR("Cannot create /proc/video\n");
+ return -1;
+ }
+
+ /* Instead of doing this search, we should
+ add some global support for /proc/video. */
+ for (i = 0; i < 8; i++) {
+ sprintf(drm_slot_name, "video/%d", i);
+ drm_dev_root = create_proc_entry(drm_slot_name, S_IFDIR, NULL);
+ if (!drm_dev_root) {
+ DRM_ERROR("Cannot create /proc/%s\n", drm_slot_name);
+ remove_proc_entry("video", NULL);
+ }
+ if (drm_dev_root->nlink == 2) break;
+ drm_dev_root = NULL;
+ }
+ if (!drm_dev_root) {
+ DRM_ERROR("Cannot find slot in /proc/video\n");
+ return -1;
+ }
+
+ for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+ ent = create_proc_entry(drm_proc_list[i].name,
+ S_IFREG|S_IRUGO, drm_dev_root);
+ if (!ent) {
+ DRM_ERROR("Cannot create /proc/%s/%s\n",
+ drm_slot_name, drm_proc_list[i].name);
+ for (j = 0; j < i; j++)
+ remove_proc_entry(drm_proc_list[i].name,
+ drm_dev_root);
+ remove_proc_entry(drm_slot_name, NULL);
+ remove_proc_entry("video", NULL);
+ return -1;
+ }
+ ent->read_proc = drm_proc_list[i].f;
+ ent->data = dev;
+ }
+
+ return 0;
+}
+
+
+int drm_proc_cleanup(void)
+{
+ int i;
+
+ if (drm_root) {
+ if (drm_dev_root) {
+ for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+ remove_proc_entry(drm_proc_list[i].name,
+ drm_dev_root);
+ }
+ remove_proc_entry(drm_slot_name, NULL);
+ }
+ remove_proc_entry("video", NULL);
+ remove_proc_entry(DRM_NAME, NULL);
+ }
+ drm_root = drm_dev_root = NULL;
+ return 0;
+}
+
+static int drm_name_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+
+ if (dev->unique) {
+ DRM_PROC_PRINT("%s 0x%x %s\n",
+ dev->name, dev->device, dev->unique);
+ } else {
+ DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device);
+ }
+ return len;
+}
+
+static int _drm_vm_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ drm_map_t *map;
+ const char *types[] = { "FB", "REG", "SHM" };
+ const char *type;
+ int i;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT("slot offset size type flags "
+ "address mtrr\n\n");
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ if (map->type < 0 || map->type > 2) type = "??";
+ else type = types[map->type];
+ DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ",
+ i,
+ map->offset,
+ map->size,
+ type,
+ map->flags,
+ (unsigned long)map->handle);
+ if (map->mtrr < 0) {
+ DRM_PROC_PRINT("none\n");
+ } else {
+ DRM_PROC_PRINT("%4d\n", map->mtrr);
+ }
+ }
+
+ return len;
+}
+
+static int drm_vm_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_vm_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+
+static int _drm_queues_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int i;
+ drm_queue_t *q;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT(" ctx/flags use fin"
+ " blk/rw/rwf wait flushed queued"
+ " locks\n\n");
+ for (i = 0; i < dev->queue_count; i++) {
+ q = dev->queuelist[i];
+ atomic_inc(&q->use_count);
+ DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
+ "%5d/0x%03x %5d %5d"
+ " %5d/%c%c/%c%c%c %5d %10d %10d %10d\n",
+ i,
+ q->flags,
+ atomic_read(&q->use_count),
+ atomic_read(&q->finalization),
+ atomic_read(&q->block_count),
+ atomic_read(&q->block_read) ? 'r' : '-',
+ atomic_read(&q->block_write) ? 'w' : '-',
+ waitqueue_active(&q->read_queue) ? 'r':'-',
+ waitqueue_active(&q->write_queue) ? 'w':'-',
+ waitqueue_active(&q->flush_queue) ? 'f':'-',
+ DRM_BUFCOUNT(&q->waitlist),
+ atomic_read(&q->total_flushed),
+ atomic_read(&q->total_queued),
+ atomic_read(&q->total_locks));
+ atomic_dec(&q->use_count);
+ }
+
+ return len;
+}
+
+static int drm_queues_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_queues_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+/* drm_bufs_info is called whenever a process reads
+ /dev/drm/<dev>/bufs. */
+
+static int _drm_bufs_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+
+ if (!dma) return 0;
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT(" o size count free segs pages kB\n\n");
+ for (i = 0; i <= DRM_MAX_ORDER; i++) {
+ if (dma->bufs[i].buf_count)
+ DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
+ i,
+ dma->bufs[i].buf_size,
+ dma->bufs[i].buf_count,
+ atomic_read(&dma->bufs[i]
+ .freelist.count),
+ dma->bufs[i].seg_count,
+ dma->bufs[i].seg_count
+ *(1 << dma->bufs[i].page_order),
+ (dma->bufs[i].seg_count
+ * (1 << dma->bufs[i].page_order))
+ * PAGE_SIZE / 1024);
+ }
+ DRM_PROC_PRINT("\n");
+ for (i = 0; i < dma->buf_count; i++) {
+ if (i && !(i%32)) DRM_PROC_PRINT("\n");
+ DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
+ }
+ DRM_PROC_PRINT("\n");
+
+ return len;
+}
+
+static int drm_bufs_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_bufs_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+
+static int _drm_clients_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ drm_file_t *priv;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n");
+ for (priv = dev->file_first; priv; priv = priv->next) {
+ DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
+ priv->authenticated ? 'y' : 'n',
+ priv->minor,
+ priv->pid,
+ priv->uid,
+ priv->magic,
+ priv->ioctl_count);
+ }
+
+ return len;
+}
+
+static int drm_clients_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_clients_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+#if DRM_DEBUG_CODE
+
+static int _drm_vma_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ drm_vma_entry_t *pt;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long i;
+ struct vm_area_struct *vma;
+ unsigned long address;
+#if defined(__i386__)
+ unsigned int pgprot;
+#endif
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
+ atomic_read(&dev->vma_count),
+ high_memory, virt_to_phys(high_memory));
+ for (pt = dev->vmalist; pt; pt = pt->next) {
+ if (!(vma = pt->vma)) continue;
+ DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+ pt->pid,
+ vma->vm_start,
+ vma->vm_end,
+ vma->vm_flags & VM_READ ? 'r' : '-',
+ vma->vm_flags & VM_WRITE ? 'w' : '-',
+ vma->vm_flags & VM_EXEC ? 'x' : '-',
+ vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
+ vma->vm_flags & VM_LOCKED ? 'l' : '-',
+ vma->vm_flags & VM_IO ? 'i' : '-',
+ vma->vm_offset );
+#if defined(__i386__)
+ pgprot = pgprot_val(vma->vm_page_prot);
+ DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
+ pgprot & _PAGE_PRESENT ? 'p' : '-',
+ pgprot & _PAGE_RW ? 'w' : 'r',
+ pgprot & _PAGE_USER ? 'u' : 's',
+ pgprot & _PAGE_PWT ? 't' : 'b',
+ pgprot & _PAGE_PCD ? 'u' : 'c',
+ pgprot & _PAGE_ACCESSED ? 'a' : '-',
+ pgprot & _PAGE_DIRTY ? 'd' : '-',
+ pgprot & _PAGE_4M ? 'm' : 'k',
+ pgprot & _PAGE_GLOBAL ? 'g' : 'l' );
+#endif
+ DRM_PROC_PRINT("\n");
+ for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
+ pgd = pgd_offset(vma->vm_mm, i);
+ pmd = pmd_offset(pgd, i);
+ pte = pte_offset(pmd, i);
+ if (pte_present(*pte)) {
+ address = __pa(pte_page(*pte))
+ + (i & (PAGE_SIZE-1));
+ DRM_PROC_PRINT(" 0x%08lx -> 0x%08lx"
+ " %c%c%c%c%c\n",
+ i,
+ address,
+ pte_read(*pte) ? 'r' : '-',
+ pte_write(*pte) ? 'w' : '-',
+ pte_exec(*pte) ? 'x' : '-',
+ pte_dirty(*pte) ? 'd' : '-',
+ pte_young(*pte) ? 'a' : '-' );
+ } else {
+ DRM_PROC_PRINT(" 0x%08lx\n", i);
+ }
+ }
+ }
+
+ return len;
+}
+
+static int drm_vma_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_vma_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+#endif
+
+
+#if DRM_DMA_HISTOGRAM
+static int _drm_histo_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+ unsigned long slot_value = DRM_DMA_HISTOGRAM_INITIAL;
+ unsigned long prev_value = 0;
+ drm_buf_t *buffer;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+
+ DRM_PROC_PRINT("general statistics:\n");
+ DRM_PROC_PRINT("total %10u\n", atomic_read(&dev->histo.total));
+ DRM_PROC_PRINT("open %10u\n", atomic_read(&dev->total_open));
+ DRM_PROC_PRINT("close %10u\n", atomic_read(&dev->total_close));
+ DRM_PROC_PRINT("ioctl %10u\n", atomic_read(&dev->total_ioctl));
+ DRM_PROC_PRINT("irq %10u\n", atomic_read(&dev->total_irq));
+ DRM_PROC_PRINT("ctx %10u\n", atomic_read(&dev->total_ctx));
+
+ DRM_PROC_PRINT("\nlock statistics:\n");
+ DRM_PROC_PRINT("locks %10u\n", atomic_read(&dev->total_locks));
+ DRM_PROC_PRINT("unlocks %10u\n", atomic_read(&dev->total_unlocks));
+ DRM_PROC_PRINT("contends %10u\n", atomic_read(&dev->total_contends));
+ DRM_PROC_PRINT("sleeps %10u\n", atomic_read(&dev->total_sleeps));
+
+
+ if (dma) {
+ DRM_PROC_PRINT("\ndma statistics:\n");
+ DRM_PROC_PRINT("prio %10u\n",
+ atomic_read(&dma->total_prio));
+ DRM_PROC_PRINT("bytes %10u\n",
+ atomic_read(&dma->total_bytes));
+ DRM_PROC_PRINT("dmas %10u\n",
+ atomic_read(&dma->total_dmas));
+ DRM_PROC_PRINT("missed:\n");
+ DRM_PROC_PRINT(" dma %10u\n",
+ atomic_read(&dma->total_missed_dma));
+ DRM_PROC_PRINT(" lock %10u\n",
+ atomic_read(&dma->total_missed_lock));
+ DRM_PROC_PRINT(" free %10u\n",
+ atomic_read(&dma->total_missed_free));
+ DRM_PROC_PRINT(" sched %10u\n",
+ atomic_read(&dma->total_missed_sched));
+ DRM_PROC_PRINT("tried %10u\n",
+ atomic_read(&dma->total_tried));
+ DRM_PROC_PRINT("hit %10u\n",
+ atomic_read(&dma->total_hit));
+ DRM_PROC_PRINT("lost %10u\n",
+ atomic_read(&dma->total_lost));
+
+ buffer = dma->next_buffer;
+ if (buffer) {
+ DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx);
+ } else {
+ DRM_PROC_PRINT("next_buffer none\n");
+ }
+ buffer = dma->this_buffer;
+ if (buffer) {
+ DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx);
+ } else {
+ DRM_PROC_PRINT("this_buffer none\n");
+ }
+ }
+
+
+ DRM_PROC_PRINT("\nvalues:\n");
+ if (dev->lock.hw_lock) {
+ DRM_PROC_PRINT("lock 0x%08x\n",
+ dev->lock.hw_lock->lock);
+ } else {
+ DRM_PROC_PRINT("lock none\n");
+ }
+ DRM_PROC_PRINT("context_flag 0x%08x\n", dev->context_flag);
+ DRM_PROC_PRINT("interrupt_flag 0x%08x\n", dev->interrupt_flag);
+ DRM_PROC_PRINT("dma_flag 0x%08x\n", dev->dma_flag);
+
+ DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count);
+ DRM_PROC_PRINT("last_context %10d\n", dev->last_context);
+ DRM_PROC_PRINT("last_switch %10lu\n", dev->last_switch);
+ DRM_PROC_PRINT("last_checked %10d\n", dev->last_checked);
+
+
+ DRM_PROC_PRINT("\n q2d d2c c2f"
+ " q2c q2f dma sch"
+ " ctx lacq lhld\n\n");
+ for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) {
+ DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u"
+ " %10u %10u %10u %10u %10u\n",
+ i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ",
+ i == DRM_DMA_HISTOGRAM_SLOTS - 1
+ ? prev_value : slot_value ,
+
+ atomic_read(&dev->histo
+ .queued_to_dispatched[i]),
+ atomic_read(&dev->histo
+ .dispatched_to_completed[i]),
+ atomic_read(&dev->histo
+ .completed_to_freed[i]),
+
+ atomic_read(&dev->histo
+ .queued_to_completed[i]),
+ atomic_read(&dev->histo
+ .queued_to_freed[i]),
+ atomic_read(&dev->histo.dma[i]),
+ atomic_read(&dev->histo.schedule[i]),
+ atomic_read(&dev->histo.ctx[i]),
+ atomic_read(&dev->histo.lacq[i]),
+ atomic_read(&dev->histo.lhld[i]));
+ prev_value = slot_value;
+ slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value);
+ }
+ return len;
+}
+
+static int drm_histo_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_histo_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+#endif
diff --git a/drivers/char/drm/sigio.c b/drivers/char/drm/sigio.c
new file mode 100644
index 000000000..bb75087df
--- /dev/null
+++ b/drivers/char/drm/sigio.c
@@ -0,0 +1,82 @@
+/* sigio.c -- Support for SIGIO handler -*- linux-c -*-
+ * Created: Thu Jun 3 15:39:18 1999 by faith@precisioninsight.com
+ * Revised: Thu Jun 3 16:16:35 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/shared/sigio.c,v 1.2 1999/06/14 21:11:29 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/sigio.c,v 1.2 1999/06/14 12:02:11 dawes Exp $
+ *
+ */
+
+
+#ifdef XFree86Server
+# include "X.h"
+# include "xf86.h"
+# include "xf86drm.h"
+# include "xf86_OSlib.h"
+# include "xf86drm.h"
+#else
+# include <unistd.h>
+# include <signal.h>
+# include <fcntl.h>
+#endif
+
+/*
+ * Linux libc5 defines FASYNC, but not O_ASYNC. Don't know if it is
+ * functional or not.
+ */
+#if defined(FASYNC) && !defined(O_ASYNC)
+# define O_ASYNC FASYNC
+#endif
+
+int
+xf86InstallSIGIOHandler(int fd, void (*f)(int))
+{
+ struct sigaction sa;
+ struct sigaction osa;
+
+ sigemptyset(&sa.sa_mask);
+ sigaddset(&sa.sa_mask, SIGIO);
+ sa.sa_flags = 0;
+ sa.sa_handler = f;
+ sigaction(SIGIO, &sa, &osa);
+ fcntl(fd, F_SETOWN, getpid());
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC);
+ return 0;
+}
+
+int
+xf86RemoveSIGIOHandler(int fd)
+{
+ struct sigaction sa;
+ struct sigaction osa;
+
+ sigemptyset(&sa.sa_mask);
+ sigaddset(&sa.sa_mask, SIGIO);
+ sa.sa_flags = 0;
+ sa.sa_handler = SIG_DFL;
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_ASYNC);
+ sigaction(SIGIO, &sa, &osa);
+ return 0;
+}
diff --git a/drivers/char/drm/vm.c b/drivers/char/drm/vm.c
new file mode 100644
index 000000000..55bfc4c45
--- /dev/null
+++ b/drivers/char/drm/vm.c
@@ -0,0 +1,264 @@
+/* vm.c -- Memory mapping for DRM -*- linux-c -*-
+ * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 22:48:11 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/vm.c,v 1.7 1999/08/21 02:48:34 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+struct vm_operations_struct drm_vm_ops = {
+ nopage: drm_vm_nopage,
+ open: drm_vm_open,
+ close: drm_vm_close,
+};
+
+struct vm_operations_struct drm_vm_shm_ops = {
+ nopage: drm_vm_shm_nopage,
+ open: drm_vm_open,
+ close: drm_vm_close,
+};
+
+struct vm_operations_struct drm_vm_dma_ops = {
+ nopage: drm_vm_dma_nopage,
+ open: drm_vm_open,
+ close: drm_vm_close,
+};
+
+unsigned long drm_vm_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+{
+ DRM_DEBUG("0x%08lx, %d\n", address, write_access);
+
+ return 0; /* Disallow mremap */
+}
+
+unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+ unsigned long physical;
+ unsigned long offset;
+ unsigned long page;
+
+ if (address > vma->vm_end) return 0; /* Disallow mremap */
+ if (!dev->lock.hw_lock) return 0; /* Nothing allocated */
+
+ offset = address - vma->vm_start;
+ page = offset >> PAGE_SHIFT;
+ physical = (unsigned long)dev->lock.hw_lock + (offset & (~PAGE_MASK));
+ atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */
+
+ DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
+ return physical;
+}
+
+unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ unsigned long physical;
+ unsigned long offset;
+ unsigned long page;
+
+ if (!dma) return 0; /* Error */
+ if (address > vma->vm_end) return 0; /* Disallow mremap */
+ if (!dma->pagelist) return 0; /* Nothing allocated */
+
+ offset = address - vma->vm_start; /* vm_offset should be 0 */
+ page = offset >> PAGE_SHIFT;
+ physical = dma->pagelist[page] + (offset & (~PAGE_MASK));
+ atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */
+
+ DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
+ return physical;
+}
+
+void drm_vm_open(struct vm_area_struct *vma)
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+#if DRM_DEBUG_CODE
+ drm_vma_entry_t *vma_entry;
+#endif
+
+ DRM_DEBUG("0x%08lx,0x%08lx\n",
+ vma->vm_start, vma->vm_end - vma->vm_start);
+ atomic_inc(&dev->vma_count);
+ MOD_INC_USE_COUNT;
+
+#if DRM_DEBUG_CODE
+ vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
+ if (vma_entry) {
+ down(&dev->struct_sem);
+ vma_entry->vma = vma;
+ vma_entry->next = dev->vmalist;
+ vma_entry->pid = current->pid;
+ dev->vmalist = vma_entry;
+ up(&dev->struct_sem);
+ }
+#endif
+}
+
+void drm_vm_close(struct vm_area_struct *vma)
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+#if DRM_DEBUG_CODE
+ drm_vma_entry_t *pt, *prev;
+#endif
+
+ DRM_DEBUG("0x%08lx,0x%08lx\n",
+ vma->vm_start, vma->vm_end - vma->vm_start);
+ MOD_DEC_USE_COUNT;
+ atomic_dec(&dev->vma_count);
+
+#if DRM_DEBUG_CODE
+ down(&dev->struct_sem);
+ for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
+ if (pt->vma == vma) {
+ if (prev) {
+ prev->next = pt->next;
+ } else {
+ dev->vmalist = pt->next;
+ }
+ drm_free(pt, sizeof(*pt), DRM_MEM_VMAS);
+ break;
+ }
+ }
+ up(&dev->struct_sem);
+#endif
+}
+
+int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ unsigned long length = vma->vm_end - vma->vm_start;
+
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, vma->vm_offset);
+
+ /* Length must match exact page count */
+ if ((length >> PAGE_SHIFT) != dma->page_count) return -EINVAL;
+
+ vma->vm_ops = &drm_vm_dma_ops;
+ vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+
+#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
+ /* In Linux 2.2.3 and above, this is
+ handled in do_mmap() in mm/mmap.c. */
+ ++filp->f_count;
+#endif
+ vma->vm_file = filp; /* Needed for drm_vm_open() */
+ drm_vm_open(vma);
+ return 0;
+}
+
+int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_map_t *map = NULL;
+ int i;
+
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, vma->vm_offset);
+
+ if (!vma->vm_offset) return drm_mmap_dma(filp, vma);
+
+ /* A sequential search of a linked list is
+ fine here because: 1) there will only be
+ about 5-10 entries in the list and, 2) a
+ DRI client only has to do this mapping
+ once, so it doesn't have to be optimized
+ for performance, even if the list was a
+ bit longer. */
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ if (map->offset == vma->vm_offset) break;
+ }
+
+ if (i >= dev->map_count) return -EINVAL;
+ if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
+ return -EPERM;
+
+ /* Check for valid size. */
+ if (map->size != vma->vm_end - vma->vm_start) return -EINVAL;
+
+
+ switch (map->type) {
+ case _DRM_FRAME_BUFFER:
+ case _DRM_REGISTERS:
+ if (vma->vm_offset >= __pa(high_memory)) {
+#if defined(__i386__)
+ if (boot_cpu_data.x86 > 3) {
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+ pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
+ }
+#endif
+ vma->vm_flags |= VM_IO; /* not in core dump */
+ }
+ if (remap_page_range(vma->vm_start,
+ vma->vm_offset,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+ vma->vm_ops = &drm_vm_ops;
+ break;
+ case _DRM_SHM:
+ vma->vm_ops = &drm_vm_shm_ops;
+ /* Don't let this area swap. Change when
+ DRM_KERNEL advisory is supported. */
+ vma->vm_flags |= VM_LOCKED;
+ break;
+ default:
+ return -EINVAL; /* This should never happen. */
+ }
+ vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+ if (map->flags & _DRM_READ_ONLY) {
+ pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
+ }
+
+
+#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
+ /* In Linux 2.2.3 and above, this is
+ handled in do_mmap() in mm/mmap.c. */
+ ++filp->f_count;
+#endif
+ vma->vm_file = filp; /* Needed for drm_vm_open() */
+ drm_vm_open(vma);
+ return 0;
+}
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 4df4a1e2b..30a76a04e 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -534,6 +534,8 @@ int __init dsp56k_init(void)
dsp56k.in_use = 0;
printk("DSP56k driver installed\n");
+
+ return 0;
}
#ifdef MODULE
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index abb8c5f35..8261e4ef2 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -1367,7 +1367,7 @@ static int block_til_ready(struct tty_struct *tty,
while(1)
{ /* Begin forever while */
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(ch->asyncflags & ASYNC_INITIALIZED))
@@ -3233,7 +3233,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
if (error)
return error;
- putUser(mflag, (unsigned long *) arg);
+ putUser(mflag, (unsigned int *) arg);
break;
@@ -4049,12 +4049,12 @@ int get_PCI_configuration(unsigned char bus, unsigned char device_fn,
if (!dev)
return(0);
- *base_addr0 = dev->base_address[0];
- *base_addr1 = dev->base_address[1];
- *base_addr2 = dev->base_address[2];
- *base_addr3 = dev->base_address[3];
- *base_addr4 = dev->base_address[4];
- *base_addr5 = dev->base_address[5];
+ *base_addr0 = dev->resource[0].start;
+ *base_addr1 = dev->resource[1].start;
+ *base_addr2 = dev->resource[2].start;
+ *base_addr3 = dev->resource[3].start;
+ *base_addr4 = dev->resource[4].start;
+ *base_addr5 = dev->resource[5].start;
/* ------------------------------------------------------------------------
NOTE - The code below mask out either the 2 or 4 bits dependent on the
@@ -4064,36 +4064,6 @@ int get_PCI_configuration(unsigned char bus, unsigned char device_fn,
be 0 when used as an address.
---------------------------------------------------------------------------- */
- if ((*base_addr0) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
- (*base_addr0) &= PCI_BASE_ADDRESS_IO_MASK;
- else
- (*base_addr0) &= PCI_BASE_ADDRESS_MEM_MASK;
-
- if ((*base_addr1) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
- (*base_addr1) &= PCI_BASE_ADDRESS_IO_MASK;
- else
- (*base_addr1) &= PCI_BASE_ADDRESS_MEM_MASK;
-
- if ((*base_addr2) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
- (*base_addr2) &= PCI_BASE_ADDRESS_IO_MASK;
- else
- (*base_addr2) &= PCI_BASE_ADDRESS_MEM_MASK;
-
- if ((*base_addr3) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
- (*base_addr3) &= PCI_BASE_ADDRESS_IO_MASK;
- else
- (*base_addr3) &= PCI_BASE_ADDRESS_MEM_MASK;
-
- if ((*base_addr4) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
- (*base_addr4) &= PCI_BASE_ADDRESS_IO_MASK;
- else
- (*base_addr4) &= PCI_BASE_ADDRESS_MEM_MASK;
-
- if ((*base_addr5) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
- (*base_addr5) &= PCI_BASE_ADDRESS_IO_MASK;
- else
- (*base_addr5) &= PCI_BASE_ADDRESS_MEM_MASK;
-
return(1);
} /* End get_PCI_configuration */
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 511794642..ff800e6c4 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -2317,7 +2317,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
scratch | UART_MCR_DTR | UART_MCR_RTS);
}
sti();
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) {
#ifdef SERIAL_DO_RESTART
diff --git a/drivers/char/ftape/lowlevel/ftape-io.c b/drivers/char/ftape/lowlevel/ftape-io.c
index 2fda1578b..464b792d3 100644
--- a/drivers/char/ftape/lowlevel/ftape-io.c
+++ b/drivers/char/ftape/lowlevel/ftape-io.c
@@ -95,13 +95,10 @@ void ftape_sleep(unsigned int time)
TRACE(ft_t_any, "%d msec, %d ticks", time/1000, ticks);
timeout = ticks;
- current->state = TASK_INTERRUPTIBLE;
save_flags(flags);
sti();
+ set_current_state(TASK_INTERRUPTIBLE);
do {
- while (current->state != TASK_RUNNING) {
- timeout = schedule_timeout(timeout);
- }
/* Mmm. Isn't current->blocked == 0xffffffff ?
*/
if (signal_pending(current)) {
@@ -109,6 +106,9 @@ void ftape_sleep(unsigned int time)
"awoken by non-blocked signal :-(");
break; /* exit on signal */
}
+ while (current->state != TASK_RUNNING) {
+ timeout = schedule_timeout(timeout);
+ }
} while (timeout);
restore_flags(flags);
}
diff --git a/drivers/char/ftape/lowlevel/ftape-setup.c b/drivers/char/ftape/lowlevel/ftape-setup.c
index 01c231bb0..1c590fde3 100644
--- a/drivers/char/ftape/lowlevel/ftape-setup.c
+++ b/drivers/char/ftape/lowlevel/ftape-setup.c
@@ -60,12 +60,15 @@ static struct param_table {
{ "mach2", &ft_mach2, CONFIG_FT_MACH2, 0, 1}
};
-void __init ftape_setup(char *str, int *ints)
+static int __init ftape_setup(char *str)
{
int i;
int param;
+ int ints[2];
+
TRACE_FUN(ft_t_flow);
+ str = get_options(str, ARRAY_SIZE(ints), ints);
if (str) {
for (i=0; i < NR_ITEMS(config_params); i++) {
if (strcmp(str,config_params[i].name) == 0){
@@ -81,13 +84,13 @@ void __init ftape_setup(char *str, int *ints)
config_params[i].name,
config_params[i].min,
config_params[i].max);
- TRACE_EXIT;
+ goto out;
}
if(config_params[i].var) {
TRACE(ft_t_info, "%s=%d", str, param);
*config_params[i].var = param;
}
- TRACE_EXIT;
+ goto out;
}
}
}
@@ -101,5 +104,8 @@ void __init ftape_setup(char *str, int *ints)
} else {
TRACE(ft_t_err, "botched ftape option");
}
- TRACE_EXIT;
+ out:
+ TRACE_EXIT 1;
}
+
+__setup("ftape=", ftape_setup);
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
new file mode 100644
index 000000000..f4ecc75a5
--- /dev/null
+++ b/drivers/char/generic_serial.c
@@ -0,0 +1,1074 @@
+/*
+ * generic_serial.c
+ *
+ * Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl
+ *
+ * written for the SX serial driver.
+ * Contains the code that should be shared over all the serial drivers.
+ *
+ * Credit for the idea to do it this way might go to Alan Cox.
+ *
+ *
+ * Version 0.1 -- December, 1998. Initial version.
+ * Version 0.2 -- March, 1999. Some more routines. Bugfixes. Etc.
+ * Version 0.5 -- August, 1999. Some more fixes. Reformat for Linus.
+ */
+
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/mm.h>
+#include <asm/semaphore.h>
+#include <linux/version.h>
+
+
+#if LINUX_VERSION_CODE < 0x020100 /* Less than 2.1.0 */
+#define TWO_ZERO
+#else
+#if LINUX_VERSION_CODE < 0x020200 /* less than 2.2.x */
+#warning "Please use a 2.2.x kernel. "
+#else
+#if LINUX_VERSION_CODE < 0x020300 /* less than 2.2.x */
+#define TWO_TWO
+#else
+#define TWO_THREE
+#endif
+#endif
+#endif
+
+#ifdef TWO_ZERO
+
+/* Here is the section that makes the 2.2 compatible driver source
+ work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2,
+ and provide for compatibility stuff here if possible. */
+
+/* Some 200 days (on intel) */
+#define MAX_SCHEDULE_TIMEOUT ((long)(~0UL>>1))
+
+
+#ifndef MODULE
+
+#define copy_to_user(a,b,c) memcpy_tofs(a,b,c)
+
+static inline int copy_from_user(void *to,const void *from, int c)
+{
+ memcpy_fromfs(to, from, c);
+ return 0;
+}
+
+
+#define capable(x) suser()
+
+#define queue_task queue_task_irq_off
+#define tty_flip_buffer_push(tty) queue_task(&tty->flip.tqueue, &tq_timer)
+#define signal_pending(current) (current->signal & ~current->blocked)
+#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0)
+#define time_after(t1,t2) (((long)t1-t2) > 0)
+
+#define test_and_set_bit(nr, addr) set_bit(nr, addr)
+#define test_and_clear_bit(nr, addr) clear_bit(nr, addr)
+
+/* Not yet implemented on 2.0 */
+#define ASYNC_SPD_SHI -1
+#define ASYNC_SPD_WARP -1
+
+
+
+/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it
+ to the "name" field that does exist. As long as the assignments are
+ done in the right order, there is nothing to worry about. */
+#define driver_name name
+
+
+/* Should be in a header somewhere. */
+#define TTY_HW_COOK_OUT 14 /* Flag to tell ntty what we can handle */
+#define TTY_HW_COOK_IN 15 /* in hardware - output and input */
+#endif
+
+#endif
+
+#ifndef TWO_ZERO
+/* This include is new with 2.2 (and required!) */
+#include <asm/uaccess.h>
+#endif
+
+#ifndef TWO_THREE
+/* These are new in 2.3. The source now uses 2.3 syntax, and here is
+ the compatibility define... */
+#define wait_queue_head_t struct wait_queue *
+#define DECLARE_MUTEX(name) struct semaphore name = MUTEX
+#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL }
+
+#endif
+
+#include "generic_serial.h"
+
+
+#ifndef MODULE
+extern void my_hd (unsigned char *ptr, int n);
+#endif
+
+static char * tmp_buf;
+static DECLARE_MUTEX(tmp_buf_sem);
+
+int gs_debug = 0;
+
+
+#ifdef DEBUG
+#define gs_dprintk(f, str...) if (gs_debug & f) printk (str)
+#else
+#define gs_dprintk(f, str...) /* nothing */
+#endif
+
+#define func_enter() gs_dprintk (SX_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
+#define func_exit() gs_dprintk (SX_DEBUG_FLOW, "gs: exit " __FUNCTION__ "\n")
+
+
+
+#if NEW_WRITE_LOCKING
+#define DECL /* Nothing */
+#define LOCKIT down (& port->port_write_sem);
+#define RELEASEIT up (&port->port_write_sem);
+#else
+#define DECL unsigned long flags;
+#define LOCKIT save_flags (flags);cli ()
+#define RELEASEIT restore_flags (flags)
+#endif
+
+
+
+void gs_put_char(struct tty_struct * tty, unsigned char ch)
+{
+ struct gs_port *port = tty->driver_data;
+ DECL
+
+ /* func_enter (); */
+
+ /* Take a lock on the serial tranmit buffer! */
+ LOCKIT;
+
+ if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+ /* Sorry, buffer is full, drop character. Update statistics???? -- REW */
+ RELEASEIT;
+ return;
+ }
+
+ port->xmit_buf[port->xmit_head++] = ch;
+ port->xmit_head &= SERIAL_XMIT_SIZE - 1;
+ port->xmit_cnt++; /* Characters in buffer */
+
+ RELEASEIT;
+ /* func_exit ();*/
+}
+
+
+#ifdef NEW_WRITE_LOCKING
+
+/*
+> Problems to take into account are:
+> -1- Interrupts that empty part of the buffer.
+> -2- page faults on the access to userspace.
+> -3- Other processes that are also trying to do a "write".
+*/
+
+int gs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct gs_port *port = tty->driver_data;
+ int c, total = 0;
+ int t;
+
+ /* func_enter (); */
+
+ if (! (port->flags & ASYNC_INITIALIZED))
+ return 0;
+
+ /* get exclusive "write" access to this port (problem 3) */
+ /* This is not a spinlock because we can have a disk access (page
+ fault) in copy_from_user */
+ down (& port->port_write_sem);
+
+ while (1) {
+
+ c = count;
+
+ /* This is safe because we "OWN" the "head". Noone else can
+ change the "head": we own the port_write_sem. */
+ /* Don't overrun the end of the buffer */
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+
+ /* This is safe because the xmit_cnt can only decrease. This
+ would increase "t", so we might copy too little chars. */
+ /* Don't copy past the "head" of the buffer */
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ /* Can't copy more? break out! */
+ if (c <= 0) break;
+ if (from_user)
+ copy_from_user (port->xmit_buf + port->xmit_head, buf, c);
+ else
+ memcpy (port->xmit_buf + port->xmit_head, buf, c);
+
+ port -> xmit_cnt += c;
+ port -> xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE -1);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ up (& port->port_write_sem);
+
+ gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n",
+ (port->flags & GS_TX_INTEN)?"enabled": "disabled");
+
+ if (port->xmit_cnt &&
+ !tty->stopped &&
+ !tty->hw_stopped &&
+ !(port->flags & GS_TX_INTEN)) {
+ port->flags |= GS_TX_INTEN;
+ port->rd->enable_tx_interrupts (port);
+ }
+ /* func_exit (); */
+ return total;
+}
+#else
+/*
+> Problems to take into account are:
+> -1- Interrupts that empty part of the buffer.
+> -2- page faults on the access to userspace.
+> -3- Other processes that are also trying to do a "write".
+*/
+
+int gs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct gs_port *port;
+ int c, total = 0;
+ int t;
+ unsigned long flags;
+
+ func_enter ();
+
+ /* The standard serial driver returns 0 in this case.
+ That sounds to me as "No error, I just didn't get to writing any
+ bytes. Feel free to try again."
+ The "official" way to write n bytes from buf is:
+
+ for (nwritten = 0;nwritten < n;nwritten += rv) {
+ rv = write (fd, buf+nwritten, n-nwritten);
+ if (rv < 0) break; // Error: bail out. //
+ }
+
+ which will loop endlessly in this case. The manual page for write
+ agrees with me. In practise almost everybody writes
+ "write (fd, buf,n);" but some people might have had to deal with
+ incomplete writes in the past and correctly implemented it by now...
+ */
+
+ if (!tty) return -EIO;
+
+ port = tty->driver_data;
+ if (!port || !port->xmit_buf || !tmp_buf)
+ return -EIO;
+
+ /* printk ("from_user = %d.\n", from_user); */
+ save_flags(flags);
+ if (from_user) {
+ /* printk ("Going into the semaphore\n"); */
+ down(&tmp_buf_sem);
+ /* printk ("got out of the semaphore\n"); */
+ while (1) {
+ c = count;
+
+ /* This is safe because we "OWN" the "head". Noone else can
+ change the "head": we own the port_write_sem. */
+ /* Don't overrun the end of the buffer */
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+
+ /* This is safe because the xmit_cnt can only decrease. This
+ would increase "t", so we might copy too little chars. */
+ /* Don't copy past the "head" of the buffer */
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ /* Can't copy more? break out! */
+ if (c <= 0) break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!total)
+ total = -EFAULT;
+ break;
+ }
+ cli();
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);
+ port->xmit_head = ((port->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ port->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ while (1) {
+ cli();
+ c = count;
+
+ /* This is safe because we "OWN" the "head". Noone else can
+ change the "head": we own the port_write_sem. */
+ /* Don't overrun the end of the buffer */
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+
+ /* This is safe because the xmit_cnt can only decrease. This
+ would increase "t", so we might copy too little chars. */
+ /* Don't copy past the "head" of the buffer */
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ /* Can't copy more? break out! */
+ if (c <= 0) {
+ restore_flags(flags);
+ break;
+ }
+ memcpy(port->xmit_buf + port->xmit_head, buf, c);
+ port->xmit_head = ((port->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ port->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ }
+
+ if (port->xmit_cnt &&
+ !tty->stopped &&
+ !tty->hw_stopped &&
+ !(port->flags & GS_TX_INTEN)) {
+ port->flags |= GS_TX_INTEN;
+ port->rd->enable_tx_interrupts (port);
+ }
+ func_exit ();
+ return total;
+}
+
+#endif
+
+
+
+int gs_write_room(struct tty_struct * tty)
+{
+ struct gs_port *port = tty->driver_data;
+ int ret;
+
+ /* func_enter (); */
+ ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ /* func_exit (); */
+ return ret;
+}
+
+
+int gs_chars_in_buffer(struct tty_struct *tty)
+{
+ struct gs_port *port = tty->driver_data;
+ func_enter ();
+
+ func_exit ();
+ return port->xmit_cnt;
+}
+
+
+int gs_real_chars_in_buffer(struct tty_struct *tty)
+{
+ struct gs_port *port = tty->driver_data;
+ func_enter ();
+
+ if (!tty) return 0;
+ port = tty->driver_data;
+
+ func_exit ();
+ return port->xmit_cnt + port->rd->chars_in_buffer (port);
+}
+
+
+static void gs_wait_tx_flushed (void * ptr, int timeout)
+{
+ struct gs_port *port = ptr;
+ long end_jiffies;
+ int jiffies_to_transmit, charsleft;
+ int to, rcib;
+
+ func_enter();
+
+ gs_dprintk (GS_DEBUG_FLUSH, "port=%p.\n", port);
+ if (port) {
+ gs_dprintk (GS_DEBUG_FLUSH, "xmit_cnt=%x, xmit_buf=%p, tty=%p.\n",
+ port->xmit_cnt, port->xmit_buf, port->tty);
+ }
+
+ if (!port || port->xmit_cnt < 0 || !port->xmit_buf) {
+ gs_dprintk (GS_DEBUG_FLUSH, "ERROR: !port, !port->xmit_buf or prot->xmit_cnt < 0.\n");
+ func_exit();
+ return; /* This is an error which we don't know how to handle. */
+ }
+ gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 1\n");
+
+ rcib = gs_real_chars_in_buffer(port->tty);
+
+ gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 2\n");
+
+ if(rcib <= 0) {
+ gs_dprintk (GS_DEBUG_FLUSH, "nothing to wait for.\n");
+ func_exit();
+ return;
+ }
+ gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 3\n");
+
+ /* stop trying: now + twice the time it would normally take + seconds */
+ end_jiffies = jiffies;
+ if (timeout != MAX_SCHEDULE_TIMEOUT)
+ end_jiffies += port->baud?(2 * rcib * 10 * HZ / port->baud):0;
+ end_jiffies += timeout;
+
+ gs_dprintk (GS_DEBUG_FLUSH, "now=%lx, end=%lx (%ld).\n",
+ jiffies, end_jiffies, end_jiffies-jiffies);
+
+ to = 100;
+ /* the expression is actually jiffies < end_jiffies, but that won't
+ work around the wraparound. Tricky eh? */
+ while (to-- &&
+ (charsleft = gs_real_chars_in_buffer (port->tty)) &&
+ time_after (end_jiffies, jiffies)) {
+ /* Units check:
+ chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies!
+ check! */
+
+ charsleft += 16; /* Allow 16 chars more to be transmitted ... */
+ jiffies_to_transmit = port->baud?(1 + charsleft * 10 * HZ / port->baud):0;
+ /* ^^^ Round up.... */
+ if (jiffies_to_transmit <= 0) jiffies_to_transmit = 1;
+
+ gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies "
+ "(%d chars).\n", jiffies_to_transmit, charsleft);
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(jiffies_to_transmit);
+ if (signal_pending (current))
+ break;
+ }
+
+ gs_dprintk (GS_DEBUG_FLUSH, "charsleft = %d.\n", charsleft);
+ current->state = TASK_RUNNING;
+
+ func_exit();
+}
+
+
+
+void gs_flush_buffer(struct tty_struct *tty)
+{
+ struct gs_port *port = tty->driver_data;
+ unsigned long flags;
+
+ func_enter ();
+ /* XXX Would the write semaphore do? */
+ save_flags(flags); cli();
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ restore_flags(flags);
+
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ func_exit ();
+}
+
+
+void gs_flush_chars(struct tty_struct * tty)
+{
+ struct gs_port *port = tty->driver_data;
+
+ func_enter ();
+ if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !port->xmit_buf) {
+ func_exit ();
+ return;
+ }
+
+ /* Beats me -- REW */
+ port->flags |= GS_TX_INTEN;
+ port->rd->enable_tx_interrupts (port);
+ func_exit ();
+}
+
+
+void gs_stop(struct tty_struct * tty)
+{
+ struct gs_port *port = tty->driver_data;
+
+ func_enter ();
+ if (port->xmit_cnt &&
+ port->xmit_buf &&
+ (port->flags & GS_TX_INTEN) ) {
+ port->flags &= ~GS_TX_INTEN;
+ port->rd->disable_tx_interrupts (port);
+ }
+ func_exit ();
+}
+
+
+void gs_start(struct tty_struct * tty)
+{
+ struct gs_port *port = tty->driver_data;
+
+ if (port->xmit_cnt &&
+ port->xmit_buf &&
+ !(port->flags & GS_TX_INTEN) ) {
+ port->flags |= GS_TX_INTEN;
+ port->rd->enable_tx_interrupts (port);
+ }
+ func_exit ();
+}
+
+
+void gs_shutdown_port (struct gs_port *port)
+{
+ long flags;
+
+ if (!(port->flags & ASYNC_INITIALIZED))
+ return;
+
+ save_flags (flags);
+ cli ();
+
+ if (port->xmit_buf) {
+ free_page((unsigned long) port->xmit_buf);
+ port->xmit_buf = 0;
+ }
+
+ if (port->tty)
+ set_bit(TTY_IO_ERROR, &port->tty->flags);
+
+ port->rd->shutdown_port (port);
+
+ port->flags &= ~ASYNC_INITIALIZED;
+ restore_flags (flags);
+}
+
+
+void gs_hangup(struct tty_struct *tty)
+{
+ struct gs_port *port = tty->driver_data;
+
+ func_enter ();
+
+ tty = port->tty;
+ if (!tty) return;
+
+ gs_shutdown_port (port);
+
+ /* gs_flush_buffer (tty); */
+ port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE |GS_ACTIVE);
+ port->tty = NULL;
+ port->count = 0;
+
+ wake_up_interruptible(&port->open_wait);
+ func_exit ();
+}
+
+
+void gs_do_softint(void *private_)
+{
+ struct gs_port *port = private_;
+ struct tty_struct *tty;
+
+ tty = port->tty;
+ if(!tty) return;
+
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+ func_exit ();
+}
+
+
+int block_til_ready(void *port_, struct file * filp)
+{
+ struct gs_port *port = port_;
+ DECLARE_WAITQUEUE(wait, current);
+ int retval;
+ int do_clocal = 0;
+ int CD;
+ struct tty_struct *tty;
+
+ func_enter ();
+ tty = port->tty;
+
+ gs_dprintk (GS_DEBUG_BTR, "Entering block_till_ready.\n");
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&port->close_wait);
+ if (port->flags & ASYNC_HUP_NOTIFY)
+ return -EAGAIN;
+ else
+ return -ERESTARTSYS;
+ }
+
+ gs_dprintk (GS_DEBUG_BTR, "after hung up\n");
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == GS_TYPE_CALLOUT) {
+ if (port->flags & ASYNC_NORMAL_ACTIVE)
+ return -EBUSY;
+ if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (port->flags & ASYNC_SESSION_LOCKOUT) &&
+ (port->session != current->session))
+ return -EBUSY;
+ if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (port->flags & ASYNC_PGRP_LOCKOUT) &&
+ (port->pgrp != current->pgrp))
+ return -EBUSY;
+ port->flags |= ASYNC_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ gs_dprintk (GS_DEBUG_BTR, "after subtype\n");
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (port->flags & ASYNC_CALLOUT_ACTIVE)
+ return -EBUSY;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ gs_dprintk (GS_DEBUG_BTR, "after nonblock\n");
+
+ if (port->flags & ASYNC_CALLOUT_ACTIVE) {
+ if (port->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (C_CLOCAL(tty))
+ do_clocal = 1;
+ }
+
+ gs_dprintk (GS_DEBUG_BTR, "after clocal check.\n");
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, port->count is dropped by one, so that
+ * rs_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&port->open_wait, &wait);
+
+ gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n");
+
+ cli();
+ if (!tty_hung_up_p(filp))
+ port->count--;
+ sti();
+ port->blocked_open++;
+ while (1) {
+ CD = port->rd->get_CD (port);
+ gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(port->flags & ASYNC_INITIALIZED)) {
+ if (port->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ break;
+ }
+ if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&
+ !(port->flags & ASYNC_CLOSING) &&
+ (do_clocal || CD))
+ break;
+ gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n",
+ (int)signal_pending (current), *(long*)(&current->blocked));
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n",
+ port->blocked_open);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&port->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ port->count++;
+ port->blocked_open--;
+ if (retval)
+ return retval;
+
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ func_exit ();
+ return 0;
+}
+
+
+void gs_close(struct tty_struct * tty, struct file * filp)
+{
+ unsigned long flags;
+ struct gs_port *port;
+
+ func_enter ();
+ port = (struct gs_port *) tty->driver_data;
+
+ gs_dprintk (GS_DEBUG_CLOSE, "tty=%p, port=%p port->tty=%p\n",
+ tty, port, port->tty);
+
+ if(! port) {
+ func_exit();
+ return;
+ }
+ if (!port->tty) {
+ printk (KERN_WARNING "gs: Odd: port->tty is NULL\n");
+ port->tty = tty;
+ }
+
+
+ save_flags(flags); cli();
+
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ port->rd->hungup (port);
+ func_exit ();
+ return;
+ }
+
+ if ((tty->count == 1) && (port->count != 1)) {
+ printk(KERN_ERR "gs: gs_close: bad port count;"
+ " tty->count is 1, port count is %d\n", port->count);
+ port->count = 1;
+ }
+ if (--port->count < 0) {
+ printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count);
+ port->count = 0;
+ }
+ if (port->count) {
+ restore_flags(flags);
+ func_exit ();
+ return;
+ }
+ port->flags |= ASYNC_CLOSING;
+
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (port->flags & ASYNC_NORMAL_ACTIVE)
+ port->normal_termios = *tty->termios;
+ if (port->flags & ASYNC_CALLOUT_ACTIVE)
+ port->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ /* if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, port->closing_wait); */
+
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receive line status interrupts, and tell the
+ * interrupt driver to stop checking the data ready bit in the
+ * line status register.
+ */
+
+ port->rd->disable_rx_interrupts (port);
+
+ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ gs_wait_tx_flushed (port, port->closing_wait);
+
+ port->flags &= ~GS_ACTIVE;
+
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ port->event = 0;
+ port->tty = 0;
+ if (port->blocked_open) {
+ if (port->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(port->close_delay);
+ }
+ wake_up_interruptible(&port->open_wait);
+ }
+ port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+ ASYNC_CLOSING | ASYNC_INITIALIZED);
+ wake_up_interruptible(&port->close_wait);
+
+ port->rd->close (port);
+ port->rd->shutdown_port (port);
+ restore_flags(flags);
+ func_exit ();
+}
+
+
+static unsigned int gs_baudrates[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
+};
+
+
+void gs_set_termios (struct tty_struct * tty,
+ struct termios * old_termios)
+{
+ struct gs_port *port = tty->driver_data;
+ int baudrate, tmp;
+ struct termios *tiosp;
+
+ func_enter();
+
+ tiosp = tty->termios;
+
+
+ if (gs_debug & GS_DEBUG_TERMIOS) {
+ gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);
+ my_hd ((unsigned char *)tiosp, sizeof (struct termios));
+ }
+
+#if 0
+ /* This is an optimization that is only allowed for dumb cards */
+ /* Smart cards require knowledge of iflags and oflags too: that
+ might change hardware cooking mode.... */
+#endif
+ if (old_termios) {
+ if( (tiosp->c_iflag == old_termios->c_iflag)
+ && (tiosp->c_oflag == old_termios->c_oflag)
+ && (tiosp->c_cflag == old_termios->c_cflag)
+ && (tiosp->c_lflag == old_termios->c_lflag)
+ && (tiosp->c_line == old_termios->c_line)
+ && (memcmp(tiosp->c_cc, old_termios->c_cc, NCC) == 0)) {
+ gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: optimized away\n");
+ return;
+ }
+ } else
+ gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: no old_termios: "
+ "no optimization\n");
+
+ if(old_termios && (gs_debug & GS_DEBUG_TERMIOS)) {
+ if(tiosp->c_iflag != old_termios->c_iflag) printk("c_iflag changed\n");
+ if(tiosp->c_oflag != old_termios->c_oflag) printk("c_oflag changed\n");
+ if(tiosp->c_cflag != old_termios->c_cflag) printk("c_cflag changed\n");
+ if(tiosp->c_lflag != old_termios->c_lflag) printk("c_lflag changed\n");
+ if(tiosp->c_line != old_termios->c_line) printk("c_line changed\n");
+ if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n");
+ }
+
+ baudrate = tiosp->c_cflag & CBAUD;
+ if (baudrate & CBAUDEX) {
+ baudrate &= ~CBAUDEX;
+ if ((baudrate < 1) || (baudrate > 4))
+ tiosp->c_cflag &= ~CBAUDEX;
+ else
+ baudrate += 15;
+ }
+
+ baudrate = gs_baudrates[baudrate];
+ if ((tiosp->c_cflag & CBAUD) == B38400) {
+ if ( (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ baudrate = 57600;
+ else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ baudrate = 115200;
+ else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ baudrate = 230400;
+ else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ baudrate = 460800;
+ else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+ baudrate = (port->baud_base / port->custom_divisor);
+ }
+
+ /* I recommend using THIS instead of the mess in termios (and
+ duplicating the above code). Next we should create a clean
+ interface towards this variable. If your card supports arbitrary
+ baud rates, (e.g. CD1400 or 16550 based cards) then everything
+ will be very easy..... */
+ port->baud = baudrate;
+
+ /* Two timer ticks seems enough to wakeup something like SLIP driver */
+ /* Baudrate/10 is cps. Divide by HZ to get chars per tick. */
+ tmp = (baudrate / 10 / HZ) * 2;
+
+ if (tmp < 0) tmp = 0;
+ if (tmp >= SERIAL_XMIT_SIZE) tmp = SERIAL_XMIT_SIZE-1;
+
+ port->wakeup_chars = tmp;
+
+ /* We should really wait for the characters to be all sent before
+ changing the settings. -- CAL */
+ gs_wait_tx_flushed (port, MAX_SCHEDULE_TIMEOUT);
+
+ port->rd->set_real_termios(port);
+
+ if ((!old_termios ||
+ (old_termios->c_cflag & CRTSCTS)) &&
+ !( tiosp->c_cflag & CRTSCTS)) {
+ tty->stopped = 0;
+ gs_start(tty);
+ }
+
+#ifdef tytso_patch_94Nov25_1726
+ /* This "makes sense", Why is it commented out? */
+
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&info->open_wait);
+#endif
+
+ func_exit();
+ return;
+}
+
+
+
+/* Must be called with interrupts enabled */
+int gs_init_port(struct gs_port *port)
+{
+ unsigned long flags;
+ unsigned long page;
+
+ save_flags (flags);
+ if (!tmp_buf) {
+ page = get_free_page(GFP_KERNEL);
+
+ cli (); /* Don't expect this to make a difference. */
+ if (tmp_buf)
+ free_page(page);
+ else
+ tmp_buf = (unsigned char *) page;
+ restore_flags (flags);
+
+ if (!tmp_buf) {
+ return -ENOMEM;
+ }
+ }
+
+ if (port->flags & ASYNC_INITIALIZED)
+ return 0;
+
+ if (!port->xmit_buf) {
+ /* We may sleep in get_free_page() */
+ unsigned long tmp;
+
+ tmp = get_free_page(GFP_KERNEL);
+
+ /* Spinlock? */
+ cli ();
+ if (port->xmit_buf)
+ free_page (tmp);
+ else
+ port->xmit_buf = (unsigned char *) tmp;
+ restore_flags (flags);
+
+ if (!port->xmit_buf)
+ return -ENOMEM;
+ }
+
+ cli();
+
+ if (port->tty)
+ clear_bit(TTY_IO_ERROR, &port->tty->flags);
+
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+
+ gs_set_termios(port->tty, NULL);
+
+ port->flags |= ASYNC_INITIALIZED;
+ port->flags &= ~GS_TX_INTEN;
+
+ restore_flags(flags);
+ return 0;
+}
+
+
+int gs_setserial(struct gs_port *port, struct serial_struct *sp)
+{
+ struct serial_struct sio;
+
+ copy_from_user(&sio, sp, sizeof(struct serial_struct));
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((sio.baud_base != port->baud_base) ||
+ (sio.close_delay != port->close_delay) ||
+ ((sio.flags & ~ASYNC_USR_MASK) !=
+ (port->flags & ~ASYNC_USR_MASK)))
+ return(-EPERM);
+ }
+
+ port->flags = (port->flags & ~ASYNC_USR_MASK) |
+ (sio.flags & ASYNC_USR_MASK);
+
+ port->baud_base = sio.baud_base;
+ port->close_delay = sio.close_delay;
+ port->closing_wait = sio.closing_wait;
+ port->custom_divisor = sio.custom_divisor;
+
+ gs_set_termios (port->tty, NULL);
+
+ return 0;
+}
+
+
+/*****************************************************************************/
+
+/*
+ * Generate the serial struct info.
+ */
+
+void gs_getserial(struct gs_port *port, struct serial_struct *sp)
+{
+ struct serial_struct sio;
+
+ memset(&sio, 0, sizeof(struct serial_struct));
+ sio.flags = port->flags;
+ sio.baud_base = port->baud_base;
+ sio.close_delay = port->close_delay;
+ sio.closing_wait = port->closing_wait;
+ sio.custom_divisor = port->custom_divisor;
+ sio.hub6 = 0;
+
+ /* If you want you can override these. */
+ sio.type = PORT_UNKNOWN;
+ sio.xmit_fifo_size = -1;
+ sio.line = -1;
+ sio.port = -1;
+ sio.irq = -1;
+
+ if (port->rd->getserial)
+ port->rd->getserial (port, &sio);
+
+ copy_to_user(sp, &sio, sizeof(struct serial_struct));
+}
+
diff --git a/drivers/char/generic_serial.h b/drivers/char/generic_serial.h
new file mode 100644
index 000000000..ca321af9b
--- /dev/null
+++ b/drivers/char/generic_serial.h
@@ -0,0 +1,101 @@
+/*
+ * generic_serial.h
+ *
+ * Copyright (C) 1998 R.E.Wolff@BitWizard.nl
+ *
+ * written for the SX serial driver.
+ * Contains the code that should be shared over all the serial drivers.
+ *
+ * Version 0.1 -- December, 1998.
+ */
+
+#ifndef GENERIC_SERIAL_H
+#define GENERIC_SERIAL_H
+
+struct real_driver {
+ void (*disable_tx_interrupts) (void *);
+ void (*enable_tx_interrupts) (void *);
+ void (*disable_rx_interrupts) (void *);
+ void (*enable_rx_interrupts) (void *);
+ int (*get_CD) (void *);
+ void (*shutdown_port) (void*);
+ void (*set_real_termios) (void*);
+ int (*chars_in_buffer) (void*);
+ void (*close) (void*);
+ void (*hungup) (void*);
+ void (*getserial) (void*, struct serial_struct *sp);
+};
+
+
+
+struct gs_port {
+ int magic;
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ /* struct semaphore port_write_sem; */
+ int flags;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
+ long session;
+ long pgrp;
+ int count;
+ int blocked_open;
+ struct tty_struct *tty;
+ int event;
+ unsigned short closing_wait;
+ int close_delay;
+ struct real_driver *rd;
+ int wakeup_chars;
+ int baud_base;
+ int baud;
+ int custom_divisor;
+};
+
+
+/* Flags */
+/* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
+ used in serial.c, but they are also used in all other serial drivers.
+ Make sure they don't clash with these here... */
+#define GS_TX_INTEN 0x00800000
+#define GS_RX_INTEN 0x00400000
+#define GS_ACTIVE 0x00200000
+
+
+
+#define GS_TYPE_NORMAL 1
+#define GS_TYPE_CALLOUT 2
+
+
+#define GS_DEBUG_FLUSH 0x00000001
+#define GS_DEBUG_BTR 0x00000002
+#define GS_DEBUG_TERMIOS 0x00000004
+#define GS_DEBUG_STUFF 0x00000008
+#define GS_DEBUG_CLOSE 0x00000010
+
+
+void gs_put_char(struct tty_struct *tty, unsigned char ch);
+int gs_write(struct tty_struct *tty, int from_user,
+ const unsigned char *buf, int count);
+int gs_write_room(struct tty_struct *tty);
+int gs_chars_in_buffer(struct tty_struct *tty);
+void gs_flush_buffer(struct tty_struct *tty);
+void gs_flush_chars(struct tty_struct *tty);
+void gs_stop(struct tty_struct *tty);
+void gs_start(struct tty_struct *tty);
+void gs_hangup(struct tty_struct *tty);
+void gs_do_softint(void *private_);
+int block_til_ready(void *port, struct file *filp);
+void gs_close(struct tty_struct *tty, struct file *filp);
+void gs_set_termios (struct tty_struct * tty,
+ struct termios * old_termios);
+int gs_init_port(struct gs_port *port);
+int gs_setserial(struct gs_port *port, struct serial_struct *sp);
+void gs_getserial(struct gs_port *port, struct serial_struct *sp);
+
+extern int gs_debug;
+
+#endif
diff --git a/drivers/char/hfmodem/Config.in b/drivers/char/hfmodem/Config.in
deleted file mode 100644
index 9d2799adb..000000000
--- a/drivers/char/hfmodem/Config.in
+++ /dev/null
@@ -1,6 +0,0 @@
-comment 'Misc. hamradio protocols'
-dep_tristate 'Shortwave radio modem driver' CONFIG_HFMODEM $CONFIG_PARPORT
-if [ "$CONFIG_HFMODEM" != "n" ]; then
- bool ' HFmodem support for Soundblaster and compatible cards' CONFIG_HFMODEM_SBC
- bool ' HFmodem support for WSS and Crystal cards' CONFIG_HFMODEM_WSS
-fi
diff --git a/drivers/char/hfmodem/Makefile b/drivers/char/hfmodem/Makefile
deleted file mode 100644
index 2219cd52e..000000000
--- a/drivers/char/hfmodem/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Makefile for the hfmodem device driver.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
-
-O_TARGET := hfmodem.o
-
-O_OBJS := refclock.o modem.o main.o
-ifeq ($(CONFIG_HFMODEM_SBC),y)
-O_OBJS += sbc.o
-endif
-ifeq ($(CONFIG_HFMODEM_WSS),y)
-O_OBJS += wss.o
-endif
-
-M_OBJS := $(O_TARGET)
-
-all: all_targets
-.PHONY: all
-
-gentbl: gentbl.c
- $(HOSTCC) $(HOSTCFLAGS) $< -o $@ -lm
-
-TBLHDR := tables.h
-
-tables.h: gentbl
- ./gentbl > $@
-
-fastdep: $(TBLHDR)
-
-include $(TOPDIR)/Rules.make
diff --git a/drivers/char/hfmodem/gentbl.c b/drivers/char/hfmodem/gentbl.c
deleted file mode 100644
index d60651b1b..000000000
--- a/drivers/char/hfmodem/gentbl.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*****************************************************************************/
-
-/*
- * gentbl.c -- Linux soundcard HF FSK driver,
- * Table generator.
- *
- * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- */
-
-/*****************************************************************************/
-
-/* This is compiled with HOSTCC - do not include any <linux/foo.h> headers. */
-#include <math.h>
-#include <stdio.h>
-
-/* --------------------------------------------------------------------- */
-
-#define SINTABBITS 9
-#define SINTABSIZE (1<<SINTABBITS)
-
-/* --------------------------------------------------------------------- */
-
-static void gensintbl(void)
-{
- int i;
-
- printf("#define SINTABBITS %d\n#define SINTABSIZE (1<<SINTABBITS)\n"
- "\nstatic short isintab[SINTABSIZE+SINTABSIZE/4] = {\n\t", SINTABBITS);
- for (i = 0; i < (SINTABSIZE+SINTABSIZE/4); i++) {
- printf("%6d", (int)(32767.0 * sin(2.0 * M_PI / SINTABSIZE * i)));
- if (i < (SINTABSIZE+SINTABSIZE/4)-1) {
- if ((i & 7) == 7)
- printf(",\n\t");
- else
- printf(",");
- }
- }
- printf("\n};\n\n");
-}
-
-/* --------------------------------------------------------------------- */
-
-int main(int argc, char *argv[])
-{
- printf("/*\n * This file is automatically generated by %s, DO NOT EDIT!\n*/\n\n",
- argv[0]);
- gensintbl();
- exit(0);
-}
-
-/* --------------------------------------------------------------------- */
-
diff --git a/drivers/char/hfmodem/main.c b/drivers/char/hfmodem/main.c
deleted file mode 100644
index a865689c1..000000000
--- a/drivers/char/hfmodem/main.c
+++ /dev/null
@@ -1,734 +0,0 @@
-/*****************************************************************************/
-
-/*
- * main.c -- Linux soundcard HF FSK driver.
- *
- * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Command line options (insmod command line)
- *
- * History:
- * 0.1 15.04.97 Adapted from baycom.c and made network driver interface
- * 0.2 05.07.97 All floating point stuff thrown out due to Linus' rantings :)
- *
- */
-
-/*****************************************************************************/
-
-
-#include <linux/config.h> /* for CONFIG_HFMODEM_WSS and CONFIG_HFMODEM_SBC */
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/ioport.h>
-#include <linux/hfmodem.h>
-
-#include <asm/io.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
-
-/* --------------------------------------------------------------------- */
-
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
-#include <asm/uaccess.h>
-#else
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_READ, from, n);
- if (i)
- return i;
- memcpy_fromfs(to, from, n);
- return 0;
-}
-
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_WRITE, to, n);
- if (i)
- return i;
- memcpy_tofs(to, from, n);
- return 0;
-}
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*static*/ const char hfmodem_drvname[] = "hfmodem";
-static const char hfmodem_drvinfo[] = KERN_INFO "hfmodem: (C) 1997 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "hfmodem: version 0.2 compiled " __TIME__ " " __DATE__ "\n";
-
-/* --------------------------------------------------------------------- */
-/*
- * currently we support only one device
- */
-
-struct hfmodem_state hfmodem_state[NR_DEVICE];
-
-/* --------------------------------------------------------------------- */
-/*
- * ===================== port checking routines ========================
- */
-
-
-#define UART_RBR(iobase) (iobase+0)
-#define UART_THR(iobase) (iobase+0)
-#define UART_IER(iobase) (iobase+1)
-#define UART_IIR(iobase) (iobase+2)
-#define UART_FCR(iobase) (iobase+2)
-#define UART_LCR(iobase) (iobase+3)
-#define UART_MCR(iobase) (iobase+4)
-#define UART_LSR(iobase) (iobase+5)
-#define UART_MSR(iobase) (iobase+6)
-#define UART_SCR(iobase) (iobase+7)
-#define UART_DLL(iobase) (iobase+0)
-#define UART_DLM(iobase) (iobase+1)
-
-#define SER_EXTENT 8
-
-#define LPT_DATA(iobase) (iobase+0)
-#define LPT_STATUS(iobase) (iobase+1)
-#define LPT_CONTROL(iobase) (iobase+2)
-#define LPT_IRQ_ENABLE 0x10
-
-#define MIDI_DATA(iobase) (iobase)
-#define MIDI_STATUS(iobase) (iobase+1)
-#define MIDI_READ_FULL 0x80 /* attention: negative logic!! */
-#define MIDI_WRITE_EMPTY 0x40 /* attention: negative logic!! */
-
-#define MIDI_EXTENT 2
-
-#define SP_SER 1
-#define SP_PAR 2
-#define SP_MIDI 4
-
-/* --------------------------------------------------------------------- */
-
-static void parptt_wakeup(void *handle)
-{
- struct hfmodem_state *dev = (struct hfmodem_state *)handle;
-
- printk(KERN_DEBUG "%s: parptt: why am I being woken up?\n", hfmodem_drvname);
- if (!parport_claim(dev->ptt_out.pardev))
- printk(KERN_DEBUG "%s: parptt: I'm broken.\n", hfmodem_drvname);
-}
-
-/* --------------------------------------------------------------------- */
-static int __init check_lpt(struct hfmodem_state *dev, unsigned int iobase)
-{
- struct parport *pp = parport_enumerate();
-
- while (pp && pp->base != iobase)
- pp = pp->next;
- if (!pp)
- return 0;
- if (!(dev->ptt_out.pardev = parport_register_device(pp, hfmodem_drvname, NULL, parptt_wakeup,
- NULL, PARPORT_DEV_EXCL, dev)))
- return 0;
- return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
-enum uart { c_uart_unknown, c_uart_8250, c_uart_16450, c_uart_16550, c_uart_16550A };
-static const char *uart_str[] __initdata = { "unknown", "8250", "16450", "16550", "16550A" };
-
-static enum uart __init check_uart(unsigned int iobase)
-{
- unsigned char b1,b2,b3;
- enum uart u;
- enum uart uart_tab[] = { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
-
- if (iobase <= 0 || iobase > 0x1000-SER_EXTENT)
- return c_uart_unknown;
- if (check_region(iobase, SER_EXTENT))
- return c_uart_unknown;
- b1 = inb(UART_MCR(iobase));
- outb(b1 | 0x10, UART_MCR(iobase)); /* loopback mode */
- b2 = inb(UART_MSR(iobase));
- outb(0x1a, UART_MCR(iobase));
- b3 = inb(UART_MSR(iobase)) & 0xf0;
- outb(b1, UART_MCR(iobase)); /* restore old values */
- outb(b2, UART_MSR(iobase));
- if (b3 != 0x90)
- return c_uart_unknown;
- inb(UART_RBR(iobase));
- inb(UART_RBR(iobase));
- outb(0x01, UART_FCR(iobase)); /* enable FIFOs */
- u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3];
- if (u == c_uart_16450) {
- outb(0x5a, UART_SCR(iobase));
- b1 = inb(UART_SCR(iobase));
- outb(0xa5, UART_SCR(iobase));
- b2 = inb(UART_SCR(iobase));
- if ((b1 != 0x5a) || (b2 != 0xa5))
- u = c_uart_8250;
- }
- return u;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int __init check_midi(unsigned int iobase)
-{
- unsigned long timeout;
- unsigned long flags;
- unsigned char b;
-
- if (iobase <= 0 || iobase > 0x1000-MIDI_EXTENT)
- return 0;
- if (check_region(iobase, MIDI_EXTENT))
- return 0;
- timeout = jiffies + (HZ / 100);
- while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY)
- if ((signed)(jiffies - timeout) > 0)
- return 0;
- save_flags(flags);
- cli();
- outb(0xff, MIDI_DATA(iobase));
- b = inb(MIDI_STATUS(iobase));
- restore_flags(flags);
- if (!(b & MIDI_WRITE_EMPTY))
- return 0;
- while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY)
- if ((signed)(jiffies - timeout) > 0)
- return 0;
- return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void output_status(struct hfmodem_state *dev, int ptt)
-{
- int dcd = 0;
-
- ptt = !!ptt;
- if (dev->ptt_out.flags & SP_SER) {
- outb(dcd | (ptt << 1), UART_MCR(dev->ptt_out.seriobase));
- outb(0x40 & (-ptt), UART_LCR(dev->ptt_out.seriobase));
- }
- if (dev->ptt_out.flags & SP_PAR) {
- outb(ptt | (dcd << 1), LPT_DATA(dev->ptt_out.pariobase));
- }
- if (dev->ptt_out.flags & SP_MIDI && ptt) {
- outb(0, MIDI_DATA(dev->ptt_out.midiiobase));
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static void __init output_check(struct hfmodem_state *dev)
-{
- enum uart u = c_uart_unknown;
-
- if (((u = check_uart(dev->ptt_out.seriobase))) != c_uart_unknown)
- printk(KERN_INFO "%s: PTT output: uart found at address 0x%x type %s\n",
- hfmodem_drvname, dev->ptt_out.seriobase, uart_str[u]);
- else {
- if (dev->ptt_out.seriobase > 0)
- printk(KERN_WARNING "%s: PTT output: no uart found at address 0x%x\n",
- hfmodem_drvname, dev->ptt_out.seriobase);
- dev->ptt_out.seriobase = 0;
- }
- if (check_lpt(dev, dev->ptt_out.pariobase))
- printk(KERN_INFO "%s: PTT output: parallel port found at address 0x%x\n",
- hfmodem_drvname, dev->ptt_out.pariobase);
- else {
- if (dev->ptt_out.pariobase > 0)
- printk(KERN_WARNING "%s: PTT output: no parallel port found at address 0x%x\n",
- hfmodem_drvname, dev->ptt_out.pariobase);
- dev->ptt_out.pariobase = 0;
- dev->ptt_out.pardev = NULL;
- }
- if (dev->ptt_out.midiiobase > 0 && dev->ptt_out.midiiobase <= 0x1000-MIDI_EXTENT &&
- check_midi(dev->ptt_out.midiiobase))
- printk(KERN_INFO "%s: PTT output: midi port found at address 0x%x\n",
- hfmodem_drvname, dev->ptt_out.midiiobase);
- else {
- if (dev->ptt_out.midiiobase > 0)
- printk(KERN_WARNING "%s: PTT output: no midi port found at address 0x%x\n",
- hfmodem_drvname, dev->ptt_out.midiiobase);
- dev->ptt_out.midiiobase = 0;
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static void output_open(struct hfmodem_state *dev)
-{
- dev->ptt_out.flags = 0;
- if (dev->ptt_out.seriobase > 0) {
- if (!check_region(dev->ptt_out.seriobase, SER_EXTENT)) {
- request_region(dev->ptt_out.seriobase, SER_EXTENT, "hfmodem ser ptt");
- dev->ptt_out.flags |= SP_SER;
- outb(0, UART_IER(dev->ptt_out.seriobase));
- /* 5 bits, 1 stop, no parity, no break, Div latch access */
- outb(0x80, UART_LCR(dev->ptt_out.seriobase));
- outb(0, UART_DLM(dev->ptt_out.seriobase));
- outb(1, UART_DLL(dev->ptt_out.seriobase)); /* as fast as possible */
- /* LCR and MCR set by output_status */
- } else
- printk(KERN_WARNING "%s: PTT output: serial port at 0x%x busy\n",
- hfmodem_drvname, dev->ptt_out.seriobase);
- }
- if (dev->ptt_out.pariobase > 0) {
- if (parport_claim(dev->ptt_out.pardev))
- printk(KERN_WARNING "%s: PTT output: parallel port at 0x%x busy\n",
- hfmodem_drvname, dev->ptt_out.pariobase);
- else
- dev->ptt_out.flags |= SP_PAR;
- }
- if (dev->ptt_out.midiiobase > 0) {
- if (!check_region(dev->ptt_out.midiiobase, MIDI_EXTENT)) {
- request_region(dev->ptt_out.midiiobase, MIDI_EXTENT, "hfmodem midi ptt");
- dev->ptt_out.flags |= SP_MIDI;
- } else
- printk(KERN_WARNING "%s: PTT output: midi port at 0x%x busy\n",
- hfmodem_drvname, dev->ptt_out.midiiobase);
- }
- output_status(dev, 0);
- printk(KERN_INFO "%s: PTT output:", hfmodem_drvname);
- if (dev->ptt_out.flags & SP_SER)
- printk(" serial interface at 0x%x", dev->ptt_out.seriobase);
- if (dev->ptt_out.flags & SP_PAR)
- printk(" parallel interface at 0x%x", dev->ptt_out.pariobase);
- if (dev->ptt_out.flags & SP_MIDI)
- printk(" mpu401 (midi) interface at 0x%x", dev->ptt_out.midiiobase);
- if (!dev->ptt_out.flags)
- printk(" none");
- printk("\n");
-}
-
-/* --------------------------------------------------------------------- */
-
-static void output_close(struct hfmodem_state *dev)
-{
- /* release regions used for PTT output */
- output_status(dev, 0);
- if (dev->ptt_out.flags & SP_SER)
- release_region(dev->ptt_out.seriobase, SER_EXTENT);
- if (dev->ptt_out.flags & SP_PAR)
- parport_release(dev->ptt_out.pardev);
- if (dev->ptt_out.flags & SP_MIDI)
- release_region(dev->ptt_out.midiiobase, MIDI_EXTENT);
- dev->ptt_out.flags = 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-#define INC_SAMPLE (1000000/HFMODEM_SRATE)
-#define INC_FRAGMENT (HFMODEM_FRAGSAMPLES*1000000/HFMODEM_SRATE)
-#define SIZE (HFMODEM_FRAGSAMPLES*HFMODEM_NUMFRAGS)
-
-static void hfmodem_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct hfmodem_state *dev = (struct hfmodem_state *)dev_id;
- unsigned int dmaptr;
- __s16 *s;
- unsigned int curfrag, nfrags;
- int i;
- hfmodem_time_t l1time;
-
- dmaptr = dev->scops->intack(dev);
- l1time = hfmodem_refclock_current(dev, ((SIZE+dmaptr-dev->dma.last_dmaptr) % SIZE) *
- INC_SAMPLE, 1);
- curfrag = (dev->dma.last_dmaptr = dmaptr) / HFMODEM_FRAGSAMPLES;
- l1time -= INC_SAMPLE * (SIZE+dmaptr-dev->dma.fragptr*HFMODEM_FRAGSAMPLES) % SIZE;
- sti();
- /*
- * handle receiving
- */
- if (dev->dma.ptt_frames <= 0) {
- while (dev->dma.fragptr != curfrag) {
- if (dev->dma.fragptr < HFMODEM_EXCESSFRAGS) {
- s = dev->dma.buf + SIZE + HFMODEM_FRAGSAMPLES * dev->dma.fragptr;
- memcpy(s, s - SIZE, HFMODEM_FRAGSIZE);
- } else
- s = dev->dma.buf + HFMODEM_FRAGSAMPLES * dev->dma.fragptr;
- if (dev->sbuf.kbuf && dev->sbuf.kptr && dev->sbuf.rem > 0) {
- i = HFMODEM_FRAGSAMPLES;
- if (i > dev->sbuf.rem)
- i = dev->sbuf.rem;
- memcpy(dev->sbuf.kptr, s, i * sizeof(s[0]));
- dev->sbuf.rem -= i;
- dev->sbuf.kptr += i;
- }
- hfmodem_input_samples(dev, l1time, INC_SAMPLE, s);
- l1time += INC_FRAGMENT;
- dev->dma.fragptr++;
- if (dev->dma.fragptr >= HFMODEM_NUMFRAGS)
- dev->dma.fragptr = 0;
- }
- /*
- * check for output
- */
- if (hfmodem_next_tx_event(dev, l1time) > (long)INC_FRAGMENT/2)
- goto int_return;
- /*
- * start output
- */
- output_status(dev, 1);
- dev->scops->prepare_output(dev);
- dev->dma.last_dmaptr = 0;
- /*
- * clock adjust
- */
- l1time = hfmodem_refclock_current(dev, 0, 0);
- /*
- * fill first two fragments
- */
- dev->dma.ptt_frames = 1;
- for (i = 0; i < 2 && i < HFMODEM_NUMFRAGS; i++)
- if (hfmodem_output_samples(dev, l1time+i*INC_FRAGMENT, INC_SAMPLE,
- dev->dma.buf+i*HFMODEM_FRAGSAMPLES))
- dev->dma.ptt_frames = i + 1;
- dev->dma.lastfrag = 0;
- dev->scops->trigger_output(dev);
- /*
- * finish already pending rx requests
- */
- hfmodem_finish_pending_rx_requests(dev);
- goto int_return;
- }
- /*
- * handle transmitting
- */
- nfrags = HFMODEM_NUMFRAGS + curfrag - dev->dma.lastfrag;
- dev->dma.lastfrag = curfrag;
- if (nfrags >= HFMODEM_NUMFRAGS)
- nfrags -= HFMODEM_NUMFRAGS;
- dev->dma.ptt_frames -= nfrags;
- if (dev->dma.ptt_frames < 0)
- dev->dma.ptt_frames = 0;
- while (dev->dma.ptt_frames < HFMODEM_NUMFRAGS && dev->dma.ptt_frames < 4 &&
- hfmodem_output_samples(dev, l1time+dev->dma.ptt_frames*INC_FRAGMENT,
- INC_SAMPLE, dev->dma.buf + HFMODEM_FRAGSAMPLES *
- ((curfrag + dev->dma.ptt_frames) % HFMODEM_NUMFRAGS)))
- dev->dma.ptt_frames++;
- if (dev->dma.ptt_frames > 0)
- goto int_return;
- /*
- * start receiving
- */
- output_status(dev, 0);
- dev->dma.last_dmaptr = 0;
- dev->dma.lastfrag = 0;
- dev->dma.fragptr = 0;
- dev->dma.ptt_frames = 0;
- dev->scops->prepare_input(dev);
- dev->scops->trigger_input(dev);
- hfmodem_refclock_current(dev, 0, 0); /* needed to reset the time difference */
-int_return:
- hfmodem_wakeup(dev);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int hfmodem_close(struct inode *inode, struct file *file)
-{
- struct hfmodem_state *dev = &hfmodem_state[0];
-
- if (!dev->active)
- return -EPERM;
- dev->active = 0;
- dev->scops->stop(dev);
- free_irq(dev->io.irq, dev);
- disable_dma(dev->io.dma);
- free_dma(dev->io.dma);
- release_region(dev->io.base_addr, dev->scops->extent);
- kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS));
- hfmodem_clear_rq(dev);
- if (dev->sbuf.kbuf) {
- kfree_s(dev->sbuf.kbuf, dev->sbuf.size);
- dev->sbuf.kbuf = dev->sbuf.kptr = NULL;
- dev->sbuf.size = dev->sbuf.rem = 0;
- }
- output_close(dev);
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int hfmodem_open(struct inode *inode, struct file *file)
-{
- struct hfmodem_state *dev = &hfmodem_state[0];
-
- if (dev->active)
- return -EBUSY;
- if (!dev->scops)
- return -EPERM;
- /*
- * clear vars
- */
- memset(&dev->l1, 0, sizeof(dev->l1));
- dev->dma.last_dmaptr = 0;
- dev->dma.lastfrag = 0;
- dev->dma.fragptr = 0;
- dev->dma.ptt_frames = 0;
- /*
- * allocate memory
- */
- if (!(dev->dma.buf = kmalloc(HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS), GFP_KERNEL | GFP_DMA)))
- return -ENOMEM;
- /*
- * allocate resources
- */
- if (request_dma(dev->io.dma, hfmodem_drvname)) {
- kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS));
- return -EBUSY;
- }
- if (request_irq(dev->io.irq, hfmodem_interrupt, SA_INTERRUPT, hfmodem_drvname, dev)) {
- free_dma(dev->io.dma);
- kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS));
- return -EBUSY;
- }
- request_region(dev->io.base_addr, dev->scops->extent, hfmodem_drvname);
-
- /* clear requests */
- dev->active++;
- MOD_INC_USE_COUNT;
- hfmodem_refclock_init(dev);
- output_open(dev);
- dev->scops->init(dev);
- dev->scops->prepare_input(dev);
- dev->scops->trigger_input(dev);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static struct file_operations hfmodem_fops = {
- NULL, /* hfmodem_seek */
- NULL, /* hfmodem_read */
- NULL, /* hfmodem_write */
- NULL, /* hfmodem_readdir */
-#if LINUX_VERSION_CODE >= 0x20100
- hfmodem_poll, /* hfmodem_poll */
-#else
- hfmodem_select, /* hfmodem_select */
-#endif
- hfmodem_ioctl, /* hfmodem_ioctl */
- NULL, /* hfmodem_mmap */
- hfmodem_open, /* hfmodem_open */
- NULL, /* flush */
- hfmodem_close, /* hfmodem_close */
- NULL, /* hfmodem_fsync */
- NULL, /* hfmodem_fasync */
- NULL, /* hfmodem_check_media_change */
- NULL /* hfmodem_revalidate */
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct miscdevice hfmodem_device = {
- HFMODEM_MINOR, hfmodem_drvname, &hfmodem_fops
-};
-
-/* --------------------------------------------------------------------- */
-
-#ifdef MODULE
-
-/*
- * Command line parameters
- */
-
-static int hw = 0;
-static unsigned int iobase = 0x220;
-static unsigned int irq = 7;
-static unsigned int dma = 1;
-
-static unsigned int serio = 0;
-static unsigned int pario = 0;
-static unsigned int midiio = 0;
-
-#if LINUX_VERSION_CODE >= 0x20115
-
-MODULE_PARM(hw, "i");
-MODULE_PARM_DESC(hw, "hardware type: 0=SBC, 1=WSS");
-MODULE_PARM(iobase, "i");
-MODULE_PARM_DESC(iobase, "io base address");
-MODULE_PARM(irq, "i");
-MODULE_PARM_DESC(irq, "interrupt number");
-MODULE_PARM(dma, "i");
-MODULE_PARM_DESC(dma, "dma number (>=4 for SB16/32/64/etc, <=3 for the rest)");
-MODULE_PARM(serio, "i");
-MODULE_PARM_DESC(serio, "address of serial port to output PTT");
-MODULE_PARM(pario, "i");
-MODULE_PARM_DESC(pario, "address of parallel port to output PTT");
-MODULE_PARM(midiio, "i");
-MODULE_PARM_DESC(midiio, "address of midi (MPU401) port to output PTT");
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("HF FSK modem code");
-
-/* these are the module parameters from refclock.c */
-
-MODULE_PARM(scale_tvusec, "i");
-MODULE_PARM_DESC(scale_tvusec, "Scaling value for the tv_usec field (can be obta
-ined by refclock)");
-
-#ifdef __i386__
-MODULE_PARM(scale_rdtsc, "i");
-MODULE_PARM_DESC(scale_rdtsc, "Scaling value for the rdtsc counter (can be obtai
-ned by refclock)");
-MODULE_PARM(rdtsc_ok, "i");
-MODULE_PARM_DESC(rdtsc_ok, "Set to 0 to disable the use of the rdtsc instruction
-");
-#endif /* __i386__ */
-
-#endif
-
-int __init init_module(void)
-{
- int i;
-
- printk(hfmodem_drvinfo);
- memset(hfmodem_state, 0, sizeof(hfmodem_state));
- memset(hfmodem_correlator_cache, 0, sizeof(hfmodem_correlator_cache));
- hfmodem_state[0].io.base_addr = iobase;
- hfmodem_state[0].io.irq = irq;
- hfmodem_state[0].io.dma = dma;
- hfmodem_state[0].ptt_out.seriobase = serio;
- hfmodem_state[0].ptt_out.pariobase = pario;
- hfmodem_state[0].ptt_out.midiiobase = midiio;
- init_waitqueue_head(&hfmodem_state[0].wait);
- hfmodem_refclock_probe();
- output_check(&hfmodem_state[0]);
-#if defined(CONFIG_HFMODEM_WSS) && defined(CONFIG_HFMODEM_SBC)
- if (hw)
- i = hfmodem_wssprobe(&hfmodem_state[0]);
- else
- i = hfmodem_sbcprobe(&hfmodem_state[0]);
-#else
- i = -EINVAL;
-#ifdef CONFIG_HFMODEM_WSS
- i = hfmodem_wssprobe(&hfmodem_state[0]);
-#endif
-#ifdef CONFIG_HFMODEM_SBC
- i = hfmodem_sbcprobe(&hfmodem_state[0]);
-#endif
-#endif
- if (i)
- return i;
- if ((i = misc_register(&hfmodem_device))) {
- printk(KERN_ERR "%s: cannot register misc device\n", hfmodem_drvname);
- return i;
- }
- return 0;
-}
-
-void cleanup_module(void)
-{
- struct hfmodem_state *dev = &hfmodem_state[0];
-
- if (dev->ptt_out.pariobase > 0)
- parport_unregister_device(dev->ptt_out.pardev);
- misc_deregister(&hfmodem_device);
-}
-
-#else /* MODULE */
-/* --------------------------------------------------------------------- */
-
-static int hw = 0;
-
-void __init hfmodem_setup(char *str, int *ints)
-{
- if (ints[0] < 7) {
- printk(KERN_WARNING "%s: setup: too few parameters\n", hfmodem_drvname);
- return;
- }
- memset(hfmodem_state, 0, sizeof(hfmodem_state));
- memset(hfmodem_correlator_cache, 0, sizeof(hfmodem_correlator_cache));
- hw = ints[1];
- hfmodem_state[0].io.base_addr = ints[2];
- hfmodem_state[0].io.irq = ints[3];
- hfmodem_state[0].io.dma = ints[4];
- if (ints[0] >= 8)
- hfmodem_state[0].ptt_out.seriobase = ints[5];
- if (ints[0] >= 9)
- hfmodem_state[0].ptt_out.pariobase = ints[6];
- if (ints[0] >= 10)
- hfmodem_state[0].ptt_out.midiiobase = ints[7];
- hfmodem_refclock_setscale(ints[ints[0]-2], ints[ints[0]-1], ints[ints[0]]);
-}
-
-void __init hfmodem_init(void)
-{
- int i;
-
- printk(hfmodem_drvinfo);
- init_waitqueue_head(&hfmode_state[0].wait);
- hfmodem_refclock_probe();
- output_check(&hfmodem_state[0]);
-#if defined(CONFIG_HFMODEM_WSS) && defined(CONFIG_HFMODEM_SBC)
- if (hw)
- i = hfmodem_wssprobe(&hfmodem_state[0]);
- else
- i = hfmodem_sbcprobe(&hfmodem_state[0]);
-#else
- i = -EINVAL;
-#ifdef CONFIG_HFMODEM_WSS
- i = hfmodem_wssprobe(&hfmodem_state[0]);
-#endif
-#ifdef CONFIG_HFMODEM_SBC
- i = hfmodem_sbcprobe(&hfmodem_state[0]);
-#endif
-#endif
- if (i) {
- printk(KERN_ERR "%s: soundcard probe failed\n", hfmodem_drvname);
- return;
- }
- if ((i = misc_register(&hfmodem_device))) {
- printk(KERN_ERR "%s: cannot register misc device\n", hfmodem_drvname);
- return;
- }
-}
-
-/* --------------------------------------------------------------------- */
-#endif /* MODULE */
diff --git a/drivers/char/hfmodem/modem.c b/drivers/char/hfmodem/modem.c
deleted file mode 100644
index 02dcad5cc..000000000
--- a/drivers/char/hfmodem/modem.c
+++ /dev/null
@@ -1,792 +0,0 @@
-/*****************************************************************************/
-
-/*
- * modem.c -- Linux soundcard HF FSK driver,
- * Modem code.
- *
- * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- */
-
-/*****************************************************************************/
-
-
-#include <linux/wait.h>
-#include <linux/malloc.h>
-#include <linux/hfmodem.h>
-
-/* --------------------------------------------------------------------- */
-
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
-#include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_READ, from, n);
- if (i)
- return i;
- memcpy_fromfs(to, from, n);
- return 0;
-}
-
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
- int i = verify_area(VERIFY_WRITE, to, n);
- if (i)
- return i;
- memcpy_tofs(to, from, n);
- return 0;
-}
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-
-struct hfmodem_correlator_cache hfmodem_correlator_cache[HFMODEM_CORRELATOR_CACHE];
-
-/* --------------------------------------------------------------------- */
-
-#include "tables.h"
-
-#define M_PI 3.14159265358979323846 /* pi */
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ int isimplecos(unsigned int arg)
-{
- return isintab[((arg+0x4000) >> (16-SINTABBITS)) & (SINTABSIZE-1)];
-}
-
-extern __inline__ int isimplesin(unsigned int arg)
-{
- return isintab[(arg >> (16-SINTABBITS)) & (SINTABSIZE-1)];
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ int itblcos(unsigned int arg)
-{
- unsigned int x;
- int dx;
- int s, c;
-
- x = (arg + (0x8000 >> SINTABBITS)) & (0xffffu & (0xffffu << (16-SINTABBITS)));
- dx = arg - x;
- x >>= (16-SINTABBITS);
- c = isintab[x+(0x4000 >> (16-SINTABBITS))];
- s = isintab[x];
- return c - ((s * dx * (int)(M_PI*64.0)) >> 21);
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ void itblcossin(unsigned int arg, int *cos, int *sin)
-{
- unsigned int x;
- int dx;
- int s, c;
-
- x = (arg + (0x8000 >> SINTABBITS)) & (0xffffu & (0xffffu << (16-SINTABBITS)));
- dx = arg - x;
- x >>= (16-SINTABBITS);
- c = isintab[x+(0x4000 >> (16-SINTABBITS))];
- s = isintab[x];
- *cos = c - ((s * dx * (int)(M_PI*64.0)) >> 21);
- *sin = s + ((c * dx * (int)(M_PI*64.0)) >> 21);
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned short random_seed;
-
-extern __inline__ unsigned short random_num(void)
-{
- random_seed = 28629 * random_seed + 157;
- return random_seed;
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * correlator cache routines
- */
-
-extern __inline__ void cc_lock(unsigned int u)
-{
- if (u >= HFMODEM_CORRELATOR_CACHE)
- return;
- hfmodem_correlator_cache[u].refcnt++;
-}
-
-extern __inline__ void cc_unlock(unsigned int u)
-{
- if (u >= HFMODEM_CORRELATOR_CACHE)
- return;
- if ((--hfmodem_correlator_cache[u].refcnt) <= 0) {
- unsigned int i;
-
- for (i = 0; i < HFMODEM_CORRELATOR_CACHE; i++)
- if (hfmodem_correlator_cache[i].lru < 32767)
- hfmodem_correlator_cache[i].lru++;
- hfmodem_correlator_cache[u].lru = 0;
- hfmodem_correlator_cache[u].refcnt = 0;
- }
-}
-
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ unsigned int cc_lookup(unsigned short phinc0, unsigned short phinc1)
-{
- unsigned int j;
-
- /* find correlator cache entry */
- for (j = 0; j < HFMODEM_CORRELATOR_CACHE; j++)
- if (hfmodem_correlator_cache[j].phase_incs[0] == phinc0 &&
- hfmodem_correlator_cache[j].phase_incs[1] == phinc1)
- return j;
- return ~0;
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ unsigned int cc_replace(void)
-{
- unsigned int j, k = HFMODEM_CORRELATOR_CACHE;
- int l = -1;
-
- for (j = 0; j < HFMODEM_CORRELATOR_CACHE; j++)
- if (hfmodem_correlator_cache[j].refcnt <= 0 && hfmodem_correlator_cache[j].lru > l) {
- k = j;
- l = hfmodem_correlator_cache[j].lru;
- }
- if (k < HFMODEM_CORRELATOR_CACHE)
- return k;
- printk(KERN_ERR "%s: modem: out of filter coefficient cache entries\n", hfmodem_drvname);
- return random_num() % HFMODEM_CORRELATOR_CACHE;
-}
-
-/* --------------------------------------------------------------------- */
-
-#define SH1 8 /* min. ceil(log2(L1CORR_LEN)) - (31-(2*15-1)) */
-#define SH2 (3*15-2*SH1)
-
-#ifdef __i386__
-
-extern __inline__ int icorr(int n, const int *coeff, const short *inp)
-{
- int ret, rethi, tmp1 = 0, tmp2 = 0;
-
- __asm__("\n1:\n\t"
- "movswl (%0),%%eax\n\t"
- "imull (%1)\n\t"
- "subl $2,%0\n\t"
- "addl $4,%1\n\t"
- "addl %%eax,%3\n\t"
- "adcl %%edx,%4\n\t"
- "decl %2\n\t"
- "jne 1b\n\t"
- : "=&S" (inp), "=&D" (coeff), "=&c" (n), "=m" (tmp1), "=m" (tmp2)
- : "0" (inp), "1" (coeff), "2" (n)
- : "ax", "dx");
- __asm__("shrdl %2,%1,%0\n\t"
- "# sarl %2,%1\n\t"
- : "=&r" (ret), "=&r" (rethi)
- : "i" (SH1), "0" (tmp1), "1" (tmp2));
-
-
- return ret;
-}
-
-#else /* __i386__ */
-
-extern __inline__ int icorr(int n, const int *coeff, const short *inp)
-{
- long long sum = 0;
- int i;
-
- for (i = n; i > 0; i--, coeff++, inp--)
- sum += (*coeff) * (*inp);
- sum >>= SH1;
- return sum;
-}
-
-#endif /* __i386__ */
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ long long isqr(int x) __attribute__ ((const));
-
-extern __inline__ long long isqr(int x)
-{
- return ((long long)x) * ((long long)x);
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ hfmodem_soft_t do_filter(struct hfmodem_l1_rxslot *slot, short *s)
-{
- unsigned int cc = slot->corr_cache;
- long long ll;
-
- if (cc >= HFMODEM_CORRELATOR_CACHE) {
- printk(KERN_ERR "do_filter: correlator cache index overrange\n");
- return 0;
- }
- ll = isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[1][0], s)) +
- isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[1][1], s)) -
- isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[0][0], s)) -
- isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[0][1], s));
- ll >>= SH2;
- return (ll * slot->scale) >> 23;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void cc_prepare(struct hfmodem_l1_rxslot *slot, unsigned short phinc0, unsigned short phinc1)
-{
- unsigned int j, k, l, ph, phinc;
-
- slot->scale = (1<<23) / (slot->corrlen*slot->corrlen);
-
- j = cc_lookup(phinc0, phinc1);
- if (j >= HFMODEM_CORRELATOR_CACHE) {
- j = cc_replace();
- /* calculate the correlator values */
- printk(KERN_DEBUG "%s: corr cache calc: %u phases: 0x%04x 0x%04x\n",
- hfmodem_drvname, j, phinc0, phinc1);
- hfmodem_correlator_cache[j].phase_incs[0] = phinc0;
- hfmodem_correlator_cache[j].phase_incs[1] = phinc1;
- for (k = 0; k < 2; k++) {
- phinc = hfmodem_correlator_cache[j].phase_incs[k];
- for (ph = l = 0; l < HFMODEM_MAXCORRLEN; l++, ph = (ph + phinc) & 0xffff)
- itblcossin(ph, &hfmodem_correlator_cache[j].correlator[k][0][l],
- &hfmodem_correlator_cache[j].correlator[k][1][l]);
- }
- hfmodem_correlator_cache[j].refcnt = 0;
-
-#if 0
- printk(KERN_DEBUG "%s: corr: %u ph: 0x%04x 0x%04x\n", hfmodem_drvname, j,
- hfmodem_correlator_cache[j].phase_incs[0],
- hfmodem_correlator_cache[j].phase_incs[1]);
- for (l = 0; l < HFMODEM_MAXCORRLEN; l++)
- printk(KERN_DEBUG "%s: corr: %6d %6d %6d %6d\n", hfmodem_drvname,
- hfmodem_correlator_cache[j].correlator[0][0][l],
- hfmodem_correlator_cache[j].correlator[0][1][l],
- hfmodem_correlator_cache[j].correlator[1][0][l],
- hfmodem_correlator_cache[j].correlator[1][1][l]);
-#endif
- }
- slot->corr_cache = j;
- cc_lock(j);
-}
-
-/* --------------------------------------------------------------------- */
-
-void hfmodem_clear_rq(struct hfmodem_state *dev)
-{
- unsigned long flags;
- unsigned int i;
-
- save_flags(flags);
- cli();
- for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
- if (dev->l1.rxslots[i].state == ss_unused)
- continue;
- dev->l1.rxslots[i].state = ss_unused;
- kfree_s(dev->l1.rxslots[i].data, dev->l1.rxslots[i].nbits * sizeof(hfmodem_soft_t));
- }
- for (i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
- if (dev->l1.txslots[i].state == ss_unused)
- continue;
- dev->l1.txslots[i].state = ss_unused;
- kfree_s(dev->l1.txslots[i].data, (dev->l1.txslots[i].nbits + 7) >> 3);
- }
- for (i = 0; i < HFMODEM_CORRELATOR_CACHE; i++)
- hfmodem_correlator_cache[i].refcnt = 0;
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-int hfmodem_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct hfmodem_state *dev = &hfmodem_state[0];
- struct hfmodem_ioctl_fsk_tx_request txrq;
- struct hfmodem_ioctl_fsk_rx_request rxrq;
- struct hfmodem_ioctl_mixer_params mix;
- struct hfmodem_ioctl_sample_params spar;
- unsigned long flags;
- unsigned int len;
- int ret, i, idx;
- void *data, *userdata;
- hfmodem_id_t id;
- hfmodem_time_t tm = 0;
-
- if (!dev->active)
- return -EBUSY;
- switch(cmd) {
- default:
- return -EINVAL;
-
- case HFMODEM_IOCTL_FSKTXREQUEST:
- if ((ret = copy_from_user(&txrq, (void *)arg, sizeof(txrq))))
- return ret;
- if (txrq.nbits > HFMODEM_MAXBITS)
- return -EINVAL;
- len = (txrq.nbits + 7) >> 3;
- if (!(data = kmalloc(len, GFP_KERNEL)))
- return -ENOMEM;
- if (copy_from_user(data, txrq.data, len)) {
- kfree_s(data, len);
- return -EFAULT;
- }
- save_flags(flags);
- cli();
- for (i = 0; i < HFMODEM_NUMTXSLOTS && dev->l1.txslots[i].state != ss_unused; i++);
- if (i >= HFMODEM_NUMTXSLOTS) {
- restore_flags(flags);
- kfree_s(data, len);
- return -EBUSY;
- }
- dev->l1.txslots[i].state = ss_ready;
- dev->l1.txslots[i].tstart = txrq.tstart;
- dev->l1.txslots[i].tinc = txrq.tinc;
- dev->l1.txslots[i].data = data;
- dev->l1.txslots[i].nbits = txrq.nbits;
- dev->l1.txslots[i].cntbits = 0;
- dev->l1.txslots[i].inv = txrq.inv ? 0xff : 0;
- dev->l1.txslots[i].id = txrq.id;
- dev->l1.txslots[i].phase_incs[0] = ((txrq.freq[0]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE)
- & 0xffff;
- dev->l1.txslots[i].phase_incs[1] = ((txrq.freq[1]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE)
- & 0xffff;
- restore_flags(flags);
- return 0;
-
- case HFMODEM_IOCTL_FSKRXREQUEST:
- if ((ret = copy_from_user(&rxrq, (void *)arg, sizeof(rxrq))))
- return ret;
- if (rxrq.nbits > HFMODEM_MAXBITS)
- return -EINVAL;
- if (rxrq.baud < HFMODEM_MINBAUD || rxrq.baud > HFMODEM_MAXBAUD)
- return -EINVAL;
- len = rxrq.nbits * sizeof(hfmodem_soft_t);
- if (verify_area(VERIFY_WRITE, rxrq.data, len))
- return -EFAULT;
- if (!(data = kmalloc(len, GFP_KERNEL)))
- return -ENOMEM;
- save_flags(flags);
- cli();
- for (i = 0; i < HFMODEM_NUMRXSLOTS && dev->l1.rxslots[i].state != ss_unused; i++);
- if (i >= HFMODEM_NUMRXSLOTS) {
- restore_flags(flags);
- kfree_s(data, len);
- return -EBUSY;
- }
- dev->l1.rxslots[i].state = ss_ready;
- dev->l1.rxslots[i].tstart = rxrq.tstart;
- dev->l1.rxslots[i].tinc = rxrq.tinc;
- dev->l1.rxslots[i].data = data;
- dev->l1.rxslots[i].userdata = rxrq.data;
- dev->l1.rxslots[i].nbits = rxrq.nbits;
- dev->l1.rxslots[i].cntbits = 0;
- dev->l1.rxslots[i].id = rxrq.id;
- dev->l1.rxslots[i].corrlen = HFMODEM_SRATE/rxrq.baud;
- cc_prepare(dev->l1.rxslots+i,
- ((rxrq.freq[0]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE) & 0xffff,
- ((rxrq.freq[1]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE) & 0xffff);
- restore_flags(flags);
- return 0;
-
- case HFMODEM_IOCTL_CLEARRQ:
- hfmodem_clear_rq(dev);
- return 0;
-
- case HFMODEM_IOCTL_GETCURTIME:
- return put_user(dev->l1.last_time + 20000L, (hfmodem_time_t *)arg); /* heuristic */
-
- case HFMODEM_IOCTL_WAITRQ:
- save_flags(flags);
- cli();
- ret = 0;
- for (idx = -1, i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
- if (dev->l1.rxslots[i].state == ss_unused)
- continue;
- if (dev->l1.rxslots[i].state != ss_retired) {
- ret++;
- continue;
- }
- if (idx < 0 || (signed)(tm - dev->l1.rxslots[i].tstart) > 0) {
- idx = i;
- tm = dev->l1.rxslots[i].tstart;
- }
- }
- if (idx >= 0) {
- cc_unlock(dev->l1.rxslots[idx].corr_cache);
- id = dev->l1.rxslots[idx].id;
- data = dev->l1.rxslots[idx].data;
- userdata = dev->l1.rxslots[idx].userdata;
- len = dev->l1.rxslots[idx].nbits * sizeof(hfmodem_soft_t);
- dev->l1.rxslots[idx].state = ss_unused;
- restore_flags(flags);
- ret = copy_to_user(userdata, data, len);
- kfree_s(data, len);
- return (put_user(id, (hfmodem_id_t *)arg)) ? -EFAULT : ret;
- }
- for (idx = -1, i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
- if (dev->l1.txslots[i].state == ss_unused)
- continue;
- if (dev->l1.txslots[i].state != ss_retired) {
- ret++;
- continue;
- }
- if (idx < 0 || (signed)(tm - dev->l1.txslots[i].tstart) > 0) {
- idx = i;
- tm = dev->l1.txslots[i].tstart;
- }
- }
- if (idx >= 0) {
- id = dev->l1.txslots[idx].id;
- data = dev->l1.txslots[idx].data;
- len = (dev->l1.txslots[idx].nbits + 7) >> 3;
- dev->l1.txslots[idx].state = ss_unused;
- restore_flags(flags);
- kfree_s(data, len);
- return put_user(id, (hfmodem_id_t *)arg);
- }
- restore_flags(flags);
- return ret ? -EAGAIN : -EPIPE;
-
- case HFMODEM_IOCTL_MIXERPARAMS:
- if ((ret = copy_from_user(&mix, (void *)arg, sizeof(mix))))
- return ret;
- dev->scops->mixer(dev, mix.src, mix.igain, mix.ogain);
- return 0;
-
- case HFMODEM_IOCTL_SAMPLESTART:
- save_flags(flags);
- cli();
- if (dev->sbuf.kbuf)
- kfree_s(dev->sbuf.kbuf, dev->sbuf.size);
- dev->sbuf.kbuf = dev->sbuf.kptr = NULL;
- dev->sbuf.size = dev->sbuf.rem = 0;
- restore_flags(flags);
- if ((ret = copy_from_user(&spar, (void *)arg, sizeof(spar))))
- return ret;
- if (spar.len == 0)
- return 0;
- if (spar.len < 2 || spar.len > 8192)
- return -EINVAL;
- if (verify_area(VERIFY_WRITE, spar.data, spar.len * sizeof(__s16)))
- return -EFAULT;
- if (!(dev->sbuf.kbuf = kmalloc(spar.len * sizeof(__s16), GFP_KERNEL)))
- return -ENOMEM;
- save_flags(flags);
- cli();
- dev->sbuf.kptr = dev->sbuf.kbuf;
- dev->sbuf.size = spar.len * sizeof(__s16);
- dev->sbuf.rem = spar.len;
- dev->sbuf.ubuf = spar.data;
- restore_flags(flags);
- return 0;
-
- case HFMODEM_IOCTL_SAMPLEFINISHED:
- save_flags(flags);
- cli();
- if (dev->sbuf.rem > 0) {
- restore_flags(flags);
- return -EAGAIN;
- }
- if (!dev->sbuf.kbuf || !dev->sbuf.size) {
- restore_flags(flags);
- return -EPIPE;
- }
- restore_flags(flags);
- ret = copy_to_user(dev->sbuf.ubuf, dev->sbuf.kbuf, dev->sbuf.size);
- kfree_s(dev->sbuf.kbuf, dev->sbuf.size);
- dev->sbuf.kbuf = dev->sbuf.kptr = NULL;
- dev->sbuf.size = dev->sbuf.rem = 0;
- return ret;
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-#if LINUX_VERSION_CODE >= 0x20100
-
-unsigned int hfmodem_poll(struct file *file, poll_table *wait)
-{
- struct hfmodem_state *dev = &hfmodem_state[0];
- unsigned long flags;
- int i, cnt1, cnt2;
-
- poll_wait(file, &dev->wait, wait);
- save_flags(flags);
- cli();
- for (i = cnt1 = cnt2 = 0; i < HFMODEM_NUMTXSLOTS; i++) {
- if (dev->l1.txslots[i].state == ss_retired)
- cnt1++;
- if (dev->l1.txslots[i].state != ss_unused)
- cnt2++;
- }
- for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
- if (dev->l1.rxslots[i].state == ss_retired)
- cnt1++;
- if (dev->l1.rxslots[i].state != ss_unused)
- cnt2++;
- }
- restore_flags(flags);
- if (cnt1 || !cnt2)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-#else
-
-int hfmodem_select(struct inode *inode, struct file *file, int sel_type, select_table *wait)
-{
- struct hfmodem_state *dev = &hfmodem_state[0];
- unsigned long flags;
- int i, cnt1, cnt2;
-
- if (sel_type == SEL_IN) {
- save_flags(flags);
- cli();
- for (i = cnt1 = cnt2 = 0; i < HFMODEM_NUMTXSLOTS; i++) {
- if (dev->l1.txslots[i].state == ss_retired)
- cnt1++;
- if (dev->l1.txslots[i].state != ss_unused)
- cnt2++;
- }
- for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
- if (dev->l1.rxslots[i].state == ss_retired)
- cnt1++;
- if (dev->l1.rxslots[i].state != ss_unused)
- cnt2++;
- }
- restore_flags(flags);
- if (cnt1 || !cnt2)
- return 1;
- select_wait(&dev->wait, wait);
- }
- return 0;
-}
-
-#endif
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ unsigned int l1fsk_phinc(struct hfmodem_l1_txslot *txs, unsigned int nbit)
-{
- return txs->phase_incs[!!((txs->data[nbit >> 3] ^ txs->inv) & (1 << (nbit & 7)))];
-}
-
-/* --------------------------------------------------------------------- */
-
-void hfmodem_input_samples(struct hfmodem_state *dev, hfmodem_time_t tstart,
- hfmodem_time_t tinc, __s16 *samples)
-{
- hfmodem_time_t tst, tend;
- __s16 *s;
- int i, j;
- hfmodem_soft_t sample;
-
- dev->l1.last_time = tstart + (HFMODEM_FRAGSAMPLES-1) * tinc;
- for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
- struct hfmodem_l1_rxslot *rxs = dev->l1.rxslots + i;
-
- if (rxs->state == ss_unused || rxs->state == ss_retired)
- continue;
- tst = tstart - (rxs->corrlen-1) * tinc;
- tend = tst + (HFMODEM_FRAGSAMPLES-1) * tinc;
- if (rxs->state == ss_ready) {
- if ((signed)(rxs->tstart - tend) > 0)
- continue;
- rxs->state = ss_oper;
- }
- for (s = samples, j = 0; j < HFMODEM_FRAGSAMPLES; j++, s++, tst += tinc)
- if ((signed)(rxs->tstart - tst) <= 0) {
- sample = do_filter(rxs, s);
- while ((signed)(rxs->tstart - tst) <= 0 &&
- rxs->cntbits < rxs->nbits) {
- rxs->data[rxs->cntbits] = sample;
- rxs->cntbits++;
- rxs->tstart += rxs->tinc;
- }
- if (rxs->cntbits >= rxs->nbits) {
- rxs->state = ss_retired;
- break;
- }
- }
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ unsigned int output_one_sample(struct hfmodem_state *dev, hfmodem_time_t tm)
-{
- int i, j, k;
- struct hfmodem_l1_txslot *txs;
- /*
- * first activate new output slots
- */
- for (j = -1, i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
- txs = dev->l1.txslots + i;
- if (txs->state == ss_ready && (signed)(txs->tstart - tm) <= 0) {
- for (k = 0; k < HFMODEM_NUMTXSLOTS; k++) {
- if (dev->l1.txslots[k].state != ss_oper)
- continue;
- dev->l1.txslots[k].state = ss_retired;
- }
- txs->state = ss_oper;
- txs->tstart += txs->tinc;
- txs->phinc = l1fsk_phinc(txs, 0);
- txs->cntbits = 1;
- };
- if (txs->state != ss_oper)
- continue;
- j = i;
- }
- if (j < 0 || j >= HFMODEM_NUMTXSLOTS)
- return 0;
- /*
- * calculate the current slot
- */
- txs = dev->l1.txslots + j;
- while ((signed)(txs->tstart - tm) <= 0) {
- if (txs->cntbits >= txs->nbits) {
- txs->state = ss_retired;
- return 0;
- }
- txs->tstart += txs->tinc;
- txs->phinc = l1fsk_phinc(txs, txs->cntbits);
- txs->cntbits++;
- }
- return txs->phinc;
-}
-
-/* --------------------------------------------------------------------- */
-
-int hfmodem_output_samples(struct hfmodem_state *dev, hfmodem_time_t tstart,
- hfmodem_time_t tinc, __s16 *samples)
-{
- int i, j;
- hfmodem_time_t tend = tstart + (HFMODEM_FRAGSAMPLES-1) * tinc;
-
- for (i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
- if (dev->l1.txslots[i].state == ss_oper)
- break;
- if (dev->l1.txslots[i].state == ss_ready &&
- (signed)(dev->l1.txslots[i].tstart - tend) <= 0)
- break;
- }
- if (i >= HFMODEM_NUMTXSLOTS)
- return 0;
- for (j = 0; j < HFMODEM_FRAGSAMPLES; j++, tstart += tinc, samples++) {
- *samples = isimplecos(dev->l1.tx_phase);
- dev->l1.tx_phase += output_one_sample(dev, tstart);
- }
- return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
-long hfmodem_next_tx_event(struct hfmodem_state *dev, hfmodem_time_t curr)
-{
- long diff = LONG_MAX, t;
- int i;
-
- for (i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
- if (dev->l1.txslots[i].state == ss_oper)
- if (diff > 0)
- diff = 0;
- if (dev->l1.txslots[i].state == ss_ready) {
- t = dev->l1.txslots[i].tstart - curr;
- if (t < diff)
- diff = t;
- }
- }
- return diff;
-}
-
-/* --------------------------------------------------------------------- */
-
-void hfmodem_finish_pending_rx_requests(struct hfmodem_state *dev)
-{
- int i;
-
- for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
- if (dev->l1.rxslots[i].state != ss_oper)
- continue;
- while (dev->l1.rxslots[i].cntbits < dev->l1.rxslots[i].nbits) {
- dev->l1.rxslots[i].data[dev->l1.rxslots[i].cntbits] = 0;
- dev->l1.rxslots[i].cntbits++;
- }
- dev->l1.rxslots[i].state = ss_retired;
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-void hfmodem_wakeup(struct hfmodem_state *dev)
-{
- int i, cnt1, cnt2;
-
- for (i = cnt1 = cnt2 = 0; i < HFMODEM_NUMTXSLOTS; i++) {
- if (dev->l1.txslots[i].state == ss_retired)
- cnt1++;
- if (dev->l1.txslots[i].state != ss_unused)
- cnt2++;
- }
- for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
- if (dev->l1.rxslots[i].state == ss_retired)
- cnt1++;
- if (dev->l1.rxslots[i].state != ss_unused)
- cnt2++;
- }
- if (cnt1 || !cnt2)
- wake_up_interruptible(&dev->wait);
-}
-
-/* --------------------------------------------------------------------- */
diff --git a/drivers/char/hfmodem/refclock.c b/drivers/char/hfmodem/refclock.c
deleted file mode 100644
index 20153c02b..000000000
--- a/drivers/char/hfmodem/refclock.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*****************************************************************************/
-
-/*
- * refclock.c -- Linux soundcard HF FSK driver,
- * Reference clock routines.
- *
- * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/time.h>
-#include <linux/hfmodem.h>
-#include <asm/processor.h>
-
-/* --------------------------------------------------------------------- */
-
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-/*
- * command line params
- */
-
-static unsigned int scale_tvusec = 1UL<<24;
-
-#ifdef __i386__
-static unsigned int scale_rdtsc = 0;
-static int rdtsc_ok = 1;
-#endif /* __i386__ */
-
-/* --------------------------------------------------------------------- */
-
-#ifdef __i386__
-static void __init i386_capability(void)
-{
- 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__ */
-
-/* --------------------------------------------------------------------- */
-
-void __init hfmodem_refclock_probe(void)
-{
-#ifdef __i386__
- if (rdtsc_ok) {
- rdtsc_ok = 0;
- i386_capability();
- if (rdtsc_ok) {
- unsigned int tmp0, tmp1, tmp2, tmp3;
- __asm__("rdtsc" : "=a" (tmp0), "=d" (tmp1));
- __asm__("rdtsc" : "=a" (tmp2), "=d" (tmp3));
- if (tmp0 == tmp2 && tmp1 == tmp3) {
- rdtsc_ok = 0;
- printk(KERN_WARNING "%s: rdtsc unusable, does not change\n",
- hfmodem_drvname);
- }
- }
- }
- printk(KERN_INFO "%s: using %s as timing source\n", hfmodem_drvname,
- rdtsc_ok ? "rdtsc" : "gettimeofday");
-#endif /* __i386__ */
-}
-
-/* --------------------------------------------------------------------- */
-
-void hfmodem_refclock_init(struct hfmodem_state *dev)
-{
- struct timeval tv;
-
- dev->clk.lasttime = 0;
-#ifdef __i386__
- if (rdtsc_ok) {
- __asm__("rdtsc;" : "=&d" (dev->clk.starttime_hi), "=&a" (dev->clk.starttime_lo));
- return;
- }
-#endif /* __i386__ */
- do_gettimeofday(&tv);
- dev->clk.last_tvusec = tv.tv_usec;
- dev->clk.time_cnt = 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-hfmodem_time_t hfmodem_refclock_current(struct hfmodem_state *dev, hfmodem_time_t expected, int exp_valid)
-{
- struct timeval tv;
- hfmodem_time_t curtime;
- long diff;
-
-#ifdef __i386__
- if (rdtsc_ok) {
- unsigned int tmp0, tmp1;
- unsigned int tmp2, tmp3;
-
- __asm__("rdtsc;\n\t"
- "subl %2,%%eax\n\t"
- "sbbl %3,%%edx\n\t" : "=&a" (tmp0), "=&d" (tmp1)
- : "m" (dev->clk.starttime_lo), "m" (dev->clk.starttime_hi) : "ax", "dx");
- __asm__("mull %1" : "=d" (tmp2) : "m" (scale_rdtsc), "a" (tmp0) : "ax");
- __asm__("mull %1" : "=a" (tmp3) : "m" (scale_rdtsc), "a" (tmp1) : "dx");
- curtime = tmp2 + tmp3;
- goto time_known;
- }
-#endif /* __i386__ */
- do_gettimeofday(&tv);
- dev->clk.time_cnt += (unsigned)(1000000 + tv.tv_usec - dev->clk.last_tvusec) % 1000000;
- dev->clk.last_tvusec = tv.tv_usec;
- curtime = (dev->clk.time_cnt * scale_tvusec) >> 24;
- time_known:
- if (exp_valid && abs(diff = (curtime - dev->clk.lasttime - expected)) >= 1000)
- printk(KERN_DEBUG "%s: refclock adjustment %ld more than 1ms\n",
- hfmodem_drvname, diff);
- return (dev->clk.lasttime = curtime);
-}
-
-/* --------------------------------------------------------------------- */
diff --git a/drivers/char/hfmodem/sbc.c b/drivers/char/hfmodem/sbc.c
deleted file mode 100644
index 8e4010619..000000000
--- a/drivers/char/hfmodem/sbc.c
+++ /dev/null
@@ -1,741 +0,0 @@
-/*****************************************************************************/
-
-/*
- * sbc.c -- Linux soundcard HF FSK driver,
- * Soundblaster specific functions.
- *
- * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/hfmodem.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-/* --------------------------------------------------------------------- */
-/*
- * the sbc converter's registers
- */
-#define DSP_RESET(iobase) (iobase+0x6)
-#define DSP_READ_DATA(iobase) (iobase+0xa)
-#define DSP_WRITE_DATA(iobase) (iobase+0xc)
-#define DSP_WRITE_STATUS(iobase) (iobase+0xc)
-#define DSP_DATA_AVAIL(iobase) (iobase+0xe)
-#define DSP_MIXER_ADDR(iobase) (iobase+0x4)
-#define DSP_MIXER_DATA(iobase) (iobase+0x5)
-#define DSP_INTACK_16BIT(iobase) (iobase+0xf)
-#define SBC_EXTENT 16
-
-/* --------------------------------------------------------------------- */
-/*
- * SBC commands
- */
-
-#define SBC_OUTPUT 0x14
-#define SBC_INPUT 0x24
-#define SBC_BLOCKSIZE 0x48
-#define SBC_HI_OUTPUT 0x91
-#define SBC_HI_INPUT 0x99
-#define SBC_LO_OUTPUT_AUTOINIT 0x1c
-#define SBC_LO_INPUT_AUTOINIT 0x2c
-#define SBC_HI_OUTPUT_AUTOINIT 0x90
-#define SBC_HI_INPUT_AUTOINIT 0x98
-#define SBC_IMMED_INT 0xf2
-#define SBC_GET_REVISION 0xe1
-#define ESS_GET_REVISION 0xe7
-#define ESS_EXTENDED_MODE 0xc6
-#define SBC_SPEAKER_ON 0xd1
-#define SBC_SPEAKER_OFF 0xd3
-#define SBC_DMA_ON 0xd0
-#define SBC_DMA_OFF 0xd4
-#define SBC_SAMPLE_RATE 0x40
-#define SBC_SAMPLE_RATE_OUT 0x41
-#define SBC_SAMPLE_RATE_IN 0x42
-#define SBC_MONO_8BIT 0xa0
-#define SBC_MONO_16BIT 0xa4
-#define SBC_STEREO_8BIT 0xa8
-#define SBC_STEREO_16BIT 0xac
-
-#define SBC4_OUT8_AI 0xc6
-#define SBC4_IN8_AI 0xce
-#define SBC4_MODE_UNS_MONO 0x00
-#define SBC4_MODE_SIGN_MONO 0x10
-
-#define SBC4_OUT16_AI 0xb6
-#define SBC4_IN16_AI 0xbe
-#define SBC4_OUT16_AI_NO_FIFO 0xb4
-#define SBC4_IN16_AI_NO_FIFO 0xbc
-
-/* --------------------------------------------------------------------- */
-
-extern const struct hfmodem_scops sbc4_scops;
-extern const struct hfmodem_scops ess_scops;
-
-/* --------------------------------------------------------------------- */
-
-static int reset_dsp(struct hfmodem_state *dev)
-{
- int i;
-
- outb(1, DSP_RESET(dev->io.base_addr));
- udelay(3);
- outb(0, DSP_RESET(dev->io.base_addr));
- for (i = 0; i < 0xffff; i++)
- if (inb(DSP_DATA_AVAIL(dev->io.base_addr)) & 0x80)
- if (inb(DSP_READ_DATA(dev->io.base_addr)) == 0xaa)
- return 1;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void write_dsp(struct hfmodem_state *dev, unsigned char data)
-{
- int i;
-
- for (i = 0; i < 0xffff; i++)
- if (!(inb(DSP_WRITE_STATUS(dev->io.base_addr)) & 0x80)) {
- outb(data, DSP_WRITE_DATA(dev->io.base_addr));
- return;
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static int read_dsp(struct hfmodem_state *dev, unsigned char *data)
-{
- int i;
-
- if (!data)
- return 0;
- for (i = 0; i < 0xffff; i++)
- if (inb(DSP_DATA_AVAIL(dev->io.base_addr)) & 0x80) {
- *data = inb(DSP_READ_DATA(dev->io.base_addr));
- return 1;
- }
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void write_ess(struct hfmodem_state *dev, unsigned char reg, unsigned char data)
-{
- write_dsp(dev, reg);
- write_dsp(dev, data);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int read_ess(struct hfmodem_state *dev, unsigned char reg, unsigned char *data)
-{
- write_dsp(dev, 0xc0);
- write_dsp(dev, reg);
- return read_dsp(dev, data);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int reset_ess(struct hfmodem_state *dev)
-{
- int i;
-
- outb(3, DSP_RESET(dev->io.base_addr)); /* reset FIFOs too */
- udelay(3);
- outb(0, DSP_RESET(dev->io.base_addr));
- for (i = 0; i < 0xffff; i++)
- if (inb(DSP_DATA_AVAIL(dev->io.base_addr)) & 0x80)
- if (inb(DSP_READ_DATA(dev->io.base_addr)) == 0xaa) {
- write_dsp(dev, ESS_EXTENDED_MODE);
- return 1;
- }
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int config_resources(struct hfmodem_state *dev)
-{
- unsigned char irqreg = 0, dmareg = 0, realirq, realdma;
- unsigned long flags;
-
- switch (dev->io.irq) {
- case 2:
- case 9:
- irqreg |= 0x01;
- break;
-
- case 5:
- irqreg |= 0x02;
- break;
-
- case 7:
- irqreg |= 0x04;
- break;
-
- case 10:
- irqreg |= 0x08;
- break;
-
- default:
- return -ENODEV;
- }
-
- switch (dev->io.dma) {
- case 0:
- dmareg |= 0x01;
- break;
-
- case 1:
- dmareg |= 0x02;
- break;
-
- case 3:
- dmareg |= 0x08;
- break;
-
- case 5:
- dmareg |= 0x20;
- break;
-
- case 6:
- dmareg |= 0x40;
- break;
-
- case 7:
- dmareg |= 0x80;
- break;
-
- default:
- return -ENODEV;
- }
- save_flags(flags);
- cli();
- outb(0x80, DSP_MIXER_ADDR(dev->io.base_addr));
- outb(irqreg, DSP_MIXER_DATA(dev->io.base_addr));
- realirq = inb(DSP_MIXER_DATA(dev->io.base_addr));
- outb(0x81, DSP_MIXER_ADDR(dev->io.base_addr));
- outb(dmareg, DSP_MIXER_DATA(dev->io.base_addr));
- realdma = inb(DSP_MIXER_DATA(dev->io.base_addr));
- restore_flags(flags);
- if ((~realirq) & irqreg || (~realdma) & dmareg) {
- printk(KERN_ERR "%s: sbc resource registers cannot be set; PnP device "
- "and IRQ/DMA specified wrongly?\n", hfmodem_drvname);
- return -EINVAL;
- }
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ void sbc_int_ack_8bit(struct hfmodem_state *dev)
-{
- inb(DSP_DATA_AVAIL(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ void sbc_int_ack_16bit(struct hfmodem_state *dev)
-{
- inb(DSP_INTACK_16BIT(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-static void set_mixer(struct hfmodem_state *dev, unsigned char reg, unsigned char data)
-{
- outb(reg, DSP_MIXER_ADDR(dev->io.base_addr));
- outb(data, DSP_MIXER_DATA(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-int hfmodem_sbcprobe(struct hfmodem_state *dev)
-{
- unsigned char revhi, revlo, essrevhi, essrevlo, tmp;
- int ret;
-
- if (dev->io.base_addr <= 0 || dev->io.base_addr > 0x1000-SBC_EXTENT ||
- dev->io.irq < 2 || dev->io.irq > 15 || dev->io.dma > 7 || dev->io.dma == 2)
- return -ENXIO;
- if (check_region(dev->io.base_addr, SBC_EXTENT))
- return -EACCES;
- /*
- * check if a card is available
- */
- if (!reset_dsp(dev)) {
- printk(KERN_ERR "%s: sbc: no card at io address 0x%x\n",
- hfmodem_drvname, dev->io.base_addr);
- return -ENODEV;
- }
- set_mixer(dev, 0, 0); /* reset mixer */
- write_dsp(dev, SBC_GET_REVISION);
- if (!read_dsp(dev, &revhi) || !read_dsp(dev, &revlo))
- return -ENODEV;
- printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%02d\n", hfmodem_drvname, revhi, revlo);
- if (revhi == 3 && revlo == 1) {
- write_dsp(dev, ESS_GET_REVISION);
- if (!read_dsp(dev, &essrevhi) || !read_dsp(dev, &essrevlo))
- return -ENODEV;
- if (essrevhi == 0x48 && (essrevlo & 0xf0) == 0x80) {
- printk(KERN_INFO "%s: ESS ES488 AudioDrive (rev %d): unsupported.\n",
- hfmodem_drvname, essrevlo & 0x0f);
- return -ENODEV;
- }
- if (essrevhi == 0x68 && (essrevlo & 0xf0) == 0x80) {
- printk(KERN_INFO "%s: ESS ES%s688 AudioDrive (rev %d)\n",
- hfmodem_drvname, ((essrevlo & 0x0f) >= 8) ? "1" : "", essrevlo & 0x0f);
- if (dev->io.dma > 3) {
- printk(KERN_INFO "%s: DMA number out of range\n", hfmodem_drvname);
- return -ENXIO;
- }
- printk(KERN_INFO "%s: ess: irq: ", hfmodem_drvname);
- read_ess(dev, 0xb1, &tmp);
- switch (tmp & 0xf) {
- case 0:
- printk("2, 9, \"all others\"");
- break;
-
- case 5:
- printk("5");
- break;
-
- case 10:
- printk("7");
- break;
-
- case 15:
- printk("10");
- break;
-
- default:
- printk("unknown (%d)", tmp & 0xf);
- break;
- }
- printk(" dma: ");
- read_ess(dev, 0xb2, &tmp);
- switch (tmp & 0xf) {
- case 0:
- printk("\"all others\"");
- break;
-
- case 5:
- printk("0");
- break;
-
- case 10:
- printk("1");
- break;
-
- case 15:
- printk("3");
- break;
-
- default:
- printk("unknown (%d)", tmp & 0xf);
- break;
- }
- printk("\n");
- dev->scops = &ess_scops;
- return 0;
- }
- }
- if (revhi < 4) {
- printk(KERN_INFO "%s: at least SB16 required\n", hfmodem_drvname);
- return -ENODEV;
- }
- if (dev->io.dma < 4) {
- printk(KERN_INFO "%s: DMA number out of range\n", hfmodem_drvname);
- return -ENXIO;
- }
- if ((ret = config_resources(dev)))
- return ret;
- dev->scops = &sbc4_scops;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_init(struct hfmodem_state *dev)
-{
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_prepare_input(struct hfmodem_state *dev)
-{
- unsigned long flags;
-
- if (!reset_dsp(dev)) {
- printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", hfmodem_drvname);
- return;
- }
- save_flags(flags);
- cli();
- disable_dma(dev->io.dma);
- clear_dma_ff(dev->io.dma);
- set_dma_mode(dev->io.dma, DMA_MODE_READ | DMA_MODE_AUTOINIT);
- set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
- set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
- enable_dma(dev->io.dma);
- sbc_int_ack_16bit(dev);
- write_dsp(dev, SBC_SAMPLE_RATE_IN); /* set sampling rate */
- write_dsp(dev, HFMODEM_SRATE >> 8);
- write_dsp(dev, HFMODEM_SRATE & 0xff);
- write_dsp(dev, SBC_SPEAKER_OFF);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_trigger_input(struct hfmodem_state *dev)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- write_dsp(dev, SBC4_IN16_AI_NO_FIFO);
- write_dsp(dev, SBC4_MODE_UNS_MONO);
- write_dsp(dev, (HFMODEM_FRAGSAMPLES-1) & 0xff);
- write_dsp(dev, (HFMODEM_FRAGSAMPLES-1) >> 8);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_prepare_output(struct hfmodem_state *dev)
-{
- unsigned long flags;
-
- if (!reset_dsp(dev)) {
- printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", hfmodem_drvname);
- return;
- }
- save_flags(flags);
- cli();
- disable_dma(dev->io.dma);
- clear_dma_ff(dev->io.dma);
- set_dma_mode(dev->io.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
- set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
- set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
- enable_dma(dev->io.dma);
- sbc_int_ack_16bit(dev);
- write_dsp(dev, SBC_SAMPLE_RATE_OUT); /* set sampling rate */
- write_dsp(dev, HFMODEM_SRATE >> 8);
- write_dsp(dev, HFMODEM_SRATE & 0xff);
- write_dsp(dev, SBC_SPEAKER_ON);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_trigger_output(struct hfmodem_state *dev)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- write_dsp(dev, SBC4_OUT16_AI_NO_FIFO);
- write_dsp(dev, SBC4_MODE_UNS_MONO);
- write_dsp(dev, (HFMODEM_FRAGSAMPLES-1) & 0xff);
- write_dsp(dev, (HFMODEM_FRAGSAMPLES-1) >> 8);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_stop(struct hfmodem_state *dev)
-{
- reset_dsp(dev);
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned int sbc4_intack(struct hfmodem_state *dev)
-{
- unsigned int dmaptr;
- unsigned long flags;
- unsigned char intsrc;
-
- save_flags(flags);
- cli();
- outb(0x82, DSP_MIXER_ADDR(dev->io.base_addr));
- intsrc = inb(DSP_MIXER_DATA(dev->io.base_addr));
- if (intsrc & 0x01)
- sbc_int_ack_8bit(dev);
- if (intsrc & 0x02)
- sbc_int_ack_16bit(dev);
- disable_dma(dev->io.dma);
- clear_dma_ff(dev->io.dma);
- dmaptr = get_dma_residue(dev->io.dma);
- enable_dma(dev->io.dma);
- restore_flags(flags);
- if (dmaptr == 0 || dmaptr > HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE)
- dmaptr = HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE;
- return (HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE - dmaptr) / 2;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_mixer(struct hfmodem_state *dev, int src, int igain, int ogain)
-{
- unsigned long flags;
- static const unsigned char srcbits[3] = { 0x18, 0x01, 0x06 };
-
- save_flags(flags);
- cli();
- if (src >= 0 && src <= 2) {
- set_mixer(dev, 0x3d, srcbits[src]);
- set_mixer(dev, 0x3e, srcbits[src]);
- }
- if (ogain >= 0 && ogain <= 255) {
- set_mixer(dev, 0x30, ogain);
- set_mixer(dev, 0x31, ogain);
- }
- if (igain >= 0 && igain <= 255) {
- set_mixer(dev, 0x36, igain);
- set_mixer(dev, 0x37, igain);
- set_mixer(dev, 0x38, igain);
- set_mixer(dev, 0x39, igain);
- set_mixer(dev, 0x3a, igain);
- }
- set_mixer(dev, 0x32, 0xff);
- set_mixer(dev, 0x33, 0xff);
- set_mixer(dev, 0x34, 0);
- set_mixer(dev, 0x35, 0);
- set_mixer(dev, 0x3b, 0); /* pc spkr vol */
- set_mixer(dev, 0x3c, 0); /* output src */
- set_mixer(dev, 0x3f, 0); /* inp gain */
- set_mixer(dev, 0x40, 0);
- set_mixer(dev, 0x41, 0); /* outp gain */
- set_mixer(dev, 0x42, 0);
- set_mixer(dev, 0x43, 1); /* mic agc off */
- set_mixer(dev, 0x44, 8<<4); /* treble */
- set_mixer(dev, 0x45, 8<<4);
- set_mixer(dev, 0x46, 8<<4); /* bass */
- set_mixer(dev, 0x47, 8<<4);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void ess_prepare_input(struct hfmodem_state *dev)
-{
- unsigned long flags;
- unsigned char tmp;
-
- if (!reset_ess(dev)) {
- printk(KERN_ERR "%s: sbc: cannot reset ess dsp\n", hfmodem_drvname);
- return;
- }
- save_flags(flags);
- cli();
- disable_dma(dev->io.dma);
- clear_dma_ff(dev->io.dma);
- set_dma_mode(dev->io.dma, DMA_MODE_READ | DMA_MODE_AUTOINIT);
- set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
- set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
- enable_dma(dev->io.dma);
- sbc_int_ack_8bit(dev);
- write_ess(dev, 0xa1, 128 - (397700 + HFMODEM_SRATE/2) / HFMODEM_SRATE);
- /*
- * Set filter divider register
- * Rolloff at 90% of the half sampling rate
- */
- write_ess(dev, 0xa2, 256-(7160000 / (82 * (HFMODEM_SRATE * 9 / 20))));
- write_dsp(dev, SBC_SPEAKER_OFF);
- write_ess(dev, 0xb8, 0x0e); /* Auto init DMA mode */
- read_ess(dev, 0xa8, &tmp);
- write_ess(dev, 0xa8, (tmp & ~0x03) | 2); /* Mono */
- write_ess(dev, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */
- /* 16 bit mono */
- write_ess(dev, 0xb7, 0x71);
- write_ess(dev, 0xb7, 0xf4);
-
- read_ess(dev, 0xb1, &tmp);
- write_ess(dev, 0xb1, (tmp & 0x0f) | 0x50);
- read_ess(dev, 0xb2, &tmp);
- write_ess(dev, 0xb2, (tmp & 0x0f) | 0x50);
-
- write_ess(dev, 0xa4, (unsigned char) ((-HFMODEM_FRAGSIZE) & 0xff));
- write_ess(dev, 0xa5, (unsigned char) (((-HFMODEM_FRAGSIZE) >> 8) & 0xff));
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void ess_trigger_input(struct hfmodem_state *dev)
-{
- unsigned long flags;
- unsigned char tmp;
-
- save_flags(flags);
- cli();
- read_ess(dev, 0xb8, &tmp);
- write_ess(dev, 0xb8, tmp | 0x0f); /* Go */
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-void ess_prepare_output(struct hfmodem_state *dev)
-{
- unsigned long flags;
- unsigned char tmp;
-
- if (!reset_ess(dev)) {
- printk(KERN_ERR "%s: sbc: cannot reset ess dsp\n", hfmodem_drvname);
- return;
- }
- save_flags(flags);
- cli();
- disable_dma(dev->io.dma);
- clear_dma_ff(dev->io.dma);
- set_dma_mode(dev->io.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
- set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
- set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
- enable_dma(dev->io.dma);
- sbc_int_ack_8bit(dev);
- write_ess(dev, 0xa1, 128 - (397700 + HFMODEM_SRATE/2) / HFMODEM_SRATE);
- /*
- * Set filter divider register
- * Rolloff at 90% of the half sampling rate
- */
- write_ess(dev, 0xa2, 256-(7160000 / (82 * (HFMODEM_SRATE * 9 / 20))));
- write_ess(dev, 0xb8, 0x04); /* Auto init DMA mode */
- read_ess(dev, 0xa8, &tmp);
- write_ess(dev, 0xa8, (tmp & ~0x03) | 2); /* Mono */
- write_ess(dev, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */
- /* 16 bit mono */
- write_ess(dev, 0xb6, 0x00);
- write_ess(dev, 0xb7, 0x71);
- write_ess(dev, 0xb7, 0xf4);
-
- read_ess(dev, 0xb1, &tmp);
- write_ess(dev, 0xb1, (tmp & 0x0f) | 0x50);
- read_ess(dev, 0xb2, &tmp);
- write_ess(dev, 0xb2, (tmp & 0x0f) | 0x50);
-
- write_ess(dev, 0xa4, (unsigned char) ((-HFMODEM_FRAGSIZE) & 0xff));
- write_ess(dev, 0xa5, (unsigned char) (((-HFMODEM_FRAGSIZE) >> 8) & 0xff));
-
- write_dsp(dev, SBC_SPEAKER_ON);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-void ess_trigger_output(struct hfmodem_state *dev)
-{
- unsigned long flags;
- unsigned char tmp;
-
- save_flags(flags);
- cli();
- read_ess(dev, 0xb8, &tmp);
- write_ess(dev, 0xb8, tmp | 0x05); /* Go */
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-unsigned int ess_intack(struct hfmodem_state *dev)
-{
- unsigned int dmaptr;
- unsigned long flags;
- unsigned char st;
-#if 0
- static unsigned int cnt = 0;
-#endif
-
- save_flags(flags);
- cli();
- st = inb(DSP_WRITE_STATUS(dev->io.base_addr));
- sbc_int_ack_8bit(dev);
- disable_dma(dev->io.dma);
- clear_dma_ff(dev->io.dma);
- dmaptr = get_dma_residue(dev->io.dma);
- enable_dma(dev->io.dma);
- restore_flags(flags);
-#if 0
- cnt = (cnt + 1) & 0x3f;
- if (!cnt)
- printk(KERN_DEBUG "%s: ess: FIFO: full:%c empty:%c half empty:%c IRQ: cpu:%c half empty:%c DMA:%c\n",
- hfmodem_drvname, '1'-!(st&0x20), '1'-!(st&0x10), '1'-!(st&0x8),
- '1'-!(st&0x4), '1'-!(st&0x2), '1'-!(st&0x1));
-#endif
- if (st & 0x20) /* FIFO full, 256 bytes */
- dmaptr += 256;
- else if (!(st & 0x10)) /* FIFO not empty, assume half full 128 bytes */
- dmaptr += 128;
- if (dmaptr > HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE)
- dmaptr -= HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE;
- if (dmaptr == 0 || dmaptr > HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE)
- dmaptr = HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE;
- return (HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE - dmaptr) / 2;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void ess_mixer(struct hfmodem_state *dev, int src, int igain, int ogain)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (src >= 0 && src <= 2)
- set_mixer(dev, 0x0c, ((src+3) & 3) << 1);
- if (ogain >= 0 && ogain <= 255)
- set_mixer(dev, 0x22, (ogain & 0xf0) | ((ogain >> 4) & 0xf));
- if (igain >= 0 && igain <= 255) {
- set_mixer(dev, 0x36, igain);
- set_mixer(dev, 0x37, igain);
- set_mixer(dev, 0x38, igain);
- set_mixer(dev, 0x39, igain);
- set_mixer(dev, 0x3a, igain);
- }
- set_mixer(dev, 0x4, 0xff);
- set_mixer(dev, 0xe, 0x0);
- set_mixer(dev, 0x26, 0);
- set_mixer(dev, 0x28, 0);
- set_mixer(dev, 0x2e, 0);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static const struct hfmodem_scops sbc4_scops = {
- SBC_EXTENT, sbc4_init, sbc4_prepare_input, sbc4_trigger_input,
- sbc4_prepare_output, sbc4_trigger_output, sbc4_stop, sbc4_intack, sbc4_mixer
-};
-
-static const struct hfmodem_scops ess_scops = {
- SBC_EXTENT, sbc4_init, ess_prepare_input, ess_trigger_input,
- ess_prepare_output, ess_trigger_output, sbc4_stop, ess_intack, ess_mixer
-};
-
-/* --------------------------------------------------------------------- */
diff --git a/drivers/char/hfmodem/wss.c b/drivers/char/hfmodem/wss.c
deleted file mode 100644
index c54aeadee..000000000
--- a/drivers/char/hfmodem/wss.c
+++ /dev/null
@@ -1,437 +0,0 @@
-/*****************************************************************************/
-
-/*
- * wss.c -- Linux soundcard HF FSK driver,
- * WindowsSoundSystem specific functions.
- *
- * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/hfmodem.h>
-
-/* --------------------------------------------------------------------- */
-
-#define WSS_CONFIG(iobase) (iobase+0)
-#define WSS_STATUS(iobase) (iobase+3)
-#define WSS_CODEC_IA(iobase) (iobase+4)
-#define WSS_CODEC_ID(iobase) (iobase+5)
-#define WSS_CODEC_STATUS(iobase) (iobase+6)
-#define WSS_CODEC_DATA(iobase) (iobase+7)
-
-#define WSS_EXTENT 8
-
-/* --------------------------------------------------------------------- */
-
-extern const struct hfmodem_scops wss_scops;
-
-/* --------------------------------------------------------------------- */
-
-static void write_codec(struct hfmodem_state *dev, unsigned char idx,
- unsigned char data)
-{
- int timeout = 900000;
-
- /* wait until codec ready */
- while (timeout > 0 && inb(WSS_CODEC_IA(dev->io.base_addr)) & 0x80)
- timeout--;
- outb(idx, WSS_CODEC_IA(dev->io.base_addr));
- outb(data, WSS_CODEC_ID(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned char read_codec(struct hfmodem_state *dev, unsigned char idx)
-{
- int timeout = 900000;
-
- /* wait until codec ready */
- while (timeout > 0 && inb(WSS_CODEC_IA(dev->io.base_addr)) & 0x80)
- timeout--;
- outb(idx & 0x1f, WSS_CODEC_IA(dev->io.base_addr));
- return inb(WSS_CODEC_ID(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ void wss_ack_int(struct hfmodem_state *dev)
-{
- outb(0, WSS_CODEC_STATUS(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-static int wss_srate_tab[16] = {
- 8000, 5510, 16000, 11025, 27420, 18900, 32000, 22050,
- -1, 37800, -1, 44100, 48000, 33075, 9600, 6620
-};
-
-static int wss_srate_index(int srate)
-{
- int i;
-
- for (i = 0; i < (sizeof(wss_srate_tab)/sizeof(wss_srate_tab[0])); i++)
- if (srate == wss_srate_tab[i] && wss_srate_tab[i] > 0)
- return i;
- return -1;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int wss_set_codec_fmt(struct hfmodem_state *dev, unsigned char fmt)
-{
- unsigned long time;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- /* Clock and data format register */
- write_codec(dev, 0x48, fmt);
- /* MCE and interface config reg */
- write_codec(dev, 0x49, 0xc);
- outb(0xb, WSS_CODEC_IA(dev->io.base_addr)); /* leave MCE */
- /*
- * wait for ACI start
- */
- time = 1000;
- while (!(read_codec(dev, 0x0b) & 0x20))
- if (!(--time)) {
- printk(KERN_WARNING "%s: ad1848 auto calibration timed out (1)\n",
- hfmodem_drvname);
- restore_flags(flags);
- return -1;
- }
- /*
- * wait for ACI end
- */
- sti();
- time = jiffies + HZ/4;
- while ((read_codec(dev, 0x0b) & 0x20) && ((signed)(jiffies - time) < 0));
- restore_flags(flags);
- if ((signed)(jiffies - time) >= 0) {
- printk(KERN_WARNING "%s: ad1848 auto calibration timed out (2)\n",
- hfmodem_drvname);
- return -1;
- }
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int wss_init_codec(struct hfmodem_state *dev)
-{
- unsigned char tmp, revwss, revid;
- static const signed char irqtab[16] = {
- -1, -1, 0x10, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20, -1, -1, -1, -1
- };
- static const signed char dmatab[4] = { 1, 2, -1, 3 };
- int fmt;
-
- if ((fmt = wss_srate_index(HFMODEM_SRATE)) < 0) {
- printk(KERN_ERR "%s: WSS: sampling rate not supported\n", hfmodem_drvname);
- return -1;
- }
- fmt &= 0x0f;
-#ifdef __BIG_ENDIAN
- fmt |= 0xc0;
-#else /* __BIG_ENDIAN */
- fmt |= 0x40;
-#endif /* __BIG_ENDIAN */
- tmp = inb(WSS_STATUS(dev->io.base_addr));
- if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x00 &&
- (tmp & 0x3f) != 0x0f) {
- printk(KERN_WARNING "%s: WSS card id register not found, "
- "address 0x%x, ID register 0x%02x\n", hfmodem_drvname,
- dev->io.base_addr, (int)tmp);
- /* return -1; */
- revwss = 0;
- } else {
- if ((tmp & 0x80) && ((dev->io.dma == 0) || ((dev->io.irq >= 8) && (dev->io.irq != 9)))) {
- printk(KERN_ERR "%s: WSS: DMA0 and/or IRQ8..IRQ15 "
- "(except IRQ9) cannot be used on an 8bit "
- "card\n", hfmodem_drvname);
- return -1;
- }
- if (dev->io.irq > 15 || irqtab[dev->io.irq] == -1) {
- printk(KERN_ERR "%s: WSS: invalid interrupt %d\n",
- hfmodem_drvname, (int)dev->io.irq);
- return -1;
- }
- if (dev->io.dma > 3 || dmatab[dev->io.dma] == -1) {
- printk(KERN_ERR "%s: WSS: invalid dma channel %d\n",
- hfmodem_drvname, (int)dev->io.dma);
- return -1;
- }
- tmp = irqtab[dev->io.irq] | dmatab[dev->io.dma];
- /* irq probe */
- outb((tmp & 0x38) | 0x40, WSS_CONFIG(dev->io.base_addr));
- if (!(inb(WSS_STATUS(dev->io.base_addr)) & 0x40)) {
- outb(0, WSS_CONFIG(dev->io.base_addr));
- printk(KERN_ERR "%s: WSS: IRQ%d is not free!\n",
- hfmodem_drvname, dev->io.irq);
- }
- outb(tmp, WSS_CONFIG(dev->io.base_addr));
- revwss = inb(WSS_STATUS(dev->io.base_addr)) & 0x3f;
- }
- /*
- * initialize the codec
- */
- write_codec(dev, 9, 0);
- write_codec(dev, 12, 0);
- write_codec(dev, 0, 0x45);
- if (read_codec(dev, 0) != 0x45)
- goto codec_err;
- write_codec(dev, 0, 0xaa);
- if (read_codec(dev, 0) != 0xaa)
- goto codec_err;
- if (wss_set_codec_fmt(dev, fmt))
- goto codec_err;
- write_codec(dev, 0, 0x40); /* left input control */
- write_codec(dev, 1, 0x40); /* right input control */
- write_codec(dev, 2, 0x80); /* left aux#1 input control */
- write_codec(dev, 3, 0x80); /* right aux#1 input control */
- write_codec(dev, 4, 0x80); /* left aux#2 input control */
- write_codec(dev, 5, 0x80); /* right aux#2 input control */
- write_codec(dev, 6, 0x80); /* left dac control */
- write_codec(dev, 7, 0x80); /* right dac control */
- write_codec(dev, 0xa, 0x2); /* pin control register */
- write_codec(dev, 0xd, 0x0); /* digital mix control */
- revid = read_codec(dev, 0xc) & 0xf;
- /*
- * print revisions
- */
- printk(KERN_INFO "%s: WSS revision %d, CODEC revision %d\n",
- hfmodem_drvname, (int)revwss, (int)revid);
- return 0;
- codec_err:
- outb(0, WSS_CONFIG(dev->io.base_addr));
- printk(KERN_ERR "%s: no WSS soundcard found at address 0x%x\n",
- hfmodem_drvname, dev->io.base_addr);
- return -1;
-}
-
-/* --------------------------------------------------------------------- */
-
-int hfmodem_wssprobe(struct hfmodem_state *dev)
-{
- if (dev->io.base_addr <= 0 || dev->io.base_addr > 0x1000-WSS_EXTENT ||
- dev->io.irq < 2 || dev->io.irq > 15 || dev->io.dma > 3 || dev->io.dma == 2)
- return -ENXIO;
- if (check_region(dev->io.base_addr, WSS_EXTENT))
- return -EACCES;
- /*
- * check if a card is available
- */
- if (wss_init_codec(dev)) {
- printk(KERN_ERR "%s: sbc: no card at io address 0x%x\n",
- hfmodem_drvname, dev->io.base_addr);
- return -ENODEV;
- }
- dev->scops = &wss_scops;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_init(struct hfmodem_state *dev)
-{
- wss_init_codec(dev);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_stop(struct hfmodem_state *dev)
-{
- unsigned long flags;
- unsigned char oldcodecmode;
- long abrt;
-
- save_flags(flags);
- cli();
- /*
- * perform the final DMA sequence to disable the codec request
- */
- oldcodecmode = read_codec(dev, 9);
- write_codec(dev, 9, 0xc); /* disable codec */
- wss_ack_int(dev);
- if (read_codec(dev, 11) & 0x10) {
- disable_dma(dev->io.dma);
- clear_dma_ff(dev->io.dma);
- set_dma_mode(dev->io.dma, (oldcodecmode & 1) ?
- (DMA_MODE_WRITE | DMA_MODE_AUTOINIT) : (DMA_MODE_READ | DMA_MODE_AUTOINIT));
- set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
- set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
- enable_dma(dev->io.dma);
- abrt = 0;
- while ((read_codec(dev, 11) & 0x10) || ((++abrt) >= 0x10000));
- }
- disable_dma(dev->io.dma);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_prepare_input(struct hfmodem_state *dev)
-{
- unsigned long flags;
-
- wss_stop(dev);
- save_flags(flags);
- cli();
- disable_dma(dev->io.dma);
- clear_dma_ff(dev->io.dma);
- set_dma_mode(dev->io.dma, DMA_MODE_READ | DMA_MODE_AUTOINIT);
- set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
- set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
- enable_dma(dev->io.dma);
- write_codec(dev, 15, (HFMODEM_FRAGSAMPLES-1) & 0xff);
- write_codec(dev, 14, (HFMODEM_FRAGSAMPLES-1) >> 8);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_trigger_input(struct hfmodem_state *dev)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- write_codec(dev, 9, 0x0e);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_prepare_output(struct hfmodem_state *dev)
-{
- unsigned long flags;
-
- wss_stop(dev);
- save_flags(flags);
- cli();
- disable_dma(dev->io.dma);
- clear_dma_ff(dev->io.dma);
- set_dma_mode(dev->io.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
- set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
- set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
- enable_dma(dev->io.dma);
- write_codec(dev, 15, (HFMODEM_FRAGSAMPLES-1) & 0xff);
- write_codec(dev, 14, (HFMODEM_FRAGSAMPLES-1) >> 8);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_trigger_output(struct hfmodem_state *dev)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- write_codec(dev, 9, 0x0d);
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned int wss_intack(struct hfmodem_state *dev)
-{
- unsigned int dmaptr, nums;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- wss_ack_int(dev);
- disable_dma(dev->io.dma);
- clear_dma_ff(dev->io.dma);
- dmaptr = get_dma_residue(dev->io.dma);
- if (dmaptr == 0 || dmaptr > HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE)
- dmaptr = HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE;
- nums = (((dmaptr - 1) % HFMODEM_FRAGSIZE) - 1) / 2;
- write_codec(dev, 15, nums & 0xff);
- write_codec(dev, 14, nums >> 8);
- enable_dma(dev->io.dma);
- restore_flags(flags);
- return (HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE - dmaptr) / 2;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_mixer(struct hfmodem_state *dev, int src, int igain, int ogain)
-{
- unsigned long flags;
- static const unsigned char srctoreg[3] = { 1, 2, 0 };
- static const unsigned char regtosrc[4] = { 2, 0, 1, 0 };
- unsigned char tmp;
-
- save_flags(flags);
- cli();
- tmp = read_codec(dev, 0x00);
- if (src < 0 || src > 2)
- src = regtosrc[(tmp >> 6) & 3];
- if (igain < 0 || igain > 255) {
- if (src == 1)
- igain = ((tmp & 0xf) + ((tmp & 0x20) ? 13 : 0)) << 3;
- else
- igain = (tmp & 0xf) << 4;
- }
- if (src == 1) {
- if (igain > (28<<3))
- tmp = 0x2f;
- else if (igain >= (13<<3))
- tmp = 0x20 + (((igain >> 3) - 13) & 0xf);
- else
- tmp = (igain >> 3) & 0xf;
- } else
- tmp = (igain >> 4) & 0xf;
- tmp |= srctoreg[src] << 6;
- write_codec(dev, 0, tmp);
- write_codec(dev, 1, tmp);
- if (ogain > 0 && ogain <= 255) {
- tmp = 63 - (ogain >> 2);
- write_codec(dev, 6, tmp);
- write_codec(dev, 7, tmp);
- } else if (ogain == 0) {
- write_codec(dev, 6, 0x80);
- write_codec(dev, 7, 0x80);
- }
- restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static const struct hfmodem_scops wss_scops = {
- WSS_EXTENT, wss_init, wss_prepare_input, wss_trigger_input,
- wss_prepare_output, wss_trigger_output, wss_stop, wss_intack, wss_mixer
-};
-
-/* --------------------------------------------------------------------- */
diff --git a/drivers/char/i2c-parport.c b/drivers/char/i2c-parport.c
index 29b5e16c9..a8f83ce8e 100644
--- a/drivers/char/i2c-parport.c
+++ b/drivers/char/i2c-parport.c
@@ -22,7 +22,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
#define I2C_DELAY 10
diff --git a/drivers/char/ip2.c b/drivers/char/ip2.c
new file mode 100644
index 000000000..e9880146a
--- /dev/null
+++ b/drivers/char/ip2.c
@@ -0,0 +1,72 @@
+// ip2.c
+// This is a dummy module to make the firmware available when needed
+// and allows it to be unloaded when not. Rumor is the __initdata
+// macro doesn't always works on all platforms so we use this kludge.
+// If not compiled as a module it just makes fip_firm avaliable then
+// __initdata should work as advertized
+//
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+
+#include "./ip2/ip2types.h"
+#include "./ip2/fip_firm.h" // the meat
+
+int
+ip2_loadmain(int *, int *, unsigned char *, int ); // ref into ip2main.c
+
+#ifdef MODULE
+static int io[IP2_MAX_BOARDS]= { 0,};
+static int irq[IP2_MAX_BOARDS] = { 0,};
+
+MODULE_AUTHOR("Doug McNash");
+MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
+MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
+MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
+MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
+
+
+//======================================================================
+int
+init_module(void)
+{
+ int rc;
+
+ MOD_INC_USE_COUNT; // hold till done
+
+ rc = ip2_loadmain(io,irq,(unsigned char *)fip_firm,sizeof(fip_firm));
+ // The call to lock and load main, create dep
+
+ MOD_DEC_USE_COUNT; //done - kerneld now can unload us
+ return rc;
+}
+
+//======================================================================
+int
+ip2_init(void)
+{
+ // call to this is int tty_io.c so we need this
+ return 0;
+}
+
+//======================================================================
+void
+cleanup_module(void)
+{
+}
+
+#else // !MODULE
+
+#ifndef NULL
+# define NULL ((void *) 0)
+#endif
+
+int
+ip2_init(void) {
+ return ip2_loadmain(NULL,NULL,(unsigned char *)fip_firm,sizeof(fip_firm));
+}
+
+#endif /* !MODULE */
diff --git a/drivers/char/ip2/.cvsignore b/drivers/char/ip2/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/char/ip2/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile
new file mode 100644
index 000000000..26fb618ca
--- /dev/null
+++ b/drivers/char/ip2/Makefile
@@ -0,0 +1,12 @@
+
+all: ip2mkdev ip2trace ip2stat
+
+ip2mkdev: ip2mkdev.c
+ cc -o ip2mkdev ip2mkdev.c
+
+ip2trace: ip2trace.c
+ cc -o ip2trace ip2trace.c
+
+ip2stat: ip2stat.c
+ cc -o ip2stat ip2stat.c
+
diff --git a/drivers/char/ip2/fip_firm.h b/drivers/char/ip2/fip_firm.h
new file mode 100644
index 000000000..d85c3fc31
--- /dev/null
+++ b/drivers/char/ip2/fip_firm.h
@@ -0,0 +1,2149 @@
+/* fip_firm.h - Intelliport II loadware */
+/* -31232 bytes read from ff.lod */
+
+unsigned char fip_firm[] __initdata = {
+0x3C,0x42,0x8A,0xE1,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x57,0x65,0x64,0x20,0x4A,0x75,0x6E,0x20,0x32,0x33,0x20,0x31,0x35,0x3A,0x33,0x30,
+0x3A,0x31,0x33,0x20,0x31,0x39,0x39,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xE9,0x68,0x0F,0x42,0x65,0x47,0x69,0x4E,0x6E,0x49,0x6E,0x47,0x20,0x6F,0x46,0x20,
+0x63,0x4F,0x64,0x45,0xCC,0x13,0x5A,0x15,0xE8,0x16,0x76,0x18,0x04,0x1A,0x92,0x1B,
+0x20,0x1D,0xAE,0x1E,0x3C,0x20,0xCA,0x21,0x58,0x23,0xE6,0x24,0x74,0x26,0x02,0x28,
+0x90,0x29,0x1E,0x2B,0xAC,0x2C,0x3A,0x2E,0xC8,0x2F,0x56,0x31,0xE4,0x32,0x72,0x34,
+0x00,0x36,0x8E,0x37,0x1C,0x39,0xAA,0x3A,0x38,0x3C,0xC6,0x3D,0x54,0x3F,0xE2,0x40,
+0x70,0x42,0xFE,0x43,0x8C,0x45,0x1A,0x47,0xA8,0x48,0x36,0x4A,0xC4,0x4B,0x52,0x4D,
+0xE0,0x4E,0x6E,0x50,0xFC,0x51,0x8A,0x53,0x18,0x55,0xA6,0x56,0x34,0x58,0xC2,0x59,
+0x50,0x5B,0xDE,0x5C,0x6C,0x5E,0xFA,0x5F,0x88,0x61,0x16,0x63,0xA4,0x64,0x32,0x66,
+0xC0,0x67,0x4E,0x69,0xDC,0x6A,0x6A,0x6C,0xF8,0x6D,0x86,0x6F,0x14,0x71,0xA2,0x72,
+0x30,0x74,0xBE,0x75,0x4C,0x77,0x6C,0x77,0x8C,0x77,0xAC,0x77,0x33,0xDB,0x8A,0xDC,
+0x53,0x33,0xDB,0x25,0x07,0x00,0x75,0x0A,0x8A,0x1E,0x08,0x01,0x83,0xE3,0x0C,0xEB,
+0x20,0x90,0x3C,0x01,0x75,0x0A,0x8A,0x1E,0x08,0x01,0x80,0xE3,0xC0,0xEB,0x12,0x90,
+0x8A,0x1E,0x0D,0x01,0x3C,0x02,0x75,0x06,0x80,0xE3,0x0C,0xEB,0x04,0x90,0x80,0xE3,
+0xC0,0x53,0x50,0x8B,0x1E,0xBA,0x13,0x8E,0xDB,0xE8,0x4C,0x65,0x55,0x8B,0xEC,0x53,
+0x1E,0x2B,0xC0,0x8E,0xD8,0x8B,0x5E,0x04,0xC1,0xE3,0x04,0x03,0x5E,0x06,0xD1,0xE3,
+0x2E,0x8B,0x9F,0x44,0x00,0x8D,0x47,0x2A,0x1E,0x5A,0x1F,0x5B,0x5D,0xC3,0x55,0x8B,
+0xEC,0x53,0x1E,0x2B,0xC0,0x8E,0xD8,0x8B,0x5E,0x04,0xC1,0xE3,0x04,0x03,0x5E,0x06,
+0xD1,0xE3,0x2E,0x8B,0x9F,0x44,0x00,0x8D,0x47,0x34,0x1E,0x5A,0x1F,0x5B,0x5D,0xC3,
+0xFB,0x55,0x8B,0xEC,0x53,0x51,0x52,0x56,0x57,0x1E,0x06,0x1E,0x07,0x33,0xC0,0x8E,
+0xD8,0x8B,0x5E,0x04,0x26,0x8A,0x47,0x59,0x25,0x03,0x00,0x8B,0xF0,0xD1,0xE6,0x2E,
+0x8B,0xB4,0xC4,0x00,0xC1,0xE0,0x04,0x26,0x02,0x47,0x1A,0xD1,0xE0,0x8B,0xE8,0x2E,
+0x8B,0xAE,0x44,0x00,0x89,0x2C,0x26,0x8A,0x47,0x1C,0x88,0x44,0x0F,0x26,0x8A,0x47,
+0x1D,0x88,0x44,0x10,0x26,0x8A,0x47,0x1E,0x88,0x44,0x11,0x26,0x8A,0x47,0x1F,0x88,
+0x44,0x12,0x26,0x8A,0x47,0x20,0x88,0x44,0x13,0x26,0x8A,0x47,0x23,0x88,0x44,0x14,
+0x26,0x8A,0x47,0x24,0x88,0x44,0x15,0x26,0x8A,0x47,0x5A,0x88,0x44,0x0E,0x33,0xC0,
+0x89,0x44,0x06,0x89,0x44,0x08,0x88,0x44,0x0B,0x88,0x44,0x0A,0xB0,0x21,0xB4,0x64,
+0x89,0x44,0x04,0x89,0x44,0x02,0xB0,0x55,0x88,0x44,0x0D,0x88,0x44,0x0C,0xE8,0x6A,
+0x00,0x72,0x5B,0xE8,0xC9,0x00,0xE8,0xBD,0x10,0x89,0x44,0x08,0x80,0x7C,0x0F,0x01,
+0x74,0x29,0xE8,0x2B,0x02,0xE8,0x7F,0x02,0x80,0x7C,0x0F,0x03,0x74,0x1D,0xE8,0xA5,
+0x10,0x8B,0xF8,0x2B,0x44,0x08,0x3D,0xA0,0x0F,0x72,0x10,0x89,0x7C,0x08,0x33,0xC0,
+0x87,0x44,0x06,0x85,0xC0,0x75,0x04,0xC6,0x44,0x0A,0xFF,0x8A,0x44,0x0A,0x84,0xC0,
+0x75,0x0B,0xB8,0x08,0x00,0xE8,0x4C,0x4A,0xE8,0xA9,0x01,0x73,0xBF,0xE8,0x4F,0x01,
+0x81,0x66,0x48,0x7F,0xFF,0x83,0x66,0x7A,0xBF,0xB0,0x02,0xE8,0x00,0x0E,0x8A,0x44,
+0x0A,0x98,0x07,0x1F,0x5F,0x5E,0x5A,0x59,0x5B,0x5D,0xC3,0x81,0x4E,0x48,0x80,0x00,
+0xB0,0x40,0xE8,0x1F,0x4A,0xE8,0x6B,0x40,0x73,0x2A,0xE8,0x49,0x10,0x8B,0xD8,0xB0,
+0x05,0xE8,0x10,0x4A,0xF6,0x46,0x27,0x02,0x75,0x1A,0xE8,0x39,0x10,0x2B,0xC3,0x3D,
+0x58,0x1B,0x72,0xEB,0x81,0x66,0x48,0x7F,0xFF,0xB0,0x02,0xE8,0xC0,0x0D,0xC6,0x44,
+0x0A,0x01,0xF9,0xC3,0x83,0x4E,0x7A,0x40,0xF8,0xC3,0xFB,0xB0,0x01,0xE8,0xE4,0x49,
+0xFA,0xE8,0x95,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xB0,0x4E,0xE6,0x0A,0xFB,0xB0,
+0x01,0xE8,0xD0,0x49,0xFA,0xE8,0x81,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xC3,0xFA,
+0xE8,0x76,0x1E,0xE4,0xEC,0x88,0x44,0x16,0xE4,0xE4,0x88,0x44,0x17,0xE4,0xF8,0x88,
+0x44,0x18,0xE4,0xF0,0x88,0x44,0x19,0xE4,0x10,0x88,0x44,0x1A,0xE4,0x12,0x88,0x44,
+0x1B,0xE4,0x14,0x88,0x44,0x1C,0xE4,0x34,0x88,0x44,0x1D,0xE4,0x36,0x88,0x44,0x1E,
+0xE4,0xD8,0x24,0x01,0x8A,0xE0,0xE4,0xDA,0x24,0x02,0x0A,0xC4,0x88,0x44,0x1F,0x8A,
+0x44,0x10,0xE8,0xC9,0x1F,0x8A,0x44,0x11,0xE8,0x31,0x21,0x8A,0x44,0x12,0xE8,0x85,
+0x21,0x8A,0x44,0x13,0xE8,0x3F,0x21,0xC6,0x86,0xA1,0x00,0x00,0xE4,0x14,0x24,0x10,
+0xE6,0x14,0xE4,0x12,0x24,0x3D,0xE6,0x12,0x8A,0x44,0x15,0x3C,0x01,0x72,0x1E,0x77,
+0x16,0xB0,0x11,0xE6,0x34,0xB0,0x13,0xE6,0x36,0xE4,0x14,0x0C,0x10,0xE6,0x14,0xE4,
+0x12,0x0C,0x40,0xE6,0x12,0xEB,0x06,0xE4,0x12,0x0C,0x02,0xE6,0x12,0x8A,0x44,0x0F,
+0x3C,0x01,0x74,0x06,0x3C,0x02,0x74,0x0A,0xEB,0x0E,0xE4,0x12,0x0C,0x08,0xE6,0x12,
+0xEB,0x06,0xE4,0x12,0x0C,0x10,0xE6,0x12,0xE8,0x2F,0xFF,0x8A,0x44,0x14,0x3C,0x02,
+0x75,0x08,0xB0,0x55,0x88,0x44,0x0C,0x88,0x44,0x0D,0xB0,0x21,0xB4,0x64,0x89,0x44,
+0x04,0x89,0x44,0x02,0xE4,0x0C,0x0C,0x10,0xE6,0x0C,0xE8,0xCF,0x39,0xFB,0xC3,0xE8,
+0x41,0x3F,0x73,0x08,0xFB,0xB0,0x0A,0xE8,0xEA,0x48,0xEB,0xF3,0xFA,0xE8,0x99,0x1D,
+0x8A,0x64,0x16,0x8A,0x44,0x17,0x89,0x86,0x94,0x00,0xE6,0xE4,0x8A,0xC4,0xE6,0xEC,
+0x8A,0x64,0x18,0x8A,0x44,0x19,0x89,0x86,0x96,0x00,0xE6,0xF0,0x8A,0xC4,0xE6,0xF8,
+0x8A,0x44,0x1A,0xE6,0x10,0x8A,0x44,0x1B,0xE6,0x12,0x8A,0x44,0x1C,0xE6,0x14,0x8A,
+0x44,0x1D,0xE6,0x34,0x8A,0x44,0x1E,0xE6,0x36,0x8A,0x44,0x1F,0xE6,0xD8,0xE6,0xDA,
+0xE9,0xB7,0xFE,0x90,0xFA,0x8A,0x44,0x0E,0xE6,0xFE,0xE4,0x02,0xA8,0x01,0x75,0x05,
+0x33,0xC0,0xFB,0xF8,0xC3,0x33,0xC0,0xE4,0x00,0xFB,0xF9,0xC3,0x8A,0x64,0x14,0x80,
+0xFC,0x02,0x74,0x2B,0xFE,0xC0,0xFE,0xC7,0x80,0xFF,0x4E,0x72,0x1C,0x74,0x09,0x80,
+0xFF,0x50,0x73,0x08,0xB0,0x0A,0xEB,0x17,0xB0,0x0D,0xEB,0x13,0x02,0xDC,0x32,0xFF,
+0x80,0xFB,0x7F,0x7C,0x02,0xB3,0x21,0x8A,0xC3,0x3C,0x7F,0x7C,0x02,0xB0,0x21,0xC3,
+0xFA,0x80,0x7C,0x0B,0x04,0x76,0x02,0xFB,0xC3,0x8B,0x46,0x24,0x3D,0x08,0x00,0x72,
+0xF6,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x8A,0x44,0x0C,0x8B,0x5C,0x02,0xAA,0xE8,0xAB,
+0xFF,0xAA,0xE8,0xA7,0xFF,0xAA,0xE8,0xA3,0xFF,0xAA,0xE8,0x9F,0xFF,0x88,0x44,0x0C,
+0x89,0x5C,0x02,0x80,0x44,0x0B,0x04,0x89,0x7E,0x22,0x83,0x6E,0x24,0x04,0x83,0x46,
+0x1A,0x04,0x80,0x7E,0x26,0x02,0x74,0x06,0x80,0x66,0x26,0xFD,0xFB,0xC3,0x60,0xB0,
+0xFD,0xE8,0xE4,0x3E,0x61,0xFB,0xC3,0xFA,0x80,0x7C,0x0F,0x03,0x75,0x09,0xC6,0x44,
+0x0B,0x00,0xE8,0xC7,0x38,0xFB,0xC3,0xC4,0x7E,0x14,0x8B,0x4E,0x3A,0x85,0xC9,0x75,
+0x35,0x26,0x8B,0x0D,0x47,0x47,0xE3,0xEA,0x3B,0x7E,0x04,0x76,0x22,0xB8,0x02,0x00,
+0x39,0x46,0x2E,0x77,0x07,0xC7,0x46,0x2E,0x00,0x00,0xEB,0x13,0x8B,0x5E,0x2C,0x89,
+0x5E,0x04,0x26,0xC7,0x07,0x00,0x00,0x43,0x43,0x89,0x5E,0x2C,0x29,0x46,0x2E,0x85,
+0xC9,0x78,0xCE,0x89,0x4E,0x3A,0x8A,0x44,0x0D,0x8B,0x5C,0x04,0x26,0x8A,0x25,0x47,
+0x3A,0xC4,0x75,0x16,0xFE,0x4C,0x0B,0xFF,0x44,0x06,0xE8,0x0F,0xFF,0xE2,0xED,0x88,
+0x44,0x0D,0x89,0x5C,0x04,0x89,0x4E,0x3A,0xEB,0xA7,0xC6,0x44,0x0A,0xFE,0xE8,0x5B,
+0x38,0xFB,0xC3,0x90,0xE8,0xAF,0x0D,0x8A,0xE8,0x8A,0x0E,0xCB,0x13,0xB3,0x07,0x8A,
+0xC1,0xEE,0xEB,0x00,0xEC,0x3A,0xC1,0x75,0x09,0x02,0xCD,0xFE,0xCB,0x75,0xF0,0xEB,
+0x0C,0x90,0x88,0x0E,0xCB,0x13,0x8A,0xE8,0xBB,0xFF,0xFF,0xF9,0xC3,0x88,0x0E,0xCB,
+0x13,0xF8,0xC3,0x90,0xBB,0x3F,0x3F,0x8A,0x8E,0x9E,0x00,0xBA,0xFE,0x00,0xEC,0x8A,
+0xE8,0x32,0xC1,0x22,0xC3,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x90,0xE8,0xE5,0xFF,0x73,
+0x01,0xC3,0xBA,0xD0,0x00,0xBB,0x03,0x03,0x8A,0x8E,0x9F,0x00,0xEC,0x8A,0xE8,0x32,
+0xC1,0x22,0xC3,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x90,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,
+0x80,0x3E,0xC8,0x13,0x00,0x75,0x07,0xB0,0x0A,0xE8,0x08,0x47,0xEB,0xF2,0xFB,0x33,
+0xDB,0x8A,0x1E,0xC9,0x13,0x43,0x43,0x83,0xFB,0x7E,0x76,0x07,0x33,0xDB,0xB0,0x02,
+0xE8,0xF1,0x46,0x2E,0x8B,0xAF,0x44,0x00,0x83,0x7E,0x08,0x00,0x74,0xE7,0x88,0x1E,
+0xC9,0x13,0xB0,0x02,0xE8,0xDD,0x46,0xFA,0xF7,0x46,0x38,0x40,0x00,0x74,0x14,0xE8,
+0x92,0x1B,0xE8,0x7F,0xFF,0x72,0x1C,0x33,0xD2,0x8A,0x96,0x9F,0x00,0x83,0xC2,0x0E,
+0xEB,0x0C,0x90,0xE8,0x73,0x1B,0xE8,0x83,0xFF,0x72,0x08,0xBA,0x48,0x00,0xE8,0x33,
+0xFF,0x73,0xAB,0x23,0xCB,0x89,0x8E,0x9A,0x00,0x89,0x96,0x9C,0x00,0xFE,0x86,0xB5,
+0x00,0xC6,0x06,0xC8,0x13,0x00,0xB0,0x0A,0xE8,0x63,0x0A,0xFB,0xEB,0x89,0x10,0x18,
+0x08,0x28,0x33,0xC0,0xA0,0x05,0x01,0x8A,0xC8,0x24,0x40,0x75,0x24,0xC7,0x06,0x7C,
+0x12,0x70,0x45,0xC7,0x06,0x42,0x12,0x01,0x00,0xC6,0x06,0x54,0x12,0x02,0xB0,0x08,
+0xF6,0xC1,0x01,0x74,0x02,0xB0,0x04,0xA3,0x46,0x12,0xA2,0x4C,0x12,0xA2,0x94,0x12,
+0xC3,0xC7,0x06,0x7C,0x12,0x98,0x45,0xA0,0x0F,0x01,0x84,0xC0,0x75,0x0E,0x6A,0x00,
+0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xAD,0x0C,0x90,0xC7,0x06,0x44,0x12,
+0x01,0x00,0xA3,0x42,0x12,0x8B,0xD8,0xC1,0xE3,0x04,0x88,0x1E,0x94,0x12,0xBE,0xE2,
+0x05,0x2B,0xF0,0x8B,0xC8,0x33,0xDB,0x8B,0xFB,0x2E,0xAC,0x88,0x85,0x48,0x12,0x8A,
+0xD8,0x0C,0x05,0xE6,0xFE,0x8A,0xE0,0xEB,0x00,0xE4,0xFE,0x32,0xC4,0xA8,0x3F,0x74,
+0x03,0xE9,0x9A,0x00,0xE4,0x00,0x88,0x85,0x50,0x12,0x8A,0xE0,0x24,0x30,0xBA,0x10,
+0xFF,0x3C,0x30,0x74,0x12,0x80,0xFC,0x04,0x74,0x0A,0xBA,0x04,0x03,0xF6,0x06,0x08,
+0x01,0xFE,0x74,0x03,0xBA,0x08,0x0F,0x88,0x95,0x4C,0x12,0x02,0xFA,0x32,0xC0,0xF6,
+0xC4,0x08,0x74,0x02,0xB0,0x01,0x88,0x85,0x58,0x12,0x8A,0xC4,0x3C,0x35,0x74,0x57,
+0x3C,0x34,0x74,0x53,0x3C,0x04,0x74,0x4F,0x3C,0x14,0x74,0x4B,0x3C,0x15,0x74,0x47,
+0xA8,0x40,0x74,0x25,0xC6,0x85,0x54,0x12,0x04,0xD1,0xE7,0xB4,0x03,0x8A,0xC3,0x89,
+0x85,0x5C,0x12,0x8A,0xC3,0x8A,0xE3,0x80,0xCC,0x01,0x89,0x85,0x64,0x12,0xD1,0xEF,
+0x47,0xE2,0x03,0xEB,0x1A,0x90,0xE9,0x70,0xFF,0xC6,0x85,0x54,0x12,0x02,0xD1,0xE7,
+0x8A,0xE6,0x8A,0xC3,0x0C,0x04,0x89,0x85,0x5C,0x12,0xD1,0xEF,0x47,0xE2,0xE7,0x33,
+0xC0,0x8A,0xC7,0xA3,0x46,0x12,0xC3,0xC6,0x85,0x54,0x12,0x06,0xEB,0xBB,0xC6,0x85,
+0x54,0x12,0x00,0x33,0xC0,0x88,0x85,0x50,0x12,0x88,0x85,0x4C,0x12,0x88,0x85,0x58,
+0x12,0xEB,0xA6,0xC7,0x46,0x26,0x02,0x12,0x8B,0x46,0x1E,0x89,0x46,0x00,0x89,0x46,
+0x22,0x8B,0x46,0x20,0x89,0x46,0x24,0xC7,0x46,0x1A,0x00,0x00,0xC3,0xC7,0x46,0x3C,
+0x80,0x00,0xC7,0x46,0x38,0x01,0x00,0x1E,0x56,0x8B,0x76,0x30,0x89,0x76,0x04,0x89,
+0x76,0x14,0x8E,0x5E,0x06,0x33,0xC0,0x89,0x04,0x46,0x46,0x89,0x76,0x2C,0x89,0x46,
+0x3A,0x8B,0x46,0x32,0x48,0x48,0x89,0x46,0x2E,0x5E,0x1F,0xC3,0x33,0xC0,0x89,0x46,
+0x48,0x89,0x46,0x4A,0xC7,0x46,0x46,0xAE,0x01,0x89,0x46,0x4E,0x8B,0x46,0x44,0x89,
+0x46,0x50,0x8B,0x46,0x42,0x89,0x46,0x40,0x89,0x46,0x08,0xC3,0x33,0xC0,0x89,0x46,
+0x76,0x89,0x46,0x78,0xC7,0x46,0x7A,0x10,0x00,0x56,0x1E,0x8B,0x76,0x70,0x89,0x76,
+0x10,0x89,0x76,0x0C,0x8E,0x5E,0x12,0xC7,0x04,0x00,0x00,0x8B,0x46,0x72,0x89,0x46,
+0x74,0x1F,0x5E,0xC3,0x89,0x56,0x18,0x89,0x56,0x02,0x89,0x56,0x06,0x89,0x56,0x0A,
+0x89,0x56,0x0E,0x89,0x56,0x12,0x89,0x56,0x16,0x8B,0xD8,0x4B,0x4B,0xC1,0xE3,0x02,
+0xBF,0x02,0x00,0x89,0x7E,0x1E,0x03,0xFB,0x89,0x7E,0x30,0x03,0xFB,0x89,0x7E,0x42,
+0x03,0xFB,0x89,0x7E,0x70,0x83,0xEB,0x08,0x89,0x5E,0x20,0x89,0x5E,0x32,0x89,0x5E,
+0x44,0x89,0x5E,0x72,0x50,0xE8,0x2B,0xFF,0xE8,0x71,0xFF,0xE8,0x3F,0xFF,0xE8,0x8B,
+0xFF,0x58,0xC3,0xB8,0x10,0x75,0xC1,0xE8,0x04,0x0E,0x5B,0x03,0xC3,0xA3,0xBA,0x13,
+0x83,0x3E,0x42,0x12,0x00,0x74,0x07,0x80,0x3E,0x94,0x12,0x00,0x75,0x0E,0x6A,0x00,
+0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xBD,0x0A,0x90,0xB8,0x30,0x7A,0xC1,
+0xE8,0x04,0x40,0xA3,0xC0,0x13,0x2B,0x06,0x12,0x01,0xF7,0xD8,0x33,0xD2,0x8B,0xCA,
+0x8A,0x0E,0x94,0x12,0xF7,0xF1,0x3D,0x80,0x00,0x77,0x0E,0x6A,0x00,0x1F,0xC6,0x06,
+0x93,0x12,0x25,0x9C,0x0E,0xE8,0x90,0x0A,0x90,0x48,0x3D,0xFF,0x07,0x72,0x03,0xB8,
+0xFF,0x07,0xA3,0xC2,0x13,0x33,0xC9,0x8A,0x0E,0x94,0x12,0x33,0xF6,0xB8,0x00,0x09,
+0x2E,0x8B,0xAC,0x44,0x00,0x89,0x46,0x4C,0x40,0x46,0x46,0xE2,0xF3,0x8A,0x0E,0x94,
+0x12,0x33,0xF6,0x8B,0x16,0xC0,0x13,0xA1,0xC2,0x13,0x2E,0x8B,0xAC,0x44,0x00,0xE8,
+0x22,0xFF,0x03,0xD0,0x46,0x46,0xE2,0xF2,0xC3,0x33,0xC0,0x2E,0x8B,0xAD,0x44,0x00,
+0x89,0x46,0x08,0x47,0x47,0xE2,0xF4,0xC3,0x51,0x33,0xC0,0x0A,0xC2,0x2E,0x8B,0xAD,
+0x44,0x00,0x89,0x86,0x9E,0x00,0x81,0x4E,0x38,0x00,0x20,0x47,0x47,0xFE,0xC4,0x80,
+0xFC,0x04,0x72,0x04,0x32,0xE4,0xFE,0xC0,0xE2,0xE3,0x59,0x83,0xE9,0x10,0x74,0x05,
+0xF7,0xD9,0xE8,0xC4,0xFF,0xC3,0x51,0x33,0xC0,0x0A,0xC2,0x2E,0x8B,0xAD,0x44,0x00,
+0x89,0x86,0x9E,0x00,0x83,0x4E,0x38,0x40,0x47,0x47,0x80,0xC4,0x10,0x79,0x04,0x32,
+0xE4,0xFE,0xC0,0xE2,0xE6,0x59,0x83,0xE9,0x10,0x74,0x05,0xF7,0xD9,0xE8,0x99,0xFF,
+0xC3,0xE8,0xD2,0xFF,0xC3,0x89,0x08,0x98,0x08,0xC6,0x08,0xF1,0x08,0x8B,0x0E,0x42,
+0x12,0x33,0xF6,0x51,0x56,0x33,0xDB,0x8B,0xCB,0x8A,0x94,0x48,0x12,0x8A,0x8C,0x4C,
+0x12,0x8A,0x9C,0x54,0x12,0x8B,0xFE,0xC1,0xE7,0x05,0x85,0xDB,0x75,0x02,0xB1,0x10,
+0x2E,0xFF,0x97,0xF5,0x08,0x5E,0x59,0x46,0xE2,0xD9,0xC3,0x01,0xCC,0x03,0xD0,0x00,
+0xE8,0x02,0xD0,0x00,0xE8,0x01,0xD0,0x00,0xE8,0x00,0xD0,0x00,0xE8,0x04,0xD0,0xA8,
+0xDA,0x00,0xDC,0x00,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x04,0xD0,0xA8,
+0xDA,0x20,0xDC,0x00,0xDE,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x00,0xD8,0x03,0xCC,0x03,
+0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,
+0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x04,0xD0,0x00,
+0xDA,0x20,0xDC,0x03,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x00,
+0xD8,0x00,0xCC,0x00,0xD0,0x00,0x00,0x56,0x52,0x1E,0x0E,0x1F,0xBE,0x2B,0x09,0x33,
+0xD2,0xFC,0xAD,0x85,0xC0,0x74,0x0D,0x8A,0xD4,0xEE,0xAD,0x85,0xC0,0x74,0x05,0x8A,
+0xD4,0xEE,0xEB,0xEE,0x1F,0x5A,0x5E,0xC3,0xE4,0x80,0x84,0xC0,0x74,0x16,0x78,0x14,
+0xB0,0x27,0xE6,0xFC,0xB0,0x11,0xE6,0x34,0xE4,0xFC,0x3C,0x27,0x75,0x06,0xE4,0x11,
+0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x83,0xEA,0x02,0xB0,
+0x10,0xEE,0x88,0x86,0xAF,0x00,0xB0,0x11,0x83,0xC2,0x04,0xEE,0x83,0xC2,0x02,0xEE,
+0xB0,0x13,0x83,0xC2,0x02,0xEE,0x83,0xC2,0x02,0xEE,0x2E,0xA1,0x2E,0x2D,0x89,0x86,
+0x94,0x00,0x83,0xEA,0x0E,0xEE,0x83,0xC2,0x02,0x8A,0xC4,0xEE,0x83,0xC2,0x04,0xB0,
+0x03,0xEE,0x88,0x86,0xA8,0x00,0x83,0xEA,0x04,0x32,0xC0,0xEE,0x83,0xC2,0x02,0xB0,
+0x89,0xEE,0x88,0x86,0xA6,0x00,0x0C,0x06,0xEE,0xB0,0x40,0xB4,0x38,0x89,0x46,0x1C,
+0xC7,0x46,0x36,0x38,0x00,0x83,0xC2,0x04,0x32,0xC0,0xEE,0x88,0x86,0xA7,0x00,0xC3,
+0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x83,0xEA,0x02,0xEC,0x3A,0x86,0xAF,0x00,0x75,0x24,
+0x83,0xC2,0x04,0xEC,0x3C,0x11,0x75,0x1C,0x83,0xC2,0x06,0xEC,0x3C,0x13,0x75,0x14,
+0x83,0xEA,0x08,0x8A,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x02,0xEC,0x24,0xC0,0x3C,0xC0,
+0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x33,0xC9,0x8B,0xD1,0x8B,0xF1,0x8A,0x0E,0x94,0x12,
+0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x0E,0x8A,
+0x86,0x9E,0x00,0xE6,0xFE,0x32,0xC0,0xE6,0x80,0x42,0xE8,0xFA,0xFE,0x83,0xC6,0x08,
+0xE2,0xE1,0x85,0xD2,0x74,0x03,0xE8,0x05,0x08,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,
+0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x06,0xE8,0x73,
+0x16,0xE8,0x12,0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,
+0x12,0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x16,
+0xE8,0x46,0x16,0xE8,0xD2,0xFE,0x73,0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1C,
+0x9C,0x0E,0xE8,0xE3,0x07,0x90,0x83,0xC6,0x08,0xE2,0xD9,0xC3,0x33,0xC9,0x8B,0xF1,
+0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x16,
+0xE8,0x21,0x16,0xE8,0x2A,0xFF,0x73,0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1C,
+0x9C,0x0E,0xE8,0xB3,0x07,0x90,0x46,0x46,0xE2,0xDA,0xC3,0x0C,0x00,0x00,0x10,0x00,
+0x13,0x12,0x00,0x00,0x14,0x00,0x28,0x3C,0x00,0x1B,0x3E,0x00,0x00,0x2A,0x00,0x00,
+0x2C,0x00,0x00,0x42,0x00,0x14,0xD8,0x00,0x00,0xDA,0x00,0x00,0x34,0x00,0x11,0x36,
+0x00,0x13,0x38,0x00,0x11,0x3A,0x00,0x13,0x00,0x00,0x56,0x50,0x52,0xBE,0x2B,0x0B,
+0x2E,0xAD,0x85,0xC0,0x74,0x06,0x92,0x2E,0xAC,0xEE,0xEB,0xF4,0x5A,0x58,0x5E,0xC3,
+0x53,0x2E,0xA1,0x5C,0x22,0xE6,0xE4,0xE6,0xF0,0x8A,0xC4,0xE6,0xEC,0xE6,0xF8,0xE8,
+0xD8,0xFF,0xB0,0x4B,0xE6,0x10,0xB0,0x50,0xE6,0x12,0xB0,0x38,0xE6,0x14,0xE8,0xAE,
+0x15,0xB0,0x46,0xE6,0x0A,0xE8,0xA7,0x15,0xB0,0x1A,0xE6,0x0A,0xE8,0xA0,0x15,0xB0,
+0x22,0xE6,0x0A,0xE8,0x99,0x15,0xE8,0xFD,0x06,0x8B,0xD8,0xE4,0x16,0xA8,0x04,0x75,
+0x18,0xE8,0xF2,0x06,0x2B,0xC3,0x3D,0x32,0x00,0x72,0xF0,0x6A,0x00,0x1F,0xC6,0x06,
+0x93,0x12,0x23,0x9C,0x0E,0xE8,0x10,0x07,0x90,0xE8,0xDA,0x06,0x2B,0xC3,0x3D,0x24,
+0x00,0x77,0x1B,0xB0,0x31,0xE6,0xFC,0x56,0x51,0x55,0xB9,0x10,0x00,0x2E,0x8B,0xAC,
+0x44,0x00,0x81,0x4E,0x38,0x80,0x00,0x46,0x46,0xE2,0xF2,0x5D,0x59,0x5E,0xE8,0x69,
+0xFF,0xE8,0x4B,0x15,0xB0,0x46,0xE6,0x0A,0xE8,0x44,0x15,0x5B,0xC3,0x33,0xF6,0x8B,
+0x0E,0x42,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x06,0xE8,
+0x17,0x15,0xE8,0x5B,0xFF,0x83,0xC6,0x20,0xE2,0xE9,0xC3,0x8B,0xC2,0x05,0x04,0x00,
+0x89,0x46,0x28,0x2E,0xA1,0x2E,0x2D,0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x89,
+0x86,0x92,0x00,0xC6,0x86,0xA3,0x00,0x0A,0xC6,0x86,0xC3,0x00,0x03,0x52,0x83,0xC2,
+0x04,0x8A,0x86,0xA6,0x00,0x0C,0x06,0xEE,0x5A,0x83,0xC2,0x02,0xB0,0x05,0xEE,0x88,
+0x86,0xA5,0x00,0xC3,0xE8,0x03,0xFF,0xE8,0xE5,0x14,0xB0,0x42,0xE6,0x0A,0xF7,0x46,
+0x38,0x80,0x00,0x74,0x06,0x2E,0xA1,0x98,0x22,0xEB,0x04,0x2E,0xA1,0x68,0x22,0xC7,
+0x46,0x1C,0x0C,0x00,0x89,0x86,0x94,0x00,0x89,0x86,0x96,0x00,0x89,0x86,0x8E,0x00,
+0x89,0x86,0x90,0x00,0x89,0x86,0x92,0x00,0xE6,0xF0,0xE6,0xE4,0x8A,0xC4,0xE6,0xF8,
+0xE6,0xEC,0xC6,0x86,0xC3,0x00,0x03,0xE8,0xA5,0x14,0xB0,0x1A,0xE6,0x0A,0xB0,0x10,
+0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,
+0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x06,0xE8,0x76,0x14,0xE8,0x5A,
+0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,0x8B,
+0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x06,0xE8,0x4C,0x14,0xE8,0x74,0xFF,
+0x46,0x46,0xE2,0xEA,0xC3,0x90,0x83,0x3E,0x44,0x12,0x00,0x75,0x14,0xB0,0x01,0xBA,
+0x06,0x01,0xEE,0x2A,0xC0,0xEE,0xB0,0x02,0xEE,0xB0,0x04,0xEE,0xB8,0x00,0x02,0xEB,
+0x0F,0xBA,0x06,0x01,0xB0,0x40,0xEE,0xB8,0x01,0x00,0x8A,0x0E,0x0E,0x01,0xD3,0xE0,
+0xA3,0x88,0x12,0xC3,0xA1,0x88,0x12,0xA3,0x84,0x12,0x2D,0x20,0x00,0xA3,0x8A,0x12,
+0x2D,0x20,0x00,0xA3,0x82,0x12,0xC7,0x06,0x86,0x12,0x20,0x00,0xC7,0x06,0x80,0x12,
+0x32,0x00,0xC3,0x83,0x3E,0x44,0x12,0x00,0x74,0x76,0x8B,0x0E,0x42,0x12,0x33,0xF6,
+0x8A,0xA4,0x54,0x12,0x84,0xE4,0x74,0x5F,0x8A,0x84,0x48,0x12,0x0C,0x04,0xE6,0xFE,
+0xF6,0xC4,0x04,0x74,0x25,0xB0,0x1B,0xBA,0x00,0x00,0xEE,0xEB,0x00,0x2A,0xC0,0xBA,
+0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,0xEE,0xEB,0x00,0x32,0xC0,0xBA,0x02,0x00,0xEE,
+0xEB,0x00,0xBA,0x00,0x00,0xB0,0x00,0xEE,0xEB,0x2D,0xB0,0x1F,0xBA,0x00,0x00,0xEE,
+0xEB,0x00,0x2A,0xC0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,0xEE,0xEB,0x00,0xD1,
+0xE6,0x8A,0x84,0x5D,0x12,0xD1,0xEE,0xF6,0xD0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xBA,
+0x00,0x00,0xB0,0x0A,0xEE,0xEB,0x00,0xE4,0x04,0xEB,0x00,0xE4,0x04,0x46,0xE2,0x90,
+0xC3,0x90,0xB8,0x14,0x00,0xBA,0x3E,0xFF,0xEF,0xB8,0x06,0x00,0xBA,0x32,0xFF,0xEF,
+0xB8,0x0F,0x00,0xBA,0x34,0xFF,0xEF,0xBA,0x36,0xFF,0xEF,0x83,0x3E,0x44,0x12,0x00,
+0x75,0x16,0xB8,0x11,0x00,0xBA,0x38,0xFF,0xEF,0xB8,0x12,0x00,0xBA,0x3A,0xFF,0xEF,
+0xB8,0x1B,0x00,0xBA,0x3C,0xFF,0xEF,0xC3,0xB8,0x11,0x00,0xBA,0x38,0xFF,0xEF,0xB8,
+0x12,0x00,0xBA,0x3A,0xFF,0xEF,0xB8,0x1B,0x00,0xBA,0x3C,0xFF,0xEF,0xC3,0xB8,0xFC,
+0x00,0xBA,0x28,0xFF,0xEF,0xFB,0x83,0x3E,0x44,0x12,0x00,0x74,0x07,0xB8,0xCC,0x00,
+0xBA,0x28,0xFF,0xEF,0xC3,0x00,0xFF,0xFF,0x20,0x24,0x28,0xFF,0x2C,0xFF,0xFF,0x30,
+0x34,0x38,0xFF,0xFF,0x3C,0x90,0x3C,0x0F,0x77,0x0E,0xBB,0x15,0x0E,0x2E,0xD7,0x3C,
+0xFF,0x74,0x05,0x8A,0xD8,0xF8,0xC3,0x90,0x2A,0xDB,0xF9,0xC3,0x83,0x3E,0x44,0x12,
+0x00,0x74,0x27,0xA0,0x06,0x01,0x80,0x26,0x06,0x01,0x30,0x80,0x3E,0x06,0x01,0x30,
+0x75,0x18,0xB9,0x02,0x00,0xBF,0xC4,0x13,0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xF8,
+0xBA,0x04,0x01,0xED,0xAB,0xE2,0xF1,0xEB,0x16,0x90,0xB9,0x04,0x00,0xBF,0xC4,0x13,
+0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xF8,0xBA,0x04,0x01,0xEC,0xAA,0xE2,0xF1,0xFA,
+0x90,0xBE,0xC4,0x13,0xAD,0x80,0xE4,0x3F,0x80,0xFC,0x02,0x74,0x0E,0x6A,0x00,0x1F,
+0xC6,0x06,0x93,0x12,0x0A,0x9C,0x0E,0xE8,0x3E,0x04,0x90,0xAD,0x3C,0x0F,0x75,0xED,
+0x8A,0xC4,0xE8,0x81,0xFF,0x72,0xE6,0x88,0x1E,0x1A,0x01,0xC6,0x06,0x8E,0x12,0x00,
+0xB0,0x00,0x0A,0x06,0x1A,0x01,0xBA,0x00,0x01,0xEE,0xC6,0x06,0x8F,0x12,0x40,0x83,
+0x3E,0x44,0x12,0x00,0x75,0x06,0xB8,0x0C,0x00,0xEB,0x04,0x90,0xB8,0x4C,0x00,0xBA,
+0x28,0xFF,0xEF,0xC3,0x83,0x3E,0x44,0x12,0x00,0x75,0x01,0xC3,0xA1,0x50,0x12,0x0B,
+0x06,0x52,0x12,0x0A,0xC4,0xA8,0x08,0x74,0xF2,0xA0,0x0F,0x01,0x2A,0xE4,0x50,0xFF,
+0x36,0xBA,0x13,0x1F,0xE8,0x36,0x56,0x83,0xC4,0x02,0x6A,0x00,0x1F,0x33,0xC0,0xA3,
+0xBC,0x13,0xA0,0x0F,0x01,0xA3,0xBE,0x13,0x8B,0x1E,0xBC,0x13,0x8A,0x87,0x50,0x12,
+0xF6,0x87,0x50,0x12,0x08,0x74,0x0D,0x24,0x07,0x8A,0xE0,0xBE,0xCC,0x00,0xA0,0xBC,
+0x13,0xE8,0x7A,0x3D,0xFF,0x06,0xBC,0x13,0xFF,0x0E,0xBE,0x13,0x75,0xDA,0xC3,0x90,
+0x1E,0x33,0xC0,0x8E,0xD8,0xB0,0x01,0xE8,0x3A,0x3D,0x1F,0xC3,0x33,0xC9,0x8B,0xF1,
+0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xC7,0x46,0x62,0x1A,0x44,0xC7,0x46,
+0x7C,0xDE,0x3B,0xC7,0x46,0x7E,0xC4,0x3B,0xC7,0x86,0x80,0x00,0xCE,0x3C,0xE8,0xAB,
+0x16,0xC6,0x86,0xC0,0x00,0x11,0x83,0x7E,0x08,0x00,0x74,0x07,0x51,0x56,0xE8,0x19,
+0x33,0x5E,0x59,0x46,0x46,0xE2,0xCD,0xC3,0x33,0xC9,0x8B,0xF1,0x8B,0xF9,0x8A,0x0E,
+0x94,0x12,0xC1,0xE9,0x02,0xE3,0x13,0x2E,0x8B,0xAC,0x44,0x00,0x8A,0x86,0x9E,0x00,
+0x88,0x85,0x6C,0x12,0x83,0xC6,0x08,0x47,0xE2,0xED,0xC3,0xFA,0xFC,0xB0,0xC0,0xBA,
+0x00,0x01,0xEE,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8E,0xD0,0xBF,0x16,0x01,0xB9,0xCC,
+0x77,0x2B,0xCF,0xD1,0xE9,0xF3,0xAB,0xBC,0x40,0x12,0xE8,0xD9,0x02,0xE8,0x56,0x3C,
+0xBE,0xC8,0x0F,0xE8,0xD8,0x3C,0xF4,0x90,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8E,0xD0,
+0xF6,0x06,0x0A,0x01,0x80,0x74,0x0B,0xBE,0x17,0x55,0xE8,0xC1,0x3C,0xB0,0x01,0xE8,
+0x92,0x3C,0xE8,0xB3,0x00,0xE8,0xFA,0xF5,0xE8,0x08,0xF8,0xE8,0x0F,0xF9,0xE8,0x85,
+0xFA,0xE8,0xB6,0xFA,0xE8,0xEF,0xFC,0xE8,0xC2,0x10,0xE8,0xE9,0x3B,0xE8,0xB2,0xFD,
+0xE8,0x30,0xFD,0xE8,0x54,0x02,0xC6,0x06,0x8F,0x12,0xC0,0xE8,0xBB,0xFA,0xE8,0xEB,
+0xFA,0xE8,0xE9,0xFB,0xE8,0xAF,0xFC,0xE8,0x8D,0xFC,0xE8,0x1F,0xFF,0xE8,0x58,0xFF,
+0xE8,0xDB,0xFD,0xE8,0x16,0xFE,0x33,0xC0,0xBE,0x5A,0x05,0xE8,0x70,0x3C,0xE8,0xA3,
+0xFE,0xE8,0xE0,0xFC,0xFB,0xBE,0x86,0x44,0xE8,0x63,0x3C,0xE9,0xB0,0x2D,0x56,0x98,
+0x8B,0xF0,0x8B,0x42,0x52,0x85,0xC0,0x75,0x27,0xC7,0x42,0x52,0x01,0x00,0x53,0x36,
+0x8B,0x9C,0x2C,0x01,0xF6,0xC3,0x01,0x75,0x0C,0x36,0x89,0x68,0x52,0x36,0x89,0xAC,
+0x2C,0x01,0x5B,0x5E,0xC3,0x36,0x89,0xAC,0x2C,0x01,0x36,0x89,0xAC,0x1C,0x01,0x5B,
+0x5E,0xC3,0x56,0x98,0x8B,0xF0,0x33,0xED,0x36,0x8B,0x84,0x1C,0x01,0xA8,0x01,0x75,
+0x15,0x8B,0xE8,0x33,0xC0,0x87,0x42,0x52,0x36,0x89,0x84,0x1C,0x01,0xA8,0x01,0x74,
+0x05,0x36,0x89,0x84,0x2C,0x01,0x5E,0xC3,0x56,0x51,0x33,0xF6,0xB8,0x01,0x00,0xB9,
+0x08,0x00,0x89,0x84,0x1C,0x01,0x89,0x84,0x2C,0x01,0x46,0x46,0xE2,0xF4,0x59,0x5E,
+0xC3,0x90,0xBB,0x01,0x00,0x8B,0xE8,0xFF,0x4E,0x6E,0x74,0x0A,0x8B,0xDD,0x8B,0x46,
+0x58,0xA8,0x01,0x74,0xF0,0xC3,0x8B,0x46,0x48,0xA9,0x08,0x00,0x74,0x45,0xF7,0x46,
+0x38,0x40,0x00,0x74,0x27,0xE8,0x5C,0x10,0x80,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x24,
+0xBF,0x88,0x86,0xA8,0x00,0xEE,0x60,0xB0,0xFE,0xE8,0x6C,0x32,0x61,0xB0,0x02,0xE8,
+0x4C,0xFF,0x8B,0x46,0x48,0x24,0xF7,0x89,0x46,0x48,0xEB,0x17,0xE8,0x2A,0x10,0x81,
+0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,
+0x8B,0x46,0x48,0xA9,0x04,0x00,0x74,0x14,0xB0,0x02,0xE8,0x21,0xFF,0x8B,0x46,0x48,
+0x24,0xFB,0x89,0x46,0x48,0x60,0xB0,0xDF,0xE8,0x2D,0x32,0x61,0x33,0xC0,0x87,0x46,
+0x58,0xF6,0xC3,0x01,0x75,0x0B,0x36,0x89,0x47,0x58,0xA8,0x01,0x75,0x0D,0xE9,0x74,
+0xFF,0xA3,0x22,0x01,0xA8,0x01,0x75,0x03,0xE9,0x6A,0xFF,0x89,0x1E,0x32,0x01,0xC3,
+0xBB,0x01,0x00,0x8B,0xE8,0xF7,0x46,0x38,0x40,0x00,0x74,0x15,0xE8,0xD5,0x0F,0x80,
+0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x0A,0x8B,0xDD,0x8B,0x46,0x56,0xA8,0x01,0x74,0xE3,
+0xC3,0x8B,0x46,0x26,0x80,0xE4,0xFE,0x80,0xCC,0x02,0x89,0x46,0x26,0xB0,0x02,0xE8,
+0xBC,0xFE,0x33,0xC0,0x87,0x46,0x56,0xF6,0xC3,0x01,0x75,0x0A,0x36,0x89,0x47,0x56,
+0xA8,0x01,0x75,0x0B,0xEB,0xBD,0xA3,0x20,0x01,0xA8,0x01,0x75,0x02,0xEB,0xB4,0x89,
+0x1E,0x30,0x01,0xC3,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA0,0x90,0x12,0x84,0xC0,
+0x75,0x49,0xA1,0x22,0x01,0xA8,0x01,0x75,0x03,0xE8,0xF6,0xFE,0xA1,0x20,0x01,0xA8,
+0x01,0x75,0x03,0xE8,0x8A,0xFF,0xA1,0xAC,0x13,0x48,0x78,0x05,0x74,0x45,0xA3,0xAC,
+0x13,0xA1,0xAE,0x13,0x48,0x78,0x05,0x74,0x51,0xA3,0xAE,0x13,0xA1,0xB0,0x13,0x48,
+0x78,0x05,0x74,0x63,0xA3,0xB0,0x13,0xA1,0x7E,0x12,0x40,0x78,0x03,0xA3,0x7E,0x12,
+0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0xA0,0x91,0x12,0x40,0x3C,
+0x02,0x72,0x0B,0x33,0xC0,0xA2,0x91,0x12,0xFF,0x16,0x7C,0x12,0xEB,0xA4,0xA2,0x91,
+0x12,0xEB,0x9F,0xA0,0x8E,0x12,0x32,0x06,0x8F,0x12,0xA2,0x8E,0x12,0x0A,0x06,0x1A,
+0x01,0xBA,0x00,0x01,0xEE,0xB8,0x2C,0x01,0xEB,0xA4,0x83,0x3E,0x84,0x12,0x10,0x72,
+0x11,0xBA,0x28,0xFF,0xED,0x0C,0x81,0xEF,0xE8,0x39,0x37,0xBA,0x28,0xFF,0xED,0x24,
+0x7E,0xEF,0xB8,0x04,0x00,0xEB,0x92,0xC6,0x06,0x8D,0x12,0x01,0xE8,0x25,0x37,0xC6,
+0x06,0x8D,0x12,0x00,0xA1,0xB2,0x13,0xEB,0x8B,0x90,0x8A,0x1E,0x0B,0x01,0x2A,0xFF,
+0x6B,0xC3,0x19,0xBA,0x62,0xFF,0xEF,0xB8,0x0A,0x00,0xBA,0x60,0xFF,0xEF,0xB8,0x01,
+0xE0,0xBA,0x66,0xFF,0xEF,0xB8,0xFF,0xFF,0xBA,0x52,0xFF,0xEF,0xB8,0x09,0xC0,0xBA,
+0x56,0xFF,0xEF,0xC7,0x06,0xAC,0x13,0x2C,0x01,0xC7,0x06,0xAE,0x13,0x04,0x00,0xC6,
+0x06,0x91,0x12,0x00,0xC3,0x90,0x8A,0x1E,0x0B,0x01,0x2A,0xFF,0x6B,0xC3,0x05,0xD1,
+0xE8,0xA3,0x18,0x01,0xC3,0x90,0x52,0xBA,0x50,0xFF,0xED,0x5A,0xC3,0x90,0x53,0x51,
+0x8B,0x1E,0x18,0x01,0xB9,0x32,0x05,0x90,0xE2,0xFE,0x4B,0x75,0xF7,0x59,0x5B,0xC3,
+0xB0,0x80,0xBA,0x00,0x01,0x0A,0x06,0x1A,0x01,0xEE,0xC3,0x90,0xB0,0x40,0xEB,0xF2,
+0xB0,0xC0,0xEB,0xEE,0xB0,0x00,0xEB,0xEA,0xFA,0x60,0x06,0x1E,0x16,0x2B,0xDB,0x8E,
+0xDB,0x2E,0xA1,0x9C,0x4C,0x2E,0xA3,0x74,0x4C,0xA0,0x93,0x12,0x98,0x8B,0xE8,0x89,
+0x26,0x2D,0x7A,0x80,0x3E,0xCA,0x13,0x00,0x74,0x03,0xE9,0x51,0x42,0xE8,0xC0,0xFF,
+0xE8,0xAB,0xFF,0xE8,0xA8,0xFF,0xB0,0x20,0xC6,0x06,0x90,0x12,0x00,0xFF,0x16,0x7C,
+0x12,0x8B,0xFD,0x83,0xFF,0x0A,0x72,0x11,0xE8,0xB9,0xFF,0xE8,0x90,0xFF,0xE8,0xAB,
+0xFF,0xE8,0x8A,0xFF,0x83,0xEF,0x0A,0xEB,0xEA,0x0B,0xFF,0x74,0x0F,0xE8,0xA4,0xFF,
+0xE8,0x7B,0xFF,0xE8,0x9A,0xFF,0xE8,0x75,0xFF,0x4F,0x75,0xF1,0xE8,0x95,0xFF,0xE8,
+0x6C,0xFF,0xEB,0xB9,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE,0x88,0x86,0xA5,0x00,0xC3,
+0x8A,0x86,0xA6,0x00,0x0C,0x02,0xEE,0xC3,0x8B,0x76,0x38,0xF7,0xC6,0x01,0x00,0x74,
+0xEF,0x8B,0x4E,0x36,0x8B,0x46,0x2E,0x3B,0xC1,0x73,0x02,0x8B,0xC8,0x2B,0xC1,0x89,
+0x46,0x2E,0x01,0x4E,0x34,0xC4,0x7E,0x04,0x26,0x01,0x0D,0x8B,0x7E,0x2C,0x83,0xEA,
+0x04,0xF3,0x6C,0x8E,0xC1,0x89,0x7E,0x2C,0x3B,0x46,0x3C,0x72,0x12,0xF7,0xC6,0x20,
+0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,0x38,0xB0,0x00,0xE8,0xA0,0xFC,0xC3,0xF7,
+0xC6,0x04,0x00,0x74,0x1B,0x8B,0xD8,0x83,0xCE,0x10,0x89,0x76,0x38,0x8A,0x86,0xA7,
+0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xC2,0x08,0xEE,0x83,0xEA,0x08,0x8B,0xC3,
+0x3D,0x40,0x00,0x72,0x01,0xC3,0x81,0x4E,0x38,0x00,0x04,0x83,0xC2,0x02,0x8A,0x86,
+0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0xC3,0x8A,0x86,0xA6,0x00,0x0C,0x02,
+0xEE,0xC3,0xF7,0x46,0x38,0x01,0x00,0x74,0xF1,0x8B,0x4E,0x2E,0x32,0xDB,0x8A,0xBE,
+0xA3,0x00,0x83,0xC2,0x06,0xC4,0x76,0x04,0x8B,0x7E,0x2C,0x83,0xF9,0x08,0x72,0x2C,
+0xEC,0xA8,0x01,0x74,0x16,0x8A,0xE0,0x83,0xEA,0x0A,0xEC,0x83,0xC2,0x0A,0x84,0xE7,
+0x75,0x51,0xAA,0xFE,0xC3,0x49,0x83,0xF9,0x08,0x73,0xE5,0x32,0xFF,0x26,0x01,0x1C,
+0x01,0x5E,0x34,0x89,0x76,0x04,0x89,0x4E,0x2E,0x89,0x7E,0x2C,0x3B,0x4E,0x3C,0x72,
+0x11,0xF6,0x46,0x38,0x20,0x74,0x01,0xC3,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xFD,
+0xFB,0xC3,0xF6,0x46,0x38,0x04,0x74,0x15,0x83,0x4E,0x38,0x10,0x8A,0x86,0xA7,0x00,
+0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xEA,0x02,0xEE,0x83,0xC2,0x02,0x3D,0x40,0x00,
+0x72,0x5D,0xC3,0x32,0xFF,0x26,0x03,0x1C,0x85,0xDB,0x74,0x09,0x26,0x89,0x1C,0x8B,
+0xF7,0x47,0x47,0x49,0x49,0x80,0xE4,0x1E,0x80,0xCC,0xC0,0x26,0x89,0x04,0xF6,0xC4,
+0x10,0x74,0x27,0x8B,0x76,0x38,0xF7,0xC6,0x00,0x10,0x74,0x0B,0x50,0xFE,0x86,0xB2,
+0x00,0xB0,0x0A,0xE8,0xA8,0xFB,0x58,0xF7,0xC6,0x00,0x01,0x74,0x0D,0xE8,0x68,0x26,
+0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,0x8B,0xF7,0x33,0xC0,0xAB,0x32,
+0xDB,0x8A,0xBE,0xA3,0x00,0x49,0x49,0x83,0xF9,0x08,0x72,0x17,0xE9,0x41,0xFF,0x81,
+0x4E,0x38,0x00,0x04,0x83,0xC2,0xF8,0x8A,0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,
+0x00,0xEE,0xC3,0xE9,0x45,0xFF,0x83,0xC2,0x08,0xEC,0x88,0x86,0xAA,0x00,0xC0,0xE8,
+0x04,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,0x32,0xE0,0x8B,0x5E,0x3E,0x84,0xE3,
+0x74,0x4F,0x8A,0xC1,0x8B,0x4E,0x26,0xF6,0xC5,0x04,0x74,0x0C,0xA8,0x08,0x74,0x05,
+0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,0x40,0xF6,0xC5,0x08,0x74,0x0C,0xA8,0x02,0x74,
+0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,0xC9,0x80,0x88,0x4E,0x26,0x8B,0xF0,0x8A,0x86,
+0xA5,0x00,0x84,0xC9,0x74,0x08,0xA8,0x02,0x74,0x15,0x24,0xFD,0xEB,0x06,0xA8,0x02,
+0x75,0x0D,0x0C,0x02,0x88,0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,0x83,0xC2,0x0A,0x8B,
+0xC6,0x84,0xE7,0x75,0x01,0xC3,0xC6,0x86,0xBA,0x00,0x01,0xB0,0x0E,0xE8,0xEE,0xFA,
+0xF7,0x46,0x38,0x00,0x02,0x74,0xEE,0x83,0x7E,0x2E,0x06,0x72,0xE8,0x8A,0xA6,0xAA,
+0x00,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0xB0,0xFF,0xAA,0xB0,0x02,0xAB,0x26,0x83,0x07,
+0x03,0x83,0x6E,0x2E,0x03,0x89,0x7E,0x2C,0xF6,0x46,0x38,0x20,0x74,0x01,0xC3,0x83,
+0x4E,0x38,0x20,0xB0,0x00,0xE8,0xB6,0xFA,0xC3,0x90,0x83,0xEA,0x08,0xE9,0xB4,0xFD,
+0x83,0xC2,0x06,0x8B,0x5E,0x26,0xF6,0xC3,0xC0,0x75,0xEF,0x8B,0x4E,0x1C,0xEC,0x88,
+0x86,0xA4,0x00,0x83,0xEA,0x0A,0xA8,0x20,0x75,0x02,0x8A,0xCD,0x32,0xED,0x8B,0x46,
+0x1A,0x3B,0xC8,0x73,0x18,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,0xC5,0x76,0x00,
+0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,0x00,0x72,0x30,0xC3,0x85,0xC0,0x74,
+0x31,0x8B,0xC8,0x01,0x46,0x2A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x80,0xCB,0x02,
+0x89,0x5E,0x26,0xE8,0x32,0xF1,0xF6,0xC7,0x01,0x75,0x16,0x83,0xC2,0x02,0xE8,0x53,
+0xFD,0xF6,0xC7,0x10,0x75,0x0B,0xB0,0x02,0xE8,0x43,0xFA,0xC3,0xF6,0xC7,0x01,0x74,
+0xF0,0xC3,0x80,0xCB,0x02,0x89,0x5E,0x26,0xF6,0xC7,0x01,0x74,0xDE,0x83,0xC2,0x02,
+0xE8,0x31,0xFD,0xF6,0x86,0xA4,0x00,0x40,0x74,0x0B,0x80,0xE7,0xFE,0x80,0xCF,0x02,
+0x89,0x5E,0x26,0xEB,0xCC,0xB0,0x04,0xE8,0x14,0xFA,0xC3,0xC0,0xC2,0xC8,0xCA,0xC4,
+0xC6,0xCC,0xCE,0xD0,0xD2,0xD8,0xDA,0xD4,0xD6,0xDC,0xDE,0x90,0xE9,0x0E,0x01,0xE4,
+0xC4,0x8A,0xE0,0xE4,0xC4,0x8B,0xD0,0x83,0xF9,0x08,0x72,0xF0,0x26,0x83,0x3F,0x00,
+0x74,0x04,0x8B,0xDF,0x49,0x49,0x8B,0xFB,0x8A,0xDE,0x83,0xE3,0x0F,0x2E,0x8A,0xA7,
+0x2B,0x16,0xAB,0xF6,0xC4,0x10,0x74,0x24,0xF7,0xC6,0x00,0x10,0x74,0x0B,0x50,0xFE,
+0x86,0xB2,0x00,0xB0,0x0A,0xE8,0xC6,0xF9,0x58,0xF7,0xC6,0x00,0x01,0x74,0x0D,0xE8,
+0x86,0x24,0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,0x89,0x7E,0x04,0x33,
+0xC0,0xAB,0x49,0x49,0x89,0x4E,0x2E,0x89,0x7E,0x2C,0x8B,0xC1,0xEB,0x4E,0x90,0xEB,
+0x9E,0x90,0xE4,0xD6,0x84,0xC0,0x79,0x63,0xE6,0xD0,0x8A,0xC8,0x25,0x03,0x00,0x03,
+0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,0x8B,0x4E,0x2E,0xC4,
+0x5E,0x04,0x8B,0x7E,0x2C,0x8B,0x76,0x38,0xE4,0x86,0x24,0x07,0x3C,0x03,0x75,0xCF,
+0xE4,0x1C,0x91,0x3B,0xC1,0x73,0x02,0x8B,0xC8,0x2B,0xC1,0x89,0x46,0x2E,0x01,0x4E,
+0x34,0x26,0x01,0x0F,0xBA,0xC4,0x00,0xF3,0x6C,0x89,0x7E,0x2C,0x3B,0x46,0x3C,0x72,
+0x1C,0xF7,0xC6,0x20,0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,0x38,0xB0,0x00,0xE8,
+0x3C,0xF9,0x8A,0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD6,0xC3,0xF9,0xC3,0xF7,0xC6,0x0A,
+0x00,0x74,0x35,0xF7,0xC6,0x10,0x00,0x75,0x2F,0x83,0xCE,0x10,0x89,0x76,0x38,0xF7,
+0xC6,0x02,0x00,0x74,0x0E,0x50,0xE4,0xD8,0x24,0xFE,0xE6,0xD8,0x58,0xF7,0xC6,0x08,
+0x00,0x74,0x15,0x50,0x51,0xB9,0xE8,0x03,0xE4,0x0A,0x84,0xC0,0xE0,0xFA,0x84,0xC0,
+0x75,0x04,0xB0,0x24,0xE6,0x0A,0x59,0x58,0x3D,0x40,0x00,0x73,0xB5,0x8A,0x86,0xA5,
+0x00,0x24,0xEF,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0xCE,0x10,0x04,0x89,0x76,0x38,
+0xEB,0xA0,0x00,0x08,0x04,0x0C,0x01,0x09,0x05,0x0D,0x02,0x0A,0x06,0x0E,0x03,0x0B,
+0x07,0x0F,0x00,0x40,0x80,0xC0,0x20,0x60,0xA0,0xE0,0x10,0x50,0x90,0xD0,0x30,0x70,
+0xB0,0xF0,0xE4,0xD2,0xE6,0xD0,0x8A,0xC8,0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E,
+0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,0xE4,0xD8,0xC0,0xE8,0x04,0x8B,0xD8,0x2E,
+0x8A,0x87,0x62,0x17,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,0x32,0xE0,0xE4,0x98,
+0x8B,0x5E,0x3E,0x84,0xE3,0x74,0x54,0x8A,0xC1,0x8B,0x4E,0x26,0xF6,0xC5,0x04,0x74,
+0x0C,0xA8,0x08,0x74,0x05,0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,0x40,0xF6,0xC5,0x08,
+0x74,0x0C,0xA8,0x02,0x74,0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,0xC9,0x80,0x88,0x4E,
+0x26,0x8B,0xF0,0x8A,0x86,0xA5,0x00,0xF6,0xC1,0xFD,0x74,0x08,0xA8,0x06,0x74,0x19,
+0x24,0xF9,0xEB,0x0F,0xA8,0x06,0x75,0x11,0xF6,0xC5,0x01,0x75,0x04,0x0C,0x04,0xEB,
+0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x8B,0xC6,0x84,0xE7,0x75,0x09,0x8A,
+0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD2,0xC3,0xC6,0x86,0xBA,0x00,0x01,0xB0,0x0E,0xE8,
+0x1C,0xF8,0xF7,0x46,0x38,0x00,0x02,0x74,0xE6,0x83,0x7E,0x2E,0x06,0x72,0xE0,0x8A,
+0x86,0xA9,0x00,0x8A,0xE0,0x86,0x86,0xAA,0x00,0x8A,0xC8,0x32,0xC4,0x80,0xC9,0x0B,
+0x22,0xC1,0xC0,0xE4,0x04,0x0A,0xE0,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0xB0,0xFF,0xAA,
+0xB0,0x02,0xAB,0x26,0x83,0x07,0x03,0x83,0x6E,0x2E,0x03,0x89,0x7E,0x2C,0xF6,0x46,
+0x38,0x20,0x75,0xAB,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xD1,0xF7,0xEB,0xA0,0x90,
+0xE4,0x12,0x24,0xDF,0xE6,0x12,0x81,0xE3,0xFE,0x9F,0x89,0x5E,0x26,0x83,0x66,0x48,
+0xF7,0xEB,0x73,0x90,0xF6,0xC7,0x20,0x75,0xE7,0xE4,0x12,0x0C,0x20,0xE6,0x12,0x32,
+0xC0,0xE6,0xC6,0xB0,0x83,0xE6,0xC6,0x80,0xCF,0x20,0x89,0x5E,0x26,0x8A,0x86,0xA5,
+0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xEB,0x74,0x90,0xF6,0xC7,0x40,0x75,
+0xD3,0xE4,0x12,0x0C,0x20,0xE6,0x12,0x32,0xC0,0xE6,0xC6,0xB0,0x81,0xE6,0xC6,0x80,
+0xE7,0xDF,0x80,0xCB,0x01,0x89,0x5E,0x26,0xB0,0x06,0xE8,0x71,0xF7,0x90,0x8A,0x86,
+0xA5,0x00,0x24,0xF9,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,0x43,0xE4,0xD4,0xE6,0xD0,
+0x8B,0xF8,0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x8B,0x5E,
+0x26,0xF6,0xC7,0x60,0x75,0xB6,0xF6,0xC3,0xC0,0x75,0xD3,0xBA,0xC6,0x00,0x8B,0x4E,
+0x1C,0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x1E,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,
+0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,0x00,0x72,0x3D,0x8B,
+0xC7,0x24,0x3F,0xE6,0xD4,0xC3,0x85,0xC0,0x74,0x39,0x8B,0xC8,0x01,0x46,0x2A,0xC5,
+0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x83,0xCB,0x02,0x89,0x5E,0x26,0xE8,0xD9,0xED,0xF6,
+0xC7,0x01,0x75,0x39,0x8A,0x86,0xA5,0x00,0x24,0xF9,0xE6,0x0C,0x88,0x86,0xA5,0x00,
+0xF6,0xC7,0x10,0x75,0xCA,0xB0,0x02,0xE8,0xE4,0xF6,0xEB,0xC3,0xF6,0xC7,0x01,0x74,
+0xEF,0xEB,0xBC,0xF6,0xC7,0x01,0x74,0xDC,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,0x11,
+0x81,0xE3,0xFF,0xFE,0x81,0xCB,0x00,0x02,0x89,0x5E,0x26,0xEB,0xC7,0x8A,0x86,0xA5,
+0x00,0x24,0xFB,0x0C,0x02,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,0x92,0x90,0xFD,0xF7,
+0xDF,0x7F,0xFE,0xFB,0xEF,0xBF,0x00,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04,
+0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
+0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04,
+0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
+0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04,
+0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
+0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04,
+0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
+0x06,0x04,0x05,0x04,0x05,0x04,0x03,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04,
+0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
+0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04,
+0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
+0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04,
+0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
+0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04,
+0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
+0x06,0x04,0x05,0x04,0x05,0x04,0x33,0xDB,0x8A,0xD8,0x8A,0x87,0x6C,0x12,0xE6,0xFE,
+0xC1,0xE3,0x02,0xE4,0xCE,0xA8,0x04,0x75,0x09,0xA8,0x02,0x74,0x03,0xE9,0x2C,0xFE,
+0xF9,0xC3,0x50,0x53,0xE8,0xCB,0xFC,0x5B,0x58,0xA8,0x02,0x74,0x03,0xE9,0x1C,0xFE,
+0xF8,0xC3,0x33,0xDB,0x8A,0xD8,0x8A,0x87,0x6C,0x12,0xE6,0xFE,0xC1,0xE3,0x02,0xE9,
+0xD0,0xFB,0x96,0x1A,0xC2,0x1A,0x00,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x0E,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
+0x02,0x00,0x04,0x00,0x02,0x00,0xC3,0x90,0xD6,0x14,0x90,0x15,0x58,0x13,0xE2,0x13,
+0xD6,0x1B,0xD6,0x1B,0xE2,0x13,0xD6,0x1B,0x8B,0x94,0x64,0x12,0xC1,0xE6,0x04,0xA8,
+0x01,0x74,0x35,0x50,0x33,0xC0,0x8A,0xC2,0xE6,0xFE,0xE4,0xA0,0x85,0xC0,0x74,0x27,
+0x8B,0xD8,0x2E,0x8A,0x9F,0xD6,0x1A,0x52,0x56,0x2E,0x8B,0xA8,0x44,0x00,0x8B,0x56,
+0x28,0xEC,0xA8,0x01,0x75,0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,0x8A,0xD8,0x2E,0xFF,
+0x97,0xD8,0x1B,0x5E,0x5A,0xEB,0xCD,0x58,0xA8,0x02,0x74,0x36,0x83,0xC6,0x10,0x33,
+0xC0,0x8A,0xC6,0xE6,0xFE,0xE4,0xA0,0x85,0xC0,0x74,0x27,0x8B,0xD8,0x2E,0x8A,0x9F,
+0xD6,0x1A,0x52,0x56,0x2E,0x8B,0xA8,0x44,0x00,0x8B,0x56,0x28,0xEC,0xA8,0x01,0x75,
+0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,0x8A,0xD8,0x2E,0xFF,0x97,0xD8,0x1B,0x5E,0x5A,
+0xEB,0xCD,0xC3,0x90,0x32,0xE4,0x8B,0xD8,0x8B,0xD0,0x2E,0x8A,0x9F,0x96,0x19,0x2E,
+0x22,0x97,0x8E,0x19,0x56,0x52,0x8A,0xC3,0x24,0x03,0x03,0xC6,0x80,0xE3,0x04,0xD0,
+0xEB,0x2E,0xFF,0x97,0xD2,0x1A,0x58,0x5E,0xA9,0x55,0x00,0x75,0xD9,0xC3,0x60,0x1E,
+0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x08,
+0x33,0xF6,0xE8,0xBF,0xFF,0xEB,0xEE,0x90,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,
+0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,
+0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x08,0xBE,0x04,0x00,0xE8,0x94,0xFF,
+0xEB,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,
+0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00,
+0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x6B,0xFF,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,
+0x22,0xC4,0x74,0xE5,0xBE,0x08,0x00,0xE8,0x5A,0xFF,0xEB,0xDD,0xA1,0x60,0x12,0xE6,
+0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0xA1,0x5C,0x12,0xE6,
+0xFE,0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,
+0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,
+0x74,0x19,0xBE,0x04,0x00,0xE8,0x1C,0xFF,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00,0x22,
+0xC4,0x74,0xE4,0xBE,0x0C,0x00,0xE8,0x0B,0xFF,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE,
+0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0xA1,0x5E,0x12,0xE6,0xFE,
+0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E,
+0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08,
+0x33,0xF6,0xE8,0x53,0xFE,0xEB,0xEE,0x90,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,
+0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,
+0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x02,0x00,0xE8,0x2C,0xFE,0xEB,0xED,0xB8,0x00,
+0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,
+0xD8,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x04,0x00,0xE8,
+0x06,0xFE,0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,
+0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,
+0x74,0x08,0xBE,0x06,0x00,0xE8,0xE0,0xFD,0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF,
+0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,
+0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x37,0xFE,0xA1,0x60,0x12,
+0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,0xAA,0xFD,0xEB,0xDD,
+0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,0x5C,0x12,0xE6,0xFE,
+0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,
+0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,
+0x74,0x19,0xBE,0x04,0x00,0xE8,0xEC,0xFD,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,
+0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x5F,0xFD,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE,
+0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x04,0x07,0xE4,0x04,
+0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,
+0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x27,
+0xFD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0xE5,0xBE,0x08,0x00,0xE8,
+0x92,0xFD,0xEB,0xDD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,
+0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E,
+0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x19,
+0xBE,0x02,0x00,0xE8,0xE2,0xFC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,
+0xE4,0xBE,0x0C,0x00,0xE8,0x4D,0xFD,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00,
+0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,
+0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,
+0xE4,0x80,0x84,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x9D,0xFC,0xA1,0x60,0x12,0xE6,0xFE,
+0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,0x8C,0xFC,0xEB,0xDD,0xA1,0x60,
+0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,0xB8,0x00,0x80,0xBA,0x22,
+0xFF,0xEF,0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,
+0xE4,0x80,0x84,0xC4,0x74,0x19,0xBE,0x02,0x00,0xE8,0x5C,0xFC,0xA1,0x62,0x12,0xE6,
+0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x4B,0xFC,0xEB,0xDC,0xA1,
+0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,0xB8,0x00,0x80,0xBA,
+0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0x90,0x2A,0xC0,
+0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,0x14,0x33,0xDB,0xE8,0xD5,0xF6,0xEB,0xEF,0x90,
+0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xF6,0x06,0x05,0x01,
+0x01,0x75,0xED,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,0xE3,0xBB,0x04,0x00,
+0xE8,0xAF,0xF6,0xEB,0xC9,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0x90,0xFB,0x90,
+0xFA,0x2A,0xC0,0xE6,0xFE,0xE4,0xCE,0xA8,0x02,0x74,0x13,0x33,0xDB,0xE8,0xCC,0xF8,
+0xEB,0xEC,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xA8,0x04,
+0x74,0xF0,0x33,0xDB,0xE8,0x5B,0xF7,0xEB,0xD5,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,
+0xD8,0x90,0xFB,0x90,0xFA,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,0x02,0x74,0x15,0xBB,
+0x04,0x00,0xE8,0x97,0xF8,0xEB,0xEB,0x90,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,
+0x1F,0x61,0xCF,0x90,0xA8,0x04,0x74,0xF0,0xBB,0x04,0x00,0xE8,0x24,0xF7,0xEB,0xD2,
+0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x09,0x9C,0x0E,0xE8,0x6B,0xF2,0x90,0x6A,0x00,
+0x1F,0xC6,0x06,0x93,0x12,0x29,0x9C,0x0E,0xE8,0x5D,0xF2,0x90,0x6E,0x20,0x6E,0x20,
+0x6E,0x20,0xCA,0x1D,0x8E,0x1C,0xE2,0x1C,0x16,0x1E,0x6E,0x20,0x7E,0x1D,0xAA,0x1E,
+0x34,0x1F,0x6E,0x20,0x7E,0x1D,0x6E,0x20,0x6E,0x20,0x34,0x1F,0x6E,0x20,0x6E,0x20,
+0x6E,0x20,0xF0,0x1D,0xB8,0x1C,0x30,0x1D,0x60,0x1E,0x6E,0x20,0xA4,0x1D,0xEE,0x1E,
+0x74,0x1F,0x6E,0x20,0xA4,0x1D,0x6E,0x20,0x6E,0x20,0x74,0x1F,0xFC,0xB9,0x40,0x00,
+0x8C,0xCB,0xB8,0x60,0x20,0x2B,0xFF,0xAB,0x93,0xAB,0x93,0xE2,0xFA,0xC7,0x06,0x4C,
+0x00,0xA4,0x11,0x83,0x3E,0x44,0x12,0x00,0x75,0x20,0xC7,0x06,0x3C,0x00,0xEA,0x4A,
+0xC7,0x06,0x30,0x00,0xB6,0x1F,0xC7,0x06,0x34,0x00,0xF6,0x1F,0xF6,0x06,0x05,0x01,
+0x01,0x75,0x06,0xC7,0x06,0x38,0x00,0x2A,0x20,0xC3,0xC7,0x06,0x3C,0x00,0x38,0x4B,
+0x33,0xDB,0x8A,0x1E,0x54,0x12,0xC1,0xE3,0x02,0x02,0x1E,0x56,0x12,0x2E,0x8B,0x87,
+0x7C,0x20,0xA3,0x30,0x00,0x8A,0x1E,0x55,0x12,0xC1,0xE3,0x02,0x02,0x1E,0x57,0x12,
+0x2E,0x8B,0x87,0x9C,0x20,0xA3,0x34,0x00,0xC3,0x8B,0x86,0x9E,0x00,0xE6,0xFE,0x86,
+0xC4,0xE6,0xD0,0xC3,0x8B,0x86,0x9E,0x00,0xE6,0xFE,0x33,0xD2,0x8A,0xD4,0xC3,0x51,
+0xB9,0x10,0x27,0xE4,0x0A,0x90,0x90,0x84,0xC0,0x74,0x05,0xE2,0xF6,0x59,0xF9,0xC3,
+0x59,0xF8,0xC3,0x84,0xC0,0x78,0x1E,0x51,0x8A,0xE8,0x8A,0xC8,0xB8,0x01,0x00,0xD3,
+0xE0,0x09,0x86,0x98,0x00,0x3A,0xAE,0xA0,0x00,0x59,0x75,0x10,0xE8,0xA9,0xE5,0x83,
+0x4E,0x26,0x02,0xF9,0xC3,0x98,0x89,0x86,0x98,0x00,0xEB,0xF0,0xF8,0xC3,0x84,0xC0,
+0x78,0x12,0x51,0x8A,0xE0,0x8A,0xC8,0xB8,0x01,0x00,0xD3,0xE0,0x59,0xF7,0xD0,0x21,
+0x86,0x98,0x00,0xC3,0xC7,0x86,0x98,0x00,0x00,0x00,0xC3,0x83,0xC2,0x04,0x8A,0x86,
+0xA6,0x00,0x0C,0x04,0xEE,0x83,0xEA,0x04,0xC3,0xE8,0x93,0xFF,0x72,0x04,0xB0,0x82,
+0xE6,0x0A,0xC3,0x8B,0x46,0x26,0xA8,0xFD,0x74,0x11,0x8A,0x86,0xA5,0x00,0xA8,0x06,
+0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xF6,0xC4,0x01,0x74,0x0A,
+0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0xEB,0x0C,0xA8,0x02,0x75,0x0F,0x8A,0x86,
+0xA5,0x00,0x24,0xFD,0x0C,0x04,0x3A,0x86,0xA5,0x00,0x75,0xD8,0xC3,0x8A,0x86,0xA5,
+0x00,0xEB,0xCF,0xE4,0xD8,0x33,0xDB,0x8A,0xD8,0xC0,0xEB,0x04,0x2E,0x8A,0x9F,0x62,
+0x17,0x88,0x9E,0xA9,0x00,0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,0xC7,0x04,0x74,0x07,
+0xA8,0x10,0x75,0x03,0x80,0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,0xA8,0x80,0x75,0x03,
+0x80,0xCB,0x40,0x88,0x5E,0x26,0x8A,0x86,0xA5,0x00,0xF6,0xC3,0xFD,0x74,0x0D,0xA8,
+0x06,0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xF6,0xC7,0x01,0x74,
+0x04,0x0C,0x02,0xEB,0xF0,0xF6,0xC3,0x02,0x75,0xE9,0x0C,0x04,0xEB,0xE7,0xC4,0x04,
+0xC4,0x04,0x85,0x04,0x59,0x04,0x48,0x04,0x41,0x04,0xC3,0x03,0x82,0x03,0x41,0x03,
+0x82,0x02,0x57,0x02,0x41,0x02,0x82,0x01,0x41,0x01,0x82,0x00,0x41,0x00,0x4E,0x02,
+0xAD,0x01,0x57,0x01,0x2D,0x00,0x2B,0x00,0x27,0x00,0x21,0x00,0x16,0x00,0xF4,0x04,
+0xF4,0x04,0xA3,0x04,0x6F,0x04,0x5B,0x04,0x51,0x04,0xF4,0x03,0xA3,0x03,0x51,0x03,
+0xA3,0x02,0x6D,0x02,0x51,0x02,0xA3,0x01,0x51,0x01,0xA3,0x00,0x51,0x00,0x62,0x02,
+0xD9,0x01,0x6D,0x01,0x38,0x00,0x36,0x00,0x31,0x00,0x29,0x00,0x1B,0x00,0x51,0x57,
+0xBF,0x02,0x00,0xEB,0x0F,0x90,0x51,0x56,0xBF,0x01,0x00,0xEB,0x07,0x90,0x51,0x56,
+0xBF,0x03,0x00,0x90,0x3C,0x19,0x76,0x02,0xB0,0x17,0x98,0x8B,0xF0,0x8A,0x82,0xC4,
+0x00,0x2A,0xE4,0x8B,0xF0,0x83,0xFE,0x18,0x73,0x46,0xD1,0xE6,0x2E,0x8B,0x8C,0x4E,
+0x22,0xF7,0x46,0x38,0x80,0x00,0x74,0x05,0x2E,0x8B,0x8C,0x7E,0x22,0xF7,0xC7,0x02,
+0x00,0x74,0x12,0x3B,0x8E,0x94,0x00,0x74,0x0C,0x89,0x8E,0x94,0x00,0x8A,0xC5,0xE6,
+0xEC,0x8A,0xC1,0xE6,0xE4,0xF7,0xC7,0x01,0x00,0x74,0x12,0x3B,0x8E,0x96,0x00,0x74,
+0x0C,0x89,0x8E,0x96,0x00,0x8A,0xC5,0xE6,0xF8,0x8A,0xC1,0xE6,0xF0,0x5E,0x59,0xC3,
+0x77,0x06,0x8B,0x8E,0x8E,0x00,0xEB,0xC5,0x8B,0x8E,0x90,0x00,0xEB,0xBF,0xD5,0x03,
+0xF6,0x00,0x3E,0x00,0x10,0x00,0x04,0x00,0xCA,0x04,0x33,0x01,0x4D,0x00,0x14,0x00,
+0x05,0x00,0x01,0x03,0x05,0x07,0x09,0x00,0x01,0x02,0x03,0x04,0x80,0x84,0x1E,0x00,
+0xA0,0x25,0x26,0x00,0x00,0x00,0x60,0x8B,0xF0,0x33,0xFF,0x2E,0xA1,0x4C,0x23,0x2E,
+0x8B,0x16,0x4E,0x23,0xBB,0x2E,0x23,0xF7,0x46,0x38,0x80,0x00,0x74,0x0C,0x2E,0xA1,
+0x50,0x23,0x2E,0x8B,0x16,0x52,0x23,0xBB,0x38,0x23,0xB9,0x05,0x00,0x2E,0x3B,0x31,
+0x73,0x0A,0x47,0x47,0xE2,0xF7,0xB8,0xFF,0xFF,0xEB,0x1D,0x90,0xD1,0xEF,0x2E,0x8A,
+0x8D,0x42,0x23,0x2A,0xED,0xD1,0xEA,0xD1,0xD8,0xE2,0xFA,0xF7,0xF6,0x05,0x02,0x00,
+0xC1,0xE8,0x02,0x2E,0x8A,0xA5,0x47,0x23,0x2E,0xA3,0x54,0x23,0x61,0x2E,0xA1,0x54,
+0x23,0xC3,0x08,0x00,0x20,0x00,0x80,0x00,0x00,0x02,0x60,0x09,0x08,0x00,0x20,0x00,
+0x80,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00,
+0x52,0x56,0x57,0x85,0xC0,0x74,0x05,0x3D,0x01,0x09,0x76,0x03,0xB8,0x01,0x09,0xBF,
+0x5B,0x01,0xF7,0x46,0x38,0x80,0x00,0x74,0x03,0xBF,0xB2,0x01,0x33,0xF6,0x2E,0x3B,
+0x84,0xB2,0x23,0x76,0x04,0x46,0x46,0xEB,0xF5,0xF7,0xE7,0x2E,0x8B,0xBC,0xBC,0x23,
+0x03,0xC7,0x83,0xD2,0x00,0xD1,0xE7,0xF7,0xF7,0x2E,0x8A,0xA4,0xC6,0x23,0x5F,0x5E,
+0x5A,0xC3,0xE4,0x3E,0x80,0xBE,0xC3,0x00,0x03,0x75,0x0C,0xF7,0x46,0x7A,0x20,0x00,
+0x74,0x05,0x0C,0x80,0xE6,0x3E,0xC3,0x24,0x7F,0xE6,0x3E,0xC3,0x24,0x03,0x88,0x86,
+0xC3,0x00,0x8A,0xE0,0xE4,0x10,0x24,0xFC,0x0A,0xC4,0xE6,0x10,0x80,0x8E,0xA1,0x00,
+0x42,0xE8,0xCE,0xFF,0xC3,0x90,0x56,0x8B,0xF0,0x83,0xE6,0x07,0xD1,0xE6,0x2E,0xFF,
+0xA4,0x54,0x24,0x90,0x64,0x24,0x68,0x24,0x6C,0x24,0x70,0x24,0x74,0x24,0x83,0x24,
+0x83,0x24,0x83,0x24,0xB4,0x00,0xEB,0x0E,0xB4,0xC0,0xEB,0x0A,0xB4,0x40,0xEB,0x06,
+0xB4,0x20,0xEB,0x02,0xB4,0xA0,0xE4,0x10,0x24,0x1F,0x0A,0xC4,0xE6,0x10,0x80,0x8E,
+0xA1,0x00,0x42,0x5E,0xC3,0x90,0x3C,0x02,0x77,0x12,0x8A,0xE0,0xE4,0x10,0x24,0xF3,
+0xC0,0xE4,0x02,0x0A,0xC4,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0xC3,0x90,0x8B,0x5E,
+0x38,0x84,0xC0,0x74,0x1F,0x3C,0x02,0x74,0x20,0x83,0xCB,0x08,0x8B,0x46,0x2E,0x3B,
+0x46,0x3C,0x77,0x0C,0xE8,0x88,0xFC,0x72,0x07,0xB0,0x24,0xE6,0x0A,0x83,0xCB,0x10,
+0x89,0x5E,0x38,0xC3,0x83,0xE3,0xF7,0xEB,0xF7,0xF7,0xC3,0x10,0x00,0x74,0xF5,0xE8,
+0x6D,0xFC,0x72,0xEC,0x8A,0x86,0xC0,0x00,0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xEB,0xE0,
+0x8B,0x5E,0x38,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0xE4,0xD8,0x77,0x0B,0x24,0xFE,0x80,
+0xCB,0x12,0xE6,0xD8,0x89,0x5E,0x38,0xC3,0x0C,0x01,0x80,0xCB,0x02,0xEB,0xF3,0x50,
+0x33,0xDB,0xC1,0xE8,0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,0x87,0x62,0x17,0x8A,
+0xDC,0x2E,0x8A,0xA7,0x62,0x17,0x09,0x46,0x3E,0x58,0xC3,0x50,0x33,0xDB,0xC1,0xE8,
+0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,0x87,0x62,0x17,0x8A,0xDC,0x2E,0x8A,0xA7,
+0x62,0x17,0xF7,0xD0,0x21,0x46,0x3E,0x58,0xC3,0x8B,0x46,0x3E,0x33,0xDB,0x8A,0xD8,
+0x0A,0xDC,0x2E,0x8A,0x87,0x72,0x17,0xE6,0x2C,0x8A,0xE0,0xE4,0x2A,0x24,0x0F,0x0A,
+0xC4,0xE6,0x2A,0x8A,0x86,0xA5,0x00,0x84,0xE4,0x75,0x0D,0xA8,0x80,0x74,0x11,0x24,
+0x7F,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x80,0x75,0x04,0x0C,0x80,0xEB,0xF1,
+0xC3,0x1E,0x60,0x33,0xC9,0x33,0xD2,0x33,0xF6,0x8E,0xD9,0x8D,0xBE,0xFD,0x00,0x57,
+0x8B,0x05,0x84,0xC0,0x74,0x16,0x8B,0xD1,0x42,0x8B,0xFE,0x4F,0x78,0x09,0x38,0xA3,
+0xE4,0x00,0x74,0x08,0x4F,0x79,0xF7,0x88,0xA2,0xE4,0x00,0x46,0x5F,0x83,0xC7,0x09,
+0x41,0x83,0xF9,0x10,0x72,0xD9,0x89,0xB6,0x86,0x00,0x89,0x96,0x84,0x00,0x61,0x1F,
+0xC3,0x53,0xC7,0x46,0x66,0x00,0x00,0x8B,0x46,0x64,0xA9,0x40,0x00,0x74,0x0D,0xB3,
+0x00,0xA9,0x80,0x00,0x74,0x02,0xB3,0x7F,0x88,0x9E,0xC1,0x00,0x32,0xDB,0xA9,0x02,
+0x00,0x74,0x03,0x80,0xCB,0x40,0xA9,0x00,0x40,0x74,0x03,0x80,0xCB,0x02,0xA9,0x00,
+0x80,0x74,0x03,0x80,0xCB,0x01,0xA9,0x30,0x1E,0x74,0x03,0x80,0xCB,0xBC,0xA9,0x00,
+0x20,0x74,0x03,0x80,0xCB,0x08,0xA9,0x04,0x01,0x74,0x03,0x80,0xCB,0x10,0xA9,0x08,
+0x00,0x74,0x03,0x80,0xCB,0x20,0x88,0x9E,0xC2,0x00,0x5B,0xC3,0x06,0x51,0x57,0x50,
+0x16,0x07,0x8D,0xBE,0xC4,0x00,0xB9,0x1F,0x00,0x33,0xC0,0xAA,0x40,0xE2,0xFC,0x8B,
+0x86,0x92,0x00,0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x58,0x5F,0x59,0x07,0xC3,
+0xE4,0xD8,0xC0,0xE8,0x04,0x53,0x25,0x0F,0x00,0x8B,0xD8,0x2E,0x8A,0x87,0x62,0x17,
+0x88,0x86,0xA9,0x00,0x5A,0xC3,0x08,0x86,0xAC,0x00,0xC6,0x86,0xBA,0x00,0x01,0xB0,
+0x0E,0xE8,0xEA,0xE9,0xC3,0xAD,0x36,0xA3,0xB4,0x13,0xAD,0x36,0xA3,0xB6,0x13,0xAD,
+0x36,0xA3,0xB8,0x13,0x83,0xE9,0x06,0x36,0xF7,0x06,0xB6,0x13,0x0F,0x00,0xC3,0x8A,
+0x46,0x26,0xF7,0x46,0x48,0x80,0x00,0x74,0x02,0x0C,0x10,0x88,0x86,0xBD,0x00,0x32,
+0xC0,0x83,0x7E,0x1A,0x00,0x75,0x0E,0x8B,0x5E,0x40,0x43,0x80,0xE3,0xFE,0x3B,0x5E,
+0x08,0x75,0x02,0x0C,0x01,0x83,0x7E,0x3A,0x00,0x75,0x0D,0x1E,0xC5,0x5E,0x14,0x8B,
+0x1F,0x1F,0x85,0xDB,0x75,0x02,0x0C,0x02,0xF7,0x46,0x38,0x10,0x00,0x74,0x02,0x0C,
+0x04,0xF7,0x46,0x7A,0x02,0x00,0x74,0x02,0x0C,0x08,0x88,0x86,0xBF,0x00,0xC3,0x90,
+0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x0D,0x9C,0x0E,0xE8,0x0B,0xEC,0x90,0xB0,0x02,
+0xE6,0xDA,0xF8,0xC3,0x33,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x01,0xE6,0xD8,0xF8,0xC3,
+0x33,0xC0,0xE6,0xD8,0xF8,0xC3,0xB0,0xFF,0xE8,0x68,0xFA,0xE8,0xBB,0xFA,0xF8,0xC3,
+0xAC,0x49,0xE8,0xC9,0xFB,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x2F,0xFD,0xF8,0xC3,0x90,
+0xAC,0x49,0xE8,0x81,0xFD,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x39,0xFD,0xF8,0xC3,0x90,
+0xAC,0x49,0xE6,0x34,0xF8,0xC3,0xAC,0x49,0xE6,0x36,0xF8,0xC3,0xAC,0x49,0x3C,0x02,
+0x77,0x1F,0x84,0xC0,0x75,0x1D,0xE4,0x14,0x24,0xEF,0xE6,0x14,0xE4,0x12,0x24,0x3F,
+0xE6,0x12,0xE4,0x16,0xA8,0x04,0x74,0x09,0xE8,0x04,0xFA,0x72,0x04,0xB0,0x18,0xE6,
+0x0A,0xF8,0xC3,0x8A,0xE0,0xE4,0x14,0x0C,0x10,0xE6,0x14,0xE4,0x12,0x0C,0xC0,0xF6,
+0xC4,0x01,0x74,0x02,0x24,0x7F,0xE6,0x12,0xF8,0xC3,0xAC,0x49,0xE8,0x3F,0xFD,0xF8,
+0xC3,0x90,0xB8,0x00,0x40,0xE8,0x97,0xFD,0xE8,0xCE,0xFD,0xE8,0xC2,0xFE,0xB0,0x01,
+0xE8,0xD3,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x9F,0xFD,0xE8,0xBA,0xFD,0xF8,
+0xC3,0x90,0xB8,0x00,0x10,0xE8,0x77,0xFD,0xE8,0xAE,0xFD,0xE8,0xA2,0xFE,0xB0,0x08,
+0xE8,0xB3,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x7F,0xFD,0xE8,0x9A,0xFD,0xF8,
+0xC3,0x90,0xB8,0x00,0x80,0xE8,0x57,0xFD,0xE8,0x8E,0xFD,0xE8,0x82,0xFE,0xB0,0x02,
+0xE8,0x93,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x5F,0xFD,0xE8,0x7A,0xFD,0xF8,
+0xC3,0x90,0xB8,0x00,0x20,0xE8,0x37,0xFD,0xE8,0x6E,0xFD,0xE8,0x62,0xFE,0xB0,0x04,
+0xE8,0x73,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x3F,0xFD,0xE8,0x5A,0xFD,0xF8,
+0xC3,0x90,0xAC,0x49,0xE8,0x48,0x14,0xE4,0x3C,0x24,0xE7,0x0A,0xC4,0xE6,0x3C,0xF8,
+0xC3,0x90,0xB8,0xDE,0x3B,0x89,0x46,0x7C,0xE4,0x3C,0x0C,0x18,0xE6,0x3C,0xF8,0xC3,
+0xE4,0x12,0x0C,0x02,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFD,0xEB,0xF6,0xE8,0xCF,
+0xFC,0xF8,0xC3,0x90,0x83,0x66,0x38,0xFD,0xF8,0xC3,0xAC,0x49,0xA8,0x01,0x74,0x06,
+0x83,0x4E,0x7A,0x20,0xEB,0x04,0x83,0x66,0x7A,0xDF,0xE8,0xE5,0xFB,0xF8,0xC3,0x90,
+0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0x4E,
+0x26,0x01,0x20,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x48,0x08,0x49,0x46,
+0xF9,0xC3,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,
+0x81,0x4E,0x26,0x01,0x20,0xAC,0xB4,0x0A,0xF6,0xE4,0xEB,0xD8,0xE8,0xFA,0x13,0xE4,
+0x3C,0x24,0xF8,0x0A,0xC4,0xE6,0x3C,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89,0x46,0x64,
+0xA9,0x01,0x00,0x74,0x1B,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x1A,0xA9,0x04,0x00,0x74,
+0x0F,0xE4,0x3E,0x0C,0x02,0xE6,0x3E,0xB8,0x1A,0x44,0x89,0x46,0x62,0xF8,0xC3,0x90,
+0xE4,0x3E,0x24,0xFC,0xEB,0xEF,0xE4,0x3E,0x24,0xFC,0xE6,0x3E,0xE8,0x02,0xFD,0xB8,
+0x8C,0x40,0xEB,0xE6,0xE8,0x88,0xF8,0x72,0x05,0xB0,0x18,0xE6,0x0A,0xF8,0xC3,0x90,
+0xAC,0x49,0xE8,0xE9,0xF9,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0xE9,0xF9,0xF8,0xC3,0x90,
+0xE8,0x82,0xFD,0x75,0x06,0x32,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x02,0xE6,0xDA,0x36,
+0xA0,0xB4,0x13,0x24,0x10,0x34,0x10,0xE8,0x16,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01,
+0x00,0x74,0x05,0xE8,0xFC,0xFE,0xEB,0x0E,0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB,
+0x02,0xB0,0x01,0xE8,0xDE,0xFE,0x36,0xA1,0xB4,0x13,0xE8,0xB5,0x13,0xE4,0x3C,0x24,
+0xF8,0x0A,0xC4,0xE6,0x3C,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01,0x00,0xE8,
+0xFA,0xFE,0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x73,0xFB,0x32,0xC0,0x36,0x8A,0x26,
+0xB5,0x13,0xF6,0xC4,0x04,0x74,0x09,0xFE,0xC0,0xF6,0xC4,0x08,0x74,0x02,0xFE,0xC0,
+0xE8,0xDB,0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x71,0xF9,0x36,0xA1,0xB6,
+0x13,0xC1,0xE8,0x04,0x25,0x03,0x00,0xE8,0xD2,0xFA,0x36,0xA1,0xB6,0x13,0xC1,0xE8,
+0x05,0x25,0x02,0x00,0xE8,0x1F,0xFB,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01,0x75,0x04,
+0x32,0xC0,0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8,0xC6,0xFA,
+0x36,0xF6,0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x83,0xFE,0xEB,0x03,0xE8,0x84,0xFE,
+0x36,0xF6,0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x65,0xFE,0xEB,0x03,0xE8,0x68,0xFE,
+0xF8,0xC3,0xE4,0x12,0x0C,0x01,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFE,0xEB,0xF6,
+0xE4,0x14,0x24,0xF0,0x0C,0x05,0xE6,0x14,0xE4,0x2A,0x24,0xF0,0x0C,0x06,0xE6,0x2A,
+0xF8,0xC3,0xE4,0x2A,0x24,0xF0,0xE6,0x2A,0xE4,0x14,0x24,0xF0,0x0C,0x07,0xE6,0x14,
+0xF8,0xC3,0xAD,0x49,0x49,0xE8,0x7E,0xF9,0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49,
+0x49,0xE8,0x72,0xF9,0x89,0x86,0x90,0x00,0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0xC2,
+0xF7,0xF8,0xC3,0x90,0x83,0x66,0x26,0xFB,0xE8,0xB8,0xF7,0xF8,0xC3,0x90,0xAC,0x49,
+0x84,0xC0,0x75,0x0D,0xE4,0x10,0x24,0xEF,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0xF8,
+0xC3,0xE4,0x10,0x0C,0x10,0xEB,0xF1,0x90,0xAC,0x49,0x3C,0x02,0x76,0x02,0x32,0xC0,
+0xC0,0xE0,0x04,0xA8,0x20,0x74,0x02,0x0C,0x08,0x24,0x18,0x8A,0xE0,0xE4,0x12,0x24,
+0xE7,0x0A,0xC4,0xE6,0x12,0x80,0x8E,0xA1,0x00,0x44,0xF8,0xC3,0xAC,0x49,0x88,0x86,
+0xC0,0x00,0xF8,0xC3,0xAC,0x49,0xE6,0x3A,0xF8,0xC3,0xAC,0x49,0x84,0xC0,0x74,0x08,
+0xE4,0x12,0x0C,0x04,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFB,0xEB,0xF6,0xAC,0x49,
+0xE8,0xF0,0xF6,0x73,0x03,0xE8,0x41,0xF7,0xF8,0xC3,0xE4,0x12,0xA8,0x02,0x74,0x04,
+0x24,0xFD,0xE6,0x12,0xB8,0xF0,0x00,0xE8,0xA1,0xFA,0x81,0x66,0x26,0xFF,0xF3,0xE8,
+0x71,0xF7,0xE8,0xB4,0xFA,0xF8,0xC3,0x90,0xB8,0x80,0x00,0xE8,0x71,0xFA,0x80,0x4E,
+0x27,0x08,0xE8,0x5E,0xF7,0xE8,0xA1,0xFA,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x7B,0xFA,
+0x81,0x66,0x26,0xFF,0xF7,0xE8,0x4B,0xF7,0xE8,0x8E,0xFA,0xF8,0xC3,0x90,0xB8,0x10,
+0x00,0xE8,0x4B,0xFA,0x80,0x4E,0x27,0x04,0xE8,0x38,0xF7,0xE8,0x7B,0xFA,0xF8,0xC3,
+0xB8,0x10,0x00,0xE8,0x55,0xFA,0x81,0x66,0x26,0xFF,0xFB,0xE8,0x25,0xF7,0xE8,0x68,
+0xFA,0xF8,0xC3,0x90,0x33,0xC0,0xAC,0x49,0x3C,0x01,0x73,0x04,0xB0,0x01,0xEB,0x06,
+0x3C,0x0C,0x76,0x02,0xB0,0x0C,0x89,0x46,0x1C,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00,
+0x20,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x83,
+0x4E,0x26,0x01,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C,
+0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xF8,0xC3,0x90,0xAC,0x49,0x50,0xE8,0x1F,0xF6,
+0x58,0x72,0x08,0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xF8,0xC3,0xF9,0xC3,0x90,0xAC,0x50,
+0xAD,0xE8,0x9C,0xF8,0x5A,0xF6,0xC2,0x01,0x74,0x12,0x39,0x86,0x96,0x00,0x74,0x0C,
+0x89,0x86,0x96,0x00,0xE6,0xF0,0x86,0xE0,0xE6,0xF8,0x86,0xE0,0xF6,0xC2,0x02,0x74,
+0x10,0x39,0x86,0x94,0x00,0x74,0x0A,0x89,0x86,0x94,0x00,0xE6,0xE4,0x86,0xE0,0xE6,
+0xEC,0x83,0xE9,0x03,0xC3,0x90,0xE4,0x16,0x88,0x86,0xBC,0x00,0xE8,0x00,0xFB,0x33,
+0xDB,0xE4,0x0C,0xA8,0x06,0x74,0x03,0x80,0xCB,0x01,0xA8,0x10,0x74,0x03,0x80,0xCB,
+0x02,0xA8,0x80,0x74,0x03,0x80,0xCB,0x04,0xE4,0x12,0x8A,0xE0,0x24,0x18,0x0A,0xD8,
+0xE4,0xDA,0xF6,0xC4,0x02,0x74,0x07,0xA8,0x40,0x75,0x03,0x80,0xCB,0x20,0xA8,0x02,
+0x75,0x09,0xE4,0x2A,0xA8,0x0F,0x74,0x03,0x80,0xCB,0x40,0xF7,0x46,0x38,0x02,0x00,
+0x74,0x09,0xE4,0xD8,0xA8,0x01,0x75,0x03,0x80,0xCB,0x80,0x88,0x9E,0xBE,0x00,0xFE,
+0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x76,0xE4,0xF8,0xC3,0xAC,0x49,0x3C,0x02,0x74,0x41,
+0x77,0x1F,0x50,0xE8,0x69,0xF5,0x58,0x72,0x0C,0x84,0xC0,0x74,0x0A,0xB0,0x12,0xE6,
+0x0A,0x80,0x4E,0x38,0x01,0xF8,0xC3,0xB0,0x11,0xE6,0x0A,0x80,0x66,0x38,0xFE,0xF8,
+0xC3,0x8B,0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9,0x00,0x04,0x75,0xE6,0x8A,
+0x86,0xA5,0x00,0xA8,0x10,0x75,0xDE,0x0C,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xF8,
+0xC3,0x81,0x4E,0x38,0x00,0x08,0x8A,0x86,0xA5,0x00,0xA8,0x10,0x74,0xC7,0x24,0xEF,
+0xEB,0xE7,0xAD,0x49,0x49,0x3C,0x01,0x72,0x11,0x3C,0x0C,0x77,0x0D,0x50,0x8A,0xE0,
+0xE4,0x14,0x25,0xF0,0x0F,0x0A,0xC4,0xE6,0x14,0x58,0x8A,0xC4,0x84,0xC0,0x74,0x02,
+0xE6,0x42,0xF8,0xC3,0xE8,0xE9,0xF9,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0xEE,0xE3,
+0xF8,0xC3,0x3A,0x86,0xAF,0x00,0x74,0x1F,0x88,0x86,0xAF,0x00,0x8A,0xE0,0x80,0xC2,
+0x06,0xB0,0xBF,0xEE,0x80,0xEA,0x02,0x8A,0xC4,0xEE,0x8A,0x86,0xA8,0x00,0x80,0xC2,
+0x02,0xEE,0x80,0xEA,0x06,0x8A,0xC4,0xC3,0x8B,0x46,0x3E,0x85,0xC0,0x8A,0x86,0xA5,
+0x00,0x74,0x12,0xA8,0x08,0x75,0x0D,0x0C,0x08,0x88,0x86,0xA5,0x00,0x80,0xC2,0x02,
+0xEE,0x80,0xEA,0x02,0xC3,0xA8,0x08,0x74,0xFB,0x24,0xF7,0xEB,0xEC,0x8B,0x46,0x26,
+0x84,0xC0,0x74,0x16,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,0x0D,0x24,0xFD,0x88,0x86,
+0xA5,0x00,0x83,0xC2,0x02,0xEE,0x83,0xEA,0x02,0xC3,0x8A,0x86,0xA5,0x00,0xA8,0x02,
+0x75,0xF7,0x0C,0x02,0xEB,0xE8,0x52,0x83,0xC2,0x0C,0xEC,0xC0,0xE8,0x04,0x88,0x86,
+0xA9,0x00,0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,0xC7,0x04,0x74,0x07,0xA8,0x08,0x75,
+0x03,0x80,0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,0xA8,0x02,0x75,0x03,0x80,0xCB,0x80,
+0x88,0x5E,0x26,0x8A,0x86,0xA5,0x00,0x84,0xDB,0x74,0x10,0xA8,0x02,0x74,0x0A,0x24,
+0xFD,0x88,0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,0x5A,0xC3,0xA8,0x02,0x75,0xFA,0x0C,
+0x02,0xEB,0xEE,0x90,0xFF,0xFF,0x00,0x48,0x00,0x30,0xBA,0x20,0xC4,0x1A,0x00,0x18,
+0x00,0x12,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x02,0x80,0x01,0xC0,0x00,0x60,0x00,
+0x30,0x00,0x18,0x00,0xCD,0x01,0x00,0x01,0x80,0x00,0x10,0x00,0x10,0x00,0x0E,0x00,
+0x0C,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x04,0x00,0x03,0x00,0x02,0x00,
+0x01,0x00,0x52,0x51,0x56,0x3C,0x1E,0x77,0x47,0x98,0x8B,0xF0,0x8A,0x82,0xC4,0x00,
+0x32,0xE4,0x83,0xFE,0x18,0x74,0x3D,0x83,0xFE,0x19,0x74,0x3E,0x83,0xFE,0x1E,0x77,
+0x2F,0xD1,0xE6,0x2E,0x8B,0x8C,0x14,0x2D,0x3B,0x8E,0x94,0x00,0x74,0x22,0x89,0x8E,
+0x94,0x00,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA,
+0x06,0x8A,0xC1,0xEE,0x83,0xC2,0x02,0x8A,0xC5,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE,
+0x5E,0x59,0x5A,0xC3,0x8B,0x8E,0x8E,0x00,0xEB,0xCE,0x8B,0x8E,0x90,0x00,0xEB,0xC8,
+0x52,0x51,0x3D,0x05,0x00,0x77,0x03,0xB8,0x05,0x00,0x8B,0xC8,0xBA,0x02,0x00,0xB8,
+0x00,0xD0,0xF7,0xF1,0x05,0x01,0x00,0xD1,0xE8,0x59,0x5A,0xC3,0x8B,0x46,0x7A,0xA8,
+0x20,0x74,0x0B,0x80,0xBE,0xC3,0x00,0x03,0x75,0x04,0x0C,0x01,0xEB,0x02,0x24,0xFE,
+0x89,0x46,0x7A,0xC3,0x24,0x03,0x88,0x86,0xC3,0x00,0x8A,0xA6,0xA8,0x00,0x8A,0xDC,
+0x80,0xE4,0xFC,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,0x06,
+0xEE,0x83,0xEA,0x06,0xE8,0xC5,0xFF,0xC3,0x00,0x08,0x18,0x38,0x28,0x90,0x3C,0x04,
+0x77,0x23,0x32,0xE4,0x8B,0xD8,0x2E,0x8A,0x87,0x08,0x2E,0x8A,0xA6,0xA8,0x00,0x8A,
+0xDC,0x80,0xE4,0xC7,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,
+0x06,0xEE,0x83,0xEA,0x06,0xC3,0x84,0xC0,0x74,0x02,0xB0,0x04,0x8A,0xA6,0xA8,0x00,
+0x8A,0xDC,0x80,0xE4,0xFB,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,
+0xC2,0x06,0xEE,0x83,0xEA,0x06,0xC3,0x90,0x8B,0x5E,0x38,0x84,0xC0,0x74,0x34,0x3C,
+0x02,0x74,0x3B,0x8A,0x86,0xAF,0x00,0x0C,0x04,0xE8,0xE6,0xFD,0x8B,0x46,0x2E,0x3B,
+0x46,0x3C,0x77,0x1B,0xF7,0xC3,0x00,0x04,0x75,0x15,0x81,0xCB,0x00,0x04,0x83,0xC2,
+0x02,0x8A,0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0x89,
+0x5E,0x38,0xC3,0x8A,0x86,0xAF,0x00,0x24,0xFB,0xE8,0xB6,0xFD,0xEB,0xF1,0xF7,0xC3,
+0x10,0x00,0x74,0xEF,0xEB,0xED,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8,0x04,
+0x88,0x86,0xA9,0x00,0xC3,0x90,0x8A,0x86,0xA7,0x00,0x0C,0x01,0x88,0x86,0xA7,0x00,
+0x8B,0xDA,0x80,0xC2,0x08,0xEE,0x8B,0xD3,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x24,0xFE,
+0xEB,0xEA,0x8A,0x86,0xA7,0x00,0x0C,0x02,0xEB,0xE2,0x8A,0x86,0xA7,0x00,0x24,0xFD,
+0xEB,0xDA,0xB0,0xFF,0xE8,0x6C,0xF2,0xE8,0xB1,0xF2,0xF8,0xC3,0xAC,0x49,0xE8,0x61,
+0xFE,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0xEB,0xFE,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x35,
+0xFF,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x05,0xFF,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06,
+0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x02,0xAC,0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE,
+0x5A,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x06,0xEB,
+0xE6,0x90,0xAC,0x49,0x3C,0x02,0x77,0x0D,0x84,0xC0,0x75,0x0B,0x8A,0x86,0xAF,0x00,
+0x24,0xFD,0xE8,0x0D,0xFD,0xF8,0xC3,0x50,0x8A,0x86,0xAF,0x00,0x0C,0x02,0xE8,0x01,
+0xFD,0x5B,0x83,0xC2,0x08,0x8A,0x86,0xA7,0x00,0xF6,0xC3,0x01,0x74,0x0C,0x24,0xDF,
+0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x0C,0x20,0xEB,0xF2,0xAC,0x49,
+0xE8,0xE5,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x83,0xF5,0xE8,0xF9,0xFC,0xE8,
+0x24,0xFF,0xB0,0x01,0xE8,0xBF,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x8B,0xF5,
+0xE8,0xE5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x63,0xF5,0xE8,0xD9,0xFC,0xE8,
+0x04,0xFF,0xB0,0x08,0xE8,0x9F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x6B,0xF5,
+0xE8,0xC5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x43,0xF5,0xE8,0xB9,0xFC,0xE8,
+0xE4,0xFE,0xB0,0x02,0xE8,0x7F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x4B,0xF5,
+0xE8,0xA5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x23,0xF5,0xE8,0x99,0xFC,0xE8,
+0xC4,0xFE,0xB0,0x04,0xE8,0x5F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x2B,0xF5,
+0xE8,0x85,0xFC,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x34,0x0C,0xF8,0xC3,0x90,0xB8,0xDE,
+0x3B,0x89,0x46,0x7C,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0x0C,0x80,0xE8,0x43,0xFC,0xF8,
+0xC3,0x90,0x8A,0x86,0xAF,0x00,0x24,0x7F,0xEB,0xF2,0x8A,0x86,0xAF,0x00,0x0C,0x40,
+0xE8,0x2F,0xFC,0xF8,0xC3,0x90,0x8A,0x86,0xAF,0x00,0x24,0xBF,0xEB,0xF2,0xAC,0x49,
+0xA8,0x01,0x74,0x07,0x83,0x4E,0x7A,0x20,0xEB,0x05,0x90,0x83,0x66,0x7A,0xDF,0xE8,
+0x8A,0xFD,0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,
+0x00,0xEE,0x83,0xEA,0x06,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x26,0x01,
+0x83,0x4E,0x48,0x08,0xB0,0x06,0xE8,0xD5,0xDF,0x49,0x46,0xF9,0xC3,0x90,0x83,0xC2,
+0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x06,0xAC,
+0xB4,0x0A,0xF6,0xE4,0xEB,0xD0,0xE8,0xE0,0x0B,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89,
+0x46,0x64,0xA9,0x01,0x00,0x74,0x19,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x0A,0xA9,0x04,
+0x00,0x74,0x0D,0xB8,0xC4,0x3F,0xEB,0x0B,0xE8,0x06,0xF5,0xB8,0x8C,0x40,0xEB,0x03,
+0xB8,0x1A,0x44,0x89,0x46,0x62,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0xA8,0x02,0x74,0x0A,
+0x24,0xFD,0xE8,0x8D,0xFB,0x0C,0x02,0xE8,0x88,0xFB,0xF8,0xC3,0xAC,0x49,0xE8,0x81,
+0xFC,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x79,0xFC,0xF8,0xC3,0x90,0xE8,0x76,0xF5,0x75,
+0x05,0xE8,0xE6,0xFD,0xF8,0xC3,0xE8,0xCD,0xFD,0x36,0xA0,0xB4,0x13,0x24,0x10,0x34,
+0x10,0xE8,0x26,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01,0x00,0x74,0x05,0xE8,0xFE,0xFE,
+0xEB,0x0E,0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB,0x02,0xB0,0x01,0xE8,0xE8,0xFE,
+0x36,0xA1,0xB4,0x13,0xE8,0xAB,0x0B,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01,
+0x00,0xE8,0x0C,0xFF,0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x2B,0xFD,0x32,0xC0,0x36,
+0x8A,0x26,0xB5,0x13,0xF6,0xC4,0x04,0x74,0x09,0xFE,0xC0,0xF6,0xC4,0x08,0x74,0x02,
+0xFE,0xC0,0xE8,0xEF,0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x03,0xFC,0x36,
+0xA1,0xB6,0x13,0xC1,0xE8,0x04,0x25,0x03,0x00,0xE8,0x88,0xFC,0x36,0xA1,0xB6,0x13,
+0xC1,0xE8,0x05,0x25,0x02,0x00,0xE8,0xCD,0xFC,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01,
+0x75,0x04,0x32,0xC0,0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8,
+0x8C,0xFC,0x36,0xF6,0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x8D,0xFE,0xEB,0x03,0xE8,
+0x94,0xFE,0x36,0xF6,0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x69,0xFE,0xEB,0x03,0xE8,
+0x70,0xFE,0xF8,0xC3,0xF8,0xC3,0x8B,0x46,0x38,0xA9,0x04,0x00,0x75,0x23,0x0D,0x04,
+0x00,0x89,0x46,0x38,0x83,0xC2,0x08,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0x73,0x14,0x83,
+0x4E,0x38,0x10,0x8A,0x86,0xA7,0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,
+0x08,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEB,0xEE,0x90,0x8B,0x46,0x38,0xA9,
+0x04,0x00,0x74,0x06,0x25,0xFB,0xFF,0x89,0x46,0x38,0xF8,0xC3,0xAD,0x49,0x49,0xE8,
+0xBE,0xFB,0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49,0x49,0xE8,0xB2,0xFB,0x89,0x86,
+0x90,0x00,0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0x92,0xFA,0xF8,0xC3,0x90,0x83,0x66,
+0x26,0xFB,0xE8,0x88,0xFA,0xF8,0xC3,0x90,0xAC,0x49,0x84,0xC0,0x75,0x07,0x80,0x8E,
+0xA3,0x00,0x04,0xF8,0xC3,0x80,0xA6,0xA3,0x00,0xFB,0xF8,0xC3,0xAC,0x49,0x83,0xC2,
+0x08,0x3C,0x02,0x76,0x02,0x32,0xC0,0x3C,0x01,0x74,0x12,0x77,0x0B,0x8A,0x86,0xA7,
+0x00,0x24,0xEF,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x8A,0x86,0xA7,
+0x00,0x0C,0x10,0xEB,0xEE,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,
+0x04,0xAC,0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE,0x5A,0xF8,0xC3,0x90,0x52,0x83,
+0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x08,0xEB,0xE6,0x90,0xAC,0x49,0xF8,0xC3,
+0xAC,0x49,0xE8,0xCE,0xEE,0x73,0x03,0xE8,0x11,0xEF,0xF8,0xC3,0x8A,0x86,0xAF,0x00,
+0x24,0x7F,0xE8,0xBD,0xF9,0xB8,0xF0,0x00,0xE8,0x80,0xF2,0x81,0x66,0x26,0xFF,0xF3,
+0xE8,0x23,0xFA,0xE8,0xD2,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x51,0xF2,0x80,0x4E,
+0x27,0x08,0xE8,0x11,0xFA,0xE8,0xC0,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x5B,0xF2,
+0x81,0x66,0x26,0xFF,0xF7,0xE8,0xFE,0xF9,0xE8,0xAD,0xF9,0xF8,0xC3,0x90,0xB8,0x10,
+0x00,0xE8,0x2B,0xF2,0x80,0x4E,0x27,0x04,0xE8,0xEB,0xF9,0xE8,0x9A,0xF9,0xF8,0xC3,
+0xB8,0x10,0x00,0xE8,0x19,0xF2,0x81,0x66,0x26,0xFF,0xFB,0xE8,0xD8,0xF9,0xF8,0xC3,
+0xAC,0x49,0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,
+0x00,0xEE,0x83,0xEA,0x06,0xF8,0xC3,0x90,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x24,
+0xBF,0xEB,0xEA,0x90,0xAC,0x49,0x8A,0xE0,0x80,0xC2,0x0A,0xEC,0x80,0xEA,0x0A,0xA8,
+0x20,0x74,0x05,0x8A,0xC4,0xEE,0xF8,0xC3,0x06,0x51,0x57,0x8B,0x4E,0x24,0xE3,0x34,
+0x49,0x89,0x4E,0x24,0xFF,0x46,0x1A,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x8A,0xC4,0xAA,
+0x89,0x7E,0x22,0x8B,0x46,0x26,0x24,0xFD,0x89,0x46,0x26,0x75,0x29,0x8A,0x86,0xA5,
+0x00,0xA8,0x02,0x75,0x21,0x80,0xC2,0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x80,
+0xEA,0x02,0xEB,0x12,0xC4,0x7E,0x00,0x3B,0x7E,0x1E,0x76,0x0A,0x4F,0x26,0x88,0x25,
+0x89,0x7E,0x00,0xFF,0x46,0x1A,0x5F,0x59,0x07,0xF8,0xC3,0x90,0xAC,0xAD,0x83,0xE9,
+0x03,0x85,0xC0,0x74,0x05,0x3D,0x00,0x20,0x72,0x05,0xB8,0xFF,0xFF,0xEB,0x03,0xC1,
+0xE0,0x03,0x3B,0x86,0x94,0x00,0x74,0x26,0x89,0x86,0x94,0x00,0x8B,0xD8,0x52,0x83,
+0xC2,0x06,0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA,0x06,0x8A,0xC3,
+0xEE,0x83,0xC2,0x02,0x8A,0xC7,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE,0x5A,0xF8,0xC3,
+0xB0,0x88,0x88,0x86,0xBC,0x00,0xE8,0xA6,0xF2,0x33,0xDB,0x8A,0x86,0xA5,0x00,0xA8,
+0x02,0x74,0x03,0x80,0xCB,0x01,0xA8,0x05,0x74,0x03,0x80,0xCB,0x02,0xA8,0x08,0x74,
+0x03,0x80,0xCB,0x04,0xF6,0x86,0xA7,0x00,0x10,0x74,0x03,0x80,0xCB,0x10,0x8A,0x86,
+0xA9,0x00,0xF6,0xC3,0x04,0x75,0x0A,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8,
+0x04,0x8A,0xE0,0x8A,0x86,0xAF,0x00,0xA8,0x80,0x74,0x08,0xF6,0xC4,0x01,0x75,0x03,
+0x80,0xCB,0x20,0xF6,0x86,0xA7,0x00,0x02,0x75,0x0A,0xF7,0x46,0x38,0x04,0x00,0x74,
+0x03,0x80,0xCB,0x40,0x88,0x9E,0xBE,0x00,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x0D,
+0xDC,0xF8,0xC3,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x02,0xDC,0xF8,0xC3,0xAC,0x49,
+0x3C,0x02,0x74,0x37,0x77,0x10,0x84,0xC0,0x74,0x06,0x80,0x4E,0x38,0x01,0xF8,0xC3,
+0x80,0x66,0x38,0xFE,0xF8,0xC3,0x8B,0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9,
+0x00,0x04,0x75,0xEA,0x8A,0x86,0xA5,0x00,0xA8,0x01,0x75,0xE2,0x0C,0x05,0x83,0xC2,
+0x02,0x88,0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0xF8,0xC3,0x81,0x4E,0x38,0x00,0x08,
+0x8A,0x86,0xA5,0x00,0xA8,0x01,0x74,0xC6,0x24,0xFA,0xEB,0xE2,0xAD,0x49,0x49,0xF8,
+0xC3,0x90,0xE8,0x11,0xFA,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0xA0,0xDB,0xF8,0xC3,
+0xB0,0xFF,0xE8,0xD9,0xEC,0xF8,0xC3,0x90,0x83,0x66,0x7A,0xFB,0xB0,0x00,0xE8,0x8D,
+0xDB,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x6D,0xD9,0x72,0x11,0x36,0x88,0x1E,0x1A,0x01,
+0x36,0xA0,0x8E,0x12,0x0A,0xC3,0x52,0xBA,0x00,0x01,0xEE,0x5A,0xF8,0xC3,0xAC,0x49,
+0x32,0xE4,0x36,0xA3,0x86,0x12,0x05,0x06,0x00,0x36,0x8B,0x1E,0x88,0x12,0x2B,0xD8,
+0x36,0x89,0x1E,0x8A,0x12,0xF8,0xC3,0x90,0xAD,0x8B,0xD8,0xAD,0x83,0xE9,0x04,0x03,
+0xC3,0x2B,0x46,0x76,0x89,0x46,0x78,0xF7,0x46,0x7A,0x02,0x00,0x74,0x0A,0x83,0x66,
+0x7A,0xFD,0xB8,0x00,0x00,0xE8,0x36,0xDB,0xF8,0xC3,0x06,0x16,0x07,0xAC,0x49,0x25,
+0x0F,0x00,0x6B,0xC0,0x09,0x8D,0xBE,0xFD,0x00,0x03,0xF8,0xAC,0x49,0x25,0x0F,0x00,
+0xAA,0x85,0xC0,0x74,0x08,0x2B,0xC8,0x51,0x8B,0xC8,0xF3,0xA4,0x59,0xE8,0x41,0xF0,
+0xE8,0x44,0x03,0x07,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0xB2,0x13,0x36,0xA3,
+0xB0,0x13,0xF8,0xC3,0x83,0x66,0x7A,0xEF,0xE8,0x2C,0x03,0xF8,0xC3,0x90,0x83,0x4E,
+0x7A,0x10,0xEB,0xF4,0xE8,0xB5,0xF0,0xF8,0xC3,0x90,0xAD,0x3C,0x19,0x77,0x0E,0x3C,
+0x19,0x77,0x0A,0x8B,0xF8,0x81,0xE7,0xFF,0x00,0x88,0xA6,0xC4,0x00,0xF8,0xC3,0x90,
+0x83,0x4E,0x26,0x20,0xAC,0x49,0x32,0xE4,0xD1,0xE0,0x8B,0xD8,0xC1,0xE3,0x02,0x03,
+0xC3,0x89,0x46,0x6E,0x83,0x4E,0x48,0x04,0xB0,0x06,0xE8,0xB1,0xDA,0x49,0x46,0xF9,
+0xC3,0x90,0xFE,0x86,0xB3,0x00,0xB0,0x0A,0xE8,0xA3,0xDA,0xF8,0xC3,0x90,0x33,0xC0,
+0xAC,0x49,0x6B,0xC0,0x0A,0x89,0x86,0x8A,0x00,0xF8,0xC3,0x90,0xAC,0x49,0x32,0xE4,
+0x3D,0x0A,0x00,0x77,0x05,0xB8,0x0A,0x00,0xEB,0x08,0x3D,0x5A,0x00,0x72,0x03,0xB8,
+0x5A,0x00,0x51,0xF7,0xD8,0x05,0x64,0x00,0x8B,0xC8,0x8B,0x46,0x44,0xF7,0xE1,0xB9,
+0x64,0x00,0xF7,0xF1,0x89,0x46,0x46,0x59,0xF8,0xC3,0xAC,0x49,0xE8,0x9F,0xEB,0xF8,
+0xC3,0x90,0xAC,0x49,0x84,0xC0,0x75,0x07,0x81,0x66,0x38,0xFF,0xFD,0xF8,0xC3,0x81,
+0x4E,0x38,0x00,0x02,0xF7,0x46,0x38,0x40,0x00,0x75,0x08,0x8A,0x86,0xA9,0x00,0x88,
+0x86,0xAA,0x00,0xF8,0xC3,0x90,0x51,0x56,0xE8,0x7F,0x0C,0x5E,0x59,0xF8,0xC3,0x90,
+0xFE,0x86,0xB6,0x00,0xB0,0x0A,0xE8,0x25,0xDA,0xF8,0xC3,0x90,0xFE,0x86,0xB7,0x00,
+0xB0,0x0A,0xE8,0x19,0xDA,0xF8,0xC3,0x90,0xFE,0x86,0xB8,0x00,0xB0,0x0A,0xE8,0x0D,
+0xDA,0xF8,0xC3,0x90,0x00,0x90,0x51,0x55,0xAC,0x2E,0xA2,0x34,0x36,0x33,0xC9,0xAD,
+0x8B,0xF9,0xC1,0xE7,0x05,0xA9,0x01,0x00,0x74,0x23,0x2E,0x8B,0xAD,0x44,0x00,0x83,
+0x7E,0x08,0x00,0x74,0x18,0x2E,0x80,0x3E,0x34,0x36,0x01,0x74,0x09,0x60,0xB0,0x04,
+0xE8,0xBB,0x0C,0x61,0xEB,0x07,0x60,0xB0,0xFB,0xE8,0xEC,0x0C,0x61,0x47,0x47,0xD1,
+0xE8,0x75,0xD2,0x41,0x83,0xF9,0x04,0x72,0xC6,0x5D,0x59,0x83,0xE9,0x05,0xF7,0x46,
+0x38,0x40,0x00,0x74,0x05,0xE8,0xA1,0xEA,0xF8,0xC3,0xE8,0xA7,0xEA,0xF8,0xC3,0x90,
+0x36,0xC6,0x06,0xC8,0x13,0x01,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0x80,0x12,
+0xAC,0x49,0x36,0x2B,0x06,0x88,0x12,0xF7,0xD8,0x36,0xA3,0x82,0x12,0xF8,0xC3,0x90,
+0xC0,0x26,0xC0,0x26,0xCE,0x26,0xD4,0x26,0xDA,0x26,0xE0,0x26,0xE6,0x26,0xF0,0x26,
+0xF8,0x26,0x00,0x27,0x08,0x27,0x10,0x27,0x16,0x27,0xA0,0x34,0xA8,0x34,0xB4,0x34,
+0x1C,0x27,0x5A,0x27,0x62,0x27,0x76,0x27,0x82,0x27,0x96,0x27,0xA2,0x27,0xB6,0x27,
+0xC2,0x27,0xD6,0x27,0xE2,0x27,0xF2,0x27,0xCE,0x34,0xC0,0x26,0x00,0x28,0x08,0x28,
+0x0E,0x28,0x14,0x28,0x1A,0x28,0x30,0x28,0x6C,0x28,0xE8,0x34,0x0A,0x35,0x7A,0x28,
+0xA0,0x28,0xB4,0x28,0xC0,0x28,0xC8,0x28,0x36,0x35,0x44,0x35,0x4E,0x35,0xD0,0x28,
+0xA2,0x29,0xAA,0x29,0xB0,0x29,0xC2,0x29,0x54,0x35,0x5A,0x35,0xD2,0x29,0xDE,0x29,
+0x70,0x35,0xEA,0x29,0xF4,0x29,0xFE,0x29,0x92,0x35,0x18,0x2A,0x9E,0x35,0x3C,0x2A,
+0x44,0x2A,0x4A,0x2A,0xAC,0x35,0x5E,0x2A,0xDA,0x35,0x6A,0x2A,0x88,0x2A,0x9A,0x2A,
+0xAE,0x2A,0xC0,0x2A,0xD4,0x2A,0xE2,0x35,0xEC,0x2A,0x06,0x2B,0x06,0x36,0x1A,0x2B,
+0x2E,0x2B,0x66,0x2B,0x10,0x36,0x1C,0x36,0x28,0x36,0x36,0x36,0xCA,0x2B,0x90,0x36,
+0x22,0x2C,0x44,0x2C,0x98,0x36,0x52,0x28,0xC0,0x26,0xC0,0x26,0xB6,0x2E,0xCA,0x2E,
+0xD2,0x2E,0xDA,0x2E,0xE2,0x2E,0xEC,0x2E,0xF4,0x2E,0xFC,0x2E,0x04,0x2F,0x0C,0x2F,
+0x24,0x2F,0xA0,0x34,0xA8,0x34,0xB4,0x34,0x32,0x2F,0x6E,0x2F,0x76,0x2F,0x8A,0x2F,
+0x96,0x2F,0xAA,0x2F,0xB6,0x2F,0xCA,0x2F,0xD6,0x2F,0xEA,0x2F,0xF6,0x2F,0xFE,0x2F,
+0xCE,0x34,0xC0,0x26,0x06,0x30,0x12,0x30,0x1A,0x30,0x26,0x30,0x2E,0x30,0x44,0x30,
+0x86,0x30,0xE8,0x34,0x0A,0x35,0x8C,0x30,0xB0,0x30,0xB8,0x30,0xCC,0x30,0xD4,0x30,
+0x36,0x35,0x44,0x35,0x4E,0x35,0xDC,0x30,0xA4,0x31,0xA4,0x31,0xA6,0x31,0xDC,0x31,
+0x54,0x35,0x5A,0x35,0xEC,0x31,0xF8,0x31,0x70,0x35,0x04,0x32,0x0E,0x32,0x18,0x32,
+0x92,0x35,0x2C,0x32,0x9E,0x35,0x56,0x32,0x6E,0x32,0x7C,0x32,0xAC,0x35,0x80,0x32,
+0xDA,0x35,0x8C,0x32,0xA8,0x32,0xBA,0x32,0xCE,0x32,0xE0,0x32,0xF0,0x32,0xE2,0x35,
+0xF4,0x32,0x08,0x33,0x06,0x36,0x14,0x33,0x7C,0x33,0xC0,0x33,0x10,0x36,0x1C,0x36,
+0x28,0x36,0x36,0x36,0x3E,0x34,0x90,0x36,0x8C,0x34,0x92,0x34,0x98,0x36,0x6E,0x30,
+0xE3,0x28,0xF7,0x46,0x38,0x40,0x00,0x75,0x32,0xE8,0xFD,0xE8,0x33,0xC0,0xAC,0x49,
+0x3D,0x5B,0x00,0x77,0x19,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0xB0,0x36,0x72,0x0B,
+0x85,0xC9,0x75,0xE8,0x8B,0x46,0x48,0xE8,0x1A,0x0C,0xC3,0x4E,0x41,0xC3,0x6A,0x00,
+0x1F,0xC6,0x06,0x93,0x12,0x0C,0x9C,0x0E,0xE8,0x7D,0xDA,0xE8,0xD6,0xE8,0x33,0xC0,
+0xAC,0x49,0x3D,0x5B,0x00,0x77,0xE7,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0x68,0x37,
+0x72,0xD9,0x85,0xC9,0x75,0xE8,0xC3,0xF7,0x46,0x7A,0x10,0x00,0x75,0x0F,0x83,0xBE,
+0x84,0x00,0x00,0x74,0x08,0xB8,0x2A,0x3A,0x89,0x86,0x80,0x00,0xC3,0x81,0xBE,0x80,
+0x00,0xCE,0x3C,0x74,0xF7,0x83,0xBE,0x88,0x00,0x00,0x75,0x05,0xB8,0xCE,0x3C,0xEB,
+0xE7,0xF7,0x46,0x7A,0x08,0x00,0x75,0x40,0x1E,0x60,0x8B,0x8E,0x88,0x00,0x3B,0x4E,
+0x74,0x77,0x33,0x3B,0x4E,0x78,0x77,0x2E,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D,
+0x47,0x47,0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xF4,0x00,0x8B,0xC1,0xF7,0x46,0x7A,0x01,
+0x00,0x75,0x1D,0xF3,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,
+0x74,0xB0,0x0C,0xE8,0x58,0xD7,0x61,0x1F,0xC7,0x86,0x88,0x00,0x00,0x00,0xEB,0xAC,
+0xE3,0xE3,0x50,0x90,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB,0xD8,0x90,0x8B,0x8E,
+0x88,0x00,0xE3,0x46,0x8B,0x9E,0x8A,0x00,0x85,0xDB,0x74,0x3E,0xBA,0x50,0xFF,0xED,
+0x2B,0x86,0x82,0x00,0x3B,0xC3,0x72,0x37,0x8D,0xB6,0xF4,0x00,0xC4,0x7E,0x10,0x8B,
+0xDF,0x26,0x03,0x3D,0x47,0x47,0x8B,0xC1,0x16,0x1F,0xF7,0x46,0x7A,0x01,0x00,0x75,
+0x24,0xF3,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC7,
+0x86,0x88,0x00,0x00,0x00,0xB0,0x0C,0xE8,0xF4,0xD6,0x83,0x66,0x7A,0xF7,0xC3,0xB0,
+0x00,0xE8,0xEA,0xD6,0xC3,0xE3,0xDC,0x50,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB,
+0xD2,0x90,0x1E,0x60,0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xFD,0x00,0x8B,0x86,0x88,0x00,
+0x8B,0x96,0x84,0x00,0x3A,0x04,0x75,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D,0xBE,0xF4,
+0x00,0xF3,0xA6,0x74,0x66,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6,0x8D,0xB6,
+0xFD,0x00,0x8B,0x96,0x84,0x00,0x3A,0x04,0x73,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D,
+0xBE,0xF4,0x00,0xF3,0xA6,0x74,0x76,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6,
+0x8D,0xB6,0xF4,0x00,0xAC,0xF7,0x46,0x7A,0x01,0x00,0x74,0x02,0x24,0x7F,0x1E,0xC5,
+0x5E,0x10,0x8B,0x37,0x88,0x40,0x02,0x46,0x89,0x37,0xFF,0x4E,0x78,0xFF,0x46,0x76,
+0xFF,0x4E,0x74,0x1F,0x8B,0x8E,0x88,0x00,0x49,0x89,0x8E,0x88,0x00,0xE3,0x43,0x8D,
+0xB6,0xF4,0x00,0x8B,0xFE,0x46,0xF3,0xA4,0xE9,0x7D,0xFF,0xC5,0x76,0x10,0x8B,0x1C,
+0x85,0xDB,0x74,0x08,0x03,0xF3,0x83,0xC6,0x03,0x83,0xE6,0xFE,0x8B,0x86,0x84,0x00,
+0x2B,0xC2,0xB4,0x80,0x89,0x04,0x46,0x46,0xC7,0x04,0x00,0x00,0x89,0x76,0x10,0x83,
+0x4E,0x7A,0x04,0xC7,0x86,0x88,0x00,0x00,0x00,0x61,0x1F,0xF9,0xC3,0x33,0xC0,0x61,
+0x1F,0xC3,0xB0,0x80,0x84,0xC0,0x61,0x1F,0xC3,0x90,0x8B,0x4E,0x78,0x2B,0x8E,0x88,
+0x00,0x76,0x27,0x89,0xB6,0x8C,0x00,0x8B,0x5E,0x74,0x3B,0xCB,0x72,0x02,0x8B,0xCB,
+0x3B,0xC8,0x72,0x02,0x8B,0xC8,0x8B,0xC1,0xE3,0x44,0x33,0xD2,0x8E,0xC2,0x8B,0xD1,
+0x83,0xBE,0x88,0x00,0x00,0x74,0x06,0xE9,0x8E,0x00,0x33,0xC0,0xC3,0x8B,0x5E,0x10,
+0x03,0x1F,0x43,0x43,0x52,0xF7,0x46,0x7A,0x01,0x00,0x75,0x2A,0xAC,0x8D,0xBE,0xE4,
+0x00,0x8B,0x8E,0x86,0x00,0xF2,0xAE,0x74,0x34,0x88,0x07,0x43,0x4A,0x75,0xED,0x58,
+0x8B,0x5E,0x10,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x8B,0xC6,
+0x2B,0x86,0x8C,0x00,0xC3,0x90,0xAC,0x8D,0xBE,0xE4,0x00,0x8B,0x8E,0x86,0x00,0xF2,
+0xAE,0x74,0x0A,0x24,0x7F,0x88,0x07,0x43,0x4A,0x75,0xEB,0xEB,0xD2,0x88,0x86,0xF4,
+0x00,0xC7,0x86,0x88,0x00,0x01,0x00,0x58,0x2B,0xC2,0x74,0x0E,0x8B,0x5E,0x10,0x01,
+0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x40,0xE8,0x94,0xFE,0x72,0xBE,
+0x4A,0x75,0x15,0x83,0xBE,0x8A,0x00,0x00,0x74,0xB4,0xBA,0x50,0xFF,0xED,0x89,0x86,
+0x82,0x00,0x83,0x4E,0x7A,0x08,0xEB,0xA6,0x8D,0xBE,0xF4,0x00,0x03,0xBE,0x88,0x00,
+0xA4,0xFF,0x86,0x88,0x00,0xE8,0x6A,0xFE,0x72,0x94,0x79,0x06,0x4A,0x74,0x8F,0xE9,
+0x5B,0xFF,0x4A,0x74,0xCE,0xEB,0xE1,0x90,0x50,0xE8,0x2B,0xCC,0x8B,0x46,0x74,0x39,
+0x46,0x72,0x74,0x27,0x1E,0x56,0x51,0x33,0xC9,0xC5,0x76,0x0C,0xAD,0x74,0x10,0x78,
+0x09,0x03,0xC8,0x05,0x01,0x00,0x24,0xFE,0x03,0xF0,0x3B,0x76,0x10,0x76,0xED,0x29,
+0x4E,0x76,0x01,0x4E,0x78,0xE8,0x51,0xCC,0x59,0x5E,0x1F,0x58,0xC3,0x90,0xC4,0x7E,
+0x10,0x26,0x8B,0x1D,0x83,0xC3,0x03,0x26,0x89,0x1D,0x4B,0x03,0xFB,0xAB,0x91,0xAA,
+0xB8,0x03,0x00,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC3,0x90,0xC4,0x7E,
+0x10,0x26,0x8B,0x1D,0x43,0x26,0x89,0x1D,0x43,0x03,0xFB,0xAA,0xFF,0x4E,0x78,0xFF,
+0x46,0x76,0xFF,0x4E,0x74,0xC3,0xE8,0xE5,0xFF,0xC3,0x80,0x81,0x84,0x85,0x82,0x83,
+0x86,0x87,0x50,0x53,0x8A,0xDC,0x83,0xE3,0x0E,0xD1,0xEB,0x2E,0x8A,0x87,0x7A,0x3B,
+0x08,0x86,0xB0,0x00,0xFE,0x86,0xB1,0x00,0xB0,0x0A,0xE8,0xA1,0xD4,0x5B,0x58,0xC3,
+0x50,0x8A,0xC8,0xB8,0xFF,0x00,0xE8,0x95,0xFF,0x58,0xC3,0x90,0x8A,0x86,0xBB,0x00,
+0xE8,0xAB,0xFF,0xC3,0xE8,0xCB,0xFF,0xE8,0xF2,0xFF,0xC3,0x90,0xE8,0xC3,0xFF,0xE8,
+0xB4,0xFF,0xC3,0x90,0x33,0xC0,0xE8,0x95,0xFF,0xC3,0xB8,0xFF,0x00,0x33,0xC9,0xE8,
+0x6C,0xFF,0xC3,0x90,0xB8,0xFF,0x01,0xB1,0x10,0xE8,0x62,0xFF,0xC3,0x90,0xC3,0xDE,
+0x3B,0xC4,0x3B,0xD4,0x3B,0xD4,0x3B,0xDE,0x3B,0xC4,0x3B,0xCA,0x3B,0xCA,0x3B,0xDE,
+0x3B,0xC4,0x3B,0xCA,0x3B,0xCA,0x3B,0xDE,0x3B,0xC4,0x3B,0xC4,0x3B,0xC4,0x3B,0x00,
+0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
+0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
+0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x51,
+0x53,0x8B,0x4E,0x38,0x81,0xE1,0xFF,0xEE,0xA8,0x04,0x74,0x04,0x81,0xC9,0x00,0x01,
+0x8A,0xE0,0x80,0xE4,0x03,0x24,0x18,0xD0,0xE4,0x0A,0xC4,0x33,0xDB,0x8A,0xD8,0x2E,
+0x8B,0x87,0xDF,0x3B,0x89,0x46,0x7C,0x2E,0x0B,0x8F,0xFF,0x3B,0x89,0x4E,0x38,0xD1,
+0xEB,0x2E,0x8A,0xA7,0x1F,0x3C,0x5B,0x59,0xC3,0xAC,0x49,0x3C,0x01,0x72,0x1D,0x74,
+0x20,0x3C,0x03,0x72,0x23,0x74,0x28,0x3C,0x08,0x72,0x2B,0x74,0x30,0x3C,0x20,0x72,
+0x37,0x74,0x3A,0xBB,0xBC,0x3B,0x32,0xE4,0x89,0x5E,0x7E,0xC3,0xBB,0x82,0x3B,0xEB,
+0xF5,0xBB,0x76,0x3B,0xB4,0x01,0xEB,0xF0,0xBB,0xDE,0x3B,0xB4,0x02,0xEB,0xE9,0xBB,
+0xC4,0x3B,0xB4,0x03,0xEB,0xE2,0xBB,0xA0,0x3B,0xB4,0x04,0xEB,0xDB,0xBB,0xAC,0x3B,
+0xAC,0x49,0x88,0x86,0xBB,0x00,0xEB,0xCE,0xBB,0xB4,0x3B,0xEB,0xF3,0xBB,0xDE,0x3B,
+0xEB,0xC4,0xA9,0x04,0x00,0x75,0xD1,0xA9,0x08,0x00,0x75,0xDA,0xEB,0xD1,0x8B,0x5E,
+0x74,0x8B,0x4E,0x78,0x3B,0xCB,0x72,0x02,0x8B,0xCB,0x3B,0xC8,0x72,0x02,0x8B,0xC8,
+0x8B,0xC1,0xE3,0x2C,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D,0x47,0x47,0xF7,0x46,
+0x7A,0x01,0x00,0x75,0x1C,0xF7,0xC7,0x01,0x00,0x74,0x02,0x49,0xA4,0xD1,0xE9,0xF3,
+0xA5,0x73,0x01,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,
+0xC3,0x50,0x53,0xBB,0x7F,0x7F,0xF7,0xC7,0x01,0x00,0x74,0x05,0x49,0xAC,0x22,0xC3,
+0xAA,0xD1,0xE9,0xE3,0x1D,0x9C,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x14,0xAD,0x23,0xC3,
+0xAB,0x49,0x74,0x0D,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x06,0xAD,0x23,0xC3,0xAB,0xE2,
+0xE5,0x9D,0x73,0x04,0xAC,0x22,0xC3,0xAB,0x5B,0x58,0xEB,0xB8,0xE8,0xE8,0xC9,0x8B,
+0x5E,0x38,0xF7,0xC3,0x10,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x40,0x00,0x74,0x05,0xE8,
+0xD2,0xE3,0xEB,0x03,0xE8,0xC2,0xE3,0x81,0x66,0x38,0xEF,0xFB,0xF6,0xC3,0x10,0x74,
+0x3C,0xF6,0xC3,0x02,0x74,0x06,0xE4,0xD8,0x0C,0x01,0xE6,0xD8,0xF6,0xC3,0x04,0x74,
+0x11,0x83,0xC2,0x08,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEE,0x88,0x86,0xA7,0x00,0x83,
+0xEA,0x08,0xF6,0xC3,0x08,0x74,0x0F,0xE8,0xA5,0xE3,0x72,0x0A,0x8A,0x86,0xC0,0x00,
+0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xF7,0xC3,0x00,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x00,
+0x08,0x75,0xF9,0x8A,0x86,0xA5,0x00,0xF6,0xC3,0x40,0x75,0x0D,0xA8,0x10,0x75,0xEC,
+0x0C,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x01,0x75,0xDF,0x83,0xC2,0x02,
+0x0C,0x05,0xEE,0x88,0x86,0xA5,0x00,0xC3,0xB0,0x00,0xE8,0x61,0xD2,0xEB,0x0F,0xB0,
+0x02,0xE8,0x90,0x0E,0xEB,0x08,0x83,0x66,0x38,0xDF,0x83,0x4E,0x7A,0x02,0x33,0xC0,
+0x8E,0xD8,0xFA,0xA0,0x92,0x12,0x40,0xA2,0x92,0x12,0x3C,0x05,0x72,0x1E,0xC6,0x06,
+0x92,0x12,0x00,0xFB,0xB0,0x01,0xE8,0x6B,0x0E,0xFA,0xA1,0x26,0x01,0x23,0x06,0x2A,
+0x01,0xA8,0x01,0x75,0x07,0xE8,0xE2,0x07,0xE8,0x61,0x09,0x90,0xB0,0x00,0xE8,0x51,
+0xD2,0xFB,0x85,0xED,0x74,0xB9,0xFA,0xF7,0x46,0x7A,0x46,0x00,0x75,0xC0,0x8B,0x46,
+0x78,0x3D,0x0A,0x00,0x72,0xB0,0x8B,0x4E,0x74,0x83,0xF9,0x50,0x72,0x9A,0x83,0x66,
+0x38,0xDF,0xC5,0x76,0x14,0x8B,0x46,0x3A,0x85,0xC0,0x75,0x58,0xAD,0x85,0xC0,0x75,
+0x0F,0xE8,0xF8,0xFE,0xF7,0x46,0x7A,0x08,0x00,0x74,0x93,0xE8,0xA0,0xFA,0xEB,0x8E,
+0x3B,0x76,0x04,0x76,0x21,0xB9,0x02,0x00,0x39,0x4E,0x2E,0x77,0x05,0xC7,0x46,0x2E,
+0x00,0x00,0x56,0x8B,0x76,0x2C,0x89,0x76,0x04,0xC7,0x04,0x00,0x00,0x46,0x46,0x89,
+0x76,0x2C,0x29,0x4E,0x2E,0x5E,0x85,0xC0,0x79,0x17,0xF6,0xC4,0x10,0x74,0x05,0xFF,
+0x56,0x7C,0xEB,0x03,0xFF,0x56,0x7E,0x89,0x76,0x14,0xB0,0x0C,0xE8,0x9F,0xD1,0xEB,
+0x86,0x89,0x46,0x3A,0xFF,0x96,0x80,0x00,0x29,0x46,0x3A,0x89,0x76,0x14,0xB0,0x0C,
+0xE8,0x8B,0xD1,0xE9,0x71,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,
+0x10,0x02,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+0xC0,0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x30,0x41,0x5A,0x41,0xB2,0x41,0xD6,0x41,0xE8,0x41,
+0xFA,0x41,0xC3,0x90,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x80,0x66,0x27,
+0xFD,0x8B,0x56,0x24,0x83,0xFA,0x04,0x72,0xE9,0x83,0xEA,0x02,0x8B,0xD9,0x3B,0xCA,
+0x76,0x02,0x8B,0xCA,0xB0,0x0A,0x57,0x51,0x8B,0xFE,0xF2,0xAE,0x8B,0xC1,0x59,0x5F,
+0x75,0x1E,0x50,0x40,0x2B,0xC8,0x74,0x06,0x2B,0xD1,0x2B,0xD9,0xF3,0xA4,0x59,0x4B,
+0x4A,0x4A,0xB0,0x0D,0xAA,0xA4,0x3B,0xCA,0x76,0x02,0x8B,0xCA,0xE3,0x13,0xEB,0xD4,
+0x2B,0xD9,0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1,0xE9,0xF3,0xA5,0x73,0x01,
+0xA4,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x29,0x7E,0x24,0x01,0x7E,0x1A,0x8B,0xCB,0x80,
+0x7E,0x26,0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,0x18,0x03,
+0x61,0xC3,0xC3,0x90,0xE8,0x7C,0x02,0x72,0xF9,0x90,0x83,0x4E,0x26,0x20,0x8B,0x46,
+0x6A,0x89,0x46,0x6E,0x8B,0x46,0x48,0x0D,0x04,0x00,0x25,0xBF,0xFF,0x89,0x46,0x48,
+0xB0,0x06,0xE8,0xD9,0xCF,0xC3,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A,0x29,
+0x7E,0x24,0x80,0x7E,0x26,0x02,0x74,0x05,0x83,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,
+0xE8,0xD5,0x02,0x61,0xC3,0x90,0x8A,0xBE,0xC2,0x00,0xEB,0x24,0xF7,0x46,0x48,0x40,
+0x00,0x75,0xB1,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x8B,0x56,0x24,0x83,
+0xEA,0x0A,0x78,0x9E,0x03,0xD7,0x80,0x66,0x27,0xFD,0x33,0xC0,0x8A,0xBE,0xC2,0x00,
+0xE3,0xB4,0x3B,0xFA,0x77,0xB0,0xAC,0x49,0x93,0x2E,0x8A,0x87,0xB6,0x3E,0x93,0x22,
+0xDF,0x75,0x17,0xAA,0xE3,0xA0,0x3B,0xFA,0x77,0x9C,0xAC,0x49,0x93,0x2E,0x8A,0x87,
+0xB6,0x3E,0x93,0x22,0xDF,0x75,0x03,0xAA,0xEB,0xD6,0xF6,0xC3,0x7F,0x75,0x05,0xFF,
+0x46,0x66,0xEB,0xDF,0xF6,0xC3,0x40,0x75,0x0C,0x8B,0xD8,0x83,0xEB,0x08,0xD1,0xE3,
+0x2E,0xFF,0xA7,0xB6,0x3F,0xFF,0x46,0x66,0x2C,0x20,0xEB,0xC7,0x85,0xC0,0x74,0x2C,
+0x89,0x46,0x6A,0x83,0x4E,0x48,0x40,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A,
+0x29,0x7E,0x24,0x80,0x7E,0x26,0x02,0x74,0x08,0x83,0x66,0x26,0xFD,0xE8,0xA3,0x01,
+0xC3,0x60,0xB0,0xFD,0xE8,0x31,0x02,0x61,0xE8,0x98,0x01,0xC3,0xE9,0x57,0xFF,0x90,
+0x8B,0x5E,0x66,0x4B,0x78,0x03,0x89,0x5E,0x66,0xAA,0x8B,0x5E,0x64,0xF7,0xC3,0x00,
+0x20,0x75,0x03,0xE9,0x40,0xFF,0xF7,0xC3,0x40,0x00,0x74,0x08,0x8A,0x86,0xC1,0x00,
+0xAA,0xE9,0x32,0xFF,0xB8,0x32,0x00,0xEB,0xA3,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68,
+0x83,0xC3,0x08,0x80,0xE3,0xF8,0x89,0x5E,0x66,0x8B,0x5E,0x64,0x81,0xE3,0x00,0x18,
+0x81,0xFB,0x00,0x18,0x74,0x2D,0xAA,0x85,0xDB,0x74,0x25,0xF7,0x46,0x64,0x40,0x00,
+0x75,0x18,0x81,0xFB,0x00,0x10,0x74,0x0C,0x8B,0x46,0x66,0x2B,0x46,0x68,0xC1,0xE0,
+0x04,0xE9,0x68,0xFF,0xB8,0x64,0x00,0xE9,0x62,0xFF,0x8A,0x86,0xC1,0x00,0xAA,0xAA,
+0xE9,0xE3,0xFE,0x51,0x8B,0x4E,0x66,0x2B,0x4E,0x68,0xB0,0x20,0xF3,0xAA,0x59,0xE9,
+0xD4,0xFE,0x8B,0x5E,0x66,0x89,0x5E,0x68,0x8B,0x5E,0x64,0xF7,0xC3,0x24,0x00,0x74,
+0x10,0xC7,0x46,0x66,0x00,0x00,0xF7,0xC3,0x04,0x00,0x74,0x05,0xB0,0x0D,0xAA,0xB0,
+0x0A,0xAA,0xEB,0x48,0x90,0x90,0xAA,0xF7,0x46,0x64,0x00,0x40,0x74,0x06,0xB8,0xD0,
+0x07,0xE9,0x18,0xFF,0xE9,0x9F,0xFE,0x90,0xAA,0xF7,0x46,0x64,0x00,0x80,0x74,0x06,
+0xB8,0xD0,0x07,0xE9,0x06,0xFF,0xE9,0x8D,0xFE,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68,
+0x85,0xDB,0x75,0x0C,0x8B,0x5E,0x64,0xF7,0xC3,0x10,0x00,0x74,0x06,0xE9,0x76,0xFE,
+0x8B,0x5E,0x64,0xF7,0xC3,0x08,0x00,0x74,0x27,0xB0,0x0A,0xAA,0xF7,0xC3,0x20,0x00,
+0x75,0x1F,0xF7,0xC3,0x00,0x01,0x75,0x03,0xE9,0x5B,0xFE,0xF7,0xC3,0x40,0x00,0x75,
+0x06,0xB8,0x64,0x00,0xE9,0xC5,0xFE,0x8A,0x86,0xC1,0x00,0xAA,0xAA,0xE9,0x46,0xFE,
+0xAA,0xC7,0x46,0x66,0x00,0x00,0xF7,0xC3,0x00,0x06,0x74,0xF1,0xF7,0xC3,0x40,0x00,
+0x74,0x19,0x8A,0x86,0xC1,0x00,0x81,0xE3,0x00,0x06,0x81,0xFB,0x00,0x04,0x72,0x06,
+0x76,0x02,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xE9,0x1B,0xFE,0x81,0xE3,0x00,0x06,0x81,
+0xFB,0x00,0x04,0x72,0x0E,0x76,0x06,0xB8,0x96,0x00,0xE9,0x7F,0xFE,0xB8,0x64,0x00,
+0xE9,0x79,0xFE,0x8B,0x46,0x68,0xE9,0x73,0xFE,0x90,0x36,0x8B,0x0E,0xDA,0x12,0x83,
+0xF9,0x32,0x73,0x1D,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8D,0x76,0x4C,0xBF,
+0xDC,0x12,0x03,0xF9,0xA5,0xA5,0xA5,0x83,0xC1,0x06,0x89,0x0E,0xDA,0x12,0x07,0x1F,
+0xC3,0xB0,0x08,0xE8,0x88,0xCD,0xC3,0x90,0x83,0x66,0x48,0xFE,0xE8,0xAD,0xC4,0xE8,
+0xC8,0xFF,0xC3,0xF6,0x46,0x27,0x02,0x75,0x0F,0x9C,0xFA,0x83,0x7E,0x1A,0x00,0x74,
+0x09,0x80,0x4E,0x27,0x01,0x9D,0xF9,0xC3,0xF8,0xC3,0x50,0x52,0xF7,0x46,0x38,0x40,
+0x00,0x74,0x1D,0xE8,0x4E,0xDE,0x83,0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x27,0x83,0xEA,
+0x08,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x5A,0x58,0xEB,0xD1,
+0xE8,0x26,0xDE,0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,
+0x0C,0x5A,0x58,0xEB,0xBC,0x80,0x4E,0x27,0x02,0x5A,0x58,0x9D,0xF8,0xC3,0x08,0x46,
+0x26,0x9C,0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38,0x40,0x00,0x75,0x14,0xF6,0xC1,
+0x06,0x74,0x23,0xE8,0xF3,0xDD,0x8A,0xC1,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,
+0x9D,0xC3,0xF6,0xC1,0x02,0x74,0x0F,0xE8,0xEA,0xDD,0x83,0xC2,0x02,0x8A,0xC1,0x24,
+0xFD,0x88,0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x8B,0x5E,0x26,0x22,0xC3,0x88,0x46,0x26,
+0x74,0x01,0xC3,0x80,0x66,0x27,0xFD,0x9C,0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38,
+0x40,0x00,0x75,0x16,0xF6,0xC1,0x04,0x75,0x0F,0xE8,0xAD,0xDD,0x8A,0xC1,0x24,0xFD,
+0x0C,0x04,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x9D,0xC3,0xF6,0xC1,0x02,0x75,0xF9,0xE8,
+0xA2,0xDD,0x83,0xC2,0x0A,0xEC,0xA8,0x20,0x75,0x0E,0x83,0xEA,0x08,0x8A,0xC1,0x0C,
+0x02,0x88,0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x83,0xEA,0x0A,0x33,0xC9,0x8A,0x4E,0x1C,
+0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x1B,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,0x1E,
+0xC5,0x76,0x00,0xF3,0x6E,0x1F,0x89,0x76,0x00,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,
+0xEB,0xCD,0x85,0xC0,0x74,0x12,0x01,0x46,0x2A,0x8B,0xC8,0x1E,0xC5,0x76,0x00,0xF3,
+0x6E,0x1F,0x89,0x76,0x00,0x89,0x4E,0x1A,0xF6,0xC7,0x01,0x75,0x23,0x80,0xCB,0x02,
+0x89,0x5E,0x26,0xE8,0x22,0xC3,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE,
+0x88,0x86,0xA5,0x00,0xF6,0xC7,0x10,0x75,0x05,0xB0,0x02,0xE8,0x30,0xCC,0x9D,0xC3,
+0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0xEB,0x86,0x90,0x8B,0xD1,0x8B,0x46,0x24,0x3B,
+0xC8,0x76,0x02,0x8B,0xC8,0x2B,0xD1,0x2B,0xC1,0x8B,0xD9,0xE3,0x22,0x80,0x66,0x27,
+0xFD,0x8E,0x46,0x02,0x8B,0x7E,0x22,0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1,
+0xE9,0xF3,0xA5,0x73,0x01,0xA4,0x89,0x7E,0x22,0x89,0x46,0x24,0x01,0x5E,0x1A,0x8B,
+0xCA,0x80,0x7E,0x26,0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,
+0xF6,0xFE,0x61,0xC3,0x50,0xE4,0x0A,0x84,0xC0,0x75,0x0A,0x86,0x86,0xA1,0x00,0x84,
+0xC0,0x74,0x0A,0xE6,0x0A,0x58,0x0C,0x20,0x89,0x46,0x48,0xF9,0xC3,0x58,0x24,0xDF,
+0x89,0x46,0x48,0xF8,0xC3,0x90,0xFB,0xB0,0x02,0xE8,0xE8,0x07,0xFA,0xE8,0x2E,0x01,
+0xFB,0xB0,0x01,0xE8,0xDE,0x07,0xFA,0xB0,0x02,0xE8,0xD6,0xCB,0xFB,0x85,0xED,0x74,
+0xE5,0xFA,0x8E,0x5E,0x0A,0xFB,0x90,0xFA,0x8B,0x46,0x48,0x8B,0x76,0x40,0xA8,0x8C,
+0x75,0xDE,0xA8,0x20,0x74,0x1A,0x50,0xE8,0x6F,0xDC,0x58,0xE8,0xA6,0xFF,0x73,0x10,
+0xB0,0x02,0xE8,0x79,0xCB,0xEB,0xC9,0x90,0x25,0xFF,0x00,0x8B,0xC8,0xEB,0x36,0x90,
+0xA8,0x01,0x75,0x22,0x46,0x83,0xE6,0xFE,0x3B,0x76,0x08,0x74,0x79,0xAD,0x8A,0xFC,
+0xB3,0xF0,0x22,0xFB,0x3A,0xFB,0x74,0xE0,0x3A,0xBE,0xA0,0x00,0x74,0x2E,0xE8,0xD2,
+0xFD,0x73,0x77,0xEB,0x9B,0x90,0x8A,0xE0,0x24,0xFC,0x88,0x46,0x48,0x8B,0x4E,0x4A,
+0xF6,0xC4,0x02,0x74,0x1D,0xE8,0xBB,0xFD,0x72,0x86,0xE8,0x13,0xF3,0x89,0x76,0x40,
+0xE3,0x93,0x83,0x4E,0x48,0x03,0x89,0x4E,0x4A,0xE9,0x74,0xFF,0x25,0xFF,0x0F,0x8B,
+0xC8,0x90,0x8B,0x86,0x98,0x00,0x85,0xC0,0x74,0x1A,0x51,0x8A,0x8E,0xA0,0x00,0xC0,
+0xE9,0x04,0xBA,0x01,0x00,0xD3,0xE2,0x59,0x23,0xC2,0x74,0x08,0x03,0xF1,0x89,0x76,
+0x40,0xE9,0x61,0xFF,0xFF,0x56,0x62,0xE3,0xF5,0x83,0x4E,0x48,0x01,0x89,0x4E,0x4A,
+0x89,0x76,0x40,0xE9,0x3A,0xFF,0x81,0x4E,0x26,0x00,0x10,0x8B,0x46,0x50,0x3B,0x46,
+0x46,0x77,0x03,0xE8,0x52,0xFD,0xE9,0x27,0xFF,0x90,0x88,0xBE,0xA0,0x00,0xEB,0xAC,
+0x0A,0x06,0x90,0x12,0x8A,0xE0,0xBA,0x06,0x01,0xB0,0x04,0xEE,0xEC,0x84,0xC0,0x75,
+0x12,0xB0,0x04,0xEE,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80,0x74,0x06,0xC7,0x06,0x84,
+0x12,0x00,0x00,0x88,0x26,0x90,0x12,0xC3,0x0A,0x06,0x90,0x12,0x8A,0xE0,0xBA,0x06,
+0x01,0xEC,0xA8,0x01,0x75,0xED,0xBA,0x08,0x01,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80,
+0x74,0xE1,0xC7,0x06,0x84,0x12,0x00,0x00,0x88,0x26,0x90,0x12,0xC3,0x90,0x36,0xF7,
+0x06,0x24,0x01,0x01,0x00,0x75,0x30,0x36,0x8B,0x0E,0xDA,0x12,0x80,0xF9,0x36,0x73,
+0x26,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0xDC,0x12,0x03,0xF9,0xB0,0x08,0xE8,0x91,
+0xCA,0x85,0xED,0x74,0x0E,0x8D,0x76,0x4C,0xA5,0xA5,0xA5,0x80,0xC1,0x06,0x80,0xF9,
+0x36,0x72,0xE9,0x89,0x0E,0xDA,0x12,0xC3,0xC3,0x90,0xF7,0x06,0x26,0x01,0x01,0x00,
+0x75,0xF6,0x8B,0x0E,0x20,0x13,0x85,0xC9,0x75,0xEE,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,
+0xBF,0x24,0x13,0xB9,0x36,0x00,0xB0,0x0A,0xE8,0x57,0xCA,0x85,0xED,0x75,0x06,0xE9,
+0x12,0x01,0xE9,0x0A,0x01,0x33,0xDB,0x8A,0x46,0x4C,0x8A,0xA6,0xB3,0x00,0xFE,0xCC,
+0x78,0x0E,0x88,0xA6,0xB3,0x00,0x0A,0xDC,0xB4,0x0A,0xAB,0x83,0xE9,0x02,0x76,0xE2,
+0x8A,0xA6,0xB2,0x00,0xFE,0xCC,0x78,0x0E,0x88,0xA6,0xB2,0x00,0x0A,0xDC,0xB4,0x08,
+0xAB,0x83,0xE9,0x02,0x76,0xCC,0x8A,0xA6,0xB1,0x00,0xFE,0xCC,0x78,0x18,0x8A,0xBE,
+0xB0,0x00,0x75,0x04,0x88,0xA6,0xB0,0x00,0x88,0xA6,0xB1,0x00,0x0A,0xDC,0x8A,0xE7,
+0xAB,0x83,0xE9,0x02,0x76,0xAC,0x8A,0xA6,0xB4,0x00,0xFE,0xCC,0x78,0x1F,0x88,0xA6,
+0xB4,0x00,0x0A,0xDC,0xB4,0x0B,0xAB,0x8A,0x86,0xBC,0x00,0x8A,0xA6,0xBD,0x00,0xAB,
+0x8B,0x86,0xBE,0x00,0xAB,0x83,0xE9,0x06,0x76,0x88,0x8A,0x46,0x4C,0x8A,0xA6,0xB6,
+0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB6,0x00,0x0A,0xDC,0xB4,0x0C,0xAB,0xE8,0xF5,
+0xCB,0xAB,0x8B,0x46,0x2A,0xAB,0x83,0xE9,0x06,0x76,0x74,0x8A,0x46,0x4C,0x8A,0xA6,
+0xB7,0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB7,0x00,0x0A,0xDC,0xB4,0x0D,0xAB,0xE8,
+0xD4,0xCB,0xAB,0x8B,0x46,0x34,0xAB,0x83,0xE9,0x06,0x76,0x53,0x8A,0x46,0x4C,0x8A,
+0xA6,0xB8,0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB8,0x00,0x0A,0xDC,0xB4,0x0E,0xAB,
+0xA1,0x50,0x12,0xAB,0xA1,0x52,0x12,0xAB,0x83,0xE9,0x06,0x76,0x32,0x8A,0x46,0x4C,
+0x8A,0xA6,0xB5,0x00,0xFE,0xCC,0x78,0x18,0x88,0xA6,0xB5,0x00,0x0A,0xDC,0xB4,0x0F,
+0xAB,0x8B,0x86,0x9A,0x00,0xAB,0x8B,0x86,0x9C,0x00,0xAB,0x83,0xE9,0x06,0x76,0x0F,
+0x84,0xDB,0x75,0x03,0xE9,0xEF,0xFE,0xB0,0x0A,0xE8,0x12,0xC9,0xE9,0xE7,0xFE,0xB0,
+0x0A,0xE8,0x0A,0xC9,0xF7,0xD9,0x83,0xC1,0x36,0x8B,0xC1,0x0D,0x80,0x00,0x86,0xC4,
+0xA3,0x22,0x13,0x41,0x41,0x89,0x0E,0x20,0x13,0xC3,0xA1,0x84,0x12,0x2B,0xC1,0x72,
+0x11,0xA3,0x84,0x12,0xBE,0x22,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x20,0x13,
+0xF8,0xC3,0xF9,0xC3,0xC3,0x81,0xEF,0x6A,0x13,0x74,0xF9,0x8B,0xC7,0x0D,0x80,0x00,
+0x86,0xC4,0xA3,0x68,0x13,0x47,0x47,0x89,0x3E,0x66,0x13,0xC3,0xF7,0x06,0x2A,0x01,
+0x01,0x00,0x75,0xE0,0x8B,0x0E,0x66,0x13,0xE3,0x07,0x80,0xF9,0x20,0x77,0xD5,0x49,
+0x49,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0x6A,0x13,0x8B,0xF7,0x03,0xF9,0x83,0xC6,
+0x34,0x3B,0xFE,0x77,0xC0,0xB0,0x0E,0xE8,0xC8,0xC8,0x85,0xED,0x74,0xB7,0x8A,0x46,
+0x4C,0x8A,0xB6,0xB9,0x00,0xFE,0xCE,0x78,0x15,0x88,0xB6,0xB9,0x00,0x8A,0xA6,0xA9,
+0x00,0x80,0xCC,0xC0,0xAB,0x84,0xF6,0x74,0x05,0xB0,0x0E,0xE8,0x70,0xC8,0x8A,0xB6,
+0xBA,0x00,0xFE,0xCE,0x78,0xCB,0x8A,0x9E,0xA9,0x00,0x8A,0xBE,0xAB,0x00,0x8A,0x56,
+0x3F,0x8A,0xF3,0x32,0xF7,0x0A,0xB6,0xAC,0x00,0xC6,0x86,0xAC,0x00,0x00,0x22,0xF2,
+0x74,0x4B,0xF6,0xC6,0x08,0x74,0x0F,0xB4,0x02,0xF6,0xC3,0x08,0x75,0x02,0xB4,0x03,
+0xAB,0x80,0xE6,0xF7,0x74,0x37,0xF6,0xC6,0x01,0x74,0x0F,0xB4,0x00,0xF6,0xC3,0x01,
+0x75,0x02,0xB4,0x01,0xAB,0x80,0xE6,0xFE,0x74,0x23,0xF6,0xC6,0x02,0x74,0x0F,0xB4,
+0x04,0xF6,0xC3,0x02,0x75,0x02,0xB4,0x05,0xAB,0x80,0xE6,0xFD,0x74,0x0F,0xF6,0xC6,
+0x04,0x74,0x0A,0xB4,0x06,0xF6,0xC3,0x04,0x75,0x02,0xB4,0x07,0xAB,0xC6,0x86,0xBA,
+0x00,0x00,0x88,0x9E,0xAB,0x00,0xE9,0x58,0xFF,0x90,0xA1,0x84,0x12,0x2B,0xC1,0x72,
+0x11,0xA3,0x84,0x12,0xBE,0x68,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x66,0x13,
+0xF8,0xC3,0xF9,0xC3,0xA1,0x84,0x12,0x41,0x41,0x2B,0xC1,0x72,0x23,0xA3,0x84,0x12,
+0x8B,0xC1,0x48,0x48,0x32,0xE4,0x0C,0x80,0x86,0xC4,0xEF,0x90,0x90,0x90,0x90,0x90,
+0xBE,0xDC,0x12,0x49,0x49,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0xDA,0x12,0xF8,0xC3,
+0xF9,0xC3,0x8A,0xC8,0x8A,0x46,0x4C,0xB4,0x01,0x83,0xEB,0x06,0xEF,0x90,0x90,0x90,
+0x90,0x90,0xB8,0x01,0x00,0xEF,0x90,0x90,0x90,0x90,0x90,0x8A,0xC1,0xEF,0x90,0x90,
+0x90,0x90,0x90,0xE9,0x97,0x00,0xE9,0xAC,0x00,0x33,0xC0,0x8E,0xD8,0x89,0x1E,0x84,
+0x12,0xC3,0x36,0x8B,0x1E,0x84,0x12,0xFB,0x90,0xFA,0xB0,0x0C,0xE8,0xA3,0xC7,0x85,
+0xED,0x74,0xE6,0xC5,0x76,0x0C,0x83,0xFB,0x14,0x72,0xDB,0xFB,0x90,0xFA,0xAD,0x85,
+0xC0,0x78,0xAF,0x74,0xE2,0x8B,0xFE,0x03,0xF8,0x36,0x8B,0x0E,0x86,0x12,0x3B,0xC1,
+0x77,0x02,0x8B,0xC8,0x83,0xEB,0x04,0x3B,0xD9,0x77,0x02,0x8B,0xCB,0x33,0xC0,0x8A,
+0x46,0x4C,0xEF,0x90,0x90,0x90,0x90,0x90,0x8B,0xC1,0xEF,0x90,0x90,0x90,0x90,0x90,
+0x41,0x80,0xE1,0xFE,0x2B,0xD9,0x51,0xD1,0xE9,0xF3,0x6F,0x90,0x59,0x8B,0xC7,0x40,
+0x24,0xFE,0x3B,0xC6,0x74,0x27,0x2B,0xFE,0x4E,0x4E,0x53,0x8B,0x5E,0x10,0x3B,0xF3,
+0x72,0x13,0x03,0x1F,0x83,0xC3,0x03,0x80,0xE3,0xFE,0xC7,0x07,0x00,0x00,0x83,0x6E,
+0x74,0x02,0x89,0x5E,0x10,0x5B,0x89,0x3C,0x89,0x76,0x0C,0xEB,0x89,0x89,0x76,0x0C,
+0x39,0x76,0x10,0x77,0x81,0x72,0x08,0x83,0x3C,0x00,0x74,0x03,0xE9,0x77,0xFF,0xE8,
+0x27,0xBE,0xE9,0x62,0xFF,0x36,0x89,0x1E,0x84,0x12,0xB0,0x0C,0xE8,0xCF,0xC6,0x33,
+0xC0,0x8E,0xD8,0xC3,0xA1,0x84,0x12,0x3D,0x10,0x00,0x72,0x77,0xBA,0x04,0x01,0x3B,
+0x06,0x88,0x12,0x75,0x06,0xC7,0x06,0x7E,0x12,0x00,0x00,0x8B,0x0E,0xDA,0x12,0xE3,
+0x0B,0xE8,0xD0,0xFE,0x72,0x57,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x20,0x13,
+0xE3,0x0B,0xE8,0xA5,0xFD,0x72,0x46,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x66,
+0x13,0xE3,0x0B,0xE8,0x94,0xFE,0x72,0x35,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0xA1,0x28,
+0x01,0xA9,0x01,0x00,0x75,0x03,0xE8,0xF9,0xFE,0x80,0x3E,0x8D,0x12,0x00,0x75,0x1D,
+0xA1,0x84,0x12,0x3D,0x20,0x00,0x76,0x15,0x3B,0x06,0x82,0x12,0x76,0x09,0xA1,0x7E,
+0x12,0x3B,0x06,0x80,0x12,0x72,0x0C,0x80,0x0E,0x90,0x12,0x80,0xC3,0xB0,0x80,0xFF,
+0x16,0x7C,0x12,0xC3,0x80,0x0E,0x90,0x12,0x40,0xC3,0x6A,0x00,0x1F,0xC6,0x06,0x93,
+0x12,0x17,0x9C,0x0E,0xE8,0xD1,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x20,0x9C,
+0x0E,0xE8,0xC4,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x16,0x9C,0x0E,0xE8,0xB7,
+0xC8,0x90,0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xCA,0xFB,0x90,0xFA,0xBA,0x04,0x01,
+0xED,0x90,0x90,0x90,0x90,0x90,0x3A,0x06,0x94,0x12,0x77,0xBE,0x33,0xDB,0x8A,0xD8,
+0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0xC4,0x7E,0x08,0x85,0xFF,0x74,0xB9,0xF6,0xC4,
+0xC0,0x75,0x55,0x32,0xC0,0xC1,0xE0,0x02,0x80,0xE4,0xF0,0x8B,0xF0,0xED,0x90,0x90,
+0x90,0x90,0x90,0x85,0xC0,0x74,0xBB,0x8B,0xC8,0x41,0x80,0xE1,0xFE,0x0B,0xC6,0x8B,
+0x5E,0x50,0x4B,0x4B,0x2B,0xD9,0x78,0x9C,0xAB,0x8B,0xC1,0x40,0x40,0x01,0x46,0x4E,
+0xD1,0xE9,0xF3,0x6D,0x90,0x89,0x5E,0x50,0x89,0x7E,0x08,0x8B,0x46,0x26,0x80,0xE4,
+0xEF,0x89,0x46,0x26,0xF6,0xC4,0x01,0x75,0x0C,0xF7,0x46,0x48,0x0C,0x00,0x75,0x05,
+0xB0,0x02,0xE8,0x99,0xC5,0xE9,0x7A,0xFF,0x86,0xC4,0x8B,0xC8,0x83,0xE1,0x3F,0x41,
+0x80,0xE1,0xFE,0xE3,0x0A,0x3C,0x80,0x72,0x09,0x24,0x3F,0xB4,0xF0,0xEB,0xB0,0xE9,
+0x60,0xFF,0x25,0x3F,0x00,0x33,0xFF,0x8E,0xC7,0xBF,0x96,0x12,0x8B,0xF7,0xD1,0xE9,
+0xF3,0x6D,0x90,0x8B,0xC8,0xE8,0x48,0xED,0xE9,0x47,0xFF,0x90,0x6A,0x00,0x1F,0xC6,
+0x06,0x93,0x12,0x1B,0x9C,0x0E,0xE8,0xEF,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E,
+0xD8,0x8E,0xC0,0xBA,0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xB0,0x06,0xEE,0xEC,0xA2,
+0x8C,0x12,0xA8,0x40,0x74,0x11,0xA1,0x88,0x12,0xA3,0x84,0x12,0xC6,0x06,0x8D,0x12,
+0x00,0xE8,0x60,0xFE,0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0x04,0xFF,0xB8,0x00,
+0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x6A,0x00,0x1F,0xC6,0x06,0x93,
+0x12,0x1B,0x9C,0x0E,0xE8,0xA1,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,
+0xC0,0xBA,0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xBA,0x08,0x01,0xEC,0xA2,0x8C,0x12,
+0xA8,0x40,0x74,0x11,0xA1,0x88,0x12,0xA3,0x84,0x12,0xC6,0x06,0x8D,0x12,0x00,0xE8,
+0x12,0xFE,0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0xB6,0xFE,0xB8,0x00,0x80,0xBA,
+0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xEE,0x86,0xE0,0xEE,0x86,0xE0,0xEC,0x86,
+0xE0,0xEC,0x86,0xE0,0x80,0xE1,0xFE,0xF3,0x6C,0x90,0x80,0xE1,0xFE,0xF3,0x6E,0x90,
+0x05,0x00,0x57,0x47,0x8A,0x4B,0x05,0x00,0x57,0x48,0x8A,0x4B,0x05,0x00,0x85,0x48,
+0x8A,0x4B,0x05,0x00,0x17,0x49,0x8A,0x4B,0x06,0x00,0x7A,0x48,0x78,0x4B,0x06,0x00,
+0x9C,0x48,0x78,0x4B,0x06,0x00,0xA5,0x48,0x78,0x4B,0x06,0x00,0xAD,0x48,0x78,0x4B,
+0x06,0x00,0x02,0x49,0x78,0x4B,0x06,0x00,0x0A,0x49,0x78,0x4B,0x06,0x00,0x30,0x4A,
+0x7E,0x4B,0x06,0x00,0x5D,0x4A,0x7E,0x4B,0x05,0x00,0x80,0x4A,0x84,0x4B,0x05,0x00,
+0xCE,0x4A,0x84,0x4B,0x00,0x00,0x1E,0x06,0x83,0x3E,0x44,0x12,0x00,0x74,0x09,0xA0,
+0x06,0x01,0x24,0x30,0x3C,0x30,0x74,0x1A,0x8C,0xC8,0x8E,0xD8,0x8E,0xC0,0xBB,0x90,
+0x4B,0x8B,0x0F,0xE3,0x0D,0x8B,0x7F,0x02,0x8B,0x77,0x04,0xF3,0xA4,0x83,0xC3,0x06,
+0xEB,0xEF,0x07,0x1F,0xC3,0x90,0x33,0xC0,0xA3,0x3E,0x01,0xB9,0x0C,0x01,0xBE,0x40,
+0x01,0x8B,0xFE,0x81,0xC6,0xB4,0x0F,0x89,0x04,0x8B,0xC6,0x2B,0xF1,0x3B,0xC7,0x77,
+0xF6,0xA3,0x3C,0x01,0xC3,0x90,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x8B,0x5E,
+0x00,0x3B,0xEB,0x74,0x2B,0x8B,0x76,0x02,0x89,0x1C,0x89,0x77,0x02,0x36,0xA1,0x3C,
+0x01,0x89,0x46,0x00,0x36,0x89,0x2E,0x3C,0x01,0x8B,0xEB,0xFF,0x4E,0x06,0x74,0x08,
+0x8B,0x6E,0x00,0xFF,0x4E,0x06,0x75,0xF8,0x36,0x89,0x2E,0x3E,0x01,0x8B,0x66,0x04,
+0x61,0x07,0x1F,0xC3,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x98,0x89,0x46,0x06,
+0x89,0x66,0x04,0x3B,0x6E,0x00,0x74,0x10,0x8B,0x6E,0x00,0xFF,0x4E,0x06,0x75,0xF8,
+0x36,0x89,0x2E,0x3E,0x01,0x8B,0x66,0x04,0x61,0x07,0x1F,0xC3,0xC3,0x90,0x1E,0x06,
+0x60,0x9C,0xFA,0x33,0xED,0x8E,0xDD,0x8B,0x2E,0x3C,0x01,0x85,0xED,0x74,0x3D,0x8B,
+0x4E,0x00,0x89,0x0E,0x3C,0x01,0x8B,0xCC,0x8D,0xA6,0x0A,0x01,0x56,0x1E,0x06,0x60,
+0x89,0x66,0x04,0xC7,0x46,0x08,0x0F,0x1A,0xC7,0x46,0x06,0x01,0x00,0x8B,0x1E,0x3E,
+0x01,0x85,0xDB,0x74,0x1D,0x8B,0xC5,0x87,0x07,0x89,0x46,0x00,0x89,0x5E,0x02,0x8B,
+0xD8,0x89,0x6F,0x02,0x8B,0xE1,0x9D,0x61,0x07,0x1F,0xF8,0xC3,0x9D,0x61,0x07,0x1F,
+0xF9,0xC3,0x89,0x2E,0x3E,0x01,0x89,0x6E,0x00,0x89,0x6E,0x02,0x87,0xE1,0x9D,0x8B,
+0xE1,0xEB,0xE4,0x00,0x0D,0x0A,0x54,0x65,0x72,0x6D,0x69,0x6E,0x61,0x6C,0x73,0x20,
+0x73,0x75,0x70,0x70,0x6F,0x72,0x74,0x65,0x64,0x3A,0x0D,0x0A,0x31,0x29,0x20,0x41,
+0x4E,0x53,0x49,0x20,0x63,0x6F,0x6D,0x70,0x61,0x74,0x69,0x62,0x6C,0x65,0x0D,0x0A,
+0x32,0x29,0x20,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x0D,0x0A,0x50,0x6C,0x65,0x61,
+0x73,0x65,0x20,0x73,0x65,0x6C,0x65,0x63,0x74,0x3A,0x20,0x00,0x0D,0x0A,0x63,0x6F,
+0x64,0x65,0x20,0x73,0x65,0x67,0x6D,0x65,0x6E,0x74,0x3D,0x00,0x0D,0x0A,0x4D,0x6F,
+0x6E,0x69,0x74,0x6F,0x72,0x20,0x76,0x32,0x2E,0x35,0x0A,0x0D,0x0A,0x3E,0x00,0x0D,
+0x0A,0x50,0x61,0x72,0x64,0x6F,0x6E,0x3F,0x00,0x0D,0x0A,0x4E,0x6F,0x20,0x61,0x64,
+0x64,0x72,0x65,0x73,0x73,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x00,
+0x0D,0x0A,0x3A,0x00,0x0D,0x0A,0x00,0x4C,0x6F,0x63,0x3D,0x00,0x0D,0x0A,0x46,0x41,
+0x54,0x41,0x4C,0x20,0x45,0x52,0x52,0x4F,0x52,0x3D,0x00,0x0D,0x0A,0x4D,0x6F,0x6E,
+0x69,0x74,0x6F,0x72,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x73,0x3A,0x2D,0x0D,
+0x0A,0x20,0x20,0x20,0x44,0x2C,0x64,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,
+0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x6D,0x65,0x6D,0x6F,
+0x72,0x79,0x0D,0x0A,0x20,0x20,0x20,0x4C,0x2C,0x6C,0x5B,0x5B,0x78,0x78,0x78,0x78,
+0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x73,
+0x69,0x6E,0x67,0x6C,0x65,0x20,0x6C,0x69,0x6E,0x65,0x0D,0x0A,0x20,0x20,0x20,0x45,
+0x2C,0x65,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,
+0x2D,0x20,0x65,0x64,0x69,0x74,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,0x0D,0x0A,0x20,
+0x20,0x20,0x46,0x2C,0x66,0x5B,0x5B,0x78,0x78,0x78,0x78,0x20,0x5D,0x78,0x78,0x78,
+0x78,0x5D,0x20,0x2D,0x20,0x66,0x69,0x6C,0x6C,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,
+0x20,0x70,0x61,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x0D,0x0A,0x20,0x20,0x20,
+0x49,0x5B,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x2D,0x20,0x77,0x6F,0x72,0x64,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72,
+0x6F,0x6D,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x69,0x5B,0x78,0x78,
+0x78,0x78,0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,
+0x79,0x74,0x65,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72,0x6F,0x6D,0x20,0x70,
+0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x4F,0x78,0x78,0x78,0x78,0x20,0x78,0x78,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75,
+0x74,0x20,0x77,0x6F,0x72,0x64,0x20,0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,
+0x20,0x20,0x20,0x6F,0x78,0x78,0x78,0x78,0x20,0x78,0x78,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75,0x74,0x20,0x62,0x79,0x74,
+0x65,0x20,0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x47,0x5B,
+0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x2D,
+0x20,0x67,0x6F,0x74,0x6F,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x0D,0x0A,0x20,
+0x20,0x20,0x57,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,
+0x20,0x20,0x20,0x2D,0x20,0x77,0x61,0x74,0x63,0x68,0x20,0x61,0x20,0x77,0x6F,0x72,
+0x64,0x0D,0x0A,0x20,0x20,0x20,0x43,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69,0x6E,0x74,0x65,0x72,0x72,0x75,
+0x70,0x74,0x73,0x20,0x6F,0x66,0x66,0x0D,0x0A,0x20,0x20,0x20,0x53,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69,
+0x6E,0x74,0x65,0x72,0x72,0x75,0x70,0x74,0x73,0x20,0x6F,0x6E,0x0D,0x0A,0x20,0x20,
+0x20,0x73,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x2D,0x20,0x73,0x69,0x6E,0x67,0x6C,0x65,0x20,0x73,0x74,0x65,0x70,0x0D,
+0x0A,0x20,0x20,0x20,0x42,0x78,0x78,0x78,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65,0x61,0x6B,0x70,0x6F,0x69,0x6E,
+0x74,0x20,0x73,0x65,0x74,0x0D,0x0A,0x20,0x20,0x20,0x62,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65,
+0x61,0x6B,0x70,0x6F,0x69,0x6E,0x74,0x20,0x63,0x6C,0x65,0x61,0x72,0x0D,0x0A,0x20,
+0x20,0x20,0x52,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x2D,0x20,0x72,0x65,0x73,0x74,0x61,0x72,0x74,0x20,0x62,0x72,0x65,
+0x61,0x6B,0x70,0x6F,0x69,0x6E,0x74,0x0D,0x0A,0x20,0x20,0x20,0x72,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x72,
+0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x20,0x61,0x74,0x20,0x62,0x72,0x6B,0x70,
+0x74,0x0D,0x0A,0x20,0x20,0x20,0x58,0x2C,0x78,0x20,0x6E,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x65,0x78,0x61,0x6D,0x69,0x6E,0x65,
+0x20,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x6E,0x0D,0x0A,0x20,0x20,0x20,0x48,
+0x2C,0x3F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x2D,0x20,0x74,0x68,0x69,0x73,0x20,0x6D,0x65,0x73,0x73,0x61,0x67,0x65,0x00,0x1B,
+0x5B,0x32,0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x41,0x4E,0x53,0x49,0x20,0x54,0x65,
+0x72,0x6D,0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x0A,0x00,0x1B,0x5B,0x4B,0x00,0x1B,0x5B,
+0x4A,0x00,0x1B,0x5B,0x32,0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x00,0x1B,0x5B,0x44,
+0x20,0x1B,0x5B,0x44,0x00,0x1B,0x5B,0x31,0x3B,0x37,0x32,0x48,0x00,0x1B,0x5B,0x00,
+0x3B,0x00,0x48,0x00,0x1B,0x5B,0x73,0x00,0x1B,0x5B,0x75,0x00,0x1B,0x7A,0x2B,0x0B,
+0x7F,0x1B,0x7A,0x2E,0x0C,0x7F,0x1B,0x7A,0x2D,0x08,0x7F,0x1B,0x7A,0x2C,0x0A,0x7F,
+0x1B,0x7A,0x22,0x08,0x7F,0x1A,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x20,0x54,0x65,
+0x72,0x6D,0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x00,0x1B,0x54,0x00,0x1B,0x59,0x00,0x1A,
+0x00,0x1E,0x00,0x08,0x20,0x08,0x00,0x00,0x1B,0x3D,0x00,0x00,0x00,0x1B,0x46,0x00,
+0x0D,0x00,0x3F,0x44,0x64,0x45,0x65,0x46,0x66,0x47,0x67,0x48,0x68,0x49,0x69,0x4F,
+0x6F,0x43,0x63,0x53,0x73,0x42,0x62,0x52,0x72,0x57,0x77,0x58,0x78,0x4C,0x6C,0x1E,
+0x60,0xB6,0x57,0xB6,0x57,0x32,0x58,0x32,0x58,0xB8,0x59,0xB8,0x59,0x96,0x59,0x96,
+0x59,0x1E,0x60,0x1E,0x60,0x4E,0x57,0x2A,0x57,0x08,0x57,0xE8,0x56,0x72,0x57,0x72,
+0x57,0x7A,0x57,0x2A,0x5F,0xEE,0x5E,0x3A,0x5F,0x15,0x5F,0x22,0x5F,0x82,0x57,0x82,
+0x57,0xE0,0x59,0xE0,0x59,0xBE,0x57,0xBE,0x57,0x6A,0x61,0x7A,0x61,0xA2,0x61,0xAE,
+0x61,0xBA,0x61,0xD8,0x61,0xE4,0x61,0x04,0x62,0xDA,0x56,0x2C,0x62,0x3A,0x62,0x42,
+0x59,0x20,0x20,0x66,0x6C,0x61,0x67,0x73,0x3D,0x00,0x20,0x20,0x61,0x78,0x3D,0x00,
+0x20,0x20,0x62,0x78,0x3D,0x00,0x20,0x20,0x63,0x78,0x3D,0x00,0x20,0x20,0x64,0x78,
+0x3D,0x00,0x20,0x20,0x63,0x73,0x3D,0x00,0x20,0x20,0x64,0x73,0x3D,0x00,0x20,0x20,
+0x65,0x73,0x3D,0x00,0x20,0x20,0x73,0x73,0x3D,0x00,0x20,0x20,0x64,0x69,0x3D,0x00,
+0x20,0x20,0x73,0x69,0x3D,0x00,0x20,0x20,0x62,0x70,0x3D,0x00,0x20,0x20,0x73,0x70,
+0x3D,0x00,0x20,0x20,0x69,0x70,0x3D,0x00,0x20,0x63,0x68,0x61,0x6E,0x65,0x6C,0x3D,
+0x00,0x20,0x20,0x20,0x20,0x73,0x65,0x67,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74,
+0x72,0x3D,0x00,0x20,0x74,0x69,0x5F,0x74,0x6F,0x73,0x3D,0x00,0x20,0x74,0x69,0x5F,
+0x6D,0x61,0x78,0x3D,0x00,0x20,0x74,0x69,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74,
+0x69,0x5F,0x73,0x69,0x7A,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74,0x66,0x3D,0x00,
+0x20,0x74,0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x74,0x69,0x5F,0x66,0x6C,0x67,
+0x3D,0x00,0x20,0x74,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x70,
+0x63,0x6E,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x72,0x69,
+0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x72,0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,
+0x72,0x69,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x69,0x7A,0x3D,
+0x00,0x20,0x72,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x6D,0x69,
+0x6E,0x3D,0x00,0x20,0x72,0x69,0x5F,0x66,0x6C,0x67,0x3D,0x00,0x20,0x72,0x69,0x5F,
+0x74,0x6F,0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x74,0x68,0x72,0x3D,0x00,0x20,0x74,
+0x68,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x74,0x72,0x3D,0x00,
+0x20,0x74,0x68,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x69,0x7A,
+0x3D,0x00,0x20,0x74,0x68,0x5F,0x74,0x72,0x67,0x3D,0x00,0x20,0x74,0x68,0x5F,0x66,
+0x6C,0x67,0x3D,0x00,0x20,0x74,0x68,0x5F,0x63,0x6E,0x74,0x3D,0x00,0x20,0x72,0x68,
+0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,
+0x72,0x68,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x69,0x7A,0x3D,
+0x00,0x20,0x72,0x68,0x5F,0x73,0x70,0x61,0x3D,0x00,0x20,0x72,0x68,0x5F,0x61,0x73,
+0x6F,0x3D,0x00,0x20,0x72,0x68,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x72,0x68,0x5F,
+0x66,0x6C,0x67,0x3D,0x00,0x20,0x6D,0x5F,0x63,0x61,0x72,0x65,0x3D,0x00,0x20,0x70,
+0x74,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x61,0x73,0x5F,0x66,0x6C,0x6F,0x3D,0x00,
+0x20,0x72,0x6D,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x20,0x20,0x71,0x5F,0x69,0x6E,
+0x3D,0x00,0x20,0x20,0x71,0x5F,0x6F,0x75,0x74,0x3D,0x00,0x20,0x71,0x5F,0x64,0x72,
+0x61,0x6E,0x3D,0x00,0x20,0x20,0x71,0x5F,0x74,0x69,0x6D,0x3D,0x00,0x20,0x20,0x20,
+0x71,0x5F,0x66,0x63,0x3D,0x00,0x20,0x71,0x5F,0x73,0x74,0x61,0x74,0x3D,0x00,0x20,
+0x71,0x5F,0x64,0x61,0x74,0x61,0x3D,0x00,0x20,0x71,0x5F,0x6D,0x6F,0x64,0x6D,0x3D,
+0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x6F,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,
+0x62,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x65,0x3D,0x00,0x20,0x68,0x61,0x6E,
+0x64,0x5F,0x69,0x3D,0x00,0x20,0x20,0x6F,0x70,0x6F,0x73,0x74,0x3D,0x00,0x20,0x20,
+0x74,0x69,0x6D,0x65,0x6F,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x31,0x3D,0x00,
+0x20,0x63,0x75,0x73,0x74,0x6D,0x32,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x64,
+0x3D,0x00,0x20,0x74,0x78,0x72,0x61,0x74,0x65,0x3D,0x00,0x20,0x72,0x78,0x72,0x61,
+0x74,0x65,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x61,0x70,0x3D,0x00,0x20,0x63,0x5F,
+0x61,0x64,0x64,0x72,0x3D,0x00,0x20,0x63,0x5F,0x61,0x69,0x73,0x72,0x3D,0x00,0x20,
+0x63,0x5F,0x78,0x74,0x61,0x67,0x3D,0x00,0x20,0x63,0x5F,0x64,0x65,0x66,0x72,0x3D,
+0x00,0x20,0x63,0x5F,0x66,0x6C,0x73,0x68,0x3D,0x00,0x20,0x74,0x78,0x6D,0x61,0x78,
+0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x65,0x6D,0x73,0x3D,0x00,0x20,0x20,0x63,0x5F,
+0x6C,0x73,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x65,0x72,0x3D,0x00,0x20,0x20,
+0x63,0x5F,0x66,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x63,0x72,0x3D,0x00,
+0x20,0x20,0x63,0x5F,0x6C,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x64,0x73,0x73,
+0x3D,0x00,0x20,0x63,0x5F,0x64,0x73,0x73,0x69,0x3D,0x00,0x20,0x63,0x5F,0x64,0x73,
+0x73,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x73,0x72,0x3D,0x00,0x20,0x20,0x63,
+0x5F,0x63,0x61,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x65,0x66,0x72,0x3D,0x00,0x20,
+0x63,0x5F,0x65,0x72,0x73,0x74,0x3D,0x00,0x20,0x63,0x5F,0x65,0x63,0x6E,0x74,0x3D,
+0x00,0x20,0x63,0x5F,0x62,0x72,0x6B,0x63,0x3D,0x00,0x20,0x63,0x5F,0x62,0x6F,0x6B,
+0x63,0x3D,0x00,0x20,0x63,0x5F,0x72,0x65,0x70,0x6C,0x3D,0x00,0x20,0x63,0x5F,0x63,
+0x63,0x73,0x72,0x3D,0x00,0x20,0x63,0x5F,0x73,0x74,0x74,0x31,0x3D,0x00,0x20,0x63,
+0x5F,0x73,0x74,0x74,0x32,0x3D,0x00,0x2B,0xC0,0x8E,0xD8,0x8E,0xC0,0xE8,0xC2,0x00,
+0xE8,0xE5,0x00,0xFA,0xBF,0x84,0x00,0xC7,0x05,0xBE,0x56,0x8C,0x4D,0x02,0xBF,0x0C,
+0x00,0xC7,0x05,0x50,0x5E,0x8C,0x4D,0x02,0xBF,0x04,0x00,0xC7,0x05,0x9C,0x5E,0x8C,
+0x4D,0x02,0xE8,0xF1,0x00,0x90,0xE8,0x49,0x01,0xE8,0x16,0x00,0xF4,0x90,0xE8,0xE5,
+0x00,0xBE,0x9C,0x4D,0xE8,0x09,0x0C,0xA0,0x93,0x12,0xE8,0x5D,0x0C,0xE8,0xC2,0x09,
+0xEB,0xE4,0xE8,0xD5,0x0C,0xE8,0xC4,0x0C,0x0A,0xC0,0x74,0xF6,0x8B,0x1E,0xF8,0x79,
+0x3C,0x0D,0x74,0x2E,0x3C,0x08,0x74,0x17,0x3C,0x7F,0x74,0x13,0x83,0xFB,0x20,0x7F,
+0xE1,0x88,0x87,0xD6,0x79,0x43,0x89,0x1E,0xF8,0x79,0xE8,0x77,0x0C,0xEB,0xD3,0x0B,
+0xDB,0x74,0xCF,0x4B,0x89,0x1E,0xF8,0x79,0x8B,0x36,0x16,0x7A,0xE8,0xC1,0x0B,0xEB,
+0xC1,0x90,0xE8,0x02,0x00,0xEB,0xBB,0xC6,0x87,0xD6,0x79,0x00,0x0B,0xDB,0x74,0x1E,
+0xA0,0xD6,0x79,0xBF,0x42,0x51,0xB9,0x1D,0x00,0x8B,0xD9,0x06,0x0E,0x07,0xF2,0xAE,
+0x07,0x75,0x17,0x41,0x2B,0xD9,0xD1,0xE3,0x2E,0xFF,0x97,0x5F,0x51,0x90,0x33,0xC0,
+0xA3,0xF8,0x79,0xBE,0x6B,0x4D,0xE8,0x87,0x0B,0xC3,0xBE,0x6F,0x4D,0xE8,0x80,0x0B,
+0xEB,0xEC,0xBA,0x00,0x02,0xB0,0x93,0xEE,0xB0,0x55,0xEE,0xBA,0x10,0x02,0xB0,0x93,
+0xEE,0xB0,0xAA,0xEE,0xBA,0x00,0x02,0xEC,0x3C,0x55,0x75,0x08,0xBA,0x10,0x02,0xEC,
+0x3C,0xAA,0x74,0x03,0xE8,0x2F,0xF6,0xC3,0xBA,0x04,0x02,0xB0,0x1A,0xEE,0xB0,0x20,
+0xEE,0xB0,0x30,0xEE,0xB0,0x40,0xEE,0xB0,0x80,0xEE,0xBA,0x00,0x02,0xB0,0x13,0xEE,
+0xB0,0x07,0xEE,0xBA,0x08,0x02,0xB0,0x80,0xEE,0xBA,0x02,0x02,0xB0,0xBB,0xEE,0xBA,
+0x04,0x02,0xB0,0x05,0xEE,0xC3,0xC6,0x06,0xCA,0x13,0x01,0xC7,0x06,0xF8,0x79,0x00,
+0x00,0xC6,0x06,0xF6,0x79,0x01,0xC7,0x06,0xD0,0x79,0x00,0x00,0xC7,0x06,0xD2,0x79,
+0x00,0x00,0xC7,0x06,0xD4,0x79,0x00,0x00,0xC7,0x06,0xFA,0x79,0x00,0x00,0xC7,0x06,
+0xFC,0x79,0x00,0x00,0xC7,0x06,0xFE,0x79,0x00,0x00,0xC7,0x06,0x00,0x7A,0x00,0x00,
+0xC7,0x06,0x02,0x7A,0xB0,0x59,0x8C,0x0E,0x04,0x7A,0xC7,0x06,0x06,0x7A,0x00,0x00,
+0xC7,0x06,0x27,0x7A,0x00,0x00,0xC6,0x06,0x29,0x7A,0x00,0xC6,0x06,0x2A,0x7A,0x00,
+0xC3,0x90,0xBE,0x04,0x4D,0xE8,0xC8,0x0A,0xE8,0x3F,0x00,0x2C,0x31,0x3C,0x01,0x77,
+0xF7,0xE8,0x81,0x09,0x8B,0x36,0x0C,0x7A,0xE8,0xB5,0x0A,0xBE,0x4C,0x4D,0xE8,0xAF,
+0x0A,0x0E,0x58,0xE8,0xF8,0x0A,0xBE,0x5C,0x4D,0xE8,0xA4,0x0A,0xC3,0x90,0x60,0xD1,
+0xE3,0x83,0xFB,0x18,0x73,0x11,0x1E,0xBA,0x00,0x00,0x8E,0xDA,0x2E,0xFF,0x97,0x99,
+0x51,0x8B,0xEC,0x89,0x46,0x10,0x1F,0x61,0xCF,0x90,0xE8,0x4F,0x0B,0x0A,0xC0,0x75,
+0x05,0xE8,0x56,0x0B,0xEB,0xF4,0xC3,0x90,0x83,0x3E,0xF8,0x79,0x01,0x74,0x16,0xBE,
+0xD7,0x79,0xE8,0x31,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x04,0x3C,0x20,0x75,0x05,
+0xE8,0x23,0x0A,0xEE,0xC3,0xE9,0xD2,0xFE,0x83,0x3E,0xF8,0x79,0x01,0x74,0xF6,0xBE,
+0xD7,0x79,0xE8,0x11,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x08,0x3C,0x20,0x74,0x04,
+0xE9,0xB7,0xFE,0x90,0xE8,0xFF,0x09,0xEF,0xC3,0x90,0x8B,0x16,0x06,0x7A,0x83,0x3E,
+0xF8,0x79,0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xEB,0x09,0x8B,0xD0,0xA3,0x06,0x7A,
+0xB0,0x20,0xE8,0x57,0x0B,0x8B,0x16,0x06,0x7A,0xEC,0xE8,0x6F,0x0B,0xC3,0x8B,0x16,
+0x06,0x7A,0x83,0x3E,0xF8,0x79,0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xC7,0x09,0x8B,
+0xD0,0xA3,0x06,0x7A,0xB0,0x20,0xE8,0x33,0x0B,0x8B,0x16,0x06,0x7A,0xED,0xE8,0x67,
+0x0B,0xC3,0xFA,0xC6,0x06,0xF6,0x79,0x00,0xC3,0x90,0xC6,0x06,0xF6,0x79,0x01,0xFB,
+0xC3,0x90,0x06,0xE8,0x58,0x09,0xB0,0x20,0xE8,0x11,0x0B,0x26,0x8B,0x05,0xE8,0x47,
+0x0B,0xB0,0x08,0xE8,0x06,0x0B,0xE8,0x03,0x0B,0xE8,0x00,0x0B,0xE8,0xFD,0x0A,0xB8,
+0x01,0x00,0xE8,0xCF,0xF4,0xBA,0x02,0x02,0xEC,0x24,0x01,0x75,0x02,0xEB,0xDC,0xBA,
+0x06,0x02,0xEC,0x07,0xC3,0x90,0xC7,0x06,0x08,0x7A,0x10,0x00,0xEB,0x06,0xC7,0x06,
+0x08,0x7A,0x01,0x00,0x06,0x8E,0x06,0xFC,0x79,0x8B,0x3E,0xFA,0x79,0xE8,0x0E,0x09,
+0xE8,0x0B,0x00,0x89,0x3E,0xFA,0x79,0x8C,0x06,0xFC,0x79,0x07,0xC3,0x90,0xBE,0x94,
+0x4D,0xE8,0x7C,0x09,0x8B,0x16,0x08,0x7A,0x52,0xE8,0x2A,0x09,0xE8,0x0F,0x0A,0xE8,
+0x0C,0x0A,0x33,0xDB,0xB9,0x10,0x00,0x90,0x26,0x8A,0x01,0xE8,0xBC,0x09,0xE8,0xFD,
+0x09,0x43,0xE2,0xF4,0xE8,0xF7,0x09,0xE8,0xF4,0x09,0x33,0xDB,0xB9,0x10,0x00,0x90,
+0x26,0x8A,0x01,0x3C,0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xE3,
+0x09,0x43,0xE2,0xEC,0xBE,0x94,0x4D,0xE8,0x36,0x09,0x83,0xC7,0x10,0x5A,0x4A,0x75,
+0xB7,0xC3,0x06,0x8E,0x06,0x00,0x7A,0x8B,0x3E,0xFE,0x79,0xE8,0xA0,0x08,0x89,0x3E,
+0xFE,0x79,0x8C,0x06,0x00,0x7A,0x57,0x8B,0x36,0x0E,0x7A,0xE8,0x12,0x09,0xC7,0x06,
+0x08,0x7A,0x10,0x00,0xBA,0x00,0x02,0xE8,0xE8,0x00,0xE8,0x81,0xFF,0x5F,0xBA,0x00,
+0x00,0xE8,0xDE,0x00,0xBE,0x97,0x4D,0xE8,0xF6,0x08,0x8C,0xC0,0xE8,0x3F,0x09,0xB0,
+0x3A,0xE8,0x90,0x09,0x8B,0xC7,0xE8,0x35,0x09,0xE8,0x7E,0x08,0xE8,0xC3,0x00,0x90,
+0xE8,0xB7,0x09,0xE8,0xA6,0x09,0x0A,0xC0,0x74,0xF6,0x3C,0x0B,0x75,0x06,0x83,0xEF,
+0x10,0xEB,0x19,0x90,0x3C,0x0A,0x75,0x06,0x83,0xC7,0x10,0xEB,0x0F,0x90,0x3C,0x0C,
+0x75,0x04,0x47,0xEB,0x07,0x90,0x3C,0x08,0x75,0x24,0x4F,0x90,0x8B,0x36,0xFE,0x79,
+0x8B,0xC7,0x2B,0xC6,0x3D,0x00,0x01,0x72,0xA5,0x3D,0x10,0x01,0x72,0x04,0x83,0xEE,
+0x20,0x90,0x83,0xC6,0x10,0x89,0x36,0xFE,0x79,0x57,0x8B,0xFE,0xEB,0x80,0x3C,0x2E,
+0x75,0x08,0xBA,0x01,0x13,0xE8,0x6A,0x00,0x07,0xC3,0xC6,0x06,0x0A,0x7A,0x02,0x32,
+0xC9,0x90,0x3C,0x30,0x72,0x4C,0x3C,0x39,0x76,0x0C,0x24,0x5F,0x3C,0x41,0x72,0x42,
+0x3C,0x46,0x77,0x3E,0x2C,0x07,0x2C,0x30,0x50,0xE8,0xCC,0x08,0x58,0x02,0xC8,0xFE,
+0x0E,0x0A,0x7A,0x74,0x0F,0xC0,0xE1,0x04,0xE8,0x2F,0x09,0xE8,0x1E,0x09,0x0A,0xC0,
+0x74,0xF6,0xEB,0xCE,0x26,0x88,0x0D,0xE8,0xE0,0x07,0x8A,0xD0,0xE8,0x23,0x00,0x8A,
+0xC1,0x3C,0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xD5,0x08,0xE9,
+0x70,0xFF,0xE8,0xC5,0x07,0xE8,0x0A,0x00,0x26,0x8A,0x05,0xE8,0x7C,0x08,0xE9,0x1D,
+0xFF,0x90,0xF6,0x06,0x26,0x7A,0x02,0x75,0x02,0x86,0xF2,0x52,0x8B,0x36,0x1A,0x7A,
+0xE8,0x0D,0x08,0x5A,0x52,0x8A,0xC6,0x02,0x06,0x24,0x7A,0xF6,0x06,0x26,0x7A,0x01,
+0x75,0x06,0xE8,0x9F,0x08,0xEB,0x0D,0x90,0x32,0xE4,0xE8,0x0D,0x08,0x8B,0x36,0x1C,
+0x7A,0xE8,0xEC,0x07,0x5A,0x8A,0xC2,0x02,0x06,0x25,0x7A,0xF6,0x06,0x26,0x7A,0x01,
+0x75,0x06,0xE8,0x7F,0x08,0xEB,0x06,0x90,0x32,0xE4,0xE8,0xED,0x07,0x8B,0x36,0x1E,
+0x7A,0xE8,0xCC,0x07,0xC3,0x90,0x06,0x8E,0x06,0x04,0x7A,0x8B,0x3E,0x02,0x7A,0xE8,
+0x3C,0x07,0x89,0x3E,0x02,0x7A,0x8C,0x06,0x04,0x7A,0x07,0xFF,0x1E,0x02,0x7A,0xC3,
+0xBE,0x79,0x4D,0xE8,0xAA,0x07,0xCB,0x90,0x06,0x57,0xBE,0xD7,0x79,0xE8,0x66,0x07,
+0x8B,0xD8,0xE8,0x61,0x07,0x8B,0xC8,0x2B,0xCB,0x78,0x11,0x8E,0xC3,0xBF,0x00,0x00,
+0xB8,0xFF,0xFF,0x51,0xB9,0x08,0x00,0xF3,0xAB,0x59,0xE2,0xF7,0x5F,0x07,0xC3,0x90,
+0x06,0xBE,0xD7,0x79,0xE8,0x3F,0x07,0x8B,0xD8,0xD1,0xE3,0x2E,0x8B,0x9F,0x44,0x00,
+0xBE,0x08,0x52,0xE8,0xF1,0x08,0x8B,0xC3,0xE8,0xDD,0x08,0xB8,0x01,0x00,0xE8,0x73,
+0xF2,0xE8,0xE0,0x08,0xBE,0x11,0x52,0xE8,0xDD,0x08,0x8B,0x47,0x18,0xE8,0xC8,0x08,
+0xBE,0x59,0x52,0xE8,0xD1,0x08,0x8B,0x47,0x26,0xE8,0xBC,0x08,0xBE,0x35,0x52,0xE8,
+0xC5,0x08,0x8B,0x47,0x1E,0xE8,0xB0,0x08,0xBE,0x3E,0x52,0xE8,0xB9,0x08,0x8B,0x47,
+0x20,0xE8,0xA4,0x08,0xBE,0x50,0x52,0xE8,0xAD,0x08,0x8B,0x47,0x24,0xE8,0x98,0x08,
+0xBE,0x62,0x52,0xE8,0xA1,0x08,0x8B,0x47,0x2A,0xE8,0x8C,0x08,0xE8,0x95,0x08,0xBE,
+0x1A,0x52,0xE8,0x92,0x08,0x8B,0x07,0xE8,0x7E,0x08,0xBE,0x23,0x52,0xE8,0x87,0x08,
+0x8B,0x47,0x1A,0xE8,0x72,0x08,0xBE,0x2C,0x52,0xE8,0x7B,0x08,0x8B,0x47,0x1C,0xE8,
+0x66,0x08,0xBE,0x47,0x52,0xE8,0x6F,0x08,0x8B,0x47,0x22,0xE8,0x5A,0x08,0xE8,0x63,
+0x08,0xBE,0xB3,0x52,0xE8,0x60,0x08,0x8B,0x47,0x38,0xE8,0x4B,0x08,0xBE,0x8F,0x52,
+0xE8,0x54,0x08,0x8B,0x47,0x30,0xE8,0x3F,0x08,0xBE,0x98,0x52,0xE8,0x48,0x08,0x8B,
+0x47,0x32,0xE8,0x33,0x08,0xBE,0x86,0x52,0xE8,0x3C,0x08,0x8B,0x47,0x2E,0xE8,0x27,
+0x08,0xBE,0xA1,0x52,0xE8,0x30,0x08,0x8B,0x47,0x34,0xE8,0x1B,0x08,0xE8,0x24,0x08,
+0xBE,0x6B,0x52,0xE8,0x21,0x08,0x8B,0x47,0x04,0xE8,0x0C,0x08,0xBE,0x74,0x52,0xE8,
+0x15,0x08,0x8B,0x47,0x14,0xE8,0x00,0x08,0xBE,0x7D,0x52,0xE8,0x09,0x08,0x8B,0x47,
+0x2C,0xE8,0xF4,0x07,0xBE,0xAA,0x52,0xE8,0xFD,0x07,0x8B,0x47,0x36,0xE8,0xE8,0x07,
+0xBE,0xBC,0x52,0xE8,0xF1,0x07,0x8B,0x47,0x3A,0xE8,0xDC,0x07,0xBE,0xC5,0x52,0xE8,
+0xE5,0x07,0x8B,0x47,0x3C,0xE8,0xD0,0x07,0xE8,0xD9,0x07,0xBE,0xFB,0x52,0xE8,0xD6,
+0x07,0x8B,0x47,0x48,0xE8,0xC1,0x07,0xBE,0xE0,0x52,0xE8,0xCA,0x07,0x8B,0x47,0x42,
+0xE8,0xB5,0x07,0xBE,0xE9,0x52,0xE8,0xBE,0x07,0x8B,0x47,0x44,0xE8,0xA9,0x07,0xBE,
+0x5E,0x53,0xE8,0xB2,0x07,0x8B,0x47,0x4C,0xE8,0x9D,0x07,0xBE,0x67,0x53,0xE8,0xA6,
+0x07,0x8B,0x47,0x4E,0xE8,0x91,0x07,0xBE,0x70,0x53,0xE8,0x9A,0x07,0x8B,0x47,0x50,
+0xE8,0x85,0x07,0xE8,0x8E,0x07,0xBE,0x04,0x53,0xE8,0x8B,0x07,0x8B,0x47,0x4A,0xE8,
+0x76,0x07,0xBE,0xCE,0x52,0xE8,0x7F,0x07,0x8B,0x47,0x08,0xE8,0x6A,0x07,0xBE,0xD7,
+0x52,0xE8,0x73,0x07,0x8B,0x47,0x40,0xE8,0x5E,0x07,0xBE,0xF2,0x52,0xE8,0x67,0x07,
+0x8B,0x47,0x46,0xE8,0x52,0x07,0xE8,0x5B,0x07,0xBE,0x4C,0x53,0xE8,0x58,0x07,0x8B,
+0x47,0x7A,0xE8,0x43,0x07,0xBE,0x1F,0x53,0xE8,0x4C,0x07,0x8B,0x47,0x70,0xE8,0x37,
+0x07,0xBE,0x28,0x53,0xE8,0x40,0x07,0x8B,0x47,0x72,0xE8,0x2B,0x07,0xBE,0x31,0x53,
+0xE8,0x34,0x07,0x8B,0x47,0x74,0xE8,0x1F,0x07,0xE8,0x28,0x07,0xBE,0x0D,0x53,0xE8,
+0x25,0x07,0x8B,0x47,0x0C,0xE8,0x10,0x07,0xBE,0x16,0x53,0xE8,0x19,0x07,0x8B,0x47,
+0x10,0xE8,0x04,0x07,0xBE,0x3A,0x53,0xE8,0x0D,0x07,0x8B,0x47,0x76,0xE8,0xF8,0x06,
+0xBE,0x43,0x53,0xE8,0x01,0x07,0x8B,0x47,0x78,0xE8,0xEC,0x06,0xBE,0x55,0x53,0xE8,
+0xF5,0x06,0x8B,0x47,0x3E,0xE8,0xE0,0x06,0xE8,0xE9,0x06,0xBE,0x79,0x53,0xE8,0xE6,
+0x06,0x8B,0x47,0x52,0xE8,0xD1,0x06,0xBE,0x82,0x53,0xE8,0xDA,0x06,0x8B,0x47,0x54,
+0xE8,0xC5,0x06,0xBE,0x8B,0x53,0xE8,0xCE,0x06,0x8B,0x47,0x56,0xE8,0xB9,0x06,0xBE,
+0x94,0x53,0xE8,0xC2,0x06,0x8B,0x47,0x58,0xE8,0xAD,0x06,0xBE,0x9D,0x53,0xE8,0xB6,
+0x06,0x8B,0x47,0x5A,0xE8,0xA1,0x06,0xBE,0xA6,0x53,0xE8,0xAA,0x06,0x8B,0x47,0x5C,
+0xE8,0x95,0x06,0xE8,0x9E,0x06,0xBE,0xAF,0x53,0xE8,0x9B,0x06,0x8B,0x47,0x5E,0xE8,
+0x86,0x06,0xBE,0xB8,0x53,0xE8,0x8F,0x06,0x8B,0x47,0x60,0xE8,0x7A,0x06,0xBE,0xC1,
+0x53,0xE8,0x83,0x06,0x8B,0x47,0x62,0xE8,0x6E,0x06,0xBE,0xCA,0x53,0xE8,0x77,0x06,
+0x8B,0x47,0x7C,0xE8,0x62,0x06,0xBE,0xD3,0x53,0xE8,0x6B,0x06,0x8B,0x47,0x7E,0xE8,
+0x56,0x06,0xBE,0xDC,0x53,0xE8,0x5F,0x06,0x8B,0x87,0x80,0x00,0xE8,0x49,0x06,0xE8,
+0x52,0x06,0xBE,0x24,0x54,0xE8,0x4F,0x06,0x8B,0x87,0x9E,0x00,0xE8,0x39,0x06,0xBE,
+0xE5,0x53,0xE8,0x42,0x06,0x8B,0x47,0x64,0xE8,0x2D,0x06,0xBE,0xEE,0x53,0xE8,0x36,
+0x06,0x8B,0x47,0x6E,0xE8,0x21,0x06,0xBE,0xF7,0x53,0xE8,0x2A,0x06,0x8B,0x87,0x8E,
+0x00,0xE8,0x14,0x06,0xBE,0x00,0x54,0xE8,0x1D,0x06,0x8B,0x87,0x90,0x00,0xE8,0x07,
+0x06,0xBE,0x09,0x54,0xE8,0x10,0x06,0x8B,0x87,0x92,0x00,0xE8,0xFA,0x05,0xE8,0x03,
+0x06,0xBE,0x12,0x54,0xE8,0x00,0x06,0x8B,0x87,0x94,0x00,0xE8,0xEA,0x05,0xBE,0x1B,
+0x54,0xE8,0xF3,0x05,0x8B,0x87,0x96,0x00,0xE8,0xDD,0x05,0xBE,0x51,0x54,0xE8,0xE6,
+0x05,0x8B,0x87,0x98,0x00,0xE8,0xD0,0x05,0xBE,0x3F,0x54,0xE8,0xD9,0x05,0x8A,0x87,
+0xA0,0x00,0xE8,0xA7,0x05,0xBE,0x36,0x54,0xE8,0xCC,0x05,0x8A,0x47,0x28,0xE8,0x9B,
+0x05,0xBE,0x48,0x54,0xE8,0xC0,0x05,0x8A,0x87,0xA1,0x00,0xE8,0x8E,0x05,0xE8,0xB3,
+0x05,0xBE,0x5A,0x54,0xE8,0xB0,0x05,0x8A,0x87,0xA2,0x00,0xE8,0x7E,0x05,0xBE,0x63,
+0x54,0xE8,0xA3,0x05,0x8A,0x87,0xA3,0x00,0xE8,0x71,0x05,0xBE,0x6C,0x54,0xE8,0x96,
+0x05,0x8A,0x87,0xA4,0x00,0xE8,0x64,0x05,0xBE,0x75,0x54,0xE8,0x89,0x05,0x8A,0x87,
+0xA5,0x00,0xE8,0x57,0x05,0xBE,0x7E,0x54,0xE8,0x7C,0x05,0x8A,0x87,0xA6,0x00,0xE8,
+0x4A,0x05,0xBE,0x87,0x54,0xE8,0x6F,0x05,0x8A,0x87,0xA7,0x00,0xE8,0x3D,0x05,0xBE,
+0x90,0x54,0xE8,0x62,0x05,0x8A,0x87,0xA8,0x00,0xE8,0x30,0x05,0xE8,0x55,0x05,0xBE,
+0x99,0x54,0xE8,0x52,0x05,0x8A,0x87,0xA9,0x00,0xE8,0x20,0x05,0xBE,0xA2,0x54,0xE8,
+0x45,0x05,0x8A,0x87,0xAA,0x00,0xE8,0x13,0x05,0xBE,0xAB,0x54,0xE8,0x38,0x05,0x8A,
+0x87,0xAB,0x00,0xE8,0x06,0x05,0xBE,0xB4,0x54,0xE8,0x2B,0x05,0x8A,0x87,0xAD,0x00,
+0xE8,0xF9,0x04,0xBE,0xBD,0x54,0xE8,0x1E,0x05,0x8A,0x87,0xAE,0x00,0xE8,0xEC,0x04,
+0xBE,0xC6,0x54,0xE8,0x11,0x05,0x8A,0x87,0xAF,0x00,0xE8,0xDF,0x04,0xBE,0xCF,0x54,
+0xE8,0x04,0x05,0x8A,0x87,0xB0,0x00,0xE8,0xD2,0x04,0xE8,0xF7,0x04,0xBE,0xD8,0x54,
+0xE8,0xF4,0x04,0x8A,0x87,0xB1,0x00,0xE8,0xC2,0x04,0xBE,0xE1,0x54,0xE8,0xE7,0x04,
+0x8A,0x87,0xB2,0x00,0xE8,0xB5,0x04,0xBE,0xEA,0x54,0xE8,0xDA,0x04,0x8A,0x87,0xB3,
+0x00,0xE8,0xA8,0x04,0xBE,0xF3,0x54,0xE8,0xCD,0x04,0x8A,0x87,0xBB,0x00,0xE8,0x9B,
+0x04,0xE8,0xC0,0x04,0xBE,0xFC,0x54,0xE8,0xBD,0x04,0x8A,0x87,0xBC,0x00,0xE8,0x8B,
+0x04,0xBE,0x05,0x55,0xE8,0xB0,0x04,0x8A,0x87,0xBE,0x00,0xE8,0x7E,0x04,0xBE,0x0E,
+0x55,0xE8,0xA3,0x04,0x8A,0x87,0xBF,0x00,0xE8,0x71,0x04,0xE8,0x96,0x04,0x07,0xC3,
+0x60,0x06,0x1E,0x16,0x8B,0xEC,0xFF,0x4E,0x16,0xF7,0x46,0x1A,0x00,0x02,0x74,0x01,
+0xFB,0xB8,0x00,0x00,0x8E,0xD8,0x8E,0xC0,0x89,0x2E,0x2D,0x7A,0xE8,0xCB,0x00,0x81,
+0x66,0x1A,0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8,0xD8,0x00,0xB8,0xE2,0x5E,0xA3,
+0x2B,0x7A,0xE8,0x5D,0x00,0x80,0x3E,0x2A,0x7A,0x00,0x74,0x0A,0x81,0x4E,0x1A,0x00,
+0x01,0xC6,0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61,0xCF,0x90,0x60,0x06,0x1E,0x16,
+0x8B,0xEC,0xF7,0x46,0x1A,0x00,0x02,0x74,0x01,0xFB,0xB8,0x00,0x00,0x8E,0xD8,0x8E,
+0xC0,0x89,0x2E,0x2D,0x7A,0x81,0x66,0x1A,0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8,
+0x92,0x00,0xB8,0xE2,0x5E,0xA3,0x2B,0x7A,0xE8,0x17,0x00,0x80,0x3E,0x2A,0x7A,0x00,
+0x74,0x0A,0x81,0x4E,0x1A,0x00,0x01,0xC6,0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61,
+0xCF,0x90,0xB8,0xF0,0x00,0xE8,0x8C,0xED,0xFF,0x26,0x2B,0x7A,0xC3,0x90,0x06,0x53,
+0x56,0x80,0x3E,0x29,0x7A,0x00,0x74,0x03,0xE8,0x3F,0x00,0xBE,0xD7,0x79,0xE8,0x25,
+0x02,0x8B,0xD8,0xA3,0x27,0x7A,0x2E,0x8A,0x07,0xA2,0x29,0x7A,0xB0,0xCC,0x2E,0x88,
+0x07,0x5E,0x5B,0x07,0xC3,0xC6,0x06,0x2A,0x7A,0x00,0xB8,0xEC,0x5E,0xA3,0x2B,0x7A,
+0xC3,0x90,0x8B,0x2E,0x2D,0x7A,0xE8,0x2B,0x00,0xC3,0xC6,0x06,0x2A,0x7A,0x01,0xE8,
+0x08,0x00,0xB8,0xEC,0x5E,0xA3,0x2B,0x7A,0xC3,0x90,0x57,0x80,0x3E,0x29,0x7A,0x00,
+0x74,0x0F,0x8B,0x3E,0x27,0x7A,0xA0,0x29,0x7A,0x2E,0x88,0x05,0xC6,0x06,0x29,0x7A,
+0x00,0x5F,0xC3,0x90,0xBE,0x94,0x4D,0xE8,0x06,0x02,0xBE,0xBA,0x51,0xE8,0x00,0x02,
+0xFF,0x76,0x14,0x58,0xE8,0x47,0x02,0xBE,0xC0,0x51,0xE8,0xF3,0x01,0xFF,0x76,0x0E,
+0x58,0xE8,0x3A,0x02,0xBE,0xC6,0x51,0xE8,0xE6,0x01,0xFF,0x76,0x12,0x58,0xE8,0x2D,
+0x02,0xBE,0xCC,0x51,0xE8,0xD9,0x01,0xFF,0x76,0x10,0x58,0xE8,0x20,0x02,0xBE,0xF6,
+0x51,0xE8,0xCC,0x01,0xFF,0x76,0x0A,0x58,0xE8,0x13,0x02,0xBE,0xFC,0x51,0xE8,0xBF,
+0x01,0xFF,0x76,0x0C,0x58,0xE8,0x06,0x02,0xBE,0xB1,0x51,0xE8,0xB2,0x01,0xFF,0x76,
+0x1A,0x58,0xE8,0xF9,0x01,0xBE,0x94,0x4D,0xE8,0xA5,0x01,0xBE,0xD2,0x51,0xE8,0x9F,
+0x01,0xFF,0x76,0x18,0x58,0xE8,0xE6,0x01,0xBE,0xD8,0x51,0xE8,0x92,0x01,0xFF,0x76,
+0x02,0x58,0xE8,0xD9,0x01,0xBE,0xDE,0x51,0xE8,0x85,0x01,0xFF,0x76,0x04,0x58,0xE8,
+0xCC,0x01,0xBE,0xE4,0x51,0xE8,0x78,0x01,0xFF,0x76,0x00,0x58,0xE8,0xBF,0x01,0xBE,
+0xEA,0x51,0xE8,0x6B,0x01,0xFF,0x76,0x06,0x58,0xE8,0xB2,0x01,0xBE,0xF0,0x51,0xE8,
+0x5E,0x01,0xFF,0x76,0x08,0x58,0xE8,0xA5,0x01,0xBE,0x02,0x52,0xE8,0x51,0x01,0xFF,
+0x76,0x16,0x58,0xE8,0x98,0x01,0xBE,0x6B,0x4D,0xE8,0x44,0x01,0xC3,0x90,0xBE,0xAB,
+0x4D,0xE8,0x3C,0x01,0xC3,0x3C,0x00,0x74,0x05,0x3C,0x01,0x74,0x59,0xC3,0xC7,0x06,
+0x0C,0x7A,0xAF,0x50,0xC7,0x06,0x0E,0x7A,0xD2,0x50,0xC7,0x06,0x10,0x7A,0xCA,0x50,
+0xC7,0x06,0x12,0x7A,0xCE,0x50,0xC7,0x06,0x14,0x7A,0xD6,0x50,0xC7,0x06,0x16,0x7A,
+0xDD,0x50,0xC7,0x06,0x18,0x7A,0xE5,0x50,0xC7,0x06,0x1A,0x7A,0xED,0x50,0xC7,0x06,
+0x1C,0x7A,0xF0,0x50,0xC7,0x06,0x1E,0x7A,0xF2,0x50,0xC7,0x06,0x20,0x7A,0xF4,0x50,
+0xC7,0x06,0x22,0x7A,0xF8,0x50,0xC6,0x06,0x24,0x7A,0x01,0xC6,0x06,0x25,0x7A,0x01,
+0xC6,0x06,0x26,0x7A,0x03,0xC3,0xC7,0x06,0x0C,0x7A,0xFC,0x50,0xC7,0x06,0x0E,0x7A,
+0x2F,0x51,0xC7,0x06,0x10,0x7A,0x29,0x51,0xC7,0x06,0x12,0x7A,0x2C,0x51,0xC7,0x06,
+0x14,0x7A,0x31,0x51,0xC7,0x06,0x16,0x7A,0x33,0x51,0xC7,0x06,0x18,0x7A,0x37,0x51,
+0xC7,0x06,0x1A,0x7A,0x38,0x51,0xC7,0x06,0x1C,0x7A,0x3B,0x51,0xC7,0x06,0x1E,0x7A,
+0x3C,0x51,0xC7,0x06,0x20,0x7A,0x3D,0x51,0xC7,0x06,0x22,0x7A,0x40,0x51,0xC6,0x06,
+0x24,0x7A,0x20,0xC6,0x06,0x25,0x7A,0x20,0xC6,0x06,0x26,0x7A,0x02,0xC3,0xA1,0xF8,
+0x79,0x48,0x74,0x14,0xBE,0xD7,0x79,0xE8,0x3C,0x00,0x8B,0xF8,0xAC,0x3C,0x3A,0x75,
+0x07,0x8E,0xC7,0xE8,0x30,0x00,0x8B,0xF8,0xC3,0x90,0x8B,0xC7,0x2B,0x06,0xFE,0x79,
+0x8A,0xF0,0x24,0x0F,0x8A,0xD0,0x02,0xD0,0x02,0xD0,0x80,0xC2,0x0B,0xC0,0xEE,0x04,
+0x80,0xC6,0x03,0x04,0x3D,0xC3,0x8C,0xC0,0xE8,0x93,0x00,0xB0,0x3A,0xE8,0xE4,0x00,
+0x8B,0xC7,0xE8,0x89,0x00,0xC3,0x51,0x33,0xC9,0x90,0xAC,0x3C,0x20,0x74,0xFB,0x90,
+0x0A,0xC0,0x74,0x26,0x2C,0x30,0x72,0x22,0x3C,0x09,0x76,0x14,0x3C,0x11,0x72,0x1A,
+0x2C,0x07,0x3C,0x0F,0x76,0x0A,0x3C,0x2A,0x72,0x10,0x2C,0x20,0x3C,0x0F,0x77,0x0A,
+0x98,0xC1,0xE1,0x04,0x03,0xC8,0xAC,0xEB,0xD7,0x90,0x4E,0x8B,0xC1,0x59,0xC3,0x90,
+0x06,0x8C,0xC8,0x8E,0xC0,0xE8,0x02,0x00,0x07,0xC3,0x26,0x8A,0x04,0x46,0x0A,0xC0,
+0x74,0x06,0xE8,0x8F,0x00,0xEB,0xF3,0x90,0xC3,0x90,0x0B,0xC0,0x74,0x7A,0x51,0x33,
+0xD2,0xB9,0xE8,0x03,0xF7,0xF1,0x8B,0xCA,0xE8,0x03,0x00,0x8B,0xC1,0x59,0xBA,0x64,
+0x00,0xF6,0xF2,0xE8,0x0C,0x00,0x8A,0xC4,0x98,0xB2,0x0A,0xF6,0xF2,0xE8,0x02,0x00,
+0x8A,0xC4,0x50,0x0A,0xF0,0x74,0x05,0x04,0x30,0xE8,0x58,0x00,0x58,0xC3,0x86,0xC4,
+0xE8,0x07,0x00,0x86,0xC4,0xE8,0x02,0x00,0xC3,0x90,0xC1,0xC8,0x04,0xE8,0x08,0x00,
+0xC1,0xC0,0x04,0xE8,0x02,0x00,0xC3,0x90,0x53,0x50,0x24,0x0F,0xBB,0xAC,0x62,0x2E,
+0xD7,0xE8,0x30,0x00,0x58,0x5B,0xC3,0x90,0x86,0xC4,0xE8,0x07,0x00,0x86,0xC4,0xE8,
+0x02,0x00,0xC3,0x90,0x50,0xB9,0x08,0x00,0x8A,0xE0,0x32,0xC0,0xD1,0xC0,0x04,0x30,
+0xE8,0x11,0x00,0xE2,0xF5,0x58,0xC3,0x90,0xB0,0x30,0xE8,0x07,0x00,0xC3,0xB0,0x20,
+0xE8,0x01,0x00,0xC3,0x56,0x8B,0x36,0xD0,0x79,0x88,0x84,0xD0,0x77,0x46,0x81,0xE6,
+0xFF,0x01,0xFF,0x06,0xD4,0x79,0x89,0x36,0xD0,0x79,0x81,0x3E,0xD4,0x79,0xFE,0x01,
+0x75,0x08,0x56,0xE8,0x14,0x00,0x5E,0xEB,0xF1,0x90,0x5E,0xC3,0xBA,0x02,0x02,0xEC,
+0x24,0x01,0x74,0x04,0xBA,0x06,0x02,0xEC,0xC3,0x90,0x80,0x3E,0xF6,0x79,0x00,0x74,
+0x09,0x60,0xB8,0x01,0x00,0xE8,0x2C,0xEA,0x61,0x90,0xBA,0x02,0x02,0xEC,0xA8,0x04,
+0x74,0x28,0x8B,0x36,0xD2,0x79,0x83,0x3E,0xD4,0x79,0x00,0x74,0x1D,0x8A,0x84,0xD0,
+0x77,0x46,0x81,0xE6,0xFF,0x01,0x89,0x36,0xD2,0x79,0xFF,0x0E,0xD4,0x79,0xBA,0x06,
+0x02,0xEE,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x75,0xDC,0xA1,0xD4,0x79,0xC3,0x52,0xBA,
+0x06,0x02,0xEE,0x5A,0xC3,0x90,0x52,0x50,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x74,0x08,
+0x58,0x5A,0xE8,0xE9,0xFF,0xF9,0xC3,0x90,0x58,0x5A,0xF8,0xC3,0x52,0x50,0xBA,0x02,
+0x02,0xEC,0xA8,0x04,0x74,0xFB,0x58,0x5A,0xE8,0xD3,0xFF,0xC3,0x30,0x31,0x32,0x33,
+0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,0x53,0x50,0x8A,0xE0,
+0x80,0xE4,0x0F,0xBB,0xAC,0x62,0xC0,0xE8,0x04,0x2E,0xD7,0xE8,0xCE,0xFF,0x8A,0xC4,
+0x2E,0xD7,0xE8,0xC7,0xFF,0x58,0x5B,0xC3,0x86,0xE0,0xE8,0xDF,0xFF,0x86,0xE0,0xE8,
+0xDA,0xFF,0xC3,0x90,0xBE,0x94,0x4D,0x50,0x2E,0xAC,0x3C,0x00,0x74,0x05,0xE8,0xAB,
+0xFF,0xEB,0xF5,0x58,0xC3,0x90,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0xBF,
+0x04,0x00,0xC7,0x46,0xFC,0x00,0x00,0xC7,0x46,0xFA,0x00,0x00,0xC7,0x46,0xF8,0x00,
+0x00,0x83,0x7E,0x06,0x00,0x75,0x0E,0x56,0xE8,0xB6,0x0E,0x59,0x0B,0xC0,0x75,0x05,
+0x8B,0xC7,0xE9,0x5B,0x01,0x8B,0x46,0xFC,0x89,0x46,0xFE,0x0B,0xFF,0x75,0x05,0xB8,
+0x01,0x00,0xEB,0x02,0x33,0xC0,0x50,0x56,0xE8,0xA4,0x0D,0x59,0x59,0xB4,0x00,0x89,
+0x46,0xFC,0x8B,0x5E,0xFC,0x83,0xFB,0x08,0x76,0x03,0xE9,0x2B,0x01,0xD1,0xE3,0x2E,
+0xFF,0xA7,0x94,0x64,0xB8,0x03,0x00,0xE9,0x26,0x01,0x83,0x7E,0xFA,0x00,0x74,0x14,
+0xC7,0x46,0xFA,0x00,0x00,0x8A,0x44,0x58,0x98,0x50,0x8A,0x44,0x59,0x98,0x50,0xE8,
+0xC2,0x0F,0x59,0x59,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,
+0xE8,0x9B,0x08,0x59,0x83,0x7E,0x06,0x00,0x75,0x05,0x8B,0xC7,0xE9,0xF1,0x00,0x83,
+0xFF,0x04,0x75,0x03,0xE9,0xE6,0x00,0x8B,0xC7,0xE9,0xE4,0x00,0x83,0x7E,0xFE,0x00,
+0x75,0x03,0xBF,0x02,0x00,0xE9,0xD5,0x00,0x83,0x7E,0xFE,0x00,0x75,0x03,0xBF,0x01,
+0x00,0xE9,0xC9,0x00,0x8B,0x5E,0xFE,0x83,0xFB,0x07,0x76,0x03,0xE9,0x86,0x00,0xD1,
+0xE3,0x2E,0xFF,0xA7,0x84,0x64,0x33,0xFF,0xE9,0x7F,0x00,0xBF,0x04,0x00,0x80,0x7C,
+0x58,0x0F,0x74,0x22,0x83,0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x44,0x58,0x6A,0x08,0x56,
+0xE8,0x7E,0x0C,0x59,0x59,0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x72,0x0C,0x59,
+0x59,0xC7,0x46,0xFA,0x01,0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,
+0x00,0x56,0xE8,0x19,0x08,0x59,0xEB,0x42,0xBF,0x04,0x00,0x80,0x7C,0x58,0x00,0x74,
+0x22,0x83,0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x4C,0x58,0x6A,0x08,0x56,0xE8,0x41,0x0C,
+0x59,0x59,0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x35,0x0C,0x59,0x59,0xC7,0x46,
+0xFA,0x01,0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,0xE8,
+0xDC,0x07,0x59,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xEB,0x31,0xBF,0x04,0x00,0xEB,
+0x2C,0xC7,0x46,0xF8,0x01,0x00,0x6A,0x08,0x56,0xE8,0x05,0x0C,0x59,0x59,0x80,0x7C,
+0x58,0x09,0x7D,0x04,0xB0,0x0F,0xEB,0x02,0xB0,0x00,0x04,0x80,0x50,0x56,0xE8,0xF0,
+0x0B,0x59,0x59,0xBF,0x04,0x00,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xE9,0xA5,0xFE,
+0x5F,0x5E,0xC9,0xC3,0xC6,0x63,0x45,0x64,0x45,0x64,0x45,0x64,0x45,0x64,0xCB,0x63,
+0x08,0x64,0x33,0x64,0x5A,0x63,0x9C,0x63,0xA8,0x63,0x78,0x64,0xB4,0x63,0x4C,0x64,
+0x4C,0x64,0x51,0x64,0x54,0x63,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x8B,
+0x7E,0x08,0x6A,0x01,0x56,0xE8,0xA9,0x0B,0x59,0x59,0x8A,0x46,0x06,0xC0,0xE0,0x06,
+0x04,0x80,0x50,0x56,0xE8,0x9A,0x0B,0x59,0x59,0xC7,0x46,0xFE,0x00,0x00,0x89,0x7E,
+0xF8,0xEB,0x03,0xFF,0x46,0xFE,0x8B,0x5E,0xF8,0xFF,0x46,0xF8,0x80,0x3F,0x00,0x75,
+0xF2,0x83,0x7E,0xFE,0x10,0x7D,0x25,0xB8,0x10,0x00,0x2B,0x46,0xFE,0xD1,0xF8,0x89,
+0x46,0xFC,0xC7,0x46,0xFA,0x00,0x00,0xEB,0x0B,0x6A,0x20,0x56,0xE8,0x62,0x0B,0x59,
+0x59,0xFF,0x46,0xFA,0x8B,0x46,0xFA,0x3B,0x46,0xFC,0x7C,0xED,0xEB,0x0C,0x8B,0xDF,
+0x47,0x8A,0x07,0x50,0x56,0xE8,0x49,0x0B,0x59,0x59,0x80,0x3D,0x00,0x75,0xEF,0x6A,
+0x02,0x56,0xE8,0x3C,0x0B,0x59,0x59,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x04,0x00,
+0x00,0x56,0x57,0x8B,0x7E,0x04,0xC7,0x46,0xFE,0x00,0x00,0xBE,0x14,0x00,0xE9,0x09,
+0x01,0x8B,0x5E,0xFE,0x83,0xC3,0x04,0x2B,0xDF,0x8A,0x87,0xAC,0x0B,0x88,0x44,0x5A,
+0xC6,0x44,0x58,0x08,0x8A,0x46,0xFE,0x88,0x44,0x59,0xC7,0x44,0x06,0x00,0x00,0xC6,
+0x44,0x19,0x00,0xC6,0x44,0x1A,0x00,0xC6,0x44,0x1B,0x00,0xC6,0x44,0x1D,0x0D,0xC6,
+0x44,0x1E,0x03,0xC6,0x44,0x1F,0x00,0xC6,0x44,0x20,0x00,0xC6,0x44,0x21,0x00,0xC6,
+0x44,0x5B,0x00,0xC6,0x44,0x5D,0x00,0xC6,0x44,0x5E,0x00,0xC6,0x44,0x5F,0x00,0xC6,
+0x44,0x60,0x00,0xC7,0x46,0xFC,0x00,0x00,0xEB,0x0D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,
+0x40,0x30,0x00,0x00,0xFF,0x46,0xFC,0x83,0x7E,0xFC,0x10,0x7C,0xED,0xC7,0x46,0xFC,
+0x00,0x00,0xEB,0x0A,0x8B,0x5E,0xFC,0xC6,0x40,0x50,0x00,0xFF,0x46,0xFC,0x83,0x7E,
+0xFC,0x04,0x7C,0xF0,0xC7,0x44,0x54,0x00,0x00,0xC7,0x44,0x56,0x00,0x00,0x8A,0x44,
+0x5A,0x98,0xBA,0xF8,0x00,0x23,0xD0,0xB8,0x05,0x00,0x0B,0xC2,0x89,0x46,0xFC,0x9C,
+0xFA,0x8A,0x46,0xFC,0xBA,0xFE,0x00,0xEE,0xBA,0x00,0x00,0xEC,0x9D,0x24,0x08,0x88,
+0x46,0xFC,0x83,0x7E,0xFC,0x00,0x75,0x02,0xEB,0x4A,0xFF,0x76,0xFE,0xE8,0x7A,0x0C,
+0x59,0x68,0x35,0x02,0x56,0xE8,0x32,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x34,0x68,0x38,
+0x02,0x56,0xE8,0x25,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x27,0x68,0x42,0x02,0x56,0xE8,
+0x18,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x1A,0x68,0x4C,0x02,0x56,0xE8,0x0B,0x0A,0x59,
+0x59,0x0B,0xC0,0x75,0x0D,0x68,0x56,0x02,0x56,0xE8,0xFE,0x09,0x59,0x59,0x0B,0xC0,
+0x74,0x02,0xEB,0x00,0xFF,0x46,0xFE,0x83,0xC6,0x62,0x39,0x7E,0xFE,0x7D,0x03,0xE9,
+0xEF,0xFE,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x46,
+0x04,0xBA,0x62,0x00,0xF7,0xEA,0x05,0x14,0x00,0x8B,0xF0,0x83,0x7E,0x06,0x00,0x74,
+0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x08,0x00,0x89,0x44,0x04,0x8A,0x46,0x08,0x88,
+0x44,0x5C,0x56,0xE8,0x59,0x04,0x59,0x8B,0xF8,0x8B,0xC7,0x89,0x44,0x56,0x89,0x44,
+0x54,0x8A,0x44,0x5D,0x88,0x44,0x2F,0x0B,0xFF,0x75,0x1D,0x68,0xC2,0x0F,0x6A,0x01,
+0x56,0xE8,0x02,0xFE,0x83,0xC4,0x06,0xEB,0x00,0x6A,0x01,0x56,0xE8,0x47,0xFC,0x59,
+0x59,0x0B,0xC0,0x75,0xF4,0xBF,0x01,0x00,0x89,0x7E,0xFA,0xB9,0x05,0x00,0xBB,0xCB,
+0x6A,0x2E,0x8B,0x07,0x3B,0x46,0xFA,0x74,0x07,0x43,0x43,0xE2,0xF4,0xE9,0xA4,0x03,
+0x2E,0xFF,0x67,0x0A,0xC7,0x44,0x06,0x02,0x00,0xC7,0x44,0x08,0xF4,0x08,0x8B,0x5E,
+0x04,0xD1,0xE3,0x8B,0x87,0xFC,0x08,0x89,0x44,0x0A,0x33,0xC0,0x8B,0xF8,0x89,0x44,
+0x54,0xE9,0x80,0x03,0x56,0xE8,0xBB,0x05,0x59,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88,
+0x44,0x60,0xE9,0x6F,0x03,0x83,0x7C,0x04,0x08,0x75,0x30,0x80,0x7C,0x5C,0x01,0x75,
+0x15,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xE4,0x08,0x56,0xE8,
+0xF7,0x08,0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,
+0xB7,0xC4,0x08,0x56,0xE8,0xE2,0x08,0x59,0x59,0xEB,0x2E,0x80,0x7C,0x5C,0x01,0x75,
+0x15,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xD4,0x08,0x56,0xE8,
+0xC7,0x08,0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,
+0xB7,0xB4,0x08,0x56,0xE8,0xB2,0x08,0x59,0x59,0x6A,0x01,0x56,0xE8,0x87,0xFB,0x59,
+0x59,0x8B,0xD8,0x83,0xFB,0x03,0x77,0x2A,0xD1,0xE3,0x2E,0xFF,0xA7,0xC3,0x6A,0xBF,
+0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x5E,0xEB,0x18,0x8A,0x44,0x5D,0x04,0xFF,0x24,
+0x07,0x88,0x44,0x5D,0xEB,0x0C,0x8A,0x44,0x5D,0xFE,0xC0,0x24,0x07,0x88,0x44,0x5D,
+0xEB,0x00,0xE9,0xCF,0x02,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,
+0xFD,0x02,0x56,0xE8,0x63,0x08,0x59,0x59,0x68,0x1D,0x03,0x56,0xE8,0x5A,0x08,0x59,
+0x59,0x6A,0x01,0x56,0xE8,0x2F,0xFB,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x77,0x36,
+0xD1,0xE3,0x2E,0xFF,0xA7,0xBB,0x6A,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x5F,
+0xEB,0x24,0x8A,0x44,0x5D,0x04,0xFF,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22,0xC2,0x88,
+0x44,0x5D,0xEB,0x12,0x8A,0x44,0x5D,0xFE,0xC0,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22,
+0xC2,0x88,0x44,0x5D,0xEB,0x00,0xE9,0x6B,0x02,0x8B,0x5C,0x06,0x83,0xC3,0xFE,0xD1,
+0xE3,0x8B,0x40,0x08,0x89,0x04,0x8B,0x1C,0xFF,0x77,0x06,0x6A,0x00,0x56,0xE8,0x85,
+0xFC,0x83,0xC4,0x06,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x40,0x08,0x89,0x44,0x02,
+0x8B,0x5C,0x02,0xFF,0x77,0x06,0x6A,0x01,0x56,0xE8,0x6A,0xFC,0x83,0xC4,0x06,0x6A,
+0x01,0x56,0xE8,0xB1,0xFA,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x76,0x03,0xE9,0x1F,
+0x02,0xD1,0xE3,0x2E,0xFF,0xA7,0xB3,0x6A,0x8B,0x5C,0x02,0x8B,0x47,0x04,0x89,0x44,
+0x02,0x8B,0x5C,0x02,0x80,0x3F,0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4,
+0x00,0x3B,0x44,0x04,0x7D,0xE2,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B,
+0x44,0x02,0x89,0x47,0x08,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40,
+0x08,0xE9,0xDE,0x01,0x8B,0x5C,0x02,0x8B,0x47,0x02,0x89,0x44,0x02,0x8B,0x5C,0x02,
+0x80,0x3F,0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4,0x00,0x3B,0x44,0x04,
+0x7D,0xE2,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B,0x44,0x02,0x89,0x47,
+0x08,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40,0x08,0xE9,0xA2,0x01,
+0xBF,0x01,0x00,0xE9,0x9C,0x01,0x8B,0x5C,0x02,0x8A,0x07,0xB4,0x00,0x89,0x46,0xF8,
+0xB9,0x0C,0x00,0xBB,0x83,0x6A,0x2E,0x8B,0x07,0x3B,0x46,0xF8,0x74,0x07,0x43,0x43,
+0xE2,0xF4,0xE9,0x77,0x01,0x2E,0xFF,0x67,0x18,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x5C,
+0x02,0x03,0xD8,0x8B,0x47,0x08,0x8B,0x5C,0x06,0xFF,0x44,0x06,0xD1,0xE3,0x89,0x40,
+0x08,0x8B,0x1C,0x80,0x7F,0x01,0x00,0x74,0x12,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,
+0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xE9,0x40,0x01,0xFF,0x4C,
+0x06,0xE9,0x3A,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6,
+0x00,0x8B,0xDA,0x88,0x40,0x18,0xE9,0x25,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,
+0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xFF,0x4C,0x06,0xE9,0x0D,
+0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,
+0x30,0x40,0x18,0xE9,0xF8,0x00,0xB8,0xF0,0x10,0x8B,0xF8,0x89,0x44,0x54,0x8A,0x44,
+0x5F,0x88,0x44,0x5D,0xE9,0xE7,0x00,0x8A,0x44,0x1C,0x98,0x3D,0x02,0x00,0x74,0x07,
+0x3D,0x03,0x00,0x74,0x02,0xEB,0x07,0xC7,0x46,0xFE,0x00,0x00,0xEB,0x2B,0x8A,0x44,
+0x1C,0x98,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x69,0x02,0x56,0xE8,0x6B,0x06,0x59,0x59,
+0x6A,0x01,0x56,0xE8,0x40,0xF9,0x59,0x59,0x89,0x46,0xFE,0x83,0x7E,0xFE,0x00,0x74,
+0x06,0x83,0x7E,0xFE,0x03,0x75,0xE9,0xEB,0x00,0x83,0x7E,0xFE,0x03,0x74,0x62,0x8A,
+0x44,0x1C,0x98,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x6D,0x02,0x56,0xE8,0x3A,0x06,0x59,
+0x59,0x56,0xE8,0x6B,0x97,0x59,0x89,0x46,0xFC,0x8B,0x5E,0xFC,0x83,0xEB,0xFE,0x83,
+0xFB,0x03,0x77,0x33,0xD1,0xE3,0x2E,0xFF,0xA7,0x7B,0x6A,0x68,0xAC,0x02,0x56,0xE8,
+0x17,0x06,0x59,0x59,0xEB,0x23,0x68,0x8F,0x02,0x56,0xE8,0x0C,0x06,0x59,0x59,0xEB,
+0x18,0x68,0x75,0x02,0x56,0xE8,0x01,0x06,0x59,0x59,0xEB,0x0D,0x68,0xC6,0x02,0x56,
+0xE8,0xF6,0x05,0x59,0x59,0xEB,0x02,0xEB,0x00,0x6A,0x01,0x56,0xE8,0xC7,0xF8,0x59,
+0x59,0xBF,0x01,0x00,0xEB,0x38,0x68,0xDD,0x02,0x56,0xE8,0xDC,0x05,0x59,0x59,0x6A,
+0x01,0x56,0xE8,0xB1,0xF8,0x59,0x59,0xBF,0x01,0x00,0xEB,0x22,0xB8,0xD0,0x30,0x8B,
+0xF8,0x89,0x44,0x54,0x8A,0x44,0x60,0x88,0x44,0x5D,0xEB,0x12,0xB8,0xE0,0x20,0x8B,
+0xF8,0x89,0x44,0x54,0x8A,0x44,0x5E,0x88,0x44,0x5D,0xEB,0x02,0xEB,0x00,0xEB,0x02,
+0xEB,0x00,0xEB,0x00,0xE9,0x41,0xFC,0x5F,0x5E,0xC9,0xC3,0xFB,0x69,0x06,0x6A,0x11,
+0x6A,0x1C,0x6A,0x00,0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x41,0x00,0x42,0x00,0x43,
+0x00,0x44,0x00,0x80,0x00,0x81,0x00,0x82,0x00,0xFF,0x00,0xF9,0x68,0x36,0x6A,0x5C,
+0x6A,0x87,0x69,0x34,0x69,0x76,0x69,0x4C,0x6A,0x49,0x69,0x34,0x69,0x61,0x69,0x49,
+0x69,0x2E,0x69,0xD6,0x68,0x58,0x68,0x94,0x68,0xD0,0x68,0xD7,0x67,0xE2,0x67,0xF4,
+0x67,0xD7,0x67,0x7F,0x67,0x8A,0x67,0x96,0x67,0x7F,0x67,0x00,0x00,0x01,0x00,0xF0,
+0x10,0xE0,0x20,0xD0,0x30,0x09,0x68,0xD4,0x66,0xA5,0x67,0x05,0x67,0xF4,0x66,0xC8,
+0x04,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x8A,0x44,0x59,0x98,0x89,0x46,0xFC,0x6A,
+0x09,0x8B,0x46,0xFC,0x05,0x84,0x01,0x50,0xE8,0x93,0x08,0x59,0x59,0x8B,0xF8,0x8B,
+0xC7,0x25,0x00,0xF0,0x3D,0x00,0x10,0x75,0x55,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xF0,
+0x00,0x75,0x4B,0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44,
+0x04,0x3B,0x46,0xFE,0x7D,0x05,0x33,0xC0,0xE9,0xEF,0x00,0x8B,0xC7,0x25,0x0F,0x00,
+0xBA,0x0F,0x00,0x2B,0xD0,0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xE9,0xDB,0x00,0xC7,
+0x44,0x02,0x04,0x09,0x8A,0x46,0xFE,0x88,0x44,0x5F,0x88,0x44,0x5D,0x8B,0x5E,0xFC,
+0xD1,0xE3,0xC7,0x87,0xFC,0x08,0x04,0x09,0xB8,0xF0,0x10,0xE9,0xBC,0x00,0x8B,0xC7,
+0x25,0x00,0xF0,0x3D,0x00,0x20,0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xE0,0x00,
+0x75,0x48,0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x83,0x7E,0xFE,
+0x08,0x7E,0x05,0x33,0xC0,0xE9,0x92,0x00,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00,
+0x2B,0xD0,0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xEB,0x7F,0x90,0xC7,0x44,0x02,0x0C,
+0x09,0x8A,0x46,0xFE,0x88,0x44,0x5E,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,
+0x87,0xFC,0x08,0x0C,0x09,0xB8,0xE0,0x20,0xEB,0x60,0x8B,0xC7,0x25,0x00,0xF0,0x3D,
+0x00,0x30,0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xD0,0x00,0x75,0x48,0x8B,0xC7,
+0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44,0x04,0x3B,0x46,0xFE,0x7D,
+0x04,0x33,0xC0,0xEB,0x35,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00,0x2B,0xD0,0x3B,
+0x56,0xFE,0x74,0x04,0x33,0xC0,0xEB,0x22,0xC7,0x44,0x02,0x14,0x09,0x8A,0x46,0xFE,
+0x88,0x44,0x60,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,0x87,0xFC,0x08,0x14,
+0x09,0xB8,0xD0,0x30,0xEB,0x04,0x33,0xC0,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x06,
+0x00,0x00,0x56,0x8B,0x76,0x04,0x6A,0x08,0x56,0xE8,0x35,0x04,0x59,0x59,0x8A,0x44,
+0x58,0x04,0x80,0x50,0x56,0xE8,0x29,0x04,0x59,0x59,0x8B,0x44,0x54,0x3B,0x44,0x56,
+0x75,0x0A,0x8A,0x44,0x5D,0x3A,0x44,0x2F,0x75,0x02,0xEB,0x64,0x8B,0x44,0x54,0x89,
+0x44,0x56,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x88,0x44,0x2F,0x8A,0x44,0x5D,0xB4,0x00,
+0xC1,0xE0,0x08,0x8B,0x54,0x54,0x0B,0xD0,0x8A,0x44,0x5D,0xB4,0x00,0xBB,0x0F,0x00,
+0x2B,0xD8,0x0B,0xD3,0x89,0x56,0xFE,0x6A,0x10,0x8A,0x44,0x59,0x98,0x05,0x04,0x00,
+0x99,0x05,0x40,0x01,0x83,0xD2,0x00,0x52,0x50,0xE8,0x54,0x08,0x83,0xC4,0x06,0x89,
+0x56,0xFC,0x89,0x46,0xFA,0x8B,0x46,0xFE,0x09,0x46,0xFA,0x83,0x4E,0xFC,0x00,0x6A,
+0x19,0xFF,0x76,0xFC,0xFF,0x76,0xFA,0xE8,0x73,0x07,0x83,0xC4,0x06,0xE8,0xFE,0x07,
+0x5E,0xC9,0xC3,0xC8,0x1C,0x00,0x00,0x56,0x57,0x8B,0x5E,0x04,0x8A,0x47,0x59,0x98,
+0x8B,0xF0,0x8B,0x5E,0x04,0x8A,0x47,0x5D,0xB4,0x00,0x89,0x46,0xE6,0x83,0x7E,0xE6,
+0x00,0x7D,0x0A,0x8B,0x5E,0x04,0x8B,0x47,0x04,0x48,0x89,0x46,0xE6,0x8B,0x5E,0x04,
+0x8B,0x47,0x04,0x3B,0x46,0xE6,0x7F,0x05,0xC7,0x46,0xE6,0x00,0x00,0x8B,0x5E,0x04,
+0x8A,0x46,0xE6,0x88,0x47,0x5D,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,
+0x02,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x03,0x30,0x8B,0xDE,
+0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x47,0x02,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,
+0x61,0x02,0xC6,0x47,0x03,0x30,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,
+0x74,0x18,0x8B,0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,
+0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA,
+0x33,0xD2,0xF7,0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA,
+0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,
+0x59,0x02,0x88,0x57,0x02,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,
+0x18,0x8B,0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,
+0xD1,0xE3,0x8B,0x9F,0x61,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA,0x33,
+0xD2,0xF7,0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA,0xBB,
+0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,
+0x02,0x88,0x57,0x02,0x8B,0x5E,0xE6,0xD1,0xE3,0xFF,0xB7,0x12,0x02,0x6A,0x00,0xFF,
+0x76,0x04,0xE8,0xD1,0xF6,0x83,0xC4,0x06,0x68,0xD3,0x0F,0x6A,0x01,0xFF,0x76,0x04,
+0xE8,0xC3,0xF6,0x83,0xC4,0x06,0xFF,0x76,0xE6,0x56,0xE8,0x1F,0x93,0x59,0x59,0x89,
+0x56,0xF2,0x89,0x46,0xF0,0xFF,0x76,0xE6,0x56,0xE8,0x32,0x93,0x59,0x59,0x89,0x56,
+0xEE,0x89,0x46,0xEC,0x9C,0xFA,0xC4,0x5E,0xF0,0x26,0x8B,0x07,0x89,0x46,0xEA,0xC4,
+0x5E,0xEC,0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE,0x9D,
+0xC7,0x46,0xE4,0x01,0x00,0xE8,0x08,0xA1,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFC,0x8B,
+0x46,0xFC,0x2B,0x46,0xFE,0x3D,0xE8,0x03,0x73,0x03,0xE9,0x80,0x01,0x9C,0xFA,0xBA,
+0x50,0xFF,0xED,0x89,0x46,0xFC,0x8B,0x46,0xFC,0x2B,0x46,0xFE,0x89,0x46,0xF8,0xC4,
+0x5E,0xF0,0x26,0x8B,0x07,0x2B,0x46,0xEA,0x89,0x46,0xF6,0xC4,0x5E,0xF0,0x26,0x8B,
+0x07,0x89,0x46,0xEA,0xC4,0x5E,0xEC,0x26,0x8B,0x07,0x2B,0x46,0xE8,0x89,0x46,0xF4,
+0xC4,0x5E,0xEC,0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE,
+0x9D,0x81,0x7E,0xF8,0xE8,0x03,0x76,0x1C,0xFF,0x76,0xF8,0xFF,0x76,0xF6,0xE8,0x76,
+0x01,0x59,0x59,0x89,0x46,0xF6,0xFF,0x76,0xF8,0xFF,0x76,0xF4,0xE8,0x68,0x01,0x59,
+0x59,0x89,0x46,0xF4,0xBF,0x0E,0x00,0xEB,0x17,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,
+0x02,0xC6,0x01,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x01,0x20,0x47,
+0x83,0xFF,0x11,0x76,0xE4,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x0D,
+0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x47,0x0D,0x30,0x83,0x7E,0xF6,
+0x09,0x77,0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF6,0x63,0x77,0x05,0xB8,0x0E,
+0x00,0xEB,0x1B,0x81,0x7E,0xF6,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81,
+0x7E,0xF6,0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8,
+0xEB,0x25,0x8B,0x46,0xF6,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,
+0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF6,
+0x33,0xD2,0xF7,0xF3,0x89,0x46,0xF6,0x83,0x7E,0xF6,0x00,0x75,0xD5,0x83,0x7E,0xF4,
+0x09,0x77,0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF4,0x63,0x77,0x05,0xB8,0x0E,
+0x00,0xEB,0x1B,0x81,0x7E,0xF4,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81,
+0x7E,0xF4,0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8,
+0xEB,0x25,0x8B,0x46,0xF4,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,
+0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF4,
+0x33,0xD2,0xF7,0xF3,0x89,0x46,0xF4,0x83,0x7E,0xF4,0x00,0x75,0xD5,0x8B,0xDE,0xD1,
+0xE3,0xFF,0xB7,0x59,0x02,0xFF,0x76,0x04,0xE8,0x6E,0x00,0x59,0x59,0x8B,0xDE,0xD1,
+0xE3,0xFF,0xB7,0x61,0x02,0xFF,0x76,0x04,0xE8,0x5E,0x00,0x59,0x59,0x6A,0x00,0xFF,
+0x76,0x04,0xE8,0x31,0xF3,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x04,0x77,0x1F,0xD1,0xE3,
+0x2E,0xFF,0xA7,0xFD,0x6F,0xEB,0x22,0xC7,0x46,0xE4,0x00,0x00,0xFF,0x4E,0xE6,0xEB,
+0x0C,0xC7,0x46,0xE4,0x00,0x00,0xFF,0x46,0xE6,0xEB,0x02,0xEB,0x00,0x83,0x7E,0xE4,
+0x00,0x74,0x03,0xE9,0x2A,0xFE,0xE9,0xD4,0xFC,0x5F,0x5E,0xC9,0xC3,0xD5,0x6F,0xD7,
+0x6F,0xE1,0x6F,0xD5,0x6F,0xEB,0x6F,0x55,0x8B,0xEC,0x8B,0x46,0x04,0xB9,0xE8,0x03,
+0xF7,0xE1,0x8B,0x4E,0x06,0xF7,0xF1,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76,0x06,
+0xEB,0x0E,0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x33,0x00,0x59,0x59,
+0x80,0x3C,0x00,0x75,0xED,0xEB,0x00,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76,
+0x06,0xEB,0x14,0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x45,0x00,0x59,
+0x59,0x0B,0xC0,0x74,0x02,0xEB,0x07,0x80,0x3C,0x00,0x75,0xE7,0xEB,0x00,0x5E,0x5D,
+0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,
+0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74,
+0x06,0x9D,0xE8,0xAB,0x9E,0xEB,0xE9,0xBA,0x00,0x00,0x8A,0x46,0x06,0xEE,0x9D,0xEB,
+0x00,0x5E,0xC9,0xC3,0xC8,0x04,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,
+0x89,0x46,0xFE,0xE8,0x00,0xA2,0x89,0x46,0xFC,0xE8,0xFA,0xA1,0x2B,0x46,0xFC,0x3D,
+0xB8,0x0B,0x76,0x05,0xB8,0x01,0x00,0xEB,0x23,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,
+0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74,0x06,0x9D,0xE8,0x62,0x9E,0xEB,0xD9,
+0xBA,0x00,0x00,0x8A,0x46,0x06,0xEE,0x9D,0x33,0xC0,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,
+0x04,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x83,0x7E,0x06,0x00,0x74,0x07,0x56,0xE8,
+0x03,0x01,0x59,0xEB,0x05,0x56,0xE8,0xA2,0x00,0x59,0x88,0x46,0xFF,0x80,0x7E,0xFF,
+0x08,0x77,0x06,0x8A,0x46,0xFF,0xE9,0x84,0x00,0x80,0x7E,0xFF,0x0F,0x76,0x03,0xEB,
+0x79,0x90,0x8A,0x46,0xFF,0xB4,0x00,0x2D,0x0A,0x00,0x8B,0xD8,0x83,0xFB,0x04,0x77,
+0x67,0xD1,0xE3,0x2E,0xFF,0xA7,0x91,0x71,0xB0,0x00,0xEB,0x61,0x56,0xE8,0x6B,0x00,
+0x59,0xB4,0x00,0x25,0x0F,0x00,0x89,0x46,0xFC,0x56,0xE8,0x5E,0x00,0x59,0xB4,0x00,
+0x8B,0xF8,0x56,0xE8,0x55,0x00,0x59,0xB4,0x00,0xC1,0xE0,0x08,0x8B,0xD7,0x03,0xD0,
+0x8B,0xFA,0x8B,0x5E,0xFC,0xD1,0xE3,0x89,0x78,0x30,0xEB,0x2E,0x56,0xE8,0x3B,0x00,
+0x59,0x88,0x44,0x5B,0xEB,0x24,0x56,0xE8,0x31,0x00,0x59,0x88,0x44,0x50,0x56,0xE8,
+0x29,0x00,0x59,0x88,0x44,0x51,0x56,0xE8,0x21,0x00,0x59,0x88,0x44,0x52,0x56,0xE8,
+0x19,0x00,0x59,0x88,0x44,0x53,0xEB,0x02,0xEB,0x00,0xE9,0x5B,0xFF,0x5F,0x5E,0xC9,
+0xC3,0x28,0x71,0x88,0x71,0x2C,0x71,0x5C,0x71,0x66,0x71,0xC8,0x04,0x00,0x00,0x56,
+0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,
+0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0x71,0x9D,0xEB,
+0xE9,0xBA,0x00,0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9,
+0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,
+0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0x32,0xE4,0x24,
+0x01,0x9D,0x5E,0xC9,0xC3,0xC8,0x06,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,
+0x98,0x89,0x46,0xFE,0xE8,0x9F,0xA0,0x89,0x46,0xFA,0xE8,0x99,0xA0,0x2B,0x46,0xFA,
+0x3D,0xB8,0x0B,0x76,0x04,0xB0,0x08,0xEB,0x24,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,
+0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0x02,0x9D,0xEB,0xDA,
+0xBA,0x00,0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9,0xC3,
+0x55,0x8B,0xEC,0x56,0x8B,0x56,0x04,0x8A,0x46,0x06,0xEE,0x33,0xF6,0xEB,0x03,0x50,
+0x58,0x46,0x83,0xFE,0x14,0x7C,0xF8,0x5E,0x5D,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,
+0x56,0x04,0xEC,0x88,0x46,0xFF,0x33,0xF6,0xEB,0x03,0x50,0x58,0x46,0x83,0xFE,0x14,
+0x7C,0xF8,0x8A,0x46,0xFF,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x57,
+0x8B,0x76,0x04,0x83,0x3E,0xB0,0x0B,0x00,0x75,0x1F,0xBA,0x88,0x01,0xB0,0x00,0xEE,
+0xBA,0x86,0x01,0xB0,0x00,0xEE,0x6A,0x09,0x6A,0x00,0x68,0x30,0x01,0xE8,0x7D,0x01,
+0x83,0xC4,0x06,0xC7,0x06,0xB0,0x0B,0x01,0x00,0x6A,0x09,0x8B,0xC6,0x05,0x80,0x01,
+0x50,0xE8,0xDA,0x00,0x59,0x59,0x8B,0xF8,0x8B,0xC7,0xC1,0xE8,0x0C,0x25,0x0F,0x00,
+0x89,0x46,0xFE,0x8B,0xC7,0xC1,0xE8,0x08,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,0xF2,
+0x0C,0x3B,0xC2,0x75,0x21,0x8B,0xC7,0xC1,0xE8,0x04,0x25,0x0F,0x00,0x8B,0x56,0xFE,
+0x83,0xF2,0x06,0x3B,0xC2,0x75,0x0F,0x8B,0xC7,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,
+0xF2,0x09,0x3B,0xC2,0x74,0x0D,0x6A,0x07,0x56,0xE8,0x38,0x00,0x59,0x59,0xC7,0x46,
+0xFE,0x07,0x00,0x8A,0x46,0xFE,0x04,0x80,0xA2,0x33,0x02,0x8B,0xC6,0xBA,0x62,0x00,
+0xF7,0xEA,0x8A,0x56,0xFE,0x8B,0xD8,0x88,0x97,0x6C,0x00,0x68,0x32,0x02,0x8B,0xC6,
+0xBA,0x62,0x00,0xF7,0xEA,0x05,0x14,0x00,0x50,0xE8,0x0E,0xFD,0x59,0x59,0xEB,0x00,
+0x5F,0x5E,0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x06,0x83,0xE6,0x0F,0x8B,
+0xC6,0xC1,0xE0,0x0C,0x8B,0xD6,0x83,0xF2,0x0C,0xC1,0xE2,0x08,0x0B,0xC2,0x8B,0xD6,
+0x83,0xF2,0x06,0xC1,0xE2,0x04,0x0B,0xC2,0x8B,0xD6,0x83,0xF2,0x09,0x0B,0xC2,0x89,
+0x46,0xFE,0x6A,0x19,0x6A,0x10,0x8B,0x46,0x04,0x99,0x05,0x40,0x01,0x83,0xD2,0x00,
+0x52,0x50,0xE8,0x6B,0x01,0x83,0xC4,0x06,0x0B,0x46,0xFE,0x83,0xCA,0x00,0x52,0x50,
+0xE8,0x9A,0x00,0x83,0xC4,0x06,0xE8,0x25,0x01,0xEB,0x00,0x5E,0xC9,0xC3,0x55,0x8B,
+0xEC,0x56,0x57,0x33,0xFF,0x6A,0x01,0x68,0x86,0x01,0xE8,0xA3,0xFE,0x59,0x59,0xB1,
+0x10,0x2A,0x4E,0x06,0xD3,0x66,0x04,0x33,0xF6,0xEB,0x2E,0x81,0x7E,0x04,0x00,0x80,
+0x72,0x04,0xB0,0x01,0xEB,0x02,0xB0,0x00,0x50,0x68,0x88,0x01,0xE8,0x81,0xFE,0x59,
+0x59,0x6A,0x03,0x68,0x86,0x01,0xE8,0x77,0xFE,0x59,0x59,0x6A,0x01,0x68,0x86,0x01,
+0xE8,0x6D,0xFE,0x59,0x59,0xD1,0x66,0x04,0x46,0x3B,0x76,0x06,0x7C,0xCD,0x33,0xF6,
+0xEB,0x24,0xD1,0xE7,0x6A,0x03,0x68,0x86,0x01,0xE8,0x54,0xFE,0x59,0x59,0x6A,0x01,
+0x68,0x86,0x01,0xE8,0x4A,0xFE,0x59,0x59,0x68,0x88,0x01,0xE8,0x5C,0xFE,0x59,0x98,
+0x25,0x01,0x00,0x0B,0xF8,0x46,0x83,0xFE,0x10,0x7C,0xD7,0x6A,0x00,0x68,0x86,0x01,
+0xE8,0x2D,0xFE,0x59,0x59,0x8B,0xC7,0xEB,0x00,0x5F,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,
+0x56,0x57,0x8B,0x7E,0x08,0x6A,0x01,0x68,0x86,0x01,0xE8,0x13,0xFE,0x59,0x59,0xB8,
+0x20,0x00,0x2B,0xC7,0x50,0xFF,0x76,0x06,0xFF,0x76,0x04,0xE8,0xA2,0x00,0x83,0xC4,
+0x06,0x89,0x56,0x06,0x89,0x46,0x04,0x33,0xF6,0xEB,0x47,0x81,0x7E,0x06,0x00,0x80,
+0x72,0x0C,0x75,0x06,0x83,0x7E,0x04,0x00,0x72,0x04,0xB0,0x01,0xEB,0x02,0xB0,0x00,
+0x50,0x68,0x88,0x01,0xE8,0xD9,0xFD,0x59,0x59,0x6A,0x03,0x68,0x86,0x01,0xE8,0xCF,
+0xFD,0x59,0x59,0x6A,0x01,0x68,0x86,0x01,0xE8,0xC5,0xFD,0x59,0x59,0x6A,0x01,0xFF,
+0x76,0x06,0xFF,0x76,0x04,0xE8,0x58,0x00,0x83,0xC4,0x06,0x89,0x56,0x06,0x89,0x46,
+0x04,0x46,0x3B,0xF7,0x7C,0xB5,0x6A,0x00,0x68,0x86,0x01,0xE8,0xA2,0xFD,0x59,0x59,
+0x6A,0x00,0x68,0x86,0x01,0xE8,0x98,0xFD,0x59,0x59,0x5F,0x5E,0x5D,0xC3,0x55,0x8B,
+0xEC,0x56,0x6A,0x01,0x68,0x86,0x01,0xE8,0x86,0xFD,0x59,0x59,0x33,0xF6,0xEB,0x00,
+0x68,0x88,0x01,0xE8,0x94,0xFD,0x59,0xA8,0x01,0x75,0x08,0x8B,0xC6,0x46,0x3D,0x64,
+0x00,0x7C,0xED,0x6A,0x00,0x68,0x86,0x01,0xE8,0x65,0xFD,0x59,0x59,0x5E,0x5D,0xC3,
+0xC8,0x04,0x00,0x00,0x8B,0x46,0x04,0x8B,0x56,0x06,0x8B,0x4E,0x08,0xE3,0x06,0xD1,
+0xE0,0xD1,0xD2,0xE2,0xFA,0x89,0x46,0xFC,0x89,0x56,0xFE,0x8B,0x56,0xFE,0x8B,0x46,
+0xFC,0xEB,0x00,0xC9,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x50,0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,0x4D,0x65,0x6E,0x75,0x00,0x42,0x65,
+0x67,0x69,0x6E,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,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,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,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,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,
+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,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,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,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,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,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,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,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,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,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,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x6F,0x72,0x74,
+0x20,0x30,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,0x00,0x50,0x6F,0x72,0x74,0x20,0x32,
+0x00,0x50,0x6F,0x72,0x74,0x20,0x33,0x00,0x50,0x6F,0x72,0x74,0x20,0x34,0x00,0x50,
+0x6F,0x72,0x74,0x20,0x35,0x00,0x50,0x6F,0x72,0x74,0x20,0x36,0x00,0x50,0x6F,0x72,
+0x74,0x20,0x37,0x00,0x50,0x6F,0x72,0x74,0x20,0x38,0x00,0x50,0x6F,0x72,0x74,0x20,
+0x39,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,0x30,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,
+0x31,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,0x32,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,
+0x33,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,0x34,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,
+0x35,0x00,0x9C,0x01,0xA3,0x01,0xAA,0x01,0xB1,0x01,0xB8,0x01,0xBF,0x01,0xC6,0x01,
+0xCD,0x01,0xD4,0x01,0xDB,0x01,0xE2,0x01,0xEA,0x01,0xF2,0x01,0xFA,0x01,0x02,0x02,
+0x0A,0x02,0x08,0x00,0x00,0x07,0x81,0x00,0x03,0x80,0x80,0x80,0x9F,0x91,0x95,0x91,
+0x9F,0x00,0x03,0x81,0x84,0x8E,0x95,0x84,0x84,0x84,0x84,0x00,0x03,0x82,0x84,0x84,
+0x84,0x84,0x95,0x8E,0x84,0x00,0x04,0x88,0x00,0xB2,0x0B,0xC6,0x0B,0xDA,0x0B,0xEE,
+0x0B,0x02,0x0C,0x16,0x0C,0x2A,0x0C,0x3E,0x0C,0x52,0x0C,0x77,0x0C,0x9C,0x0C,0xBE,
+0x0C,0xE0,0x0C,0x02,0x0D,0x01,0x80,0x20,0x54,0x65,0x73,0x74,0x20,0x50,0x61,0x73,
+0x73,0x65,0x64,0x20,0x1F,0x20,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x02,0x00,0x01,
+0x80,0x20,0x4D,0x69,0x73,0x73,0x69,0x6E,0x67,0x20,0x52,0x78,0x20,0x44,0x61,0x74,
+0x61,0x1F,0x20,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x02,0x00,0x01,0x80,0x20,0x42,
+0x61,0x64,0x20,0x52,0x78,0x20,0x44,0x61,0x74,0x61,0x20,0x1F,0x20,0x50,0x72,0x65,
+0x73,0x73,0x20,0x80,0x02,0x00,0x01,0x80,0x20,0x58,0x6D,0x74,0x72,0x20,0x42,0x75,
+0x73,0x79,0x1F,0x20,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x02,0x00,0x01,0x80,0x20,
+0x6E,0x6F,0x74,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x6C,0x79,0x1F,0x20,0x20,
+0x69,0x6D,0x70,0x6C,0x65,0x6D,0x65,0x6E,0x74,0x65,0x64,0x02,0x00,0x24,0x0D,0x2F,
+0x0D,0x3A,0x0D,0x45,0x0D,0x50,0x0D,0x5B,0x0D,0x66,0x0D,0x71,0x0D,0x7C,0x0D,0x87,
+0x0D,0x92,0x0D,0x9D,0x0D,0xA8,0x0D,0xB3,0x0D,0xBE,0x0D,0xC9,0x0D,0x53,0x80,0x2C,
+0x32,0x54,0x44,0x20,0x53,0x86,0x2C,0x33,0x44,0x54,0x52,0x20,0x53,0x82,0x2C,0x33,
+0x52,0x54,0x53,0x20,0x1F,0x53,0x81,0x2C,0x32,0x52,0x44,0x20,0x53,0x85,0x2C,0x32,
+0x43,0x44,0x20,0x53,0x83,0x2C,0x33,0x43,0x54,0x53,0x20,0x53,0x84,0x2C,0x33,0x44,
+0x53,0x52,0x20,0x53,0x87,0x2C,0x32,0x52,0x49,0x27,0x02,0x00,0x01,0x80,0x20,0x20,
+0x44,0x43,0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,0x30,0x1F,0x27,0x53,0x85,
+0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
+0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x53,0x52,
+0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x31,0x31,0x1F,0x27,0x53,0x84,0x2E,0x31,0x81,
+0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,
+0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x43,0x54,0x53,0x20,0x2D,0x20,
+0x70,0x69,0x6E,0x20,0x34,0x1F,0x27,0x53,0x83,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,
+0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,
+0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x49,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,
+0x32,0x1F,0x27,0x53,0x87,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,
+0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,
+0x20,0x20,0x44,0x54,0x52,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x36,0x2F,0x38,0x1F,
+0x27,0x53,0x86,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,
+0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,
+0x52,0x54,0x53,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x35,0x1F,0x27,0x53,0x82,0x2E,
+0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,
+0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x78,0x44,0x20,
+0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,0x1F,0x27,0x53,0x81,0x2E,0x30,0x53,0x4D,0x81,
+0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,
+0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x54,0x78,0x44,0x20,0x2D,0x20,
+0x70,0x69,0x6E,0x20,0x33,0x1F,0x27,0x53,0x80,0x2E,0x30,0x53,0x4D,0x81,0x82,0x63,
+0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,
+0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x43,0x44,0x20,0x2D,0x20,0x70,0x69,
+0x6E,0x20,0x35,0x1F,0x27,0x53,0x85,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,
+0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,
+0x01,0x80,0x20,0x20,0x44,0x53,0x52,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x35,0x1F,
+0x27,0x53,0x84,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,
+0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,
+0x43,0x54,0x53,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x31,0x1F,0x27,0x53,0x83,0x2E,
+0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,
+0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x49,0x20,0x2D,
+0x20,0x28,0x6E,0x2E,0x63,0x2E,0x29,0x1F,0x27,0x53,0x87,0x2E,0x31,0x81,0x82,0x63,
+0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,
+0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x54,0x52,0x20,0x2D,0x20,0x70,0x69,
+0x6E,0x20,0x32,0x1F,0x27,0x53,0x86,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,
+0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,
+0x01,0x80,0x20,0x20,0x52,0x54,0x53,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x37,0x1F,
+0x27,0x53,0x82,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,
+0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,
+0x52,0x78,0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x36,0x1F,0x27,0x53,0x81,0x2E,
+0x30,0x53,0x4D,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,
+0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x54,0x78,
+0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x33,0x1F,0x27,0x53,0x80,0x2E,0x30,0x53,
+0x4D,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,
+0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x43,0x44,0x20,
+0x2D,0x20,0x70,0x69,0x6E,0x20,0x35,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x85,0x2E,
+0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,
+0x01,0x80,0x20,0x20,0x44,0x53,0x52,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x35,0x1F,
+0x20,0x20,0x20,0x20,0x27,0x53,0x84,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,
+0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x43,0x54,0x53,0x20,
+0x2D,0x20,0x70,0x69,0x6E,0x20,0x31,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x83,0x2E,
+0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,
+0x01,0x80,0x20,0x20,0x52,0x49,0x20,0x2D,0x20,0x28,0x6E,0x2E,0x63,0x2E,0x29,0x1F,
+0x20,0x20,0x20,0x20,0x27,0x53,0x87,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,
+0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x54,0x52,0x20,
+0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x86,0x2E,
+0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,
+0x01,0x80,0x20,0x20,0x52,0x54,0x53,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x37,0x1F,
+0x20,0x20,0x20,0x20,0x27,0x53,0x82,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,
+0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x78,0x44,0x20,
+0x2D,0x20,0x70,0x69,0x6E,0x20,0x36,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x81,0x2E,
+0x30,0x53,0x4D,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,
+0x02,0x00,0x01,0x80,0x20,0x20,0x54,0x78,0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,
+0x33,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x80,0x2E,0x30,0x53,0x4D,0x81,0x82,0x63,
+0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,
+0x44,0x43,0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,0x30,0x1F,0x20,0x20,0x20,
+0x20,0x27,0x53,0x85,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,
+0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x53,0x52,0x20,0x2D,0x20,0x70,
+0x69,0x6E,0x20,0x31,0x31,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x84,0x2E,0x31,0x81,
+0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,
+0x20,0x20,0x43,0x54,0x53,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x34,0x1F,0x20,0x20,
+0x20,0x20,0x27,0x53,0x83,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,
+0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x49,0x20,0x2D,0x20,0x70,
+0x69,0x6E,0x20,0x32,0x32,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x87,0x2E,0x31,0x81,
+0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,
+0x20,0x20,0x44,0x54,0x52,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x36,0x2F,0x38,0x1F,
+0x20,0x20,0x20,0x20,0x27,0x53,0x86,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,
+0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x54,0x53,0x20,
+0x2D,0x20,0x70,0x69,0x6E,0x20,0x35,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x82,0x2E,
+0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,
+0x01,0x80,0x20,0x20,0x52,0x78,0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,0x1F,
+0x20,0x20,0x20,0x20,0x27,0x53,0x81,0x2E,0x30,0x53,0x4D,0x81,0x82,0x63,0x88,0x80,
+0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x54,0x78,
+0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x33,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,
+0x80,0x2E,0x30,0x53,0x4D,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,
+0x87,0x27,0x02,0x00,0x68,0x04,0x96,0x04,0xB6,0x03,0x3C,0x04,0x0E,0x04,0x89,0x03,
+0x5C,0x03,0xE2,0x03,0x60,0x08,0x8A,0x08,0xBE,0x07,0x38,0x08,0x0E,0x08,0x95,0x07,
+0x6C,0x07,0xE6,0x07,0x1C,0x05,0x74,0x05,0xFA,0x05,0xC4,0x04,0xF0,0x04,0xCC,0x05,
+0xA0,0x05,0x48,0x05,0x78,0x06,0xC8,0x06,0x42,0x07,0x28,0x06,0x50,0x06,0x18,0x07,
+0xF0,0x06,0xA0,0x06,0x00,0x00,0xF4,0x08,0xF4,0x08,0xD4,0x0D,0x04,0x09,0x04,0x09,
+0x04,0x09,0x04,0x09,0x42,0x00,0x0C,0x09,0x1C,0x09,0xE5,0x0D,0x02,0x00,0x14,0x09,
+0x04,0x09,0xF4,0x0D,0x43,0x00,0x1C,0x09,0x0C,0x09,0x05,0x0E,0x00,0x04,0x04,0x09,
+0x14,0x09,0x12,0x0E,0x2C,0x09,0x2C,0x09,0x2C,0x09,0x2C,0x09,0x00,0x00,0x3C,0x09,
+0x6C,0x09,0x1E,0x0E,0x74,0x09,0x74,0x09,0x74,0x09,0x74,0x09,0x00,0x01,0x4C,0x09,
+0x2C,0x09,0x2D,0x0E,0x74,0x09,0x74,0x09,0x74,0x09,0x74,0x09,0x00,0x02,0x5C,0x09,
+0x3C,0x09,0x3D,0x0E,0x74,0x09,0x74,0x09,0x74,0x09,0x74,0x09,0x00,0x03,0x6C,0x09,
+0x4C,0x09,0x4D,0x0E,0x74,0x09,0x74,0x09,0x74,0x09,0x74,0x09,0xFF,0x00,0x2C,0x09,
+0x5C,0x09,0x00,0x00,0x00,0x05,0x84,0x09,0xEC,0x09,0x5E,0x0E,0xF4,0x09,0xF4,0x09,
+0xF4,0x09,0xF4,0x09,0x00,0x06,0x94,0x09,0x74,0x09,0x68,0x0E,0xAC,0x0A,0xAC,0x0A,
+0xAC,0x0A,0xAC,0x0A,0x00,0x07,0xA4,0x09,0x84,0x09,0x72,0x0E,0xBC,0x0A,0xBC,0x0A,
+0xBC,0x0A,0xBC,0x0A,0x00,0x08,0xB4,0x09,0x94,0x09,0x7C,0x0E,0xD4,0x0A,0xD4,0x0A,
+0xD4,0x0A,0xD4,0x0A,0x00,0x0B,0xC4,0x09,0xA4,0x09,0x83,0x0E,0xFC,0x0A,0xFC,0x0A,
+0xFC,0x0A,0xFC,0x0A,0x00,0x0C,0xD4,0x09,0xB4,0x09,0x90,0x0E,0x14,0x0B,0x14,0x0B,
+0x14,0x0B,0x14,0x0B,0x00,0x02,0xE4,0x09,0xC4,0x09,0xA0,0x0E,0x2C,0x0B,0x2C,0x0B,
+0x2C,0x0B,0x2C,0x0B,0x04,0x00,0xEC,0x09,0xD4,0x09,0x0E,0x00,0xFF,0x00,0x74,0x09,
+0xE4,0x09,0x00,0x00,0x82,0x01,0xFC,0x09,0xA4,0x0A,0xAC,0x0E,0x82,0x02,0x04,0x0A,
+0xF4,0x09,0xAF,0x0E,0x82,0x03,0x0C,0x0A,0xFC,0x09,0xB2,0x0E,0x82,0x04,0x14,0x0A,
+0x04,0x0A,0xB6,0x0E,0x82,0x05,0x1C,0x0A,0x0C,0x0A,0xBC,0x0E,0x82,0x06,0x24,0x0A,
+0x14,0x0A,0xC0,0x0E,0x82,0x07,0x2C,0x0A,0x1C,0x0A,0xC4,0x0E,0x82,0x08,0x34,0x0A,
+0x24,0x0A,0xC8,0x0E,0x82,0x09,0x3C,0x0A,0x2C,0x0A,0xCC,0x0E,0x82,0x0A,0x44,0x0A,
+0x34,0x0A,0xD1,0x0E,0x82,0x10,0x4C,0x0A,0x3C,0x0A,0xD6,0x0E,0x82,0x0B,0x54,0x0A,
+0x44,0x0A,0xDB,0x0E,0x82,0x11,0x5C,0x0A,0x4C,0x0A,0xE0,0x0E,0x82,0x0C,0x64,0x0A,
+0x54,0x0A,0xE5,0x0E,0x82,0x12,0x6C,0x0A,0x5C,0x0A,0xEA,0x0E,0x82,0x0D,0x74,0x0A,
+0x64,0x0A,0xEF,0x0E,0x82,0x0E,0x7C,0x0A,0x6C,0x0A,0xF4,0x0E,0x82,0x0F,0x84,0x0A,
+0x74,0x0A,0xFB,0x0E,0x82,0x13,0x8C,0x0A,0x7C,0x0A,0x02,0x0F,0x82,0x14,0x94,0x0A,
+0x84,0x0A,0x09,0x0F,0x82,0x15,0x9C,0x0A,0x8C,0x0A,0x10,0x0F,0x82,0x16,0xA4,0x0A,
+0x94,0x0A,0x17,0x0F,0x82,0x17,0xF4,0x09,0x9C,0x0A,0x1E,0x0F,0x82,0x02,0xB4,0x0A,
+0xB4,0x0A,0x26,0x0F,0x82,0x03,0xAC,0x0A,0xAC,0x0A,0x2D,0x0F,0x82,0x00,0xC4,0x0A,
+0xCC,0x0A,0x34,0x0F,0x82,0x01,0xCC,0x0A,0xBC,0x0A,0x3F,0x0F,0x82,0x02,0xBC,0x0A,
+0xC4,0x0A,0x4D,0x0F,0x82,0x00,0xDC,0x0A,0xF4,0x0A,0x59,0x0F,0x82,0x01,0xE4,0x0A,
+0xD4,0x0A,0x63,0x0F,0x82,0x02,0xEC,0x0A,0xDC,0x0A,0x6E,0x0F,0x82,0x03,0xF4,0x0A,
+0xE4,0x0A,0x7A,0x0F,0x82,0x04,0xD4,0x0A,0xEC,0x0A,0x87,0x0F,0x82,0x00,0x04,0x0B,
+0x0C,0x0B,0x93,0x0F,0x82,0x01,0x0C,0x0B,0xFC,0x0A,0x9B,0x0F,0x82,0x02,0xFC,0x0A,
+0x04,0x0B,0xA7,0x0F,0x82,0x00,0x1C,0x0B,0x24,0x0B,0xB0,0x0F,0x82,0x01,0x24,0x0B,
+0x14,0x0B,0xB5,0x0F,0x82,0x02,0x14,0x0B,0x1C,0x0B,0xBE,0x0F,0x44,0x00,0x34,0x0B,
+0xA4,0x0B,0x9C,0x01,0x44,0x01,0x3C,0x0B,0x2C,0x0B,0xA3,0x01,0x44,0x02,0x44,0x0B,
+0x34,0x0B,0xAA,0x01,0x44,0x03,0x4C,0x0B,0x3C,0x0B,0xB1,0x01,0x44,0x04,0x54,0x0B,
+0x44,0x0B,0xB8,0x01,0x44,0x05,0x5C,0x0B,0x4C,0x0B,0xBF,0x01,0x44,0x06,0x64,0x0B,
+0x54,0x0B,0xC6,0x01,0x44,0x07,0x6C,0x0B,0x5C,0x0B,0xCD,0x01,0x44,0x08,0x74,0x0B,
+0x64,0x0B,0xD4,0x01,0x44,0x09,0x7C,0x0B,0x6C,0x0B,0xDB,0x01,0x44,0x0A,0x84,0x0B,
+0x74,0x0B,0xE2,0x01,0x44,0x0B,0x8C,0x0B,0x7C,0x0B,0xEA,0x01,0x44,0x0C,0x94,0x0B,
+0x84,0x0B,0xF2,0x01,0x44,0x0D,0x9C,0x0B,0x8C,0x0B,0xFA,0x01,0x44,0x0E,0xA4,0x0B,
+0x94,0x0B,0x02,0x02,0x44,0x0F,0x2C,0x0B,0x9C,0x0B,0x0A,0x02,0x17,0x1F,0x0F,0x2F,
+0x00,0x00,0x01,0x80,0x78,0x78,0x3A,0x20,0x74,0x78,0x20,0x63,0x70,0x73,0x20,0x2A,
+0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0x80,0x78,0x78,0x3A,0x20,0x74,0x78,0x20,0x63,
+0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0x80,0x78,0x78,0x3A,0x20,
+0x74,0x78,0x20,0x63,0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0x80,
+0x78,0x78,0x3A,0x20,0x74,0x78,0x20,0x63,0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A,
+0x02,0x00,0x01,0xC0,0x78,0x78,0x3A,0x20,0x72,0x63,0x20,0x63,0x70,0x73,0x20,0x2A,
+0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0xC0,0x78,0x78,0x3A,0x20,0x72,0x63,0x20,0x63,
+0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0xC0,0x78,0x78,0x3A,0x20,
+0x72,0x63,0x20,0x63,0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0xC0,
+0x78,0x78,0x3A,0x20,0x72,0x63,0x20,0x63,0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A,
+0x02,0x00,0x01,0x80,0x49,0x6E,0x73,0x74,0x61,0x6C,0x6C,0x20,0x4C,0x6F,0x6F,0x70,
+0x62,0x61,0x63,0x6B,0x1F,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x20,0x74,0x6F,0x20,
+0x73,0x74,0x61,0x72,0x74,0x02,0x00,0x01,0x80,0x20,0x43,0x61,0x62,0x6C,0x65,0x20,
+0x74,0x6F,0x20,0x52,0x65,0x6D,0x6F,0x74,0x65,0x1F,0x50,0x72,0x65,0x73,0x73,0x20,
+0x80,0x20,0x74,0x6F,0x20,0x73,0x74,0x61,0x72,0x74,0x02,0x00,0x01,0x80,0x20,0x4C,
+0x6F,0x63,0x61,0x6C,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,0x63,0x6B,0x20,0x1F,0x20,
+0x20,0x52,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x2E,0x2E,0x2E,0x02,0x00,0x01,0x80,
+0x52,0x65,0x6D,0x6F,0x74,0x65,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,0x63,0x6B,0x20,
+0x1F,0x20,0x20,0x52,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x2E,0x2E,0x2E,0x02,0x00,
+0x01,0x80,0x20,0x49,0x6E,0x74,0x72,0x6E,0x6C,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,
+0x63,0x6B,0x1F,0x20,0x20,0x52,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x2E,0x2E,0x2E,
+0x02,0x00,0x01,0x80,0x54,0x72,0x61,0x6E,0x73,0x6D,0x69,0x74,0x20,0x50,0x61,0x74,
+0x74,0x65,0x72,0x6E,0x1F,0x20,0x20,0x52,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x2E,
+0x2E,0x2E,0x02,0x00,0x01,0x80,0x20,0x20,0x30,0x3A,0x20,0x27,0x43,0x80,0x00,0x01,
+0x80,0x20,0x20,0x31,0x3A,0x20,0x27,0x43,0x81,0x00,0x01,0x80,0x20,0x20,0x32,0x3A,
+0x20,0x27,0x43,0x82,0x00,0x01,0x80,0x20,0x20,0x33,0x3A,0x20,0x27,0x43,0x83,0x00,
+0x01,0x80,0x20,0x20,0x34,0x3A,0x20,0x27,0x43,0x84,0x00,0x01,0x80,0x20,0x20,0x35,
+0x3A,0x20,0x27,0x43,0x85,0x00,0x01,0x80,0x20,0x20,0x36,0x3A,0x20,0x27,0x43,0x86,
+0x00,0x01,0x80,0x20,0x20,0x37,0x3A,0x20,0x27,0x43,0x87,0x00,0x01,0x80,0x20,0x20,
+0x38,0x3A,0x20,0x27,0x43,0x88,0x00,0x01,0x80,0x20,0x20,0x39,0x3A,0x20,0x27,0x43,
+0x89,0x00,0x01,0x80,0x20,0x31,0x30,0x3A,0x20,0x27,0x43,0x8A,0x00,0x01,0x80,0x20,
+0x31,0x31,0x3A,0x20,0x27,0x43,0x8B,0x00,0x01,0x80,0x20,0x31,0x32,0x3A,0x20,0x27,
+0x43,0x8C,0x00,0x01,0x80,0x20,0x31,0x33,0x3A,0x20,0x27,0x43,0x8D,0x00,0x01,0x80,
+0x20,0x31,0x34,0x3A,0x20,0x27,0x43,0x8E,0x00,0x01,0x80,0x20,0x31,0x35,0x3A,0x20,
+0x27,0x43,0x8F,0x00,0x2A,0x2A,0x20,0x4D,0x61,0x69,0x6E,0x20,0x20,0x4D,0x65,0x6E,
+0x75,0x20,0x2A,0x2A,0x00,0x4D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x20,0x61,0x20,0x50,
+0x6F,0x72,0x74,0x00,0x4D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x20,0x61,0x20,0x53,0x69,
+0x67,0x6E,0x61,0x6C,0x00,0x45,0x73,0x74,0x69,0x6D,0x61,0x74,0x65,0x20,0x43,0x50,
+0x53,0x00,0x44,0x69,0x61,0x67,0x6E,0x6F,0x73,0x74,0x69,0x63,0x73,0x00,0x4C,0x6F,
+0x63,0x61,0x6C,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,0x63,0x6B,0x00,0x52,0x65,0x6D,
+0x6F,0x74,0x65,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,0x63,0x6B,0x00,0x49,0x6E,0x74,
+0x72,0x6E,0x6C,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,0x63,0x6B,0x00,0x54,0x72,0x61,
+0x6E,0x73,0x6D,0x69,0x74,0x20,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x00,0x42,0x61,
+0x75,0x64,0x20,0x52,0x61,0x74,0x65,0x00,0x44,0x61,0x74,0x61,0x20,0x42,0x69,0x74,
+0x73,0x00,0x53,0x74,0x6F,0x70,0x20,0x42,0x69,0x74,0x73,0x00,0x50,0x61,0x72,0x69,
+0x74,0x79,0x00,0x44,0x61,0x74,0x61,0x20,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x00,
+0x54,0x78,0x20,0x46,0x6C,0x6F,0x77,0x20,0x43,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x00,
+0x50,0x6F,0x72,0x74,0x20,0x4E,0x75,0x6D,0x62,0x65,0x72,0x00,0x35,0x30,0x00,0x37,
+0x35,0x00,0x31,0x31,0x30,0x00,0x31,0x33,0x34,0x2E,0x35,0x00,0x31,0x35,0x30,0x00,
+0x32,0x30,0x30,0x00,0x33,0x30,0x30,0x00,0x36,0x30,0x30,0x00,0x31,0x32,0x30,0x30,
+0x00,0x31,0x38,0x30,0x30,0x00,0x32,0x30,0x30,0x30,0x00,0x32,0x34,0x30,0x30,0x00,
+0x33,0x36,0x30,0x30,0x00,0x34,0x38,0x30,0x30,0x00,0x37,0x32,0x30,0x30,0x00,0x39,
+0x36,0x30,0x30,0x00,0x31,0x39,0x2C,0x32,0x30,0x30,0x00,0x33,0x38,0x2C,0x34,0x30,
+0x30,0x00,0x35,0x36,0x2C,0x30,0x30,0x30,0x00,0x35,0x37,0x2C,0x36,0x30,0x30,0x00,
+0x36,0x34,0x2C,0x30,0x30,0x30,0x00,0x37,0x36,0x2C,0x38,0x30,0x30,0x00,0x31,0x31,
+0x35,0x2C,0x32,0x30,0x30,0x00,0x37,0x20,0x62,0x69,0x74,0x73,0x00,0x38,0x20,0x62,
+0x69,0x74,0x73,0x00,0x31,0x20,0x73,0x74,0x6F,0x70,0x20,0x62,0x69,0x74,0x00,0x31,
+0x2E,0x35,0x20,0x73,0x74,0x6F,0x70,0x20,0x62,0x69,0x74,0x73,0x00,0x32,0x20,0x73,
+0x74,0x6F,0x70,0x20,0x62,0x69,0x74,0x73,0x00,0x6E,0x6F,0x20,0x70,0x61,0x72,0x69,
+0x74,0x79,0x00,0x6F,0x64,0x64,0x20,0x70,0x61,0x72,0x69,0x74,0x79,0x00,0x65,0x76,
+0x65,0x6E,0x20,0x70,0x61,0x72,0x69,0x74,0x79,0x00,0x73,0x70,0x61,0x63,0x65,0x20,
+0x70,0x61,0x72,0x69,0x74,0x79,0x00,0x6D,0x61,0x72,0x6B,0x20,0x70,0x61,0x72,0x69,
+0x74,0x79,0x00,0x43,0x6F,0x6C,0x75,0x6D,0x6E,0x73,0x00,0x42,0x61,0x72,0x62,0x65,
+0x72,0x20,0x50,0x6F,0x6C,0x65,0x00,0x55,0x55,0x55,0x55,0x55,0x2E,0x2E,0x2E,0x00,
+0x4E,0x6F,0x6E,0x65,0x00,0x58,0x6F,0x6E,0x2F,0x58,0x6F,0x66,0x66,0x00,0x43,0x54,
+0x53,0x00,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x20,0x66,0x6F,0x72,0x20,0x6D,0x65,
+0x6E,0x75,0x00,0x28,0x63,0x6F,0x75,0x6E,0x74,0x69,0x6E,0x67,0x2E,0x2E,0x2E,0x29,
+0x00,0x00,0x65,0x4E,0x64,0x20,0x4F,0x66,0x20,0x43,0x6F,0x44,0x65,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,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,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,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,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,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,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,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,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
diff --git a/drivers/char/ip2/i2cmd.c b/drivers/char/ip2/i2cmd.c
new file mode 100644
index 000000000..ce4216631
--- /dev/null
+++ b/drivers/char/ip2/i2cmd.c
@@ -0,0 +1,264 @@
+/*******************************************************************************
+*
+* (c) 1998 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Definition table for In-line and Bypass commands. Applicable
+* only when the standard loadware is active. (This is included
+* source code, not a separate compilation module.)
+*
+*******************************************************************************/
+
+//------------------------------------------------------------------------------
+//
+// Revision History:
+//
+// 10 October 1991 MAG First Draft
+// 7 November 1991 MAG Reflects additional commands.
+// 24 February 1992 MAG Additional commands for 1.4.x loadware
+// 11 March 1992 MAG Additional commands
+// 30 March 1992 MAG Additional command: CMD_DSS_NOW
+// 18 May 1992 MAG Discovered commands 39 & 40 must be at the end of a
+// packet: affects implementation.
+//------------------------------------------------------------------------------
+
+//************
+//* Includes *
+//************
+
+#include "i2cmd.h" /* To get some bit-defines */
+
+//------------------------------------------------------------------------------
+// Here is the table of global arrays which represent each type of command
+// supported in the IntelliPort standard loadware. See also i2cmd.h
+// for a more complete explanation of what is going on.
+//------------------------------------------------------------------------------
+
+// Here are the various globals: note that the names are not used except through
+// the macros defined in i2cmd.h. Also note that although they are character
+// arrays here (for extendability) they are cast to structure pointers in the
+// i2cmd.h macros. See i2cmd.h for flags definitions.
+
+// Length Flags Command
+static UCHAR ct02[] = { 1, BTH, 0x02 }; // DTR UP
+static UCHAR ct03[] = { 1, BTH, 0x03 }; // DTR DN
+static UCHAR ct04[] = { 1, BTH, 0x04 }; // RTS UP
+static UCHAR ct05[] = { 1, BTH, 0x05 }; // RTS DN
+static UCHAR ct06[] = { 1, BYP, 0x06 }; // START FL
+static UCHAR ct07[] = { 2, BTH, 0x07,0 }; // BAUD
+static UCHAR ct08[] = { 2, BTH, 0x08,0 }; // BITS
+static UCHAR ct09[] = { 2, BTH, 0x09,0 }; // STOP
+static UCHAR ct10[] = { 2, BTH, 0x0A,0 }; // PARITY
+static UCHAR ct11[] = { 2, BTH, 0x0B,0 }; // XON
+static UCHAR ct12[] = { 2, BTH, 0x0C,0 }; // XOFF
+static UCHAR ct13[] = { 1, BTH, 0x0D }; // STOP FL
+static UCHAR ct14[] = { 1, BYP|VIP, 0x0E }; // ACK HOTK
+//static UCHAR ct15[]={ 2, BTH|VIP, 0x0F,0 }; // IRQ SET
+static UCHAR ct16[] = { 2, INL, 0x10,0 }; // IXONOPTS
+static UCHAR ct17[] = { 2, INL, 0x11,0 }; // OXONOPTS
+static UCHAR ct18[] = { 1, INL, 0x12 }; // CTSENAB
+static UCHAR ct19[] = { 1, BTH, 0x13 }; // CTSDSAB
+static UCHAR ct20[] = { 1, INL, 0x14 }; // DCDENAB
+static UCHAR ct21[] = { 1, BTH, 0x15 }; // DCDDSAB
+static UCHAR ct22[] = { 1, BTH, 0x16 }; // DSRENAB
+static UCHAR ct23[] = { 1, BTH, 0x17 }; // DSRDSAB
+static UCHAR ct24[] = { 1, BTH, 0x18 }; // RIENAB
+static UCHAR ct25[] = { 1, BTH, 0x19 }; // RIDSAB
+static UCHAR ct26[] = { 2, BTH, 0x1A,0 }; // BRKENAB
+static UCHAR ct27[] = { 1, BTH, 0x1B }; // BRKDSAB
+//static UCHAR ct28[]={ 2, BTH, 0x1C,0 }; // MAXBLOKSIZE
+//static UCHAR ct29[]={ 2, 0, 0x1D,0 }; // reserved
+static UCHAR ct30[] = { 1, INL, 0x1E }; // CTSFLOWENAB
+static UCHAR ct31[] = { 1, INL, 0x1F }; // CTSFLOWDSAB
+static UCHAR ct32[] = { 1, INL, 0x20 }; // RTSFLOWENAB
+static UCHAR ct33[] = { 1, INL, 0x21 }; // RTSFLOWDSAB
+static UCHAR ct34[] = { 2, BTH, 0x22,0 }; // ISTRIPMODE
+static UCHAR ct35[] = { 2, BTH|END, 0x23,0 }; // SENDBREAK
+static UCHAR ct36[] = { 2, BTH, 0x24,0 }; // SETERRMODE
+//static UCHAR ct36a[]={ 3, INL, 0x24,0,0 }; // SET_REPLACE
+
+// The following is listed for completeness, but should never be sent directly
+// by user-level code. It is sent only by library routines in response to data
+// movement.
+//static UCHAR ct37[]={ 5, BYP|VIP, 0x25,0,0,0,0 }; // FLOW PACKET
+
+// Back to normal
+static UCHAR ct38[] = {11, BTH|VAR, 0x26,0,0,0,0,0,0,0,0,0,0 }; // DEF KEY SEQ
+//static UCHAR ct39[]={ 3, BTH|END, 0x27,0,0 }; // OPOSTON
+//static UCHAR ct40[]={ 1, BTH|END, 0x28 }; // OPOSTOFF
+static UCHAR ct41[] = { 1, BYP, 0x29 }; // RESUME
+//static UCHAR ct42[]={ 2, BTH, 0x2A,0 }; // TXBAUD
+//static UCHAR ct43[]={ 2, BTH, 0x2B,0 }; // RXBAUD
+//static UCHAR ct44[]={ 2, BTH, 0x2C,0 }; // MS PING
+//static UCHAR ct45[]={ 1, BTH, 0x2D }; // HOTENAB
+//static UCHAR ct46[]={ 1, BTH, 0x2E }; // HOTDSAB
+static UCHAR ct47[] = { 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS
+//static UCHAR ct48[]={ 1, BTH, 0x30 }; // DSRFLOWENAB
+//static UCHAR ct49[]={ 1, BTH, 0x31 }; // DSRFLOWDSAB
+//static UCHAR ct50[]={ 1, BTH, 0x32 }; // DTRFLOWENAB
+//static UCHAR ct51[]={ 1, BTH, 0x33 }; // DTRFLOWDSAB
+//static UCHAR ct52[]={ 1, BTH, 0x34 }; // BAUDTABRESET
+static UCHAR ct53[] = { 3, BTH, 0x35,0,0 }; // BAUDREMAP
+static UCHAR ct54[] = { 3, BTH, 0x36,0,0 }; // CUSTOMBAUD1
+static UCHAR ct55[] = { 3, BTH, 0x37,0,0 }; // CUSTOMBAUD2
+static UCHAR ct56[] = { 2, BTH|END, 0x38,0 }; // PAUSE
+static UCHAR ct57[] = { 1, BYP, 0x39 }; // SUSPEND
+static UCHAR ct58[] = { 1, BYP, 0x3A }; // UNSUSPEND
+static UCHAR ct59[] = { 2, BTH, 0x3B,0 }; // PARITYCHK
+static UCHAR ct60[] = { 1, INL|VIP, 0x3C }; // BOOKMARKREQ
+//static UCHAR ct61[]={ 2, BTH, 0x3D,0 }; // INTERNALLOOP
+//static UCHAR ct62[]={ 2, BTH, 0x3E,0 }; // HOTKTIMEOUT
+static UCHAR ct63[] = { 2, INL, 0x3F,0 }; // SETTXON
+static UCHAR ct64[] = { 2, INL, 0x40,0 }; // SETTXOFF
+//static UCHAR ct65[]={ 2, BTH, 0x41,0 }; // SETAUTORTS
+//static UCHAR ct66[]={ 2, BTH, 0x42,0 }; // SETHIGHWAT
+//static UCHAR ct67[]={ 2, BYP, 0x43,0 }; // STARTSELFL
+//static UCHAR ct68[]={ 2, INL, 0x44,0 }; // ENDSELFL
+//static UCHAR ct69[]={ 1, BYP, 0x45 }; // HWFLOW_OFF
+//static UCHAR ct70[]={ 1, BTH, 0x46 }; // ODSRFL_ENAB
+//static UCHAR ct71[]={ 1, BTH, 0x47 }; // ODSRFL_DSAB
+//static UCHAR ct72[]={ 1, BTH, 0x48 }; // ODCDFL_ENAB
+//static UCHAR ct73[]={ 1, BTH, 0x49 }; // ODCDFL_DSAB
+//static UCHAR ct74[]={ 2, BTH, 0x4A,0 }; // LOADLEVEL
+//static UCHAR ct75[]={ 2, BTH, 0x4B,0 }; // STATDATA
+//static UCHAR ct76[]={ 1, BYP, 0x4C }; // BREAK_ON
+//static UCHAR ct77[]={ 1, BYP, 0x4D }; // BREAK_OFF
+//static UCHAR ct78[]={ 1, BYP, 0x4E }; // GETFC
+static UCHAR ct79[] = { 2, BYP, 0x4F,0 }; // XMIT_NOW
+//static UCHAR ct80[]={ 4, BTH, 0x50,0,0,0 }; // DIVISOR_LATCH
+//static UCHAR ct81[]={ 1, BYP, 0x51 }; // GET_STATUS
+//static UCHAR ct82[]={ 1, BYP, 0x52 }; // GET_TXCNT
+//static UCHAR ct83[]={ 1, BYP, 0x53 }; // GET_RXCNT
+//static UCHAR ct84[]={ 1, BYP, 0x54 }; // GET_BOXIDS
+//static UCHAR ct85[]={10, BYP, 0x55,0,0,0,0,0,0,0,0,0 }; // ENAB_MULT
+//static UCHAR ct86[]={ 2, BTH, 0x56,0 }; // RCV_ENABLE
+static UCHAR ct87[] = { 1, BYP, 0x57 }; // HW_TEST
+//static UCHAR ct88[]={ 3, BTH, 0x58,0,0 }; // RCV_THRESHOLD
+//static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW
+//static UCHAR ct90[]={ 3, BYP, 0x5A,0,0 }; // Set SILO
+//static UCHAR ct91[]={ 2, BYP, 0x5B,0 }; // timed break
+
+// Some composite commands as well
+//static UCHAR cc01[]={ 2, BTH, 0x02,0x04 }; // DTR & RTS UP
+//static UCHAR cc02[]={ 2, BTH, 0x03,0x05 }; // DTR & RTS DN
+
+//********
+//* Code *
+//********
+
+//******************************************************************************
+// Function: i2cmdSetSeq(type, size, string)
+// Parameters: type - sequence number
+// size - length of sequence
+// string - substitution string
+//
+// Returns: Pointer to command structure
+//
+// Description:
+//
+// This routine sets the parameters of command 38 Define Hot Key sequence (alias
+// "special receive sequence"). Returns a pointer to the structure. Endeavours
+// to be bullet-proof in that the sequence number is forced in range, and any
+// out-of-range sizes are forced to zero.
+//******************************************************************************
+cmdSyntaxPtr
+i2cmdSetSeq(unsigned char type, unsigned char size, unsigned char *string)
+{
+ cmdSyntaxPtr pCM = (cmdSyntaxPtr) ct38;
+ unsigned char *pc;
+
+ pCM->cmd[1] = ((type > 0xf) ? 0xf : type); // Sequence number
+ size = ((size > 0x8) ? 0 : size); // size
+ pCM->cmd[2] = size;
+ pCM->length = 3 + size; // UPDATES THE LENGTH!
+
+ pc = &(pCM->cmd[3]);
+
+ while(size--) {
+ *pc++ = *string++;
+ }
+ return pCM;
+}
+
+//******************************************************************************
+// Function: i2cmdUnixFlags(iflag, cflag, lflag)
+// Parameters: Unix tty flags
+//
+// Returns: Pointer to command structure
+//
+// Description:
+//
+// This routine sets the parameters of command 47 and returns a pointer to the
+// appropriate structure.
+//******************************************************************************
+cmdSyntaxPtr
+i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag)
+{
+ cmdSyntaxPtr pCM = (cmdSyntaxPtr) ct47;
+
+ pCM->cmd[1] = (unsigned char) iflag;
+ pCM->cmd[2] = (unsigned char) (iflag >> 8);
+ pCM->cmd[3] = (unsigned char) cflag;
+ pCM->cmd[4] = (unsigned char) (cflag >> 8);
+ pCM->cmd[5] = (unsigned char) lflag;
+ pCM->cmd[6] = (unsigned char) (lflag >> 8);
+ return pCM;
+}
+
+//******************************************************************************
+// Function: i2cmdBaudRemap(dest,src)
+// Parameters: ?
+//
+// Returns: Pointer to command structure
+//
+// Description:
+//
+// This routine sets the parameters of command 53 and returns a pointer to the
+// appropriate structure.
+//******************************************************************************
+cmdSyntaxPtr
+i2cmdBaudRemap(unsigned char dest, unsigned char src)
+{
+ cmdSyntaxPtr pCM = (cmdSyntaxPtr) ct53;
+
+ pCM->cmd[1] = dest;
+ pCM->cmd[2] = src;
+ return pCM;
+}
+
+//******************************************************************************
+// Function: i2cmdBaudDef(which, rate)
+// Parameters: ?
+//
+// Returns: Pointer to command structure
+//
+// Description:
+//
+// This routine sets the parameters of commands 54 or 55 (according to the
+// argument which), and returns a pointer to the appropriate structure.
+//******************************************************************************
+cmdSyntaxPtr
+i2cmdBaudDef(int which, unsigned short rate)
+{
+ cmdSyntaxPtr pCM;
+
+ switch(which)
+ {
+ case 1:
+ pCM = (cmdSyntaxPtr) ct54;
+ break;
+ default:
+ case 2:
+ pCM = (cmdSyntaxPtr) ct55;
+ break;
+ }
+ pCM->cmd[1] = (unsigned char) rate;
+ pCM->cmd[2] = (unsigned char) (rate >> 8);
+ return pCM;
+}
+
diff --git a/drivers/char/ip2/i2cmd.h b/drivers/char/ip2/i2cmd.h
new file mode 100644
index 000000000..83475167f
--- /dev/null
+++ b/drivers/char/ip2/i2cmd.h
@@ -0,0 +1,660 @@
+/*******************************************************************************
+*
+* (c) 1999 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Definitions and support for In-line and Bypass commands.
+* Applicable only when the standard loadware is active.
+*
+*******************************************************************************/
+//------------------------------------------------------------------------------
+// Revision History:
+//
+// 10 October 1991 MAG First Draft
+// 7 November 1991 MAG Reflects some new commands
+// 20 February 1992 MAG CMD_HOTACK corrected: no argument.
+// 24 February 1992 MAG Support added for new commands for 1.4.x loadware.
+// 11 March 1992 MAG Additional commands.
+// 16 March 1992 MAG Additional commands.
+// 30 March 1992 MAG Additional command: CMD_DSS_NOW
+// 18 May 1992 MAG Changed CMD_OPOST
+//
+//------------------------------------------------------------------------------
+#ifndef I2CMD_H // To prevent multiple includes
+#define I2CMD_H 1
+
+#include "ip2types.h"
+
+// This module is designed to provide a uniform method of sending commands to
+// the board through command packets. The difficulty is, some commands take
+// parameters, others do not. Furthermore, it is often useful to send several
+// commands to the same channel as part of the same packet. (See also i2pack.h.)
+//
+// This module is designed so that the caller should not be responsible for
+// remembering the exact syntax of each command, or at least so that the
+// compiler could check things somewhat. I'll explain as we go...
+//
+// First, a structure which can embody the syntax of each type of command.
+//
+typedef struct _cmdSyntax
+{
+ UCHAR length; // Number of bytes in the command
+ UCHAR flags; // Information about the command (see below)
+
+ // The command and its parameters, which may be of arbitrary length. Don't
+ // worry yet how the parameters will be initialized; macros later take care
+ // of it. Also, don't worry about the arbitrary length issue; this structure
+ // is never used to allocate space (see i2cmd.c).
+ UCHAR cmd[2];
+} cmdSyntax, *cmdSyntaxPtr;
+
+// Bit assignments for flags
+
+#define INL 1 // Set if suitable for inline commands
+#define BYP 2 // Set if suitable for bypass commands
+#define BTH (INL|BYP) // suitable for either!
+#define END 4 // Set if this must be the last command in a block
+#define VIP 8 // Set if this command is special in some way and really
+ // should only be sent from the library-level and not
+ // directly from user-level
+#define VAR 0x10 // This command is of variable length!
+
+//-----------------------------------
+// External declarations for i2cmd.c
+//-----------------------------------
+// Routine to set up parameters for the "define hot-key sequence" command. Since
+// there is more than one parameter to assign, we must use a function rather
+// than a macro (used usually).
+//
+extern cmdSyntaxPtr i2cmdSetSeq(UCHAR seqno, UCHAR size, UCHAR *string);
+extern cmdSyntaxPtr i2cmdUnixFlags(USHORT iflag,USHORT cflag,USHORT lflag);
+extern cmdSyntaxPtr i2cmdBaudRemap(UCHAR dest, UCHAR src);
+extern cmdSyntaxPtr i2cmdBaudDef(int which, USHORT rate);
+
+// Declarations for the global arrays used to bear the commands and their
+// arguments.
+//
+// Note: Since these are globals and the arguments might change, it is important
+// that the library routine COPY these into buffers from whence they would be
+// sent, rather than merely storing the pointers. In multi-threaded
+// environments, important that the copy should obtain before any context switch
+// is allowed. Also, for parameterized commands, DO NOT ISSUE THE SAME COMMAND
+// MORE THAN ONCE WITH THE SAME PARAMETERS in the same call.
+//
+static UCHAR ct02[];
+static UCHAR ct03[];
+static UCHAR ct04[];
+static UCHAR ct05[];
+static UCHAR ct06[];
+static UCHAR ct07[];
+static UCHAR ct08[];
+static UCHAR ct09[];
+static UCHAR ct10[];
+static UCHAR ct11[];
+static UCHAR ct12[];
+static UCHAR ct13[];
+static UCHAR ct14[];
+static UCHAR ct15[];
+static UCHAR ct16[];
+static UCHAR ct17[];
+static UCHAR ct18[];
+static UCHAR ct19[];
+static UCHAR ct20[];
+static UCHAR ct21[];
+static UCHAR ct22[];
+static UCHAR ct23[];
+static UCHAR ct24[];
+static UCHAR ct25[];
+static UCHAR ct26[];
+static UCHAR ct27[];
+static UCHAR ct28[];
+static UCHAR ct29[];
+static UCHAR ct30[];
+static UCHAR ct31[];
+static UCHAR ct32[];
+static UCHAR ct33[];
+static UCHAR ct34[];
+static UCHAR ct35[];
+static UCHAR ct36[];
+static UCHAR ct36a[];
+static UCHAR ct41[];
+static UCHAR ct42[];
+static UCHAR ct43[];
+static UCHAR ct44[];
+static UCHAR ct45[];
+static UCHAR ct46[];
+static UCHAR ct48[];
+static UCHAR ct49[];
+static UCHAR ct50[];
+static UCHAR ct51[];
+static UCHAR ct52[];
+static UCHAR ct56[];
+static UCHAR ct57[];
+static UCHAR ct58[];
+static UCHAR ct59[];
+static UCHAR ct60[];
+static UCHAR ct61[];
+static UCHAR ct62[];
+static UCHAR ct63[];
+static UCHAR ct64[];
+static UCHAR ct65[];
+static UCHAR ct66[];
+static UCHAR ct67[];
+static UCHAR ct68[];
+static UCHAR ct69[];
+static UCHAR ct70[];
+static UCHAR ct71[];
+static UCHAR ct72[];
+static UCHAR ct73[];
+static UCHAR ct74[];
+static UCHAR ct75[];
+static UCHAR ct76[];
+static UCHAR ct77[];
+static UCHAR ct78[];
+static UCHAR ct79[];
+static UCHAR ct80[];
+static UCHAR ct81[];
+static UCHAR ct82[];
+static UCHAR ct83[];
+static UCHAR ct84[];
+static UCHAR ct85[];
+static UCHAR ct86[];
+static UCHAR ct87[];
+static UCHAR ct88[];
+static UCHAR ct89[];
+static UCHAR ct90[];
+static UCHAR ct91[];
+static UCHAR cc01[];
+static UCHAR cc02[];
+
+// Now, refer to i2cmd.c, and see the character arrays defined there. They are
+// cast here to cmdSyntaxPtr.
+//
+// There are library functions for issuing bypass or inline commands. These
+// functions take one or more arguments of the type cmdSyntaxPtr. The routine
+// then can figure out how long each command is supposed to be and easily add it
+// to the list.
+//
+// For ease of use, we define manifests which return pointers to appropriate
+// cmdSyntaxPtr things. But some commands also take arguments. If a single
+// argument is used, we define a macro which performs the single assignment and
+// (through the expedient of a comma expression) references the appropriate
+// pointer. For commands requiring several arguments, we actually define a
+// function to perform the assignments.
+
+#define CMD_DTRUP (cmdSyntaxPtr)(ct02) // Raise DTR
+#define CMD_DTRDN (cmdSyntaxPtr)(ct03) // Lower DTR
+#define CMD_RTSUP (cmdSyntaxPtr)(ct04) // Raise RTS
+#define CMD_RTSDN (cmdSyntaxPtr)(ct05) // Lower RTS
+#define CMD_STARTFL (cmdSyntaxPtr)(ct06) // Start Flushing Data
+
+#define CMD_DTRRTS_UP (cmdSyntaxPtr)(cc01) // Raise DTR and RTS
+#define CMD_DTRRTS_DN (cmdSyntaxPtr)(cc02) // Lower DTR and RTS
+
+// Set Baud Rate for transmit and receive
+#define CMD_SETBAUD(arg) \
+ (((cmdSyntaxPtr)(ct07))->cmd[1] = (arg),(cmdSyntaxPtr)(ct07))
+
+#define CBR_50 1
+#define CBR_75 2
+#define CBR_110 3
+#define CBR_134 4
+#define CBR_150 5
+#define CBR_200 6
+#define CBR_300 7
+#define CBR_600 8
+#define CBR_1200 9
+#define CBR_1800 10
+#define CBR_2400 11
+#define CBR_4800 12
+#define CBR_9600 13
+#define CBR_19200 14
+#define CBR_38400 15
+#define CBR_2000 16
+#define CBR_3600 17
+#define CBR_7200 18
+#define CBR_56000 19
+#define CBR_57600 20
+#define CBR_64000 21
+#define CBR_76800 22
+#define CBR_115200 23
+#define CBR_C1 24 // Custom baud rate 1
+#define CBR_C2 25 // Custom baud rate 2
+#define CBR_153600 26
+#define CBR_230400 27
+#define CBR_307200 28
+#define CBR_460800 29
+#define CBR_921600 30
+
+// Set Character size
+//
+#define CMD_SETBITS(arg) \
+ (((cmdSyntaxPtr)(ct08))->cmd[1] = (arg),(cmdSyntaxPtr)(ct08))
+
+#define CSZ_5 0
+#define CSZ_6 1
+#define CSZ_7 2
+#define CSZ_8 3
+
+// Set number of stop bits
+//
+#define CMD_SETSTOP(arg) \
+ (((cmdSyntaxPtr)(ct09))->cmd[1] = (arg),(cmdSyntaxPtr)(ct09))
+
+#define CST_1 0
+#define CST_15 1 // 1.5 stop bits
+#define CST_2 2
+
+// Set parity option
+//
+#define CMD_SETPAR(arg) \
+ (((cmdSyntaxPtr)(ct10))->cmd[1] = (arg),(cmdSyntaxPtr)(ct10))
+
+#define CSP_NP 0 // no parity
+#define CSP_OD 1 // odd parity
+#define CSP_EV 2 // Even parity
+#define CSP_SP 3 // Space parity
+#define CSP_MK 4 // Mark parity
+
+// Define xon char for transmitter flow control
+//
+#define CMD_DEF_IXON(arg) \
+ (((cmdSyntaxPtr)(ct11))->cmd[1] = (arg),(cmdSyntaxPtr)(ct11))
+
+// Define xoff char for transmitter flow control
+//
+#define CMD_DEF_IXOFF(arg) \
+ (((cmdSyntaxPtr)(ct12))->cmd[1] = (arg),(cmdSyntaxPtr)(ct12))
+
+#define CMD_STOPFL (cmdSyntaxPtr)(ct13) // Stop Flushing data
+
+// Acknowledge receipt of hotkey signal
+//
+#define CMD_HOTACK (cmdSyntaxPtr)(ct14)
+
+// Define irq level to use. Should actually be sent by library-level code, not
+// directly from user...
+//
+#define CMDVALUE_IRQ 15 // For library use at initialization. Until this command
+ // is sent, board processing doesn't really start.
+#define CMD_SET_IRQ(arg) \
+ (((cmdSyntaxPtr)(ct15))->cmd[1] = (arg),(cmdSyntaxPtr)(ct15))
+
+#define CIR_POLL 0 // No IRQ - Poll
+#define CIR_3 3 // IRQ 3
+#define CIR_4 4 // IRQ 4
+#define CIR_5 5 // IRQ 5
+#define CIR_7 7 // IRQ 7
+#define CIR_10 10 // IRQ 10
+#define CIR_11 11 // IRQ 11
+#define CIR_12 12 // IRQ 12
+#define CIR_15 15 // IRQ 15
+
+// Select transmit flow xon/xoff options
+//
+#define CMD_IXON_OPT(arg) \
+ (((cmdSyntaxPtr)(ct16))->cmd[1] = (arg),(cmdSyntaxPtr)(ct16))
+
+#define CIX_NONE 0 // Incoming Xon/Xoff characters not special
+#define CIX_XON 1 // Xoff disable, Xon enable
+#define CIX_XANY 2 // Xoff disable, any key enable
+
+// Select receive flow xon/xoff options
+//
+#define CMD_OXON_OPT(arg) \
+ (((cmdSyntaxPtr)(ct17))->cmd[1] = (arg),(cmdSyntaxPtr)(ct17))
+
+#define COX_NONE 0 // Don't send Xon/Xoff
+#define COX_XON 1 // Send xon/xoff to start/stop incoming data
+
+
+#define CMD_CTS_REP (cmdSyntaxPtr)(ct18) // Enable CTS reporting
+#define CMD_CTS_NREP (cmdSyntaxPtr)(ct19) // Disable CTS reporting
+
+#define CMD_DCD_REP (cmdSyntaxPtr)(ct20) // Enable DCD reporting
+#define CMD_DCD_NREP (cmdSyntaxPtr)(ct21) // Disable DCD reporting
+
+#define CMD_DSR_REP (cmdSyntaxPtr)(ct22) // Enable DSR reporting
+#define CMD_DSR_NREP (cmdSyntaxPtr)(ct23) // Disable DSR reporting
+
+#define CMD_RI_REP (cmdSyntaxPtr)(ct24) // Enable RI reporting
+#define CMD_RI_NREP (cmdSyntaxPtr)(ct25) // Disable RI reporting
+
+// Enable break reporting and select style
+//
+#define CMD_BRK_REP(arg) \
+ (((cmdSyntaxPtr)(ct26))->cmd[1] = (arg),(cmdSyntaxPtr)(ct26))
+
+#define CBK_STAT 0x00 // Report breaks as a status (exception,irq)
+#define CBK_NULL 0x01 // Report breaks as a good null
+#define CBK_STAT_SEQ 0x02 // Report breaks as a status AND as in-band character
+ // sequence FFh, 01h, 10h
+#define CBK_SEQ 0x03 // Report breaks as the in-band
+ //sequence FFh, 01h, 10h ONLY.
+#define CBK_FLSH 0x04 // if this bit set also flush input data
+#define CBK_POSIX 0x08 // if this bit set report as FF,0,0 sequence
+#define CBK_SINGLE 0x10 // if this bit set with CBK_SEQ or CBK_STAT_SEQ
+ //then reports single null instead of triple
+
+#define CMD_BRK_NREP (cmdSyntaxPtr)(ct27) // Disable break reporting
+
+// Specify maximum block size for received data
+//
+#define CMD_MAX_BLOCK(arg) \
+ (((cmdSyntaxPtr)(ct28))->cmd[1] = (arg),(cmdSyntaxPtr)(ct28))
+
+// -- COMMAND 29 is reserved --
+
+#define CMD_CTSFL_ENAB (cmdSyntaxPtr)(ct30) // Enable CTS flow control
+#define CMD_CTSFL_DSAB (cmdSyntaxPtr)(ct31) // Disable CTS flow control
+#define CMD_RTSFL_ENAB (cmdSyntaxPtr)(ct32) // Enable RTS flow control
+#define CMD_RTSFL_DSAB (cmdSyntaxPtr)(ct33) // Disable RTS flow control
+
+// Specify istrip option
+//
+#define CMD_ISTRIP_OPT(arg) \
+ (((cmdSyntaxPtr)(ct34))->cmd[1] = (arg),(cmdSyntaxPtr)(ct34))
+
+#define CIS_NOSTRIP 0 // Strip characters to character size
+#define CIS_STRIP 1 // Strip any 8-bit characters to 7 bits
+
+// Send a break of arg milliseconds
+//
+#define CMD_SEND_BRK(arg) \
+ (((cmdSyntaxPtr)(ct35))->cmd[1] = (arg),(cmdSyntaxPtr)(ct35))
+
+// Set error reporting mode
+//
+#define CMD_SET_ERROR(arg) \
+ (((cmdSyntaxPtr)(ct36))->cmd[1] = (arg),(cmdSyntaxPtr)(ct36))
+
+#define CSE_ESTAT 0 // Report error in a status packet
+#define CSE_NOREP 1 // Treat character as though it were good
+#define CSE_DROP 2 // Discard the character
+#define CSE_NULL 3 // Replace with a null
+#define CSE_MARK 4 // Replace with a 3-character sequence (as Unix)
+
+#define CMD_SET_REPLACEMENT(arg,ch) \
+ (((cmdSyntaxPtr)(ct36a))->cmd[1] = (arg), \
+ (((cmdSyntaxPtr)(ct36a))->cmd[2] = (ch), \
+ (cmdSyntaxPtr)(ct36a))
+
+#define CSE_REPLACE 0x8 // Replace the errored character with the
+ // replacement character defined here
+
+#define CSE_STAT_REPLACE 0x18 // Replace the errored character with the
+ // replacement character defined here AND
+ // report the error as a status packet (as in
+ // CSE_ESTAT).
+
+
+// COMMAND 37, to send flow control packets, is handled only by low-level
+// library code in response to data movement and shouldn't ever be sent by the
+// user code. See i2pack.h and the body of i2lib.c for details.
+
+// COMMAND 38: Define the hot-key sequence
+// seqno: sequence number 0-15
+// size: number of characters in sequence (1-8)
+// string: pointer to the characters
+// (if size == 0, "undefines" this sequence
+//
+#define CMD_SET_SEQ(seqno,size,string) i2cmdSetSeq(seqno,size,string)
+
+// Enable on-board post-processing, using options given in oflag argument.
+// Formerly, this command was automatically preceded by a CMD_OPOST_OFF command
+// because the loadware does not permit sending back-to-back CMD_OPOST_ON
+// commands without an intervening CMD_OPOST_OFF. BUT, WE LEARN 18 MAY 92, that
+// CMD_OPOST_ON and CMD_OPOST_OFF must each be at the end of a packet (or in a
+// solo packet). This means the caller must specify separately CMD_OPOST_OFF,
+// CMD_OPOST_ON(parm) when he calls i2QueueCommands(). That function will ensure
+// each gets a separate packet. Extra CMD_OPOST_OFF's are always ok.
+//
+#define CMD_OPOST_ON(oflag) \
+ (*(USHORT *)(((cmdSyntaxPtr)(ct39))->cmd[1]) = (oflag), \
+ (cmdSyntaxPtr)(ct39))
+
+#define CMD_OPOST_OFF (cmdSyntaxPtr)(ct40) // Disable on-board post-proc
+
+#define CMD_RESUME (cmdSyntaxPtr)(ct41) // Resume: behave as though an XON
+ // were received;
+
+// Set Transmit baud rate (see command 7 for arguments)
+//
+#define CMD_SETBAUD_TX(arg) \
+ (((cmdSyntaxPtr)(ct42))->cmd[1] = (arg),(cmdSyntaxPtr)(ct42))
+
+// Set Receive baud rate (see command 7 for arguments)
+//
+#define CMD_SETBAUD_RX(arg) \
+ (((cmdSyntaxPtr)(ct43))->cmd[1] = (arg),(cmdSyntaxPtr)(ct43))
+
+// Request interrupt from board each arg milliseconds. Interrupt will specify
+// "received data", even though there may be no data present. If arg == 0,
+// disables any such interrupts.
+//
+#define CMD_PING_REQ(arg) \
+ (((cmdSyntaxPtr)(ct44))->cmd[1] = (arg),(cmdSyntaxPtr)(ct44))
+
+#define CMD_HOT_ENAB (cmdSyntaxPtr)(ct45) // Enable Hot-key checking
+#define CMD_HOT_DSAB (cmdSyntaxPtr)(ct46) // Disable Hot-key checking
+
+// COMMAND 47: Send Protocol info via Unix flags:
+// iflag = Unix tty t_iflag
+// cflag = Unix tty t_cflag
+// lflag = Unix tty t_lflag
+// See System V Unix/Xenix documentation for the meanings of the bit fields
+// within these flags
+//
+#define CMD_UNIX_FLAGS(iflag,cflag,lflag) i2cmdUnixFlags(iflag,cflag,lflag)
+
+#define CMD_DSRFL_ENAB (cmdSyntaxPtr)(ct48) // Enable DSR receiver ctrl
+#define CMD_DSRFL_DSAB (cmdSyntaxPtr)(ct49) // Disable DSR receiver ctrl
+#define CMD_DTRFL_ENAB (cmdSyntaxPtr)(ct50) // Enable DTR flow control
+#define CMD_DTRFL_DSAB (cmdSyntaxPtr)(ct51) // Disable DTR flow control
+#define CMD_BAUD_RESET (cmdSyntaxPtr)(ct52) // Reset baudrate table
+
+// COMMAND 53: Remap baud rate table
+// dest = index of table entry to be changed
+// src = index value to substitute.
+// at default mapping table is f(x) = x
+//
+#define CMD_BAUD_REMAP(dest,src) i2cmdBaudRemap(dest,src)
+
+// COMMAND 54: Define custom rate #1
+// rate = (short) 1/10 of the desired baud rate
+//
+#define CMD_BAUD_DEF1(rate) i2cmdBaudDef(1,rate)
+
+// COMMAND 55: Define custom rate #2
+// rate = (short) 1/10 of the desired baud rate
+//
+#define CMD_BAUD_DEF2(rate) i2cmdBaudDef(2,rate)
+
+// Pause arg hundredths of seconds. (Note, this is NOT milliseconds.)
+//
+#define CMD_PAUSE(arg) \
+ (((cmdSyntaxPtr)(ct56))->cmd[1] = (arg),(cmdSyntaxPtr)(ct56))
+
+#define CMD_SUSPEND (cmdSyntaxPtr)(ct57) // Suspend output
+#define CMD_UNSUSPEND (cmdSyntaxPtr)(ct58) // Un-Suspend output
+
+// Set parity-checking options
+//
+#define CMD_PARCHK(arg) \
+ (((cmdSyntaxPtr)(ct59))->cmd[1] = (arg),(cmdSyntaxPtr)(ct59))
+
+#define CPK_ENAB 0 // Enable parity checking on input
+#define CPK_DSAB 1 // Disable parity checking on input
+
+#define CMD_BMARK_REQ (cmdSyntaxPtr)(ct60) // Bookmark request
+
+
+// Enable/Disable internal loopback mode
+//
+#define CMD_INLOOP(arg) \
+ (((cmdSyntaxPtr)(ct61))->cmd[1] = (arg),(cmdSyntaxPtr)(ct61))
+
+#define CIN_DISABLE 0 // Normal operation (default)
+#define CIN_ENABLE 1 // Internal (local) loopback
+#define CIN_REMOTE 2 // Remote loopback
+
+// Specify timeout for hotkeys: Delay will be (arg x 10) milliseconds, arg == 0
+// --> no timeout: wait forever.
+//
+#define CMD_HOT_TIME(arg) \
+ (((cmdSyntaxPtr)(ct62))->cmd[1] = (arg),(cmdSyntaxPtr)(ct62))
+
+
+// Define (outgoing) xon for receive flow control
+//
+#define CMD_DEF_OXON(arg) \
+ (((cmdSyntaxPtr)(ct63))->cmd[1] = (arg),(cmdSyntaxPtr)(ct63))
+
+// Define (outgoing) xoff for receiver flow control
+//
+#define CMD_DEF_OXOFF(arg) \
+ (((cmdSyntaxPtr)(ct64))->cmd[1] = (arg),(cmdSyntaxPtr)(ct64))
+
+// Enable/Disable RTS on transmit (1/2 duplex-style)
+//
+#define CMD_RTS_XMIT(arg) \
+ (((cmdSyntaxPtr)(ct65))->cmd[1] = (arg),(cmdSyntaxPtr)(ct65))
+
+#define CHD_DISABLE 0
+#define CHD_ENABLE 1
+
+// Set high-water-mark level (debugging use only)
+//
+#define CMD_SETHIGHWAT(arg) \
+ (((cmdSyntaxPtr)(ct66))->cmd[1] = (arg),(cmdSyntaxPtr)(ct66))
+
+// Start flushing tagged data (tag = 0-14)
+//
+#define CMD_START_SELFL(tag) \
+ (((cmdSyntaxPtr)(ct67))->cmd[1] = (tag),(cmdSyntaxPtr)(ct67))
+
+// End flushing tagged data (tag = 0-14)
+//
+#define CMD_END_SELFL(tag) \
+ (((cmdSyntaxPtr)(ct68))->cmd[1] = (tag),(cmdSyntaxPtr)(ct68))
+
+#define CMD_HWFLOW_OFF (cmdSyntaxPtr)(ct69) // Disable HW TX flow control
+#define CMD_ODSRFL_ENAB (cmdSyntaxPtr)(ct70) // Enable DSR output f/c
+#define CMD_ODSRFL_DSAB (cmdSyntaxPtr)(ct71) // Disable DSR output f/c
+#define CMD_ODCDFL_ENAB (cmdSyntaxPtr)(ct72) // Enable DCD output f/c
+#define CMD_ODCDFL_DSAB (cmdSyntaxPtr)(ct73) // Disable DCD output f/c
+
+// Set transmit interrupt load level. Count should be an even value 2-12
+//
+#define CMD_LOADLEVEL(count) \
+ (((cmdSyntaxPtr)(ct74))->cmd[1] = (count),(cmdSyntaxPtr)(ct74))
+
+// If reporting DSS changes, map to character sequence FFh, 2, MSR
+//
+#define CMD_STATDATA(arg) \
+ (((cmdSyntaxPtr)(ct75))->cmd[1] = (arg),(cmdSyntaxPtr)(ct75))
+
+#define CSTD_DISABLE// Report DSS changes as status packets only (default)
+#define CSTD_ENABLE // Report DSS changes as in-band data sequence as well as
+ // by status packet.
+
+#define CMD_BREAK_ON (cmdSyntaxPtr)(ct76)// Set break and stop xmit
+#define CMD_BREAK_OFF (cmdSyntaxPtr)(ct77)// End break and restart xmit
+#define CMD_GETFC (cmdSyntaxPtr)(ct78)// Request for flow control packet
+ // from board.
+
+// Transmit this character immediately
+//
+#define CMD_XMIT_NOW(ch) \
+ (((cmdSyntaxPtr)(ct79))->cmd[1] = (ch),(cmdSyntaxPtr)(ct79))
+
+// Set baud rate via "divisor latch"
+//
+#define CMD_DIVISOR_LATCH(which,value) \
+ (((cmdSyntaxPtr)(ct80))->cmd[1] = (which), \
+ *(USHORT *)(((cmdSyntaxPtr)(ct80))->cmd[2]) = (value), \
+ (cmdSyntaxPtr)(ct80))
+
+#define CDL_RX 1 // Set receiver rate
+#define CDL_TX 2 // Set transmit rate
+ // (CDL_TX | CDL_RX) Set both rates
+
+// Request for special diagnostic status pkt from the board.
+//
+#define CMD_GET_STATUS (cmdSyntaxPtr)(ct81)
+
+// Request time-stamped transmit character count packet.
+//
+#define CMD_GET_TXCNT (cmdSyntaxPtr)(ct82)
+
+// Request time-stamped receive character count packet.
+//
+#define CMD_GET_RXCNT (cmdSyntaxPtr)(ct83)
+
+// Request for box/board I.D. packet.
+#define CMD_GET_BOXIDS (cmdSyntaxPtr)(ct84)
+
+// Enable or disable multiple channels according to bit-mapped ushorts box 1-4
+//
+#define CMD_ENAB_MULT(enable, box1, box2, box3, box4) \
+ (((cmdSytaxPtr)(ct85))->cmd[1] = (enable), \
+ *(USHORT *)(((cmdSyntaxPtr)(ct85))->cmd[2]) = (box1), \
+ *(USHORT *)(((cmdSyntaxPtr)(ct85))->cmd[4]) = (box2), \
+ *(USHORT *)(((cmdSyntaxPtr)(ct85))->cmd[6]) = (box3), \
+ *(USHORT *)(((cmdSyntaxPtr)(ct85))->cmd[8]) = (box4), \
+ (cmdSyntaxPtr)(ct85))
+
+#define CEM_DISABLE 0
+#define CEM_ENABLE 1
+
+// Enable or disable receiver or receiver interrupts (default both enabled)
+//
+#define CMD_RCV_ENABLE(ch) \
+ (((cmdSyntaxPtr)(ct86))->cmd[1] = (ch),(cmdSyntaxPtr)(ct86))
+
+#define CRE_OFF 0 // Disable the receiver
+#define CRE_ON 1 // Enable the receiver
+#define CRE_INTOFF 2 // Disable receiver interrupts (to loadware)
+#define CRE_INTON 3 // Enable receiver interrupts (to loadware)
+
+// Starts up a hardware test process, which runs transparently, and sends a
+// STAT_HWFAIL packet in case a hardware failure is detected.
+//
+#define CMD_HW_TEST (cmdSyntaxPtr)(ct87)
+
+// Change receiver threshold and timeout value:
+// Defaults: timeout = 20mS
+// threshold count = 8 when DTRflow not in use,
+// threshold count = 5 when DTRflow in use.
+//
+#define CMD_RCV_THRESHOLD(count,ms) \
+ (((cmdSyntaxPtr)(ct88))->cmd[1] = (count), \
+ ((cmdSyntaxPtr)(ct88))->cmd[2] = (ms), \
+ (cmdSyntaxPtr)(ct88))
+
+// Makes the loadware report DSS signals for this channel immediately.
+//
+#define CMD_DSS_NOW (cmdSyntaxPtr)(ct89)
+
+// Set the receive silo parameters
+// timeout is ms idle wait until delivery (~VTIME)
+// threshold is max characters cause interrupt (~VMIN)
+//
+#define CMD_SET_SILO(timeout,threshold) \
+ (((cmdSyntaxPtr)(ct90))->cmd[1] = (timeout), \
+ ((cmdSyntaxPtr)(ct90))->cmd[2] = (threshold), \
+ (cmdSyntaxPtr)(ct90))
+
+// Set timed break in decisecond (1/10s)
+//
+#define CMD_LBREAK(ds) \
+ (((cmdSyntaxPtr)(ct91))->cmd[1] = (ds),(cmdSyntaxPtr)(ct66))
+
+
+
+#endif // I2CMD_H
diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c
new file mode 100644
index 000000000..c45509bcd
--- /dev/null
+++ b/drivers/char/ip2/i2ellis.c
@@ -0,0 +1,1470 @@
+/*******************************************************************************
+*
+* (c) 1998 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Low-level interface code for the device driver
+* (This is included source code, not a separate compilation
+* module.)
+*
+*******************************************************************************/
+//---------------------------------------------
+// Function declarations private to this module
+//---------------------------------------------
+// Functions called only indirectly through i2eBordStr entries.
+
+static int iiWriteBuf16(i2eBordStrPtr, unsigned char *, int);
+static int iiWriteBuf8(i2eBordStrPtr, unsigned char *, int);
+static int iiReadBuf16(i2eBordStrPtr, unsigned char *, int);
+static int iiReadBuf8(i2eBordStrPtr, unsigned char *, int);
+
+static unsigned short iiReadWord16(i2eBordStrPtr);
+static unsigned short iiReadWord8(i2eBordStrPtr);
+static void iiWriteWord16(i2eBordStrPtr, unsigned short);
+static void iiWriteWord8(i2eBordStrPtr, unsigned short);
+
+static int iiWaitForTxEmptyII(i2eBordStrPtr, int);
+static int iiWaitForTxEmptyIIEX(i2eBordStrPtr, int);
+static int iiTxMailEmptyII(i2eBordStrPtr);
+static int iiTxMailEmptyIIEX(i2eBordStrPtr);
+static int iiTrySendMailII(i2eBordStrPtr, unsigned char);
+static int iiTrySendMailIIEX(i2eBordStrPtr, unsigned char);
+
+static unsigned short iiGetMailII(i2eBordStrPtr);
+static unsigned short iiGetMailIIEX(i2eBordStrPtr);
+
+static void iiEnableMailIrqII(i2eBordStrPtr);
+static void iiEnableMailIrqIIEX(i2eBordStrPtr);
+static void iiWriteMaskII(i2eBordStrPtr, unsigned char);
+static void iiWriteMaskIIEX(i2eBordStrPtr, unsigned char);
+
+static void ii2DelayTimer(unsigned int);
+static void ii2DelayWakeup(unsigned long id);
+static void ii2Nop(void);
+
+//***************
+//* Static Data *
+//***************
+
+static int ii2Safe = 0; // Safe I/O address for delay routine
+
+static int iiDelayed = 0; // Set when the iiResetDelay function is
+ // called. Cleared when ANY board is reset.
+static struct timer_list * pDelayTimer; // Used by iiDelayTimer
+static wait_queue_head_t pDelayWait; // Used by iiDelayTimer
+static spinlock_t Dl_spinlock;
+
+//********
+//* Code *
+//********
+
+//=======================================================
+// Initialization Routines
+//
+// iiSetAddress
+// iiReset
+// iiResetDelay
+// iiInitialize
+//=======================================================
+
+//******************************************************************************
+// Function: iiEllisInit()
+// Parameters: None
+//
+// Returns: Nothing
+//
+// Description:
+//
+// This routine performs any required initialization of the iiEllis subsystem.
+//
+//******************************************************************************
+static void
+iiEllisInit(void)
+{
+ pDelayTimer = kmalloc ( sizeof (struct timer_list), GFP_KERNEL );
+ init_waitqueue_head(&pDelayWait);
+ LOCK_INIT(&Dl_spinlock);
+}
+
+//******************************************************************************
+// Function: iiEllisCleanup()
+// Parameters: None
+//
+// Returns: Nothing
+//
+// Description:
+//
+// This routine performs any required cleanup of the iiEllis subsystem.
+//
+//******************************************************************************
+static void
+iiEllisCleanup(void)
+{
+ if ( pDelayTimer != NULL ) {
+ kfree ( pDelayTimer );
+ }
+}
+
+//******************************************************************************
+// Function: iiSetAddress(pB, address, delay)
+// Parameters: pB - pointer to the board structure
+// address - the purported I/O address of the board
+// delay - pointer to the 1-ms delay function to use
+// in this and any future operations to this board
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// This routine (roughly) checks for address validity, sets the i2eValid OK and
+// sets the state to II_STATE_COLD which means that we haven't even sent a reset
+// yet.
+//
+//******************************************************************************
+static int
+iiSetAddress( i2eBordStrPtr pB, int address, delayFunc_t delay )
+{
+ // Should any failure occur before init is finished...
+ pB->i2eValid = I2E_INCOMPLETE;
+
+ // Cannot check upper limit except extremely: Might be microchannel
+ // Address must be on an 8-byte boundary
+
+ if ((unsigned int)address <= 0x100
+ || (unsigned int)address >= 0xfff8
+ || (address & 0x7)
+ )
+ {
+ COMPLETE(pB,I2EE_BADADDR);
+ }
+
+ // Initialize accelerators
+ pB->i2eBase = address;
+ pB->i2eData = address + FIFO_DATA;
+ pB->i2eStatus = address + FIFO_STATUS;
+ pB->i2ePointer = address + FIFO_PTR;
+ pB->i2eXMail = address + FIFO_MAIL;
+ pB->i2eXMask = address + FIFO_MASK;
+
+ // Initialize i/o address for ii2DelayIO
+ ii2Safe = address + FIFO_NOP;
+
+ // Initialize the delay routine
+ pB->i2eDelay = ((delay != (delayFunc_t)NULL) ? delay : (delayFunc_t)ii2Nop);
+
+ pB->i2eValid = I2E_MAGIC;
+ pB->i2eState = II_STATE_COLD;
+
+ COMPLETE(pB, I2EE_GOOD);
+}
+
+//******************************************************************************
+// Function: iiReset(pB)
+// Parameters: pB - pointer to the board structure
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Attempts to reset the board (see also i2hw.h). Normally, we would use this to
+// reset a board immediately after iiSetAddress(), but it is valid to reset a
+// board from any state, say, in order to change or re-load loadware. (Under
+// such circumstances, no reason to re-run iiSetAddress(), which is why it is a
+// separate routine and not included in this routine.
+//
+//******************************************************************************
+static int
+iiReset(i2eBordStrPtr pB)
+{
+ // Magic number should be set, else even the address is suspect
+ if (pB->i2eValid != I2E_MAGIC)
+ {
+ COMPLETE(pB, I2EE_BADMAGIC);
+ }
+
+ OUTB(pB->i2eBase + FIFO_RESET, 0); // Any data will do
+ iiDelay(pB, 50); // Pause between resets
+ OUTB(pB->i2eBase + FIFO_RESET, 0); // Second reset
+
+ // We must wait before even attempting to read anything from the FIFO: the
+ // board's P.O.S.T may actually attempt to read and write its end of the
+ // FIFO in order to check flags, loop back (where supported), etc. On
+ // completion of this testing it would reset the FIFO, and on completion
+ // of all // P.O.S.T., write the message. We must not mistake data which
+ // might have been sent for testing as part of the reset message. To
+ // better utilize time, say, when resetting several boards, we allow the
+ // delay to be performed externally; in this way the caller can reset
+ // several boards, delay a single time, then call the initialization
+ // routine for all.
+
+ pB->i2eState = II_STATE_RESET;
+
+ iiDelayed = 0; // i.e., the delay routine hasn't been called since the most
+ // recent reset.
+
+ // Ensure anything which would have been of use to standard loadware is
+ // blanked out, since board has now forgotten everything!.
+
+ pB->i2eUsingIrq = IRQ_UNDEFINED; // Not set up to use an interrupt yet
+ pB->i2eWaitingForEmptyFifo = 0;
+ pB->i2eOutMailWaiting = 0;
+ pB->i2eChannelPtr = NULL;
+ pB->i2eChannelCnt = 0;
+
+ pB->i2eLeadoffWord[0] = 0;
+ pB->i2eFifoInInts = 0;
+ pB->i2eFifoOutInts = 0;
+ pB->i2eFatalTrap = NULL;
+ pB->i2eFatal = 0;
+
+ COMPLETE(pB, I2EE_GOOD);
+}
+
+//******************************************************************************
+// Function: iiResetDelay(pB)
+// Parameters: pB - pointer to the board structure
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Using the delay defined in board structure, waits two seconds (for board to
+// reset).
+//
+//******************************************************************************
+static int
+iiResetDelay(i2eBordStrPtr pB)
+{
+ if (pB->i2eValid != I2E_MAGIC) {
+ COMPLETE(pB, I2EE_BADMAGIC);
+ }
+ if (pB->i2eState != II_STATE_RESET) {
+ COMPLETE(pB, I2EE_BADSTATE);
+ }
+ iiDelay(pB,2000); /* Now we wait for two seconds. */
+ iiDelayed = 1; /* Delay has been called: ok to initialize */
+ COMPLETE(pB, I2EE_GOOD);
+}
+
+//******************************************************************************
+// Function: iiInitialize(pB)
+// Parameters: pB - pointer to the board structure
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Attempts to read the Power-on reset message. Initializes any remaining fields
+// in the pB structure.
+//
+// This should be called as the third step of a process beginning with
+// iiReset(), then iiResetDelay(). This routine checks to see that the structure
+// is "valid" and in the reset state, also confirms that the delay routine has
+// been called since the latest reset (to any board! overly strong!).
+//
+//******************************************************************************
+static int
+iiInitialize(i2eBordStrPtr pB)
+{
+ int itemp;
+ unsigned char c;
+ unsigned short utemp;
+ unsigned int ilimit;
+
+ if (pB->i2eValid != I2E_MAGIC)
+ {
+ COMPLETE(pB, I2EE_BADMAGIC);
+ }
+
+ if (pB->i2eState != II_STATE_RESET || !iiDelayed)
+ {
+ COMPLETE(pB, I2EE_BADSTATE);
+ }
+
+ // In case there is a failure short of our completely reading the power-up
+ // message.
+ pB->i2eValid = I2E_INCOMPLETE;
+
+
+ // Now attempt to read the message.
+
+ for (itemp = 0; itemp < sizeof(porStr); itemp++)
+ {
+ // We expect the entire message is ready.
+ if (HAS_NO_INPUT(pB))
+ {
+ pB->i2ePomSize = itemp;
+ COMPLETE(pB, I2EE_PORM_SHORT);
+ }
+
+ pB->i2ePom.c[itemp] = c = BYTE_FROM(pB);
+
+ // We check the magic numbers as soon as they are supposed to be read
+ // (rather than after) to minimize effect of reading something we
+ // already suspect can't be "us".
+ if ( (itemp == POR_1_INDEX && c != POR_MAGIC_1) ||
+ (itemp == POR_2_INDEX && c != POR_MAGIC_2))
+ {
+ pB->i2ePomSize = itemp+1;
+ COMPLETE(pB, I2EE_BADMAGIC);
+ }
+ }
+
+ pB->i2ePomSize = itemp;
+
+ // Ensure that this was all the data...
+ if (HAS_INPUT(pB))
+ COMPLETE(pB, I2EE_PORM_LONG);
+
+ // For now, we'll fail to initialize if P.O.S.T reports bad chip mapper:
+ // Implying we will not be able to download any code either: That's ok: the
+ // condition is pretty explicit.
+ if (pB->i2ePom.e.porDiag1 & POR_BAD_MAPPER)
+ {
+ COMPLETE(pB, I2EE_POSTERR);
+ }
+
+ // Determine anything which must be done differently depending on the family
+ // of boards!
+ switch (pB->i2ePom.e.porID & POR_ID_FAMILY)
+ {
+ case POR_ID_FII: // IntelliPort-II
+
+ pB->i2eFifoStyle = FIFO_II;
+ pB->i2eFifoSize = 512; // 512 bytes, always
+ pB->i2eDataWidth16 = NO;
+
+ pB->i2eMaxIrq = 15; // Because board cannot tell us it is in an 8-bit
+ // slot, we do allow it to be done (documentation!)
+
+ pB->i2eGoodMap[1] =
+ pB->i2eGoodMap[2] =
+ pB->i2eGoodMap[3] =
+ pB->i2eChannelMap[1] =
+ pB->i2eChannelMap[2] =
+ pB->i2eChannelMap[3] = 0;
+
+ switch (pB->i2ePom.e.porID & POR_ID_SIZE)
+ {
+ case POR_ID_II_4:
+ pB->i2eGoodMap[0] =
+ pB->i2eChannelMap[0] = 0x0f; // four-port
+
+ // Since porPorts1 is based on the Hardware ID register, the numbers
+ // should always be consistent for IntelliPort-II. Ditto below...
+ if (pB->i2ePom.e.porPorts1 != 4)
+ {
+ COMPLETE(pB, I2EE_INCONSIST);
+ }
+ break;
+
+ case POR_ID_II_8:
+ case POR_ID_II_8R:
+ pB->i2eGoodMap[0] =
+ pB->i2eChannelMap[0] = 0xff; // Eight port
+ if (pB->i2ePom.e.porPorts1 != 8)
+ {
+ COMPLETE(pB, I2EE_INCONSIST);
+ }
+ break;
+
+ case POR_ID_II_6:
+ pB->i2eGoodMap[0] =
+ pB->i2eChannelMap[0] = 0x3f; // Six Port
+ if (pB->i2ePom.e.porPorts1 != 6)
+ {
+ COMPLETE(pB, I2EE_INCONSIST);
+ }
+ break;
+ }
+
+ // Fix up the "good channel list based on any errors reported.
+ if (pB->i2ePom.e.porDiag1 & POR_BAD_UART1)
+ {
+ pB->i2eGoodMap[0] &= ~0x0f;
+ }
+
+ if (pB->i2ePom.e.porDiag1 & POR_BAD_UART2)
+ {
+ pB->i2eGoodMap[0] &= ~0xf0;
+ }
+
+ break; // POR_ID_FII case
+
+ case POR_ID_FIIEX: // IntelliPort-IIEX
+
+ pB->i2eFifoStyle = FIFO_IIEX;
+
+ itemp = pB->i2ePom.e.porFifoSize;
+
+ // Implicit assumption that fifo would not grow beyond 32k,
+ // nor would ever be less than 256.
+
+ if (itemp < 8 || itemp > 15)
+ {
+ COMPLETE(pB, I2EE_INCONSIST);
+ }
+ pB->i2eFifoSize = (1 << itemp);
+
+ // These are based on what P.O.S.T thinks should be there, based on
+ // box ID registers
+ ilimit = pB->i2ePom.e.porNumBoxes;
+ if (ilimit > ABS_MAX_BOXES)
+ {
+ ilimit = ABS_MAX_BOXES;
+ }
+
+ // For as many boxes as EXIST, gives the type of box.
+ // Added 8/6/93: check for the ISA-4 (asic) which looks like an
+ // expandable but for whom "8 or 16?" is not the right question.
+
+ utemp = pB->i2ePom.e.porFlags;
+ if (utemp & POR_CEX4)
+ {
+ pB->i2eChannelMap[0] = 0x000f;
+ } else {
+ utemp &= POR_BOXES;
+ for (itemp = 0; itemp < ilimit; itemp++)
+ {
+ pB->i2eChannelMap[itemp] =
+ ((utemp & POR_BOX_16) ? 0xffff : 0x00ff);
+ utemp >>= 1;
+ }
+ }
+
+ // These are based on what P.O.S.T actually found.
+
+ utemp = (pB->i2ePom.e.porPorts2 << 8) + pB->i2ePom.e.porPorts1;
+
+ for (itemp = 0; itemp < ilimit; itemp++)
+ {
+ pB->i2eGoodMap[itemp] = 0;
+ if (utemp & 1) pB->i2eGoodMap[itemp] |= 0x000f;
+ if (utemp & 2) pB->i2eGoodMap[itemp] |= 0x00f0;
+ if (utemp & 4) pB->i2eGoodMap[itemp] |= 0x0f00;
+ if (utemp & 8) pB->i2eGoodMap[itemp] |= 0xf000;
+ utemp >>= 4;
+ }
+
+ // Now determine whether we should transfer in 8 or 16-bit mode.
+ switch (pB->i2ePom.e.porBus & (POR_BUS_SLOT16 | POR_BUS_DIP16) )
+ {
+ case POR_BUS_SLOT16 | POR_BUS_DIP16:
+ pB->i2eDataWidth16 = YES;
+ pB->i2eMaxIrq = 15;
+ break;
+
+ case POR_BUS_SLOT16:
+ pB->i2eDataWidth16 = NO;
+ pB->i2eMaxIrq = 15;
+ break;
+
+ case 0:
+ case POR_BUS_DIP16: // In an 8-bit slot, DIP switch don't care.
+ default:
+ pB->i2eDataWidth16 = NO;
+ pB->i2eMaxIrq = 7;
+ break;
+ }
+ break; // POR_ID_FIIEX case
+
+ default: // Unknown type of board
+ COMPLETE(pB, I2EE_BAD_FAMILY);
+ break;
+ } // End the switch based on family
+
+ // Temporarily, claim there is no room in the outbound fifo.
+ // We will maintain this whenever we check for an empty outbound FIFO.
+ pB->i2eFifoRemains = 0;
+
+ // Now, based on the bus type, should we expect to be able to re-configure
+ // interrupts (say, for testing purposes).
+ switch (pB->i2ePom.e.porBus & POR_BUS_TYPE)
+ {
+ case POR_BUS_T_ISA:
+ case POR_BUS_T_UNK: // If the type of bus is undeclared, assume ok.
+ pB->i2eChangeIrq = YES;
+ break;
+ case POR_BUS_T_MCA:
+ case POR_BUS_T_EISA:
+ pB->i2eChangeIrq = NO;
+ break;
+ default:
+ COMPLETE(pB, I2EE_BADBUS);
+ }
+
+ if (pB->i2eDataWidth16 == YES)
+ {
+ pB->i2eWriteBuf = iiWriteBuf16;
+ pB->i2eReadBuf = iiReadBuf16;
+ pB->i2eWriteWord = iiWriteWord16;
+ pB->i2eReadWord = iiReadWord16;
+ } else {
+ pB->i2eWriteBuf = iiWriteBuf8;
+ pB->i2eReadBuf = iiReadBuf8;
+ pB->i2eWriteWord = iiWriteWord8;
+ pB->i2eReadWord = iiReadWord8;
+ }
+
+ switch(pB->i2eFifoStyle)
+ {
+ case FIFO_II:
+ pB->i2eWaitForTxEmpty = iiWaitForTxEmptyII;
+ pB->i2eTxMailEmpty = iiTxMailEmptyII;
+ pB->i2eTrySendMail = iiTrySendMailII;
+ pB->i2eGetMail = iiGetMailII;
+ pB->i2eEnableMailIrq = iiEnableMailIrqII;
+ pB->i2eWriteMask = iiWriteMaskII;
+
+ break;
+
+ case FIFO_IIEX:
+ pB->i2eWaitForTxEmpty = iiWaitForTxEmptyIIEX;
+ pB->i2eTxMailEmpty = iiTxMailEmptyIIEX;
+ pB->i2eTrySendMail = iiTrySendMailIIEX;
+ pB->i2eGetMail = iiGetMailIIEX;
+ pB->i2eEnableMailIrq = iiEnableMailIrqIIEX;
+ pB->i2eWriteMask = iiWriteMaskIIEX;
+
+ break;
+
+ default:
+ COMPLETE(pB, I2EE_INCONSIST);
+ }
+
+ // Initialize state information.
+ pB->i2eState = II_STATE_READY; // Ready to load loadware.
+
+ // Some Final cleanup:
+ // For some boards, the bootstrap firmware may perform some sort of test
+ // resulting in a stray character pending in the incoming mailbox. If one is
+ // there, it should be read and discarded, especially since for the standard
+ // firmware, it's the mailbox that interrupts the host.
+
+ pB->i2eStartMail = iiGetMail(pB);
+
+ // Everything is ok now, return with good status/
+
+ pB->i2eValid = I2E_MAGIC;
+ COMPLETE(pB, I2EE_GOOD);
+}
+
+//=======================================================
+// Delay Routines
+//
+// iiDelayIO
+// iiNop
+//=======================================================
+
+static void
+ii2DelayWakeup(unsigned long id)
+{
+ wake_up_interruptible ( &pDelayWait );
+}
+
+//******************************************************************************
+// Function: ii2DelayTimer(mseconds)
+// Parameters: mseconds - number of milliseconds to delay
+//
+// Returns: Nothing
+//
+// Description:
+//
+// This routine delays for approximately mseconds milliseconds and is intended
+// to be called indirectly through i2Delay field in i2eBordStr. It uses the
+// Linux timer_list mechanism.
+//
+// The Linux timers use a unit called "jiffies" which are 10mS in the Intel
+// architecture. This function rounds the delay period up to the next "jiffy".
+// In the Alpha architecture the "jiffy" is 1mS, but this driver is not intended
+// for Alpha platforms at this time.
+//
+//******************************************************************************
+static void
+ii2DelayTimer(unsigned int mseconds)
+{
+ init_timer ( pDelayTimer );
+
+ pDelayTimer->expires = jiffies + ( mseconds + 9 ) / 10;
+ pDelayTimer->function = ii2DelayWakeup;
+ pDelayTimer->data = 0;
+
+ add_timer ( pDelayTimer );
+ interruptible_sleep_on ( &pDelayWait );
+ del_timer ( pDelayTimer );
+}
+
+#if 0
+//static void ii2DelayIO(unsigned int);
+//******************************************************************************
+// !!! Not Used, this is DOS crap, some of you young folks may be interested in
+// in how things were done in the stone age of caculating machines !!!
+// Function: ii2DelayIO(mseconds)
+// Parameters: mseconds - number of milliseconds to delay
+//
+// Returns: Nothing
+//
+// Description:
+//
+// This routine delays for approximately mseconds milliseconds and is intended
+// to be called indirectly through i2Delay field in i2eBordStr. It is intended
+// for use where a clock-based function is impossible: for example, DOS drivers.
+//
+// This function uses the IN instruction to place bounds on the timing and
+// assumes that ii2Safe has been set. This is because I/O instructions are not
+// subject to caching and will therefore take a certain minimum time. To ensure
+// the delay is at least long enough on fast machines, it is based on some
+// fastest-case calculations. On slower machines this may cause VERY long
+// delays. (3 x fastest case). In the fastest case, everything is cached except
+// the I/O instruction itself.
+//
+// Timing calculations:
+// The fastest bus speed for I/O operations is likely to be 10 MHz. The I/O
+// operation in question is a byte operation to an odd address. For 8-bit
+// operations, the architecture generally enforces two wait states. At 10 MHz, a
+// single cycle time is 100nS. A read operation at two wait states takes 6
+// cycles for a total time of 600nS. Therefore approximately 1666 iterations
+// would be required to generate a single millisecond delay. The worst
+// (reasonable) case would be an 8MHz system with no cacheing. In this case, the
+// I/O instruction would take 125nS x 6 cyles = 750 nS. More importantly, code
+// fetch of other instructions in the loop would take time (zero wait states,
+// however) and would be hard to estimate. This is minimized by using in-line
+// assembler for the in inner loop of IN instructions. This consists of just a
+// few bytes. So we'll guess about four code fetches per loop. Each code fetch
+// should take four cycles, so we have 125nS * 8 = 1000nS. Worst case then is
+// that what should have taken 1 mS takes instead 1666 * (1750) = 2.9 mS.
+//
+// So much for theoretical timings: results using 1666 value on some actual
+// machines:
+// IBM 286 6MHz 3.15 mS
+// Zenith 386 33MHz 2.45 mS
+// (brandX) 386 33MHz 1.90 mS (has cache)
+// (brandY) 486 33MHz 2.35 mS
+// NCR 486 ?? 1.65 mS (microchannel)
+//
+// For most machines, it is probably safe to scale this number back (remember,
+// for robust operation use an actual timed delay if possible), so we are using
+// a value of 1190. This yields 1.17 mS for the fastest machine in our sample,
+// 1.75 mS for typical 386 machines, and 2.25 mS the absolute slowest machine.
+//
+// 1/29/93:
+// The above timings are too slow. Actual cycle times might be faster. ISA cycle
+// times could approach 500 nS, and ...
+// The IBM model 77 being microchannel has no wait states for 8-bit reads and
+// seems to be accessing the I/O at 440 nS per access (from start of one to
+// start of next). This would imply we need 1000/.440 = 2272 iterations to
+// guarantee we are fast enough. In actual testing, we see that 2 * 1190 are in
+// fact enough. For diagnostics, we keep the level at 1190, but developers note
+// this needs tuning.
+//
+// Safe assumption: 2270 i/o reads = 1 millisecond
+//
+//******************************************************************************
+
+
+static int ii2DelValue = 1190; // See timing calculations below
+ // 1666 for fastest theoretical machine
+ // 1190 safe for most fast 386 machines
+ // 1000 for fastest machine tested here
+ // 540 (sic) for AT286/6Mhz
+static void
+ii2DelayIO(unsigned int mseconds)
+{
+ if (!ii2Safe)
+ return; /* Do nothing if this variable uninitialized */
+
+ while(mseconds--) {
+ int i = ii2DelValue;
+ while ( i-- ) {
+ INB ( ii2Safe );
+ }
+ }
+}
+#endif
+
+//******************************************************************************
+// Function: ii2Nop()
+// Parameters: None
+//
+// Returns: Nothing
+//
+// Description:
+//
+// iiInitialize will set i2eDelay to this if the delay parameter is NULL. This
+// saves checking for a NULL pointer at every call.
+//******************************************************************************
+static void
+ii2Nop(void)
+{
+ return; // no mystery here
+}
+
+//=======================================================
+// Routines which are available in 8/16-bit versions, or
+// in different fifo styles. These are ALL called
+// indirectly through the board structure.
+//=======================================================
+
+//******************************************************************************
+// Function: iiWriteBuf16(pB, address, count)
+// Parameters: pB - pointer to board structure
+// address - address of data to write
+// count - number of data bytes to write
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Writes 'count' bytes from 'address' to the data fifo specified by the board
+// structure pointer pB. Should count happen to be odd, an extra pad byte is
+// sent (identity unknown...). Uses 16-bit (word) operations. Is called
+// indirectly through pB->i2eWriteBuf.
+//
+//******************************************************************************
+static int
+iiWriteBuf16(i2eBordStrPtr pB, unsigned char *address, int count)
+{
+ // Rudimentary sanity checking here.
+ if (pB->i2eValid != I2E_MAGIC)
+ COMPLETE(pB, I2EE_INVALID);
+
+ OUTSW ( pB->i2eData, address, count);
+
+ COMPLETE(pB, I2EE_GOOD);
+}
+
+//******************************************************************************
+// Function: iiWriteBuf8(pB, address, count)
+// Parameters: pB - pointer to board structure
+// address - address of data to write
+// count - number of data bytes to write
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Writes 'count' bytes from 'address' to the data fifo specified by the board
+// structure pointer pB. Should count happen to be odd, an extra pad byte is
+// sent (identity unknown...). This is to be consistant with the 16-bit version.
+// Uses 8-bit (byte) operations. Is called indirectly through pB->i2eWriteBuf.
+//
+//******************************************************************************
+static int
+iiWriteBuf8(i2eBordStrPtr pB, unsigned char *address, int count)
+{
+ /* Rudimentary sanity checking here */
+ if (pB->i2eValid != I2E_MAGIC)
+ COMPLETE(pB, I2EE_INVALID);
+
+ OUTSB ( pB->i2eData, address, count );
+
+ COMPLETE(pB, I2EE_GOOD);
+}
+
+//******************************************************************************
+// Function: iiReadBuf16(pB, address, count)
+// Parameters: pB - pointer to board structure
+// address - address to put data read
+// count - number of data bytes to read
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Reads 'count' bytes into 'address' from the data fifo specified by the board
+// structure pointer pB. Should count happen to be odd, an extra pad byte is
+// received (identity unknown...). Uses 16-bit (word) operations. Is called
+// indirectly through pB->i2eReadBuf.
+//
+//******************************************************************************
+static int
+iiReadBuf16(i2eBordStrPtr pB, unsigned char *address, int count)
+{
+ // Rudimentary sanity checking here.
+ if (pB->i2eValid != I2E_MAGIC)
+ COMPLETE(pB, I2EE_INVALID);
+
+ INSW ( pB->i2eData, address, count);
+
+ COMPLETE(pB, I2EE_GOOD);
+}
+
+//******************************************************************************
+// Function: iiReadBuf8(pB, address, count)
+// Parameters: pB - pointer to board structure
+// address - address to put data read
+// count - number of data bytes to read
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Reads 'count' bytes into 'address' from the data fifo specified by the board
+// structure pointer pB. Should count happen to be odd, an extra pad byte is
+// received (identity unknown...). This to match the 16-bit behaviour. Uses
+// 8-bit (byte) operations. Is called indirectly through pB->i2eReadBuf.
+//
+//******************************************************************************
+static int
+iiReadBuf8(i2eBordStrPtr pB, unsigned char *address, int count)
+{
+ // Rudimentary sanity checking here.
+ if (pB->i2eValid != I2E_MAGIC)
+ COMPLETE(pB, I2EE_INVALID);
+
+ INSB ( pB->i2eData, address, count);
+
+ COMPLETE(pB, I2EE_GOOD);
+}
+
+//******************************************************************************
+// Function: iiReadWord16(pB)
+// Parameters: pB - pointer to board structure
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Returns the word read from the data fifo specified by the board-structure
+// pointer pB. Uses a 16-bit operation. Is called indirectly through
+// pB->i2eReadWord.
+//
+//******************************************************************************
+static unsigned short
+iiReadWord16(i2eBordStrPtr pB)
+{
+ return (unsigned short)( INW(pB->i2eData) );
+}
+
+//******************************************************************************
+// Function: iiReadWord8(pB)
+// Parameters: pB - pointer to board structure
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Returns the word read from the data fifo specified by the board-structure
+// pointer pB. Uses two 8-bit operations. Bytes are assumed to be LSB first. Is
+// called indirectly through pB->i2eReadWord.
+//
+//******************************************************************************
+static unsigned short
+iiReadWord8(i2eBordStrPtr pB)
+{
+ unsigned short urs;
+
+ urs = INB ( pB->i2eData );
+
+ return ( ( INB ( pB->i2eData ) << 8 ) | urs );
+}
+
+//******************************************************************************
+// Function: iiWriteWord16(pB, value)
+// Parameters: pB - pointer to board structure
+// value - data to write
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Writes the word 'value' to the data fifo specified by the board-structure
+// pointer pB. Uses 16-bit operation. Is called indirectly through
+// pB->i2eWriteWord.
+//
+//******************************************************************************
+static void
+iiWriteWord16(i2eBordStrPtr pB, unsigned short value)
+{
+ WORD_TO(pB, (int)value);
+}
+
+//******************************************************************************
+// Function: iiWriteWord8(pB, value)
+// Parameters: pB - pointer to board structure
+// value - data to write
+//
+// Returns: True if everything appears copacetic.
+// False if there is any error: the pB->i2eError field has the error
+//
+// Description:
+//
+// Writes the word 'value' to the data fifo specified by the board-structure
+// pointer pB. Uses two 8-bit operations (writes LSB first). Is called
+// indirectly through pB->i2eWriteWord.
+//
+//******************************************************************************
+static void
+iiWriteWord8(i2eBordStrPtr pB, unsigned short value)
+{
+ BYTE_TO(pB, (char)value);
+ BYTE_TO(pB, (char)(value >> 8) );
+}
+
+//******************************************************************************
+// Function: iiWaitForTxEmptyII(pB, mSdelay)
+// Parameters: pB - pointer to board structure
+// mSdelay - period to wait before returning
+//
+// Returns: True if the FIFO is empty.
+// False if it not empty in the required time: the pB->i2eError
+// field has the error.
+//
+// Description:
+//
+// Waits up to "mSdelay" milliseconds for the outgoing FIFO to become empty; if
+// not empty by the required time, returns false and error in pB->i2eError,
+// otherwise returns true.
+//
+// mSdelay == 0 is taken to mean must be empty on the first test.
+//
+// This version operates on IntelliPort-II - style FIFO's
+//
+// Note this routine is organized so that if status is ok there is no delay at
+// all called either before or after the test. Is called indirectly through
+// pB->i2eWaitForTxEmpty.
+//
+//******************************************************************************
+static int
+iiWaitForTxEmptyII(i2eBordStrPtr pB, int mSdelay)
+{
+ unsigned long flags;
+ int itemp;
+
+ for (;;)
+ {
+ // This routine hinges on being able to see the "other" status register
+ // (as seen by the local processor). His incoming fifo is our outgoing
+ // FIFO.
+ //
+ // By the nature of this routine, you would be using this as part of a
+ // larger atomic context: i.e., you would use this routine to ensure the
+ // fifo empty, then act on this information. Between these two halves,
+ // you will generally not want to service interrupts or in any way
+ // disrupt the assumptions implicit in the larger context.
+ //
+ // Even worse, however, this routine "shifts" the status register to
+ // point to the local status register which is not the usual situation.
+ // Therefore for extra safety, we force the critical section to be
+ // completely atomic, and pick up after ourselves before allowing any
+ // interrupts of any kind.
+
+
+ WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags)
+ OUTB(pB->i2ePointer, SEL_COMMAND);
+ OUTB(pB->i2ePointer, SEL_CMD_SH);
+
+ itemp = INB(pB->i2eStatus);
+
+ OUTB(pB->i2ePointer, SEL_COMMAND);
+ OUTB(pB->i2ePointer, SEL_CMD_UNSH);
+
+ if (itemp & ST_IN_EMPTY)
+ {
+ UPDATE_FIFO_ROOM(pB);
+ WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
+ COMPLETE(pB, I2EE_GOOD);
+ }
+
+ WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
+
+ if (mSdelay-- == 0)
+ break;
+
+ iiDelay(pB, 1); /* 1 mS granularity on checking condition */
+ }
+ COMPLETE(pB, I2EE_TXE_TIME);
+}
+
+//******************************************************************************
+// Function: iiWaitForTxEmptyIIEX(pB, mSdelay)
+// Parameters: pB - pointer to board structure
+// mSdelay - period to wait before returning
+//
+// Returns: True if the FIFO is empty.
+// False if it not empty in the required time: the pB->i2eError
+// field has the error.
+//
+// Description:
+//
+// Waits up to "mSdelay" milliseconds for the outgoing FIFO to become empty; if
+// not empty by the required time, returns false and error in pB->i2eError,
+// otherwise returns true.
+//
+// mSdelay == 0 is taken to mean must be empty on the first test.
+//
+// This version operates on IntelliPort-IIEX - style FIFO's
+//
+// Note this routine is organized so that if status is ok there is no delay at
+// all called either before or after the test. Is called indirectly through
+// pB->i2eWaitForTxEmpty.
+//
+//******************************************************************************
+static int
+iiWaitForTxEmptyIIEX(i2eBordStrPtr pB, int mSdelay)
+{
+ unsigned long flags;
+
+ for (;;)
+ {
+ // By the nature of this routine, you would be using this as part of a
+ // larger atomic context: i.e., you would use this routine to ensure the
+ // fifo empty, then act on this information. Between these two halves,
+ // you will generally not want to service interrupts or in any way
+ // disrupt the assumptions implicit in the larger context.
+
+ WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags)
+
+ if (INB(pB->i2eStatus) & STE_OUT_MT) {
+ UPDATE_FIFO_ROOM(pB);
+ WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
+ COMPLETE(pB, I2EE_GOOD);
+ }
+ WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
+
+ if (mSdelay-- == 0)
+ break;
+
+ iiDelay(pB, 1); // 1 mS granularity on checking condition
+ }
+ COMPLETE(pB, I2EE_TXE_TIME);
+}
+
+//******************************************************************************
+// Function: iiTxMailEmptyII(pB)
+// Parameters: pB - pointer to board structure
+//
+// Returns: True if the transmit mailbox is empty.
+// False if it not empty.
+//
+// Description:
+//
+// Returns true or false according to whether the transmit mailbox is empty (and
+// therefore able to accept more mail)
+//
+// This version operates on IntelliPort-II - style FIFO's
+//
+//******************************************************************************
+static int
+iiTxMailEmptyII(i2eBordStrPtr pB)
+{
+ int port = pB->i2ePointer;
+ OUTB ( port, SEL_OUTMAIL );
+ return ( INB(port) == 0 );
+}
+
+//******************************************************************************
+// Function: iiTxMailEmptyIIEX(pB)
+// Parameters: pB - pointer to board structure
+//
+// Returns: True if the transmit mailbox is empty.
+// False if it not empty.
+//
+// Description:
+//
+// Returns true or false according to whether the transmit mailbox is empty (and
+// therefore able to accept more mail)
+//
+// This version operates on IntelliPort-IIEX - style FIFO's
+//
+//******************************************************************************
+static int
+iiTxMailEmptyIIEX(i2eBordStrPtr pB)
+{
+ return !(INB(pB->i2eStatus) & STE_OUT_MAIL);
+}
+
+//******************************************************************************
+// Function: iiTrySendMailII(pB,mail)
+// Parameters: pB - pointer to board structure
+// mail - value to write to mailbox
+//
+// Returns: True if the transmit mailbox is empty, and mail is sent.
+// False if it not empty.
+//
+// Description:
+//
+// If outgoing mailbox is empty, sends mail and returns true. If outgoing
+// mailbox is not empty, returns false.
+//
+// This version operates on IntelliPort-II - style FIFO's
+//
+//******************************************************************************
+static int
+iiTrySendMailII(i2eBordStrPtr pB, unsigned char mail)
+{
+ int port = pB->i2ePointer;
+
+ OUTB(port, SEL_OUTMAIL);
+ if (INB(port) == 0) {
+ OUTB(port, SEL_OUTMAIL);
+ OUTB(port, mail);
+ return 1;
+ }
+ return 0;
+}
+
+//******************************************************************************
+// Function: iiTrySendMailIIEX(pB,mail)
+// Parameters: pB - pointer to board structure
+// mail - value to write to mailbox
+//
+// Returns: True if the transmit mailbox is empty, and mail is sent.
+// False if it not empty.
+//
+// Description:
+//
+// If outgoing mailbox is empty, sends mail and returns true. If outgoing
+// mailbox is not empty, returns false.
+//
+// This version operates on IntelliPort-IIEX - style FIFO's
+//
+//******************************************************************************
+static int
+iiTrySendMailIIEX(i2eBordStrPtr pB, unsigned char mail)
+{
+ if(INB(pB->i2eStatus) & STE_OUT_MAIL) {
+ return 0;
+ }
+ OUTB(pB->i2eXMail, mail);
+ return 1;
+}
+
+//******************************************************************************
+// Function: iiGetMailII(pB,mail)
+// Parameters: pB - pointer to board structure
+//
+// Returns: Mailbox data or NO_MAIL_HERE.
+//
+// Description:
+//
+// If no mail available, returns NO_MAIL_HERE otherwise returns the data from
+// the mailbox, which is guaranteed != NO_MAIL_HERE.
+//
+// This version operates on IntelliPort-II - style FIFO's
+//
+//******************************************************************************
+static unsigned short
+iiGetMailII(i2eBordStrPtr pB)
+{
+ if (HAS_MAIL(pB)) {
+ OUTB(pB->i2ePointer, SEL_INMAIL);
+ return INB(pB->i2ePointer);
+ } else {
+ return NO_MAIL_HERE;
+ }
+}
+
+//******************************************************************************
+// Function: iiGetMailIIEX(pB,mail)
+// Parameters: pB - pointer to board structure
+//
+// Returns: Mailbox data or NO_MAIL_HERE.
+//
+// Description:
+//
+// If no mail available, returns NO_MAIL_HERE otherwise returns the data from
+// the mailbox, which is guaranteed != NO_MAIL_HERE.
+//
+// This version operates on IntelliPort-IIEX - style FIFO's
+//
+//******************************************************************************
+static unsigned short
+iiGetMailIIEX(i2eBordStrPtr pB)
+{
+ if (HAS_MAIL(pB)) {
+ return INB(pB->i2eXMail);
+ } else {
+ return NO_MAIL_HERE;
+ }
+}
+
+//******************************************************************************
+// Function: iiEnableMailIrqII(pB)
+// Parameters: pB - pointer to board structure
+//
+// Returns: Nothing
+//
+// Description:
+//
+// Enables board to interrupt host (only) by writing to host's in-bound mailbox.
+//
+// This version operates on IntelliPort-II - style FIFO's
+//
+//******************************************************************************
+static void
+iiEnableMailIrqII(i2eBordStrPtr pB)
+{
+ OUTB(pB->i2ePointer, SEL_MASK);
+ OUTB(pB->i2ePointer, ST_IN_MAIL);
+}
+
+//******************************************************************************
+// Function: iiEnableMailIrqIIEX(pB)
+// Parameters: pB - pointer to board structure
+//
+// Returns: Nothing
+//
+// Description:
+//
+// Enables board to interrupt host (only) by writing to host's in-bound mailbox.
+//
+// This version operates on IntelliPort-IIEX - style FIFO's
+//
+//******************************************************************************
+static void
+iiEnableMailIrqIIEX(i2eBordStrPtr pB)
+{
+ OUTB(pB->i2eXMask, MX_IN_MAIL);
+}
+
+//******************************************************************************
+// Function: iiWriteMaskII(pB)
+// Parameters: pB - pointer to board structure
+//
+// Returns: Nothing
+//
+// Description:
+//
+// Writes arbitrary value to the mask register.
+//
+// This version operates on IntelliPort-II - style FIFO's
+//
+//******************************************************************************
+static void
+iiWriteMaskII(i2eBordStrPtr pB, unsigned char value)
+{
+ OUTB(pB->i2ePointer, SEL_MASK);
+ OUTB(pB->i2ePointer, value);
+}
+
+//******************************************************************************
+// Function: iiWriteMaskIIEX(pB)
+// Parameters: pB - pointer to board structure
+//
+// Returns: Nothing
+//
+// Description:
+//
+// Writes arbitrary value to the mask register.
+//
+// This version operates on IntelliPort-IIEX - style FIFO's
+//
+//******************************************************************************
+static void
+iiWriteMaskIIEX(i2eBordStrPtr pB, unsigned char value)
+{
+ OUTB(pB->i2eXMask, value);
+}
+
+//******************************************************************************
+// Function: iiDownloadBlock(pB, pSource, isStandard)
+// Parameters: pB - pointer to board structure
+// pSource - loadware block to download
+// isStandard - True if "standard" loadware, else false.
+//
+// Returns: Success or Failure
+//
+// Description:
+//
+// Downloads a single block (at pSource)to the board referenced by pB. Caller
+// sets isStandard to true/false according to whether the "standard" loadware is
+// what's being loaded. The normal process, then, is to perform an iiInitialize
+// to the board, then perform some number of iiDownloadBlocks using the returned
+// state to determine when download is complete.
+//
+// Possible return values: (see I2ELLIS.H)
+// II_DOWN_BADVALID
+// II_DOWN_BADFILE
+// II_DOWN_CONTINUING
+// II_DOWN_GOOD
+// II_DOWN_BAD
+// II_DOWN_BADSTATE
+// II_DOWN_TIMEOUT
+//
+// Uses the i2eState and i2eToLoad fields (initialized at iiInitialize) to
+// determine whether this is the first block, whether to check for magic
+// numbers, how many blocks there are to go...
+//
+//******************************************************************************
+static int
+iiDownloadBlock ( i2eBordStrPtr pB, loadHdrStrPtr pSource, int isStandard)
+{
+ int itemp;
+ int loadedFirst;
+
+ if (pB->i2eValid != I2E_MAGIC) return II_DOWN_BADVALID;
+
+ switch(pB->i2eState)
+ {
+ case II_STATE_READY:
+
+ // Loading the first block after reset. Must check the magic number of the
+ // loadfile, store the number of blocks we expect to load.
+ if (pSource->e.loadMagic != MAGIC_LOADFILE)
+ {
+ return II_DOWN_BADFILE;
+ }
+
+ // Next we store the total number of blocks to load, including this one.
+ pB->i2eToLoad = 1 + pSource->e.loadBlocksMore;
+
+ // Set the state, store the version numbers. ('Cause this may have come
+ // from a file - we might want to report these versions and revisions in
+ // case of an error!
+ pB->i2eState = II_STATE_LOADING;
+ pB->i2eLVersion = pSource->e.loadVersion;
+ pB->i2eLRevision = pSource->e.loadRevision;
+ pB->i2eLSub = pSource->e.loadSubRevision;
+
+ // The time and date of compilation is also available but don't bother
+ // storing it for normal purposes.
+ loadedFirst = 1;
+ break;
+
+ case II_STATE_LOADING:
+ loadedFirst = 0;
+ break;
+
+ default:
+ return II_DOWN_BADSTATE;
+ }
+
+ // Now we must be in the II_STATE_LOADING state, and we assume i2eToLoad
+ // must be positive still, because otherwise we would have cleaned up last
+ // time and set the state to II_STATE_LOADED.
+ if (!iiWaitForTxEmpty(pB, MAX_DLOAD_READ_TIME)) {
+ return II_DOWN_TIMEOUT;
+ }
+
+ if (!iiWriteBuf(pB, pSource->c, LOADWARE_BLOCK_SIZE)) {
+ return II_DOWN_BADVALID;
+ }
+
+ // If we just loaded the first block, wait for the fifo to empty an extra
+ // long time to allow for any special startup code in the firmware, like
+ // sending status messages to the LCD's.
+
+ if (loadedFirst) {
+ if (!iiWaitForTxEmpty(pB, MAX_DLOAD_START_TIME)) {
+ return II_DOWN_TIMEOUT;
+ }
+ }
+
+ // Determine whether this was our last block!
+ if (--(pB->i2eToLoad)) {
+ return II_DOWN_CONTINUING; // more to come...
+ }
+
+ // It WAS our last block: Clean up operations...
+ // ...Wait for last buffer to drain from the board...
+ if (!iiWaitForTxEmpty(pB, MAX_DLOAD_READ_TIME)) {
+ return II_DOWN_TIMEOUT;
+ }
+ // If there were only a single block written, this would come back
+ // immediately and be harmless, though not strictly necessary.
+ itemp = MAX_DLOAD_ACK_TIME/10;
+ while (--itemp) {
+ if (HAS_INPUT(pB)) {
+ switch(BYTE_FROM(pB))
+ {
+ case LOADWARE_OK:
+ pB->i2eState =
+ isStandard ? II_STATE_STDLOADED :II_STATE_LOADED;
+
+ // Some revisions of the bootstrap firmware (e.g. ISA-8 1.0.2)
+ // will, // if there is a debug port attached, require some
+ // time to send information to the debug port now. It will do
+ // this before // executing any of the code we just downloaded.
+ // It may take up to 700 milliseconds.
+ if (pB->i2ePom.e.porDiag2 & POR_DEBUG_PORT) {
+ iiDelay(pB, 700);
+ }
+
+ return II_DOWN_GOOD;
+
+ case LOADWARE_BAD:
+ default:
+ return II_DOWN_BAD;
+ }
+ }
+
+ iiDelay(pB, 10); // 10 mS granularity on checking condition
+ }
+
+ // Drop-through --> timed out waiting for firmware confirmation
+
+ pB->i2eState = II_STATE_BADLOAD;
+ return II_DOWN_TIMEOUT;
+}
+
+//******************************************************************************
+// Function: iiDownloadAll(pB, pSource, isStandard, size)
+// Parameters: pB - pointer to board structure
+// pSource - loadware block to download
+// isStandard - True if "standard" loadware, else false.
+// size - size of data to download (in bytes)
+//
+// Returns: Success or Failure
+//
+// Description:
+//
+// Given a pointer to a board structure, a pointer to the beginning of some
+// loadware, whether it is considered the "standard loadware", and the size of
+// the array in bytes loads the entire array to the board as loadware.
+//
+// Assumes the board has been freshly reset and the power-up reset message read.
+// (i.e., in II_STATE_READY). Complains if state is bad, or if there seems to be
+// too much or too little data to load, or if iiDownloadBlock complains.
+//******************************************************************************
+static int
+iiDownloadAll(i2eBordStrPtr pB, loadHdrStrPtr pSource, int isStandard, int size)
+{
+ int status;
+
+ // We know (from context) board should be ready for the first block of
+ // download. Complain if not.
+ if (pB->i2eState != II_STATE_READY) return II_DOWN_BADSTATE;
+
+ while (size > 0) {
+ size -= LOADWARE_BLOCK_SIZE; // How much data should there be left to
+ // load after the following operation ?
+
+ // Note we just bump pSource by "one", because its size is actually that
+ // of an entire block, same as LOADWARE_BLOCK_SIZE.
+ status = iiDownloadBlock(pB, pSource++, isStandard);
+
+ switch(status)
+ {
+ case II_DOWN_GOOD:
+ return ( (size > 0) ? II_DOWN_OVER : II_DOWN_GOOD);
+
+ case II_DOWN_CONTINUING:
+ break;
+
+ default:
+ return status;
+ }
+ }
+
+ // We shouldn't drop out: it means "while" caught us with nothing left to
+ // download, yet the previous DownloadBlock did not return complete. Ergo,
+ // not enough data to match the size byte in the header.
+ return II_DOWN_UNDER;
+}
diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h
new file mode 100644
index 000000000..56fd03fd2
--- /dev/null
+++ b/drivers/char/ip2/i2ellis.h
@@ -0,0 +1,609 @@
+/*******************************************************************************
+*
+* (c) 1999 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Mainline code for the device driver
+*
+*******************************************************************************/
+//------------------------------------------------------------------------------
+// i2ellis.h
+//
+// IntelliPort-II and IntelliPort-IIEX
+//
+// Extremely
+// Low
+// Level
+// Interface
+// Services
+//
+// Structure Definitions and declarations for "ELLIS" service routines found in
+// i2ellis.c
+//
+// These routines are based on properties of the IntelliPort-II and -IIEX
+// hardware and bootstrap firmware, and are not sensitive to particular
+// conventions of any particular loadware.
+//
+// Unlike i2hw.h, which provides IRONCLAD hardware definitions, the material
+// here and in i2ellis.c is intended to provice a useful, but not required,
+// layer of insulation from the hardware specifics.
+//------------------------------------------------------------------------------
+#ifndef I2ELLIS_H /* To prevent multiple includes */
+#define I2ELLIS_H 1
+//------------------------------------------------
+// Revision History:
+//
+// 30 September 1991 MAG First Draft Started
+// 12 October 1991 ...continued...
+//
+// 20 December 1996 AKM Linux version
+//-------------------------------------------------
+
+//----------------------
+// Mandatory Includes:
+//----------------------
+#include "ip2types.h"
+#include "i2hw.h" // The hardware definitions
+
+//------------------------------------------
+// STAT_BOXIDS packets
+//------------------------------------------
+#define MAX_BOX 4
+
+typedef struct _bidStat
+{
+ unsigned char bid_value[MAX_BOX];
+} bidStat, *bidStatPtr;
+
+// This packet is sent in response to a CMD_GET_BOXIDS bypass command. For -IIEX
+// boards, reports the hardware-specific "asynchronous resource register" on
+// each expansion box. Boxes not present report 0xff. For -II boards, the first
+// element contains 0x80 for 8-port, 0x40 for 4-port boards.
+
+// Box IDs aka ARR or Async Resource Register (more than you want to know)
+// 7 6 5 4 3 2 1 0
+// F F N N L S S S
+// =============================
+// F F - Product Family Designator
+// =====+++++++++++++++++++++++++++++++
+// 0 0 - Intelliport II EX / ISA-8
+// 1 0 - IntelliServer
+// 0 1 - SAC - Port Device (Intelliport III ??? )
+// =====+++++++++++++++++++++++++++++++++++++++
+// N N - Number of Ports
+// 0 0 - 8 (eight)
+// 0 1 - 4 (four)
+// 1 0 - 12 (twelve)
+// 1 1 - 16 (sixteen)
+// =++++++++++++++++++++++++++++++++++
+// L - LCD Display Module Present
+// 0 - No
+// 1 - LCD module present
+// =========+++++++++++++++++++++++++++++++++++++
+// S S S - Async Signals Supported Designator
+// 0 0 0 - 8dss, Mod DCE DB25 Female
+// 0 0 1 - 6dss, RJ-45
+// 0 1 0 - RS-232/422 dss, DB25 Female
+// 0 1 1 - RS-232/422 dss, separate 232/422 DB25 Female
+// 1 0 0 - 6dss, 921.6 I/F with ST654's
+// 1 0 1 - RS-423/232 8dss, RJ-45 10Pin
+// 1 1 0 - 6dss, Mod DCE DB25 Female
+// 1 1 1 - NO BOX PRESENT
+
+#define FF(c) ((c & 0xC0) >> 6)
+#define NN(c) ((c & 0x30) >> 4)
+#define L(c) ((c & 0x08) >> 3)
+#define SSS(c) (c & 0x07)
+
+#define BID_HAS_654(x) (SSS(x) == 0x04)
+#define BID_NO_BOX 0xff /* no box */
+#define BID_8PORT 0x80 /* IP2-8 port */
+#define BID_4PORT 0x81 /* IP2-4 port */
+#define BID_EXP_MASK 0x30 /* IP2-EX */
+#define BID_EXP_8PORT 0x00 /* 8, */
+#define BID_EXP_4PORT 0x10 /* 4, */
+#define BID_EXP_UNDEF 0x20 /* UNDEF, */
+#define BID_EXP_16PORT 0x30 /* 16, */
+#define BID_LCD_CTRL 0x08 /* LCD Controller */
+#define BID_LCD_NONE 0x00 /* - no controller present */
+#define BID_LCD_PRES 0x08 /* - controller present */
+#define BID_CON_MASK 0x07 /* - connector pinouts */
+#define BID_CON_DB25 0x00 /* - DB-25 F */
+#define BID_CON_RJ45 0x01 /* - rj45 */
+
+//------------------------------------------------------------------------------
+// i2eBordStr
+//
+// This structure contains all the information the ELLIS routines require in
+// dealing with a particular board.
+//------------------------------------------------------------------------------
+// There are some queues here which are guaranteed to never contain the entry
+// for a single channel twice. So they must be slightly larger to allow
+// unambiguous full/empty management
+//
+#define CH_QUEUE_SIZE ABS_MOST_PORTS+2
+
+typedef struct _i2eBordStr
+{
+ porStr i2ePom; // Structure containing the power-on message.
+
+ unsigned short i2ePomSize;
+ // The number of bytes actually read if
+ // different from sizeof i2ePom, indicates
+ // there is an error!
+
+ unsigned short i2eStartMail;
+ // Contains whatever inbound mailbox data
+ // present at startup. NO_MAIL_HERE indicates
+ // nothing was present. No special
+ // significance as of this writing, but may be
+ // useful for diagnostic reasons.
+
+ unsigned short i2eValid;
+ // Indicates validity of the structure; if
+ // i2eValid == I2E_MAGIC, then we can trust
+ // the other fields. Some (especially
+ // initialization) functions are good about
+ // checking for validity. Many functions do
+ // not, it being assumed that the larger
+ // context assures we are using a valid
+ // i2eBordStrPtr.
+
+ unsigned short i2eError;
+ // Used for returning an error condition from
+ // several functions which use i2eBordStrPtr
+ // as an argument.
+
+ // Accelerators to characterize separate features of a board, derived from a
+ // number of sources.
+
+ unsigned short i2eFifoSize;
+ // Always, the size of the FIFO. For
+ // IntelliPort-II, always the same, for -IIEX
+ // taken from the Power-On reset message.
+
+ volatile
+ unsigned short i2eFifoRemains;
+ // Used during normal operation to indicate a
+ // lower bound on the amount of data which
+ // might be in the outbound fifo.
+
+ unsigned char i2eFifoStyle;
+ // Accelerator which tells which style (-II or
+ // -IIEX) FIFO we are using.
+
+ unsigned char i2eDataWidth16;
+ // Accelerator which tells whether we should
+ // do 8 or 16-bit data transfers.
+
+ unsigned char i2eMaxIrq;
+ // The highest allowable IRQ, based on the
+ // slot size.
+
+ unsigned char i2eChangeIrq;
+ // Whether tis valid to change IRQ's
+ // ISA = ok, EISA, MicroChannel, no
+
+ // Accelerators for various addresses on the board
+ int i2eBase; // I/O Address of the Board
+ int i2eData; // From here data transfers happen
+ int i2eStatus; // From here status reads happen
+ int i2ePointer; // (IntelliPort-II: pointer/commands)
+ int i2eXMail; // (IntelliPOrt-IIEX: mailboxes
+ int i2eXMask; // (IntelliPort-IIEX: mask write
+
+ //-------------------------------------------------------
+ // Information presented in a common format across boards
+ // For each box, bit map of the channels present. Box closest to
+ // the host is box 0. LSB is channel 0. IntelliPort-II (non-expandable)
+ // is taken to be box 0. These are derived from product i.d. registers.
+
+ unsigned short i2eChannelMap[ABS_MAX_BOXES];
+
+ // Same as above, except each is derived from firmware attempting to detect
+ // the uart presence (by reading a valid GFRCR register). If bits are set in
+ // i2eChannelMap and not in i2eGoodMap, there is a potential problem.
+
+ unsigned short i2eGoodMap[ABS_MAX_BOXES];
+
+ // ---------------------------
+ // For indirect function calls
+
+ // Routine to cause an N-millisecond delay: Patched by the ii2Initialize
+ // function.
+
+ void (*i2eDelay)(unsigned int);
+
+ // Routine to write N bytes to the board through the FIFO. Returns true if
+ // all copacetic, otherwise returns false and error is in i2eError field.
+ // IF COUNT IS ODD, ROUNDS UP TO THE NEXT EVEN NUMBER.
+
+ int (*i2eWriteBuf)(struct _i2eBordStr *, unsigned char *, int);
+
+ // Routine to read N bytes from the board through the FIFO. Returns true if
+ // copacetic, otherwise returns false and error in i2eError.
+ // IF COUNT IS ODD, ROUNDS UP TO THE NEXT EVEN NUMBER.
+
+ int (*i2eReadBuf)(struct _i2eBordStr *, unsigned char *, int);
+
+ // Returns a word from FIFO. Will use 2 byte operations if needed.
+
+ unsigned short (*i2eReadWord)(struct _i2eBordStr *);
+
+ // Writes a word to FIFO. Will use 2 byte operations if needed.
+
+ void (*i2eWriteWord)(struct _i2eBordStr *, unsigned short);
+
+ // Waits specified time for the Transmit FIFO to go empty. Returns true if
+ // ok, otherwise returns false and error in i2eError.
+
+ int (*i2eWaitForTxEmpty)(struct _i2eBordStr *, int);
+
+ // Returns true or false according to whether the outgoing mailbox is empty.
+
+ int (*i2eTxMailEmpty)(struct _i2eBordStr *);
+
+ // Checks whether outgoing mailbox is empty. If so, sends mail and returns
+ // true. Otherwise returns false.
+
+ int (*i2eTrySendMail)(struct _i2eBordStr *, unsigned char);
+
+ // If no mail available, returns NO_MAIL_HERE, else returns the value in the
+ // mailbox (guaranteed can't be NO_MAIL_HERE).
+
+ unsigned short (*i2eGetMail)(struct _i2eBordStr *);
+
+ // Enables the board to interrupt the host when it writes to the mailbox.
+ // Irqs will not occur, however, until the loadware separately enables
+ // interrupt generation to the host. The standard loadware does this in
+ // response to a command packet sent by the host. (Also, disables
+ // any other potential interrupt sources from the board -- other than the
+ // inbound mailbox).
+
+ void (*i2eEnableMailIrq)(struct _i2eBordStr *);
+
+ // Writes an arbitrary value to the mask register.
+
+ void (*i2eWriteMask)(struct _i2eBordStr *, unsigned char);
+
+
+ // State information
+
+ // During downloading, indicates the number of blocks remaining to download
+ // to the board.
+
+ short i2eToLoad;
+
+ // State of board (see manifests below) (e.g., whether in reset condition,
+ // whether standard loadware is installed, etc.
+
+ unsigned char i2eState;
+
+ // These three fields are only valid when there is loadware running on the
+ // board. (i2eState == II_STATE_LOADED or i2eState == II_STATE_STDLOADED )
+
+ unsigned char i2eLVersion; // Loadware version
+ unsigned char i2eLRevision; // Loadware revision
+ unsigned char i2eLSub; // Loadware subrevision
+
+ // Flags which only have meaning in the context of the standard loadware.
+ // Somewhat violates the layering concept, but there is so little additional
+ // needed at the board level (while much additional at the channel level),
+ // that this beats maintaining two different per-board structures.
+
+ // Indicates which IRQ the board has been initialized (from software) to use
+ // For MicroChannel boards, any value different from IRQ_UNDEFINED means
+ // that the software command has been sent to enable interrupts (or specify
+ // they are disabled). Special value: IRQ_UNDEFINED indicates that the
+ // software command to select the interrupt has not yet been sent, therefore
+ // (since the standard loadware insists that it be sent before any other
+ // packets are sent) no other packets should be sent yet.
+
+ unsigned short i2eUsingIrq;
+
+ // This is set when we hit the MB_OUT_STUFFED mailbox, which prevents us
+ // putting more in the mailbox until an appropriate mailbox message is
+ // received.
+
+ unsigned char i2eWaitingForEmptyFifo;
+
+ // Any mailbox bits waiting to be sent to the board are OR'ed in here.
+
+ unsigned char i2eOutMailWaiting;
+
+ // The head of any incoming packet is read into here, is then examined and
+ // we dispatch accordingly.
+
+ unsigned short i2eLeadoffWord[1];
+
+ // Running counter of interrupts where the mailbox indicated incoming data.
+
+ unsigned short i2eFifoInInts;
+
+ // Running counter of interrupts where the mailbox indicated outgoing data
+ // had been stripped.
+
+ unsigned short i2eFifoOutInts;
+
+ // If not void, gives the address of a routine to call if fatal board error
+ // is found (only applies to standard l/w).
+
+ void (*i2eFatalTrap)(struct _i2eBordStr *);
+
+ // Will point to an array of some sort of channel structures (whose format
+ // is unknown at this level, being a function of what loadware is
+ // installed and the code configuration (max sizes of buffers, etc.)).
+
+ void *i2eChannelPtr;
+
+ // Set indicates that the board has gone fatal.
+
+ unsigned short i2eFatal;
+
+ // The number of elements pointed to by i2eChannelPtr.
+
+ unsigned short i2eChannelCnt;
+
+ // Ring-buffers of channel structures whose channels have particular needs.
+
+ spinlock_t Fbuf_spinlock;
+ volatile
+ unsigned short i2Fbuf_strip; // Strip index
+ volatile
+ unsigned short i2Fbuf_stuff; // Stuff index
+ void *i2Fbuf[CH_QUEUE_SIZE]; // An array of channel pointers
+ // of channels who need to send
+ // flow control packets.
+ spinlock_t Dbuf_spinlock;
+ volatile
+ unsigned short i2Dbuf_strip; // Strip index
+ volatile
+ unsigned short i2Dbuf_stuff; // Stuff index
+ void *i2Dbuf[CH_QUEUE_SIZE]; // An array of channel pointers
+ // of channels who need to send
+ // data or in-line command packets.
+ spinlock_t Bbuf_spinlock;
+ volatile
+ unsigned short i2Bbuf_strip; // Strip index
+ volatile
+ unsigned short i2Bbuf_stuff; // Stuff index
+ void *i2Bbuf[CH_QUEUE_SIZE]; // An array of channel pointers
+ // of channels who need to send
+ // bypass command packets.
+
+ /*
+ * A set of flags to indicate that certain events have occurred on at least
+ * one of the ports on this board. We use this to decide whether to spin
+ * through the channels looking for breaks, etc.
+ */
+ int got_input;
+ int status_change;
+ bidStat channelBtypes;
+
+ /*
+ * Debugging counters, etc.
+ */
+ unsigned long debugFlowQueued;
+ unsigned long debugInlineQueued;
+ unsigned long debugDataQueued;
+ unsigned long debugBypassQueued;
+ unsigned long debugFlowCount;
+ unsigned long debugInlineCount;
+ unsigned long debugBypassCount;
+
+ spinlock_t read_fifo_spinlock;
+ spinlock_t write_fifo_spinlock;
+
+} i2eBordStr, *i2eBordStrPtr;
+
+//-------------------------------------------------------------------
+// Macro Definitions for the indirect calls defined in the i2eBordStr
+//-------------------------------------------------------------------
+//
+#define iiDelay(a,b) (*(a)->i2eDelay)(b)
+#define iiWriteBuf(a,b,c) (*(a)->i2eWriteBuf)(a,b,c)
+#define iiReadBuf(a,b,c) (*(a)->i2eReadBuf)(a,b,c)
+
+#define iiWriteWord(a,b) (*(a)->i2eWriteWord)(a,b)
+#define iiReadWord(a) (*(a)->i2eReadWord)(a)
+
+#define iiWaitForTxEmpty(a,b) (*(a)->i2eWaitForTxEmpty)(a,b)
+
+#define iiTxMailEmpty(a) (*(a)->i2eTxMailEmpty)(a)
+#define iiTrySendMail(a,b) (*(a)->i2eTrySendMail)(a,b)
+
+#define iiGetMail(a) (*(a)->i2eGetMail)(a)
+#define iiEnableMailIrq(a) (*(a)->i2eEnableMailIrq)(a)
+#define iiDisableMailIrq(a) (*(a)->i2eWriteMask)(a,0)
+#define iiWriteMask(a,b) (*(a)->i2eWriteMask)(a,b)
+
+//-------------------------------------------
+// Manifests for i2eBordStr:
+//-------------------------------------------
+
+#define YES 1
+#define NO 0
+
+#define NULLFUNC (void (*)(void))0
+#define NULLPTR (void *)0
+
+typedef void (*delayFunc_t)(unsigned int);
+
+// i2eValid
+//
+#define I2E_MAGIC 0x4251 // Structure is valid.
+#define I2E_INCOMPLETE 0x1122 // Structure failed during init.
+
+
+// i2eError
+//
+#define I2EE_GOOD 0 // Operation successful
+#define I2EE_BADADDR 1 // Address out of range
+#define I2EE_BADSTATE 2 // Attempt to perform a function when the board
+ // structure was in the incorrect state
+#define I2EE_BADMAGIC 3 // Bad magic number from Power On test (i2ePomSize
+ // reflects what was read
+#define I2EE_PORM_SHORT 4 // Power On message too short
+#define I2EE_PORM_LONG 5 // Power On message too long
+#define I2EE_BAD_FAMILY 6 // Un-supported board family type
+#define I2EE_INCONSIST 7 // Firmware reports something impossible,
+ // e.g. unexpected number of ports... Almost no
+ // excuse other than bad FIFO...
+#define I2EE_POSTERR 8 // Power-On self test reported a bad error
+#define I2EE_BADBUS 9 // Unknown Bus type declared in message
+#define I2EE_TXE_TIME 10 // Timed out waiting for TX Fifo to empty
+#define I2EE_INVALID 11 // i2eValid field does not indicate a valid and
+ // complete board structure (for functions which
+ // require this be so.)
+#define I2EE_BAD_PORT 12 // Discrepancy between channels actually found and
+ // what the product is supposed to have. Check
+ // i2eGoodMap vs i2eChannelMap for details.
+#define I2EE_BAD_IRQ 13 // Someone specified an unsupported IRQ
+#define I2EE_NOCHANNELS 14 // No channel structures have been defined (for
+ // functions requiring this).
+
+// i2eFifoStyle
+//
+#define FIFO_II 0 /* IntelliPort-II style: see also i2hw.h */
+#define FIFO_IIEX 1 /* IntelliPort-IIEX style */
+
+// i2eGetMail
+//
+#define NO_MAIL_HERE 0x1111 // Since mail is unsigned char, cannot possibly
+ // promote to 0x1111.
+// i2eState
+//
+#define II_STATE_COLD 0 // Addresses have been defined, but board not even
+ // reset yet.
+#define II_STATE_RESET 1 // Board,if it exists, has just been reset
+#define II_STATE_READY 2 // Board ready for its first block
+#define II_STATE_LOADING 3 // Board continuing load
+#define II_STATE_LOADED 4 // Board has finished load: status ok
+#define II_STATE_BADLOAD 5 // Board has finished load: failed!
+#define II_STATE_STDLOADED 6 // Board has finished load: standard firmware
+
+// i2eUsingIrq
+//
+#define IRQ_UNDEFINED 0x1352 // No valid irq (or polling = 0) can ever
+ // promote to this!
+//------------------------------------------
+// Handy Macros for i2ellis.c and others
+// Note these are common to -II and -IIEX
+//------------------------------------------
+
+// Given a pointer to the board structure, does the input FIFO have any data or
+// not?
+//
+#define HAS_INPUT(pB) !(INB(pB->i2eStatus) & ST_IN_EMPTY)
+#define HAS_NO_INPUT(pB) (INB(pB->i2eStatus) & ST_IN_EMPTY)
+
+// Given a pointer to board structure, read a byte or word from the fifo
+//
+#define BYTE_FROM(pB) (unsigned char)INB(pB->i2eData)
+#define WORD_FROM(pB) (unsigned short)INW(pB->i2eData)
+
+// Given a pointer to board structure, is there room for any data to be written
+// to the data fifo?
+//
+#define HAS_OUTROOM(pB) !(INB(pB->i2eStatus) & ST_OUT_FULL)
+#define HAS_NO_OUTROOM(pB) (INB(pB->i2eStatus) & ST_OUT_FULL)
+
+// Given a pointer to board structure, write a single byte to the fifo
+// structure. Note that for 16-bit interfaces, the high order byte is undefined
+// and unknown.
+//
+#define BYTE_TO(pB, c) OUTB(pB->i2eData,(c))
+
+// Write a word to the fifo structure. For 8-bit interfaces, this may have
+// unknown results.
+//
+#define WORD_TO(pB, c) OUTW(pB->i2eData,(c))
+
+// Given a pointer to the board structure, is there anything in the incoming
+// mailbox?
+//
+#define HAS_MAIL(pB) (INB(pB->i2eStatus) & ST_IN_MAIL)
+
+#define UPDATE_FIFO_ROOM(pB) (pB)->i2eFifoRemains=(pB)->i2eFifoSize
+
+// Handy macro to round up a number (like the buffer write and read routines do)
+//
+#define ROUNDUP(number) (((number)+1) & (~1))
+
+//------------------------------------------
+// Function Declarations for i2ellis.c
+//------------------------------------------
+//
+// Functions called directly
+//
+// Initialization of a board & structure is in four (five!) parts:
+//
+// 0) iiEllisInit() - Initialize iiEllis subsystem.
+// 1) iiSetAddress() - Define the board address & delay function for a board.
+// 2) iiReset() - Reset the board (provided it exists)
+// -- Note you may do this to several boards --
+// 3) iiResetDelay() - Delay for 2 seconds (once for all boards)
+// 4) iiInitialize() - Attempt to read Power-up message; further initialize
+// accelerators
+//
+// Then you may use iiDownloadAll() or iiDownloadFile() (in i2file.c) to write
+// loadware. To change loadware, you must begin again with step 2, resetting
+// the board again (step 1 not needed).
+
+static void iiEllisInit(void);
+static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t );
+static int iiReset(i2eBordStrPtr);
+static int iiResetDelay(i2eBordStrPtr);
+static int iiInitialize(i2eBordStrPtr);
+
+// Routine to validate that all channels expected are there.
+//
+extern int iiValidateChannels(i2eBordStrPtr);
+
+// Routine used to download a block of loadware.
+//
+static int iiDownloadBlock(i2eBordStrPtr, loadHdrStrPtr, int);
+
+// Return values given by iiDownloadBlock, iiDownloadAll, iiDownloadFile:
+//
+#define II_DOWN_BADVALID 0 // board structure is invalid
+#define II_DOWN_CONTINUING 1 // So far, so good, firmware expects more
+#define II_DOWN_GOOD 2 // Download complete, CRC good
+#define II_DOWN_BAD 3 // Download complete, but CRC bad
+#define II_DOWN_BADFILE 4 // Bad magic number in loadware file
+#define II_DOWN_BADSTATE 5 // Board is in an inappropriate state for
+ // downloading loadware. (see i2eState)
+#define II_DOWN_TIMEOUT 6 // Timeout waiting for firmware
+#define II_DOWN_OVER 7 // Too much data
+#define II_DOWN_UNDER 8 // Not enough data
+#define II_DOWN_NOFILE 9 // Loadware file not found
+
+// Routine to download an entire loadware module: Return values are a subset of
+// iiDownloadBlock's, excluding, of course, II_DOWN_CONTINUING
+//
+static int iiDownloadAll(i2eBordStrPtr, loadHdrStrPtr, int, int);
+
+// Called indirectly always. Needed externally so the routine might be
+// SPECIFIED as an argument to iiReset()
+//
+//static void ii2DelayIO(unsigned int); // N-millisecond delay using
+ //hardware spin
+//static void ii2DelayTimer(unsigned int); // N-millisecond delay using Linux
+ //timer
+
+// Many functions defined here return True if good, False otherwise, with an
+// error code in i2eError field. Here is a handy macro for setting the error
+// code and returning.
+//
+#define COMPLETE(pB,code) \
+ if(1){ \
+ pB->i2eError = code; \
+ return (code == I2EE_GOOD);\
+ }
+
+#endif // I2ELLIS_H
diff --git a/drivers/char/ip2/i2hw.h b/drivers/char/ip2/i2hw.h
new file mode 100644
index 000000000..9e5b07ca0
--- /dev/null
+++ b/drivers/char/ip2/i2hw.h
@@ -0,0 +1,648 @@
+/*******************************************************************************
+*
+* (c) 1999 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Definitions limited to properties of the hardware or the
+* bootstrap firmware. As such, they are applicable regardless of
+* operating system or loadware (standard or diagnostic).
+*
+*******************************************************************************/
+#ifndef I2HW_H
+#define I2HW_H 1
+//------------------------------------------------------------------------------
+// Revision History:
+//
+// 23 September 1991 MAG First Draft Started...through...
+// 11 October 1991 ... Continuing development...
+// 6 August 1993 Added support for ISA-4 (asic) which is architected
+// as an ISA-CEX with a single 4-port box.
+//
+// 20 December 1996 AKM Version for Linux
+//
+//------------------------------------------------------------------------------
+/*------------------------------------------------------------------------------
+
+HARDWARE DESCRIPTION:
+
+Introduction:
+
+The IntelliPort-II and IntelliPort-IIEX products occupy a block of eight (8)
+addresses in the host's I/O space.
+
+Some addresses are used to transfer data to/from the board, some to transfer
+so-called "mailbox" messages, and some to read bit-mapped status information.
+While all the products in the line are functionally similar, some use a 16-bit
+data path to transfer data while others use an 8-bit path. Also, the use of
+command /status/mailbox registers differs slightly between the II and IIEX
+branches of the family.
+
+The host determines what type of board it is dealing with by reading a string of
+sixteen characters from the board. These characters are always placed in the
+fifo by the board's local processor whenever the board is reset (either from
+power-on or under software control) and are known as the "Power-on Reset
+Message." In order that this message can be read from either type of board, the
+hardware registers used in reading this message are the same. Once this message
+has been read by the host, then it has the information required to operate.
+
+General Differences between boards:
+
+The greatest structural difference is between the -II and -IIEX families of
+product. The -II boards use the Am4701 dual 512x8 bidirectional fifo to support
+the data path, mailbox registers, and status registers. This chip contains some
+features which are not used in the IntelliPort-II products; a description of
+these is omitted here. Because of these many features, it contains many
+registers, too many to access directly within a small address space. They are
+accessed by first writing a value to a "pointer" register. This value selects
+the register to be accessed. The next read or write to that address accesses
+the selected register rather than the pointer register.
+
+The -IIEX boards use a proprietary design similar to the Am4701 in function. But
+because of a simpler, more streamlined design it doesn't require so many
+registers. This means they can be accessed directly in single operations rather
+than through a pointer register.
+
+Besides these differences, there are differences in whether 8-bit or 16-bit
+transfers are used to move data to the board.
+
+The -II boards are capable only of 8-bit data transfers, while the -IIEX boards
+may be configured for either 8-bit or 16-bit data transfers. If the on-board DIP
+switch #8 is ON, and the card has been installed in a 16-bit slot, 16-bit
+transfers are supported (and will be expected by the standard loadware). The
+on-board firmware can determine the position of the switch, and whether the
+board is installed in a 16-bit slot; it supplies this information to the host as
+part of the power-up reset message.
+
+The configuration switch (#8) and slot selection do not directly configure the
+hardware. It is up to the on-board loadware and host-based drivers to act
+according to the selected options. That is, loadware and drivers could be
+written to perform 8-bit transfers regardless of the state of the DIP switch or
+slot (and in a diagnostic environment might well do so). Likewise, 16-bit
+transfers could be performed as long as the card is in a 16-bit slot.
+
+Note the slot selection and DIP switch selection are provided separately: a
+board running in 8-bit mode in a 16-bit slot has a greater range of possible
+interrupts to choose from; information of potential use to the host.
+
+All 8-bit data transfers are done in the same way, regardless of whether on a
+-II board or a -IIEX board.
+
+The host must consider two things then: 1) whether a -II or -IIEX product is
+being used, and 2) whether an 8-bit or 16-bit data path is used.
+
+A further difference is that -II boards always have a 512-byte fifo operating in
+each direction. -IIEX boards may use fifos of varying size; this size is
+reported as part of the power-up message.
+
+I/O Map Of IntelliPort-II and IntelliPort-IIEX boards:
+(Relative to the chosen base address)
+
+Addr R/W IntelliPort-II IntelliPort-IIEX
+---- --- -------------- ----------------
+0 R/W Data Port (byte) Data Port (byte or word)
+1 R/W (Not used) (MSB of word-wide data written to Data Port)
+2 R Status Register Status Register
+2 W Pointer Register Interrupt Mask Register
+3 R/W (Not used) Mailbox Registers (6 bits: 11111100)
+4,5 -- Reserved for future products
+6 -- Reserved for future products
+7 R Guaranteed to have no effect
+7 W Hardware reset of board.
+
+
+Rules:
+All data transfers are performed using the even i/o address. If byte-wide data
+transfers are being used, do INB/OUTB operations on the data port. If word-wide
+transfers are used, do INW/OUTW operations. In some circumstances (such as
+reading the power-up message) you will do INB from the data port, but in this
+case the MSB of each word read is lost. When accessing all other unreserved
+registers, use byte operations only.
+------------------------------------------------------------------------------*/
+
+//------------------------------------------------
+// Mandatory Includes:
+//------------------------------------------------
+//
+#include "ip2types.h"
+#include "i2os.h" /* For any o.s., compiler, or host-related issues */
+
+//-------------------------------------------------------------------------
+// Manifests for the I/O map:
+//-------------------------------------------------------------------------
+// R/W: Data port (byte) for IntelliPort-II,
+// R/W: Data port (byte or word) for IntelliPort-IIEX
+// Incoming or outgoing data passes through a FIFO, the status of which is
+// available in some of the bits in FIFO_STATUS. This (bidirectional) FIFO is
+// the primary means of transferring data, commands, flow-control, and status
+// information between the host and board.
+//
+#define FIFO_DATA 0
+
+// Another way of passing information between the the board and the host is
+// through "mailboxes". Unlike a FIFO, a mailbox holds only a single byte of
+// data. Writing data to the mailbox causes a status bit to be set, and
+// potentially interrupting the intended receiver. The sender has some way to
+// determine whether the data has been read yet; as soon as it has, it may send
+// more. The mailboxes are handled differently on -II and -IIEX products, as
+// suggested below.
+//------------------------------------------------------------------------------
+// Read: Status Register for IntelliPort-II or -IIEX
+// The presence of any bit set here will cause an interrupt to the host,
+// provided the corresponding bit has been unmasked in the interrupt mask
+// register. Furthermore, interrupts to the host are disabled globally until the
+// loadware selects the irq line to use. With the exception of STN_MR, the bits
+// remain set so long as the associated condition is true.
+//
+#define FIFO_STATUS 2
+
+// Bit map of status bits which are identical for -II and -IIEX
+//
+#define ST_OUT_FULL 0x40 // Outbound FIFO full
+#define ST_IN_EMPTY 0x20 // Inbound FIFO empty
+#define ST_IN_MAIL 0x04 // Inbound Mailbox full
+
+// The following exists only on the Intelliport-IIEX, and indicates that the
+// board has not read the last outgoing mailbox data yet. In the IntelliPort-II,
+// the outgoing mailbox may be read back: a zero indicates the board has read
+// the data.
+//
+#define STE_OUT_MAIL 0x80 // Outbound mailbox full (!)
+
+// The following bits are defined differently for -II and -IIEX boards. Code
+// which relies on these bits will need to be functionally different for the two
+// types of boards and should be generally avoided because of the additional
+// complexity this creates:
+
+// Bit map of status bits only on -II
+
+// Fifo has been RESET (cleared when the status register is read). Note that
+// this condition cannot be masked and would always interrupt the host, except
+// that the hardware reset also disables interrupts globally from the board
+// until re-enabled by loadware. This could also arise from the
+// Am4701-supported command to reset the chip, but this command is generally not
+// used here.
+//
+#define STN_MR 0x80
+
+// See the AMD Am4701 data sheet for details on the following four bits. They
+// are not presently used by Computone drivers.
+//
+#define STN_OUT_AF 0x10 // Outbound FIFO almost full (programmable)
+#define STN_IN_AE 0x08 // Inbound FIFO almost empty (programmable)
+#define STN_BD 0x02 // Inbound byte detected
+#define STN_PE 0x01 // Parity/Framing condition detected
+
+// Bit-map of status bits only on -IIEX
+//
+#define STE_OUT_HF 0x10 // Outbound FIFO half full
+#define STE_IN_HF 0x08 // Inbound FIFO half full
+#define STE_IN_FULL 0x02 // Inbound FIFO full
+#define STE_OUT_MT 0x01 // Outbound FIFO empty
+
+//------------------------------------------------------------------------------
+
+// Intelliport-II -- Write Only: the pointer register.
+// Values are written to this register to select the Am4701 internal register to
+// be accessed on the next operation.
+//
+#define FIFO_PTR 0x02
+
+// Values for the pointer register
+//
+#define SEL_COMMAND 0x1 // Selects the Am4701 command register
+
+// Some possible commands:
+//
+#define SEL_CMD_MR 0x80 // Am4701 command to reset the chip
+#define SEL_CMD_SH 0x40 // Am4701 command to map the "other" port into the
+ // status register.
+#define SEL_CMD_UNSH 0 // Am4701 command to "unshift": port maps into its
+ // own status register.
+#define SEL_MASK 0x2 // Selects the Am4701 interrupt mask register. The
+ // interrupt mask register is bit-mapped to match
+ // the status register (FIFO_STATUS) except for
+ // STN_MR. (See above.)
+#define SEL_BYTE_DET 0x3 // Selects the Am4701 byte-detect register. (Not
+ // normally used except in diagnostics.)
+#define SEL_OUTMAIL 0x4 // Selects the outbound mailbox (R/W). Reading back
+ // a value of zero indicates that the mailbox has
+ // been read by the board and is available for more
+ // data./ Writing to the mailbox optionally
+ // interrupts the board, depending on the loadware's
+ // setting of its interrupt mask register.
+#define SEL_AEAF 0x5 // Selects AE/AF threshold register.
+#define SEL_INMAIL 0x6 // Selects the inbound mailbox (Read)
+
+//------------------------------------------------------------------------------
+// IntelliPort-IIEX -- Write Only: interrupt mask (and misc flags) register:
+// Unlike IntelliPort-II, bit assignments do NOT match those of the status
+// register.
+//
+#define FIFO_MASK 0x2
+
+// Mailbox readback select:
+// If set, reads to FIFO_MAIL will read the OUTBOUND mailbox (host to board). If
+// clear (default on reset) reads to FIFO_MAIL will read the INBOUND mailbox.
+// This is the normal situation. The clearing of a mailbox is determined on
+// -IIEX boards by waiting for the STE_OUT_MAIL bit to clear. Readback
+// capability is provided for diagnostic purposes only.
+//
+#define MX_OUTMAIL_RSEL 0x80
+
+#define MX_IN_MAIL 0x40 // Enables interrupts when incoming mailbox goes
+ // full (ST_IN_MAIL set).
+#define MX_IN_FULL 0x20 // Enables interrupts when incoming FIFO goes full
+ // (STE_IN_FULL).
+#define MX_IN_MT 0x08 // Enables interrupts when incoming FIFO goes empty
+ // (ST_IN_MT).
+#define MX_OUT_FULL 0x04 // Enables interrupts when outgoing FIFO goes full
+ // (ST_OUT_FULL).
+#define MX_OUT_MT 0x01 // Enables interrupts when outgoing FIFO goes empty
+ // (STE_OUT_MT).
+
+// Any remaining bits are reserved, and should be written to ZERO for
+// compatibility with future Computone products.
+
+//------------------------------------------------------------------------------
+// IntelliPort-IIEX: -- These are only 6-bit mailboxes !!! -- 11111100 (low two
+// bits always read back 0).
+// Read: One of the mailboxes, usually Inbound.
+// Inbound Mailbox (MX_OUTMAIL_RSEL = 0)
+// Outbound Mailbox (MX_OUTMAIL_RSEL = 1)
+// Write: Outbound Mailbox
+// For the IntelliPort-II boards, the outbound mailbox is read back to determine
+// whether the board has read the data (0 --> data has been read). For the
+// IntelliPort-IIEX, this is done by reading a status register. To determine
+// whether mailbox is available for more outbound data, use the STE_OUT_MAIL bit
+// in FIFO_STATUS. Moreover, although the Outbound Mailbox can be read back by
+// setting MX_OUTMAIL_RSEL, it is NOT cleared when the board reads it, as is the
+// case with the -II boards. For this reason, FIFO_MAIL is normally used to read
+// the inbound FIFO, and MX_OUTMAIL_RSEL kept clear. (See above for
+// MX_OUTMAIL_RSEL description.)
+//
+#define FIFO_MAIL 0x3
+
+//------------------------------------------------------------------------------
+// WRITE ONLY: Resets the board. (Data doesn't matter).
+//
+#define FIFO_RESET 0x7
+
+//------------------------------------------------------------------------------
+// READ ONLY: Will have no effect. (Data is undefined.)
+// Actually, there will be an effect, in that the operation is sure to generate
+// a bus cycle: viz., an I/O byte Read. This fact can be used to enforce short
+// delays when no comparable time constant is available.
+//
+#define FIFO_NOP 0x7
+
+//------------------------------------------------------------------------------
+// RESET & POWER-ON RESET MESSAGE
+/*------------------------------------------------------------------------------
+RESET:
+
+The IntelliPort-II and -IIEX boards are reset in three ways: Power-up, channel
+reset, and via a write to the reset register described above. For products using
+the ISA bus, these three sources of reset are equvalent. For MCA and EISA buses,
+the Power-up and channel reset sources cause additional hardware initialization
+which should only occur at system startup time.
+
+The third type of reset, called a "command reset", is done by writing any data
+to the FIFO_RESET address described above. This resets the on-board processor,
+FIFO, UARTS, and associated hardware.
+
+This passes control of the board to the bootstrap firmware, which performs a
+Power-On Self Test and which detects its current configuration. For example,
+-IIEX products determine the size of FIFO which has been installed, and the
+number and type of expansion boxes attached.
+
+This and other information is then written to the FIFO in a 16-byte data block
+to be read by the host. This block is guaranteed to be present within two (2)
+seconds of having received the command reset. The firmware is now ready to
+receive loadware from the host.
+
+It is good practice to perform a command reset to the board explicitly as part
+of your software initialization. This allows your code to properly restart from
+a soft boot. (Many systems do not issue channel reset on soft boot).
+
+Because of a hardware reset problem on some of the Cirrus Logic 1400's which are
+used on the product, it is recommended that you reset the board twice, separated
+by an approximately 50 milliseconds delay. (VERY approximately: probably ok to
+be off by a factor of five. The important point is that the first command reset
+in fact generates a reset pulse on the board. This pulse is guaranteed to last
+less than 10 milliseconds. The additional delay ensures the 1400 has had the
+chance to respond sufficiently to the first reset. Why not a longer delay? Much
+more than 50 milliseconds gets to be noticable, but the board would still work.
+
+Once all 16 bytes of the Power-on Reset Message have been read, the bootstrap
+firmware is ready to receive loadware.
+
+Note on Power-on Reset Message format:
+The various fields have been designed with future expansion in view.
+Combinations of bitfields and values have been defined which define products
+which may not currently exist. This has been done to allow drivers to anticipate
+the possible introduction of products in a systematic fashion. This is not
+intended to suggest that each potential product is actually under consideration.
+------------------------------------------------------------------------------*/
+
+//----------------------------------------
+// Format of Power-on Reset Message
+//----------------------------------------
+
+typedef union _porStr // "por" stands for Power On Reset
+{
+ unsigned char c[16]; // array used when considering the message as a
+ // string of undifferentiated characters
+
+ struct // Elements used when considering values
+ {
+ // The first two bytes out of the FIFO are two magic numbers. These are
+ // intended to establish that there is indeed a member of the
+ // IntelliPort-II(EX) family present. The remaining bytes may be
+ // expected // to be valid. When reading the Power-on Reset message,
+ // if the magic numbers do not match it is probably best to stop
+ // reading immediately. You are certainly not reading our board (unless
+ // hardware is faulty), and may in fact be reading some other piece of
+ // hardware.
+
+ unsigned char porMagic1; // magic number: first byte == POR_MAGIC_1
+ unsigned char porMagic2; // magic number: second byte == POR_MAGIC_2
+
+ // The Version, Revision, and Subrevision are stored as absolute numbers
+ // and would normally be displayed in the format V.R.S (e.g. 1.0.2)
+
+ unsigned char porVersion; // Bootstrap firmware version number
+ unsigned char porRevision; // Bootstrap firmware revision number
+ unsigned char porSubRev; // Bootstrap firmware sub-revision number
+
+ unsigned char porID; // Product ID: Bit-mapped according to
+ // conventions described below. Among other
+ // things, this allows us to distinguish
+ // IntelliPort-II boards from IntelliPort-IIEX
+ // boards.
+
+ unsigned char porBus; // IntelliPort-II: Unused
+ // IntelliPort-IIEX: Bus Information:
+ // Bit-mapped below
+
+ unsigned char porMemory; // On-board DRAM size: in 32k blocks
+
+ // porPorts1 (and porPorts2) are used to determine the ports which are
+ // available to the board. For non-expandable product, a single number
+ // is sufficient. For expandable product, the board may be connected
+ // to as many as four boxes. Each box may be (so far) either a 16-port
+ // or an 8-port size. Whenever an 8-port box is used, the remaining 8
+ // ports leave gaps between existing channels. For that reason,
+ // expandable products must report a MAP of available channels. Since
+ // each UART supports four ports, we represent each UART found by a
+ // single bit. Using two bytes to supply the mapping information we
+ // report the presense or absense of up to 16 UARTS, or 64 ports in
+ // steps of 4 ports. For -IIEX products, the ports are numbered
+ // starting at the box closest to the controller in the "chain".
+
+ // Interpreted Differently for IntelliPort-II and -IIEX.
+ // -II: Number of ports (Derived actually from product ID). See
+ // Diag1&2 to indicate if uart was actually detected.
+ // -IIEX: Bit-map of UARTS found, LSB (see below for MSB of this). This
+ // bitmap is based on detecting the uarts themselves;
+ // see porFlags for information from the box i.d's.
+ unsigned char porPorts1;
+
+ unsigned char porDiag1; // Results of on-board P.O.S.T, 1st byte
+ unsigned char porDiag2; // Results of on-board P.O.S.T, 2nd byte
+ unsigned char porSpeed; // Speed of local CPU: given as MHz x10
+ // e.g., 16.0 MHz CPU is reported as 160
+ unsigned char porFlags; // Misc information (see manifests below)
+ // Bit-mapped: CPU type, UART's present
+
+ unsigned char porPorts2; // -II: Undefined
+ // -IIEX: Bit-map of UARTS found, MSB (see
+ // above for LSB)
+
+ // IntelliPort-II: undefined
+ // IntelliPort-IIEX: 1 << porFifoSize gives the size, in bytes, of the
+ // host interface FIFO, in each direction. When running the -IIEX in
+ // 8-bit mode, fifo capacity is halved. The bootstrap firmware will
+ // have already accounted for this fact in generating this number.
+ unsigned char porFifoSize;
+
+ // IntelliPort-II: undefined
+ // IntelliPort-IIEX: The number of boxes connected. (Presently 1-4)
+ unsigned char porNumBoxes;
+ } e;
+} porStr, *porStrPtr;
+
+//--------------------------
+// Values for porStr fields
+//--------------------------
+
+//---------------------
+// porMagic1, porMagic2
+//----------------------
+//
+#define POR_MAGIC_1 0x96 // The only valid value for porMagic1
+#define POR_MAGIC_2 0x35 // The only valid value for porMagic2
+#define POR_1_INDEX 0 // Byte position of POR_MAGIC_1
+#define POR_2_INDEX 1 // Ditto for POR_MAGIC_2
+
+//----------------------
+// porID
+//----------------------
+//
+#define POR_ID_FAMILY 0xc0 // These bits indicate the general family of
+ // product.
+#define POR_ID_FII 0x00 // Family is "IntelliPort-II"
+#define POR_ID_FIIEX 0x40 // Family is "IntelliPort-IIEX"
+
+// These bits are reserved, presently zero. May be used at a later date to
+// convey other product information.
+//
+#define POR_ID_RESERVED 0x3c
+
+#define POR_ID_SIZE 0x03 // Remaining bits indicate number of ports &
+ // Connector information.
+#define POR_ID_II_8 0x00 // For IntelliPort-II, indicates 8-port using
+ // standard brick.
+#define POR_ID_II_8R 0x01 // For IntelliPort-II, indicates 8-port using
+ // RJ11's (no CTS)
+#define POR_ID_II_6 0x02 // For IntelliPort-II, indicates 6-port using
+ // RJ45's
+#define POR_ID_II_4 0x03 // For IntelliPort-II, indicates 4-port using
+ // 4xRJ45 connectors
+#define POR_ID_EX 0x00 // For IntelliPort-IIEX, indicates standard
+ // expandable controller (other values reserved)
+
+//----------------------
+// porBus
+//----------------------
+
+// IntelliPort-IIEX only: Board is installed in a 16-bit slot
+//
+#define POR_BUS_SLOT16 0x20
+
+// IntelliPort-IIEX only: DIP switch #8 is on, selecting 16-bit host interface
+// operation.
+//
+#define POR_BUS_DIP16 0x10
+
+// Bits 0-2 indicate type of bus: This information is stored in the bootstrap
+// loadware, different loadware being used on different products for different
+// buses. For most situations, the drivers do not need this information; but it
+// is handy in a diagnostic environment. For example, on microchannel boards,
+// you would not want to try to test several interrupts, only the one for which
+// you were configured.
+//
+#define POR_BUS_TYPE 0x07
+
+// Unknown: this product doesn't know what bus it is running in. (e.g. if same
+// bootstrap firmware were wanted for two different buses.)
+//
+#define POR_BUS_T_UNK 0
+
+// Note: existing firmware for ISA-8 and MC-8 currently report the POR_BUS_T_UNK
+// state, since the same bootstrap firmware is used for each.
+
+#define POR_BUS_T_MCA 1 // MCA BUS */
+#define POR_BUS_T_EISA 2 // EISA BUS */
+#define POR_BUS_T_ISA 3 // ISA BUS */
+
+// Values 4-7 Reserved
+
+// Remaining bits are reserved
+
+//----------------------
+// porDiag1
+//----------------------
+
+#define POR_BAD_MAPPER 0x80 // HW failure on P.O.S.T: Chip mapper failed
+
+// These two bits valid only for the IntelliPort-II
+//
+#define POR_BAD_UART1 0x01 // First 1400 bad
+#define POR_BAD_UART2 0x02 // Second 1400 bad
+
+//----------------------
+// porDiag2
+//----------------------
+
+#define POR_DEBUG_PORT 0x80 // debug port was detected by the P.O.S.T
+#define POR_DIAG_OK 0x00 // Indicates passage: Failure codes not yet
+ // available.
+ // Other bits undefined.
+//----------------------
+// porFlags
+//----------------------
+
+#define POR_CPU 0x03 // These bits indicate supposed CPU type
+#define POR_CPU_8 0x01 // Board uses an 80188 (no such thing yet)
+#define POR_CPU_6 0x02 // Board uses an 80186 (all existing products)
+#define POR_CEX4 0x04 // If set, this is an ISA-CEX/4: An ISA-4 (asic)
+ // which is architected like an ISA-CEX connected
+ // to a (hitherto impossible) 4-port box.
+#define POR_BOXES 0xf0 // Valid for IntelliPort-IIEX only: Map of Box
+ // sizes based on box I.D.
+#define POR_BOX_16 0x10 // Set indicates 16-port, clear 8-port
+
+//-------------------------------------
+// LOADWARE and DOWNLOADING CODE
+//-------------------------------------
+
+/*
+Loadware may be sent to the board in two ways:
+1) It may be read from a (binary image) data file block by block as each block
+ is sent to the board. This is only possible when the initialization is
+ performed by code which can access your file system. This is most suitable
+ for diagnostics and appications which use the interface library directly.
+
+2) It may be hard-coded into your source by including a .h file (typically
+ supplied by Computone), which declares a data array and initializes every
+ element. This acheives the same result as if an entire loadware file had
+ been read into the array.
+
+ This requires more data space in your program, but access to the file system
+ is not required. This method is more suited to driver code, which typically
+ is running at a level too low to access the file system directly.
+
+At present, loadware can only be generated at Computone.
+
+All Loadware begins with a header area which has a particular format. This
+includes a magic number which identifies the file as being (purportedly)
+loadware, CRC (for the loader), and version information.
+*/
+
+
+//-----------------------------------------------------------------------------
+// Format of loadware block
+//
+// This is defined as a union so we can pass a pointer to one of these items
+// and (if it is the first block) pick out the version information, etc.
+//
+// Otherwise, to deal with this as a simple character array
+//------------------------------------------------------------------------------
+
+#define LOADWARE_BLOCK_SIZE 512 // Number of bytes in each block of loadware
+
+typedef union _loadHdrStr
+{
+ unsigned char c[LOADWARE_BLOCK_SIZE]; // Valid for every block
+
+ struct // These fields are valid for only the first block of loadware.
+ {
+ unsigned char loadMagic; // Magic number: see below
+ unsigned char loadBlocksMore; // How many more blocks?
+ unsigned char loadCRC[2]; // Two CRC bytes: used by loader
+ unsigned char loadVersion; // Version number
+ unsigned char loadRevision; // Revision number
+ unsigned char loadSubRevision; // Sub-revision number
+ unsigned char loadSpares[9]; // Presently unused
+ unsigned char loadDates[32]; // Null-terminated string which can give
+ // date and time of compilation
+ } e;
+} loadHdrStr, *loadHdrStrPtr;
+
+//------------------------------------
+// Defines for downloading code:
+//------------------------------------
+
+// The loadMagic field in the first block of the loadfile must be this, else the
+// file is not valid.
+//
+#define MAGIC_LOADFILE 0x3c
+
+// How do we know the load was successful? On completion of the load, the
+// bootstrap firmware returns a code to indicate whether it thought the download
+// was valid and intends to execute it. These are the only possible valid codes:
+//
+#define LOADWARE_OK 0xc3 // Download was ok
+#define LOADWARE_BAD 0x5a // Download was bad (CRC error)
+
+// Constants applicable to writing blocks of loadware:
+// The first block of loadware might take 600 mS to load, in extreme cases.
+// (Expandable board: worst case for sending startup messages to the LCD's).
+// The 600mS figure is not really a calculation, but a conservative
+// guess/guarantee. Usually this will be within 100 mS, like subsequent blocks.
+//
+#define MAX_DLOAD_START_TIME 1000 // 1000 mS
+#define MAX_DLOAD_READ_TIME 100 // 100 mS
+
+// Firmware should respond with status (see above) within this long of host
+// having sent the final block.
+//
+#define MAX_DLOAD_ACK_TIME 100 // 100 mS, again!
+
+//------------------------------------------------------
+// MAXIMUM NUMBER OF PORTS PER BOARD:
+// This is fixed for now (with the expandable), but may
+// be expanding according to even newer products.
+//------------------------------------------------------
+//
+#define ABS_MAX_BOXES 4 // Absolute most boxes per board
+#define ABS_BIGGEST_BOX 16 // Absolute the most ports per box
+#define ABS_MOST_PORTS (ABS_MAX_BOXES * ABS_BIGGEST_BOX)
+
+#endif // I2HW_H
+
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
new file mode 100644
index 000000000..c24bca783
--- /dev/null
+++ b/drivers/char/ip2/i2lib.c
@@ -0,0 +1,2253 @@
+/*******************************************************************************
+*
+* (c) 1999 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: High-level interface code for the device driver. Uses the
+* Extremely Low Level Interface Support (i2ellis.c). Provides an
+* interface to the standard loadware, to support drivers or
+* application code. (This is included source code, not a separate
+* compilation module.)
+*
+*******************************************************************************/
+//------------------------------------------------------------------------------
+// Note on Strategy:
+// Once the board has been initialized, it will interrupt us when:
+// 1) It has something in the fifo for us to read (incoming data, flow control
+// packets, or whatever).
+// 2) It has stripped whatever we have sent last time in the FIFO (and
+// consequently is ready for more).
+//
+// Note also that the buffer sizes declared in i2lib.h are VERY SMALL. This
+// worsens performance considerably, but is done so that a great many channels
+// might use only a little memory.
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Revision History:
+//
+// 0.00 - 4/16/91 --- First Draft
+// 0.01 - 4/29/91 --- 1st beta release
+// 0.02 - 6/14/91 --- Changes to allow small model compilation
+// 0.03 - 6/17/91 MAG Break reporting protected from interrupts routines with
+// in-line asm added for moving data to/from ring buffers,
+// replacing a variety of methods used previously.
+// 0.04 - 6/21/91 MAG Initial flow-control packets not queued until
+// i2_enable_interrupts time. Former versions would enqueue
+// them at i2_init_channel time, before we knew how many
+// channels were supposed to exist!
+// 0.05 - 10/12/91 MAG Major changes: works through the ellis.c routines now;
+// supports new 16-bit protocol and expandable boards.
+// - 10/24/91 MAG Most changes in place and stable.
+// 0.06 - 2/20/92 MAG Format of CMD_HOTACK corrected: the command takes no
+// argument.
+// 0.07 -- 3/11/92 MAG Support added to store special packet types at interrupt
+// level (mostly responses to specific commands.)
+// 0.08 -- 3/30/92 MAG Support added for STAT_MODEM packet
+// 0.09 -- 6/24/93 MAG i2Link... needed to update number of boards BEFORE
+// turning on the interrupt.
+// 0.10 -- 6/25/93 MAG To avoid gruesome death from a bad board, we sanity check
+// some incoming.
+//
+// 1.1 - 12/25/96 AKM Linux version.
+// - 10/09/98 DMC Revised Linux version.
+//------------------------------------------------------------------------------
+
+//************
+//* Includes *
+//************
+
+#include <linux/sched.h>
+#include "i2lib.h"
+
+
+//***********************
+//* Function Prototypes *
+//***********************
+static void i2QueueNeeds(i2eBordStrPtr, i2ChanStrPtr, int);
+static i2ChanStrPtr i2DeQueueNeeds(i2eBordStrPtr, int );
+static void i2StripFifo(i2eBordStrPtr);
+static void i2StuffFifoBypass(i2eBordStrPtr);
+static void i2StuffFifoFlow(i2eBordStrPtr);
+static void i2StuffFifoInline(i2eBordStrPtr);
+static int i2RetryFlushOutput(i2ChanStrPtr);
+
+// Not a documented part of the library routines (careful...) but the Diagnostic
+// i2diag.c finds them useful to help the throughput in certain limited
+// single-threaded operations.
+static void iiSendPendingMail(i2eBordStrPtr);
+static void serviceOutgoingFifo(i2eBordStrPtr);
+
+// Functions defined in ip2.c as part of interrupt handling
+static void do_input(i2ChanStrPtr);
+static void do_status(i2ChanStrPtr);
+
+//***************
+//* Debug Data *
+//***************
+#ifdef DEBUG_FIFO
+
+unsigned char DBGBuf[0x4000];
+unsigned short I = 0;
+
+static void
+WriteDBGBuf(char *s, unsigned char *src, unsigned short n )
+{
+ char *p = src;
+
+ // XXX: We need a spin lock here if we ever use this again
+
+ while (*s) { // copy label
+ DBGBuf[I] = *s++;
+ I = I++ & 0x3fff;
+ }
+ while (n--) { // copy data
+ DBGBuf[I] = *p++;
+ I = I++ & 0x3fff;
+ }
+}
+
+static void
+fatality(i2eBordStrPtr pB )
+{
+ int i;
+
+ for (i=0;i<sizeof(DBGBuf);i++) {
+ if ((i%16) == 0)
+ printk("\n%4x:",i);
+ printk("%02x ",DBGBuf[i]);
+ }
+ printk("\n");
+ for (i=0;i<sizeof(DBGBuf);i++) {
+ if ((i%16) == 0)
+ printk("\n%4x:",i);
+ if (DBGBuf[i] >= ' ' && DBGBuf[i] <= '~') {
+ printk(" %c ",DBGBuf[i]);
+ } else {
+ printk(" . ");
+ }
+ }
+ printk("\n");
+ printk("Last index %x\n",I);
+}
+#endif /* DEBUG_FIFO */
+
+//********
+//* Code *
+//********
+
+inline int
+i2Validate ( i2ChanStrPtr pCh )
+{
+ //ip2trace(pCh->port_index, ITRC_VERIFY,ITRC_ENTER,2,pCh->validity,
+ // (CHANNEL_MAGIC | CHANNEL_SUPPORT));
+ return ((pCh->validity & (CHANNEL_MAGIC_BITS | CHANNEL_SUPPORT))
+ == (CHANNEL_MAGIC | CHANNEL_SUPPORT));
+}
+
+//******************************************************************************
+// Function: iiSendPendingMail(pB)
+// Parameters: Pointer to a board structure
+// Returns: Nothing
+//
+// Description:
+// If any outgoing mail bits are set and there is outgoing mailbox is empty,
+// send the mail and clear the bits.
+//******************************************************************************
+static inline void
+iiSendPendingMail(i2eBordStrPtr pB)
+{
+ if (pB->i2eOutMailWaiting && (!pB->i2eWaitingForEmptyFifo) )
+ {
+ if (iiTrySendMail(pB, pB->i2eOutMailWaiting))
+ {
+ /* If we were already waiting for fifo to empty,
+ * or just sent MB_OUT_STUFFED, then we are
+ * still waiting for it to empty, until we should
+ * receive an MB_IN_STRIPPED from the board.
+ */
+ pB->i2eWaitingForEmptyFifo |=
+ (pB->i2eOutMailWaiting & MB_OUT_STUFFED);
+ pB->i2eOutMailWaiting = 0;
+ }
+ }
+}
+
+//******************************************************************************
+// Function: i2InitChannels(pB, nChannels, pCh)
+// Parameters: Pointer to Ellis Board structure
+// Number of channels to initialize
+// Pointer to first element in an array of channel structures
+// Returns: Success or failure
+//
+// Description:
+//
+// This function patches pointers, back-pointers, and initializes all the
+// elements in the channel structure array.
+//
+// This should be run after the board structure is initialized, through having
+// loaded the standard loadware (otherwise it complains).
+//
+// In any case, it must be done before any serious work begins initializing the
+// irq's or sending commands...
+//
+//******************************************************************************
+static int
+i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh)
+{
+ int index, stuffIndex;
+ i2ChanStrPtr *ppCh;
+
+ if (pB->i2eValid != I2E_MAGIC) {
+ COMPLETE(pB, I2EE_BADMAGIC);
+ }
+ if (pB->i2eState != II_STATE_STDLOADED) {
+ COMPLETE(pB, I2EE_BADSTATE);
+ }
+
+ LOCK_INIT(&pB->read_fifo_spinlock);
+ LOCK_INIT(&pB->write_fifo_spinlock);
+ LOCK_INIT(&pB->Dbuf_spinlock);
+ LOCK_INIT(&pB->Bbuf_spinlock);
+ LOCK_INIT(&pB->Fbuf_spinlock);
+
+ // NO LOCK needed yet - this is init
+
+ pB->i2eChannelPtr = pCh;
+ pB->i2eChannelCnt = nChannels;
+
+ pB->i2Fbuf_strip = pB->i2Fbuf_stuff = 0;
+ pB->i2Dbuf_strip = pB->i2Dbuf_stuff = 0;
+ pB->i2Bbuf_strip = pB->i2Bbuf_stuff = 0;
+
+ memset ( pCh, 0, sizeof (i2ChanStr) * nChannels );
+
+ for (index = stuffIndex = 0, ppCh = (i2ChanStrPtr *)(pB->i2Fbuf);
+ nChannels && index < ABS_MOST_PORTS;
+ index++)
+ {
+ if ( !(pB->i2eChannelMap[index >> 4] & (1 << (index & 0xf)) ) ) {
+ continue;
+ }
+ LOCK_INIT(&pCh->Ibuf_spinlock);
+ LOCK_INIT(&pCh->Obuf_spinlock);
+ LOCK_INIT(&pCh->Cbuf_spinlock);
+ LOCK_INIT(&pCh->Pbuf_spinlock);
+ // NO LOCK needed yet - this is init
+ // Set up validity flag according to support level
+ if (pB->i2eGoodMap[index >> 4] & (1 << (index & 0xf)) ) {
+ pCh->validity = CHANNEL_MAGIC | CHANNEL_SUPPORT;
+ } else {
+ pCh->validity = CHANNEL_MAGIC;
+ }
+ pCh->pMyBord = pB; /* Back-pointer */
+
+ // Prepare an outgoing flow-control packet to send as soon as the chance
+ // occurs.
+ if ( pCh->validity & CHANNEL_SUPPORT ) {
+ pCh->infl.hd.i2sChannel = index;
+ pCh->infl.hd.i2sCount = 5;
+ pCh->infl.hd.i2sType = PTYPE_BYPASS;
+ pCh->infl.fcmd = 37;
+ pCh->infl.asof = 0;
+ pCh->infl.room = IBUF_SIZE - 1;
+
+ pCh->whenSendFlow = (IBUF_SIZE/5)*4; // when 80% full
+
+ // The following is similar to calling i2QueueNeeds, except that this
+ // is done in longhand, since we are setting up initial conditions on
+ // many channels at once.
+ pCh->channelNeeds = NEED_FLOW; // Since starting from scratch
+ pCh->sinceLastFlow = 0; // No bytes received since last flow
+ // control packet was queued
+ stuffIndex++;
+ *ppCh++ = pCh; // List this channel as needing
+ // initial flow control packet sent
+ }
+
+ // Don't allow anything to be sent until the status packets come in from
+ // the board.
+
+ pCh->outfl.asof = 0;
+ pCh->outfl.room = 0;
+
+ // Initialize all the ring buffers
+
+ pCh->Ibuf_stuff = pCh->Ibuf_strip = 0;
+ pCh->Obuf_stuff = pCh->Obuf_strip = 0;
+ pCh->Cbuf_stuff = pCh->Cbuf_strip = 0;
+
+ memset( &pCh->icount, 0, sizeof (struct async_icount) );
+ pCh->hotKeyIn = HOT_CLEAR;
+ pCh->channelOptions = 0;
+ pCh->bookMarks = 0;
+ init_waitqueue_head(&pCh->pBookmarkWait);
+
+ init_waitqueue_head(&pCh->open_wait);
+ init_waitqueue_head(&pCh->close_wait);
+ init_waitqueue_head(&pCh->delta_msr_wait);
+
+ // Set base and divisor so default custom rate is 9600
+ pCh->BaudBase = 921600; // MAX for ST654, changed after we get
+ pCh->BaudDivisor = 96; // the boxids (UART types) later
+
+ pCh->dataSetIn = 0;
+ pCh->dataSetOut = 0;
+
+ pCh->wopen = 0;
+ pCh->throttled = 0;
+
+ pCh->speed = CBR_9600;
+
+ pCh->flags = 0;
+ pCh->session = 0;
+ pCh->pgrp = 0;
+
+ pCh->ClosingDelay = 5*HZ/10;
+ pCh->ClosingWaitTime = 30*HZ;
+
+#ifdef USE_IQ
+ // Initialize task queue objects
+ pCh->tqueue_input.routine = (void(*)(void*)) do_input;
+ pCh->tqueue_input.data = pCh;
+ pCh->tqueue_status.routine = (void(*)(void*)) do_status;
+ pCh->tqueue_status.data = pCh;
+#endif
+
+ pCh->trace = ip2trace;
+
+ ++pCh;
+ --nChannels;
+ }
+ // No need to check for wrap here; this is initialization.
+ pB->i2Fbuf_stuff = stuffIndex;
+ COMPLETE(pB, I2EE_GOOD);
+
+}
+
+//******************************************************************************
+// Function: i2DeQueueNeeds(pB, type)
+// Parameters: Pointer to a board structure
+// type bit map: may include NEED_INLINE, NEED_BYPASS, or NEED_FLOW
+// Returns:
+// Pointer to a channel structure
+//
+// Description: Returns pointer struct of next channel that needs service of
+// the type specified. Otherwise returns a NULL reference.
+//
+//******************************************************************************
+static i2ChanStrPtr
+i2DeQueueNeeds(i2eBordStrPtr pB, int type)
+{
+ unsigned short queueIndex;
+ unsigned long flags;
+
+ i2ChanStrPtr pCh = NULL;
+
+ switch(type) {
+
+ case NEED_INLINE:
+
+ WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags);
+ if ( pB->i2Dbuf_stuff != pB->i2Dbuf_strip)
+ {
+ queueIndex = pB->i2Dbuf_strip;
+ pCh = pB->i2Dbuf[queueIndex];
+ queueIndex++;
+ if (queueIndex >= CH_QUEUE_SIZE) {
+ queueIndex = 0;
+ }
+ pB->i2Dbuf_strip = queueIndex;
+ pCh->channelNeeds &= ~NEED_INLINE;
+ }
+ WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags);
+ break;
+
+ case NEED_BYPASS:
+
+ WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags);
+ if (pB->i2Bbuf_stuff != pB->i2Bbuf_strip)
+ {
+ queueIndex = pB->i2Bbuf_strip;
+ pCh = pB->i2Bbuf[queueIndex];
+ queueIndex++;
+ if (queueIndex >= CH_QUEUE_SIZE) {
+ queueIndex = 0;
+ }
+ pB->i2Bbuf_strip = queueIndex;
+ pCh->channelNeeds &= ~NEED_BYPASS;
+ }
+ WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags);
+ break;
+
+ case NEED_FLOW:
+
+ WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags);
+ if (pB->i2Fbuf_stuff != pB->i2Fbuf_strip)
+ {
+ queueIndex = pB->i2Fbuf_strip;
+ pCh = pB->i2Fbuf[queueIndex];
+ queueIndex++;
+ if (queueIndex >= CH_QUEUE_SIZE) {
+ queueIndex = 0;
+ }
+ pB->i2Fbuf_strip = queueIndex;
+ pCh->channelNeeds &= ~NEED_FLOW;
+ }
+ WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags);
+ break;
+ default:
+ printk(KERN_ERR "i2DeQueueNeeds called with bad type:%x\n",type);
+ break;
+ }
+ return pCh;
+}
+
+//******************************************************************************
+// Function: i2QueueNeeds(pB, pCh, type)
+// Parameters: Pointer to a board structure
+// Pointer to a channel structure
+// type bit map: may include NEED_INLINE, NEED_BYPASS, or NEED_FLOW
+// Returns: Nothing
+//
+// Description:
+// For each type of need selected, if the given channel is not already in the
+// queue, adds it, and sets the flag indicating it is in the queue.
+//******************************************************************************
+static void
+i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type)
+{
+ unsigned short queueIndex;
+ unsigned long flags;
+
+ // We turn off all the interrupts during this brief process, since the
+ // interrupt-level code might want to put things on the queue as well.
+
+ switch (type) {
+
+ case NEED_INLINE:
+
+ WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags);
+ if ( !(pCh->channelNeeds & NEED_INLINE) )
+ {
+ pCh->channelNeeds |= NEED_INLINE;
+ queueIndex = pB->i2Dbuf_stuff;
+ pB->i2Dbuf[queueIndex++] = pCh;
+ if (queueIndex >= CH_QUEUE_SIZE)
+ queueIndex = 0;
+ pB->i2Dbuf_stuff = queueIndex;
+ }
+ WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags);
+ break;
+
+ case NEED_BYPASS:
+
+ WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags);
+ if ((type & NEED_BYPASS) && !(pCh->channelNeeds & NEED_BYPASS))
+ {
+ pCh->channelNeeds |= NEED_BYPASS;
+ queueIndex = pB->i2Bbuf_stuff;
+ pB->i2Bbuf[queueIndex++] = pCh;
+ if (queueIndex >= CH_QUEUE_SIZE)
+ queueIndex = 0;
+ pB->i2Bbuf_stuff = queueIndex;
+ }
+ WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags);
+ break;
+
+ case NEED_FLOW:
+
+ WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags);
+ if ((type & NEED_FLOW) && !(pCh->channelNeeds & NEED_FLOW))
+ {
+ pCh->channelNeeds |= NEED_FLOW;
+ queueIndex = pB->i2Fbuf_stuff;
+ pB->i2Fbuf[queueIndex++] = pCh;
+ if (queueIndex >= CH_QUEUE_SIZE)
+ queueIndex = 0;
+ pB->i2Fbuf_stuff = queueIndex;
+ }
+ WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags);
+ break;
+
+ case NEED_CREDIT:
+ pCh->channelNeeds |= NEED_CREDIT;
+ break;
+ default:
+ printk(KERN_ERR "i2QueueNeeds called with bad type:%x\n",type);
+ break;
+ }
+ return;
+}
+
+//******************************************************************************
+// Function: i2QueueCommands(type, pCh, timeout, nCommands, pCs,...)
+// Parameters: type - PTYPE_BYPASS or PTYPE_INLINE
+// pointer to the channel structure
+// maximum period to wait
+// number of commands (n)
+// n commands
+// Returns: Number of commands sent, or -1 for error
+//
+// get board lock before calling
+//
+// Description:
+// Queues up some commands to be sent to a channel. To send possibly several
+// bypass or inline commands to the given channel. The timeout parameter
+// indicates how many HUNDREDTHS OF SECONDS to wait until there is room:
+// 0 = return immediately if no room, -ive = wait forever, +ive = number of
+// 1/100 seconds to wait. Return values:
+// -1 Some kind of nasty error: bad channel structure or invalid arguments.
+// 0 No room to send all the commands
+// (+) Number of commands sent
+//******************************************************************************
+static int
+i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
+ cmdSyntaxPtr pCs0,...)
+{
+ int totalsize = 0;
+ int blocksize;
+ int lastended;
+ cmdSyntaxPtr *ppCs;
+ cmdSyntaxPtr pCs;
+ int count;
+ int flag;
+ i2eBordStrPtr pB;
+
+ unsigned short maxBlock;
+ unsigned short maxBuff;
+ short bufroom;
+ unsigned short stuffIndex;
+ unsigned char *pBuf;
+ unsigned char *pInsert;
+ unsigned char *pDest, *pSource;
+ unsigned short channel;
+ int cnt;
+ unsigned long flags = 0;
+ spinlock_t *lock_var_p = NULL;
+
+ // Make sure the channel exists, otherwise do nothing
+ if ( !i2Validate ( pCh ) ) {
+ return -1;
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_QUEUE, ITRC_ENTER, 0 );
+#endif
+ pB = pCh->pMyBord;
+
+ // Board must also exist, and THE INTERRUPT COMMAND ALREADY SENT
+ if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == IRQ_UNDEFINED) {
+ return -2;
+ }
+ // If the board has gone fatal, return bad, and also hit the trap routine if
+ // it exists.
+ if (pB->i2eFatal) {
+ if ( pB->i2eFatalTrap ) {
+ (*(pB)->i2eFatalTrap)(pB);
+ }
+ return -3;
+ }
+ // Set up some variables, Which buffers are we using? How big are they?
+ switch(type)
+ {
+ case PTYPE_INLINE:
+ flag = INL;
+ maxBlock = MAX_OBUF_BLOCK;
+ maxBuff = OBUF_SIZE;
+ pBuf = pCh->Obuf;
+ break;
+ case PTYPE_BYPASS:
+ flag = BYP;
+ maxBlock = MAX_CBUF_BLOCK;
+ maxBuff = CBUF_SIZE;
+ pBuf = pCh->Cbuf;
+ break;
+ default:
+ return -4;
+ }
+ // Determine the total size required for all the commands
+ totalsize = blocksize = sizeof(i2CmdHeader);
+ lastended = 0;
+ ppCs = &pCs0;
+ for ( count = nCommands; count; count--, ppCs++)
+ {
+ pCs = *ppCs;
+ cnt = pCs->length;
+ // Will a new block be needed for this one?
+ // Two possible reasons: too
+ // big or previous command has to be at the end of a packet.
+ if ((blocksize + cnt > maxBlock) || lastended) {
+ blocksize = sizeof(i2CmdHeader);
+ totalsize += sizeof(i2CmdHeader);
+ }
+ totalsize += cnt;
+ blocksize += cnt;
+
+ // If this command had to end a block, then we will make sure to
+ // account for it should there be any more blocks.
+ lastended = pCs->flags & END;
+ }
+ for (;;) {
+ // Make sure any pending flush commands go out before we add more data.
+ if ( !( pCh->flush_flags && i2RetryFlushOutput( pCh ) ) ) {
+ // How much room (this time through) ?
+ switch(type) {
+ case PTYPE_INLINE:
+ lock_var_p = &pCh->Obuf_spinlock;
+ WRITE_LOCK_IRQSAVE(lock_var_p,flags);
+ stuffIndex = pCh->Obuf_stuff;
+ bufroom = pCh->Obuf_strip - stuffIndex;
+ break;
+ case PTYPE_BYPASS:
+ lock_var_p = &pCh->Cbuf_spinlock;
+ WRITE_LOCK_IRQSAVE(lock_var_p,flags);
+ stuffIndex = pCh->Cbuf_stuff;
+ bufroom = pCh->Cbuf_strip - stuffIndex;
+ break;
+ default:
+ return -5;
+ }
+ if (--bufroom < 0) {
+ bufroom += maxBuff;
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_QUEUE, 2, 1, bufroom );
+#endif
+ // Check for overflow
+ if (totalsize <= bufroom) {
+ // Normal Expected path - We still hold LOCK
+ break; /* from for()- Enough room: goto proceed */
+ }
+ }
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_QUEUE, 3, 1, totalsize );
+#endif
+ // Prepare to wait for buffers to empty
+ WRITE_UNLOCK_IRQRESTORE(lock_var_p,flags);
+ serviceOutgoingFifo(pB); // Dump what we got
+
+ if (timeout == 0) {
+ return 0; // Tired of waiting
+ }
+ if (timeout > 0)
+ timeout--; // So negative values == forever
+
+ if (!in_interrupt()) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1); // short nap
+ } else {
+ // we cannot sched/sleep in interrrupt silly
+ return 0;
+ }
+ if (signal_pending(current)) {
+ return 0; // Wake up! Time to die!!!
+ }
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_QUEUE, 4, 0 );
+#endif
+ } // end of for(;;)
+
+ // At this point we have room and the lock - stick them in.
+ channel = pCh->infl.hd.i2sChannel;
+ pInsert = &pBuf[stuffIndex]; // Pointer to start of packet
+ pDest = CMD_OF(pInsert); // Pointer to start of command
+
+ // When we start counting, the block is the size of the header
+ for (blocksize = sizeof(i2CmdHeader), count = nCommands,
+ lastended = 0, ppCs = &pCs0;
+ count;
+ count--, ppCs++)
+ {
+ pCs = *ppCs; // Points to command protocol structure
+
+ // If this is a bookmark request command, post the fact that a bookmark
+ // request is pending. NOTE THIS TRICK ONLY WORKS BECAUSE CMD_BMARK_REQ
+ // has no parameters! The more general solution would be to reference
+ // pCs->cmd[0].
+ if (pCs == CMD_BMARK_REQ) {
+ pCh->bookMarks++;
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_DRAIN, 30, 1, pCh->bookMarks );
+#endif
+ }
+ cnt = pCs->length;
+
+ // If this command would put us over the maximum block size or
+ // if the last command had to be at the end of a block, we end
+ // the existing block here and start a new one.
+ if ((blocksize + cnt > maxBlock) || lastended) {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_QUEUE, 5, 0 );
+#endif
+ PTYPE_OF(pInsert) = type;
+ CHANNEL_OF(pInsert) = channel;
+ // count here does not include the header
+ CMD_COUNT_OF(pInsert) = blocksize - sizeof(i2CmdHeader);
+ stuffIndex += blocksize;
+ if(stuffIndex >= maxBuff) {
+ stuffIndex = 0;
+ pInsert = pBuf;
+ }
+ pInsert = &pBuf[stuffIndex]; // Pointer to start of next pkt
+ pDest = CMD_OF(pInsert);
+ blocksize = sizeof(i2CmdHeader);
+ }
+ // Now we know there is room for this one in the current block
+
+ blocksize += cnt; // Total bytes in this command
+ pSource = pCs->cmd; // Copy the command into the buffer
+ while (cnt--) {
+ *pDest++ = *pSource++;
+ }
+ // If this command had to end a block, then we will make sure to account
+ // for it should there be any more blocks.
+ lastended = pCs->flags & END;
+ } // end for
+ // Clean up the final block by writing header, etc
+
+ PTYPE_OF(pInsert) = type;
+ CHANNEL_OF(pInsert) = channel;
+ // count here does not include the header
+ CMD_COUNT_OF(pInsert) = blocksize - sizeof(i2CmdHeader);
+ stuffIndex += blocksize;
+ if(stuffIndex >= maxBuff) {
+ stuffIndex = 0;
+ pInsert = pBuf;
+ }
+ // Updates the index, and post the need for service. When adding these to
+ // the queue of channels, we turn off the interrupt while doing so,
+ // because at interrupt level we might want to push a channel back to the
+ // end of the queue.
+ switch(type)
+ {
+ case PTYPE_INLINE:
+ pCh->Obuf_stuff = stuffIndex; // Store buffer pointer
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+
+ pB->debugInlineQueued++;
+ // Add the channel pointer to list of channels needing service (first
+ // come...), if it's not already there.
+ i2QueueNeeds(pB, pCh, NEED_INLINE);
+ break;
+
+ case PTYPE_BYPASS:
+ pCh->Cbuf_stuff = stuffIndex; // Store buffer pointer
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags);
+
+ pB->debugBypassQueued++;
+ // Add the channel pointer to list of channels needing service (first
+ // come...), if it's not already there.
+ i2QueueNeeds(pB, pCh, NEED_BYPASS);
+ break;
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_QUEUE, ITRC_RETURN, 1, nCommands );
+#endif
+ return nCommands; // Good status: number of commands sent
+}
+
+//******************************************************************************
+// Function: i2GetStatus(pCh,resetBits)
+// Parameters: Pointer to a channel structure
+// Bit map of status bits to clear
+// Returns: Bit map of current status bits
+//
+// Description:
+// Returns the state of data set signals, and whether a break has been received,
+// (see i2lib.h for bit-mapped result). resetBits is a bit-map of any status
+// bits to be cleared: I2_BRK, I2_PAR, I2_FRA, I2_OVR,... These are cleared
+// AFTER the condition is passed. If pCh does not point to a valid channel,
+// returns -1 (which would be impossible otherwise.
+//******************************************************************************
+static int
+i2GetStatus(i2ChanStrPtr pCh, int resetBits)
+{
+ unsigned short status;
+ i2eBordStrPtr pB;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_STATUS, ITRC_ENTER, 2, pCh->dataSetIn, resetBits );
+#endif
+
+ // Make sure the channel exists, otherwise do nothing */
+ if ( !i2Validate ( pCh ) )
+ return -1;
+
+ pB = pCh->pMyBord;
+
+ status = pCh->dataSetIn;
+
+ // Clear any specified error bits: but note that only actual error bits can
+ // be cleared, regardless of the value passed.
+ if (resetBits)
+ {
+ pCh->dataSetIn &= ~(resetBits & (I2_BRK | I2_PAR | I2_FRA | I2_OVR));
+ pCh->dataSetIn &= ~(I2_DDCD | I2_DCTS | I2_DDSR | I2_DRI);
+ }
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_STATUS, ITRC_RETURN, 1, pCh->dataSetIn );
+#endif
+
+ return status;
+}
+
+//******************************************************************************
+// Function: i2Input(pChpDest,count)
+// Parameters: Pointer to a channel structure
+// Pointer to data buffer
+// Number of bytes to read
+// Returns: Number of bytes read, or -1 for error
+//
+// Description:
+// Strips data from the input buffer and writes it to pDest. If there is a
+// collosal blunder, (invalid structure pointers or the like), returns -1.
+// Otherwise, returns the number of bytes read.
+//******************************************************************************
+static int
+i2Input(i2ChanStrPtr pCh)
+{
+ int amountToMove;
+ unsigned short stripIndex;
+ int count;
+ unsigned long flags = 0;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_INPUT, ITRC_ENTER, 0);
+#endif
+
+ // Ensure channel structure seems real
+ if ( !i2Validate( pCh ) ) {
+ count = -1;
+ goto i2Input_exit;
+ }
+ WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+
+ // initialize some accelerators and private copies
+ stripIndex = pCh->Ibuf_strip;
+
+ count = pCh->Ibuf_stuff - stripIndex;
+
+ // If buffer is empty or requested data count was 0, (trivial case) return
+ // without any further thought.
+ if ( count == 0 ) {
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ goto i2Input_exit;
+ }
+ // Adjust for buffer wrap
+ if ( count < 0 ) {
+ count += IBUF_SIZE;
+ }
+ // Don't give more than can be taken by the line discipline
+ amountToMove = pCh->pTTY->ldisc.receive_room( pCh->pTTY );
+ if (count > amountToMove) {
+ count = amountToMove;
+ }
+ // How much could we copy without a wrap?
+ amountToMove = IBUF_SIZE - stripIndex;
+
+ if (amountToMove > count) {
+ amountToMove = count;
+ }
+ // Move the first block
+ pCh->pTTY->ldisc.receive_buf( pCh->pTTY,
+ &(pCh->Ibuf[stripIndex]), NULL, amountToMove );
+ // If we needed to wrap, do the second data move
+ if (count > amountToMove) {
+ pCh->pTTY->ldisc.receive_buf( pCh->pTTY,
+ pCh->Ibuf, NULL, count - amountToMove );
+ }
+ // Bump and wrap the stripIndex all at once by the amount of data read. This
+ // method is good regardless of whether the data was in one or two pieces.
+ stripIndex += count;
+ if (stripIndex >= IBUF_SIZE) {
+ stripIndex -= IBUF_SIZE;
+ }
+ pCh->Ibuf_strip = stripIndex;
+
+ // Update our flow control information and possibly queue ourselves to send
+ // it, depending on how much data has been stripped since the last time a
+ // packet was sent.
+ pCh->infl.asof += count;
+
+ if ((pCh->sinceLastFlow += count) >= pCh->whenSendFlow) {
+ pCh->sinceLastFlow -= pCh->whenSendFlow;
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW);
+ } else {
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ }
+
+i2Input_exit:
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_INPUT, ITRC_RETURN, 1, count);
+#endif
+ return count;
+}
+
+//******************************************************************************
+// Function: i2InputFlush(pCh)
+// Parameters: Pointer to a channel structure
+// Returns: Number of bytes stripped, or -1 for error
+//
+// Description:
+// Strips any data from the input buffer. If there is a collosal blunder,
+// (invalid structure pointers or the like), returns -1. Otherwise, returns the
+// number of bytes stripped.
+//******************************************************************************
+static int
+i2InputFlush(i2ChanStrPtr pCh)
+{
+ int count;
+ unsigned long flags;
+
+ // Ensure channel structure seems real
+ if ( !i2Validate ( pCh ) )
+ return -1;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_INPUT, 10, 0);
+#endif
+
+ WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ count = pCh->Ibuf_stuff - pCh->Ibuf_strip;
+
+ // Adjust for buffer wrap
+ if (count < 0) {
+ count += IBUF_SIZE;
+ }
+
+ // Expedient way to zero out the buffer
+ pCh->Ibuf_strip = pCh->Ibuf_stuff;
+
+
+ // Update our flow control information and possibly queue ourselves to send
+ // it, depending on how much data has been stripped since the last time a
+ // packet was sent.
+
+ pCh->infl.asof += count;
+
+ if ( (pCh->sinceLastFlow += count) >= pCh->whenSendFlow )
+ {
+ pCh->sinceLastFlow -= pCh->whenSendFlow;
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW);
+ } else {
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_INPUT, 19, 1, count);
+#endif
+ return count;
+}
+
+//******************************************************************************
+// Function: i2InputAvailable(pCh)
+// Parameters: Pointer to a channel structure
+// Returns: Number of bytes available, or -1 for error
+//
+// Description:
+// If there is a collosal blunder, (invalid structure pointers or the like),
+// returns -1. Otherwise, returns the number of bytes stripped. Otherwise,
+// returns the number of bytes available in the buffer.
+//******************************************************************************
+#if 0
+static int
+i2InputAvailable(i2ChanStrPtr pCh)
+{
+ int count;
+
+ // Ensure channel structure seems real
+ if ( !i2Validate ( pCh ) ) return -1;
+
+
+ // initialize some accelerators and private copies
+ READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ count = pCh->Ibuf_stuff - pCh->Ibuf_strip;
+ READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+
+ // Adjust for buffer wrap
+ if (count < 0)
+ {
+ count += IBUF_SIZE;
+ }
+
+ return count;
+}
+#endif
+
+//******************************************************************************
+// Function: i2Output(pCh, pSource, count)
+// Parameters: Pointer to channel structure
+// Pointer to source data
+// Number of bytes to send
+// Returns: Number of bytes sent, or -1 for error
+//
+// Description:
+// Queues the data at pSource to be sent as data packets to the board. If there
+// is a collosal blunder, (invalid structure pointers or the like), returns -1.
+// Otherwise, returns the number of bytes written. What if there is not enough
+// room for all the data? If pCh->channelOptions & CO_NBLOCK_WRITE is set, then
+// we transfer as many characters as we can now, then return. If this bit is
+// clear (default), routine will spin along until all the data is buffered.
+// Should this occur, the 1-ms delay routine is called while waiting to avoid
+// applications that one cannot break out of.
+//******************************************************************************
+static int
+i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user )
+{
+ i2eBordStrPtr pB;
+ unsigned char *pInsert;
+ int amountToMove;
+ int countOriginal = count;
+ unsigned short channel;
+ unsigned short stuffIndex;
+ unsigned long flags;
+ int rc = 0;
+
+ int bailout = 10;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, user );
+#endif
+
+ // Ensure channel structure seems real
+ if ( !i2Validate ( pCh ) )
+ return -1;
+
+ // initialize some accelerators and private copies
+ pB = pCh->pMyBord;
+ channel = pCh->infl.hd.i2sChannel;
+
+ // If the board has gone fatal, return bad, and also hit the trap routine if
+ // it exists.
+ if (pB->i2eFatal) {
+ if (pB->i2eFatalTrap) {
+ (*(pB)->i2eFatalTrap)(pB);
+ }
+ return -1;
+ }
+ // Proceed as though we would do everything
+ while ( count > 0 ) {
+
+ // How much room in output buffer is there?
+ READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1;
+ READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ if (amountToMove < 0) {
+ amountToMove += OBUF_SIZE;
+ }
+ // Subtract off the headers size and see how much room there is for real
+ // data. If this is negative, we will discover later.
+ amountToMove -= sizeof (i2DataHeader);
+
+ // Don't move more (now) than can go in a single packet
+ if ( amountToMove > (int)(MAX_OBUF_BLOCK - sizeof(i2DataHeader)) ) {
+ amountToMove = MAX_OBUF_BLOCK - sizeof(i2DataHeader);
+ }
+ // Don't move more than the count we were given
+ if (amountToMove > count) {
+ amountToMove = count;
+ }
+ // Now we know how much we must move: NB because the ring buffers have
+ // an overflow area at the end, we needn't worry about wrapping in the
+ // middle of a packet.
+
+// Small WINDOW here with no LOCK but I can't call Flush with LOCK
+// We would be flushing (or ending flush) anyway
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, 10, 1, amountToMove );
+#endif
+ if ( !(pCh->flush_flags && i2RetryFlushOutput(pCh) )
+ && amountToMove > 0 )
+ {
+ WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ stuffIndex = pCh->Obuf_stuff;
+
+ // Had room to move some data: don't know whether the block size,
+ // buffer space, or what was the limiting factor...
+ pInsert = &(pCh->Obuf[stuffIndex]);
+
+ // Set up the header
+ CHANNEL_OF(pInsert) = channel;
+ PTYPE_OF(pInsert) = PTYPE_DATA;
+ TAG_OF(pInsert) = 0;
+ ID_OF(pInsert) = ID_ORDINARY_DATA;
+ DATA_COUNT_OF(pInsert) = amountToMove;
+
+ // Move the data
+ if ( user ) {
+ rc=copy_from_user((char*)(DATA_OF(pInsert)), pSource,
+ amountToMove );
+ } else {
+ memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove );
+ }
+ // Adjust pointers and indices
+ pSource += amountToMove;
+ pCh->Obuf_char_count += amountToMove;
+ stuffIndex += amountToMove + sizeof(i2DataHeader);
+ count -= amountToMove;
+
+ if (stuffIndex >= OBUF_SIZE) {
+ stuffIndex = 0;
+ }
+ pCh->Obuf_stuff = stuffIndex;
+
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, 13, 1, stuffIndex );
+#endif
+
+ } else {
+
+ // Cannot move data
+ // becuz we need to stuff a flush
+ // or amount to move is <= 0
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace(CHANN, ITRC_OUTPUT, 14, 3,
+ amountToMove, pB->i2eFifoRemains, pB->i2eWaitingForEmptyFifo );
+#endif
+ // Put this channel back on queue
+ // this ultimatly gets more data or wakes write output
+ i2QueueNeeds(pB, pCh, NEED_INLINE);
+
+ if ( pB->i2eWaitingForEmptyFifo ) {
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, 16, 0 );
+#endif
+ // or schedule
+ if (!in_interrupt()) {
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, 61, 0 );
+#endif
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(2);
+ if (signal_pending(current)) {
+ break;
+ }
+ continue;
+ } else {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, 62, 0 );
+#endif
+ // let interrupt in = WAS restore_flags()
+ // We hold no lock nor is irq off anymore???
+
+ break;
+ }
+ break; // from while(count)
+ }
+ else if ( pB->i2eFifoRemains < 32 && !pB->i2eTxMailEmpty ( pB ) )
+ {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, 19, 2, pB->i2eFifoRemains,
+ pB->i2eTxMailEmpty );
+#endif
+ break; // from while(count)
+ } else if ( pCh->channelNeeds & NEED_CREDIT ) {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, 22, 0 );
+#endif
+ break; // from while(count)
+ } else if ( --bailout) {
+
+ // Try to throw more things (maybe not us) in the fifo if we're
+ // not already waiting for it.
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, 20, 0 );
+#endif
+ serviceOutgoingFifo(pB);
+ //break; CONTINUE;
+ } else {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, 21, 3, pB->i2eFifoRemains,
+ pB->i2eOutMailWaiting, pB->i2eWaitingForEmptyFifo );
+#endif
+ break; // from while(count)
+ }
+ }
+ } // End of while(count)
+
+ i2QueueNeeds(pB, pCh, NEED_INLINE);
+
+ // We drop through either when the count expires, or when there is some
+ // count left, but there was a non-blocking write.
+ if (countOriginal > count) {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, 17, 2, countOriginal, count );
+#endif
+ serviceOutgoingFifo( pB );
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_OUTPUT, ITRC_RETURN, 2, countOriginal, count );
+#endif
+
+ return countOriginal - count;
+}
+
+//******************************************************************************
+// Function: i2FlushOutput(pCh)
+// Parameters: Pointer to a channel structure
+// Returns: Nothing
+//
+// Description:
+// Sends bypass command to start flushing (waiting possibly forever until there
+// is room), then sends inline command to stop flushing output, (again waiting
+// possibly forever).
+//******************************************************************************
+static inline void
+i2FlushOutput(i2ChanStrPtr pCh)
+{
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_FLUSH, 1, 1, pCh->flush_flags );
+#endif
+
+ if (pCh->flush_flags)
+ return;
+
+ if ( 1 != i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_STARTFL) ) {
+ pCh->flush_flags = STARTFL_FLAG; // Failed - flag for later
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_FLUSH, 2, 0 );
+#endif
+ } else if ( 1 != i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL) ) {
+ pCh->flush_flags = STOPFL_FLAG; // Failed - flag for later
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_FLUSH, 3, 0 );
+#endif
+ }
+}
+
+static int
+i2RetryFlushOutput(i2ChanStrPtr pCh)
+{
+ int old_flags = pCh->flush_flags;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_FLUSH, 14, 1, old_flags );
+#endif
+
+ pCh->flush_flags = 0; // Clear flag so we can avoid recursion
+ // and queue the commands
+
+ if ( old_flags & STARTFL_FLAG ) {
+ if ( 1 == i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_STARTFL) ) {
+ old_flags = STOPFL_FLAG; //Success - send stop flush
+ } else {
+ old_flags = STARTFL_FLAG; //Failure - Flag for retry later
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_FLUSH, 15, 1, old_flags );
+#endif
+ }
+ if ( old_flags & STOPFL_FLAG ) {
+ if ( 1 == i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL) > 0 ) {
+ old_flags = 0; // Success - clear flags
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_FLUSH, 16, 1, old_flags );
+#endif
+ }
+ pCh->flush_flags = old_flags;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_FLUSH, 17, 1, old_flags );
+#endif
+ return old_flags;
+}
+
+//******************************************************************************
+// Function: i2DrainOutput(pCh,timeout)
+// Parameters: Pointer to a channel structure
+// Maximum period to wait
+// Returns: ?
+//
+// Description:
+// Uses the bookmark request command to ask the board to send a bookmark back as
+// soon as all the data is completely sent.
+//******************************************************************************
+static void
+i2DrainWakeup(i2ChanStrPtr pCh)
+{
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_DRAIN, 10, 1, pCh->BookmarkTimer.expires );
+#endif
+ pCh->BookmarkTimer.expires = 0;
+ wake_up_interruptible( &pCh->pBookmarkWait );
+}
+
+static void
+i2DrainOutput(i2ChanStrPtr pCh, int timeout)
+{
+ i2eBordStrPtr pB;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_DRAIN, ITRC_ENTER, 1, pCh->BookmarkTimer.expires);
+#endif
+ pB = pCh->pMyBord;
+ // If the board has gone fatal, return bad,
+ // and also hit the trap routine if it exists.
+ if (pB->i2eFatal) {
+ if (pB->i2eFatalTrap) {
+ (*(pB)->i2eFatalTrap)(pB);
+ }
+ return;
+ }
+ if ((timeout > 0) && (pCh->BookmarkTimer.expires == 0 )) {
+ // One per customer (channel)
+ init_timer( &(pCh->BookmarkTimer) );
+ pCh->BookmarkTimer.expires = jiffies + timeout;
+ pCh->BookmarkTimer.function = (void*)(unsigned long)i2DrainWakeup;
+ pCh->BookmarkTimer.data = (unsigned long)pCh;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_DRAIN, 1, 1, pCh->BookmarkTimer.expires );
+#endif
+
+ add_timer( &(pCh->BookmarkTimer) );
+ }
+
+ i2QueueCommands( PTYPE_INLINE, pCh, -1, 1, CMD_BMARK_REQ );
+ serviceOutgoingFifo( pB );
+
+ interruptible_sleep_on( &(pCh->pBookmarkWait) );
+
+ // if expires == 0 then timer poped, then do not need to del_timer
+ if ((timeout > 0) && pCh->BookmarkTimer.expires &&
+ (pCh->BookmarkTimer.expires > jiffies)) {
+ del_timer( &(pCh->BookmarkTimer) );
+ pCh->BookmarkTimer.expires = 0;
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_DRAIN, 3, 1, pCh->BookmarkTimer.expires );
+#endif
+
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_DRAIN, ITRC_RETURN, 1, pCh->BookmarkTimer.expires );
+#endif
+ return;
+}
+
+//******************************************************************************
+// Function: i2OutputFree(pCh)
+// Parameters: Pointer to a channel structure
+// Returns: Space in output buffer
+//
+// Description:
+// Returns -1 if very gross error. Otherwise returns the amount of bytes still
+// free in the output buffer.
+//******************************************************************************
+static int
+i2OutputFree(i2ChanStrPtr pCh)
+{
+ int amountToMove;
+ unsigned long flags;
+
+ // Ensure channel structure seems real
+ if ( !i2Validate ( pCh ) ) {
+ return -1;
+ }
+ READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1;
+ READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+
+ if (amountToMove < 0) {
+ amountToMove += OBUF_SIZE;
+ }
+ // If this is negative, we will discover later
+ amountToMove -= sizeof(i2DataHeader);
+
+ return (amountToMove < 0) ? 0 : amountToMove;
+}
+static void
+
+ip2_owake( PTTY tp)
+{
+ i2ChanStrPtr pCh;
+
+ if (tp == NULL) return;
+
+ pCh = tp->driver_data;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_SICMD, 10, 2, tp->flags, (1 << TTY_DO_WRITE_WAKEUP) );
+#endif
+ wake_up_interruptible ( &tp->write_wait );
+ if ( ( tp->flags & (1 << TTY_DO_WRITE_WAKEUP) )
+ && tp->ldisc.write_wakeup )
+ {
+ (tp->ldisc.write_wakeup) ( tp );
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_SICMD, 11, 0 );
+#endif
+ }
+}
+
+static inline void
+set_baud_params(i2eBordStrPtr pB)
+{
+ int i,j;
+ i2ChanStrPtr *pCh;
+
+ pCh = (i2ChanStrPtr *) pB->i2eChannelPtr;
+
+ for (i = 0; i < ABS_MAX_BOXES; i++) {
+ if (pB->channelBtypes.bid_value[i]) {
+ if (BID_HAS_654(pB->channelBtypes.bid_value[i])) {
+ for (j = 0; j < ABS_BIGGEST_BOX; j++) {
+ if (pCh[i*16+j] == NULL)
+ break;
+ (pCh[i*16+j])->BaudBase = 921600; // MAX for ST654
+ (pCh[i*16+j])->BaudDivisor = 96;
+ }
+ } else { // has cirrus cd1400
+ for (j = 0; j < ABS_BIGGEST_BOX; j++) {
+ if (pCh[i*16+j] == NULL)
+ break;
+ (pCh[i*16+j])->BaudBase = 115200; // MAX for CD1400
+ (pCh[i*16+j])->BaudDivisor = 12;
+ }
+ }
+ }
+ }
+}
+
+//******************************************************************************
+// Function: i2StripFifo(pB)
+// Parameters: Pointer to a board structure
+// Returns: ?
+//
+// Description:
+// Strips all the available data from the incoming FIFO, identifies the type of
+// packet, and either buffers the data or does what needs to be done.
+//
+// Note there is no overflow checking here: if the board sends more data than it
+// ought to, we will not detect it here, but blindly overflow...
+//******************************************************************************
+
+// A buffer for reading in blocks for unknown channels
+static unsigned char junkBuffer[IBUF_SIZE];
+
+// A buffer to read in a status packet. Because of the size of the count field
+// for these things, the maximum packet size must be less than MAX_CMD_PACK_SIZE
+static unsigned char cmdBuffer[MAX_CMD_PACK_SIZE + 4];
+
+// This table changes the bit order from MSR order given by STAT_MODEM packet to
+// status bits used in our library.
+static char xlatDss[16] = {
+0 | 0 | 0 | 0 ,
+0 | 0 | 0 | I2_CTS ,
+0 | 0 | I2_DSR | 0 ,
+0 | 0 | I2_DSR | I2_CTS ,
+0 | I2_RI | 0 | 0 ,
+0 | I2_RI | 0 | I2_CTS ,
+0 | I2_RI | I2_DSR | 0 ,
+0 | I2_RI | I2_DSR | I2_CTS ,
+I2_DCD | 0 | 0 | 0 ,
+I2_DCD | 0 | 0 | I2_CTS ,
+I2_DCD | 0 | I2_DSR | 0 ,
+I2_DCD | 0 | I2_DSR | I2_CTS ,
+I2_DCD | I2_RI | 0 | 0 ,
+I2_DCD | I2_RI | 0 | I2_CTS ,
+I2_DCD | I2_RI | I2_DSR | 0 ,
+I2_DCD | I2_RI | I2_DSR | I2_CTS };
+
+static inline void
+i2StripFifo(i2eBordStrPtr pB)
+{
+ i2ChanStrPtr pCh;
+ int channel;
+ int count;
+ unsigned short stuffIndex;
+ int amountToRead;
+ unsigned char *pc, *pcLimit;
+ unsigned char uc;
+ unsigned char dss_change;
+ unsigned long bflags,cflags;
+
+#ifdef IP2DEBUG_TRACE
+ //ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_ENTER, 0 );
+#endif
+
+ while (HAS_INPUT(pB)) {
+#ifdef IP2DEBUG_TRACE
+ //ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 2, 0 );
+#endif
+ // Process packet from fifo a one atomic unit
+ WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock,bflags);
+
+ // The first word (or two bytes) will have channel number and type of
+ // packet, possibly other information
+ pB->i2eLeadoffWord[0] = iiReadWord(pB);
+
+ switch(PTYPE_OF(pB->i2eLeadoffWord))
+ {
+ case PTYPE_DATA:
+ pB->got_input = 1;
+
+#ifdef IP2DEBUG_TRACE
+ //ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 3, 0 );
+#endif
+ channel = CHANNEL_OF(pB->i2eLeadoffWord); /* Store channel */
+ count = iiReadWord(pB); /* Count is in the next word */
+
+// NEW: Check the count for sanity! Should the hardware fail, our death
+// is more pleasant. While an oversize channel is acceptable (just more
+// than the driver supports), an over-length count clearly means we are
+// sick!
+ if ( ((unsigned int)count) > IBUF_SIZE ) {
+ pB->i2eFatal = 2;
+ WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ return; /* Bail out ASAP */
+ }
+ // Channel is illegally big ?
+ if (channel >= pB->i2eChannelCnt ||
+ (pCh = (((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])) == NULL)
+ {
+ iiReadBuf(pB, junkBuffer, count);
+ WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ break; /* From switch: ready for next packet */
+ }
+
+ // Channel should be valid, then
+
+ // If this is a hot-key, merely post its receipt for now. These are
+ // always supposed to be 1-byte packets, so we won't even check the
+ // count. Also we will post an acknowledgement to the board so that
+ // more data can be forthcoming. Note that we are not trying to use
+ // these sequences in this driver, merely to robustly ignore them.
+ if(ID_OF(pB->i2eLeadoffWord) == ID_HOT_KEY)
+ {
+ pCh->hotKeyIn = iiReadWord(pB) & 0xff;
+ WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_HOTACK);
+ break; /* From the switch: ready for next packet */
+ }
+
+ // Normal data! We crudely assume there is room for the data in our
+ // buffer because the board wouldn't have exceeded his credit limit.
+ WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags);// We have 2 locks now
+ stuffIndex = pCh->Ibuf_stuff;
+ amountToRead = IBUF_SIZE - stuffIndex;
+ if (amountToRead > count)
+ amountToRead = count;
+
+ // stuffIndex would have been already adjusted so there would
+ // always be room for at least one, and count is always at least
+ // one.
+
+ iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead);
+
+ // Update the stuffIndex by the amount of data moved. Note we could
+ // never ask for more data than would just fit. However, we might
+ // have read in one more byte than we wanted because the read
+ // rounds up to even bytes. If this byte is on the end of the
+ // packet, and is padding, we ignore it. If the byte is part of
+ // the actual data, we need to move it.
+
+ stuffIndex += amountToRead;
+
+ if (stuffIndex >= IBUF_SIZE) {
+ if ((amountToRead & 1) && (count > amountToRead)) {
+ pCh->Ibuf[0] = pCh->Ibuf[IBUF_SIZE];
+ amountToRead++;
+ stuffIndex = 1;
+ } else {
+ stuffIndex = 0;
+ }
+ }
+
+ // If there is anything left over, read it as well
+ if (count > amountToRead) {
+ amountToRead = count - amountToRead;
+ iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead);
+ stuffIndex += amountToRead;
+ }
+
+ // Update stuff index
+ pCh->Ibuf_stuff = stuffIndex;
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,cflags);
+ WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+
+#ifdef USE_IQ
+ queue_task(&pCh->tqueue_input, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+#else
+ do_input(pCh);
+#endif
+
+ // Note we do not need to maintain any flow-control credits at this
+ // time: if we were to increment .asof and decrement .room, there
+ // would be no net effect. Instead, when we strip data, we will
+ // increment .asof and leave .room unchanged.
+
+ break; // From switch: ready for next packet
+
+ case PTYPE_STATUS:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 4, 0 );
+#endif
+
+ count = CMD_COUNT_OF(pB->i2eLeadoffWord);
+
+ iiReadBuf(pB, cmdBuffer, count);
+ // We can release early with buffer grab
+ WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+
+ pc = cmdBuffer;
+ pcLimit = &(cmdBuffer[count]);
+
+ while (pc < pcLimit) {
+ channel = *pc++;
+#ifdef IP2DEBUG_TRACE
+ ip2trace (channel, ITRC_SFIFO, 7, 2, channel, *pc );
+#endif
+ /* check for valid channel */
+ if (channel < pB->i2eChannelCnt
+ &&
+ (pCh = (((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])) != NULL
+ )
+ {
+ dss_change = 0;
+
+ switch (uc = *pc++)
+ {
+ /* Breaks and modem signals are easy: just update status */
+ case STAT_CTS_UP:
+ if ( !(pCh->dataSetIn & I2_CTS) )
+ {
+ pCh->dataSetIn |= I2_DCTS;
+ ++pCh->icount.cts;
+ dss_change = 1;
+ }
+ pCh->dataSetIn |= I2_CTS;
+ break;
+
+ case STAT_CTS_DN:
+ if ( pCh->dataSetIn & I2_CTS )
+ {
+ pCh->dataSetIn |= I2_DCTS;
+ ++pCh->icount.cts;
+ dss_change = 1;
+ }
+ pCh->dataSetIn &= ~I2_CTS;
+ break;
+
+ case STAT_DCD_UP:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (channel, ITRC_MODEM, 1, 1, pCh->dataSetIn );
+#endif
+ if ( !(pCh->dataSetIn & I2_DCD) )
+ {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_MODEM, 2, 0 );
+#endif
+ pCh->dataSetIn |= I2_DDCD;
+ ++pCh->icount.dcd;
+ dss_change = 1;
+ }
+ pCh->dataSetIn |= I2_DCD;
+#ifdef IP2DEBUG_TRACE
+ ip2trace (channel, ITRC_MODEM, 3, 1, pCh->dataSetIn );
+#endif
+ break;
+
+ case STAT_DCD_DN:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (channel, ITRC_MODEM, 4, 1, pCh->dataSetIn );
+#endif
+ if ( pCh->dataSetIn & I2_DCD )
+ {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (channel, ITRC_MODEM, 5, 0 );
+#endif
+ pCh->dataSetIn |= I2_DDCD;
+ ++pCh->icount.dcd;
+ dss_change = 1;
+ }
+ pCh->dataSetIn &= ~I2_DCD;
+#ifdef IP2DEBUG_TRACE
+ ip2trace (channel, ITRC_MODEM, 6, 1, pCh->dataSetIn );
+#endif
+ break;
+
+ case STAT_DSR_UP:
+ if ( !(pCh->dataSetIn & I2_DSR) )
+ {
+ pCh->dataSetIn |= I2_DDSR;
+ ++pCh->icount.dsr;
+ dss_change = 1;
+ }
+ pCh->dataSetIn |= I2_DSR;
+ break;
+
+ case STAT_DSR_DN:
+ if ( pCh->dataSetIn & I2_DSR )
+ {
+ pCh->dataSetIn |= I2_DDSR;
+ ++pCh->icount.dsr;
+ dss_change = 1;
+ }
+ pCh->dataSetIn &= ~I2_DSR;
+ break;
+
+ case STAT_RI_UP:
+ if ( !(pCh->dataSetIn & I2_RI) )
+ {
+ pCh->dataSetIn |= I2_DRI;
+ ++pCh->icount.rng;
+ dss_change = 1;
+ }
+ pCh->dataSetIn |= I2_RI ;
+ break;
+
+ case STAT_RI_DN:
+ if ( pCh->dataSetIn & I2_RI )
+ {
+ pCh->dataSetIn |= I2_DRI;
+ dss_change = 1;
+ }
+ pCh->dataSetIn &= ~I2_RI ;
+ break;
+
+ case STAT_BRK_DET:
+ pCh->dataSetIn |= I2_BRK;
+ dss_change = 1;
+ break;
+
+ // Bookmarks? one less request we're waiting for
+ case STAT_BMARK:
+ pCh->bookMarks--;
+ if (pCh->bookMarks <= 0 ) {
+ pCh->bookMarks = 0;
+ wake_up_interruptible( &pCh->pBookmarkWait );
+#ifdef IP2DEBUG_TRACE
+ ip2trace (channel, ITRC_DRAIN, 20, 1, pCh->BookmarkTimer.expires );
+#endif
+ }
+ break;
+
+ // Flow control packets? Update the new credits, and if
+ // someone was waiting for output, queue him up again.
+ case STAT_FLOW:
+ pCh->outfl.room =
+ ((flowStatPtr)pc)->room -
+ (pCh->outfl.asof - ((flowStatPtr)pc)->asof);
+#ifdef IP2DEBUG_TRACE
+ ip2trace (channel, ITRC_STFLW, 1, 1, pCh->outfl.room );
+#endif
+ if (pCh->channelNeeds & NEED_CREDIT)
+ {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (channel, ITRC_STFLW, 2, 1, pCh->channelNeeds);
+#endif
+ pCh->channelNeeds &= ~NEED_CREDIT;
+ i2QueueNeeds(pB, pCh, NEED_INLINE);
+ if ( pCh->pTTY )
+ ip2_owake(pCh->pTTY);
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (channel, ITRC_STFLW, 3, 1, pCh->channelNeeds);
+#endif
+ pc += sizeof(flowStat);
+ break;
+
+ /* Special packets: */
+ /* Just copy the information into the channel structure */
+
+ case STAT_STATUS:
+
+ pCh->channelStatus = *((debugStatPtr)pc);
+ pc += sizeof(debugStat);
+ break;
+
+ case STAT_TXCNT:
+
+ pCh->channelTcount = *((cntStatPtr)pc);
+ pc += sizeof(cntStat);
+ break;
+
+ case STAT_RXCNT:
+
+ pCh->channelRcount = *((cntStatPtr)pc);
+ pc += sizeof(cntStat);
+ break;
+
+ case STAT_BOXIDS:
+ pB->channelBtypes = *((bidStatPtr)pc);
+ pc += sizeof(bidStat);
+//printk("boxids: %x %x %x %x\n",
+// pB->channelBtypes.bid_value[0],pB->channelBtypes.bid_value[1],
+// pB->channelBtypes.bid_value[2],pB->channelBtypes.bid_value[3]);
+ set_baud_params(pB);
+ break;
+
+ case STAT_HWFAIL:
+ i2QueueCommands (PTYPE_INLINE, pCh, 0, 1, CMD_HW_TEST);
+ pCh->channelFail = *((failStatPtr)pc);
+ pc += sizeof(failStat);
+ break;
+
+ /* No explicit match? then
+ * Might be an error packet...
+ */
+ default:
+ switch (uc & STAT_MOD_ERROR)
+ {
+ case STAT_ERROR:
+ if (uc & STAT_E_PARITY)
+ pCh->dataSetIn |= I2_PAR;
+ if (uc & STAT_E_FRAMING)
+ pCh->dataSetIn |= I2_FRA;
+ if (uc & STAT_E_OVERRUN)
+ pCh->dataSetIn |= I2_OVR;
+ break;
+
+ case STAT_MODEM:
+ pCh->dataSetIn = (pCh->dataSetIn
+ & ~(I2_RI | I2_CTS | I2_DCD | I2_DSR) )
+ | xlatDss[uc & 0xf];
+ default:
+ break;
+ }
+ } /* End of switch on status type */
+ if (dss_change) {
+#ifdef USE_IQ
+ queue_task(&pCh->tqueue_status, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+#else
+ do_status(pCh);
+#endif
+ }
+ }
+ else /* Or else, channel is invalid */
+ {
+ // Even though the channel is invalid, we must test the
+ // status to see how much additional data it has (to be
+ // skipped)
+ switch (*pc++)
+ {
+ case STAT_FLOW:
+ pc += 4; /* Skip the data */
+ break;
+
+ case STAT_CTS_UP:
+ case STAT_CTS_DN:
+ case STAT_DCD_UP:
+ case STAT_DCD_DN:
+ case STAT_DSR_UP:
+ case STAT_DSR_DN:
+ case STAT_RI_UP:
+ case STAT_RI_DN:
+ case STAT_BRK_DET:
+ case STAT_BMARK:
+ default:
+ break;
+ }
+ }
+ } // End of while (there is still some status packet left)
+ break;
+
+ default: // Neither packet? should be impossible
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 5, 1,
+ PTYPE_OF(pB->i2eLeadoffWord) );
+#endif
+ break;
+ } // End of switch on type of packets
+ } //while(board HAS_INPUT)
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_RETURN, 0 );
+#endif
+ // Send acknowledgement to the board even if there was no data!
+ pB->i2eOutMailWaiting |= MB_IN_STRIPPED;
+ return;
+}
+
+//******************************************************************************
+// Function: i2Write2Fifo(pB,address,count)
+// Parameters: Pointer to a board structure, source address, byte count
+// Returns: bytes written
+//
+// Description:
+// Writes count bytes to board io address(implied) from source
+// Adjusts count, leaves reserve for next time around bypass cmds
+//******************************************************************************
+static int
+i2Write2Fifo(i2eBordStrPtr pB, unsigned char *source, int count,int reserve)
+{
+ int rc = 0;
+ unsigned long flags;
+ WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ if (!pB->i2eWaitingForEmptyFifo) {
+ if (pB->i2eFifoRemains > (count+reserve)) {
+ pB->i2eFifoRemains -= count;
+ iiWriteBuf(pB, source, count);
+ pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
+ rc = count;
+ }
+ }
+ WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ return rc;
+}
+//******************************************************************************
+// Function: i2StuffFifoBypass(pB)
+// Parameters: Pointer to a board structure
+// Returns: Nothing
+//
+// Description:
+// Stuffs as many bypass commands into the fifo as possible. This is simpler
+// than stuffing data or inline commands to fifo, since we do not have
+// flow-control to deal with.
+//******************************************************************************
+static inline void
+i2StuffFifoBypass(i2eBordStrPtr pB)
+{
+ i2ChanStrPtr pCh;
+ unsigned char *pRemove;
+ unsigned short stripIndex;
+ unsigned short packetSize;
+ unsigned short paddedSize;
+ unsigned short notClogged = 1;
+ unsigned long flags;
+
+ int bailout = 1000;
+
+ // Continue processing so long as there are entries, or there is room in the
+ // fifo. Each entry represents a channel with something to do.
+ while ( --bailout && notClogged &&
+ (NULL != (pCh = i2DeQueueNeeds(pB,NEED_BYPASS))))
+ {
+ WRITE_LOCK_IRQSAVE(&pCh->Cbuf_spinlock,flags);
+ stripIndex = pCh->Cbuf_strip;
+
+ // as long as there are packets for this channel...
+
+ while (stripIndex != pCh->Cbuf_stuff) {
+ pRemove = &(pCh->Cbuf[stripIndex]);
+ packetSize = CMD_COUNT_OF(pRemove) + sizeof(i2CmdHeader);
+ paddedSize = ROUNDUP(packetSize);
+
+ if (paddedSize > 0) {
+ if ( 0 == i2Write2Fifo(pB, pRemove, paddedSize,0)) {
+ notClogged = 0; /* fifo full */
+ i2QueueNeeds(pB, pCh, NEED_BYPASS); // Put back on queue
+ break; // Break from the channel
+ }
+ }
+#ifdef DEBUG_FIFO
+WriteDBGBuf("BYPS", pRemove, paddedSize);
+#endif /* DEBUG_FIFO */
+ pB->debugBypassCount++;
+
+ pRemove += packetSize;
+ stripIndex += packetSize;
+ if (stripIndex >= CBUF_SIZE) {
+ stripIndex = 0;
+ pRemove = pCh->Cbuf;
+ }
+ }
+ // Done with this channel. Move to next, removing this one from
+ // the queue of channels if we cleaned it out (i.e., didn't get clogged.
+ pCh->Cbuf_strip = stripIndex;
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags);
+ } // Either clogged or finished all the work
+
+#ifdef IP2DEBUG_TRACE
+ if ( !bailout ) {
+ ip2trace (ITRC_NO_PORT, ITRC_ERROR, 1, 0 );
+ }
+#endif
+}
+
+//******************************************************************************
+// Function: i2StuffFifoFlow(pB)
+// Parameters: Pointer to a board structure
+// Returns: Nothing
+//
+// Description:
+// Stuffs as many flow control packets into the fifo as possible. This is easier
+// even than doing normal bypass commands, because there is always at most one
+// packet, already assembled, for each channel.
+//******************************************************************************
+static inline void
+i2StuffFifoFlow(i2eBordStrPtr pB)
+{
+ i2ChanStrPtr pCh;
+ unsigned short paddedSize = ROUNDUP(sizeof(flowIn));
+
+#ifdef IP2DEBUG_TRACE
+ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_ENTER, 2, pB->i2eFifoRemains, paddedSize );
+#endif
+
+ // Continue processing so long as there are entries, or there is room in the
+ // fifo. Each entry represents a channel with something to do.
+ while ( (NULL != (pCh = i2DeQueueNeeds(pB,NEED_FLOW)))) {
+ pB->debugFlowCount++;
+
+ // NO Chan LOCK needed ???
+ if ( 0 == i2Write2Fifo(pB,(unsigned char *)&(pCh->infl),paddedSize,0)) {
+ break;
+ }
+#ifdef DEBUG_FIFO
+WriteDBGBuf("FLOW",(unsigned char *) &(pCh->infl), paddedSize);
+#endif /* DEBUG_FIFO */
+
+ } // Either clogged or finished all the work
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_RETURN, 0 );
+#endif
+}
+
+//******************************************************************************
+// Function: i2StuffFifoInline(pB)
+// Parameters: Pointer to a board structure
+// Returns: Nothing
+//
+// Description:
+// Stuffs as much data and inline commands into the fifo as possible. This is
+// the most complex fifo-stuffing operation, since there if now the channel
+// flow-control issue to deal with.
+//******************************************************************************
+static inline void
+i2StuffFifoInline(i2eBordStrPtr pB)
+{
+ i2ChanStrPtr pCh;
+ unsigned char *pRemove;
+ unsigned short stripIndex;
+ unsigned short packetSize;
+ unsigned short paddedSize;
+ unsigned short notClogged = 1;
+ unsigned short flowsize;
+ unsigned long flags;
+
+ int bailout = 1000;
+ int bailout2;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_SICMD, ITRC_ENTER, 3, pB->i2eFifoRemains,
+ pB->i2Dbuf_strip, pB->i2Dbuf_stuff );
+#endif
+
+ // Continue processing so long as there are entries, or there is room in the
+ // fifo. Each entry represents a channel with something to do.
+ while ( --bailout && notClogged &&
+ (NULL != (pCh = i2DeQueueNeeds(pB,NEED_INLINE))) )
+ {
+ WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ stripIndex = pCh->Obuf_strip;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_SICMD, 3, 2, stripIndex, pCh->Obuf_stuff );
+#endif
+ // as long as there are packets for this channel...
+ bailout2 = 1000;
+ while ( --bailout2 && stripIndex != pCh->Obuf_stuff) {
+ pRemove = &(pCh->Obuf[stripIndex]);
+
+ // Must determine whether this be a data or command packet to
+ // calculate correctly the header size and the amount of
+ // flow-control credit this type of packet will use.
+ if (PTYPE_OF(pRemove) == PTYPE_DATA) {
+ flowsize = DATA_COUNT_OF(pRemove);
+ packetSize = flowsize + sizeof(i2DataHeader);
+ } else {
+ flowsize = CMD_COUNT_OF(pRemove);
+ packetSize = flowsize + sizeof(i2CmdHeader);
+ }
+ flowsize = CREDIT_USAGE(flowsize);
+ paddedSize = ROUNDUP(packetSize);
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_SICMD, 4, 2, pB->i2eFifoRemains, paddedSize );
+#endif
+ // If we don't have enough credits from the board to send the data,
+ // flag the channel that we are waiting for flow control credit, and
+ // break out. This will clean up this channel and remove us from the
+ // queue of hot things to do.
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_SICMD, 5, 2, pCh->outfl.room, flowsize );
+#endif
+ if (pCh->outfl.room <= flowsize) {
+ // Do Not have the credits to send this packet.
+ i2QueueNeeds(pB, pCh, NEED_CREDIT);
+ notClogged = 0;
+ break; // So to do next channel
+ }
+ if ( (paddedSize > 0)
+ && ( 0 == i2Write2Fifo(pB, pRemove, paddedSize, 128))) {
+ // Do Not have room in fifo to send this packet.
+ notClogged = 0;
+ i2QueueNeeds(pB, pCh, NEED_INLINE);
+ break; // Break from the channel
+ }
+#ifdef DEBUG_FIFO
+WriteDBGBuf("DATA", pRemove, paddedSize);
+#endif /* DEBUG_FIFO */
+ pB->debugInlineCount++;
+
+ // Update current credits
+ pCh->outfl.room -= flowsize;
+ pCh->outfl.asof += flowsize;
+ if (PTYPE_OF(pRemove) == PTYPE_DATA) {
+ pCh->Obuf_char_count -= DATA_COUNT_OF(pRemove);
+ }
+ pRemove += packetSize;
+ stripIndex += packetSize;
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_SICMD, 6, 2, stripIndex, pCh->Obuf_strip);
+#endif
+ if (stripIndex >= OBUF_SIZE) {
+ stripIndex = 0;
+ pRemove = pCh->Obuf;
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_SICMD, 7, 1, stripIndex );
+#endif
+ }
+ } /* while */
+ if ( !bailout2 ) {
+ ip2trace (CHANN, ITRC_ERROR, 3, 0 );
+ }
+ // Done with this channel. Move to next, removing this one from the
+ // queue of channels if we cleaned it out (i.e., didn't get clogged.
+ pCh->Obuf_strip = stripIndex;
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ if ( notClogged )
+ {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (CHANN, ITRC_SICMD, 8, 0 );
+#endif
+ if ( pCh->pTTY ) {
+ ip2_owake(pCh->pTTY);
+ }
+ }
+ } // Either clogged or finished all the work
+#ifdef IP2DEBUG_TRACE
+ if ( !bailout ) {
+ ip2trace (ITRC_NO_PORT, ITRC_ERROR, 4, 0 );
+ }
+#endif
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_SICMD, ITRC_RETURN, 1,pB->i2Dbuf_strip);
+#endif
+}
+
+//******************************************************************************
+// Function: serviceOutgoingFifo(pB)
+// Parameters: Pointer to a board structure
+// Returns: Nothing
+//
+// Description:
+// Helper routine to put data in the outgoing fifo, if we aren't already waiting
+// for something to be there. If the fifo has only room for a very little data,
+// go head and hit the board with a mailbox hit immediately. Otherwise, it will
+// have to happen later in the interrupt processing. Since this routine may be
+// called both at interrupt and foreground time, we must turn off interrupts
+// during the entire process.
+//******************************************************************************
+static void
+serviceOutgoingFifo(i2eBordStrPtr pB)
+{
+ // If we aren't currently waiting for the board to empty our fifo, service
+ // everything that is pending, in priority order (especially, Bypass before
+ // Inline).
+ if ( ! pB->i2eWaitingForEmptyFifo )
+ {
+ i2StuffFifoFlow(pB);
+ i2StuffFifoBypass(pB);
+ i2StuffFifoInline(pB);
+
+ iiSendPendingMail(pB);
+ }
+}
+
+//******************************************************************************
+// Function: i2ServiceBoard(pB)
+// Parameters: Pointer to a board structure
+// Returns: Nothing
+//
+// Description:
+// Normally this is called from interrupt level, but there is deliberately
+// nothing in here specific to being called from interrupt level. All the
+// hardware-specific, interrupt-specific things happen at the outer levels.
+//
+// For example, a timer interrupt could drive this routine for some sort of
+// polled operation. The only requirement is that the programmer deal with any
+// atomiticity/concurrency issues that result.
+//
+// This routine responds to the board's having sent mailbox information to the
+// host (which would normally cause an interrupt). This routine reads the
+// incoming mailbox. If there is no data in it, this board did not create the
+// interrupt and/or has nothing to be done to it. (Except, if we have been
+// waiting to write mailbox data to it, we may do so.
+//
+// Based on the value in the mailbox, we may take various actions.
+//
+// No checking here of pB validity: after all, it shouldn't have been called by
+// the handler unless pB were on the list.
+//******************************************************************************
+static inline int
+i2ServiceBoard ( i2eBordStrPtr pB )
+{
+ unsigned inmail;
+ unsigned long flags;
+
+
+ inmail = iiGetMail(pB);
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INTR, 2, 1, inmail );
+#endif
+
+ if (inmail != NO_MAIL_HERE) {
+ // If the board has gone fatal, nothing to do but hit a bit that will
+ // alert foreground tasks to protest!
+ if ( inmail & MB_FATAL_ERROR ) {
+ pB->i2eFatal = 1;
+ goto exit_i2ServiceBoard;
+ }
+
+ /* Assuming no fatal condition, we proceed to do work */
+ if ( inmail & MB_IN_STUFFED ) {
+ pB->i2eFifoInInts++;
+ i2StripFifo(pB); /* There might be incoming packets */
+ }
+
+ if (inmail & MB_OUT_STRIPPED) {
+ pB->i2eFifoOutInts++;
+ WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ pB->i2eFifoRemains = pB->i2eFifoSize;
+ pB->i2eWaitingForEmptyFifo = 0;
+ WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INTR, 30, 1, pB->i2eFifoRemains );
+#endif
+ }
+ serviceOutgoingFifo(pB);
+ }
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INTR, 8, 0 );
+#endif
+
+exit_i2ServiceBoard:
+
+ return 0;
+}
diff --git a/drivers/char/ip2/i2lib.h b/drivers/char/ip2/i2lib.h
new file mode 100644
index 000000000..21f0e1af9
--- /dev/null
+++ b/drivers/char/ip2/i2lib.h
@@ -0,0 +1,350 @@
+/*******************************************************************************
+*
+* (c) 1998 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Header file for high level library functions
+*
+*******************************************************************************/
+#ifndef I2LIB_H
+#define I2LIB_H 1
+//------------------------------------------------------------------------------
+// I2LIB.H
+//
+// IntelliPort-II and IntelliPort-IIEX
+//
+// Defines, structure definitions, and external declarations for i2lib.c
+//------------------------------------------------------------------------------
+//--------------------------------------
+// Mandatory Includes:
+//--------------------------------------
+#include "ip2types.h"
+#include "i2ellis.h"
+#include "i2pack.h"
+#include "i2cmd.h"
+
+//------------------------------------------------------------------------------
+// i2ChanStr -- Channel Structure:
+// Used to track per-channel information for the library routines using standard
+// loadware. Note also, a pointer to an array of these structures is patched
+// into the i2eBordStr (see i2ellis.h)
+//------------------------------------------------------------------------------
+//
+// If we make some limits on the maximum block sizes, we can avoid dealing with
+// buffer wrap. The wrapping of the buffer is based on where the start of the
+// packet is. Then there is always room for the packet contiguously.
+//
+// Maximum total length of an outgoing data or in-line command block. The limit
+// of 36 on data is quite arbitrary and based more on DOS memory limitations
+// than the board interface. However, for commands, the maximum packet length is
+// MAX_CMD_PACK_SIZE, because the field size for the count is only a few bits
+// (see I2PACK.H) in such packets. For data packets, the count field size is not
+// the limiting factor. As of this writing, MAX_OBUF_BLOCK < MAX_CMD_PACK_SIZE,
+// but be careful if wanting to modify either.
+//
+#define MAX_OBUF_BLOCK 36
+
+// Another note on maximum block sizes: we are buffering packets here. Data is
+// put into the buffer (if there is room) regardless of the credits from the
+// board. The board sends new credits whenever it has removed from his buffers a
+// number of characters equal to 80% of total buffer size. (Of course, the total
+// buffer size is what is reported when the very first set of flow control
+// status packets are received from the board. Therefore, to be robust, you must
+// always fill the board to at least 80% of the current credit limit, else you
+// might not give it enough to trigger a new report. These conditions are
+// obtained here so long as the maximum output block size is less than 20% the
+// size of the board's output buffers. This is true at present by "coincidence"
+// or "infernal knowledge": the board's output buffers are at least 700 bytes
+// long (20% = 140 bytes, at least). The 80% figure is "official", so the safest
+// strategy might be to trap the first flow control report and guarantee that
+// the effective maxObufBlock is the minimum of MAX_OBUF_BLOCK and 20% of first
+// reported buffer credit.
+//
+#define MAX_CBUF_BLOCK 6 // Maximum total length of a bypass command block
+
+#define IBUF_SIZE 500 // character capacity of input buffer per channel
+#define OBUF_SIZE 2048// character capacity of output buffer per channel
+#define CBUF_SIZE 10 // character capacity of output bypass buffer
+
+typedef struct _i2ChanStr
+{
+ // First, back-pointers so that given a pointer to this structure, you can
+ // determine the correct board and channel number to reference, (say, when
+ // issuing commands, etc. (Note, channel number is in infl.hd.i2sChannel.)
+
+ int port_index; // Index of port in channel structure array attached
+ // to board structure.
+ PTTY pTTY; // Pointer to tty structure for port (OS specific)
+ USHORT validity; // Indicates whether the given channel has been
+ // initialized, really exists (or is a missing
+ // channel, e.g. channel 9 on an 8-port box.)
+
+ i2eBordStrPtr pMyBord; // Back-pointer to this channel's board structure
+
+ int wopen; // waiting fer carrier
+
+ int throttled; // Set if upper layer can take no data
+
+ int flags; // Defined in tty.h
+ int session; // Defined in tty.h
+ int pgrp; // Defined in tty.h
+
+ PWAITQ open_wait; // Pointer for OS sleep function.
+ PWAITQ close_wait; // Pointer for OS sleep function.
+ PWAITQ delta_msr_wait;// Pointer for OS sleep function.
+
+ struct timer_list BookmarkTimer; // Used by i2DrainOutput
+ wait_queue_head_t pBookmarkWait; // Used by i2DrainOutput
+
+ struct termios NormalTermios;
+ struct termios CalloutTermios;
+
+ int BaudBase;
+ int BaudDivisor;
+
+ USHORT ClosingDelay;
+ USHORT ClosingWaitTime;
+
+ volatile
+ flowIn infl; // This structure is initialized as a completely
+ // formed flow-control command packet, and as such
+ // has the channel number, also the capacity and
+ // "as-of" data needed continuously.
+
+ USHORT sinceLastFlow; // Counts the number of characters read from input
+ // buffers, since the last time flow control info
+ // was sent.
+
+ USHORT whenSendFlow; // Determines when new flow control is to be sent to
+ // the board. Note unlike earlier manifestations of
+ // the driver, these packets can be sent from
+ // in-place.
+
+ USHORT channelNeeds; // Bit map of important things which must be done
+ // for this channel. (See bits below )
+
+ volatile
+ flowStat outfl; // Same type of structure is used to hold current
+ // flow control information used to control our
+ // output. "asof" is kept updated as data is sent,
+ // and "room" never goes to zero.
+
+ // The incoming ring buffer
+ // Unlike the outgoing buffers, this holds raw data, not packets. The two
+ // extra bytes are used to hold the byte-padding when there is room for an
+ // odd number of bytes before we must wrap.
+ //
+ UCHAR Ibuf[IBUF_SIZE + 2];
+ volatile
+ USHORT Ibuf_stuff; // Stuffing index
+ volatile
+ USHORT Ibuf_strip; // Stripping index
+
+ // The outgoing ring-buffer: Holds Data and command packets. N.B., even
+ // though these are in the channel structure, the channel is also written
+ // here, the easier to send it to the fifo when ready. HOWEVER, individual
+ // packets here are NOT padded to even length: the routines for writing
+ // blocks to the the fifo will pad to even byte counts.
+ //
+ UCHAR Obuf[OBUF_SIZE+MAX_OBUF_BLOCK+4];
+ volatile
+ USHORT Obuf_stuff; // Stuffing index
+ volatile
+ USHORT Obuf_strip; // Stripping index
+ int Obuf_char_count;
+
+ // The outgoing bypass-command buffer. Unlike earlier manifestations, the
+ // flow control packets are sent directly from the structures. As above, the
+ // channel number is included in the packet, but they are NOT padded to even
+ // size.
+ //
+ UCHAR Cbuf[CBUF_SIZE+MAX_CBUF_BLOCK+2];
+ volatile
+ USHORT Cbuf_stuff; // Stuffing index
+ volatile
+ USHORT Cbuf_strip; // Stripping index
+
+ // The temporary buffer for the Linux tty driver PutChar entry.
+ //
+ UCHAR Pbuf[MAX_OBUF_BLOCK - sizeof (i2DataHeader)];
+ volatile
+ USHORT Pbuf_stuff; // Stuffing index
+
+ // The state of incoming data-set signals
+ //
+ USHORT dataSetIn; // Bit-mapped according to below. Also indicates
+ // whether a break has been detected since last
+ // inquiry.
+
+ // The state of outcoming data-set signals (as far as we can tell!)
+ //
+ USHORT dataSetOut; // Bit-mapped according to below.
+
+ // Most recent hot-key identifier detected
+ //
+ USHORT hotKeyIn; // Hot key as sent by the board, HOT_CLEAR indicates
+ // no hot key detected since last examined.
+
+ // Counter of outstanding requests for bookmarks
+ //
+ short bookMarks; // Number of outstanding bookmark requests, (+ive
+ // whenever a bookmark request if queued up, -ive
+ // whenever a bookmark is received).
+
+ // Misc options
+ //
+ USHORT channelOptions; // See below
+
+ // To store various incoming special packets
+ //
+ debugStat channelStatus;
+ cntStat channelRcount;
+ cntStat channelTcount;
+ failStat channelFail;
+
+ // To store the last values for line characteristics we sent to the board.
+ //
+ int speed;
+
+ int flush_flags;
+
+ void (*trace)(unsigned short,unsigned char,unsigned char,unsigned long,...);
+
+#ifdef __KERNEL__
+ /*
+ * Kernel counters for the 4 input interrupts
+ */
+ struct async_icount icount;
+
+ /*
+ * Task queues for processing input packets from the board.
+ */
+ struct tq_struct tqueue_input;
+ struct tq_struct tqueue_status;
+ struct tq_struct tqueue_hangup;
+#endif
+
+ spinlock_t Ibuf_spinlock;
+ spinlock_t Obuf_spinlock;
+ spinlock_t Cbuf_spinlock;
+ spinlock_t Pbuf_spinlock;
+
+} i2ChanStr, *i2ChanStrPtr;
+
+//---------------------------------------------------
+// Manifests and bit-maps for elements in i2ChanStr
+//---------------------------------------------------
+//
+// flush flags
+//
+#define STARTFL_FLAG 1
+#define STOPFL_FLAG 2
+
+// validity
+//
+#define CHANNEL_MAGIC_BITS 0xff00
+#define CHANNEL_MAGIC 0x5300 // (validity & CHANNEL_MAGIC_BITS) ==
+ // CHANNEL_MAGIC --> structure good
+
+#define CHANNEL_SUPPORT 0x0001 // Indicates channel is supported, exists,
+ // and passed P.O.S.T.
+
+// channelNeeds
+//
+#define NEED_FLOW 1 // Indicates flow control has been queued
+#define NEED_INLINE 2 // Indicates inline commands or data queued
+#define NEED_BYPASS 4 // Indicates bypass commands queued
+#define NEED_CREDIT 8 // Indicates would be sending except has not sufficient
+ // credit. The data is still in the channel structure,
+ // but the channel is not enqueued in the board
+ // structure again until there is a credit received from
+ // the board.
+
+// dataSetIn (Also the bits for i2GetStatus return value)
+//
+#define I2_DCD 1
+#define I2_CTS 2
+#define I2_DSR 4
+#define I2_RI 8
+
+// dataSetOut (Also the bits for i2GetStatus return value)
+//
+#define I2_DTR 1
+#define I2_RTS 2
+
+// i2GetStatus() can optionally clear these bits
+//
+#define I2_BRK 0x10 // A break was detected
+#define I2_PAR 0x20 // A parity error was received
+#define I2_FRA 0x40 // A framing error was received
+#define I2_OVR 0x80 // An overrun error was received
+
+// i2GetStatus() automatically clears these bits */
+//
+#define I2_DDCD 0x100 // DCD changed from its former value
+#define I2_DCTS 0x200 // CTS changed from its former value
+#define I2_DDSR 0x400 // DSR changed from its former value
+#define I2_DRI 0x800 // RI changed from its former value
+
+// hotKeyIn
+//
+#define HOT_CLEAR 0x1322 // Indicates that no hot-key has been detected
+
+// channelOptions
+//
+#define CO_NBLOCK_WRITE 1 // Writes don't block waiting for buffer. (Default
+ // is, they do wait.)
+
+// fcmodes
+//
+#define I2_OUTFLOW_CTS 0x0001
+#define I2_INFLOW_RTS 0x0002
+#define I2_INFLOW_DSR 0x0004
+#define I2_INFLOW_DTR 0x0008
+#define I2_OUTFLOW_DSR 0x0010
+#define I2_OUTFLOW_DTR 0x0020
+#define I2_OUTFLOW_XON 0x0040
+#define I2_OUTFLOW_XANY 0x0080
+#define I2_INFLOW_XON 0x0100
+
+#define I2_CRTSCTS (I2_OUTFLOW_CTS|I2_INFLOW_RTS)
+#define I2_IXANY_MODE (I2_OUTFLOW_XON|I2_OUTFLOW_XANY)
+
+//-------------------------------------------
+// Macros used from user level like functions
+//-------------------------------------------
+
+// Macros to set and clear channel options
+//
+#define i2SetOption(pCh, option) pCh->channelOptions |= option
+#define i2ClrOption(pCh, option) pCh->channelOptions &= ~option
+
+// Macro to set fatal-error trap
+//
+#define i2SetFatalTrap(pB, routine) pB->i2eFatalTrap = routine
+
+//--------------------------------------------
+// Declarations and prototypes for i2lib.c
+//--------------------------------------------
+//
+static int i2InitChannels(i2eBordStrPtr, int, i2ChanStrPtr);
+static int i2QueueCommands(int, i2ChanStrPtr, int, int, cmdSyntaxPtr,...);
+static int i2GetStatus(i2ChanStrPtr, int);
+static int i2Input(i2ChanStrPtr);
+static int i2InputFlush(i2ChanStrPtr);
+static int i2Output(i2ChanStrPtr, const char *, int, int);
+static int i2OutputFree(i2ChanStrPtr);
+static int i2ServiceBoard(i2eBordStrPtr);
+static void i2DrainOutput(i2ChanStrPtr, int);
+
+// Argument to i2QueueCommands
+//
+#define C_IN_LINE 1
+#define C_BYPASS 0
+
+#endif // I2LIB_H
diff --git a/drivers/char/ip2/i2os.h b/drivers/char/ip2/i2os.h
new file mode 100644
index 000000000..f85822c1a
--- /dev/null
+++ b/drivers/char/ip2/i2os.h
@@ -0,0 +1,145 @@
+/*******************************************************************************
+*
+* (c) 1999 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Defines, definitions and includes which are heavily dependant
+* on O/S, host, compiler, etc. This file is tailored for:
+* Linux v2.0.0 and later
+* Gnu gcc c2.7.2
+* 80x86 architecture
+*
+*******************************************************************************/
+
+#ifndef I2OS_H /* To prevent multiple includes */
+#define I2OS_H 1
+
+#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
+
+//-------------------------------------------------
+// Required Includes
+//-------------------------------------------------
+
+#include "ip2types.h"
+#include <asm/io.h> /* For inb, etc */
+
+//------------------------------------
+// Defines for I/O instructions:
+//------------------------------------
+
+#define INB(port) inb(port)
+#define OUTB(port,value) outb((value),(port))
+#define INW(port) inw(port)
+#define OUTW(port,value) outw((value),(port))
+#define OUTSW(port,addr,count) outsw((port),(addr),(((count)+1)/2))
+#define OUTSB(port,addr,count) outsb((port),(addr),(((count)+1))&-2)
+#define INSW(port,addr,count) insw((port),(addr),(((count)+1)/2))
+#define INSB(port,addr,count) insb((port),(addr),(((count)+1))&-2)
+
+//--------------------------------------------
+// Interrupt control
+//--------------------------------------------
+
+#if LINUX_VERSION_CODE < 0x00020100
+typedef int spinlock_t;
+#define spin_lock_init()
+#define spin_lock(a)
+#define spin_unlock(a)
+#define spin_lock_irqsave(a,b) {save_flags((b));cli();}
+#define spin_unlock_irqrestore(a,b) {restore_flags((b));}
+#define write_lock_irqsave(a,b) spin_lock_irqsave(a,b)
+#define write_unlock_irqrestore(a,b) spin_unlock_irqrestore(a,b)
+#define read_lock_irqsave(a,b) spin_lock_irqsave(a,b)
+#define read_unlock_irqrestore(a,b) spin_unlock_irqrestore(a,b)
+#endif
+
+//#define SAVE_AND_DISABLE_INTS(a,b) spin_lock_irqsave(a,b)
+//#define RESTORE_INTS(a,b) spin_unlock_irqrestore(a,b)
+
+#define LOCK_INIT(a) spin_lock_init(a)
+
+#define SAVE_AND_DISABLE_INTS(a,b) { \
+ /* printk("get_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
+ spin_lock_irqsave(a,b); \
+}
+
+#define RESTORE_INTS(a,b) { \
+ /* printk("rel_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
+ spin_unlock_irqrestore(a,b); \
+}
+
+#define READ_LOCK_IRQSAVE(a,b) { \
+ /* printk("get_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
+ read_lock_irqsave(a,b); \
+}
+
+#define READ_UNLOCK_IRQRESTORE(a,b) { \
+ /* printk("rel_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
+ read_unlock_irqrestore(a,b); \
+}
+
+#define WRITE_LOCK_IRQSAVE(a,b) { \
+ /* printk("get_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
+ write_lock_irqsave(a,b); \
+}
+
+#define WRITE_UNLOCK_IRQRESTORE(a,b) { \
+ /* printk("rel_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
+ write_unlock_irqrestore(a,b); \
+}
+
+
+//------------------------------------------------------------------------------
+// Hardware-delay loop
+//
+// Probably used in only one place (see i2ellis.c) but this helps keep things
+// together. Note we have unwound the IN instructions. On machines with a
+// reasonable cache, the eight instructions (1 byte each) should fit in cache
+// nicely, and on un-cached machines, the code-fetch would tend not to dominate.
+// Note that cx is shifted so that "count" still reflects the total number of
+// iterations assuming no unwinding.
+//------------------------------------------------------------------------------
+
+//#define DELAY1MS(port,count,label)
+
+//------------------------------------------------------------------------------
+// Macros to switch to a new stack, saving stack pointers, and to restore the
+// old stack (Used, for example, in i2lib.c) "heap" is the address of some
+// buffer which will become the new stack (working down from highest address).
+// The two words at the two lowest addresses in this stack are for storing the
+// SS and SP.
+//------------------------------------------------------------------------------
+
+//#define TO_NEW_STACK(heap,size)
+//#define TO_OLD_STACK(heap)
+
+//------------------------------------------------------------------------------
+// Macros to save the original IRQ vectors and masks, and to patch in new ones.
+//------------------------------------------------------------------------------
+
+//#define SAVE_IRQ_MASKS(dest)
+//#define WRITE_IRQ_MASKS(src)
+//#define SAVE_IRQ_VECTOR(value,dest)
+//#define WRITE_IRQ_VECTOR(value,src)
+
+//------------------------------------------------------------------------------
+// Macro to copy data from one far pointer to another.
+//------------------------------------------------------------------------------
+
+#define I2_MOVE_DATA(fpSource,fpDest,count) memmove(fpDest,fpSource,count);
+
+//------------------------------------------------------------------------------
+// Macros to issue eoi's to host interrupt control (IBM AT 8259-style).
+//------------------------------------------------------------------------------
+
+//#define MASTER_EOI
+//#define SLAVE_EOI
+
+#endif /* I2OS_H */
+
+
diff --git a/drivers/char/ip2/i2pack.h b/drivers/char/ip2/i2pack.h
new file mode 100644
index 000000000..e9b87a786
--- /dev/null
+++ b/drivers/char/ip2/i2pack.h
@@ -0,0 +1,364 @@
+/*******************************************************************************
+*
+* (c) 1998 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Definitions of the packets used to transfer data and commands
+* Host <--> Board. Information provided here is only applicable
+* when the standard loadware is active.
+*
+*******************************************************************************/
+#ifndef I2PACK_H
+#define I2PACK_H 1
+
+//-----------------------------------------------
+// Revision History:
+//
+// 10 October 1991 MAG First draft
+// 24 February 1992 MAG Additions for 1.4.x loadware
+// 11 March 1992 MAG New status packets
+//
+//-----------------------------------------------
+
+//------------------------------------------------------------------------------
+// Packet Formats:
+//
+// Information passes between the host and board through the FIFO in packets.
+// These have headers which indicate the type of packet. Because the fifo data
+// path may be 16-bits wide, the protocol is constrained such that each packet
+// is always padded to an even byte count. (The lower-level interface routines
+// -- i2ellis.c -- are designed to do this).
+//
+// The sender (be it host or board) must place some number of complete packets
+// in the fifo, then place a message in the mailbox that packets are available.
+// Placing such a message interrupts the "receiver" (be it board or host), who
+// reads the mailbox message and determines that there are incoming packets
+// ready. Since there are no partial packets, and the length of a packet is
+// given in the header, the remainder of the packet can be read without checking
+// for FIFO empty condition. The process is repeated, packet by packet, until
+// the incoming FIFO is empty. Then the receiver uses the outbound mailbox to
+// signal the board that it has read the data. Only then can the sender place
+// additional data in the fifo.
+//------------------------------------------------------------------------------
+//
+//------------------------------------------------
+// Definition of Packet Header Area
+//------------------------------------------------
+//
+// Caution: these only define header areas. In actual use the data runs off
+// beyond the end of these structures.
+//
+// Since these structures are based on sequences of bytes which go to the board,
+// there cannot be ANY padding between the elements.
+#pragma pack(1)
+
+//----------------------------
+// DATA PACKETS
+//----------------------------
+
+typedef struct _i2DataHeader
+{
+ unsigned char i2sChannel; /* The channel number: 0-255 */
+
+ // -- Bitfields are allocated LSB first --
+
+ // For incoming data, indicates whether this is an ordinary packet or a
+ // special one (e.g., hot key hit).
+ unsigned i2sId : 2 __attribute__ ((__packed__));
+
+ // For tagging data packets. There are flush commands which flush only data
+ // packets bearing a particular tag. (used in implementing IntelliView and
+ // IntelliPrint). THE TAG VALUE 0xf is RESERVED and must not be used (it has
+ // meaning internally to the loadware).
+ unsigned i2sTag : 4;
+
+ // These two bits determine the type of packet sent/received.
+ unsigned i2sType : 2;
+
+ // The count of data to follow: does not include the possible additional
+ // padding byte. MAXIMUM COUNT: 4094. The top four bits must be 0.
+ unsigned short i2sCount;
+
+} i2DataHeader, *i2DataHeaderPtr;
+
+// Structure is immediately followed by the data, proper.
+
+//----------------------------
+// NON-DATA PACKETS
+//----------------------------
+
+typedef struct _i2CmdHeader
+{
+ unsigned char i2sChannel; // The channel number: 0-255 (Except where noted
+ // - see below
+
+ // Number of bytes of commands, status or whatever to follow
+ unsigned i2sCount : 6;
+
+ // These two bits determine the type of packet sent/received.
+ unsigned i2sType : 2;
+
+} i2CmdHeader, *i2CmdHeaderPtr;
+
+// Structure is immediately followed by the applicable data.
+
+//---------------------------------------
+// Flow Control Packets (Outbound)
+//---------------------------------------
+
+// One type of outbound command packet is so important that the entire structure
+// is explicitly defined here. That is the flow-control packet. This is never
+// sent by user-level code (as would be the commands to raise/lower DTR, for
+// example). These are only sent by the library routines in response to reading
+// incoming data into the buffers.
+//
+// The parameters inside the command block are maintained in place, then the
+// block is sent at the appropriate time.
+
+typedef struct _flowIn
+{
+ i2CmdHeader hd; // Channel #, count, type (see above)
+ unsigned char fcmd; // The flow control command (37)
+ unsigned short asof; // As of byte number "asof" (LSB first!) I have room
+ // for "room" bytes
+ unsigned short room;
+} flowIn, *flowInPtr;
+
+//----------------------------------------
+// (Incoming) Status Packets
+//----------------------------------------
+
+// Incoming packets which are non-data packets are status packets. In this case,
+// the channel number in the header is unimportant. What follows are one or more
+// sub-packets, the first word of which consists of the channel (first or low
+// byte) and the status indicator (second or high byte), followed by possibly
+// more data.
+
+#define STAT_CTS_UP 0 /* CTS raised (no other bytes) */
+#define STAT_CTS_DN 1 /* CTS dropped (no other bytes) */
+#define STAT_DCD_UP 2 /* DCD raised (no other bytes) */
+#define STAT_DCD_DN 3 /* DCD dropped (no other bytes) */
+#define STAT_DSR_UP 4 /* DSR raised (no other bytes) */
+#define STAT_DSR_DN 5 /* DSR dropped (no other bytes) */
+#define STAT_RI_UP 6 /* RI raised (no other bytes) */
+#define STAT_RI_DN 7 /* RI dropped (no other bytes) */
+#define STAT_BRK_DET 8 /* BRK detect (no other bytes) */
+#define STAT_FLOW 9 /* Flow control(-- more: see below */
+#define STAT_BMARK 10 /* Bookmark (no other bytes)
+ * Bookmark is sent as a response to
+ * a command 60: request for bookmark
+ */
+#define STAT_STATUS 11 /* Special packet: see below */
+#define STAT_TXCNT 12 /* Special packet: see below */
+#define STAT_RXCNT 13 /* Special packet: see below */
+#define STAT_BOXIDS 14 /* Special packet: see below */
+#define STAT_HWFAIL 15 /* Special packet: see below */
+
+#define STAT_MOD_ERROR 0xc0
+#define STAT_MODEM 0xc0/* If status & STAT_MOD_ERROR:
+ * == STAT_MODEM, then this is a modem
+ * status packet, given in response to a
+ * CMD_DSS_NOW command.
+ * The low nibble has each data signal:
+ */
+#define STAT_MOD_DCD 0x8
+#define STAT_MOD_RI 0x4
+#define STAT_MOD_DSR 0x2
+#define STAT_MOD_CTS 0x1
+
+#define STAT_ERROR 0x80/* If status & STAT_MOD_ERROR
+ * == STAT_ERROR, then
+ * sort of error on the channel.
+ * The remaining seven bits indicate
+ * what sort of error it is.
+ */
+/* The low three bits indicate parity, framing, or overrun errors */
+
+#define STAT_E_PARITY 4 /* Parity error */
+#define STAT_E_FRAMING 2 /* Framing error */
+#define STAT_E_OVERRUN 1 /* (uxart) overrun error */
+
+//---------------------------------------
+// STAT_FLOW packets
+//---------------------------------------
+
+typedef struct _flowStat
+{
+ unsigned short asof;
+ unsigned short room;
+}flowStat, *flowStatPtr;
+
+// flowStat packets are received from the board to regulate the flow of outgoing
+// data. A local copy of this structure is also kept to track the amount of
+// credits used and credits remaining. "room" is the amount of space in the
+// board's buffers, "as of" having received a certain byte number. When sending
+// data to the fifo, you must calculate how much buffer space your packet will
+// use. Add this to the current "asof" and subtract it from the current "room".
+//
+// The calculation for the board's buffer is given by CREDIT_USAGE, where size
+// is the un-rounded count of either data characters or command characters.
+// (Which is to say, the count rounded up, plus two).
+
+#define CREDIT_USAGE(size) (((size) + 3) & ~1)
+
+//---------------------------------------
+// STAT_STATUS packets
+//---------------------------------------
+
+typedef struct _debugStat
+{
+ unsigned char d_ccsr;
+ unsigned char d_txinh;
+ unsigned char d_stat1;
+ unsigned char d_stat2;
+} debugStat, *debugStatPtr;
+
+// debugStat packets are sent to the host in response to a CMD_GET_STATUS
+// command. Each byte is bit-mapped as described below:
+
+#define D_CCSR_XON 2 /* Has received XON, ready to transmit */
+#define D_CCSR_XOFF 4 /* Has received XOFF, not transmitting */
+#define D_CCSR_TXENAB 8 /* Transmitter is enabled */
+#define D_CCSR_RXENAB 0x80 /* Receiver is enabled */
+
+#define D_TXINH_BREAK 1 /* We are sending a break */
+#define D_TXINH_EMPTY 2 /* No data to send */
+#define D_TXINH_SUSP 4 /* Output suspended via command 57 */
+#define D_TXINH_CMD 8 /* We are processing an in-line command */
+#define D_TXINH_LCD 0x10 /* LCD diagnostics are running */
+#define D_TXINH_PAUSE 0x20 /* We are processing a PAUSE command */
+#define D_TXINH_DCD 0x40 /* DCD is low, preventing transmission */
+#define D_TXINH_DSR 0x80 /* DSR is low, preventing transmission */
+
+#define D_STAT1_TXEN 1 /* Transmit INTERRUPTS enabled */
+#define D_STAT1_RXEN 2 /* Receiver INTERRUPTS enabled */
+#define D_STAT1_MDEN 4 /* Modem (data set sigs) interrupts enabled */
+#define D_STAT1_RLM 8 /* Remote loopback mode selected */
+#define D_STAT1_LLM 0x10 /* Local internal loopback mode selected */
+#define D_STAT1_CTS 0x20 /* CTS is low, preventing transmission */
+#define D_STAT1_DTR 0x40 /* DTR is low, to stop remote transmission */
+#define D_STAT1_RTS 0x80 /* RTS is low, to stop remote transmission */
+
+#define D_STAT2_TXMT 1 /* Transmit buffers are all empty */
+#define D_STAT2_RXMT 2 /* Receive buffers are all empty */
+#define D_STAT2_RXINH 4 /* Loadware has tried to inhibit remote
+ * transmission: dropped DTR, sent XOFF,
+ * whatever...
+ */
+#define D_STAT2_RXFLO 8 /* Loadware can send no more data to host
+ * until it receives a flow-control packet
+ */
+//-----------------------------------------
+// STAT_TXCNT and STAT_RXCNT packets
+//----------------------------------------
+
+typedef struct _cntStat
+{
+ unsigned short cs_time; // (Assumes host is little-endian!)
+ unsigned short cs_count;
+} cntStat, *cntStatPtr;
+
+// These packets are sent in response to a CMD_GET_RXCNT or a CMD_GET_TXCNT
+// bypass command. cs_time is a running 1 Millisecond counter which acts as a
+// time stamp. cs_count is a running counter of data sent or received from the
+// uxarts. (Not including data added by the chip itself, as with CRLF
+// processing).
+//------------------------------------------
+// STAT_HWFAIL packets
+//------------------------------------------
+
+typedef struct _failStat
+{
+ unsigned char fs_written;
+ unsigned char fs_read;
+ unsigned short fs_address;
+} failStat, *failStatPtr;
+
+// This packet is sent whenever the on-board diagnostic process detects an
+// error. At startup, this process is dormant. The host can wake it up by
+// issuing the bypass command CMD_HW_TEST. The process runs at low priority and
+// performs continuous hardware verification; writing data to certain on-board
+// registers, reading it back, and comparing. If it detects an error, this
+// packet is sent to the host, and the process goes dormant again until the host
+// sends another CMD_HW_TEST. It then continues with the next register to be
+// tested.
+
+//------------------------------------------------------------------------------
+// Macros to deal with the headers more easily! Note that these are defined so
+// they may be used as "left" as well as "right" expressions.
+//------------------------------------------------------------------------------
+
+// Given a pointer to the packet, reference the channel number
+//
+#define CHANNEL_OF(pP) ((i2DataHeaderPtr)(pP))->i2sChannel
+
+// Given a pointer to the packet, reference the Packet type
+//
+#define PTYPE_OF(pP) ((i2DataHeaderPtr)(pP))->i2sType
+
+// The possible types of packets
+//
+#define PTYPE_DATA 0 /* Host <--> Board */
+#define PTYPE_BYPASS 1 /* Host ---> Board */
+#define PTYPE_INLINE 2 /* Host ---> Board */
+#define PTYPE_STATUS 2 /* Host <--- Board */
+
+// Given a pointer to a Data packet, reference the Tag
+//
+#define TAG_OF(pP) ((i2DataHeaderPtr)(pP))->i2sTag
+
+// Given a pointer to a Data packet, reference the data i.d.
+//
+#define ID_OF(pP) ((i2DataHeaderPtr)(pP))->i2sId
+
+// The possible types of ID's
+//
+#define ID_ORDINARY_DATA 0
+#define ID_HOT_KEY 1
+
+// Given a pointer to a Data packet, reference the count
+//
+#define DATA_COUNT_OF(pP) ((i2DataHeaderPtr)(pP))->i2sCount
+
+// Given a pointer to a Data packet, reference the beginning of data
+//
+#define DATA_OF(pP) &((unsigned char *)(pP))[4] // 4 = size of header
+
+// Given a pointer to a Non-Data packet, reference the count
+//
+#define CMD_COUNT_OF(pP) ((i2CmdHeaderPtr)(pP))->i2sCount
+
+#define MAX_CMD_PACK_SIZE 62 // Maximum size of such a count
+
+// Given a pointer to a Non-Data packet, reference the beginning of data
+//
+#define CMD_OF(pP) &((unsigned char *)(pP))[2] // 2 = size of header
+
+//--------------------------------
+// MailBox Bits:
+//--------------------------------
+
+//--------------------------
+// Outgoing (host to board)
+//--------------------------
+//
+#define MB_OUT_STUFFED 0x80 // Host has placed output in fifo
+#define MB_IN_STRIPPED 0x40 // Host has read in all input from fifo
+
+//--------------------------
+// Incoming (board to host)
+//--------------------------
+//
+#define MB_IN_STUFFED 0x80 // Board has placed input in fifo
+#define MB_OUT_STRIPPED 0x40 // Board has read all output from fifo
+#define MB_FATAL_ERROR 0x20 // Board has encountered a fatal error
+
+#pragma pack(4) // Reset padding to command-line default
+
+#endif // I2PACK_H
+
diff --git a/drivers/char/ip2/ip2.h b/drivers/char/ip2/ip2.h
new file mode 100644
index 000000000..7236744b0
--- /dev/null
+++ b/drivers/char/ip2/ip2.h
@@ -0,0 +1,109 @@
+/*******************************************************************************
+*
+* (c) 1998 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Driver constants for configuration and tuning
+*
+* NOTES:
+*
+*******************************************************************************/
+#ifndef IP2_H
+#define IP2_H
+
+#include "ip2types.h"
+#include "i2cmd.h"
+
+/*************/
+/* Constants */
+/*************/
+
+/* Device major numbers
+ * The first set are the major numbers allocated from the Linux Device Registry.
+ * This was expanded from 64 to 128 with version 2.0.26. If this code is built
+ * under earlier versions we use majors from the LOCAL/EXPERIMENTAL range.
+ */
+#if MAX_CHRDEV > 64
+# define IP2_TTY_MAJOR 71
+# define IP2_CALLOUT_MAJOR 72
+# define IP2_IPL_MAJOR 73
+#else
+# define IP2_TTY_MAJOR 60
+# define IP2_CALLOUT_MAJOR 61
+# define IP2_IPL_MAJOR 62
+#endif
+
+
+/* Board configuration array.
+ * This array defines the hardware irq and address for up to IP2_MAX_BOARDS
+ * (4 supported per ip2_types.h) ISA board addresses and irqs MUST be specified,
+ * PCI and EISA boards are probed for and automagicly configed
+ * iff the addresses are set to 1 and 2 respectivily.
+ * 0x0100 - 0x03f0 == ISA
+ * 1 == PCI
+ * 2 == EISA
+ * 0 == (skip this board)
+ * This array defines the hardware addresses for them. Special
+ * addresses are EISA and PCI which go sniffing for boards.
+
+ * In a multiboard system the position in the array determines which port
+ * devices are assigned to each board:
+ * board 0 is assigned ttyF0.. to ttyF63,
+ * board 1 is assigned ttyF64 to ttyF127,
+ * board 2 is assigned ttyF128 to ttyF191,
+ * board 3 is assigned ttyF192 to ttyF255.
+ *
+ * In PCI and EISA bus systems each range is mapped to card in
+ * monotonically increasing slot number order, ISA position is as specified
+ * here.
+
+ * If the irqs are ALL set to 0,0,0,0 all boards operate in
+ * polled mode. For interrupt operation ISA boards require that the IRQ be
+ * specified, while PCI and EISA boards any nonzero entry
+ * will enable interrupts using the BIOS configured irq for the board.
+ * An invalid irq entry will default to polled mode for that card and print
+ * console warning.
+
+ * When the driver is loaded as a module these setting can be overridden on the
+ * modprobe command line or on an option line in /etc/conf.modules
+ * or /etc/modules.conf depending on your distrubution.
+ * If the driver is built-in the configuration must be
+ * set here for ISA cards and address set to 1 and 2 for PCI and EISA.
+ *
+ * Here is an example that shows most if not all possibe combinations:
+
+ *static ip2config_t ip2config =
+ *{
+ * {11,1,0,0}, // irqs
+ * { // Addresses
+ * 0x0308, // Board 0, ttyF0 - ttyF63// ISA card at io=0x308, irq=11
+ * 0x0001, // Board 1, ttyF64 - ttyF127//PCI card configured by BIOS
+ * 0x0000, // Board 2, ttyF128 - ttyF191// Slot skipped
+ * 0x0002 // Board 3, ttyF192 - ttyF255//EISA card configured by BIOS
+ * // but polled not irq driven
+ * }
+ *};
+ */
+
+ /* this structure is zeroed out because the suggested method is to configure
+ * the driver as a module, set up the parameters with an options line in
+ * /etc/modules.conf or /etc/conf.modules and load with modprobe, kerneld or
+ * kmod, the kernel module loader
+ */
+static ip2config_t ip2config =
+{
+ {0,0,0,0}, // irqs
+ { // Addresses
+ 0x0000, // Board 0, ttyF0 - ttyF63
+ 0x0000, // Board 1, ttyF64 - ttyF127
+ 0x0000, // Board 2, ttyF128 - ttyF191
+ 0x0000 // Board 3, ttyF192 - ttyF255
+ }
+};
+
+#endif
diff --git a/drivers/char/ip2/ip2ioctl.h b/drivers/char/ip2/ip2ioctl.h
new file mode 100644
index 000000000..aa0a9da85
--- /dev/null
+++ b/drivers/char/ip2/ip2ioctl.h
@@ -0,0 +1,35 @@
+/*******************************************************************************
+*
+* (c) 1998 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Driver constants for configuration and tuning
+*
+* NOTES:
+*
+*******************************************************************************/
+
+#ifndef IP2IOCTL_H
+#define IP2IOCTL_H
+
+//*************
+//* Constants *
+//*************
+
+// High baud rates (if not defined elsewhere.
+#ifndef B153600
+# define B153600 0010005
+#endif
+#ifndef B307200
+# define B307200 0010006
+#endif
+#ifndef B921600
+# define B921600 0010007
+#endif
+
+#endif
diff --git a/drivers/char/ip2/ip2trace.h b/drivers/char/ip2/ip2trace.h
new file mode 100644
index 000000000..020aabb73
--- /dev/null
+++ b/drivers/char/ip2/ip2trace.h
@@ -0,0 +1,43 @@
+
+//
+union ip2breadcrumb
+{
+ struct {
+ unsigned char port, cat, codes, label;
+ } __attribute__ ((packed)) hdr;
+ unsigned long value;
+};
+
+#define ITRC_NO_PORT 0xFF
+#define PORTN (port->port_index)
+#define CHANN (pCh->port_index)
+
+#define ITRC_ERROR '!'
+#define ITRC_INIT 'A'
+#define ITRC_OPEN 'B'
+#define ITRC_CLOSE 'C'
+#define ITRC_DRAIN 'D'
+#define ITRC_IOCTL 'E'
+#define ITRC_FLUSH 'F'
+#define ITRC_STATUS 'G'
+#define ITRC_HANGUP 'H'
+#define ITRC_INTR 'I'
+#define ITRC_SFLOW 'J'
+#define ITRC_SBCMD 'K'
+#define ITRC_SICMD 'L'
+#define ITRC_MODEM 'M'
+#define ITRC_INPUT 'N'
+#define ITRC_OUTPUT 'O'
+#define ITRC_PUTC 'P'
+#define ITRC_QUEUE 'Q'
+#define ITRC_STFLW 'R'
+#define ITRC_SFIFO 'S'
+#define ITRC_VERIFY 'V'
+#define ITRC_WRITE 'W'
+
+#define ITRC_ENTER 0x00
+#define ITRC_RETURN 0xFF
+
+#define ITRC_QUEUE_ROOM 2
+#define ITRC_QUEUE_CMD 6
+
diff --git a/drivers/char/ip2/ip2types.h b/drivers/char/ip2/ip2types.h
new file mode 100644
index 000000000..8d2b37999
--- /dev/null
+++ b/drivers/char/ip2/ip2types.h
@@ -0,0 +1,54 @@
+/*******************************************************************************
+*
+* (c) 1998 by Computone Corporation
+*
+********************************************************************************
+*
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Driver constants and type definitions.
+*
+* NOTES:
+*
+*******************************************************************************/
+#ifndef IP2TYPES_H
+#define IP2TYPES_H
+
+//*************
+//* Constants *
+//*************
+
+// Define some limits for this driver. Ports per board is a hardware limitation
+// that will not change. Current hardware limits this to 64 ports per board.
+// Boards per driver is a self-imposed limit.
+//
+#define IP2_MAX_BOARDS 4
+#define IP2_PORTS_PER_BOARD ABS_MOST_PORTS
+#define IP2_MAX_PORTS (IP2_MAX_BOARDS*IP2_PORTS_PER_BOARD)
+
+#define ISA 0
+#define PCI 1
+#define EISA 2
+
+//********************
+//* Type Definitions *
+//********************
+
+typedef struct tty_struct * PTTY;
+typedef wait_queue_head_t PWAITQ;
+
+typedef unsigned char UCHAR;
+typedef unsigned int UINT;
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+
+typedef struct
+{
+ short irq[IP2_MAX_BOARDS];
+ unsigned short addr[IP2_MAX_BOARDS];
+ int type[IP2_MAX_BOARDS];
+} ip2config_t;
+
+#endif
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
new file mode 100644
index 000000000..8f0ef75ae
--- /dev/null
+++ b/drivers/char/ip2main.c
@@ -0,0 +1,3235 @@
+/*
+*
+* (c) 1999 by Computone Corporation
+*
+********************************************************************************
+*
+* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport
+* serial I/O controllers.
+*
+* DESCRIPTION: Mainline code for the device driver
+*
+*******************************************************************************/
+/************/
+/* Includes */
+/************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/major.h>
+#include <linux/wait.h>
+
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/termios.h>
+#include <linux/tty_driver.h>
+#include <linux/serial.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+
+#include <linux/cdk.h>
+#include <linux/comstats.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <asm/serial.h>
+
+#include <asm/uaccess.h>
+#define pcibios_strerror(status) \
+ printk( KERN_ERR "IP2: PCI error 0x%x \n", status );
+
+#include "./ip2/ip2types.h"
+#include "./ip2/ip2trace.h"
+#include "./ip2/ip2ioctl.h"
+#include "./ip2/ip2.h"
+#include "./ip2/i2ellis.h"
+#include "./ip2/i2lib.h"
+
+/*****************
+ * /proc/ip2mem *
+ *****************/
+
+#include <linux/proc_fs.h>
+
+int ip2_read_procmem(char *, char **, off_t, int, int );
+int ip2_read_proc(char *, char **, off_t, int, int *, void * );
+
+struct proc_dir_entry ip2_proc_entry = {
+ 0,
+ 6,"ip2mem",
+ S_IFREG | S_IRUGO,
+ 1, 0, 0,
+ 0,
+ NULL,
+ ip2_read_procmem
+};
+
+/********************/
+/* Type Definitions */
+/********************/
+
+/*************/
+/* Constants */
+/*************/
+
+/* String constants to identify ourselves */
+static char *pcName = "Computone IntelliPort Plus multiport driver";
+static char *pcVersion = "1.2.4";
+
+/* String constants for port names */
+static char *pcDriver_name = "ip2";
+static char *pcTty = "ttyf";
+static char *pcCallout = "cuf";
+static char *pcIpl = "ip2ipl";
+
+/* Serial subtype definitions */
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+
+// cheezy kludge or genius - you decide?
+int ip2_loadmain(int *, int *, unsigned char *, int);
+static unsigned char *Fip_firmware;
+static int Fip_firmware_size;
+
+/***********************/
+/* Function Prototypes */
+/***********************/
+
+/* Global module entry functions */
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+#endif
+
+int old_ip2_init(void);
+
+/* Private (static) functions */
+static int ip2_open(PTTY, struct file *);
+static void ip2_close(PTTY, struct file *);
+static int ip2_write(PTTY, int, const unsigned char *, int);
+static void ip2_putchar(PTTY, unsigned char);
+static void ip2_flush_chars(PTTY);
+static int ip2_write_room(PTTY);
+static int ip2_chars_in_buf(PTTY);
+static void ip2_flush_buffer(PTTY);
+static int ip2_ioctl(PTTY, struct file *, UINT, ULONG);
+static void ip2_set_termios(PTTY, struct termios *);
+static void ip2_set_line_discipline(PTTY);
+static void ip2_throttle(PTTY);
+static void ip2_unthrottle(PTTY);
+static void ip2_stop(PTTY);
+static void ip2_start(PTTY);
+static void ip2_hangup(PTTY);
+
+static void set_irq(int, int);
+static void ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static void ip2_poll(unsigned long arg);
+static inline void service_all_boards(void);
+static inline void do_input(i2ChanStrPtr pCh);
+static inline void do_status(i2ChanStrPtr pCh);
+
+static void ip2_wait_until_sent(PTTY,int);
+
+static void set_params (i2ChanStrPtr, struct termios *);
+static int get_modem_info(i2ChanStrPtr, unsigned int *);
+static int set_modem_info(i2ChanStrPtr, unsigned int, unsigned int *);
+static int get_serial_info(i2ChanStrPtr, struct serial_struct *);
+static int set_serial_info(i2ChanStrPtr, struct serial_struct *);
+
+static ssize_t ip2_ipl_read(struct file *, char *, size_t, loff_t *) ;
+static ssize_t ip2_ipl_write(struct file *, const char *, size_t, loff_t *);
+static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG);
+static int ip2_ipl_open(struct inode *, struct file *);
+
+void ip2trace(unsigned short,unsigned char,unsigned char,unsigned long,...);
+static int DumpTraceBuffer(char *, int);
+static int DumpFifoBuffer( char *, int);
+
+static void ip2_init_board(int);
+static unsigned short find_eisa_board(int);
+
+/***************/
+/* Static Data */
+/***************/
+
+static struct tty_driver ip2_tty_driver;
+static struct tty_driver ip2_callout_driver;
+
+static int ref_count;
+
+/* Here, then is a table of board pointers which the interrupt routine should
+ * scan through to determine who it must service.
+ */
+static unsigned short i2nBoards = 0; // Number of boards here
+
+static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS];
+
+static i2ChanStrPtr DevTable[IP2_MAX_PORTS];
+//DevTableMem just used to save addresses for kfree
+static void *DevTableMem[IP2_MAX_BOARDS] = {NULL,NULL,NULL,NULL};
+
+static struct tty_struct * TtyTable[IP2_MAX_PORTS];
+static struct termios * Termios[IP2_MAX_PORTS];
+static struct termios * TermiosLocked[IP2_MAX_PORTS];
+
+/* This is the driver descriptor for the ip2ipl device, which is used to
+ * download the loadware to the boards.
+ */
+static struct file_operations
+ip2_ipl = {
+ NULL,
+ ip2_ipl_read,
+ ip2_ipl_write,
+ NULL,
+ NULL,
+ ip2_ipl_ioctl,
+ NULL,
+ ip2_ipl_open,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* NULL, NULL 2.2 */
+};
+
+static long irq_counter = 0;
+static long bh_counter = 0;
+
+// Use immediate queue to service interrupts
+//#define USE_IQI // PCI&2.2 needs work
+//#define USE_IQ // PCI&2.2 needs work
+
+/* The timer_list entry for our poll routine. If interrupt operation is not
+ * selected, the board is serviced periodically to see if anything needs doing.
+ */
+#define POLL_TIMEOUT (jiffies + 1)
+static struct timer_list PollTimer = { NULL, NULL, 0, 0, ip2_poll };
+// next, prev, expires,data, func()
+static char TimerOn = 0;
+
+#ifdef IP2DEBUG_TRACE
+/* Trace (debug) buffer data */
+#define TRACEMAX 1000
+static unsigned long tracebuf[TRACEMAX];
+static int tracestuff = 0;
+static int tracestrip = 0;
+static int tracewrap = 0;
+#endif
+
+/**********/
+/* Macros */
+/**********/
+
+#if defined(MODULE) && defined(IP2DEBUG_OPEN)
+#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
+ kdevname(tty->device),(pCh->flags),ref_count, \
+ tty->count,/*GET_USE_COUNT(module)*/0,s)
+#else
+#define DBG_CNT(s)
+#endif
+
+#define MIN(a,b) ( ( (a) < (b) ) ? (a) : (b) )
+#define MAX(a,b) ( ( (a) > (b) ) ? (a) : (b) )
+
+/********/
+/* Code */
+/********/
+
+#include "./ip2/i2ellis.c" /* Extremely low-level interface services */
+#include "./ip2/i2cmd.c" /* Standard loadware command definitions */
+#include "./ip2/i2lib.c" /* High level interface services */
+
+/* Configuration area for modprobe */
+#ifdef MODULE
+MODULE_AUTHOR("Doug McNash");
+MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+#endif /* MODULE */
+
+static int poll_only = 0;
+
+static int Pci_index = 0;
+static int Eisa_irq = 0;
+static int Eisa_slot = 0;
+
+static int iindx = 0;
+static char rirqs[IP2_MAX_BOARDS] = {0,};
+static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
+
+/******************************************************************************/
+/* Initialisation Section */
+/******************************************************************************/
+int
+ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
+{
+ int i;
+ /* process command line arguments to modprobe or insmod i.e. iop & irqp */
+ /* otherwise ip2config is initialized by what's in ip2/ip2.h */
+ /* command line trumps initialization in ip2.h */
+ /* first two args are null if builtin to kernel */
+ if ((irqp != NULL) || (iop != NULL)) {
+ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if (irqp && irqp[i]) {
+ ip2config.irq[i] = irqp[i];
+ }
+ if (iop && iop[i]) {
+ ip2config.addr[i] = iop[i];
+ }
+ }
+ }
+ Fip_firmware = firmware;
+ Fip_firmware_size = firmsize;
+ return old_ip2_init();
+}
+
+// Some functions to keep track of what irq's we have
+
+static int __init
+is_valid_irq(int irq)
+{
+ int *i = Valid_Irqs;
+
+ while ((*i != 0) && (*i != irq)) {
+ i++;
+ }
+ return (*i);
+}
+
+static void __init
+mark_requested_irq( char irq )
+{
+ rirqs[iindx++] = irq;
+}
+
+static int __init
+clear_requested_irq( char irq )
+{
+ int i;
+ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if (rirqs[i] == irq) {
+ rirqs[i] = 0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int __init
+have_requested_irq( char irq )
+{
+ // array init to zeros so 0 irq will not be requested as a side effect
+ int i;
+ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if (rirqs[i] == irq)
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/* Function: init_module() */
+/* Parameters: None */
+/* Returns: Success (0) */
+/* */
+/* Description: */
+/* This is a required entry point for an installable module. It simply calls */
+/* the driver initialisation function and returns what it returns. */
+/******************************************************************************/
+#ifdef MODULE
+int
+init_module(void)
+{
+#ifdef IP2DEBUG_INIT
+ printk (KERN_DEBUG "Loading module ...\n" );
+#endif
+ //was return old_ip2_init();
+ return 0;
+}
+#endif /* MODULE */
+
+/******************************************************************************/
+/* Function: cleanup_module() */
+/* Parameters: None */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* This is a required entry point for an installable module. It has to return */
+/* the device and the driver to a passive state. It should not be necessary */
+/* to reset the board fully, especially as the loadware is downloaded */
+/* externally rather than in the driver. We just want to disable the board */
+/* and clear the loadware to a reset state. To allow this there has to be a */
+/* way to detect whether the board has the loadware running at init time to */
+/* handle subsequent installations of the driver. All memory allocated by the */
+/* driver should be returned since it may be unloaded from memory. */
+/******************************************************************************/
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+ int err;
+ int i;
+
+#ifdef IP2DEBUG_INIT
+ printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion );
+#endif
+
+
+ /* Stop poll timer if we had one. */
+ if ( TimerOn ) {
+ del_timer ( &PollTimer );
+ TimerOn = 0;
+ }
+
+ /* Reset the boards we have. */
+ for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if ( i2BoardPtrTable[i] ) {
+ iiReset ( i2BoardPtrTable[i] );
+ }
+ }
+
+ /* The following is done at most once, if any boards were installed. */
+ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if ( i2BoardPtrTable[i] ) {
+ iiResetDelay( i2BoardPtrTable[i] );
+ /* free io addresses and Tibet */
+ release_region( ip2config.addr[i], 8 );
+ }
+ /* Disable and remove interrupt handler. */
+ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {
+ free_irq ( ip2config.irq[i], (void *)&pcName);
+ clear_requested_irq( ip2config.irq[i]);
+ }
+ }
+ if ( ( err = tty_unregister_driver ( &ip2_tty_driver ) ) ) {
+ printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
+ }
+ if ( ( err = tty_unregister_driver ( &ip2_callout_driver ) ) ) {
+ printk(KERN_ERR "IP2: failed to unregister callout driver (%d)\n", err);
+ }
+ if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) {
+ printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err);
+ }
+ if ( ( err = proc_unregister( &proc_root, ip2_proc_entry.low_ino ) ) ) {
+ printk(KERN_ERR "IP2: failed to unregister read_procmem (%d)\n", err);
+ }
+
+ // free memory
+ for (i = 0; i < IP2_MAX_BOARDS; i++) {
+ void *pB;
+ if ((pB = i2BoardPtrTable[i]) != 0 ) {
+ kfree ( pB );
+ i2BoardPtrTable[i] = NULL;
+ }
+ if ((DevTableMem[i]) != NULL ) {
+ kfree ( DevTableMem[i] );
+ DevTableMem[i] = NULL;
+ }
+ }
+
+ /* Cleanup the iiEllis subsystem. */
+ iiEllisCleanup();
+#ifdef IP2DEBUG_INIT
+ printk (KERN_DEBUG "IP2 Unloaded\n" );
+#endif
+}
+#endif /* MODULE */
+
+/******************************************************************************/
+/* Function: old_ip2_init() */
+/* Parameters: irq, io from command line of insmod et. al. */
+/* Returns: Success (0) */
+/* */
+/* Description: */
+/* This was the required entry point for all drivers (now in ip2.c) */
+/* It performs all */
+/* initialisation of the devices and driver structures, and registers itself */
+/* with the relevant kernel modules. */
+/******************************************************************************/
+/* SA_INTERRUPT- if set blocks all interrupts else only this line */
+/* SA_SHIRQ - for shared irq PCI or maybe EISA only */
+/* SA_RANDOM - can be source for cert. random number generators */
+#define IP2_SA_FLAGS 0
+
+int __init
+old_ip2_init(void)
+{
+ int i;
+ int err;
+ int status = 0;
+ i2eBordStrPtr pB = NULL;
+ int rc = -1;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
+#endif
+
+ /* Announce our presence */
+ printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
+
+ /* if all irq config is zero we shall poll_only */
+ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ poll_only |= ip2config.irq[i];
+ }
+ poll_only = !poll_only;
+
+ /* Initialise the iiEllis subsystem. */
+ iiEllisInit();
+
+ /* Initialize arrays. */
+ memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable );
+ memset( DevTable, 0, sizeof DevTable );
+ memset( TtyTable, 0, sizeof TtyTable );
+ memset( Termios, 0, sizeof Termios );
+ memset( TermiosLocked, 0, sizeof TermiosLocked );
+
+ /* Initialise all the boards we can find (up to the maximum). */
+ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ switch ( ip2config.addr[i] ) {
+ case 0: /* skip this slot even if card is present */
+ break;
+ default: /* ISA */
+ /* ISA address must be specified */
+ if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) {
+ printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n",
+ i, ip2config.addr[i] );
+ ip2config.addr[i] = 0;
+ } else {
+ ip2config.type[i] = ISA;
+
+ /* Check for valid irq argument, set for polling if invalid */
+ if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) {
+ printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]);
+ ip2config.irq[i] = 0;// 0 is polling and is valid in that sense
+ }
+ }
+ break;
+ case PCI:
+#ifdef CONFIG_PCI
+ if (pci_present()) {
+ struct pci_dev *pci_dev_i = NULL;
+ pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE,
+ PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
+ if (pci_dev_i != NULL) {
+ unsigned int addr;
+ unsigned char pci_irq;
+
+ ip2config.type[i] = PCI;
+ /*
+ * Update Pci_index, so that the next time we go
+ * searching for a PCI board we find a different
+ * one.
+ */
+ ++Pci_index;
+ status =
+ pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
+ if ( addr & 1 ) {
+ ip2config.addr[i]=(USHORT)(addr&0xfffe);
+ } else {
+ printk( KERN_ERR "IP2: PCI I/O address error\n");
+ }
+ status =
+ pci_read_config_byte(pci_dev_i, PCI_INTERRUPT_LINE, &pci_irq);
+
+ if (!is_valid_irq(pci_irq)) {
+ printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
+ pci_irq = 0;
+ }
+ ip2config.irq[i] = pci_irq;
+ } else { // ann error
+ ip2config.addr[i] = 0;
+ if (status == PCIBIOS_DEVICE_NOT_FOUND) {
+ printk( KERN_ERR "IP2: PCI board %d not found\n", i );
+ } else {
+ pcibios_strerror(status);
+ }
+ }
+ }
+#else
+ printk( KERN_ERR "IP2: PCI card specified but PCI support not\n");
+ printk( KERN_ERR "IP2: configured in this kernel.\n");
+ printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n");
+#endif /* CONFIG_PCI */
+ break;
+ case EISA:
+ if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) {
+ /* Eisa_irq set as side effect, boo */
+ ip2config.type[i] = EISA;
+ }
+ ip2config.irq[i] = Eisa_irq;
+ break;
+ } /* switch */
+ } /* for */
+ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if ( ip2config.addr[i] ) {
+ pB = kmalloc( sizeof(i2eBordStr), GFP_KERNEL);
+ if ( pB != NULL ) {
+ i2BoardPtrTable[i] = pB;
+ memset( pB, 0, sizeof(i2eBordStr) );
+ iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer );
+ iiReset( pB );
+ } else {
+ printk(KERN_ERR "IP2: board memory allocation error\n");
+ }
+ }
+ }
+ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if ( ( pB = i2BoardPtrTable[i] ) != NULL ) {
+ iiResetDelay( pB );
+ break;
+ }
+ }
+ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if ( i2BoardPtrTable[i] != NULL ) {
+ ip2_init_board( i );
+ }
+ }
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 );
+#endif
+
+ /* Zero out the normal tty device structure. */
+ memset ( &ip2_tty_driver, 0, sizeof ip2_tty_driver );
+
+ /* Initialise the relevant fields. */
+ ip2_tty_driver.magic = TTY_DRIVER_MAGIC;
+ ip2_tty_driver.name = pcTty;
+ ip2_tty_driver.driver_name = pcDriver_name;
+ ip2_tty_driver.read_proc = ip2_read_proc;
+ ip2_tty_driver.major = IP2_TTY_MAJOR;
+ ip2_tty_driver.minor_start = 0;
+ ip2_tty_driver.num = IP2_MAX_PORTS;
+ ip2_tty_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ ip2_tty_driver.subtype = SERIAL_TYPE_NORMAL;
+ ip2_tty_driver.init_termios = tty_std_termios;
+ ip2_tty_driver.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
+ ip2_tty_driver.flags = TTY_DRIVER_REAL_RAW;
+ ip2_tty_driver.refcount = &ref_count;
+ ip2_tty_driver.table = TtyTable;
+ ip2_tty_driver.termios = Termios;
+ ip2_tty_driver.termios_locked = TermiosLocked;
+
+ /* Setup the pointers to the implemented functions. */
+ ip2_tty_driver.open = ip2_open;
+ ip2_tty_driver.close = ip2_close;
+ ip2_tty_driver.write = ip2_write;
+ ip2_tty_driver.put_char = ip2_putchar;
+ ip2_tty_driver.flush_chars = ip2_flush_chars;
+ ip2_tty_driver.write_room = ip2_write_room;
+ ip2_tty_driver.chars_in_buffer = ip2_chars_in_buf;
+ ip2_tty_driver.flush_buffer = ip2_flush_buffer;
+ ip2_tty_driver.ioctl = ip2_ioctl;
+ ip2_tty_driver.throttle = ip2_throttle;
+ ip2_tty_driver.unthrottle = ip2_unthrottle;
+ ip2_tty_driver.set_termios = ip2_set_termios;
+ ip2_tty_driver.set_ldisc = ip2_set_line_discipline;
+ ip2_tty_driver.stop = ip2_stop;
+ ip2_tty_driver.start = ip2_start;
+ ip2_tty_driver.hangup = ip2_hangup;
+
+ /* Initialise the callout driver structure from the tty driver, and
+ * make the needed adjustments.
+ */
+ ip2_callout_driver = ip2_tty_driver;
+ ip2_callout_driver.name = pcCallout;
+ ip2_callout_driver.driver_name = pcDriver_name;
+ ip2_callout_driver.read_proc = NULL;
+ ip2_callout_driver.major = IP2_CALLOUT_MAJOR;
+ ip2_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
+#endif
+
+ /* Register the tty devices. */
+ if ( ( err = tty_register_driver ( &ip2_tty_driver ) ) ) {
+ printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err);
+ } else
+ if ( ( err = tty_register_driver ( &ip2_callout_driver ) ) ) {
+ printk(KERN_ERR "IP2: failed to register callout driver (%d)\n", err);
+ } else
+ /* Register the IPL driver. */
+ if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
+ printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
+ } else
+ /* Register the read_procmem thing */
+ if ( ( err = proc_register( &proc_root, &ip2_proc_entry ) ) ) {
+ printk(KERN_ERR "IP2: failed to register read_procmem (%d)\n", err );
+ } else {
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 );
+#endif
+ /* Register the interrupt handler or poll handler, depending upon the
+ * specified interrupt.
+ */
+ for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if ( 0 == ip2config.addr[i] ) {
+ continue;
+ }
+ if (poll_only) {
+ ip2config.irq[i] = CIR_POLL;
+ }
+ if ( ip2config.irq[i] == CIR_POLL ) {
+retry:
+ if (!TimerOn) {
+ PollTimer.expires = POLL_TIMEOUT;
+ add_timer ( &PollTimer );
+ TimerOn = 1;
+ printk( KERN_INFO "IP2: polling\n");
+ }
+ } else {
+ if (have_requested_irq(ip2config.irq[i]))
+ continue;
+ rc = request_irq( ip2config.irq[i], ip2_interrupt,
+ IP2_SA_FLAGS | (ip2config.type[i] == PCI ? SA_SHIRQ : 0),
+ pcName, (void *)&pcName);
+ if (rc) {
+ printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc);
+ ip2config.irq[i] = CIR_POLL;
+ printk( KERN_INFO "IP2: Polling %ld/sec.\n",
+ (POLL_TIMEOUT - jiffies));
+ goto retry;
+ }
+ mark_requested_irq(ip2config.irq[i]);
+ /* Initialise the interrupt handler bottom half (aka slih). */
+ }
+ }
+ for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ if ( i2BoardPtrTable[i] ) {
+ set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
+ }
+ }
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
+#endif
+
+ return 0;
+}
+
+/******************************************************************************/
+/* Function: ip2_init_board() */
+/* Parameters: Index of board in configuration structure */
+/* Returns: Success (0) */
+/* */
+/* Description: */
+/* This function initializes the specified board. The loadware is copied to */
+/* the board, the channel structures are initialized, and the board details */
+/* are reported on the console. */
+/******************************************************************************/
+static void __init
+ip2_init_board( int boardnum )
+{
+ int i,rc;
+ int nports = 0, nboxes = 0;
+ i2ChanStrPtr pCh;
+ i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
+
+ if ( !iiInitialize ( pB ) ) {
+ printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
+ pB->i2eBase, pB->i2eError );
+ kfree ( pB );
+ i2BoardPtrTable[boardnum] = NULL;
+ return;
+ }
+ printk(KERN_INFO "Board %d: addr=0x%x irq=%d ", boardnum + 1,
+ ip2config.addr[boardnum], ip2config.irq[boardnum] );
+
+ if (0 != ( rc = check_region( ip2config.addr[boardnum], 8))) {
+ i2BoardPtrTable[boardnum] = NULL;
+ printk(KERN_ERR "bad addr=0x%x rc = %d\n",
+ ip2config.addr[boardnum], rc );
+ return;
+ }
+ request_region( ip2config.addr[boardnum], 8, pcName );
+
+ if ( iiDownloadAll ( pB, (loadHdrStrPtr)Fip_firmware, 1, Fip_firmware_size )
+ != II_DOWN_GOOD ) {
+ printk ( KERN_ERR "IP2:failed to download loadware " );
+ } else {
+ printk ( KERN_INFO "fv=%d.%d.%d lv=%d.%d.%d\n",
+ pB->i2ePom.e.porVersion,
+ pB->i2ePom.e.porRevision,
+ pB->i2ePom.e.porSubRev, pB->i2eLVersion,
+ pB->i2eLRevision, pB->i2eLSub );
+ }
+
+ switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
+
+ default:
+ printk( KERN_ERR "IP2: Unknown board type, ID = %x",
+ pB->i2ePom.e.porID );
+ nports = 0;
+ goto ex_exit;
+ break;
+
+ case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
+ printk ( KERN_INFO "ISA-4" );
+ nports = 4;
+ break;
+
+ case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
+ printk ( KERN_INFO "ISA-8 std" );
+ nports = 8;
+ break;
+
+ case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
+ printk ( KERN_INFO "ISA-8 RJ11" );
+ nports = 8;
+ break;
+
+ case POR_ID_FIIEX: /* IntelliPort IIEX */
+ {
+ int portnum = IP2_PORTS_PER_BOARD * boardnum;
+ int box;
+
+ for( box = 0; box < ABS_MAX_BOXES; ++box ) {
+ if ( pB->i2eChannelMap[box] != 0 ) {
+ ++nboxes;
+ }
+ for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
+ if ( pB->i2eChannelMap[box] & 1<< i ) {
+ ++nports;
+ }
+ }
+ }
+ DevTableMem[boardnum] = pCh =
+ kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
+ if ( !i2InitChannels( pB, nports, pCh ) ) {
+ printk(KERN_ERR "i2InitChannels failed: %d\n",pB->i2eError);
+ }
+ pB->i2eChannelPtr = &DevTable[portnum];
+ pB->i2eChannelCnt = ABS_MOST_PORTS;
+
+ for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) {
+ for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
+ if ( pB->i2eChannelMap[box] & (1 << i) ) {
+ DevTable[portnum + i] = pCh;
+ pCh->port_index = portnum + i;
+ pCh++;
+ }
+ }
+ }
+ printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit",
+ nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
+ }
+ goto ex_exit;
+ break;
+ }
+ DevTableMem[boardnum] = pCh =
+ kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
+ pB->i2eChannelPtr = pCh;
+ pB->i2eChannelCnt = nports;
+ i2InitChannels ( pB, pB->i2eChannelCnt, pCh );
+ pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
+
+ for( i = 0; i < pB->i2eChannelCnt; ++i ) {
+ DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh;
+ pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i;
+ pCh++;
+ }
+ex_exit:
+ printk ( KERN_INFO "\n" );
+}
+
+/******************************************************************************/
+/* Function: find_eisa_board ( int start_slot ) */
+/* Parameters: First slot to check */
+/* Returns: Address of EISA IntelliPort II controller */
+/* */
+/* Description: */
+/* This function searches for an EISA IntelliPort controller, starting */
+/* from the specified slot number. If the motherboard is not identified as an */
+/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
+/* it returns the base address of the controller. */
+/******************************************************************************/
+static unsigned short __init
+find_eisa_board( int start_slot )
+{
+ int i, j;
+ unsigned int idm = 0;
+ unsigned int idp = 0;
+ unsigned int base = 0;
+ unsigned int value;
+ int setup_address;
+ int setup_irq;
+ int ismine = 0;
+
+ /*
+ * First a check for an EISA motherboard, which we do by comparing the
+ * EISA ID registers for the system board and the first couple of slots.
+ * No slot ID should match the system board ID, but on an ISA or PCI
+ * machine the odds are that an empty bus will return similar values for
+ * each slot.
+ */
+ i = 0x0c80;
+ value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3);
+ for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) {
+ j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3);
+ if ( value == j )
+ return 0;
+ }
+
+ /*
+ * OK, so we are inclined to believe that this is an EISA machine. Find
+ * an IntelliPort controller.
+ */
+ for( i = start_slot; i < 16; i++ ) {
+ base = i << 12;
+ idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff);
+ idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff);
+ ismine = 0;
+ if ( idm == 0x0e8e ) {
+ if ( idp == 0x0281 || idp == 0x0218 ) {
+ ismine = 1;
+ } else if ( idp == 0x0282 || idp == 0x0283 ) {
+ ismine = 3; /* Can do edge-trigger */
+ }
+ if ( ismine ) {
+ Eisa_slot = i;
+ break;
+ }
+ }
+ }
+ if ( !ismine )
+ return 0;
+
+ /* It's some sort of EISA card, but at what address is it configured? */
+
+ setup_address = base + 0xc88;
+ value = inb(base + 0xc86);
+ setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0;
+
+ if ( (ismine & 2) && !(value & 0x10) ) {
+ ismine = 1; /* Could be edging, but not */
+ }
+
+ if ( Eisa_irq == 0 ) {
+ Eisa_irq = setup_irq;
+ } else if ( Eisa_irq != setup_irq ) {
+ printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" );
+ }
+
+#ifdef IP2DEBUG_INIT
+printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x",
+ base >> 12, idm, idp, setup_address);
+ if ( Eisa_irq ) {
+ printk(KERN_DEBUG ", Interrupt %d %s\n",
+ setup_irq, (ismine & 2) ? "(edge)" : "(level)");
+ } else {
+ printk(KERN_DEBUG ", (polled)\n");
+ }
+#endif
+ return setup_address;
+}
+
+/******************************************************************************/
+/* Function: set_irq() */
+/* Parameters: index to board in board table */
+/* IRQ to use */
+/* Returns: Success (0) */
+/* */
+/* Description: */
+/******************************************************************************/
+static void
+set_irq( int boardnum, int boardIrq )
+{
+ i2ChanStrPtr pCh;
+ unsigned char tempCommand[16];
+ i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
+ unsigned long flags;
+
+ /*
+ * Notify the boards they may generate interrupts. This is done by
+ * sending an in-line command to channel 0 on each board. This is why
+ * the channels have to be defined already. For each board, if the
+ * interrupt has never been defined, we must do so NOW, directly, since
+ * board will not send flow control or even give an interrupt until this
+ * is done. If polling we must send 0 as the interrupt parameter.
+ */
+
+ pCh = (i2ChanStrPtr) pB->i2eChannelPtr;
+
+ // We will get an interrupt here at the end of this function
+
+ iiDisableMailIrq(pB);
+
+ /* We build up the entire packet header. */
+ CHANNEL_OF(tempCommand) = 0;
+ PTYPE_OF(tempCommand) = PTYPE_INLINE;
+ CMD_COUNT_OF(tempCommand) = 2;
+ (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ;
+ (CMD_OF(tempCommand))[1] = boardIrq;
+ /*
+ * Write to FIFO; don't bother to adjust fifo capacity for this, since
+ * board will respond almost immediately after SendMail hit.
+ */
+ WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ iiWriteBuf(pB, tempCommand, 4);
+ WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ pB->i2eUsingIrq = boardIrq;
+ pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
+
+ /* Need to update number of boards before you enable mailbox int */
+ ++i2nBoards;
+
+ CHANNEL_OF(tempCommand) = 0;
+ PTYPE_OF(tempCommand) = PTYPE_BYPASS;
+ CMD_COUNT_OF(tempCommand) = 6;
+ (CMD_OF(tempCommand))[0] = 88; // SILO
+ (CMD_OF(tempCommand))[1] = 64; // chars
+ (CMD_OF(tempCommand))[2] = 32; // ms
+
+ (CMD_OF(tempCommand))[3] = 28; // MAX_BLOCK
+ (CMD_OF(tempCommand))[4] = 64; // chars
+
+ (CMD_OF(tempCommand))[5] = 87; // HW_TEST
+ WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ iiWriteBuf(pB, tempCommand, 8);
+ WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+
+ CHANNEL_OF(tempCommand) = 0;
+ PTYPE_OF(tempCommand) = PTYPE_BYPASS;
+ CMD_COUNT_OF(tempCommand) = 1;
+ (CMD_OF(tempCommand))[0] = 84; /* get BOX_IDS */
+ iiWriteBuf(pB, tempCommand, 3);
+
+#ifdef XXX
+ // enable heartbeat for test porpoises
+ CHANNEL_OF(tempCommand) = 0;
+ PTYPE_OF(tempCommand) = PTYPE_BYPASS;
+ CMD_COUNT_OF(tempCommand) = 2;
+ (CMD_OF(tempCommand))[0] = 44; /* get ping */
+ (CMD_OF(tempCommand))[1] = 200; /* 200 ms */
+ WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ iiWriteBuf(pB, tempCommand, 4);
+ WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+#endif
+
+ iiEnableMailIrq(pB);
+ iiSendPendingMail(pB);
+}
+
+/******************************************************************************/
+/* Interrupt Handler Section */
+/******************************************************************************/
+
+static inline void
+service_all_boards()
+{
+ int i;
+ i2eBordStrPtr pB;
+
+ /* Service every board on the list */
+ for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ pB = i2BoardPtrTable[i];
+ if ( pB ) {
+ i2ServiceBoard( pB );
+ }
+ }
+}
+
+
+#ifdef USE_IQI
+static struct tq_struct
+senior_service =
+{ // it's the death that worse than fate
+ NULL,
+ 0,
+ (void(*)(void*)) service_all_boards,
+ NULL, //later - board address XXX
+};
+#endif
+
+/******************************************************************************/
+/* Function: ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs) */
+/* Parameters: irq - interrupt number */
+/* pointer to optional device ID structure */
+/* pointer to register structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static void
+ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ int i;
+ i2eBordStrPtr pB;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
+#endif
+
+#ifdef USE_IQI
+
+ queue_task(&senior_service, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+#else
+ /* Service just the boards on the list using this irq */
+ for( i = 0; i < i2nBoards; ++i ) {
+ pB = i2BoardPtrTable[i];
+ if ( pB && (pB->i2eUsingIrq == irq) ) {
+ i2ServiceBoard( pB );
+ }
+ }
+
+#endif /* USE_IQI */
+
+ ++irq_counter;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
+#endif
+}
+
+/******************************************************************************/
+/* Function: ip2_poll(unsigned long arg) */
+/* Parameters: ? */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* This function calls the library routine i2ServiceBoard for each board in */
+/* the board table. This is used instead of the interrupt routine when polled */
+/* mode is specified. */
+/******************************************************************************/
+static void
+ip2_poll(unsigned long arg)
+{
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
+#endif
+ TimerOn = 0; // it's the truth but not checked in service
+
+ bh_counter++;
+
+#ifdef USE_IQI
+
+ queue_task(&senior_service, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+#else
+ // Just polled boards, service_all might be better
+ ip2_interrupt(0, NULL, NULL);
+
+#endif /* USE_IQI */
+
+ PollTimer.expires = POLL_TIMEOUT;
+ add_timer( &PollTimer );
+ TimerOn = 1;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
+#endif
+}
+
+static inline void
+do_input( i2ChanStrPtr pCh )
+{
+ unsigned long flags;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace(PORTN, ITRC_INPUT, 21, 0 );
+#endif
+ // Data input
+ if ( pCh->pTTY != NULL ) {
+ READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
+ if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
+ READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ i2Input( pCh );
+ } else
+ READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ } else {
+#ifdef IP2DEBUG_TRACE
+ ip2trace(PORTN, ITRC_INPUT, 22, 0 );
+#endif
+ i2InputFlush( pCh );
+ }
+}
+
+// code duplicated from n_tty (ldisc)
+static inline void
+isig(int sig, struct tty_struct *tty, int flush)
+{
+ if (tty->pgrp > 0)
+ kill_pg(tty->pgrp, sig, 1);
+ if (flush || !L_NOFLSH(tty)) {
+ if ( tty->ldisc.flush_buffer )
+ tty->ldisc.flush_buffer(tty);
+ i2InputFlush( tty->driver_data );
+ }
+}
+
+static inline void
+do_status( i2ChanStrPtr pCh )
+{
+ int status;
+
+ status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_STATUS, 21, 1, status );
+#endif
+
+ if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
+ if ( (status & I2_BRK) ) {
+ // code duplicated from n_tty (ldisc)
+ if (I_IGNBRK(pCh->pTTY))
+ goto skip_this;
+ if (I_BRKINT(pCh->pTTY)) {
+ isig(SIGINT, pCh->pTTY, 1);
+ goto skip_this;
+ }
+ wake_up_interruptible(&pCh->pTTY->read_wait);
+ }
+#ifdef NEVER_HAPPENS_AS_SETUP_XXX
+ // and can't work because we don't know the_char
+ // as the_char is reported on a seperate path
+ // The intelligent board does this stuff as setup
+ {
+ char brkf = TTY_NORMAL;
+ unsigned char brkc = '\0';
+ unsigned char tmp;
+ if ( (status & I2_BRK) ) {
+ brkf = TTY_BREAK;
+ brkc = '\0';
+ }
+ else if (status & I2_PAR) {
+ brkf = TTY_PARITY;
+ brkc = the_char;
+ } else if (status & I2_FRA) {
+ brkf = TTY_FRAME;
+ brkc = the_char;
+ } else if (status & I2_OVR) {
+ brkf = TTY_OVERRUN;
+ brkc = the_char;
+ }
+ tmp = pCh->pTTY->real_raw;
+ pCh->pTTY->real_raw = 0;
+ pCh->pTTY->ldisc.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
+ pCh->pTTY->real_raw = tmp;
+ }
+#endif /* NEVER_HAPPENS_AS_SETUP_XXX */
+ }
+skip_this:
+
+ if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) {
+ wake_up_interruptible(&pCh->delta_msr_wait);
+
+ if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) {
+ if ( status & I2_DCD ) {
+ if ( pCh->wopen ) {
+ wake_up_interruptible ( &pCh->open_wait );
+ }
+ } else if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) ) {
+ if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
+ tty_hangup( pCh->pTTY );
+ }
+ }
+ }
+ }
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_STATUS, 26, 0 );
+#endif
+}
+
+/******************************************************************************/
+/* Device Open/Close/Ioctl Entry Point Section */
+/******************************************************************************/
+
+/******************************************************************************/
+/* Function: open_sanity_check() */
+/* Parameters: Pointer to tty structure */
+/* Pointer to file structure */
+/* Returns: Success or failure */
+/* */
+/* Description: */
+/* Verifies the structure magic numbers and cross links. */
+/******************************************************************************/
+#ifdef IP2DEBUG_OPEN
+static void
+open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
+{
+ if ( pBrd->i2eValid != I2E_MAGIC ) {
+ printk(KERN_ERR "IP2: invalid board structure\n" );
+ } else if ( pBrd != pCh->pMyBord ) {
+ printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n",
+ pCh->pMyBord );
+ } else if ( pBrd->i2eChannelCnt < pCh->port_index ) {
+ printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index );
+ } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) {
+ } else {
+ printk(KERN_INFO "IP2: all pointers check out!\n" );
+ }
+}
+#endif
+
+
+/******************************************************************************/
+/* Function: ip2_open() */
+/* Parameters: Pointer to tty structure */
+/* Pointer to file structure */
+/* Returns: Success or failure */
+/* */
+/* Description: (MANDATORY) */
+/* A successful device open has to run a gauntlet of checks before it */
+/* completes. After some sanity checking and pointer setup, the function */
+/* blocks until all conditions are satisfied. It then initialises the port to */
+/* the default characteristics and returns. */
+/******************************************************************************/
+static int
+ip2_open( PTTY tty, struct file *pFile )
+{
+ int rc = 0;
+ int do_clocal = 0;
+ i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (MINOR(tty->device), ITRC_OPEN, ITRC_ENTER, 0 );
+#endif
+
+ if ( pCh == NULL ) {
+ return -ENODEV;
+ }
+ /* Setup pointer links in device and tty structures */
+ pCh->pTTY = tty;
+ tty->driver_data = pCh;
+ MOD_INC_USE_COUNT;
+
+#ifdef IP2DEBUG_OPEN
+ printk(KERN_DEBUG \
+ "IP2:open(tty=%p,pFile=%p):dev=%x,maj=%d,min=%d,ch=%d,idx=%d\n",
+ tty, pFile, tty->device, MAJOR(tty->device), MINOR(tty->device),
+ pCh->infl.hd.i2sChannel, pCh->port_index);
+ open_sanity_check ( pCh, pCh->pMyBord );
+#endif
+
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
+ pCh->dataSetOut |= (I2_DTR | I2_RTS);
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 3,
+ CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
+ serviceOutgoingFifo( pCh->pMyBord );
+
+ /* Block here until the port is ready (per serial and istallion) */
+ /*
+ * 1. If the port is in the middle of closing wait for the completion
+ * and then return the appropriate error.
+ */
+ if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
+ if ( pCh->flags & ASYNC_CLOSING ) {
+ interruptible_sleep_on( &pCh->close_wait);
+ }
+ if ( tty_hung_up_p(pFile) ) {
+ return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
+ }
+ }
+ /*
+ * 2. If this is a callout device, make sure the normal port is not in
+ * use, and that someone else doesn't have the callout device locked.
+ * (These are the only tests the standard serial driver makes for
+ * callout devices.)
+ */
+ if ( tty->driver.subtype == SERIAL_TYPE_CALLOUT ) {
+ if ( pCh->flags & ASYNC_NORMAL_ACTIVE ) {
+ return -EBUSY;
+ }
+ if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) &&
+ ( pCh->flags & ASYNC_SESSION_LOCKOUT ) &&
+ ( pCh->session != current->session ) ) {
+ return -EBUSY;
+ }
+ if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) &&
+ ( pCh->flags & ASYNC_PGRP_LOCKOUT ) &&
+ ( pCh->pgrp != current->pgrp ) ) {
+ return -EBUSY;
+ }
+ pCh->flags |= ASYNC_CALLOUT_ACTIVE;
+ goto noblock;
+ }
+ /*
+ * 3. Handle a non-blocking open of a normal port.
+ */
+ if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
+ if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) {
+ return -EBUSY;
+ }
+ pCh->flags |= ASYNC_NORMAL_ACTIVE;
+ goto noblock;
+ }
+ /*
+ * 4. Now loop waiting for the port to be free and carrier present
+ * (if required).
+ */
+ if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) {
+ if ( pCh->NormalTermios.c_cflag & CLOCAL ) {
+ do_clocal = 1;
+ }
+ } else {
+ if ( tty->termios->c_cflag & CLOCAL ) {
+ do_clocal = 1;
+ }
+ }
+
+#ifdef IP2DEBUG_OPEN
+ printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
+#endif
+
+ ++pCh->wopen;
+ for(;;) {
+ if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE)) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
+ pCh->dataSetOut |= (I2_DTR | I2_RTS);
+ serviceOutgoingFifo( pCh->pMyBord );
+ }
+ if ( tty_hung_up_p(pFile) ) {
+ return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
+ }
+ if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) &&
+ !(pCh->flags & ASYNC_CLOSING) &&
+ (do_clocal || (pCh->dataSetIn & I2_DCD) )) {
+ rc = 0;
+ break;
+ }
+
+#ifdef IP2DEBUG_OPEN
+ printk(KERN_DEBUG "ASYNC_CALLOUT_ACTIVE = %s\n",
+ (pCh->flags & ASYNC_CALLOUT_ACTIVE)?"True":"False");
+ printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
+ (pCh->flags & ASYNC_CLOSING)?"True":"False");
+ printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
+#endif
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE),
+ (pCh->flags & ASYNC_CLOSING) );
+#endif
+ /* check for signal */
+ if (signal_pending(current)) {
+ rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
+ break;
+ }
+ interruptible_sleep_on(&pCh->open_wait);
+ }
+ --pCh->wopen; //why count?
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_OPEN, 4, 0 );
+#endif
+ if (rc != 0 ) {
+ return rc;
+ }
+ pCh->flags |= ASYNC_NORMAL_ACTIVE;
+
+noblock:
+
+ /* first open - Assign termios structure to port */
+ if ( tty->count == 1 ) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
+ if ( pCh->flags & ASYNC_SPLIT_TERMIOS ) {
+ if ( tty->driver.subtype == SERIAL_TYPE_NORMAL ) {
+ *tty->termios = pCh->NormalTermios;
+ } else {
+ *tty->termios = pCh->CalloutTermios;
+ }
+ }
+ /* Now we must send the termios settings to the loadware */
+ set_params( pCh, NULL );
+ }
+
+ /* override previous and never reset ??? */
+ pCh->session = current->session;
+ pCh->pgrp = current->pgrp;
+
+ /*
+ * Now set any i2lib options. These may go away if the i2lib code ends
+ * up rolled into the mainline.
+ */
+ pCh->channelOptions |= CO_NBLOCK_WRITE;
+
+#ifdef IP2DEBUG_OPEN
+ printk (KERN_DEBUG "IP2: open completed\n" );
+#endif
+ serviceOutgoingFifo( pCh->pMyBord );
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_OPEN, ITRC_RETURN, 0 );
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+/* Function: ip2_close() */
+/* Parameters: Pointer to tty structure */
+/* Pointer to file structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static void
+ip2_close( PTTY tty, struct file *pFile )
+{
+ i2ChanStrPtr pCh = tty->driver_data;
+
+ if ( !pCh ) {
+ return;
+ }
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_CLOSE, ITRC_ENTER, 0 );
+#endif
+
+#ifdef IP2DEBUG_OPEN
+ printk(KERN_DEBUG "IP2:close ttyF%02X:\n",MINOR(tty->device));
+#endif
+
+ if ( tty_hung_up_p ( pFile ) ) {
+ MOD_DEC_USE_COUNT;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_CLOSE, 2, 1, 2 );
+#endif
+ return;
+ }
+ if ( tty->count > 1 ) { /* not the last close */
+ MOD_DEC_USE_COUNT;
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_CLOSE, 2, 1, 3 );
+#endif
+ return;
+ }
+ pCh->flags |= ASYNC_CLOSING; // last close actually
+
+ /*
+ * Save the termios structure, since this port may have separate termios
+ * for callout and dialin.
+ */
+ if (pCh->flags & ASYNC_NORMAL_ACTIVE)
+ pCh->NormalTermios = *tty->termios;
+ if (pCh->flags & ASYNC_CALLOUT_ACTIVE)
+ pCh->CalloutTermios = *tty->termios;
+
+ tty->closing = 1;
+
+ if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) {
+ /*
+ * Before we drop DTR, make sure the transmitter has completely drained.
+ * This uses an timeout, after which the close
+ * completes.
+ */
+ ip2_wait_until_sent(tty, pCh->ClosingWaitTime );
+ }
+ /*
+ * At this point we stop accepting input. Here we flush the channel
+ * input buffer which will allow the board to send up more data. Any
+ * additional input is tossed at interrupt/poll time.
+ */
+ i2InputFlush( pCh );
+
+ /* disable DSS reporting */
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
+ if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
+ pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
+ i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
+ }
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 3,
+ CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
+
+ serviceOutgoingFifo ( pCh->pMyBord );
+
+ if ( tty->driver.flush_buffer )
+ tty->driver.flush_buffer(tty);
+ if ( tty->ldisc.flush_buffer )
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+
+ pCh->pTTY = NULL;
+
+ if (pCh->wopen) {
+ if (pCh->ClosingDelay) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(pCh->ClosingDelay);
+ }
+ wake_up_interruptible(&pCh->open_wait);
+ }
+
+ pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
+ wake_up_interruptible(&pCh->close_wait);
+
+#ifdef IP2DEBUG_OPEN
+ DBG_CNT("ip2_close: after wakeups--");
+#endif
+
+ MOD_DEC_USE_COUNT;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
+#endif
+ return;
+}
+
+/******************************************************************************/
+/* Function: ip2_hangup() */
+/* Parameters: Pointer to tty structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static void
+ip2_hangup ( PTTY tty )
+{
+ i2ChanStrPtr pCh = tty->driver_data;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_HANGUP, ITRC_ENTER, 0 );
+#endif
+
+ ip2_flush_buffer(tty);
+
+ /* disable DSS reporting */
+
+ i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
+ i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
+ if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
+ i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
+ pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
+ i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
+ }
+ i2QueueCommands(PTYPE_INLINE, pCh, 1, 3,
+ CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
+ serviceOutgoingFifo ( pCh->pMyBord );
+
+ wake_up_interruptible ( &pCh->delta_msr_wait );
+
+ pCh->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+ pCh->pTTY = NULL;
+ wake_up_interruptible ( &pCh->open_wait );
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_HANGUP, ITRC_RETURN, 0 );
+#endif
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/* Device Output Section */
+/******************************************************************************/
+/******************************************************************************/
+
+/******************************************************************************/
+/* Function: ip2_write() */
+/* Parameters: Pointer to tty structure */
+/* Flag denoting data is in user (1) or kernel (0) space */
+/* Pointer to data */
+/* Number of bytes to write */
+/* Returns: Number of bytes actually written */
+/* */
+/* Description: (MANDATORY) */
+/* */
+/* */
+/******************************************************************************/
+static int
+ip2_write( PTTY tty, int user, const unsigned char *pData, int count)
+{
+ i2ChanStrPtr pCh = tty->driver_data;
+ int bytesSent = 0;
+ unsigned long flags;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
+#endif
+
+ /* Flush out any buffered data left over from ip2_putchar() calls. */
+ ip2_flush_chars( tty );
+
+ /* This is the actual move bit. Make sure it does what we need!!!!! */
+ WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ bytesSent = i2Output( pCh, pData, count, user );
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
+#endif
+ return bytesSent > 0 ? bytesSent : 0;
+}
+
+/******************************************************************************/
+/* Function: ip2_putchar() */
+/* Parameters: Pointer to tty structure */
+/* Character to write */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static void
+ip2_putchar( PTTY tty, unsigned char ch )
+{
+ i2ChanStrPtr pCh = tty->driver_data;
+ unsigned long flags;
+
+#ifdef IP2DEBUG_TRACE
+// ip2trace (PORTN, ITRC_PUTC, ITRC_ENTER, 1, ch );
+#endif
+
+ WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
+ if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ ip2_flush_chars( tty );
+ } else
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+
+#ifdef IP2DEBUG_TRACE
+// ip2trace (PORTN, ITRC_PUTC, ITRC_RETURN, 1, ch );
+#endif
+}
+
+/******************************************************************************/
+/* Function: ip2_flush_chars() */
+/* Parameters: Pointer to tty structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* */
+/******************************************************************************/
+static void
+ip2_flush_chars( PTTY tty )
+{
+ int strip;
+ i2ChanStrPtr pCh = tty->driver_data;
+ unsigned long flags;
+
+ WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ if ( pCh->Pbuf_stuff ) {
+#ifdef IP2DEBUG_TRACE
+// ip2trace (PORTN, ITRC_PUTC, 10, 1, strip );
+#endif
+ //
+ // We may need to restart i2Output if it does not fullfill this request
+ //
+ strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff, 0 );
+ if ( strip != pCh->Pbuf_stuff ) {
+ memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
+ }
+ pCh->Pbuf_stuff -= strip;
+ }
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+}
+
+/******************************************************************************/
+/* Function: ip2_write_room() */
+/* Parameters: Pointer to tty structure */
+/* Returns: Number of bytes that the driver can accept */
+/* */
+/* Description: */
+/* */
+/******************************************************************************/
+static int
+ip2_write_room ( PTTY tty )
+{
+ int bytesFree;
+ i2ChanStrPtr pCh = tty->driver_data;
+ unsigned long flags;
+
+ READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
+ READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_WRITE, 11, 1, bytesFree );
+#endif
+
+ return ((bytesFree > 0) ? bytesFree : 0);
+}
+
+/******************************************************************************/
+/* Function: ip2_chars_in_buf() */
+/* Parameters: Pointer to tty structure */
+/* Returns: Number of bytes queued for transmission */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static int
+ip2_chars_in_buf ( PTTY tty )
+{
+ i2ChanStrPtr pCh = tty->driver_data;
+ int rc;
+ unsigned long flags;
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
+#endif
+#ifdef IP2DEBUG_WRITE
+ printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
+ pCh->Obuf_char_count + pCh->Pbuf_stuff,
+ pCh->Obuf_char_count, pCh->Pbuf_stuff );
+#endif
+ READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ rc = pCh->Obuf_char_count;
+ READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ rc += pCh->Pbuf_stuff;
+ READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ return rc;
+}
+
+/******************************************************************************/
+/* Function: ip2_flush_buffer() */
+/* Parameters: Pointer to tty structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static void
+ip2_flush_buffer( PTTY tty )
+{
+ i2ChanStrPtr pCh = tty->driver_data;
+ unsigned long flags;
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_FLUSH, ITRC_ENTER, 0 );
+#endif
+#ifdef IP2DEBUG_WRITE
+ printk (KERN_DEBUG "IP2: flush buffer\n" );
+#endif
+ WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ pCh->Pbuf_stuff = 0;
+ WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ i2FlushOutput( pCh );
+ ip2_owake(tty);
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_FLUSH, ITRC_RETURN, 0 );
+#endif
+}
+
+/******************************************************************************/
+/* Function: ip2_wait_until_sent() */
+/* Parameters: Pointer to tty structure */
+/* Timeout for wait. */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* This function is used in place of the normal tty_wait_until_sent, which */
+/* only waits for the driver buffers to be empty (or rather, those buffers */
+/* reported by chars_in_buffer) which doesn't work for IP2 due to the */
+/* indeterminate number of bytes buffered on the board. */
+/******************************************************************************/
+static void
+ip2_wait_until_sent ( PTTY tty, int timeout )
+{
+ int i = jiffies;
+ i2ChanStrPtr pCh = tty->driver_data;
+
+ tty_wait_until_sent(tty, timeout );
+ if ( (i = timeout - (jiffies -i)) > 0)
+ i2DrainOutput( pCh, i );
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/* Device Input Section */
+/******************************************************************************/
+/******************************************************************************/
+
+/******************************************************************************/
+/* Function: ip2_throttle() */
+/* Parameters: Pointer to tty structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static void
+ip2_throttle ( PTTY tty )
+{
+ i2ChanStrPtr pCh = tty->driver_data;
+
+#ifdef IP2DEBUG_READ
+ printk (KERN_DEBUG "IP2: throttle\n" );
+#endif
+ /*
+ * Signal the poll/interrupt handlers not to forward incoming data to
+ * the line discipline. This will cause the buffers to fill up in the
+ * library and thus cause the library routines to send the flow control
+ * stuff.
+ */
+ pCh->throttled = 1;
+}
+
+/******************************************************************************/
+/* Function: ip2_unthrottle() */
+/* Parameters: Pointer to tty structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static void
+ip2_unthrottle ( PTTY tty )
+{
+ i2ChanStrPtr pCh = tty->driver_data;
+ unsigned long flags;
+
+#ifdef IP2DEBUG_READ
+ printk (KERN_DEBUG "IP2: unthrottle\n" );
+#endif
+
+ /* Pass incoming data up to the line discipline again. */
+ pCh->throttled = 0;
+ i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
+ serviceOutgoingFifo( pCh->pMyBord );
+ READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
+ if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
+ READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+#ifdef IP2DEBUG_READ
+ printk (KERN_DEBUG "i2Input called from unthrottle\n" );
+#endif
+ i2Input( pCh );
+ } else
+ READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+}
+
+static void
+ip2_start ( PTTY tty )
+{
+ i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
+
+ i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
+ i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND);
+ i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME);
+#ifdef IP2DEBUG_WRITE
+ printk (KERN_DEBUG "IP2: start tx\n" );
+#endif
+}
+
+static void
+ip2_stop ( PTTY tty )
+{
+ i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
+
+ i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND);
+#ifdef IP2DEBUG_WRITE
+ printk (KERN_DEBUG "IP2: stop tx\n" );
+#endif
+}
+
+/******************************************************************************/
+/* Device Ioctl Section */
+/******************************************************************************/
+
+/******************************************************************************/
+/* Function: ip2_ioctl() */
+/* Parameters: Pointer to tty structure */
+/* Pointer to file structure */
+/* Command */
+/* Argument */
+/* Returns: Success or failure */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static int
+ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
+{
+ i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
+ struct async_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct *p_cuser; /* user space */
+ int rc = 0;
+
+ if ( pCh == NULL ) {
+ return -ENODEV;
+ }
+
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
+#endif
+
+#ifdef IP2DEBUG_IOCTL
+ printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
+#endif
+
+ switch(cmd) {
+ case TIOCGSERIAL:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 2, 1, rc );
+#endif
+ rc = get_serial_info(pCh, (struct serial_struct *) arg);
+ if (rc)
+ return rc;
+ break;
+
+ case TIOCSSERIAL:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 3, 1, rc );
+#endif
+ rc = set_serial_info(pCh, (struct serial_struct *) arg);
+ if (rc)
+ return rc;
+ break;
+
+ case TCXONC:
+ rc = tty_check_change(tty);
+ if (rc)
+ return rc;
+ switch (arg) {
+ case TCOOFF:
+ //return -ENOIOCTLCMD;
+ break;
+ case TCOON:
+ //return -ENOIOCTLCMD;
+ break;
+ case TCIOFF:
+ if (STOP_CHAR(tty) != __DISABLED_CHAR) {
+ i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
+ CMD_XMIT_NOW(STOP_CHAR(tty)));
+ }
+ break;
+ case TCION:
+ if (START_CHAR(tty) != __DISABLED_CHAR) {
+ i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
+ CMD_XMIT_NOW(START_CHAR(tty)));
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ rc = tty_check_change(tty);
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 4, 1, rc );
+#endif
+ if (!rc) {
+ ip2_wait_until_sent(tty,0);
+ if (!arg) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250));
+ serviceOutgoingFifo( pCh->pMyBord );
+ }
+ }
+ break;
+
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ rc = tty_check_change(tty);
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 5, 1, rc );
+#endif
+ if (!rc) {
+ ip2_wait_until_sent(tty,0);
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
+ CMD_SEND_BRK(arg ? arg*100 : 250));
+ serviceOutgoingFifo ( pCh->pMyBord );
+ }
+ break;
+
+ case TIOCGSOFTCAR:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 6, 1, rc );
+#endif
+ rc=put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+ if (rc)
+ return rc;
+ break;
+
+ case TIOCSSOFTCAR:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 7, 1, rc );
+#endif
+ rc=get_user(arg,(unsigned long *) arg);
+ if (rc)
+ return rc;
+ tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
+ | (arg ? CLOCAL : 0));
+
+ break;
+
+ case TIOCMGET:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 8, 1, rc );
+#endif
+ rc = get_modem_info(pCh, (unsigned int *) arg);
+ if (rc)
+ return rc;
+ break;
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 9, 0 );
+#endif
+ rc = set_modem_info(pCh, cmd, (unsigned int *) arg);
+ break;
+
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
+ * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
+ * for masking). Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ cprev = pCh->icount; /* note the counters on entry */
+ for(;;) {
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 10, 0 );
+#endif
+ interruptible_sleep_on(&pCh->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current)) {
+ rc = -ERESTARTSYS;
+ break;
+ }
+ cnow = pCh->icount; /* atomic copy */
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+ rc = -EIO; /* no change => rc */
+ break;
+ }
+ if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+ rc = 0;
+ break;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+ break;
+
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for RI where
+ * only 0->1 is counted. The controller is quite capable of counting
+ * both, but this done to preserve compatibility with the standard
+ * serial driver.
+ */
+ case TIOCGICOUNT:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 11, 1, rc );
+#endif
+ cnow = pCh->icount;
+ p_cuser = (struct serial_icounter_struct *) arg;
+ put_user(cnow.cts, &p_cuser->cts);
+ put_user(cnow.dsr, &p_cuser->dsr);
+ put_user(cnow.rng, &p_cuser->rng);
+ put_user(cnow.dcd, &p_cuser->dcd);
+ break;
+
+ /*
+ * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
+ * will be passed to the line discipline for it to handle.
+ */
+ case TIOCSERCONFIG:
+ case TIOCSERGWILD:
+ case TIOCSERGETLSR:
+ case TIOCSERSWILD:
+ case TIOCSERGSTRUCT:
+ case TIOCSERGETMULTI:
+ case TIOCSERSETMULTI:
+
+ default:
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, 12, 0 );
+#endif
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+#ifdef IP2DEBUG_TRACE
+ ip2trace (PORTN, ITRC_IOCTL, ITRC_RETURN, 0 );
+#endif
+ return rc;
+}
+/******************************************************************************/
+/* Function: get_modem_info() */
+/* Parameters: Pointer to channel structure */
+/* Pointer to destination for data */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* This returns the current settings of the dataset signal inputs to the user */
+/* program. */
+/******************************************************************************/
+static int
+get_modem_info(i2ChanStrPtr pCh, unsigned int *value)
+{
+ unsigned short status;
+ unsigned int result;
+ int rc;
+
+ status = pCh->dataSetIn; // snapshot settings
+ result = ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
+ | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
+ | ((status & I2_DCD) ? TIOCM_CAR : 0)
+ | ((status & I2_RI) ? TIOCM_RNG : 0)
+ | ((status & I2_DSR) ? TIOCM_DSR : 0)
+ | ((status & I2_CTS) ? TIOCM_CTS : 0);
+ rc=put_user(result,value);
+ return rc;
+}
+
+/******************************************************************************/
+/* Function: set_modem_info() */
+/* Parameters: Pointer to channel structure */
+/* Specific ioctl command */
+/* Pointer to source for new settings */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* This returns the current settings of the dataset signal inputs to the user */
+/* program. */
+/******************************************************************************/
+static int
+set_modem_info(i2ChanStrPtr pCh, unsigned cmd, unsigned int *value)
+{
+ int rc;
+ unsigned int arg;
+
+ rc=get_user(arg,value);
+ if (rc)
+ return rc;
+ switch(cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
+ pCh->dataSetOut |= I2_RTS;
+ }
+ if (arg & TIOCM_DTR) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
+ pCh->dataSetOut |= I2_DTR;
+ }
+ break;
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
+ pCh->dataSetOut &= ~I2_RTS;
+ }
+ if (arg & TIOCM_DTR) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
+ pCh->dataSetOut &= ~I2_DTR;
+ }
+ break;
+ case TIOCMSET:
+ if ( (arg & TIOCM_RTS) && !(pCh->dataSetOut & I2_RTS) ) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
+ pCh->dataSetOut |= I2_RTS;
+ } else if ( !(arg & TIOCM_RTS) && (pCh->dataSetOut & I2_RTS) ) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
+ pCh->dataSetOut &= ~I2_RTS;
+ }
+ if ( (arg & TIOCM_DTR) && !(pCh->dataSetOut & I2_DTR) ) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
+ pCh->dataSetOut |= I2_DTR;
+ } else if ( !(arg & TIOCM_DTR) && (pCh->dataSetOut & I2_DTR) ) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
+ pCh->dataSetOut &= ~I2_DTR;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ serviceOutgoingFifo( pCh->pMyBord );
+ return 0;
+}
+
+/******************************************************************************/
+/* Function: GetSerialInfo() */
+/* Parameters: Pointer to channel structure */
+/* Pointer to old termios structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* This is to support the setserial command, and requires processing of the */
+/* standard Linux serial structure. */
+/******************************************************************************/
+static int
+get_serial_info ( i2ChanStrPtr pCh, struct serial_struct *retinfo )
+{
+ struct serial_struct tmp;
+ int rc=0;
+
+ if ( !retinfo ) {
+ return -EFAULT;
+ }
+
+ memset ( &tmp, 0, sizeof(tmp) );
+ tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16];
+ if (BID_HAS_654(tmp.type)) {
+ tmp.type = PORT_16650;
+ } else {
+ tmp.type = PORT_CIRRUS;
+ }
+ tmp.line = pCh->port_index;
+ tmp.port = pCh->pMyBord->i2eBase;
+ tmp.irq = ip2config.irq[pCh->port_index/64];
+ tmp.flags = pCh->flags;
+ tmp.baud_base = pCh->BaudBase;
+ tmp.close_delay = pCh->ClosingDelay;
+ tmp.closing_wait = pCh->ClosingWaitTime;
+ tmp.custom_divisor = pCh->BaudDivisor;
+ if(copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ rc= -EFAULT;
+ return rc;
+}
+
+/******************************************************************************/
+/* Function: SetSerialInfo() */
+/* Parameters: Pointer to channel structure */
+/* Pointer to old termios structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* This function provides support for setserial, which uses the TIOCSSERIAL */
+/* ioctl. Not all setserial parameters are relevant. If the user attempts to */
+/* change the IRQ, address or type of the port the ioctl fails. */
+/******************************************************************************/
+static int
+set_serial_info( i2ChanStrPtr pCh, struct serial_struct *new_info )
+{
+ struct serial_struct ns;
+ int old_flags, old_baud_divisor;
+ int rc = 0;
+
+ if ( !new_info ) {
+ return -EFAULT;
+ }
+ rc=copy_from_user(&ns, new_info, sizeof (ns) );
+ if (rc) {
+ return rc;
+ }
+ /*
+ * We don't allow setserial to change IRQ, board address, type or baud
+ * base. Also line nunber as such is meaningless but we use it for our
+ * array index so it is fixed also.
+ */
+ if ( ns.irq != ip2config.irq
+ || (int) ns.port != ((int) pCh->pMyBord->i2eBase)
+ || ns.baud_base != pCh->BaudBase
+ || ns.line != pCh->port_index ) {
+ return -EINVAL;
+ }
+
+ old_flags = pCh->flags;
+ old_baud_divisor = pCh->BaudDivisor;
+
+ if ( !suser() ) {
+ if ( ( ns.close_delay != pCh->ClosingDelay ) ||
+ ( (ns.flags & ~ASYNC_USR_MASK) !=
+ (pCh->flags & ~ASYNC_USR_MASK) ) ) {
+ return -EPERM;
+ }
+
+ pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) |
+ (ns.flags & ASYNC_USR_MASK);
+ pCh->BaudDivisor = ns.custom_divisor;
+ } else {
+ pCh->flags = (pCh->flags & ~ASYNC_FLAGS) |
+ (ns.flags & ASYNC_FLAGS);
+ pCh->BaudDivisor = ns.custom_divisor;
+ pCh->ClosingDelay = ns.close_delay * HZ/100;
+ pCh->ClosingWaitTime = ns.closing_wait * HZ/100;
+ }
+
+ if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) )
+ || (old_baud_divisor != pCh->BaudDivisor) ) {
+ // Invalidate speed and reset parameters
+ set_params( pCh, NULL );
+ }
+
+ return rc;
+}
+
+/******************************************************************************/
+/* Function: ip2_set_termios() */
+/* Parameters: Pointer to tty structure */
+/* Pointer to old termios structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static void
+ip2_set_termios( PTTY tty, struct termios *old_termios )
+{
+ i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
+
+#ifdef IP2DEBUG_IOCTL
+ printk (KERN_DEBUG "IP2: set termios %p\n", old_termios );
+#endif
+
+ set_params( pCh, old_termios );
+}
+
+/******************************************************************************/
+/* Function: ip2_set_line_discipline() */
+/* Parameters: Pointer to tty structure */
+/* Returns: Nothing */
+/* */
+/* Description: Does nothing */
+/* */
+/* */
+/******************************************************************************/
+static void
+ip2_set_line_discipline ( PTTY tty )
+{
+#ifdef IP2DEBUG_IOCTL
+ printk (KERN_DEBUG "IP2: set line discipline\n" );
+#endif
+#ifdef IP2DEBUG_TRACE
+ ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
+#endif
+}
+
+/******************************************************************************/
+/* Function: SetLine Characteristics() */
+/* Parameters: Pointer to channel structure */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* This routine is called to update the channel structure with the new line */
+/* characteristics, and send the appropriate commands to the board when they */
+/* change. */
+/******************************************************************************/
+static void
+set_params( i2ChanStrPtr pCh, struct termios *o_tios )
+{
+ tcflag_t cflag, iflag, lflag;
+ char stop_char, start_char;
+ struct termios dummy;
+
+ lflag = pCh->pTTY->termios->c_lflag;
+ cflag = pCh->pTTY->termios->c_cflag;
+ iflag = pCh->pTTY->termios->c_iflag;
+
+ if (o_tios == NULL) {
+ dummy.c_lflag = ~lflag;
+ dummy.c_cflag = ~cflag;
+ dummy.c_iflag = ~iflag;
+ o_tios = &dummy;
+ }
+
+ {
+ switch ( cflag & CBAUD ) {
+ case B0:
+ i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
+ pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
+ i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
+ pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag);
+ goto service_it;
+ break;
+ case B38400:
+ /*
+ * This is the speed that is overloaded with all the other high
+ * speeds, depending upon the flag settings.
+ */
+ if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) {
+ pCh->speed = CBR_57600;
+ } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) {
+ pCh->speed = CBR_115200;
+ } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) {
+ pCh->speed = CBR_C1;
+ } else {
+ pCh->speed = CBR_38400;
+ }
+ break;
+ case B50: pCh->speed = CBR_50; break;
+ case B75: pCh->speed = CBR_75; break;
+ case B110: pCh->speed = CBR_110; break;
+ case B134: pCh->speed = CBR_134; break;
+ case B150: pCh->speed = CBR_150; break;
+ case B200: pCh->speed = CBR_200; break;
+ case B300: pCh->speed = CBR_300; break;
+ case B600: pCh->speed = CBR_600; break;
+ case B1200: pCh->speed = CBR_1200; break;
+ case B1800: pCh->speed = CBR_1800; break;
+ case B2400: pCh->speed = CBR_2400; break;
+ case B4800: pCh->speed = CBR_4800; break;
+ case B9600: pCh->speed = CBR_9600; break;
+ case B19200: pCh->speed = CBR_19200; break;
+ case B57600: pCh->speed = CBR_57600; break;
+ case B115200: pCh->speed = CBR_115200; break;
+ case B153600: pCh->speed = CBR_153600; break;
+ case B230400: pCh->speed = CBR_230400; break;
+ case B307200: pCh->speed = CBR_307200; break;
+ case B460800: pCh->speed = CBR_460800; break;
+ case B921600: pCh->speed = CBR_921600; break;
+ default: pCh->speed = CBR_9600; break;
+ }
+ if ( pCh->speed == CBR_C1 ) {
+ // Process the custom speed parameters.
+ int bps = pCh->BaudBase / pCh->BaudDivisor;
+ if ( bps == 921600 ) {
+ pCh->speed = CBR_921600;
+ } else {
+ bps = bps/10;
+ i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) );
+ }
+ }
+ i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed));
+
+ i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
+ pCh->dataSetOut |= (I2_DTR | I2_RTS);
+ }
+ if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag))
+ {
+ i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
+ CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1));
+ }
+ if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag))
+ {
+ i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
+ CMD_SETPAR(
+ (cflag & PARENB ? (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP)
+ )
+ );
+ }
+ /* byte size and parity */
+ if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag))
+ {
+ int datasize;
+ switch ( cflag & CSIZE ) {
+ case CS5: datasize = CSZ_5; break;
+ case CS6: datasize = CSZ_6; break;
+ case CS7: datasize = CSZ_7; break;
+ case CS8: datasize = CSZ_8; break;
+ default: datasize = CSZ_5; break; /* as per serial.c */
+ }
+ i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) );
+ }
+ /* Process CTS flow control flag setting */
+ if ( (cflag & CRTSCTS) ) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100,
+ 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB);
+ } else {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100,
+ 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
+ }
+ //
+ // Process XON/XOFF flow control flags settings
+ //
+ stop_char = STOP_CHAR(pCh->pTTY);
+ start_char = START_CHAR(pCh->pTTY);
+
+ //////////// can't be \000
+ if (stop_char == __DISABLED_CHAR )
+ {
+ stop_char = ~__DISABLED_CHAR;
+ }
+ if (start_char == __DISABLED_CHAR )
+ {
+ start_char = ~__DISABLED_CHAR;
+ }
+ /////////////////////////////////
+
+ if ( o_tios->c_cc[VSTART] != start_char )
+ {
+ i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char));
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char));
+ }
+ if ( o_tios->c_cc[VSTOP] != stop_char )
+ {
+ i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char));
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char));
+ }
+ if (stop_char == __DISABLED_CHAR )
+ {
+ stop_char = ~__DISABLED_CHAR; //TEST123
+ goto no_xoff;
+ }
+ if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF)))
+ {
+ if ( iflag & IXOFF ) { // Enable XOFF output flow control
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON));
+ } else { // Disable XOFF output flow control
+no_xoff:
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE));
+ }
+ }
+ if (start_char == __DISABLED_CHAR )
+ {
+ goto no_xon;
+ }
+ if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY)))
+ {
+ if ( iflag & IXON ) {
+ if ( iflag & IXANY ) { // Enable XON/XANY output flow control
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY));
+ } else { // Enable XON output flow control
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON));
+ }
+ } else { // Disable XON output flow control
+no_xon:
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE));
+ }
+ }
+ if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) )
+ {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
+ CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0)));
+ }
+ if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) )
+ {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
+ CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB));
+ }
+
+ if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR))
+ ^ ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) )
+ {
+ char brkrpt = 0;
+ char parrpt = 0;
+
+ if ( iflag & IGNBRK ) { /* Ignore breaks altogether */
+ /* Ignore breaks altogether */
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP);
+ } else {
+ if ( iflag & BRKINT ) {
+ if ( iflag & PARMRK ) {
+ brkrpt = 0x0a; // exception an inline triple
+ } else {
+ brkrpt = 0x1a; // exception and NULL
+ }
+ brkrpt |= 0x04; // flush input
+ } else {
+ if ( iflag & PARMRK ) {
+ brkrpt = 0x0b; //POSIX triple \0377 \0 \0
+ } else {
+ brkrpt = 0x01; // Null only
+ }
+ }
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt));
+ }
+
+ if (iflag & IGNPAR) {
+ parrpt = 0x20;
+ /* would be 2 for not cirrus bug */
+ /* would be 0x20 cept for cirrus bug */
+ } else {
+ if ( iflag & PARMRK ) {
+ /*
+ * Replace error characters with 3-byte sequence (\0377,\0,char)
+ */
+ parrpt = 0x04 ;
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0));
+ } else {
+ parrpt = 0x03;
+ }
+ }
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
+ }
+ if (cflag & CLOCAL) {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
+ pCh->flags &= ~ASYNC_CHECK_CD;
+ } else {
+ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
+ pCh->flags |= ASYNC_CHECK_CD;
+ }
+
+#ifdef XXX
+do_flags_thing: // This is a test, we don't do the flags thing
+
+ if ( (cflag & CRTSCTS) ) {
+ cflag |= 014000000000;
+ }
+ i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1,
+ CMD_UNIX_FLAGS(iflag,cflag,lflag));
+#endif
+
+service_it:
+ i2DrainOutput( pCh, 100 );
+}
+
+/******************************************************************************/
+/* IPL Device Section */
+/******************************************************************************/
+
+/******************************************************************************/
+/* Function: ip2_ipl_read() */
+/* Parameters: Pointer to device inode */
+/* Pointer to file structure */
+/* Pointer to data */
+/* Number of bytes to read */
+/* Returns: Success or failure */
+/* */
+/* Description: Ugly */
+/* */
+/* */
+/******************************************************************************/
+
+static
+ssize_t
+ip2_ipl_read(struct file *pFile, char *pData, size_t count, loff_t *off )
+{
+ unsigned int minor = MINOR( pFile->f_dentry->d_inode->i_rdev );
+ int rc = 0;
+
+#ifdef IP2DEBUG_IPL
+ printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count );
+#endif
+
+ switch( minor ) {
+ case 0: // IPL device
+ rc = -EINVAL;
+ break;
+ case 1: // Status dump
+ rc = -EINVAL;
+ break;
+ case 2: // Ping device
+ rc = -EINVAL;
+ break;
+ case 3: // Trace device
+ rc = DumpTraceBuffer ( pData, count );
+ break;
+ case 4: // Trace device
+ rc = DumpFifoBuffer ( pData, count );
+ break;
+ default:
+ rc = -ENODEV;
+ break;
+ }
+ return rc;
+}
+
+static int
+DumpFifoBuffer ( char *pData, int count )
+{
+#ifdef DEBUG_FIFO
+ int rc=0;
+ if(copy_to_user(pData, DBGBuf, count))
+ rc=-EFAULT;
+
+ printk(KERN_DEBUG "Last index %d\n", I );
+
+ return count;
+#endif /* DEBUG_FIFO */
+ return 0;
+}
+
+static int
+DumpTraceBuffer ( char *pData, int count )
+{
+#ifdef IP2DEBUG_TRACE
+ int rc;
+ int dumpcount;
+ int chunk;
+ int *pIndex = (int*)pData;
+
+ if ( count < (sizeof(int) * 6) ) {
+ return -EIO;
+ }
+ put_user(tracewrap, pIndex );
+ put_user(TRACEMAX, ++pIndex );
+ put_user(tracestrip, ++pIndex );
+ put_user(tracestuff, ++pIndex );
+ pData += sizeof(int) * 6;
+ count -= sizeof(int) * 6;
+
+ dumpcount = tracestuff - tracestrip;
+ if ( dumpcount < 0 ) {
+ dumpcount += TRACEMAX;
+ }
+ if ( dumpcount > count ) {
+ dumpcount = count;
+ }
+ chunk = TRACEMAX - tracestrip;
+ if ( dumpcount > chunk ) {
+ rc=copy_to_user(pData, &tracebuf[tracestrip],
+ chunk * sizeof(tracebuf[0]) )?-EFAULT:0;
+ pData += chunk * sizeof(tracebuf[0]);
+ tracestrip = 0;
+ chunk = dumpcount - chunk;
+ } else {
+ chunk = dumpcount;
+ }
+ rc=copy_to_user(pData, &tracebuf[tracestrip],
+ chunk * sizeof(tracebuf[0]) )?-EFAULT:0
+ tracestrip += chunk;
+ tracewrap = 0;
+
+ put_user(tracestrip, ++pIndex );
+ put_user(tracestuff, ++pIndex );
+
+ return dumpcount;
+#else
+ return 0;
+#endif
+}
+
+/******************************************************************************/
+/* Function: ip2_ipl_write() */
+/* Parameters: */
+/* Pointer to file structure */
+/* Pointer to data */
+/* Number of bytes to write */
+/* Returns: Success or failure */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static ssize_t
+ip2_ipl_write(struct file *pFile, const char *pData, size_t count, loff_t *off)
+{
+#ifdef IP2DEBUG_IPL
+ printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count );
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+/* Function: ip2_ipl_ioctl() */
+/* Parameters: Pointer to device inode */
+/* Pointer to file structure */
+/* Command */
+/* Argument */
+/* Returns: Success or failure */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static int
+ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
+{
+ unsigned int iplminor = MINOR(pInode->i_rdev);
+ int rc = 0;
+ ULONG *pIndex = (ULONG*)arg;
+ i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4];
+ i2ChanStrPtr pCh;
+
+#ifdef IP2DEBUG_IPL
+ printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
+#endif
+
+ switch ( iplminor ) {
+ case 0: // IPL device
+ rc = -EINVAL;
+ break;
+ case 1: // Status dump
+ case 5:
+ case 9:
+ case 13:
+ switch ( cmd ) {
+ case 64: /* Driver - ip2stat */
+ put_user(ref_count, pIndex++ );
+ put_user(irq_counter, pIndex++ );
+ put_user(bh_counter, pIndex++ );
+ break;
+
+ case 65: /* Board - ip2stat */
+ if ( pB ) {
+ if(copy_to_user((char*)arg, (char*)pB, sizeof(i2eBordStr) ))
+ rc=-EFAULT;
+ put_user(INB(pB->i2eStatus),
+ (ULONG*)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
+ } else {
+ rc = -ENODEV;
+ }
+ break;
+
+ default:
+ pCh = DevTable[cmd];
+ if ( pCh )
+ {
+ if(copy_to_user((char*)arg, (char*)pCh, sizeof(i2ChanStr) ))
+ rc = -EFAULT;
+ } else {
+ rc = cmd < 64 ? -ENODEV : -EINVAL;
+ }
+ }
+ break;
+
+ case 2: // Ping device
+ rc = -EINVAL;
+ break;
+ case 3: // Trace device
+ if ( cmd == 1 ) {
+ put_user(iiSendPendingMail, pIndex++ );
+ put_user(i2InitChannels, pIndex++ );
+ put_user(i2QueueNeeds, pIndex++ );
+ put_user(i2QueueCommands, pIndex++ );
+ put_user(i2GetStatus, pIndex++ );
+ put_user(i2Input, pIndex++ );
+ put_user(i2InputFlush, pIndex++ );
+ put_user(i2Output, pIndex++ );
+ put_user(i2FlushOutput, pIndex++ );
+ put_user(i2DrainWakeup, pIndex++ );
+ put_user(i2DrainOutput, pIndex++ );
+ put_user(i2OutputFree, pIndex++ );
+ put_user(i2StripFifo, pIndex++ );
+ put_user(i2StuffFifoBypass, pIndex++ );
+ put_user(i2StuffFifoFlow, pIndex++ );
+ put_user(i2StuffFifoInline, pIndex++ );
+ put_user(i2ServiceBoard, pIndex++ );
+ put_user(serviceOutgoingFifo, pIndex++ );
+ // put_user(ip2_init, pIndex++ );
+ put_user(ip2_init_board, pIndex++ );
+ put_user(find_eisa_board, pIndex++ );
+ put_user(set_irq, pIndex++ );
+ put_user(ip2_interrupt, pIndex++ );
+ put_user(ip2_poll, pIndex++ );
+ put_user(service_all_boards, pIndex++ );
+ put_user(do_input, pIndex++ );
+ put_user(do_status, pIndex++ );
+#ifndef IP2DEBUG_OPEN
+ put_user(0, pIndex++ );
+#else
+ put_user(open_sanity_check, pIndex++ );
+#endif
+ put_user(ip2_open, pIndex++ );
+ put_user(ip2_close, pIndex++ );
+ put_user(ip2_hangup, pIndex++ );
+ put_user(ip2_write, pIndex++ );
+ put_user(ip2_putchar, pIndex++ );
+ put_user(ip2_flush_chars, pIndex++ );
+ put_user(ip2_write_room, pIndex++ );
+ put_user(ip2_chars_in_buf, pIndex++ );
+ put_user(ip2_flush_buffer, pIndex++ );
+
+ //put_user(ip2_wait_until_sent, pIndex++ );
+ put_user(0, pIndex++ );
+
+ put_user(ip2_throttle, pIndex++ );
+ put_user(ip2_unthrottle, pIndex++ );
+ put_user(ip2_ioctl, pIndex++ );
+ put_user(get_modem_info, pIndex++ );
+ put_user(set_modem_info, pIndex++ );
+ put_user(get_serial_info, pIndex++ );
+ put_user(set_serial_info, pIndex++ );
+ put_user(ip2_set_termios, pIndex++ );
+ put_user(ip2_set_line_discipline, pIndex++ );
+ put_user(set_params, pIndex++ );
+ } else {
+ rc = -EINVAL;
+ }
+
+ break;
+
+ default:
+ rc = -ENODEV;
+ break;
+ }
+ return rc;
+}
+
+/******************************************************************************/
+/* Function: ip2_ipl_open() */
+/* Parameters: Pointer to device inode */
+/* Pointer to file structure */
+/* Returns: Success or failure */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+static int
+ip2_ipl_open( struct inode *pInode, struct file *pFile )
+{
+ unsigned int iplminor = MINOR(pInode->i_rdev);
+ i2eBordStrPtr pB;
+ i2ChanStrPtr pCh;
+
+#ifdef IP2DEBUG_IPL
+ printk (KERN_DEBUG "IP2IPL: open\n" );
+#endif
+
+ //MOD_INC_USE_COUNT; // Needs close entry with decrement.
+
+ switch(iplminor) {
+ // These are the IPL devices
+ case 0:
+ case 4:
+ case 8:
+ case 12:
+ break;
+
+ // These are the status devices
+ case 1:
+ case 5:
+ case 9:
+ case 13:
+ break;
+
+ // These are the debug devices
+ case 2:
+ case 6:
+ case 10:
+ case 14:
+ pB = i2BoardPtrTable[iplminor / 4];
+ pCh = (i2ChanStrPtr) pB->i2eChannelPtr;
+ break;
+
+ // This is the trace device
+ case 3:
+ break;
+ }
+ return 0;
+}
+/******************************************************************************/
+/* Function: ip2_read_procmem */
+/* Parameters: */
+/* */
+/* Returns: Length of output */
+/* */
+/* Description: */
+/* Supplies some driver operating parameters */
+/* Not real useful unless your debugging the fifo */
+/* */
+/******************************************************************************/
+
+#define LIMIT (PAGE_SIZE - 120)
+
+int
+ip2_read_procmem(char *buf, char **start, off_t offset, int len, int unused)
+{
+ i2eBordStrPtr pB;
+ i2ChanStrPtr pCh;
+ PTTY tty;
+ int i;
+
+ len = 0;
+
+#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
+#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
+#define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
+
+ len += sprintf(buf+len,"\n");
+
+ for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ pB = i2BoardPtrTable[i];
+ if ( pB ) {
+ len += sprintf(buf+len,"board %d:\n",i);
+ len += sprintf(buf+len,"\tFifo rem: %d mty: %x outM %x\n",
+ pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
+ }
+ }
+
+ len += sprintf(buf+len,"#: tty flags, port flags, cflags, iflags\n");
+ for (i=0; i < IP2_MAX_PORTS; i++) {
+ if (len > LIMIT)
+ break;
+ pCh = DevTable[i];
+ if (pCh) {
+ tty = pCh->pTTY;
+ if (tty && tty->count) {
+ len += sprintf(buf+len,FMTLINE,i,(int)tty->flags,pCh->flags,
+ tty->termios->c_cflag,tty->termios->c_iflag);
+
+ len += sprintf(buf+len,FMTLIN2,
+ pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
+ len += sprintf(buf+len,FMTLIN3,pCh->infl.asof,pCh->infl.room);
+ }
+ }
+ }
+ return len;
+}
+
+/*
+ * This is the handler for /proc/tty/driver/ip2
+ *
+ * This stretch of code has been largely plagerized from at least three
+ * different sources including ip2mkdev.c and a couple of other drivers.
+ * The bugs are all mine. :-) =mhw=
+ */
+int ip2_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int i, j, box;
+ int len = 0;
+ int boxes = 0;
+ int ports = 0;
+ int tports = 0;
+ off_t begin = 0;
+ i2eBordStrPtr pB;
+
+ len += sprintf(page, "ip2info: 1.0 driver: %s\n", pcVersion );
+ len += sprintf(page+len, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
+ IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
+ IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
+
+ for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ /* This need to be reset for a board by board count... */
+ boxes = 0;
+ pB = i2BoardPtrTable[i];
+ if( pB ) {
+ switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED )
+ {
+ case POR_ID_FIIEX:
+ len += sprintf( page+len, "Board %d: EX ports=", i );
+ for( box = 0; box < ABS_MAX_BOXES; ++box )
+ {
+ ports = 0;
+
+ if( pB->i2eChannelMap[box] != 0 ) ++boxes;
+ for( j = 0; j < ABS_BIGGEST_BOX; ++j )
+ {
+ if( pB->i2eChannelMap[box] & 1<< j ) {
+ ++ports;
+ }
+ }
+ len += sprintf( page+len, "%d,", ports );
+ tports += ports;
+ }
+
+ --len; /* Backup over that last comma */
+
+ len += sprintf( page+len, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8 );
+ break;
+
+ case POR_ID_II_4:
+ len += sprintf(page+len, "Board %d: ISA-4 ports=4 boxes=1", i );
+ tports = ports = 4;
+ break;
+
+ case POR_ID_II_8:
+ len += sprintf(page+len, "Board %d: ISA-8-std ports=8 boxes=1", i );
+ tports = ports = 8;
+ break;
+
+ case POR_ID_II_8R:
+ len += sprintf(page+len, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i );
+ tports = ports = 8;
+ break;
+
+ default:
+ len += sprintf(page+len, "Board %d: unknown", i );
+ /* Don't try and probe for minor numbers */
+ tports = ports = 0;
+ }
+
+ } else {
+ /* Don't try and probe for minor numbers */
+ len += sprintf(page+len, "Board %d: vacant", i );
+ tports = ports = 0;
+ }
+
+ if( tports ) {
+ len += sprintf(page+len, " minors=" );
+
+ for ( box = 0; box < ABS_MAX_BOXES; ++box )
+ {
+ for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
+ {
+ if ( pB->i2eChannelMap[box] & (1 << j) )
+ {
+ len += sprintf (page+len,"%d,",
+ j + ABS_BIGGEST_BOX *
+ (box+i*ABS_MAX_BOXES));
+ }
+ }
+ }
+
+ page[ len - 1 ] = '\n'; /* Overwrite that last comma */
+ } else {
+ len += sprintf (page+len,"\n" );
+ }
+
+ if (len+begin > off+count)
+ break;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+
+ if (i >= IP2_MAX_BOARDS)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+ }
+
+/******************************************************************************/
+/* Function: ip2trace() */
+/* Parameters: Value to add to trace buffer */
+/* Returns: Nothing */
+/* */
+/* Description: */
+/* */
+/* */
+/******************************************************************************/
+void
+ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
+{
+#ifdef IP2DEBUG_TRACE
+ long flags;
+ unsigned long *pCode = &codes;
+ union ip2breadcrumb bc;
+ i2ChanStrPtr pCh;
+
+
+ tracebuf[tracestuff++] = jiffies;
+ if ( tracestuff == TRACEMAX ) {
+ tracestuff = 0;
+ }
+ if ( tracestuff == tracestrip ) {
+ if ( ++tracestrip == TRACEMAX ) {
+ tracestrip = 0;
+ }
+ ++tracewrap;
+ }
+
+ bc.hdr.port = 0xff & pn;
+ bc.hdr.cat = cat;
+ bc.hdr.codes = (unsigned char)( codes & 0xff );
+ bc.hdr.label = label;
+ tracebuf[tracestuff++] = bc.value;
+
+ for (;;) {
+ if ( tracestuff == TRACEMAX ) {
+ tracestuff = 0;
+ }
+ if ( tracestuff == tracestrip ) {
+ if ( ++tracestrip == TRACEMAX ) {
+ tracestrip = 0;
+ }
+ ++tracewrap;
+ }
+
+ if ( !codes-- )
+ break;
+
+ tracebuf[tracestuff++] = *++pCode;
+ }
+#endif
+}
+
+
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index e99decb62..041858997 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -14,7 +14,8 @@
* Printk clean up
* 9/12/98 alan@redhat.com Rough port to 2.1.x
*
- *
+ * 10/6/99 sameer Merged the ISA and PCI drivers to
+ * a new unified driver.
* ***********************************************************
*
* To use this driver you also need the support package. You
@@ -51,8 +52,21 @@
#include <asm/io.h>
#include <asm/system.h>
+#include <linux/pci.h>
+
#include <linux/isicom.h>
+static int device_id[] = { 0x2028,
+ 0x2051,
+ 0x2052,
+ 0x2053,
+ 0x2054,
+ 0x2055,
+ 0x2056,
+ 0x2057,
+ 0x2058
+ };
+
static int isicom_refcount = 0;
static int prev_card = 3; /* start servicing isi_card[0] */
static struct isi_board * irq_to_board[16] = { NULL, };
@@ -147,7 +161,7 @@ static int ISILoad_release(struct inode *inode, struct file *filp)
static int ISILoad_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- unsigned int card, i, j, signature, status;
+ unsigned int card, i, j, signature, status, portcount = 0;
unsigned short word_count, base;
bin_frame frame;
/* exec_record exec_rec; */
@@ -180,19 +194,38 @@ static int ISILoad_ioctl(struct inode *inode, struct file *filp,
printk(".");
}
signature=(inw(base+0x4)) & 0xff;
-
- if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {
+ if (isi_card[card].isa) {
+
+ if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {
#ifdef ISICOM_DEBUG
- printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
+ printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
#endif
- printk("\nISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
- return -EIO;
- }
-
+ printk("\nISILoad:ISA Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
+ return -EIO;
+ }
+ }
+ else {
+ portcount = inw(base+0x2);
+ if (!(inw(base+0xe) & 0x1) || ((portcount!=0) && (portcount!=4) && (portcount!=8))) {
+#ifdef ISICOM_DEBUG
+ printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
+#endif
+ printk("\nISILoad:PCI Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
+ return -EIO;
+ }
+ }
switch(signature) {
case 0xa5:
case 0xbb:
- case 0xdd: isi_card[card].port_count = 8;
+ case 0xdd:
+ if (isi_card[card].isa)
+ isi_card[card].port_count = 8;
+ else {
+ if (portcount == 4)
+ isi_card[card].port_count = 4;
+ else
+ isi_card[card].port_count = 8;
+ }
isi_card[card].shift_count = 12;
break;
@@ -310,7 +343,8 @@ static int ISILoad_ioctl(struct inode *inode, struct file *filp,
outw(0x0, base);
outw(0x0, base);
InterruptTheCard(base);
-
+ outw(0x0, base+0x4); /* for ISI4608 cards */
+
isi_card[card].status |= FIRMWARE_LOADED;
return 0;
@@ -455,28 +489,7 @@ static void isicom_tx(unsigned long _data)
txcount--;
}
}
-/*
- * Replaced the code below with hopefully a faster loop - sameer
- */
-/*
- while (1) {
- wrd = port->xmit_buf[port->xmit_tail++];
- port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
- port->xmit_cnt--;
- if (--txcount > 0) {
- wrd |= (port->xmit_buf[port->xmit_tail++] << 8);
- port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
- port->xmit_cnt--;
- outw(wrd, base);
- if (--txcount <= 0) break;
- }
- else {
- outw(wrd, base);
- break;
- }
- }
-*/
InterruptTheCard(base);
if (port->xmit_cnt <= 0)
port->status &= ~ISI_TXOK;
@@ -531,12 +544,34 @@ static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs)
unsigned char channel;
short byte_count;
- card = irq_to_board[irq];
+ /*
+ * find the source of interrupt
+ */
+
+ for(count = 0; count < BOARD_COUNT; count++) {
+ card = &isi_card[count];
+ if (card->base != 0) {
+ if (((card->isa == YES) && (card->irq == irq)) ||
+ ((card->isa == NO) && (card->irq == irq) && (inw(card->base+0x0e) & 0x02)))
+ break;
+ }
+ card = NULL;
+ }
+
if (!card || !(card->status & FIRMWARE_LOADED)) {
- printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);
+/* printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);*/
return;
}
+
base = card->base;
+ if (card->isa == NO) {
+ /*
+ * disable any interrupts from the PCI card and lower the
+ * interrupt line
+ */
+ outw(0x8000, base+0x04);
+ ClearInterrupt(base);
+ }
inw(base); /* get the dummy word out */
header = inw(base);
@@ -548,12 +583,18 @@ static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs)
if ((channel+1) > card->port_count) {
printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n",
base, channel+1);
- ClearInterrupt(base);
+ if (card->isa)
+ ClearInterrupt(base);
+ else
+ outw(0x0000, base+0x04); /* enable interrupts */
return;
}
port = card->ports + channel;
if (!(port->flags & ASYNC_INITIALIZED)) {
- ClearInterrupt(base);
+ if (card->isa)
+ ClearInterrupt(base);
+ else
+ outw(0x0000, base+0x04); /* enable interrupts */
return;
}
@@ -681,7 +722,10 @@ static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs)
}
queue_task(&tty->flip.tqueue, &tq_timer);
}
- ClearInterrupt(base);
+ if (card->isa == YES)
+ ClearInterrupt(base);
+ else
+ outw(0x0000, base+0x04); /* enable interrupts */
return;
}
@@ -951,7 +995,7 @@ static int block_til_ready(struct tty_struct * tty, struct file * filp, struct i
raise_dtr_rts(port);
sti();
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
@@ -1023,12 +1067,11 @@ static int isicom_open(struct tty_struct * tty, struct file * filp)
return -ENODEV;
}
- /* open on higher 8 dev files on a 8 port card !!! */
- if (card->port_count == 8)
- if (line > ((board * 16)+7)) {
- printk(KERN_ERR "ISICOM: Opened >8 on a 8 port card.\n");
- return -ENODEV;
- }
+ /* open on a port greater than the port count for the card !!! */
+ if (line > ((board * 16) + card->port_count - 1)) {
+ printk(KERN_ERR "ISICOM: Open on a port which exceeds the port_count of the card!\n");
+ return -ENODEV;
+ }
port = &isi_ports[line];
if (isicom_paranoia_check(port, tty->device, "isicom_open"))
return -ENODEV;
@@ -1362,7 +1405,7 @@ static int isicom_get_modem_info(struct isi_port * port, unsigned int * value)
((status & ISI_DSR) ? TIOCM_DSR : 0) |
((status & ISI_CTS) ? TIOCM_CTS : 0) |
((status & ISI_RI ) ? TIOCM_RI : 0);
- put_user(info, (unsigned long *) value);
+ put_user(info, (unsigned int *) value);
return 0;
}
@@ -1764,21 +1807,47 @@ static void unregister_drivers(void)
static int register_isr(void)
{
- int count, done=0;
+ int count, done=0, card;
+ int flag;
+ unsigned char request;
for (count=0; count < BOARD_COUNT; count++ ) {
if (isi_card[count].base) {
- if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) {
- printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n",
- isi_card[count].irq, count+1);
+ /*
+ * verify if the required irq has already been requested for
+ * another ISI Card, if so we already have it, else request it
+ */
+ request = YES;
+ for(card = 0; card < count; card++)
+ if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) {
+ request = NO;
+ if ((isi_card[count].isa == NO) && (isi_card[card].isa == NO))
+ break;
+ /*
+ * ISA cards cannot share interrupts with other
+ * PCI or ISA devices hence disable this card.
+ */
release_region(isi_card[count].base,16);
- isi_card[count].base=0;
+ isi_card[count].base = 0;
+ break;
}
- else {
- printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n",
- count+1, isi_card[count].base, isi_card[count].irq);
+ flag=0;
+ if(isi_card[count].isa == NO)
+ flag |= SA_SHIRQ;
- irq_to_board[isi_card[count].irq]=&isi_card[count];
- done++;
+ if (request == YES) {
+ if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT|flag, ISICOM_NAME, NULL)) {
+ printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n",
+ isi_card[count].irq, count+1);
+ release_region(isi_card[count].base,16);
+ isi_card[count].base=0;
+ }
+ else {
+ printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n",
+ count+1, isi_card[count].base, isi_card[count].irq);
+
+ irq_to_board[isi_card[count].irq]=&isi_card[count];
+ done++;
+ }
}
}
}
@@ -1787,14 +1856,24 @@ static int register_isr(void)
static void unregister_isr(void)
{
- int count;
- for (count=0; count < BOARD_COUNT; count++ )
+ int count, card;
+ unsigned char freeirq;
+ for (count=0; count < BOARD_COUNT; count++ ) {
if (isi_card[count].base) {
- free_irq(isi_card[count].irq, NULL);
+ freeirq = YES;
+ for(card = 0; card < count; card++)
+ if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) {
+ freeirq = NO;
+ break;
+ }
+ if (freeirq == YES) {
+ free_irq(isi_card[count].irq, NULL);
#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1);
-#endif
+ printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1);
+#endif
+ }
}
+ }
}
static int isicom_init(void)
@@ -1883,29 +1962,75 @@ MODULE_PARM_DESC(irq, "Interrupts for the cards");
int init_module(void)
{
- int retval, card;
-
- for(card=0; card < BOARD_COUNT; card++)
- {
- isi_card[card].base=io[card];
- isi_card[card].irq=irq[card];
+ struct pci_dev *dev = NULL;
+ int retval, card, idx, count;
+ unsigned char pciirq;
+ unsigned int ioaddr;
+
+ card = 0;
+ for(idx=0; idx < BOARD_COUNT; idx++) {
+ if (io[idx]) {
+ isi_card[idx].base=io[idx];
+ isi_card[idx].irq=irq[idx];
+ isi_card[idx].isa=YES;
+ card++;
+ }
+ else {
+ isi_card[idx].base = 0;
+ isi_card[idx].irq = 0;
+ }
}
- for (card=0 ;card < BOARD_COUNT; card++) {
- if (!((isi_card[card].irq==2)||(isi_card[card].irq==3)||
- (isi_card[card].irq==4)||(isi_card[card].irq==5)||
- (isi_card[card].irq==7)||(isi_card[card].irq==10)||
- (isi_card[card].irq==11)||(isi_card[card].irq==12)||
- (isi_card[card].irq==15))) {
+ for (idx=0 ;idx < card; idx++) {
+ if (!((isi_card[idx].irq==2)||(isi_card[idx].irq==3)||
+ (isi_card[idx].irq==4)||(isi_card[idx].irq==5)||
+ (isi_card[idx].irq==7)||(isi_card[idx].irq==10)||
+ (isi_card[idx].irq==11)||(isi_card[idx].irq==12)||
+ (isi_card[idx].irq==15))) {
- if (isi_card[card].base) {
+ if (isi_card[idx].base) {
printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n",
- isi_card[card].irq, card+1);
- isi_card[card].base=0;
+ isi_card[idx].irq, idx+1);
+ isi_card[idx].base=0;
+ card--;
}
}
}
+ if (pci_present() && (card < BOARD_COUNT)) {
+ for (idx=0; idx < DEVID_COUNT; idx++) {
+ dev = NULL;
+ for (;;){
+ if (!(dev = pci_find_device(VENDOR_ID, device_id[idx], dev)))
+ break;
+ if (card >= BOARD_COUNT)
+ break;
+
+ /* found a PCI ISI card! */
+ ioaddr = dev->resource[3].start; /* i.e at offset 0x1c in the
+ * PCI configuration register
+ * space.
+ */
+ ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+ pciirq = dev->irq;
+ printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]);
+ /*
+ * allot the first empty slot in the array
+ */
+ for (count=0; count < BOARD_COUNT; count++) {
+ if (isi_card[count].base == 0) {
+ isi_card[count].base = ioaddr;
+ isi_card[count].irq = pciirq;
+ isi_card[count].isa = NO;
+ card++;
+ break;
+ }
+ }
+ }
+ if (card >= BOARD_COUNT) break;
+ }
+ }
+
if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) {
printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n");
return -EIO;
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index b689bb7a5..5176f28f4 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -4,7 +4,7 @@
* istallion.c -- stallion intelligent multiport serial driver.
*
* Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au).
- * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer.
*
* This code is loosely based on the Linux serial driver, written by
* Linus Torvalds, Theodore T'so and others.
@@ -167,7 +167,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.5.1";
+static char *stli_drvversion = "5.6.0";
static char *stli_serialname = "ttyE";
static char *stli_calloutname = "cue";
@@ -186,7 +186,7 @@ static int stli_refcount;
* is already swapping a shared buffer won't make things any worse.
*/
static char *stli_tmpwritebuf = (char *) NULL;
-static struct semaphore stli_tmpwritesem = MUTEX;
+static DECLARE_MUTEX(stli_tmpwritesem);
#define STLI_TXBUFSIZE 4096
@@ -3375,6 +3375,9 @@ static inline int stli_initports(stlibrd_t *brdp)
portp->closing_wait = 30 * HZ;
portp->tqhangup.routine = stli_dohangup;
portp->tqhangup.data = portp;
+ init_waitqueue_head(&portp->open_wait);
+ init_waitqueue_head(&portp->close_wait);
+ init_waitqueue_head(&portp->raw_wait);
portp->normaltermios = stli_deftermios;
portp->callouttermios = stli_deftermios;
panelport++;
@@ -4387,7 +4390,7 @@ stli_donestartup:
* Probe and initialize the specified board.
*/
-__initfunc(static int stli_brdinit(stlibrd_t *brdp))
+static int __init stli_brdinit(stlibrd_t *brdp)
{
#if DEBUG
printk("stli_brdinit(brdp=%x)\n", (int) brdp);
@@ -4671,16 +4674,16 @@ static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp)
#if DEBUG
printk("%s(%d): BAR[]=%x,%x,%x,%x\n", __FILE__, __LINE__,
- devp->base_address[0], devp->base_address[1],
- devp->base_address[2], devp->base_address[3]);
+ devp->resource[0].start, devp->resource[1].start,
+ devp->resource[2].start, devp->resource[3].start);
#endif
/*
* We have all resources from the board, so lets setup the actual
* board structure now.
*/
- brdp->iobase = (devp->base_address[3] & PCI_BASE_ADDRESS_IO_MASK);
- brdp->memaddr = (devp->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK);
+ brdp->iobase = (devp->resource[3].start & PCI_BASE_ADDRESS_IO_MASK);
+ brdp->memaddr = (devp->resource[2].start & PCI_BASE_ADDRESS_MEM_MASK);
stli_brdinit(brdp);
return(0);
@@ -5305,7 +5308,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
/*****************************************************************************/
-__initfunc(int stli_init(void))
+int __init stli_init(void)
{
printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
diff --git a/drivers/char/joystick/joystick.c b/drivers/char/joystick/joystick.c
index 4d9d94aa1..941f1795d 100644
--- a/drivers/char/joystick/joystick.c
+++ b/drivers/char/joystick/joystick.c
@@ -42,8 +42,9 @@
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
#include <linux/poll.h>
#endif
@@ -525,8 +526,8 @@ static int js_read(struct inode *inode, struct file *file, char *buf, int count)
if (GOF(curl->tail) == jd->bhead && curl->startup == jd->num_axes + jd->num_buttons) {
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&jd->wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
while (GOF(curl->tail) == jd->bhead) {
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index c25f24bc4..def0b7c19 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -155,6 +155,7 @@ struct pt_regs * kbd_pt_regs;
#ifdef CONFIG_MAGIC_SYSRQ
static int sysrq_pressed;
+int sysrq_enabled = 1;
#endif
/*
@@ -247,7 +248,7 @@ void handle_scancode(unsigned char scancode, int down)
sysrq_pressed = !up_flag;
return;
} else if (sysrq_pressed) {
- if (!up_flag) {
+ if (!up_flag && sysrq_enabled) {
handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
return;
}
@@ -916,7 +917,7 @@ static void kbd_bh(void)
}
}
-__initfunc(int kbd_init(void))
+int __init kbd_init(void)
{
int i;
struct kbd_struct kbd0;
diff --git a/drivers/char/logibusmouse.c b/drivers/char/logibusmouse.c
new file mode 100644
index 000000000..d8c7d37dd
--- /dev/null
+++ b/drivers/char/logibusmouse.c
@@ -0,0 +1,157 @@
+/*
+ * Logitech Bus Mouse Driver for Linux
+ * by James Banks
+ *
+ * Mods by Matthew Dillon
+ * calls verify_area()
+ * tracks better when X is busy or paging
+ *
+ * Heavily modified by David Giller
+ * changed from queue- to counter- driven
+ * hacked out a (probably incorrect) mouse_select
+ *
+ * Modified again by Nathan Laredo to interface with
+ * 0.96c-pl1 IRQ handling changes (13JUL92)
+ * didn't bother touching select code.
+ *
+ * Modified the select() code blindly to conform to the VFS
+ * requirements. 92.07.14 - Linus. Somebody should test it out.
+ *
+ * Modified by Johan Myreen to make room for other mice (9AUG92)
+ * removed assignment chr_fops[10] = &mouse_fops; see mouse.c
+ * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
+ * renamed this file mouse.c => busmouse.c
+ *
+ * Minor addition by Cliff Matthews
+ * added fasync support
+ *
+ * Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
+ *
+ * Replaced dumb busy loop with udelay() 16 Nov 95
+ * Nathan Laredo <laredo@gnu.ai.mit.edu>
+ *
+ * Track I/O ports with request_region(). 12 Dec 95 Philip Blundell
+ *
+ * Converted to use new generic busmouse code. 5 Apr 1998
+ * Russell King <rmk@arm.uk.linux.org>
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/logibusmouse.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#include "busmouse.h"
+
+static int msedev;
+static int mouse_irq = MOUSE_IRQ;
+
+#ifdef MODULE
+MODULE_PARM(mouse_irq, "i");
+#endif
+
+void __init bmouse_setup(char *str, int *ints)
+{
+ if (ints[0] > 0)
+ mouse_irq=ints[1];
+}
+
+static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ char dx, dy;
+ unsigned char buttons;
+
+ outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
+ dx = (inb(MSE_DATA_PORT) & 0xf);
+ outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
+ dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
+ outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
+ dy = (inb(MSE_DATA_PORT) & 0xf);
+ outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
+ buttons = inb(MSE_DATA_PORT);
+ dy |= (buttons & 0xf) << 4;
+ buttons = ((buttons >> 5) & 0x07);
+ busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
+ MSE_INT_ON();
+}
+
+/*
+ * close access to the mouse
+ */
+static int close_mouse(struct inode * inode, struct file * file)
+{
+ MSE_INT_OFF();
+ free_irq(mouse_irq, NULL);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * open access to the mouse
+ */
+
+static int open_mouse(struct inode * inode, struct file * file)
+{
+ if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL))
+ return -EBUSY;
+ MOD_INC_USE_COUNT;
+ MSE_INT_ON();
+ return 0;
+}
+
+static struct busmouse busmouse = {
+ LOGITECH_BUSMOUSE, "busmouse", open_mouse, close_mouse, 7
+};
+
+int __init logi_busmouse_init(void)
+{
+ if (check_region(LOGIBM_BASE, LOGIBM_EXTENT))
+ return -EIO;
+
+ outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
+ outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
+ udelay(100L); /* wait for reply from mouse */
+ if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE)
+ return -EIO;
+
+ outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
+ MSE_INT_OFF();
+
+ request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse");
+
+ msedev = register_busmouse(&busmouse);
+ if (msedev < 0)
+ printk(KERN_WARNING "Unable to register busmouse driver.\n");
+ else
+ printk(KERN_INFO "Logitech busmouse installed.\n");
+ return msedev < 0 ? msedev : 0;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ return logi_busmouse_init();
+}
+
+void cleanup_module(void)
+{
+ unregister_busmouse(msedev);
+ release_region(LOGIBM_BASE, LOGIBM_EXTENT);
+}
+#endif
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 7aa14a886..4092d6b55 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -333,6 +333,9 @@ static ssize_t lp_write(struct file * file, const char * buf,
if (copy_from_user (kbuf, buf, copy_size))
return -EFAULT;
+ if (down_interruptible (&lp_table[minor].port_mutex))
+ return -EINTR;
+
/* Claim Parport or sleep until it becomes available
*/
lp_parport_claim (minor);
@@ -341,10 +344,6 @@ static ssize_t lp_write(struct file * file, const char * buf,
parport_negotiate (port, IEEE1284_MODE_COMPAT);
do {
- /* Wait until lp_read has finished. */
- if (down_interruptible (&lp_table[minor].port_mutex))
- break;
-
/* Write the data. */
written = parport_write (port, kbuf, copy_size);
if (written >= 0) {
@@ -354,8 +353,6 @@ static ssize_t lp_write(struct file * file, const char * buf,
retv += written;
}
- up (&lp_table[minor].port_mutex);
-
if (signal_pending (current)) {
if (retv == 0)
retv = -EINTR;
@@ -392,6 +389,8 @@ static ssize_t lp_write(struct file * file, const char * buf,
lp_parport_release (minor);
+ up (&lp_table[minor].port_mutex);
+
return retv;
}
@@ -414,29 +413,28 @@ static ssize_t lp_read(struct file * file, char * buf,
if (count > LP_BUFFER_SIZE)
count = LP_BUFFER_SIZE;
+ if (down_interruptible (&lp_table[minor].port_mutex))
+ return -EINTR;
+
lp_parport_claim (minor);
- if (!down_interruptible (&lp_table[minor].port_mutex)) {
- for (;;) {
- retval = parport_read (port, kbuf, count);
+ for (;;) {
+ retval = parport_read (port, kbuf, count);
- if (retval)
- break;
+ if (retval)
+ break;
- if (file->f_flags & O_NONBLOCK)
- break;
+ if (file->f_flags & O_NONBLOCK)
+ break;
- /* Wait for an interrupt. */
- interruptible_sleep_on_timeout (&lp_table[minor].waitq,
- LP_TIMEOUT_POLLED);
+ /* Wait for an interrupt. */
+ interruptible_sleep_on_timeout (&lp_table[minor].waitq,
+ LP_TIMEOUT_POLLED);
- if (signal_pending (current)) {
- retval = -EINTR;
- break;
- }
+ if (signal_pending (current)) {
+ retval = -EINTR;
+ break;
}
-
- up (&lp_table[minor].port_mutex);
}
lp_parport_release (minor);
@@ -444,6 +442,8 @@ static ssize_t lp_read(struct file * file, char * buf,
if (retval > 0 && copy_to_user (buf, kbuf, retval))
retval = -EFAULT;
+ up (&lp_table[minor].port_mutex);
+
return retval;
}
@@ -711,7 +711,7 @@ static int reset = 0;
static int parport_ptr = 0;
-__initfunc(void lp_setup(char *str, int *ints))
+void __init lp_setup(char *str, int *ints)
{
if (!str) {
if (ints[0] == 0 || ints[1] == 0) {
@@ -755,6 +755,17 @@ static int lp_register(int nr, struct parport *port)
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
(port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
+#ifdef CONFIG_LP_CONSOLE
+ if (!nr) {
+ if (port->modes & PARPORT_MODE_SAFEININT) {
+ register_console (&lpcons);
+ printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP);
+ } else
+ printk (KERN_ERR "lp%d: cannot run console on %s\n",
+ CONSOLE_LP, port->name);
+ }
+#endif
+
return 0;
}
@@ -842,12 +853,6 @@ int __init lp_init (void)
printk (KERN_INFO "lp: (is IEEE 1284.3 support enabled?)\n");
#endif
}
-#ifdef CONFIG_LP_CONSOLE
- else {
- register_console (&lpcons);
- printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP);
- }
-#endif
return 0;
}
diff --git a/drivers/char/lp_intern.c b/drivers/char/lp_intern.c
deleted file mode 100644
index e4fc30403..000000000
--- a/drivers/char/lp_intern.c
+++ /dev/null
@@ -1,364 +0,0 @@
-
-/*
- * split into mid and low-level for better support of different hardware
- * by Joerg Dorchain (dorchain@mpi-sb.mpg.de)
- *
- * Amiga printer device by Michael Rausch (linux@uni-koblenz.de);
- * Atari support added by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de);
- * based upon work from
- *
- * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
- * Copyright (C) 1992,1993 by Michael K. Johnson
- * - Thanks much to Gunter Windau for pointing out to me where the error
- * checking ought to be.
- * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
- */
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <asm/irq.h>
-#include <asm/setup.h>
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#endif
-#ifdef CONFIG_ATARI
-#include <linux/delay.h>
-#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);
-static int lp_int_pout(int);
-static int lp_int_online(int);
-
-
-static void
-lp_int_out (int c, int dev)
-{
- switch (m68k_machtype)
- {
-#ifdef CONFIG_AMIGA
- case MACH_AMIGA:
- {
- int wait = 0;
- while (wait != lp_table[dev]->wait) wait++;
- ciaa.prb = c;
- }
- break;
-#endif
-#ifdef CONFIG_ATARI
- case MACH_ATARI:
- {
- int wait = 0;
- sound_ym.rd_data_reg_sel = 15;
- sound_ym.wd_data = c;
- sound_ym.rd_data_reg_sel = 14;
- while (wait != lp_table[dev]->wait) wait++;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
- while (wait) wait--;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
- 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
- }
-}
-
-static int
-lp_int_busy (int dev)
-{
- switch (m68k_machtype)
- {
-#ifdef CONFIG_AMIGA
- case MACH_AMIGA:
- return ciab.pra & 1;
-#endif
-#ifdef CONFIG_ATARI
- 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;
- }
-}
-
-static int
-lp_int_pout (int dev)
-{
- switch (m68k_machtype)
- {
-#ifdef CONFIG_AMIGA
- case MACH_AMIGA:
- return ciab.pra & 2;
-#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;
- }
-}
-
-static int
-lp_int_online (int dev)
-{
- switch (m68k_machtype)
- {
-#ifdef CONFIG_AMIGA
- case MACH_AMIGA:
- return ciab.pra & 4;
-#endif
-#ifdef CONFIG_ATARI
- 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;
- }
-}
-
-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);
-}
-
-static int lp_int_open(int dev)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-static void lp_int_release(int dev)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static struct lp_struct tab = {
- "Builtin parallel port", /* name */
- 0, /* irq */
- lp_int_out,
- lp_int_busy,
- lp_int_pout,
- lp_int_online,
- 0,
- NULL, /* ioctl */
- lp_int_open,
- lp_int_release,
- LP_EXIST,
- LP_INIT_CHAR,
- LP_INIT_TIME,
- LP_INIT_WAIT,
- NULL,
- NULL,
-};
-
-__initfunc(int lp_internal_init(void))
-{
-#ifdef CONFIG_AMIGA
- if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL))
- {
- ciaa.ddrb = 0xff;
- ciab.ddra &= 0xf8;
- if (lp_irq)
- tab.irq = request_irq(IRQ_AMIGA_CIAA_FLG, lp_int_interrupt,
- 0, "builtin printer port", lp_int_interrupt);
- tab.base = (void *) &ciaa.prb; /* dummy, not used */
- tab.type = LP_AMIGA;
- }
-#endif
-#ifdef CONFIG_ATARI
- if (MACH_IS_ATARI)
- {
- unsigned long flags;
-
- save_flags(flags);
- cli();
- sound_ym.rd_data_reg_sel = 7;
- sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
- restore_flags(flags);
- if (lp_irq)
- tab.irq = request_irq(IRQ_MFP_BUSY, lp_int_interrupt,
- IRQ_TYPE_SLOW, "builtin printer port", lp_int_interrupt);
- tab.base = (void *) &sound_ym.wd_data; /* dummy, not used */
- 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");
- if (lp_irq) {
-#ifdef CONFIG_AMIGA
- if (MACH_IS_AMIGA)
- free_irq(IRQ_AMIGA_CIAA_FLG, lp_int_interrupt);
-#endif
-#ifdef CONFIG_ATARI
- 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;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-int init_module(void)
-{
-return lp_internal_init();
-}
-
-void cleanup_module(void)
-{
-if (lp_irq) {
-#ifdef CONFIG_AMIGA
- if (MACH_IS_AMIGA)
- free_irq(IRQ_AMIGA_CIAA_FLG, lp_int_interrupt);
-#endif
-#ifdef CONFIG_ATARI
- 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);
-}
-#endif
diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c
deleted file mode 100644
index 7eecf2965..000000000
--- a/drivers/char/lp_m68k.c
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * split in two parts for better support of different hardware
- * by Joerg Dorchain (dorchain@mpi-sb.mpg.de)
- *
- * Amiga printer device by Michael Rausch (linux@uni-koblenz.de);
- * Atari support added by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de);
- * based upon work from
- *
- * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
- * Copyright (C) 1992,1993 by Michael K. Johnson
- * - Thanks much to Gunter Windau for pointing out to me where the error
- * checking ought to be.
- * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
- */
-
-/* 01/17/95: Matthias Welwarsky (dg8y@rs11.hrz.th-darmstadt.de)
- * lp_write(): rewritten from scratch
- * lp_interrupt(): fixed cli()/sti()-bug
- *
- * 95/05/28: Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
- * lp_write() fixed to make it work again.
- * 95/08/18: Andreas Schwab
- * lp_write_interrupt: fix race condition
- *
- * * CAUTION, please do check! *
- *
- * on 68000-based machines sti() must NEVER appear in interrupt driven
- * code. The 68k-CPU has a priority-based interrupt scheme. while an interrupt
- * with a certain priority is executed, all requests with lower or same
- * priority get locked out. executing the sti()-macro allows ANY interrupt
- * to be served. this really causes BIG trouble!
- * to protect an interrupt driven routine against being interrupted
- * (if absolutely needed!) one should use save_flags();cli()/restore_flags()!
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-
-#ifdef CONFIG_AMIGA
-#ifdef CONFIG_MULTIFACE_III_LP
-#include <linux/lp_mfc.h>
-#endif
-#endif
-
-#include <linux/lp_m68k.h>
-#include <linux/lp_intern.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-
-/*
- * why bother around with the pio driver when the interrupt works;
- * so, for "security" reasons only, it's configurable here.
- * saves some bytes, at least ...
- */
-#define FORCE_POLLING 0
-#define FORCE_INTERRUPT 1
-/*
- * PREFER_INTERRUPT doesn't make much sense on m68k.
- * it is preserved here in case of joining with the i386 driver
- *
-#define PREFER_INTERRUPT 2
- */
-
-#define WHICH_DRIVER FORCE_INTERRUPT
-
-struct lp_struct *lp_table[MAX_LP] = {NULL,};
-
-static int max_lp; /* the real number of devices */
-
-/*
- * All my debugging code assumes that you debug with only one printer at
- * a time. RWWH
- */
-
-#define LP_DEBUG
-#undef LP_DEBUG
-
-
-#if WHICH_DRIVER != FORCE_INTERRUPT
-#ifdef LP_DEBUG
-static int lp_max_count = 1;
-#endif
-
-static int lp_char_polled(char lpchar, int dev)
-{
- unsigned long count = 0;
-
- do {
- count ++;
- if (current->need_resched)
- schedule();
- } while (lp_table[dev]->lp_is_busy(dev) && count < lp_table[dev]->chars);
-
- if (count == lp_table[dev]->chars) {
- return 0;
- /* we timed out, and the character was /not/ printed */
- }
-#ifdef LP_DEBUG
- if (count > lp_max_count) {
- printk("lp success after %d counts.\n",count);
- lp_max_count = count;
- }
-#endif
- lp_table[dev]->lp_out(lpchar, dev);
- return 1;
-}
-#endif
-
-
-#ifdef LP_DEBUG
-unsigned int lp_total_chars = 0;
-unsigned int lp_last_call = 0;
-#endif
-
-
-#if WHICH_DRIVER != FORCE_POLLING
-static __inline__ int lp_char_interrupt(char lpchar, int dev)
-{
- if (!lp_table[dev]->lp_is_busy(dev)) {
- lp_table[dev]->lp_out(lpchar,dev);
- return 1;
- }
- return 0;
-}
-
-static int lp_error;
-
-void lp_interrupt(int dev)
-{
- if (dev >= 0 && dev < MAX_LP && lp_table[dev]->do_print)
- {
- if (lp_table[dev]->copy_size)
- {
- unsigned long flags;
- save_flags(flags);
- cli();
- if (lp_char_interrupt(lp_table[dev]->lp_buffer[lp_table[dev]->bytes_written], dev)) {
- --lp_table[dev]->copy_size;
- ++lp_table[dev]->bytes_written;
- restore_flags(flags);
- }
- else
- {
- lp_table[dev]->do_print = 0;
- restore_flags(flags);
- lp_error = 1;
- wake_up_interruptible(&lp_table[dev]->lp_wait_q);
- }
- }
- else
- {
- lp_table[dev]->do_print = 0;
- lp_error = 0;
- wake_up_interruptible(&lp_table[dev]->lp_wait_q);
- }
-
- }
-}
-
-#if WHICH_DRIVER == FORCE_INTERRUPT
-static ssize_t lp_write(struct file *file, const char *buf,
- size_t count, loff_t *ppos)
-#else
-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;
- long timeout;
- int rc;
- int dev = MINOR(inode->i_rdev);
-
- do {
- lp_table[dev]->do_print = 0; /* disable lp_interrupt() */
- 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);
- 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 */
- lp_table[dev]->do_print = 1; /* enable lp_interrupt() */
- if (lp_char_interrupt(lp_table[dev]->lp_buffer[lp_table[dev]->bytes_written], dev)) {
- ++lp_table[dev]->bytes_written;
- --lp_table[dev]->copy_size;
- lp_error = 0;
- } else { /* something went wrong */
- lp_table[dev]->do_print = 0; /* disable lp_interrupt() */
- lp_error = 1; /* printer caused error */
- }
- if (lp_error) {
-
- /* something blocked printing, so we don't want to sleep too long,
- in case we have to rekick the interrupt */
-
- timeout = LP_TIMEOUT_POLLED;
- } else {
- timeout = LP_TIMEOUT_INTERRUPT;
- }
-
- interruptible_sleep_on_timeout(&lp_table[dev]->lp_wait_q, timeout);
- restore_flags(flags);
-
- /* we're up again and running. we first disable lp_interrupt(), then
- check what happened meanwhile */
-
- lp_table[dev]->do_print = 0;
- rc = total_bytes_written + lp_table[dev]->bytes_written;
-
- if (signal_pending(current)) {
- if (rc == 0)
- rc = -EINTR;
- return rc;
- }
- if (lp_error) {
-
- /* an error has occurred, maybe in lp_interrupt().
- figure out the type of error, exit on request or if nothing has
- been printed at all. */
-
- if (lp_table[dev]->lp_has_pout(dev)) {
- printk(KERN_NOTICE "lp%d: paper-out\n",dev);
- if (!rc) rc = -ENOSPC;
- } else if (!lp_table[dev]->lp_is_online(dev)) {
- printk(KERN_NOTICE "lp%d: off-line\n",dev);
- if (!rc) rc = -EIO;
- } else if (lp_table[dev]->lp_is_busy(dev)) {
- printk(KERN_NOTICE "lp%d: on fire\n",dev);
- if (!rc) rc = -EIO;
- }
- if (lp_table[dev]->flags & LP_ABORT)
- return rc;
- }
- /* check if our buffer was completely printed, if not, most likely
- an unsolved error blocks the printer. As we can`t do anything
- against, we start all over again. Else we set the read-pointer
- of the buffer and count the printed characters */
-
- if (!lp_table[dev]->copy_size) {
- total_bytes_written += lp_table[dev]->bytes_written;
- buf += lp_table[dev]->bytes_written;
- count -= lp_table[dev]->bytes_written;
- }
- }
- } while (count > 0);
- return total_bytes_written;
-}
-#else
-void (*lp_interrupt)() = NULL;
-#endif
-
-#if WHICH_DRIVER != FORCE_INTERRUPT
-#if WHICH_DRIVER == FORCE_POLLING
-static ssize_t lp_write(struct file *file, const char *buf,
- size_t count, loff_t *ppos)
-#else
-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);
-
-#ifdef LP_DEBUG
- if (time_after(jiffies, lp_last_call + lp_table[dev]->time)) {
- lp_total_chars = 0;
- lp_max_count = 1;
- }
- lp_last_call = jiffies;
-#endif
-
- temp = buf;
- while (count > 0) {
- 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)
- 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)
- 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)
- error = -EIO;
- }
- else
- timeout = lp_table[dev]->time;
-
- /* check for signals before going to sleep */
- if (error == 0 && signal_pending(current))
- error = -EINTR;
- if (error) {
- if (temp != buf)
- return temp-buf;
- else
- return error;
- }
-
-#ifdef LP_DEBUG
- printk("lp sleeping at %d characters for %d jiffies\n",
- lp_total_chars, timeout);
- lp_total_chars = 0;
-#endif
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(timeout);
- }
- }
- return temp - buf;
-}
-#endif
-
-unsigned int lp_irq = 0;
-
-#if WHICH_DRIVER == PREFER_INTERRUPT
-static ssize_t lp_write(struct file *file, const char *buf, size_t count,
- loff_t *ppos)
-{
- if (lp_irq)
- return lp_write_interrupt(file, buf, count, ppos);
- else
- return lp_write_polled(file, buf, count, ppos);
-}
-#endif
-
-static long long lp_lseek(struct file * file, long long offset, int origin)
-{
- return -ESPIPE;
-}
-
-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)
- goto out_err;
-
- if (!lp_table[dev]) {
- char modname[30];
-
- sprintf(modname, "char-major-%d-%d", LP_MAJOR, dev);
- request_module(modname);
- }
- if (!lp_table[dev])
- goto out_err;
- if (!(lp_table[dev]->flags & LP_EXIST))
- goto out_err;
- ret = -EBUSY;
- if (lp_table[dev]->flags & LP_BUSY)
- 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;
- goto out_err;
- }
- return ret;
-
-out_err:
- MOD_DEC_USE_COUNT;
- return ret;
-}
-
-static int lp_release(struct inode *inode, struct file *file)
-{
- int dev =MINOR(inode->i_rdev);
-
- lp_table[dev]->flags &= ~LP_BUSY;
- lp_table[dev]->lp_release(dev);
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-
-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 = -ENODEV;
-
-#ifdef LP_DEBUG
- printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
-#endif
- if (minor >= max_lp)
- goto out;
- if (!(lp_table[minor]->flags & LP_EXIST))
- goto out;
- retval = 0;
- switch (cmd) {
- case LPTIME:
- lp_table[minor]->time = arg;
- break;
- case LPCHAR:
- lp_table[minor]->chars = arg;
- break;
- case LPABORT:
- if (arg)
- lp_table[minor]->flags |= LP_ABORT;
- else
- lp_table[minor]->flags &= ~LP_ABORT;
- break;
- case LPWAIT:
- lp_table[minor]->wait = arg;
- break;
- case LPSETIRQ:
- case LPGETIRQ:
- retval = lp_irq;
- break;
- default:
- retval = -EINVAL;
- if (lp_table[minor]->lp_ioctl)
- retval = lp_table[minor]->lp_ioctl(minor, cmd, arg);
- }
-out:
- return retval;
-}
-
-
-static struct file_operations lp_fops = {
- lp_lseek,
- NULL, /* lp_read */
- lp_write,
- NULL, /* lp_readdir */
- NULL, /* lp_poll */
- lp_ioctl,
- NULL, /* lp_mmap */
- lp_open,
- NULL, /* flush */
- lp_release
-};
-
-EXPORT_SYMBOL(lp_table);
-EXPORT_SYMBOL(lp_irq);
-EXPORT_SYMBOL(lp_interrupt);
-EXPORT_SYMBOL(register_parallel);
-EXPORT_SYMBOL(unregister_parallel);
-
-__initfunc(int lp_m68k_init(void))
-{
- extern char m68k_debug_device[];
-
- if (!strcmp( m68k_debug_device, "par" ))
- return -EBUSY;
-
- if (register_chrdev(LP_MAJOR,"lp", &lp_fops)) {
- printk(KERN_ERR "unable to get major %d for line printer\n", LP_MAJOR);
- return -ENXIO;
- }
-
-#if WHICH_DRIVER == FORCE_POLLING
- lp_irq = 0;
- printk(KERN_INFO "lp_init: lp using polling driver\n");
-#else
-
- lp_irq = 1;
- printk(KERN_INFO "lp_init: lp using interrupt driver\n");
-#endif
-
-#ifndef MODULE
- lp_internal_init();
-#ifdef CONFIG_MULTIFACE_III_LP
- lp_mfc_init();
-#endif
-#endif
- return 0;
-}
-
-/*
- * Currently we do not accept any lp-parameters, but that may change.
- */
-__initfunc(void lp_setup(char *str, int *ints))
-{
-}
-
-#ifdef MODULE
-int init_module(void)
-{
- return lp_m68k_init();
-}
-
-void cleanup_module(void)
-{
- unregister_chrdev(LP_MAJOR, "lp");
-}
-#endif
-
-/*
- * (un-)register for hardware drivers
- * tab is an inititalised lp_struct, dev the desired minor
- * if dev < 0, let the driver choose the first free minor
- * if successful return the minor, else -1
- */
-int register_parallel(struct lp_struct *tab, int dev)
-{
-if (dev < 0) {
- dev = 0;
- while ((dev < MAX_LP) && (lp_table[dev] != NULL))
- dev++;
-}
-if (dev > MAX_LP)
- return -1;
-if (lp_table[dev] != NULL)
- return -1;
-lp_table[dev] = tab;
-printk(KERN_INFO "lp%d: %s at 0x%08lx\n", dev, tab->name, (long)tab->base);
-return dev;
-}
-
-#ifdef CONFIG_MODULES
-void unregister_parallel(int dev)
-{
-if ((dev < 0) || (dev > MAX_LP) || (lp_table[dev] == NULL))
- printk(KERN_ERR "WARNING: unregister_parallel for non-existant device ignored!\n");
-else
- lp_table[dev] = NULL;
-}
-#endif
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index d83775f7c..ff3158e96 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -16,6 +16,8 @@
#include <linux/init.h>
#include <linux/joystick.h>
#include <linux/i2c.h>
+#include <linux/raw.h>
+#include <linux/capability.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -266,6 +268,7 @@ static ssize_t write_kmem(struct file * file, const char * buf,
return do_write_mem(file, (void*)p, p, buf, count, ppos);
}
+#if !defined(CONFIG_PPC) && !defined(__mc68000__)
static ssize_t read_port(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
@@ -303,6 +306,7 @@ static ssize_t write_port(struct file * file, const char * buf,
*ppos = i;
return tmp-buf;
}
+#endif
static ssize_t read_null(struct file * file, char * buf,
size_t count, loff_t *ppos)
@@ -458,11 +462,18 @@ static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
}
}
+static int open_port(struct inode * inode, struct file * filp)
+{
+ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
#define mmap_kmem mmap_mem
#define zero_lseek null_lseek
#define full_lseek null_lseek
#define write_zero write_null
#define read_full read_zero
+#define open_mem open_port
+#define open_kmem open_mem
static struct file_operations mem_fops = {
memory_lseek,
@@ -472,7 +483,7 @@ static struct file_operations mem_fops = {
NULL, /* mem_poll */
NULL, /* mem_ioctl */
mmap_mem,
- NULL, /* no special open code */
+ open_mem,
NULL, /* flush */
NULL, /* no special release code */
NULL /* fsync */
@@ -486,7 +497,7 @@ static struct file_operations kmem_fops = {
NULL, /* kmem_poll */
NULL, /* kmem_ioctl */
mmap_kmem,
- NULL, /* no special open code */
+ open_kmem,
NULL, /* flush */
NULL, /* no special release code */
NULL /* fsync */
@@ -506,6 +517,7 @@ static struct file_operations null_fops = {
NULL /* fsync */
};
+#if !defined(CONFIG_PPC) && !defined(__mc68000__)
static struct file_operations port_fops = {
memory_lseek,
read_port,
@@ -514,11 +526,12 @@ static struct file_operations port_fops = {
NULL, /* port_poll */
NULL, /* port_ioctl */
NULL, /* port_mmap */
- NULL, /* no special open code */
+ open_port,
NULL, /* flush */
NULL, /* no special release code */
NULL /* fsync */
};
+#endif
static struct file_operations zero_fops = {
zero_lseek,
@@ -597,11 +610,12 @@ static struct file_operations memory_fops = {
NULL /* fsync */
};
-__initfunc(int chr_dev_init(void))
+int __init chr_dev_init(void)
{
if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
rand_initialize();
+ raw_init();
#ifdef CONFIG_USB
usb_init();
#endif
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 024706dc6..e9eec975c 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -28,7 +28,7 @@
* corrected by Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* Changes for kmod (from kerneld):
- Cyrus Durgin <cider@speakeasy.org>
+ * Cyrus Durgin <cider@speakeasy.org>
*/
#include <linux/module.h>
@@ -43,14 +43,13 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-#endif
#include <linux/tty.h>
#include <linux/selection.h>
#include <linux/kmod.h>
+#include "busmouse.h"
+
/*
* Head entry for the doubly linked miscdevice list
*/
@@ -62,14 +61,7 @@ static struct miscdevice misc_list = { 0, "head", NULL, &misc_list, &misc_list }
#define DYNAMIC_MINORS 64 /* like dynamic majors */
static unsigned char misc_minors[DYNAMIC_MINORS / 8];
-extern int bus_mouse_init(void);
-extern int qpmouse_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 sun_mouse_init(void);
-extern int adb_mouse_init(void);
+extern int psaux_init(void);
#ifdef CONFIG_SGI_NEWPORT_GFX
extern void gfx_register(void);
#endif
@@ -85,9 +77,12 @@ 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);
extern int pc110pad_init(void);
extern int pmu_device_init(void);
+extern int qpmouse_init(void);
+extern int ds1620_init(void);
+extern int nwbutton_init(void);
+extern int nwflash_init(void);
static int misc_read_proc(char *buf, char **start, off_t offset,
int len, int *eof, void *private)
@@ -184,7 +179,7 @@ int misc_deregister(struct miscdevice * misc)
EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);
-static struct proc_dir_entry *proc_misc;
+static struct proc_dir_entry *proc_misc;
int __init misc_init(void)
{
@@ -197,24 +192,6 @@ int __init misc_init(void)
#if defined CONFIG_82C710_MOUSE
qpmouse_init();
#endif
-#ifdef CONFIG_MS_BUSMOUSE
- ms_bus_mouse_init();
-#endif
-#ifdef CONFIG_ATIXL_BUSMOUSE
- atixl_busmouse_init();
-#endif
-#ifdef CONFIG_AMIGAMOUSE
- amiga_mouse_init();
-#endif
-#ifdef CONFIG_ATARIMOUSE
- atari_mouse_init();
-#endif
-#ifdef CONFIG_SUN_MOUSE
- sun_mouse_init();
-#endif
-#ifdef CONFIG_ADBMOUSE
- adb_mouse_init();
-#endif
#ifdef CONFIG_PC110_PAD
pc110pad_init();
#endif
@@ -239,9 +216,6 @@ int __init misc_init(void)
#ifdef CONFIG_DTLK
dtlk_init();
#endif
-#ifdef CONFIG_APM
- apm_bios_init();
-#endif
#ifdef CONFIG_H8
h8_init();
#endif
@@ -263,18 +237,12 @@ int __init misc_init(void)
#ifdef CONFIG_ATARI_DSP56K
dsp56k_init();
#endif
-#ifdef CONFIG_HFMODEM
- hfmodem_init();
-#endif
#ifdef CONFIG_NVRAM
nvram_init();
#endif
#ifdef CONFIG_MISC_RADIO
radio_init();
#endif
-#ifdef CONFIG_HFMODEM
- hfmodem_init();
-#endif
#ifdef CONFIG_PMAC_PBOOK
pmu_device_init();
#endif
@@ -284,6 +252,15 @@ int __init misc_init(void)
#ifdef CONFIG_SGI_IP22
streamable_init ();
#endif
+#ifdef CONFIG_DS1620
+ ds1620_init();
+#endif
+#ifdef CONFIG_NWBUTTON
+ nwbutton_init();
+#endif
+#ifdef CONFIG_NWFLASH
+ nwflash_init();
+#endif
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c
index f580be0bb..753c9d460 100644
--- a/drivers/char/msbusmouse.c
+++ b/drivers/char/msbusmouse.c
@@ -27,6 +27,9 @@
*
* Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
*
+ * Converted to use new generic busmouse code. 5 Apr 1998
+ * Russell King <rmk@arm.uk.linux.org>
+ *
* version 0.3b
*/
@@ -35,7 +38,7 @@
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/sched.h>
-#include <linux/busmouse.h>
+#include <linux/logibusmouse.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
@@ -48,14 +51,16 @@
#include <asm/system.h>
#include <asm/irq.h>
-static struct mouse_status mouse;
+#include "busmouse.h"
+
+static int msedev;
static int mouse_irq = MOUSE_IRQ;
#ifdef MODULE
MODULE_PARM(mouse_irq, "i");
#endif
-__initfunc(void msmouse_setup(char *str, int *ints))
+void __init msmouse_setup(char *str, int *ints)
{
if (ints[0] > 0)
mouse_irq=ints[1];
@@ -81,35 +86,17 @@ static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT);
- if (dx != 0 || dy != 0 || buttons != mouse.buttons || ((~buttons) & 0x07)) {
- add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
- mouse.buttons = buttons;
- mouse.dx += dx;
- mouse.dy += dy;
- mouse.ready = 1;
- wake_up_interruptible(&mouse.wait);
- if (mouse.fasyncptr)
- kill_fasync(mouse.fasyncptr, SIGIO);
- }
-}
-
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
- int retval;
-
- retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
- if (retval < 0)
- return retval;
- return 0;
+ /* why did the original have:
+ * if (dx != 0 || dy != 0 || buttons != mouse.buttons ||
+ * ((~buttons) & 0x07))
+ * ^^^^^^^^^^^^^^^^^^^ this?
+ */
+ busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
}
static int release_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(-1, file, 0);
- if (--mouse.active)
- return 0;
MS_MSE_INT_OFF();
- mouse.ready = 0;
free_irq(mouse_irq, NULL);
MOD_DEC_USE_COUNT;
return 0;
@@ -117,86 +104,24 @@ static int release_mouse(struct inode * inode, struct file * file)
static int open_mouse(struct inode * inode, struct file * file)
{
- if (!mouse.present)
- return -EINVAL;
- if (mouse.active++)
- return 0;
- if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL)) {
- mouse.active--;
+ if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL))
return -EBUSY;
- }
- mouse.ready = mouse.dx = mouse.dy = 0;
- mouse.buttons = 0x80;
+
outb(MS_MSE_START, MS_MSE_CONTROL_PORT);
MOD_INC_USE_COUNT;
MS_MSE_INT_ON();
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 i, dx, dy;
-
- if (count < 3)
- return -EINVAL;
- if (!mouse.ready)
- return -EAGAIN;
- put_user(mouse.buttons | 0x80, buffer);
- dx = mouse.dx < -127 ? -127 : mouse.dx > 127 ? 127 : mouse.dx;
- dy = mouse.dy < -127 ? 127 : mouse.dy > 127 ? -127 : -mouse.dy;
- put_user((char)dx, buffer + 1);
- put_user((char)dy, buffer + 2);
- for (i = 3; i < count; i++)
- put_user(0x00, buffer + i);
- mouse.dx -= dx;
- mouse.dy += dy;
- mouse.ready = 0;
- return i;
-}
-
-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 ms_bus_mouse_fops = {
- NULL, /* mouse_seek */
- read_mouse,
- write_mouse,
- NULL, /* mouse_readdir */
- mouse_poll, /* mouse_poll */
- NULL, /* mouse_ioctl */
- NULL, /* mouse_mmap */
- open_mouse,
- NULL, /* flush */
- release_mouse,
- NULL,
- fasync_mouse,
-};
-
-static struct miscdevice ms_bus_mouse = {
- MICROSOFT_BUSMOUSE, "msbusmouse", &ms_bus_mouse_fops
+static struct busmouse msbusmouse = {
+ MICROSOFT_BUSMOUSE, "msbusmouse", open_mouse, release_mouse, 0
};
-__initfunc(int ms_bus_mouse_init(void))
+int __init ms_bus_mouse_init(void)
{
+ int present = 0;
int mse_byte, i;
- mouse.present = mouse.active = mouse.ready = 0;
- mouse.buttons = 0x80;
- mouse.dx = mouse.dy = 0;
- init_waitqueue_head(&mouse.wait);
-
if (check_region(MS_MSE_CONTROL_PORT, 0x04))
return -ENODEV;
@@ -207,32 +132,30 @@ __initfunc(int ms_bus_mouse_init(void))
for (i = 0; i < 4; i++) {
if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte)
- mouse.present = 1;
+ present = 1;
else
- mouse.present = 0;
+ present = 0;
} else
- mouse.present = 0;
+ present = 0;
}
}
- if (mouse.present == 0)
+ if (present == 0)
return -EIO;
MS_MSE_INT_OFF();
request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse");
- printk(KERN_INFO "Microsoft BusMouse detected and installed.\n");
- misc_register(&ms_bus_mouse);
- return 0;
+ msedev = register_busmouse(&msbusmouse);
+ if (msedev < 0)
+ printk(KERN_WARNING "Unable to register msbusmouse driver.\n");
+ else
+ printk(KERN_INFO "Microsoft BusMouse detected and installed.\n");
+ return msedev < 0 ? msedev : 0;
}
-#ifdef MODULE
-int init_module(void)
+void ms_bus_mouse_exit(void)
{
- return ms_bus_mouse_init();
-}
-
-void cleanup_module(void)
-{
- misc_deregister(&ms_bus_mouse);
+ unregister_busmouse(msedev);
release_region(MS_MSE_CONTROL_PORT, 0x04);
}
-#endif
+module_init(ms_bus_mouse_init)
+module_exit(ms_bus_mouse_exit)
diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c
index 5791e149e..2990efbb6 100644
--- a/drivers/char/msp3400.c
+++ b/drivers/char/msp3400.c
@@ -795,9 +795,8 @@ static int msp3410d_thread(void *data)
UNLOCK_I2C_BUS(msp->bus);
/* wait 1 sec */
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + HZ;
- schedule();
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
if (signal_pending(current))
goto done;
if (msp->restart) {
@@ -992,16 +991,16 @@ msp3400c_mixer_llseek(struct file *file, loff_t offset, int origin)
}
static /*const*/ struct file_operations msp3400c_mixer_fops = {
- &msp3400c_mixer_llseek,
+ msp3400c_mixer_llseek,
NULL, /* read */
NULL, /* write */
NULL, /* readdir */
NULL, /* poll */
- &msp3400c_mixer_ioctl,
+ msp3400c_mixer_ioctl,
NULL, /* mmap */
- &msp3400c_mixer_open,
+ msp3400c_mixer_open,
NULL,
- &msp3400c_mixer_release,
+ msp3400c_mixer_release,
NULL, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
new file mode 100644
index 000000000..a2097967e
--- /dev/null
+++ b/drivers/char/n_r3964.c
@@ -0,0 +1,1488 @@
+/* r3964 linediscipline for linux
+ *
+ * -----------------------------------------------------------
+ * Copyright by
+ * Philips Automation Projects
+ * Kassel (Germany)
+ * http://www.pap-philips.de
+ * -----------------------------------------------------------
+ * This software may be used and distributed according to the terms of
+ * the GNU Public License, incorporated herein by reference.
+ *
+ * Author:
+ * L. Haag
+ *
+ * $Log: r3964.c,v $
+ * Revision 1.7 1999/28/08 11:41:50 dwmw2
+ * Port to 2.3 kernel
+ *
+ * Revision 1.6 1998/09/30 00:40:40 dwmw2
+ * Fixed compilation on 2.0.x kernels
+ * Updated to newly registered tty-ldisc number 9
+ *
+ * Revision 1.5 1998/09/04 21:57:36 dwmw2
+ * Signal handling bug fixes, port to 2.1.x.
+ *
+ * Revision 1.4 1998/04/02 20:26:59 lhaag
+ * select, blocking, ...
+ *
+ * Revision 1.3 1998/02/12 18:58:43 root
+ * fixed some memory leaks
+ * calculation of checksum characters
+ *
+ * Revision 1.2 1998/02/07 13:03:34 root
+ * ioctl read_telegram
+ *
+ * Revision 1.1 1998/02/06 19:21:03 root
+ * Initial revision
+ *
+ *
+ */
+#define R3964_VERSION "1.7"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h> /* used in new tty drivers */
+#include <linux/signal.h> /* used in new tty drivers */
+#include <linux/ioctl.h>
+#include <linux/n_r3964.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+
+//#define DEBUG_QUEUE
+
+/* Log successfull handshake and protocol operations */
+//#define DEBUG_PROTO_S
+
+/* Log handshake and protocol errors: */
+//#define DEBUG_PROTO_E
+
+/* Log Linediscipline operations (open, close, read, write...): */
+//#define DEBUG_LDISC
+
+/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
+//#define DEBUG_MODUL
+
+/* Macro helpers for debug output: */
+#define TRACE(format, args...) printk("r3964: " format "\n" , ## args);
+
+#ifdef DEBUG_MODUL
+#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args);
+#else
+#define TRACE_M(fmt, arg...) /**/
+#endif
+
+#ifdef DEBUG_PROTO_S
+#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args);
+#else
+#define TRACE_PS(fmt, arg...) /**/
+#endif
+
+#ifdef DEBUG_PROTO_E
+#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args);
+#else
+#define TRACE_PE(fmt, arg...) /**/
+#endif
+
+#ifdef DEBUG_LDISC
+#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args);
+#else
+#define TRACE_L(fmt, arg...) /**/
+#endif
+
+#ifdef DEBUG_QUEUE
+#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args);
+#else
+#define TRACE_Q(fmt, arg...) /**/
+#endif
+
+void cleanup_module(void);
+
+static void on_timer_1(void*);
+static void on_timer_2(void*);
+static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
+static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
+static void put_char(struct r3964_info *pInfo, unsigned char ch);
+static void trigger_transmit(struct r3964_info *pInfo);
+static void retry_transmit(struct r3964_info *pInfo);
+static void transmit_block(struct r3964_info *pInfo);
+static void receive_char(struct r3964_info *pInfo, const unsigned char c);
+static void receive_error(struct r3964_info *pInfo, const char flag);
+static void on_timeout(struct r3964_info *pInfo);
+static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg);
+static int read_telegram(struct r3964_info *pInfo, pid_t pid, unsigned char *buf);
+static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
+ int error_code, struct r3964_block_header *pBlock);
+static struct r3964_message* remove_msg(struct r3964_info *pInfo,
+ struct r3964_client_info *pClient);
+static void remove_client_block(struct r3964_info *pInfo,
+ struct r3964_client_info *pClient);
+
+static int r3964_open(struct tty_struct *tty);
+static void r3964_close(struct tty_struct *tty);
+static int r3964_read(struct tty_struct *tty, struct file *file,
+ unsigned char *buf, unsigned int nr);
+static int r3964_write(struct tty_struct * tty, struct file * file,
+ const unsigned char * buf, unsigned int nr);
+static int r3964_ioctl(struct tty_struct * tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
+static void r3964_set_termios(struct tty_struct *tty, struct termios * old);
+static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
+ struct poll_table_struct *wait);
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count);
+static int r3964_receive_room(struct tty_struct *tty);
+
+static struct tty_ldisc tty_ldisc_N_R3964 = {
+ TTY_LDISC_MAGIC, /* magic */
+ "R3964", /* name */
+ 0, /* num */
+ 0, /* flags */
+ r3964_open, /* open */
+ r3964_close, /* close */
+ 0, /* flush_buffer */
+ 0, /* chars_in_buffer */
+ r3964_read, /* read */
+ r3964_write, /* write */
+ r3964_ioctl, /* ioctl */
+ r3964_set_termios, /* set_termios */
+ r3964_poll, /* poll */
+ r3964_receive_buf, /* receive_buf */
+ r3964_receive_room, /* receive_room */
+ 0 /* write_wakeup */
+};
+
+
+
+static void dump_block(const unsigned char *block, unsigned int length)
+{
+ unsigned int i,j;
+ char linebuf[16*3+1];
+
+ for(i=0;i<length;i+=16)
+ {
+ for(j=0;(j<16) && (j+i<length);j++)
+ {
+ sprintf(linebuf+3*j,"%02x ",block[i+j]);
+ }
+ linebuf[3*j]='\0';
+ TRACE_PS("%s",linebuf);
+ }
+}
+
+
+
+
+/*************************************************************
+ * Driver initialisation
+ *************************************************************/
+
+
+/*************************************************************
+ * Module support routines
+ *************************************************************/
+
+#ifdef MODULE
+
+#define r3964_init init_module
+
+void cleanup_module(void)
+{
+ int status;
+
+ TRACE_M ("cleanup_module()");
+
+ status=tty_register_ldisc(N_R3964, NULL);
+
+ if(status!=0)
+ {
+ printk(KERN_ERR "r3964: error unregistering linediscipline: %d\n", status);
+ }
+ else
+ {
+ TRACE_L("linediscipline successfully unregistered");
+ }
+
+}
+
+
+#endif /* MODULE */
+
+static int __init r3964_init(void)
+{
+ int status;
+
+ printk ("r3964: Philips r3964 Driver V%s\n", R3964_VERSION);
+
+ /*
+ * Register the tty line discipline
+ */
+
+ status = tty_register_ldisc (N_R3964, &tty_ldisc_N_R3964);
+ if (status == 0)
+ {
+ TRACE_L("line discipline %d registered", N_R3964);
+ TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
+ tty_ldisc_N_R3964.num);
+ TRACE_L("open=%x", (int)tty_ldisc_N_R3964.open);
+ TRACE_L("tty_ldisc_N_R3964 = %x", (int)&tty_ldisc_N_R3964);
+ }
+ else
+ {
+ printk (KERN_ERR "r3964: error registering line discipline: %d\n", status);
+ }
+ return status;
+}
+
+#ifndef MODULE
+__initcall (r3964_init);
+#endif
+
+/*************************************************************
+ * Protocol implementation routines
+ *************************************************************/
+
+static void on_timer_1(void *arg)
+{
+ struct r3964_info *pInfo = (struct r3964_info *)arg;
+
+ if(pInfo->count_down)
+ {
+ if(!--pInfo->count_down)
+ {
+ on_timeout(pInfo);
+ }
+ }
+ queue_task(&pInfo->bh_2, &tq_timer);
+}
+
+static void on_timer_2(void *arg)
+{
+ struct r3964_info *pInfo = (struct r3964_info *)arg;
+
+ if(pInfo->count_down)
+ {
+ if(!--pInfo->count_down)
+ {
+ on_timeout(pInfo);
+ }
+ }
+ queue_task(&pInfo->bh_1, &tq_timer);
+}
+
+static void add_tx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ pHeader->next = NULL;
+
+ if(pInfo->tx_last == NULL)
+ {
+ pInfo->tx_first = pInfo->tx_last = pHeader;
+ }
+ else
+ {
+ pInfo->tx_last->next = pHeader;
+ pInfo->tx_last = pHeader;
+ }
+
+ restore_flags(flags);
+
+ TRACE_Q("add_tx_queue %x, length %d, tx_first = %x",
+ (int)pHeader, pHeader->length, (int)pInfo->tx_first );
+}
+
+static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
+{
+ struct r3964_block_header *pHeader;
+ unsigned long flags;
+#ifdef DEBUG_QUEUE
+ struct r3964_block_header *pDump;
+#endif
+
+ pHeader = pInfo->tx_first;
+
+ if(pHeader==NULL)
+ return;
+
+#ifdef DEBUG_QUEUE
+ printk("r3964: remove_from_tx_queue: %x, length %d - ",
+ (int)pHeader, (int)pHeader->length );
+ for(pDump=pHeader;pDump;pDump=pDump->next)
+ printk("%x ", (int)pDump);
+ printk("\n");
+#endif
+
+
+ if(pHeader->owner)
+ {
+ if(error_code)
+ {
+ add_msg(pHeader->owner, R3964_MSG_ACK, 0,
+ error_code, NULL);
+ }
+ else
+ {
+ add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
+ error_code, NULL);
+ }
+ wake_up_interruptible (&pInfo->read_wait);
+ }
+
+ save_flags(flags);
+ cli();
+
+ pInfo->tx_first = pHeader->next;
+ if(pInfo->tx_first==NULL)
+ {
+ pInfo->tx_last = NULL;
+ }
+
+ restore_flags(flags);
+
+ kfree(pHeader);
+ TRACE_M("remove_from_tx_queue - kfree %x",(int)pHeader);
+
+ TRACE_Q("remove_from_tx_queue: tx_first = %x, tx_last = %x",
+ (int)pInfo->tx_first, (int)pInfo->tx_last );
+}
+
+static void add_rx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ pHeader->next = NULL;
+
+ if(pInfo->rx_last == NULL)
+ {
+ pInfo->rx_first = pInfo->rx_last = pHeader;
+ }
+ else
+ {
+ pInfo->rx_last->next = pHeader;
+ pInfo->rx_last = pHeader;
+ }
+ pInfo->blocks_in_rx_queue++;
+
+ restore_flags(flags);
+
+ TRACE_Q("add_rx_queue: %x, length = %d, rx_first = %x, count = %d",
+ (int)pHeader, pHeader->length,
+ (int)pInfo->rx_first, pInfo->blocks_in_rx_queue);
+}
+
+static void remove_from_rx_queue(struct r3964_info *pInfo,
+ struct r3964_block_header *pHeader)
+{
+ unsigned long flags;
+ struct r3964_block_header *pFind;
+
+ if(pHeader==NULL)
+ return;
+
+ TRACE_Q("remove_from_rx_queue: rx_first = %x, rx_last = %x, count = %d",
+ (int)pInfo->rx_first, (int)pInfo->rx_last, pInfo->blocks_in_rx_queue );
+ TRACE_Q("remove_from_rx_queue: %x, length %d",
+ (int)pHeader, (int)pHeader->length );
+
+ save_flags(flags);
+ cli();
+
+ if(pInfo->rx_first == pHeader)
+ {
+ /* Remove the first block in the linked list: */
+ pInfo->rx_first = pHeader->next;
+
+ if(pInfo->rx_first==NULL)
+ {
+ pInfo->rx_last = NULL;
+ }
+ pInfo->blocks_in_rx_queue--;
+ }
+ else
+ {
+ /* Find block to remove: */
+ for(pFind=pInfo->rx_first; pFind; pFind=pFind->next)
+ {
+ if(pFind->next == pHeader)
+ {
+ /* Got it. */
+ pFind->next = pHeader->next;
+ pInfo->blocks_in_rx_queue--;
+ if(pFind->next==NULL)
+ {
+ /* Oh, removed the last one! */
+ pInfo->rx_last = pFind;
+ }
+ break;
+ }
+ }
+ }
+
+ restore_flags(flags);
+
+ kfree(pHeader);
+ TRACE_M("remove_from_rx_queue - kfree %x",(int)pHeader);
+
+ TRACE_Q("remove_from_rx_queue: rx_first = %x, rx_last = %x, count = %d",
+ (int)pInfo->rx_first, (int)pInfo->rx_last, pInfo->blocks_in_rx_queue );
+}
+
+static void put_char(struct r3964_info *pInfo, unsigned char ch)
+{
+ struct tty_struct *tty = pInfo->tty;
+
+ if(tty==NULL)
+ return;
+
+ if(tty->driver.put_char)
+ {
+ tty->driver.put_char(tty, ch);
+ }
+ pInfo->bcc ^= ch;
+}
+
+static void flush(struct r3964_info *pInfo)
+{
+ struct tty_struct *tty = pInfo->tty;
+
+ if(tty==NULL)
+ return;
+
+ if(tty->driver.flush_chars)
+ {
+ tty->driver.flush_chars(tty);
+ }
+}
+
+static void trigger_transmit(struct r3964_info *pInfo)
+{
+ unsigned long flags;
+
+
+ save_flags(flags);
+ cli();
+
+ if((pInfo->state == R3964_IDLE) && (pInfo->tx_first!=NULL))
+ {
+ pInfo->state = R3964_TX_REQUEST;
+ pInfo->count_down = R3964_TO_QVZ;
+ pInfo->nRetry=0;
+ pInfo->flags &= ~R3964_ERROR;
+
+ restore_flags(flags);
+
+ TRACE_PS("trigger_transmit - sent STX");
+
+ put_char(pInfo, STX);
+ flush(pInfo);
+
+ pInfo->bcc = 0;
+ }
+ else
+ {
+ restore_flags(flags);
+ }
+}
+
+static void retry_transmit(struct r3964_info *pInfo)
+{
+ if(pInfo->nRetry<R3964_MAX_RETRIES)
+ {
+ TRACE_PE("transmission failed. Retry #%d",
+ pInfo->nRetry);
+ pInfo->bcc = 0;
+ put_char(pInfo, STX);
+ flush(pInfo);
+ pInfo->state = R3964_TX_REQUEST;
+ pInfo->count_down = R3964_TO_QVZ;
+ pInfo->nRetry++;
+ }
+ else
+ {
+ TRACE_PE("transmission failed after %d retries",
+ R3964_MAX_RETRIES);
+
+ remove_from_tx_queue(pInfo, R3964_TX_FAIL);
+
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ pInfo->state = R3964_IDLE;
+
+ trigger_transmit(pInfo);
+ }
+}
+
+
+static void transmit_block(struct r3964_info *pInfo)
+{
+ struct tty_struct *tty = pInfo->tty;
+ struct r3964_block_header *pBlock = pInfo->tx_first;
+ int room=0;
+
+ if((tty==NULL) || (pBlock==NULL))
+ {
+ return;
+ }
+
+ if(tty->driver.write_room)
+ room=tty->driver.write_room(tty);
+
+ TRACE_PS("transmit_block %x, room %d, length %d",
+ (int)pBlock, room, pBlock->length);
+
+ while(pInfo->tx_position < pBlock->length)
+ {
+ if(room<2)
+ break;
+
+ if(pBlock->data[pInfo->tx_position]==DLE)
+ {
+ /* send additional DLE char: */
+ put_char(pInfo, DLE);
+ }
+ put_char(pInfo, pBlock->data[pInfo->tx_position++]);
+
+ room--;
+ }
+
+ if((pInfo->tx_position == pBlock->length) && (room>=3))
+ {
+ put_char(pInfo, DLE);
+ put_char(pInfo, ETX);
+ if(pInfo->flags & R3964_BCC)
+ {
+ put_char(pInfo, pInfo->bcc);
+ }
+ pInfo->state = R3964_WAIT_FOR_TX_ACK;
+ pInfo->count_down = R3964_TO_QVZ;
+ }
+ flush(pInfo);
+}
+
+static void on_receive_block(struct r3964_info *pInfo)
+{
+ unsigned int length;
+ struct r3964_client_info *pClient;
+ struct r3964_block_header *pBlock;
+
+ length=pInfo->rx_position;
+
+ /* compare byte checksum characters: */
+ if(pInfo->flags & R3964_BCC)
+ {
+ if(pInfo->bcc!=pInfo->last_rx)
+ {
+ TRACE_PE("checksum error - got %x but expected %x",
+ pInfo->last_rx, pInfo->bcc);
+ pInfo->flags |= R3964_CHECKSUM;
+ }
+ }
+
+ /* check for errors (parity, overrun,...): */
+ if(pInfo->flags & R3964_ERROR)
+ {
+ TRACE_PE("on_receive_block - transmission failed error %x",
+ pInfo->flags & R3964_ERROR);
+
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ if(pInfo->nRetry<R3964_MAX_RETRIES)
+ {
+ pInfo->state=R3964_WAIT_FOR_RX_REPEAT;
+ pInfo->count_down = R3964_TO_RX_PANIC;
+ pInfo->nRetry++;
+ }
+ else
+ {
+ TRACE_PE("on_receive_block - failed after max retries");
+ pInfo->state=R3964_IDLE;
+ }
+ return;
+ }
+
+
+ /* received block; submit DLE: */
+ put_char(pInfo, DLE);
+ flush(pInfo);
+ pInfo->count_down=0;
+ TRACE_PS(" rx success: got %d chars", length);
+
+ /* prepare struct r3964_block_header: */
+ pBlock = kmalloc(length+sizeof(struct r3964_block_header), GFP_KERNEL);
+ TRACE_M("on_receive_block - kmalloc %x",(int)pBlock);
+
+ if(pBlock==NULL)
+ return;
+
+ pBlock->length = length;
+ pBlock->data = ((unsigned char*)pBlock)+sizeof(struct r3964_block_header);
+ pBlock->locks = 0;
+ pBlock->next = NULL;
+ pBlock->owner = NULL;
+
+ memcpy(pBlock->data, pInfo->rx_buf, length);
+
+ /* queue block into rx_queue: */
+ add_rx_queue(pInfo, pBlock);
+
+ /* notify attached client processes: */
+ for(pClient=pInfo->firstClient; pClient; pClient=pClient->next)
+ {
+ if(pClient->sig_flags & R3964_SIG_DATA)
+ {
+ add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, pBlock);
+ }
+ }
+ wake_up_interruptible (&pInfo->read_wait);
+
+ pInfo->state = R3964_IDLE;
+
+ trigger_transmit(pInfo);
+}
+
+
+static void receive_char(struct r3964_info *pInfo, const unsigned char c)
+{
+ switch(pInfo->state)
+ {
+ case R3964_TX_REQUEST:
+ if(c==DLE)
+ {
+ TRACE_PS("TX_REQUEST - got DLE");
+
+ pInfo->state = R3964_TRANSMITTING;
+ pInfo->tx_position = 0;
+
+ transmit_block(pInfo);
+ }
+ else if(c==STX)
+ {
+ if(pInfo->nRetry==0)
+ {
+ TRACE_PE("TX_REQUEST - init conflict");
+ if(pInfo->priority == R3964_SLAVE)
+ {
+ goto start_receiving;
+ }
+ }
+ else
+ {
+ TRACE_PE("TX_REQUEST - secondary init conflict!?"
+ " Switching to SLAVE mode for next rx.");
+ goto start_receiving;
+ }
+ }
+ else
+ {
+ TRACE_PE("TX_REQUEST - char != DLE: %x", c);
+ retry_transmit(pInfo);
+ }
+ break;
+ case R3964_TRANSMITTING:
+ if(c==NAK)
+ {
+ TRACE_PE("TRANSMITTING - got NAK");
+ retry_transmit(pInfo);
+ }
+ else
+ {
+ TRACE_PE("TRANSMITTING - got illegal char");
+
+ pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
+ pInfo->count_down = R3964_TO_ZVZ;
+ }
+ break;
+ case R3964_WAIT_FOR_TX_ACK:
+ if(c==DLE)
+ {
+ TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
+ remove_from_tx_queue(pInfo, R3964_OK);
+
+ pInfo->state = R3964_IDLE;
+ trigger_transmit(pInfo);
+ }
+ else
+ {
+ retry_transmit(pInfo);
+ }
+ break;
+ case R3964_WAIT_FOR_RX_REPEAT:
+ /* FALLTROUGH */
+ case R3964_IDLE:
+ if(c==STX)
+ {
+ /* Prevent rx_queue from overflow: */
+ if(pInfo->blocks_in_rx_queue >= R3964_MAX_BLOCKS_IN_RX_QUEUE)
+ {
+ TRACE_PE("IDLE - got STX but no space in rx_queue!");
+ pInfo->state=R3964_WAIT_FOR_RX_BUF;
+ pInfo->count_down = R3964_TO_NO_BUF;
+ break;
+ }
+start_receiving:
+ /* Ok, start receiving: */
+ TRACE_PS("IDLE - got STX");
+ pInfo->rx_position = 0;
+ pInfo->last_rx = 0;
+ pInfo->flags &= ~R3964_ERROR;
+ pInfo->state=R3964_RECEIVING;
+ pInfo->count_down = R3964_TO_ZVZ;
+ pInfo->nRetry = 0;
+ put_char(pInfo, DLE);
+ flush(pInfo);
+ pInfo->bcc = 0;
+ }
+ break;
+ case R3964_RECEIVING:
+ if(pInfo->rx_position < RX_BUF_SIZE)
+ {
+ pInfo->bcc ^= c;
+
+ if(c==DLE)
+ {
+ if(pInfo->last_rx==DLE)
+ {
+ pInfo->last_rx = 0;
+ goto char_to_buf;
+ }
+ pInfo->last_rx = DLE;
+ break;
+ }
+ else if((c==ETX) && (pInfo->last_rx==DLE))
+ {
+ if(pInfo->flags & R3964_BCC)
+ {
+ pInfo->state = R3964_WAIT_FOR_BCC;
+ pInfo->count_down = R3964_TO_ZVZ;
+ }
+ else
+ {
+ on_receive_block(pInfo);
+ }
+ }
+ else
+ {
+ pInfo->last_rx = c;
+char_to_buf:
+ pInfo->rx_buf[pInfo->rx_position++] = c;
+ pInfo->count_down = R3964_TO_ZVZ;
+ }
+ }
+ /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
+ break;
+ case R3964_WAIT_FOR_BCC:
+ pInfo->last_rx = c;
+ on_receive_block(pInfo);
+ break;
+ }
+}
+
+static void receive_error(struct r3964_info *pInfo, const char flag)
+{
+ switch (flag)
+ {
+ case TTY_NORMAL:
+ break;
+ case TTY_BREAK:
+ TRACE_PE("received break")
+ pInfo->flags |= R3964_BREAK;
+ break;
+ case TTY_PARITY:
+ TRACE_PE("parity error")
+ pInfo->flags |= R3964_PARITY;
+ break;
+ case TTY_FRAME:
+ TRACE_PE("frame error")
+ pInfo->flags |= R3964_FRAME;
+ break;
+ case TTY_OVERRUN:
+ TRACE_PE("frame overrun")
+ pInfo->flags |= R3964_OVERRUN;
+ break;
+ default:
+ TRACE_PE("receive_error - unknown flag %d", flag);
+ pInfo->flags |= R3964_UNKNOWN;
+ break;
+ }
+}
+
+static void on_timeout(struct r3964_info *pInfo)
+{
+ switch(pInfo->state)
+ {
+ case R3964_TX_REQUEST:
+ TRACE_PE("TX_REQUEST - timeout");
+ retry_transmit(pInfo);
+ break;
+ case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ retry_transmit(pInfo);
+ break;
+ case R3964_WAIT_FOR_TX_ACK:
+ TRACE_PE("WAIT_FOR_TX_ACK - timeout");
+ retry_transmit(pInfo);
+ break;
+ case R3964_WAIT_FOR_RX_BUF:
+ TRACE_PE("WAIT_FOR_RX_BUF - timeout");
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ pInfo->state=R3964_IDLE;
+ break;
+ case R3964_RECEIVING:
+ TRACE_PE("RECEIVING - timeout after %d chars",
+ pInfo->rx_position);
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ pInfo->state=R3964_IDLE;
+ break;
+ case R3964_WAIT_FOR_RX_REPEAT:
+ TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
+ pInfo->state=R3964_IDLE;
+ break;
+ case R3964_WAIT_FOR_BCC:
+ TRACE_PE("WAIT_FOR_BCC - timeout");
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ pInfo->state=R3964_IDLE;
+ break;
+ }
+}
+
+static struct r3964_client_info *findClient(
+ struct r3964_info *pInfo, pid_t pid)
+{
+ struct r3964_client_info *pClient;
+
+ for(pClient=pInfo->firstClient; pClient; pClient=pClient->next)
+ {
+ if(pClient->pid == pid)
+ {
+ return pClient;
+ }
+ }
+ return NULL;
+}
+
+static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg)
+{
+ struct r3964_client_info *pClient;
+ struct r3964_client_info **ppClient;
+ struct r3964_message *pMsg;
+
+ if((arg & R3964_SIG_ALL)==0)
+ {
+ /* Remove client from client list */
+ for(ppClient=&pInfo->firstClient; *ppClient; ppClient=&(*ppClient)->next)
+ {
+ pClient = *ppClient;
+
+ if(pClient->pid == pid)
+ {
+ TRACE_PS("removing client %d from client list", pid);
+ *ppClient = pClient->next;
+ while(pClient->msg_count)
+ {
+ pMsg=remove_msg(pInfo, pClient);
+ if(pMsg)
+ {
+ kfree(pMsg);
+ TRACE_M("enable_signals - msg kfree %x",(int)pMsg);
+ }
+ }
+ kfree(pClient);
+ TRACE_M("enable_signals - kfree %x",(int)pClient);
+ return 0;
+ }
+ }
+ return -EINVAL;
+ }
+ else
+ {
+ pClient=findClient(pInfo, pid);
+ if(pClient)
+ {
+ /* update signal options */
+ pClient->sig_flags=arg;
+ }
+ else
+ {
+ /* add client to client list */
+ pClient=kmalloc(sizeof(struct r3964_client_info), GFP_KERNEL);
+ TRACE_M("enable_signals - kmalloc %x",(int)pClient);
+ if(pClient==NULL)
+ return -ENOMEM;
+
+ TRACE_PS("add client %d to client list", pid);
+ pClient->sig_flags=arg;
+ pClient->pid = pid;
+ pClient->next=pInfo->firstClient;
+ pClient->first_msg = NULL;
+ pClient->last_msg = NULL;
+ pClient->next_block_to_read = NULL;
+ pClient->msg_count = 0;
+ pInfo->firstClient=pClient;
+ }
+ }
+
+ return 0;
+}
+
+static int read_telegram(struct r3964_info *pInfo, pid_t pid, unsigned char *buf)
+{
+ struct r3964_client_info *pClient;
+ struct r3964_block_header *block;
+
+ if(!buf)
+ {
+ return -EINVAL;
+ }
+
+ pClient=findClient(pInfo,pid);
+ if(pClient==NULL)
+ {
+ return -EINVAL;
+ }
+
+ block=pClient->next_block_to_read;
+ if(!block)
+ {
+ return 0;
+ }
+ else
+ {
+ if (copy_to_user (buf, block->data, block->length))
+ return -EFAULT;
+
+ remove_client_block(pInfo, pClient);
+ return block->length;
+ }
+
+ return -EINVAL;
+}
+
+static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
+ int error_code, struct r3964_block_header *pBlock)
+{
+ struct r3964_message *pMsg;
+ unsigned long flags;
+
+ if(pClient->msg_count<R3964_MAX_MSG_COUNT-1)
+ {
+queue_the_message:
+
+ save_flags(flags);
+ cli();
+
+ pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL);
+ TRACE_M("add_msg - kmalloc %x",(int)pMsg);
+ if(pMsg==NULL)
+ return;
+
+ pMsg->msg_id = msg_id;
+ pMsg->arg = arg;
+ pMsg->error_code = error_code;
+ pMsg->block = pBlock;
+ pMsg->next = NULL;
+
+ if(pClient->last_msg==NULL)
+ {
+ pClient->first_msg=pClient->last_msg=pMsg;
+ }
+ else
+ {
+ pClient->last_msg->next = pMsg;
+ pClient->last_msg=pMsg;
+ }
+
+ pClient->msg_count++;
+
+ if(pBlock!=NULL)
+ {
+ pBlock->locks++;
+ }
+ restore_flags(flags);
+ }
+ else
+ {
+ if((pClient->last_msg->msg_id == R3964_MSG_ACK)
+ && (pClient->last_msg->error_code==R3964_OVERFLOW))
+ {
+ pClient->last_msg->arg++;
+ TRACE_PE("add_msg - inc prev OVERFLOW-msg");
+ }
+ else
+ {
+ msg_id = R3964_MSG_ACK;
+ arg = 0;
+ error_code = R3964_OVERFLOW;
+ pBlock = NULL;
+ TRACE_PE("add_msg - queue OVERFLOW-msg");
+ goto queue_the_message;
+ }
+ }
+ /* Send SIGIO signal to client process: */
+ if(pClient->sig_flags & R3964_USE_SIGIO)
+ {
+ kill_proc(pClient->pid, SIGIO, 1);
+ }
+}
+
+static struct r3964_message *remove_msg(struct r3964_info *pInfo,
+ struct r3964_client_info *pClient)
+{
+ struct r3964_message *pMsg=NULL;
+ unsigned long flags;
+
+ if(pClient->first_msg)
+ {
+ save_flags(flags);
+ cli();
+
+ pMsg = pClient->first_msg;
+ pClient->first_msg = pMsg->next;
+ if(pClient->first_msg==NULL)
+ {
+ pClient->last_msg = NULL;
+ }
+
+ pClient->msg_count--;
+ if(pMsg->block)
+ {
+ remove_client_block(pInfo, pClient);
+ pClient->next_block_to_read = pMsg->block;
+ }
+ restore_flags(flags);
+ }
+ return pMsg;
+}
+
+static void remove_client_block(struct r3964_info *pInfo,
+ struct r3964_client_info *pClient)
+{
+ struct r3964_block_header *block;
+
+ TRACE_PS("remove_client_block PID %d", pClient->pid);
+
+ block=pClient->next_block_to_read;
+ if(block)
+ {
+ block->locks--;
+ if(block->locks==0)
+ {
+ remove_from_rx_queue(pInfo, block);
+ }
+ }
+ pClient->next_block_to_read = NULL;
+}
+
+
+/*************************************************************
+ * Line discipline routines
+ *************************************************************/
+
+static int r3964_open(struct tty_struct *tty)
+{
+ struct r3964_info *pInfo;
+
+ MOD_INC_USE_COUNT;
+
+ TRACE_L("open");
+ TRACE_L("tty=%x, PID=%d, disc_data=%x",
+ (int)tty, current->pid, (int)tty->disc_data);
+
+ pInfo=kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
+ TRACE_M("r3964_open - info kmalloc %x",(int)pInfo);
+
+ if(!pInfo)
+ {
+ printk(KERN_ERR "r3964: failed to alloc info structure\n");
+ return -ENOMEM;
+ }
+
+ pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
+ TRACE_M("r3964_open - rx_buf kmalloc %x",(int)pInfo->rx_buf);
+
+ if(!pInfo->rx_buf)
+ {
+ printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
+ kfree(pInfo);
+ TRACE_M("r3964_open - info kfree %x",(int)pInfo);
+ return -ENOMEM;
+ }
+
+ pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
+ TRACE_M("r3964_open - tx_buf kmalloc %x",(int)pInfo->tx_buf);
+
+ if(!pInfo->tx_buf)
+ {
+ printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
+ kfree(pInfo->rx_buf);
+ TRACE_M("r3964_open - rx_buf kfree %x",(int)pInfo->rx_buf);
+ kfree(pInfo);
+ TRACE_M("r3964_open - info kfree %x",(int)pInfo);
+ return -ENOMEM;
+ }
+
+ pInfo->tty = tty;
+ init_waitqueue_head (&pInfo->read_wait);
+ pInfo->priority = R3964_MASTER;
+ pInfo->rx_first = pInfo->rx_last = NULL;
+ pInfo->tx_first = pInfo->tx_last = NULL;
+ pInfo->rx_position = 0;
+ pInfo->tx_position = 0;
+ pInfo->last_rx = 0;
+ pInfo->blocks_in_rx_queue = 0;
+ pInfo->firstClient=NULL;
+ pInfo->state=R3964_IDLE;
+ pInfo->flags = R3964_DEBUG;
+ pInfo->count_down = 0;
+ pInfo->nRetry = 0;
+
+ tty->disc_data = pInfo;
+
+ /*
+ * Add 'on_timer' to timer task queue
+ * (will be called from timer bh)
+ */
+ pInfo->bh_1.next = NULL;
+ pInfo->bh_1.sync = 0;
+ pInfo->bh_1.routine = &on_timer_1;
+ pInfo->bh_1.data = pInfo;
+
+ pInfo->bh_2.next = NULL;
+ pInfo->bh_2.sync = 0;
+ pInfo->bh_2.routine = &on_timer_2;
+ pInfo->bh_2.data = pInfo;
+
+ queue_task(&pInfo->bh_1, &tq_timer);
+
+ return 0;
+}
+
+static void r3964_close(struct tty_struct *tty)
+{
+ struct tq_struct *tq, *prev;
+ struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
+ struct r3964_client_info *pClient, *pNext;
+ struct r3964_message *pMsg;
+ struct r3964_block_header *pHeader, *pNextHeader;
+ unsigned long flags;
+
+ TRACE_L("close");
+
+ /*
+ * Make sure that our task queue isn't activated. If it
+ * is, take it out of the linked list.
+ */
+ save_flags(flags);
+ cli();
+
+ for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {
+ if ((tq == &pInfo->bh_1) || (tq==&pInfo->bh_2)) {
+ if (prev)
+ prev->next = tq->next;
+ else
+ tq_timer = tq->next;
+ break;
+ }
+ }
+ restore_flags(flags);
+
+ /* Remove client-structs and message queues: */
+ pClient=pInfo->firstClient;
+ while(pClient)
+ {
+ pNext=pClient->next;
+ while(pClient->msg_count)
+ {
+ pMsg=remove_msg(pInfo, pClient);
+ if(pMsg)
+ {
+ kfree(pMsg);
+ TRACE_M("r3964_close - msg kfree %x",(int)pMsg);
+ }
+ }
+ kfree(pClient);
+ TRACE_M("r3964_close - client kfree %x",(int)pClient);
+ pClient=pNext;
+ }
+ /* Remove jobs from tx_queue: */
+ save_flags(flags);
+ cli();
+ pHeader=pInfo->tx_first;
+ pInfo->tx_first=pInfo->tx_last=NULL;
+ restore_flags(flags);
+
+ while(pHeader)
+ {
+ pNextHeader=pHeader->next;
+ kfree(pHeader);
+ pHeader=pNextHeader;
+ }
+
+ /* Free buffers: */
+ wake_up_interruptible(&pInfo->read_wait);
+ kfree(pInfo->rx_buf);
+ TRACE_M("r3964_close - rx_buf kfree %x",(int)pInfo->rx_buf);
+ kfree(pInfo->tx_buf);
+ TRACE_M("r3964_close - tx_buf kfree %x",(int)pInfo->tx_buf);
+ kfree(pInfo);
+ TRACE_M("r3964_close - info kfree %x",(int)pInfo);
+
+ MOD_DEC_USE_COUNT;
+}
+
+static int r3964_read(struct tty_struct *tty, struct file *file,
+ unsigned char *buf, unsigned int nr)
+{
+ struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
+ struct r3964_client_info *pClient;
+ struct r3964_message *pMsg;
+ struct r3964_client_message theMsg;
+ DECLARE_WAITQUEUE (wait, current);
+
+ int pid = current->pid;
+ int count;
+
+ TRACE_L("read()");
+
+ pClient=findClient(pInfo, pid);
+ if(pClient)
+ {
+ pMsg = remove_msg(pInfo, pClient);
+ if(pMsg==NULL)
+ {
+ /* no messages available. */
+ if (file->f_flags & O_NONBLOCK)
+ {
+ return -EAGAIN;
+ }
+ /* block until there is a message: */
+ add_wait_queue(&pInfo->read_wait, &wait);
+repeat:
+ pMsg = remove_msg(pInfo, pClient);
+ current->state = TASK_INTERRUPTIBLE;
+ if (!pMsg && !signal_pending(current))
+ {
+ schedule();
+ goto repeat;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&pInfo->read_wait, &wait);
+ }
+
+ /* If we still haven't got a message, we must have been signalled */
+
+ if (!pMsg) return -EINTR;
+
+ /* deliver msg to client process: */
+ theMsg.msg_id = pMsg->msg_id;
+ theMsg.arg = pMsg->arg;
+ theMsg.error_code = pMsg->error_code;
+ count = sizeof(struct r3964_client_message);
+
+ kfree(pMsg);
+ TRACE_M("r3964_read - msg kfree %x",(int)pMsg);
+
+ if (copy_to_user(buf,&theMsg, count))
+ return -EFAULT;
+
+ TRACE_PS("read - return %d", count);
+ return count;
+ }
+ return -EPERM;
+}
+
+static int r3964_write(struct tty_struct * tty, struct file * file,
+ const unsigned char *data, unsigned int count)
+{
+ struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
+ struct r3964_block_header *pHeader;
+ struct r3964_client_info *pClient;
+ unsigned char *new_data;
+ int status;
+ int pid;
+
+ TRACE_L("write request, %d characters", count);
+/*
+ * Verify the pointers
+ */
+
+ if(!pInfo)
+ return -EIO;
+
+ status = verify_area (VERIFY_READ, data, count);
+ if (status != 0)
+ {
+ return status;
+ }
+
+/*
+ * Ensure that the caller does not wish to send too much.
+ */
+ if (count > R3964_MTU)
+ {
+ if (pInfo->flags & R3964_DEBUG)
+ {
+ TRACE_L (KERN_WARNING
+ "r3964_write: truncating user packet "
+ "from %u to mtu %d", count, R3964_MTU);
+ }
+ count = R3964_MTU;
+ }
+/*
+ * Allocate a buffer for the data and fetch it from the user space.
+ */
+ new_data = kmalloc (count+sizeof(struct r3964_block_header), GFP_KERNEL);
+ TRACE_M("r3964_write - kmalloc %x",(int)new_data);
+ if (new_data == NULL) {
+ if (pInfo->flags & R3964_DEBUG)
+ {
+ printk (KERN_ERR
+ "r3964_write: no memory\n");
+ }
+ return -ENOSPC;
+ }
+
+ pHeader = (struct r3964_block_header *)new_data;
+ pHeader->data = new_data + sizeof(struct r3964_block_header);
+ pHeader->length = count;
+ pHeader->locks = 0;
+ pHeader->owner = NULL;
+
+ pid=current->pid;
+
+ pClient=findClient(pInfo, pid);
+ if(pClient)
+ {
+ pHeader->owner = pClient;
+ }
+
+ copy_from_user (pHeader->data, data, count); /* We already verified this */
+
+ if(pInfo->flags & R3964_DEBUG)
+ {
+ dump_block(pHeader->data, count);
+ }
+
+/*
+ * Add buffer to transmit-queue:
+ */
+ add_tx_queue(pInfo, pHeader);
+ trigger_transmit(pInfo);
+
+ return 0;
+}
+
+static int r3964_ioctl(struct tty_struct * tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
+ if(pInfo==NULL)
+ return -EINVAL;
+ switch(cmd)
+ {
+ case R3964_ENABLE_SIGNALS:
+ return enable_signals(pInfo, current->pid, arg);
+ case R3964_SETPRIORITY:
+ if(arg<R3964_MASTER || arg>R3964_SLAVE)
+ return -EINVAL;
+ pInfo->priority = arg & 0xff;
+ return 0;
+ case R3964_USE_BCC:
+ if(arg)
+ pInfo->flags |= R3964_BCC;
+ else
+ pInfo->flags &= ~R3964_BCC;
+ return 0;
+ case R3964_READ_TELEGRAM:
+ return read_telegram(pInfo, current->pid, (unsigned char *)arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static void r3964_set_termios(struct tty_struct *tty, struct termios * old)
+{
+ TRACE_L("set_termios");
+}
+
+static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
+ struct poll_table_struct *wait)
+{
+ struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
+ int pid=current->pid;
+ struct r3964_client_info *pClient;
+ struct r3964_message *pMsg=NULL;
+ unsigned int flags;
+ int result = POLLOUT;
+
+ TRACE_L("POLL");
+
+ pClient=findClient(pInfo,pid);
+ if(pClient)
+ {
+ poll_wait(file, &pInfo->read_wait, wait);
+ save_flags(flags);
+ cli();
+ pMsg=pClient->first_msg;
+ restore_flags(flags);
+ if(pMsg)
+ result |= POLLIN | POLLRDNORM;
+ }
+ else
+ {
+ result = -EINVAL;
+ }
+ return result;
+}
+
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count)
+{
+ struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
+ const unsigned char *p;
+ char *f, flags = 0;
+ int i;
+
+ for (i=count, p = cp, f = fp; i; i--, p++) {
+ if (f)
+ flags = *f++;
+ if(flags==TTY_NORMAL)
+ {
+ receive_char(pInfo, *p);
+ }
+ else
+ {
+ receive_error(pInfo, flags);
+ }
+
+ }
+}
+
+static int r3964_receive_room(struct tty_struct *tty)
+{
+ TRACE_L("receive_room");
+ return -1;
+}
+
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index af4daecfb..d95cda30e 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -948,7 +948,7 @@ do_it_again:
/* This statement must be first before checking for input
so that any interrupt will set the state back to
TASK_RUNNING. */
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
((minimum - (b - buf)) >= 1))
@@ -1073,7 +1073,7 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
add_wait_queue(&tty->write_wait, &wait);
while (1) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 11e7eadcf..dde61fe77 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -413,7 +413,7 @@ static struct miscdevice nvram_dev = {
};
-__initfunc(int nvram_init(void))
+int __init nvram_init(void)
{
/* First test whether the driver should init at all */
if (!CHECK_DRIVER_INIT())
@@ -479,7 +479,7 @@ static void pc_set_checksum( void )
#ifdef CONFIG_PROC_FS
static char *floppy_types[] = {
- "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M"
+ "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M", "3.5'' 2.88M"
};
static char *gfx_types[] = {
@@ -521,14 +521,14 @@ static int pc_proc_infos( unsigned char *nvram, char *buffer, int *len,
PRINT_PROC( "HD 0 type : " );
type = nvram[4] >> 4;
if (type)
- PRINT_PROC( " %02x\n", type == 0x0f ? nvram[11] : type );
+ PRINT_PROC( "%02x\n", type == 0x0f ? nvram[11] : type );
else
PRINT_PROC( "none\n" );
PRINT_PROC( "HD 1 type : " );
type = nvram[4] & 0x0f;
if (type)
- PRINT_PROC( " %02x\n", type == 0x0f ? nvram[12] : type );
+ PRINT_PROC( "%02x\n", type == 0x0f ? nvram[12] : type );
else
PRINT_PROC( "none\n" );
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index 080cbdef8..2acab7d8f 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -17,7 +17,7 @@
#include <linux/config.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
@@ -512,11 +512,14 @@ void pckbd_leds(unsigned char leds)
#endif
/* for "kbd-reset" cmdline param */
-void __init kbd_reset_setup(char *str, int *ints)
+static int __init kbd_reset_setup(char *str)
{
kbd_startup_reset = 1;
+ return 1;
}
+__setup("kbd-reset", kbd_reset_setup);
+
#define KBD_NO_DATA (-1) /* No data */
#define KBD_BAD_DATA (-2) /* Parity or other error */
@@ -694,8 +697,6 @@ static char * __init initialize_kbd(void)
void __init pckbd_init_hw(void)
{
- kbd_request_region();
-
/* Flush any pending input. */
kbd_clear_input();
@@ -875,7 +876,7 @@ static ssize_t read_aux(struct file * file, char * buffer,
return -EAGAIN;
add_wait_queue(&queue->proc_list, &wait);
repeat:
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (queue_empty() && !signal_pending(current)) {
schedule();
goto repeat;
diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c
index 7a7d73c06..fa69f138f 100644
--- a/drivers/char/pcwd.c
+++ b/drivers/char/pcwd.c
@@ -59,6 +59,7 @@
#include <linux/watchdog.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -96,6 +97,7 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
static int current_readport, revision, temp_panic;
static int is_open, initial_status, supports_temp, mode_debug;
+static spinlock_t io_lock;
/*
* PCWD_CHECKCARD
@@ -246,7 +248,12 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
return i ? -EFAULT : 0;
case WDIOC_GETSTATUS:
- cdat = inb(current_readport);
+ spin_lock(&io_lock);
+ if (revision == PCWD_REVISION_A)
+ cdat = inb(current_readport);
+ else
+ cdat = inb(current_readport + 1 );
+ spin_unlock(&io_lock);
rv = 0;
if (revision == PCWD_REVISION_A)
@@ -309,7 +316,9 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
rv = 0;
if ((supports_temp) && (mode_debug == 0))
{
+ spin_lock(&io_lock);
rv = inb(current_readport);
+ spin_unlock(&io_lock);
if(put_user(rv, (int*) arg))
return -EFAULT;
} else if(put_user(rv, (int*) arg))
@@ -324,9 +333,11 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
if (rv & WDIOS_DISABLECARD)
{
+ spin_lock(&io_lock);
outb_p(0xA5, current_readport + 3);
outb_p(0xA5, current_readport + 3);
cdat = inb_p(current_readport + 2);
+ spin_unlock(&io_lock);
if ((cdat & 0x10) == 0)
{
printk("pcwd: Could not disable card.\n");
@@ -338,8 +349,10 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
if (rv & WDIOS_ENABLECARD)
{
+ spin_lock(&io_lock);
outb_p(0x00, current_readport + 3);
cdat = inb_p(current_readport + 2);
+ spin_unlock(&io_lock);
if (cdat & 0x10)
{
printk("pcwd: Could not enable card.\n");
@@ -388,7 +401,11 @@ static int pcwd_open(struct inode *ino, struct file *filep)
MOD_INC_USE_COUNT;
/* Enable the port */
if (revision == PCWD_REVISION_C)
- outb_p(0x00, current_readport + 3);
+ {
+ spin_lock(&io_lock);
+ outb_p(0x00, current_readport + 3);
+ spin_unlock(&io_lock);
+ }
is_open = 1;
return(0);
case TEMP_MINOR:
@@ -402,7 +419,7 @@ static int pcwd_open(struct inode *ino, struct file *filep)
static ssize_t pcwd_read(struct file *file, char *buf, size_t count,
loff_t *ppos)
{
- unsigned short c = inb(current_readport);
+ unsigned short c;
unsigned char cp;
/* Can't seek (pread) on this device */
@@ -415,6 +432,8 @@ static ssize_t pcwd_read(struct file *file, char *buf, size_t count,
* Convert metric to Fahrenheit, since this was
* the decided 'standard' for this return value.
*/
+
+ c = inb(current_readport);
cp = (c * 9 / 5) + 32;
if(copy_to_user(buf, &cp, 1))
return -EFAULT;
@@ -433,8 +452,10 @@ static int pcwd_close(struct inode *ino, struct file *filep)
#ifndef CONFIG_WATCHDOG_NOWAYOUT
/* Disable the board */
if (revision == PCWD_REVISION_C) {
+ spin_lock(&io_lock);
outb_p(0xA5, current_readport + 3);
outb_p(0xA5, current_readport + 3);
+ spin_unlock(&io_lock);
}
#endif
}
@@ -449,11 +470,15 @@ static inline void get_support(void)
static inline int get_revision(void)
{
+ int r = PCWD_REVISION_C;
+
+ spin_lock(&io_lock);
if ((inb(current_readport + 2) == 0xFF) ||
(inb(current_readport + 3) == 0xFF))
- return(PCWD_REVISION_A);
+ r=PCWD_REVISION_A;
+ spin_unlock(&io_lock);
- return(PCWD_REVISION_C);
+ return r;
}
static int __init send_command(int cmd)
@@ -581,7 +606,8 @@ int __init pcwatchdog_init(void)
#endif
{
int i, found = 0;
-
+ spin_lock_init(&io_lock);
+
revision = PCWD_REVISION_A;
printk("pcwd: v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c
index dda54324e..36db3299d 100644
--- a/drivers/char/pcxx.c
+++ b/drivers/char/pcxx.c
@@ -79,6 +79,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
+#include <asm/semaphore.h>
#define VERSION "1.6.1"
@@ -356,7 +357,7 @@ static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct chan
memoff(info);
}
sti();
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) {
if(info->asyncflags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
@@ -894,7 +895,7 @@ static void pcxe_flush_chars(struct tty_struct *tty)
* Driver setup function when linked into the kernel to optionally parse multible
* "digi="-lines and initialize the driver at boot time. No probing.
*/
-__initfunc(void pcxx_setup(char *str, int *ints))
+void __init pcxx_setup(char *str, int *ints)
{
struct board_info board;
@@ -1085,7 +1086,7 @@ __initfunc(void pcxx_setup(char *str, int *ints))
* function to initialize the driver with the given parameters, which are either
* the default values from this file or the parameters given at boot.
*/
-__initfunc(int pcxe_init(void))
+int __init pcxe_init(void)
{
ulong memory_seg=0, memory_size=0;
int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
@@ -1588,8 +1589,8 @@ load_fep:
ch->blocked_open = 0;
ch->callout_termios = pcxe_callout.init_termios;
ch->normal_termios = pcxe_driver.init_termios;
- ch->open_wait = 0;
- ch->close_wait = 0;
+ init_waitqueue_head(ch->open_wait);
+ init_waitqueue_head(ch->close_wait);
ch->asyncflags = 0;
}
diff --git a/drivers/char/planb.c b/drivers/char/planb.c
index 1c6bf655b..524ab7be5 100644
--- a/drivers/char/planb.c
+++ b/drivers/char/planb.c
@@ -383,7 +383,7 @@ static void __planb_wait(struct planb *pb)
add_wait_queue(&pb->lockq, &wait);
repeat:
- current->state = TASK_UNINTERRUPTIBLE;
+ set_current_state(TASK_UNINTERRUPTIBLE);
if (pb->lock) {
schedule();
goto repeat;
@@ -1533,7 +1533,8 @@ static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
- if (!capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN)
+ || !capable(CAP_SYS_RAWIO))
return -EPERM;
if (copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
@@ -2359,7 +2360,7 @@ static void release_planb(void)
int init_module(void)
{
#else
-__initfunc(int init_planbs(struct video_init *unused))
+int __init init_planbs(struct video_init *unused)
{
#endif
int i;
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 881e521ad..c210b0785 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -11,7 +11,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * A /dev/parportxy device node represents an arbitrary device ('y')
+ * A /dev/parportx device node represents an arbitrary device
* on port 'x'. The following operations are possible:
*
* open do nothing, set up default IEEE 1284 protocol to be COMPAT
@@ -21,6 +21,8 @@
* CLAIM (register device first time) parport_claim_or_block
* RELEASE parport_release
* SETMODE set the IEEE 1284 protocol to use for read/write
+ * SETPHASE set the IEEE 1284 phase of a particular mode. Not to be
+ * confused with ioctl(fd, SETPHASER, &stun). ;-)
* DATADIR data_forward / data_reverse
* WDATA write_data
* RDATA read_data
@@ -30,6 +32,8 @@
* RSTATUS read_status
* NEGOT parport_negotiate
* YIELD parport_yield_blocking
+ * WCTLONIRQ on interrupt, set control lines
+ * CLRIRQ clear (and return) interrupt count
* read/write read or write in current IEEE 1284 protocol
* select wait for interrupt (in readfds)
*/
@@ -50,16 +54,15 @@
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
-/* The device minor encodes the parport number and (arbitrary)
- * pardevice number as (port << 4) | dev. */
-#define PP_PORT(minor) ((minor >> 4) & 0xf)
-#define PP_DEV(minor) ((minor) & 0xf)
-
struct pp_struct {
struct pardevice * pdev;
wait_queue_head_t irq_wait;
- int mode;
+ atomic_t irqc;
unsigned int flags;
+ int irqresponse;
+ unsigned char irqctl;
+ struct ieee1284_info state;
+ struct ieee1284_info saved_state;
};
/* pp_struct.flags bitfields */
@@ -71,111 +74,31 @@ struct pp_struct {
#define PP_BUFFER_SIZE 256
#define PARDEVICE_MAX 8
-static struct pp_struct pp_table[PARPORT_MAX][PARDEVICE_MAX];
-
-static loff_t pp_lseek (struct file * file, long long offset, int origin)
-{
- return -ESPIPE;
-}
-
-/* This looks a bit like parport_read. The difference is that we don't
- * determine the mode to use from the port data, but rather from the
- * mode the driver told us to use. */
-static ssize_t do_read (struct pp_struct *pp, void *buf, size_t len)
+static inline void enable_irq (struct pp_struct *pp)
{
- size_t (*fn) (struct parport *, void *, size_t, int);
struct parport *port = pp->pdev->port;
-
- switch (pp->mode) {
- case IEEE1284_MODE_COMPAT:
- /* This is a write-only mode. */
- return -EIO;
-
- case IEEE1284_MODE_NIBBLE:
- fn = port->ops->nibble_read_data;
- break;
-
- case IEEE1284_MODE_BYTE:
- fn = port->ops->byte_read_data;
- break;
-
- case IEEE1284_MODE_EPP:
- fn = port->ops->epp_read_data;
- break;
-
- case IEEE1284_MODE_ECP:
- case IEEE1284_MODE_ECPRLE:
- fn = port->ops->ecp_read_data;
- break;
-
- case IEEE1284_MODE_ECPSWE:
- fn = parport_ieee1284_ecp_read_data;
- break;
-
- default:
- printk (KERN_DEBUG "%s: unknown mode 0x%02x\n",
- pp->pdev->name, pp->mode);
- return -EINVAL;
- }
-
- return (*fn) (port, buf, len, 0);
+ port->ops->enable_irq (port);
}
-/* This looks a bit like parport_write. The difference is that we don't
- * determine the mode to use from the port data, but rather from the
- * mode the driver told us to use. */
-static ssize_t do_write (struct pp_struct *pp, const void *buf, size_t len)
+static loff_t pp_lseek (struct file * file, long long offset, int origin)
{
- size_t (*fn) (struct parport *, const void *, size_t, int);
- struct parport *port = pp->pdev->port;
-
- switch (pp->mode) {
- case IEEE1284_MODE_NIBBLE:
- case IEEE1284_MODE_BYTE:
- /* Read-only modes. */
- return -EIO;
-
- case IEEE1284_MODE_COMPAT:
- fn = port->ops->compat_write_data;
- break;
-
- case IEEE1284_MODE_EPP:
- fn = port->ops->epp_write_data;
- break;
-
- case IEEE1284_MODE_ECP:
- case IEEE1284_MODE_ECPRLE:
- fn = port->ops->ecp_write_data;
- break;
-
- case IEEE1284_MODE_ECPSWE:
- fn = parport_ieee1284_ecp_write_data;
- break;
-
- default:
- printk (KERN_DEBUG "%s: unknown mode 0x%02x\n",
- pp->pdev->name, pp->mode);
- return -EINVAL;
- }
-
- return (*fn) (port, buf, len, 0);
+ return -ESPIPE;
}
static ssize_t pp_read (struct file * file, char * buf, size_t count,
loff_t * ppos)
{
unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
+ struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_read = 0;
ssize_t got = 0;
- if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) {
+ if (!(pp->flags & PP_CLAIMED)) {
/* Don't have the port claimed */
- printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+ printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
minor);
- return -EPERM;
+ return -EINVAL;
}
kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
@@ -185,16 +108,16 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
while (bytes_read < count) {
ssize_t need = min(count - bytes_read, PP_BUFFER_SIZE);
- got = do_read (&pp_table[portnum][dev], kbuffer, need);
+ got = parport_read (pp->pdev->port, kbuffer, need);
- if (got < 0) {
+ if (got <= 0) {
if (!bytes_read)
bytes_read = got;
break;
}
- if (copy_to_user (kbuffer, buf + bytes_read, got)) {
+ if (copy_to_user (buf + bytes_read, kbuffer, got)) {
bytes_read = -EFAULT;
break;
}
@@ -212,6 +135,7 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
}
kfree (kbuffer);
+ enable_irq (pp);
return bytes_read;
}
@@ -219,17 +143,16 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
loff_t * ppos)
{
unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
+ struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_written = 0;
ssize_t wrote;
- if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) {
+ if (!(pp->flags & PP_CLAIMED)) {
/* Don't have the port claimed */
- printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+ printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
minor);
- return -EPERM;
+ return -EINVAL;
}
kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
@@ -244,7 +167,7 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
break;
}
- wrote = do_write (&pp_table[portnum][dev], kbuffer, n);
+ wrote = parport_write (pp->pdev->port, kbuffer, n);
if (wrote < 0) {
if (!bytes_written)
@@ -265,19 +188,25 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
}
kfree (kbuffer);
+ enable_irq (pp);
return bytes_written;
}
static void pp_irq (int irq, void * private, struct pt_regs * unused)
{
struct pp_struct * pp = (struct pp_struct *) private;
+
+ if (pp->irqresponse) {
+ parport_write_control (pp->pdev->port, pp->irqctl);
+ pp->irqresponse = 0;
+ }
+
+ atomic_inc (&pp->irqc);
wake_up_interruptible (&pp->irq_wait);
}
-static int register_device (int minor)
+static int register_device (int minor, struct pp_struct *pp)
{
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
struct parport * port;
struct pardevice * pdev = NULL;
char *name;
@@ -287,10 +216,10 @@ static int register_device (int minor)
if (name == NULL)
return -ENOMEM;
- sprintf (name, CHRDEV "%02x", minor);
+ sprintf (name, CHRDEV "%x", minor);
port = parport_enumerate (); /* FIXME: use attach/detach */
- while (port && port->number != portnum)
+ while (port && port->number != minor)
port = port->next;
if (!port) {
@@ -299,9 +228,9 @@ static int register_device (int minor)
return -ENXIO;
}
- fl = (pp_table[portnum][dev].flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
+ fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
pdev = parport_register_device (port, name, NULL, NULL, pp_irq, fl,
- &pp_table[portnum][dev]);
+ pp);
if (!pdev) {
printk (KERN_WARNING "%s: failed to register device!\n", name);
@@ -309,45 +238,68 @@ static int register_device (int minor)
return -ENXIO;
}
- pp_table[portnum][dev].pdev = pdev;
+ pp->pdev = pdev;
printk (KERN_DEBUG "%s: registered pardevice\n", name);
return 0;
}
+static enum ieee1284_phase init_phase (int mode)
+{
+ switch (mode & ~(IEEE1284_DEVICEID
+ | IEEE1284_ADDR)) {
+ case IEEE1284_MODE_NIBBLE:
+ case IEEE1284_MODE_BYTE:
+ return IEEE1284_PH_REV_IDLE;
+ }
+ return IEEE1284_PH_FWD_IDLE;
+}
+
static int pp_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
unsigned int minor = MINOR(inode->i_rdev);
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
+ struct pp_struct *pp = file->private_data;
struct parport * port;
/* First handle the cases that don't take arguments. */
if (cmd == PPCLAIM) {
- if (pp_table[portnum][dev].flags & PP_CLAIMED) {
+ struct ieee1284_info *info;
+
+ if (pp->flags & PP_CLAIMED) {
printk (KERN_DEBUG CHRDEV
- "%02x: you've already got it!\n", minor);
+ "%x: you've already got it!\n", minor);
return -EINVAL;
}
/* Deferred device registration. */
- if (!pp_table[portnum][dev].pdev) {
- int err = register_device (minor);
+ if (!pp->pdev) {
+ int err = register_device (minor, pp);
if (err)
return err;
}
- parport_claim_or_block (pp_table[portnum][dev].pdev);
- pp_table[portnum][dev].flags |= PP_CLAIMED;
+ parport_claim_or_block (pp->pdev);
+ pp->flags |= PP_CLAIMED;
+
+ /* For interrupt-reporting to work, we need to be
+ * informed of each interrupt. */
+ enable_irq (pp);
+
+ /* We may need to fix up the state machine. */
+ info = &pp->pdev->port->ieee1284;
+ pp->saved_state.mode = info->mode;
+ pp->saved_state.phase = info->phase;
+ info->mode = pp->state.mode;
+ info->phase = pp->state.phase;
+
return 0;
}
- port = pp_table[portnum][dev].pdev->port;
if (cmd == PPEXCL) {
- if (pp_table[portnum][dev].pdev) {
- printk (KERN_DEBUG CHRDEV "%02x: too late for PPEXCL; "
+ if (pp->pdev) {
+ printk (KERN_DEBUG CHRDEV "%x: too late for PPEXCL; "
"already registered\n", minor);
- if (pp_table[portnum][dev].flags & PP_EXCL)
+ if (pp->flags & PP_EXCL)
/* But it's not really an error. */
return 0;
/* There's no chance of making the driver happy. */
@@ -356,22 +308,54 @@ static int pp_ioctl(struct inode *inode, struct file *file,
/* Just remember to register the device exclusively
* when we finally do the registration. */
- pp_table[portnum][dev].flags |= PP_EXCL;
+ pp->flags |= PP_EXCL;
+ return 0;
+ }
+
+ if (cmd == PPSETMODE) {
+ int mode;
+ if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+ return -EFAULT;
+ /* FIXME: validate mode */
+ pp->state.mode = mode;
+ pp->state.phase = init_phase (mode);
+
+ if (pp->flags & PP_CLAIMED) {
+ pp->pdev->port->ieee1284.mode = mode;
+ pp->pdev->port->ieee1284.phase = pp->state.phase;
+ }
+
+ return 0;
+ }
+
+ if (cmd == PPSETPHASE) {
+ int phase;
+ if (copy_from_user (&phase, (int *) arg, sizeof (phase)))
+ return -EFAULT;
+ /* FIXME: validate phase */
+ pp->state.phase = phase;
+
+ if (pp->flags & PP_CLAIMED)
+ pp->pdev->port->ieee1284.phase = phase;
+
return 0;
}
/* Everything else requires the port to be claimed, so check
* that now. */
- if ((pp_table[portnum][dev].flags & PP_CLAIMED) == 0) {
- printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+ if ((pp->flags & PP_CLAIMED) == 0) {
+ printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
minor);
- return -EPERM;
+ return -EINVAL;
}
+ port = pp->pdev->port;
switch (cmd) {
+ struct ieee1284_info *info;
unsigned char reg;
unsigned char mask;
int mode;
+ int ret;
case PPRSTATUS:
reg = parport_read_status (port);
@@ -389,19 +373,18 @@ static int pp_ioctl(struct inode *inode, struct file *file,
sizeof (reg));
case PPYIELD:
- parport_yield_blocking (pp_table[portnum][dev].pdev);
+ parport_yield_blocking (pp->pdev);
return 0;
case PPRELEASE:
- parport_release (pp_table[portnum][dev].pdev);
- pp_table[portnum][dev].flags &= ~PP_CLAIMED;
- return 0;
-
- case PPSETMODE:
- if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
- return -EFAULT;
- /* FIXME: validate mode */
- pp_table[portnum][dev].mode = mode;
+ /* Save the state machine's state. */
+ info = &pp->pdev->port->ieee1284;
+ pp->state.mode = info->mode;
+ pp->state.phase = info->phase;
+ info->mode = pp->saved_state.mode;
+ info->phase = pp->saved_state.phase;
+ parport_release (pp->pdev);
+ pp->flags &= ~PP_CLAIMED;
return 0;
case PPWCONTROL:
@@ -438,11 +421,38 @@ static int pp_ioctl(struct inode *inode, struct file *file,
case PPNEGOT:
if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
return -EFAULT;
- /* FIXME: validate mode */
- return parport_negotiate (port, mode);
+ switch ((ret = parport_negotiate (port, mode))) {
+ case 0: break;
+ case -1: /* handshake failed, peripheral not IEEE 1284 */
+ ret = -EIO;
+ break;
+ case 1: /* handshake succeeded, peripheral rejected mode */
+ ret = -ENXIO;
+ break;
+ }
+ enable_irq (pp);
+ return ret;
+
+ case PPWCTLONIRQ:
+ if (copy_from_user (&reg, (unsigned char *) arg,
+ sizeof (reg)))
+ return -EFAULT;
+
+ /* Remember what to set the control lines to, for next
+ * time we get an interrupt. */
+ pp->irqctl = reg;
+ pp->irqresponse = 1;
+ return 0;
+
+ case PPCLRIRQ:
+ ret = atomic_read (&pp->irqc);
+ if (copy_to_user ((int *) arg, &ret, sizeof (ret)))
+ return -EFAULT;
+ atomic_sub (ret, &pp->irqc);
+ return 0;
default:
- printk (KERN_DEBUG CHRDEV "%02x: What? (cmd=0x%x\n", minor,
+ printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor,
cmd);
return -EINVAL;
}
@@ -454,24 +464,27 @@ static int pp_ioctl(struct inode *inode, struct file *file,
static int pp_open (struct inode * inode, struct file * file)
{
unsigned int minor = MINOR (inode->i_rdev);
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
+ struct pp_struct *pp;
- if (portnum >= PARPORT_MAX)
+ if (minor >= PARPORT_MAX)
return -ENXIO;
- if (pp_table[portnum][dev].pdev)
- return -EBUSY;
+ pp = kmalloc (GFP_KERNEL, sizeof (struct pp_struct));
+ if (!pp)
+ return -ENOMEM;
- pp_table[portnum][dev].mode = IEEE1284_MODE_COMPAT;
- pp_table[portnum][dev].flags = 0;
- init_waitqueue_head (&pp_table[portnum][dev].irq_wait);
+ pp->state.mode = IEEE1284_MODE_COMPAT;
+ pp->state.phase = init_phase (pp->state.mode);
+ pp->flags = 0;
+ atomic_set (&pp->irqc, 0);
+ init_waitqueue_head (&pp->irq_wait);
/* Defer the actual device registration until the first claim.
* That way, we know whether or not the driver wants to have
* exclusive access to the port (PPEXCL).
*/
- pp_table[portnum][dev].pdev = NULL;
+ pp->pdev = NULL;
+ file->private_data = pp;
MOD_INC_USE_COUNT;
return 0;
@@ -480,42 +493,46 @@ static int pp_open (struct inode * inode, struct file * file)
static int pp_release (struct inode * inode, struct file * file)
{
unsigned int minor = MINOR (inode->i_rdev);
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
+ struct pp_struct *pp = file->private_data;
- if (pp_table[portnum][dev].flags & PP_CLAIMED) {
- parport_release (pp_table[portnum][dev].pdev);
- printk (KERN_DEBUG CHRDEV "%02x: released pardevice because "
+ if (pp->flags & PP_CLAIMED) {
+ parport_release (pp->pdev);
+ printk (KERN_DEBUG CHRDEV "%x: released pardevice because "
"user-space forgot\n", minor);
}
- if (pp_table[portnum][dev].pdev) {
- kfree (pp_table[portnum][dev].pdev->name);
- parport_unregister_device (pp_table[portnum][dev].pdev);
- pp_table[portnum][dev].pdev = NULL;
- printk (KERN_DEBUG CHRDEV "%02x: unregistered pardevice\n",
+ if (pp->pdev) {
+ parport_unregister_device (pp->pdev);
+ kfree (pp->pdev->name);
+ pp->pdev = NULL;
+ printk (KERN_DEBUG CHRDEV "%x: unregistered pardevice\n",
minor);
}
+ kfree (pp);
+
MOD_DEC_USE_COUNT;
return 0;
}
-#if 0
static unsigned int pp_poll (struct file * file, poll_table * wait)
{
- unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
- poll_wait (file, &pp_table[minor].irq_wait, wait);
- return 0; /* FIXME! Return value is wrong here */
+ struct pp_struct *pp = file->private_data;
+ unsigned int mask = 0;
+
+ if (atomic_read (&pp->irqc))
+ mask |= POLLIN | POLLRDNORM;
+
+ poll_wait (file, &pp->irq_wait, wait);
+ return mask;
}
-#endif
static struct file_operations pp_fops = {
pp_lseek,
pp_read,
pp_write,
NULL, /* pp_readdir */
- NULL, /* pp_poll */
+ pp_poll,
pp_ioctl,
NULL, /* pp_mmap */
pp_open,
diff --git a/drivers/char/ppdev.h b/drivers/char/ppdev.h
index f52d3c79d..976374aed 100644
--- a/drivers/char/ppdev.h
+++ b/drivers/char/ppdev.h
@@ -63,3 +63,12 @@ struct ppdev_frob_struct {
/* Negotiate a particular IEEE 1284 mode. */
#define PPNEGOT _IOW(PP_IOCTL, 0x91, int)
+
+/* Set control lines when an interrupt occurs. */
+#define PPWCTLONIRQ _IOW(PP_IOCTL, 0x92, unsigned char)
+
+/* Clear (and return) interrupt count. */
+#define PPCLRIRQ _IOR(PP_IOCTL, 0x93, int)
+
+/* Set the IEEE 1284 phase that we're in (e.g. IEEE1284_PH_FWD_IDLE) */
+#define PPSETPHASE _IOW(PP_IOCTL, 0x94, int)
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 1e67c604e..5f35b24ad 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -334,7 +334,7 @@ static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios)
tty->termios->c_cflag |= (CS8 | CREAD);
}
-__initfunc(int pty_init(void))
+int __init pty_init(void)
{
int i;
diff --git a/drivers/char/q40_keyb.c b/drivers/char/q40_keyb.c
new file mode 100644
index 000000000..7ee9818ef
--- /dev/null
+++ b/drivers/char/q40_keyb.c
@@ -0,0 +1,454 @@
+/*
+ * linux/drivers/char/q40_keyb.c
+ *
+ */
+
+#include <linux/config.h>
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/sysrq.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/q40_master.h>
+#include <asm/irq.h>
+#include <asm/q40ints.h>
+
+/* Some configuration switches are present in the include file... */
+
+#define KBD_REPORT_ERR
+
+/* Simple translation table for the SysRq keys */
+
+#define SYSRQ_KEY 0x54
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char q40kbd_sysrq_xlate[128] =
+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+ "\r\000/"; /* 0x60 - 0x6f */
+#endif
+
+/* Q40 uses AT scancodes - no way to change it. so we have to translate ..*/
+/* 0x00 means not a valid entry or no conversion known */
+
+unsigned static char q40cl[256] =
+{/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, */
+ 0x00,0x43,0x00,0x3f,0x3d,0x3b,0x3c,0x58,0x00,0x44,0x42,0x40,0x3e,0x0f,0x29,0x00, /* 0x00 - 0x0f */
+ 0x00,0x38,0x2a,0x00,0x1d,0x10,0x02,0x00,0x00,0x00,0x2c,0x1f,0x1e,0x11,0x03,0x00, /* 0x10 - 0x1f */
+ 0x00,0x2e,0x2d,0x20,0x12,0x05,0x04,0x00,0x21,0x39,0x2f,0x21,0x14,0x13,0x06,0x00, /* 0x20 - 0x2f 'f' is at 0x2b, what is 0x28 ???*/
+ 0x00,0x31,0x30,0x23,0x22,0x15,0x07,0x00,0x24,0x00,0x32,0x24,0x16,0x08,0x09,0x00, /* 0x30 - 0x3f */
+ 0x00,0x33,0x25,0x17,0x18,0x0b,0x0a,0x00,0x00,0x34,0x35,0x26,0x27,0x19,0x0c,0x00, /* 0x40 - 0x4f */
+ 0x00,0x00,0x28,0x00,0x1a,0x0d,0x00,0x00,0x3a,0x36,0x1c,0x1b,0x00,0x2b,0x00,0x00, /* 0x50 - 0x5f*/
+ 0x00,0x56,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00, /* 0x60 - 0x6f */
+ 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x00, /* 0x70 - 0x7f */
+ 0x00,0x00,0x00,0x41,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x80 - 0x8f 0x84/0x37 is SySrq*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x90 - 0x9f */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xa0 - 0xaf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xb0 - 0xbf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xc0 - 0xcf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xd0 - 0xdf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xe0 - 0xef */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xf0 - 0xff */
+};
+
+/* another table, AT 0xe0 codes to PC 0xe0 codes,
+ 0xff special entry for SysRq - DROPPED right now */
+static unsigned char q40ecl[]=
+{/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x00 - 0x0f*/
+ 0x00,0x38,0x2a,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x10 - 0x1f */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x20 - 0x2f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x30 - 0x3f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x00,0x00, /* 0x40 - 0x4f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x1c,0x00,0x00,0x00,0x00,0x00, /* 0x50 - 0x5f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00, /* 0x60 - 0x6f*/
+ 0x52,0x53,0x50,0x00,0x4d,0x48,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x49,0x00,0x00, /* 0x70 - 0x7f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x80 - 0x8f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x90 - 0x9f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xa0 - 0xaf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xb0 - 0xbf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xc0 - 0xcf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xd0 - 0xdf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xe0 - 0xef*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 0xf0 - 0xff*/
+};
+
+
+spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+
+
+/*
+ * Translation of escaped scancodes to keycodes.
+ * This is now user-settable.
+ * The keycodes 1-88,96-111,119 are fairly standard, and
+ * should probably not be changed - changing might confuse X.
+ * X also interprets scancode 0x5d (KEY_Begin).
+ *
+ * For 1-88 keycode equals scancode.
+ */
+
+#define E0_KPENTER 96
+#define E0_RCTRL 97
+#define E0_KPSLASH 98
+#define E0_PRSCR 99
+#define E0_RALT 100
+#define E0_BREAK 101 /* (control-pause) */
+#define E0_HOME 102
+#define E0_UP 103
+#define E0_PGUP 104
+#define E0_LEFT 105
+#define E0_RIGHT 106
+#define E0_END 107
+#define E0_DOWN 108
+#define E0_PGDN 109
+#define E0_INS 110
+#define E0_DEL 111
+
+#define E1_PAUSE 119
+
+/*
+ * The keycodes below are randomly located in 89-95,112-118,120-127.
+ * They could be thrown away (and all occurrences below replaced by 0),
+ * but that would force many users to use the `setkeycodes' utility, where
+ * they needed not before. It does not matter that there are duplicates, as
+ * long as no duplication occurs for any single keyboard.
+ */
+#define SC_LIM 89
+
+#define FOCUS_PF1 85 /* actual code! */
+#define FOCUS_PF2 89
+#define FOCUS_PF3 90
+#define FOCUS_PF4 91
+#define FOCUS_PF5 92
+#define FOCUS_PF6 93
+#define FOCUS_PF7 94
+#define FOCUS_PF8 95
+#define FOCUS_PF9 120
+#define FOCUS_PF10 121
+#define FOCUS_PF11 122
+#define FOCUS_PF12 123
+
+#define JAP_86 124
+/* tfj@olivia.ping.dk:
+ * The four keys are located over the numeric keypad, and are
+ * labelled A1-A4. It's an rc930 keyboard, from
+ * Regnecentralen/RC International, Now ICL.
+ * Scancodes: 59, 5a, 5b, 5c.
+ */
+#define RGN1 124
+#define RGN2 125
+#define RGN3 126
+#define RGN4 127
+
+static unsigned char high_keys[128 - SC_LIM] = {
+ RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */
+ 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */
+ FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */
+ FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */
+};
+
+/* BTC */
+#define E0_MACRO 112
+/* LK450 */
+#define E0_F13 113
+#define E0_F14 114
+#define E0_HELP 115
+#define E0_DO 116
+#define E0_F17 117
+#define E0_KPMINPLUS 118
+/*
+ * My OmniKey generates e0 4c for the "OMNI" key and the
+ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
+ */
+#define E0_OK 124
+/*
+ * New microsoft keyboard is rumoured to have
+ * e0 5b (left window button), e0 5c (right window button),
+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
+ * [or: Windows_L, Windows_R, TaskMan]
+ */
+#define E0_MSLW 125
+#define E0_MSRW 126
+#define E0_MSTM 127
+
+/* this can be changed using setkeys : */
+static unsigned char e0_keys[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
+ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
+ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */
+ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */
+ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
+ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
+ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */
+ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
+};
+
+static unsigned int prev_scancode = 0; /* remember E0, E1 */
+
+int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+ if (scancode < SC_LIM || scancode > 255 || keycode > 127)
+ return -EINVAL;
+ if (scancode < 128)
+ high_keys[scancode - SC_LIM] = keycode;
+ else
+ e0_keys[scancode - 128] = keycode;
+ return 0;
+}
+
+int q40kbd_getkeycode(unsigned int scancode)
+{
+ return
+ (scancode < SC_LIM || scancode > 255) ? -EINVAL :
+ (scancode < 128) ? high_keys[scancode - SC_LIM] :
+ e0_keys[scancode - 128];
+}
+
+
+#define disable_keyboard()
+#define enable_keyboard()
+
+
+
+
+int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
+{
+ if (scancode == 0xe0 || scancode == 0xe1) {
+ prev_scancode = scancode;
+ return 0;
+ }
+
+ if (prev_scancode) {
+ /*
+ * usually it will be 0xe0, but a Pause key generates
+ * e1 1d 45 e1 9d c5 when pressed, and nothing when released
+ */
+ if (prev_scancode != 0xe0) {
+ if (prev_scancode == 0xe1 && scancode == 0x1d) {
+ prev_scancode = 0x100;
+ return 0;
+ } else if (prev_scancode == 0x100 && scancode == 0x45) {
+ *keycode = E1_PAUSE;
+ prev_scancode = 0;
+ } else {
+#ifdef KBD_REPORT_UNKN
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+#endif
+ prev_scancode = 0;
+ return 0;
+ }
+ } else {
+ prev_scancode = 0;
+ /*
+ * The keyboard maintains its own internal caps lock and
+ * num lock statuses. In caps lock mode E0 AA precedes make
+ * code and E0 2A follows break code. In num lock mode,
+ * E0 2A precedes make code and E0 AA follows break code.
+ * We do our own book-keeping, so we will just ignore these.
+ */
+ /*
+ * For my keyboard there is no caps lock mode, but there are
+ * both Shift-L and Shift-R modes. The former mode generates
+ * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
+ * So, we should also ignore the latter. - aeb@cwi.nl
+ */
+ if (scancode == 0x2a || scancode == 0x36)
+ return 0;
+
+ if (e0_keys[scancode])
+ *keycode = e0_keys[scancode];
+ else {
+#ifdef KBD_REPORT_UNKN
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+ scancode);
+#endif
+ return 0;
+ }
+ }
+ } else if (scancode >= SC_LIM) {
+ /* This happens with the FOCUS 9000 keyboard
+ Its keys PF1..PF12 are reported to generate
+ 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
+ Moreover, unless repeated, they do not generate
+ key-down events, so we have to zero up_flag below */
+ /* Also, Japanese 86/106 keyboards are reported to
+ generate 0x73 and 0x7d for \ - and \ | respectively. */
+ /* Also, some Brazilian keyboard is reported to produce
+ 0x73 and 0x7e for \ ? and KP-dot, respectively. */
+
+ *keycode = high_keys[scancode - SC_LIM];
+
+ if (!*keycode) {
+ if (!raw_mode) {
+#ifdef KBD_REPORT_UNKN
+ printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
+ " - ignored\n", scancode);
+#endif
+ }
+ return 0;
+ }
+ } else
+ *keycode = scancode;
+ return 1;
+}
+
+char q40kbd_unexpected_up(unsigned char keycode)
+{
+ /* unexpected, but this can happen: maybe this was a key release for a
+ FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
+ if (keycode >= SC_LIM || keycode == 85)
+ return 0;
+ else
+ return 0200;
+}
+
+static int keyup=0;
+static int qprev=0;
+
+static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+ unsigned char status;
+
+ disable_keyboard();
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kbd_pt_regs = regs;
+
+ status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
+ if (status )
+ {
+ unsigned char scancode,qcode;
+
+ qcode = master_inb(KEYCODE_REG);
+
+ if (qcode != 0xf0)
+ {
+ if (qcode == 0xe0)
+ {
+ qprev=0xe0;
+ handle_scancode(qprev , 1);
+ goto exit;
+ }
+
+ scancode=qprev ? q40ecl[qcode] : q40cl[qcode];
+#if 0
+/* next line is last resort to hanlde some oddities */
+ if (qprev && !scancode) scancode=q40cl[qcode];
+#endif
+ qprev=0;
+ if (!scancode)
+ {
+ printk("unknown scancode %x\n",qcode);
+ goto exit;
+ }
+ if (scancode==0xff) /* SySrq */
+ scancode=SYSRQ_KEY;
+
+ handle_scancode(scancode, ! keyup );
+ keyup=0;
+ mark_bh(KEYBOARD_BH);
+
+ }
+ else
+ keyup=1;
+ }
+exit:
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+ master_outb(-1,KEYBOARD_UNLOCK_REG); /* keyb ints reenabled herewith */
+ enable_keyboard();
+}
+
+
+
+
+#ifdef CONFIG_MAGIC_SYSRQ
+int kbd_is_sysrq(unsigned char keycode)
+{
+ return( keycode == SYSRQ_KEY );
+}
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+
+
+
+#define KBD_NO_DATA (-1) /* No data */
+#define KBD_BAD_DATA (-2) /* Parity or other error */
+
+static int __init kbd_read_input(void)
+{
+ int retval = KBD_NO_DATA;
+ unsigned char status;
+
+ status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
+ if (status) {
+ unsigned char data = master_inb(KEYCODE_REG);
+
+ retval = data;
+ master_outb(-1,KEYBOARD_UNLOCK_REG);
+ }
+ return retval;
+}
+
+extern void q40kbd_leds(unsigned char leds)
+{ /* nothing can be done */ }
+
+static void __init kbd_clear_input(void)
+{
+ int maxread = 100; /* Random number */
+
+ do {
+ if (kbd_read_input() == KBD_NO_DATA)
+ break;
+ } while (--maxread);
+}
+
+
+void __init q40kbd_init_hw(void)
+{
+#if 0
+ /* Get the keyboard controller registers (incomplete decode) */
+ request_region(0x60, 16, "keyboard");
+#endif
+ /* Flush any pending input. */
+ kbd_clear_input();
+
+ /* Ok, finally allocate the IRQ, and off we go.. */
+ request_irq(Q40_IRQ_KEYBOARD, keyboard_interrupt, 0, "keyboard", NULL);
+ master_outb(-1,KEYBOARD_UNLOCK_REG);
+ master_outb(1,KEY_IRQ_ENABLE_REG);
+
+}
+
diff --git a/drivers/char/qpmouse.c b/drivers/char/qpmouse.c
index 2aa736190..8d5f9aa34 100644
--- a/drivers/char/qpmouse.c
+++ b/drivers/char/qpmouse.c
@@ -267,7 +267,7 @@ static ssize_t read_qp(struct file * file, char * buffer,
return -EAGAIN;
add_wait_queue(&queue->proc_list, &wait);
repeat:
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (queue_empty() && !signal_pending(current)) {
schedule();
goto repeat;
diff --git a/drivers/char/radio-aimslab.c b/drivers/char/radio-aimslab.c
index fc3101f34..ee986b335 100644
--- a/drivers/char/radio-aimslab.c
+++ b/drivers/char/radio-aimslab.c
@@ -35,6 +35,7 @@
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
#include <linux/config.h> /* CONFIG_RADIO_RTRACK_PORT */
+#include <asm/semaphore.h> /* Lock for the I/O */
#ifndef CONFIG_RADIO_RTRACK_PORT
#define CONFIG_RADIO_RTRACK_PORT -1
@@ -42,6 +43,7 @@
static int io = CONFIG_RADIO_RTRACK_PORT;
static int users = 0;
+static struct semaphore lock;
struct rt_device
{
@@ -86,19 +88,23 @@ static void rt_incvol(void)
static void rt_mute(struct rt_device *dev)
{
dev->muted = 1;
+ down(&lock);
outb(0xd0, io); /* volume steady, off */
+ up(&lock);
}
static int rt_setvol(struct rt_device *dev, int vol)
{
int i;
+ down(&lock);
+
if(vol == dev->curvol) { /* requested volume = current */
if (dev->muted) { /* user is unmuting the card */
dev->muted = 0;
outb (0xd8, io); /* enable card */
}
-
+ up(&lock);
return 0;
}
@@ -107,6 +113,7 @@ static int rt_setvol(struct rt_device *dev, int vol)
sleep_delay(2000000); /* make sure it's totally down */
outb(0xd0, io); /* volume steady, off */
dev->curvol = 0; /* track the volume state! */
+ up(&lock);
return 0;
}
@@ -119,7 +126,7 @@ static int rt_setvol(struct rt_device *dev, int vol)
rt_decvol();
dev->curvol = vol;
-
+ up(&lock);
return 0;
}
@@ -165,6 +172,8 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
freq += 171200; /* Add 10.7 MHz IF */
freq /= 800; /* Convert to 50 kHz units */
+
+ down(&lock); /* Stop other ops interfering */
send_0_byte (io, dev); /* 0: LSB of frequency */
@@ -191,11 +200,13 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
outb (0xd0, io); /* volume steady + sigstr */
else
outb (0xd8, io); /* volume steady + sigstr + on */
+
+ up(&lock);
return 0;
}
-int rt_getsigstr(struct rt_device *dev)
+static int rt_getsigstr(struct rt_device *dev)
{
if (inb(io) & 2) /* bit set = no signal present */
return 0;
@@ -324,8 +335,14 @@ static struct video_device rtrack_radio=
NULL
};
-int __init rtrack_init(struct video_init *v)
+static int __init rtrack_init(void)
{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+ return -EINVAL;
+ }
+
if (check_region(io, 2))
{
printk(KERN_ERR "rtrack: port 0x%x already in use\n", io);
@@ -340,6 +357,10 @@ int __init rtrack_init(struct video_init *v)
request_region(io, 2, "rtrack");
printk(KERN_INFO "AIMSlab Radiotrack/radioreveal card driver.\n");
+ /* Set up the I/O locking */
+
+ init_MUTEX(&lock);
+
/* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
@@ -351,8 +372,6 @@ int __init rtrack_init(struct video_init *v)
return 0;
}
-#ifdef MODULE
-
MODULE_AUTHOR("M.Kirkwood");
MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
MODULE_PARM(io, "i");
@@ -360,20 +379,12 @@ 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)
+static void __exit cleanup_rtrack_module(void)
{
video_unregister_device(&rtrack_radio);
release_region(io,2);
}
-#endif
+module_init(rtrack_init);
+module_exit(cleanup_rtrack_module);
+
diff --git a/drivers/char/radio-aztech.c b/drivers/char/radio-aztech.c
index 1c26bba93..2fb8714ad 100644
--- a/drivers/char/radio-aztech.c
+++ b/drivers/char/radio-aztech.c
@@ -42,6 +42,7 @@
static int io = CONFIG_RADIO_AZTECH_PORT;
static int radio_wait_time = 1000;
static int users = 0;
+static struct semaphore lock;
struct az_device
{
@@ -86,7 +87,9 @@ static void send_1_byte (struct az_device *dev)
static int az_setvol(struct az_device *dev, int vol)
{
+ down(&lock);
outb (volconvert(vol), io);
+ up(&lock);
return 0;
}
@@ -119,6 +122,8 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
frequency += 171200; /* Add 10.7 MHz IF */
frequency /= 800; /* Convert to 50 kHz units */
+ down(&lock);
+
send_0_byte (dev); /* 0: LSB of frequency */
for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
@@ -146,6 +151,8 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
udelay (radio_wait_time);
outb_p(128+64+volconvert(dev->curvol), io);
+
+ up(&lock);
return 0;
}
@@ -279,14 +286,21 @@ static struct video_device aztech_radio=
NULL
};
-int __init aztech_init(struct video_init *v)
+static int __init aztech_init(void)
{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+ return -EINVAL;
+ }
+
if (check_region(io, 2))
{
printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
return -EBUSY;
}
+ init_MUTEX(&lock);
aztech_radio.priv=&aztech_unit;
if(video_register_device(&aztech_radio, VFL_TYPE_RADIO)==-1)
@@ -299,8 +313,6 @@ int __init aztech_init(struct video_init *v)
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");
@@ -308,20 +320,11 @@ 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)
+static void __exit aztech_cleanup(void)
{
video_unregister_device(&aztech_radio);
release_region(io,2);
}
-#endif
+module_init(aztech_init);
+module_exit(aztech_cleanup);
diff --git a/drivers/char/radio-gemtek.c b/drivers/char/radio-gemtek.c
index 9cee2342e..523ac0955 100644
--- a/drivers/char/radio-gemtek.c
+++ b/drivers/char/radio-gemtek.c
@@ -23,6 +23,7 @@
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
#include <linux/config.h> /* CONFIG_RADIO_GEMTEK_PORT */
+#include <linux/spinlock.h>
#ifndef CONFIG_RADIO_GEMTEK_PORT
#define CONFIG_RADIO_GEMTEK_PORT -1
@@ -30,6 +31,7 @@
static int io = CONFIG_RADIO_GEMTEK_PORT;
static int users = 0;
+static spinlock_t lock;
struct gemtek_device
{
@@ -48,7 +50,9 @@ static void gemtek_mute(struct gemtek_device *dev)
{
if(dev->muted)
return;
+ spin_lock(&lock);
outb(0x10, io);
+ spin_unlock(&lock);
dev->muted = 1;
}
@@ -56,7 +60,9 @@ static void gemtek_unmute(struct gemtek_device *dev)
{
if(dev->muted == 0)
return;
+ spin_lock(&lock);
outb(0x20, io);
+ spin_unlock(&lock);
dev->muted = 0;
}
@@ -87,6 +93,8 @@ static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
freq *= 7825;
freq /= 100000;
+ spin_lock(&lock);
+
/* 2 start bits */
outb_p(0x03, io);
udelay(5);
@@ -114,13 +122,17 @@ static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
outb_p(0x07, io);
udelay(5);
+ spin_unlock(&lock);
+
return 0;
}
int gemtek_getsigstr(struct gemtek_device *dev)
{
+ spin_lock(&lock);
inb(io);
udelay(5);
+ spin_unlock(&lock);
if (inb(io) & 8) /* bit set = no signal present */
return 0;
return 1; /* signal present */
@@ -250,8 +262,14 @@ static struct video_device gemtek_radio=
NULL
};
-int __init gemtek_init(struct video_init *v)
+static int __init gemtek_init(void)
{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (or io=0x248 for the combined sound/radiocard)\n");
+ return -EINVAL;
+ }
+
if (check_region(io, 4))
{
printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
@@ -266,6 +284,7 @@ int __init gemtek_init(struct video_init *v)
request_region(io, 4, "gemtek");
printk(KERN_INFO "GemTek Radio Card driver.\n");
+ spin_lock_init(&lock);
/* mute card - prevents noisy bootups */
outb(0x10, io);
udelay(5);
@@ -277,8 +296,6 @@ int __init gemtek_init(struct video_init *v)
return 0;
}
-#ifdef MODULE
-
MODULE_AUTHOR("Jonas Munsin");
MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
MODULE_PARM(io, "i");
@@ -286,23 +303,14 @@ MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x3
EXPORT_NO_SYMBOLS;
-int init_module(void)
-{
- if(io==-1)
- {
- printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (or io=0x248 for the combined sound/radiocard)\n");
- return -EINVAL;
- }
- return gemtek_init(NULL);
-}
-
-void cleanup_module(void)
+static void __exit gemtek_cleanup(void)
{
video_unregister_device(&gemtek_radio);
release_region(io,4);
}
-#endif
+module_init(gemtek_init);
+module_exit(gemtek_cleanup);
/*
Local variables:
diff --git a/drivers/char/radio-miropcm20.c b/drivers/char/radio-miropcm20.c
index 66314f72f..04beea2d5 100644
--- a/drivers/char/radio-miropcm20.c
+++ b/drivers/char/radio-miropcm20.c
@@ -205,7 +205,7 @@ static struct video_device pcm20_radio=
NULL
};
-int __init pcm20_init(struct video_init *v)
+static int __init pcm20_init(void)
{
pcm20_radio.priv=&pcm20_unit;
@@ -224,22 +224,16 @@ int __init pcm20_init(struct video_init *v)
return 0;
}
-#ifdef MODULE
-
MODULE_AUTHOR("Ruurd Reitsma");
MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
EXPORT_NO_SYMBOLS;
-int init_module(void)
-{
-
- return pcm20_init(NULL);
-}
-
-void cleanup_module(void)
+static void __exit pcm20_cleanup(void)
{
video_unregister_device(&pcm20_radio);
}
-#endif
+module_init(pcm20_init);
+module_exit(pcm20_cleanup);
+
diff --git a/drivers/char/radio-rtrack2.c b/drivers/char/radio-rtrack2.c
index 7370f3a61..8876d789d 100644
--- a/drivers/char/radio-rtrack2.c
+++ b/drivers/char/radio-rtrack2.c
@@ -16,6 +16,7 @@
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
#include <linux/config.h> /* CONFIG_RADIO_RTRACK2_PORT */
+#include <linux/spinlock.h>
#ifndef CONFIG_RADIO_RTRACK2_PORT
#define CONFIG_RADIO_RTRACK2_PORT -1
@@ -23,6 +24,7 @@
static int io = CONFIG_RADIO_RTRACK2_PORT;
static int users = 0;
+static spinlock_t lock;
struct rt_device
{
@@ -38,7 +40,9 @@ static void rt_mute(struct rt_device *dev)
{
if(dev->muted)
return;
+ spin_lock(&lock);
outb(1, io);
+ spin_unlock(&lock);
dev->muted = 1;
}
@@ -46,7 +50,9 @@ static void rt_unmute(struct rt_device *dev)
{
if(dev->muted == 0)
return;
+ spin_lock(&lock);
outb(0, io);
+ spin_unlock(&lock);
dev->muted = 0;
}
@@ -69,6 +75,8 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
int i;
freq = freq / 200 + 856;
+
+ spin_lock(&lock);
outb_p(0xc8, io);
outb_p(0xc9, io);
@@ -85,11 +93,13 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
outb_p(0xc8, io);
if (!dev->muted)
- outb_p(0, io);
+ outb_p(0, io);
+
+ spin_unlock(&lock);
return 0;
}
-int rt_getsigstr(struct rt_device *dev)
+static int rt_getsigstr(struct rt_device *dev)
{
if (inb(io) & 2) /* bit set = no signal present */
return 0;
@@ -227,7 +237,8 @@ int __init rtrack2_init(struct video_init *v)
}
rtrack2_radio.priv=&rtrack2_unit;
-
+
+ spin_lock_init(&lock);
if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO)==-1)
return -EINVAL;
diff --git a/drivers/char/radio-sf16fmi.c b/drivers/char/radio-sf16fmi.c
index c659cc7ba..ef73f2d77 100644
--- a/drivers/char/radio-sf16fmi.c
+++ b/drivers/char/radio-sf16fmi.c
@@ -22,6 +22,7 @@
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
#include <linux/config.h> /* CONFIG_RADIO_SF16MI_PORT */
+#include <asm/semaphore.h>
struct fmi_device
{
@@ -37,6 +38,7 @@ struct fmi_device
static int io = CONFIG_RADIO_SF16FMI_PORT;
static int users = 0;
+static struct semaphore lock;
/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
/* It is only usefull to give freq in intervall of 800 (=0.05Mhz),
@@ -67,12 +69,16 @@ static void outbits(int bits, unsigned int data, int port)
static inline void fmi_mute(int port)
{
+ down(&lock);
outb(0x00, port);
+ up(&lock);
}
static inline void fmi_unmute(int port)
{
+ down(&lock);
outb(0x08, port);
+ up(&lock);
}
static inline int fmi_setfreq(struct fmi_device *dev)
@@ -81,6 +87,8 @@ static inline int fmi_setfreq(struct fmi_device *dev)
unsigned long freq = dev->curfreq;
int i;
+ down(&lock);
+
outbits(16, RSF16_ENCODE(freq), myport);
outbits(8, 0xC0, myport);
for(i=0; i< 100; i++)
@@ -93,6 +101,8 @@ static inline int fmi_setfreq(struct fmi_device *dev)
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ/7);
*/
+
+ up(&lock);
if (dev->curvol) fmi_unmute(myport);
return 0;
}
@@ -104,6 +114,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
int myport = dev->port;
int i;
+ down(&lock);
val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */
outb(val, myport);
outb(val | 0x10, myport);
@@ -119,6 +130,8 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
*/
res = (int)inb(myport+1);
outb(val, myport);
+
+ up(&lock);
return (res & 2) ? 0 : 0xFFFF;
}
@@ -290,6 +303,8 @@ int __init fmi_init(struct video_init *v)
fmi_unit.flags = VIDEO_TUNER_LOW;
fmi_radio.priv = &fmi_unit;
+ init_MUTEX(&lock);
+
if(video_register_device(&fmi_radio, VFL_TYPE_RADIO)==-1)
return -EINVAL;
diff --git a/drivers/char/radio-terratec.c b/drivers/char/radio-terratec.c
index ae14d11f4..9fb119c30 100644
--- a/drivers/char/radio-terratec.c
+++ b/drivers/char/radio-terratec.c
@@ -31,6 +31,7 @@
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
#include <linux/config.h> /* CONFIG_RADIO_TERRATEC_PORT */
+#include <linux/spinlock.h>
#ifndef CONFIG_RADIO_TERRATEC_PORT
#define CONFIG_RADIO_TERRATEC_PORT 0x590
@@ -50,6 +51,7 @@
static int io = CONFIG_RADIO_TERRATEC_PORT;
static int users = 0;
+static spinlock_t lock;
struct tt_device
{
@@ -66,12 +68,14 @@ static void cardWriteVol(int volume)
{
int i;
volume = volume+(volume * 32); // change both channels
+ spin_lock(&lock);
for (i=0;i<8;i++)
{
if (volume & (0x80>>i))
outb(0x80, VOLPORT);
else outb(0x00, VOLPORT);
}
+ spin_unlock(&lock);
}
@@ -148,6 +152,8 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
temp = temp/2;
}
+ spin_lock(&lock);
+
for (i=24;i>-1;i--) /* bit shift the values to the radiocard */
{
if (buffer[i]==1)
@@ -163,6 +169,8 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
}
}
outb(0x00, BASEPORT);
+
+ spin_unlock(&lock);
return 0;
}
@@ -299,7 +307,7 @@ static struct video_device terratec_radio=
NULL
};
-__initfunc(int terratec_init(struct video_init *v))
+int __init terratec_init(struct video_init *v)
{
if (check_region(io, 2))
{
@@ -309,6 +317,8 @@ __initfunc(int terratec_init(struct video_init *v))
terratec_radio.priv=&terratec_unit;
+ spin_lock_init(&lock);
+
if(video_register_device(&terratec_radio, VFL_TYPE_RADIO)==-1)
return -EINVAL;
diff --git a/drivers/char/radio-trust.c b/drivers/char/radio-trust.c
new file mode 100644
index 000000000..15dee607a
--- /dev/null
+++ b/drivers/char/radio-trust.c
@@ -0,0 +1,354 @@
+/* radio-trust.c - Trust FM Radio card driver for Linux 2.2
+ * by Eric Lammerts <eric@scintilla.utwente.nl>
+ *
+ * Based on radio-aztech.c. Original notes:
+ *
+ * Adapted to support the Video for Linux API by
+ * Russell Kroll <rkroll@exploits.org>. Based on original tuner 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/
+ */
+
+#include <stdarg.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/config.h> /* CONFIG_RADIO_TRUST_PORT */
+
+/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
+
+#ifndef CONFIG_RADIO_TRUST_PORT
+#define CONFIG_RADIO_TRUST_PORT -1
+#endif
+
+static int io = CONFIG_RADIO_TRUST_PORT;
+static int ioval = 0xf;
+static int users = 0;
+static __u16 curvol;
+static __u16 curbass;
+static __u16 curtreble;
+static unsigned long curfreq;
+static int curstereo;
+static int curmute;
+
+/* i2c addresses */
+#define TDA7318_ADDR 0x88
+#define TSA6060T_ADDR 0xc4
+
+#define TR_DELAY do { inb(io); inb(io); inb(io); } while(0)
+#define TR_SET_SCL outb(ioval |= 2, io)
+#define TR_CLR_SCL outb(ioval &= 0xfd, io)
+#define TR_SET_SDA outb(ioval |= 1, io)
+#define TR_CLR_SDA outb(ioval &= 0xfe, io)
+
+static void write_i2c(int n, ...)
+{
+ unsigned char val, mask;
+ va_list args;
+
+ va_start(args, n);
+
+ /* start condition */
+ TR_SET_SDA;
+ TR_SET_SCL;
+ TR_DELAY;
+ TR_CLR_SDA;
+ TR_CLR_SCL;
+ TR_DELAY;
+
+ for(; n; n--) {
+ val = va_arg(args, unsigned);
+ for(mask = 0x80; mask; mask >>= 1) {
+ if(val & mask)
+ TR_SET_SDA;
+ else
+ TR_CLR_SDA;
+ TR_SET_SCL;
+ TR_DELAY;
+ TR_CLR_SCL;
+ TR_DELAY;
+ }
+ /* acknowledge bit */
+ TR_SET_SDA;
+ TR_SET_SCL;
+ TR_DELAY;
+ TR_CLR_SCL;
+ TR_DELAY;
+ }
+
+ /* stop condition */
+ TR_CLR_SDA;
+ TR_DELAY;
+ TR_SET_SCL;
+ TR_DELAY;
+ TR_SET_SDA;
+ TR_DELAY;
+
+ va_end(args);
+}
+
+static void tr_setvol(__u16 vol)
+{
+ curvol = vol / 2048;
+ write_i2c(2, TDA7318_ADDR, curvol ^ 0x1f);
+}
+
+static int basstreble2chip[15] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8
+};
+
+static void tr_setbass(__u16 bass)
+{
+ curbass = bass / 4370;
+ write_i2c(2, TDA7318_ADDR, 0x60 | basstreble2chip[curbass]);
+}
+
+static void tr_settreble(__u16 treble)
+{
+ curtreble = treble / 4370;
+ write_i2c(2, TDA7318_ADDR, 0x70 | basstreble2chip[curtreble]);
+}
+
+static void tr_setstereo(int stereo)
+{
+ curstereo = !!stereo;
+ ioval = (ioval & 0xfb) | (!curstereo << 2);
+ outb(ioval, io);
+}
+
+static void tr_setmute(int mute)
+{
+ curmute = !!mute;
+ ioval = (ioval & 0xf7) | (curmute << 3);
+ outb(ioval, io);
+}
+
+static int tr_getsigstr(void)
+{
+ int i, v;
+
+ for(i = 0, v = 0; i < 100; i++) v |= inb(io);
+ return (v & 1)? 0 : 0xffff;
+}
+
+static int tr_getstereo(void)
+{
+ /* don't know how to determine it, just return the setting */
+ return curstereo;
+}
+
+static void tr_setfreq(unsigned long f)
+{
+ f /= 160; /* Convert to 10 kHz units */
+ f += 1070; /* Add 10.7 MHz IF */
+
+ write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
+}
+
+static int tr_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ switch(cmd)
+ {
+ case VIDIOCGCAP:
+ {
+ struct video_capability v;
+
+ v.type=VID_TYPE_TUNER;
+ v.channels=1;
+ v.audios=1;
+
+ /* No we don't do pictures */
+ v.maxwidth=0;
+ v.maxheight=0;
+ v.minwidth=0;
+ v.minheight=0;
+
+ strcpy(v.name, "Trust FM Radio");
+
+ 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 = 87500 * 16;
+ v.rangehigh = 108000 * 16;
+ v.flags = VIDEO_TUNER_LOW;
+ v.mode = VIDEO_MODE_AUTO;
+
+ v.signal = tr_getsigstr();
+ if(tr_getstereo())
+ v.flags |= VIDEO_TUNER_STEREO_ON;
+
+ strcpy(v.name, "FM");
+
+ 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;
+
+ return 0;
+ }
+ case VIDIOCGFREQ:
+ if(copy_to_user(arg, &curfreq, sizeof(curfreq)))
+ return -EFAULT;
+ return 0;
+
+ case VIDIOCSFREQ:
+ {
+ unsigned long f;
+
+ if(copy_from_user(&f, arg, sizeof(curfreq)))
+ return -EFAULT;
+ tr_setfreq(f);
+ return 0;
+ }
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio v;
+
+ memset(&v,0, sizeof(v));
+ v.flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
+ VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
+ v.mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+ v.volume = curvol * 2048;
+ v.step = 2048;
+ v.bass = curbass * 4370;
+ v.treble = curtreble * 4370;
+
+ strcpy(v.name, "Trust FM 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;
+
+ tr_setvol(v.volume);
+ tr_setbass(v.bass);
+ tr_settreble(v.treble);
+ tr_setstereo(v.mode & VIDEO_SOUND_STEREO);
+ tr_setmute(v.flags & VIDEO_AUDIO_MUTE);
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int tr_open(struct video_device *dev, int flags)
+{
+ if(users)
+ return -EBUSY;
+ users++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void tr_close(struct video_device *dev)
+{
+ users--;
+ MOD_DEC_USE_COUNT;
+}
+
+static struct video_device trust_radio=
+{
+ "Trust FM Radio",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_TRUST,
+ tr_open,
+ tr_close,
+ NULL, /* Can't read (no capture ability) */
+ NULL, /* Can't write */
+ NULL, /* No poll */
+ tr_ioctl,
+ NULL,
+ NULL
+};
+
+static int __init trust_init(void)
+{
+ if(io == -1) {
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+ return -EINVAL;
+ }
+ if(check_region(io, 2)) {
+ printk(KERN_ERR "trust: port 0x%x already in use\n", io);
+ return -EBUSY;
+ }
+ if(video_register_device(&trust_radio, VFL_TYPE_RADIO)==-1)
+ return -EINVAL;
+
+ request_region(io, 2, "Trust FM Radio");
+
+ printk(KERN_INFO "Trust FM Radio card driver v1.0.\n");
+
+ write_i2c(2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */
+ write_i2c(2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */
+ write_i2c(2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
+ write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */
+ write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */
+
+ tr_setvol(0x8000);
+ tr_setbass(0x8000);
+ tr_settreble(0x8000);
+ tr_setstereo(1);
+
+ /* mute card - prevents noisy bootups */
+ tr_setmute(1);
+
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
+MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
+
+EXPORT_NO_SYMBOLS;
+
+#endif /* MODULE */
+
+static void __exit cleanup_trust_module(void)
+{
+ video_unregister_device(&trust_radio);
+ release_region(io, 2);
+}
+
+module_init(trust_init);
+module_exit(cleanup_trust_module);
diff --git a/drivers/char/radio-zoltrix.c b/drivers/char/radio-zoltrix.c
index f0d8e37c7..a11de7ba8 100644
--- a/drivers/char/radio-zoltrix.c
+++ b/drivers/char/radio-zoltrix.c
@@ -47,6 +47,7 @@ struct zol_device {
unsigned long curfreq;
int muted;
unsigned int stereo;
+ struct semaphore lock;
};
@@ -64,26 +65,30 @@ static int zol_setvol(struct zol_device *dev, int vol)
if (dev->muted)
return 0;
+ down(&dev->lock);
if (vol == 0) {
outb(0, io);
outb(0, io);
inb(io + 3); /* Zoltrix needs to be read to confirm */
+ up(&dev->lock);
return 0;
}
outb(dev->curvol-1, io);
sleep_delay();
inb(io + 2);
-
+ up(&dev->lock);
return 0;
}
static void zol_mute(struct zol_device *dev)
{
dev->muted = 1;
+ down(&dev->lock);
outb(0, io);
outb(0, io);
inb(io + 3); /* Zoltrix needs to be read to confirm */
+ up(&dev->lock);
}
static void zol_unmute(struct zol_device *dev)
@@ -107,6 +112,8 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
bitmask = 0xc480402c10080000ull;
i = 45;
+ down(&dev->lock);
+
outb(0, io);
outb(0, io);
inb(io + 3); /* Zoltrix needs to be read to confirm */
@@ -141,14 +148,21 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
inb(io+2);
udelay(1000);
+
if (dev->muted)
{
outb(0, io);
outb(0, io);
inb(io + 3);
udelay(1000);
- } else
- zol_setvol(dev, dev->curvol);
+ }
+
+ up(&dev->lock);
+
+ if(!dev->muted)
+ {
+ zol_setvol(dev, dev->curvol);
+ }
return 0;
}
@@ -158,6 +172,7 @@ int zol_getsigstr(struct zol_device *dev)
{
int a, b;
+ down(&dev->lock);
outb(0x00, io); /* This stuff I found to do nothing */
outb(dev->curvol, io);
sleep_delay();
@@ -167,6 +182,8 @@ int zol_getsigstr(struct zol_device *dev)
sleep_delay();
b = inb(io);
+ up(&dev->lock);
+
if (a != b)
return (0);
@@ -180,6 +197,8 @@ int zol_is_stereo (struct zol_device *dev)
{
int x1, x2;
+ down(&dev->lock);
+
outb(0x00, io);
outb(dev->curvol, io);
sleep_delay();
@@ -189,6 +208,8 @@ int zol_is_stereo (struct zol_device *dev)
sleep_delay();
x2 = inb(io);
+ up(&dev->lock);
+
if ((x1 == x2) && (x1 == 0xcf))
return 1;
return 0;
@@ -351,6 +372,8 @@ int __init zoltrix_init(struct video_init *v)
request_region(io, 2, "zoltrix");
printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
+ init_MUTEX(&zoltrix_unit.lock);
+
/* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
diff --git a/drivers/char/random.c b/drivers/char/random.c
index f1dd26cd2..d97304a13 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1,10 +1,10 @@
/*
* random.c -- A strong random number generator
*
- * Version 1.04, last modified 26-Apr-98
+ * Version 1.89, last modified 19-Sep-99
*
- * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998. All rights
- * reserved.
+ * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All
+ * rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,15 +27,16 @@
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
*/
/*
@@ -223,8 +224,8 @@
* 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
+ * implementation, which has been placed in the public domain.
+ * The MD5 cryptographic checksum was devised by Ronald Rivest, and is
* documented in RFC 1321, "The MD5 Message Digest Algorithm".
*
* Further background information on this topic may be obtained from
@@ -232,11 +233,6 @@
* Eastlake, Steve Crocker, and Jeff Schiller.
*/
-/*
- * Added a check for signal pending in the extract_entropy() loop to allow
- * the read(2) syscall to be interrupted. Copyright (C) 1998 Andrea Arcangeli
- */
-
#include <linux/utsname.h>
#include <linux/config.h>
#include <linux/kernel.h>
@@ -256,72 +252,77 @@
/*
* Configuration information
*/
-#undef RANDOM_BENCHMARK
-#undef BENCHMARK_NOINT
-#define ROTATE_PARANOIA
+#define DEFAULT_POOL_SIZE 512
+#define SECONDARY_POOL_SIZE 128
+#define BATCH_ENTROPY_SIZE 256
+#define USE_SHA
-#define POOLWORDS 128 /* Power of 2 - note that this is 32-bit words */
-#define POOLBITS (POOLWORDS*32)
/*
- * 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.
+ * The minimum number of bits of entropy before we wake up a read on
+ * /dev/random. Should always be at least 8, or at least 1 byte.
*/
-#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
+static int random_read_wakeup_thresh = 8;
+
+/*
+ * If the entropy count falls under this number of bits, then we
+ * should wake up processes which are selecting or polling on write
+ * access to /dev/random.
+ */
+static int random_write_wakeup_thresh = 128;
+
+/*
+ * A pool of size POOLWORDS 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.
+ */
+static struct poolinfo {
+ int poolwords;
+ int tap1, tap2, tap3, tap4, tap5;
+} poolinfo_table[] = {
+ /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */
+ { 2048, 1638, 1231, 819, 411, 1 },
+
+ /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */
+ { 1024, 817, 615, 412, 204, 1 },
+
+#if 0 /* Alternate polynomial */
+ /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */
+ { 1024, 819, 616, 410, 207, 2 },
#endif
+
+ /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */
+ { 512, 411, 308, 208, 104, 1 },
+
+#if 0 /* Alternates */
+ /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */
+ { 512, 409, 307, 206, 102, 2 },
+ /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */
+ { 512, 409, 309, 205, 103, 2 },
+#endif
+
+ /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */
+ { 256, 205, 155, 101, 52, 1 },
+
+ /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */
+ { 128, 103, 76, 51, 25, 1 },
+
+#if 0 /* Alternate polynomial */
+ /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */
+ { 128, 103, 78, 51, 27, 2 },
+#endif
+
+ /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */
+ { 64, 52, 39, 26, 14, 1 },
+ /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */
+ { 32, 26, 20, 14, 7, 1 },
+
+ { 0, 0, 0, 0, 0, 0 },
+};
+
/*
* For the purposes of better mixing, we use the CRC-32 polynomial as
* well to make a twisted Generalized Feedback Shift Reigster
@@ -332,25 +333,26 @@
* II. ACM Transactions on Mdeling and Computer Simulation 4:254-266)
*
* 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.
+ *
+ * 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
+ * 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
@@ -365,82 +367,36 @@
*/
/*
- * The minimum number of bits to release a "wait on input". Should
- * probably always be 8, since a /dev/random read can return a single
- * byte.
- */
-#define WAIT_INPUT_BITS 8
-/*
- * The limit number of bits under which to release a "wait on
- * output". Should probably always be the same as WAIT_INPUT_BITS, so
- * that an output wait releases when and only when a wait on input
- * would block.
+ * Linux 2.2 compatibility
*/
-#define WAIT_OUTPUT_BITS WAIT_INPUT_BITS
-
-/* There is actually only one of these, globally. */
-struct random_bucket {
- unsigned add_ptr;
- unsigned entropy_count;
-#ifdef ROTATE_PARANOIA
- int input_rotate;
+#ifndef DECLARE_WAITQUEUE
+#define DECLARE_WAITQUEUE(WAIT, PTR) struct wait_queue WAIT = { PTR, NULL }
#endif
- __u32 pool[POOLWORDS];
-};
-
-#ifdef RANDOM_BENCHMARK
-/* For benchmarking only */
-struct random_benchmark {
- unsigned long long start_time;
- int times; /* # of samples */
- unsigned long min;
- unsigned long max;
- unsigned long accum; /* accumulator for average */
- const char *descr;
- int unit;
- unsigned long flags;
-};
-
-#define BENCHMARK_INTERVAL 500
-
-static void initialize_benchmark(struct random_benchmark *bench,
- const char *descr, int unit);
-static void begin_benchmark(struct random_benchmark *bench);
-static void end_benchmark(struct random_benchmark *bench);
-
-struct random_benchmark timer_benchmark;
+#ifndef DECLARE_WAIT_QUEUE_HEAD
+#define DECLARE_WAIT_QUEUE_HEAD(WAIT) struct wait_queue *WAIT
#endif
-/* There is one of these per entropy source */
-struct timer_rand_state {
- __u32 last_time;
- __s32 last_delta,last_delta2;
- int dont_count_entropy:1;
-};
-
-static struct random_bucket random_state;
-static struct timer_rand_state keyboard_timer_state;
-static struct timer_rand_state mouse_timer_state;
-static struct timer_rand_state extract_timer_state;
-static struct timer_rand_state *irq_timer_state[NR_IRQS];
-static struct timer_rand_state *blkdev_timer_state[MAX_BLKDEV];
+/*
+ * Static global variables
+ */
+static struct entropy_store *random_state; /* The default global store */
+static struct entropy_store *sec_random_state; /* secondary store */
static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
-static ssize_t random_read(struct file * file, char * buf,
- size_t nbytes, loff_t *ppos);
-static ssize_t random_read_unlimited(struct file * file, char * buf,
- size_t nbytes, loff_t *ppos);
-static unsigned int random_poll(struct file *file, poll_table * wait);
-static ssize_t random_write(struct file * file, const char * buffer,
- size_t count, loff_t *ppos);
-static int random_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg);
-
-static inline void fast_add_entropy_words(struct random_bucket *r,
- __u32 x, __u32 y);
+/*
+ * Forward procedure declarations
+ */
+#ifdef CONFIG_SYSCTL
+static void sysctl_init_random(struct entropy_store *random_state);
+#endif
-static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y);
+/*****************************************************************
+ *
+ * Utility functions, with some ASM defined functions for speed
+ * purposes
+ *
+ *****************************************************************/
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -504,185 +460,236 @@ static inline __u32 int_ln_12bits(__u32 word)
}
#endif
-
-/*
- * Initialize the random pool with standard stuff.
+/**********************************************************************
*
- * NOTE: This is an OS-dependent function.
+ * OS independent entropy store. Here are the functions which handle
+ * storing entropy in an entropy pool.
+ *
+ **********************************************************************/
+
+struct entropy_store {
+ unsigned add_ptr;
+ int entropy_count;
+ int input_rotate;
+ int extract_count;
+ struct poolinfo poolinfo;
+ __u32 *pool;
+};
+
+/*
+ * Initialize the entropy store. The input argument is the size of
+ * the random pool.
+ *
+ * Returns an negative error if there is a problem.
*/
-static void init_std_data(struct random_bucket *r)
+static int create_entropy_store(int size, struct entropy_store **ret_bucket)
{
- __u32 words[2], *p;
- int i;
- struct timeval tv;
+ struct entropy_store *r;
+ struct poolinfo *p;
+ int poolwords;
- do_gettimeofday(&tv);
- add_entropy_words(r, tv.tv_sec, tv.tv_usec);
+ poolwords = (size + 3) / 4; /* Convert bytes->words */
+ /* The pool size must be a multiple of 16 32-bit words */
+ poolwords = ((poolwords + 15) / 16) * 16;
- /*
- * 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);
+ for (p = poolinfo_table; p->poolwords; p++) {
+ if (poolwords == p->poolwords)
+ break;
}
-
+ if (p->poolwords == 0)
+ return -EINVAL;
+
+ r = kmalloc(sizeof(struct entropy_store), GFP_KERNEL);
+ if (!r)
+ return -ENOMEM;
+
+ memset (r, 0, sizeof(struct entropy_store));
+ r->poolinfo = *p;
+
+ r->pool = kmalloc(poolwords*4, GFP_KERNEL);
+ if (!r->pool) {
+ kfree_s(r, sizeof(struct entropy_store));
+ return -ENOMEM;
+ }
+ memset(r->pool, 0, poolwords*4);
+ *ret_bucket = r;
+ return 0;
}
/* Clear the entropy pool and associated counters. */
-static void rand_clear_pool(void)
+static void clear_entropy_store(struct entropy_store *r)
{
- memset(&random_state, 0, sizeof(random_state));
- init_std_data(&random_state);
+ r->add_ptr = 0;
+ r->entropy_count = 0;
+ r->input_rotate = 0;
+ r->extract_count = 0;
+ memset(r->pool, 0, r->poolinfo.poolwords*4);
}
-__initfunc(void rand_initialize(void))
+static void free_entropy_store(struct entropy_store *r)
{
- int i;
-
- rand_clear_pool();
- for (i = 0; i < NR_IRQS; i++)
- irq_timer_state[i] = NULL;
- for (i = 0; i < MAX_BLKDEV; i++)
- blkdev_timer_state[i] = NULL;
- memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state));
- memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state));
- memset(&extract_timer_state, 0, sizeof(struct timer_rand_state));
-#ifdef RANDOM_BENCHMARK
- initialize_benchmark(&timer_benchmark, "timer", 0);
-#endif
- extract_timer_state.dont_count_entropy = 1;
+ if (r->pool)
+ kfree(r->pool);
+ kfree_s(r, sizeof(struct entropy_store));
}
-void rand_initialize_irq(int irq)
+/*
+ * This function adds a byte into the entropy "pool". It does not
+ * update the entropy estimate. The caller should call
+ * credit_entropy_store if this is appropriate.
+ *
+ * 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 void add_entropy_words(struct entropy_store *r, const __u32 *in,
+ int num)
{
- struct timer_rand_state *state;
-
- if (irq >= NR_IRQS || irq_timer_state[irq])
- return;
+ static __u32 const twist_table[8] = {
+ 0, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+ 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
+ unsigned i;
+ int new_rotate;
+ __u32 w;
- /*
- * If kmalloc returns null, we just won't use that entropy
- * source.
- */
- state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
- if (state) {
- irq_timer_state[irq] = state;
- memset(state, 0, sizeof(struct timer_rand_state));
+ while (num--) {
+ w = rotate_left(r->input_rotate, *in);
+ i = r->add_ptr = (r->add_ptr - 1) & (r->poolinfo.poolwords-1);
+ /*
+ * 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.
+ */
+ new_rotate = r->input_rotate + 14;
+ if (i)
+ new_rotate = r->input_rotate + 7;
+ r->input_rotate = new_rotate & 31;
+
+ /* XOR in the various taps */
+ w ^= r->pool[(i+r->poolinfo.tap1)&(r->poolinfo.poolwords-1)];
+ w ^= r->pool[(i+r->poolinfo.tap2)&(r->poolinfo.poolwords-1)];
+ w ^= r->pool[(i+r->poolinfo.tap3)&(r->poolinfo.poolwords-1)];
+ w ^= r->pool[(i+r->poolinfo.tap4)&(r->poolinfo.poolwords-1)];
+ w ^= r->pool[(i+r->poolinfo.tap5)&(r->poolinfo.poolwords-1)];
+ w ^= r->pool[i];
+ r->pool[i] = (w >> 3) ^ twist_table[w & 7];
}
}
-void rand_initialize_blkdev(int major, int mode)
+/*
+ * Credit (or debit) the entropy store with n bits of entropy
+ */
+static void credit_entropy_store(struct entropy_store *r, int num)
{
- struct timer_rand_state *state;
-
- if (major >= MAX_BLKDEV || blkdev_timer_state[major])
- return;
+ int max_entropy = r->poolinfo.poolwords*32;
- /*
- * If kmalloc returns null, we just won't use that entropy
- * source.
- */
- state = kmalloc(sizeof(struct timer_rand_state), mode);
- if (state) {
- blkdev_timer_state[major] = state;
- memset(state, 0, sizeof(struct timer_rand_state));
- }
+ if (r->entropy_count + num < 0)
+ r->entropy_count = 0;
+ else if (r->entropy_count + num > max_entropy)
+ r->entropy_count = max_entropy;
+ else
+ r->entropy_count = r->entropy_count + num;
}
-/*
- * This function adds a byte into the entropy "pool". It does not
- * update the entropy estimate. The caller must do this if appropriate.
+/**********************************************************************
*
- * This function is tuned for speed above most other considerations.
+ * Entropy batch input management
*
- * 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.
- */
-#define MASK(x) ((x) & (POOLWORDS-1)) /* Convenient abreviation */
-static inline void fast_add_entropy_words(struct random_bucket *r,
- __u32 x, __u32 y)
-{
- static __u32 const twist_table[8] = {
- 0, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
- 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
- unsigned i, j;
+ * We batch entropy to be added to avoid increasing interrupt latency
+ *
+ **********************************************************************/
- i = MASK(r->add_ptr - 2); /* i is always even */
- r->add_ptr = i;
+static __u32 *batch_entropy_pool;
+static int *batch_entropy_credit;
+static int batch_max;
+static int batch_head, batch_tail;
+static struct tq_struct batch_tqueue;
+static void batch_entropy_process(void *private_);
-#ifdef ROTATE_PARANOIA
- j = r->input_rotate + 14;
- if (i)
- j -= 7;
- r->input_rotate = j & 31;
+/* note: the size must be a power of 2 */
+static int batch_entropy_init(int size, struct entropy_store *r)
+{
+ batch_entropy_pool = kmalloc(2*size*sizeof(__u32), GFP_KERNEL);
+ if (!batch_entropy_pool)
+ return -1;
+ batch_entropy_credit =kmalloc(size*sizeof(int), GFP_KERNEL);
+ if (!batch_entropy_credit) {
+ kfree(batch_entropy_pool);
+ return -1;
+ }
+ batch_head = batch_tail = 0;
+ batch_max = size;
+ batch_tqueue.routine = batch_entropy_process;
+ batch_tqueue.data = r;
+ return 0;
+}
- x = rotate_left(r->input_rotate, x);
- y = rotate_left(r->input_rotate, y);
-#endif
+static void batch_entropy_store(__u32 a, __u32 b, int num)
+{
+ int new;
- /*
- * 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?)
- */
-#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];
+ if (!batch_max)
+ return;
+
+ batch_entropy_pool[2*batch_head] = a;
+ batch_entropy_pool[(2*batch_head) + 1] = b;
+ batch_entropy_credit[batch_head] = num;
+
+ new = (batch_head+1) & (batch_max-1);
+ if (new != batch_tail) {
+ queue_task(&batch_tqueue, &tq_timer);
+ batch_head = new;
+ } else {
+#if 0
+ printk(KERN_NOTICE "random: batch entropy buffer full\n");
#endif
+ }
}
-/*
- * For places where we don't need the inlined version
- */
-static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y)
+static void batch_entropy_process(void *private_)
{
- fast_add_entropy_words(r, x, y);
+ int num = 0;
+ int max_entropy;
+ struct entropy_store *r = (struct entropy_store *) private_, *p;
+
+ if (!batch_max)
+ return;
+
+ max_entropy = r->poolinfo.poolwords*32;
+ while (batch_head != batch_tail) {
+ add_entropy_words(r, batch_entropy_pool + 2*batch_tail, 2);
+ p = r;
+ if (r->entropy_count > max_entropy && (num & 1))
+ r = sec_random_state;
+ credit_entropy_store(r, batch_entropy_credit[batch_tail]);
+ batch_tail = (batch_tail+1) & (batch_max-1);
+ num++;
+ }
+ if (r->entropy_count >= random_read_wakeup_thresh)
+ wake_up_interruptible(&random_read_wait);
}
+/*********************************************************************
+ *
+ * Entropy input management
+ *
+ *********************************************************************/
+
+/* There is one of these per entropy source */
+struct timer_rand_state {
+ __u32 last_time;
+ __s32 last_delta,last_delta2;
+ int dont_count_entropy:1;
+};
+
+static struct timer_rand_state keyboard_timer_state;
+static struct timer_rand_state mouse_timer_state;
+static struct timer_rand_state extract_timer_state;
+static struct timer_rand_state *irq_timer_state[NR_IRQS];
+static struct timer_rand_state *blkdev_timer_state[MAX_BLKDEV];
+
/*
* This function adds entropy to the entropy "pool" by using timing
* delays. It uses the timer_rand_state structure to make an estimate
@@ -695,15 +702,12 @@ static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y)
* are used for a high-resolution timer.
*
*/
-static void add_timer_randomness(struct random_bucket *r,
- struct timer_rand_state *state, unsigned num)
+static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
{
__u32 time;
__s32 delta, delta2, delta3;
+ int entropy = 0;
-#ifdef RANDOM_BENCHMARK
- begin_benchmark(&timer_benchmark);
-#endif
#if defined (__i386__)
if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
__u32 high;
@@ -717,14 +721,12 @@ static void add_timer_randomness(struct random_bucket *r,
time = jiffies;
#endif
- fast_add_entropy_words(r, (__u32)num, time);
-
/*
* 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 ((r->entropy_count < POOLBITS) && !state->dont_count_entropy) {
+ if (!state->dont_count_entropy) {
delta = time - state->last_time;
state->last_time = time;
@@ -753,30 +755,19 @@ static void add_timer_randomness(struct random_bucket *r,
delta >>= 1;
delta &= (1 << 12) - 1;
- 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);
+ entropy = int_ln_12bits(delta);
}
-
-#ifdef RANDOM_BENCHMARK
- end_benchmark(&timer_benchmark);
-#endif
+ batch_entropy_store(num, time, entropy);
}
void add_keyboard_randomness(unsigned char scancode)
{
- add_timer_randomness(&random_state, &keyboard_timer_state, scancode);
+ add_timer_randomness(&keyboard_timer_state, scancode);
}
void add_mouse_randomness(__u32 mouse_data)
{
- add_timer_randomness(&random_state, &mouse_timer_state, mouse_data);
+ add_timer_randomness(&mouse_timer_state, mouse_data);
}
void add_interrupt_randomness(int irq)
@@ -784,7 +775,7 @@ void add_interrupt_randomness(int irq)
if (irq >= NR_IRQS || irq_timer_state[irq] == 0)
return;
- add_timer_randomness(&random_state, irq_timer_state[irq], 0x100+irq);
+ add_timer_randomness(irq_timer_state[irq], 0x100+irq);
}
void add_blkdev_randomness(int major)
@@ -798,10 +789,15 @@ void add_blkdev_randomness(int major)
return;
}
- add_timer_randomness(&random_state, blkdev_timer_state[major],
- 0x200+major);
+ add_timer_randomness(blkdev_timer_state[major], 0x200+major);
}
+/******************************************************************
+ *
+ * Hash function definition
+ *
+ *******************************************************************/
+
/*
* This chunk of code defines a function
* void HASH_TRANSFORM(__u32 digest[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE],
@@ -821,12 +817,11 @@ void add_blkdev_randomness(int major)
* 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.
+ * fixed in length, so appending a bit count in the usual way is not
+ * cryptographically necessary.
*/
-#define USE_SHA
#ifdef USE_SHA
@@ -1074,9 +1069,6 @@ static void SHATransform(__u32 digest[85], __u32 const data[16])
/*
* MD5 transform algorithm, taken from code written by Colin Plumb,
* and put into the public domain
- *
- * QUESTION: Replace this with SHA, which as generally received better
- * reviews from the cryptographic community?
*/
/* The four core functions - F1 is optimized somewhat */
@@ -1187,39 +1179,94 @@ static void MD5Transform(__u32 buf[HASH_BUFFER_SIZE], __u32 const in[16])
#endif /* !USE_SHA */
+/*********************************************************************
+ *
+ * Entropy extraction routines
+ *
+ *********************************************************************/
+
+#define EXTRACT_ENTROPY_USER 1
+#define EXTRACT_ENTROPY_SECONDARY 2
+#define TMP_BUF_SIZE (HASH_BUFFER_SIZE + HASH_EXTRA_SIZE)
+#define SEC_XFER_SIZE (TMP_BUF_SIZE*4)
+
+static ssize_t extract_entropy(struct entropy_store *r, void * buf,
+ size_t nbytes, int flags);
+
+/*
+ * This utility inline function is responsible for transfering entropy
+ * from the primary pool to the secondary extraction pool. We pull
+ * randomness under two conditions; one is if there isn't enough entropy
+ * in the secondary pool. The other is after we have extract 1024 bytes,
+ * at which point we do a "catastrophic reseeding".
+ */
+static inline void xfer_secondary_pool(struct entropy_store *r,
+ size_t nbytes)
+{
+ __u32 tmp[TMP_BUF_SIZE];
+
+ if (r->entropy_count < nbytes*8) {
+ extract_entropy(random_state, tmp, sizeof(tmp), 0);
+ add_entropy_words(r, tmp, TMP_BUF_SIZE);
+ credit_entropy_store(r, TMP_BUF_SIZE*8);
+ }
+ if (r->extract_count > 1024) {
+ extract_entropy(random_state, tmp, sizeof(tmp), 0);
+ add_entropy_words(r, tmp, TMP_BUF_SIZE);
+ r->extract_count = 0;
+ }
+}
-#if POOLWORDS % 16 != 0
-#error extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
-#endif
/*
* This function extracts randomness from the "entropy pool", and
* returns it in a buffer. This function computes how many remaining
* bits of entropy are left in the pool, but it does not restrict the
- * number of bytes that are actually obtained.
+ * number of bytes that are actually obtained. If the EXTRACT_ENTROPY_USER
+ * flag is given, then the buf pointer is assumed to be in user space.
+ * If the EXTRACT_ENTROPY_SECONDARY flag is given, then this function will
+ *
+ * Note: extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
*/
-static ssize_t extract_entropy(struct random_bucket *r, char * buf,
- size_t nbytes, int to_user)
+static ssize_t extract_entropy(struct entropy_store *r, void * buf,
+ size_t nbytes, int flags)
{
ssize_t ret, i;
- __u32 tmp[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
+ __u32 tmp[TMP_BUF_SIZE];
__u32 x;
- add_timer_randomness(r, &extract_timer_state, nbytes);
+ add_timer_randomness(&extract_timer_state, nbytes);
/* Redundant, but just in case... */
- if (r->entropy_count > POOLBITS)
- r->entropy_count = POOLBITS;
+ if (r->entropy_count > r->poolinfo.poolwords)
+ r->entropy_count = r->poolinfo.poolwords;
+
+ if (flags & EXTRACT_ENTROPY_SECONDARY)
+ xfer_secondary_pool(r, nbytes);
- ret = nbytes;
if (r->entropy_count / 8 >= nbytes)
r->entropy_count -= nbytes*8;
else
r->entropy_count = 0;
- if (r->entropy_count < WAIT_OUTPUT_BITS)
+ if (r->entropy_count < random_write_wakeup_thresh)
wake_up_interruptible(&random_write_wait);
+
+ r->extract_count += nbytes;
+ ret = 0;
while (nbytes) {
+ /*
+ * Check if we need to break out or reschedule....
+ */
+ if ((flags & EXTRACT_ENTROPY_USER) && current->need_resched) {
+ if (signal_pending(current)) {
+ if (ret == 0)
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+
/* Hash the pool to get the output */
tmp[0] = 0x67452301;
tmp[1] = 0xefcdab89;
@@ -1228,39 +1275,34 @@ static ssize_t extract_entropy(struct random_bucket *r, char * buf,
#ifdef USE_SHA
tmp[4] = 0xc3d2e1f0;
#endif
- for (i = 0; i < POOLWORDS; i += 16)
- HASH_TRANSFORM(tmp, r->pool+i);
-
/*
- * 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.)
+ * As we hash the pool, we mix intermediate values of
+ * the hash back into the pool. This eliminates
+ * backtracking attacks (where the attacker knows
+ * the state of the pool plus the current outputs, and
+ * attempts to find previous ouputs), unless the hash
+ * function can be inverted.
*/
- 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;
+ for (i = 0, x = 0; i < r->poolinfo.poolwords; i += 16, x+=2) {
+ HASH_TRANSFORM(tmp, r->pool+i);
+ add_entropy_words(r, &tmp[x%HASH_BUFFER_SIZE], 1);
}
+
+ /*
+ * In case the hash function has some recognizable
+ * output pattern, we fold it in half.
+ */
+ for (i = 0; i < HASH_BUFFER_SIZE/2; i++)
+ tmp[i] ^= tmp[i + (HASH_BUFFER_SIZE+1)/2];
#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)((unsigned long)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);
- if (to_user) {
+ if (flags & EXTRACT_ENTROPY_USER) {
i -= copy_to_user(buf, (__u8 const *)tmp, i);
if (!i) {
ret = -EFAULT;
@@ -1270,16 +1312,8 @@ static ssize_t extract_entropy(struct random_bucket *r, char * buf,
memcpy(buf, (__u8 const *)tmp, i);
nbytes -= i;
buf += i;
- add_timer_randomness(r, &extract_timer_state, nbytes);
- if (to_user && current->need_resched)
- {
- if (signal_pending(current))
- {
- ret = -EINTR;
- break;
- }
- schedule();
- }
+ ret += i;
+ add_timer_randomness(&extract_timer_state, nbytes);
}
/* Wipe data just returned from memory */
@@ -1295,9 +1329,114 @@ static ssize_t extract_entropy(struct random_bucket *r, char * buf,
*/
void get_random_bytes(void *buf, int nbytes)
{
- extract_entropy(&random_state, (char *) buf, nbytes, 0);
+ if (sec_random_state)
+ extract_entropy(sec_random_state, (char *) buf, nbytes,
+ EXTRACT_ENTROPY_SECONDARY);
+ else if (random_state)
+ extract_entropy(random_state, (char *) buf, nbytes, 0);
+ else
+ printk(KERN_NOTICE "get_random_bytes called before "
+ "random driver initialization\n");
}
+/*********************************************************************
+ *
+ * Functions to interface with Linux
+ *
+ *********************************************************************/
+
+/*
+ * Initialize the random pool with standard stuff.
+ *
+ * NOTE: This is an OS-dependent function.
+ */
+static void init_std_data(struct entropy_store *r)
+{
+ struct timeval tv;
+ __u32 words[2];
+ char *p;
+ int i;
+
+ do_gettimeofday(&tv);
+ words[0] = tv.tv_sec;
+ words[1] = tv.tv_usec;
+ add_entropy_words(r, words, 2);
+
+ /*
+ * This doesn't lock system.utsname. However, we are generating
+ * entropy so a race with a name set here is fine.
+ */
+ p = (char *) &system_utsname;
+ for (i = sizeof(system_utsname) / sizeof(words); i; i--) {
+ memcpy(words, p, sizeof(words));
+ add_entropy_words(r, words, sizeof(words)/4);
+ p += sizeof(words);
+ }
+}
+
+void __init rand_initialize(void)
+{
+ int i;
+
+ if (create_entropy_store(DEFAULT_POOL_SIZE, &random_state))
+ return; /* Error, return */
+ if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state))
+ return; /* Error, return */
+ if (create_entropy_store(SECONDARY_POOL_SIZE, &sec_random_state))
+ return; /* Error, return */
+ clear_entropy_store(random_state);
+ clear_entropy_store(sec_random_state);
+ init_std_data(random_state);
+#ifdef CONFIG_SYSCTL
+ sysctl_init_random(random_state);
+#endif
+ for (i = 0; i < NR_IRQS; i++)
+ irq_timer_state[i] = NULL;
+ for (i = 0; i < MAX_BLKDEV; i++)
+ blkdev_timer_state[i] = NULL;
+ memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state));
+ memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state));
+ memset(&extract_timer_state, 0, sizeof(struct timer_rand_state));
+ extract_timer_state.dont_count_entropy = 1;
+}
+
+void rand_initialize_irq(int irq)
+{
+ struct timer_rand_state *state;
+
+ if (irq >= NR_IRQS || irq_timer_state[irq])
+ return;
+
+ /*
+ * If kmalloc returns null, we just won't use that entropy
+ * source.
+ */
+ state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
+ if (state) {
+ memset(state, 0, sizeof(struct timer_rand_state));
+ irq_timer_state[irq] = state;
+ }
+}
+
+void rand_initialize_blkdev(int major, int mode)
+{
+ struct timer_rand_state *state;
+
+ if (major >= MAX_BLKDEV || blkdev_timer_state[major])
+ return;
+
+ /*
+ * If kmalloc returns null, we just won't use that entropy
+ * source.
+ */
+ state = kmalloc(sizeof(struct timer_rand_state), mode);
+ if (state) {
+ memset(state, 0, sizeof(struct timer_rand_state));
+ blkdev_timer_state[major] = state;
+ }
+}
+
+
static ssize_t
random_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
{
@@ -1309,11 +1448,13 @@ random_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
add_wait_queue(&random_read_wait, &wait);
while (nbytes > 0) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
n = nbytes;
- if (n > random_state.entropy_count / 8)
- n = random_state.entropy_count / 8;
+ if (n > SEC_XFER_SIZE)
+ n = SEC_XFER_SIZE;
+ if (n > random_state->entropy_count / 8)
+ n = random_state->entropy_count / 8;
if (n == 0) {
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
@@ -1326,7 +1467,9 @@ random_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
schedule();
continue;
}
- n = extract_entropy(&random_state, buf, n, 1);
+ n = extract_entropy(sec_random_state, buf, n,
+ EXTRACT_ENTROPY_USER |
+ EXTRACT_ENTROPY_SECONDARY);
if (n < 0) {
retval = n;
break;
@@ -1351,10 +1494,12 @@ random_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
}
static ssize_t
-random_read_unlimited(struct file * file, char * buf,
+urandom_read(struct file * file, char * buf,
size_t nbytes, loff_t *ppos)
{
- return extract_entropy(&random_state, buf, nbytes, 1);
+ return extract_entropy(sec_random_state, buf, nbytes,
+ EXTRACT_ENTROPY_USER |
+ EXTRACT_ENTROPY_SECONDARY);
}
static unsigned int
@@ -1365,9 +1510,9 @@ random_poll(struct file *file, poll_table * wait)
poll_wait(file, &random_read_wait, wait);
poll_wait(file, &random_write_wait, wait);
mask = 0;
- if (random_state.entropy_count >= WAIT_INPUT_BITS)
+ if (random_state->entropy_count >= random_read_wakeup_thresh)
mask |= POLLIN | POLLRDNORM;
- if (random_state.entropy_count < WAIT_OUTPUT_BITS)
+ if (random_state->entropy_count < random_write_wakeup_thresh)
mask |= POLLOUT | POLLWRNORM;
return mask;
}
@@ -1378,7 +1523,6 @@ random_write(struct file * file, const char * buffer,
{
int ret = 0;
size_t bytes;
- unsigned i;
__u32 buf[16];
const char *p = buffer;
size_t c = count;
@@ -1393,11 +1537,10 @@ random_write(struct file * file, const char * buffer,
}
c -= bytes;
p += bytes;
-
- i = (unsigned)((bytes-1) / (2 * sizeof(__u32)));
- do {
- add_entropy_words(&random_state, buf[2*i], buf[2*i+1]);
- } while (i--);
+
+ /* Convert bytes to words */
+ bytes = (bytes + 3) / sizeof(__u32);
+ add_entropy_words(random_state, buf, bytes);
}
if (p == buffer) {
return (ssize_t)ret;
@@ -1417,7 +1560,7 @@ random_ioctl(struct inode * inode, struct file * file,
switch (cmd) {
case RNDGETENTCNT:
- ent_count = random_state.entropy_count;
+ ent_count = random_state->entropy_count;
if (put_user(ent_count, (int *) arg))
return -EFAULT;
return 0;
@@ -1426,45 +1569,31 @@ random_ioctl(struct inode * inode, struct file * file,
return -EPERM;
if (get_user(ent_count, (int *) arg))
return -EFAULT;
- /*
- * Add i to entropy_count, limiting the result to be
- * between 0 and POOLBITS.
- */
- if (ent_count < -random_state.entropy_count)
- random_state.entropy_count = 0;
- else if (ent_count > POOLBITS)
- random_state.entropy_count = POOLBITS;
- else {
- random_state.entropy_count += ent_count;
- if (random_state.entropy_count > POOLBITS)
- random_state.entropy_count = POOLBITS;
- if (random_state.entropy_count < 0)
- random_state.entropy_count = 0;
- }
+ credit_entropy_store(random_state, ent_count);
/*
* Wake up waiting processes if we have enough
* entropy.
*/
- if (random_state.entropy_count >= WAIT_INPUT_BITS)
+ if (random_state->entropy_count >= random_read_wakeup_thresh)
wake_up_interruptible(&random_read_wait);
return 0;
case RNDGETPOOL:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
p = (int *) arg;
- ent_count = random_state.entropy_count;
+ ent_count = random_state->entropy_count;
if (put_user(ent_count, p++))
return -EFAULT;
if (get_user(size, p))
return -EFAULT;
- if (put_user(POOLWORDS, p++))
+ if (put_user(random_state->poolinfo.poolwords, p++))
return -EFAULT;
if (size < 0)
return -EINVAL;
- if (size > POOLWORDS)
- size = POOLWORDS;
- if (copy_to_user(p, random_state.pool, size*sizeof(__u32)))
+ if (size > random_state->poolinfo.poolwords)
+ size = random_state->poolinfo.poolwords;
+ if (copy_to_user(p, random_state->pool, size*sizeof(__u32)))
return -EFAULT;
return 0;
case RNDADDENTROPY:
@@ -1481,36 +1610,25 @@ random_ioctl(struct inode * inode, struct file * file,
size, &file->f_pos);
if (retval < 0)
return retval;
- /*
- * Add ent_count to entropy_count, limiting the result to be
- * between 0 and POOLBITS.
- */
- if (ent_count > POOLBITS)
- random_state.entropy_count = POOLBITS;
- else {
- random_state.entropy_count += ent_count;
- if (random_state.entropy_count > POOLBITS)
- random_state.entropy_count = POOLBITS;
- if (random_state.entropy_count < 0)
- random_state.entropy_count = 0;
- }
+ credit_entropy_store(random_state, ent_count);
/*
* Wake up waiting processes if we have enough
* entropy.
*/
- if (random_state.entropy_count >= WAIT_INPUT_BITS)
+ if (random_state->entropy_count >= random_read_wakeup_thresh)
wake_up_interruptible(&random_read_wait);
return 0;
case RNDZAPENTCNT:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- random_state.entropy_count = 0;
+ random_state->entropy_count = 0;
return 0;
case RNDCLEARPOOL:
/* Clear the entropy pool and associated counters. */
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- rand_clear_pool();
+ clear_entropy_store(random_state);
+ init_std_data(random_state);
return 0;
default:
return -EINVAL;
@@ -1532,7 +1650,7 @@ struct file_operations random_fops = {
struct file_operations urandom_fops = {
NULL, /* unrandom_lseek */
- random_read_unlimited,
+ urandom_read,
random_write,
NULL, /* urandom_readdir */
NULL, /* urandom_poll */
@@ -1543,6 +1661,210 @@ struct file_operations urandom_fops = {
NULL /* no special release code */
};
+/***************************************************************
+ * Random UUID interface
+ *
+ * Used here for a Boot ID, but can be useful for other kernel
+ * drivers.
+ ***************************************************************/
+
+/*
+ * Generate random UUID
+ */
+void generate_random_uuid(unsigned char uuid_out[16])
+{
+ get_random_bytes(uuid_out, 16);
+ /* Set UUID version to 4 --- truely random generation */
+ uuid_out[6] = (uuid_out[6] & 0x0F) | 0x40;
+ /* Set the UUID variant to DCE */
+ uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80;
+}
+
+/********************************************************************
+ *
+ * Sysctl interface
+ *
+ ********************************************************************/
+
+#ifdef CONFIG_SYSCTL
+
+#include <linux/sysctl.h>
+
+static int sysctl_poolsize;
+static int min_read_thresh, max_read_thresh;
+static int min_write_thresh, max_write_thresh;
+static char sysctl_bootid[16];
+
+/*
+ * This function handles a request from the user to change the pool size
+ * of the primary entropy store.
+ */
+static int change_poolsize(int poolsize)
+{
+ struct entropy_store *new_store, *old_store;
+ int ret;
+
+ if ((ret = create_entropy_store(poolsize, &new_store)))
+ return ret;
+
+ add_entropy_words(new_store, random_state->pool,
+ random_state->poolinfo.poolwords);
+ credit_entropy_store(new_store, random_state->entropy_count);
+
+ sysctl_init_random(new_store);
+ old_store = random_state;
+ random_state = batch_tqueue.data = new_store;
+ free_entropy_store(old_store);
+ return 0;
+}
+
+static int proc_do_poolsize(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp)
+{
+ int ret;
+
+ sysctl_poolsize = random_state->poolinfo.poolwords * 4;
+
+ ret = proc_dointvec(table, write, filp, buffer, lenp);
+ if (ret || !write ||
+ (sysctl_poolsize == random_state->poolinfo.poolwords * 4))
+ return ret;
+
+ return change_poolsize(sysctl_poolsize);
+}
+
+static int poolsize_strategy(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen, void **context)
+{
+ int len;
+
+ sysctl_poolsize = random_state->poolinfo.poolwords * 4;
+
+ /*
+ * We only handle the write case, since the read case gets
+ * handled by the default handler (and we don't care if the
+ * write case happens twice; it's harmless).
+ */
+ if (newval && newlen) {
+ len = newlen;
+ if (len > table->maxlen)
+ len = table->maxlen;
+ if (copy_from_user(table->data, newval, len))
+ return -EFAULT;
+ }
+
+ if (sysctl_poolsize != random_state->poolinfo.poolwords * 4)
+ return change_poolsize(sysctl_poolsize);
+
+ return 0;
+}
+
+/*
+ * These functions is used to return both the bootid UUID, and random
+ * UUID. The difference is in whether table->data is NULL; if it is,
+ * then a new UUID is generated and returned to the user.
+ *
+ * If the user accesses this via the proc interface, it will be returned
+ * as an ASCII string in the standard UUID format. If accesses via the
+ * sysctl system call, it is returned as 16 bytes of binary data.
+ */
+static int proc_do_uuid(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp)
+{
+ ctl_table fake_table;
+ unsigned char buf[64], tmp_uuid[16], *uuid;
+
+ uuid = table->data;
+ if (!uuid) {
+ uuid = tmp_uuid;
+ uuid[8] = 0;
+ }
+ if (uuid[8] == 0)
+ generate_random_uuid(uuid);
+
+ sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x",
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+ fake_table.data = buf;
+ fake_table.maxlen = sizeof(buf);
+
+ return proc_dostring(&fake_table, write, filp, buffer, lenp);
+}
+
+static int uuid_strategy(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen, void **context)
+{
+ unsigned char tmp_uuid[16], *uuid;
+ int len;
+
+ if (!oldval || !oldlenp)
+ return 1;
+
+ uuid = table->data;
+ if (!uuid) {
+ uuid = tmp_uuid;
+ uuid[8] = 0;
+ }
+ if (uuid[8] == 0)
+ generate_random_uuid(uuid);
+
+ get_user(len, oldlenp);
+ if (len) {
+ if (len > 16)
+ len = 16;
+ if (copy_to_user(oldval, table->data, len))
+ return -EFAULT;
+ if (put_user(len, oldlenp))
+ return -EFAULT;
+ }
+ return 1;
+}
+
+ctl_table random_table[] = {
+ {RANDOM_POOLSIZE, "poolsize",
+ &sysctl_poolsize, sizeof(int), 0644, NULL,
+ &proc_do_poolsize, &poolsize_strategy},
+ {RANDOM_ENTROPY_COUNT, "entropy_avail",
+ NULL, sizeof(int), 0444, NULL,
+ &proc_dointvec},
+ {RANDOM_READ_THRESH, "read_wakeup_threshold",
+ &random_read_wakeup_thresh, sizeof(int), 0644, NULL,
+ &proc_dointvec_minmax, &sysctl_intvec, 0,
+ &min_read_thresh, &max_read_thresh},
+ {RANDOM_WRITE_THRESH, "write_wakeup_threshold",
+ &random_write_wakeup_thresh, sizeof(int), 0644, NULL,
+ &proc_dointvec_minmax, &sysctl_intvec, 0,
+ &min_write_thresh, &max_write_thresh},
+ {RANDOM_BOOT_ID, "boot_id",
+ &sysctl_bootid, 16, 0444, NULL,
+ &proc_do_uuid, &uuid_strategy},
+ {RANDOM_UUID, "uuid",
+ NULL, 16, 0444, NULL,
+ &proc_do_uuid, &uuid_strategy},
+ {0}
+};
+
+static void sysctl_init_random(struct entropy_store *random_state)
+{
+ min_read_thresh = 8;
+ min_write_thresh = 0;
+ max_read_thresh = max_write_thresh =
+ random_state->poolinfo.poolwords * 32;
+ random_table[1].data = &random_state->entropy_count;
+}
+#endif /* CONFIG_SYSCTL */
+
+/********************************************************************
+ *
+ * Random funtions for networking
+ *
+ ********************************************************************/
+
/*
* TCP initial sequence number picking. This uses the random number
* generator to pick an initial secret value. This value is hashed
@@ -1696,7 +2018,7 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
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);
+ get_random_bytes(&secret[3], sizeof(secret)-12);
count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
}
@@ -1831,71 +2153,3 @@ __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, __u16 sport,
return (cookie - tmp[17]) & COOKIEMASK; /* Leaving the data behind */
}
#endif
-
-
-#ifdef RANDOM_BENCHMARK
-/*
- * This is so we can do some benchmarking of the random driver, to see
- * how much overhead add_timer_randomness really takes. This only
- * works on a Pentium, since it depends on the timer clock...
- *
- * Note: the results of this benchmark as of this writing (5/27/96)
- *
- * On a Pentium, add_timer_randomness() takes between 150 and 1000
- * clock cycles, with an average of around 600 clock cycles. On a 75
- * MHz Pentium, this translates to 2 to 13 microseconds, with an
- * average time of 8 microseconds. This should be fast enough so we
- * can use add_timer_randomness() even with the fastest of interrupts...
- */
-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 << 32) | low);
-}
-
-__initfunc(static void
-initialize_benchmark(struct random_benchmark *bench,
- const char *descr, int unit))
-{
- bench->times = 0;
- bench->accum = 0;
- bench->max = 0;
- bench->min = 1 << 31;
- bench->descr = descr;
- bench->unit = unit;
-}
-
-static void begin_benchmark(struct random_benchmark *bench)
-{
-#ifdef BENCHMARK_NOINT
- save_flags(bench->flags); cli();
-#endif
- bench->start_time = get_clock_cnt();
-}
-
-static void end_benchmark(struct random_benchmark *bench)
-{
- unsigned long ticks;
-
- ticks = (unsigned long) (get_clock_cnt() - bench->start_time);
-#ifdef BENCHMARK_NOINT
- restore_flags(bench->flags);
-#endif
- if (ticks < bench->min)
- bench->min = ticks;
- if (ticks > bench->max)
- bench->max = ticks;
- bench->accum += ticks;
- bench->times++;
- if (bench->times == BENCHMARK_INTERVAL) {
- printk("Random benchmark: %s %d: %lu min, %lu avg, "
- "%lu max\n", bench->descr, bench->unit, bench->min,
- bench->accum / BENCHMARK_INTERVAL, bench->max);
- bench->times = 0;
- bench->accum = 0;
- bench->max = 0;
- bench->min = 1 << 31;
- }
-}
-#endif /* RANDOM_BENCHMARK */
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
new file mode 100644
index 000000000..c8936ceb6
--- /dev/null
+++ b/drivers/char/raw.c
@@ -0,0 +1,394 @@
+/*
+ * linux/drivers/char/raw.c
+ *
+ * Front-end raw character devices. These can be bound to any block
+ * devices to provide genuine Unix raw character device semantics.
+ *
+ * We reserve minor number 0 for a control interface. ioctl()s on this
+ * device are used to bind the other minor numbers to block devices.
+ */
+
+#include <linux/fs.h>
+#include <linux/iobuf.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/raw.h>
+#include <linux/capability.h>
+#include <asm/uaccess.h>
+
+#define dprintk(x...)
+
+static kdev_t raw_device_bindings[256] = {};
+static int raw_device_inuse[256] = {};
+static int raw_device_sector_size[256] = {};
+static int raw_device_sector_bits[256] = {};
+
+extern struct file_operations * get_blkfops(unsigned int major);
+
+static ssize_t rw_raw_dev(int rw, struct file *, char *, size_t, loff_t *);
+
+ssize_t raw_read(struct file *, char *, size_t, loff_t *);
+ssize_t raw_write(struct file *, const char *, size_t, loff_t *);
+int raw_open(struct inode *, struct file *);
+int raw_release(struct inode *, struct file *);
+int raw_ctl_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+
+static struct file_operations raw_fops = {
+ NULL, /* llseek */
+ raw_read, /* read */
+ raw_write, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ raw_open, /* open */
+ NULL, /* flush */
+ raw_release, /* release */
+ NULL /* fsync */
+};
+
+static struct file_operations raw_ctl_fops = {
+ NULL, /* llseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ raw_ctl_ioctl, /* ioctl */
+ NULL, /* mmap */
+ raw_open, /* open */
+ NULL, /* flush */
+ NULL, /* no special release code */
+ NULL /* fsync */
+};
+
+
+
+void __init raw_init(void)
+{
+ register_chrdev(RAW_MAJOR, "raw", &raw_fops);
+}
+
+
+/*
+ * The raw IO open and release code needs to fake appropriate
+ * open/release calls to the underlying block devices.
+ */
+
+static int bdev_open(kdev_t dev, int mode)
+{
+ int err = 0;
+ struct file dummy_file = {};
+ struct dentry dummy_dentry = {};
+ struct inode * inode = get_empty_inode();
+
+ if (!inode)
+ return -ENOMEM;
+
+ dummy_file.f_op = get_blkfops(MAJOR(dev));
+ if (!dummy_file.f_op) {
+ err = -ENODEV;
+ goto done;
+ }
+
+ if (dummy_file.f_op->open) {
+ inode->i_rdev = dev;
+ dummy_dentry.d_inode = inode;
+ dummy_file.f_dentry = &dummy_dentry;
+ dummy_file.f_mode = mode;
+ err = dummy_file.f_op->open(inode, &dummy_file);
+ }
+
+ done:
+ iput(inode);
+ return err;
+}
+
+static int bdev_close(kdev_t dev)
+{
+ int err;
+ struct inode * inode = get_empty_inode();
+
+ if (!inode)
+ return -ENOMEM;
+
+ inode->i_rdev = dev;
+ err = blkdev_release(inode);
+ iput(inode);
+ return err;
+}
+
+
+
+/*
+ * Open/close code for raw IO.
+ */
+
+int raw_open(struct inode *inode, struct file *filp)
+{
+ int minor;
+ kdev_t bdev;
+ int err;
+ int sector_size;
+ int sector_bits;
+
+ minor = MINOR(inode->i_rdev);
+
+ /*
+ * Is it the control device?
+ */
+
+ if (minor == 0) {
+ filp->f_op = &raw_ctl_fops;
+ return 0;
+ }
+
+ /*
+ * No, it is a normal raw device. All we need to do on open is
+ * to check that the device is bound, and force the underlying
+ * block device to a sector-size blocksize.
+ */
+
+ bdev = raw_device_bindings[minor];
+ if (bdev == NODEV)
+ return -ENODEV;
+
+ err = bdev_open(bdev, filp->f_mode);
+ if (err)
+ return err;
+
+ /*
+ * Don't change the blocksize if we already have users using
+ * this device
+ */
+
+ if (raw_device_inuse[minor]++)
+ return 0;
+
+ /*
+ * Don't interfere with mounted devices: we cannot safely set
+ * the blocksize on a device which is already mounted.
+ */
+
+ sector_size = 512;
+ if (lookup_vfsmnt(bdev) != NULL) {
+ if (blksize_size[MAJOR(bdev)])
+ sector_size = blksize_size[MAJOR(bdev)][MINOR(bdev)];
+ } else {
+ if (hardsect_size[MAJOR(bdev)])
+ sector_size = hardsect_size[MAJOR(bdev)][MINOR(bdev)];
+ }
+
+ set_blocksize(bdev, sector_size);
+ raw_device_sector_size[minor] = sector_size;
+
+ for (sector_bits = 0; !(sector_size & 1); )
+ sector_size>>=1, sector_bits++;
+ raw_device_sector_bits[minor] = sector_bits;
+
+ return 0;
+}
+
+int raw_release(struct inode *inode, struct file *filp)
+{
+ int minor;
+ kdev_t bdev;
+
+ minor = MINOR(inode->i_rdev);
+ bdev = raw_device_bindings[minor];
+ bdev_close(bdev);
+ raw_device_inuse[minor]--;
+ return 0;
+}
+
+
+
+/*
+ * Deal with ioctls against the raw-device control interface, to bind
+ * and unbind other raw devices.
+ */
+
+int raw_ctl_ioctl(struct inode *inode,
+ struct file *flip,
+ unsigned int command,
+ unsigned long arg)
+{
+ struct raw_config_request rq;
+ int err = 0;
+ int minor;
+
+ switch (command) {
+ case RAW_SETBIND:
+ case RAW_GETBIND:
+
+ /* First, find out which raw minor we want */
+
+ err = copy_from_user(&rq, (void *) arg, sizeof(rq));
+ if (err)
+ break;
+
+ minor = rq.raw_minor;
+ if (minor == 0 || minor > MINORMASK) {
+ err = -EINVAL;
+ break;
+ }
+
+ if (command == RAW_SETBIND) {
+ /*
+ * This is like making block devices, so demand the
+ * same capability
+ */
+ if (!capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ break;
+ }
+
+ /*
+ * For now, we don't need to check that the underlying
+ * block device is present or not: we can do that when
+ * the raw device is opened. Just check that the
+ * major/minor numbers make sense.
+ */
+
+ if (rq.block_major == NODEV ||
+ rq.block_major > MAX_BLKDEV ||
+ rq.block_minor > MINORMASK) {
+ err = -EINVAL;
+ break;
+ }
+
+ if (raw_device_inuse[minor]) {
+ err = -EBUSY;
+ break;
+ }
+ raw_device_bindings[minor] =
+ MKDEV(rq.block_major, rq.block_minor);
+ } else {
+ rq.block_major = MAJOR(raw_device_bindings[minor]);
+ rq.block_minor = MINOR(raw_device_bindings[minor]);
+ err = copy_to_user((void *) arg, &rq, sizeof(rq));
+ }
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+
+
+ssize_t raw_read(struct file *filp, char * buf,
+ size_t size, loff_t *offp)
+{
+ return rw_raw_dev(READ, filp, buf, size, offp);
+}
+
+ssize_t raw_write(struct file *filp, const char *buf,
+ size_t size, loff_t *offp)
+{
+ return rw_raw_dev(WRITE, filp, (char *) buf, size, offp);
+}
+
+#define SECTOR_BITS 9
+#define SECTOR_SIZE (1U << SECTOR_BITS)
+#define SECTOR_MASK (SECTOR_SIZE - 1)
+
+ssize_t rw_raw_dev(int rw, struct file *filp, char *buf,
+ size_t size, loff_t *offp)
+{
+ struct kiobuf * iobuf;
+ int err;
+ unsigned long blocknr, blocks;
+ unsigned long b[KIO_MAX_SECTORS];
+ size_t transferred;
+ int iosize;
+ int i;
+ int minor;
+ kdev_t dev;
+ unsigned long limit;
+
+ int sector_size, sector_bits, sector_mask;
+ int max_sectors;
+
+ /*
+ * First, a few checks on device size limits
+ */
+
+ minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+ dev = raw_device_bindings[minor];
+ sector_size = raw_device_sector_size[minor];
+ sector_bits = raw_device_sector_bits[minor];
+ sector_mask = sector_size- 1;
+ max_sectors = KIO_MAX_SECTORS >> (sector_bits - 9);
+
+ if (blk_size[MAJOR(dev)])
+ limit = (((loff_t) blk_size[MAJOR(dev)][MINOR(dev)]) << BLOCK_SIZE_BITS) >> sector_bits;
+ else
+ limit = INT_MAX;
+ dprintk ("rw_raw_dev: dev %d:%d (+%d)\n",
+ MAJOR(dev), MINOR(dev), limit);
+
+ if ((*offp & sector_mask) || (size & sector_mask))
+ return -EINVAL;
+ if ((*offp >> sector_bits) > limit)
+ return 0;
+
+ /*
+ * We'll just use one kiobuf
+ */
+
+ err = alloc_kiovec(1, &iobuf);
+ if (err)
+ return err;
+
+ /*
+ * Split the IO into KIO_MAX_SECTORS chunks, mapping and
+ * unmapping the single kiobuf as we go to perform each chunk of
+ * IO.
+ */
+
+ transferred = 0;
+ blocknr = *offp >> sector_bits;
+ while (size > 0) {
+ blocks = size >> sector_bits;
+ if (blocks > max_sectors)
+ blocks = max_sectors;
+ if (blocks > limit - blocknr)
+ blocks = limit - blocknr;
+ if (!blocks)
+ break;
+
+ iosize = blocks << sector_bits;
+
+ err = map_user_kiobuf(rw, iobuf, (unsigned long) buf, iosize);
+ if (err)
+ break;
+
+ for (i=0; i < blocks; i++)
+ b[i] = blocknr++;
+
+ err = brw_kiovec(rw, 1, &iobuf, dev, b, sector_size, 0);
+
+ if (err >= 0) {
+ transferred += err;
+ size -= err;
+ buf += err;
+ }
+
+ unmap_kiobuf(iobuf);
+
+ if (err != iosize)
+ break;
+ }
+
+ free_kiovec(1, &iobuf);
+
+ if (transferred) {
+ *offp += transferred;
+ return transferred;
+ }
+
+ return err;
+}
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index adfa0a165..d53aa4e52 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -232,7 +232,7 @@ extern inline void rc_long_delay(unsigned long delay)
}
/* Reset and setup CD180 chip */
-__initfunc(static void rc_init_CD180(struct riscom_board const * bp))
+static void __init rc_init_CD180(struct riscom_board const * bp)
{
unsigned long flags;
@@ -257,7 +257,7 @@ __initfunc(static void rc_init_CD180(struct riscom_board const * bp))
}
/* Main probing routine, also sets irq. */
-__initfunc(static int rc_probe(struct riscom_board *bp))
+static int __init rc_probe(struct riscom_board *bp)
{
unsigned char val1, val2;
int irqs = 0;
@@ -1027,7 +1027,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
rc_out(bp, RC_DTR, bp->DTR);
}
sti();
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(port->flags & ASYNC_INITIALIZED)) {
if (port->flags & ASYNC_HUP_NOTIFY)
@@ -1820,7 +1820,7 @@ static void rc_release_drivers(void)
* addresses in this case.
*
*/
-__initfunc(void riscom8_setup(char *str, int * ints))
+void __init riscom8_setup(char *str, int * ints)
{
int i;
@@ -1836,7 +1836,7 @@ __initfunc(void riscom8_setup(char *str, int * ints))
/*
* This routine must be called by kernel at boot time
*/
-__initfunc(int riscom8_init(void))
+int __init riscom8_init(void)
{
int i;
int found = 0;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index cc0027ebe..22f936e19 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -88,8 +88,6 @@
#endif
#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
#include <linux/init.h>
-#else
-#define __initfunc(x) x
#endif
#include "rocket_int.h"
@@ -890,7 +888,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
sSetDTR(&info->channel);
sSetRTS(&info->channel);
}
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(info->flags & ROCKET_INITIALIZED)) {
if (info->flags & ROCKET_HUP_NOTIFY)
@@ -1958,7 +1956,7 @@ static struct pci_dev *pci_find_slot(unsigned char bus,
}
#endif
-__initfunc(int register_PCI(int i, unsigned int bus, unsigned int device_fn))
+int __init register_PCI(int i, unsigned int bus, unsigned int device_fn)
{
int num_aiops, aiop, max_num_aiops, num_chan, chan;
unsigned int aiopio[MAX_AIOPS_PER_BOARD];
@@ -1973,15 +1971,7 @@ __initfunc(int register_PCI(int i, unsigned int bus, unsigned int device_fn))
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
+ rcktpt_io_addr[i] = dev->resource[0].start;
switch(dev->device) {
case PCI_DEVICE_ID_RP4QUAD:
str = "Quadcable";
@@ -2047,7 +2037,7 @@ __initfunc(int register_PCI(int i, unsigned int bus, unsigned int device_fn))
return(1);
}
-__initfunc(static int init_PCI(int boards_found))
+static int __init init_PCI(int boards_found)
{
unsigned char bus, device_fn;
int i, count = 0;
@@ -2102,7 +2092,7 @@ __initfunc(static int init_PCI(int boards_found))
}
#endif
-__initfunc(static int init_ISA(int i, int *reserved_controller))
+static int __init init_ISA(int i, int *reserved_controller)
{
int num_aiops, num_chan;
int aiop, chan;
@@ -2154,7 +2144,7 @@ __initfunc(static int init_ISA(int i, int *reserved_controller))
/*
* The module "startup" routine; it's run when the module is loaded.
*/
-__initfunc(int rp_init(void))
+int __init rp_init(void)
{
int i, retval, pci_boards_found, isa_boards_found;
int reserved_controller = 0;
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 4339d5514..cc7155150 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -525,7 +525,7 @@ static struct miscdevice rtc_dev=
&rtc_fops
};
-__initfunc(int rtc_init(void))
+int __init rtc_init(void)
{
unsigned long flags;
#if defined(__alpha__) || defined(__mips__)
@@ -552,7 +552,7 @@ __initfunc(int rtc_init(void))
return -EIO;
found:
- rtc_port = edev->base_address[0];
+ rtc_port = edev->resource[0].start;
rtc_irq = edev->irqs[0];
/*
* XXX Interrupt pin #7 in Espresso is shared between RTC and
diff --git a/drivers/char/saa5249.c b/drivers/char/saa5249.c
index 2e93553c5..5ab107a0f 100644
--- a/drivers/char/saa5249.c
+++ b/drivers/char/saa5249.c
@@ -79,9 +79,9 @@ static const int disp_modes[8][3] =
-#define PAGE_WAIT 30 /* Time in jiffies between requesting page and */
+#define PAGE_WAIT (300*HZ/1000) /* Time between requesting page and */
/* checking status bits */
-#define PGBUF_EXPIRE 1500 /* Time in jiffies to wait before retransmitting */
+#define PGBUF_EXPIRE (15*HZ) /* Time to wait before retransmitting */
/* page regardless of infobits */
typedef struct {
u8 pgbuf[VTX_VIRTUALSIZE]; /* Page-buffer */
@@ -107,9 +107,9 @@ struct saa5249_device
#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 CLEAR_DELAY (HZ/20) /* Time required to clear a page */
+#define I2C_TIMEOUT (3*HZ) /* open/close/SDA-check timeout */
+#define READY_TIMEOUT (30*HZ/1000) /* Time 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) */
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index 1529bd7ee..f0f67c0cf 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -301,7 +301,7 @@ int paste_selection(struct tty_struct *tty)
poke_blanked_console();
add_wait_queue(&vt->paste_wait, &wait);
while (sel_buffer && sel_buffer_lth > pasted) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (test_bit(TTY_THROTTLED, &tty->flags)) {
schedule();
continue;
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 6c4b9beac..99513eed6 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -2,6 +2,8 @@
* linux/drivers/char/serial.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
+ * 1998, 1999 Theodore Ts'o
*
* Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now
* much more extensible to support other serial cards based on the
@@ -34,6 +36,11 @@
* 4/98: Added changes to support the ARM architecture proposed by
* Russell King
*
+ * 5/99: Updated to include support for the XR16C850 and ST16C654
+ * uarts. Stuart MacDonald <stuartm@connecttech.com>
+ *
+ * 8/99: Generalized PCI support added. Theodore Ts'o
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
@@ -64,13 +71,16 @@
* ever possible.
*/
+#include <linux/config.h>
+#include <linux/version.h>
+
#undef SERIAL_PARANOIA_CHECK
#define CONFIG_SERIAL_NOPAUSE_IO
#define SERIAL_DO_RESTART
+#define CONFIG_SERIAL_PCI_MEMMAPPED
#if 0
-/* Normally these defines are controlled by the autoconf.h */
-
+/* These defines are normally controlled by the autoconf.h */
#define CONFIG_SERIAL_MANY_PORTS
#define CONFIG_SERIAL_SHARE_IRQ
#define CONFIG_SERIAL_DETECT_IRQ
@@ -78,6 +88,19 @@
#define CONFIG_HUB6
#endif
+#if (defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= 131072))
+#define ENABLE_SERIAL_PCI
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+#undef SERIAL_DEBUG_PCI
+
/* Sanity checks */
#ifdef CONFIG_SERIAL_MULTIPORT
@@ -95,18 +118,11 @@
#endif
#endif
-/* Set of debugging defines */
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-
#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256
#define IRQ_T(state) \
- ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+ ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
#define SERIAL_INLINE
@@ -121,8 +137,33 @@
* End of serial driver configuration section.
*/
-#include <linux/config.h>
+#if (LINUX_VERSION_CODE > 66304)
+#define NEW_MODULES
+#ifdef LOCAL_HEADERS /* We're building standalone */
+#define MODULE
+#endif
+#endif
+
+#ifdef NEW_MODULES
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#else /* !NEW_MODULES */
+#ifdef MODVERSIONS
+#define MODULE
+#endif
+#endif /* NEW_MODULES */
#include <linux/module.h>
+
+#ifdef LOCAL_HEADERS
+#include "serial_local.h"
+#else
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <asm/serial.h>
+static char *serial_version = "4.30";
+#endif
+
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -130,8 +171,6 @@
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
@@ -139,31 +178,47 @@
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
#include <linux/init.h>
+#else
+#define __initfunc(x) x
+#endif
#include <linux/delay.h>
#ifdef CONFIG_SERIAL_CONSOLE
#include <linux/console.h>
#endif
+#ifdef ENABLE_SERIAL_PCI
+#include <linux/pci.h>
+#endif
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/uaccess.h>
#include <asm/bitops.h>
-#include <asm/serial.h>
+
+#ifdef CONFIG_MAC_SERIAL
+#define SERIAL_DEV_OFFSET 2
+#else
+#define SERIAL_DEV_OFFSET 0
+#endif
#ifdef SERIAL_INLINE
#define _INLINE_ inline
#endif
static char *serial_name = "Serial driver";
-static char *serial_version = "4.27";
static DECLARE_TASK_QUEUE(tq_serial);
static struct tty_driver serial_driver, callout_driver;
static int serial_refcount;
+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+#endif
+
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
@@ -196,20 +251,33 @@ static struct serial_uart_config uart_config[] = {
{ "16450", 1, 0 },
{ "16550", 1, 0 },
{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
- { "cirrus", 1, 0 },
- { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
+ { "cirrus", 1, 0 }, /* usurped by cyclades.c */
+ { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH },
{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
UART_STARTECH },
{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+ { "Startech", 1, 0}, /* usurped by cyclades.c */
+ { "16C950", 128, UART_CLEAR_FIFO | UART_USE_FIFO},
+ { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO |
+ UART_STARTECH },
+ { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
+ UART_STARTECH },
{ 0, 0}
};
-static struct serial_state rs_table[] = {
+static struct serial_state rs_table[RS_TABLE_SIZE] = {
SERIAL_PORT_DFNS /* Defined in serial.h */
};
#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
+#ifdef ENABLE_SERIAL_PCI
+#define NR_PCI_BOARDS 8
+static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
+static int serial_pci_board_idx = 0;
+#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start)
+#endif /* ENABLE_SERIAL_PCI */
+
static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
@@ -228,7 +296,93 @@ static struct termios *serial_termios_locked[NR_PORTS];
* memory if large numbers of serial ports are open.
*/
static unsigned char *tmp_buf;
+#ifdef DECLARE_MUTEX
static DECLARE_MUTEX(tmp_buf_sem);
+#else
+static struct semaphore tmp_buf_sem = MUTEX;
+#endif
+
+/*
+ * Provide backwards compatibility for kernels prior to 2.1.XX.
+ */
+#if (LINUX_VERSION_CODE < 0x20000)
+typedef dev_t kdev_t;
+#endif
+
+#if (LINUX_VERSION_CODE < 0x02017E)
+static signed long schedule_timeout(signed long timeout)
+{
+ unsigned long expire;
+
+ expire = timeout + jiffies;
+
+ current->timeout = jiffies + timeout;
+ schedule();
+
+ timeout = expire - jiffies;
+ return timeout < 0 ? 0 : timeout;
+}
+#endif
+
+#ifndef time_after
+#define time_after(a,b) ((long)(b) - (long)(a) < 0)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x020100)
+static inline int irq_cannonicalize(int irq)
+{
+ return ((irq == 2) ? 9 : irq);
+}
+#endif
+
+#if (LINUX_VERSION_CODE < 131336)
+static int copy_from_user(void *to, const void *from_user, unsigned long len)
+{
+ int error;
+
+ error = verify_area(VERIFY_READ, from_user, len);
+ if (error)
+ return len;
+ memcpy_fromfs(to, from_user, len);
+ return 0;
+}
+
+static int copy_to_user(void *to_user, const void *from, unsigned long len)
+{
+ int error;
+
+ error = verify_area(VERIFY_WRITE, to_user, len);
+ if (error)
+ return 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
+
+#ifdef CAP_SYS_ADMIN
+#define serial_isroot() (capable(CAP_SYS_ADMIN))
+#else
+#define serial_isroot() (suser())
+#endif
+
+#if (LINUX_VERSION_CODE < 131394) /* 2.1.66 */
+#define test_and_clear_bit(x,y) clear_bit(x,y)
+
+static inline void remove_bh(int nr)
+{
+ bh_base[nr] = NULL;
+ bh_mask &= ~(1 << nr);
+}
+#endif
+
static inline int serial_paranoia_check(struct async_struct *info,
kdev_t device, const char *routine)
@@ -325,6 +479,26 @@ static inline void serial_outp(struct async_struct *info, int offset,
}
/*
+ * For the 16C950
+ */
+void serial_icr_write(struct async_struct *info, int offset, int value)
+{
+ serial_out(info, UART_SCR, offset);
+ serial_out(info, UART_ICR, value);
+}
+
+unsigned int serial_icr_read(struct async_struct *info, int offset)
+{
+ int value;
+
+ serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD);
+ serial_out(info, UART_SCR, offset);
+ value = serial_in(info, UART_ICR);
+ serial_icr_write(info, UART_ACR, info->ACR);
+ return value;
+}
+
+/*
* ------------------------------------------------------------
* rs_stop() and rs_start()
*
@@ -345,6 +519,10 @@ static void rs_stop(struct tty_struct *tty)
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
+ if (info->state->type == PORT_16C950) {
+ info->ACR |= UART_ACR_TXDIS;
+ serial_icr_write(info, UART_ACR, info->ACR);
+ }
restore_flags(flags);
}
@@ -361,6 +539,10 @@ static void rs_start(struct tty_struct *tty)
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
+ if (info->state->type == PORT_16C950) {
+ info->ACR &= ~UART_ACR_TXDIS;
+ serial_icr_write(info, UART_ACR, info->ACR);
+ }
restore_flags(flags);
}
@@ -475,7 +657,11 @@ static _INLINE_ void receive_chars(struct async_struct *info,
ignore_char:
*status = serial_inp(info, UART_LSR);
} while (*status & UART_LSR_DR);
+#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
tty_flip_buffer_push(tty);
+#else
+ queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+#endif
}
static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
@@ -954,7 +1140,7 @@ static int startup(struct async_struct * info)
goto errout;
}
- if (!state->port || !state->type) {
+ if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
free_page(page);
@@ -973,8 +1159,28 @@ static int startup(struct async_struct * info)
/* Wake up UART */
serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, UART_EFR_ECB);
+ /*
+ * Turn off LCR == 0xBF so we actually set the IER
+ * register on the XR16C850
+ */
+ serial_outp(info, UART_LCR, 0);
serial_outp(info, UART_IER, 0);
+ /*
+ * Now reset LCR so we can turn off the ECB bit
+ */
+ serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, 0);
+ /*
+ * For a XR16C850, we need to set the trigger levels
+ */
+ if (info->state->type == PORT_16850) {
+ serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
+ UART_FCTR_RX);
+ serial_outp(info, UART_TRG, UART_TRG_96);
+ serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
+ UART_FCTR_TX);
+ serial_outp(info, UART_TRG, UART_TRG_96);
+ }
serial_outp(info, UART_LCR, 0);
}
@@ -983,13 +1189,38 @@ static int startup(struct async_struct * info)
serial_outp(info, UART_IER, 0);
}
+ if (info->state->type == PORT_16C950) {
+ /* Wake up and initialize UART */
+ info->ACR = 0;
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_EFR, UART_EFR_ECB);
+ serial_outp(info, UART_IER, 0);
+ serial_outp(info, UART_LCR, 0);
+ serial_icr_write(info, UART_CSR, 0); /* Reset the UART */
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_EFR, UART_EFR_ECB);
+ serial_outp(info, UART_LCR, 0);
+ }
+
/*
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
*/
- if (uart_config[state->type].flags & UART_CLEAR_FIFO)
- serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+ if (uart_config[state->type].flags & UART_CLEAR_FIFO) {
+ serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
+ serial_outp(info, UART_FCR, 0);
+ }
+
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) serial_inp(info, UART_LSR);
+ (void) serial_inp(info, UART_RX);
+ (void) serial_inp(info, UART_IIR);
+ (void) serial_inp(info, UART_MSR);
/*
* At this point there's no way the LSR could still be 0xFF;
@@ -997,7 +1228,8 @@ static int startup(struct async_struct * info)
* here.
*/
if (serial_inp(info, UART_LSR) == 0xff) {
- if (capable(CAP_SYS_ADMIN)) {
+ printk("LSR safety check engaged!\n");
+ if (serial_isroot()) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
} else
@@ -1029,7 +1261,7 @@ static int startup(struct async_struct * info)
retval = request_irq(state->irq, handler, IRQ_T(state),
"serial", NULL);
if (retval) {
- if (capable(CAP_SYS_ADMIN)) {
+ if (serial_isroot()) {
if (info->tty)
set_bit(TTY_IO_ERROR,
&info->tty->flags);
@@ -1050,14 +1282,6 @@ static int startup(struct async_struct * info)
figure_IRQ_timeout(state->irq);
/*
- * Clear the interrupt registers.
- */
- /* (void) serial_inp(info, UART_LSR); */ /* (see above) */
- (void) serial_inp(info, UART_RX);
- (void) serial_inp(info, UART_IIR);
- (void) serial_inp(info, UART_MSR);
-
- /*
* Now, initialize the UART
*/
serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
@@ -1075,12 +1299,7 @@ static int startup(struct async_struct * info)
if (state->irq != 0)
info->MCR |= UART_MCR_OUT2;
}
-#if defined(__alpha__) && !defined(CONFIG_PCI)
- /*
- * DEC did something gratutiously wrong....
- */
- info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
+ info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
serial_outp(info, UART_MCR, info->MCR);
/*
@@ -1119,6 +1338,7 @@ static int startup(struct async_struct * info)
/*
* Set up the tty->alt_speed kludge
*/
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
if (info->tty) {
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
info->tty->alt_speed = 57600;
@@ -1129,6 +1349,7 @@ static int startup(struct async_struct * info)
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
}
+#endif
/*
* and set the speed of the serial port
@@ -1215,12 +1436,7 @@ static void shutdown(struct async_struct * info)
} else
#endif
info->MCR &= ~UART_MCR_OUT2;
-#if defined(__alpha__) && !defined(CONFIG_PCI)
- /*
- * DEC did something gratutiously wrong....
- */
- info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
+ info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
/* disable break condition */
serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
@@ -1252,6 +1468,37 @@ static void shutdown(struct async_struct * info)
restore_flags(flags);
}
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static int baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300,
+ 600, 1200, 1800, 2400, 4800, 9600, 19200,
+ 38400, 57600, 115200, 230400, 460800, 0 };
+
+static int tty_get_baud_rate(struct tty_struct *tty)
+{
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ unsigned int cflag, i;
+
+ cflag = tty->termios->c_cflag;
+
+ i = cflag & CBAUD;
+ if (i & CBAUDEX) {
+ i &= ~CBAUDEX;
+ if (i < 1 || i > 2)
+ tty->termios->c_cflag &= ~CBAUDEX;
+ else
+ i += 15;
+ }
+ if (i == 15) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ i += 1;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ i += 2;
+ }
+ return baud_table[i];
+}
+#endif
+
/*
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
@@ -1259,7 +1506,6 @@ static void shutdown(struct async_struct * info)
static void change_speed(struct async_struct *info,
struct termios *old_termios)
{
- unsigned short port;
int quot = 0, baud_base, baud;
unsigned cflag, cval, fcr = 0;
int bits;
@@ -1268,7 +1514,7 @@ static void change_speed(struct async_struct *info,
if (!info->tty || !info->tty->termios)
return;
cflag = info->tty->termios->c_cflag;
- if (!(port = info->port))
+ if (!CONFIGURED_SERIAL_PORT(info))
return;
/* byte size and parity */
@@ -1300,6 +1546,18 @@ static void change_speed(struct async_struct *info,
if (!baud)
baud = 9600; /* B0 transition handled in rs_set_termios */
baud_base = info->state->baud_base;
+ if (info->state->type == PORT_16C950) {
+ if (baud <= baud_base)
+ serial_icr_write(info, UART_TCR, 0);
+ else if (baud <= 2*baud_base) {
+ serial_icr_write(info, UART_TCR, 0x8);
+ baud_base = baud_base * 2;
+ } else if (baud <= 4*baud_base) {
+ serial_icr_write(info, UART_TCR, 0x4);
+ baud_base = baud_base * 4;
+ } else
+ serial_icr_write(info, UART_TCR, 0);
+ }
if (baud == 38400 &&
((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
quot = info->state->custom_divisor;
@@ -1405,6 +1663,7 @@ static void change_speed(struct async_struct *info,
if (info->state->type == PORT_16750)
serial_outp(info, UART_FCR, fcr); /* set fcr */
serial_outp(info, UART_LCR, cval); /* reset DLAB */
+ info->LCR = cval; /* Save LCR */
if (info->state->type != PORT_16750)
serial_outp(info, UART_FCR, fcr); /* set fcr */
restore_flags(flags);
@@ -1686,7 +1945,7 @@ static int set_serial_info(struct async_struct * info,
change_port = (new_serial.port != state->port) ||
(new_serial.hub6 != state->hub6);
- if (!capable(CAP_SYS_ADMIN)) {
+ if (!serial_isroot()) {
if (change_irq || change_port ||
(new_serial.baud_base != state->baud_base) ||
(new_serial.type != state->type) ||
@@ -1743,11 +2002,14 @@ static int set_serial_info(struct async_struct * info,
state->type = new_serial.type;
state->close_delay = new_serial.close_delay * HZ/100;
state->closing_wait = new_serial.closing_wait * HZ/100;
+#if (LINUX_VERSION_CODE > 0x200100)
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
info->xmit_fifo_size = state->xmit_fifo_size =
new_serial.xmit_fifo_size;
- release_region(state->port,8);
+ if (state->type != PORT_UNKNOWN && state->port)
+ release_region(state->port,8);
if (change_port || change_irq) {
/*
* We need to shutdown the serial port at the old
@@ -1758,7 +2020,7 @@ static int set_serial_info(struct async_struct * info,
info->port = state->port = new_serial.port;
info->hub6 = state->hub6 = new_serial.hub6;
}
- if (state->type != PORT_UNKNOWN)
+ if ((state->type != PORT_UNKNOWN) && state->port)
request_region(state->port,8,"serial(set)");
@@ -1769,6 +2031,7 @@ check_and_exit:
if (((old_state.flags & ASYNC_SPD_MASK) !=
(state->flags & ASYNC_SPD_MASK)) ||
(old_state.custom_divisor != state->custom_divisor)) {
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
info->tty->alt_speed = 57600;
if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
@@ -1777,6 +2040,7 @@ check_and_exit:
info->tty->alt_speed = 230400;
if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
+#endif
change_speed(info, 0);
}
} else
@@ -1805,7 +2069,9 @@ static int get_lsr_info(struct async_struct * info, unsigned int *value)
status = serial_in(info, UART_LSR);
restore_flags(flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result,value);
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
}
@@ -1829,19 +2095,21 @@ static int get_modem_info(struct async_struct * info, unsigned int *value)
| ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
| ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
| ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
- return put_user(result,value);
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
}
static int set_modem_info(struct async_struct * info, unsigned int cmd,
unsigned int *value)
{
- int error;
unsigned int arg;
unsigned long flags;
- error = get_user(arg, value);
- if (error)
- return error;
+ if (copy_from_user(&arg, value, sizeof(int)))
+ return -EFAULT;
+
switch (cmd) {
case TIOCMBIS:
if (arg & TIOCM_RTS)
@@ -1885,6 +2153,7 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd,
return -EINVAL;
}
save_flags(flags); cli();
+ info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
serial_out(info, UART_MCR, info->MCR);
restore_flags(flags);
return 0;
@@ -1894,7 +2163,7 @@ static int do_autoconfig(struct async_struct * info)
{
int retval;
- if (!capable(CAP_SYS_ADMIN))
+ if (!serial_isroot())
return -EPERM;
if (info->state->count > 1)
@@ -1917,6 +2186,22 @@ static int do_autoconfig(struct async_struct * info)
/*
* rs_break() --- routine which turns the break handling on or off
*/
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static void send_break( struct async_struct * info, int duration)
+{
+ if (!CONFIGURED_SERIAL_PORT(info))
+ return;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + duration;
+ cli();
+ info->LCR |= UART_LCR_SBC;
+ serial_out(info, UART_LCR, info->LCR);
+ schedule();
+ info->LCR &= ~UART_LCR_SBC;
+ serial_out(info, UART_LCR, info->LCR);
+ sti();
+}
+#else
static void rs_break(struct tty_struct *tty, int break_state)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
@@ -1925,17 +2210,17 @@ static void rs_break(struct tty_struct *tty, int break_state)
if (serial_paranoia_check(info, tty->device, "rs_break"))
return;
- if (!info->port)
+ if (!CONFIGURED_SERIAL_PORT(info))
return;
save_flags(flags); cli();
if (break_state == -1)
- serial_out(info, UART_LCR,
- serial_inp(info, UART_LCR) | UART_LCR_SBC);
+ info->LCR |= UART_LCR_SBC;
else
- serial_out(info, UART_LCR,
- serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+ info->LCR &= ~UART_LCR_SBC;
+ serial_out(info, UART_LCR, info->LCR);
restore_flags(flags);
}
+#endif
#ifdef CONFIG_SERIAL_MULTIPORT
static int get_multiport_struct(struct async_struct * info,
@@ -1981,7 +2266,7 @@ static int set_multiport_struct(struct async_struct * info,
int retval;
void (*handler)(int, void *, struct pt_regs *);
- if (!capable(CAP_SYS_ADMIN))
+ if (!serial_isroot())
return -EPERM;
state = info->state;
@@ -2054,11 +2339,13 @@ static int set_multiport_struct(struct async_struct * info,
static int rs_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int error;
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 */
+ struct serial_icounter_struct icount;
unsigned long flags;
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+ int retval, tmp;
+#endif
if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
return -ENODEV;
@@ -2071,6 +2358,45 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
}
switch (cmd) {
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ if (!arg) {
+ send_break(info, HZ/4); /* 1/4 second */
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ if (signal_pending(current))
+ return -EINTR;
+ return 0;
+ case TIOCGSOFTCAR:
+ tmp = C_CLOCAL(tty) ? 1 : 0;
+ if (copy_to_user((void *)arg, &tmp, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ case TIOCSSOFTCAR:
+ if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
+ return -EFAULT;
+
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (tmp ? CLOCAL : 0));
+ return 0;
+#endif
case TIOCMGET:
return get_modem_info(info, (unsigned int *) arg);
case TIOCMBIS:
@@ -2146,31 +2472,21 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
save_flags(flags); cli();
cnow = info->state->icount;
restore_flags(flags);
- p_cuser = (struct serial_icounter_struct *) arg;
- error = put_user(cnow.cts, &p_cuser->cts);
- if (error) return error;
- error = put_user(cnow.dsr, &p_cuser->dsr);
- if (error) return error;
- error = put_user(cnow.rng, &p_cuser->rng);
- 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;
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+ return -EFAULT;
return 0;
-
case TIOCSERGWILD:
case TIOCSERSWILD:
/* "setserial -W" is called in Debian boot */
@@ -2444,7 +2760,11 @@ static void rs_hangup(struct tty_struct *tty)
static int block_til_ready(struct tty_struct *tty, struct file * filp,
struct async_struct *info)
{
+#ifdef DECLARE_WAITQUEUE
DECLARE_WAITQUEUE(wait, current);
+#else
+ struct wait_queue wait = { current, NULL };
+#endif
struct serial_state *state = info->state;
int retval;
int do_clocal = 0, extra_count = 0;
@@ -2533,7 +2853,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
serial_inp(info, UART_MCR) |
(UART_MCR_DTR | UART_MCR_RTS));
restore_flags(flags);
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) {
#ifdef SERIAL_DO_RESTART
@@ -2593,12 +2913,18 @@ static int get_async_struct(int line, struct async_struct **ret_info)
return -ENOMEM;
}
memset(info, 0, sizeof(struct async_struct));
+#ifdef DECLARE_WAITQUEUE
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
init_waitqueue_head(&info->delta_msr_wait);
+#endif
info->magic = SERIAL_MAGIC;
info->port = sstate->port;
info->flags = sstate->flags;
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ info->iomem_base = sstate->iomem_base;
+ info->iomem_reg_shift = sstate->iomem_reg_shift;
+#endif
info->xmit_fifo_size = sstate->xmit_fifo_size;
info->line = line;
info->tqueue.routine = do_softint;
@@ -2638,21 +2964,20 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
}
tty->driver_data = info;
info->tty = tty;
- if (serial_paranoia_check(info, tty->device, "rs_open")) {
- /* MOD_DEC_USE_COUNT; "info->tty" will cause this */
+ if (serial_paranoia_check(info, tty->device, "rs_open"))
return -ENODEV;
- }
#ifdef SERIAL_DEBUG_OPEN
printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
info->state->count);
#endif
+#if (LINUX_VERSION_CODE > 0x20100)
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
if (!tmp_buf) {
page = get_free_page(GFP_KERNEL);
if (!page) {
- /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
return -ENOMEM;
}
if (tmp_buf)
@@ -2668,7 +2993,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
(info->flags & ASYNC_CLOSING)) {
if (info->flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->close_wait);
- /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
@@ -2682,13 +3006,11 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
*/
retval = startup(info);
if (retval) {
- /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
return retval;
}
retval = block_til_ready(tty, filp, info);
if (retval) {
- /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
#ifdef SERIAL_DEBUG_OPEN
printk("rs_open returning after block_til_ready with %d\n",
retval);
@@ -2860,6 +3182,13 @@ static _INLINE_ void show_serial_version(void)
printk(" DETECT_IRQ");
#define SERIAL_OPT
#endif
+#ifdef ENABLE_SERIAL_PCI
+ printk(" SERIAL_PCI");
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ printk(" PCI_IOMEM");
+#endif
+#define SERIAL_OPT
+#endif
#ifdef SERIAL_OPT
printk(" enabled\n");
#else
@@ -2935,51 +3264,155 @@ static unsigned detect_uart_irq (struct serial_state * state)
}
/*
+ * This is a quickie test to see how big the FIFO is.
+ * It doesn't work at all the time, more's the pity.
+ */
+static int size_fifo(struct async_struct *info)
+{
+ unsigned char old_fcr, old_mcr, old_dll, old_dlm;
+ int count;
+
+ old_fcr = serial_inp(info, UART_FCR);
+ old_mcr = serial_inp(info, UART_MCR);
+ serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ serial_outp(info, UART_MCR, UART_MCR_LOOP);
+ serial_outp(info, UART_LCR, UART_LCR_DLAB);
+ old_dll = serial_inp(info, UART_DLL);
+ old_dlm = serial_inp(info, UART_DLM);
+ serial_outp(info, UART_DLL, 0x01);
+ serial_outp(info, UART_DLM, 0x00);
+ serial_outp(info, UART_LCR, 0x03);
+ for (count = 0; count < 256; count++)
+ serial_outp(info, UART_TX, count);
+ mdelay(20);
+ for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) &&
+ (count < 256); count++)
+ serial_inp(info, UART_RX);
+ serial_outp(info, UART_FCR, old_fcr);
+ serial_outp(info, UART_MCR, old_mcr);
+ serial_outp(info, UART_LCR, UART_LCR_DLAB);
+ serial_outp(info, UART_DLL, old_dll);
+ serial_outp(info, UART_DLM, old_dlm);
+
+ return count;
+}
+
+/*
+ * This is a helper routine to autodetect StarTech/Exar UART's. When
+ * this function is called we know it is at least a StarTech 16650 V2,
+ * but it might be one of several StarTech UARTs, or one of its
+ * clones. (We treat the broken original StarTech 16650 V1 as a
+ * 16550A, and why not? Startech doesn't seem to even acknowledge its
+ * existence.)
+ *
+ * What evil have men's minds wrought...
+ */
+static void autoconfig_startech_uarts(struct async_struct *info,
+ struct serial_state *state,
+ unsigned long flags)
+{
+ unsigned char scratch, status1, status2, old_fctr, old_emsr;
+
+ /*
+ * Here we check for the XR16C85x family. We do this by
+ * checking for to see if we can replace the scratch register
+ * with the receive FIFO count register.
+ *
+ * XXX I don't have one of these chips, but it should also be
+ * possible to check for them by setting DLL and DLM to 0, and
+ * then reading back DLL and DLM. If the DLM reads back as
+ * 0x10, then the UART is a XR16C850 and the DLL contains the
+ * chip revision.
+ */
+ old_fctr = serial_inp(info, UART_FCTR);
+ serial_outp(info, UART_FCTR, old_fctr | UART_FCTR_SCR_SWAP);
+ old_emsr = serial_inp(info, UART_EMSR);
+ serial_outp(info, UART_EMSR, 0x00);
+ serial_outp(info, UART_LCR, 0x00);
+ scratch = serial_in(info, UART_SCR);
+ serial_outp(info, UART_SCR, 0xa5);
+ status1 = serial_in(info, UART_SCR);
+ serial_outp(info, UART_SCR, 0x5a);
+ status2 = serial_in(info, UART_SCR);
+ serial_outp(info, UART_SCR, scratch);
+ if ((status1 != 0xa5) || (status2 != 0x5a)) {
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_FCTR, old_fctr | UART_FCTR_SCR_SWAP);
+ serial_outp(info, UART_EMSR, old_emsr);
+ serial_outp(info, UART_FCTR, old_fctr);
+ state->type = PORT_16850;
+ return;
+ }
+ serial_outp(info, UART_IER, old_fctr);
+
+ /*
+ * We distinguish between the '654 and the '650 by counting
+ * how many bytes are in the FIFO. I'm using this for now,
+ * since that's the technique that was sent to me in the
+ * serial driver update, but I'm not convinced this works.
+ * I've had problems doing this in the past. -TYT
+ */
+ if (size_fifo(info) == 64)
+ state->type = PORT_16654;
+ else
+ state->type = PORT_16650V2;
+}
+
+/*
* This routine is called by rs_init() to initialize a specific serial
* port. It determines what type of UART chip this serial port is
* using: 8250, 16450, 16550, 16550A. The important question is
- * whether or not this UART is a 16550A, since this will determine
- * whether or not we can use its FIFO features.
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
*/
static void autoconfig(struct serial_state * state)
{
- unsigned char status1, status2, scratch, scratch2;
+ unsigned char status1, status2, scratch, scratch2, scratch3;
struct async_struct *info, scr_info;
unsigned long flags;
state->type = PORT_UNKNOWN;
- if (!state->port)
+ if (!CONFIGURED_SERIAL_PORT(state))
return;
info = &scr_info; /* This is just for serial_{in,out} */
info->magic = SERIAL_MAGIC;
+ info->state = state;
info->port = state->port;
info->flags = state->flags;
#ifdef CONFIG_HUB6
info->hub6 = state->hub6;
#endif
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
+#endif
save_flags(flags); cli();
- /*
- * Do a simple existence test first; if we fail this, there's
- * no point trying anything else.
- *
- * 0x80 is used as a nonsense port to prevent against false
- * positives due to ISA bus float. The assumption is that
- * 0x80 is a non-existent port; which should be safe since
- * include/asm/io.h also makes this assumption.
- */
- scratch = serial_inp(info, UART_IER);
- serial_outp(info, UART_IER, 0);
- outb(0xff, 0x080);
- scratch2 = serial_inp(info, UART_IER);
- serial_outp(info, UART_IER, scratch);
- if (scratch2) {
- restore_flags(flags);
- return; /* We failed; there's nothing here */
+ if (!state->iomem_base) {
+ /*
+ * Do a simple existence test first; if we fail this,
+ * there's no point trying anything else.
+ *
+ * 0x80 is used as a nonsense port to prevent against
+ * false positives due to ISA bus float. The
+ * assumption is that 0x80 is a non-existent port;
+ * which should be safe since include/asm/io.h also
+ * makes this assumption.
+ */
+ scratch = serial_inp(info, UART_IER);
+ serial_outp(info, UART_IER, 0);
+ outb(0xff, 0x080);
+ scratch2 = serial_inp(info, UART_IER);
+ serial_outp(info, UART_IER, scratch);
+ if (scratch2) {
+ restore_flags(flags);
+ return; /* We failed; there's nothing here */
+ }
}
/*
@@ -3002,7 +3435,7 @@ static void autoconfig(struct serial_state * state)
return;
}
}
-
+
scratch2 = serial_in(info, UART_LCR);
serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */
serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
@@ -3024,14 +3457,27 @@ static void autoconfig(struct serial_state * state)
break;
}
if (state->type == PORT_16550A) {
+ /* Check for Oxford Semiconductor 16C950 */
+ scratch = serial_icr_read(info, UART_ID1);
+ scratch2 = serial_icr_read(info, UART_ID2);
+ scratch3 = serial_icr_read(info, UART_ID3);
+
+ if (scratch == 0x16 && scratch2 == 0xC9 &&
+ (scratch3 == 0x50 || scratch3 == 0x52 ||
+ scratch3 == 0x54)) {
+ state->type = PORT_16C950;
+ state->revision = serial_icr_read(info, UART_REV);
+ }
+ }
+ if (state->type == PORT_16550A) {
/* Check for Startech UART's */
- serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+ serial_outp(info, UART_LCR, UART_LCR_DLAB);
if (serial_in(info, UART_EFR) == 0) {
state->type = PORT_16650;
} else {
serial_outp(info, UART_LCR, 0xBF);
if (serial_in(info, UART_EFR) == 0)
- state->type = PORT_16650V2;
+ autoconfig_startech_uarts(info, state, flags);
}
}
if (state->type == PORT_16550A) {
@@ -3041,7 +3487,16 @@ static void autoconfig(struct serial_state * state)
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
scratch = serial_in(info, UART_IIR) >> 5;
if (scratch == 7) {
+ /*
+ * If this is a 16750, and not a cheap UART
+ * clone, then it should only go into 64 byte
+ * mode if the UART_FCR7_64BYTE bit was set
+ * while UART_LCR_DLAB was latched.
+ */
+ serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
serial_outp(info, UART_LCR, 0);
+ serial_outp(info, UART_FCR,
+ UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
scratch = serial_in(info, UART_IIR) >> 5;
if (scratch == 6)
state->type = PORT_16750;
@@ -3067,20 +3522,13 @@ static void autoconfig(struct serial_state * state)
return;
}
- request_region(info->port,8,"serial(auto)");
+ if (info->port)
+ request_region(info->port,8,"serial(auto)");
/*
* Reset the UART.
*/
-#if defined(__alpha__) && !defined(CONFIG_PCI)
- /*
- * I wonder what DEC did to the OUT1 and OUT2 lines?
- * clearing them results in endless interrupts.
- */
- serial_outp(info, UART_MCR, 0x0c);
-#else
- serial_outp(info, UART_MCR, 0x00);
-#endif
+ serial_outp(info, UART_MCR, 0x00 | ALPHA_KLUDGE_MCR); /* Don't ask */
serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
(void)serial_in(info, UART_RX);
@@ -3092,13 +3540,321 @@ static void autoconfig(struct serial_state * state)
int register_serial(struct serial_struct *req);
void unregister_serial(int line);
+#if (LINUX_VERSION_CODE > 0x20100)
EXPORT_SYMBOL(register_serial);
EXPORT_SYMBOL(unregister_serial);
+#else
+static struct symbol_table serial_syms = {
+#include <linux/symtab_begin.h>
+ X(register_serial),
+ X(unregister_serial),
+#include <linux/symtab_end.h>
+};
+#endif
+
+#ifdef ENABLE_SERIAL_PCI
+/*
+ * Some PCI serial cards using the PLX 9050 PCI interface chip require
+ * that the card interrupt be explicitly enabled or disabled. This
+ * seems to be mainly needed on card using the PLX which also use I/O
+ * mapped memory.
+ *
+ * Note that __init is a no-op if MODULE is defined; we depend on this.
+ */
+static void __init pci_plx9050_fn(struct pci_dev *dev,
+ struct pci_board *board,
+ int enable)
+{
+ u8 data, *p;
+
+ pci_read_config_byte(dev, PCI_COMMAND, &data);
+
+ if (enable)
+ pci_write_config_byte(dev, PCI_COMMAND,
+ data | PCI_COMMAND_MEMORY);
+
+ /* enable/disable interrupts */
+ p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80);
+ writel(enable ? 0x41 : 0x00, p + 0x4c);
+ iounmap(p);
+
+ if (!enable)
+ pci_write_config_byte(dev, PCI_COMMAND,
+ data & ~PCI_COMMAND_MEMORY);
+}
+
+/*
+ * This is the configuration table for all of the PCI serial boards
+ * which we support.
+ */
+static struct pci_board pci_boards[] = {
+ /*
+ * Vendor ID, Device ID,
+ * Subvendor ID, Subdevice ID,
+ * Number of Ports, Base (Maximum) Baud Rate,
+ * Offset of register holding Uart register offset
+ * Mask to apply to above register's value
+ */
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
+ SPCI_FL_BASE1, 8, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
+ SPCI_FL_BASE1, 4, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
+ SPCI_FL_BASE1, 2, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
+ SPCI_FL_BASE1, 8, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
+ SPCI_FL_BASE1, 4, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
+ SPCI_FL_BASE1, 2, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485,
+ SPCI_FL_BASE1, 8, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4,
+ SPCI_FL_BASE1, 8, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485,
+ SPCI_FL_BASE1, 4, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2,
+ SPCI_FL_BASE1, 4, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485,
+ SPCI_FL_BASE1, 2, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485,
+ SPCI_FL_BASE1, 8, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4,
+ SPCI_FL_BASE1, 8, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485,
+ SPCI_FL_BASE1, 4, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2,
+ SPCI_FL_BASE1, 4, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485,
+ SPCI_FL_BASE1, 2, 921600 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 8, 115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_KEYSPAN,
+ PCI_SUBDEVICE_ID_KEYSPAN_SX2,
+ SPCI_FL_BASE2 | SPCI_FL_IOMEM, 2, 921600,
+ 0x400, 7, pci_plx9050_fn },
+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_IOMEM, 4, 921600,
+ 0x400, 7, pci_plx9050_fn },
+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_IOMEM, 2, 921600,
+ 0x400, 7, pci_plx9050_fn },
+ { 0, }
+};
+
+/*
+ * Query PCI space for known serial boards
+ * If found, add them to the PCI device space in rs_table[]
+ *
+ * Accept a maximum of eight boards
+ *
+ */
+static void probe_serial_pci(void)
+{
+ u16 subvendor, subdevice;
+ int k, line;
+ struct pci_dev *dev = NULL;
+ struct pci_board *board;
+ struct serial_struct fake_state;
+ int uart_offset, base_baud, base_idx;
+ unsigned long port;
+
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG "Entered probe_serial_pci()\n");
+#endif
+
+ if (!pcibios_present()) {
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n");
+#endif
+ return;
+ }
+
+ for(dev=pci_devices; dev; dev=dev->next) {
+ pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID,
+ &subvendor);
+ pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subdevice);
+
+ for (board = pci_boards; board->vendor; board++) {
+ if (board->vendor != (unsigned short) PCI_ANY_ID &&
+ dev->vendor != board->vendor)
+ continue;
+ if (board->device != (unsigned short) PCI_ANY_ID &&
+ dev->device != board->device)
+ continue;
+ if (board->subvendor != (unsigned short) PCI_ANY_ID &&
+ subvendor != board->subvendor)
+ continue;
+ if (board->subdevice != (unsigned short) PCI_ANY_ID &&
+ subdevice != board->subdevice)
+ continue;
+ break;
+ }
+
+ if (board->vendor == 0) {
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG
+ "Found unknown serial board: %x:%x, %x:%x, %x\n",
+ dev->vendor, dev->device, subvendor, subdevice,
+ dev->class);
+ printk(KERN_DEBUG
+ " Addresses: %lx, %lx, %lx, %lx\n",
+ PCI_BASE_ADDRESS(dev, 0), PCI_BASE_ADDRESS(dev, 1),
+ PCI_BASE_ADDRESS(dev, 2), PCI_BASE_ADDRESS(dev, 3));
+#endif
+ continue;
+ }
+
+ /*
+ * Run the initialization function, if any
+ */
+ if (board->init_fn)
+ (board->init_fn)(dev, board, 1);
+
+ /*
+ * Register the serial board in the array so we can
+ * shutdown the board later, if necessary.
+ */
+ serial_pci_board[serial_pci_board_idx].board = board;
+ serial_pci_board[serial_pci_board_idx].dev = dev;
+ serial_pci_board_idx++;
+
+ base_idx = board->flags & SPCI_FL_BASE_MASK;
+ port = PCI_BASE_ADDRESS(dev, base_idx);
+ if (board->flags & SPCI_FL_IOMEM)
+ port &= PCI_BASE_ADDRESS_MEM_MASK;
+ else
+ port &= PCI_BASE_ADDRESS_IO_MASK;
+
+ /*
+ * Set some defaults for the loop below, which
+ * actually registers each serial port belonging to
+ * the card.
+ */
+ uart_offset = board->uart_offset;
+ if (!uart_offset)
+ uart_offset = 8;
+ base_baud = board->base_baud;
+ if (!base_baud)
+ base_baud = BASE_BAUD;
+#ifndef CONFIG_SERIAL_PCI_MEMMAPPED
+ if (board->flags & SPCI_FL_IOMEM) {
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG
+ "Can't support memory mapped PCI serial device\n");
+#endif
+ continue;
+ }
+#endif
+ memset(&fake_state, 0, sizeof(fake_state));
+
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG
+ "Found Serial PCI device: %x:%x, %x:%x, %x\n",
+ dev->vendor, dev->device, subvendor, subdevice,
+ dev->class);
+ printk(KERN_DEBUG
+ " IRQ: %d, base: %lx (%s), num_ports: %d\n",
+ dev->irq, port, board->flags & SPCI_FL_IOMEM ?
+ "iomem" : "port", board->num_ports);
+#endif
+
+ for (k=0; k < board->num_ports; k++) {
+ if (board->flags & SPCI_FL_BASE_TABLE) {
+ port = PCI_BASE_ADDRESS(dev, base_idx++);
+ if (board->flags & SPCI_FL_IOMEM)
+ port &= PCI_BASE_ADDRESS_MEM_MASK;
+ else
+ port &= PCI_BASE_ADDRESS_IO_MASK;
+ }
+ fake_state.irq = dev->irq;
+ fake_state.port = port;
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ if (board->flags & SPCI_FL_IOMEM) {
+ fake_state.iomem_base =
+ ioremap(port, board->uart_offset);
+ fake_state.iomem_reg_shift = board->reg_shift;
+ fake_state.port = 0;
+ }
+#endif
+ port += uart_offset;
+ fake_state.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
+ line = register_serial(&fake_state);
+ if (line < 0)
+ break;
+ rs_table[line].baud_base = base_baud;
+ }
+ }
+
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
+#endif
+ return;
+}
+
+#endif /* ENABLE_SERIAL_PCI */
/*
* The serial driver boot-time initialization code!
*/
-__initfunc(int rs_init(void))
+int __init rs_init(void)
{
int i;
struct serial_state * state;
@@ -3142,10 +3898,12 @@ __initfunc(int rs_init(void))
memset(&serial_driver, 0, sizeof(struct tty_driver));
serial_driver.magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x20100)
serial_driver.driver_name = "serial";
+#endif
serial_driver.name = "ttyS";
serial_driver.major = TTY_MAJOR;
- serial_driver.minor_start = 64;
+ serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
serial_driver.num = NR_PORTS;
serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
serial_driver.subtype = SERIAL_TYPE_NORMAL;
@@ -3169,14 +3927,18 @@ __initfunc(int rs_init(void))
serial_driver.ioctl = rs_ioctl;
serial_driver.throttle = rs_throttle;
serial_driver.unthrottle = rs_unthrottle;
- serial_driver.send_xchar = rs_send_xchar;
serial_driver.set_termios = rs_set_termios;
serial_driver.stop = rs_stop;
serial_driver.start = rs_start;
serial_driver.hangup = rs_hangup;
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
serial_driver.break_ctl = rs_break;
+#endif
+#if (LINUX_VERSION_CODE >= 131343)
+ serial_driver.send_xchar = rs_send_xchar;
serial_driver.wait_until_sent = rs_wait_until_sent;
serial_driver.read_proc = rs_read_proc;
+#endif
/*
* The callout device is just like normal device except for
@@ -3186,8 +3948,10 @@ __initfunc(int rs_init(void))
callout_driver.name = "cua";
callout_driver.major = TTYAUX_MAJOR;
callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+#if (LINUX_VERSION_CODE >= 131343)
callout_driver.read_proc = 0;
callout_driver.proc_entry = 0;
+#endif
if (tty_register_driver(&serial_driver))
panic("Couldn't register serial driver\n");
@@ -3209,15 +3973,11 @@ __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))
+ if (state->port && check_region(state->port,8))
continue;
if (state->flags & ASYNC_BOOT_AUTOCONF)
autoconfig(state);
}
- /*
- * Detect the IRQ only once every port is initialised,
- * because some 16450 do not reset to 0 the MCR register.
- */
for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
if (state->type == PORT_UNKNOWN)
continue;
@@ -3226,11 +3986,14 @@ __initfunc(int rs_init(void))
&& (state->port != 0))
state->irq = detect_uart_irq(state);
printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n",
- state->line,
+ state->line + SERIAL_DEV_OFFSET,
(state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
state->port, state->irq,
uart_config[state->type].name);
}
+#ifdef ENABLE_SERIAL_PCI
+ probe_serial_pci();
+#endif
return 0;
}
@@ -3247,7 +4010,8 @@ int register_serial(struct serial_struct *req)
save_flags(flags);
cli();
for (i = 0; i < NR_PORTS; i++) {
- if (rs_table[i].port == req->port)
+ if ((rs_table[i].port == req->port) &&
+ (rs_table[i].iomem_base == req->iomem_base))
break;
}
if (i == NR_PORTS) {
@@ -3270,6 +4034,10 @@ int register_serial(struct serial_struct *req)
state->irq = req->irq;
state->port = req->port;
state->flags = req->flags;
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ state->iomem_base = req->iomem_base;
+ state->iomem_reg_shift = req->iomem_reg_shift;
+#endif
autoconfig(state);
if (state->type == PORT_UNKNOWN) {
@@ -3279,13 +4047,16 @@ int register_serial(struct serial_struct *req)
}
restore_flags(flags);
- if ((state->flags & ASYNC_AUTO_IRQ) && (state->port != 0))
+ if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
state->irq = detect_uart_irq(state);
- printk(KERN_INFO "tty%02d at 0x%04x (irq = %d) is a %s\n",
- state->line, state->port, state->irq,
- uart_config[state->type].name);
- return state->line;
+ printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
+ state->line + SERIAL_DEV_OFFSET,
+ state->iomem_base ? "iomem" : "port",
+ state->iomem_base ? (unsigned long)state->iomem_base :
+ (unsigned long)state->port,
+ state->irq, uart_config[state->type].name);
+ return state->line + SERIAL_DEV_OFFSET;
}
void unregister_serial(int line)
@@ -3313,6 +4084,7 @@ void cleanup_module(void)
unsigned long flags;
int e1, e2;
int i;
+ struct async_struct *info;
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
save_flags(flags);
@@ -3330,9 +4102,26 @@ void cleanup_module(void)
restore_flags(flags);
for (i = 0; i < NR_PORTS; i++) {
- if (rs_table[i].type != PORT_UNKNOWN)
+ if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port)
release_region(rs_table[i].port, 8);
+ info = rs_table[i].info;
+ if (info) {
+ rs_table[i].info = NULL;
+ kfree_s(info, sizeof(struct async_struct));
+ }
+#if defined(ENABLE_SERIAL_PCI) && defined (CONFIG_SERIAL_PCI_MEMMAPPED)
+ if (rs_table[i].iomem_base)
+ iounmap(rs_table[i].iomem_base);
+#endif
}
+#ifdef ENABLE_SERIAL_PCI
+ for (i=0; i < serial_pci_board_idx; i++) {
+ struct pci_board_inst *brd = &serial_pci_board[i];
+
+ if (brd->board->init_fn)
+ (brd->board->init_fn)(brd->dev, brd->board, 0);
+ }
+#endif
if (tmp_buf) {
free_page((unsigned long) tmp_buf);
tmp_buf = NULL;
@@ -3466,7 +4255,7 @@ static kdev_t serial_console_device(struct console *c)
* - initialize the serial port
* Return non-zero if we didn't find a serial port.
*/
-__initfunc(static int serial_console_setup(struct console *co, char *options))
+static int __init serial_console_setup(struct console *co, char *options)
{
struct serial_state *ser;
unsigned cval;
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 3851616ab..5142c8495 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -1500,7 +1500,7 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
| ((status & CyDCD) ? TIOCM_CAR : 0)
| ((status & CyDSR) ? TIOCM_DSR : 0)
| ((status & CyCTS) ? TIOCM_CTS : 0);
- cy_put_user(result,(unsigned long *) value);
+ cy_put_user(result,(unsigned int *) value);
return 0;
} /* get_modem_info */
@@ -2094,7 +2094,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
#endif
}
restore_flags(flags);
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp)
|| !(info->flags & ASYNC_INITIALIZED) ){
if (info->flags & ASYNC_HUP_NOTIFY) {
diff --git a/drivers/char/softdog.c b/drivers/char/softdog.c
index c8f21a184..92cc0ea3e 100644
--- a/drivers/char/softdog.c
+++ b/drivers/char/softdog.c
@@ -23,6 +23,9 @@
* Added soft_margin; use upon insmod to change the timer delay.
* NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
* minors.
+ *
+ * 19980911 Alan Cox
+ * Made SMP safe for 2.3.x
*/
#include <linux/module.h>
@@ -106,10 +109,8 @@ static void softdog_ping(void)
/*
* Refresh the timer.
*/
- del_timer(&watchdog_ticktock);
- watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
- add_timer(&watchdog_ticktock);
- return;
+
+ mod_timer(&watchdog_ticktock, jiffies + (soft_margin * HZ));
}
static ssize_t softdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
@@ -178,7 +179,7 @@ static struct miscdevice softdog_miscdev=
&softdog_fops
};
-__initfunc(void watchdog_init(void))
+void __init watchdog_init(void)
{
misc_register(&softdog_miscdev);
init_timer(&watchdog_ticktock);
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index c6fecb819..22014dacf 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -1398,7 +1398,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
}
}
sti();
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(port->flags & ASYNC_INITIALIZED)) {
if (port->flags & ASYNC_HUP_NOTIFY)
@@ -1755,7 +1755,7 @@ static int sx_get_modem_info(struct specialix_port * port, unsigned int *value)
|/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */
| ((status & MSVR_CTS) ? TIOCM_CTS : 0);
}
- put_user(result,(unsigned long *) value);
+ put_user(result,(unsigned int *) value);
return 0;
}
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 23b8df504..b25be2cd0 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -4,7 +4,7 @@
* stallion.c -- stallion multiport serial driver.
*
* Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au).
- * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer.
*
* This code is loosely based on the Linux serial driver, written by
* Linus Torvalds, Theodore T'so and others.
@@ -135,7 +135,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.5.1";
+static char *stl_drvversion = "5.6.0";
static char *stl_serialname = "ttyE";
static char *stl_calloutname = "cue";
@@ -2280,7 +2280,7 @@ static void stl_offintr(void *private)
* interrupt across multiple boards.
*/
-__initfunc(static int stl_mapirq(int irq, char *name))
+static int __init stl_mapirq(int irq, char *name)
{
int rc, i;
@@ -2294,7 +2294,7 @@ __initfunc(static int stl_mapirq(int irq, char *name))
break;
}
if (i >= stl_numintrs) {
- if (request_irq(irq, stl_intr, SA_INTERRUPT, name, NULL) != 0) {
+ if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) {
printk("STALLION: failed to register interrupt "
"routine for %s irq=%d\n", name, irq);
rc = -ENODEV;
@@ -2311,7 +2311,7 @@ __initfunc(static int stl_mapirq(int irq, char *name))
* Initialize all the ports on a panel.
*/
-__initfunc(static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp))
+static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
{
stlport_t *portp;
int chipmask, i;
@@ -2348,6 +2348,8 @@ __initfunc(static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp))
portp->callouttermios = stl_deftermios;
portp->tqueue.routine = stl_offintr;
portp->tqueue.data = portp;
+ init_waitqueue_head(&portp->open_wait);
+ init_waitqueue_head(&portp->close_wait);
portp->stats.brd = portp->brdnr;
portp->stats.panel = portp->panelnr;
portp->stats.port = portp->portnr;
@@ -2700,7 +2702,7 @@ static int inline stl_initech(stlbrd_t *brdp)
* since the initial search and setup is very different.
*/
-__initfunc(static int stl_brdinit(stlbrd_t *brdp))
+static int __init stl_brdinit(stlbrd_t *brdp)
{
int i;
@@ -2780,7 +2782,7 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
#if DEBUG
printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype,
- dev->bus->number, dev->devfn);
+ devp->bus->number, devp->devfn);
#endif
if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
@@ -2798,8 +2800,8 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
*/
#if DEBUG
printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
- devp->base_address[0], devp->base_address[1],
- devp->base_address[2], devp->base_address[3], devp->irq);
+ devp->resource[0].start, devp->resource[1].start,
+ devp->resource[2].start, devp->resource[3].start, devp->irq);
#endif
/*
@@ -2808,21 +2810,21 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
*/
switch (brdtype) {
case BRD_ECHPCI:
- brdp->ioaddr2 = (devp->base_address[0] &
+ brdp->ioaddr2 = (devp->resource[0].start &
PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr1 = (devp->base_address[1] &
+ brdp->ioaddr1 = (devp->resource[1].start &
PCI_BASE_ADDRESS_IO_MASK);
break;
case BRD_ECH64PCI:
- brdp->ioaddr2 = (devp->base_address[2] &
+ brdp->ioaddr2 = (devp->resource[2].start &
PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr1 = (devp->base_address[1] &
+ brdp->ioaddr1 = (devp->resource[1].start &
PCI_BASE_ADDRESS_IO_MASK);
break;
case BRD_EASYIOPCI:
- brdp->ioaddr1 = (devp->base_address[2] &
+ brdp->ioaddr1 = (devp->resource[2].start &
PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr2 = (devp->base_address[1] &
+ brdp->ioaddr2 = (devp->resource[1].start &
PCI_BASE_ADDRESS_IO_MASK);
break;
default:
@@ -3204,7 +3206,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
/*****************************************************************************/
-__initfunc(int stl_init(void))
+int __init stl_init(void)
{
printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
@@ -4209,6 +4211,7 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
if ((tty == (struct tty_struct *) NULL) ||
(tty->flip.char_buf_ptr == (char *) NULL) ||
((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+ len = MIN(len, sizeof(stl_unwanted));
outb((RDSR + portp->uartaddr), ioaddr);
insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
@@ -5175,6 +5178,7 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
if ((tty == (struct tty_struct *) NULL) ||
(tty->flip.char_buf_ptr == (char *) NULL) ||
((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+ len = MIN(len, sizeof(stl_unwanted));
outb(GRXFIFO, (ioaddr + XP_ADDR));
insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
new file mode 100644
index 000000000..7e5ff9465
--- /dev/null
+++ b/drivers/char/sx.c
@@ -0,0 +1,2684 @@
+
+/* sx.c -- driver for the Specialix SX series cards.
+ *
+ * This driver will also support the older SI, and XIO cards.
+ *
+ *
+ * (C) 1998 R.E.Wolff@BitWizard.nl
+ *
+ * Simon Allen (simonallen@cix.compulink.co.uk) wrote a previous
+ * version of this driver. Some fragments may have been copied. (none
+ * yet :-)
+ *
+ * Specialix pays for the development and support of this driver.
+ * Please DO contact support@specialix.co.uk if you require
+ * support. But please read the documentation (sx.txt) first.
+ *
+ *
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ * Revision history:
+ * $Log: sx.c,v $
+ * Revision 1.26 1999/08/05 15:22:14 wolff
+ * - Port to 2.3.x
+ * - Reformatted to Linus' liking.
+ *
+ * Revision 1.25 1999/07/30 14:24:08 wolff
+ * Had accidentally left "gs_debug" set to "-1" instead of "off" (=0).
+ *
+ * Revision 1.24 1999/07/28 09:41:52 wolff
+ * - I noticed the remark about use-count straying in sx.txt. I checked
+ * sx_open, and found a few places where that could happen. I hope it's
+ * fixed now.
+ *
+ * Revision 1.23 1999/07/28 08:56:06 wolff
+ * - Fixed crash when sx_firmware run twice.
+ * - Added sx_slowpoll as a module parameter (I guess nobody really wanted
+ * to change it from the default... )
+ * - Fixed a stupid editing problem I introduced in 1.22.
+ * - Fixed dropping characters on a termios change.
+ *
+ * Revision 1.22 1999/07/26 21:01:43 wolff
+ * Russell Brown noticed that I had overlooked 4 out of six modem control
+ * signals in sx_getsignals. Ooops.
+ *
+ * Revision 1.21 1999/07/23 09:11:33 wolff
+ * I forgot to free dynamically allocated memory when the driver is unloaded.
+ *
+ * Revision 1.20 1999/07/20 06:25:26 wolff
+ * The "closing wait" wasn't honoured. Thanks to James Griffiths for
+ * reporting this.
+ *
+ * Revision 1.19 1999/07/11 08:59:59 wolff
+ * Fixed an oops in close, when an open was pending. Changed the memtest
+ * a bit. Should also test the board in word-mode, however my card fails the
+ * memtest then. I still have to figure out what is wrong...
+ *
+ * Revision 1.18 1999/06/10 09:38:42 wolff
+ * Changed the format of the firmware revision from %04x to %x.%02x .
+ *
+ * Revision 1.17 1999/06/04 09:44:35 wolff
+ * fixed problem: reference to pci stuff when config_pci was off...
+ * Thanks to Jorge Novo for noticing this.
+ *
+ * Revision 1.16 1999/06/02 08:30:15 wolff
+ * added/removed the workaround for the DCD bug in the Firmware.
+ * A bit more debugging code to locate that...
+ *
+ * Revision 1.15 1999/06/01 11:35:30 wolff
+ * when DCD is left low (floating?), on TA's the firmware first tells us
+ * that DCD is high, but after a short while suddenly comes to the
+ * conclusion that it is low. All this would be fine, if it weren't that
+ * Unix requires us to send a "hangup" signal in that case. This usually
+ * all happens BEFORE the program has had a chance to ioctl the device
+ * into clocal mode..
+ *
+ * Revision 1.14 1999/05/25 11:18:59 wolff
+ * Added PCI-fix.
+ * Added checks for return code of sx_sendcommand.
+ * Don't issue "reconfig" if port isn't open yet. (bit us on TA modules...)
+ *
+ * Revision 1.13 1999/04/29 15:18:01 wolff
+ * Fixed an "oops" that showed on SuSE 6.0 systems.
+ * Activate DTR again after stty 0.
+ *
+ * Revision 1.12 1999/04/29 07:49:52 wolff
+ * Improved "stty 0" handling a bit. (used to change baud to 9600 assuming
+ * the connection would be dropped anyway. That is not always the case,
+ * and confuses people).
+ * Told the card to always monitor the modem signals.
+ * Added support for dynamic gs_debug adjustments.
+ * Now tells the rest of the system the number of ports.
+ *
+ * Revision 1.11 1999/04/24 11:11:30 wolff
+ * Fixed two stupid typos in the memory test.
+ *
+ * Revision 1.10 1999/04/24 10:53:39 wolff
+ * Added some of Christian's suggestions.
+ * Fixed an HW_COOK_IN bug (ISIG was not in I_OTHER. We used to trust the
+ * card to send the signal to the process.....)
+ *
+ * Revision 1.9 1999/04/23 07:26:38 wolff
+ * Included Christian Lademann's 2.0 compile-warning fixes and interrupt
+ * assignment redesign.
+ * Cleanup of some other stuff.
+ *
+ * Revision 1.8 1999/04/16 13:05:30 wolff
+ * fixed a DCD change unnoticed bug.
+ *
+ * Revision 1.7 1999/04/14 22:19:51 wolff
+ * Fixed typo that showed up in 2.0.x builds (get_user instead of Get_user!)
+ *
+ * Revision 1.6 1999/04/13 18:40:20 wolff
+ * changed misc-minor to 161, as assigned by HPA.
+ *
+ * Revision 1.5 1999/04/13 15:12:25 wolff
+ * Fixed use-count leak when "hangup" occurred.
+ * Added workaround for a stupid-PCIBIOS bug.
+ *
+ *
+ * Revision 1.4 1999/04/01 22:47:40 wolff
+ * Fixed < 1M linux-2.0 problem.
+ * (vremap isn't compatible with ioremap in that case)
+ *
+ * Revision 1.3 1999/03/31 13:45:45 wolff
+ * Firmware loading is now done through a separate IOCTL.
+ *
+ * Revision 1.2 1999/03/28 12:22:29 wolff
+ * rcs cleanup
+ *
+ * Revision 1.1 1999/03/28 12:10:34 wolff
+ * Readying for release on 2.0.x (sorry David, 1.01 becomes 1.1 for RCS).
+ *
+ * Revision 0.12 1999/03/28 09:20:10 wolff
+ * Fixed problem in 0.11, continueing cleanup.
+ *
+ * Revision 0.11 1999/03/28 08:46:44 wolff
+ * cleanup. Not good.
+ *
+ * Revision 0.10 1999/03/28 08:09:43 wolff
+ * Fixed loosing characters on close.
+ *
+ * Revision 0.9 1999/03/21 22:52:01 wolff
+ * Ported back to 2.2.... (minor things)
+ *
+ * Revision 0.8 1999/03/21 22:40:33 wolff
+ * Port to 2.0
+ *
+ * Revision 0.7 1999/03/21 19:06:34 wolff
+ * Fixed hangup processing.
+ *
+ * Revision 0.6 1999/02/05 08:45:14 wolff
+ * fixed real_raw problems. Inclusion into kernel imminent.
+ *
+ * Revision 0.5 1998/12/21 23:51:06 wolff
+ * Snatched a nasty bug: sx_transmit_chars was getting re-entered, and it
+ * shouldn't have. THATs why I want to have transmit interrupts even when
+ * the buffer is empty.
+ *
+ * Revision 0.4 1998/12/17 09:34:46 wolff
+ * PPP works. ioctl works. Basically works!
+ *
+ * Revision 0.3 1998/12/15 13:05:18 wolff
+ * It works! Wow! Gotta start implementing IOCTL and stuff....
+ *
+ * Revision 0.2 1998/12/01 08:33:53 wolff
+ * moved over to 2.1.130
+ *
+ * Revision 0.1 1998/11/03 21:23:51 wolff
+ * Initial revision. Detects SX card.
+ *
+ * */
+
+
+#define RCS_ID "$Id: sx.c,v 1.26 1999/08/05 15:22:14 wolff Exp $"
+#define RCS_REV "$Revision: 1.26 $"
+
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/miscdevice.h>
+
+/* The 3.0.0 version of sxboards/sxwindow.h uses BYTE and WORD.... */
+#define BYTE u8
+#define WORD u16
+
+/* .... but the 3.0.4 version uses _u8 and _u16. */
+#define _u8 u8
+#define _u16 u16
+
+#include "sxboards.h"
+#include "sxwindow.h"
+
+
+/* I don't think that this driver can handle more than 256 ports on
+ one machine. You'll have to increase the number of boards in sx.h
+ if you want more than 4 boards. */
+
+
+/* ************************************************************** */
+/* * This section can be removed when 2.0 becomes outdated.... * */
+/* ************************************************************** */
+
+
+#if LINUX_VERSION_CODE < 0x020100 /* Less than 2.1.0 */
+#define TWO_ZERO
+#else
+#if LINUX_VERSION_CODE < 0x020200 /* less than 2.2.x */
+#warning "Please use a 2.2.x kernel. "
+#else
+#if LINUX_VERSION_CODE < 0x020300 /* less than 2.3.x */
+#define TWO_TWO
+#else
+#define TWO_THREE
+#endif
+#endif
+#endif
+
+#ifdef TWO_ZERO
+
+/* Here is the section that makes the 2.2 compatible driver source
+ work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2,
+ and provide for compatibility stuff here if possible. */
+
+#include <linux/bios32.h>
+
+#define Get_user(a,b) a = get_user(b)
+#define Put_user(a,b) 0,put_user(a,b)
+#define copy_to_user(a,b,c) memcpy_tofs(a,b,c)
+
+static inline int copy_from_user(void *to,const void *from, int c)
+{
+ memcpy_fromfs(to, from, c);
+ return 0;
+}
+
+#define pci_present pcibios_present
+#define pci_read_config_word pcibios_read_config_word
+#define pci_read_config_dword pcibios_read_config_dword
+
+static inline unsigned char get_irq (unsigned char bus, unsigned char fn)
+{
+ unsigned char t;
+ pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &t);
+ return t;
+}
+
+static inline void *ioremap(unsigned long base, long length)
+{
+ if (base < 0x100000) return (void *)base;
+ return vremap (base, length);
+}
+
+#define my_iounmap(x, b) (((long)x<0x100000)?0:vfree ((void*)x))
+
+#define capable(x) suser()
+
+#define queue_task queue_task_irq_off
+#define tty_flip_buffer_push(tty) queue_task(&tty->flip.tqueue, &tq_timer)
+#define signal_pending(current) (current->signal & ~current->blocked)
+#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0)
+#define time_after(t1,t2) (((long)t1-t2) > 0)
+
+
+#define test_and_set_bit(nr, addr) set_bit(nr, addr)
+#define test_and_clear_bit(nr, addr) clear_bit(nr, addr)
+
+/* Not yet implemented on 2.0 */
+#define ASYNC_SPD_SHI -1
+#define ASYNC_SPD_WARP -1
+
+
+/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it
+ to the "name" field that does exist. As long as the assignments are
+ done in the right order, there is nothing to worry about. */
+#define driver_name name
+
+/* Should be in a header somewhere. They are in tty.h on 2.2 */
+#define TTY_HW_COOK_OUT 14 /* Flag to tell ntty what we can handle */
+#define TTY_HW_COOK_IN 15 /* in hardware - output and input */
+
+/* The return type of a "close" routine. */
+#define INT void
+#define NO_ERROR /* Nothing */
+
+#else
+
+/* The 2.2.x compatibility section. */
+#include <asm/uaccess.h>
+
+
+#define Get_user(a,b) get_user(a,b)
+#define Put_user(a,b) put_user(a,b)
+#define get_irq(pdev) pdev->irq
+
+#define INT int
+#define NO_ERROR 0
+
+#define my_iounmap(x,b) (iounmap((char *)(b)))
+
+#endif
+
+#ifndef TWO_THREE
+/* These are new in 2.3. The source now uses 2.3 syntax, and here is
+ the compatibility define... */
+#define wait_queue_head_t struct wait_queue *
+#define DECLARE_MUTEX(name) struct semaphore name = MUTEX
+#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL }
+
+#endif
+
+
+
+#include "generic_serial.h"
+#include "sx.h"
+
+
+/* ************************************************************** */
+/* * End of compatibility section.. * */
+/* ************************************************************** */
+
+
+
+/* Why the hell am I defining these here? */
+#define SX_TYPE_NORMAL 1
+#define SX_TYPE_CALLOUT 2
+
+#ifndef SX_NORMAL_MAJOR
+/* This allows overriding on the compiler commandline, or in a "major.h"
+ include or something like that */
+#define SX_NORMAL_MAJOR 32
+#define SX_CALLOUT_MAJOR 33
+#endif
+
+#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
+#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
+#endif
+
+
+
+/* Configurable options:
+ (Don't be too sure that it'll work if you toggle them) */
+
+/* Am I paranoid or not ? ;-) */
+#undef SX_PARANOIA_CHECK
+
+
+/* 20 -> 2000 per second. The card should rate-limit interrupts at 100
+ Hz, but it is user configurable. I don't recommend going above 1000
+ Hz. The interrupt ratelimit might trigger if the interrupt is
+ shared with a very active other device. */
+#define IRQ_RATE_LIMIT 20
+
+/* Sharing interrupts is possible now. If the other device wants more
+ than 2000 interrupts per second, we'd gracefully decline further
+ interrupts. That's not what we want. On the other hand, if the
+ other device interrupts 2000 times a second, don't use the SX
+ interrupt. Use polling. */
+#undef IRQ_RATE_LIMIT
+
+
+#if 0
+/* Not implemented */
+/*
+ * The following defines are mostly for testing purposes. But if you need
+ * some nice reporting in your syslog, you can define them also.
+ */
+#define SX_REPORT_FIFO
+#define SX_REPORT_OVERRUN
+#endif
+
+
+/* Function prototypes */
+static void sx_disable_tx_interrupts (void * ptr);
+static void sx_enable_tx_interrupts (void * ptr);
+static void sx_disable_rx_interrupts (void * ptr);
+static void sx_enable_rx_interrupts (void * ptr);
+static int sx_get_CD (void * ptr);
+static void sx_shutdown_port (void * ptr);
+static void sx_set_real_termios (void *ptr);
+static void sx_hungup (void *ptr);
+static void sx_close (void *ptr);
+static int sx_chars_in_buffer (void * ptr);
+static int sx_init_board (struct sx_board *board);
+static int sx_init_portstructs (int nboards, int nports);
+static int sx_fw_ioctl (struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+static int sx_fw_open(struct inode *inode, struct file *filp);
+static INT sx_fw_release(struct inode *inode, struct file *filp);
+static int sx_init_drivers(void);
+void my_hd (unsigned char *addr, int len);
+
+
+
+static struct tty_driver sx_driver, sx_callout_driver;
+
+static struct tty_struct * sx_table[SX_NPORTS] = { NULL, };
+static struct termios ** sx_termios;
+static struct termios ** sx_termios_locked;
+
+struct sx_board boards[SX_NBOARDS];
+struct sx_port *sx_ports;
+int sx_refcount;
+int sx_initialized = 0;
+int sx_nports = 0;
+int sx_debug = 0;
+
+
+/* You can have the driver poll your card.
+ - Set sx_poll to 1 to poll every timer tick (10ms on Intel).
+ This is used when the card cannot use an interrupt for some reason.
+
+ - set sx_slowpoll to 100 to do an extra poll once a second (on Intel). If
+ the driver misses an interrupt (report this if it DOES happen to you!)
+ everything will continue to work....
+ */
+int sx_poll = 1;
+int sx_slowpoll = 0;
+
+/* The card limits the number of interrupts per second.
+ At 115k2 "100" should be sufficient.
+ If you're using higher baudrates, you can increase this...
+ */
+
+int sx_maxints = 100;
+
+/* These are the only open spaces in my computer. Yours may have more
+ or less.... */
+int sx_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
+ 0xc8000, 0xd8000, 0xe8000};
+int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
+ 0xc8000, 0xd8000, 0xe8000};
+
+#define NR_SX_ADDRS (sizeof(sx_probe_addrs)/sizeof (int))
+#define NR_SI_ADDRS (sizeof(si_probe_addrs)/sizeof (int))
+
+
+/* Set the mask to all-ones. This alas, only supports 32 interrupts.
+ Some architectures may need more. */
+int sx_irqmask = -1;
+
+#ifndef TWO_ZERO
+#ifdef MODULE
+MODULE_PARM(sx_poll, "i");
+MODULE_PARM(sx_slowpoll, "i");
+MODULE_PARM(sx_maxints, "i");
+MODULE_PARM(sx_debug, "i");
+MODULE_PARM(sx_irqmask, "i");
+#endif
+#endif
+
+static struct real_driver sx_real_driver = {
+ sx_disable_tx_interrupts,
+ sx_enable_tx_interrupts,
+ sx_disable_rx_interrupts,
+ sx_enable_rx_interrupts,
+ sx_get_CD,
+ sx_shutdown_port,
+ sx_set_real_termios,
+ sx_chars_in_buffer,
+ sx_close,
+ sx_hungup,
+ NULL
+};
+
+
+/*
+ This driver can spew a whole lot of debugging output at you. If you
+ need maximum performance, you should disable the DEBUG define. To
+ aid in debugging in the field, I'm leaving the compile-time debug
+ features enabled, and disable them "runtime". That allows me to
+ instruct people with problems to enable debugging without requiring
+ them to recompile...
+*/
+#define DEBUG
+
+
+#ifdef DEBUG
+#define sx_dprintk(f, str...) if (sx_debug & f) printk (str)
+#else
+#define sx_dprintk(f, str...) /* nothing */
+#endif
+
+
+
+#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ "\n")
+#define func_exit() sx_dprintk (SX_DEBUG_FLOW, "sx: exit " __FUNCTION__ "\n")
+
+#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ \
+ "(port %d)\n", port->line)
+
+
+
+
+/*
+ * Firmware loader driver specific routines
+ *
+ */
+
+static struct file_operations sx_fw_fops = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* select */
+ sx_fw_ioctl,
+ NULL, /* mmap */
+ sx_fw_open,
+#ifndef TWO_ZERO
+ NULL, /* flush */
+#endif
+ sx_fw_release,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+};
+
+struct miscdevice sx_fw_device = {
+ SXCTL_MISC_MINOR, "sxctl", &sx_fw_fops
+};
+
+
+
+
+
+#ifdef SX_PARANOIA_CHECK
+
+/* This doesn't work. Who's paranoid around here? Not me! */
+
+static inline int sx_paranoia_check(struct sx_port const * port,
+ kdev_t device, const char *routine)
+{
+
+ static const char *badmagic =
+ KERN_ERR "sx: Warning: bad sx port magic number for device %s in %s\n";
+ static const char *badinfo =
+ KERN_ERR "sx: Warning: null sx port for device %s in %s\n";
+
+ if (!port) {
+ printk(badinfo, kdevname(device), routine);
+ return 1;
+ }
+ if (port->magic != SX_MAGIC) {
+ printk(badmagic, kdevname(device), routine);
+ return 1;
+ }
+
+ return 0;
+}
+#else
+#define sx_paranoia_check(a,b,c) 0
+#endif
+
+/* The timeouts. First try 30 times as fast as possible. Then give
+ the card some time to breathe between accesses. (Otherwise the
+ processor on the card might not be able to access its OWN bus... */
+
+#define TIMEOUT_1 30
+#define TIMEOUT_2 1000000
+
+
+/* This needs redoing for Alpha -- REW -- Done. */
+
+inline void write_sx_byte (struct sx_board *board, int offset, u8 byte)
+{
+ writeb (byte, board->base+offset);
+}
+
+inline u8 read_sx_byte (struct sx_board *board, int offset)
+{
+ return readb (board->base+offset);
+}
+
+
+inline void write_sx_word (struct sx_board *board, int offset, u16 word)
+{
+ writew (word, board->base+offset);
+}
+
+inline u16 read_sx_word (struct sx_board *board, int offset)
+{
+ return readw (board->base + offset);
+}
+
+
+int sx_busy_wait_eq (struct sx_board *board,
+ int offset,
+ int mask,
+ int correctval)
+{
+ int i;
+
+ func_enter ();
+
+ for (i=0; i < TIMEOUT_1 > 0;i++)
+ if ((read_sx_byte (board, offset) & mask) == correctval) {
+ func_exit ();
+ return 1;
+ }
+
+ for (i=0; i < TIMEOUT_2 > 0;i++) {
+ if ((read_sx_byte (board, offset) & mask) == correctval) {
+ func_exit ();
+ return 1;
+ }
+ udelay (1);
+ }
+
+ func_exit ();
+ return 0;
+}
+
+
+int sx_busy_wait_neq (struct sx_board *board,
+ int offset,
+ int mask,
+ int badval)
+{
+ int i;
+
+ func_enter ();
+
+ for (i=0; i < TIMEOUT_1 > 0;i++)
+ if ((read_sx_byte (board, offset) & mask) != badval) {
+ func_exit ();
+ return 1;
+ }
+
+ for (i=0; i < TIMEOUT_2 > 0;i++) {
+ if ((read_sx_byte (board, offset) & mask) != badval) {
+ func_exit ();
+ return 1;
+ }
+ udelay (1);
+ }
+
+ func_exit ();
+ return 0;
+}
+
+
+
+/* 5.6.4 of 6210028 r2.3 */
+int sx_reset (struct sx_board *board)
+{
+ func_enter ();
+
+ if (IS_SX_BOARD (board)) {
+
+ write_sx_byte (board, SX_CONFIG, 0);
+ write_sx_byte (board, SX_RESET, 1); /* Value doesn't matter */
+
+ if (!sx_busy_wait_eq (board, SX_RESET_STATUS, 1, 0)) {
+ printk (KERN_INFO "sx: Card doesn't respond to reset....\n");
+ return 0;
+ }
+ } else {
+ /* Gory details of the SI/ISA board */
+ write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_SET);
+ write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_CLEAR);
+ write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_CLEAR);
+ write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_CLEAR);
+ write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
+ write_sx_byte (board, SI2_ISA_IRQSET, SI2_ISA_IRQSET_CLEAR);
+ }
+
+ func_exit ();
+ return 1;
+}
+
+
+/* This doesn't work on machines where "NULL" isn't 0 */
+/* If you have one of those, someone will need to write
+ the equivalent of this, which will amount to about 3 lines. I don't
+ want to complicate this right now. -- REW
+ (See, I do write comments every now and then :-) */
+#define OFFSETOF(strct, elem) ((long)&(((struct strct *)NULL)->elem))
+
+
+#define CHAN_OFFSET(port,elem) (port->ch_base + OFFSETOF (_SXCHANNEL, elem))
+#define MODU_OFFSET(board,addr,elem) (addr + OFFSETOF (_SXMODULE, elem))
+#define BRD_OFFSET(board,elem) (OFFSETOF (_SXCARD, elem))
+
+
+#define sx_write_channel_byte(port, elem, val) \
+ write_sx_byte (port->board, CHAN_OFFSET (port, elem), val)
+
+#define sx_read_channel_byte(port, elem) \
+ read_sx_byte (port->board, CHAN_OFFSET (port, elem))
+
+#define sx_write_channel_word(port, elem, val) \
+ write_sx_word (port->board, CHAN_OFFSET (port, elem), val)
+
+#define sx_read_channel_word(port, elem) \
+ read_sx_word (port->board, CHAN_OFFSET (port, elem))
+
+
+#define sx_write_module_byte(board, addr, elem, val) \
+ write_sx_byte (board, MODU_OFFSET (board, addr, elem), val)
+
+#define sx_read_module_byte(board, addr, elem) \
+ read_sx_byte (board, MODU_OFFSET (board, addr, elem))
+
+#define sx_write_module_word(board, addr, elem, val) \
+ write_sx_word (board, MODU_OFFSET (board, addr, elem), val)
+
+#define sx_read_module_word(board, addr, elem) \
+ read_sx_word (board, MODU_OFFSET (board, addr, elem))
+
+
+#define sx_write_board_byte(board, elem, val) \
+ write_sx_byte (board, BRD_OFFSET (board, elem), val)
+
+#define sx_read_board_byte(board, elem) \
+ read_sx_byte (board, BRD_OFFSET (board, elem))
+
+#define sx_write_board_word(board, elem, val) \
+ write_sx_word (board, BRD_OFFSET (board, elem), val)
+
+#define sx_read_board_word(board, elem) \
+ read_sx_word (board, BRD_OFFSET (board, elem))
+
+
+int sx_start_board (struct sx_board *board)
+{
+ if (IS_SX_BOARD (board)) {
+ write_sx_byte (board, SX_CONFIG, SX_CONF_BUSEN);
+ } else {
+ /* Don't bug me about the clear_set.
+ I haven't the foggiest idea what it's about -- REW*/
+ write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_CLEAR);
+ write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+ }
+ return 1;
+}
+
+#define SX_IRQ_REG_VAL(board) \
+ ((board->flags & SX_ISA_BOARD)?(board->irq << 4):0)
+
+/* Note. The SX register is write-only. Therefore, we have to enable the
+ bus too. This is a no-op, if you don't mess with this driver... */
+int sx_start_interrupts (struct sx_board *board)
+{
+
+ /* Don't call this with board->irq == 0 */
+
+ if (IS_SX_BOARD(board)) {
+ write_sx_byte (board, SX_CONFIG, SX_IRQ_REG_VAL (board) |
+ SX_CONF_BUSEN |
+ SX_CONF_HOSTIRQ);
+ } else {
+ switch (board->irq) {
+ case 11:write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);break;
+ case 12:write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);break;
+ case 15:write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);break;
+ default:printk (KERN_INFO "sx: SI/XIO card doesn't support interrupt %d.\n",
+ board->irq);
+ return 0;
+ }
+ write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+ }
+
+ return 1;
+}
+
+
+int sx_send_command (struct sx_port *port,
+ int command,
+ int mask,
+ int newstat)
+{
+ func_enter2 ();
+ write_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat), command);
+ func_exit ();
+ return sx_busy_wait_eq (port->board, CHAN_OFFSET (port, hi_hstat), mask, newstat);
+}
+
+
+char *mod_type_s (int module_type)
+{
+ switch (module_type) {
+ case TA4: return "TA4";
+ case TA8: return "TA8";
+ case TA4_ASIC: return "TA4_ASIC";
+ case TA8_ASIC: return "TA8_ASIC";
+ case MTA_CD1400:return "MTA_CD1400";
+ case SXDC: return "SXDC";
+ default:return "Unknown/invalid";
+ }
+}
+
+
+char *pan_type_s (int pan_type)
+{
+ switch (pan_type) {
+ case MOD_RS232DB25: return "MOD_RS232DB25";
+ case MOD_RS232RJ45: return "MOD_RS232RJ45";
+ case MOD_RS422DB25: return "MOD_RS422DB25";
+ case MOD_PARALLEL: return "MOD_PARALLEL";
+ case MOD_2_RS232DB25: return "MOD_2_RS232DB25";
+ case MOD_2_RS232RJ45: return "MOD_2_RS232RJ45";
+ case MOD_2_RS422DB25: return "MOD_2_RS422DB25";
+ case MOD_RS232DB25MALE: return "MOD_RS232DB25MALE";
+ case MOD_2_PARALLEL: return "MOD_2_PARALLEL";
+ case MOD_BLANK: return "empty";
+ default:return "invalid";
+ }
+}
+
+
+int mod_compat_type (int module_type)
+{
+ return module_type >> 4;
+}
+
+
+static void sx_setsignals (struct sx_port *port, int dtr, int rts)
+{
+ int t;
+ func_enter2 ();
+
+ t = sx_read_channel_byte (port, hi_op);
+ if (dtr >= 0) t = dtr? (t | OP_DTR): (t & ~OP_DTR);
+ if (rts >= 0) t = rts? (t | OP_RTS): (t & ~OP_RTS);
+ sx_write_channel_byte (port, hi_op, t);
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts);
+ func_exit ();
+}
+
+
+
+static int sx_getsignals (struct sx_port *port)
+{
+ int i_stat,o_stat;
+
+ o_stat = sx_read_channel_byte (port, hi_op);
+ i_stat = sx_read_channel_byte (port, hi_ip);
+
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) %02x/%02x\n",
+ (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0,
+ port->c_dcd, sx_get_CD (port),
+ sx_read_channel_byte (port, hi_ip),
+ sx_read_channel_byte (port, hi_state));
+
+ return (((o_stat & OP_DTR)?TIOCM_DTR:0) |
+ ((o_stat & OP_RTS)?TIOCM_RTS:0) |
+ ((i_stat & IP_CTS)?TIOCM_CTS:0) |
+ ((i_stat & IP_DCD)?TIOCM_CAR:0) |
+ ((i_stat & IP_DSR)?TIOCM_DSR:0) |
+ ((i_stat & IP_RI)?TIOCM_RNG:0)
+ );
+}
+
+
+static void sx_set_baud (struct sx_port *port)
+{
+ int t;
+
+ if (port->board->ta_type == MOD_SXDC) {
+ switch (port->gs.baud) {
+ /* Save some typing work... */
+#define e(x) case x:t= BAUD_ ## x ; break
+ e(50);e(75);e(110);e(150);e(200);e(300);e(600);
+ e(1200);e(1800);e(2000);e(2400);e(4800);e(7200);
+ e(9600);e(14400);e(19200);e(28800);e(38400);
+ e(56000);e(57600);e(64000);e(76800);e(115200);
+ e(128000);e(150000);e(230400);e(256000);e(460800);
+ e(921600);
+ case 134 :t = BAUD_134_5; break;
+ case 0 :t = -1;
+ break;
+ default:
+ /* Can I return "invalid"? */
+ t = BAUD_9600;
+ printk (KERN_INFO "sx: unsupported baud rate: %d.\n", port->gs.baud);
+ break;
+ }
+#undef e
+ if (t > 0) {
+ /* The baud rate is not set to 0, so we're enabeling DTR... -- REW */
+ sx_setsignals (port, 1, -1);
+ /* XXX This is not TA & MTA compatible */
+ sx_write_channel_byte (port, hi_csr, 0xff);
+
+ sx_write_channel_byte (port, hi_txbaud, t);
+ sx_write_channel_byte (port, hi_rxbaud, t);
+ } else {
+ sx_setsignals (port, 0, -1);
+ }
+ } else {
+ switch (port->gs.baud) {
+#define e(x) case x:t= CSR_ ## x ; break
+ e(75);e(150);e(300);e(600);e(1200);e(2400);e(4800);
+ e(1800);e(9600);
+ e(19200);e(57600);e(38400);
+ /* TA supports 110, but not 115200, MTA supports 115200, but not 110 */
+ case 110:
+ if (port->board->ta_type == MOD_TA) {
+ t = CSR_110;
+ break;
+ } else {
+ t = CSR_9600;
+ printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+ break;
+ }
+ case 115200:
+ if (port->board->ta_type == MOD_TA) {
+ t = CSR_9600;
+ printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+ break;
+ } else {
+ t = CSR_110;
+ break;
+ }
+ case 0 :t = -1;
+ break;
+ default:
+ t = CSR_9600;
+ printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+ break;
+ }
+#undef e
+ if (t >= 0) {
+ sx_setsignals (port, 1, -1);
+ sx_write_channel_byte (port, hi_csr, t * 0x11);
+ } else {
+ sx_setsignals (port, 0, -1);
+ }
+ }
+}
+
+
+/* Simon Allen's version of this routine was 225 lines long. 85 is a lot
+ better. -- REW */
+
+static void sx_set_real_termios (void *ptr)
+{
+ struct sx_port *port = ptr;
+
+ func_enter2();
+
+ /* What is this doing here? -- REW
+ Ha! figured it out. It is to allow you to get DTR active again
+ if you've dropped it with stty 0. Moved to set_baud, where it
+ belongs (next to the drop dtr if baud == 0) -- REW */
+ /* sx_setsignals (port, 1, -1); */
+
+ sx_set_baud (port);
+
+#define CFLAG port->gs.tty->termios->c_cflag
+ sx_write_channel_byte (port, hi_mr1,
+ (C_PARENB (port->gs.tty)? MR1_WITH:MR1_NONE) |
+ (C_PARODD (port->gs.tty)? MR1_ODD:MR1_EVEN) |
+ (C_CRTSCTS(port->gs.tty)? MR1_RTS_RXFLOW:0) |
+ (((CFLAG & CSIZE)==CS8) ? MR1_8_BITS:0) |
+ (((CFLAG & CSIZE)==CS7) ? MR1_7_BITS:0) |
+ (((CFLAG & CSIZE)==CS6) ? MR1_6_BITS:0) |
+ (((CFLAG & CSIZE)==CS5) ? MR1_5_BITS:0) );
+
+ sx_write_channel_byte (port, hi_mr2,
+ (C_CRTSCTS(port->gs.tty)?MR2_CTS_TXFLOW:0) |
+ (C_CSTOPB (port->gs.tty)?MR2_2_STOP:MR2_1_STOP));
+
+ switch (CFLAG & CSIZE) {
+ case CS8:sx_write_channel_byte (port, hi_mask, 0xff);break;
+ case CS7:sx_write_channel_byte (port, hi_mask, 0x7f);break;
+ case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break;
+ case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break;
+ default:
+ printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE);
+ break;
+ }
+
+ sx_write_channel_byte (port, hi_prtcl,
+ (I_IXON (port->gs.tty)?SP_TXEN:0) |
+ (I_IXOFF (port->gs.tty)?SP_RXEN:0) |
+ (I_IXANY (port->gs.tty)?SP_TANY:0) |
+ SP_DCEN);
+
+ sx_write_channel_byte (port, hi_break,
+ I_OTHER(port->gs.tty) ? 0:
+ (I_IGNBRK(port->gs.tty)?BR_IGN:0 |
+ I_BRKINT(port->gs.tty)?BR_INT:0));
+
+ sx_write_channel_byte (port, hi_txon, START_CHAR (port->gs.tty));
+ sx_write_channel_byte (port, hi_rxon, START_CHAR (port->gs.tty));
+ sx_write_channel_byte (port, hi_txoff, STOP_CHAR (port->gs.tty));
+ sx_write_channel_byte (port, hi_rxoff, STOP_CHAR (port->gs.tty));
+
+ if (sx_read_channel_byte (port, hi_hstat) == HS_IDLE_OPEN) {
+ if (sx_send_command (port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) {
+ printk (KERN_WARNING "sx: Sent reconfigure command, but card didn't react.\n");
+ }
+ } else {
+ sx_dprintk (SX_DEBUG_TERMIOS,
+ "sx: Not sending reconfigure: port isn't open (%02x).\n",
+ sx_read_channel_byte (port, hi_hstat));
+ }
+
+
+ /* Tell line discipline whether we will do input cooking */
+ if(I_OTHER(port->gs.tty)) {
+ clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
+ } else {
+ set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
+ }
+ sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
+ port->gs.tty->termios->c_iflag,
+ I_OTHER(port->gs.tty));
+
+
+/* Tell line discipline whether we will do output cooking.
+ * If OPOST is set and no other output flags are set then we can do output
+ * processing. Even if only *one* other flag in the O_OTHER group is set
+ * we do cooking in software.
+ */
+ if(O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) {
+ set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
+ } else {
+ clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
+ }
+ sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
+ port->gs.tty->termios->c_oflag,
+ O_OTHER(port->gs.tty));
+ /* port->c_dcd = sx_get_CD (port); */
+ func_exit ();
+}
+
+
+
+/* ********************************************************************** *
+ * the interrupt related routines *
+ * ********************************************************************** */
+
+/* Note:
+ Other drivers use the macro "MIN" to calculate how much to copy.
+ This has the disadvantage that it will evaluate parts twice. That's
+ expensive when it's IO (and the compiler cannot optimize those away!).
+ Moreover, I'm not sure that you're race-free.
+
+ I assign a value, and then only allow the value to decrease. This
+ is always safe. This makes the code a few lines longer, and you
+ know I'm dead against that, but I think it is required in this
+ case. */
+
+
+void sx_transmit_chars (struct sx_port *port)
+{
+ int c;
+ int tx_ip;
+ int txroom;
+
+ func_enter2 ();
+ sx_dprintk (SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n",
+ port, port->gs.xmit_cnt);
+
+ if (test_and_set_bit (SX_PORT_TRANSMIT_LOCK, &port->locks)) {
+ return;
+ }
+
+ while (1) {
+ c = port->gs.xmit_cnt;
+
+ sx_dprintk (SX_DEBUG_TRANSMIT, "Copying %d ", c);
+ tx_ip = sx_read_channel_byte (port, hi_txipos);
+
+ /* Took me 5 minutes to deduce this formula.
+ Luckily it is literally in the manual in section 6.5.4.3.5 */
+ txroom = (sx_read_channel_byte (port, hi_txopos) - tx_ip - 1) & 0xff;
+
+ /* Don't copy more bytes than there is room for in the buffer */
+ if (c > txroom)
+ c = txroom;
+ sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom );
+
+ /* Don't copy past the end of the hardware transmit buffer */
+ if (c > 0x100 - tx_ip)
+ c = 0x100 - tx_ip;
+
+ sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100-tx_ip );
+
+ /* Don't copy pas the end of the source buffer */
+ if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail)
+ c = SERIAL_XMIT_SIZE - port->gs.xmit_tail;
+
+ sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) \n",
+ c, SERIAL_XMIT_SIZE- port->gs.xmit_tail);
+
+ /* If for one reason or another, we can't copy more data, we're done! */
+ if (c == 0) break;
+
+
+ memcpy_toio (port->board->base + CHAN_OFFSET(port,hi_txbuf) + tx_ip,
+ port->gs.xmit_buf + port->gs.xmit_tail, c);
+
+ /* Update the pointer in the card */
+ sx_write_channel_byte (port, hi_txipos, (tx_ip+c) & 0xff);
+
+ /* Update the kernel buffer end */
+ port->gs.xmit_tail = (port->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1);
+
+ /* This one last. (this is essential)
+ It would allow others to start putting more data into the buffer! */
+ port->gs.xmit_cnt -= c;
+ }
+
+ if (port->gs.xmit_cnt == 0) {
+ sx_disable_tx_interrupts (port);
+ }
+
+ if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {
+ if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ port->gs.tty->ldisc.write_wakeup)
+ (port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+ sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
+ port->gs.wakeup_chars);
+ wake_up_interruptible(&port->gs.tty->write_wait);
+ }
+
+ clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks);
+ func_exit ();
+}
+
+
+/* Note the symmetry between receiving chars and transmitting them!
+ Note: The kernel should have implemented both a receive buffer and
+ a transmit buffer. */
+
+/* Inlined: Called only once. Remove the inline when you add another call */
+inline void sx_receive_chars (struct sx_port *port)
+{
+ int c;
+ int rx_op;
+ struct tty_struct *tty;
+ int copied=0;
+
+ /* func_enter2 (); */
+ tty = port->gs.tty;
+ while (1) {
+ rx_op = sx_read_channel_byte (port, hi_rxopos);
+ c = (sx_read_channel_byte (port, hi_rxipos) - rx_op) & 0xff;
+
+ sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c);
+
+ /* Don't copy more bytes than there is room for in the buffer */
+ if (tty->flip.count + c > TTY_FLIPBUF_SIZE)
+ c = TTY_FLIPBUF_SIZE - tty->flip.count;
+
+ sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
+
+ /* Don't copy past the end of the hardware receive buffer */
+ if (rx_op + c > 0x100) c = 0x100 - rx_op;
+
+ sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
+
+ /* If for one reason or another, we can't copy more data, we're done! */
+ if (c == 0) break;
+
+ sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c,
+ read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op),
+ CHAN_OFFSET(port, hi_rxbuf));
+ memcpy_fromio (tty->flip.char_buf_ptr,
+ port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c);
+ memset(tty->flip.flag_buf_ptr, TTY_NORMAL, c);
+
+ /* Update the kernel buffer end */
+ tty->flip.count += c;
+ tty->flip.char_buf_ptr += c;
+ tty->flip.flag_buf_ptr += c;
+
+ /* This one last. ( Not essential.)
+ It allows the card to start putting more data into the buffer!
+ Update the pointer in the card */
+ sx_write_channel_byte (port, hi_rxopos, (rx_op + c) & 0xff);
+
+ copied += c;
+ }
+ if (copied) {
+ struct timeval tv;
+
+ do_gettimeofday (&tv);
+ sx_dprintk (SX_DEBUG_RECEIVE,
+ "pushing flipq port %d (%3d chars): %d.%06d (%d/%d)\n",
+ port->line, copied,
+ (int) (tv.tv_sec % 60), (int)tv.tv_usec, tty->raw, tty->real_raw);
+
+ /* Tell the rest of the system the news. Great news. New characters! */
+ tty_flip_buffer_push (tty);
+ /* tty_schedule_flip (tty); */
+ }
+
+ /* func_exit (); */
+}
+
+/* Inlined: it is called only once. Remove the inline if you add another
+ call */
+inline void sx_check_modem_signals (struct sx_port *port)
+{
+ int hi_state;
+ int c_dcd;
+
+ hi_state = sx_read_channel_byte (port, hi_state);
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",
+ port->c_dcd, sx_get_CD (port));
+
+ if (hi_state & ST_BREAK) {
+ hi_state &= ~ST_BREAK;
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n");
+
+ sx_write_channel_byte (port, hi_state, hi_state);
+ if (port->gs.flags & ASYNC_SAK) {
+ do_SAK (port->gs.tty);
+ }
+ }
+ if (hi_state & ST_DCD) {
+ hi_state &= ~ST_DCD;
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");
+ sx_write_channel_byte (port, hi_state, hi_state);
+ c_dcd = sx_get_CD (port);
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);
+ if (c_dcd != port->c_dcd) {
+ port->c_dcd = c_dcd;
+ if (sx_get_CD (port)) {
+ /* DCD went UP */
+ if( (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) ||
+ ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) &&
+ (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED)) {
+ /* Are we blocking in open?*/
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n");
+ wake_up_interruptible(&port->gs.open_wait);
+ } else {
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD raised. Ignoring.\n");
+ }
+ } else {
+ /* DCD went down! */
+ if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) &&
+ (port->gs.flags & ASYNC_CALLOUT_NOHUP))) {
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n");
+ tty_hangup (port->gs.tty);
+ } else {
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. ignoring.\n");
+ }
+ }
+ } else {
+ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us DCD changed, but it didn't.\n");
+ }
+ }
+}
+
+
+/* This is what an interrupt routine should look like.
+ * Small, elegant, clear.
+ */
+
+static void sx_interrupt (int irq, void *ptr, struct pt_regs *regs)
+{
+ struct sx_board *board = ptr;
+ struct sx_port *port;
+ int i;
+
+ /* func_enter (); */
+ sx_dprintk (SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq, board->irq);
+
+ /* AAargh! The order in which to do these things is essential and
+ not trivial.
+
+ - Rate limit goes before "recursive". Otherwise a series of
+ recursive calls will hang the machine in the interrupt routine.
+
+ - hardware twiddling goes before "recursive". Otherwise when we
+ poll the card, and a recursive interrupt happens, we wont
+ ack the card, so it might keep on interrupting us. (especially
+ level sensitive interrupt systems like PCI).
+
+ - Rate limit goes before hardware twiddling. Otherwise we won't
+ catch a card that has gone bonkers.
+
+ - The "initialized" test goes after the hardware twiddling. Otherwise
+ the card will stick us in the interrupt routine again.
+
+ - The initialized test goes before recursive.
+ */
+
+
+
+#ifdef IRQ_RATE_LIMIT
+ /* Aaargh! I'm ashamed. This costs more lines-of-code than the
+ actual interrupt routine!. (Well, used to when I wrote that comment) */
+ {
+ static int lastjif;
+ static int nintr=0;
+
+ if (lastjif == jiffies) {
+ if (++nintr > IRQ_RATE_LIMIT) {
+ free_irq (board->irq, board);
+ printk (KERN_ERR "sx: Too many interrupts. Turning off interrupt %d.\n",
+ board->irq);
+ }
+ } else {
+ lastjif = jiffies;
+ nintr = 0;
+ }
+ }
+#endif
+
+
+ if (board->irq == irq) {
+ /* Tell the card we've noticed the interrupt. */
+
+ sx_write_board_word (board, cc_int_pending, 0);
+ if (IS_SX_BOARD (board)) {
+ write_sx_byte (board, SX_RESET_IRQ, 1);
+ } else {
+ write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
+ write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+ }
+ }
+
+ if (!sx_initialized) return;
+ if (!(board->flags & SX_BOARD_INITIALIZED)) return;
+
+ if (test_and_set_bit (SX_BOARD_INTR_LOCK, &board->locks)) {
+ printk (KERN_ERR "Recursive interrupt! (%d)\n", board->irq);
+ return;
+ }
+
+ for (i=0;i<board->nports;i++) {
+ port = &board->ports[i];
+ if (port->gs.flags & GS_ACTIVE) {
+ if (sx_read_channel_byte (port, hi_state)) {
+ sx_dprintk (SX_DEBUG_INTERRUPTS,
+ "Port %d: modem signal change?... \n", i);
+ sx_check_modem_signals (port);
+ }
+ if (port->gs.xmit_cnt) {
+ sx_transmit_chars (port);
+ }
+ if (!(port->gs.flags & SX_RX_THROTTLE)) {
+ sx_receive_chars (port);
+ }
+ }
+ }
+
+ clear_bit (SX_BOARD_INTR_LOCK, &board->locks);
+
+ sx_dprintk (SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq, board->irq);
+ /* func_exit (); */
+}
+
+
+static void sx_pollfunc (unsigned long data)
+{
+ struct sx_board *board = (struct sx_board *) data;
+
+ func_enter ();
+
+ sx_interrupt (0, board, NULL);
+
+ board->timer.expires = jiffies + sx_poll;
+ add_timer (&board->timer);
+ func_exit ();
+}
+
+
+
+/* ********************************************************************** *
+ * Here are the routines that actually *
+ * interface with the generic_serial driver *
+ * ********************************************************************** */
+
+/* Ehhm. I don't know how to fiddle with interrupts on the SX card. --REW */
+/* Hmm. Ok I figured it out. You don't. */
+
+static void sx_disable_tx_interrupts (void * ptr)
+{
+ struct sx_port *port = ptr;
+ func_enter2();
+
+ port->gs.flags &= ~GS_TX_INTEN;
+
+ func_exit();
+}
+
+
+static void sx_enable_tx_interrupts (void * ptr)
+{
+ struct sx_port *port = ptr;
+ int data_in_buffer;
+ func_enter2();
+
+ /* First transmit the characters that we're supposed to */
+ sx_transmit_chars (port);
+
+ /* The sx card will never interrupt us if we don't fill the buffer
+ past 25%. So we keep considering interrupts off if that's the case. */
+ data_in_buffer = (sx_read_channel_byte (port, hi_txipos) -
+ sx_read_channel_byte (port, hi_txopos)) & 0xff;
+
+ /* XXX Must be "HIGH_WATER" for SI card according to doc. */
+ if (data_in_buffer < LOW_WATER)
+ port->gs.flags &= ~GS_TX_INTEN;
+
+ func_exit();
+}
+
+
+static void sx_disable_rx_interrupts (void * ptr)
+{
+ /* struct sx_port *port = ptr; */
+ func_enter();
+
+ func_exit();
+}
+
+static void sx_enable_rx_interrupts (void * ptr)
+{
+ /* struct sx_port *port = ptr; */
+ func_enter();
+
+ func_exit();
+}
+
+
+/* Jeez. Isn't this simple? */
+static int sx_get_CD (void * ptr)
+{
+ struct sx_port *port = ptr;
+ func_enter2();
+
+ func_exit();
+ return ((sx_read_channel_byte (port, hi_ip) & IP_DCD) != 0);
+}
+
+
+/* Jeez. Isn't this simple? */
+static int sx_chars_in_buffer (void * ptr)
+{
+ struct sx_port *port = ptr;
+ func_enter2();
+
+ func_exit();
+ return ((sx_read_channel_byte (port, hi_txipos) -
+ sx_read_channel_byte (port, hi_txopos)) & 0xff);
+}
+
+
+static void sx_shutdown_port (void * ptr)
+{
+ struct sx_port *port = ptr;
+
+ func_enter();
+
+ port->gs.flags &= ~ GS_ACTIVE;
+ if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) {
+ sx_setsignals (port, 0, 0);
+ }
+
+ func_exit();
+}
+
+
+
+
+
+/* ********************************************************************** *
+ * Here are the routines that actually *
+ * interface with the rest of the system *
+ * ********************************************************************** */
+
+
+static int sx_fw_open(struct inode *inode, struct file *filp)
+{
+ func_enter ();
+ MOD_INC_USE_COUNT;
+ func_exit ();
+ return 0;
+}
+
+
+static INT sx_fw_release(struct inode *inode, struct file *filp)
+{
+ func_enter ();
+ MOD_DEC_USE_COUNT;
+ func_exit ();
+ return NO_ERROR;
+}
+
+
+static int sx_open (struct tty_struct * tty, struct file * filp)
+{
+ struct sx_port *port;
+ int retval, line;
+
+ func_enter();
+
+ if (!sx_initialized) {
+ return -EIO;
+ }
+
+ line = MINOR(tty->device);
+ sx_dprintk (SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, np=%d)\n",
+ current->pid, line, tty, current->tty, sx_nports);
+
+ if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports))
+ return -ENODEV;
+
+ port = & sx_ports[line];
+ port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a
+ 1 -> 0 transition. */
+
+
+ sx_dprintk (SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);
+
+ tty->driver_data = port;
+ port->gs.tty = tty;
+ port->gs.count++;
+
+ sx_dprintk (SX_DEBUG_OPEN, "starting port\n");
+
+ /*
+ * Start up serial port
+ */
+ retval = gs_init_port(&port->gs);
+ sx_dprintk (SX_DEBUG_OPEN, "done gs_init\n");
+ if (retval) {
+ port->gs.count--;
+ return retval;
+ }
+
+ port->gs.flags |= GS_ACTIVE;
+ sx_setsignals (port, 1,1);
+
+ sx_dprintk (SX_DEBUG_OPEN, "before inc_use_count (count=%d.\n",
+ port->gs.count);
+ if (port->gs.count == 1) {
+ MOD_INC_USE_COUNT;
+ }
+ sx_dprintk (SX_DEBUG_OPEN, "after inc_use_count\n");
+
+#if 0
+ if (sx_debug & SX_DEBUG_OPEN)
+ my_hd ((unsigned char *)port, sizeof (*port));
+#else
+ if (sx_debug & SX_DEBUG_OPEN)
+ my_hd ((unsigned char *)port->board->base + port->ch_base,
+ sizeof (*port));
+#endif
+
+ if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
+ printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n");
+ MOD_DEC_USE_COUNT;
+ port->gs.count--;
+ return -EIO;
+ }
+
+ retval = block_til_ready(port, filp);
+ sx_dprintk (SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",
+ retval, port->gs.count);
+
+ if (retval) {
+ MOD_DEC_USE_COUNT;
+ port->gs.count--;
+ return retval;
+ }
+ /* tty->low_latency = 1; */
+
+ if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = port->gs.normal_termios;
+ else
+ *tty->termios = port->gs.callout_termios;
+ sx_set_real_termios (port);
+ }
+
+ port->gs.session = current->session;
+ port->gs.pgrp = current->pgrp;
+ port->c_dcd = sx_get_CD (port);
+ sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
+ func_exit();
+ return 0;
+
+}
+
+
+/* I haven't the foggiest why the decrement use count has to happen
+ here. The whole linux serial drivers stuff needs to be redesigned.
+ My guess is that this is a hack to minimize the impact of a bug
+ elsewhere. Thinking about it some more. (try it sometime) Try
+ running minicom on a serial port that is driven by a modularized
+ driver. Have the modem hangup. Then remove the driver module. Then
+ exit minicom. I expect an "oops". -- REW */
+static void sx_hungup (void *ptr)
+{
+ func_enter ();
+ MOD_DEC_USE_COUNT;
+ func_exit ();
+}
+
+
+static void sx_close (void *ptr)
+{
+ struct sx_port *port = ptr;
+ /* Give the port 5 seconds to close down. */
+ int to = 5 * HZ;
+
+ func_enter ();
+ sx_send_command (port, HS_CLOSE, 0, 0);
+
+ while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout (1);
+ if (signal_pending (current))
+ break;
+ }
+ current->state = TASK_RUNNING;
+ if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) {
+ if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) {
+ printk (KERN_ERR
+ "sx: sent the force_close command, but card didn't react\n");
+ } else
+ sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n");
+ }
+
+ sx_dprintk (SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n",
+ 5 * HZ - to - 1, port->gs.count);
+
+ MOD_DEC_USE_COUNT;
+ func_exit ();
+}
+
+
+
+/* This is relatively thorough. But then again it is only 20 lines. */
+#define MARCHUP for (i=min;i<max;i++)
+#define MARCHDOWN for (i=max-1;i>=min;i--)
+#define W0 write_sx_byte (board, i, 0x55)
+#define W1 write_sx_byte (board, i, 0xaa)
+#define R0 if (read_sx_byte (board, i) != 0x55) return 1
+#define R1 if (read_sx_byte (board, i) != 0xaa) return 1
+
+/* This memtest takes a human-noticable time. You normally only do it
+ once a boot, so I guess that it is worth it. */
+int do_memtest (struct sx_board *board, int min, int max)
+{
+ int i;
+
+ /* This is a marchb. Theoretically, marchb catches much more than
+ simpler tests. In practise, the longer test just catches more
+ intermittent errors. -- REW
+ (For the theory behind memory testing see:
+ Testing Semiconductor Memories by A.J. van de Goor.) */
+ MARCHUP {W0;}
+ MARCHUP {R0;W1;R1;W0;R0;W1;}
+ MARCHUP {R1;W0;W1;}
+ MARCHDOWN {R1;W0;W1;W0;}
+ MARCHDOWN {R0;W1;W0;}
+
+ return 0;
+}
+
+
+#undef MARCHUP
+#undef MARCHDOWN
+#undef W0
+#undef W1
+#undef R0
+#undef R1
+
+#define MARCHUP for (i=min;i<max;i+=2)
+#define MARCHDOWN for (i=max-1;i>=min;i-=2)
+#define W0 write_sx_word (board, i, 0x55aa)
+#define W1 write_sx_word (board, i, 0xaa55)
+#define R0 if (read_sx_word (board, i) != 0x55aa) return 1
+#define R1 if (read_sx_word (board, i) != 0xaa55) return 1
+
+/* This memtest takes a human-noticable time. You normally only do it
+ once a boot, so I guess that it is worth it. */
+int do_memtest_w (struct sx_board *board, int min, int max)
+{
+ int i;
+
+ MARCHUP {W0;}
+ MARCHUP {R0;W1;R1;W0;R0;W1;}
+ MARCHUP {R1;W0;W1;}
+ MARCHDOWN {R1;W0;W1;W0;}
+ MARCHDOWN {R0;W1;W0;}
+
+ return 0;
+}
+
+
+static int sx_fw_ioctl (struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ int *descr = (int *)arg, i;
+ static struct sx_board *board = NULL;
+ int nbytes, offset, data;
+ char *tmp;
+
+ func_enter();
+
+#if 0
+ /* Removed superuser check: Sysops can use the permissions on the device
+ file to restrict access. Recommendation: Root only. (root.root 600) */
+ if (!suser ()) {
+ return -EPERM;
+ }
+#endif
+
+ sx_dprintk (SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);
+
+ if (!board) board = &boards[0];
+ if (board->flags & SX_BOARD_PRESENT) {
+ sx_dprintk (SX_DEBUG_FIRMWARE, "Board present! (%x)\n",
+ board->flags);
+ } else {
+ sx_dprintk (SX_DEBUG_FIRMWARE, "Board not present! (%x) all:",
+ board->flags);
+ for (i=0;i< SX_NBOARDS;i++)
+ sx_dprintk (SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags);
+ sx_dprintk (SX_DEBUG_FIRMWARE, "\n");
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case SXIO_SET_BOARD:
+ sx_dprintk (SX_DEBUG_FIRMWARE, "set board to %ld\n", arg);
+ if (arg > SX_NBOARDS) return -EIO;
+ sx_dprintk (SX_DEBUG_FIRMWARE, "not out of range\n");
+ if (!(boards[arg].flags & SX_BOARD_PRESENT)) return -EIO;
+ sx_dprintk (SX_DEBUG_FIRMWARE, ".. and present!\n");
+ board = &boards[arg];
+ break;
+ case SXIO_GET_TYPE:
+ rc = IS_SX_BOARD (board)? SX_TYPE_SX:SX_TYPE_SI;
+ sx_dprintk (SX_DEBUG_FIRMWARE, "returning type= %d\n", rc);
+ break;
+ case SXIO_DO_RAMTEST:
+ if (sx_initialized) /* Already initialized: better not ramtest the board. */
+ return -EPERM;
+ if (IS_SX_BOARD (board)) {
+ rc = do_memtest (board, 0, 0x7000);
+ if (!rc) rc = do_memtest (board, 0, 0x7000);
+ /*if (!rc) rc = do_memtest_w (board, 0, 0x7000);*/
+ } else {
+ rc = do_memtest (board, 0, 0x7ff8);
+ /* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */
+ }
+ sx_dprintk (SX_DEBUG_FIRMWARE, "returning memtest result= %d\n", rc);
+ break;
+ case SXIO_DOWNLOAD:
+ if (sx_initialized) /* Already initialized */
+ return -EEXIST;
+ if (!sx_reset (board))
+ return -EIO;
+ sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
+
+ tmp = kmalloc (SX_CHUNK_SIZE, GFP_USER);
+ if (!tmp) return -ENOMEM;
+ Get_user (nbytes, descr++);
+ Get_user (offset, descr++);
+ Get_user (data, descr++);
+ while (nbytes && data) {
+ for (i=0;i<nbytes;i += SX_CHUNK_SIZE) {
+ copy_from_user (tmp, (char *)data+i,
+ (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE);
+ memcpy_toio ((char *) (board->base + offset + i), tmp,
+ (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE);
+ }
+
+ Get_user (nbytes, descr++);
+ Get_user (offset, descr++);
+ Get_user (data, descr++);
+ }
+ kfree (tmp);
+ sx_nports += sx_init_board (board);
+ rc = sx_nports;
+ break;
+ case SXIO_INIT:
+ if (sx_initialized) /* Already initialized */
+ return -EEXIST;
+ /* This is not allowed until all boards are initialized... */
+ for (i=0;i<SX_NBOARDS;i++) {
+ if ( (boards[i].flags & SX_BOARD_PRESENT) &&
+ !(boards[i].flags & SX_BOARD_INITIALIZED))
+ return -EIO;
+ }
+ for (i=0;i<SX_NBOARDS;i++)
+ if (!(boards[i].flags & SX_BOARD_PRESENT)) break;
+
+ sx_dprintk (SX_DEBUG_FIRMWARE, "initing portstructs, %d boards, "
+ "%d channels, first board: %d ports\n",
+ i, sx_nports, boards[0].nports);
+ rc = sx_init_portstructs (i, sx_nports);
+ sx_init_drivers ();
+ if (rc >= 0)
+ sx_initialized++;
+ break;
+ case SXIO_SETDEBUG:
+ sx_debug = arg;
+ break;
+ case SXIO_GETDEBUG:
+ rc = sx_debug;
+ break;
+ case SXIO_SETGSDEBUG:
+ gs_debug = arg;
+ break;
+ case SXIO_GETGSDEBUG:
+ rc = gs_debug;
+ break;
+ default:
+ printk (KERN_WARNING "Unknown ioctl on firmware device (%x).\n", cmd);
+ break;
+ }
+ func_exit ();
+ return rc;
+}
+
+
+static int sx_ioctl (struct tty_struct * tty, struct file * filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc;
+ struct sx_port *port = tty->driver_data;
+ int ival;
+
+ /* func_enter2(); */
+
+ rc = 0;
+ switch (cmd) {
+ case TIOCGSOFTCAR:
+ rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
+ (unsigned int *) arg);
+ break;
+ case TIOCSSOFTCAR:
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(int))) == 0) {
+ Get_user(ival, (unsigned int *) arg);
+ tty->termios->c_cflag =
+ (tty->termios->c_cflag & ~CLOCAL) |
+ (ival ? CLOCAL : 0);
+ }
+ break;
+ case TIOCGSERIAL:
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct serial_struct))) == 0)
+ gs_getserial(&port->gs, (struct serial_struct *) arg);
+ break;
+ case TIOCSSERIAL:
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(struct serial_struct))) == 0)
+ rc = gs_setserial(&port->gs, (struct serial_struct *) arg);
+ break;
+ case TIOCMGET:
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int))) == 0) {
+ ival = sx_getsignals(port);
+ put_user(ival, (unsigned int *) arg);
+ }
+ break;
+ case TIOCMBIS:
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(unsigned int))) == 0) {
+ Get_user(ival, (unsigned int *) arg);
+ sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1),
+ ((ival & TIOCM_RTS) ? 1 : -1));
+ }
+ break;
+ case TIOCMBIC:
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(unsigned int))) == 0) {
+ Get_user(ival, (unsigned int *) arg);
+ sx_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1),
+ ((ival & TIOCM_RTS) ? 0 : -1));
+ }
+ break;
+ case TIOCMSET:
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(unsigned int))) == 0) {
+ Get_user(ival, (unsigned int *) arg);
+ sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0),
+ ((ival & TIOCM_RTS) ? 1 : 0));
+ }
+ break;
+
+ default:
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+
+ /* func_exit(); */
+ return rc;
+}
+
+
+/* The throttle/unthrottle scheme for the Specialix card is different
+ * from other drivers and deserves some explanation.
+ * The Specialix hardware takes care of XON/XOFF
+ * and CTS/RTS flow control itself. This means that all we have to
+ * do when signalled by the upper tty layer to throttle/unthrottle is
+ * to make a note of it here. When we come to read characters from the
+ * rx buffers on the card (sx_receive_chars()) we look to see if the
+ * upper layer can accept more (as noted here in sx_rx_throt[]).
+ * If it can't we simply don't remove chars from the cards buffer.
+ * When the tty layer can accept chars, we again note that here and when
+ * sx_receive_chars() is called it will remove them from the cards buffer.
+ * The card will notice that a ports buffer has drained below some low
+ * water mark and will unflow control the line itself, using whatever
+ * flow control scheme is in use for that port. -- Simon Allen
+ */
+
+static void sx_throttle (struct tty_struct * tty)
+{
+ struct sx_port *port = (struct sx_port *)tty->driver_data;
+
+ func_enter2();
+ /* If the port is using any type of input flow
+ * control then throttle the port.
+ */
+ if((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) {
+ port->gs.flags |= SX_RX_THROTTLE;
+ }
+ func_exit();
+}
+
+
+static void sx_unthrottle (struct tty_struct * tty)
+{
+ struct sx_port *port = (struct sx_port *)tty->driver_data;
+
+ func_enter2();
+ /* Always unthrottle even if flow control is not enabled on
+ * this port in case we disabled flow control while the port
+ * was throttled
+ */
+ port->gs.flags &= ~SX_RX_THROTTLE;
+ func_exit();
+ return;
+}
+
+
+/* ********************************************************************** *
+ * Here are the initialization routines. *
+ * ********************************************************************** */
+
+
+
+
+static int sx_init_board (struct sx_board *board)
+{
+ int addr;
+ int chans;
+ int type;
+
+ func_enter();
+
+ /* This is preceded by downloading the download code. */
+
+ board->flags |= SX_BOARD_INITIALIZED;
+
+ /* This resets the processor again, to make sure it didn't do any
+ foolish things while we were downloading the image */
+ if (!sx_reset (board))
+ return 0;
+
+ sx_start_board (board);
+
+ if (!sx_busy_wait_neq (board, 0, 0xff, 0)) {
+ printk (KERN_ERR "sx: Ooops. Board won't initialize.\n");
+ return 0;
+ }
+
+ /* Ok. So now the processor on the card is running. It gathered
+ some info for us... */
+ sx_dprintk (SX_DEBUG_INIT, "The sxcard structure:\n");
+ if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base), 0x10);
+ sx_dprintk (SX_DEBUG_INIT, "the first sx_module structure:\n");
+ if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base + 0x80), 0x30);
+
+ sx_dprintk (SX_DEBUG_INIT,
+ "init_status: %x, %dk memory, firmware V%x.%02x,\n",
+ read_sx_byte (board, 0), read_sx_byte(board, 1),
+ read_sx_byte (board, 5), read_sx_byte(board, 4));
+
+ if (read_sx_byte (board, 0) == 0xff) {
+ printk (KERN_INFO "sx: No modules found. Sorry.\n");
+ board->nports = 0;
+ return 0;
+ }
+
+ chans = 0;
+
+ if (IS_SX_BOARD(board)) {
+ sx_write_board_word (board, cc_int_count, sx_maxints);
+ } else {
+ if (sx_maxints)
+ sx_write_board_word (board, cc_int_count, SI_PROCESSOR_CLOCK/8/sx_maxints);
+ }
+
+ /* grab the first module type... */
+ /* board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */
+ board->ta_type = mod_compat_type (sx_read_module_byte (board, 0x80, mc_chip));
+
+ /* XXX byteorder */
+ for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) {
+ type = sx_read_module_byte (board, addr, mc_chip);
+ sx_dprintk (SX_DEBUG_INIT, "Module at %x: %d channels\n",
+ addr, read_sx_byte (board, addr + 2));
+
+ chans += sx_read_module_byte (board, addr, mc_type);
+
+ sx_dprintk (SX_DEBUG_INIT, "module is an %s, which has %s/%s panels\n",
+ mod_type_s (type),
+ pan_type_s (sx_read_module_byte (board, addr, mc_mods) & 0xf),
+ pan_type_s (sx_read_module_byte (board, addr, mc_mods) >> 4));
+
+ sx_dprintk (SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC version: %x\n",
+ sx_read_module_byte (board, addr, mc_rev1),
+ sx_read_module_byte (board, addr, mc_rev2),
+ sx_read_module_byte (board, addr, mc_mtaasic_rev));
+
+ /* The following combinations are illegal: It should theoretically
+ work, but timing problems make the bus HANG. */
+
+ if (mod_compat_type (type) != board->ta_type) {
+ printk (KERN_ERR "sx: This is an invalid configuration.\n"
+ "Don't mix TA/MTA/SXDC on the same hostadapter.\n");
+ chans=0;
+ break;
+ }
+ if (IS_SI_BOARD(board) && (mod_compat_type(type) == 4)) {
+ printk (KERN_ERR "sx: This is an invalid configuration.\n"
+ "Don't use SXDCs on an SI/XIO adapter.\n");
+ chans=0;
+ break;
+ }
+#if 0 /* Problem fixed: firmware 3.05 */
+ if (IS_SX_BOARD(board) && (type == TA8)) {
+ /* There are some issues with the firmware and the DCD/RTS
+ lines. It might work if you tie them together or something.
+ It might also work if you get a newer sx_firmware. Therefore
+ this is just a warning. */
+ printk (KERN_WARNING "sx: The SX host doesn't work too well "
+ "with the TA8 adapters.\nSpecialix is working on it.\n");
+ }
+#endif
+ }
+
+ if (chans) {
+ /* board->flags |= SX_BOARD_PRESENT; */
+ if(board->irq > 0) {
+ /* fixed irq, probably PCI */
+ if(sx_irqmask & (1 << board->irq)) { /* may we use this irq? */
+ if(request_irq(board->irq, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board)) {
+ printk(KERN_ERR "sx: Cannot allocate irq %d.\n", board->irq);
+ board->irq = 0;
+ }
+ } else
+ board->irq = 0;
+ } else if(board->irq < 0 && sx_irqmask) {
+ /* auto-allocate irq */
+ int irqnr;
+ int irqmask = sx_irqmask & (IS_SX_BOARD(board) ? SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK);
+ for(irqnr = 15; irqnr > 0; irqnr--)
+ if(irqmask & (1 << irqnr))
+ if(! request_irq(irqnr, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board))
+ break;
+ if(! irqnr)
+ printk(KERN_ERR "sx: Cannot allocate IRQ.\n");
+ board->irq = irqnr;
+ } else
+ board->irq = 0;
+
+ if (board->irq) {
+ /* Found a valid interrupt, start up interrupts! */
+ sx_dprintk (SX_DEBUG_INIT, "Using irq %d.\n", board->irq);
+ sx_start_interrupts (board);
+ board->poll = sx_slowpoll;
+ board->flags |= SX_IRQ_ALLOCATED;
+ } else {
+ /* no irq: setup board for polled operation */
+ board->poll = sx_poll;
+ sx_dprintk (SX_DEBUG_INIT, "Using poll-interval %d.\n", board->poll);
+ }
+
+ /* The timer should be initialized anyway: That way we can safely
+ del_timer it when the module is unloaded. */
+ init_timer (&board->timer);
+
+ if (board->poll) {
+ board->timer.data = (unsigned long) board;
+ board->timer.function = sx_pollfunc;
+ board->timer.expires = jiffies + board->poll;
+ add_timer (&board->timer);
+ }
+ } else {
+ board->irq = 0;
+ }
+
+ board->nports = chans;
+ sx_dprintk (SX_DEBUG_INIT, "returning %d ports.", board->nports);
+
+ func_exit();
+ return chans;
+}
+
+
+void printheader(void)
+{
+ static int header_printed = 0;
+
+ if (!header_printed) {
+ printk (KERN_INFO "Specialix SX driver "
+ "(C) 1998/1999 R.E.Wolff@BitWizard.nl \n");
+ printk (KERN_INFO "sx: version %s\n", RCS_ID);
+ header_printed = 1;
+ }
+}
+
+
+int probe_sx (struct sx_board *board)
+{
+ struct vpd_prom vpdp;
+ char *p;
+ int i;
+
+ func_enter();
+ sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %x.\n",
+ board->base + SX_VPD_ROM);
+
+ if (sx_debug & SX_DEBUG_PROBE)
+ my_hd ((char *)(board->base + SX_VPD_ROM), 0x40);
+
+ p = (char *) &vpdp;
+ for (i=0;i< sizeof (struct vpd_prom);i++)
+ *p++ = read_sx_byte (board, SX_VPD_ROM + i*2);
+
+ if (sx_debug & SX_DEBUG_PROBE)
+ my_hd ((char *)&vpdp, 0x20);
+
+ sx_dprintk (SX_DEBUG_PROBE, "checking identifier...\n");
+
+ if (strncmp (vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) {
+ sx_dprintk (SX_DEBUG_PROBE, "Got non-SX identifier: '%s'\n",
+ vpdp.identifier);
+ return 0;
+ }
+
+ printheader ();
+
+ printk (KERN_DEBUG "sx: Found an SX board at %x\n", board->hw_base);
+ printk (KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, uniq ID:%08x, ",
+ vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
+ printk ( "Manufactured: %d/%d\n",
+ 1970 + vpdp.myear, vpdp.mweek);
+
+
+ if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_PCI_UNIQUEID1) &&
+ (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) {
+ /* This might be a bit harsh. This was the primary reason the
+ SX/ISA card didn't work at first... */
+ printk (KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA card. Sorry: giving up.\n");
+ return (0);
+ }
+
+ if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) {
+ if (board->base & 0x8000) {
+ printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %x.\n", board->base);
+ printk (KERN_WARNING "sx: Read sx.txt for more info.\n");
+ }
+ }
+
+
+ board->nports = -1;
+
+ /* This resets the processor, and keeps it off the bus. */
+ if (!sx_reset (board))
+ return 0;
+ sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
+
+ board->flags |= SX_BOARD_PRESENT;
+
+ func_exit();
+ return 1;
+}
+
+
+
+/* Specialix probes for this card at 32k increments from 640k to 16M.
+ I consider machines with less than 16M unlikely nowadays, so I'm
+ not probing above 1Mb. Also, 0xa0000, 0xb0000, are taken by the VGA
+ card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves
+ 0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */
+
+int probe_si (struct sx_board *board)
+{
+ int i;
+
+ func_enter();
+ sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %x.\n",
+ board->base + SI2_ISA_ID_BASE);
+
+ if (sx_debug & SX_DEBUG_PROBE)
+ my_hd ((char *)(board->base + SI2_ISA_ID_BASE), 0x8);
+
+ for (i=0;i<8;i++) {
+ if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) {
+ return 0;
+ }
+ }
+
+ printheader ();
+
+ printk (KERN_DEBUG "sx: Found an SI board at %x\n", board->hw_base);
+ /* Compared to the SX boards, it is a complete guess as to what
+ this card is up to... */
+
+ board->nports = -1;
+
+ /* This resets the processor, and keeps it off the bus. */
+ if (!sx_reset (board))
+ return 0;
+ sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
+
+ board->flags |= SX_BOARD_PRESENT;
+
+ func_exit();
+ return 1;
+}
+
+
+static int sx_init_drivers(void)
+{
+ int error;
+
+ func_enter();
+
+ memset(&sx_driver, 0, sizeof(sx_driver));
+ sx_driver.magic = TTY_DRIVER_MAGIC;
+ sx_driver.driver_name = "specialix_sx";
+ sx_driver.name = "ttyX";
+ sx_driver.major = SX_NORMAL_MAJOR;
+ sx_driver.num = sx_nports;
+ sx_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ sx_driver.subtype = SX_TYPE_NORMAL;
+ sx_driver.init_termios = tty_std_termios;
+ sx_driver.init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ sx_driver.flags = TTY_DRIVER_REAL_RAW;
+ sx_driver.refcount = &sx_refcount;
+ sx_driver.table = sx_table;
+ sx_driver.termios = sx_termios;
+ sx_driver.termios_locked = sx_termios_locked;
+
+ sx_driver.open = sx_open;
+ sx_driver.close = gs_close;
+ sx_driver.write = gs_write;
+ sx_driver.put_char = gs_put_char;
+ sx_driver.flush_chars = gs_flush_chars;
+ sx_driver.write_room = gs_write_room;
+ sx_driver.chars_in_buffer = gs_chars_in_buffer;
+ sx_driver.flush_buffer = gs_flush_buffer;
+ sx_driver.ioctl = sx_ioctl;
+ sx_driver.throttle = sx_throttle;
+ sx_driver.unthrottle = sx_unthrottle;
+ sx_driver.set_termios = gs_set_termios;
+ sx_driver.stop = gs_stop;
+ sx_driver.start = gs_start;
+ sx_driver.hangup = gs_hangup;
+
+ sx_callout_driver = sx_driver;
+ sx_callout_driver.name = "cux";
+ sx_callout_driver.major = SX_CALLOUT_MAJOR;
+ sx_callout_driver.subtype = SX_TYPE_CALLOUT;
+
+ if ((error = tty_register_driver(&sx_driver))) {
+ printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n",
+ error);
+ return 1;
+ }
+ if ((error = tty_register_driver(&sx_callout_driver))) {
+ tty_unregister_driver(&sx_driver);
+ printk(KERN_ERR "sx: Couldn't register sx callout driver, error = %d\n",
+ error);
+ return 1;
+ }
+
+ func_exit();
+ return 0;
+}
+
+
+void * ckmalloc (int size)
+{
+ void *p;
+
+ p = kmalloc(size, GFP_KERNEL);
+ if (p)
+ memset(p, 0, size);
+ return p;
+}
+
+
+static int sx_init_portstructs (int nboards, int nports)
+{
+ struct sx_board *board;
+ struct sx_port *port;
+ int i, j;
+ int addr, chans;
+ int portno;
+
+ func_enter();
+
+ /* Many drivers statically allocate the maximum number of ports
+ There is no reason not to allocate them dynamically. Is there? -- REW */
+ sx_ports = ckmalloc(nports * sizeof (struct sx_port));
+ if (!sx_ports)
+ return -ENOMEM;
+
+ sx_termios = ckmalloc(nports * sizeof (struct termios *));
+ if (!sx_termios) {
+ kfree (sx_ports);
+ return -ENOMEM;
+ }
+
+ sx_termios_locked = ckmalloc(nports * sizeof (struct termios *));
+ if (!sx_termios_locked) {
+ kfree (sx_ports);
+ kfree (sx_termios);
+ return -ENOMEM;
+ }
+
+ /* Adjust the values in the "driver" */
+ sx_driver.termios = sx_termios;
+ sx_driver.termios_locked = sx_termios_locked;
+
+ port = sx_ports;
+ for (i = 0; i < nboards; i++) {
+ board = &boards[i];
+ board->ports = port;
+ for (j=0; j < boards[i].nports;j++) {
+ sx_dprintk (SX_DEBUG_INIT, "initing port %d\n", j);
+ port->gs.callout_termios = tty_std_termios;
+ port->gs.normal_termios = tty_std_termios;
+ port->gs.magic = SX_MAGIC;
+ port->gs.close_delay = HZ/2;
+ port->gs.closing_wait = 30 * HZ;
+ port->board = board;
+ port->gs.rd = &sx_real_driver;
+#ifdef NEW_WRITE_LOCKING
+ port->gs.port_write_sem = MUTEX;
+#endif
+ port++;
+ }
+ }
+
+ port = sx_ports;
+ portno = 0;
+ for (i = 0; i < nboards; i++) {
+ board = &boards[i];
+ board->port_base = portno;
+ /* Possibly the configuration was rejected. */
+ sx_dprintk (SX_DEBUG_PROBE, "Board has %d channels\n", board->nports);
+ if (board->nports <= 0) continue;
+ /* XXX byteorder ?? */
+ for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) {
+ chans = sx_read_module_byte (board, addr, mc_type);
+ sx_dprintk (SX_DEBUG_PROBE, "Module at %x: %d channels\n", addr, chans);
+ sx_dprintk (SX_DEBUG_PROBE, "Port at");
+ for (j=0;j<chans;j++) {
+ /* The "sx-way" is the way it SHOULD be done. That way in the
+ future, the firmware may for example pack the structures a bit
+ more efficient. Neil tells me it isn't going to happen anytime
+ soon though. */
+ if (IS_SX_BOARD(board))
+ port->ch_base = sx_read_module_word (board, addr+j*2, mc_chan_pointer);
+ else
+ port->ch_base = addr + 0x100 + 0x300*j;
+
+ sx_dprintk (SX_DEBUG_PROBE, " %x", port->ch_base);
+ port->line = portno++;
+ port++;
+ }
+ sx_dprintk (SX_DEBUG_PROBE, "\n");
+ }
+ /* This has to be done earlier. */
+ /* board->flags |= SX_BOARD_INITIALIZED; */
+ }
+
+ func_exit();
+ return 0;
+}
+
+
+static void sx_release_drivers(void)
+{
+ func_enter();
+ tty_unregister_driver(&sx_driver);
+ tty_unregister_driver(&sx_callout_driver);
+ func_exit();
+}
+
+#ifdef TWO_ZERO
+#define PDEV unsigned char pci_bus, unsigned pci_fun
+#define pdev pci_bus, pci_fun
+#else
+#define PDEV struct pci_dev *pdev
+#endif
+
+
+#ifdef CONFIG_PCI
+ /********************************************************
+ * Setting bit 17 in the CNTRL register of the PLX 9050 *
+ * chip forces a retry on writes while a read is pending.*
+ * This is to prevent the card locking up on Intel Xeon *
+ * multiprocessor systems with the NX chipset. -- NV *
+ ********************************************************/
+
+/* Newer cards are produced with this bit set from the configuration
+ EEprom. As the bit is read/write for the CPU, we can fix it here,
+ if we detect that it isn't set correctly. -- REW */
+
+void fix_sx_pci (PDEV, struct sx_board *board)
+{
+ unsigned int hwbase;
+ unsigned long rebase;
+ int t;
+
+#define CNTRL_REG_OFFSET 0x14
+
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
+ hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
+ rebase = (ulong) ioremap(hwbase, 0x80);
+ t = readb (rebase + CNTRL_REG_OFFSET*4 + 2);
+ if (t != 0x06) {
+ printk (KERN_DEBUG "sx: performing cntrl reg fix: %02x -> 06\n", t);
+ writeb (0x06, rebase + CNTRL_REG_OFFSET*4+2);
+ }
+ my_iounmap (hwbase, rebase);
+
+}
+#endif
+
+
+#ifdef MODULE
+#define sx_init init_module
+#endif
+
+int sx_init(void)
+{
+ int i;
+ int found = 0;
+ struct sx_board *board;
+
+#ifdef CONFIG_PCI
+#ifndef TWO_ZERO
+ struct pci_dev *pdev = NULL;
+#else
+ unsigned char pci_bus, pci_fun;
+ /* in 2.2.x pdev is a pointer defining a PCI device. In 2.0 its the bus/fn */
+#endif
+ unsigned int tint;
+ unsigned short tshort;
+#endif
+
+ func_enter();
+ sx_dprintk (SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n", sx_debug);
+ if (abs ((long) (&sx_debug) - sx_debug) < 0x10000) {
+ printk (KERN_WARNING "sx: sx_debug is an address, instead of a value. "
+ "Assuming -1.\n");
+ printk ("(%p)\n", &sx_debug);
+ sx_debug=-1;
+ }
+
+#ifdef CONFIG_PCI
+ if (pci_present ()) {
+#ifndef TWO_ZERO
+ while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
+ PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
+ pdev))) {
+#else
+ for (i=0;i< SX_NBOARDS;i++) {
+ if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX,
+ PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, i,
+ &pci_bus, &pci_fun)) break;
+#endif
+ /* Specialix has a whole bunch of cards with
+ 0x2000 as the device ID. They say its because
+ the standard requires it. Stupid standard. */
+ /* It seems that reading a word doesn't work reliably on 2.0.
+ Also, reading a non-aligned dword doesn't work. So we read the
+ whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
+ ourselves */
+ /* I don't know why the define doesn't work, constant 0x2c does --REW */
+ pci_read_config_dword (pdev, 0x2c, &tint);
+ tshort = (tint >> 16) & 0xffff;
+ sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
+ /* sx_dprintk (SX_DEBUG_PROBE, "pdev = %d/%d (%x)\n", pdev, tint); */
+ if (tshort != 0x0200) {
+ sx_dprintk (SX_DEBUG_PROBE, "But it's not an SX card (%d)...\n",
+ tshort);
+ continue;
+ }
+ board = &boards[found];
+
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint);
+ board->hw_base = tint & PCI_BASE_ADDRESS_MEM_MASK;
+ board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN);
+ board->irq = get_irq (pdev);
+ board->flags &= ~SX_BOARD_TYPE;
+ board->flags |= SX_PCI_BOARD;
+
+ sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%x(%d).\n",
+ tint, boards[found].base, board->irq);
+
+ if (probe_sx (board)) {
+ found++;
+ fix_sx_pci (pdev, board);
+ } else
+ my_iounmap (board->hw_base, board->base);
+ }
+ }
+#endif
+
+ for (i=0;i<NR_SX_ADDRS;i++) {
+ board = &boards[found];
+ board->hw_base = sx_probe_addrs[i];
+ board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN);
+ board->flags &= ~SX_BOARD_TYPE;
+ board->flags |= SX_ISA_BOARD;
+ board->irq = sx_irqmask?-1:0;
+
+ if (probe_sx (board)) {
+ found++;
+ } else {
+ my_iounmap (board->hw_base, board->base);
+ }
+ }
+
+ for (i=0;i<NR_SI_ADDRS;i++) {
+ board = &boards[found];
+ board->hw_base = si_probe_addrs[i];
+ board->base = (ulong) ioremap(board->hw_base, SI2_ISA_WINDOW_LEN);
+ board->flags &= ~SX_BOARD_TYPE;
+ board->flags |= SI_ISA_BOARD;
+ board->irq = sx_irqmask ?-1:0;
+
+ if (probe_si (board)) {
+ found++;
+ } else {
+ my_iounmap (board->hw_base, board->base);
+ }
+ }
+
+ if (found) {
+ printk (KERN_INFO "sx: total of %d boards detected.\n", found);
+
+ if (misc_register(&sx_fw_device) < 0) {
+ printk(KERN_ERR "SX: Unable to register firmware loader driver.\n");
+ return -EIO;
+ }
+ }
+
+ func_exit();
+ return found?0:-EIO;
+}
+
+
+
+void cleanup_module(void)
+{
+ int i;
+ struct sx_board *board;
+
+ func_enter();
+ for (i = 0; i < SX_NBOARDS; i++) {
+ board = &boards[i];
+ if (board->flags & SX_BOARD_INITIALIZED) {
+ sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %x\n", board->base);
+ /* The board should stop messing with us.
+ (actually I mean the interrupt) */
+ sx_reset (board);
+ if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED))
+ free_irq (board->irq, board);
+
+ /* It is safe/allowed to del_timer a non-active timer */
+ del_timer (& board->timer);
+ my_iounmap (board->hw_base, board->base);
+ }
+ }
+ if (misc_deregister(&sx_fw_device) < 0) {
+ printk (KERN_INFO "sx: couldn't deregister firmware loader device\n");
+ }
+ sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized);
+ if (sx_initialized)
+ sx_release_drivers ();
+
+ kfree (sx_ports);
+ kfree (sx_termios);
+ kfree (sx_termios_locked);
+ func_exit();
+}
+
+
+#ifdef DEBUG
+void my_hd (unsigned char *addr, int len)
+{
+ int i, j, ch;
+
+ for (i=0;i<len;i+=16) {
+ printk ("%08x ", (int) addr+i);
+ for (j=0;j<16;j++) {
+ printk ("%02x %s", addr[j+i], (j==7)?" ":"");
+ }
+ for (j=0;j<16;j++) {
+ ch = addr[j+i];
+ printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+ }
+ printk ("\n");
+ }
+}
+#endif
+
+#ifdef MODULE
+#undef func_enter
+#undef func_exit
+
+#include "generic_serial.c"
+#endif
+
+
+/*
+ * Anybody who knows why this doesn't work for me, please tell me -- REW.
+ * Snatched from scsi.c (fixed one spelling error):
+ * Overrides for Emacs so that we follow Linus' tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/char/sx.h b/drivers/char/sx.h
new file mode 100644
index 000000000..e046482e4
--- /dev/null
+++ b/drivers/char/sx.h
@@ -0,0 +1,180 @@
+
+/*
+ * sx.h
+ *
+ * Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl
+ *
+ * SX serial driver.
+ * -- Supports SI, XIO and SX host cards.
+ * -- Supports TAs, MTAs and SXDCs.
+ *
+ * Version 1.3 -- March, 1999.
+ *
+ */
+
+#define SX_NBOARDS 4
+#define SX_PORTSPERBOARD 32
+#define SX_NPORTS (SX_NBOARDS * SX_PORTSPERBOARD)
+
+#ifdef __KERNEL__
+
+#define SX_MAGIC 0x12345678
+
+struct sx_port {
+ struct gs_port gs;
+ /*
+ struct tq_struct tqueue;
+ struct tq_struct tqueue_hangup;
+ */
+ struct wait_queue *shutdown_wait;
+ int ch_base;
+ int c_dcd;
+ struct sx_board *board;
+ int line;
+ int locks;
+};
+
+struct sx_board {
+ int magic;
+ unsigned int base;
+ unsigned int hw_base;
+ int port_base; /* Number of the first port */
+ struct sx_port *ports;
+ int nports;
+ int flags;
+ int irq;
+ int poll;
+ int ta_type;
+ struct timer_list timer;
+ int locks;
+};
+
+struct vpd_prom {
+ unsigned short id;
+ char hwrev;
+ char hwass;
+ int uniqid;
+ char myear;
+ char mweek;
+ char hw_feature[5];
+ char oem_id;
+ char identifier[16];
+};
+
+#ifndef MOD_RS232DB25MALE
+#define MOD_RS232DB25MALE 0x0a
+#endif
+
+
+#define SX_BOARD_PRESENT 0x00000001
+#define SX_ISA_BOARD 0x00000002
+#define SX_PCI_BOARD 0x00000004
+#define SI_ISA_BOARD 0x00000008
+#define SX_BOARD_INITIALIZED 0x00000010
+#define SX_IRQ_ALLOCATED 0x00000020
+
+#define SX_BOARD_TYPE (SX_ISA_BOARD|SX_PCI_BOARD|SI_ISA_BOARD)
+
+#define IS_SX_BOARD(board) (board->flags & (SX_PCI_BOARD | SX_ISA_BOARD))
+#define IS_SI_BOARD(board) (board->flags & SI_ISA_BOARD)
+
+
+#define SERIAL_TYPE_NORMAL 1
+
+/* The SI processor clock is required to calculate the cc_int_count register
+ value for the SI cards. */
+#define SI_PROCESSOR_CLOCK 25000000
+
+
+/* port flags */
+/* Make sure these don't clash with gs flags or async flags */
+#define SX_RX_THROTTLE 0x0000001
+
+
+
+#define SX_PORT_TRANSMIT_LOCK 0
+#define SX_BOARD_INTR_LOCK 0
+
+
+
+/* Debug flags. Add these together to get more debug info. */
+
+#define SX_DEBUG_OPEN 0x00000001
+#define SX_DEBUG_SETTING 0x00000002
+#define SX_DEBUG_FLOW 0x00000004
+#define SX_DEBUG_MODEMSIGNALS 0x00000008
+#define SX_DEBUG_TERMIOS 0x00000010
+#define SX_DEBUG_TRANSMIT 0x00000020
+#define SX_DEBUG_RECEIVE 0x00000040
+#define SX_DEBUG_INTERRUPTS 0x00000080
+#define SX_DEBUG_PROBE 0x00000100
+#define SX_DEBUG_INIT 0x00000200
+#define SX_DEBUG_CLEANUP 0x00000400
+#define SX_DEBUG_CLOSE 0x00000800
+#define SX_DEBUG_FIRMWARE 0x00001000
+#define SX_DEBUG_MEMTEST 0x00002000
+
+#define SX_DEBUG_ALL 0xffffffff
+
+
+#define O_OTHER(tty) \
+ ((O_OLCUC(tty)) ||\
+ (O_ONLCR(tty)) ||\
+ (O_OCRNL(tty)) ||\
+ (O_ONOCR(tty)) ||\
+ (O_ONLRET(tty)) ||\
+ (O_OFILL(tty)) ||\
+ (O_OFDEL(tty)) ||\
+ (O_NLDLY(tty)) ||\
+ (O_CRDLY(tty)) ||\
+ (O_TABDLY(tty)) ||\
+ (O_BSDLY(tty)) ||\
+ (O_VTDLY(tty)) ||\
+ (O_FFDLY(tty)))
+
+/* Same for input. */
+#define I_OTHER(tty) \
+ ((I_INLCR(tty)) ||\
+ (I_IGNCR(tty)) ||\
+ (I_ICRNL(tty)) ||\
+ (I_IUCLC(tty)) ||\
+ (L_ISIG(tty)))
+
+#define MOD_TA ( TA>>4)
+#define MOD_MTA (MTA_CD1400>>4)
+#define MOD_SXDC ( SXDC>>4)
+
+
+/* We copy the download code over to the card in chunks of ... bytes */
+#define SX_CHUNK_SIZE 128
+
+#endif /* __KERNEL__ */
+
+
+
+/* Specialix document 6210046-11 page 3 */
+#define SPX(X) (('S'<<24) | ('P' << 16) | (X))
+
+/* Specialix-Linux specific IOCTLS. */
+#define SPXL(X) (SPX(('L' << 8) | (X)))
+
+
+#define SXIO_SET_BOARD SPXL(0x01)
+#define SXIO_GET_TYPE SPXL(0x02)
+#define SXIO_DOWNLOAD SPXL(0x03)
+#define SXIO_INIT SPXL(0x04)
+#define SXIO_SETDEBUG SPXL(0x05)
+#define SXIO_GETDEBUG SPXL(0x06)
+#define SXIO_DO_RAMTEST SPXL(0x07)
+#define SXIO_SETGSDEBUG SPXL(0x08)
+#define SXIO_GETGSDEBUG SPXL(0x09)
+
+
+#ifndef SXCTL_MISC_MINOR
+/* Allow others to gather this into "major.h" or something like that */
+#define SXCTL_MISC_MINOR 167
+#endif
+
+#define SX_TYPE_SX 0x01
+#define SX_TYPE_SI 0x02
+
diff --git a/drivers/char/sxboards.h b/drivers/char/sxboards.h
new file mode 100644
index 000000000..45636c9e9
--- /dev/null
+++ b/drivers/char/sxboards.h
@@ -0,0 +1,181 @@
+/************************************************************************/
+/* */
+/* Title : SX/SI/XIO Board Hardware Definitions */
+/* */
+/* Author : N.P.Vassallo */
+/* */
+/* Creation : 16th March 1998 */
+/* */
+/* Version : 3.0.0 */
+/* */
+/* Copyright : (c) Specialix International Ltd. 1998 */
+/* */
+/* Description : Prototypes, structures and definitions */
+/* describing the SX/SI/XIO board hardware */
+/* */
+/************************************************************************/
+
+/* History...
+
+3.0.0 16/03/98 NPV Creation.
+
+*/
+
+#ifndef _sxboards_h /* If SXBOARDS.H not already defined */
+#define _sxboards_h 1
+
+/*****************************************************************************
+******************************* ******************************
+******************************* Board Types ******************************
+******************************* ******************************
+*****************************************************************************/
+
+/* BUS types... */
+#define BUS_ISA 0
+#define BUS_MCA 1
+#define BUS_EISA 2
+#define BUS_PCI 3
+
+/* Board phases... */
+#define SI1_Z280 1
+#define SI2_Z280 2
+#define SI3_T225 3
+
+/* Board types... */
+#define CARD_TYPE(bus,phase) (bus<<4|phase)
+#define CARD_BUS(type) ((type>>4)&0xF)
+#define CARD_PHASE(type) (type&0xF)
+
+#define TYPE_SI2_ISA CARD_TYPE(BUS_ISA,SI2_Z280)
+#define TYPE_SI2_EISA CARD_TYPE(BUS_EISA,SI2_Z280)
+#define TYPE_SI2_PCI CARD_TYPE(BUS_PCI,SI2_Z280)
+
+#define TYPE_SX_ISA CARD_TYPE(BUS_ISA,SI3_T225)
+#define TYPE_SX_PCI CARD_TYPE(BUS_PCI,SI3_T225)
+
+/*****************************************************************************
+****************************** ******************************
+****************************** Phase 2 Z280 ******************************
+****************************** ******************************
+*****************************************************************************/
+
+/* ISA board details... */
+#define SI2_ISA_WINDOW_LEN 0x8000 /* 32 Kbyte shared memory window */
+#define SI2_ISA_MEMORY_LEN 0x7FF8 /* Usable memory */
+#define SI2_ISA_ADDR_LOW 0x0A0000 /* Lowest address = 640 Kbyte */
+#define SI2_ISA_ADDR_HIGH 0xFF8000 /* Highest address = 16Mbyte - 32Kbyte */
+#define SI2_ISA_ADDR_STEP SI2_ISA_WINDOW_LEN/* ISA board address step */
+#define SI2_ISA_IRQ_MASK 0x9800 /* IRQs 15,12,11 */
+
+/* ISA board, register definitions... */
+#define SI2_ISA_ID_BASE 0x7FF8 /* READ: Board ID string */
+#define SI2_ISA_RESET SI2_ISA_ID_BASE /* WRITE: Host Reset */
+#define SI2_ISA_IRQ11 (SI2_ISA_ID_BASE+1) /* WRITE: Set IRQ11 */
+#define SI2_ISA_IRQ12 (SI2_ISA_ID_BASE+2) /* WRITE: Set IRQ12 */
+#define SI2_ISA_IRQ15 (SI2_ISA_ID_BASE+3) /* WRITE: Set IRQ15 */
+#define SI2_ISA_IRQSET (SI2_ISA_ID_BASE+4) /* WRITE: Set Host Interrupt */
+#define SI2_ISA_INTCLEAR (SI2_ISA_ID_BASE+5) /* WRITE: Enable Host Interrupt */
+
+#define SI2_ISA_IRQ11_SET 0x10
+#define SI2_ISA_IRQ11_CLEAR 0x00
+#define SI2_ISA_IRQ12_SET 0x10
+#define SI2_ISA_IRQ12_CLEAR 0x00
+#define SI2_ISA_IRQ15_SET 0x10
+#define SI2_ISA_IRQ15_CLEAR 0x00
+#define SI2_ISA_INTCLEAR_SET 0x10
+#define SI2_ISA_INTCLEAR_CLEAR 0x00
+#define SI2_ISA_IRQSET_CLEAR 0x10
+#define SI2_ISA_IRQSET_SET 0x00
+#define SI2_ISA_RESET_SET 0x00
+#define SI2_ISA_RESET_CLEAR 0x10
+
+/* PCI board details... */
+#define SI2_PCI_WINDOW_LEN 0x100000 /* 1 Mbyte memory window */
+
+/* PCI board register definitions... */
+#define SI2_PCI_SET_IRQ 0x40001 /* Set Host Interrupt */
+#define SI2_PCI_RESET 0xC0001 /* Host Reset */
+
+/*****************************************************************************
+****************************** ******************************
+****************************** Phase 3 T225 ******************************
+****************************** ******************************
+*****************************************************************************/
+
+/* General board details... */
+#define SX_WINDOW_LEN 64*1024 /* 64 Kbyte memory window */
+
+/* ISA board details... */
+#define SX_ISA_ADDR_LOW 0x0A0000 /* Lowest address = 640 Kbyte */
+#define SX_ISA_ADDR_HIGH 0xFF8000 /* Highest address = 16Mbyte - 32Kbyte */
+#define SX_ISA_ADDR_STEP SX_WINDOW_LEN /* ISA board address step */
+#define SX_ISA_IRQ_MASK 0x9E00 /* IRQs 15,12,11,10,9 */
+
+/* Hardware register definitions... */
+#define SX_EVENT_STATUS 0x7800 /* READ: T225 Event Status */
+#define SX_EVENT_STROBE 0x7800 /* WRITE: T225 Event Strobe */
+#define SX_EVENT_ENABLE 0x7880 /* WRITE: T225 Event Enable */
+#define SX_VPD_ROM 0x7C00 /* READ: Vital Product Data ROM */
+#define SX_CONFIG 0x7C00 /* WRITE: Host Configuration Register */
+#define SX_IRQ_STATUS 0x7C80 /* READ: Host Interrupt Status */
+#define SX_SET_IRQ 0x7C80 /* WRITE: Set Host Interrupt */
+#define SX_RESET_STATUS 0x7D00 /* READ: Host Reset Status */
+#define SX_RESET 0x7D00 /* WRITE: Host Reset */
+#define SX_RESET_IRQ 0x7D80 /* WRITE: Reset Host Interrupt */
+
+/* SX_VPD_ROM definitions... */
+#define SX_VPD_SLX_ID1 0x00
+#define SX_VPD_SLX_ID2 0x01
+#define SX_VPD_HW_REV 0x02
+#define SX_VPD_HW_ASSEM 0x03
+#define SX_VPD_UNIQUEID4 0x04
+#define SX_VPD_UNIQUEID3 0x05
+#define SX_VPD_UNIQUEID2 0x06
+#define SX_VPD_UNIQUEID1 0x07
+#define SX_VPD_MANU_YEAR 0x08
+#define SX_VPD_MANU_WEEK 0x09
+#define SX_VPD_IDENT 0x10
+#define SX_VPD_IDENT_STRING "JET HOST BY KEV#"
+
+/* SX unique identifiers... */
+#define SX_UNIQUEID_MASK 0xF0
+#define SX_ISA_UNIQUEID1 0x20
+#define SX_PCI_UNIQUEID1 0x50
+
+/* SX_CONFIG definitions... */
+#define SX_CONF_BUSEN 0x02 /* Enable T225 memory and I/O */
+#define SX_CONF_HOSTIRQ 0x04 /* Enable board to host interrupt */
+
+/* SX bootstrap... */
+#define SX_BOOTSTRAP "\x28\x20\x21\x02\x60\x0a"
+#define SX_BOOTSTRAP_SIZE 6
+#define SX_BOOTSTRAP_ADDR (0x8000-SX_BOOTSTRAP_SIZE)
+
+/*****************************************************************************
+********************************** **********************************
+********************************** EISA **********************************
+********************************** **********************************
+*****************************************************************************/
+
+#define SI2_EISA_OFF 0x42
+#define SI2_EISA_VAL 0x01
+
+/*****************************************************************************
+*********************************** **********************************
+*********************************** PCI **********************************
+*********************************** **********************************
+*****************************************************************************/
+
+/* General definitions... */
+
+#define SPX_VENDOR_ID 0x11CB /* Assigned by the PCI SIG */
+#define SPX_DEVICE_ID 0x4000 /* SI/XIO boards */
+#define SPX_PLXDEVICE_ID 0x2000 /* SX boards */
+
+#define SPX_SUB_VENDOR_ID SPX_VENDOR_ID /* Same as vendor id */
+#define SI2_SUB_SYS_ID 0x400 /* Phase 2 (Z280) board */
+#define SX_SUB_SYS_ID 0x200 /* Phase 3 (t225) board */
+
+#endif /*_sxboards_h */
+
+/* End of SXBOARDS.H */
diff --git a/drivers/char/sxwindow.h b/drivers/char/sxwindow.h
new file mode 100644
index 000000000..cf01b662a
--- /dev/null
+++ b/drivers/char/sxwindow.h
@@ -0,0 +1,393 @@
+/************************************************************************/
+/* */
+/* Title : SX Shared Memory Window Structure */
+/* */
+/* Author : N.P.Vassallo */
+/* */
+/* Creation : 16th March 1998 */
+/* */
+/* Version : 3.0.0 */
+/* */
+/* Copyright : (c) Specialix International Ltd. 1998 */
+/* */
+/* Description : Prototypes, structures and definitions */
+/* describing the SX/SI/XIO cards shared */
+/* memory window structure: */
+/* SXCARD */
+/* SXMODULE */
+/* SXCHANNEL */
+/* */
+/************************************************************************/
+
+/* History...
+
+3.0.0 16/03/98 NPV Creation. (based on STRUCT.H)
+
+*/
+
+#ifndef _sxwindow_h /* If SXWINDOW.H not already defined */
+#define _sxwindow_h 1
+
+/*****************************************************************************
+*************************** ***************************
+*************************** Common Definitions ***************************
+*************************** ***************************
+*****************************************************************************/
+
+typedef struct _SXCARD *PSXCARD; /* SXCARD structure pointer */
+typedef struct _SXMODULE *PMOD; /* SXMODULE structure pointer */
+typedef struct _SXCHANNEL *PCHAN; /* SXCHANNEL structure pointer */
+
+/*****************************************************************************
+********************************* *********************************
+********************************* SXCARD *********************************
+********************************* *********************************
+*****************************************************************************/
+
+typedef struct _SXCARD
+{
+ BYTE cc_init_status; /* 0x00 Initialisation status */
+ BYTE cc_mem_size; /* 0x01 Size of memory on card */
+ WORD cc_int_count; /* 0x02 Interrupt count */
+ WORD cc_revision; /* 0x04 Download code revision */
+ BYTE cc_isr_count; /* 0x06 Count when ISR is run */
+ BYTE cc_main_count; /* 0x07 Count when main loop is run */
+ WORD cc_int_pending; /* 0x08 Interrupt pending */
+ WORD cc_poll_count; /* 0x0A Count when poll is run */
+ BYTE cc_int_set_count; /* 0x0C Count when host interrupt is set */
+ BYTE cc_rfu[0x80 - 0x0D]; /* 0x0D Pad structure to 128 bytes (0x80) */
+
+} SXCARD;
+
+/* SXCARD.cc_init_status definitions... */
+#define ADAPTERS_FOUND (BYTE)0x01
+#define NO_ADAPTERS_FOUND (BYTE)0xFF
+
+/* SXCARD.cc_mem_size definitions... */
+#define SX_MEMORY_SIZE (BYTE)0x40
+
+/* SXCARD.cc_int_count definitions... */
+#define INT_COUNT_DEFAULT 100 /* Hz */
+
+/*****************************************************************************
+******************************** ********************************
+******************************** SXMODULE ********************************
+******************************** ********************************
+*****************************************************************************/
+
+#define TOP_POINTER(a) ((a)|0x8000) /* Sets top bit of word */
+#define UNTOP_POINTER(a) ((a)&~0x8000) /* Clears top bit of word */
+
+typedef struct _SXMODULE
+{
+ WORD mc_next; /* 0x00 Next module "pointer" (ORed with 0x8000) */
+ BYTE mc_type; /* 0x02 Type of TA in terms of number of channels */
+ BYTE mc_mod_no; /* 0x03 Module number on SI bus cable (0 closest to card) */
+ BYTE mc_dtr; /* 0x04 Private DTR copy (TA only) */
+ BYTE mc_rfu1; /* 0x05 Reserved */
+ WORD mc_uart; /* 0x06 UART base address for this module */
+ BYTE mc_chip; /* 0x08 Chip type / number of ports */
+ BYTE mc_current_uart; /* 0x09 Current uart selected for this module */
+#ifdef DOWNLOAD
+ PCHAN mc_chan_pointer[8]; /* 0x0A Pointer to each channel structure */
+#else
+ WORD mc_chan_pointer[8]; /* 0x0A Define as WORD if not compiling into download */
+#endif
+ WORD mc_rfu2; /* 0x1A Reserved */
+ BYTE mc_opens1; /* 0x1C Number of open ports on first four ports on MTA/SXDC */
+ BYTE mc_opens2; /* 0x1D Number of open ports on second four ports on MTA/SXDC */
+ BYTE mc_mods; /* 0x1E Types of connector module attached to MTA/SXDC */
+ BYTE mc_rev1; /* 0x1F Revision of first CD1400 on MTA/SXDC */
+ BYTE mc_rev2; /* 0x20 Revision of second CD1400 on MTA/SXDC */
+ BYTE mc_mtaasic_rev; /* 0x21 Revision of MTA ASIC 1..4 -> A, B, C, D */
+ BYTE mc_rfu3[0x100 - 0x22]; /* 0x22 Pad structure to 256 bytes (0x100) */
+
+} SXMODULE;
+
+/* SXMODULE.mc_type definitions... */
+#define FOUR_PORTS (BYTE)4
+#define EIGHT_PORTS (BYTE)8
+
+/* SXMODULE.mc_chip definitions... */
+#define CHIP_MASK 0xF0
+#define TA (BYTE)0
+#define TA4 (TA | FOUR_PORTS)
+#define TA8 (TA | EIGHT_PORTS)
+#define TA4_ASIC (BYTE)0x0A
+#define TA8_ASIC (BYTE)0x0B
+#define MTA_CD1400 (BYTE)0x28
+#define SXDC (BYTE)0x48
+
+/* SXMODULE.mc_mods definitions... */
+#define MOD_RS232DB25 0x00 /* RS232 DB25 (socket/plug) */
+#define MOD_RS232RJ45 0x01 /* RS232 RJ45 (shielded/opto-isolated) */
+#define MOD_RESERVED_2 0x02 /* Reserved (RS485) */
+#define MOD_RS422DB25 0x03 /* RS422 DB25 Socket */
+#define MOD_RESERVED_4 0x04 /* Reserved */
+#define MOD_PARALLEL 0x05 /* Parallel */
+#define MOD_RESERVED_6 0x06 /* Reserved (RS423) */
+#define MOD_RESERVED_7 0x07 /* Reserved */
+#define MOD_2_RS232DB25 0x08 /* Rev 2.0 RS232 DB25 (socket/plug) */
+#define MOD_2_RS232RJ45 0x09 /* Rev 2.0 RS232 RJ45 */
+#define MOD_RESERVED_A 0x0A /* Rev 2.0 Reserved */
+#define MOD_2_RS422DB25 0x0B /* Rev 2.0 RS422 DB25 */
+#define MOD_RESERVED_C 0x0C /* Rev 2.0 Reserved */
+#define MOD_2_PARALLEL 0x0D /* Rev 2.0 Parallel */
+#define MOD_RESERVED_E 0x0E /* Rev 2.0 Reserved */
+#define MOD_BLANK 0x0F /* Blank Panel */
+
+/*****************************************************************************
+******************************** *******************************
+******************************** SXCHANNEL *******************************
+******************************** *******************************
+*****************************************************************************/
+
+#define TX_BUFF_OFFSET 0x60 /* Transmit buffer offset in channel structure */
+#define BUFF_POINTER(a) (((a)+TX_BUFF_OFFSET)|0x8000)
+#define UNBUFF_POINTER(a) (jet_channel*)(((a)&~0x8000)-TX_BUFF_OFFSET)
+#define BUFFER_SIZE 256
+#define HIGH_WATER ((BUFFER_SIZE / 4) * 3)
+#define LOW_WATER (BUFFER_SIZE / 4)
+
+typedef struct _SXCHANNEL
+{
+ WORD next_item; /* 0x00 Offset from window base of next channels hi_txbuf (ORred with 0x8000) */
+ WORD addr_uart; /* 0x02 INTERNAL pointer to uart address. Includes FASTPATH bit */
+ WORD module; /* 0x04 Offset from window base of parent SXMODULE structure */
+ BYTE type; /* 0x06 Chip type / number of ports (copy of mc_chip) */
+ BYTE chan_number; /* 0x07 Channel number on the TA/MTA/SXDC */
+ WORD xc_status; /* 0x08 Flow control and I/O status */
+ BYTE hi_rxipos; /* 0x0A Receive buffer input index */
+ BYTE hi_rxopos; /* 0x0B Receive buffer output index */
+ BYTE hi_txopos; /* 0x0C Transmit buffer output index */
+ BYTE hi_txipos; /* 0x0D Transmit buffer input index */
+ BYTE hi_hstat; /* 0x0E Command register */
+ BYTE dtr_bit; /* 0x0F INTERNAL DTR control byte (TA only) */
+ BYTE txon; /* 0x10 INTERNAL copy of hi_txon */
+ BYTE txoff; /* 0x11 INTERNAL copy of hi_txoff */
+ BYTE rxon; /* 0x12 INTERNAL copy of hi_rxon */
+ BYTE rxoff; /* 0x13 INTERNAL copy of hi_rxoff */
+ BYTE hi_mr1; /* 0x14 Mode Register 1 (databits,parity,RTS rx flow)*/
+ BYTE hi_mr2; /* 0x15 Mode Register 2 (stopbits,local,CTS tx flow)*/
+ BYTE hi_csr; /* 0x16 Clock Select Register (baud rate) */
+ BYTE hi_op; /* 0x17 Modem Output Signal */
+ BYTE hi_ip; /* 0x18 Modem Input Signal */
+ BYTE hi_state; /* 0x19 Channel status */
+ BYTE hi_prtcl; /* 0x1A Channel protocol (flow control) */
+ BYTE hi_txon; /* 0x1B Transmit XON character */
+ BYTE hi_txoff; /* 0x1C Transmit XOFF character */
+ BYTE hi_rxon; /* 0x1D Receive XON character */
+ BYTE hi_rxoff; /* 0x1E Receive XOFF character */
+ BYTE close_prev; /* 0x1F INTERNAL channel previously closed flag */
+ BYTE hi_break; /* 0x20 Break and error control */
+ BYTE break_state; /* 0x21 INTERNAL copy of hi_break */
+ BYTE hi_mask; /* 0x22 Mask for received data */
+ BYTE mask; /* 0x23 INTERNAL copy of hi_mask */
+ BYTE mod_type; /* 0x24 MTA/SXDC hardware module type */
+ BYTE ccr_state; /* 0x25 INTERNAL MTA/SXDC state of CCR register */
+ BYTE ip_mask; /* 0x26 Input handshake mask */
+ BYTE hi_parallel; /* 0x27 Parallel port flag */
+ BYTE par_error; /* 0x28 Error code for parallel loopback test */
+ BYTE any_sent; /* 0x29 INTERNAL data sent flag */
+ BYTE asic_txfifo_size; /* 0x2A INTERNAL SXDC transmit FIFO size */
+ BYTE rfu1[2]; /* 0x2B Reserved */
+ BYTE csr; /* 0x2D INTERNAL copy of hi_csr */
+#ifdef DOWNLOAD
+ PCHAN nextp; /* 0x2E Offset from window base of next channel structure */
+#else
+ WORD nextp; /* 0x2E Define as WORD if not compiling into download */
+#endif
+ BYTE prtcl; /* 0x30 INTERNAL copy of hi_prtcl */
+ BYTE mr1; /* 0x31 INTERNAL copy of hi_mr1 */
+ BYTE mr2; /* 0x32 INTERNAL copy of hi_mr2 */
+ BYTE hi_txbaud; /* 0x33 Extended transmit baud rate (SXDC only if((hi_csr&0x0F)==0x0F) */
+ BYTE hi_rxbaud; /* 0x34 Extended receive baud rate (SXDC only if((hi_csr&0xF0)==0xF0) */
+ BYTE txbreak_state; /* 0x35 INTERNAL MTA/SXDC transmit break state */
+ BYTE txbaud; /* 0x36 INTERNAL copy of hi_txbaud */
+ BYTE rxbaud; /* 0x37 INTERNAL copy of hi_rxbaud */
+ WORD err_framing; /* 0x38 Count of receive framing errors */
+ WORD err_parity; /* 0x3A Count of receive parity errors */
+ WORD err_overrun; /* 0x3C Count of receive overrun errors */
+ WORD err_overflow; /* 0x3E Count of receive buffer overflow errors */
+ BYTE rfu2[TX_BUFF_OFFSET - 0x40]; /* 0x40 Reserved until hi_txbuf */
+ BYTE hi_txbuf[BUFFER_SIZE]; /* 0x060 Transmit buffer */
+ BYTE hi_rxbuf[BUFFER_SIZE]; /* 0x160 Receive buffer */
+ BYTE rfu3[0x300 - 0x260]; /* 0x260 Reserved until 768 bytes (0x300) */
+
+} SXCHANNEL;
+
+/* SXCHANNEL.addr_uart definitions... */
+#define FASTPATH 0x1000 /* Set to indicate fast rx/tx processing (TA only) */
+
+/* SXCHANNEL.xc_status definitions... */
+#define X_TANY 0x0001 /* XON is any character (TA only) */
+#define X_TION 0x0001 /* Tx interrupts on (MTA only) */
+#define X_TXEN 0x0002 /* Tx XON/XOFF enabled (TA only) */
+#define X_RTSEN 0x0002 /* RTS FLOW enabled (MTA only) */
+#define X_TXRC 0x0004 /* XOFF received (TA only) */
+#define X_RTSLOW 0x0004 /* RTS dropped (MTA only) */
+#define X_RXEN 0x0008 /* Rx XON/XOFF enabled */
+#define X_ANYXO 0x0010 /* XOFF pending/sent or RTS dropped */
+#define X_RXSE 0x0020 /* Rx XOFF sent */
+#define X_NPEND 0x0040 /* Rx XON pending or XOFF pending */
+#define X_FPEND 0x0080 /* Rx XOFF pending */
+#define C_CRSE 0x0100 /* Carriage return sent (TA only) */
+#define C_TEMR 0x0100 /* Tx empty requested (MTA only) */
+#define C_TEMA 0x0200 /* Tx empty acked (MTA only) */
+#define C_ANYP 0x0200 /* Any protocol bar tx XON/XOFF (TA only) */
+#define C_EN 0x0400 /* Cooking enabled (on MTA means port is also || */
+#define C_HIGH 0x0800 /* Buffer previously hit high water */
+#define C_CTSEN 0x1000 /* CTS automatic flow-control enabled */
+#define C_DCDEN 0x2000 /* DCD/DTR checking enabled */
+#define C_BREAK 0x4000 /* Break detected */
+#define C_RTSEN 0x8000 /* RTS automatic flow control enabled (MTA only) */
+#define C_PARITY 0x8000 /* Parity checking enabled (TA only) */
+
+/* SXCHANNEL.hi_hstat definitions... */
+#define HS_IDLE_OPEN 0x00 /* Channel open state */
+#define HS_LOPEN 0x02 /* Local open command (no modem monitoring) */
+#define HS_MOPEN 0x04 /* Modem open command (wait for DCD signal) */
+#define HS_IDLE_MPEND 0x06 /* Waiting for DCD signal state */
+#define HS_CONFIG 0x08 /* Configuration command */
+#define HS_CLOSE 0x0A /* Close command */
+#define HS_START 0x0C /* Start transmit break command */
+#define HS_STOP 0x0E /* Stop transmit break command */
+#define HS_IDLE_CLOSED 0x10 /* Closed channel state */
+#define HS_IDLE_BREAK 0x12 /* Transmit break state */
+#define HS_FORCE_CLOSED 0x14 /* Force close command */
+#define HS_RESUME 0x16 /* Clear pending XOFF command */
+#define HS_WFLUSH 0x18 /* Flush transmit buffer command */
+#define HS_RFLUSH 0x1A /* Flush receive buffer command */
+#define HS_SUSPEND 0x1C /* Suspend output command (like XOFF received) */
+#define PARALLEL 0x1E /* Parallel port loopback test command (Diagnostics Only) */
+#define ENABLE_RX_INTS 0x20 /* Enable receive interrupts command (Diagnostics Only) */
+#define ENABLE_TX_INTS 0x22 /* Enable transmit interrupts command (Diagnostics Only) */
+#define ENABLE_MDM_INTS 0x24 /* Enable modem interrupts command (Diagnostics Only) */
+#define DISABLE_INTS 0x26 /* Disable interrupts command (Diagnostics Only) */
+
+/* SXCHANNEL.hi_mr1 definitions... */
+#define MR1_BITS 0x03 /* Data bits mask */
+#define MR1_5_BITS 0x00 /* 5 data bits */
+#define MR1_6_BITS 0x01 /* 6 data bits */
+#define MR1_7_BITS 0x02 /* 7 data bits */
+#define MR1_8_BITS 0x03 /* 8 data bits */
+#define MR1_PARITY 0x1C /* Parity mask */
+#define MR1_ODD 0x04 /* Odd parity */
+#define MR1_EVEN 0x00 /* Even parity */
+#define MR1_WITH 0x00 /* Parity enabled */
+#define MR1_FORCE 0x08 /* Force parity */
+#define MR1_NONE 0x10 /* No parity */
+#define MR1_NOPARITY MR1_NONE /* No parity */
+#define MR1_ODDPARITY (MR1_WITH|MR1_ODD) /* Odd parity */
+#define MR1_EVENPARITY (MR1_WITH|MR1_EVEN) /* Even parity */
+#define MR1_MARKPARITY (MR1_FORCE|MR1_ODD) /* Mark parity */
+#define MR1_SPACEPARITY (MR1_FORCE|MR1_EVEN) /* Space parity */
+#define MR1_RTS_RXFLOW 0x80 /* RTS receive flow control */
+
+/* SXCHANNEL.hi_mr2 definitions... */
+#define MR2_STOP 0x0F /* Stop bits mask */
+#define MR2_1_STOP 0x07 /* 1 stop bit */
+#define MR2_2_STOP 0x0F /* 2 stop bits */
+#define MR2_CTS_TXFLOW 0x10 /* CTS transmit flow control */
+#define MR2_RTS_TOGGLE 0x20 /* RTS toggle on transmit */
+#define MR2_NORMAL 0x00 /* Normal mode */
+#define MR2_AUTO 0x40 /* Auto-echo mode (TA only) */
+#define MR2_LOCAL 0x80 /* Local echo mode */
+#define MR2_REMOTE 0xC0 /* Remote echo mode (TA only) */
+
+/* SXCHANNEL.hi_csr definitions... */
+#define CSR_75 0x0 /* 75 baud */
+#define CSR_110 0x1 /* 110 baud (TA), 115200 (MTA/SXDC) */
+#define CSR_38400 0x2 /* 38400 baud */
+#define CSR_150 0x3 /* 150 baud */
+#define CSR_300 0x4 /* 300 baud */
+#define CSR_600 0x5 /* 600 baud */
+#define CSR_1200 0x6 /* 1200 baud */
+#define CSR_2000 0x7 /* 2000 baud */
+#define CSR_2400 0x8 /* 2400 baud */
+#define CSR_4800 0x9 /* 4800 baud */
+#define CSR_1800 0xA /* 1800 baud */
+#define CSR_9600 0xB /* 9600 baud */
+#define CSR_19200 0xC /* 19200 baud */
+#define CSR_57600 0xD /* 57600 baud */
+#define CSR_EXTBAUD 0xF /* Extended baud rate (hi_txbaud/hi_rxbaud) */
+
+/* SXCHANNEL.hi_op definitions... */
+#define OP_RTS 0x01 /* RTS modem output signal */
+#define OP_DTR 0x02 /* DTR modem output signal */
+
+/* SXCHANNEL.hi_ip definitions... */
+#define IP_CTS 0x02 /* CTS modem input signal */
+#define IP_DCD 0x04 /* DCD modem input signal */
+#define IP_DSR 0x20 /* DTR modem input signal */
+#define IP_RI 0x40 /* RI modem input signal */
+
+/* SXCHANNEL.hi_state definitions... */
+#define ST_BREAK 0x01 /* Break received (clear with config) */
+#define ST_DCD 0x02 /* DCD signal changed state */
+
+/* SXCHANNEL.hi_prtcl definitions... */
+#define SP_TANY 0x01 /* Transmit XON/XANY (if SP_TXEN enabled) */
+#define SP_TXEN 0x02 /* Transmit XON/XOFF flow control */
+#define SP_CEN 0x04 /* Cooking enabled */
+#define SP_RXEN 0x08 /* Rx XON/XOFF enabled */
+#define SP_DCEN 0x20 /* DCD / DTR check */
+#define SP_DTR_RXFLOW 0x40 /* DTR receive flow control */
+#define SP_PAEN 0x80 /* Parity checking enabled */
+
+/* SXCHANNEL.hi_break definitions... */
+#define BR_IGN 0x01 /* Ignore any received breaks */
+#define BR_INT 0x02 /* Interrupt on received break */
+#define BR_PARMRK 0x04 /* Enable parmrk parity error processing */
+#define BR_PARIGN 0x08 /* Ignore chars with parity errors */
+#define BR_ERRINT 0x80 /* Treat parity/framing/overrun errors as exceptions */
+
+/* SXCHANNEL.par_error definitions.. */
+#define DIAG_IRQ_RX 0x01 /* Indicate serial receive interrupt (diags only) */
+#define DIAG_IRQ_TX 0x02 /* Indicate serial transmit interrupt (diags only) */
+#define DIAG_IRQ_MD 0x04 /* Indicate serial modem interrupt (diags only) */
+
+/* SXCHANNEL.hi_txbaud/hi_rxbaud definitions... (SXDC only) */
+#define BAUD_75 0x00 /* 75 baud */
+#define BAUD_115200 0x01 /* 115200 baud */
+#define BAUD_38400 0x02 /* 38400 baud */
+#define BAUD_150 0x03 /* 150 baud */
+#define BAUD_300 0x04 /* 300 baud */
+#define BAUD_600 0x05 /* 600 baud */
+#define BAUD_1200 0x06 /* 1200 baud */
+#define BAUD_2000 0x07 /* 2000 baud */
+#define BAUD_2400 0x08 /* 2400 baud */
+#define BAUD_4800 0x09 /* 4800 baud */
+#define BAUD_1800 0x0A /* 1800 baud */
+#define BAUD_9600 0x0B /* 9600 baud */
+#define BAUD_19200 0x0C /* 19200 baud */
+#define BAUD_57600 0x0D /* 57600 baud */
+#define BAUD_230400 0x0E /* 230400 baud */
+#define BAUD_460800 0x0F /* 460800 baud */
+#define BAUD_921600 0x10 /* 921600 baud */
+#define BAUD_50 0x11 /* 50 baud */
+#define BAUD_110 0x12 /* 110 baud */
+#define BAUD_134_5 0x13 /* 134.5 baud */
+#define BAUD_200 0x14 /* 200 baud */
+#define BAUD_7200 0x15 /* 7200 baud */
+#define BAUD_56000 0x16 /* 56000 baud */
+#define BAUD_64000 0x17 /* 64000 baud */
+#define BAUD_76800 0x18 /* 76800 baud */
+#define BAUD_128000 0x19 /* 128000 baud */
+#define BAUD_150000 0x1A /* 150000 baud */
+#define BAUD_14400 0x1B /* 14400 baud */
+#define BAUD_256000 0x1C /* 256000 baud */
+#define BAUD_28800 0x1D /* 28800 baud */
+
+/* SXCHANNEL.txbreak_state definiions... */
+#define TXBREAK_OFF 0 /* Not sending break */
+#define TXBREAK_START 1 /* Begin sending break */
+#define TXBREAK_START1 2 /* Begin sending break, part 1 */
+#define TXBREAK_ON 3 /* Sending break */
+#define TXBREAK_STOP 4 /* Stop sending break */
+#define TXBREAK_STOP1 5 /* Stop sending break, part 1 */
+
+#endif /* _sxwindow_h */
+
+/* End of SXWINDOW.H */
+
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 3b6c7eacf..d07532a17 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -3413,7 +3413,6 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
if ( info->params.mode == MGSL_MODE_HDLC ) {
while (info->tx_active) {
current->state = TASK_INTERRUPTIBLE;
- current->counter = 0; /* make us low-priority */
schedule_timeout(char_time);
if (signal_pending(current))
break;
@@ -3424,7 +3423,6 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
while (!(usc_InReg(info,TCSR) & TXSTATUS_ALL_SENT) &&
info->tx_enabled) {
current->state = TASK_INTERRUPTIBLE;
- current->counter = 0; /* make us low-priority */
schedule_timeout(char_time);
if (signal_pending(current))
break;
@@ -3561,7 +3559,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
retval = (info->flags & ASYNC_HUP_NOTIFY) ?
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index e6f50ebf1..85e436565 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -40,7 +40,7 @@ static void send_sig_all(int sig, int even_init)
struct task_struct *p;
for_each_task(p) {
- if (p->pid && p->mm != &init_mm) { /* Not swapper nor kernel thread */
+ if (p->mm) { /* Not swapper nor kernel thread */
if (p->pid == 1 && even_init) /* Ugly hack to kill init */
p->pid = 0x8000;
force_sig(sig, p);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 62ec86628..7d99d5b68 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -125,11 +125,15 @@ static int tty_release(struct inode *, struct file *);
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static int tty_fasync(int fd, struct file * filp, int on);
+#ifdef CONFIG_SX
+extern int sx_init (void);
+#endif
#ifdef CONFIG_8xx
extern long console_8xx_init(long, long);
extern int rs_8xx_init(void);
#endif /* CONFIG_8xx */
+
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
@@ -1495,10 +1499,11 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
return 0;
}
-static int tioccons(struct tty_struct *tty, struct tty_struct *real_tty)
+static int tioccons(struct inode *inode,
+ struct tty_struct *tty, struct tty_struct *real_tty)
{
- if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE ||
- tty->driver.type == TTY_DRIVER_TYPE_SYSCONS) {
+ if (inode->i_rdev == SYSCONS_DEV ||
+ inode->i_rdev == CONSOLE_DEV) {
if (!suser())
return -EPERM;
redirect = NULL;
@@ -1627,7 +1632,7 @@ static int tiocsetd(struct tty_struct *tty, int *arg)
static int send_break(struct tty_struct *tty, int duration)
{
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
tty->driver.break_ctl(tty, -1);
if (!signal_pending(current))
@@ -1708,7 +1713,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
case TIOCSWINSZ:
return tiocswinsz(tty, real_tty, (struct winsize *) arg);
case TIOCCONS:
- return tioccons(tty, real_tty);
+ return tioccons(inode, tty, real_tty);
case FIONBIO:
return fionbio(file, (int *) arg);
case TIOCEXCL:
@@ -2080,7 +2085,7 @@ static struct tty_driver dev_console_driver;
* Ok, now we can initialize the rest of the tty devices and can count
* on memory allocations, interrupts etc..
*/
-__initfunc(int tty_init(void))
+int __init tty_init(void)
{
if (sizeof(struct tty_struct) > PAGE_SIZE)
panic("size of tty structure > PAGE_SIZE!");
@@ -2148,6 +2153,9 @@ __initfunc(int tty_init(void))
#ifdef CONFIG_SERIAL
rs_init();
#endif
+#ifdef CONFIG_COMPUTONE
+ ip2_init();
+#endif
#ifdef CONFIG_MAC_SERIAL
macserial_init();
#endif
@@ -2178,6 +2186,9 @@ __initfunc(int tty_init(void))
#ifdef CONFIG_SPECIALIX
specialix_init();
#endif
+#ifdef CONFIG_SX
+ sx_init();
+#endif
#ifdef CONFIG_8xx
rs_8xx_init();
#endif /* CONFIG_8xx */
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 44dfbfcd8..c05b80392 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -59,7 +59,7 @@ void tty_wait_until_sent(struct tty_struct * tty, long timeout)
printk("waiting %s...(%d)\n", tty_name(tty, buf),
tty->driver.chars_in_buffer(tty));
#endif
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current))
goto stop_waiting;
if (!tty->driver.chars_in_buffer(tty))
diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c
index 55ff8eacc..108ea55a7 100644
--- a/drivers/char/tuner.c
+++ b/drivers/char/tuner.c
@@ -84,9 +84,11 @@ static struct tunertype tuners[] = {
// 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
16*170.00,16*450.00,0x02,0x04,0x01,0x8e,0xc2,623},
{"Temic 4036 FY5 NTSC", TEMIC, NTSC,
- 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
- {"Alps HSBH1", TEMIC, NTSC,
- 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732},
+ 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
+ {"Alps TSBH1",TEMIC,NTSC,
+ 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732},
+ {"Alps TSBE1",TEMIC,PAL,
+ 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732},
};
/* ---------------------------------------------------------------------- */
@@ -192,12 +194,13 @@ static int tuner_attach(struct i2c_device *device)
/*
* For now we only try and attach these tuners to the BT848
- * bus. This same module will however work different species
- * of card using these chips. Just change the constraints
+ * or ZORAN bus. This same module will however work different
+ * species of card using these chips. Just change the constraints
* (i2c doesn't have a totally clash free 'address' space)
*/
- if(device->bus->id!=I2C_BUSID_BT848)
+ if(device->bus->id!=I2C_BUSID_BT848 &&
+ device->bus->id!=I2C_BUSID_ZORAN)
return -EINVAL;
device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index 4db4e6efb..a25013fea 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -310,7 +310,7 @@ static struct file_operations vcs_fops = {
NULL /* fsync */
};
-__initfunc(int vcs_init(void))
+int __init vcs_init(void)
{
int error;
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index 39bb5f256..eb76d446d 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -57,24 +57,12 @@ extern int init_bw_qcams(struct video_init *);
#ifdef CONFIG_VIDEO_PLANB
extern int init_planbs(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_RTRACK2
extern int rtrack2_init(struct video_init *);
#endif
#ifdef CONFIG_RADIO_SF16FMI
extern int fmi_init(struct video_init *);
#endif
-#ifdef CONFIG_RADIO_MIROPCM20
-extern int pcm20_init(struct video_init *);
-#endif
-#ifdef CONFIG_RADIO_GEMTEK
-extern int gemtek_init(struct video_init *);
-#endif
#ifdef CONFIG_RADIO_TYPHOON
extern int typhoon_init(struct video_init *);
#endif
@@ -84,9 +72,6 @@ extern int cadet_init(struct video_init *);
#ifdef CONFIG_RADIO_TERRATEC
extern int terratec_init(struct video_init *);
#endif
-#ifdef CONFIG_VIDEO_PMS
-extern int init_pms_cards(struct video_init *);
-#endif
#ifdef CONFIG_VIDEO_ZORAN
extern int init_zoran_cards(struct video_init *);
#endif
@@ -105,33 +90,18 @@ static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_BWQCAM
{"bw-qcam", init_bw_qcams},
#endif
-#ifdef CONFIG_VIDEO_PMS
- {"PMS", init_pms_cards},
-#endif
#ifdef CONFIG_VIDEO_PLANB
{"planb", init_planbs},
#endif
-#ifdef CONFIG_RADIO_AZTECH
- {"Aztech", aztech_init},
-#endif
-#ifdef CONFIG_RADIO_RTRACK
- {"RTrack", rtrack_init},
-#endif
#ifdef CONFIG_RADIO_RTRACK2
{"RTrack2", rtrack2_init},
#endif
#ifdef CONFIG_RADIO_SF16FMI
{"SF16FMI", fmi_init},
#endif
-#ifdef CONFIG_RADIO_MIROPCM20
- {"PCM20", pcm20_init},
-#endif
#ifdef CONFIG_RADIO_CADET
{"Cadet", cadet_init},
#endif
-#ifdef CONFIG_RADIO_GEMTEK
- {"GemTek", gemtek_init},
-#endif
#ifdef CONFIG_RADIO_TYPHOON
{"radio-typhoon", typhoon_init},
#endif
@@ -144,7 +114,6 @@ static struct video_init video_init_list[]={
{"end", NULL}
};
-#if LINUX_VERSION_CODE >= 0x020100
/*
* Read will do some smarts later on. Buffer pin etc.
*/
@@ -160,7 +129,6 @@ static ssize_t video_read(struct file *file,
}
-
/*
* Write for now does nothing. No reason it shouldnt do overlay setting
* for some boards I guess..
@@ -191,31 +159,6 @@ static unsigned int video_poll(struct file *file, poll_table * wait)
}
-#else
-static int video_read(struct inode *ino,struct file *file,
- char *buf, int count)
-{
- int err;
- struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
- if (vfl->read)
- return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
- else
- return -EINVAL;
-}
-
-static int video_write(struct inode *ino,struct file *file, const char *buf,
- int count)
-{
- int err;
- struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
- if (vfl->write)
- return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
- else
- return 0;
-}
-
-#endif
-
/*
* Open a video device.
*/
diff --git a/drivers/char/vino.c b/drivers/char/vino.c
index 6e0036786..a9ac3086b 100644
--- a/drivers/char/vino.c
+++ b/drivers/char/vino.c
@@ -1,4 +1,4 @@
-/* $Id: vino.c,v 1.3 1999/02/09 23:54:24 ulfc Exp $
+/* $Id: vino.c,v 1.4 1999/02/09 23:59:36 ulfc Exp $
* drivers/char/vino.c
*
* (incomplete) Driver for the Vino Video input system found in SGI Indys.
@@ -9,7 +9,6 @@
* some more code.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -241,7 +240,7 @@ static struct video_device vino_dev = {
0
};
-__initfunc(int init_vino(struct video_device *dev))
+int __init init_vino(struct video_device *dev)
{
int err;
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index a3c00925d..020120d4d 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -62,7 +62,7 @@ struct vt_struct *vt_cons[MAX_NR_CONSOLES];
unsigned char keyboard_type = KB_101;
#if !defined(__alpha__) && !defined(__mips__)
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
#endif
unsigned int video_font_height;
@@ -670,7 +670,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDSIGACCEPT:
{
extern int spawnpid, spawnsig;
- if (!perm)
+ if (!perm || !capable(CAP_KILL))
return -EPERM;
if (arg < 1 || arg > _NSIG || arg == SIGKILL)
return -EINVAL;
@@ -1113,7 +1113,7 @@ int vt_waitactive(int vt)
add_wait_queue(&vt_activate_queue, &wait);
for (;;) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
retval = 0;
if (vt == fg_console)
break;
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index 174175808..1792bbac4 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -64,7 +64,7 @@ static int irq=11;
* Setup options
*/
-__initfunc(void wdt_setup(char *str, int *ints))
+void __init wdt_setup(char *str, int *ints)
{
if(ints[0]>0)
{
@@ -365,7 +365,7 @@ void cleanup_module(void)
#endif
-__initfunc(int wdt_init(void))
+int __init wdt_init(void)
{
printk("WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq);
if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL))