home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 4 / DATAFILE_PDCD4.iso / unix / armlinux / kernel_src / linux-2.0.,fff / linuxarm-2.0.18
Encoding:
Text File  |  1996-09-07  |  1.8 MB  |  69,168 lines

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. diff -u -X rej --recursive --new-file linux.orig/CREDITS linux/CREDITS
  2. --- linux.orig/CREDITS    Sat Sep  7 19:07:16 1996
  3. +++ linux/CREDITS    Fri Sep  6 21:14:50 1996
  4. @@ -692,6 +692,12 @@
  5.  S: D-64283 Darmstadt
  6.  S: Germany
  7.  
  8. +N: Russell King
  9. +E: rmk92@ecs.soton.ac.uk
  10. +D: Linux/arm port & hacker
  11. +S: 28 Waterer Gardens, Burgh Heath, Tadworth, Surrey. KT20 5PB
  12. +S: England
  13. +
  14.  N: Olaf Kirch
  15.  E: okir@monad.swb.de
  16.  D: Author of the Linux Network Administrators' Guide
  17. diff -u -X rej --recursive --new-file linux.orig/Documentation/Configure.help linux/Documentation/Configure.help
  18. --- linux.orig/Documentation/Configure.help    Sat Sep  7 18:59:20 1996
  19. +++ linux/Documentation/Configure.help    Sat Aug 10 10:29:48 1996
  20. @@ -322,6 +322,11 @@
  21.    in and removed from the running kernel whenever you want), say M
  22.    here and read Documentation/modules.txt. If unsure, say Y.
  23.  
  24. +Adfs Image File System (IMG)
  25. +CONFIG_BLK_DEV_IMG
  26. +  This is a device driver that allows access to partitions held in
  27. +  files on a RiscOS formatted hard disk drive.
  28. +
  29.  Support for Deskstation RPC44 
  30.  CONFIG_DESKSTATION_RPC44
  31.    This is a machine with a R4400 100 MHz CPU. To compile a Linux
  32. diff -u -X rej --recursive --new-file linux.orig/MAINTAINERS linux/MAINTAINERS
  33. --- linux.orig/MAINTAINERS    Sat Sep  7 19:00:01 1996
  34. +++ linux/MAINTAINERS    Sat Aug 17 23:13:11 1996
  35. @@ -341,6 +341,18 @@
  36.  M:    jam@acm.org
  37.  S:    Maintained
  38.  
  39. +ARM:
  40. +P:    Russell King
  41. +M:    rmk92@ecs.soton.ac.uk
  42. +L:    linux-arm@vger.rutgers.edu
  43. +W:    http://whirligig.ecs.soton.ac.uk/~rmk92/armlinux.html
  44. +S:    Maintained
  45. +
  46. +ARM MFM AND FLOPPY DRIVERS
  47. +P:    Dave Gilbert
  48. +M:    dag@cs.man.ac.uk
  49. +S:    Maintained
  50. +
  51.  REST:
  52.  P:    Linus Torvalds
  53.  S:    Buried alive in email
  54. diff -u -X rej --recursive --new-file linux.orig/Makefile linux/Makefile
  55. --- linux.orig/Makefile    Sat Sep  7 19:07:17 1996
  56. +++ linux/Makefile    Fri Sep  6 21:14:50 1996
  57. @@ -2,7 +2,7 @@
  58.  PATCHLEVEL = 0
  59.  SUBLEVEL = 18
  60.  
  61. -ARCH = i386
  62. +ARCH = arm
  63.  
  64.  #
  65.  # For SMP kernels, set this. We don't want to have this in the config file
  66. @@ -113,12 +113,16 @@
  67.  # Include the make variables (CC, etc...)
  68.  #
  69.  
  70. +# Modified 11/02/96 by Russell King
  71. +#    - Doesn't include the drivers subdirectory as standard.
  72. +#    - Modified the 'nm' line in vmlinux so that we remove local and absolute symbols.
  73. +
  74.  ARCHIVES    =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o net/network.a
  75.  FILESYSTEMS    =fs/filesystems.a
  76. -DRIVERS        =drivers/block/block.a \
  77. +DRIVERS     =drivers/block/block.a \
  78.           drivers/char/char.a
  79.  LIBS        =$(TOPDIR)/lib/lib.a
  80. -SUBDIRS        =kernel drivers mm fs net ipc lib
  81. +SUBDIRS        =kernel mm fs net ipc lib
  82.  
  83.  ifeq ($(CONFIG_ISDN),y)
  84.  DRIVERS := $(DRIVERS) drivers/isdn/isdn.a
  85. @@ -148,10 +152,14 @@
  86.  
  87.  include arch/$(ARCH)/Makefile
  88.  
  89. +ifndef CONFIG_ARM
  90. +SUBDIRS := drivers $(SUBDIRS)
  91. +endif
  92. +
  93.  ifdef SMP
  94.  
  95.  .S.s:
  96. -    $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.s $<
  97. +    $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
  98.  .S.o:
  99.      $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
  100.  
  101. @@ -176,9 +184,9 @@
  102.          $(FILESYSTEMS) \
  103.          $(DRIVERS) \
  104.          $(LIBS) -o vmlinux
  105. -    $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | sort > System.map
  106. +    $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)\|\( A \)\|\( t L\)' | sort > System.map
  107.  
  108. -symlinks:
  109. +symlinks::
  110.      rm -f include/asm
  111.      ( cd include ; ln -sf asm-$(ARCH) asm)
  112.  
  113. @@ -316,7 +324,7 @@
  114.      rm -fr modules/*
  115.      rm -f submenu*
  116.  
  117. -mrproper: clean
  118. +mrproper:: clean
  119.      rm -f include/linux/autoconf.h include/linux/version.h
  120.      rm -f drivers/sound/local.h drivers/sound/.defines
  121.      rm -f drivers/scsi/aic7xxx_asm drivers/scsi/aic7xxx_seq.h
  122. @@ -331,11 +339,11 @@
  123.      rm -f $(TOPDIR)/include/linux/modversions.h
  124.      rm -f $(TOPDIR)/include/linux/modules/*
  125.  
  126. -
  127.  distclean: mrproper
  128.      rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
  129. -                -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
  130. -                -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS
  131. +        -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
  132. +        -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS
  133. +
  134.  
  135.  backup: mrproper
  136.      cd .. && tar cf - linux/ | gzip -9 > backup.gz
  137. diff -u -X rej --recursive --new-file linux.orig/README.arm linux/README.arm
  138. --- linux.orig/README.arm    Thu Jan  1 01:00:00 1970
  139. +++ linux/README.arm    Sat Aug 17 23:32:37 1996
  140. @@ -0,0 +1,121 @@
  141. +ARM Linux 2.0.13
  142. +================
  143. +
  144. +*** Warning ***
  145. +---------------
  146. +
  147. +  Currently, 1.3.45 onwards contains new Image file drivers (IMG)
  148. +  that are in alpha testing.  I make no claims to their stability
  149. +  at the moment, so use it at your peril - it may destroy your
  150. +  hard disk!
  151. +
  152. +Contributors
  153. +------------
  154. +
  155. +  Here is a list of people actively working on the project (If you
  156. +  wish to be added to the list, please email me):
  157. +
  158. +  Name: Russell King
  159. +  Mail: rmk92@ecs.soton.ac.uk
  160. +  Desc: Original developer of ARM Linux, A5000 code and project
  161. +        co-ordinator.
  162. +
  163. +  Name: Dave Gilbert
  164. +  Mail: gilbertd@cs.man.ac.uk
  165. +  Desc: A3/4/5xx floppy and hard disk code maintainer.
  166. +
  167. +  Name: Ian Jeffray
  168. +  Mail: ian_jeffray@MENTORG.COM
  169. +  Desc: A3/4/5xx serial and parallel port code maintainer.
  170. +
  171. +
  172. +Notes
  173. +=====
  174. +
  175. +Cross compilation
  176. +-----------------
  177. +
  178. +  In order to compile ARM Linux, you will need the cross-utilities on
  179. +  ftp.ecs.soton.ac.uk in the /pub/armlinux/cross-compilers subdirectory,
  180. +  or a working version of ARM Linux with the compiler distribution.
  181. +
  182. +  To configure the kernel, edit the top-level makefile, replacing:
  183. +
  184. +    ARCH = i386 with ARCH = arm
  185. +
  186. +  Also, alter CC= and HOSTCC= to point to your compiler.
  187. +
  188. +  Then examine arch/arm/Makefile for sub-architecture options (including
  189. +  processor and machine type), setting them as required.
  190. +
  191. +  Do a 'make config', followed by 'make dep', and finally 'make all' to
  192. +  build the kernel (vmlinux).  A compressed image can be built by doing
  193. +  a 'make zImage' instead of 'make all'.
  194. +
  195. +  Please send all patches, bug reports and code for the ARM Linux project
  196. +  to rmk92@ecs.soton.ac.uk.  Patches will not be included into future
  197. +  kernels unless they come to me (or the relevant person concerned).
  198. +
  199. +Kernel initialisation abort codes
  200. +---------------------------------
  201. +
  202. +  When the kernel is unable to boot, it will if possible display a colour
  203. +  at the top of the screen.  The colours have the following significance
  204. +  when run in a 16 colour mode with the default palette:
  205. +
  206. +    Stripes of White,Red,Yellow,Green:
  207. +       Wrong/incorrect processor architecture detected.
  208. +    Red:
  209. +       Undefined instruction handler was entered.
  210. +    Green:
  211. +       Prefetch abort handler entered.
  212. +    Yellow:
  213. +       Data abort handler entered.
  214. +    Magenta:
  215. +       Address exception handler entered.
  216. +
  217. +Request to developers
  218. +---------------------
  219. +
  220. +  When writing device drivers which include a separate assember file, please
  221. +  include it in with the C file, and not the arch/arm/lib directory.  This
  222. +  helps to allow the driver to be compiled as a loadable module without
  223. +  requiring half the code to be needlessly compiled into the main kernel
  224. +  image.
  225. +
  226. +IMG drivers
  227. +-----------
  228. +
  229. +  The new image drivers (introduced in v1.3.45) have changed again.  They
  230. +  now hook into the ll_rw code, and appears to give 770k/s now (used to be
  231. +  660k/s).  However, they're not fully tested yet!
  232. +
  233. +ST506 hard drives
  234. +-----------------
  235. +
  236. +  The ST506 hard drive controllers seem to be working fine (if
  237. +  a little slowly).  At the moment they will only work off the
  238. +  controllers on an A4x0's motherboard, but for it to work
  239. +  off a Podule just requires someone with a podule to add the
  240. +  addresses for the IRQ mask and the HDC base to the source.
  241. +
  242. +  As of 31/3/96 it works with two drives (you should get the
  243. +  ADFS *configure harddrive set to 2). I've got an internal
  244. +  20MB and a great big external 5.25" FH 64MB drive (who could
  245. +  ever want more :-) ).
  246. +
  247. +  I've just got 240K/s off it (a dd with bs=128k); thats about half of what
  248. +  RiscOS gets; but its a heck of a lot better than the 50K/s I was getting
  249. +  last week :-)
  250. +
  251. +  Known bug: Drive data errors can cause a hang; including cases where
  252. +  the controller has fixed the error using ECC. (Possibly ONLY
  253. +  in that case...hmm).
  254. +
  255. +
  256. +1772 Floppy
  257. +-----------
  258. +  This also seems to work OK, but hasn't been stressed much lately.
  259. +  It hasn't got any code for disc change detection in there at the
  260. +  moment which could be a bit of a problem!  Suggestions on the
  261. +  correct way to do this are welcome.
  262. diff -u -X rej --recursive --new-file linux.orig/arch/arm/Makefile linux/arch/arm/Makefile
  263. --- linux.orig/arch/arm/Makefile    Thu Jan  1 01:00:00 1970
  264. +++ linux/arch/arm/Makefile    Sun Aug 25 10:33:23 1996
  265. @@ -0,0 +1,135 @@
  266. +#
  267. +# arch/arm/Makefile
  268. +#
  269. +# THIS IS THE VERSION/[PATCHLEVELS]:  2.0.10/[2,1,0]
  270. +#  [RMK,DAG,IC]
  271. +#
  272. +# This file is included by the global makefile so that you can add your own
  273. +# architecture-specific flags and dependencies. Remember to do have actions
  274. +# for "archclean" and "archdep" for cleaning up and making dependencies for
  275. +# this architecture
  276. +#
  277. +# This file is subject to the terms and conditions of the GNU General Public
  278. +# License.  See the file "COPYING" in the main directory of this archive
  279. +# for more details.
  280. +#
  281. +# Copyright (C) 1995, 1996 by Russell King
  282. +
  283. +
  284. +# MACHINE can be: arc a5k rpc
  285. +# PROCESSOR can be: arm2 arm3 arm6
  286. +# Computer:    MACHINE:  PROCESSOR:
  287. +#  A3xx        arc      arm2
  288. +#  A4xx        arc      arm2
  289. +#  A5xx        arc      arm2
  290. +#  A5000    a5k      arm3
  291. +#  A4000    a5k      arm3
  292. +#  A3020    a5k      arm3 (arm250 really)
  293. +#
  294. +CONFIG_ARCH_A5K      = 1
  295. +#CONFIG_ARCH_ARM      = 1
  296. +#CONFIG_ARCH_SA110EVAL     = 1
  297. +#
  298. +#CONFIG_PROC_ARM2     = 1
  299. +CONFIG_PROC_ARM3     = 1
  300. +#CONFIG_PROC_ARM6     = 1
  301. +#CONFIG_PROC_SA110     = 1
  302. +
  303. +# Machine Architecture
  304. +ifdef CONFIG_ARCH_A5K
  305. +CFLAGS        += -DCONFIG_ARCH_A5K
  306. +MACHINE         = a5k
  307. +endif
  308. +
  309. +ifdef CONFIG_ARCH_ARM
  310. +CFLAGS        += -DCONFIG_ARCH_ARM
  311. +MACHINE         = a5k
  312. +endif
  313. +
  314. +ifdef CONFIG_ARCH_SA110EVAL
  315. +CFLAGS        += -DCONFIG_ARCH_SA110EVAL
  316. +MACHINE         = sa110eval
  317. +endif
  318. +
  319. +# Processor Architecture
  320. +ifdef CONFIG_PROC_ARM2
  321. +CFLAGS_ARCH    += -m2
  322. +PROCESSOR     = arm2
  323. +TEXTADDR     = 0x01800000
  324. +endif
  325. +
  326. +ifdef CONFIG_PROC_ARM3
  327. +CFLAGS_ARCH    += -m3
  328. +PROCESSOR     = arm3
  329. +TEXTADDR     = 0x01800000
  330. +endif
  331. +
  332. +ifdef CONFIG_PROC_ARM6
  333. +CFLAGS_ARCH    += -m6
  334. +PROCESSOR     = arm6
  335. +TEXTADDR     = 0xC0000000
  336. +endif
  337. +
  338. +ifdef CONFIG_PROC_SA110
  339. +CFLAGS_ARCH    += -m6
  340. +PROCESSOR     = sa110
  341. +TEXTADDR     = 0xC0000000
  342. +endif
  343. +
  344. +OBJDUMP         = objdump
  345. +CPP         = $(CC) -E
  346. +ARCHCC        := $(word 1,$(CC))
  347. +GCCLIB        := `$(ARCHCC) $(CFLAGS_ARCH) --print-libgcc-file-name`
  348. +HOSTCFLAGS    := $(CFLAGS:-fomit-frame-pointer=)
  349. +CFLAGS        := $(CFLAGS:-fomit-frame-pointer=) $(CFLAGS_ARCH)
  350. +LINKFLAGS     = -Ttext $(TEXTADDR)
  351. +ZLINKFLAGS     = -N -Ttext $(TEXTADDR)
  352. +
  353. +HEAD        := arch/arm/kernel/head.o
  354. +SUBDIRS        := $(SUBDIRS) arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/drivers
  355. +ARCHIVES    := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(ARCHIVES)
  356. +LIBS        := arch/arm/lib/lib.a $(LIBS) $(GCCLIB)
  357. +DRIVERS        := arch/arm/drivers/block/block.a arch/arm/drivers/char/char.a \
  358. +           arch/arm/drivers/net/net.a
  359. +
  360. +ifdef CONFIG_SOUND
  361. +DRIVERS        := $(DRIVERS) arch/arm/drivers/sound/sound.a
  362. +endif
  363. +
  364. +ifdef CONFIG_SCSI
  365. +DRIVERS        := $(DRIVERS) arch/arm/drivers/scsi/scsi.a
  366. +endif
  367. +
  368. +symlinks::
  369. +    rm -f include/asm-arm/arch include/asm-arm/proc
  370. +    (cd include/asm-arm; ln -sf arch-$(MACHINE) arch; ln -sf proc-$(PROCESSOR) proc)
  371. +
  372. +mrproper::
  373. +    rm -f include/asm-arm/arch include/asm-arm/proc
  374. +    @$(MAKE) -C arch/$(ARCH)/drivers mrproper
  375. +
  376. +arch/arm/kernel: dummy
  377. +    $(MAKE) linuxsubdirs SUBDIRS=arch/arm/kernel
  378. +
  379. +arch/arm/mm: dummy
  380. +    $(MAKE) linuxsubdirs SUBDIRS=arch/arm/mm
  381. +
  382. +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
  383. +
  384. +zImage:
  385. +    @$(MAKEBOOT) zImage
  386. +
  387. +zinstall:
  388. +    @$(MAKEBOOT) zinstall
  389. +
  390. +Image: vmlinux
  391. +    @$(MAKEBOOT) Image
  392. +
  393. +install: vmlinux
  394. +    @$(MAKEBOOT) install
  395. +
  396. +archclean:
  397. +    @$(MAKEBOOT) clean
  398. +
  399. +archdep:
  400. +    @$(MAKEBOOT) dep
  401. diff -u -X rej --recursive --new-file linux.orig/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile
  402. --- linux.orig/arch/arm/boot/Makefile    Thu Jan  1 01:00:00 1970
  403. +++ linux/arch/arm/boot/Makefile    Mon Mar 11 20:46:17 1996
  404. @@ -0,0 +1,34 @@
  405. +#
  406. +# arch/arm/boot/Makefile
  407. +#
  408. +# This file is subject to the terms and conditions of the GNU General Public
  409. +# License.  See the file "COPYING" in the main directory of this archive
  410. +# for more details.
  411. +#
  412. +# Copyright (C) 1995, 1996 Russell King
  413. +#
  414. +
  415. +Image:    $(CONFIGURE) tools/build $(TOPDIR)/vmlinux
  416. +    tools/build $(TOPDIR)/vmlinux > Image
  417. +    sync
  418. +
  419. +zImage:    $(CONFIGURE) tools/build compressed/vmlinux
  420. +    tools/build compressed/vmlinux > zImage
  421. +
  422. +compressed/vmlinux: $(TOPDIR)/vmlinux dep
  423. +    @$(MAKE) -C compressed vmlinux
  424. +
  425. +install: $(CONFIGURE) Image
  426. +    sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) Image $(TOPDIR)/System.map "$(INSTALL_PATH)"
  427. +
  428. +zinstall: $(CONFIGURE) zImage
  429. +    sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
  430. +
  431. +tools/build: tools/build.c
  432. +    $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
  433. +
  434. +clean:
  435. +    rm -f Image zImage tools/build
  436. +    @$(MAKE) -C compressed clean
  437. +
  438. +dep:
  439. diff -u -X rej --recursive --new-file linux.orig/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile
  440. --- linux.orig/arch/arm/boot/compressed/Makefile    Thu Jan  1 01:00:00 1970
  441. +++ linux/arch/arm/boot/compressed/Makefile    Thu Jul 11 09:44:26 1996
  442. @@ -0,0 +1,59 @@
  443. +#
  444. +# linux/arch/arm/boot/compressed/Makefile
  445. +#
  446. +# create a compressed vmlinux image from the original vmlinux
  447. +#
  448. +# With this config, max compressed image size = 640k
  449. +# Uncompressed image size = 1.3M (text+data)
  450. +
  451. +CFLAGS = -O2 -DSTDC_HEADERS
  452. +LOADADDR = 0x01800000
  453. +RELADDR = 0x01960000
  454. +ARFLAGS = rcv
  455. +
  456. +SYSTEM = $(TOPDIR)/vmlinux
  457. +DECOMP_OBJS = misc.o ../../lib/ll_char_wr.o
  458. +
  459. +
  460. +all:        vmlinux
  461. +
  462. +vmlinux:    head.o piggy.o
  463. +        $(LD) -Ttext=$(LOADADDR) -o vmlinux head.o piggy.o
  464. +
  465. +head.o:     head.S
  466. +        $(CC) -traditional -DRELADDR=$(RELADDR) -c head.S
  467. +
  468. +piggy.o:    decomphead.o decompress.a compressed.o
  469. +        $(LD) -s -Ttext=$(RELADDR) -o a.out decomphead.o compressed.o decompress.a
  470. +        strip a.out
  471. +        ./piggyback a.out > piggy.o
  472. +        rm -f a.out
  473. +
  474. +compressed.o:    $(SYSTEM) xtract piggyback
  475. +        ./xtract $(SYSTEM) | gzip -9 | ./piggyback > compressed.o
  476. +
  477. +
  478. +# rules for decompression part of kernel
  479. +
  480. +decompress.a:    $(DECOMP_OBJS)
  481. +        $(AR) $(ARFLAGS) decompress.a $(DECOMP_OBJS)
  482. +
  483. +decomphead.o:    decomphead.S
  484. +        $(CC) -traditional -DLOADADDR=$(LOADADDR) -c decomphead.S
  485. +
  486. +../../lib/ll_char_wr.o:
  487. +        make -C ../../lib ll_char_wr.o
  488. +
  489. +
  490. +# rules for extracting & piggybacking the kernel
  491. +
  492. +xtract:     xtract.c
  493. +        $(HOSTCC) $(HOSTCFLAGS) -o xtract xtract.c
  494. +
  495. +piggyback:    piggyback.c
  496. +        $(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c
  497. +
  498. +
  499. +clean:
  500. +        rm -f xtract piggyback vmlinux decompress.a a.out
  501. +
  502. diff -u -X rej --recursive --new-file linux.orig/arch/arm/boot/compressed/decomphead.S linux/arch/arm/boot/compressed/decomphead.S
  503. --- linux.orig/arch/arm/boot/compressed/decomphead.S    Thu Jan  1 01:00:00 1970
  504. +++ linux/arch/arm/boot/compressed/decomphead.S    Thu Jul 11 09:59:45 1996
  505. @@ -0,0 +1,25 @@
  506. +/*
  507. + *  linux/arch/arm/boot/decomphead.S
  508. + */
  509. +
  510. +.text
  511. +    .global    __stext
  512. +__stext:
  513. +    b    start
  514. +LC0:
  515. +    .word    __edata
  516. +    .word    __end
  517. +    .word    LOADADDR + 0x23
  518. +    .word    _user_stack+4096
  519. +start:
  520. +    adr    r1, LC0
  521. +    ldmia    r1, {r2, r3, r4, sp}
  522. +    mov    r1, #0
  523. +clrzlp:    str    r1, [r2], #4
  524. +    cmp    r2, r3
  525. +    blt    clrzlp
  526. +    bic    r0, r4, #3
  527. +    bl    _decompress_kernel
  528. +    mov    r0, #0
  529. +    mov    pc, r4
  530. +
  531. diff -u -X rej --recursive --new-file linux.orig/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S
  532. --- linux.orig/arch/arm/boot/compressed/head.S    Thu Jan  1 01:00:00 1970
  533. +++ linux/arch/arm/boot/compressed/head.S    Sun Feb 11 09:32:10 1996
  534. @@ -0,0 +1,36 @@
  535. +        .text
  536. +        .align
  537. +
  538. +@ Entry point
  539. +@ r0 = kernel info page
  540. +@ r1 = kernel length (length of this code+data)
  541. +
  542. +        .global __stext
  543. +__stext:
  544. +        b    start
  545. +LC0:
  546. +        .word    _input_data
  547. +        .word    _input_end
  548. +        .word    RELADDR
  549. +start:
  550. +        teq    r0, #0
  551. +        beq    newparams
  552. +        mov    r4,     #0x02000000
  553. +        add    r4, r4, #0x0007C000    @ = 0x0207C000 [new param location]
  554. +        mov    r3,     #0x4000
  555. +        sub    r3, r3, #4
  556. +lp2:        ldmia    r0!, {r5, r6, r7, r8, r9, r10, r11, r12}
  557. +        stmia    r4!, {r5, r6, r7, r8, r9, r10, r11, r12}
  558. +        subs    r3, r3, #32
  559. +        bpl    lp2
  560. +newparams:    adr    r3, LC0
  561. +        ldmia    r3, {r2, r3, r4}
  562. +        sub    r3, r3, r2
  563. +        mov    r1, r4
  564. +lp:        ldmia    r2!, {r5, r6, r7, r8, r9, r10, r11, r12}
  565. +        stmia    r4!, {r5, r6, r7, r8, r9, r10, r11, r12}
  566. +        subs    r3, r3, #32
  567. +        bpl    lp
  568. +        ldr    r1, [r1, #0x14]
  569. +        mov    pc, r1
  570. +
  571. diff -u -X rej --recursive --new-file linux.orig/arch/arm/boot/compressed/misc.c linux/arch/arm/boot/compressed/misc.c
  572. --- linux.orig/arch/arm/boot/compressed/misc.c    Thu Jan  1 01:00:00 1970
  573. +++ linux/arch/arm/boot/compressed/misc.c    Thu Jul 11 09:57:17 1996
  574. @@ -0,0 +1,402 @@
  575. +/*
  576. + * misc.c
  577. + * 
  578. + * This is a collection of several routines from gzip-1.0.3 
  579. + * adapted for Linux.
  580. + *
  581. + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
  582. + * puts by Nick Holloway 1993
  583. + */
  584. +
  585. +#include <string.h>
  586. +
  587. +#include <asm/segment.h>
  588. +#include <asm/io.h>
  589. +
  590. +/*
  591. + * gzip delarations
  592. + */
  593. +
  594. +#define OF(args)  args
  595. +#define STATIC static
  596. +
  597. +/*
  598. + * Optimised C version of memzero for the ARM.
  599. + */
  600. +extern __inline__ __ptr_t memzero (__ptr_t s, size_t n)
  601. +{
  602. +    int i = n;
  603. +    union { int i; char *cp; unsigned long *lp; } ss;
  604. +    ss.cp = (char *)s;
  605. +
  606. +    if (i > 3) {
  607. +        while (ss.i & 3) {
  608. +            *ss.cp++ = 0;
  609. +            i --;
  610. +        }
  611. +    }
  612. +
  613. +    while (i > 32) {
  614. +        *(unsigned long *)ss.lp++ = 0;
  615. +        *(unsigned long *)ss.lp++ = 0;
  616. +        *(unsigned long *)ss.lp++ = 0;
  617. +        *(unsigned long *)ss.lp++ = 0;
  618. +        *(unsigned long *)ss.lp++ = 0;
  619. +        *(unsigned long *)ss.lp++ = 0;
  620. +        *(unsigned long *)ss.lp++ = 0;
  621. +        *(unsigned long *)ss.lp++ = 0;
  622. +        i -= 32;
  623. +    }
  624. +
  625. +    for (; i > 0; i--)
  626. +        *ss.cp++ = 0;
  627. +    return s;
  628. +}
  629. +
  630. +typedef unsigned char  uch;
  631. +typedef unsigned short ush;
  632. +typedef unsigned long  ulg;
  633. +
  634. +#define WSIZE 0x8000        /* Window size must be at least 32k, */
  635. +                /* and a power of two */
  636. +
  637. +static uch *inbuf;        /* input buffer */
  638. +static uch window[WSIZE];    /* Sliding window buffer */
  639. +
  640. +static unsigned insize = 0;    /* valid bytes in inbuf */
  641. +static unsigned inptr = 0;    /* index of next byte to be processed in inbuf */
  642. +static unsigned outcnt = 0;    /* bytes in output buffer */
  643. +
  644. +/* gzip flag byte */
  645. +#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
  646. +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
  647. +#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
  648. +#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
  649. +#define COMMENT      0x10 /* bit 4 set: file comment present */
  650. +#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
  651. +#define RESERVED     0xC0 /* bit 6,7:   reserved */
  652. +
  653. +#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
  654. +
  655. +/* Diagnostic functions */
  656. +#ifdef DEBUG
  657. +#  define Assert(cond,msg) {if(!(cond)) error(msg);}
  658. +#  define Trace(x) fprintf x
  659. +#  define Tracev(x) {if (verbose) fprintf x ;}
  660. +#  define Tracevv(x) {if (verbose>1) fprintf x ;}
  661. +#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
  662. +#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
  663. +#else
  664. +#  define Assert(cond,msg)
  665. +#  define Trace(x)
  666. +#  define Tracev(x)
  667. +#  define Tracevv(x)
  668. +#  define Tracec(c,x)
  669. +#  define Tracecv(c,x)
  670. +#endif
  671. +
  672. +static int  fill_inbuf(void);
  673. +static void flush_window(void);
  674. +static void error(char *m);
  675. +static void gzip_mark(void **);
  676. +static void gzip_release(void **);
  677. +
  678. +/*
  679. + * These are set up by the setup-routine at boot-time:
  680. + */
  681. +
  682. +struct param_struct
  683. +{
  684. +    unsigned long page_size;
  685. +    unsigned long nr_pages;
  686. +    unsigned long ramdisk_size;
  687. +    unsigned long mountrootrdonly;
  688. +    unsigned long rootdev;
  689. +    unsigned long video_num_cols;
  690. +    unsigned long video_num_rows;
  691. +    unsigned long video_x;
  692. +    unsigned long video_y;
  693. +    unsigned long memc_control_reg;
  694. +    unsigned char sounddefault;
  695. +    unsigned char adfsdrives;
  696. +    unsigned char bytes_per_char_h;
  697. +    unsigned char bytes_per_char_v;
  698. +    unsigned long unused[256/4-11];
  699. +    char paths[8][128];
  700. +    char commandline[256];
  701. +};
  702. +
  703. +static struct param_struct *params=(struct param_struct *)0x0207C000; 
  704. +
  705. +extern char input_data[], input_end[];
  706. +
  707. +static long bytes_out = 0;
  708. +static uch *output_data;
  709. +static unsigned long output_ptr = 0;
  710. +
  711. +static void *malloc(int size);
  712. +static void free(void *where);
  713. +static void error(char *m);
  714. +static void gzip_mark(void **);
  715. +static void gzip_release(void **);
  716. +
  717. +static void puts(const char *);
  718. +
  719. +unsigned int bytes_per_char_h;
  720. +unsigned int video_num_lines;
  721. +unsigned int video_num_columns;
  722. +static unsigned int white;
  723. +static unsigned char *vidmem = (unsigned char *)0x02000000;
  724. +
  725. +extern int end;
  726. +static long free_mem_ptr = (long)&end;
  727. +
  728. +#define HEAP_SIZE 0x2000
  729. +
  730. +#include "../../../../lib/inflate.c"
  731. +
  732. +static void *malloc(int size)
  733. +{
  734. +    void *p;
  735. +
  736. +    if (size <0) error("Malloc error\n");
  737. +    if (free_mem_ptr <= 0) error("Memory error\n");
  738. +
  739. +    free_mem_ptr = (free_mem_ptr + 3) & ~3;    /* Align */
  740. +
  741. +    p = (void *)free_mem_ptr;
  742. +    free_mem_ptr += size;
  743. +
  744. +    /*
  745. +     * The part of the compressed kernel which has already been expanded
  746. +     * is no longer needed. Therefore we can reuse it for malloc.
  747. +     * With bigger kernels, this is necessary.
  748. +     */
  749. +    if (free_mem_ptr >= 0x01a00000)
  750. +        error("\nOut of memory\n");
  751. +    return p;
  752. +}
  753. +
  754. +static void free(void *where)
  755. +{    /* Don't care */
  756. +}
  757. +
  758. +static void gzip_mark(void **ptr)
  759. +{
  760. +    *ptr = (void *) free_mem_ptr;
  761. +}
  762. +
  763. +static void gzip_release(void **ptr)
  764. +{
  765. +    free_mem_ptr = (long) *ptr;
  766. +}
  767. +
  768. +const char cmap_80[][8]=
  769. +{
  770. + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /*   */
  771. + {0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x00}, /* ! */
  772. + {0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, /* " */
  773. + {0x36,0x36,0x7F,0x36,0x7F,0x36,0x36,0x00}, /* # */
  774. + {0x0C,0x3F,0x68,0x3E,0x0B,0x7E,0x18,0x00}, /* $ */
  775. + {0x60,0x66,0x0C,0x18,0x30,0x66,0x06,0x00}, /* % */
  776. + {0x38,0x6C,0x6C,0x38,0x6D,0x66,0x3B,0x00}, /* & */
  777. + {0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, /* ' */
  778. + {0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, /* ( */
  779. + {0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, /* ) */
  780. + {0x00,0x18,0x7E,0x3C,0x7E,0x18,0x00,0x00}, /* * */
  781. + {0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00}, /* + */
  782. + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, /* , */
  783. + {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, /* - */
  784. + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, /* . */
  785. + {0x00,0x06,0x0C,0x18,0x30,0x60,0x00,0x00}, /* / */
  786. + {0x3C,0x66,0x6E,0x7E,0x76,0x66,0x3C,0x00}, /* 0 */
  787. + {0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00}, /* 1 */
  788. + {0x3C,0x66,0x06,0x0C,0x18,0x30,0x7E,0x00}, /* 2 */
  789. + {0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, /* 3 */
  790. + {0x0C,0x1C,0x3C,0x6C,0x7E,0x0C,0x0C,0x00}, /* 4 */
  791. + {0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, /* 5 */
  792. + {0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, /* 6 */
  793. + {0x7E,0x06,0x0C,0x18,0x30,0x30,0x30,0x00}, /* 7 */
  794. + {0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, /* 8 */
  795. + {0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, /* 9 */
  796. + {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x00}, /* : */
  797. + {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x30}, /* ; */
  798. + {0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, /* < */
  799. + {0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00}, /* = */
  800. + {0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, /* > */
  801. + {0x3C,0x66,0x0C,0x18,0x18,0x00,0x18,0x00}, /* ? */
  802. + {0x3C,0x66,0x6E,0x6A,0x6E,0x60,0x3C,0x00}, /* @ */
  803. + {0x3C,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, /* A */
  804. + {0x7C,0x66,0x66,0x7C,0x66,0x66,0x7C,0x00}, /* B */
  805. + {0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x00}, /* C */
  806. + {0x78,0x6C,0x66,0x66,0x66,0x6C,0x78,0x00}, /* D */
  807. + {0x7E,0x60,0x60,0x7C,0x60,0x60,0x7E,0x00}, /* E */
  808. + {0x7E,0x60,0x60,0x7C,0x60,0x60,0x60,0x00}, /* F */
  809. + {0x3C,0x66,0x60,0x6E,0x66,0x66,0x3C,0x00}, /* G */
  810. + {0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, /* H */
  811. + {0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00}, /* I */
  812. + {0x3E,0x0C,0x0C,0x0C,0x0C,0x6C,0x38,0x00}, /* J */
  813. + {0x66,0x6C,0x78,0x70,0x78,0x6C,0x66,0x00}, /* K */
  814. + {0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00}, /* L */
  815. + {0x63,0x77,0x7F,0x6B,0x6B,0x63,0x63,0x00}, /* M */
  816. + {0x66,0x66,0x76,0x7E,0x6E,0x66,0x66,0x00}, /* N */
  817. + {0x3C,0x66,0x66,0x66,0x66,0x66,0x3C,0x00}, /* O */
  818. + {0x7C,0x66,0x66,0x7C,0x60,0x60,0x60,0x00}, /* P */
  819. + {0x3C,0x66,0x66,0x66,0x6A,0x6C,0x36,0x00}, /* Q */
  820. + {0x7C,0x66,0x66,0x7C,0x6C,0x66,0x66,0x00}, /* R */
  821. + {0x3C,0x66,0x60,0x3C,0x06,0x66,0x3C,0x00}, /* S */
  822. + {0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, /* T */
  823. + {0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00}, /* U */
  824. + {0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, /* V */
  825. + {0x63,0x63,0x6B,0x6B,0x7F,0x77,0x63,0x00}, /* W */
  826. + {0x66,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00}, /* X */
  827. + {0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00}, /* Y */
  828. + {0x7E,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00}, /* Z */
  829. + {0x7C,0x60,0x60,0x60,0x60,0x60,0x7C,0x00}, /* [ */
  830. + {0x00,0x60,0x30,0x18,0x0C,0x06,0x00,0x00}, /* \ */
  831. + {0x3E,0x06,0x06,0x06,0x06,0x06,0x3E,0x00}, /* ] */
  832. + {0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00}, /* ^ */
  833. + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, /* _ */
  834. + {0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00}, /* ` */
  835. + {0x00,0x00,0x3C,0x06,0x3E,0x66,0x3E,0x00}, /* a */
  836. + {0x60,0x60,0x7C,0x66,0x66,0x66,0x7C,0x00}, /* b */
  837. + {0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, /* c */
  838. + {0x06,0x06,0x3E,0x66,0x66,0x66,0x3E,0x00}, /* d */
  839. + {0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, /* e */
  840. + {0x1C,0x30,0x30,0x7C,0x30,0x30,0x30,0x00}, /* f */
  841. + {0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x3C}, /* g */
  842. + {0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x00}, /* h */
  843. + {0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, /* i */
  844. + {0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x70}, /* j */
  845. + {0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00}, /* k */
  846. + {0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, /* l */
  847. + {0x00,0x00,0x36,0x7F,0x6B,0x6B,0x63,0x00}, /* m */
  848. + {0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, /* n */
  849. + {0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, /* o */
  850. + {0x00,0x00,0x7C,0x66,0x66,0x7C,0x60,0x60}, /* p */
  851. + {0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x07}, /* q */
  852. + {0x00,0x00,0x6C,0x76,0x60,0x60,0x60,0x00}, /* r */
  853. + {0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, /* s */
  854. + {0x30,0x30,0x7C,0x30,0x30,0x30,0x1C,0x00}, /* t */
  855. + {0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x00}, /* u */
  856. + {0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, /* v */
  857. + {0x00,0x00,0x63,0x6B,0x6B,0x7F,0x36,0x00}, /* w */
  858. + {0x00,0x00,0x66,0x3C,0x18,0x3C,0x66,0x00}, /* x */
  859. + {0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x3C}, /* y */
  860. + {0x00,0x00,0x7E,0x0C,0x18,0x30,0x7E,0x00}, /* z */
  861. + {0x0C,0x18,0x18,0x70,0x18,0x18,0x0C,0x00}, /* { */
  862. + {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, /* | */
  863. + {0x30,0x18,0x18,0x0E,0x18,0x18,0x30,0x00}, /* } */
  864. + {0x31,0x6B,0x46,0x00,0x00,0x00,0x00,0x00}, /* ~ */
  865. + {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}  /*  */
  866. +};
  867. +
  868. +static void puts(const char *s)
  869. +{
  870. +    extern void ll_write_char(char *, unsigned long);
  871. +    int x,y;
  872. +    unsigned char c;
  873. +    char *ptr;
  874. +
  875. +    x = params->video_x;
  876. +    y = params->video_y;
  877. +
  878. +    while ( ( c = *(unsigned char *)s++ ) != '\0' ) {
  879. +        if ( c == '\n' ) {
  880. +            x = 0;
  881. +            if ( ++y >= video_num_lines ) {
  882. +                y--;
  883. +            }
  884. +        } else {
  885. +            ptr = vidmem + (y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h;
  886. +            ll_write_char (ptr, c|(white<<8));
  887. +            if ( ++x >= video_num_columns ) {
  888. +                x = 0;
  889. +                if ( ++y >= video_num_lines ) {
  890. +                    y--;
  891. +                }
  892. +            }
  893. +        }
  894. +    }
  895. +
  896. +    params->video_x = x;
  897. +    params->video_y = y;
  898. +}
  899. +        
  900. +__ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
  901. +                size_t __n)
  902. +{
  903. +    int i;
  904. +    char *d = (char *)__dest, *s = (char *)__src;
  905. +
  906. +    for (i=0;i<__n;i++) d[i] = s[i];
  907. +}
  908. +
  909. +/* ===========================================================================
  910. + * Fill the input buffer. This is called only when the buffer is empty
  911. + * and at least one byte is really needed.
  912. + */
  913. +int fill_inbuf()
  914. +{
  915. +    if (insize != 0) {
  916. +    error("ran out of input data\n");
  917. +    }
  918. +
  919. +    inbuf = input_data;
  920. +    insize = input_end - input_data;
  921. +    inptr = 1;
  922. +    return inbuf[0];
  923. +}
  924. +
  925. +/* ===========================================================================
  926. + * Write the output window window[0..outcnt-1] and update crc and bytes_out.
  927. + * (Used for the decompressed data only.)
  928. + */
  929. +void flush_window()
  930. +{
  931. +    ulg c = crc;
  932. +    unsigned n;
  933. +    uch *in, *out, ch;
  934. +
  935. +    in = window;
  936. +    out = &output_data[output_ptr];
  937. +    for (n = 0; n < outcnt; n++) {
  938. +    ch = *out++ = *in++;
  939. +    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
  940. +    }
  941. +    crc = c;
  942. +    bytes_out += (ulg)outcnt;
  943. +    output_ptr += (ulg)outcnt;
  944. +    outcnt = 0;
  945. +}
  946. +
  947. +static void error(char *x)
  948. +{
  949. +    puts("\n\n");
  950. +    puts(x);
  951. +    puts("\n\n -- System halted");
  952. +
  953. +    while(1);    /* Halt */
  954. +}
  955. +
  956. +#define STACK_SIZE (4096)
  957. +
  958. +long user_stack [STACK_SIZE];
  959. +
  960. +void decompress_kernel(int output_start)
  961. +{
  962. +    video_num_lines = params->video_num_rows;
  963. +    video_num_columns  = params->video_num_cols;
  964. +    bytes_per_char_h = params->bytes_per_char_h;
  965. +    white = bytes_per_char_h == 8 ? 0xfc : 7;
  966. +    
  967. +    if (params->nr_pages * params->page_size < 2048*1024) error("<2M of mem\n");
  968. +
  969. +    output_data = (char *)output_start;    /* Points to kernel start */
  970. +
  971. +    makecrc();
  972. +    puts("Uncompressing Linux...");
  973. +    gunzip();
  974. +    puts("done.\nNow booting the kernel\n");
  975. +}
  976. diff -u -X rej --recursive --new-file linux.orig/arch/arm/boot/compressed/piggyback.c linux/arch/arm/boot/compressed/piggyback.c
  977. --- linux.orig/arch/arm/boot/compressed/piggyback.c    Thu Jan  1 01:00:00 1970
  978. +++ linux/arch/arm/boot/compressed/piggyback.c    Sun Jul  7 12:34:25 1996
  979. @@ -0,0 +1,91 @@
  980. +/*
  981. + *    linux/zBoot/piggyback.c
  982. + *
  983. + *    (C) 1993 Hannu Savolainen
  984. + */
  985. +
  986. +/*
  987. + *    This program reads the compressed system image from stdin and
  988. + *    encapsulates it into an object file written to the stdout.
  989. + */
  990. +
  991. +#include <stdio.h>
  992. +#include <unistd.h>
  993. +#include <a.out.h>
  994. +#include <sys/fcntl.h>
  995. +
  996. +int main(int argc, char *argv[])
  997. +{
  998. +    int n=0, len=0, fd = 0;
  999. +    char tmp_buf[640*1024];
  1000. +    
  1001. +    struct exec obj = {0x00670107};    /* object header */
  1002. +    char string_names[] = {"_input_data\0_input_end\0"};
  1003. +
  1004. +    struct nlist var_names[2] = /* Symbol table */
  1005. +        {
  1006. +            {    /* _input_data    */
  1007. +                {(char *)4}, 7, 0, 0, 0
  1008. +            },
  1009. +            {    /* _input_len */
  1010. +                {(char *)16}, 7, 0, 0, 0
  1011. +            }
  1012. +        };
  1013. +
  1014. +
  1015. +    if (argc > 1) {
  1016. +        fd = open (argv[1], O_RDONLY);
  1017. +        if (fd < 0) {
  1018. +            fprintf (stderr, "%s: ", argv[0]);
  1019. +            perror (argv[1]);
  1020. +            exit (1);
  1021. +        }
  1022. +    }
  1023. +
  1024. +    len = 0;
  1025. +    while ((n = read(fd, &tmp_buf[len], sizeof(tmp_buf)-len+1)) > 0)
  1026. +          len += n;
  1027. +
  1028. +    len = (len + 3) & ~3;
  1029. +
  1030. +    if (n==-1) {
  1031. +        perror("stdin");
  1032. +        exit(-1);
  1033. +    }
  1034. +
  1035. +    if (len >= sizeof(tmp_buf)) {
  1036. +        fprintf(stderr, "%s: Input too large\n", argv[0]);
  1037. +        exit(-1);
  1038. +    }
  1039. +
  1040. +    if (argc < 2)
  1041. +        fprintf(stderr, "Compressed size %d.\n", len);
  1042. +
  1043. +/*
  1044. + *    Output object header
  1045. + */
  1046. +    obj.a_data = len /* + sizeof(long) */;
  1047. +    obj.a_syms = sizeof(var_names);
  1048. +    write(1, (char *)&obj, sizeof(obj));
  1049. +
  1050. +/*
  1051. + *    Output data segment (compressed system & len)
  1052. + */
  1053. +    write(1, tmp_buf, len);
  1054. +
  1055. +/*
  1056. + *    Output symbol table
  1057. + */
  1058. +    var_names[1].n_value = len;
  1059. +    write(1, (char *)&var_names, sizeof(var_names));
  1060. +
  1061. +/*
  1062. + *    Output string table
  1063. + */
  1064. +    len = sizeof(string_names) + sizeof(len);
  1065. +    write(1, (char *)&len, sizeof(len));
  1066. +    write(1, string_names, sizeof(string_names));
  1067. +
  1068. +    exit(0);
  1069. +
  1070. +}
  1071. diff -u -X rej --recursive --new-file linux.orig/arch/arm/boot/compressed/xtract.c linux/arch/arm/boot/compressed/xtract.c
  1072. --- linux.orig/arch/arm/boot/compressed/xtract.c    Thu Jan  1 01:00:00 1970
  1073. +++ linux/arch/arm/boot/compressed/xtract.c    Sat Jul 13 19:20:28 1996
  1074. @@ -0,0 +1,86 @@
  1075. +/*
  1076. + *  linux/zBoot/xtract.c
  1077. + *
  1078. + *  Copyright (C) 1993  Hannu Savolainen
  1079. + *
  1080. + *    Extracts the system image and writes it to the stdout.
  1081. + *    based on tools/build.c by Linus Torvalds
  1082. + */
  1083. +
  1084. +#include <stdio.h>    /* fprintf */
  1085. +#include <string.h>
  1086. +#include <stdlib.h>    /* contains exit */
  1087. +#include <sys/types.h>    /* unistd.h needs this */
  1088. +#include <sys/stat.h>
  1089. +#include <sys/sysmacros.h>
  1090. +#include <unistd.h>    /* contains read/write */
  1091. +#include <fcntl.h>
  1092. +#include <a.out.h>
  1093. +
  1094. +#define N_MAGIC_OFFSET 1024
  1095. +
  1096. +static int GCC_HEADER = sizeof(struct exec);
  1097. +
  1098. +#define STRINGIFY(x) #x
  1099. +
  1100. +void die(char * str)
  1101. +{
  1102. +    fprintf(stderr,"%s\n",str);
  1103. +    exit(1);
  1104. +}
  1105. +
  1106. +void usage(void)
  1107. +{
  1108. +    die("Usage: xtract system [ | gzip | piggyback > piggy.s]");
  1109. +}
  1110. +
  1111. +int main(int argc, char ** argv)
  1112. +{
  1113. +    int /*i,c,*/id, sz;
  1114. +    char buf[1024];
  1115. +/*    char major_root, minor_root;*/
  1116. +/*    struct stat sb;*/
  1117. +
  1118. +    struct exec *ex = (struct exec *)buf;
  1119. +
  1120. +    if (argc  != 2)
  1121. +        usage();
  1122. +    
  1123. +    if ((id=open(argv[1],O_RDONLY,0))<0)
  1124. +        die("Unable to open 'system'");
  1125. +    if (read(id,buf,GCC_HEADER) != GCC_HEADER)
  1126. +        die("Unable to read header of 'system'");
  1127. +    if (N_MAGIC(*ex) == ZMAGIC) {
  1128. +        GCC_HEADER = N_MAGIC_OFFSET;
  1129. +        lseek(id, GCC_HEADER, SEEK_SET);
  1130. +    } else if (N_MAGIC(*ex) != QMAGIC)
  1131. +        die("Non-GCC header of 'system'");
  1132. +
  1133. +    sz = N_SYMOFF(*ex) - GCC_HEADER + 4;    /* +4 to get the same result than tools/build */
  1134. +
  1135. +    fprintf(stderr, "System size is %d\n", sz);
  1136. +
  1137. +    while (sz)
  1138. +    {
  1139. +        int l, n;
  1140. +
  1141. +        l = sz;
  1142. +        if (l > sizeof(buf)) l = sizeof(buf);
  1143. +
  1144. +        if ((n=read(id, buf, l)) !=l)
  1145. +        {
  1146. +            if (n == -1) 
  1147. +               perror(argv[1]);
  1148. +            else
  1149. +               fprintf(stderr, "Unexpected EOF\n");
  1150. +
  1151. +            die("Can't read system");
  1152. +        }
  1153. +
  1154. +        write(1, buf, l);
  1155. +        sz -= l;
  1156. +    }
  1157. +
  1158. +    close(id);
  1159. +    return(0);
  1160. +}
  1161. diff -u -X rej --recursive --new-file linux.orig/arch/arm/boot/install.sh linux/arch/arm/boot/install.sh
  1162. --- linux.orig/arch/arm/boot/install.sh    Thu Jan  1 01:00:00 1970
  1163. +++ linux/arch/arm/boot/install.sh    Wed May  8 22:00:32 1996
  1164. @@ -0,0 +1,60 @@
  1165. +#!/bin/sh
  1166. +#
  1167. +# arch/i386/boot/install.sh
  1168. +#
  1169. +# This file is subject to the terms and conditions of the GNU General Public
  1170. +# License.  See the file "COPYING" in the main directory of this archive
  1171. +# for more details.
  1172. +#
  1173. +# Copyright (C) 1995 by Linus Torvalds
  1174. +#
  1175. +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
  1176. +#
  1177. +# "make install" script for i386 architecture
  1178. +#
  1179. +# Arguments:
  1180. +#   $1 - kernel version
  1181. +#   $2 - kernel image file
  1182. +#   $3 - kernel map file
  1183. +#   $4 - default install path (blank if root directory)
  1184. +#
  1185. +
  1186. +# User may have a custom install script
  1187. +
  1188. +if [ -x /sbin/installkernel ]; then
  1189. +  exec /sbin/installkernel "$@"
  1190. +fi
  1191. +
  1192. +if [ "$2" = "zImage" ]; then
  1193. +# Compressed install
  1194. +  echo "Installing compressed kernel"
  1195. +  if [ -f $4/vmlinuz-$1 ]; then
  1196. +    mv $4/vmlinuz-$1 $4/vmlinuz.old
  1197. +  fi
  1198. +
  1199. +  if [ -f $4/System.map-$1 ]; then
  1200. +    mv $4/System.map-$1 $4/System.old
  1201. +  fi
  1202. +
  1203. +  cat $2 > $4/vmlinuz-$1
  1204. +  cp $3 $4/System.map-$1
  1205. +else
  1206. +# Normal install
  1207. +  echo "Installing normal kernel"
  1208. +  if [ -f $4/vmlinux-$1 ]; then
  1209. +    mv $4/vmlinux-$1 $4/vmlinux.old
  1210. +  fi
  1211. +
  1212. +  if [ -f $4/System.map ]; then
  1213. +    mv $4/System.map $4/System.old
  1214. +  fi
  1215. +
  1216. +  cat $2 > $4/vmlinux-$1
  1217. +  cp $3 $4/System.map
  1218. +fi
  1219. +
  1220. +if [ -x /sbin/loadmap ]; then
  1221. +  /sbin/loadmap --rdev /dev/ima
  1222. +else
  1223. +  echo "You have to install it yourself"
  1224. +fi
  1225. diff -u -X rej --recursive --new-file linux.orig/arch/arm/boot/tools/build.c linux/arch/arm/boot/tools/build.c
  1226. --- linux.orig/arch/arm/boot/tools/build.c    Thu Jan  1 01:00:00 1970
  1227. +++ linux/arch/arm/boot/tools/build.c    Sun Feb 11 22:01:19 1996
  1228. @@ -0,0 +1,56 @@
  1229. +#include <stdio.h>
  1230. +#include <stdlib.h>
  1231. +#include <a.out.h>
  1232. +#include <string.h>
  1233. +
  1234. +int main(int argc, char **argv)
  1235. +{
  1236. +    void *data;
  1237. +    struct exec ex;
  1238. +    FILE *f;
  1239. +    int totlen;
  1240. +
  1241. +    if (argc < 2) {
  1242. +        fprintf(stderr, "Usage: build kernel-name\n");
  1243. +        exit(1);
  1244. +    }
  1245. +
  1246. +    f = fopen(argv[1], "rb");
  1247. +
  1248. +    fread(&ex, 1, sizeof(ex), f);
  1249. +
  1250. +    if(N_MAGIC(ex) == ZMAGIC) {
  1251. +        fseek(f, 4096, SEEK_SET);
  1252. +        totlen = ex.a_text + ex.a_data + ex.a_bss;
  1253. +    } else
  1254. +    if(N_MAGIC(ex) == QMAGIC) {
  1255. +        unsigned long my_header[8];
  1256. +        
  1257. +        fseek(f, 0x20, SEEK_SET);
  1258. +
  1259. +        memset(my_header, 0, 0x20);
  1260. +
  1261. +        my_header[0] = 0xea000006;
  1262. +        
  1263. +        fwrite(my_header, 4, 8, stdout);
  1264. +        
  1265. +        totlen = ex.a_text + ex.a_data + ex.a_bss - 0x20;
  1266. +    } else {
  1267. +        fprintf(stderr, "Unacceptable a.out header on kernel\n");
  1268. +        fclose(f);
  1269. +        exit(1);
  1270. +    }
  1271. +
  1272. +    fprintf(stderr, "Kernel is %dk (%dk text, %dk data, %dk bss)\n",
  1273. +        (ex.a_text + ex.a_data + ex.a_bss)/1024,
  1274. +         ex.a_text/1024, ex.a_data/1024, ex.a_bss/1024);
  1275. +
  1276. +    data = malloc(totlen);
  1277. +    fread(data, 1, totlen, f);
  1278. +    fwrite(data, 1, totlen, stdout);
  1279. +
  1280. +    free(data);
  1281. +    fclose(f);
  1282. +    fflush(stdout);
  1283. +    return 0;
  1284. +}
  1285. diff -u -X rej --recursive --new-file linux.orig/arch/arm/config.in linux/arch/arm/config.in
  1286. --- linux.orig/arch/arm/config.in    Thu Jan  1 01:00:00 1970
  1287. +++ linux/arch/arm/config.in    Wed Jul 31 13:35:08 1996
  1288. @@ -0,0 +1,89 @@
  1289. +#
  1290. +# For a description of the syntax of this configuration file,
  1291. +# see the Configure script.
  1292. +#
  1293. +# architecture in arch/arm/Makefile'
  1294. +
  1295. +mainmenu_name "Linux kernel configuration"
  1296. +
  1297. +define_bool CONFIG_ARM y
  1298. +
  1299. +mainmenu_option next_comment
  1300. +comment 'Code maturity level options'
  1301. +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
  1302. +endmenu
  1303. +
  1304. +mainmenu_option next_comment
  1305. +comment 'Loadable module support'
  1306. +bool 'Enable loadable module support' CONFIG_MODULES
  1307. +if [ "$CONFIG_MODULES" = "y" ]; then
  1308. +  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
  1309. +  bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
  1310. +fi
  1311. +endmenu
  1312. +
  1313. +mainmenu_option next_comment
  1314. +comment 'General setup'
  1315. +bool 'Networking support' CONFIG_NET
  1316. +bool 'System V IPC' CONFIG_SYSVIPC
  1317. +define_bool CONFIG_BINFMT_AOUT y
  1318. +define_bool CONFIG_BINFMT_ELF n
  1319. +define_bool CONFIG_BINFMT_JAVA n
  1320. +endmenu
  1321. +
  1322. +source arch/arm/drivers/block/Config.in
  1323. +
  1324. +if [ "$CONFIG_NET" = "y" ]; then
  1325. +  source net/Config.in
  1326. +fi
  1327. +
  1328. +mainmenu_option next_comment
  1329. +comment 'SCSI support'
  1330. +
  1331. +tristate 'SCSI support?' CONFIG_SCSI
  1332. +
  1333. +if [ "$CONFIG_SCSI" != "n" ]; then
  1334. +  source arch/arm/drivers/scsi/Config.in
  1335. +fi
  1336. +endmenu
  1337. +
  1338. +if [ "$CONFIG_NET" = "y" ]; then
  1339. +  mainmenu_option next_comment
  1340. +  comment 'Network device support'
  1341. +
  1342. +  bool 'Network device support?' CONFIG_NETDEVICES
  1343. +  if [ "$CONFIG_NETDEVICES" = "y" ]; then
  1344. +    source arch/arm/drivers/net/Config.in
  1345. +  fi
  1346. +  endmenu
  1347. +fi
  1348. +
  1349. +# mainmenu_option next_comment
  1350. +# comment 'ISDN subsystem'
  1351. +#
  1352. +# tristate 'ISDN support' CONFIG_ISDN
  1353. +# if [ "$CONFIG_ISDN" != "n" ]; then
  1354. +#   source drivers/isdn/Config.in
  1355. +# fi
  1356. +# endmenu
  1357. +
  1358. +source fs/Config.in
  1359. +
  1360. +source arch/arm/drivers/char/Config.in
  1361. +
  1362. +mainmenu_option next_comment
  1363. +comment 'Sound'
  1364. +
  1365. +bool 'Sound support' CONFIG_SOUND
  1366. +endmenu
  1367. +
  1368. +mainmenu_option next_comment
  1369. +comment 'Kernel hacking'
  1370. +
  1371. +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
  1372. +bool 'Kernel profiling support' CONFIG_PROFILE
  1373. +if [ "$CONFIG_PROFILE" = "y" ]; then
  1374. +  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
  1375. +fi
  1376. +endmenu
  1377. +
  1378. diff -u -X rej --recursive --new-file linux.orig/arch/arm/defconfig linux/arch/arm/defconfig
  1379. --- linux.orig/arch/arm/defconfig    Thu Jan  1 01:00:00 1970
  1380. +++ linux/arch/arm/defconfig    Tue Jul 30 17:17:14 1996
  1381. @@ -0,0 +1,164 @@
  1382. +#
  1383. +# Automatically generated make config: don't edit
  1384. +#
  1385. +CONFIG_ARM=y
  1386. +
  1387. +#
  1388. +# Code maturity level options
  1389. +#
  1390. +# CONFIG_EXPERIMENTAL is not set
  1391. +
  1392. +#
  1393. +# Loadable module support
  1394. +#
  1395. +CONFIG_MODULES=y
  1396. +CONFIG_MODVERSIONS=y
  1397. +# CONFIG_KERNELD is not set
  1398. +
  1399. +#
  1400. +# General setup
  1401. +#
  1402. +CONFIG_NET=y
  1403. +CONFIG_SYSVIPC=y
  1404. +CONFIG_BINFMT_AOUT=y
  1405. +# CONFIG_BINFMT_ELF is not set
  1406. +# CONFIG_BINFMT_JAVA is not set
  1407. +
  1408. +#
  1409. +# Floppy, IDE, and other block devices
  1410. +#
  1411. +CONFIG_BLK_DEV_FD=y
  1412. +CONFIG_BLK_DEV_IDE=y
  1413. +
  1414. +#
  1415. +# Please see Documentation/ide.txt for help/info on IDE drives
  1416. +#
  1417. +# CONFIG_BLK_DEV_IDECD is not set
  1418. +# CONFIG_BLK_DEV_IDETAPE is not set
  1419. +# CONFIG_BLK_DEV_IDE_CARDS is not set
  1420. +# CONFIG_BLK_DEV_XD is not set
  1421. +
  1422. +#
  1423. +# Additional Block Devices
  1424. +#
  1425. +# CONFIG_BLK_DEV_LOOP is not set
  1426. +# CONFIG_BLK_DEV_MD is not set
  1427. +# CONFIG_BLK_DEV_RAM is not set
  1428. +CONFIG_BLK_DEV_IMG=y
  1429. +
  1430. +#
  1431. +# Networking options
  1432. +#
  1433. +# CONFIG_FIREWALL is not set
  1434. +# CONFIG_NET_ALIAS is not set
  1435. +CONFIG_INET=y
  1436. +# CONFIG_IP_FORWARD is not set
  1437. +# CONFIG_IP_MULTICAST is not set
  1438. +# CONFIG_IP_ACCT is not set
  1439. +# CONFIG_IP_ROUTER is not set
  1440. +# CONFIG_NET_IPIP is not set
  1441. +
  1442. +#
  1443. +# (it is safe to leave these untouched)
  1444. +#
  1445. +# CONFIG_INET_PCTCP is not set
  1446. +# CONFIG_INET_RARP is not set
  1447. +# CONFIG_NO_PATH_MTU_DISCOVERY is not set
  1448. +# CONFIG_IP_NOSR is not set
  1449. +# CONFIG_SKB_LARGE is not set
  1450. +
  1451. +#
  1452. +#  
  1453. +#
  1454. +# CONFIG_IPX is not set
  1455. +# CONFIG_ATALK is not set
  1456. +# CONFIG_AX25 is not set
  1457. +# CONFIG_BRIDGE is not set
  1458. +# CONFIG_NETLINK is not set
  1459. +
  1460. +#
  1461. +# SCSI support
  1462. +#
  1463. +# CONFIG_SCSI is not set
  1464. +
  1465. +#
  1466. +# SCSI support type (disk, tape, CDrom)
  1467. +#
  1468. +# CONFIG_BLK_DEV_SD is not set
  1469. +# CONFIG_CHR_DEV_ST is not set
  1470. +# CONFIG_BLK_DEV_SR is not set
  1471. +# CONFIG_CHR_DEV_SG is not set
  1472. +
  1473. +#
  1474. +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
  1475. +#
  1476. +# CONFIG_SCSI_MULTI_LUN is not set
  1477. +# CONFIG_SCSI_CONSTANTS is not set
  1478. +
  1479. +#
  1480. +# SCSI low-level drivers
  1481. +#
  1482. +# CONFIG_SCSI_ACORNSCSI_3 is not set
  1483. +# CONFIG_SCSI_CUMANA_1 is not set
  1484. +# CONFIG_SCSI_ECOSCSI is not set
  1485. +# CONFIG_SCSI_OAK is not set
  1486. +
  1487. +#
  1488. +# Network device support
  1489. +#
  1490. +CONFIG_NETDEVICES=y
  1491. +CONFIG_DUMMY=y
  1492. +# CONFIG_EQUALIZER is not set
  1493. +CONFIG_PPP=y
  1494. +
  1495. +#
  1496. +# CCP compressors for PPP are only built as modules.
  1497. +#
  1498. +# CONFIG_SLIP is not set
  1499. +# CONFIG_ETHER1 is not set
  1500. +# CONFIG_ETHER3 is not set
  1501. +
  1502. +#
  1503. +# Filesystems
  1504. +#
  1505. +# CONFIG_QUOTA is not set
  1506. +# CONFIG_LOCK_MANDATORY is not set
  1507. +CONFIG_MINIX_FS=y
  1508. +# CONFIG_EXT_FS is not set
  1509. +CONFIG_EXT2_FS=y
  1510. +# CONFIG_XIA_FS is not set
  1511. +CONFIG_FAT_FS=y
  1512. +CONFIG_MSDOS_FS=y
  1513. +# CONFIG_VFAT_FS is not set
  1514. +# CONFIG_UMSDOS_FS is not set
  1515. +CONFIG_PROC_FS=y
  1516. +CONFIG_NFS_FS=y
  1517. +# CONFIG_ROOT_NFS is not set
  1518. +CONFIG_SMB_FS=m
  1519. +CONFIG_SMB_LONG=y
  1520. +# CONFIG_ISO9660_FS is not set
  1521. +# CONFIG_HPFS_FS is not set
  1522. +# CONFIG_SYSV_FS is not set
  1523. +# CONFIG_AFFS_FS is not set
  1524. +# CONFIG_UFS_FS is not set
  1525. +
  1526. +#
  1527. +# Character devices
  1528. +#
  1529. +# CONFIG_SERIAL_ECHO is not set
  1530. +CONFIG_SERIAL=y
  1531. +CONFIG_ATOMWIDE_SERIAL=y
  1532. +# CONFIG_DUALSP_SERIAL is not set
  1533. +CONFIG_MOUSE=y
  1534. +CONFIG_KBDMOUSE=y
  1535. +CONFIG_PRINTER=y
  1536. +
  1537. +#
  1538. +# Sound
  1539. +#
  1540. +CONFIG_SOUND=y
  1541. +
  1542. +#
  1543. +# Kernel hacking
  1544. +#
  1545. +# CONFIG_PROFILE is not set
  1546. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/Makefile linux/arch/arm/drivers/Makefile
  1547. --- linux.orig/arch/arm/drivers/Makefile    Thu Jan  1 01:00:00 1970
  1548. +++ linux/arch/arm/drivers/Makefile    Thu Mar 28 11:51:08 1996
  1549. @@ -0,0 +1,37 @@
  1550. +#
  1551. +# Makefile for the linux kernel device drivers.
  1552. +#
  1553. +# Note! Dependencies are done automagically by 'make dep', which also
  1554. +# removes any old dependencies. DON'T put your own dependencies here
  1555. +# unless it's something special (ie not a .c file).
  1556. +#
  1557. +# Note 2! The CFLAGS definitions are now in the main makefile...
  1558. +
  1559. +SUB_DIRS     := block char net #streams
  1560. +MOD_SUB_DIRS := $(SUB_DIRS)
  1561. +ALL_SUB_DIRS := $(SUB_DIRS) scsi sound
  1562. +
  1563. +# If CONFIG_SCSI is set, the core of scsi support will be added to the kernel,
  1564. +# but some of the low-level things may also be modules.
  1565. +ifeq ($(CONFIG_SCSI),y)
  1566. +SUB_DIRS += scsi
  1567. +MOD_SUB_DIRS += scsi
  1568. +else
  1569. +  ifeq ($(CONFIG_SCSI),m)
  1570. +  MOD_SUB_DIRS += scsi
  1571. +  endif
  1572. +endif
  1573. +
  1574. +ifeq ($(CONFIG_SOUND),y)
  1575. +SUB_DIRS += sound
  1576. +else
  1577. +  ifeq ($(CONFIG_SOUND),m)
  1578. +  MOD_SUB_DIRS += sound
  1579. +  endif
  1580. +endif
  1581. +
  1582. +include $(TOPDIR)/Rules.make
  1583. +
  1584. +mrproper:
  1585. +    set -e; for i in $(ALL_SUB_DIRS); do $(MAKE) -C $$i mrproper; done
  1586. +
  1587. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/Config.in linux/arch/arm/drivers/block/Config.in
  1588. --- linux.orig/arch/arm/drivers/block/Config.in    Thu Jan  1 01:00:00 1970
  1589. +++ linux/arch/arm/drivers/block/Config.in    Fri Aug  9 22:51:44 1996
  1590. @@ -0,0 +1,43 @@
  1591. +#
  1592. +# Block device driver configuration
  1593. +#
  1594. +mainmenu_option next_comment
  1595. +comment 'Floppy, IDE, and other block devices'
  1596. +
  1597. +tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
  1598. +bool 'Enhanced IDE disk/cdrom/tape support' CONFIG_BLK_DEV_IDE
  1599. +comment 'Please see Documentation/ide.txt for help/info on IDE drives'
  1600. +if [ "$CONFIG_BLK_DEV_IDE" = "n" ]; then
  1601. +  bool 'Use Old IDE harddisk driver' CONFIG_BLK_DEV_HD_ONLY
  1602. +else
  1603. +  bool '  Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD
  1604. +  bool '  Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE
  1605. +  bool '  Support expansion card IDE interfaces' CONFIG_BLK_DEV_IDE_CARDS
  1606. +  if [ "$CONFIG_BLK_DEV_IDE_CARDS" = "y" ]; then
  1607. +    bool '    ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICS
  1608. +  fi
  1609. +fi
  1610. +
  1611. +tristate 'MFM harddisk support' CONFIG_BLK_DEV_XD
  1612. +
  1613. +comment 'Additional Block Devices'
  1614. +
  1615. +tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
  1616. +bool 'Multiple device driver support' CONFIG_BLK_DEV_MD
  1617. +if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
  1618. +  tristate '  Linear (append) mode' CONFIG_MD_LINEAR
  1619. +  tristate '  RAID-0 (striping) mode' CONFIG_MD_STRIPED
  1620. +fi
  1621. +tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
  1622. +if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
  1623. +  bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
  1624. +fi
  1625. +bool 'ADFS image file support' CONFIG_BLK_DEV_IMG
  1626. +
  1627. +if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
  1628. +  define_bool CONFIG_BLK_DEV_HD y
  1629. +else
  1630. +  define_bool CONFIG_BLK_DEV_HD n
  1631. +fi
  1632. +
  1633. +endmenu
  1634. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/Makefile linux/arch/arm/drivers/block/Makefile
  1635. --- linux.orig/arch/arm/drivers/block/Makefile    Thu Jan  1 01:00:00 1970
  1636. +++ linux/arch/arm/drivers/block/Makefile    Sun Aug 25 15:35:26 1996
  1637. @@ -0,0 +1,148 @@
  1638. +#
  1639. +# Makefile for the kernel block device drivers.
  1640. +#
  1641. +# Note! Dependencies are done automagically by 'make dep', which also
  1642. +# removes any old dependencies. DON'T put your own dependencies here
  1643. +# unless it's something special (ie not a .c file).
  1644. +#
  1645. +# Note 2! The CFLAGS definition is now inherited from the
  1646. +# parent makefile.
  1647. +#
  1648. +
  1649. +all: links first_rule
  1650. +
  1651. +L_TARGET := block.a
  1652. +L_OBJS   := ll_rw_blk.o genhd.o
  1653. +M_OBJS   :=
  1654. +MOD_LIST_NAME := BLOCK_MODULES
  1655. +
  1656. +LK      = README.fd README.hd README.ide README.md \
  1657. +        ide_modes.h ide-cd.c ide-tape.c ide-tape.h \
  1658. +        linear.c loop.c md.c raid0.c rd.c
  1659. +
  1660. +# Architecture dependencies
  1661. +
  1662. +ifeq ($(MACHINE),a5k)
  1663. +  FLOPPY = floppy.o floppydma.o
  1664. +  FLOPPYMOD = floppy-mod.o
  1665. +endif
  1666. +
  1667. +ifeq ($(MACHINE),arc)
  1668. +  FLOPPY = fd1772.o fd1772dma.o
  1669. +  FLOPPYMOD = fd1772-mod.o
  1670. +endif
  1671. +
  1672. +# Common dependencies
  1673. +
  1674. +ifdef FLOPPY
  1675. +  ifeq ($(CONFIG_BLK_DEV_FD),y)
  1676. +    L_OBJS += $(FLOPPY)
  1677. +  else
  1678. +    ifeq ($(CONFIG_BLK_DEV_FD),m)
  1679. +      M_OBJS += $(FLOPPYMOD)
  1680. +    endif
  1681. +  endif
  1682. +endif
  1683. +
  1684. +ifeq ($(CONFIG_BLK_DEV_IMG),y)
  1685. +  L_OBJS += adfsimg.o adfspart.o
  1686. +endif
  1687. +
  1688. +ifeq ($(CONFIG_BLK_DEV_RAM),y)
  1689. +  L_OBJS += rd.o
  1690. +else
  1691. +  ifeq ($(CONFIG_BLK_DEV_RAM),m)
  1692. +    M_OBJS += rd.o
  1693. +  endif
  1694. +endif
  1695. +
  1696. +ifeq ($(CONFIG_BLK_DEV_LOOP),y)
  1697. +  L_OBJS += loop.o
  1698. +else
  1699. +  ifeq ($(CONFIG_BLK_DEV_LOOP),m)
  1700. +    M_OBJS += loop.o
  1701. +  endif
  1702. +endif
  1703. +
  1704. +ifeq ($(CONFIG_BLK_DEV_HD),y)
  1705. +  L_OBJS += hd.o
  1706. +endif
  1707. +
  1708. +ifeq ($(CONFIG_BLK_DEV_IDE),y)
  1709. +  L_OBJS += ide.o
  1710. +endif
  1711. +
  1712. +ifeq (*(CONFIG_BLK_DEV_IDE_ICS),y)
  1713. +  L_OBJS += ide-ics.o
  1714. +else
  1715. +  ifeq ($(CONFIG_BLK_DEV_IDE_ICS),m)
  1716. +    M_OBJS += ide-ics.o
  1717. +  endif
  1718. +endif
  1719. +
  1720. +ifeq ($(CONFIG_BLK_DEV_IDECD),y)
  1721. +  L_OBJS += ide-cd.o
  1722. +endif
  1723. +
  1724. +ifeq ($(CONFIG_BLK_DEV_IDETAPE),y)
  1725. +  L_OBJS += ide-tape.o
  1726. +endif
  1727. +
  1728. +ifeq ($(CONFIG_BLK_DEV_XD),y)
  1729. +  L_OBJS += mfmhd.o mfm.o
  1730. +else
  1731. +  ifeq ($(CONFIG_BLK_DEV_XD),m)
  1732. +    M_OBJS += mfmhd_mod.o
  1733. +  endif
  1734. +endif
  1735. +
  1736. +ifeq ($(CONFIG_BLK_DEV_MD),y)
  1737. +  LX_OBJS += md.o
  1738. +  ifeq ($(CONFIG_MD_LINEAR),y)
  1739. +    L_OBJS += linear.o
  1740. +  else
  1741. +    ifeq ($(CONFIG_MD_LINEAR),m)
  1742. +      M_OBJS += linear.o
  1743. +    endif
  1744. +  endif
  1745. +  ifeq ($(CONFIG_MD_STRIPED),y)
  1746. +    L_OBJS += raid0.o
  1747. +  else
  1748. +    ifeq ($(CONFIG_MD_STRIPED),m)
  1749. +      M_OBJS += raid0.o
  1750. +    endif
  1751. +  endif
  1752. +endif
  1753. +
  1754. +include $(TOPDIR)/Rules.make
  1755. +
  1756. +fastdep: links
  1757. +
  1758. +# Most modules require to be linked against GCCLIB.
  1759. +
  1760. +floppy_mod.o: $(FLOPPY)
  1761. +    ld -r -o $@ $(FLOPPY) $(GCCLIB)
  1762. +
  1763. +fd1772_mod.o: $(FLOPPY)
  1764. +    ld -r -o $@ $(FLOPPY) $(GCCLIB)
  1765. +
  1766. +mfmhd_mod.o: mfmhd.o mfm.o
  1767. +    ld -r -o $@ mfmhd.o mfm.o $(GCCLIB)
  1768. +
  1769. +.PHONY: links
  1770. +links:
  1771. +    -@for f in $(LK); do \
  1772. +        if [ ! -e $$f ]; then \
  1773. +            echo "ln -s ../../../../drivers/block/$$f ."; \
  1774. +            ln -s ../../../../drivers/block/$$f .; \
  1775. +        fi; \
  1776. +    done
  1777. +
  1778. +mrproper:
  1779. +    -@for f in $(LK); do \
  1780. +        if [ -L $$f ]; then \
  1781. +            echo $(RM) $$f; \
  1782. +            $(RM) $$f; \
  1783. +        fi; \
  1784. +    done
  1785. +
  1786. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/adfs.h linux/arch/arm/drivers/block/adfs.h
  1787. --- linux.orig/arch/arm/drivers/block/adfs.h    Thu Jan  1 01:00:00 1970
  1788. +++ linux/arch/arm/drivers/block/adfs.h    Tue Apr  2 19:36:15 1996
  1789. @@ -0,0 +1,75 @@
  1790. +/*
  1791. + * linux/arch/arm/drivers/block/adfs.h
  1792. + *
  1793. + * Copyright (c) 1996 Russell King.
  1794. + */
  1795. +
  1796. +/*
  1797. + * Disc record size
  1798. + */
  1799. +#define RECSIZE 60
  1800. +
  1801. +/*
  1802. + * Disc record
  1803. + */
  1804. +struct disc_record {
  1805. +    unsigned char  log2secsize;
  1806. +    unsigned char  secspertrack;
  1807. +    unsigned char  heads;
  1808. +    unsigned char  density;
  1809. +    unsigned char  idlen;
  1810. +    unsigned char  log2bpmb;
  1811. +    unsigned char  skew;
  1812. +    unsigned char  bootoption;
  1813. +    unsigned char  lowsector;
  1814. +    unsigned char  nzones;
  1815. +    unsigned short zone_spare;
  1816. +    unsigned long  root;
  1817. +    unsigned long  disc_size;
  1818. +    unsigned short disc_id;
  1819. +    unsigned char  disc_name[10];
  1820. +    unsigned long  disc_type;
  1821. +};
  1822. +
  1823. +/*
  1824. + * Partition types.
  1825. + */
  1826. +#define PARTITION_RISCIX 1
  1827. +
  1828. +/*
  1829. + * New-directory disks have a separate attributes byte - this is the bit mask.
  1830. + */
  1831. +#define OBJ_OWNREAD    1
  1832. +#define OBJ_OWNWRITE    2
  1833. +#define OBJ_LOCKED    4
  1834. +#define OBJ_DIRECTORY    8
  1835. +#define OBJ_EXECUTE    16
  1836. +#define OBJ_PUBREAD    32
  1837. +#define OBJ_PUBWRITE    64
  1838. +
  1839. +/*
  1840. + * Offset in bytes of the boot block on the disk.
  1841. + */
  1842. +#define BOOT_SECTOR_ADDRESS 0xc00
  1843. +
  1844. +/*
  1845. + * Calculate the boot block checksum on an ADFS drive.  Note that this will
  1846. + * appear to be correct if the sector contains all zeros, so also check that
  1847. + * the disk size is non-zero!!!
  1848. + */
  1849. +extern inline int adfs_checkbblk (unsigned char *ptr)
  1850. +{
  1851. +    unsigned int result;
  1852. +    
  1853. +    __asm__ ("
  1854. +    adds    %3, %2, %3
  1855. +    sub    %3, %3, #1
  1856. +1:    ldrb    %4, [%3, #-1]!
  1857. +    adc    %0, %0, %4
  1858. +    movs    %0, %0, lsl #24
  1859. +    mov    %0, %0, lsr #24
  1860. +    teqs    %2, %3
  1861. +    bne    1b
  1862. +    " : "=r" (result) : "0" (0), "r" (ptr), "r" (512), "r" (0));
  1863. +    return result != ptr[511];
  1864. +}
  1865. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/adfsimg.c linux/arch/arm/drivers/block/adfsimg.c
  1866. --- linux.orig/arch/arm/drivers/block/adfsimg.c    Thu Jan  1 01:00:00 1970
  1867. +++ linux/arch/arm/drivers/block/adfsimg.c    Sat Aug  3 23:03:05 1996
  1868. @@ -0,0 +1,1119 @@
  1869. +/*
  1870. + * linux/arch/arm/drivers/block/adfsimg.c
  1871. + *
  1872. + * Copyright (c) 1996 Russell King.
  1873. + *
  1874. + * Implement image files under Linux (allows Linux to access partition files
  1875. + *  on ADFS disks).
  1876. + *
  1877. + * This file is split into two halves: the first half is the actual image
  1878. + * mapper creation code, and the second half is the device driver.
  1879. + *
  1880. + * Changelog:
  1881. + *  28-03-1996    RMK    Created
  1882. + *  02-04-1996    RMK    Cleaned up per-device data into structure [should
  1883. + *              improve code].
  1884. + *  24-06-1996    RMK    Marked 4GB problem areas.
  1885. + *            Altered blocksize checking code - now uses the larger
  1886. + *              of the sector size and map bit size.
  1887. + *  04-06-1996    RMK    Re-wrote mapping function.  Now applies mapping as
  1888. + *              blocks come to be put on the queues.
  1889. + *  06-06-1996    RMK    Pass through blocks that need to be split up.
  1890. + */
  1891. +
  1892. +#include <linux/kernel.h>
  1893. +#include <linux/major.h>
  1894. +#include <linux/string.h>
  1895. +#include <linux/ctype.h>
  1896. +#include <linux/malloc.h>
  1897. +#include <linux/blkdev.h>
  1898. +#include <linux/errno.h>
  1899. +#include <linux/genhd.h>
  1900. +#include <linux/hdreg.h>
  1901. +
  1902. +#include <asm/segment.h>
  1903. +#include <asm/bitops.h>
  1904. +
  1905. +#define MAJOR_NR ADFSIMG_MAJOR
  1906. +#include "blk.h"
  1907. +#include "adfs.h"
  1908. +
  1909. +/*----------------------------------------------------------------------------------------
  1910. + * User configuration
  1911. + *
  1912. + * Number of minors per device, and number of devices.  Note that we have
  1913. + * a limit of 256 on the number of minors at the moment.
  1914. + */
  1915. +#define ADFSIMG_SHIFT    5
  1916. +#define ADFSIMG_NRDEV    (256 / (1 << ADFSIMG_SHIFT))
  1917. +#define ADFSIMG_PARMASK    ((1 << ADFSIMG_SHIFT) - 1)
  1918. +/*
  1919. + * This maps a device onto an index into the adfsimage structure
  1920. + */
  1921. +#define TARGETMAP(kdev) DEVICE_NR(kdev)
  1922. +/*
  1923. + * Debugging contants...
  1924. + */
  1925. +#define DEBUG_SWAP        32
  1926. +#define DEBUG_CHANGED        16
  1927. +#define DEBUG_MAPPING        8
  1928. +#define DEBUG_BUFFERS        4
  1929. +#define DEBUG_REQUESTS        2
  1930. +#define DEBUG_ADDMAPPING    1
  1931. +#define DEBUG            (DEBUG_CHANGED)
  1932. +
  1933. +/*
  1934. + * This is left over from the old code - the old !Config filenames for the files
  1935. + * get copied into this array.
  1936. + */
  1937. +static char arc_hd_files[8][128];
  1938. +
  1939. +struct adfsimage {
  1940. +    kdev_t        dev;        /* device on which to look for filename        */
  1941. +    char        *filename;    /* adfs filename without the 'fsname::drive.$.'    */
  1942. +    /*
  1943. +     * Private data
  1944. +     */
  1945. +    kdev_t        mapdev;        /* Current device map array is associated with    */
  1946. +    struct map        *mapstrt;    /* Map array                    */
  1947. +    unsigned int    mapsize;    /* number of map entries - 1            */
  1948. +    unsigned int    mapalloced;    /* Size of map array                */
  1949. +    unsigned int    blocksize;    /* blocksize this device supports        */
  1950. +    unsigned int    accesscount;    /* number of times this has been opened        */
  1951. +    unsigned int    capacity;    /* number of sectors in this image file        */
  1952. +    struct request    *req;        /* Currently executing request            */
  1953. +    struct file        filp;        /* fake filp for open device            */
  1954. +    struct inode    inode;        /* fake inode for open device            */
  1955. +    unsigned char    busy:1,        /* Device is currently busy            */
  1956. +            changed:1;    /* Mapped device has been changed        */
  1957. +} adfsimg_images[ADFSIMG_NRDEV] = {
  1958. +  { 0, arc_hd_files[0], 0x000, NULL, 0, 0, 0, 0, 0, NULL, {0, }, {0, }, 0, 0 },
  1959. +  { 0, arc_hd_files[1], 0x000, NULL, 0, 0, 0, 0, 0, NULL, {0, }, {0, }, 0, 0 },
  1960. +  { 0, arc_hd_files[2], 0x000, NULL, 0, 0, 0, 0, 0, NULL, {0, }, {0, }, 0, 0 },
  1961. +  { 0, arc_hd_files[3], 0x000, NULL, 0, 0, 0, 0, 0, NULL, {0, }, {0, }, 0, 0 },
  1962. +  { 0, arc_hd_files[4], 0x000, NULL, 0, 0, 0, 0, 0, NULL, {0, }, {0, }, 0, 0 },
  1963. +  { 0, arc_hd_files[5], 0x000, NULL, 0, 0, 0, 0, 0, NULL, {0, }, {0, }, 0, 0 },
  1964. +  { 0, arc_hd_files[6], 0x000, NULL, 0, 0, 0, 0, 0, NULL, {0, }, {0, }, 0, 0 },
  1965. +  { 0, arc_hd_files[7], 0x000, NULL, 0, 0, 0, 0, 0, NULL, {0, }, {0, }, 0, 0 }
  1966. +};
  1967. +
  1968. +void adfsimg_add_image (int slot, kdev_t dev, char *path)
  1969. +{
  1970. +    adfsimg_images[slot].dev = dev;
  1971. +    strcpy (adfsimg_images[slot].filename, path);
  1972. +}
  1973. +
  1974. +struct map {
  1975. +    unsigned long strt_sblk;
  1976. +    unsigned long strt_dblk;
  1977. +    unsigned long length;
  1978. +};
  1979. +
  1980. +static struct wait_queue *busy_wait;
  1981. +
  1982. +/*
  1983. + * These are private to the map generation code
  1984. + */
  1985. +static void *_adfsimg_map;
  1986. +static struct disc_record adfsimg_dr;
  1987. +static int adfsimg_zonesize;
  1988. +static int adfsimg_idsperzone;
  1989. +static int adfsimg_maplen;
  1990. +
  1991. +/*
  1992. + * Lock a device - prevents opens/closes/revalidates all happening at the same time.
  1993. + */
  1994. +static inline void
  1995. +adfsimg_lockdev (struct adfsimage *img)
  1996. +{
  1997. +    while (img->busy) {
  1998. +        barrier ();
  1999. +    sleep_on (&busy_wait);
  2000. +    }
  2001. +    img->busy = 1;
  2002. +}    
  2003. +
  2004. +static inline void
  2005. +adfsimg_unlockdev (struct adfsimage *img)
  2006. +{
  2007. +    img->busy = 0;
  2008. +    wake_up (&busy_wait);
  2009. +}
  2010. +
  2011. +/*
  2012. + * read blocks to an area of memory.  [eg map, boot block etc].
  2013. + */
  2014. +static void *
  2015. +adfsimg_read (void *data, struct adfsimage *img, unsigned long blkaddr, int length)
  2016. +{
  2017. +    struct buffer_head *bh;
  2018. +    unsigned char *p;
  2019. +
  2020. +    for (p = (unsigned char *)data; length > 0; blkaddr ++, length -= img->blocksize) {
  2021. +    bh = breada (img->dev, blkaddr, img->blocksize, 0, PAGE_SIZE);
  2022. +
  2023. +    if (!bh)
  2024. +        return NULL;
  2025. +    memcpy (p, bh->b_data, img->blocksize);
  2026. +    p += img->blocksize;
  2027. +    brelse (bh);
  2028. +    }
  2029. +
  2030. +    return data;
  2031. +}
  2032. +
  2033. +/*
  2034. + * Calculate block number for zone, zone index.
  2035. + */
  2036. +static inline unsigned long
  2037. +adfsimg_calcblockno (struct adfsimage *img, unsigned int zone, unsigned int start)
  2038. +{
  2039. +    /* *** 4GB LIMITATION ALERT! *** */
  2040. +    return (((zone ? zone * adfsimg_zonesize - RECSIZE * 8 : 0) + start) << adfsimg_dr.log2bpmb) /
  2041. +           img->blocksize;
  2042. +}
  2043. +
  2044. +static inline void
  2045. +adfsimg_addmapping (struct adfsimage *img, unsigned int zone, unsigned int start, unsigned int len)
  2046. +{
  2047. +    struct map newmap;
  2048. +
  2049. +    /*
  2050. +     * totaladdr  - starting block number for this segment
  2051. +     * startaddr  - sector on media for start
  2052. +     * lengthaddr - length in sectors of this block
  2053. +     */
  2054. +#if DEBUG & DEBUG_ADDMAPPING
  2055. +    printk ("Z: %8d S: %8d E: %8d ", zone, start, start + len);
  2056. +#endif
  2057. +    newmap.strt_sblk = 0;
  2058. +    newmap.strt_dblk = adfsimg_calcblockno (img, zone, start);
  2059. +    /* *** 4GB LIMITATION ALERT! *** */
  2060. +    newmap.length    = (len << adfsimg_dr.log2bpmb) / img->blocksize;
  2061. +
  2062. +    if (!img->mapstrt) {
  2063. +    img->mapstrt = kmalloc (5 * sizeof (newmap), GFP_KERNEL);
  2064. +    img->mapsize = 0; /* Size - 1 */
  2065. +    img->mapalloced = 5; /* allocated size */
  2066. +    memcpy (img->mapstrt, &newmap, sizeof (newmap));
  2067. +    } else {
  2068. +    struct map *mp;
  2069. +    mp = img->mapstrt + img->mapsize;
  2070. +    if (mp->strt_dblk + mp->length == newmap.strt_dblk)
  2071. +        mp->length += newmap.length;
  2072. +    else
  2073. +    if (img->mapsize < img->mapalloced - 1) {
  2074. +        newmap.strt_sblk = mp->strt_sblk + mp->length;
  2075. +        img->mapsize ++;
  2076. +        memcpy (&img->mapstrt[img->mapsize], &newmap, sizeof (newmap));
  2077. +    } else {
  2078. +        newmap.strt_sblk = mp->strt_sblk + mp->length;
  2079. +        mp = kmalloc ((img->mapalloced + 5) * sizeof (newmap), GFP_KERNEL);
  2080. +        img->mapalloced += 5;
  2081. +        img->mapsize ++;
  2082. +        memcpy (mp, img->mapstrt, img->mapsize * sizeof (newmap));
  2083. +        kfree (img->mapstrt);
  2084. +        img->mapstrt = mp;
  2085. +        memcpy (&img->mapstrt[img->mapsize], &newmap, sizeof (newmap));
  2086. +    }
  2087. +    }
  2088. +#if DEBUG & DEBUG_ADDMAPPING
  2089. +    printk ("SSB: %08lX STB: %08lX LEN: %08lX\n", img->mapstrt[img->mapsize].strt_sblk,
  2090. +        img->mapstrt[img->mapsize].strt_dblk, img->mapstrt[img->mapsize].length);
  2091. +#endif
  2092. +}
  2093. +
  2094. +static unsigned long
  2095. +adfsimg_scanmap (struct adfsimage *img, unsigned long internaladdr, int objlength, int simple)
  2096. +{
  2097. +    unsigned int fragment, zone, startzone, sectoroff, mapoff, found;
  2098. +
  2099. +    fragment  = (int)internaladdr >> 8;
  2100. +    startzone = zone = fragment / adfsimg_idsperzone;
  2101. +    sectoroff = (internaladdr & 0xff) ? (internaladdr & 0xff) - 1 : 0;
  2102. +/*
  2103. + * Problem area: if log2secsize < log2bpmb, then the map offset calculation
  2104. + *    breaks horribly.  However, can an internal address refer to a non-allocation
  2105. + *    unit sector offset?
  2106. + *
  2107. + * Ideas:
  2108. + *  if (adfsimg_dr.log2secsize > adfsimg_dr.log2bpmb)
  2109. + *    mapoff = sectoroff << (adfsimg_dr.log2secsize - adfsimg_dr.log2bpmb);
  2110. + *  else
  2111. + *    mapoff = sectoroff >> (adfsimg_dr.log2bpmb - adfsimg_dr.log2secsize);
  2112. + *
  2113. + *  shift = adfsimg_dr.log2secsize - adfsimg_dr.log2bpmb;
  2114. + *  if (shift < 0)
  2115. + *    mapoff = sectoroff >> (- shift);
  2116. + *  else
  2117. + *    mapoff = sectoroff << shift;
  2118. + */
  2119. +    mapoff = sectoroff << (adfsimg_dr.log2secsize - adfsimg_dr.log2bpmb);
  2120. +    objlength >>= adfsimg_dr.log2bpmb;
  2121. +    found = 0;
  2122. +
  2123. +    do {
  2124. +        unsigned char const *map;
  2125. +        unsigned int bmoff, bmoff_max;
  2126. +
  2127. +    map = ((unsigned char *)_adfsimg_map) + (zone << adfsimg_dr.log2secsize) + 4 +
  2128. +            (zone == 0 ? RECSIZE : 0);
  2129. +    bmoff_max = adfsimg_zonesize - ((zone == 0) ? RECSIZE << 3 : 0);
  2130. +    bmoff = 0;
  2131. +
  2132. +    while (bmoff < bmoff_max) {
  2133. +        unsigned long t;
  2134. +        unsigned int n, start;
  2135. +        int z;
  2136. +
  2137. +        start = bmoff;
  2138. +        z = bmoff >> 3;
  2139. +
  2140. +        t = ((map[z] | (map[z + 1] << 8) | (map[z + 2] << 16)) >> (bmoff & 7))
  2141. +        & ((1 << adfsimg_dr.idlen) - 1);
  2142. +        bmoff += adfsimg_dr.idlen;
  2143. +
  2144. +        /*
  2145. +         * I think that this would be better coded in assembler...
  2146. +         */
  2147. +        if (bmoff & 7) {
  2148. +            n = map[bmoff >> 3] >> (bmoff & 7);
  2149. +            if (!n)
  2150. +            bmoff = (bmoff + 8) & ~7;
  2151. +        else
  2152. +            for (; (n & 1) == 0; n >>= 1, bmoff += 1);
  2153. +        }
  2154. +        if (!(bmoff & 7)) {
  2155. +        while ((n = map[bmoff >> 3]) == 0)
  2156. +            bmoff += 8;
  2157. +
  2158. +        for (; (n & 1) == 0; n >>= 1, bmoff += 1);
  2159. +            }
  2160. +        bmoff += 1;
  2161. +        if (t == fragment) {
  2162. +        int length = bmoff - start;
  2163. +        if (mapoff) {
  2164. +            if (length < mapoff) {
  2165. +            mapoff -= length;
  2166. +            length = 0;
  2167. +            } else {
  2168. +            start += mapoff;
  2169. +            length -= mapoff;
  2170. +                mapoff = 0;
  2171. +            }
  2172. +        }
  2173. +        if (length) {
  2174. +            if (objlength < length)
  2175. +            length = objlength;
  2176. +            objlength -= length;
  2177. +            if (simple)
  2178. +            return adfsimg_calcblockno (img, zone, start);
  2179. +            else
  2180. +            adfsimg_addmapping(img, zone, start, length);
  2181. +            found += 1;
  2182. +            if (!objlength)
  2183. +            return found;
  2184. +        }
  2185. +        }
  2186. +    }
  2187. +    zone += 1;
  2188. +    if (zone == adfsimg_dr.nzones)
  2189. +        zone = 0;
  2190. +    bmoff = 0;
  2191. +    } while (zone != startzone);
  2192. +    return found;
  2193. +}
  2194. +
  2195. +static int
  2196. +adfsimg_decenddirs (struct adfsimage *img, int showinfo, unsigned long diraddr, char **ptr)
  2197. +{
  2198. +    char *leftptr, *p;
  2199. +    char dirname[16];
  2200. +    unsigned char *dir;
  2201. +    int i, length;
  2202. +
  2203. +    dir = kmalloc (2048, GFP_KERNEL);
  2204. +    if (!dir)
  2205. +    return 0;
  2206. +
  2207. +    leftptr = *ptr;
  2208. +
  2209. +    while (1) {
  2210. +        unsigned char *dirptr;
  2211. +    if (!adfsimg_read (dir, img, diraddr, 2048)) {
  2212. +        if (showinfo)
  2213. +        printk (" dir unreadable");
  2214. +        kfree (dir);
  2215. +        return 0;
  2216. +    }
  2217. +    /*
  2218. +     * Check that the directory looks feasable
  2219. +     */
  2220. +    if ((strncmp ((char *)dir + 1, "Nick", 4) && strncmp ((char *)dir + 1, "Hugo", 4)) ||
  2221. +        strncmp ((char *)dir + 1, (char *)dir + 2043, 4)) {
  2222. +        if (showinfo)
  2223. +        printk (" broken dir");
  2224. +        kfree (dir);
  2225. +        return 0;
  2226. +    }
  2227. +
  2228. +    p = strchr (leftptr, '.');
  2229. +    if (!p)
  2230. +        strcpy (dirname, leftptr);
  2231. +    else {
  2232. +        strncpy (dirname, leftptr, p - leftptr);
  2233. +        dirname[p - leftptr] = '\0';
  2234. +        leftptr = ++p;
  2235. +    }
  2236. +
  2237. +    for (dirptr = dir + 5; *dirptr; dirptr += 26) {
  2238. +        for (i = 0; i < 10; i++) {
  2239. +            char c1, c2;
  2240. +            if (dirptr[i] == 0x0d || dirname[i] == '\0')
  2241. +            break;
  2242. +        c1 = tolower(dirptr[i]);
  2243. +        c2 = tolower(dirname[i]);
  2244. +        if (c1 != c2)
  2245. +            break;
  2246. +        }
  2247. +        if (dirname[i] == '\0' && (i == 10 || dirptr[i] == 0x0d))
  2248. +        break;
  2249. +    }
  2250. +
  2251. +    if (!*dirptr) {
  2252. +        if (showinfo)
  2253. +        printk (" %s '%s' not found\n", p ? "dir" : "file", dirname);
  2254. +        kfree (dir);
  2255. +        return 0;
  2256. +    }
  2257. +
  2258. +    /*
  2259. +     * Check that we're not referencing a file when we mean a directory or
  2260. +     * vice versa.
  2261. +     */
  2262. +    if ((dirptr[25] & OBJ_DIRECTORY && !p) || (!(dirptr[25] & OBJ_DIRECTORY) && p)) {
  2263. +        if (showinfo)
  2264. +        printk (" %s '%s' is not a %s\n", p ? "file" : "dir", dirname, p ? "dir" : "file");
  2265. +        kfree (dir);
  2266. +        return 0;
  2267. +    }
  2268. +
  2269. +    length = (unsigned long) dirptr[18] | (dirptr[19] << 8) |
  2270. +         (dirptr[20] << 16) | (dirptr[21] << 24);
  2271. +    diraddr = (unsigned long) dirptr[22] | (dirptr[23] << 8) | (dirptr[24] << 16);
  2272. +    diraddr = adfsimg_scanmap (img, diraddr, length, p ? 1 : 0);
  2273. +    if (!diraddr) {
  2274. +        if (showinfo)
  2275. +        printk (" internal error");
  2276. +        kfree (dir);
  2277. +        return 0;
  2278. +    }
  2279. +    if (!p) {
  2280. +        /*
  2281. +         * We must have come to the end of the string.  This entry is the
  2282. +         * filename.
  2283. +         */
  2284. +        kfree (dir);
  2285. +        return 1;
  2286. +    }
  2287. +    }
  2288. +}
  2289. +
  2290. +/*
  2291. + * Read in either map, and check the cross-check.  If the first map
  2292. + * has an invalid cross-check, try the other map.
  2293. + */
  2294. +static unsigned long
  2295. +adfsimg_readmap (struct adfsimage *img, int showinfo)
  2296. +{
  2297. +    unsigned int map_no, bad, maplen;
  2298. +    unsigned long mapaddr;
  2299. +
  2300. +    /* *** 4GB LIMITATION ALERT! *** */
  2301. +    mapaddr = (((adfsimg_dr.nzones >> 1) * adfsimg_zonesize -
  2302. +        ((adfsimg_dr.nzones > 1) ? RECSIZE * 8 : 0)) << adfsimg_dr.log2bpmb) /
  2303. +            img->blocksize;
  2304. +    adfsimg_maplen = adfsimg_dr.nzones << adfsimg_dr.log2secsize;
  2305. +    maplen = (adfsimg_maplen | (img->blocksize - 1)) / img->blocksize;
  2306. +
  2307. +    if (!(_adfsimg_map = vmalloc (maplen * img->blocksize))) {
  2308. +    if (showinfo)
  2309. +        printk (" no mem");
  2310. +    return 0;
  2311. +    }
  2312. +
  2313. +    /*
  2314. +     * We try to read the first map.
  2315. +     */
  2316. +    for (map_no = 0; map_no < 2; map_no ++) {
  2317. +    unsigned long blk_strt;
  2318. +    unsigned int off, chk;
  2319. +    unsigned char *map;
  2320. +
  2321. +    /*
  2322. +     * If img->blocksize > 1<<adfsimg_dr.log2secsize, then we could
  2323. +     * have problems here when trying the second map.
  2324. +     */
  2325. +    blk_strt = mapaddr + (map_no ? maplen : 0);
  2326. +    bad = 0;
  2327. +
  2328. +    if (!adfsimg_read (_adfsimg_map, img, blk_strt, maplen * img->blocksize)) {
  2329. +        bad = 1;
  2330. +        if (showinfo)
  2331. +        printk (" map %d unreadable", map_no);
  2332. +        break;
  2333. +    }
  2334. +
  2335. +    map = (unsigned char *)_adfsimg_map;
  2336. +    for (off = 3, chk = 0; off < (adfsimg_dr.nzones << adfsimg_dr.log2secsize);
  2337. +            off += 1 << adfsimg_dr.log2secsize)
  2338. +        chk ^= map[off];
  2339. +
  2340. +    if (chk != 0xff) {
  2341. +        bad = 1;
  2342. +        if (showinfo)
  2343. +        printk (" map %d corrupt", map_no + 1);
  2344. +    } else
  2345. +        break;
  2346. +    }
  2347. +    if (bad)
  2348. +        vfree (_adfsimg_map);
  2349. +
  2350. +    return bad ? 0 : mapaddr + 2 * maplen;
  2351. +}
  2352. +
  2353. +/*
  2354. + * Read in the boot sector, and validate it.  Also validate the
  2355. + * block size that we are using.
  2356. + */
  2357. +static struct disc_record *
  2358. +adfsimg_readbootsect (struct adfsimage *img, int showinfo)
  2359. +{
  2360. +    unsigned char *boot_sectors;
  2361. +    int allocation_unit_size;
  2362. +    struct buffer_head *bh;
  2363. +
  2364. +    if (!(bh = bread (img->dev, BOOT_SECTOR_ADDRESS / img->blocksize,
  2365. +        img->blocksize > 512 ? img->blocksize : 512))) {
  2366. +    if (showinfo)
  2367. +        printk (" bread failed");
  2368. +    return NULL;
  2369. +    }
  2370. +
  2371. +    boot_sectors = bh->b_data + BOOT_SECTOR_ADDRESS % img->blocksize;
  2372. +
  2373. +    if (adfs_checkbblk (boot_sectors)) {
  2374. +    if (showinfo)
  2375. +        printk (" non-adfs");
  2376. +    brelse (bh);
  2377. +    return NULL;
  2378. +    }
  2379. +
  2380. +    memcpy (&adfsimg_dr, boot_sectors + 0x1c0, sizeof (adfsimg_dr));
  2381. +    brelse (bh);
  2382. +
  2383. +    /*
  2384. +     * The blocksize must not be larger than the sector size specified
  2385. +     * in the boot sector, or else all this code breaks.
  2386. +     */
  2387. +    if (adfsimg_dr.log2secsize > adfsimg_dr.log2bpmb)
  2388. +    allocation_unit_size = 1 << adfsimg_dr.log2secsize;
  2389. +    else
  2390. +    allocation_unit_size = 1 << adfsimg_dr.log2bpmb;
  2391. +    if (img->blocksize > allocation_unit_size) {
  2392. +    if (showinfo)
  2393. +        printk (" allocation unit size too large - %d > %d", img->blocksize, allocation_unit_size);
  2394. +    return NULL;
  2395. +    }
  2396. +
  2397. +    return &adfsimg_dr;
  2398. +}
  2399. +
  2400. +static int adfsimg_init_onedisk (int target, int showinfo)
  2401. +{
  2402. +    struct adfsimage *img = adfsimg_images + target;
  2403. +    unsigned long root_dir_address;
  2404. +    unsigned int blocksize;
  2405. +    char *p;
  2406. +
  2407. +    img->mapdev = MKDEV(UNNAMED_MAJOR, 0);
  2408. +    if (MAJOR(img->dev) == ADFSIMG_MAJOR)
  2409. +    return 0;
  2410. +
  2411. +    if (img->filename == NULL || strlen (img->filename) == 0 || MAJOR(img->dev) == UNNAMED_MAJOR)
  2412. +    return 0;
  2413. +
  2414. +    if (showinfo)
  2415. +    printk (" im%c", target + 'a');
  2416. +
  2417. +    /*
  2418. +     * Sort out the sector size that we can support.  Most devices
  2419. +     * default to 1024 byte blocks, and 512 byte sectors.
  2420. +     *
  2421. +     * TODO:
  2422. +     * However, we do check this against the size wanted in the boot
  2423. +     * block.  If it says that the sector size is 1024, then we might
  2424. +     * as well stick with 1024 byte blocks, otherwise switch to 512...
  2425. +     *
  2426. +     * Change:
  2427. +     * We now check the blocksize against the larger of the sector size
  2428. +     * and the map bit size.
  2429. +     */
  2430. +    if (hardsect_size[MAJOR(img->dev)])
  2431. +    blocksize = hardsect_size[MAJOR(img->dev)][MINOR(img->dev)];
  2432. +    else
  2433. +    blocksize = 512;
  2434. +
  2435. +    set_blocksize (img->dev, blocksize);
  2436. +    img->blocksize = blocksize;
  2437. +
  2438. +    /*
  2439. +     * Now read in the boot sector.  This has to be blocksize
  2440. +     * independent.
  2441. +     */
  2442. +    if (!adfsimg_readbootsect (img, showinfo))
  2443. +    return 0;
  2444. +
  2445. +    adfsimg_zonesize   = (8 << adfsimg_dr.log2secsize) - adfsimg_dr.zone_spare;
  2446. +    adfsimg_idsperzone = adfsimg_zonesize / (adfsimg_dr.idlen + 1);
  2447. +
  2448. +    if (!(root_dir_address = adfsimg_readmap (img, showinfo)))
  2449. +    return 0;
  2450. +
  2451. +    p = img->filename;
  2452. +    adfsimg_decenddirs (img, showinfo, root_dir_address, &p);
  2453. +
  2454. +    if (_adfsimg_map != NULL) {
  2455. +    vfree (_adfsimg_map);
  2456. +    _adfsimg_map = NULL;
  2457. +    }
  2458. +
  2459. +    img->mapdev = img->dev;
  2460. +
  2461. +    return img->mapstrt[img->mapsize].strt_sblk + img->mapstrt[img->mapsize].length;
  2462. +}
  2463. +
  2464. +/*
  2465. + * Get an index into the mapping array for this 'block'.  Once we have found
  2466. + * it, then as we map following blocks, we can just increment the index.
  2467. + */
  2468. +static inline int adfsimg_getindex (struct adfsimage *img, unsigned long block)
  2469. +{
  2470. +    unsigned int i, low, high;
  2471. +    const struct map *mp;
  2472. +
  2473. +    mp = img->mapstrt;
  2474. +
  2475. +    if (block >= (mp[img->mapsize].strt_sblk + mp[img->mapsize].length)) {
  2476. +    printk ("%s: access requested to block outside device: blk %lX\n",
  2477. +        kdevname (img->dev), block);
  2478. +    return -1;
  2479. +    }
  2480. +    for (low = 0, i = (high = img->mapsize) / 2; low != high; i = (high + low) >> 1) {
  2481. +    if (block < mp[i].strt_sblk)
  2482. +        high = i;
  2483. +    else if (block >= mp[i].strt_sblk + mp[i].length)
  2484. +        low = i + 1;
  2485. +    else break;
  2486. +    }
  2487. +#if DEBUG & DEBUG_MAPPING
  2488. +    printk ("Map entry: %lX [%lX-%lX]->[%lX-%lX]\n", block,
  2489. +        mp[i].strt_sblk, mp[i].strt_sblk + mp[i].length,
  2490. +        mp[i].strt_dblk, mp[i].strt_dblk + mp[i].length);
  2491. +#endif
  2492. +    return i;
  2493. +}
  2494. +
  2495. +/*========================================================================================
  2496. + * This is the 'device' driver for the image files.
  2497. + */
  2498. +
  2499. +static struct hd_struct adfsimg_parts[256] = { {0, 0}, };
  2500. +
  2501. +/*
  2502. + * Every request that comes in here is a request that needs to be split up into
  2503. + * a maximum of 64 separate requests.
  2504. + */
  2505. +static void adfsimg_request (void)
  2506. +{
  2507. +    while (1) {
  2508. +    unsigned int target, minor;
  2509. +    unsigned long block, length, nsectors, offset;
  2510. +    struct adfsimage *img;
  2511. +    int index;
  2512. +
  2513. +    INIT_REQUEST;
  2514. +
  2515. +    target = TARGETMAP(CURRENT->rq_dev);
  2516. +    img = adfsimg_images + target;
  2517. +
  2518. +    if (MAJOR(img->mapdev) == UNNAMED_MAJOR) {
  2519. +        printk (KERN_ERR
  2520. +        "im%c: request for mapping to unnamed device\n",
  2521. +            target + 'a');
  2522. +        end_request (0);
  2523. +        continue;
  2524. +    }
  2525. +
  2526. +    if (img->changed) {
  2527. +        end_request (0);
  2528. +        continue;
  2529. +    }
  2530. +
  2531. +    minor = MINOR(CURRENT->rq_dev);
  2532. +    block = CURRENT->sector;
  2533. +    nsectors = CURRENT->current_nr_sectors;
  2534. +    if (block >= adfsimg_parts[minor].nr_sects ||
  2535. +        (block + nsectors) > adfsimg_parts[minor].nr_sects) {
  2536. +        printk (KERN_ERR
  2537. +        "im%c: invalid block/size: minor = %u, block = %lu count = %lu\n",
  2538. +            target + 'a', minor, block, nsectors);
  2539. +        end_request (0);
  2540. +        continue;
  2541. +    }
  2542. +
  2543. +    block += adfsimg_parts[minor].start_sect;
  2544. +    index = adfsimg_getindex (img, block);
  2545. +    if (index < 0) {
  2546. +        printk (KERN_ERR
  2547. +            "im%c: invalid index: block = %lX\n", target + 'a', block);
  2548. +        end_request (0);
  2549. +        continue;
  2550. +    }
  2551. +#if 0
  2552. +     printk (KERN_ERR "Received an adfsimg_request (blk %lu len %lu ", block, nsectors);
  2553. +#endif
  2554. +    offset = block - img->mapstrt[index].strt_sblk;
  2555. +    block = offset + img->mapstrt[index].strt_dblk;
  2556. +    length = img->mapstrt[index].length - offset;
  2557. +#if 0
  2558. +    printk ("-> blk %lu len %lu), blksz=%d ", block, length, img->blocksize);
  2559. +#endif
  2560. +
  2561. +    while (nsectors) {
  2562. +        struct buffer_head *bh;
  2563. +        bh = getblk (img->mapdev, block, img->blocksize);
  2564. +        if (!bh) {
  2565. +        printk (KERN_ERR
  2566. +            "im%c: getblk(-,%ld,%d) returned NULL",
  2567. +            target + 'a', block, img->blocksize);
  2568. +        end_request (0);
  2569. +        break;
  2570. +        }
  2571. +        if (!buffer_uptodate(bh) && CURRENT->cmd == READ) {
  2572. +        ll_rw_block(READ, 1, &bh);
  2573. +        wait_on_buffer(bh);
  2574. +        if (!buffer_uptodate(bh)) {
  2575. +            brelse(bh);
  2576. +#if 0
  2577. +            printk ("error\n");
  2578. +#endif
  2579. +            end_request (0);
  2580. +            break;
  2581. +        }
  2582. +        }
  2583. +        if (CURRENT->cmd == READ)
  2584. +        memcpy (CURRENT->buffer, bh->b_data, img->blocksize);
  2585. +        else {
  2586. +            memcpy (bh->b_data, CURRENT->buffer, img->blocksize);
  2587. +            mark_buffer_uptodate(bh, 1);
  2588. +            mark_buffer_dirty(bh, 1);
  2589. +        }
  2590. +        brelse(bh);
  2591. +        CURRENT->buffer += img->blocksize;
  2592. +        CURRENT->sector += img->blocksize >> 9;
  2593. +        nsectors -= 1;
  2594. +        block ++;
  2595. +        if (!--length) {
  2596. +            index ++;
  2597. +        block = img->mapstrt[index].strt_dblk;
  2598. +        length = img->mapstrt[index].length;
  2599. +        }
  2600. +        if (nsectors == 0) {
  2601. +#if 0
  2602. +        printk ("ok\n");
  2603. +#endif
  2604. +        end_request (1);
  2605. +        }        
  2606. +    }
  2607. +    }
  2608. +}
  2609. +
  2610. +static int adfsimg_revalidate_disk (kdev_t dev, int maxusage);
  2611. +/*
  2612. + * TODO:
  2613. + *   IOCTL to get mapping filenames
  2614. + *   IOCTL to set mapping filenames
  2615. + *    - lock device.
  2616. + *    - set changed flag on device.
  2617. + *    - create new map.
  2618. + *    - unlock device.
  2619. + */
  2620. +static int
  2621. +adfsimg_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
  2622. +{
  2623. +    struct hd_geometry *loc = (struct hd_geometry *) arg;
  2624. +    int err, target;
  2625. +
  2626. +    if (!inode || !(inode->i_rdev))
  2627. +    return -EINVAL;
  2628. +
  2629. +    target = TARGETMAP(inode->i_rdev);
  2630. +
  2631. +    if (target >= ADFSIMG_NRDEV)
  2632. +    return -ENODEV;
  2633. +
  2634. +    switch (cmd) {
  2635. +    case HDIO_GETGEO:
  2636. +    if (!loc) return -EINVAL;
  2637. +    err = verify_area (VERIFY_WRITE, loc, sizeof (*loc));
  2638. +    if (err)
  2639. +        return err;
  2640. +    put_user (4, (char *)&loc->heads);
  2641. +    put_user (17, (char *)&loc->sectors);
  2642. +    put_user (adfsimg_parts[MINOR(inode->i_rdev)].nr_sects / (17 * 4), (short *)&loc->cylinders);
  2643. +    put_user (adfsimg_parts[MINOR(inode->i_rdev)].start_sect, (long *)&loc->start);
  2644. +    return 0;
  2645. +    case BLKRASET:
  2646. +    if (!suser ()) return -EACCES;
  2647. +    if (arg > 0xff) return -EINVAL;
  2648. +    read_ahead[MAJOR(inode->i_rdev)] = arg;
  2649. +    return 0;
  2650. +    case BLKRAGET:
  2651. +    if (!arg)  return -EINVAL;
  2652. +    err = verify_area (VERIFY_WRITE, (long *)arg, sizeof (long));
  2653. +    if (err)
  2654. +        return err;
  2655. +    put_user (read_ahead[MAJOR(inode->i_rdev)], (long *)arg);
  2656. +    return 0;
  2657. +    case BLKGETSIZE: /* Return device size */
  2658. +    if (!arg)  return -EINVAL;
  2659. +    err = verify_area (VERIFY_WRITE, (long *)arg, sizeof (long));
  2660. +    if (err)
  2661. +        return err;
  2662. +    put_user (adfsimg_parts[MINOR(inode->i_rdev)].nr_sects, (long *)arg);
  2663. +    return 0;
  2664. +    case BLKFLSBUF:
  2665. +    if (!suser ()) return -EACCES;
  2666. +    fsync_dev (inode->i_rdev);
  2667. +    invalidate_buffers (inode->i_rdev);
  2668. +    return 0;
  2669. +
  2670. +    case BLKRRPART:
  2671. +    return adfsimg_revalidate_disk (inode->i_rdev, 1);
  2672. +#if 0
  2673. +    case IMGFNGET:
  2674. +    return -EINVAL;
  2675. +
  2676. +    case IMGFNSET:
  2677. +    if (!suser ()) return -EACCES;
  2678. +    return -EINVAL;
  2679. +#endif
  2680. +
  2681. +    RO_IOCTLS(inode->i_rdev, arg);
  2682. +    default:
  2683. +    return -EINVAL;
  2684. +    }
  2685. +}
  2686. +
  2687. +/*
  2688. + * Open an mapped device.  Check for disk changes etc, and open
  2689. + * the real device.  This means that if that device wants to, it
  2690. + * can do things like locking the drive door.  We force ourself
  2691. + * to be busy while opening the real device.
  2692. + */
  2693. +static int adfsimg_open (struct inode *inode, struct file *filp)
  2694. +{
  2695. +    struct adfsimage *img;
  2696. +    unsigned int target;
  2697. +    int retval = 0;
  2698. +
  2699. +    target = TARGETMAP(inode->i_rdev);
  2700. +
  2701. +    if (target >= ADFSIMG_NRDEV)
  2702. +    return -ENODEV;
  2703. +
  2704. +    img = adfsimg_images + target;
  2705. +
  2706. +    if (MAJOR(img->mapdev) == UNNAMED_MAJOR)
  2707. +    return -ENODEV;
  2708. +#if 1
  2709. +    if (filp->f_mode & 2)
  2710. +    return -EROFS;
  2711. +#endif
  2712. +    check_disk_change (inode->i_rdev);
  2713. +
  2714. +    /*
  2715. +     * If the device is still changed, then it means that we haven't
  2716. +     * been able to revalidate it yet.
  2717. +     */
  2718. +    if (img->changed)
  2719. +    return -ENXIO;
  2720. +
  2721. +    adfsimg_lockdev (img);
  2722. +
  2723. +    if (img->accesscount == 0) {
  2724. +    /* was this the first open? */
  2725. +    struct file *d_filp;
  2726. +    struct inode *d_inode;
  2727. +    int retval;
  2728. +
  2729. +    d_filp = &img->filp;
  2730. +    d_inode = &img->inode;
  2731. +
  2732. +    memset (d_filp, 0, sizeof (*d_filp));
  2733. +    memset (d_inode, 0, sizeof (*d_inode));
  2734. +
  2735. +    d_inode->i_rdev = img->mapdev;
  2736. +    d_filp->f_inode = d_inode;
  2737. +    d_filp->f_mode  = filp->f_mode;
  2738. +
  2739. +    retval = blkdev_open (d_inode, d_filp);
  2740. +    }
  2741. +
  2742. +    if (retval == 0)
  2743. +    img->accesscount ++;
  2744. +
  2745. +    adfsimg_unlockdev (img);
  2746. +
  2747. +    return retval;
  2748. +}
  2749. +
  2750. +/*
  2751. + * Releasing a block device means we sync() it, so that it can safely
  2752. + * be forgotten about...  Close the real device as well if this is the
  2753. + * last release.
  2754. + */
  2755. +static void adfsimg_release (struct inode *inode, struct file *filp)
  2756. +{
  2757. +    struct adfsimage *img;
  2758. +    unsigned int target;
  2759. +
  2760. +    /*
  2761. +     * Make this image file busy while we unmount the device (we may sleep).
  2762. +     */
  2763. +
  2764. +    sync_dev (inode->i_rdev);
  2765. +    target = TARGETMAP(inode->i_rdev);
  2766. +
  2767. +    if (target >= ADFSIMG_NRDEV) {
  2768. +    printk ("im: releasing invalid device %d\n", target);
  2769. +    return;
  2770. +    }
  2771. +
  2772. +    img = adfsimg_images + target;
  2773. +
  2774. +    adfsimg_lockdev (img);
  2775. +
  2776. +    img->accesscount --;
  2777. +    if (img->accesscount == 0 && img->filp.f_op && img->filp.f_op->release)
  2778. +    img->filp.f_op->release (&img->inode, NULL);
  2779. +
  2780. +    /*
  2781. +     * Don't forget to wake up anything on the busy queues.
  2782. +     */
  2783. +    adfsimg_unlockdev (img);
  2784. +}
  2785. +
  2786. +static void adfsimg_geninit (struct gendisk *dev);
  2787. +
  2788. +static int adfsimg_sizes[256]      = { 0, };
  2789. +static int adfsimg_blocksizes[256] = { 0, };
  2790. +static int adfsimg_hardsizes[256]  = { 0, };
  2791. +
  2792. +static struct gendisk adfsimg_gendisk = {
  2793. +    MAJOR_NR,        /* major number */
  2794. +    "im",        /* major name   */
  2795. +    ADFSIMG_SHIFT,    /* bits to shift to get real from partition */
  2796. +    1 << ADFSIMG_SHIFT,    /* number of partitions per real */
  2797. +    ADFSIMG_NRDEV,    /* maximum number of reals */
  2798. +    adfsimg_geninit,    /* init function */
  2799. +    adfsimg_parts,    /* adfsimg_struct */
  2800. +    adfsimg_sizes,    /* block sizes */
  2801. +    0,            /* number */
  2802. +    (void *)NULL,    /* internal */
  2803. +    NULL        /* next */
  2804. +};
  2805. +
  2806. +/*
  2807. + * This is the ADFS Image file init entry point
  2808. + */
  2809. +static void adfsimg_geninit (struct gendisk *dev)
  2810. +{
  2811. +    int i;
  2812. +
  2813. +    adfsimg_gendisk.nr_real = ADFSIMG_NRDEV;
  2814. +
  2815. +    for (i = 0; i < 256; i++) {
  2816. +    adfsimg_blocksizes[i] = 1024;
  2817. +    adfsimg_hardsizes[i] = 512;
  2818. +    }
  2819. +
  2820. +    blksize_size[MAJOR_NR] = adfsimg_blocksizes;
  2821. +    hardsect_size[MAJOR_NR] = adfsimg_hardsizes;
  2822. +
  2823. +    printk (" im :");
  2824. +    for (i = 0; i < ADFSIMG_NRDEV; i++) {
  2825. +        int retval;
  2826. +
  2827. +        retval = adfsimg_init_onedisk (i, 1);
  2828. +        if (retval > 0) {
  2829. +        adfsimg_gendisk.part[i << ADFSIMG_SHIFT].nr_sects = retval;
  2830. +        adfsimg_images[i].capacity = retval;
  2831. +        adfsimg_images[i].changed = 0;
  2832. +    } else {
  2833. +        adfsimg_gendisk.part[i << ADFSIMG_SHIFT].start_sect = -1;
  2834. +        adfsimg_gendisk.part[i << ADFSIMG_SHIFT].nr_sects = 0;
  2835. +        adfsimg_images[i].capacity = retval;
  2836. +        adfsimg_images[i].changed = 1;
  2837. +    }
  2838. +    }
  2839. +    printk ("\n");
  2840. +}
  2841. +
  2842. +/*
  2843. + * Check to see if our media that we are mapping has changed, or
  2844. + * the mapped file has been altered.  I do wish that there were
  2845. + * upcalls...
  2846. + *
  2847. + * This will always return 1 until:
  2848. + * a) ALL opens on the device have been closed.
  2849. + * b) The device is re-opened.
  2850. + */
  2851. +static int adfsimg_checkmediachange (kdev_t dev)
  2852. +{
  2853. +    struct adfsimage *img;
  2854. +    int target;
  2855. +
  2856. +    target = TARGETMAP(dev);
  2857. +
  2858. +    if (target >= ADFSIMG_NRDEV) {
  2859. +    printk ("im: adfsimg_checkmediachange: invalid device\n");
  2860. +    return 0;
  2861. +    }
  2862. +
  2863. +    img = adfsimg_images + target;
  2864. +
  2865. +    if (MAJOR(img->mapdev) == UNNAMED_MAJOR)
  2866. +     return 0;
  2867. +
  2868. +    /*
  2869. +     * Check our mapped device first.  This way, our mapped device
  2870. +     * gets invalidated, and we can tell our device that its changed.
  2871. +     */
  2872. +    if (check_disk_change(img->mapdev)) {
  2873. +    /* its changed */
  2874. +    int i;
  2875. +    for (i = 0; i < ADFSIMG_NRDEV; i++) {
  2876. +        if (img->mapdev == adfsimg_images[i].mapdev) {
  2877. +        adfsimg_images[i].changed = 1;
  2878. +#if DEBUG & DEBUG_CHANGED
  2879. +        printk ("im: checkdiskchange: host device changed [target = %d]\n", i);
  2880. +#endif
  2881. +        }
  2882. +    }
  2883. +    }
  2884. +    if (img->changed)
  2885. +    return 1;
  2886. +    return 0;
  2887. +}
  2888. +
  2889. +/*
  2890. + * Revalidate our partitions.  We do not revalidate the device that
  2891. + * we are mapping, since that should have already been done.  However,
  2892. + * we do call it the disk change just to make sure.
  2893. + *
  2894. + * This means that we don't re-read our mapping information, and
  2895. + * we keep our size info on the raw image file.
  2896. + */
  2897. +static int adfsimg_revalidate_disk (kdev_t dev, int maxusage)
  2898. +{
  2899. +    int target, max_p, start, i;
  2900. +    struct adfsimage *img;
  2901. +    unsigned long flags;
  2902. +
  2903. +    target = TARGETMAP(dev);
  2904. +
  2905. +    if (target >= ADFSIMG_NRDEV) {
  2906. +    printk ("im: adfsimg_revalidate: invalid device\n");
  2907. +    return 0;
  2908. +    }
  2909. +#if DEBUG & DEBUG_CHANGED
  2910. +printk ("im: adfsimg_revalidate: target %d\n", target);
  2911. +#endif
  2912. +    img = adfsimg_images + target;
  2913. +
  2914. +    if (MAJOR(img->mapdev) == UNNAMED_MAJOR)
  2915. +    return 0;
  2916. +
  2917. +    save_flags_cli (flags);
  2918. +    if (img->busy || img->accesscount > maxusage) {
  2919. +        restore_flags (flags);
  2920. +    return -EBUSY;
  2921. +    }
  2922. +    img->busy = 1;
  2923. +    restore_flags (flags);
  2924. +
  2925. +    start = target << ADFSIMG_SHIFT;
  2926. +    max_p = adfsimg_gendisk.max_p;
  2927. +
  2928. +    for (i = adfsimg_gendisk.max_p - 1; i >= 0; i--) {
  2929. +    int minor = start + i;
  2930. +    if (adfsimg_gendisk.part[minor].nr_sects > 0) {
  2931. +        kdev_t devi = MKDEV(MAJOR_NR, minor);
  2932. +        sync_dev (devi);
  2933. +        invalidate_inodes (devi);
  2934. +        invalidate_buffers (devi);
  2935. +    }
  2936. +    adfsimg_gendisk.part[minor].start_sect = 0;
  2937. +    adfsimg_gendisk.part[minor].nr_sects = 0;
  2938. +    blksize_size[MAJOR_NR][minor] = 1024;
  2939. +    }
  2940. +
  2941. +    if (!check_disk_change (img->mapdev)) {
  2942. +    img->changed = 0;
  2943. +
  2944. +    adfsimg_gendisk.part[start].nr_sects = img->capacity;
  2945. +    resetup_one_dev (&adfsimg_gendisk, target);
  2946. +    }
  2947. +
  2948. +    adfsimg_unlockdev (img);
  2949. +    return 0;
  2950. +}
  2951. +
  2952. +static int adfsimg_revalidate (kdev_t dev)
  2953. +{
  2954. +    return adfsimg_revalidate_disk (dev, 0);
  2955. +}
  2956. +
  2957. +static struct file_operations adfsimg_fops = {
  2958. +    NULL,        /* lseek - default */
  2959. +    block_read,        /* read - general block-dev read */
  2960. +    block_write,    /* write - general block-dev write */
  2961. +    NULL,        /* readdir - bad */
  2962. +    NULL,        /* select */
  2963. +    adfsimg_ioctl,    /* ioctl */
  2964. +    NULL,        /* mmap */
  2965. +    adfsimg_open,    /* open */
  2966. +    adfsimg_release,    /* release */
  2967. +    block_fsync,    /* fsync */
  2968. +    NULL,        /* fasync */
  2969. +    adfsimg_checkmediachange, /* disk change */
  2970. +    adfsimg_revalidate    /* revalidate */
  2971. +};
  2972. +
  2973. +int adfsimg_init (void)
  2974. +{
  2975. +    struct gendisk **gdp;
  2976. +
  2977. +    if (register_blkdev (MAJOR_NR, "im", &adfsimg_fops)) {
  2978. +    printk ("adfsimg: unable to get major %d for image file system\n", MAJOR_NR);
  2979. +    return -1;
  2980. +    }
  2981. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  2982. +    read_ahead[MAJOR_NR] = 0;    /* we rely on the hardware reading ahead */
  2983. +
  2984. +    for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next));
  2985. +    *gdp = &adfsimg_gendisk;    /* link onto tail of list */
  2986. +    return 0;
  2987. +}
  2988. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/adfspart.c linux/arch/arm/drivers/block/adfspart.c
  2989. --- linux.orig/arch/arm/drivers/block/adfspart.c    Thu Jan  1 01:00:00 1970
  2990. +++ linux/arch/arm/drivers/block/adfspart.c    Mon Jul 15 21:32:56 1996
  2991. @@ -0,0 +1,364 @@
  2992. +/*
  2993. + * linux/arch/arm/drivers/block/adfspart.c
  2994. + *
  2995. + * Copyright (c) 1996 Russell King.
  2996. + *
  2997. + * Scan ADFS partitions on hard disk drives.
  2998. + */
  2999. +
  3000. +#include <linux/config.h>
  3001. +#include <linux/kernel.h>
  3002. +#include <linux/kdev_t.h>
  3003. +#include <linux/major.h>
  3004. +#include <linux/string.h>
  3005. +#include <linux/genhd.h>
  3006. +#include <linux/fs.h>
  3007. +
  3008. +#include "adfs.h"
  3009. +
  3010. +#undef  CONFIG_WRITE_PROTECT_ADFS
  3011. +#define CONFIG_ICS
  3012. +#define CONFIG_ADFS
  3013. +#undef  CONFIG_CUMANA
  3014. +
  3015. +/*
  3016. + * All partition types below here have been disabled.
  3017. + */
  3018. +#define PARTITION_LINUX        16
  3019. +extern void add_partition (struct gendisk *hd, int minor, int start, int size);
  3020. +
  3021. +static void adfspart_setgeometry (kdev_t dev, int secspertrack, int heads, unsigned long totalblocks)
  3022. +{
  3023. +    extern void hd_set_geometry (kdev_t dev, unsigned char, unsigned char, unsigned long, unsigned int);
  3024. +    extern void xd_set_geometry (kdev_t dev, unsigned char, unsigned char, unsigned long, unsigned int);
  3025. +
  3026. +    switch (MAJOR(dev)) {
  3027. +#ifdef CONFIG_BLK_DEV_HD
  3028. +    /*
  3029. +     * It would actually look like the HD driver doesn't actually need this,
  3030. +     * since it asks the drive about its the geometry...  However, the 'BIOS'
  3031. +     * information is not updated...
  3032. +     */
  3033. +    case HD_MAJOR:
  3034. +    hd_set_geometry (dev, secspertrack, heads, totalblocks, 1);
  3035. +    break;
  3036. +#endif
  3037. +#ifdef CONFIG_BLK_DEV_IDE
  3038. +#ifndef CONFIG_BLK_DEV_HD
  3039. +    case IDE0_MAJOR:
  3040. +#endif
  3041. +    case IDE1_MAJOR:
  3042. +    case IDE2_MAJOR:
  3043. +    case IDE3_MAJOR:
  3044. +    break;
  3045. +#endif
  3046. +#ifdef CONFIG_BLK_DEV_XD
  3047. +    case XT_DISK_MAJOR:
  3048. +    xd_set_geometry (dev, secspertrack, heads, totalblocks, 1);
  3049. +    break;
  3050. +#endif
  3051. +    default:
  3052. +    printk ("%s: don't know how to set geometry\n", kdevname (dev));
  3053. +    break;
  3054. +    }
  3055. +}
  3056. +
  3057. +#ifdef CONFIG_CUMANA
  3058. +static int adfspart_check_CUMANA (struct gendisk *hd, kdev_t dev,
  3059. +    unsigned long first_sector, int minor)
  3060. +{
  3061. +    struct buffer_head *bh;
  3062. +    struct disc_record *dr;
  3063. +    unsigned long start_sect = 0, nr_sects;
  3064. +    int first = 1, mask = (1 << hd->minor_shift) - 1;
  3065. +
  3066. +    /*
  3067. +     * Try Cumana style partitions - sector 3 contains ADFS boot block with pointer
  3068. +     * to next 'drive'.
  3069. +     *
  3070. +     * There are unknowns in this code - is the 'cylinder number' of the next
  3071. +     * partition relative to the start of this one - I'm assuming it is.
  3072. +     *
  3073. +     * Also, which ID did Cumana use?
  3074. +     *
  3075. +     * This is totally unfinished, and will require more work to get it going.
  3076. +     * Hence it is totally untested.
  3077. +     */
  3078. +
  3079. +    while (1) {
  3080. +    unsigned long end_sector;
  3081. +
  3082. +    if (!(bh = bread (dev, first_sector + 3, 1024)))
  3083. +        return -1;
  3084. +
  3085. +    if (adfspart_checkbblk (bh->b_data)) {
  3086. +        brelse (bh);
  3087. +        return first ? 0 : 1;
  3088. +    }
  3089. +
  3090. +    dr = (struct disc_record *)(bh->b_data + 0x1c0);
  3091. +
  3092. +    if (dr->disc_size == 0) {
  3093. +        brelse (bh);
  3094. +        return first ? 0 : 1;
  3095. +    }
  3096. +
  3097. +    end_sector = (bh->b_data[0x1fd] + (bh->b_data[0x1fe] << 8)) *
  3098. +         (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) * dr->secspertrack;
  3099. +
  3100. +    switch (bh->b_data[0x1fc] & 15) {
  3101. +        case 0: /* No partition / ADFS? */
  3102. +        if (end_cylinder == 0) {
  3103. +            /*
  3104. +             * No partition
  3105. +             */
  3106. +            nr_sects = dr->disc_size >> bb->log2secsize;
  3107. +            add_partition (hd, minor, first_sector, nr_sects);
  3108. +            return 1;
  3109. +        }
  3110. +        break;
  3111. +
  3112. +        case 1: /* RiscIX - we don't know how to find the next one. */
  3113. +        add_partition (hd, minor, first_sector, end_sector);
  3114. +        first_sector += end_sector;
  3115. +        break;
  3116. +    }
  3117. +    brelse (bh);
  3118. +    }
  3119. +}
  3120. +#endif
  3121. +
  3122. +#ifdef CONFIG_ADFS
  3123. +/*
  3124. + * Purpose: allocate ADFS partitions.
  3125. + *
  3126. + * Params : hd        - pointer to gendisk structure to store partition info.
  3127. + *        dev        - device number to access.
  3128. + *        first_sector- first readable sector on the device.
  3129. + *        minor    - first available minor on device.
  3130. + *
  3131. + * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok.
  3132. + *
  3133. + * Alloc  : hda  = whole drive
  3134. + *        hda1 = ADFS partition on first drive.
  3135. + *        hda2 = non-ADFS partition.
  3136. + */
  3137. +static int adfspart_check_ADFS (struct gendisk *hd, kdev_t dev,
  3138. +    unsigned long first_sector, int minor)
  3139. +{
  3140. +    struct buffer_head *bh;
  3141. +    unsigned long start_sect, nr_sects;
  3142. +    struct disc_record *dr;
  3143. +    int sectors_per_track, heads;
  3144. +
  3145. +    if (!(bh = bread (dev, first_sector + 3, 1024)))
  3146. +    return -1;
  3147. +
  3148. +    if (adfs_checkbblk (bh->b_data)) {
  3149. +        brelse (bh);
  3150. +        return 0;
  3151. +    }
  3152. +
  3153. +    dr = (struct disc_record *)(bh->b_data + 0x1c0);
  3154. +
  3155. +    if (dr->disc_size == 0) {
  3156. +    brelse (bh);
  3157. +    return 0;
  3158. +    }
  3159. +
  3160. +    printk (" [ADFS]");
  3161. +#ifdef CONFIG_WRITE_PROTECT_ADFS
  3162. +    write_protect (hd, MINOR(dev));
  3163. +#endif
  3164. +
  3165. +    sectors_per_track = dr->secspertrack;
  3166. +    heads = dr->heads + (dr->lowsector & 0x40 ? 1 : 0);
  3167. +
  3168. +    nr_sects = dr->disc_size >> dr->log2secsize;
  3169. +    /*
  3170. +     * insert ADFS drive partition details
  3171. +     */
  3172. +    add_partition (hd, minor, first_sector, nr_sects);
  3173. +#ifdef CONFIG_WRITE_PROTECT_ADFS
  3174. +    write_protect (hd, minor);
  3175. +#endif
  3176. +    adfspart_setgeometry (dev, sectors_per_track, heads, nr_sects);
  3177. +
  3178. +    /*
  3179. +     * Work out start of non-adfs partition.
  3180. +     */
  3181. +    start_sect = ((bh->b_data[0x1fe] << 8) + bh->b_data[0x1fd]) * sectors_per_track * heads;
  3182. +
  3183. +    if (start_sect) {
  3184. +    /*
  3185. +     * we now have a problem - how to set the origional disk size if the
  3186. +     * disk doesn't report it, since there is no standard way of getting
  3187. +     * that info.
  3188. +     */
  3189. +    switch (bh->b_data[0x1fc] & 15) {
  3190. +    case PARTITION_RISCIX:
  3191. +        printk (" [RiscIX]");
  3192. +        nr_sects = 1;        /* need to do something about that... */
  3193. +
  3194. +        adfspart_setgeometry (dev, sectors_per_track, heads, start_sect + nr_sects);
  3195. +        add_partition (hd, minor, first_sector + start_sect, nr_sects);
  3196. +        break;
  3197. +
  3198. +    case PARTITION_LINUX:
  3199. +        printk (" [Linux]");
  3200. +        nr_sects = 1;        /* need to do something about that... */
  3201. +
  3202. +        adfspart_setgeometry (dev, sectors_per_track, heads, start_sect + nr_sects);
  3203. +        break;
  3204. +    }
  3205. +    }
  3206. +    return 1;
  3207. +}
  3208. +#endif
  3209. +
  3210. +#ifdef CONFIG_ICS
  3211. +/*
  3212. + * Purpose: allocate ICS partitions.
  3213. + *
  3214. + * Params : hd        - pointer to gendisk structure to store partition info.
  3215. + *        dev        - device number to access.
  3216. + *        first_sector- first readable sector on the device.
  3217. + *        minor    - first available minor on device.
  3218. + *
  3219. + * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
  3220. + *
  3221. + * Alloc  : hda  = whole drive
  3222. + *        hda1 = ADFS partition 0 on first drive.
  3223. + *        hda2 = optional 'adfs' style partition after ADFS partition 0.
  3224. + *        hda3 = ADFS partition 1 on first drive.
  3225. + *        hda4 = optional 'adfs' style partition after ADFS partition 1.
  3226. + *        ..etc..
  3227. + */
  3228. +static int adfspart_check_ICS (struct gendisk *hd, kdev_t dev,
  3229. +    unsigned long first_sector, int minor)
  3230. +{
  3231. +    unsigned long sum, start_sect, nr_sects, last_sect = 0, *p;
  3232. +    int i, mask = (1 << hd->minor_shift) - 1;
  3233. +    int sectors_per_track, heads;
  3234. +    struct buffer_head *bh, *bh2;
  3235. +    struct disc_record *dr;
  3236. +
  3237. +    /*
  3238. +     * Try ICS style partitions - sector 0 contains partition info.
  3239. +     */
  3240. +
  3241. +    if (!(bh = bread (dev, first_sector, 1024)))
  3242. +        return -1;
  3243. +
  3244. +    /*
  3245. +     * The fax is a bit unclear here - it says:
  3246. +     * 'The checksum is caluclated as the 32-bit sum of all the bytes in the sector
  3247. +     *  from (0 to 507) + &50617274, and is stored at 508 - 511.'  Does this mean
  3248. +     * a step of 4 bytes, or one byte?
  3249. +     */
  3250. +    for (i = 0, sum = 0x50617274; i < 507; i++)
  3251. +    sum += bh->b_data[i];
  3252. +
  3253. +    if (sum != *(unsigned long *)(&bh->b_data[507])) {
  3254. +        brelse (bh);
  3255. +    return 0; /* not ICS partition table */
  3256. +    }
  3257. +
  3258. +    /*
  3259. +     * Now get the disc record from the boot sectors (the first partition MUST be ADFS)
  3260. +     */
  3261. +    if (!(bh2 = bread (dev, first_sector + 3, 1024))) {
  3262. +        brelse (bh);
  3263. +    return -1;
  3264. +    }
  3265. +
  3266. +    if (adfs_checkbblk (bh2->b_data)) {
  3267. +        brelse (bh2);
  3268. +        brelse (bh);
  3269. +        return 0;
  3270. +    }
  3271. +    
  3272. +    dr = (struct disc_record *)(bh->b_data + 0x1c0);
  3273. +
  3274. +    if (dr->disc_size == 0) {
  3275. +        brelse (bh2);
  3276. +    brelse (bh);
  3277. +    return 0;
  3278. +    }
  3279. +
  3280. +    sectors_per_track = dr->secspertrack;
  3281. +    heads = dr->heads + (dr->lowsector & 0x40 ? 1 : 0);
  3282. +
  3283. +    brelse (bh2);
  3284. +
  3285. +    printk (" [ICS]");
  3286. +#ifdef CONFIG_WRITE_PROTECT_ADFS
  3287. +    write_protect (hd, MINOR(dev));
  3288. +#endif
  3289. +
  3290. +    p = (unsigned long *)bh->b_data;
  3291. +    while (1) {
  3292. +    if ((minor & mask) == 0)
  3293. +        break;
  3294. +
  3295. +    start_sect = *p++;
  3296. +    nr_sects = *p++;
  3297. +    if (!start_sect || !nr_sects)
  3298. +        break;
  3299. +
  3300. +    add_partition (hd, minor, first_sector + start_sect, nr_sects);
  3301. +    last_sect = first_sector + start_sect + nr_sects;
  3302. +#ifdef CONFIG_WRITE_PROTECT_ADFS
  3303. +    write_protect (hd, minor);
  3304. +#endif
  3305. +    /*
  3306. +     * We have detected a partition.  It could be followed by another non-ICS
  3307. +     * partition specified in the boot block. [currently not implemented].
  3308. +     */
  3309. +    minor += 2;
  3310. +    }
  3311. +
  3312. +    brelse (bh);
  3313. +
  3314. +    adfspart_setgeometry (dev, sectors_per_track, heads, last_sect);
  3315. +
  3316. +    return 1;
  3317. +}
  3318. +#endif
  3319. +
  3320. +/*
  3321. + * Purpose: initialise all the partitions on an ADFS drive.
  3322. + *          These may be other ADFS partitions or a Linux/RiscBSD/RiscIX
  3323. + *        partition.
  3324. + *
  3325. + * Params : hd         - pointer to gendisk structure to store devices partitions.
  3326. + *          dev         - device number to access
  3327. + *        first_sector - first available sector on the disk.
  3328. + *        minor     - first available minor on this device.
  3329. + *
  3330. + * Returns: -1 on error, 0 if not ADFS format, 1 if ok.
  3331. + */
  3332. +int adfspart_initdev (struct gendisk *hd, kdev_t dev,
  3333. +        unsigned long first_sector, int minor)
  3334. +{
  3335. +    int r = 0;
  3336. +
  3337. +#ifdef CONFIG_ICS
  3338. +    if (r == 0)
  3339. +    r = adfspart_check_ICS (hd, dev, first_sector, minor);
  3340. +#endif
  3341. +#ifdef CONFIG_CUMANA
  3342. +    if (r == 0)    
  3343. +    r = adfspart_check_CUMANA (hd, dev, first_sector, minor);
  3344. +#endif
  3345. +#ifdef CONFIG_ADFS
  3346. +    if (r == 0)
  3347. +    r = adfspart_check_ADFS (hd, dev, first_sector, minor);
  3348. +#endif
  3349. +    if (r < 0)
  3350. +    printk (" unable to read boot sectors / partition sectors");
  3351. +    else
  3352. +    if (r)
  3353. +    printk ("\n");
  3354. +    return r;
  3355. +}
  3356. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/blk.h linux/arch/arm/drivers/block/blk.h
  3357. --- linux.orig/arch/arm/drivers/block/blk.h    Thu Jan  1 01:00:00 1970
  3358. +++ linux/arch/arm/drivers/block/blk.h    Fri Sep  6 23:58:51 1996
  3359. @@ -0,0 +1,446 @@
  3360. +#ifndef _BLK_H
  3361. +#define _BLK_H
  3362. +
  3363. +#include <linux/blkdev.h>
  3364. +#include <linux/locks.h>
  3365. +#include <linux/config.h>
  3366. +
  3367. +/*
  3368. + * NR_REQUEST is the number of entries in the request-queue.
  3369. + * NOTE that writes may use only the low 2/3 of these: reads
  3370. + * take precedence.
  3371. + */
  3372. +#define NR_REQUEST    64
  3373. +
  3374. +/*
  3375. + * This is used in the elevator algorithm.  We don't prioritise reads
  3376. + * over writes any more --- although reads are more time-critical than
  3377. + * writes, by treating them equally we increase filesystem throughput.
  3378. + * This turns out to give better overall performance.  -- sct
  3379. + */
  3380. +#define IN_ORDER(s1,s2) \
  3381. +((s1)->rq_dev < (s2)->rq_dev || (((s1)->rq_dev == (s2)->rq_dev && \
  3382. +(s1)->sector < (s2)->sector)))
  3383. +
  3384. +/*
  3385. + * These will have to be changed to be aware of different buffer
  3386. + * sizes etc.. It actually needs a major cleanup.
  3387. + */
  3388. +#if defined(IDE_DRIVER) || defined(MD_DRIVER)
  3389. +#define SECTOR_MASK ((BLOCK_SIZE >> 9) - 1)
  3390. +#else
  3391. +#define SECTOR_MASK (blksize_size[MAJOR_NR] &&     \
  3392. +    blksize_size[MAJOR_NR][MINOR(CURRENT->rq_dev)] ? \
  3393. +    ((blksize_size[MAJOR_NR][MINOR(CURRENT->rq_dev)] >> 9) - 1) :  \
  3394. +    ((BLOCK_SIZE >> 9)  -  1))
  3395. +#endif /* IDE_DRIVER */
  3396. +
  3397. +#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
  3398. +
  3399. +#ifdef CONFIG_CDU31A
  3400. +extern int cdu31a_init(void);
  3401. +#endif CONFIG_CDU31A
  3402. +#ifdef CONFIG_MCD
  3403. +extern int mcd_init(void);
  3404. +#endif CONFIG_MCD
  3405. +#ifdef CONFIG_MCDX
  3406. +extern int mcdx_init(void);
  3407. +#endif CONFIG_MCDX
  3408. +#ifdef CONFIG_SBPCD
  3409. +extern int sbpcd_init(void);
  3410. +#endif CONFIG_SBPCD
  3411. +#ifdef CONFIG_AZTCD
  3412. +extern int aztcd_init(void);
  3413. +#endif CONFIG_AZTCD
  3414. +#ifdef CONFIG_CDU535
  3415. +extern int sony535_init(void);
  3416. +#endif CONFIG_CDU535
  3417. +#ifdef CONFIG_GSCD
  3418. +extern int gscd_init(void);
  3419. +#endif CONFIG_GSCD
  3420. +#ifdef CONFIG_CM206
  3421. +extern int cm206_init(void);
  3422. +#endif CONFIG_CM206
  3423. +#ifdef CONFIG_OPTCD
  3424. +extern int optcd_init(void);
  3425. +#endif CONFIG_OPTCD
  3426. +#ifdef CONFIG_SJCD
  3427. +extern int sjcd_init(void);
  3428. +#endif CONFIG_SJCD
  3429. +#ifdef CONFIG_BLK_DEV_HD
  3430. +extern int hd_init(void);
  3431. +#endif
  3432. +#ifdef CONFIG_BLK_DEV_IDE
  3433. +extern int ide_init(void);
  3434. +#endif
  3435. +#ifdef CONFIG_BLK_DEV_XD
  3436. +extern int xd_init(void);
  3437. +#endif
  3438. +#ifdef CONFIG_BLK_DEV_LOOP
  3439. +extern int loop_init(void);
  3440. +#endif
  3441. +#ifdef CONFIG_BLK_DEV_MD
  3442. +extern int md_init(void);
  3443. +#endif CONFIG_BLK_DEV_MD
  3444. +
  3445. +extern void set_device_ro(kdev_t dev,int flag);
  3446. +void add_blkdev_randomness(int major);
  3447. +
  3448. +extern int floppy_init(void);
  3449. +extern void rd_load(void);
  3450. +extern int rd_init(void);
  3451. +extern int rd_doload;        /* 1 = load ramdisk, 0 = don't load */
  3452. +extern int rd_prompt;        /* 1 = prompt for ramdisk, 0 = don't prompt */
  3453. +extern int rd_image_start;    /* starting block # of image */
  3454. +
  3455. +#ifdef CONFIG_BLK_DEV_INITRD
  3456. +
  3457. +#define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */
  3458. +
  3459. +extern unsigned long initrd_start,initrd_end;
  3460. +extern int mount_initrd; /* zero if initrd should not be mounted */
  3461. +void initrd_init(void);
  3462. +
  3463. +#endif
  3464. +
  3465. +#define RO_IOCTLS(dev,where) \
  3466. +  case BLKROSET: { int __err;  if (!suser()) return -EACCES; \
  3467. +           __err = verify_area(VERIFY_READ, (void *) (where), sizeof(long)); \
  3468. +           if (!__err) set_device_ro((dev),get_fs_long((long *) (where))); return __err; } \
  3469. +  case BLKROGET: { int __err = verify_area(VERIFY_WRITE, (void *) (where), sizeof(long)); \
  3470. +           if (!__err) put_fs_long(0!=is_read_only(dev),(long *) (where)); return __err; }
  3471. +         
  3472. +#if defined(MAJOR_NR) || defined(IDE_DRIVER)
  3473. +
  3474. +/*
  3475. + * Add entries as needed.
  3476. + */
  3477. +
  3478. +#ifdef IDE_DRIVER
  3479. +
  3480. +#define DEVICE_NR(device)    (MINOR(device) >> PARTN_BITS)
  3481. +#define DEVICE_ON(device)    /* nothing */
  3482. +#define DEVICE_OFF(device)    /* nothing */
  3483. +
  3484. +#elif (MAJOR_NR == RAMDISK_MAJOR)
  3485. +
  3486. +/* ram disk */
  3487. +#define DEVICE_NAME "ramdisk"
  3488. +#define DEVICE_REQUEST rd_request
  3489. +#define DEVICE_NR(device) (MINOR(device))
  3490. +#define DEVICE_ON(device) 
  3491. +#define DEVICE_OFF(device)
  3492. +#define DEVICE_NO_RANDOM
  3493. +
  3494. +#elif (MAJOR_NR == FLOPPY_MAJOR)
  3495. +
  3496. +static void floppy_off(unsigned int nr);
  3497. +
  3498. +#define DEVICE_NAME "floppy"
  3499. +#define DEVICE_INTR do_floppy
  3500. +#define DEVICE_REQUEST do_fd_request
  3501. +#define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 ))
  3502. +#define DEVICE_ON(device)
  3503. +#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
  3504. +
  3505. +#elif (MAJOR_NR == HD_MAJOR)
  3506. +
  3507. +/* harddisk: timeout is 6 seconds.. */
  3508. +#define DEVICE_NAME "harddisk"
  3509. +#define DEVICE_INTR do_hd
  3510. +#define DEVICE_TIMEOUT HD_TIMER
  3511. +#define TIMEOUT_VALUE (6*HZ)
  3512. +#define DEVICE_REQUEST do_hd_request
  3513. +#define DEVICE_NR(device) (MINOR(device)>>6)
  3514. +#define DEVICE_ON(device)
  3515. +#define DEVICE_OFF(device)
  3516. +
  3517. +#elif (MAJOR_NR == SCSI_DISK_MAJOR)
  3518. +
  3519. +#define DEVICE_NAME "scsidisk"
  3520. +#define DEVICE_INTR do_sd  
  3521. +#define TIMEOUT_VALUE (2*HZ)
  3522. +#define DEVICE_REQUEST do_sd_request
  3523. +#define DEVICE_NR(device) (MINOR(device) >> 4)
  3524. +#define DEVICE_ON(device)
  3525. +#define DEVICE_OFF(device)
  3526. +
  3527. +/* Kludge to use the same number for both char and block major numbers */
  3528. +#elif  (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER)
  3529. +
  3530. +#define DEVICE_NAME "Multiple devices driver"
  3531. +#define DEVICE_REQUEST do_md_request
  3532. +#define DEVICE_NR(device) (MINOR(device))
  3533. +#define DEVICE_ON(device)
  3534. +#define DEVICE_OFF(device)
  3535. +
  3536. +#elif (MAJOR_NR == SCSI_TAPE_MAJOR)
  3537. +
  3538. +#define DEVICE_NAME "scsitape"
  3539. +#define DEVICE_INTR do_st  
  3540. +#define DEVICE_NR(device) (MINOR(device) & 0x7f)
  3541. +#define DEVICE_ON(device)
  3542. +#define DEVICE_OFF(device)
  3543. +
  3544. +#elif (MAJOR_NR == SCSI_CDROM_MAJOR)
  3545. +
  3546. +#define DEVICE_NAME "CD-ROM"
  3547. +#define DEVICE_INTR do_sr
  3548. +#define DEVICE_REQUEST do_sr_request
  3549. +#define DEVICE_NR(device) (MINOR(device))
  3550. +#define DEVICE_ON(device)
  3551. +#define DEVICE_OFF(device)
  3552. +
  3553. +#elif (MAJOR_NR == XT_DISK_MAJOR)
  3554. +
  3555. +#define DEVICE_NAME "xt disk"
  3556. +#define DEVICE_REQUEST do_xd_request
  3557. +#define DEVICE_NR(device) (MINOR(device) >> 6)
  3558. +#define DEVICE_ON(device)
  3559. +#define DEVICE_OFF(device)
  3560. +
  3561. +#elif defined(MFM_DISK_MAJOR) && (MAJOR_NR == MFM_DISK_MAJOR)
  3562. +
  3563. +#define DEVICE_NAME "mfm disk"
  3564. +#define DEVICE_INTR do_mfm
  3565. +#define DEVICE_REQUEST do_mfm_request
  3566. +#define DEVICE_NR(device) (MINOR(device) >> 6)
  3567. +#define DEVICE_ON(device)
  3568. +#define DEVICE_OFF(device)
  3569. +
  3570. +#elif (MAJOR_NR == CDU31A_CDROM_MAJOR)
  3571. +
  3572. +#define DEVICE_NAME "CDU31A"
  3573. +#define DEVICE_REQUEST do_cdu31a_request
  3574. +#define DEVICE_NR(device) (MINOR(device))
  3575. +#define DEVICE_ON(device)
  3576. +#define DEVICE_OFF(device)
  3577. +
  3578. +#elif (MAJOR_NR == MITSUMI_CDROM_MAJOR)
  3579. +
  3580. +#define DEVICE_NAME "Mitsumi CD-ROM"
  3581. +/* #define DEVICE_INTR do_mcd */
  3582. +#define DEVICE_REQUEST do_mcd_request
  3583. +#define DEVICE_NR(device) (MINOR(device))
  3584. +#define DEVICE_ON(device)
  3585. +#define DEVICE_OFF(device)
  3586. +
  3587. +#elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR)
  3588. +
  3589. +#define DEVICE_NAME "Mitsumi CD-ROM"
  3590. +/* #define DEVICE_INTR do_mcdx */
  3591. +#define DEVICE_REQUEST do_mcdx_request
  3592. +#define DEVICE_NR(device) (MINOR(device))
  3593. +#define DEVICE_ON(device)
  3594. +#define DEVICE_OFF(device)
  3595. +
  3596. +#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
  3597. +
  3598. +#define DEVICE_NAME "Matsushita CD-ROM controller #1"
  3599. +#define DEVICE_REQUEST do_sbpcd_request
  3600. +#define DEVICE_NR(device) (MINOR(device))
  3601. +#define DEVICE_ON(device)
  3602. +#define DEVICE_OFF(device)
  3603. +
  3604. +#elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR)
  3605. +
  3606. +#define DEVICE_NAME "Matsushita CD-ROM controller #2"
  3607. +#define DEVICE_REQUEST do_sbpcd2_request
  3608. +#define DEVICE_NR(device) (MINOR(device))
  3609. +#define DEVICE_ON(device)
  3610. +#define DEVICE_OFF(device)
  3611. +
  3612. +#elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR)
  3613. +
  3614. +#define DEVICE_NAME "Matsushita CD-ROM controller #3"
  3615. +#define DEVICE_REQUEST do_sbpcd3_request
  3616. +#define DEVICE_NR(device) (MINOR(device))
  3617. +#define DEVICE_ON(device)
  3618. +#define DEVICE_OFF(device)
  3619. +
  3620. +#elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR)
  3621. +
  3622. +#define DEVICE_NAME "Matsushita CD-ROM controller #4"
  3623. +#define DEVICE_REQUEST do_sbpcd4_request
  3624. +#define DEVICE_NR(device) (MINOR(device))
  3625. +#define DEVICE_ON(device)
  3626. +#define DEVICE_OFF(device)
  3627. +
  3628. +#elif (MAJOR_NR == AZTECH_CDROM_MAJOR)
  3629. +
  3630. +#define DEVICE_NAME "Aztech CD-ROM"
  3631. +#define DEVICE_REQUEST do_aztcd_request
  3632. +#define DEVICE_NR(device) (MINOR(device))
  3633. +#define DEVICE_ON(device)
  3634. +#define DEVICE_OFF(device)
  3635. +
  3636. +#elif (MAJOR_NR == CDU535_CDROM_MAJOR)
  3637. +
  3638. +#define DEVICE_NAME "SONY-CDU535"
  3639. +#define DEVICE_INTR do_cdu535
  3640. +#define DEVICE_REQUEST do_cdu535_request
  3641. +#define DEVICE_NR(device) (MINOR(device))
  3642. +#define DEVICE_ON(device)
  3643. +#define DEVICE_OFF(device)
  3644. +
  3645. +#elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR)
  3646. +
  3647. +#define DEVICE_NAME "Goldstar R420"
  3648. +#define DEVICE_REQUEST do_gscd_request
  3649. +#define DEVICE_NR(device) (MINOR(device))
  3650. +#define DEVICE_ON(device)
  3651. +#define DEVICE_OFF(device)
  3652. +
  3653. +#elif (MAJOR_NR == CM206_CDROM_MAJOR)
  3654. +#define DEVICE_NAME "Philips/LMS cd-rom cm206"
  3655. +#define DEVICE_REQUEST do_cm206_request
  3656. +#define DEVICE_NR(device) (MINOR(device))
  3657. +#define DEVICE_ON(device)
  3658. +#define DEVICE_OFF(device)
  3659. +
  3660. +#elif (MAJOR_NR == OPTICS_CDROM_MAJOR)
  3661. +
  3662. +#define DEVICE_NAME "DOLPHIN 8000AT CD-ROM"
  3663. +#define DEVICE_REQUEST do_optcd_request
  3664. +#define DEVICE_NR(device) (MINOR(device))
  3665. +#define DEVICE_ON(device)
  3666. +#define DEVICE_OFF(device)
  3667. +
  3668. +#elif (MAJOR_NR == SANYO_CDROM_MAJOR)
  3669. +
  3670. +#define DEVICE_NAME "Sanyo H94A CD-ROM"
  3671. +#define DEVICE_REQUEST do_sjcd_request
  3672. +#define DEVICE_NR(device) (MINOR(device))
  3673. +#define DEVICE_ON(device)
  3674. +#define DEVICE_OFF(device)
  3675. +
  3676. +#elif (MAJOR_NR == ADFSIMG_MAJOR)
  3677. +
  3678. +#define DEVICE_NAME "im"
  3679. +#define DEVICE_REQUEST adfsimg_request
  3680. +#define DEVICE_NR(device) (MINOR(device) >> ADFSIMG_SHIFT)
  3681. +#define DEVICE_ON(device)
  3682. +#define DEVICE_OFF(device)
  3683. +
  3684. +#endif /* MAJOR_NR == whatever */
  3685. +
  3686. +#if (MAJOR_NR != SCSI_TAPE_MAJOR)
  3687. +#if !defined(IDE_DRIVER)
  3688. +
  3689. +#ifndef CURRENT
  3690. +#define CURRENT (blk_dev[MAJOR_NR].current_request)
  3691. +#endif
  3692. +
  3693. +#define CURRENT_DEV DEVICE_NR(CURRENT->rq_dev)
  3694. +
  3695. +#ifdef DEVICE_INTR
  3696. +static void (*DEVICE_INTR)(void) = NULL;
  3697. +#endif
  3698. +#ifdef DEVICE_TIMEOUT
  3699. +
  3700. +#define SET_TIMER \
  3701. +((timer_table[DEVICE_TIMEOUT].expires = jiffies + TIMEOUT_VALUE), \
  3702. +(timer_active |= 1<<DEVICE_TIMEOUT))
  3703. +
  3704. +#define CLEAR_TIMER \
  3705. +timer_active &= ~(1<<DEVICE_TIMEOUT)
  3706. +
  3707. +#define SET_INTR(x) \
  3708. +if ((DEVICE_INTR = (x)) != NULL) \
  3709. +    SET_TIMER; \
  3710. +else \
  3711. +    CLEAR_TIMER;
  3712. +
  3713. +#else
  3714. +
  3715. +#define SET_INTR(x) (DEVICE_INTR = (x))
  3716. +
  3717. +#endif /* DEVICE_TIMEOUT */
  3718. +
  3719. +static void (DEVICE_REQUEST)(void);
  3720. +
  3721. +#ifdef DEVICE_INTR
  3722. +#define CLEAR_INTR SET_INTR(NULL)
  3723. +#else
  3724. +#define CLEAR_INTR
  3725. +#endif
  3726. +
  3727. +#define INIT_REQUEST \
  3728. +    if (!CURRENT) {\
  3729. +        CLEAR_INTR; \
  3730. +        return; \
  3731. +    } \
  3732. +    if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \
  3733. +        panic(DEVICE_NAME ": request list destroyed"); \
  3734. +    if (CURRENT->bh) { \
  3735. +        if (!buffer_locked(CURRENT->bh)) \
  3736. +            panic(DEVICE_NAME ": block not locked"); \
  3737. +    }
  3738. +
  3739. +#endif /* !defined(IDE_DRIVER) */
  3740. +
  3741. +/* end_request() - SCSI devices have their own version */
  3742. +/*               - IDE drivers have their own copy too */
  3743. +
  3744. +#if ! SCSI_BLK_MAJOR(MAJOR_NR)
  3745. +
  3746. +#if defined(IDE_DRIVER) && !defined(_IDE_C) /* shared copy for IDE modules */
  3747. +void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
  3748. +#else
  3749. +
  3750. +#ifdef IDE_DRIVER
  3751. +void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup) {
  3752. +    struct request *req = hwgroup->rq;
  3753. +#else
  3754. +static void end_request(int uptodate) {
  3755. +    struct request *req = CURRENT;
  3756. +#endif /* IDE_DRIVER */
  3757. +    struct buffer_head * bh;
  3758. +
  3759. +    req->errors = 0;
  3760. +    if (!uptodate) {
  3761. +        printk("end_request: I/O error, dev %s, sector %lu\n",
  3762. +            kdevname(req->rq_dev), req->sector);
  3763. +        req->nr_sectors--;
  3764. +        req->nr_sectors &= ~SECTOR_MASK;
  3765. +        req->sector += (BLOCK_SIZE / 512);
  3766. +        req->sector &= ~SECTOR_MASK;        
  3767. +    }
  3768. +
  3769. +    if ((bh = req->bh) != NULL) {
  3770. +        req->bh = bh->b_reqnext;
  3771. +        bh->b_reqnext = NULL;
  3772. +        mark_buffer_uptodate(bh, uptodate);
  3773. +        unlock_buffer(bh);
  3774. +        if ((bh = req->bh) != NULL) {
  3775. +            req->current_nr_sectors = bh->b_size >> 9;
  3776. +            if (req->nr_sectors < req->current_nr_sectors) {
  3777. +                req->nr_sectors = req->current_nr_sectors;
  3778. +                printk("end_request: buffer-list destroyed\n");
  3779. +            }
  3780. +            req->buffer = bh->b_data;
  3781. +            return;
  3782. +        }
  3783. +    }
  3784. +#ifndef DEVICE_NO_RANDOM
  3785. +    add_blkdev_randomness(MAJOR(req->rq_dev));
  3786. +#endif
  3787. +#ifdef IDE_DRIVER
  3788. +    blk_dev[MAJOR(req->rq_dev)].current_request = req->next;
  3789. +    hwgroup->rq = NULL;
  3790. +#else
  3791. +    DEVICE_OFF(req->rq_dev);
  3792. +    CURRENT = req->next;
  3793. +#endif /* IDE_DRIVER */
  3794. +    if (req->sem != NULL)
  3795. +        up(req->sem);
  3796. +    req->rq_status = RQ_INACTIVE;
  3797. +    wake_up(&wait_for_request);
  3798. +}
  3799. +#endif /* defined(IDE_DRIVER) && !defined(_IDE_C) */
  3800. +#endif /* ! SCSI_BLK_MAJOR(MAJOR_NR) */
  3801. +#endif /* (MAJOR_NR != SCSI_TAPE_MAJOR) */
  3802. +
  3803. +#endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */
  3804. +
  3805. +#endif /* _BLK_H */
  3806. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/fd1772.c linux/arch/arm/drivers/block/fd1772.c
  3807. --- linux.orig/arch/arm/drivers/block/fd1772.c    Thu Jan  1 01:00:00 1970
  3808. +++ linux/arch/arm/drivers/block/fd1772.c    Sat Sep  7 21:09:40 1996
  3809. @@ -0,0 +1,1638 @@
  3810. +/*
  3811. + *  linux/kernel/arch/arm/drivers/block/fd1772.c
  3812. + *  Based on ataflop.c in the m68k Linux
  3813. + *  Copyright (C) 1993  Greg Harp
  3814. + *  Atari Support by Bjoern Brauel, Roman Hodek
  3815. + *  Archimedes Support by Dave Gilbert (gilbertd@cs.man.ac.uk)
  3816. + *
  3817. + *  Big cleanup Sep 11..14 1994 Roman Hodek:
  3818. + *   - Driver now works interrupt driven
  3819. + *   - Support for two drives; should work, but I cannot test that :-(
  3820. + *   - Reading is done in whole tracks and buffered to speed up things
  3821. + *   - Disk change detection and drive deselecting after motor-off
  3822. + *     similar to TOS
  3823. + *   - Autodetection of disk format (DD/HD); untested yet, because I
  3824. + *     don't have an HD drive :-(
  3825. + *
  3826. + *  Fixes Nov 13 1994 Martin Schaller:
  3827. + *   - Autodetection works now
  3828. + *   - Support for 5 1/4" disks
  3829. + *   - Removed drive type (unknown on atari)
  3830. + *   - Do seeks with 8 Mhz
  3831. + *
  3832. + *  Changes by Andreas Schwab:
  3833. + *   - After errors in multiple read mode try again reading single sectors
  3834. + *  (Feb 1995):
  3835. + *   - Clean up error handling
  3836. + *   - Set blk_size for proper size checking
  3837. + *   - Initialize track register when testing presence of floppy
  3838. + *   - Implement some ioctl's
  3839. + *
  3840. + *  Changes by Torsten Lang:
  3841. + *   - When probing the floppies we should add the FDC1772CMDADD_H flag since
  3842. + *     the FDC1772 will otherwise wait forever when no disk is inserted...
  3843. + *
  3844. + *  Things left to do:
  3845. + *   - Formatting
  3846. + *   - Maybe a better strategy for disk change detection (does anyone
  3847. + *     know one?)
  3848. + *   - There are some strange problems left: The strangest one is
  3849. + *     that, at least on my TT (4+4MB), the first 2 Bytes of the last
  3850. + *     page of the TT-Ram (!) change their contents (some bits get
  3851. + *     set) while a floppy DMA is going on. But there are no accesses
  3852. + *     to these memory locations from the kernel... (I tested that by
  3853. + *     making the page read-only). I cannot explain what's going on...
  3854. + *   - Sometimes the drive-change-detection stops to work. The
  3855. + *     function is still called, but the WP bit always reads as 0...
  3856. + *     Maybe a problem with the status reg mode or a timing problem.
  3857. + *     Note 10/12/94: The change detection now seems to work reliably.
  3858. + *     There is no proof, but I've seen no hang for a long time...
  3859. + *
  3860. + * ARCHIMEDES changes: (gilbertd@cs.man.ac.uk)
  3861. + *     26/12/95 - Changed all names starting with FDC to FDC1772
  3862. + *                Removed all references to clock speed of FDC - we're stuck with 8MHz
  3863. + *                Modified disk_type structure to remove HD formats
  3864. + *
  3865. + *      7/ 1/96 - Wrote FIQ code, removed most remaining atariisms
  3866. + *
  3867. + *     13/ 1/96 - Well I think its read a single sector; but there is a problem
  3868. + *                fd_rwsec_done which is called in FIQ mode starts another transfer
  3869. + *                off (in fd_rwsec) while still in FIQ mode.  Because its still in
  3870. + *                FIQ mode it can't service the DMA and loses data. So need to
  3871. + *                heavily restructure.
  3872. + *     14/ 1/96 - Found that the definitions of the register numbers of the
  3873. + *                FDC were multiplied by 2 in the header for the 16bit words
  3874. + *                of the atari so half the writes were going in the wrong place.
  3875. + *                Also realised that the FIQ entry didn't make any attempt to
  3876. + *                preserve registers or return correctly; now in assembler.
  3877. + *
  3878. + *     11/ 2/96 - Hmm - doesn't work on real machine.  Auto detect doesn't
  3879. + *                and hacking that past seems to wait forever - check motor
  3880. + *                being turned on.
  3881. + *
  3882. + *     17/ 2/96 - still having problems - forcing track to -1 when selecting
  3883. + *                new drives seems to allow it to read first few sectors
  3884. + *                but then we get solid hangs at apparently random places
  3885. + *                which change depending what is happening.
  3886. + *
  3887. + *      9/ 3/96 - Fiddled a lot of stuff around to move to kernel 1.3.35
  3888. + *                A lot of fiddling in DMA stuff. Having problems with it
  3889. + *                constnatly thinking its timeing out. Ah - its timeout
  3890. + *                was set to (6*HZ) rather than jiffies+(6*HZ).  Now giving
  3891. + *                duff data!
  3892. + *
  3893. + *      5/ 4/96 - Made it use the new IOC_ macros rather than *ioc
  3894. + *                Hmm - giving unexpected FIQ and then timeouts
  3895. + *     18/ 8/96 - Ran through indent -kr -i8
  3896. + *                Some changes to disc change detect; don't know how well it
  3897. + *                works.
  3898. + *     24/ 8/96 - Put all the track buffering code back in from the atari
  3899. + *                code - I wonder if it will still work... No :-)
  3900. + *                Still works if I turn off track buffering.
  3901. + *     25/ 8/96 - Changed the timer expires that I'd added back to be 
  3902. + *                jiffies + ....; and it all sprang to life! Got 2.8K/sec
  3903. + *                off a cp -r of a 679K disc (showed 94% cpu usage!)
  3904. + *                (PC gets 14.3K/sec - 0% CPU!) Hmm - hard drive corrupt!
  3905. + *                Also perhaps that compile was with cache off.
  3906. + *                changed cli in fd_readtrack_check to cliIF
  3907. + *                changed vmallocs to kmalloc (whats the difference!!)
  3908. + *                Removed the busy wait loop in do_fd_request and replaced
  3909. + *                by a routine on tq_immediate; only 11% cpu on a dd off the
  3910. + *                raw disc - but the speed is the same.
  3911. + */
  3912. +
  3913. +#include <linux/config.h>
  3914. +#include <linux/sched.h>
  3915. +#include <linux/fs.h>
  3916. +#include <linux/fcntl.h>
  3917. +#include <linux/kernel.h>
  3918. +#include <linux/interrupt.h>
  3919. +#include <linux/timer.h>
  3920. +#include <linux/tqueue.h>
  3921. +#include <linux/fd.h>
  3922. +#include <linux/fd1772.h>
  3923. +#include <linux/errno.h>
  3924. +#include <linux/types.h>
  3925. +#include <linux/delay.h>
  3926. +#include <linux/mm.h>
  3927. +
  3928. +#include <asm/arch/oldlatches.h>
  3929. +#include <asm/system.h>
  3930. +#include <asm/bitops.h>
  3931. +#include <asm/dma.h>
  3932. +#include <asm/hardware.h>
  3933. +#include <asm/io.h>
  3934. +#include <asm/irq.h>
  3935. +#include <asm/irq-no.h>
  3936. +#include <asm/pgtable.h>
  3937. +
  3938. +#define MAJOR_NR FLOPPY_MAJOR
  3939. +#define FLOPPY_DMA 0
  3940. +#include "blk.h"
  3941. +
  3942. +/* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with
  3943. + * little additional rework in this file). But I'm not yet sure if
  3944. + * some other code depends on the number of floppies... (It is defined
  3945. + * in a public header!)
  3946. + */
  3947. +#if 0
  3948. +#undef FD_MAX_UNITS
  3949. +#define    FD_MAX_UNITS    2
  3950. +#endif
  3951. +
  3952. +/* Ditto worries for Arc - DAG */
  3953. +#define FD_MAX_UNITS 4
  3954. +#define TRACKBUFFER 0
  3955. +/*#define DEBUG*/
  3956. +
  3957. +#ifdef DEBUG
  3958. +#define DPRINT(a)    printk a
  3959. +#else
  3960. +#define DPRINT(a)
  3961. +#endif
  3962. +
  3963. +/* Disk types: DD */
  3964. +static struct archy_disk_type {
  3965. +    const char *name;
  3966. +    unsigned spt;        /* sectors per track */
  3967. +    unsigned blocks;    /* total number of blocks */
  3968. +    unsigned stretch;    /* track doubling ? */
  3969. +} disk_type[] = {
  3970. +
  3971. +    { "d360", 9, 720, 0 },            /* 360kB diskette */
  3972. +    { "D360", 9, 720, 1 },            /* 360kb in 720kb drive */
  3973. +    { "D720", 9, 1440, 0 },            /* 720kb diskette (DD) */
  3974. +    /*{ "D820", 10,1640, 0}, *//* DD disk with 82 tracks/10 sectors 
  3975. +                                  - DAG - can't see how type detect can distinguish this
  3976. +                      from 720K until it reads block 4 by which time its too late! */
  3977. +};
  3978. +
  3979. +#define    NUM_DISK_TYPES (sizeof(disk_type)/sizeof(*disk_type))
  3980. +
  3981. +/*
  3982. + * Maximum disk size (in kilobytes). This default is used whenever the
  3983. + * current disk size is unknown.
  3984. + */
  3985. +#define MAX_DISK_SIZE 720
  3986. +
  3987. +static int floppy_sizes[256];
  3988. +static int floppy_blocksizes[256] = {0,};
  3989. +
  3990. +/* current info on each unit */
  3991. +static struct archy_floppy_struct {
  3992. +    int connected;        /* !=0 : drive is connected */
  3993. +    int autoprobe;        /* !=0 : do autoprobe       */
  3994. +
  3995. +    struct archy_disk_type *disktype;    /* current type of disk */
  3996. +
  3997. +    int track;        /* current head position or -1
  3998. +                   * if unknown */
  3999. +    unsigned int steprate;    /* steprate setting */
  4000. +    unsigned int wpstat;    /* current state of WP signal
  4001. +                   * (for disk change detection) */
  4002. +} unit[FD_MAX_UNITS];
  4003. +
  4004. +/* DAG: On Arc we spin on a flag being cleared by fdc1772_comendhandler which
  4005. +   is an assembler routine */
  4006. +extern void fdc1772_comendhandler(void);    /* Actually doens't have these parameters - see fd1772.S */
  4007. +extern volatile int fdc1772_comendstatus;
  4008. +extern volatile int fdc1772_fdc_int_done;
  4009. +
  4010. +#define FDC1772BASE (0x3210000>>2)
  4011. +
  4012. +#define FDC1772_READ(reg) inb(FDC1772BASE+(reg/2))
  4013. +
  4014. +/* DAG: You wouldn't be silly to ask why FDC1772_WRITE is a function rather
  4015. +   than the #def below - well simple - the #def won't compile - and I
  4016. +   don't understand why (__outwc not defined) */
  4017. +/* NOTE: Reg is 0,2,4,6 as opposed to 0,1,2,3 or 0,4,8,12 to keep compatibility
  4018. +   with the ST version of fd1772.h */
  4019. +/*#define FDC1772_WRITE(reg,val) outw(val,(reg+FDC1772BASE)); */
  4020. +void FDC1772_WRITE(int reg, unsigned char val)
  4021. +{
  4022. +    if (reg == FDC1772REG_CMD) {
  4023. +        DPRINT(("FDC1772_WRITE new command 0x%x\n", val));
  4024. +        if (fdc1772_fdc_int_done) {
  4025. +            DPRINT(("FDC1772_WRITE: Hmm fdc1772_fdc_int_done true - resetting\n"));
  4026. +            fdc1772_fdc_int_done = 0;
  4027. +        };
  4028. +    };
  4029. +    outb(val, (reg / 2) + FDC1772BASE);
  4030. +};
  4031. +
  4032. +#define    MAX_SECTORS    22
  4033. +
  4034. +unsigned char *DMABuffer;    /* buffer for writes */
  4035. +/*static unsigned long PhysDMABuffer; *//* physical address */
  4036. +/* DAG: On Arc we just go straight for the DMA buffer */
  4037. +#define PhysDMABuffer DMABuffer
  4038. +
  4039. +#ifdef TRACKBUFFER   
  4040. +unsigned char *TrackBuffer;       /* buffer for reads */
  4041. +#define PhysTrackBuffer TrackBuffer /* physical address */
  4042. +static int BufferDrive, BufferSide, BufferTrack;
  4043. +static int read_track;    /* non-zero if we are reading whole tracks */
  4044. +  
  4045. +#define SECTOR_BUFFER(sec)  (TrackBuffer + ((sec)-1)*512)
  4046. +#define IS_BUFFERED(drive,side,track) \
  4047. +    (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track))
  4048. +#endif
  4049. +
  4050. +/*
  4051. + * These are global variables, as that's the easiest way to give
  4052. + * information to interrupts. They are the data used for the current
  4053. + * request.
  4054. + */
  4055. +static int SelectedDrive = 0;
  4056. +static int ReqCmd, ReqBlock;
  4057. +static int ReqSide, ReqTrack, ReqSector, ReqCnt;
  4058. +static int HeadSettleFlag = 0;
  4059. +static unsigned char *ReqData, *ReqBuffer;
  4060. +static int MotorOn = 0, MotorOffTrys;
  4061. +
  4062. +/* Synchronization of FDC1772 access. */
  4063. +static volatile int fdc_busy = 0;
  4064. +static struct wait_queue *fdc_wait = NULL;
  4065. +
  4066. +
  4067. +static unsigned int changed_floppies = 0xff, fake_change = 0;
  4068. +#define    CHECK_CHANGE_DELAY    HZ/2
  4069. +
  4070. +/* DAG - increased to 30*HZ - not sure if this is the correct thing to do */
  4071. +#define    FD_MOTOR_OFF_DELAY    (30*HZ)
  4072. +#define    FD_MOTOR_OFF_MAXTRY    (10*20)
  4073. +
  4074. +#define FLOPPY_TIMEOUT        (6*HZ)
  4075. +#define RECALIBRATE_ERRORS    4    /* After this many errors the drive
  4076. +                     * will be recalibrated. */
  4077. +#define MAX_ERRORS            8    /* After this many errors the driver
  4078. +                         * will give up. */
  4079. +
  4080. +
  4081. +#define    START_MOTOR_OFF_TIMER(delay)            \
  4082. +    do {                        \
  4083. +        motor_off_timer.expires = jiffies + (delay);        \
  4084. +        add_timer( &motor_off_timer );            \
  4085. +        MotorOffTrys = 0;                \
  4086. +    } while(0)
  4087. +
  4088. +#define    START_CHECK_CHANGE_TIMER(delay)                \
  4089. +    do {                            \
  4090. +        timer_table[FLOPPY_TIMER].expires = jiffies + (delay);    \
  4091. +        timer_active |= (1 << FLOPPY_TIMER);            \
  4092. +    } while(0)
  4093. +
  4094. +#define    START_TIMEOUT()                    \
  4095. +    do {                        \
  4096. +        del_timer( &timeout_timer );            \
  4097. +        timeout_timer.expires = jiffies + FLOPPY_TIMEOUT;    \
  4098. +        add_timer( &timeout_timer );            \
  4099. +    } while(0)
  4100. +
  4101. +#define    STOP_TIMEOUT()                    \
  4102. +    do {                        \
  4103. +        del_timer( &timeout_timer );            \
  4104. +    } while(0)
  4105. +
  4106. +#define ENABLE_IRQ() enable_irq(FIQ_FD1772+16);
  4107. +
  4108. +#define DISABLE_IRQ() disable_irq(FIQ_FD1772+16);
  4109. +
  4110. +static void fd1772_checkint(void);
  4111. +
  4112. +struct tq_struct fd1772_tq = 
  4113. +{ 0,0, (void *)fd1772_checkint, 0 };
  4114. +/*
  4115. + * The driver is trying to determine the correct media format
  4116. + * while Probing is set. fd_rwsec_done() clears it after a
  4117. + * successful access.
  4118. + */
  4119. +static int Probing = 0;
  4120. +
  4121. +/* This flag is set when a dummy seek is necesary to make the WP
  4122. + * status bit accessible.
  4123. + */
  4124. +static int NeedSeek = 0;
  4125. +
  4126. +
  4127. +/***************************** Prototypes *****************************/
  4128. +
  4129. +static void fd_select_side(int side);
  4130. +static void fd_select_drive(int drive);
  4131. +static void fd_deselect(void);
  4132. +static void fd_motor_off_timer(unsigned long dummy);
  4133. +static void check_change(void);
  4134. +static __inline__ void set_head_settle_flag(void);
  4135. +static __inline__ int get_head_settle_flag(void);
  4136. +static void floppy_irqconsequencehandler(void);
  4137. +static void fd_error(void);
  4138. +static void do_fd_action(int drive);
  4139. +static void fd_calibrate(void);
  4140. +static void fd_calibrate_done(int status);
  4141. +static void fd_seek(void);
  4142. +static void fd_seek_done(int status);
  4143. +static void fd_rwsec(void);
  4144. +#ifdef TRACKBUFFER   
  4145. +static void fd_readtrack_check( unsigned long dummy );  
  4146. +#endif
  4147. +static void fd_rwsec_done(int status);
  4148. +static void fd_times_out(unsigned long dummy);
  4149. +static void finish_fdc(void);
  4150. +static void finish_fdc_done(int dummy);
  4151. +static void floppy_off(unsigned int nr);
  4152. +static __inline__ void copy_buffer(void *from, void *to);
  4153. +static void setup_req_params(int drive);
  4154. +static void redo_fd_request(void);
  4155. +static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int
  4156. +            cmd, unsigned long param);
  4157. +static void fd_probe(int drive);
  4158. +static int fd_test_drive_present(int drive);
  4159. +static void config_types(void);
  4160. +static int floppy_open(struct inode *inode, struct file *filp);
  4161. +static void floppy_release(struct inode *inode, struct file *filp);
  4162. +
  4163. +/************************* End of Prototypes **************************/
  4164. +
  4165. +static struct timer_list motor_off_timer =
  4166. +{NULL, NULL, 0, 0, fd_motor_off_timer};
  4167. +#ifdef TRACKBUFFER
  4168. +static struct timer_list readtrack_timer =
  4169. +             { NULL, NULL, 0, 0, fd_readtrack_check };
  4170. +#endif
  4171. +static struct timer_list timeout_timer =
  4172. +{NULL, NULL, 0, 0, fd_times_out};
  4173. +
  4174. +/* DAG: Haven't got a clue what this is? */
  4175. +int stdma_islocked(void)
  4176. +{
  4177. +    return 0;
  4178. +};
  4179. +
  4180. +/* Select the side to use. */
  4181. +
  4182. +static void fd_select_side(int side)
  4183. +{
  4184. +    unsigned long flags;
  4185. +
  4186. +    save_flags(flags);
  4187. +    cli();
  4188. +
  4189. +    oldlatch_aupdate(LATCHA_SIDESEL, side ? 0 : LATCHA_SIDESEL);
  4190. +    restore_flags(flags);
  4191. +}
  4192. +
  4193. +
  4194. +/* Select a drive, update the FDC1772's track register
  4195. + */
  4196. +
  4197. +static void fd_select_drive(int drive)
  4198. +{
  4199. +    unsigned long flags;
  4200. +
  4201. +#ifdef DEBUG
  4202. +    printk("fd_select_drive:%d\n", drive);
  4203. +#endif
  4204. +    /* Hmm - nowhere do we seem to turn the motor on - I'm going to do it here! */
  4205. +    oldlatch_aupdate(LATCHA_MOTOR | LATCHA_INUSE, 0);
  4206. +
  4207. +    if (drive == SelectedDrive)
  4208. +        return;
  4209. +
  4210. +    save_flags(flags);
  4211. +    cli();
  4212. +    oldlatch_aupdate(LATCHA_FDSELALL, 0xf - (1 << drive));
  4213. +    restore_flags(flags);
  4214. +
  4215. +    /* restore track register to saved value */
  4216. +    FDC1772_WRITE(FDC1772REG_TRACK, unit[drive].track);
  4217. +    udelay(25);
  4218. +
  4219. +    SelectedDrive = drive;
  4220. +}
  4221. +
  4222. +
  4223. +/* Deselect both drives. */
  4224. +
  4225. +static void fd_deselect(void)
  4226. +{
  4227. +    unsigned long flags;
  4228. +
  4229. +    DPRINT(("fd_deselect\n"));
  4230. +
  4231. +    save_flags(flags);
  4232. +    cli();
  4233. +    oldlatch_aupdate(LATCHA_FDSELALL | LATCHA_MOTOR | LATCHA_INUSE, 0xf | LATCHA_MOTOR | LATCHA_INUSE);
  4234. +    restore_flags(flags);
  4235. +
  4236. +    SelectedDrive = -1;
  4237. +}
  4238. +
  4239. +
  4240. +/* This timer function deselects the drives when the FDC1772 switched the
  4241. + * motor off. The deselection cannot happen earlier because the FDC1772
  4242. + * counts the index signals, which arrive only if one drive is selected.
  4243. + */
  4244. +
  4245. +static void fd_motor_off_timer(unsigned long dummy)
  4246. +{
  4247. +    unsigned long flags;
  4248. +    unsigned char status;
  4249. +    int delay;
  4250. +
  4251. +    del_timer(&motor_off_timer);
  4252. +
  4253. +    if (SelectedDrive < 0)
  4254. +        /* no drive selected, needn't deselect anyone */
  4255. +        return;
  4256. +
  4257. +    save_flags(flags);
  4258. +    cli();
  4259. +
  4260. +    if (fdc_busy)        /* was stdma_islocked */
  4261. +        goto retry;
  4262. +
  4263. +    status = FDC1772_READ(FDC1772REG_STATUS);
  4264. +
  4265. +    if (!(status & 0x80)) {
  4266. +        /* motor already turned off by FDC1772 -> deselect drives */
  4267. +        DPRINT(("fdc1772: deselecting in fd_motor_off_timer\n"));
  4268. +        fd_deselect();
  4269. +        restore_flags(flags);
  4270. +        MotorOn = 0;
  4271. +        return;
  4272. +    }
  4273. +    /* not yet off, try again */
  4274. +
  4275. +      retry:
  4276. +    restore_flags(flags);
  4277. +    /* Test again later; if tested too often, it seems there is no disk
  4278. +     * in the drive and the FDC1772 will leave the motor on forever (or,
  4279. +     * at least until a disk is inserted). So we'll test only twice
  4280. +     * per second from then on...
  4281. +     */
  4282. +    delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?
  4283. +        (++MotorOffTrys, HZ / 20) : HZ / 2;
  4284. +    START_MOTOR_OFF_TIMER(delay);
  4285. +}
  4286. +
  4287. +
  4288. +/* This function is repeatedly called to detect disk changes (as good
  4289. + * as possible) and keep track of the current state of the write protection.
  4290. + */
  4291. +
  4292. +static void check_change(void)
  4293. +{
  4294. +    static int drive = 0;
  4295. +
  4296. +    unsigned long flags;
  4297. +    int stat;
  4298. +
  4299. +    if (fdc_busy)
  4300. +        return;        /* Don't start poking about if the fdc is busy */
  4301. +
  4302. +    return;            /* lets just forget it for the mo DAG */
  4303. +
  4304. +    if (++drive > 1 || !unit[drive].connected)
  4305. +        drive = 0;
  4306. +
  4307. +    save_flags(flags);
  4308. +    cli();
  4309. +
  4310. +    if (!stdma_islocked()) {
  4311. +        stat = !!(FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_WPROT);
  4312. +
  4313. +        /* The idea here is that if the write protect line has changed then
  4314. +        the disc must have changed */
  4315. +        if (stat != unit[drive].wpstat) {
  4316. +            DPRINT(("wpstat[%d] = %d\n", drive, stat));
  4317. +            unit[drive].wpstat = stat;
  4318. +            set_bit(drive, &changed_floppies);
  4319. +        }
  4320. +    }
  4321. +    restore_flags(flags);
  4322. +
  4323. +    START_CHECK_CHANGE_TIMER(CHECK_CHANGE_DELAY);
  4324. +}
  4325. +
  4326. +
  4327. +/* Handling of the Head Settling Flag: This flag should be set after each
  4328. + * seek operation, because we dont't use seeks with verify.
  4329. + */
  4330. +
  4331. +static __inline__ void set_head_settle_flag(void)
  4332. +{
  4333. +    HeadSettleFlag = FDC1772CMDADD_E;
  4334. +}
  4335. +
  4336. +static __inline__ int get_head_settle_flag(void)
  4337. +{
  4338. +    int tmp = HeadSettleFlag;
  4339. +    HeadSettleFlag = 0;
  4340. +    return (tmp);
  4341. +}
  4342. +
  4343. +
  4344. +
  4345. +
  4346. +/* General Interrupt Handling */
  4347. +
  4348. +static void (*FloppyIRQHandler) (int status) = NULL;
  4349. +
  4350. +static void floppy_irqconsequencehandler(void)
  4351. +{
  4352. +    unsigned char status;
  4353. +    void (*handler) (int);
  4354. +
  4355. +    fdc1772_fdc_int_done = 0;
  4356. +
  4357. +    handler = FloppyIRQHandler;
  4358. +    FloppyIRQHandler = NULL;
  4359. +
  4360. +    if (handler) {
  4361. +        nop();
  4362. +        status = (unsigned char) fdc1772_comendstatus;
  4363. +        DPRINT(("FDC1772 irq, status = %02x handler = %08lx\n", (unsigned int) status, (unsigned long) handler));
  4364. +        handler(status);
  4365. +    } else {
  4366. +        DPRINT(("FDC1772 irq, no handler status=%02x\n", fdc1772_comendstatus));
  4367. +    }
  4368. +    DPRINT(("FDC1772 irq: end of floppy_irq\n"));
  4369. +}
  4370. +
  4371. +
  4372. +/* Error handling: If some error happened, retry some times, then
  4373. + * recalibrate, then try again, and fail after MAX_ERRORS.
  4374. + */
  4375. +
  4376. +static void fd_error(void)
  4377. +{
  4378. +    printk("FDC1772: fd_error\n");
  4379. +    /*panic("fd1772: fd_error"); *//* DAG tmp */
  4380. +    if (!CURRENT)
  4381. +        return;
  4382. +    CURRENT->errors++;
  4383. +    if (CURRENT->errors >= MAX_ERRORS) {
  4384. +        printk("fd%d: too many errors.\n", SelectedDrive);
  4385. +        end_request(0);
  4386. +    } else if (CURRENT->errors == RECALIBRATE_ERRORS) {
  4387. +        printk("fd%d: recalibrating\n", SelectedDrive);
  4388. +        if (SelectedDrive != -1)
  4389. +            unit[SelectedDrive].track = -1;
  4390. +    }
  4391. +    redo_fd_request();
  4392. +}
  4393. +
  4394. +
  4395. +
  4396. +#define    SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0)
  4397. +
  4398. +
  4399. +/* do_fd_action() is the general procedure for a fd request: All
  4400. + * required parameter settings (drive select, side select, track
  4401. + * position) are checked and set if needed. For each of these
  4402. + * parameters and the actual reading or writing exist two functions:
  4403. + * one that starts the setting (or skips it if possible) and one
  4404. + * callback for the "done" interrupt. Each done func calls the next
  4405. + * set function to propagate the request down to fd_rwsec_done().
  4406. + */
  4407. +
  4408. +static void do_fd_action(int drive)
  4409. +{
  4410. +    DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track));
  4411. +
  4412. +#ifdef TRACKBUFFER
  4413. +  repeat:
  4414. +
  4415. +  if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
  4416. +    if (ReqCmd == READ) {
  4417. +      copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
  4418. +      if (++ReqCnt < CURRENT->current_nr_sectors) {
  4419. +        /* read next sector */
  4420. +        setup_req_params( drive );
  4421. +        goto repeat;
  4422. +      }
  4423. +      else {
  4424. +        /* all sectors finished */
  4425. +        CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
  4426. +        CURRENT->sector += CURRENT->current_nr_sectors;
  4427. +        end_request( 1 );
  4428. +        redo_fd_request();
  4429. +        return;
  4430. +      }
  4431. +    }
  4432. +    else {
  4433. +      /* cmd == WRITE, pay attention to track buffer
  4434. +       * consistency! */
  4435. +      copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) );
  4436. +    }
  4437. +  }
  4438. +#endif
  4439. +
  4440. +    if (SelectedDrive != drive) {
  4441. +        /*unit[drive].track = -1; DAG */
  4442. +        fd_select_drive(drive);
  4443. +    };
  4444. +
  4445. +
  4446. +    if (unit[drive].track == -1)
  4447. +        fd_calibrate();
  4448. +    else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch)
  4449. +        fd_seek();
  4450. +    else
  4451. +        fd_rwsec();
  4452. +}
  4453. +
  4454. +
  4455. +/* Seek to track 0 if the current track is unknown */
  4456. +
  4457. +static void fd_calibrate(void)
  4458. +{
  4459. +    DPRINT(("fd_calibrate\n"));
  4460. +    if (unit[SelectedDrive].track >= 0) {
  4461. +        fd_calibrate_done(0);
  4462. +        return;
  4463. +    }
  4464. +    DPRINT(("fd_calibrate (after track compare)\n"));
  4465. +    SET_IRQ_HANDLER(fd_calibrate_done);
  4466. +    /* we can't verify, since the speed may be incorrect */
  4467. +    FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | unit[SelectedDrive].steprate);
  4468. +
  4469. +    NeedSeek = 1;
  4470. +    MotorOn = 1;
  4471. +    START_TIMEOUT();
  4472. +    /* wait for IRQ */
  4473. +}
  4474. +
  4475. +
  4476. +static void fd_calibrate_done(int status)
  4477. +{
  4478. +    printk("fd_calibrate_done()\n");
  4479. +    STOP_TIMEOUT();
  4480. +
  4481. +    /* set the correct speed now */
  4482. +    if (status & FDC1772STAT_RECNF) {
  4483. +        printk("fd%d: restore failed\n", SelectedDrive);
  4484. +        fd_error();
  4485. +    } else {
  4486. +        unit[SelectedDrive].track = 0;
  4487. +        fd_seek();
  4488. +    }
  4489. +}
  4490. +
  4491. +
  4492. +/* Seek the drive to the requested track. The drive must have been
  4493. + * calibrated at some point before this.
  4494. + */
  4495. +
  4496. +static void fd_seek(void)
  4497. +{
  4498. +    DPRINT(("fd_seek() to track %d (unit[SelectedDrive].track=%d)\n", ReqTrack,
  4499. +        unit[SelectedDrive].track));
  4500. +    if (unit[SelectedDrive].track == ReqTrack <<
  4501. +        unit[SelectedDrive].disktype->stretch) {
  4502. +        fd_seek_done(0);
  4503. +        return;
  4504. +    }
  4505. +    FDC1772_WRITE(FDC1772REG_DATA, ReqTrack <<
  4506. +              unit[SelectedDrive].disktype->stretch);
  4507. +    udelay(25);
  4508. +    SET_IRQ_HANDLER(fd_seek_done);
  4509. +    FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK | unit[SelectedDrive].steprate);
  4510. +
  4511. +    MotorOn = 1;
  4512. +    set_head_settle_flag();
  4513. +    START_TIMEOUT();
  4514. +    /* wait for IRQ */
  4515. +}
  4516. +
  4517. +
  4518. +static void fd_seek_done(int status)
  4519. +{
  4520. +    DPRINT(("fd_seek_done()\n"));
  4521. +    STOP_TIMEOUT();
  4522. +
  4523. +    /* set the correct speed */
  4524. +    if (status & FDC1772STAT_RECNF) {
  4525. +        printk("fd%d: seek error (to track %d)\n",
  4526. +               SelectedDrive, ReqTrack);
  4527. +        /* we don't know exactly which track we are on now! */
  4528. +        unit[SelectedDrive].track = -1;
  4529. +        fd_error();
  4530. +    } else {
  4531. +        unit[SelectedDrive].track = ReqTrack <<
  4532. +            unit[SelectedDrive].disktype->stretch;
  4533. +        NeedSeek = 0;
  4534. +        fd_rwsec();
  4535. +    }
  4536. +}
  4537. +
  4538. +
  4539. +/* This does the actual reading/writing after positioning the head
  4540. + * over the correct track.
  4541. + */
  4542. +
  4543. +#ifdef TRACKBUFFER
  4544. +static int MultReadInProgress = 0;
  4545. +#endif
  4546. +
  4547. +
  4548. +static void fd_rwsec(void)
  4549. +{
  4550. +    unsigned long paddr, flags;
  4551. +    unsigned int rwflag, old_motoron;
  4552. +    unsigned int track;
  4553. +
  4554. +    DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n", ReqSector, ReqCmd == WRITE ? 'w' : 'r'));
  4555. +    if (ReqCmd == WRITE) {
  4556. +        /*cache_push( (unsigned long)ReqData, 512 ); */
  4557. +        paddr = (unsigned long) ReqData;
  4558. +        rwflag = 0x100;
  4559. +    } else {
  4560. +#ifdef TRACKBUFFER
  4561. +    if (read_track)
  4562. +      paddr = (unsigned long)PhysTrackBuffer;
  4563. +    else
  4564. +      paddr =(unsigned long)PhysDMABuffer;
  4565. +#else
  4566. +    paddr = (unsigned long)PhysDMABuffer;
  4567. +#endif
  4568. +        rwflag = 0;
  4569. +    }
  4570. +
  4571. +    DPRINT(("fd_rwsec() before sidesel rwflag=%d sec=%d trk=%d\n", rwflag,
  4572. +        ReqSector, FDC1772_READ(FDC1772REG_TRACK)));
  4573. +    fd_select_side(ReqSide);
  4574. +
  4575. +    /*DPRINT(("fd_rwsec() before start sector \n")); */
  4576. +    /* Start sector of this operation */
  4577. +#ifdef TRACKBUFFER
  4578. +  FDC1772_WRITE( FDC1772REG_SECTOR, !read_track ? ReqSector : 1 );
  4579. +#else
  4580. +  FDC1772_WRITE( FDC1772REG_SECTOR, ReqSector );
  4581. +#endif
  4582. +
  4583. +    /* Cheat for track if stretch != 0 */
  4584. +    if (unit[SelectedDrive].disktype->stretch) {
  4585. +        track = FDC1772_READ(FDC1772REG_TRACK);
  4586. +        FDC1772_WRITE(FDC1772REG_TRACK, track >>
  4587. +                  unit[SelectedDrive].disktype->stretch);
  4588. +    }
  4589. +    udelay(25);
  4590. +
  4591. +    DPRINT(("fd_rwsec() before setup DMA \n"));
  4592. +    /* Setup DMA - Heavily modified by DAG */
  4593. +    save_flags(flags);
  4594. +    cliIF();
  4595. +    disable_dma(FLOPPY_DMA);
  4596. +    set_dma_mode(FLOPPY_DMA, rwflag ? DMA_MODE_WRITE : DMA_MODE_READ);
  4597. +    set_dma_addr(FLOPPY_DMA, (long) paddr);        /* DAG - changed from Atari specific */
  4598. +#ifdef TRACKBUFFER
  4599. +  set_dma_count(FLOPPY_DMA,(!read_track ? 1 : unit[SelectedDrive].disktype->spt)*512);
  4600. +#else
  4601. +    set_dma_count(FLOPPY_DMA, 512);        /* Block/sector size - going to have to change */
  4602. +#endif
  4603. +    SET_IRQ_HANDLER(fd_rwsec_done);
  4604. +    /* Turn on dma int */
  4605. +    enable_dma(FLOPPY_DMA);
  4606. +    restore_flags(flags);
  4607. +    /* Now give it something to do */
  4608. +    FDC1772_WRITE(FDC1772REG_CMD, (rwflag ? (FDC1772CMD_WRSEC | FDC1772CMDADD_P) : 
  4609. +#ifdef TRACKBUFFER
  4610. +              (FDC1772CMD_RDSEC | (read_track ? FDC1772CMDADD_M : 0))
  4611. +#else
  4612. +              FDC1772CMD_RDSEC
  4613. +#endif
  4614. +    ));
  4615. +
  4616. +    DPRINT(("fd_rwsec() after DMA setup flags=0x%08x\n", flags));
  4617. +    /*sti(); *//* DAG - Hmm */
  4618. +    /* Hmm - should do something DAG */
  4619. +    old_motoron = MotorOn;
  4620. +    MotorOn = 1;
  4621. +    NeedSeek = 1;
  4622. +
  4623. +    /* wait for interrupt */
  4624. +
  4625. +#ifdef TRACKBUFFER
  4626. +  if (read_track) {
  4627. +    /* If reading a whole track, wait about one disk rotation and
  4628. +     * then check if all sectors are read. The FDC will even
  4629. +     * search for the first non-existant sector and need 1 sec to
  4630. +     * recognise that it isn't present :-(
  4631. +     */
  4632. +    readtrack_timer.expires = jiffies + HZ/5 + (old_motoron ? 0 : HZ);
  4633. +                              /* 1 rot. + 5 rot.s if motor was off  */
  4634. +    add_timer( &readtrack_timer );
  4635. +    MultReadInProgress = 1;
  4636. + }
  4637. +#endif
  4638. +
  4639. +    /*DPRINT(("fd_rwsec() before START_TIMEOUT \n")); */
  4640. +    START_TIMEOUT();
  4641. +    /*DPRINT(("fd_rwsec() after START_TIMEOUT \n")); */
  4642. +}
  4643. +
  4644. +
  4645. +#ifdef TRACKBUFFER
  4646. +
  4647. +static void fd_readtrack_check( unsigned long dummy )
  4648. +
  4649. +{ unsigned long flags, addr;
  4650. +  extern unsigned char *fdc1772_dataaddr;
  4651. +
  4652. +  save_flags(flags);
  4653. +  cliIF();
  4654. +
  4655. +  del_timer( &readtrack_timer );
  4656. +
  4657. +  if (!MultReadInProgress) {
  4658. +    /* This prevents a race condition that could arise if the
  4659. +     * interrupt is triggered while the calling of this timer
  4660. +     * callback function takes place. The IRQ function then has
  4661. +     * already cleared 'MultReadInProgress'  when control flow
  4662. +     * gets here.
  4663. +     */
  4664. +        restore_flags(flags);
  4665. +    return;
  4666. +  }
  4667. +
  4668. +  /* get the current DMA address */
  4669. +  addr=*fdc1772_dataaddr; /* DAG - ? */
  4670. +
  4671. +  if (addr >= PhysTrackBuffer + unit[SelectedDrive].disktype->spt*512) {
  4672. +    /* already read enough data, force an FDC interrupt to stop
  4673. +     * the read operation
  4674. +     */
  4675. +    SET_IRQ_HANDLER( NULL );
  4676. +    restore_flags(flags);
  4677. +    DPRINT(("fd_readtrack_check(): done\n"));
  4678. +    FDC1772_WRITE( FDC1772REG_CMD, FDC1772CMD_FORCI );
  4679. +    udelay(25);
  4680. +
  4681. +    /* No error until now -- the FDC would have interrupted
  4682. +     * otherwise!
  4683. +     */
  4684. +    fd_rwsec_done( 0 );
  4685. +  }
  4686. +  else {
  4687. +    /* not yet finished, wait another tenth rotation */
  4688. +    restore_flags(flags);
  4689. +    DPRINT(("fd_readtrack_check(): not yet finished\n"));
  4690. +    readtrack_timer.expires = jiffies + HZ/5/10;
  4691. +    add_timer( &readtrack_timer );
  4692. +  }
  4693. +}
  4694. +
  4695. +#endif
  4696. +
  4697. +static void fd_rwsec_done(int status)
  4698. +{
  4699. +    unsigned int track;
  4700. +
  4701. +    DPRINT(("fd_rwsec_done() status=%d\n", status));
  4702. +
  4703. +#ifdef TRACKBUFFER
  4704. +  if (read_track && !MultReadInProgress) return;
  4705. +  MultReadInProgress = 0;
  4706. +
  4707. +  STOP_TIMEOUT();
  4708. +
  4709. +  if (read_track)
  4710. +    del_timer( &readtrack_timer );
  4711. +#endif
  4712. +
  4713. +
  4714. +    /* Correct the track if stretch != 0 */
  4715. +    if (unit[SelectedDrive].disktype->stretch) {
  4716. +        track = FDC1772_READ(FDC1772REG_TRACK);
  4717. +        FDC1772_WRITE(FDC1772REG_TRACK, track <<
  4718. +                  unit[SelectedDrive].disktype->stretch);
  4719. +    }
  4720. +    if (ReqCmd == WRITE && (status & FDC1772STAT_WPROT)) {
  4721. +        printk("fd%d: is write protected\n", SelectedDrive);
  4722. +        goto err_end;
  4723. +    }
  4724. +    if ((status & FDC1772STAT_RECNF)
  4725. +#ifdef TRACKBUFFER
  4726. +    /* RECNF is no error after a multiple read when the FDC
  4727. +     * searched for a non-existant sector!
  4728. +     */
  4729. +    && !(read_track &&
  4730. +       FDC1772_READ(FDC1772REG_SECTOR) > unit[SelectedDrive].disktype->spt)
  4731. +#endif
  4732. +    ) {
  4733. +        if (Probing) {
  4734. +            if (unit[SelectedDrive].disktype > disk_type) {
  4735. +                /* try another disk type */
  4736. +                unit[SelectedDrive].disktype--;
  4737. +                floppy_sizes[SelectedDrive]
  4738. +                    = unit[SelectedDrive].disktype->blocks >> 1;
  4739. +            } else
  4740. +                Probing = 0;
  4741. +        } else {
  4742. +            /* record not found, but not probing. Maybe stretch wrong ? Restart probing */
  4743. +            if (unit[SelectedDrive].autoprobe) {
  4744. +                unit[SelectedDrive].disktype = disk_type + NUM_DISK_TYPES - 1;
  4745. +                floppy_sizes[SelectedDrive]
  4746. +                    = unit[SelectedDrive].disktype->blocks >> 1;
  4747. +                Probing = 1;
  4748. +            }
  4749. +        }
  4750. +        if (Probing) {
  4751. +            setup_req_params(SelectedDrive);
  4752. +#ifdef TRACKBUFFER
  4753. +      BufferDrive = -1;
  4754. +#endif
  4755. +            do_fd_action(SelectedDrive);
  4756. +            return;
  4757. +        }
  4758. +        printk("fd%d: sector %d not found (side %d, track %d)\n",
  4759. +               SelectedDrive, FDC1772_READ(FDC1772REG_SECTOR), ReqSide, ReqTrack);
  4760. +        goto err_end;
  4761. +    }
  4762. +    if (status & FDC1772STAT_CRC) {
  4763. +        printk("fd%d: CRC error (side %d, track %d, sector %d)\n",
  4764. +               SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR));
  4765. +        goto err_end;
  4766. +    }
  4767. +    if (status & FDC1772STAT_LOST) {
  4768. +        printk("fd%d: lost data (side %d, track %d, sector %d)\n",
  4769. +               SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR));
  4770. +        goto err_end;
  4771. +    }
  4772. +    Probing = 0;
  4773. +
  4774. +    if (ReqCmd == READ) {
  4775. +#ifdef TRACKBUFFER
  4776. +    if (!read_track)
  4777. +      {
  4778. +        /*cache_clear (PhysDMABuffer, 512);*/
  4779. +        copy_buffer (DMABuffer, ReqData);
  4780. +      }
  4781. +    else
  4782. +      {
  4783. +        /*cache_clear (PhysTrackBuffer, MAX_SECTORS * 512);*/
  4784. +        BufferDrive = SelectedDrive;
  4785. +        BufferSide  = ReqSide;
  4786. +        BufferTrack = ReqTrack;
  4787. +        copy_buffer (SECTOR_BUFFER (ReqSector), ReqData);
  4788. +      }
  4789. +#else
  4790. +        /*cache_clear( PhysDMABuffer, 512 ); */
  4791. +        copy_buffer(DMABuffer, ReqData);
  4792. +#endif
  4793. +    }
  4794. +    if (++ReqCnt < CURRENT->current_nr_sectors) {
  4795. +        /* read next sector */
  4796. +        setup_req_params(SelectedDrive);
  4797. +        do_fd_action(SelectedDrive);
  4798. +    } else {
  4799. +        /* all sectors finished */
  4800. +        CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
  4801. +        CURRENT->sector += CURRENT->current_nr_sectors;
  4802. +        end_request(1);
  4803. +        redo_fd_request();
  4804. +    }
  4805. +    return;
  4806. +
  4807. +  err_end:
  4808. +#ifdef TRACKBUFFER
  4809. +  BufferDrive = -1;
  4810. +#endif
  4811. +
  4812. +    fd_error();
  4813. +}
  4814. +
  4815. +
  4816. +static void fd_times_out(unsigned long dummy)
  4817. +{
  4818. +    SET_IRQ_HANDLER(NULL);
  4819. +    /* If the timeout occured while the readtrack_check timer was
  4820. +     * active, we need to cancel it, else bad things will happen */
  4821. +    del_timer( &readtrack_timer ); 
  4822. +    FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
  4823. +    udelay(25);
  4824. +
  4825. +    printk("floppy timeout\n");
  4826. +    STOP_TIMEOUT();        /* hmm - should we do this ? */
  4827. +    fd_error();
  4828. +}
  4829. +
  4830. +
  4831. +/* The (noop) seek operation here is needed to make the WP bit in the
  4832. + * FDC1772 status register accessible for check_change. If the last disk
  4833. + * operation would have been a RDSEC, this bit would always read as 0
  4834. + * no matter what :-( To save time, the seek goes to the track we're
  4835. + * already on.
  4836. + */
  4837. +
  4838. +static void finish_fdc(void)
  4839. +{
  4840. +    /* DAG - just try without this dummy seek! */
  4841. +    finish_fdc_done(0);
  4842. +    return;
  4843. +
  4844. +    if (!NeedSeek) {
  4845. +        finish_fdc_done(0);
  4846. +    } else {
  4847. +        DPRINT(("finish_fdc: dummy seek started\n"));
  4848. +        FDC1772_WRITE(FDC1772REG_DATA, unit[SelectedDrive].track);
  4849. +        SET_IRQ_HANDLER(finish_fdc_done);
  4850. +        FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK);
  4851. +        MotorOn = 1;
  4852. +        START_TIMEOUT();
  4853. +        /* we must wait for the IRQ here, because the ST-DMA is
  4854. +         * released immediatly afterwards and the interrupt may be
  4855. +         * delivered to the wrong driver.
  4856. +         */
  4857. +    }
  4858. +}
  4859. +
  4860. +
  4861. +static void finish_fdc_done(int dummy)
  4862. +{
  4863. +    unsigned long flags;
  4864. +
  4865. +    DPRINT(("finish_fdc_done entered\n"));
  4866. +    STOP_TIMEOUT();
  4867. +    NeedSeek = 0;
  4868. +
  4869. +    if ((timer_active & (1 << FLOPPY_TIMER)) &&
  4870. +        timer_table[FLOPPY_TIMER].expires < jiffies + 5)
  4871. +        /* If the check for a disk change is done too early after this
  4872. +         * last seek command, the WP bit still reads wrong :-((
  4873. +         */
  4874. +        timer_table[FLOPPY_TIMER].expires = jiffies + 5;
  4875. +    else {
  4876. +        /*      START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
  4877. +    };
  4878. +    del_timer(&motor_off_timer);
  4879. +    START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY);
  4880. +
  4881. +    save_flags(flags);
  4882. +    cli();
  4883. +    /* stdma_release(); - not sure if I should do something DAG  */
  4884. +    fdc_busy = 0;
  4885. +    wake_up(&fdc_wait);
  4886. +    restore_flags(flags);
  4887. +
  4888. +    DPRINT(("finish_fdc() finished\n"));
  4889. +}
  4890. +
  4891. +
  4892. +/* Prevent "aliased" accesses. */
  4893. +static fd_ref[4] =
  4894. +{0, 0, 0, 0};
  4895. +static fd_device[4] =
  4896. +{0, 0, 0, 0};
  4897. +
  4898. +/*
  4899. + * Current device number. Taken either from the block header or from the
  4900. + * format request descriptor.
  4901. + */
  4902. +#define CURRENT_DEVICE (CURRENT->rq_dev)
  4903. +
  4904. +/* Current error count. */
  4905. +#define CURRENT_ERRORS (CURRENT->errors)
  4906. +
  4907. +
  4908. +/* dummy for blk.h */
  4909. +static void floppy_off(unsigned int nr)
  4910. +{
  4911. +}
  4912. +
  4913. +
  4914. +/* On the old arcs write protect depends on the particular model
  4915. +   of machine.  On the A310, R140, and A440 there is a disc changed
  4916. +   detect, however on the A4x0/1 range there is not.  There
  4917. +   is nothing to tell you which machine your on.
  4918. +   At the moment I'm just marking changed always. I've
  4919. +   left the Atari's 'change on write protect change' code in this
  4920. +   part (but nothing sets it).
  4921. +   RiscOS apparently checks the disc serial number etc. to detect changes
  4922. +   - but if it sees a disc change line go high (?) it flips to using
  4923. +   it. Well  maybe I'll add that in the future (!?)
  4924. +*/
  4925. +static int check_floppy_change(dev_t dev)
  4926. +{
  4927. +    unsigned int drive = (dev & 0x03);
  4928. +
  4929. +    if (MAJOR(dev) != MAJOR_NR) {
  4930. +        printk("floppy_changed: not a floppy\n");
  4931. +        return 0;
  4932. +    }
  4933. +    if (test_bit(drive, &fake_change)) {
  4934. +        /* simulated change (e.g. after formatting) */
  4935. +        return 1;
  4936. +    }
  4937. +    if (test_bit(drive, &changed_floppies)) {
  4938. +        /* surely changed (the WP signal changed at least once) */
  4939. +        return 1;
  4940. +    }
  4941. +    if (unit[drive].wpstat) {
  4942. +        /* WP is on -> could be changed: to be sure, buffers should be
  4943. +           * invalidated...
  4944. +         */
  4945. +        return 1;
  4946. +    }
  4947. +    return 1; /* DAG - was 0 */
  4948. +}
  4949. +
  4950. +static int floppy_revalidate(dev_t dev)
  4951. +{
  4952. +    int drive = dev & 3;
  4953. +
  4954. +    if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change)
  4955. +        || unit[drive].disktype == 0) {
  4956. +#ifdef TRACKBUFFER
  4957. +      BufferDrive = -1;
  4958. +#endif
  4959. +        clear_bit(drive, &fake_change);
  4960. +        clear_bit(drive, &changed_floppies);
  4961. +        unit[drive].disktype = 0;
  4962. +    }
  4963. +    return 0;
  4964. +}
  4965. +
  4966. +static __inline__ void copy_buffer(void *from, void *to)
  4967. +{
  4968. +    ulong *p1 = (ulong *) from, *p2 = (ulong *) to;
  4969. +    int cnt;
  4970. +
  4971. +    for (cnt = 512 / 4; cnt; cnt--)
  4972. +        *p2++ = *p1++;
  4973. +}
  4974. +
  4975. +
  4976. +/* This sets up the global variables describing the current request. */
  4977. +
  4978. +static void setup_req_params(int drive)
  4979. +{
  4980. +    int block = ReqBlock + ReqCnt;
  4981. +
  4982. +    ReqTrack = block / unit[drive].disktype->spt;
  4983. +    ReqSector = block - ReqTrack * unit[drive].disktype->spt + 1;
  4984. +    ReqSide = ReqTrack & 1;
  4985. +    ReqTrack >>= 1;
  4986. +    ReqData = ReqBuffer + 512 * ReqCnt;
  4987. +
  4988. +#ifdef TRACKBUFFER
  4989. +  read_track = (ReqCmd == READ && CURRENT_ERRORS == 0);
  4990. +#endif
  4991. +
  4992. +    DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n", ReqSide,
  4993. +        ReqTrack, ReqSector, (unsigned long) ReqData));
  4994. +}
  4995. +
  4996. +
  4997. +static void redo_fd_request(void)
  4998. +{
  4999. +    int device, drive, type;
  5000. +    struct archy_floppy_struct *floppy;
  5001. +
  5002. +    DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->rq_dev=%04x CURRENT->sector=%ld\n",
  5003. +        (unsigned long) CURRENT, CURRENT ? CURRENT->rq_dev : 0,
  5004. +        CURRENT ? CURRENT->sector : 0));
  5005. +
  5006. +    if (CURRENT && CURRENT->rq_dev < 0)
  5007. +        goto the_end;
  5008. +
  5009. +      repeat:
  5010. +
  5011. +    if (!CURRENT)
  5012. +        goto the_end;
  5013. +
  5014. +    if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
  5015. +        panic(DEVICE_NAME ": request list destroyed");
  5016. +
  5017. +    if (CURRENT->bh) {
  5018. +        if (!buffer_locked(CURRENT->bh))
  5019. +            panic(DEVICE_NAME ": block not locked");
  5020. +    }
  5021. +    device = MINOR(CURRENT_DEVICE);
  5022. +    drive = device & 3;
  5023. +    type = device >> 2;
  5024. +    floppy = &unit[drive];
  5025. +
  5026. +    if (!floppy->connected) {
  5027. +        /* drive not connected */
  5028. +        printk("Unknown Device: fd%d\n", drive);
  5029. +        end_request(0);
  5030. +        goto repeat;
  5031. +    }
  5032. +    if (type == 0) {
  5033. +        if (!floppy->disktype) {
  5034. +            Probing = 1;
  5035. +            floppy->disktype = disk_type + NUM_DISK_TYPES - 1;
  5036. +            floppy_sizes[drive] = floppy->disktype->blocks >> 1;
  5037. +            floppy->autoprobe = 1;
  5038. +        }
  5039. +    } else {
  5040. +        /* user supplied disk type */
  5041. +        --type;
  5042. +        if (type >= NUM_DISK_TYPES) {
  5043. +            printk("fd%d: invalid disk format", drive);
  5044. +            end_request(0);
  5045. +            goto repeat;
  5046. +        }
  5047. +        floppy->disktype = &disk_type[type];
  5048. +        floppy_sizes[drive] = disk_type[type].blocks >> 1;
  5049. +        floppy->autoprobe = 0;
  5050. +    }
  5051. +
  5052. +    if (CURRENT->sector + 1 > floppy->disktype->blocks) {
  5053. +        end_request(0);
  5054. +        goto repeat;
  5055. +    }
  5056. +    /* stop deselect timer */
  5057. +    del_timer(&motor_off_timer);
  5058. +
  5059. +    ReqCnt = 0;
  5060. +    ReqCmd = CURRENT->cmd;
  5061. +    ReqBlock = CURRENT->sector;
  5062. +    ReqBuffer = CURRENT->buffer;
  5063. +    setup_req_params(drive);
  5064. +    do_fd_action(drive);
  5065. +
  5066. +    return;
  5067. +
  5068. +      the_end:
  5069. +    finish_fdc();
  5070. +}
  5071. +
  5072. +static void fd1772_checkint(void)
  5073. +{
  5074. +  /*printk("fd1772_checkint %d\n",fdc1772_fdc_int_done);*/
  5075. +  if (fdc1772_fdc_int_done)
  5076. +    floppy_irqconsequencehandler();
  5077. +  if (fdc_busy) {
  5078. +    queue_task(&fd1772_tq,&tq_immediate);
  5079. +    mark_bh(IMMEDIATE_BH);
  5080. +  };
  5081. +};
  5082. +
  5083. +void do_fd_request(void)
  5084. +{
  5085. +    unsigned long flags;
  5086. +
  5087. +    DPRINT(("do_fd_request for pid %d\n", current->pid));
  5088. +    if (fdc_busy) return;
  5089. +    save_flags(flags);
  5090. +    cli();
  5091. +    while (fdc_busy)
  5092. +        sleep_on(&fdc_wait);
  5093. +    fdc_busy = 1;
  5094. +    ENABLE_IRQ();
  5095. +    restore_flags(flags);
  5096. +
  5097. +    fdc1772_fdc_int_done = 0;
  5098. +
  5099. +    redo_fd_request();
  5100. +
  5101. +  queue_task(&fd1772_tq,&tq_immediate);
  5102. +  mark_bh(IMMEDIATE_BH);
  5103. +}
  5104. +
  5105. +
  5106. +static int invalidate_drive(int rdev)
  5107. +{
  5108. +    /* invalidate the buffer track to force a reread */
  5109. +#ifdef TRACKBUFFER
  5110. +  BufferDrive = -1;
  5111. +#endif
  5112. +
  5113. +    set_bit(rdev & 3, &fake_change);
  5114. +    check_disk_change(rdev);
  5115. +    return 0;
  5116. +}
  5117. +
  5118. +static int fd_ioctl(struct inode *inode, struct file *filp,
  5119. +            unsigned int cmd, unsigned long param)
  5120. +{
  5121. +#define IOCTL_MODE_BIT 8
  5122. +#define OPEN_WRITE_BIT 16
  5123. +#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
  5124. +
  5125. +    int drive, device;
  5126. +
  5127. +    device = inode->i_rdev;
  5128. +    switch (cmd) {
  5129. +        RO_IOCTLS(inode->i_rdev, param);
  5130. +    }
  5131. +    drive = MINOR(device);
  5132. +    if (!IOCTL_ALLOWED)
  5133. +        return -EPERM;
  5134. +    switch (cmd) {
  5135. +    case FDFMTBEG:
  5136. +        return 0;
  5137. +        /* case FDC1772LRPRM:  ??? DAG what does this do?? 
  5138. +           unit[drive].disktype = NULL;
  5139. +           floppy_sizes[drive] = MAX_DISK_SIZE;
  5140. +           return invalidate_drive (device); */
  5141. +    case FDFMTEND:
  5142. +    case FDFLUSH:
  5143. +        return invalidate_drive(drive);
  5144. +    }
  5145. +    if (!suser())
  5146. +        return -EPERM;
  5147. +    if (drive < 0 || drive > 3)
  5148. +        return -EINVAL;
  5149. +    switch (cmd) {
  5150. +    default:
  5151. +        return -EINVAL;
  5152. +    }
  5153. +    return 0;
  5154. +}
  5155. +
  5156. +
  5157. +/* Initialize the 'unit' variable for drive 'drive' */
  5158. +
  5159. +static void fd_probe(int drive)
  5160. +{
  5161. +    unit[drive].connected = 0;
  5162. +    unit[drive].disktype = NULL;
  5163. +
  5164. +    if (!fd_test_drive_present(drive))
  5165. +        return;
  5166. +
  5167. +    unit[drive].connected = 1;
  5168. +    unit[drive].track = -1; /* If we put the auto detect back in this can go to 0 */
  5169. +    unit[drive].steprate = FDC1772STEP_6;
  5170. +    MotorOn = 1;        /* from probe restore operation! */
  5171. +}
  5172. +
  5173. +
  5174. +/* This function tests the physical presence of a floppy drive (not
  5175. + * whether a disk is inserted). This is done by issuing a restore
  5176. + * command, waiting max. 2 seconds (that should be enough to move the
  5177. + * head across the whole disk) and looking at the state of the "TR00"
  5178. + * signal. This should now be raised if there is a drive connected
  5179. + * (and there is no hardware failure :-) Otherwise, the drive is
  5180. + * declared absent.
  5181. + */
  5182. +
  5183. +static int fd_test_drive_present(int drive)
  5184. +{
  5185. +    unsigned long timeout;
  5186. +    unsigned char status;
  5187. +    int ok;
  5188. +
  5189. +    printk("fd_test_drive_present %d\n", drive);
  5190. +    if (drive > 1)
  5191. +        return (0);
  5192. +    return (1);        /* Simple hack for the moment - the autodetect doesn't seem to work on arc */
  5193. +    fd_select_drive(drive);
  5194. +
  5195. +    /* disable interrupt temporarily */
  5196. +    DISABLE_IRQ();
  5197. +    FDC1772_WRITE(FDC1772REG_TRACK, 0x00);    /* was ff00 why? */
  5198. +    FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | FDC1772CMDADD_H | FDC1772STEP_6);
  5199. +
  5200. +    /*printk("fd_test_drive_present: Going into timeout loop\n"); */
  5201. +    for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; jiffies < timeout;) {
  5202. +        /*  What does this piece of atariism do? - query for an interrupt? */
  5203. +        /*  if (!(mfp.par_dt_reg & 0x20))
  5204. +           break; */
  5205. +        /* Well this is my nearest guess - quit when we get an FDC interrupt */
  5206. +        if (IOC_FIQSTAT & 2)
  5207. +            break;
  5208. +    }
  5209. +
  5210. +    /*printk("fd_test_drive_present: Coming out of timeout loop\n"); */
  5211. +    status = FDC1772_READ(FDC1772REG_STATUS);
  5212. +    ok = (status & FDC1772STAT_TR00) != 0;
  5213. +
  5214. +    /*printk("fd_test_drive_present: ok=%d\n",ok); */
  5215. +    /* force interrupt to abort restore operation (FDC1772 would try
  5216. +     * about 50 seconds!) */
  5217. +    FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
  5218. +    udelay(500);
  5219. +    status = FDC1772_READ(FDC1772REG_STATUS);
  5220. +    udelay(20);
  5221. +    /*printk("fd_test_drive_present: just before OK code %d\n",ok); */
  5222. +
  5223. +    if (ok) {
  5224. +        /* dummy seek command to make WP bit accessible */
  5225. +        FDC1772_WRITE(FDC1772REG_DATA, 0);
  5226. +        FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK);
  5227. +        printk("fd_test_drive_present: just before wait for int\n");
  5228. +        /* DAG: Guess means wait for interrupt */
  5229. +        while (!(IOC_FIQSTAT & 2));
  5230. +        printk("fd_test_drive_present: just after wait for int\n");
  5231. +        status = FDC1772_READ(FDC1772REG_STATUS);
  5232. +    }
  5233. +    printk("fd_test_drive_present: just before ENABLE_IRQ\n");
  5234. +    ENABLE_IRQ();
  5235. +    printk("fd_test_drive_present: about to return\n");
  5236. +    return (ok);
  5237. +}
  5238. +
  5239. +
  5240. +/* Look how many and which kind of drives are connected. If there are
  5241. + * floppies, additionally start the disk-change and motor-off timers.
  5242. + */
  5243. +
  5244. +static void config_types(void)
  5245. +{
  5246. +    int drive, cnt = 0;
  5247. +
  5248. +    printk("Probing floppy drive(s):\n");
  5249. +    for (drive = 0; drive < FD_MAX_UNITS; drive++) {
  5250. +        fd_probe(drive);
  5251. +        if (unit[drive].connected) {
  5252. +            printk("fd%d\n", drive);
  5253. +            ++cnt;
  5254. +        }
  5255. +    }
  5256. +
  5257. +    if (FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_BUSY) {
  5258. +        /* If FDC1772 is still busy from probing, give it another FORCI
  5259. +         * command to abort the operation. If this isn't done, the FDC1772
  5260. +         * will interrupt later and its IRQ line stays low, because
  5261. +         * the status register isn't read. And this will block any
  5262. +         * interrupts on this IRQ line :-(
  5263. +         */
  5264. +        FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
  5265. +        udelay(500);
  5266. +        FDC1772_READ(FDC1772REG_STATUS);
  5267. +        udelay(20);
  5268. +    }
  5269. +    if (cnt > 0) {
  5270. +        START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY);
  5271. +        if (cnt == 1)
  5272. +            fd_select_drive(0);
  5273. +        /*START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
  5274. +    }
  5275. +}
  5276. +
  5277. +/*
  5278. + * floppy_open check for aliasing (/dev/fd0 can be the same as
  5279. + * /dev/PS0 etc), and disallows simultaneous access to the same
  5280. + * drive with different device numbers.
  5281. + */
  5282. +
  5283. +static int floppy_open(struct inode *inode, struct file *filp)
  5284. +{
  5285. +    int drive;
  5286. +    int old_dev;
  5287. +
  5288. +    if (!filp) {
  5289. +        DPRINT(("Weird, open called with filp=0\n"));
  5290. +        return -EIO;
  5291. +    }
  5292. +    drive = MINOR(inode->i_rdev) & 3;
  5293. +    if ((MINOR(inode->i_rdev) >> 2) > NUM_DISK_TYPES)
  5294. +        return -ENXIO;
  5295. +
  5296. +    old_dev = fd_device[drive];
  5297. +
  5298. +    if (fd_ref[drive])
  5299. +        if (old_dev != inode->i_rdev)
  5300. +            return -EBUSY;
  5301. +
  5302. +    if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL))
  5303. +        return -EBUSY;
  5304. +
  5305. +    if (filp->f_flags & O_EXCL)
  5306. +        fd_ref[drive] = -1;
  5307. +    else
  5308. +        fd_ref[drive]++;
  5309. +
  5310. +    fd_device[drive] = inode->i_rdev;
  5311. +
  5312. +    if (old_dev && old_dev != inode->i_rdev)
  5313. +        invalidate_buffers(old_dev);
  5314. +
  5315. +    /* Allow ioctls if we have write-permissions even if read-only open */
  5316. +    if (filp->f_mode & 2 || permission(inode, 2) == 0)
  5317. +        filp->f_mode |= IOCTL_MODE_BIT;
  5318. +    if (filp->f_mode & 2)
  5319. +        filp->f_mode |= OPEN_WRITE_BIT;
  5320. +
  5321. +    if (filp->f_flags & O_NDELAY)
  5322. +        return 0;
  5323. +
  5324. +    if (filp->f_mode & 3) {
  5325. +        check_disk_change(inode->i_rdev);
  5326. +        if (filp->f_mode & 2) {
  5327. +            if (unit[drive].wpstat) {
  5328. +                floppy_release(inode, filp);
  5329. +                return -EROFS;
  5330. +            }
  5331. +        }
  5332. +    }
  5333. +    return 0;
  5334. +}
  5335. +
  5336. +
  5337. +static void floppy_release(struct inode *inode, struct file *filp)
  5338. +{
  5339. +    int drive;
  5340. +
  5341. +    drive = inode->i_rdev & 3;
  5342. +
  5343. +    if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
  5344. +        /* if the file is mounted OR (writable now AND writable at open
  5345. +           time) Linus: Does this cover all cases? */
  5346. +        block_fsync(inode, filp);
  5347. +
  5348. +    if (fd_ref[drive] < 0)
  5349. +        fd_ref[drive] = 0;
  5350. +    else if (!fd_ref[drive]--) {
  5351. +        printk("floppy_release with fd_ref == 0");
  5352. +        fd_ref[drive] = 0;
  5353. +    }
  5354. +}
  5355. +
  5356. +static struct file_operations floppy_fops =
  5357. +{
  5358. +    NULL,            /* lseek - default */
  5359. +    block_read,        /* read - general block-dev read */
  5360. +    block_write,        /* write - general block-dev write */
  5361. +    NULL,            /* readdir - bad */
  5362. +    NULL,            /* select */
  5363. +    fd_ioctl,        /* ioctl */
  5364. +    NULL,            /* mmap */
  5365. +    floppy_open,        /* open */
  5366. +    floppy_release,        /* release */
  5367. +    block_fsync,        /* fsync */
  5368. +    NULL,            /* fasync */
  5369. +    check_floppy_change,    /* media_change */
  5370. +    floppy_revalidate,    /* revalidate */
  5371. +};
  5372. +
  5373. +
  5374. +int floppy_init(void)
  5375. +{
  5376. +    int i;
  5377. +
  5378. +    if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
  5379. +        printk("Unable to get major %d for floppy\n", MAJOR_NR);
  5380. +        return;
  5381. +    }
  5382. +    /* Actually this does almost nothing - we actually do this by starting DMA
  5383. +       on channel 1 */
  5384. +    /*if (request_irq(FIQ_FD1772+16,fdc1772_comendhandler,SA_INTERRUPT,"fd1772")) {
  5385. +       printk("Unable to grab IRQ%d for the floppy (1772) driver\n",FIQ_FD1772+16);
  5386. +       return ;
  5387. +       }; */
  5388. +
  5389. +    if (request_dma(FLOPPY_DMA, "fd1772")) {
  5390. +        printk("Unable to grab DMA%d for the floppy (1772) driver\n", FLOPPY_DMA);
  5391. +        free_irq(FIQ_FD1772 + 16);
  5392. +        return;
  5393. +    };
  5394. +
  5395. +    if (request_dma(FIQ_FD1772, "fd1772 end")) {
  5396. +        printk("Unable to grab DMA%d for the floppy (1772) driver\n", FIQ_FD1772);
  5397. +        free_irq(FIQ_FD1772 + 16);
  5398. +        return;
  5399. +    };
  5400. +    enable_dma(FIQ_FD1772);    /* This inserts a call to our command end routine */
  5401. +
  5402. +    /* initialize variables */
  5403. +    SelectedDrive = -1;
  5404. +#ifdef TRACKBUFFER
  5405. +  BufferDrive = -1;
  5406. +#endif
  5407. +
  5408. +    /* initialize check_change timer */
  5409. +    timer_table[FLOPPY_TIMER].fn = check_change;
  5410. +    timer_active &= ~(1 << FLOPPY_TIMER);
  5411. +
  5412. +
  5413. +#ifdef TRACKBUFFER
  5414. +  DMABuffer = (char *)kmalloc((MAX_SECTORS+1)*512); /* Atari uses 512 - I want to eventually cope with 1K sectors */
  5415. +  TrackBuffer = DMABuffer + 512;
  5416. +#else
  5417. +    /* Allocate memory for the DMAbuffer - on the Atari this takes it
  5418. +       out of some special memory... */
  5419. +    DMABuffer = (char *) kmalloc(2048);    /* Copes with pretty large sectors */
  5420. +#endif
  5421. +#ifdef TRACKBUFFER  
  5422. +  BufferDrive = BufferSide = BufferTrack = -1;
  5423. +#endif
  5424. +
  5425. +    for (i = 0; i < FD_MAX_UNITS; i++) {
  5426. +        unit[i].track = -1;
  5427. +    }
  5428. +
  5429. +    for (i = 0; i < 256; i++)
  5430. +        if ((i >> 2) > 0 && (i >> 2) <= NUM_DISK_TYPES)
  5431. +            floppy_sizes[i] = disk_type[(i >> 2) - 1].blocks >> 1;
  5432. +        else
  5433. +            floppy_sizes[i] = MAX_DISK_SIZE;
  5434. +
  5435. +    blk_size[MAJOR_NR] = floppy_sizes;
  5436. +    blksize_size[MAJOR_NR] = floppy_blocksizes;
  5437. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  5438. +
  5439. +    config_types();
  5440. +
  5441. +    return 0;
  5442. +}
  5443. +
  5444. +/* Just a dummy at the moment */
  5445. +void floppy_setup(char *str, int *ints)
  5446. +{
  5447. +}
  5448. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/fd1772dma.S linux/arch/arm/drivers/block/fd1772dma.S
  5449. --- linux.orig/arch/arm/drivers/block/fd1772dma.S    Thu Jan  1 01:00:00 1970
  5450. +++ linux/arch/arm/drivers/block/fd1772dma.S    Sat Sep  7 21:09:51 1996
  5451. @@ -0,0 +1,100 @@
  5452. +#include <asm/hardware.h>
  5453. +
  5454. +@ Code for DMA with the 1772 fdc
  5455. +.text
  5456. +
  5457. +
  5458. +  .global _fdc1772_dataaddr
  5459. +_fdc1772_fiqdata:
  5460. +@ Number of bytes left to DMA
  5461. +  .global _fdc1772_bytestogo
  5462. +_fdc1772_bytestogo:
  5463. +  .word 0
  5464. +@ Place to put/get data from in DMA
  5465. +  .global _fdc1772_dataaddr
  5466. +_fdc1772_dataaddr:
  5467. +  .word 0
  5468. +  
  5469. +  .global _fdc1772_fdc_int_done
  5470. +_fdc1772_fdc_int_done:
  5471. +  .word 0
  5472. +  .global _fdc1772_comendstatus
  5473. +_fdc1772_comendstatus:
  5474. +  .word 0
  5475. +
  5476. +@ We hang this off DMA channel 1
  5477. +    .global _fdc1772_comendhandler
  5478. +_fdc1772_comendhandler:
  5479. +  mov      r8,#IOC_BASE
  5480. +  ldrb     r9,[r8,#0x34]    @ IOC FIQ status
  5481. +  tst      r9,#2
  5482. +  subeqs   pc,r14,#4        @ should I leave a space here
  5483. +  orr      r9,r8,#0x10000   @ FDC base
  5484. +  adr      r8,_fdc1772_fdc_int_done
  5485. +  ldrb     r10,[r9,#0]  @ FDC status
  5486. +  mov      r9,#1        @ Got a FIQ flag
  5487. +  stmia    r8,{r9,r10}
  5488. +  subs     pc,r14,#4
  5489. +
  5490. +
  5491. +    .global _fdc1772_dma_read
  5492. +_fdc1772_dma_read:
  5493. +  mov      r8,#IOC_BASE
  5494. +  ldrb     r9,[r8,#0x34]    @ IOC FIQ status
  5495. +  tst      r9,#1
  5496. +  beq      _fdc1772_dma_read_notours
  5497. +  orr      r8,r8,#0x10000   @ FDC base
  5498. +  ldrb     r10,[r8,#0xc]   @ Read from FDC data reg (also clears interrupt)
  5499. +  ldmia    r11,{r8,r9}
  5500. +  subs     r8,r8,#1        @ One less byte to go
  5501. +  @ If there was somewhere for this data to go then store it and update pointers
  5502. +  strplb   r10,[r9],#1     @ Store the data and increment the pointer
  5503. +  stmplia  r11,{r8,r9}     @ Update count/pointers
  5504. +  @ Handle any other interrupts if there are any
  5505. +_fdc1772_dma_read_notours:
  5506. +  @ Cant branch because this code has been copied down to the FIQ vector
  5507. +  ldr pc,[pc,#-4]
  5508. +  .word _fdc1772_comendhandler
  5509. +  .global _fdc1772_dma_read_end
  5510. +_fdc1772_dma_read_end:
  5511. +
  5512. +    .global _fdc1772_dma_write
  5513. +_fdc1772_dma_write:
  5514. +  mov      r8,#IOC_BASE
  5515. +  ldrb     r9,[r8,#0x34]    @ IOC FIQ status
  5516. +  tst      r9,#1
  5517. +  beq      _fdc1772_dma_write_notours
  5518. +  orr      r8,r8,#0x10000   @ FDC base
  5519. +  ldmia    r11,{r9,r10}
  5520. +  subs     r9,r9,#1        @ One less byte to go
  5521. +  @ If there really is some data then get it, store it and update count
  5522. +  ldrplb   r12,[r10],#1
  5523. +  strplb   r12,[r8,#0xc]   @ write it to FDC data reg
  5524. +  stmplia  r11,{r9,r10}    @ Update count and pointer - should clear interrupt
  5525. +  @ Handle any other interrupts
  5526. +_fdc1772_dma_write_notours:
  5527. +  @ Cant branch because this code has been copied down to the FIQ vector
  5528. +  ldr pc,[pc,#-4]
  5529. +  .word _fdc1772_comendhandler
  5530. +
  5531. +  .global _fdc1772_dma_write_end
  5532. +_fdc1772_dma_write_end:
  5533. +  
  5534. +
  5535. +@ Setup the FIQ R11 to point to the data and store the count, address
  5536. +@ for this dma
  5537. +@ R0=count
  5538. +@ R1=address
  5539. +  .global _fdc1772_setupdma
  5540. +_fdc1772_setupdma:
  5541. +    @ The big job is flipping in and out of FIQ mode
  5542. +    adr    r2,_fdc1772_fiqdata    @ This is what we really came here for
  5543. +  stmia  r2,{r0,r1}
  5544. +    mov    r3, pc
  5545. +    teqp    pc,#0x0c000001    @ Disable FIQs, IRQs and switch to FIQ mode
  5546. +    mov    r0,r0          @ NOP
  5547. +    mov r11,r2
  5548. +    teqp    r3,#0        @ Normal mode
  5549. +    mov    r0,r0        @ NOP
  5550. +  mov pc,r14
  5551. +
  5552. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/floppy.c linux/arch/arm/drivers/block/floppy.c
  5553. --- linux.orig/arch/arm/drivers/block/floppy.c    Thu Jan  1 01:00:00 1970
  5554. +++ linux/arch/arm/drivers/block/floppy.c    Fri Sep  6 21:08:31 1996
  5555. @@ -0,0 +1,4318 @@
  5556. +/*
  5557. + *  linux/arch/arm/drivers/block/floppy.c
  5558. + *  [ was linux/drivers/block/floppy.c ]
  5559. + *
  5560. + *  Copyright (C) 1991, 1992  Linus Torvalds
  5561. + *  Copyright (C) 1993, 1994  Alain Knaff
  5562. + *  Modifications Copyright (C) 1995 Russell King
  5563. + */
  5564. +/*
  5565. + * 02.12.91 - Changed to static variables to indicate need for reset
  5566. + * and recalibrate. This makes some things easier (output_byte reset
  5567. + * checking etc), and means less interrupt jumping in case of errors,
  5568. + * so the code is hopefully easier to understand.
  5569. + */
  5570. +
  5571. +/*
  5572. + * This file is certainly a mess. I've tried my best to get it working,
  5573. + * but I don't like programming floppies, and I have only one anyway.
  5574. + * Urgel. I should check for more errors, and do more graceful error
  5575. + * recovery. Seems there are problems with several drives. I've tried to
  5576. + * correct them. No promises.
  5577. + */
  5578. +
  5579. +/*
  5580. + * As with hd.c, all routines within this file can (and will) be called
  5581. + * by interrupts, so extreme caution is needed. A hardware interrupt
  5582. + * handler may not sleep, or a kernel panic will happen. Thus I cannot
  5583. + * call "floppy-on" directly, but have to set a special timer interrupt
  5584. + * etc.
  5585. + */
  5586. +
  5587. +/*
  5588. + * 28.02.92 - made track-buffering routines, based on the routines written
  5589. + * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
  5590. + */
  5591. +
  5592. +/*
  5593. + * Automatic floppy-detection and formatting written by Werner Almesberger
  5594. + * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
  5595. + * the floppy-change signal detection.
  5596. + */
  5597. +
  5598. +/*
  5599. + * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
  5600. + * FDC data overrun bug, added some preliminary stuff for vertical
  5601. + * recording support.
  5602. + *
  5603. + * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
  5604. + *
  5605. + * TODO: Errors are still not counted properly.
  5606. + */
  5607. +
  5608. +/* 1992/9/20
  5609. + * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
  5610. + * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
  5611. + * Christoph H. Hochst\"atter.
  5612. + * I have fixed the shift values to the ones I always use. Maybe a new
  5613. + * ioctl() should be created to be able to modify them.
  5614. + * There is a bug in the driver that makes it impossible to format a
  5615. + * floppy as the first thing after bootup.
  5616. + */
  5617. +
  5618. +/*
  5619. + * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
  5620. + * this helped the floppy driver as well. Much cleaner, and still seems to
  5621. + * work.
  5622. + */
  5623. +
  5624. +/* 1994/6/24 --bbroad-- added the floppy table entries and made
  5625. + * minor modifications to allow 2.88 floppies to be run.
  5626. + */
  5627. +
  5628. +/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
  5629. + * disk types.
  5630. + */
  5631. +
  5632. +/*
  5633. + * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
  5634. + * format bug fixes, but unfortunately some new bugs too...
  5635. + */
  5636. +
  5637. +/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
  5638. + * errors to allow safe writing by specialized programs.
  5639. + */
  5640. +
  5641. +/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
  5642. + * by defining bit 1 of the "stretch" parameter to mean put sectors on the
  5643. + * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
  5644. + * drives are "upside-down").
  5645. + */
  5646. +
  5647. +/*
  5648. + * 1995/8/26 -- Andreas Busse -- added Mips support.
  5649. + */
  5650. +
  5651. +/*
  5652. + * 1995/8/16 -- Russell King -- altered method for turning floppy drives on
  5653. + * for the arm.
  5654. + */
  5655. +
  5656. +/*
  5657. + * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
  5658. + * features to asm/floppy.h.
  5659. + */
  5660. +
  5661. +
  5662. +#define FLOPPY_SANITY_CHECK
  5663. +#undef  FLOPPY_SILENT_DCL_CLEAR
  5664. +
  5665. +#define DEBUGT 2
  5666. +#define DCL_DEBUG /* debug disk change line */
  5667. +
  5668. +/* do print messages for unexpected interrupts */
  5669. +static int print_unex=1;
  5670. +#include <linux/utsname.h>
  5671. +#include <linux/module.h>
  5672. +
  5673. +/* the following is the mask of allowed drives. By default units 2 and
  5674. + * 3 of both floppy controllers are disabled, because switching on the
  5675. + * motor of these drives causes system hangs on some PCI computers. drive
  5676. + * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
  5677. + * a drive is allowed. */
  5678. +static int allowed_drive_mask=0x33;
  5679. +
  5680. +#define FLOPPY_IRQ 12
  5681. +#define FLOPPY_DMA 2
  5682. +#define FDC1 0x3f0
  5683. +#define N_DRIVE 8
  5684. +#define N_FDC 1
  5685. +static int FDC2=-1;
  5686. +#define FLOPPY0_TYPE 4
  5687. +#define FLOPPY1_TYPE 4
  5688. +
  5689. +#include <linux/sched.h>
  5690. +#include <linux/fs.h>
  5691. +#include <linux/kernel.h>
  5692. +#include <linux/timer.h>
  5693. +#include <linux/tqueue.h>
  5694. +#define FDPATCHES
  5695. +#include <linux/fdreg.h>
  5696. +
  5697. +
  5698. +#include <linux/fd.h>
  5699. +
  5700. +
  5701. +#define OLDFDRAWCMD 0x020d /* send a raw command to the FDC */
  5702. +
  5703. +struct old_floppy_raw_cmd {
  5704. +  void *data;
  5705. +  long length;
  5706. +
  5707. +  unsigned char rate;
  5708. +  unsigned char flags;
  5709. +  unsigned char cmd_count;
  5710. +  unsigned char cmd[9];
  5711. +  unsigned char reply_count;
  5712. +  unsigned char reply[7];
  5713. +  int track;
  5714. +};
  5715. +
  5716. +#include <linux/errno.h>
  5717. +#include <linux/malloc.h>
  5718. +#include <linux/mm.h>
  5719. +#include <linux/string.h>
  5720. +#include <linux/fcntl.h>
  5721. +#include <linux/delay.h>
  5722. +
  5723. +#include <linux/ioport.h>
  5724. +#include <linux/interrupt.h>
  5725. +
  5726. +#include <asm/dma.h>
  5727. +#include <asm/irq.h>
  5728. +#include <asm/system.h>
  5729. +#include <asm/io.h>
  5730. +#include <asm/segment.h>
  5731. +
  5732. +static int use_virtual_dma=0; /* virtual DMA for Intel */
  5733. +static unsigned short virtual_dma_port=0x3f0;
  5734. +void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs);
  5735. +static int set_dor(int fdc, char mask, char data);
  5736. +static inline int __get_order(unsigned long size);
  5737. +#include <asm/floppy.h>
  5738. +
  5739. +
  5740. +#define MAJOR_NR FLOPPY_MAJOR
  5741. +
  5742. +#include <linux/blk.h>
  5743. +#include <linux/cdrom.h> /* for the compatibility eject ioctl */
  5744. +
  5745. +
  5746. +#ifndef FLOPPY_MOTOR_MASK
  5747. +#define FLOPPY_MOTOR_MASK 0xf0
  5748. +#endif
  5749. +
  5750. +#ifndef fd_get_dma_residue
  5751. +#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
  5752. +#endif
  5753. +
  5754. +/* Dma Memory related stuff */
  5755. +
  5756. +/* Pure 2^n version of get_order */
  5757. +static inline int __get_order(unsigned long size)
  5758. +{
  5759. +    int order;
  5760. +
  5761. +    size = (size-1) >> (PAGE_SHIFT-1);
  5762. +    order = -1;
  5763. +    do {
  5764. +        size >>= 1;
  5765. +        order++;
  5766. +    } while (size);
  5767. +    return order;
  5768. +}
  5769. +
  5770. +#ifndef fd_dma_mem_free
  5771. +#define fd_dma_mem_free(addr, size) free_pages(addr, __get_order(size))
  5772. +#endif
  5773. +
  5774. +#ifndef fd_dma_mem_alloc
  5775. +#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,__get_order(size))
  5776. +#endif
  5777. +
  5778. +/* End dma memory related stuff */
  5779. +
  5780. +static unsigned int fake_change = 0;
  5781. +static int initialising=1;
  5782. +
  5783. +static inline int TYPE(kdev_t x) {
  5784. +    return  (MINOR(x)>>2) & 0x1f;
  5785. +}
  5786. +static inline int DRIVE(kdev_t x) {
  5787. +    return (MINOR(x)&0x03) | ((MINOR(x)&0x80) >> 5);
  5788. +}
  5789. +#define ITYPE(x) (((x)>>2) & 0x1f)
  5790. +#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
  5791. +#define UNIT(x) ((x) & 0x03)        /* drive on fdc */
  5792. +#define FDC(x) (((x) & 0x04) >> 2)  /* fdc of drive */
  5793. +#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
  5794. +                /* reverse mapping from unit and fdc to drive */
  5795. +#define DP (&drive_params[current_drive])
  5796. +#define DRS (&drive_state[current_drive])
  5797. +#define DRWE (&write_errors[current_drive])
  5798. +#define FDCS (&fdc_state[fdc])
  5799. +#define CLEARF(x) (clear_bit(x##_BIT, &DRS->flags))
  5800. +#define SETF(x) (set_bit(x##_BIT, &DRS->flags))
  5801. +#define TESTF(x) (test_bit(x##_BIT, &DRS->flags))
  5802. +
  5803. +#define UDP (&drive_params[drive])
  5804. +#define UDRS (&drive_state[drive])
  5805. +#define UDRWE (&write_errors[drive])
  5806. +#define UFDCS (&fdc_state[FDC(drive)])
  5807. +#define UCLEARF(x) (clear_bit(x##_BIT, &UDRS->flags))
  5808. +#define USETF(x) (set_bit(x##_BIT, &UDRS->flags))
  5809. +#define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags))
  5810. +
  5811. +#define DPRINT(format, args...) printk(DEVICE_NAME "%d: " format, current_drive , ## args)
  5812. +
  5813. +#define PH_HEAD(floppy,head) (((((floppy)->stretch & 2) >>1) ^ head) << 2)
  5814. +#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
  5815. +
  5816. +#define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x)))
  5817. +
  5818. +#define INT_OFF save_flags(flags); cli()
  5819. +#define INT_ON  restore_flags(flags)
  5820. +
  5821. +/* read/write */
  5822. +#define COMMAND raw_cmd->cmd[0]
  5823. +#define DR_SELECT raw_cmd->cmd[1]
  5824. +#define TRACK raw_cmd->cmd[2]
  5825. +#define HEAD raw_cmd->cmd[3]
  5826. +#define SECTOR raw_cmd->cmd[4]
  5827. +#define SIZECODE raw_cmd->cmd[5]
  5828. +#define SECT_PER_TRACK raw_cmd->cmd[6]
  5829. +#define GAP raw_cmd->cmd[7]
  5830. +#define SIZECODE2 raw_cmd->cmd[8]
  5831. +#define NR_RW 9
  5832. +
  5833. +/* format */
  5834. +#define F_SIZECODE raw_cmd->cmd[2]
  5835. +#define F_SECT_PER_TRACK raw_cmd->cmd[3]
  5836. +#define F_GAP raw_cmd->cmd[4]
  5837. +#define F_FILL raw_cmd->cmd[5]
  5838. +#define NR_F 6
  5839. +
  5840. +/*
  5841. + * Maximum disk size (in kilobytes). This default is used whenever the
  5842. + * current disk size is unknown.
  5843. + * [Now it is rather a minimum]
  5844. + */
  5845. +#define MAX_DISK_SIZE 2 /* 3984*/
  5846. +
  5847. +#define K_64    0x10000        /* 64kB */
  5848. +
  5849. +/*
  5850. + * globals used by 'result()'
  5851. + */
  5852. +#define MAX_REPLIES 16
  5853. +static unsigned char reply_buffer[MAX_REPLIES];
  5854. +static int inr; /* size of reply buffer, when called from interrupt */
  5855. +#define ST0 (reply_buffer[0])
  5856. +#define ST1 (reply_buffer[1])
  5857. +#define ST2 (reply_buffer[2])
  5858. +#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
  5859. +#define R_TRACK (reply_buffer[3])
  5860. +#define R_HEAD (reply_buffer[4])
  5861. +#define R_SECTOR (reply_buffer[5])
  5862. +#define R_SIZECODE (reply_buffer[6])
  5863. +
  5864. +#define SEL_DLY (2*HZ/100)
  5865. +
  5866. +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  5867. +/*
  5868. + * this struct defines the different floppy drive types.
  5869. + */
  5870. +static struct {
  5871. +    struct floppy_drive_params params;
  5872. +    const char *name; /* name printed while booting */
  5873. +} default_drive_params[]= {
  5874. +/* NOTE: the time values in jiffies should be in msec!
  5875. + CMOS drive type
  5876. +  |     Maximum data rate supported by drive type
  5877. +  |     |   Head load time, msec
  5878. +  |     |   |   Head unload time, msec (not used)
  5879. +  |     |   |   |     Step rate interval, usec
  5880. +  |     |   |   |     |       Time needed for spinup time (jiffies)
  5881. +  |     |   |   |     |       |      Timeout for spinning down (jiffies)
  5882. +  |     |   |   |     |       |      |   Spindown offset (where disk stops)
  5883. +  |     |   |   |     |       |      |   |     Select delay
  5884. +  |     |   |   |     |       |      |   |     |     RPS
  5885. +  |     |   |   |     |       |      |   |     |     |    Max number of tracks
  5886. +  |     |   |   |     |       |      |   |     |     |    |     Interrupt timeout
  5887. +  |     |   |   |     |       |      |   |     |     |    |     |   Max nonintlv. sectors
  5888. +  |     |   |   |     |       |      |   |     |     |    |     |   | -Max Errors- flags */
  5889. +{{0,  500, 16, 16, 8000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  80, 3*HZ, 20, {3,1,2,0,2}, 0,
  5890. +      0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
  5891. +
  5892. +{{1,  300, 16, 16, 8000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  40, 3*HZ, 17, {3,1,2,0,2}, 0,
  5893. +      0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
  5894. +
  5895. +{{2,  500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6,  83, 3*HZ, 17, {3,1,2,0,2}, 0,
  5896. +      0, { 2, 5, 6,23,10,20,11, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
  5897. +
  5898. +{{3,  250, 16, 16, 3000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
  5899. +      0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
  5900. +#if 0
  5901. +{{4,  500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
  5902. +      0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
  5903. +#else
  5904. +{{4,  500, 16, 16, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 20, {3,1,2,0,0}, FTD_MSG,
  5905. +      0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
  5906. +#endif
  5907. +{{5, 1000, 15,  8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
  5908. +      0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
  5909. +
  5910. +{{6, 1000, 15,  8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
  5911. +      0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
  5912. +/*    |  --autodetected formats---   |      |      |
  5913. + *    read_track                     |      |    Name printed when booting
  5914. + *                                   |     Native format
  5915. + *                                 Frequency of disk change checks */
  5916. +};
  5917. +
  5918. +static struct floppy_drive_params drive_params[N_DRIVE];
  5919. +static struct floppy_drive_struct drive_state[N_DRIVE];
  5920. +static struct floppy_write_errors write_errors[N_DRIVE];
  5921. +static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
  5922. +
  5923. +/*
  5924. + * This struct defines the different floppy types.
  5925. + *
  5926. + * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
  5927. + * types (e.g. 360kB diskette in 1.2MB drive, etc.).  Bit 1 of 'stretch'
  5928. + * tells if the disk is in Commodore 1581 format, which means side 0 sectors
  5929. + * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
  5930. + * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
  5931. + * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
  5932. + * side 0 is on physical side 0 (but with the misnamed sector IDs).
  5933. + * 'stretch' should probably be renamed to something more general, like
  5934. + * 'options'.  Other parameters should be self-explanatory (see also
  5935. + * setfdprm(8)).
  5936. + */
  5937. +/*
  5938. +             Size
  5939. +             |  Sectors per track
  5940. +             |  | Head
  5941. +             |  | |  Tracks
  5942. +             |  | |  | Stretch
  5943. +             |  | |  | |  Gap 1 size
  5944. +             |  | |  | |    |  Data rate, | 0x40 for perp
  5945. +         |  | |  | |    |    |  Spec1 (stepping rate, head unload
  5946. +             |  | |  | |    |    |    |    /fmt gap (gap2) */
  5947. +static struct floppy_struct floppy_type[32] = {
  5948. +    {    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL    },    /*  0 no testing    */
  5949. +    {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360"  }, /*  1 360KB PC      */
  5950. +    { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" },    /*  2 1.2MB AT      */
  5951. +    {  720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360"  },    /*  3 360KB SS 3.5" */
  5952. +    { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720"  },    /*  4 720KB 3.5"    */
  5953. +    {  720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360"  },    /*  5 360KB AT      */
  5954. +    { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720"  },    /*  6 720KB AT      */
  5955. +    { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" },    /*  7 1.44MB 3.5"   */
  5956. +    { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" },    /*  8 2.88MB 3.5"   */
  5957. +    { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" },    /*  9 3.12MB 3.5"   */
  5958. +
  5959. +    { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25"  */
  5960. +    { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5"   */
  5961. +    {  820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410"  },    /* 12 410KB 5.25"   */
  5962. +    { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820"  },    /* 13 820KB 3.5"    */
  5963. +    { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" },    /* 14 1.48MB 5.25"  */
  5964. +    { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" },    /* 15 1.72MB 3.5"   */
  5965. +    {  840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420"  },    /* 16 420KB 5.25"   */
  5966. +    { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830"  },    /* 17 830KB 3.5"    */
  5967. +    { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" },    /* 18 1.49MB 5.25"  */
  5968. +    { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5"  */
  5969. +
  5970. +    { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880"  }, /* 20 880KB 5.25"   */
  5971. +    { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5"   */
  5972. +    { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5"   */
  5973. +    { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25"   */
  5974. +    { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5"   */
  5975. +    { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5"   */
  5976. +    { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5"   */
  5977. +    { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5"   */
  5978. +    { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5"   */
  5979. +
  5980. +    { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5"   */
  5981. +    { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800"  },    /* 30 800KB 3.5"    */
  5982. +    { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5"    */
  5983. +};
  5984. +
  5985. +#define    NUMBER(x)    (sizeof(x) / sizeof(*(x)))
  5986. +#define SECTSIZE (_FD_SECTSIZE(*floppy))
  5987. +
  5988. +/* Auto-detection: Disk type used until the next media change occurs. */
  5989. +static struct floppy_struct *current_type[N_DRIVE] = {
  5990. +    NULL, NULL, NULL, NULL,
  5991. +    NULL, NULL, NULL, NULL
  5992. +};
  5993. +
  5994. +/*
  5995. + * User-provided type information. current_type points to
  5996. + * the respective entry of this array.
  5997. + */
  5998. +static struct floppy_struct user_params[N_DRIVE];
  5999. +
  6000. +static int floppy_sizes[256];
  6001. +static int floppy_blocksizes[256] = { 0, };
  6002. +
  6003. +/*
  6004. + * The driver is trying to determine the correct media format
  6005. + * while probing is set. rw_interrupt() clears it after a
  6006. + * successful access.
  6007. + */
  6008. +static int probing = 0;
  6009. +
  6010. +/* Synchronization of FDC access. */
  6011. +#define FD_COMMAND_NONE -1
  6012. +#define FD_COMMAND_ERROR 2
  6013. +#define FD_COMMAND_OKAY 3
  6014. +
  6015. +static volatile int command_status = FD_COMMAND_NONE, fdc_busy = 0;
  6016. +static struct wait_queue *fdc_wait = NULL, *command_done = NULL;
  6017. +#define NO_SIGNAL (!(current->signal & ~current->blocked) || !interruptible)
  6018. +#define CALL(x) if ((x) == -EINTR) return -EINTR
  6019. +#define ECALL(x) if ((ret = (x))) return ret;
  6020. +#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
  6021. +#define WAIT(x) _WAIT((x),interruptible)
  6022. +#define IWAIT(x) _WAIT((x),1)
  6023. +
  6024. +/* Errors during formatting are counted here. */
  6025. +static int format_errors;
  6026. +
  6027. +/* Format request descriptor. */
  6028. +static struct format_descr format_req;
  6029. +
  6030. +/*
  6031. + * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
  6032. + * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
  6033. + * H is head unload time (1=16ms, 2=32ms, etc)
  6034. + */
  6035. +
  6036. +/*
  6037. + * Track buffer
  6038. + * Because these are written to by the DMA controller, they must
  6039. + * not contain a 64k byte boundary crossing, or data will be
  6040. + * corrupted/lost.
  6041. + */
  6042. +static char *floppy_track_buffer=NULL;
  6043. +static int max_buffer_sectors=0;
  6044. +
  6045. +static int *errors;
  6046. +typedef void (*done_f)(int);
  6047. +static struct cont_t {
  6048. +    void (*interrupt)(void); /* this is called after the interrupt of the
  6049. +                  * main command */
  6050. +    void (*redo)(void); /* this is called to retry the operation */
  6051. +    void (*error)(void); /* this is called to tally an error */
  6052. +    done_f done; /* this is called to say if the operation has
  6053. +              * succeeded/failed */
  6054. +} *cont=NULL;
  6055. +
  6056. +static void floppy_ready(void);
  6057. +static void floppy_start(void);
  6058. +static void process_fd_request(void);
  6059. +static void recalibrate_floppy(void);
  6060. +static void floppy_shutdown(void);
  6061. +
  6062. +static int floppy_grab_irq_and_dma(void);
  6063. +static void floppy_release_irq_and_dma(void);
  6064. +
  6065. +/*
  6066. + * The "reset" variable should be tested whenever an interrupt is scheduled,
  6067. + * after the commands have been sent. This is to ensure that the driver doesn't
  6068. + * get wedged when the interrupt doesn't come because of a failed command.
  6069. + * reset doesn't need to be tested before sending commands, because
  6070. + * output_byte is automatically disabled when reset is set.
  6071. + */
  6072. +#define CHECK_RESET { if ( FDCS->reset ){ reset_fdc(); return ; } }
  6073. +static void reset_fdc(void);
  6074. +
  6075. +/*
  6076. + * These are global variables, as that's the easiest way to give
  6077. + * information to interrupts. They are the data used for the current
  6078. + * request.
  6079. + */
  6080. +#define NO_TRACK -1
  6081. +#define NEED_1_RECAL -2
  6082. +#define NEED_2_RECAL -3
  6083. +
  6084. +/* */
  6085. +static int usage_count = 0;
  6086. +
  6087. +
  6088. +/* buffer related variables */
  6089. +static int buffer_track = -1;
  6090. +static int buffer_drive = -1;
  6091. +static int buffer_min = -1;
  6092. +static int buffer_max = -1;
  6093. +
  6094. +/* fdc related variables, should end up in a struct */
  6095. +static struct floppy_fdc_state fdc_state[N_FDC];
  6096. +static int fdc; /* current fdc */
  6097. +
  6098. +static struct floppy_struct *_floppy = floppy_type;
  6099. +static unsigned char current_drive = 0;
  6100. +static long current_count_sectors = 0;
  6101. +static unsigned char sector_t; /* sector in track */
  6102. +
  6103. +#ifndef fd_eject
  6104. +#define fd_eject(x) -EINVAL
  6105. +#endif
  6106. +
  6107. +/*
  6108. + * Floppy_selects1 is the list of DOR's to select a drive n
  6109. + * Floppy_selects2 is the list of DOR's to select drive fd
  6110. + * On initialisation, the floppy list is scanned, and the drives allocated
  6111. + * in the order that they are found.  This is done by seeking the drive
  6112. + * to a non-zero track, and then restoring it to track 0.  If an error occurs,
  6113. + * then there is no floppy drive present.
  6114. + */
  6115. +/*extern*/ int no_floppies;
  6116. +unsigned char floppy_selects1[]={ 0x10, 0x21, 0x23, 0x33 };
  6117. +unsigned char floppy_selects2[]={ 0   , 0   , 0   , 0    };
  6118. +
  6119. +#define fd_disable_dma()    disable_dma(FLOPPY_DMA)
  6120. +#define fd_clear_dma_ff()    clear_dma_ff(FLOPPY_DMA)
  6121. +#define fd_set_dma_mode(mode)    set_dma_mode(FLOPPY_DMA, (mode))
  6122. +#define fd_set_dma_addr(addr)    set_dma_addr(FLOPPY_DMA, (addr))
  6123. +#define fd_set_dma_count(len)    set_dma_count(FLOPPY_DMA, (len))
  6124. +#define fd_enable_dma()        enable_dma(FLOPPY_DMA)
  6125. +#define fd_cacheflush(addr, sz)
  6126. +#define fd_outb(val,port)    outb_p((val),(port))
  6127. +#define fd_inb(port)        inb_p((port))
  6128. +#define fd_request_irq()    request_irq(FLOPPY_IRQ, floppy_interrupt,SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL)
  6129. +#define fd_free_irq()        free_irq(FLOPPY_IRQ,NULL)
  6130. +#define fd_request_dma()    request_dma(FLOPPY_DMA,"floppy")
  6131. +#define fd_free_dma()        free_dma(FLOPPY_DMA)
  6132. +#define fd_enable_irq()        enable_irq(FLOPPY_IRQ)
  6133. +#define fd_disable_irq()    disable_irq(FLOPPY_IRQ)
  6134. +
  6135. +#ifdef DEBUGT
  6136. +static long unsigned debugtimer;
  6137. +#endif
  6138. +
  6139. +/*
  6140. + * Debugging
  6141. + * =========
  6142. + */
  6143. +static inline void set_debugt(void)
  6144. +{
  6145. +#ifdef DEBUGT
  6146. +    debugtimer = jiffies;
  6147. +#endif
  6148. +}
  6149. +
  6150. +static inline void debugt(const char *message)
  6151. +{
  6152. +#ifdef DEBUGT
  6153. +  if ( DP->flags & DEBUGT )
  6154. +    printk("%s dtime=%lu\n", message, jiffies-debugtimer );
  6155. +#endif
  6156. +}
  6157. +
  6158. +typedef void (*timeout_fn)(unsigned long);
  6159. +static struct timer_list fd_timeout ={ NULL, NULL, 0, 0,
  6160. +                    (timeout_fn) floppy_shutdown };
  6161. +
  6162. +static const char *timeout_message;
  6163. +
  6164. +#ifdef FLOPPY_SANITY_CHECK
  6165. +static void is_alive(const char *message)
  6166. +{
  6167. +    /* this routine checks whether the floppy driver is "alive" */
  6168. +    if (fdc_busy && command_status < 2 && !fd_timeout.prev){
  6169. +        DPRINT("timeout handler died: %s\n",message);
  6170. +    }
  6171. +}
  6172. +#endif
  6173. +
  6174. +#ifdef FLOPPY_SANITY_CHECK
  6175. +
  6176. +#define OLOGSIZE 20
  6177. +
  6178. +static void (*lasthandler)(void) = NULL;
  6179. +static int interruptjiffies=0;
  6180. +static int resultjiffies=0;
  6181. +static int resultsize=0;
  6182. +static int lastredo=0;
  6183. +
  6184. +static struct output_log {
  6185. +    unsigned char data;
  6186. +    unsigned char status;
  6187. +    unsigned long jiffies;
  6188. +} output_log[OLOGSIZE];
  6189. +
  6190. +static int output_log_pos=0;
  6191. +#endif
  6192. +
  6193. +#define CURRENTD -1
  6194. +#define MAXTIMEOUT -2
  6195. +
  6196. +static void reschedule_timeout(int drive, const char *message, int marg)
  6197. +{
  6198. +    if (drive == CURRENTD )
  6199. +        drive = current_drive;
  6200. +    del_timer(&fd_timeout);
  6201. +    if (drive < 0 || drive > N_DRIVE) {
  6202. +        fd_timeout.expires = jiffies + 20*HZ;
  6203. +        drive = 0;
  6204. +    } else
  6205. +        fd_timeout.expires = jiffies + UDP->timeout;
  6206. +    add_timer(&fd_timeout);
  6207. +    if (UDP->flags & FD_DEBUG) {
  6208. +        DPRINT("reschedule timeout ");
  6209. +        printk(message, marg);
  6210. +        printk("\n");
  6211. +    }
  6212. +    timeout_message = message;
  6213. +}
  6214. +
  6215. +static int maximum(int a, int b)
  6216. +{
  6217. +    if(a > b)
  6218. +        return a;
  6219. +    else
  6220. +        return b;
  6221. +}
  6222. +#define INFBOUND(a,b) (a)=maximum((a),(b));
  6223. +
  6224. +static int minimum(int a, int b)
  6225. +{
  6226. +    if(a < b)
  6227. +        return a;
  6228. +    else
  6229. +        return b;
  6230. +}
  6231. +#define SUPBOUND(a,b) (a)=minimum((a),(b));
  6232. +
  6233. +
  6234. +/*
  6235. + * Bottom half floppy driver.
  6236. + * ==========================
  6237. + *
  6238. + * This part of the file contains the code talking directly to the hardware,
  6239. + * and also the main service loop (seek-configure-spinup-command)
  6240. + */
  6241. +
  6242. +/*
  6243. + * disk change.
  6244. + * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
  6245. + * and the last_checked date.
  6246. + *
  6247. + * last_checked is the date of the last check which showed 'no disk change'
  6248. + * FD_DISK_CHANGE is set under two conditions:
  6249. + * 1. The floppy has been changed after some i/o to that floppy already
  6250. + *    took place.
  6251. + * 2. No floppy disk is in the drive. This is done in order to ensure that
  6252. + *    requests are quickly flushed in case there is no disk in the drive. It
  6253. + *    follows that FD_DISK_CHANGE can only be cleared if there is a disk in
  6254. + *    the drive.
  6255. + *
  6256. + * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
  6257. + * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
  6258. + *  each seek. If a disk is present, the disk change line should also be
  6259. + *  cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
  6260. + *  change line is set, this means either that no disk is in the drive, or
  6261. + *  that it has been removed since the last seek.
  6262. + *
  6263. + * This means that we really have a third possibility too:
  6264. + *  The floppy has been changed after the last seek.
  6265. + */
  6266. +
  6267. +static int disk_change(int drive)
  6268. +{
  6269. +    int fdc=FDC(drive);
  6270. +#ifdef FLOPPY_SANITY_CHECK
  6271. +    if(jiffies - UDRS->select_date < UDP->select_delay)
  6272. +        DPRINT("WARNING disk change called early\n");
  6273. +    if(! (FDCS->dor & (0x10 << UNIT(drive))) ||
  6274. +       (FDCS->dor & 3) != UNIT(drive) ||
  6275. +       fdc != FDC(drive)){
  6276. +           DPRINT("probing disk change on unselected drive\n");
  6277. +           DPRINT("drive=%d fdc=%d dor=%x\n",drive, FDC(drive),
  6278. +               (unsigned int)FDCS->dor);
  6279. +    }
  6280. +#endif
  6281. +
  6282. +#ifdef DCL_DEBUG
  6283. +    if (UDP->flags & FD_DEBUG){
  6284. +        DPRINT("checking disk change line for drive %d\n",drive);
  6285. +        DPRINT("jiffies=%ld\n", jiffies);
  6286. +        DPRINT("disk change line=%x\n", fd_inb(FD_DIR)&0x80);
  6287. +        DPRINT("flags=%x\n",UDRS->flags);
  6288. +    }
  6289. +#endif
  6290. +    if (UDP->flags & FD_BROKEN_DCL)
  6291. +        return UTESTF(FD_DISK_CHANGED);
  6292. +    if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80){
  6293. +        USETF(FD_VERIFY); /* verify write protection */
  6294. +        if(UDRS->maxblock){
  6295. +            /* mark it changed */
  6296. +            USETF(FD_DISK_CHANGED);
  6297. +        }
  6298. +
  6299. +        /* invalidate its geometry */
  6300. +        if (UDRS->keep_data >= 0) {
  6301. +            if ((UDP->flags & FTD_MSG) &&
  6302. +                current_type[drive] != NULL)
  6303. +                DPRINT("Disk type is undefined after "
  6304. +                       "disk change\n");
  6305. +            current_type[drive] = NULL;
  6306. +            floppy_sizes[TOMINOR(current_drive)] = MAX_DISK_SIZE;
  6307. +        }
  6308. +
  6309. +        /*USETF(FD_DISK_NEWCHANGE);*/
  6310. +        return 1;
  6311. +    } else {
  6312. +        UDRS->last_checked=jiffies;
  6313. +        UCLEARF(FD_DISK_NEWCHANGE);
  6314. +    }
  6315. +    return 0;
  6316. +}
  6317. +
  6318. +static inline int is_selected(int dor, int unit)
  6319. +{
  6320. +    return ( (dor  & (0x10 << unit)) && (dor &3) == unit);
  6321. +}
  6322. +
  6323. +static inline void arm_set_dor(int dor)
  6324. +{
  6325. +    if(dor & 0xf0)
  6326. +        fd_outb((dor & 0x0c) | floppy_selects1[dor & 3], FD_DOR);
  6327. +    else
  6328. +        fd_outb((dor & 0x0c), FD_DOR);
  6329. +}
  6330. +
  6331. +static int set_dor(int fdc, char mask, char data)
  6332. +{
  6333. +    register unsigned char drive, unit, newdor,olddor;
  6334. +
  6335. +    if (FDCS->address == -1)
  6336. +        return -1;
  6337. +
  6338. +    olddor = FDCS->dor;
  6339. +    newdor =  (olddor & mask) | data;
  6340. +    if ( newdor != olddor ){
  6341. +        unit = olddor & 0x3;
  6342. +        if(is_selected(olddor, unit) && !is_selected(newdor, unit)){
  6343. +            drive = REVDRIVE(fdc,unit);
  6344. +#ifdef DCL_DEBUG
  6345. +            if (UDP->flags & FD_DEBUG){
  6346. +                DPRINT("calling disk change from set_dor\n");
  6347. +            }
  6348. +#endif
  6349. +            disk_change(drive);
  6350. +        }
  6351. +        FDCS->dor = newdor;
  6352. +        arm_set_dor(newdor);
  6353. +
  6354. +        unit = newdor & 0x3;
  6355. +        if(!is_selected(olddor, unit) && is_selected(newdor, unit)){
  6356. +            drive = REVDRIVE(fdc,unit);
  6357. +            UDRS->select_date = jiffies;
  6358. +        }
  6359. +    }
  6360. +    if (newdor & FLOPPY_MOTOR_MASK)
  6361. +        floppy_grab_irq_and_dma();
  6362. +    if (olddor & FLOPPY_MOTOR_MASK)
  6363. +        floppy_release_irq_and_dma();
  6364. +    return olddor;
  6365. +}
  6366. +
  6367. +static void twaddle(void)
  6368. +{
  6369. +    if (DP->select_delay)
  6370. +        return;
  6371. +    arm_set_dor(FDCS->dor & ~(0x10<<UNIT(current_drive)));
  6372. +    arm_set_dor(FDCS->dor);
  6373. +    DRS->select_date = jiffies;
  6374. +}
  6375. +
  6376. +/* reset all driver information about the current fdc. This is needed after
  6377. + * a reset, and after a raw command. */
  6378. +static void reset_fdc_info(int mode)
  6379. +{
  6380. +    int drive;
  6381. +
  6382. +    FDCS->spec1 = FDCS->spec2 = -1;
  6383. +    FDCS->need_configure = 1;
  6384. +    FDCS->perp_mode = 1;
  6385. +    FDCS->rawcmd = 0;
  6386. +    for ( drive = 0; drive < N_DRIVE; drive++)
  6387. +        if (FDC(drive) == fdc &&
  6388. +            ( mode || UDRS->track != NEED_1_RECAL))
  6389. +            UDRS->track = NEED_2_RECAL;
  6390. +}
  6391. +
  6392. +/* selects the fdc and drive, and enables the fdc's input/dma. */
  6393. +static void set_fdc(int drive)
  6394. +{
  6395. +    if ( drive >= 0 && drive < N_DRIVE){
  6396. +        fdc = FDC(drive);
  6397. +        current_drive = drive;
  6398. +    }
  6399. +    if (fdc != 1 && fdc != 0) {
  6400. +        printk("bad fdc value\n");
  6401. +        return;
  6402. +    }
  6403. +    set_dor(fdc,~0,8);
  6404. +#if N_FDC > 1
  6405. +    set_dor(1-fdc, ~8, 0);
  6406. +#endif
  6407. +    if (FDCS->rawcmd == 2)
  6408. +        reset_fdc_info(1);
  6409. +    if (fd_inb(FD_STATUS) != STATUS_READY)
  6410. +        FDCS->reset = 1;
  6411. +}
  6412. +
  6413. +/* locks the driver */
  6414. +static int lock_fdc(int drive, int interruptible)
  6415. +{
  6416. +    unsigned long flags;
  6417. +
  6418. +    if(!usage_count){
  6419. +        printk("trying to lock fdc while usage count=0\n");
  6420. +        return -1;
  6421. +    }
  6422. +    floppy_grab_irq_and_dma();
  6423. +    INT_OFF;
  6424. +    while (fdc_busy && NO_SIGNAL)
  6425. +        interruptible_sleep_on(&fdc_wait);
  6426. +    if(fdc_busy){
  6427. +        INT_ON;
  6428. +        return -EINTR;
  6429. +    }
  6430. +    fdc_busy = 1;
  6431. +    INT_ON;
  6432. +    command_status = FD_COMMAND_NONE;
  6433. +    reschedule_timeout(drive, "lock fdc", 0);
  6434. +    set_fdc(drive);
  6435. +    return 0;
  6436. +}
  6437. +
  6438. +#define LOCK_FDC(drive,interruptible) \
  6439. +if(lock_fdc(drive,interruptible)) return -EINTR;
  6440. +
  6441. +
  6442. +/* unlocks the driver */
  6443. +static inline void unlock_fdc(void)
  6444. +{
  6445. +    raw_cmd = 0;
  6446. +    if (!fdc_busy)
  6447. +        DPRINT("FDC access conflict!\n");
  6448. +
  6449. +    if ( DEVICE_INTR )
  6450. +        DPRINT("device interrupt still active at FDC release: %p!\n",
  6451. +            DEVICE_INTR);
  6452. +    command_status = FD_COMMAND_NONE;
  6453. +    del_timer(&fd_timeout);
  6454. +    cont = NULL;
  6455. +    fdc_busy = 0;
  6456. +    floppy_release_irq_and_dma();
  6457. +    wake_up(&fdc_wait);
  6458. +}
  6459. +
  6460. +/* switches the motor off after a given timeout */
  6461. +static void motor_off_callback(unsigned long nr)
  6462. +{
  6463. +    unsigned char mask = ~(0x10 << UNIT(nr));
  6464. +
  6465. +    set_dor( FDC(nr), mask, 0 );
  6466. +}
  6467. +
  6468. +static struct timer_list motor_off_timer[N_DRIVE] = {
  6469. +    { NULL, NULL, 0, 0, motor_off_callback },
  6470. +    { NULL, NULL, 0, 1, motor_off_callback },
  6471. +    { NULL, NULL, 0, 2, motor_off_callback },
  6472. +    { NULL, NULL, 0, 3, motor_off_callback },
  6473. +    { NULL, NULL, 0, 4, motor_off_callback },
  6474. +    { NULL, NULL, 0, 5, motor_off_callback },
  6475. +    { NULL, NULL, 0, 6, motor_off_callback },
  6476. +    { NULL, NULL, 0, 7, motor_off_callback }
  6477. +};
  6478. +
  6479. +/* schedules motor off */
  6480. +static void floppy_off(unsigned int drive)
  6481. +{
  6482. +    unsigned long volatile delta;
  6483. +    register int fdc=FDC(drive);
  6484. +
  6485. +    if( !(FDCS->dor & ( 0x10 << UNIT(drive))))
  6486. +        return;
  6487. +
  6488. +    del_timer(motor_off_timer+drive);
  6489. +
  6490. +    /* make spindle stop in a position which minimizes spinup time
  6491. +     * next time */
  6492. +    if ( UDP->rps ){
  6493. +        delta = jiffies - UDRS->first_read_date + HZ -
  6494. +            UDP->spindown_offset;
  6495. +        delta = (( delta * UDP->rps) % HZ ) / UDP->rps;
  6496. +        motor_off_timer[drive].expires = jiffies + UDP->spindown - delta;
  6497. +    }
  6498. +    add_timer(motor_off_timer+drive);
  6499. +}
  6500. +
  6501. +/*
  6502. + * cycle through all N_DRIVE floppy drives, for disk change testing.
  6503. + * stopping at current drive. This is done before any long operation, to
  6504. + * be sure to have up to date disk change information.
  6505. + */
  6506. +static void scandrives(void)
  6507. +{
  6508. +    int i, drive, saved_drive;
  6509. +
  6510. +    if (DP->select_delay)
  6511. +        return;
  6512. +
  6513. +    saved_drive = current_drive;
  6514. +    for(i=0; i< N_DRIVE; i++){
  6515. +        drive = (saved_drive + i + 1 ) % N_DRIVE;
  6516. +        if ( UDRS->fd_ref == 0 || UDP->select_delay != 0)
  6517. +            continue; /* skip closed drives */
  6518. +        set_fdc(drive);
  6519. +        if(! (set_dor( fdc, ~3, UNIT(drive) | ( 0x10 << UNIT(drive))) &
  6520. +              (0x10 << UNIT(drive))))
  6521. +            /* switch the motor off again, if it was off to
  6522. +             * begin with */
  6523. +            set_dor( fdc, ~( 0x10 << UNIT(drive) ), 0 );
  6524. +    }
  6525. +    set_fdc(saved_drive);
  6526. +}
  6527. +
  6528. +static void empty(void)
  6529. +{
  6530. +}
  6531. +
  6532. +static struct tq_struct floppy_tq =
  6533. +{ 0, 0, 0, 0 };
  6534. +
  6535. +static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 };
  6536. +
  6537. +static void cancel_activity(void)
  6538. +{
  6539. +    CLEAR_INTR;
  6540. +    floppy_tq.routine = (void *)(void *) empty;
  6541. +    del_timer(&fd_timer);
  6542. +}
  6543. +
  6544. +/* this function makes sure that the disk stays in the drive during the
  6545. + * transfer */
  6546. +static void fd_watchdog(void)
  6547. +{
  6548. +#ifdef DCL_DEBUG
  6549. +    if (DP->flags & FD_DEBUG){
  6550. +        DPRINT("calling disk change from watchdog\n");
  6551. +    }
  6552. +#endif
  6553. +
  6554. +    if ( disk_change(current_drive) ){
  6555. +        DPRINT("disk removed during i/o\n");
  6556. +        cancel_activity();
  6557. +        cont->done(0);
  6558. +        reset_fdc();
  6559. +    } else {
  6560. +        del_timer(&fd_timer);
  6561. +        fd_timer.function = (timeout_fn) fd_watchdog;
  6562. +        fd_timer.expires = jiffies + HZ / 10;
  6563. +        add_timer(&fd_timer);
  6564. +    }
  6565. +}
  6566. +
  6567. +static void main_command_interrupt(void)
  6568. +{
  6569. +    del_timer(&fd_timer);
  6570. +    cont->interrupt();
  6571. +}
  6572. +
  6573. +/* waits for a delay (spinup or select) to pass */
  6574. +static int wait_for_completion(int delay, timeout_fn function)
  6575. +{
  6576. +    if ( FDCS->reset ){
  6577. +        reset_fdc(); /* do the reset during sleep to win time
  6578. +                  * if we don't need to sleep, it's a good
  6579. +                  * occasion anyways */
  6580. +        return 1;
  6581. +    }
  6582. +
  6583. +    if ((signed) (jiffies - delay) < 0) {
  6584. +        del_timer(&fd_timer);
  6585. +        fd_timer.function = function;
  6586. +        fd_timer.expires = delay;
  6587. +        add_timer(&fd_timer);
  6588. +        return 1;
  6589. +    }
  6590. +    return 0;
  6591. +}
  6592. +
  6593. +static int hlt_disabled=0;
  6594. +static void floppy_disable_hlt(void)
  6595. +{
  6596. +    unsigned long flags;
  6597. +
  6598. +    INT_OFF;
  6599. +    if(!hlt_disabled){
  6600. +        hlt_disabled=1;
  6601. +#ifdef HAVE_DISABLE_HLT
  6602. +        disable_hlt();
  6603. +#endif
  6604. +    }
  6605. +    INT_ON;
  6606. +}
  6607. +
  6608. +static void floppy_enable_hlt(void)
  6609. +{
  6610. +    unsigned long flags;
  6611. +
  6612. +    INT_OFF;
  6613. +    if(hlt_disabled){
  6614. +        hlt_disabled=0;
  6615. +#ifdef HAVE_DISABLE_HLT
  6616. +        enable_hlt();
  6617. +#endif
  6618. +    }
  6619. +    INT_ON;
  6620. +}
  6621. +
  6622. +
  6623. +static void setup_DMA(void)
  6624. +{
  6625. +    unsigned long flags;
  6626. +
  6627. +#ifdef FLOPPY_SANITY_CHECK
  6628. +    if (raw_cmd->length == 0){
  6629. +        int i;
  6630. +
  6631. +        printk("zero dma transfer size:");
  6632. +        for(i=0; i< raw_cmd->cmd_count; i++)
  6633. +            printk("%x,", raw_cmd->cmd[i]);
  6634. +        printk("\n");
  6635. +        cont->done(0);
  6636. +        FDCS->reset = 1;
  6637. +        return;
  6638. +    }
  6639. +#if 0
  6640. +    if ((long) raw_cmd->kernel_data % 512 ){
  6641. +        printk("non aligned address: %p\n", raw_cmd->kernel_data );
  6642. +        cont->done(0);
  6643. +        FDCS->reset=1;
  6644. +        return;
  6645. +    }
  6646. +    if (CROSS_64KB(raw_cmd->kernel_data, raw_cmd->length)) {
  6647. +        printk("DMA crossing 64-K boundary %p-%p\n",
  6648. +               raw_cmd->kernel_data,
  6649. +               raw_cmd->kernel_data + raw_cmd->length);
  6650. +        cont->done(0);
  6651. +        FDCS->reset=1;
  6652. +        return;
  6653. +    }
  6654. +#endif
  6655. +#endif
  6656. +    INT_OFF;
  6657. +    fd_disable_dma();
  6658. +    fd_clear_dma_ff();
  6659. +    fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
  6660. +    fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)?
  6661. +             DMA_MODE_READ : DMA_MODE_WRITE);
  6662. +    fd_set_dma_addr(virt_to_bus(raw_cmd->kernel_data));
  6663. +    fd_set_dma_count(raw_cmd->length);
  6664. +    virtual_dma_port = FDCS->address;
  6665. +    fd_enable_dma();
  6666. +    INT_ON;
  6667. +    floppy_disable_hlt();
  6668. +}
  6669. +
  6670. +void show_floppy(void);
  6671. +
  6672. +/* waits until the fdc becomes ready */
  6673. +static int wait_til_ready(void)
  6674. +{
  6675. +    int counter, status;
  6676. +    if(FDCS->reset)
  6677. +        return -1;
  6678. +    for (counter = 0; counter < 10000; counter++) {
  6679. +        status = fd_inb(FD_STATUS);
  6680. +        if (status & STATUS_READY)
  6681. +            return status;
  6682. +    }
  6683. +    if (!initialising) {
  6684. +        DPRINT("Getstatus times out (%x) on fdc %d\n",
  6685. +            status, fdc);
  6686. +        show_floppy();
  6687. +    }
  6688. +    FDCS->reset = 1;
  6689. +    return -1;
  6690. +}
  6691. +
  6692. +/* sends a command byte to the fdc */
  6693. +static int output_byte(char byte)
  6694. +{
  6695. +    int status;
  6696. +
  6697. +    if ((status = wait_til_ready()) < 0)
  6698. +        return -1;
  6699. +    if ((status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY){
  6700. +        fd_outb(byte,FD_DATA);
  6701. +#ifdef FLOPPY_SANITY_CHECK
  6702. +        output_log[output_log_pos].data = byte;
  6703. +        output_log[output_log_pos].status = status;
  6704. +        output_log[output_log_pos].jiffies = jiffies;
  6705. +        output_log_pos = (output_log_pos + 1) % OLOGSIZE;
  6706. +#endif
  6707. +        return 0;
  6708. +    }
  6709. +    FDCS->reset = 1;
  6710. +    if (!initialising) {
  6711. +        DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
  6712. +            byte, fdc, status);
  6713. +        show_floppy();
  6714. +    }
  6715. +    return -1;
  6716. +}
  6717. +#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;}
  6718. +
  6719. +/* gets the response from the fdc */
  6720. +static int result(void)
  6721. +{
  6722. +    int i, status;
  6723. +
  6724. +    for(i=0; i < MAX_REPLIES; i++) {
  6725. +        if ((status = wait_til_ready()) < 0)
  6726. +            break;
  6727. +        status &= STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA;
  6728. +        if ((status & ~STATUS_BUSY) == STATUS_READY){
  6729. +#ifdef FLOPPY_SANITY_CHECK
  6730. +            resultjiffies = jiffies;
  6731. +            resultsize = i;
  6732. +#endif
  6733. +            return i;
  6734. +        }
  6735. +        if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY))
  6736. +            reply_buffer[i] = fd_inb(FD_DATA);
  6737. +        else
  6738. +            break;
  6739. +    }
  6740. +    if (!initialising) {
  6741. +        DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
  6742. +            fdc, status, i);
  6743. +        show_floppy();
  6744. +    }
  6745. +    FDCS->reset = 1;
  6746. +    return -1;
  6747. +}
  6748. +
  6749. +#define MORE_OUTPUT -2
  6750. +/* does the fdc need more output? */
  6751. +static int need_more_output(void)
  6752. +{
  6753. +    int status;
  6754. +    if ((status = wait_til_ready()) < 0)
  6755. +        return -1;
  6756. +    if ((status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY)
  6757. +        return MORE_OUTPUT;
  6758. +    return result();
  6759. +}
  6760. +
  6761. +/* Set perpendicular mode as required, based on data rate, if supported.
  6762. + * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
  6763. + */
  6764. +static inline void perpendicular_mode(void)
  6765. +{
  6766. +    unsigned char perp_mode;
  6767. +
  6768. +    if (raw_cmd->rate & 0x40){
  6769. +        switch(raw_cmd->rate & 3){
  6770. +            case 0:
  6771. +                perp_mode=2;
  6772. +                break;
  6773. +            case 3:
  6774. +                perp_mode=3;
  6775. +                break;
  6776. +            default:
  6777. +                DPRINT("Invalid data rate for perpendicular mode!\n");
  6778. +                cont->done(0);
  6779. +                FDCS->reset = 1; /* convenient way to return to
  6780. +                          * redo without to much hassle (deep
  6781. +                          * stack et al. */
  6782. +                return;
  6783. +        }
  6784. +    } else
  6785. +        perp_mode = 0;
  6786. +
  6787. +    if ( FDCS->perp_mode == perp_mode )
  6788. +        return;
  6789. +    if (FDCS->version >= FDC_82077_ORIG) {
  6790. +        output_byte(FD_PERPENDICULAR);
  6791. +        output_byte(perp_mode);
  6792. +        FDCS->perp_mode = perp_mode;
  6793. +    } else if (perp_mode) {
  6794. +        DPRINT("perpendicular mode not supported by this FDC.\n");
  6795. +    }
  6796. +} /* perpendicular_mode */
  6797. +
  6798. +static int fifo_depth = 0xa;
  6799. +static int no_fifo = 0;
  6800. +
  6801. +static int fdc_configure(void)
  6802. +{
  6803. +    /* Turn on FIFO */
  6804. +    output_byte(FD_CONFIGURE);
  6805. +    if(need_more_output() != MORE_OUTPUT)
  6806. +        return 0;
  6807. +    output_byte(0);
  6808. +    output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
  6809. +    output_byte(0); /* pre-compensation from track
  6810. +               0 upwards */
  6811. +    return 1;
  6812. +}
  6813. +
  6814. +#define NOMINAL_DTR 500
  6815. +
  6816. +/* Issue a "SPECIFY" command to set the step rate time, head unload time,
  6817. + * head load time, and DMA disable flag to values needed by floppy.
  6818. + *
  6819. + * The value "dtr" is the data transfer rate in Kbps.  It is needed
  6820. + * to account for the data rate-based scaling done by the 82072 and 82077
  6821. + * FDC types.  This parameter is ignored for other types of FDCs (i.e.
  6822. + * 8272a).
  6823. + *
  6824. + * Note that changing the data transfer rate has a (probably deleterious)
  6825. + * effect on the parameters subject to scaling for 82072/82077 FDCs, so
  6826. + * fdc_specify is called again after each data transfer rate
  6827. + * change.
  6828. + *
  6829. + * srt: 1000 to 16000 in microseconds
  6830. + * hut: 16 to 240 milliseconds
  6831. + * hlt: 2 to 254 milliseconds
  6832. + *
  6833. + * These values are rounded up to the next highest available delay time.
  6834. + */
  6835. +static void fdc_specify(void)
  6836. +{
  6837. +    unsigned char spec1, spec2;
  6838. +    int srt, hlt, hut;
  6839. +    unsigned long dtr = NOMINAL_DTR;
  6840. +    unsigned long scale_dtr = NOMINAL_DTR;
  6841. +    int hlt_max_code = 0x7f;
  6842. +    int hut_max_code = 0xf;
  6843. +
  6844. +    if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
  6845. +        fdc_configure();
  6846. +        FDCS->need_configure = 0;
  6847. +        /*DPRINT("FIFO enabled\n");*/
  6848. +    }
  6849. +
  6850. +    switch (raw_cmd->rate & 0x03) {
  6851. +        case 3:
  6852. +            dtr = 1000;
  6853. +            break;
  6854. +        case 1:
  6855. +            dtr = 300;
  6856. +            if (FDCS->version >= FDC_82078) {
  6857. +                /* chose the default rate table, not the one
  6858. +                 * where 1 = 2 Mbps */
  6859. +                output_byte(FD_DRIVESPEC);
  6860. +                if(need_more_output() == MORE_OUTPUT) {
  6861. +                    output_byte(UNIT(current_drive));
  6862. +                    output_byte(0xc0);
  6863. +                }
  6864. +            }
  6865. +            break;
  6866. +        case 2:
  6867. +            dtr = 250;
  6868. +            break;
  6869. +    }
  6870. +
  6871. +    if (FDCS->version >= FDC_82072) {
  6872. +        scale_dtr = dtr;
  6873. +        hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
  6874. +        hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
  6875. +    }
  6876. +
  6877. +    /* Convert step rate from microseconds to milliseconds and 4 bits */
  6878. +    srt = 16 - (DP->srt*scale_dtr/1000 + NOMINAL_DTR - 1)/NOMINAL_DTR;
  6879. +    SUPBOUND(srt, 0xf);
  6880. +    INFBOUND(srt, 0);
  6881. +
  6882. +    hlt = (DP->hlt*scale_dtr/2 + NOMINAL_DTR - 1)/NOMINAL_DTR;
  6883. +    if (hlt < 0x01)
  6884. +        hlt = 0x01;
  6885. +    else if (hlt > 0x7f)
  6886. +        hlt = hlt_max_code;
  6887. +
  6888. +    hut = (DP->hut*scale_dtr/16 + NOMINAL_DTR - 1)/NOMINAL_DTR;
  6889. +    if (hut < 0x1)
  6890. +        hut = 0x1;
  6891. +    else if (hut > 0xf)
  6892. +        hut = hut_max_code;
  6893. +
  6894. +    spec1 = (srt << 4) | hut;
  6895. +    spec2 = (hlt << 1) | (use_virtual_dma & 1);
  6896. +
  6897. +    /* If these parameters did not change, just return with success */
  6898. +    if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
  6899. +        /* Go ahead and set spec1 and spec2 */
  6900. +        output_byte(FD_SPECIFY);
  6901. +        output_byte(FDCS->spec1 = spec1);
  6902. +        output_byte(FDCS->spec2 = spec2);
  6903. +    }
  6904. +} /* fdc_specify */
  6905. +
  6906. +/* Set the FDC's data transfer rate on behalf of the specified drive.
  6907. + * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
  6908. + * of the specify command (i.e. using the fdc_specify function).
  6909. + */
  6910. +static int fdc_dtr(void)
  6911. +{
  6912. +    /* If data rate not already set to desired value, set it. */
  6913. +    if ((raw_cmd->rate & 3) == FDCS->dtr)
  6914. +        return 0;
  6915. +
  6916. +    /* Set dtr */
  6917. +    fd_outb(raw_cmd->rate & 3, FD_DCR);
  6918. +
  6919. +    /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
  6920. +     * need a stabilization period of several milliseconds to be
  6921. +     * enforced after data rate changes before R/W operations.
  6922. +     * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
  6923. +     */
  6924. +    FDCS->dtr = raw_cmd->rate & 3;
  6925. +    return(wait_for_completion(jiffies+2*HZ/100,
  6926. +                   (timeout_fn) floppy_ready));
  6927. +} /* fdc_dtr */
  6928. +
  6929. +static void tell_sector(void)
  6930. +{
  6931. +    printk(": track %d, head %d, sector %d, size %d",
  6932. +           R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
  6933. +} /* tell_sector */
  6934. +
  6935. +
  6936. +/*
  6937. + * OK, this error interpreting routine is called after a
  6938. + * DMA read/write has succeeded
  6939. + * or failed, so we check the results, and copy any buffers.
  6940. + * hhb: Added better error reporting.
  6941. + * ak: Made this into a separate routine.
  6942. + */
  6943. +static int interpret_errors(void)
  6944. +{
  6945. +    char bad;
  6946. +int res = get_dma_residue(FLOPPY_DMA);
  6947. +if(res) {printk("\n-- DMA residue (%d)",res); tell_sector(); printk("\n");}
  6948. +    if (inr!=7) {
  6949. +        DPRINT("-- FDC reply error");
  6950. +        FDCS->reset = 1;
  6951. +        return 1;
  6952. +    }
  6953. +
  6954. +    /* check IC to find cause of interrupt */
  6955. +    switch (ST0 & ST0_INTR) {
  6956. +        case 0x40:    /* error occurred during command execution */
  6957. +            if (ST1 & ST1_EOC)
  6958. +                return 0; /* occurs with pseudo-DMA */
  6959. +            bad = 1;
  6960. +            if (ST1 & ST1_WP) {
  6961. +                DPRINT("Drive is write protected\n");
  6962. +                CLEARF(FD_DISK_WRITABLE);
  6963. +                cont->done(0);
  6964. +                bad = 2;
  6965. +            } else if (ST1 & ST1_ND) {
  6966. +                SETF(FD_NEED_TWADDLE);
  6967. +            } else if (ST1 & ST1_OR) {
  6968. +                if (DP->flags & FTD_MSG )
  6969. +                    DPRINT("Over/Underrun - retrying\n");
  6970. +                bad = 0;
  6971. +            }else if(*errors >= DP->max_errors.reporting){
  6972. +                DPRINT("");
  6973. +                if (ST0 & ST0_ECE) {
  6974. +                    printk("Recalibrate failed!");
  6975. +                } else if (ST2 & ST2_CRC) {
  6976. +                    printk("data CRC error");
  6977. +                    tell_sector();
  6978. +                } else if (ST1 & ST1_CRC) {
  6979. +                    printk("CRC error");
  6980. +                    tell_sector();
  6981. +                } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) {
  6982. +                    if (!probing) {
  6983. +                        printk("sector not found");
  6984. +                        tell_sector();
  6985. +                    } else
  6986. +                        printk("probe failed...");
  6987. +                } else if (ST2 & ST2_WC) {    /* seek error */
  6988. +                    printk("wrong cylinder");
  6989. +                } else if (ST2 & ST2_BC) {    /* cylinder marked as bad */
  6990. +                    printk("bad cylinder");
  6991. +                } else {
  6992. +                    printk("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x", ST0, ST1, ST2);
  6993. +                    tell_sector();
  6994. +                }
  6995. +                printk("\n");
  6996. +
  6997. +            }
  6998. +            if ( ST2 & ST2_WC || ST2 & ST2_BC)
  6999. +                /* wrong cylinder => recal */
  7000. +                DRS->track = NEED_2_RECAL;
  7001. +            return bad;
  7002. +        case 0x80: /* invalid command given */
  7003. +            DPRINT("Invalid FDC command given!\n");
  7004. +            cont->done(0);
  7005. +            return 2;
  7006. +        case 0xc0:
  7007. +            DPRINT("Abnormal termination caused by polling\n");
  7008. +            cont->error();
  7009. +            return 2;
  7010. +        default: /* (0) Normal command termination */
  7011. +            return 0;
  7012. +    }
  7013. +}
  7014. +
  7015. +/*
  7016. + * This routine is called when everything should be correctly set up
  7017. + * for the transfer (i.e. floppy motor is on, the correct floppy is
  7018. + * selected, and the head is sitting on the right track).
  7019. + */
  7020. +static void setup_rw_floppy(void)
  7021. +{
  7022. +    int i,ready_date,r, flags,dflags;
  7023. +    timeout_fn function;
  7024. +
  7025. +    flags = raw_cmd->flags;
  7026. +    if ( flags & ( FD_RAW_READ | FD_RAW_WRITE))
  7027. +        flags |= FD_RAW_INTR;
  7028. +
  7029. +    if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)){
  7030. +        ready_date = DRS->spinup_date + DP->spinup;
  7031. +        /* If spinup will take a long time, rerun scandrives
  7032. +         * again just before spinup completion. Beware that
  7033. +         * after scandrives, we must again wait for selection.
  7034. +         */
  7035. +        if ((signed) (ready_date - jiffies) > DP->select_delay){
  7036. +            ready_date -= DP->select_delay;
  7037. +            function = (timeout_fn) floppy_start;
  7038. +        } else
  7039. +            function = (timeout_fn) setup_rw_floppy;
  7040. +
  7041. +        /* wait until the floppy is spinning fast enough */
  7042. +        if (wait_for_completion(ready_date,function))
  7043. +            return;
  7044. +    }
  7045. +    dflags = DRS->flags;
  7046. +
  7047. +    if ( (flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
  7048. +        setup_DMA();
  7049. +
  7050. +    if ( flags & FD_RAW_INTR )
  7051. +        SET_INTR(main_command_interrupt);
  7052. +
  7053. +    r=0;
  7054. +    for(i=0; i< raw_cmd->cmd_count; i++)
  7055. +        r|=output_byte( raw_cmd->cmd[i] );
  7056. +
  7057. +#ifdef DEBUGT
  7058. +    debugt("rw_command: ");
  7059. +#endif
  7060. +    if (r) {
  7061. +        cont->error();
  7062. +        reset_fdc();
  7063. +        return;
  7064. +    }
  7065. +
  7066. +    if ( ! ( flags & FD_RAW_INTR )){
  7067. +        inr = result();
  7068. +        cont->interrupt();
  7069. +    } else if ( flags & FD_RAW_NEED_DISK )
  7070. +        fd_watchdog();
  7071. +}
  7072. +
  7073. +static int blind_seek;
  7074. +
  7075. +/*
  7076. + * This is the routine called after every seek (or recalibrate) interrupt
  7077. + * from the floppy controller.
  7078. + */
  7079. +static void seek_interrupt(void)
  7080. +{
  7081. +#ifdef DEBUGT
  7082. +    debugt("seek interrupt:");
  7083. +#endif
  7084. +    if (inr != 2 || (ST0 & 0xF8) != 0x20 ) {
  7085. +        DPRINT("seek failed\n");
  7086. +        DRS->track = NEED_2_RECAL;
  7087. +        cont->error();
  7088. +        cont->redo();
  7089. +        return;
  7090. +    }
  7091. +    if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek){
  7092. +#ifdef DCL_DEBUG
  7093. +        if (DP->flags & FD_DEBUG){
  7094. +            DPRINT("clearing NEWCHANGE flag because of effective seek\n");
  7095. +            DPRINT("jiffies=%ld\n", jiffies);
  7096. +        }
  7097. +#endif
  7098. +        CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
  7099. +        DRS->select_date = jiffies;
  7100. +    }
  7101. +    DRS->track = ST1;
  7102. +    floppy_ready();
  7103. +}
  7104. +
  7105. +static void check_wp(void)
  7106. +{
  7107. +    if (TESTF(FD_VERIFY)) {
  7108. +        /* check write protection */
  7109. +        output_byte( FD_GETSTATUS );
  7110. +        output_byte( UNIT(current_drive) );
  7111. +        if ( result() != 1 ){
  7112. +            FDCS->reset = 1;
  7113. +            return;
  7114. +        }
  7115. +        CLEARF(FD_VERIFY);
  7116. +        CLEARF(FD_NEED_TWADDLE);
  7117. +#ifdef DCL_DEBUG
  7118. +        if (DP->flags & FD_DEBUG){
  7119. +            DPRINT("checking whether disk is write protected\n");
  7120. +            DPRINT("wp=%x\n",ST3 & 0x40);
  7121. +        }
  7122. +#endif
  7123. +        if (!( ST3  & 0x40))
  7124. +            SETF(FD_DISK_WRITABLE);
  7125. +        else
  7126. +            CLEARF(FD_DISK_WRITABLE);
  7127. +    }
  7128. +}
  7129. +
  7130. +static void seek_floppy(void)
  7131. +{
  7132. +    int track;
  7133. +
  7134. +    blind_seek=0;
  7135. +
  7136. +#ifdef DCL_DEBUG
  7137. +    if (DP->flags & FD_DEBUG){
  7138. +        DPRINT("calling disk change from seek\n");
  7139. +    }
  7140. +#endif
  7141. +
  7142. +    if (!TESTF(FD_DISK_NEWCHANGE) &&
  7143. +        disk_change(current_drive) &&
  7144. +        (raw_cmd->flags & FD_RAW_NEED_DISK)){
  7145. +        /* the media changed flag should be cleared after the seek.
  7146. +         * If it isn't, this means that there is really no disk in
  7147. +         * the drive.
  7148. +         */
  7149. +        SETF(FD_DISK_CHANGED);
  7150. +        cont->done(0);
  7151. +        cont->redo();
  7152. +        return;
  7153. +    }
  7154. +    if ( DRS->track <= NEED_1_RECAL ){
  7155. +        recalibrate_floppy();
  7156. +        return;
  7157. +    } else if (TESTF(FD_DISK_NEWCHANGE) &&
  7158. +           (raw_cmd->flags & FD_RAW_NEED_DISK) &&
  7159. +           (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
  7160. +        /* we seek to clear the media-changed condition. Does anybody
  7161. +         * know a more elegant way, which works on all drives? */
  7162. +        if ( raw_cmd->track )
  7163. +            track = raw_cmd->track - 1;
  7164. +        else {
  7165. +            if(DP->flags & FD_SILENT_DCL_CLEAR){
  7166. +                set_dor(fdc, ~ (0x10 << UNIT(current_drive)), 0);
  7167. +                blind_seek = 1;
  7168. +                raw_cmd->flags |= FD_RAW_NEED_SEEK;
  7169. +            }
  7170. +            track = 1;
  7171. +        }
  7172. +    } else {
  7173. +        check_wp();
  7174. +        if (raw_cmd->track != DRS->track &&
  7175. +            (raw_cmd->flags & FD_RAW_NEED_SEEK))
  7176. +            track = raw_cmd->track;
  7177. +        else {
  7178. +            setup_rw_floppy();
  7179. +            return;
  7180. +        }
  7181. +    }
  7182. +
  7183. +    SET_INTR(seek_interrupt);
  7184. +    output_byte(FD_SEEK);
  7185. +    output_byte(UNIT(current_drive));
  7186. +    LAST_OUT(track);
  7187. +#ifdef DEBUGT
  7188. +    debugt("seek command:");
  7189. +#endif
  7190. +}
  7191. +
  7192. +static void recal_interrupt(void)
  7193. +{
  7194. +#ifdef DEBUGT
  7195. +    debugt("recal interrupt:");
  7196. +#endif
  7197. +    if (inr !=2 )
  7198. +        FDCS->reset = 1;
  7199. +    else if (ST0 & ST0_ECE) {
  7200. +               switch(DRS->track){
  7201. +                   case NEED_1_RECAL:
  7202. +#ifdef DEBUGT
  7203. +                debugt("recal interrupt need 1 recal:");
  7204. +#endif
  7205. +                /* after a second recalibrate, we still haven't
  7206. +                 * reached track 0. Probably no drive. Raise an
  7207. +                 * error, as failing immediately might upset
  7208. +                 * computers possessed by the Devil :-) */
  7209. +                cont->error();
  7210. +                cont->redo();
  7211. +                return;
  7212. +            case NEED_2_RECAL:
  7213. +#ifdef DEBUGT
  7214. +                debugt("recal interrupt need 2 recal:");
  7215. +#endif
  7216. +                /* If we already did a recalibrate,
  7217. +                 * and we are not at track 0, this
  7218. +                 * means we have moved. (The only way
  7219. +                 * not to move at recalibration is to
  7220. +                 * be already at track 0.) Clear the
  7221. +                 * new change flag */
  7222. +#ifdef DCL_DEBUG
  7223. +                if (DP->flags & FD_DEBUG){
  7224. +                    DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
  7225. +                }
  7226. +#endif
  7227. +
  7228. +                CLEARF(FD_DISK_NEWCHANGE);
  7229. +                DRS->select_date = jiffies;
  7230. +                /* fall through */
  7231. +            default:
  7232. +#ifdef DEBUGT
  7233. +                debugt("recal interrupt default:");
  7234. +#endif
  7235. +                /* Recalibrate moves the head by at
  7236. +                 * most 80 steps. If after one
  7237. +                 * recalibrate we don't have reached
  7238. +                 * track 0, this might mean that we
  7239. +                 * started beyond track 80.  Try
  7240. +                 * again.  */
  7241. +                DRS->track = NEED_1_RECAL;
  7242. +                break;
  7243. +        }
  7244. +    } else
  7245. +        DRS->track = ST1;
  7246. +    floppy_ready();
  7247. +}
  7248. +
  7249. +static void print_result(char *message, int inr)
  7250. +{
  7251. +    int i;
  7252. +
  7253. +    DPRINT("%s ", message);
  7254. +    if (inr >= 0)
  7255. +        for(i=0; i<inr; i++)
  7256. +            printk("repl[%d]=%x ", i, reply_buffer[i]);
  7257. +        printk("\n");
  7258. +}
  7259. +
  7260. +/* interrupt handler */
  7261. +void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  7262. +{
  7263. +    void (*handler)(void) = DEVICE_INTR;
  7264. +    int do_print;
  7265. +
  7266. +    lasthandler = handler;
  7267. +    interruptjiffies = jiffies;
  7268. +
  7269. +    fd_disable_dma();
  7270. +    floppy_enable_hlt();
  7271. +    CLEAR_INTR;
  7272. +    if ( fdc >= N_FDC || FDCS->address == -1){
  7273. +        /* we don't even know which FDC is the culprit */
  7274. +        printk("DOR0=%x\n", (unsigned int)fdc_state[0].dor);
  7275. +        printk("floppy interrupt on bizarre fdc %d\n",fdc);
  7276. +        printk("handler=%p\n", handler);
  7277. +        is_alive("bizarre fdc");
  7278. +        return;
  7279. +    }
  7280. +
  7281. +    FDCS->reset = 0;
  7282. +    /* We have to clear the reset flag here, because apparently on boxes
  7283. +     * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
  7284. +     * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
  7285. +     * emission of the SENSEI's.
  7286. +     * It is OK to emit floppy commands because we are in an interrupt
  7287. +     * handler here, and thus we have to fear no interference of other
  7288. +     * activity.
  7289. +     */
  7290. +
  7291. +    do_print = !handler && print_unex && !initialising;
  7292. +
  7293. +    inr = result();
  7294. +    if (do_print)
  7295. +        print_result("unexpected interrupt", inr);
  7296. +    if (inr == 0) {
  7297. +        do {
  7298. +            output_byte(FD_SENSEI);
  7299. +            inr = result();
  7300. +            if(do_print)
  7301. +                print_result("sensei", inr);
  7302. +        } while ( (ST0 & 0x83) != UNIT(current_drive) && inr == 2);
  7303. +    }
  7304. +    if (handler) {
  7305. +        if(intr_count >= 2) {
  7306. +            /* expected interrupt */        
  7307. +            floppy_tq.routine = (void *)(void *) handler;
  7308. +            queue_task_irq(&floppy_tq, &tq_immediate);
  7309. +            mark_bh(IMMEDIATE_BH);
  7310. +        } else
  7311. +            handler();
  7312. +    } else
  7313. +        FDCS->reset = 1;
  7314. +    is_alive("normal interrupt end");
  7315. +}
  7316. +
  7317. +static void recalibrate_floppy(void)
  7318. +{
  7319. +#ifdef DEBUGT
  7320. +    debugt("recalibrate floppy:");
  7321. +#endif
  7322. +    SET_INTR(recal_interrupt);
  7323. +    output_byte(FD_RECALIBRATE);
  7324. +    LAST_OUT(UNIT(current_drive));
  7325. +}
  7326. +
  7327. +/*
  7328. + * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
  7329. + */
  7330. +static void reset_interrupt(void)
  7331. +{
  7332. +#ifdef DEBUGT
  7333. +    debugt("reset interrupt:");
  7334. +#endif
  7335. +    result();        /* get the status ready for set_fdc */
  7336. +    if (FDCS->reset) {
  7337. +        printk("reset set in interrupt, calling %p\n", cont->error);
  7338. +        cont->error(); /* a reset just after a reset. BAD! */
  7339. +    }
  7340. +    cont->redo();
  7341. +}
  7342. +
  7343. +/*
  7344. + * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
  7345. + * or by setting the self clearing bit 7 of STATUS (newer FDCs)
  7346. + */
  7347. +static void reset_fdc(void)
  7348. +{
  7349. +    SET_INTR(reset_interrupt);
  7350. +    FDCS->reset = 0;
  7351. +    reset_fdc_info(0);
  7352. +
  7353. +    /* Pseudo-DMA may intercept 'reset finished' interrupt.  */
  7354. +    /* Irrelevant for systems with true DMA (i386).          */
  7355. +    fd_disable_dma();
  7356. +
  7357. +    if (FDCS->version >= FDC_82072A)
  7358. +        fd_outb(0x80 | (FDCS->dtr &3), FD_STATUS);
  7359. +    else {
  7360. +        arm_set_dor(FDCS->dor & ~0x04);
  7361. +        udelay(FD_RESET_DELAY);
  7362. +        arm_set_dor(FDCS->dor);
  7363. +    }
  7364. +}
  7365. +
  7366. +void show_floppy(void)
  7367. +{
  7368. +    int i;
  7369. +
  7370. +    printk("\n");
  7371. +    printk("floppy driver state\n");
  7372. +    printk("-------------------\n");
  7373. +    printk("now=%ld last interrupt=%d last called handler=%p\n",
  7374. +        jiffies, interruptjiffies, lasthandler);
  7375. +
  7376. +
  7377. +#ifdef FLOPPY_SANITY_CHECK
  7378. +    printk("timeout_message=%s\n", timeout_message);
  7379. +    printk("last output bytes:\n");
  7380. +    for(i=0; i < OLOGSIZE; i++)
  7381. +        printk("%2x %2x %ld\n",
  7382. +            output_log[(i+output_log_pos) % OLOGSIZE].data,
  7383. +            output_log[(i+output_log_pos) % OLOGSIZE].status,
  7384. +            output_log[(i+output_log_pos) % OLOGSIZE].jiffies);
  7385. +    printk("last result at %d\n", resultjiffies);
  7386. +    printk("last redo_fd_request at %d\n", lastredo);
  7387. +    for(i=0; i<resultsize; i++){
  7388. +        printk("%2x ", reply_buffer[i]);
  7389. +    }
  7390. +    printk("\n");
  7391. +#endif
  7392. +
  7393. +    printk("status=%x\n", fd_inb(FD_STATUS));
  7394. +    printk("fdc_busy=%d\n", fdc_busy);
  7395. +    if( DEVICE_INTR)
  7396. +        printk("DEVICE_INTR=%p\n", DEVICE_INTR);
  7397. +    if(floppy_tq.sync)
  7398. +        printk("floppy_tq.routine=%p\n", floppy_tq.routine);
  7399. +    if(fd_timer.prev)
  7400. +        printk("fd_timer.function=%p\n", fd_timer.function);
  7401. +    if(fd_timeout.prev){
  7402. +        printk("timer_table=%p\n",fd_timeout.function);
  7403. +        printk("expires=%ld\n",fd_timeout.expires-jiffies);
  7404. +        printk("now=%ld\n",jiffies);
  7405. +    }
  7406. +    printk("cont=%p\n", cont);
  7407. +    printk("CURRENT=%p\n", CURRENT);
  7408. +    printk("command_status=%d\n", command_status);
  7409. +    printk("\n");
  7410. +}
  7411. +
  7412. +static void floppy_shutdown(void)
  7413. +{
  7414. +    if (!initialising)
  7415. +        show_floppy();
  7416. +    cancel_activity();
  7417. +    sti();
  7418. +
  7419. +    floppy_enable_hlt();
  7420. +    fd_disable_dma();
  7421. +    /* avoid dma going to a random drive after shutdown */
  7422. +    
  7423. +    if(!initialising)
  7424. +        DPRINT("floppy timeout called\n");
  7425. +    FDCS->reset = 1;
  7426. +    if (cont){
  7427. +        cont->done(0);
  7428. +        cont->redo(); /* this will recall reset when needed */
  7429. +    } else {
  7430. +        printk("no cont in shutdown!\n");
  7431. +        process_fd_request();
  7432. +    }
  7433. +    is_alive("floppy shutdown");
  7434. +}
  7435. +/*typedef void (*timeout_fn)(unsigned long);*/
  7436. +
  7437. +/* start motor, check media-changed condition and write protection */
  7438. +static int start_motor( void (*function)(void)  )
  7439. +{
  7440. +    int mask, data;
  7441. +
  7442. +    mask = 0xfc;
  7443. +    data = UNIT(current_drive);
  7444. +    if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)){
  7445. +        if(!(FDCS->dor & ( 0x10 << UNIT(current_drive) ) )){
  7446. +            set_debugt();
  7447. +            /* no read since this drive is running */
  7448. +            DRS->first_read_date = 0;
  7449. +            /* note motor start time if motor is not yet running */
  7450. +            DRS->spinup_date = jiffies;
  7451. +            data |= (0x10 << UNIT(current_drive));
  7452. +        }
  7453. +    } else
  7454. +        if (FDCS->dor & ( 0x10 << UNIT(current_drive) ) )
  7455. +            mask &= ~(0x10 << UNIT(current_drive));
  7456. +
  7457. +    /* starts motor and selects floppy */
  7458. +    del_timer(motor_off_timer + current_drive);
  7459. +    set_dor( fdc, mask, data);
  7460. +
  7461. +    /* wait_for_completion also schedules reset if needed. */
  7462. +    return(wait_for_completion(DRS->select_date+DP->select_delay,
  7463. +                   (timeout_fn) function));
  7464. +}
  7465. +
  7466. +static void floppy_ready(void)
  7467. +{
  7468. +    CHECK_RESET;
  7469. +    if(start_motor(floppy_ready)) return;
  7470. +    if(fdc_dtr()) return;
  7471. +
  7472. +#ifdef DCL_DEBUG
  7473. +    if (DP->flags & FD_DEBUG){
  7474. +        DPRINT("calling disk change from floppy_ready\n");
  7475. +    }
  7476. +#endif
  7477. +
  7478. +    if(!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
  7479. +       disk_change(current_drive) &&
  7480. +       !DP->select_delay)
  7481. +           twaddle(); /* this clears the dcl on certain drive/controller
  7482. +                   * combinations */
  7483. +
  7484. +    if ( raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){
  7485. +        perpendicular_mode();
  7486. +        fdc_specify(); /* must be done here because of hut, hlt ... */
  7487. +        seek_floppy();
  7488. +    } else
  7489. +        setup_rw_floppy();
  7490. +}
  7491. +
  7492. +static void floppy_start(void)
  7493. +{
  7494. +    reschedule_timeout(CURRENTD, "floppy start", 0);
  7495. +
  7496. +    scandrives();
  7497. +#ifdef DCL_DEBUG
  7498. +    if (DP->flags & FD_DEBUG){
  7499. +        DPRINT("setting NEWCHANGE in floppy_start\n");
  7500. +    }
  7501. +#endif
  7502. +    SETF(FD_DISK_NEWCHANGE);
  7503. +    floppy_ready();
  7504. +}
  7505. +
  7506. +/*
  7507. + * ========================================================================
  7508. + * here ends the bottom half. Exported routines are:
  7509. + * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
  7510. + * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
  7511. + * Initialization also uses output_byte, result, set_dor, floppy_interrupt
  7512. + * and set_dor.
  7513. + * ========================================================================
  7514. + */
  7515. +/*
  7516. + * General purpose continuations.
  7517. + * ==============================
  7518. + */
  7519. +
  7520. +static void do_wakeup(void)
  7521. +{
  7522. +    reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
  7523. +    cont = 0;
  7524. +    command_status += 2;
  7525. +    wake_up(&command_done);
  7526. +}
  7527. +
  7528. +static struct cont_t wakeup_cont={
  7529. +    empty,
  7530. +    do_wakeup,
  7531. +    empty,
  7532. +    (done_f)empty
  7533. +};
  7534. +
  7535. +
  7536. +static struct cont_t intr_cont={
  7537. +    empty,
  7538. +    process_fd_request,
  7539. +    empty,
  7540. +    (done_f) empty
  7541. +};
  7542. +
  7543. +static int wait_til_done( void (*handler)(void ), int interruptible )
  7544. +{
  7545. +    int ret;
  7546. +    unsigned long flags;
  7547. +
  7548. +    floppy_tq.routine = (void *)(void *) handler;
  7549. +    queue_task(&floppy_tq, &tq_immediate);
  7550. +    mark_bh(IMMEDIATE_BH);
  7551. +    INT_OFF;
  7552. +    while(command_status < 2 && NO_SIGNAL){
  7553. +        is_alive("wait_til_done");
  7554. +        if (interruptible)
  7555. +            interruptible_sleep_on(&command_done);
  7556. +        else
  7557. +            sleep_on(&command_done);
  7558. +    }
  7559. +    if(command_status < 2){
  7560. +        cancel_activity();
  7561. +        cont = &intr_cont;
  7562. +        reset_fdc();
  7563. +        INT_ON;
  7564. +        return -EINTR;
  7565. +    }
  7566. +    INT_ON;
  7567. +
  7568. +    if ( FDCS->reset )
  7569. +        command_status = FD_COMMAND_ERROR;
  7570. +    if ( command_status == FD_COMMAND_OKAY )
  7571. +        ret=0;
  7572. +    else
  7573. +        ret=-EIO;
  7574. +    command_status = FD_COMMAND_NONE;
  7575. +    return ret;
  7576. +}
  7577. +
  7578. +static void generic_done(int result)
  7579. +{
  7580. +    command_status = result;
  7581. +    cont = &wakeup_cont;
  7582. +}
  7583. +
  7584. +static void generic_success(void)
  7585. +{
  7586. +    cont->done(1);
  7587. +}
  7588. +
  7589. +static void generic_failure(void)
  7590. +{
  7591. +    cont->done(0);
  7592. +}
  7593. +
  7594. +static void success_and_wakeup(void)
  7595. +{
  7596. +    generic_success();
  7597. +    cont->redo();
  7598. +}
  7599. +
  7600. +
  7601. +/*
  7602. + * formatting and rw support.
  7603. + * ==========================
  7604. + */
  7605. +
  7606. +static int next_valid_format(void)
  7607. +{
  7608. +    int probed_format;
  7609. +
  7610. +    probed_format = DRS->probed_format;
  7611. +    while(1){
  7612. +        if ( probed_format >= 8 ||
  7613. +            ! DP->autodetect[probed_format] ){
  7614. +            DRS->probed_format = 0;
  7615. +            return 1;
  7616. +        }
  7617. +        if ( floppy_type[DP->autodetect[probed_format]].sect ){
  7618. +            DRS->probed_format = probed_format;
  7619. +            return 0;
  7620. +        }
  7621. +        probed_format++;
  7622. +    }
  7623. +}
  7624. +
  7625. +static void bad_flp_intr(void)
  7626. +{
  7627. +    if ( probing ){
  7628. +        DRS->probed_format++;
  7629. +        if ( !next_valid_format())
  7630. +            return;
  7631. +    }
  7632. +    (*errors)++;
  7633. +    INFBOUND(DRWE->badness, *errors);
  7634. +    if (*errors > DP->max_errors.abort)
  7635. +        cont->done(0);
  7636. +    if (*errors > DP->max_errors.reset)
  7637. +        FDCS->reset = 1;
  7638. +    else if (*errors > DP->max_errors.recal)
  7639. +        DRS->track = NEED_2_RECAL;
  7640. +}
  7641. +
  7642. +static void set_floppy(kdev_t device)
  7643. +{
  7644. +    if (TYPE(device))
  7645. +        _floppy = TYPE(device) + floppy_type;
  7646. +    else
  7647. +        _floppy = current_type[ DRIVE(device) ];
  7648. +}
  7649. +
  7650. +/*
  7651. + * formatting support.
  7652. + * ===================
  7653. + */
  7654. +static void format_interrupt(void)
  7655. +{
  7656. +    switch (interpret_errors()){
  7657. +        case 1:
  7658. +            cont->error();
  7659. +        case 2:
  7660. +            break;
  7661. +        case 0:
  7662. +            cont->done(1);
  7663. +    }
  7664. +    cont->redo();
  7665. +}
  7666. +
  7667. +#define CODE2SIZE (ssize = ( ( 1 << SIZECODE ) + 3 ) >> 2)
  7668. +#define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80 ) >>1))
  7669. +#define CT(x) ( (x) | 0x40 )
  7670. +static void setup_format_params(int track)
  7671. +{
  7672. +    struct fparm {
  7673. +        unsigned char track,head,sect,size;
  7674. +    } *here = (struct fparm *)floppy_track_buffer;
  7675. +    int il,n;
  7676. +    int count,head_shift,track_shift;
  7677. +
  7678. +    raw_cmd = &default_raw_cmd;
  7679. +    raw_cmd->track = track;
  7680. +    
  7681. +    raw_cmd->flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
  7682. +        FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
  7683. +    raw_cmd->rate = _floppy->rate & 0x43;
  7684. +    raw_cmd->cmd_count = NR_F;
  7685. +    COMMAND = FM_MODE(_floppy,FD_FORMAT);
  7686. +    DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy,format_req.head);
  7687. +    F_SIZECODE = FD_SIZECODE(_floppy);
  7688. +    F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
  7689. +    F_GAP = _floppy->fmt_gap;
  7690. +    F_FILL = FD_FILL_BYTE;
  7691. +
  7692. +    raw_cmd->kernel_data = floppy_track_buffer;
  7693. +    raw_cmd->length = 4 * F_SECT_PER_TRACK;
  7694. +
  7695. +    /* allow for about 30ms for data transport per track */
  7696. +    head_shift  = (F_SECT_PER_TRACK + 5) / 6;
  7697. +
  7698. +    /* a ``cylinder'' is two tracks plus a little stepping time */
  7699. +    track_shift = 2 * head_shift + 3;
  7700. +
  7701. +    /* position of logical sector 1 on this track */
  7702. +    n = (track_shift * format_req.track + head_shift * format_req.head )
  7703. +        % F_SECT_PER_TRACK;
  7704. +
  7705. +    /* determine interleave */
  7706. +    il = 1;
  7707. +    if (_floppy->sect > DP->interleave_sect && F_SIZECODE == 2)
  7708. +        il++;
  7709. +
  7710. +    /* initialize field */
  7711. +    for (count = 0; count < F_SECT_PER_TRACK; ++count) {
  7712. +        here[count].track = format_req.track;
  7713. +        here[count].head = format_req.head;
  7714. +        here[count].sect = 0;
  7715. +        here[count].size = F_SIZECODE;
  7716. +    }
  7717. +    /* place logical sectors */
  7718. +    for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
  7719. +        here[n].sect = count;
  7720. +        n = (n+il) % F_SECT_PER_TRACK;
  7721. +        if (here[n].sect) { /* sector busy, find next free sector */
  7722. +            ++n;
  7723. +            if (n>= F_SECT_PER_TRACK) {
  7724. +                n-=F_SECT_PER_TRACK;
  7725. +                while (here[n].sect) ++n;
  7726. +            }
  7727. +        }
  7728. +    }
  7729. +}
  7730. +
  7731. +static void redo_format(void)
  7732. +{
  7733. +    buffer_track = -1;
  7734. +    setup_format_params(format_req.track << STRETCH(_floppy));
  7735. +    floppy_start();
  7736. +#ifdef DEBUGT
  7737. +    debugt("queue format request");
  7738. +#endif
  7739. +}
  7740. +
  7741. +static struct cont_t format_cont={
  7742. +    format_interrupt,
  7743. +    redo_format,
  7744. +    bad_flp_intr,
  7745. +    generic_done };
  7746. +
  7747. +static int do_format(kdev_t device, struct format_descr *tmp_format_req)
  7748. +{
  7749. +    int ret;
  7750. +    int drive=DRIVE(device);
  7751. +
  7752. +    LOCK_FDC(drive,1);
  7753. +    set_floppy(device);
  7754. +    if (!_floppy ||
  7755. +        _floppy->track > DP->tracks ||
  7756. +        tmp_format_req->track >= _floppy->track ||
  7757. +        tmp_format_req->head >= _floppy->head ||
  7758. +        (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
  7759. +        !_floppy->fmt_gap) {
  7760. +        process_fd_request();
  7761. +        return -EINVAL;
  7762. +    }
  7763. +    format_req = *tmp_format_req;
  7764. +    format_errors = 0;
  7765. +    cont = &format_cont;
  7766. +    errors = &format_errors;
  7767. +    IWAIT(redo_format);
  7768. +    process_fd_request();
  7769. +    return ret;
  7770. +}
  7771. +
  7772. +/*
  7773. + * Buffer read/write and support
  7774. + * =============================
  7775. + */
  7776. +
  7777. +/* new request_done. Can handle physical sectors which are smaller than a
  7778. + * logical buffer */
  7779. +static void request_done(int uptodate)
  7780. +{
  7781. +    int block;
  7782. +
  7783. +    probing = 0;
  7784. +    reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate);
  7785. +
  7786. +    if (!CURRENT){
  7787. +        DPRINT("request list destroyed in floppy request done\n");
  7788. +        return;
  7789. +    }
  7790. +
  7791. +    if (uptodate){
  7792. +        /* maintain values for invalidation on geometry
  7793. +         * change */
  7794. +        block = current_count_sectors + CURRENT->sector;
  7795. +        INFBOUND(DRS->maxblock, block);
  7796. +        if (block > _floppy->sect)
  7797. +            DRS->maxtrack = 1;
  7798. +
  7799. +        /* unlock chained buffers */
  7800. +        while (current_count_sectors && CURRENT &&
  7801. +               current_count_sectors >= CURRENT->current_nr_sectors ){
  7802. +            current_count_sectors -= CURRENT->current_nr_sectors;
  7803. +            CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
  7804. +            CURRENT->sector += CURRENT->current_nr_sectors;
  7805. +            end_request(1);
  7806. +        }
  7807. +        if ( current_count_sectors && CURRENT){
  7808. +            /* "unlock" last subsector */
  7809. +            CURRENT->buffer += current_count_sectors <<9;
  7810. +            CURRENT->current_nr_sectors -= current_count_sectors;
  7811. +            CURRENT->nr_sectors -= current_count_sectors;
  7812. +            CURRENT->sector += current_count_sectors;
  7813. +            return;
  7814. +        }
  7815. +
  7816. +        if ( current_count_sectors && ! CURRENT )
  7817. +            DPRINT("request list destroyed in floppy request done\n");
  7818. +
  7819. +    } else {
  7820. +        if(CURRENT->cmd == WRITE) {
  7821. +            /* record write error information */
  7822. +            DRWE->write_errors++;
  7823. +            if(DRWE->write_errors == 1) {
  7824. +                DRWE->first_error_sector = CURRENT->sector;
  7825. +                DRWE->first_error_generation = DRS->generation;
  7826. +            }
  7827. +            DRWE->last_error_sector = CURRENT->sector;
  7828. +            DRWE->last_error_generation = DRS->generation;
  7829. +        }
  7830. +        end_request(0);
  7831. +    }
  7832. +}
  7833. +
  7834. +/* Interrupt handler evaluating the result of the r/w operation */
  7835. +static void rw_interrupt(void)
  7836. +{
  7837. +    int nr_sectors, ssize, eoc;
  7838. +
  7839. +    if ( ! DRS->first_read_date )
  7840. +        DRS->first_read_date = jiffies;
  7841. +
  7842. +    nr_sectors = 0;
  7843. +    CODE2SIZE;
  7844. +
  7845. +    if(ST1 & ST1_EOC)
  7846. +        eoc = 1;
  7847. +    else
  7848. +        eoc = 0;
  7849. +    nr_sectors = ((R_TRACK-TRACK)*_floppy->head+R_HEAD-HEAD) *
  7850. +        _floppy->sect + ((R_SECTOR-SECTOR+eoc) <<  SIZECODE >> 2) -
  7851. +        (sector_t % _floppy->sect) % ssize;
  7852. +
  7853. +#ifdef FLOPPY_SANITY_CHECK
  7854. +    if ( nr_sectors > current_count_sectors + ssize -
  7855. +         (current_count_sectors + sector_t) % ssize +
  7856. +         sector_t % ssize){
  7857. +        DPRINT("long rw: %x instead of %lx\n",
  7858. +            nr_sectors, current_count_sectors);
  7859. +        printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
  7860. +        printk("rh=%d h=%d\n", R_HEAD, HEAD);
  7861. +        printk("rt=%d t=%d\n", R_TRACK, TRACK);
  7862. +        printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,
  7863. +               sector_t, ssize);
  7864. +    }
  7865. +#endif
  7866. +    INFBOUND(nr_sectors,0);
  7867. +    SUPBOUND(current_count_sectors, nr_sectors);
  7868. +
  7869. +    switch (interpret_errors()){
  7870. +        case 2:
  7871. +            cont->redo();
  7872. +            return;
  7873. +        case 1:
  7874. +            if (  !current_count_sectors){
  7875. +                cont->error();
  7876. +                cont->redo();
  7877. +                return;
  7878. +            }
  7879. +            break;
  7880. +        case 0:
  7881. +            if (  !current_count_sectors){
  7882. +                cont->redo();
  7883. +                return;
  7884. +            }
  7885. +            current_type[current_drive] = _floppy;
  7886. +            floppy_sizes[TOMINOR(current_drive) ]= _floppy->size>>1;
  7887. +            break;
  7888. +    }
  7889. +
  7890. +    if (probing) {
  7891. +        if (DP->flags & FTD_MSG)
  7892. +            DPRINT("Auto-detected floppy type %s in fd%d\n",
  7893. +                _floppy->name,current_drive);
  7894. +        current_type[current_drive] = _floppy;
  7895. +        floppy_sizes[TOMINOR(current_drive)] = _floppy->size >> 1;
  7896. +        probing = 0;
  7897. +    }
  7898. +
  7899. +    if ( CT(COMMAND) != FD_READ ||
  7900. +         raw_cmd->kernel_data == CURRENT->buffer ){
  7901. +        /* transfer directly from buffer */
  7902. +        cont->done(1);
  7903. +    } else if ( CT(COMMAND) == FD_READ){
  7904. +        buffer_track = raw_cmd->track;
  7905. +        buffer_drive = current_drive;
  7906. +        INFBOUND(buffer_max, nr_sectors + sector_t);
  7907. +    }
  7908. +    cont->redo();
  7909. +}
  7910. +
  7911. +/* Compute maximal contiguous buffer size. */
  7912. +static int buffer_chain_size(void)
  7913. +{
  7914. +    struct buffer_head *bh;
  7915. +    int size;
  7916. +    char *base;
  7917. +
  7918. +    base = CURRENT->buffer;
  7919. +    size = CURRENT->current_nr_sectors << 9;
  7920. +    bh = CURRENT->bh;
  7921. +
  7922. +    if(bh){
  7923. +        bh = bh->b_reqnext;
  7924. +        while ( bh && bh->b_data == base + size ){
  7925. +            size += bh->b_size;
  7926. +            bh = bh->b_reqnext;
  7927. +        }
  7928. +    }
  7929. +    return size >> 9;
  7930. +}
  7931. +
  7932. +/* Compute the maximal transfer size */
  7933. +static int transfer_size(int ssize, int max_sector, int max_size)
  7934. +{
  7935. +    SUPBOUND(max_sector, sector_t + max_size);
  7936. +
  7937. +    /* alignment */
  7938. +    max_sector -= (max_sector % _floppy->sect ) % ssize;
  7939. +
  7940. +    /* transfer size, beginning not aligned */
  7941. +    current_count_sectors = max_sector - sector_t ;
  7942. +
  7943. +    return max_sector;
  7944. +}
  7945. +
  7946. +/*
  7947. + * Move data from/to the track buffer to/from the buffer cache.
  7948. + */
  7949. +static void copy_buffer(int ssize, int max_sector, int max_sector_2)
  7950. +{
  7951. +    int remaining; /* number of transferred 512-byte sectors */
  7952. +    struct buffer_head *bh;
  7953. +    char *buffer, *dma_buffer;
  7954. +    int size;
  7955. +
  7956. +    max_sector = transfer_size(ssize,
  7957. +                   minimum(max_sector, max_sector_2),
  7958. +                   CURRENT->nr_sectors);
  7959. +
  7960. +    if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
  7961. +        buffer_max > sector_t + CURRENT->nr_sectors)
  7962. +        current_count_sectors = minimum(buffer_max - sector_t,
  7963. +                        CURRENT->nr_sectors);
  7964. +
  7965. +    remaining = current_count_sectors << 9;
  7966. +#ifdef FLOPPY_SANITY_CHECK
  7967. +    if ((remaining >> 9) > CURRENT->nr_sectors  &&
  7968. +        CT(COMMAND) == FD_WRITE ){
  7969. +        DPRINT("in copy buffer\n");
  7970. +        printk("current_count_sectors=%ld\n", current_count_sectors);
  7971. +        printk("remaining=%d\n", remaining >> 9);
  7972. +        printk("CURRENT->nr_sectors=%ld\n",CURRENT->nr_sectors);
  7973. +        printk("CURRENT->current_nr_sectors=%ld\n",
  7974. +               CURRENT->current_nr_sectors);
  7975. +        printk("max_sector=%d\n", max_sector);
  7976. +        printk("ssize=%d\n", ssize);
  7977. +    }
  7978. +#endif
  7979. +
  7980. +    buffer_max = maximum(max_sector, buffer_max);
  7981. +
  7982. +    dma_buffer = floppy_track_buffer + ((sector_t - buffer_min) << 9);
  7983. +
  7984. +    bh = CURRENT->bh;
  7985. +    size = CURRENT->current_nr_sectors << 9;
  7986. +    buffer = CURRENT->buffer;
  7987. +
  7988. +    while ( remaining > 0){
  7989. +        SUPBOUND(size, remaining);
  7990. +#ifdef FLOPPY_SANITY_CHECK
  7991. +        if (dma_buffer + size >
  7992. +            floppy_track_buffer + (max_buffer_sectors << 10) ||
  7993. +            dma_buffer < floppy_track_buffer ){
  7994. +            DPRINT("buffer overrun in copy buffer %d\n",
  7995. +                (int) ((floppy_track_buffer - dma_buffer) >>9));
  7996. +            printk("sector_t=%d buffer_min=%d\n",
  7997. +                   sector_t, buffer_min);
  7998. +            printk("current_count_sectors=%ld\n",
  7999. +                   current_count_sectors);
  8000. +            if ( CT(COMMAND) == FD_READ )
  8001. +                printk("read\n");
  8002. +            if ( CT(COMMAND) == FD_READ )
  8003. +                printk("write\n");
  8004. +            break;
  8005. +        }
  8006. +        if ( ((unsigned long)buffer) % 512 )
  8007. +            DPRINT("%p buffer not aligned\n", buffer);
  8008. +#endif
  8009. +        if (CT(COMMAND) == FD_READ)
  8010. +            memcpy( buffer, dma_buffer, size);
  8011. +        else
  8012. +            memcpy( dma_buffer, buffer, size);
  8013. +        remaining -= size;
  8014. +        if ( !remaining)
  8015. +            break;
  8016. +
  8017. +        dma_buffer += size;
  8018. +        bh = bh->b_reqnext;
  8019. +#ifdef FLOPPY_SANITY_CHECK
  8020. +        if ( !bh){
  8021. +            DPRINT("bh=null in copy buffer after copy\n");
  8022. +            break;
  8023. +        }
  8024. +#endif
  8025. +        size = bh->b_size;
  8026. +        buffer = bh->b_data;
  8027. +    }
  8028. +#ifdef FLOPPY_SANITY_CHECK
  8029. +    if ( remaining ){
  8030. +        if ( remaining > 0 )
  8031. +            max_sector -= remaining >> 9;
  8032. +        DPRINT("weirdness: remaining %d\n", remaining>>9);
  8033. +    }
  8034. +#endif
  8035. +}
  8036. +
  8037. +/*
  8038. + * Formulate a read/write request.
  8039. + * this routine decides where to load the data (directly to buffer, or to
  8040. + * tmp floppy area), how much data to load (the size of the buffer, the whole
  8041. + * track, or a single sector)
  8042. + * All floppy_track_buffer handling goes in here. If we ever add track buffer
  8043. + * allocation on the fly, it should be done here. No other part should need
  8044. + * modification.
  8045. + */
  8046. +
  8047. +static int make_raw_rw_request(void)
  8048. +{
  8049. +    int aligned_sector_t;
  8050. +    int max_sector, max_size, tracksize, ssize;
  8051. +
  8052. +    set_fdc(DRIVE(CURRENT->rq_dev));
  8053. +
  8054. +    raw_cmd = &default_raw_cmd;
  8055. +    raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
  8056. +        FD_RAW_NEED_SEEK;
  8057. +    raw_cmd->cmd_count = NR_RW;
  8058. +    if (CURRENT->cmd == READ){
  8059. +        raw_cmd->flags |= FD_RAW_READ;
  8060. +        COMMAND = FM_MODE(_floppy,FD_READ);
  8061. +    } else if (CURRENT->cmd == WRITE){
  8062. +        raw_cmd->flags |= FD_RAW_WRITE;
  8063. +        COMMAND = FM_MODE(_floppy,FD_WRITE);
  8064. +    } else {
  8065. +        DPRINT("make_raw_rw_request: unknown command\n");
  8066. +        return 0;
  8067. +    }
  8068. +
  8069. +    max_sector = _floppy->sect * _floppy->head;
  8070. +    
  8071. +    TRACK = CURRENT->sector / max_sector;
  8072. +    sector_t = CURRENT->sector % max_sector;
  8073. +    if (_floppy->track && TRACK >= _floppy->track )
  8074. +        return 0;
  8075. +    HEAD = sector_t / _floppy->sect;
  8076. +
  8077. +    if (((_floppy->stretch & FD_SWAPSIDES) || TESTF(FD_NEED_TWADDLE)) &&
  8078. +        sector_t < _floppy->sect)
  8079. +        max_sector = _floppy->sect;
  8080. +
  8081. +    /* 2M disks have phantom sectors on the first track */
  8082. +    if ((_floppy->rate & FD_2M ) && (!TRACK) && (!HEAD)){
  8083. +        max_sector = 2 * _floppy->sect / 3;
  8084. +        if (sector_t >= max_sector){
  8085. +            current_count_sectors = minimum(_floppy->sect - sector_t,
  8086. +                            CURRENT->nr_sectors);
  8087. +            return 1;
  8088. +        }
  8089. +        SIZECODE = 2;
  8090. +    } else
  8091. +        SIZECODE = FD_SIZECODE(_floppy);
  8092. +    raw_cmd->rate = _floppy->rate & 0x43;
  8093. +    if ((_floppy->rate & FD_2M) &&
  8094. +        (TRACK || HEAD ) &&
  8095. +        raw_cmd->rate == 2)
  8096. +        raw_cmd->rate = 1;
  8097. +
  8098. +    if ( SIZECODE )
  8099. +        SIZECODE2 = 0xff;
  8100. +    else
  8101. +        SIZECODE2 = 0x80;
  8102. +    raw_cmd->track = TRACK << STRETCH(_floppy);
  8103. +    DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy,HEAD);
  8104. +    GAP = _floppy->gap;
  8105. +    CODE2SIZE;
  8106. +    SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
  8107. +    SECTOR = ((sector_t % _floppy->sect) << 2 >> SIZECODE) + 1;
  8108. +    tracksize = _floppy->sect - _floppy->sect % ssize;
  8109. +    if ( tracksize < _floppy->sect ){
  8110. +        SECT_PER_TRACK ++;
  8111. +        if (  tracksize <= sector_t % _floppy->sect)
  8112. +            SECTOR--;
  8113. +        while ( tracksize <= sector_t % _floppy->sect){
  8114. +            while( tracksize + ssize > _floppy->sect ){
  8115. +                SIZECODE--;
  8116. +                ssize >>= 1;
  8117. +            }
  8118. +            SECTOR++; SECT_PER_TRACK ++;
  8119. +            tracksize += ssize;
  8120. +        }
  8121. +        max_sector = HEAD * _floppy->sect + tracksize;
  8122. +    } else if ( !TRACK && !HEAD && !( _floppy->rate & FD_2M ) && probing)
  8123. +        max_sector = _floppy->sect;
  8124. +
  8125. +    aligned_sector_t = sector_t - ( sector_t % _floppy->sect ) % ssize;
  8126. +    max_size = CURRENT->nr_sectors;
  8127. +    if ((raw_cmd->track == buffer_track) &&
  8128. +        (current_drive == buffer_drive) &&
  8129. +        (sector_t >= buffer_min) && (sector_t < buffer_max)) {
  8130. +        /* data already in track buffer */
  8131. +        if (CT(COMMAND) == FD_READ) {
  8132. +            copy_buffer(1, max_sector, buffer_max);
  8133. +            return 1;
  8134. +        }
  8135. +    } else if (aligned_sector_t != sector_t || CURRENT->nr_sectors < ssize){
  8136. +        if (CT(COMMAND) == FD_WRITE){
  8137. +            if(sector_t + CURRENT->nr_sectors > ssize &&
  8138. +               sector_t + CURRENT->nr_sectors < ssize + ssize)
  8139. +                max_size = ssize + ssize;
  8140. +            else
  8141. +                max_size = ssize;
  8142. +        }
  8143. +        raw_cmd->flags &= ~FD_RAW_WRITE;
  8144. +        raw_cmd->flags |= FD_RAW_READ;
  8145. +        COMMAND = FM_MODE(_floppy,FD_READ);
  8146. +    } else if ((unsigned long)CURRENT->buffer < MAX_DMA_ADDRESS ) {
  8147. +#if 0
  8148. +        unsigned long dma_limit;
  8149. +#endif
  8150. +        int direct, indirect;
  8151. +
  8152. +        indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) -
  8153. +            sector_t;
  8154. +
  8155. +        /*
  8156. +         * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
  8157. +         * on a 64 bit machine!
  8158. +         */
  8159. +        max_size = buffer_chain_size();
  8160. +#if 0
  8161. +        dma_limit = (MAX_DMA_ADDRESS - ((unsigned long) CURRENT->buffer)) >> 9;
  8162. +        if ((unsigned long) max_size > dma_limit) {
  8163. +            max_size = dma_limit;
  8164. +        }
  8165. +        /* 64 kb boundaries */
  8166. +        if (CROSS_64KB(CURRENT->buffer, max_size << 9))
  8167. +            max_size = ( K_64 - ((long) CURRENT->buffer) % K_64)>>9;
  8168. +#endif
  8169. +        direct = transfer_size(ssize,max_sector,max_size) - sector_t;
  8170. +        /*
  8171. +         * We try to read tracks, but if we get too many errors, we
  8172. +         * go back to reading just one sector at a time.
  8173. +         *
  8174. +         * This means we should be able to read a sector even if there
  8175. +         * are other bad sectors on this track.
  8176. +         */
  8177. +        if (!direct ||
  8178. +            (indirect * 2 > direct * 3 &&
  8179. +             *errors < DP->max_errors.read_track &&
  8180. +             /*!TESTF( FD_NEED_TWADDLE) &&*/
  8181. +             ((!probing || (DP->read_track&(1<<DRS->probed_format)))))){
  8182. +            max_size = CURRENT->nr_sectors;
  8183. +        } else {
  8184. +            raw_cmd->kernel_data = CURRENT->buffer;
  8185. +            raw_cmd->length = current_count_sectors << 9;
  8186. +            if (raw_cmd->length == 0){
  8187. +                DPRINT("zero dma transfer attempted from make_raw_request\n");
  8188. +                DPRINT("indirect=%d direct=%d sector_t=%d",
  8189. +                    indirect, direct, sector_t);
  8190. +                return 0;
  8191. +            }
  8192. +            return 2;
  8193. +        }
  8194. +    }
  8195. +
  8196. +    if ( CT(COMMAND) == FD_READ )
  8197. +        max_size = max_sector; /* unbounded */
  8198. +
  8199. +    /* claim buffer track if needed */
  8200. +    if (buffer_track != raw_cmd->track ||  /* bad track */
  8201. +        buffer_drive !=current_drive || /* bad drive */
  8202. +        sector_t > buffer_max ||
  8203. +        sector_t < buffer_min ||
  8204. +        ((CT(COMMAND) == FD_READ ||
  8205. +          (aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize ))&&
  8206. +         max_sector > 2 * max_buffer_sectors + buffer_min &&
  8207. +         max_size + sector_t > 2 * max_buffer_sectors + buffer_min)
  8208. +        /* not enough space */ ){
  8209. +        buffer_track = -1;
  8210. +        buffer_drive = current_drive;
  8211. +        buffer_max = buffer_min = aligned_sector_t;
  8212. +    }
  8213. +    raw_cmd->kernel_data = floppy_track_buffer +
  8214. +        ((aligned_sector_t-buffer_min )<<9);
  8215. +
  8216. +    if ( CT(COMMAND) == FD_WRITE ){
  8217. +        /* copy write buffer to track buffer.
  8218. +         * if we get here, we know that the write
  8219. +         * is either aligned or the data already in the buffer
  8220. +         * (buffer will be overwritten) */
  8221. +#ifdef FLOPPY_SANITY_CHECK
  8222. +        if (sector_t != aligned_sector_t && buffer_track == -1 )
  8223. +            DPRINT("internal error offset !=0 on write\n");
  8224. +#endif
  8225. +        buffer_track = raw_cmd->track;
  8226. +        buffer_drive = current_drive;
  8227. +        copy_buffer(ssize, max_sector, 2*max_buffer_sectors+buffer_min);
  8228. +    } else
  8229. +        transfer_size(ssize, max_sector,
  8230. +                  2*max_buffer_sectors+buffer_min-aligned_sector_t);
  8231. +
  8232. +    /* round up current_count_sectors to get dma xfer size */
  8233. +    raw_cmd->length = sector_t+current_count_sectors-aligned_sector_t;
  8234. +    raw_cmd->length = ((raw_cmd->length -1)|(ssize-1))+1;
  8235. +    raw_cmd->length <<= 9;
  8236. +#ifdef FLOPPY_SANITY_CHECK
  8237. +    if ((raw_cmd->length < current_count_sectors << 9) ||
  8238. +        (raw_cmd->kernel_data != CURRENT->buffer &&
  8239. +         CT(COMMAND) == FD_WRITE &&
  8240. +         (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
  8241. +          aligned_sector_t < buffer_min )) ||
  8242. +        raw_cmd->length % ( 128 << SIZECODE ) ||
  8243. +        raw_cmd->length <= 0 || current_count_sectors <= 0){
  8244. +        DPRINT("fractionary current count b=%lx s=%lx\n",
  8245. +            raw_cmd->length, current_count_sectors);
  8246. +        if ( raw_cmd->kernel_data != CURRENT->buffer )
  8247. +            printk("addr=%d, length=%ld\n",
  8248. +                   (int) ((raw_cmd->kernel_data -
  8249. +                       floppy_track_buffer ) >> 9),
  8250. +                   current_count_sectors);
  8251. +        printk("st=%d ast=%d mse=%d msi=%d\n",
  8252. +               sector_t, aligned_sector_t, max_sector, max_size);
  8253. +        printk("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
  8254. +        printk("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
  8255. +               COMMAND, SECTOR, HEAD, TRACK);
  8256. +        printk("buffer drive=%d\n", buffer_drive);
  8257. +        printk("buffer track=%d\n", buffer_track);
  8258. +        printk("buffer_min=%d\n", buffer_min );
  8259. +        printk("buffer_max=%d\n", buffer_max );
  8260. +        return 0;
  8261. +    }
  8262. +
  8263. +    if (raw_cmd->kernel_data != CURRENT->buffer ){
  8264. +        if (raw_cmd->kernel_data < floppy_track_buffer ||
  8265. +            current_count_sectors < 0 ||
  8266. +            raw_cmd->length < 0 ||
  8267. +            raw_cmd->kernel_data + raw_cmd->length >
  8268. +            floppy_track_buffer + (max_buffer_sectors  << 10)){
  8269. +            DPRINT("buffer overrun in schedule dma\n");
  8270. +            printk("sector_t=%d buffer_min=%d current_count=%ld\n",
  8271. +                   sector_t, buffer_min,
  8272. +                   raw_cmd->length >> 9 );
  8273. +            printk("current_count_sectors=%ld\n",
  8274. +                   current_count_sectors);
  8275. +            if ( CT(COMMAND) == FD_READ )
  8276. +                printk("read\n");
  8277. +            if ( CT(COMMAND) == FD_READ )
  8278. +                printk("write\n");
  8279. +            return 0;
  8280. +        }
  8281. +    } else if (raw_cmd->length > CURRENT->nr_sectors << 9 ||
  8282. +           current_count_sectors > CURRENT->nr_sectors){
  8283. +        DPRINT("buffer overrun in direct transfer\n");
  8284. +        return 0;
  8285. +    } else if ( raw_cmd->length < current_count_sectors << 9 ){
  8286. +        DPRINT("more sectors than bytes\n");
  8287. +        printk("bytes=%ld\n", raw_cmd->length >> 9 );
  8288. +        printk("sectors=%ld\n", current_count_sectors);
  8289. +    }
  8290. +    if (raw_cmd->length == 0){
  8291. +        DPRINT("zero dma transfer attempted from make_raw_request\n");
  8292. +        return 0;
  8293. +    }
  8294. +#endif
  8295. +    return 2;
  8296. +}
  8297. +
  8298. +static void redo_fd_request(void)
  8299. +{
  8300. +#define REPEAT {request_done(0); continue; }
  8301. +    kdev_t device;
  8302. +    int tmp;
  8303. +
  8304. +    lastredo = jiffies;
  8305. +    if (current_drive < N_DRIVE)
  8306. +        floppy_off(current_drive);
  8307. +
  8308. +    if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){
  8309. +        CLEAR_INTR;
  8310. +        unlock_fdc();
  8311. +        return;
  8312. +    }
  8313. +
  8314. +    while(1){
  8315. +        if (!CURRENT) {
  8316. +            CLEAR_INTR;
  8317. +            unlock_fdc();
  8318. +            return;
  8319. +        }
  8320. +        if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
  8321. +            panic(DEVICE_NAME ": request list destroyed");
  8322. +        if (CURRENT->bh && !buffer_locked(CURRENT->bh))
  8323. +            panic(DEVICE_NAME ": block not locked");
  8324. +
  8325. +        device = CURRENT->rq_dev;
  8326. +        set_fdc( DRIVE(device));
  8327. +        reschedule_timeout(CURRENTD, "redo fd request", 0);
  8328. +
  8329. +        set_floppy(device);
  8330. +        raw_cmd = & default_raw_cmd;
  8331. +        raw_cmd->flags = 0;
  8332. +        if(start_motor(redo_fd_request)) return;
  8333. +        disk_change(current_drive);
  8334. +        if(test_bit(current_drive, &fake_change) ||
  8335. +           TESTF(FD_DISK_CHANGED)){
  8336. +            DPRINT("disk absent or changed during operation\n");
  8337. +            REPEAT;
  8338. +        }
  8339. +        if (!_floppy) { /* Autodetection */
  8340. +            if (!probing){
  8341. +                DRS->probed_format = 0;
  8342. +                if ( next_valid_format() ){
  8343. +                    DPRINT("no autodetectable formats\n");
  8344. +                    _floppy = NULL;
  8345. +                    REPEAT;
  8346. +                }
  8347. +            }
  8348. +            probing = 1;
  8349. +            _floppy = floppy_type+DP->autodetect[DRS->probed_format];
  8350. +        } else
  8351. +            probing = 0;
  8352. +        errors = & (CURRENT->errors);
  8353. +        tmp = make_raw_rw_request();
  8354. +        if ( tmp < 2 ){
  8355. +            request_done(tmp);
  8356. +            continue;
  8357. +        }
  8358. +
  8359. +        if (TESTF(FD_NEED_TWADDLE))
  8360. +            twaddle();
  8361. +        floppy_tq.routine = (void *)(void *) floppy_start;
  8362. +        queue_task(&floppy_tq, &tq_immediate);
  8363. +        mark_bh(IMMEDIATE_BH);
  8364. +#ifdef DEBUGT
  8365. +        debugt("queue fd request");
  8366. +#endif
  8367. +        return;
  8368. +    }
  8369. +#undef REPEAT
  8370. +}
  8371. +
  8372. +static struct cont_t rw_cont={
  8373. +    rw_interrupt,
  8374. +    redo_fd_request,
  8375. +    bad_flp_intr,
  8376. +    request_done };
  8377. +
  8378. +static struct tq_struct request_tq =
  8379. +{ 0, 0, (void *) (void *) redo_fd_request, 0 };
  8380. +
  8381. +static void process_fd_request(void)
  8382. +{
  8383. +    cont = &rw_cont;
  8384. +    queue_task(&request_tq, &tq_immediate);
  8385. +    mark_bh(IMMEDIATE_BH);
  8386. +}
  8387. +
  8388. +static void do_fd_request(void)
  8389. +{
  8390. +    sti();
  8391. +    if (fdc_busy){
  8392. +        /* fdc busy, this new request will be treated when the
  8393. +           current one is done */
  8394. +        is_alive("do fd request, old request running");
  8395. +        return;
  8396. +    }
  8397. +    lock_fdc(MAXTIMEOUT,0);
  8398. +    process_fd_request();
  8399. +    is_alive("do fd request");
  8400. +}
  8401. +
  8402. +static struct cont_t poll_cont={
  8403. +    success_and_wakeup,
  8404. +    floppy_ready,
  8405. +    generic_failure,
  8406. +    generic_done };
  8407. +
  8408. +static int poll_drive(int interruptible, int flag)
  8409. +{
  8410. +    int ret;
  8411. +    /* no auto-sense, just clear dcl */
  8412. +    raw_cmd = &default_raw_cmd;
  8413. +    raw_cmd->flags= flag;
  8414. +    raw_cmd->track=0;
  8415. +    raw_cmd->cmd_count=0;
  8416. +    cont = &poll_cont;
  8417. +#ifdef DCL_DEBUG
  8418. +    if (DP->flags & FD_DEBUG){
  8419. +        DPRINT("setting NEWCHANGE in poll_drive\n");
  8420. +    }
  8421. +#endif
  8422. +    SETF(FD_DISK_NEWCHANGE);
  8423. +    WAIT(floppy_ready);
  8424. +    return ret;
  8425. +}
  8426. +
  8427. +/*
  8428. + * User triggered reset
  8429. + * ====================
  8430. + */
  8431. +
  8432. +static void reset_intr(void)
  8433. +{
  8434. +    printk("weird, reset interrupt called\n");
  8435. +}
  8436. +
  8437. +static struct cont_t reset_cont={
  8438. +    reset_intr,
  8439. +    success_and_wakeup,
  8440. +    generic_failure,
  8441. +    generic_done };
  8442. +
  8443. +static int user_reset_fdc(int drive, int arg, int interruptible)
  8444. +{
  8445. +    int ret;
  8446. +
  8447. +    ret=0;
  8448. +    LOCK_FDC(drive,interruptible);
  8449. +    if(arg == FD_RESET_ALWAYS)
  8450. +        FDCS->reset=1;
  8451. +    if ( FDCS->reset ){
  8452. +        cont = &reset_cont;
  8453. +        WAIT(reset_fdc);
  8454. +    }
  8455. +    process_fd_request();
  8456. +    return ret;
  8457. +}
  8458. +
  8459. +/*
  8460. + * Misc Ioctl's and support
  8461. + * ========================
  8462. + */
  8463. +static int fd_copyout(void *param, const void *address, int size)
  8464. +{
  8465. +    int ret;
  8466. +
  8467. +    ECALL(verify_area(VERIFY_WRITE,param,size));
  8468. +    memcpy_tofs(param,(void *) address, size);
  8469. +    return 0;
  8470. +}
  8471. +
  8472. +static int fd_copyin(void *param, void *address, int size)
  8473. +{
  8474. +    int ret;
  8475. +
  8476. +    ECALL(verify_area(VERIFY_READ,param,size));
  8477. +    memcpy_fromfs((void *) address, param, size);
  8478. +    return 0;
  8479. +}
  8480. +
  8481. +#define COPYOUT(x) ECALL(fd_copyout( (void *)param, &(x), sizeof(x)))
  8482. +#define COPYIN(x) ECALL(fd_copyin( (void *)param, &(x), sizeof(x)))
  8483. +
  8484. +static inline const char *drive_name(int type, int drive)
  8485. +{
  8486. +    struct floppy_struct *floppy;
  8487. +
  8488. +    if ( type )
  8489. +        floppy = floppy_type + type;
  8490. +    else {
  8491. +        if ( UDP->native_format )
  8492. +            floppy = floppy_type + UDP->native_format;
  8493. +        else
  8494. +            return "(null)";
  8495. +    }
  8496. +    if ( floppy->name )
  8497. +        return floppy->name;
  8498. +    else
  8499. +        return "(null)";
  8500. +}
  8501. +
  8502. +
  8503. +/* raw commands */
  8504. +static void raw_cmd_done(int flag)
  8505. +{
  8506. +    int i;
  8507. +
  8508. +    if(!flag) {
  8509. +        raw_cmd->flags |= FD_RAW_FAILURE;
  8510. +        raw_cmd->flags |= FD_RAW_HARDFAILURE;
  8511. +    } else {
  8512. +        raw_cmd->reply_count = inr;
  8513. +        for( i=0; i< raw_cmd->reply_count; i++)
  8514. +            raw_cmd->reply[i] = reply_buffer[i];
  8515. +
  8516. +        if ( raw_cmd->flags & ( FD_RAW_READ | FD_RAW_WRITE ))
  8517. +            raw_cmd->length = fd_get_dma_residue();
  8518. +
  8519. +        if( (raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
  8520. +            (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
  8521. +            raw_cmd->flags |= FD_RAW_FAILURE;
  8522. +
  8523. +        if( disk_change(current_drive) )
  8524. +            raw_cmd->flags |= FD_RAW_DISK_CHANGE;
  8525. +        else
  8526. +            raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
  8527. +        if(raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
  8528. +            motor_off_callback(current_drive);
  8529. +
  8530. +        if(raw_cmd->next &&
  8531. +           (!(raw_cmd->flags & FD_RAW_FAILURE) ||
  8532. +            !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
  8533. +           ((raw_cmd->flags & FD_RAW_FAILURE) ||
  8534. +            !(raw_cmd->flags &FD_RAW_STOP_IF_SUCCESS))) {
  8535. +            raw_cmd = raw_cmd->next;
  8536. +            return;
  8537. +        }
  8538. +    }
  8539. +    generic_done(flag);
  8540. +}
  8541. +
  8542. +
  8543. +static struct cont_t raw_cmd_cont={
  8544. +    success_and_wakeup,
  8545. +    floppy_start,
  8546. +    generic_failure,
  8547. +    raw_cmd_done
  8548. +};
  8549. +
  8550. +static inline int raw_cmd_copyout(int cmd, char *param,
  8551. +                  struct floppy_raw_cmd *ptr)
  8552. +{
  8553. +    struct old_floppy_raw_cmd old_raw_cmd;
  8554. +    int ret;
  8555. +
  8556. +    while(ptr) {
  8557. +        if(cmd == OLDFDRAWCMD) {
  8558. +            old_raw_cmd.flags = ptr->flags;
  8559. +            old_raw_cmd.data = ptr->data;
  8560. +            old_raw_cmd.length = ptr->length;
  8561. +            old_raw_cmd.rate = ptr->rate;
  8562. +            old_raw_cmd.reply_count = ptr->reply_count;
  8563. +            memcpy(old_raw_cmd.reply, ptr->reply, 7);
  8564. +            COPYOUT(old_raw_cmd);
  8565. +            param += sizeof(old_raw_cmd);
  8566. +        } else {
  8567. +            COPYOUT(*ptr);
  8568. +            param += sizeof(struct floppy_raw_cmd);
  8569. +        }
  8570. +
  8571. +        if ( (ptr->flags & FD_RAW_READ) && ptr->buffer_length){
  8572. +            if(ptr->length>=0 && ptr->length<=ptr->buffer_length)
  8573. +                ECALL(fd_copyout(ptr->data,
  8574. +                         ptr->kernel_data,
  8575. +                         ptr->buffer_length -
  8576. +                         ptr->length));
  8577. +        }
  8578. +        ptr = ptr->next;
  8579. +    }
  8580. +    return 0;
  8581. +}
  8582. +
  8583. +
  8584. +static void raw_cmd_free(struct floppy_raw_cmd **ptr)
  8585. +{
  8586. +    struct floppy_raw_cmd *next,*this;
  8587. +
  8588. +    this = *ptr;
  8589. +    *ptr = 0;
  8590. +    while(this) {
  8591. +        if (this->buffer_length) {
  8592. +            fd_dma_mem_free((unsigned long)this->kernel_data,
  8593. +                    this->buffer_length);
  8594. +            this->buffer_length = 0;
  8595. +        }
  8596. +        next = this->next;
  8597. +        kfree(this);
  8598. +        this = next;
  8599. +    }
  8600. +}
  8601. +
  8602. +
  8603. +static inline int raw_cmd_copyin(int cmd, char *param,
  8604. +                 struct floppy_raw_cmd **rcmd)
  8605. +{
  8606. +    struct floppy_raw_cmd *ptr;
  8607. +    struct old_floppy_raw_cmd old_raw_cmd;
  8608. +    int ret;
  8609. +    int i;
  8610. +
  8611. +    *rcmd = 0;
  8612. +    while(1) {
  8613. +        ptr = (struct floppy_raw_cmd *)
  8614. +            kmalloc(sizeof (struct floppy_raw_cmd ), GFP_USER);
  8615. +        if (!ptr)
  8616. +            return -ENOMEM;
  8617. +        *rcmd = ptr;
  8618. +        if(cmd == OLDFDRAWCMD){
  8619. +            COPYIN(old_raw_cmd);
  8620. +            ptr->flags = old_raw_cmd.flags;
  8621. +            ptr->data = old_raw_cmd.data;
  8622. +            ptr->length = old_raw_cmd.length;
  8623. +            ptr->rate = old_raw_cmd.rate;
  8624. +            ptr->cmd_count = old_raw_cmd.cmd_count;
  8625. +            ptr->track = old_raw_cmd.track;
  8626. +            ptr->phys_length = 0;
  8627. +            ptr->next = 0;
  8628. +            ptr->buffer_length = 0;
  8629. +            memcpy(ptr->cmd, old_raw_cmd.cmd, 9);
  8630. +            param += sizeof(struct old_floppy_raw_cmd);
  8631. +            if(ptr->cmd_count > 9)
  8632. +                return -EINVAL;
  8633. +        } else {
  8634. +            COPYIN(*ptr);
  8635. +            ptr->next = 0;
  8636. +            ptr->buffer_length = 0;
  8637. +            param += sizeof(struct floppy_raw_cmd);
  8638. +            if (ptr->cmd_count > 33)
  8639. +                /* the command may now also take up the space
  8640. +                 * initially intended for the reply & the
  8641. +                 * reply count. Needed for long 82078 commands
  8642. +                 * such as RESTORE, which takes ... 17 command
  8643. +                 * bytes. Murphy's law #137: When you reserve
  8644. +                 * 16 bytes for a structure, you'll one day
  8645. +                 * discover that you really need 17...
  8646. +                 */
  8647. +                return -EINVAL;
  8648. +        }
  8649. +
  8650. +        for(i=0; i< 16; i++)
  8651. +            ptr->reply[i] = 0;
  8652. +        ptr->resultcode = 0;
  8653. +        ptr->kernel_data = 0;
  8654. +
  8655. +        if(ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
  8656. +            if (ptr->length <= 0)
  8657. +                return -EINVAL;
  8658. +            ptr->kernel_data =(char*)fd_dma_mem_alloc(ptr->length);
  8659. +            if(!ptr->kernel_data)
  8660. +                return -ENOMEM;
  8661. +            ptr->buffer_length = ptr->length;
  8662. +        }
  8663. +        if ( ptr->flags & FD_RAW_READ )
  8664. +            ECALL( verify_area( VERIFY_WRITE, ptr->data,
  8665. +                        ptr->length ));
  8666. +        if(ptr->flags & FD_RAW_WRITE)
  8667. +            ECALL(fd_copyin(ptr->data, ptr->kernel_data,
  8668. +                    ptr->length));
  8669. +        rcmd = & (ptr->next);
  8670. +        if( ! (ptr->flags & FD_RAW_MORE))
  8671. +            return 0;
  8672. +        ptr->rate &= 0x43;
  8673. +    }
  8674. +}
  8675. +
  8676. +
  8677. +static int raw_cmd_ioctl(int cmd, void *param)
  8678. +{
  8679. +    int drive, ret, ret2;
  8680. +    struct floppy_raw_cmd *my_raw_cmd;
  8681. +
  8682. +    if ( FDCS->rawcmd <= 1 )
  8683. +        FDCS->rawcmd = 1;
  8684. +    for ( drive= 0; drive < N_DRIVE; drive++){
  8685. +        if ( FDC(drive) != fdc)
  8686. +            continue;
  8687. +        if ( drive == current_drive ){
  8688. +            if ( UDRS->fd_ref > 1 ){
  8689. +                FDCS->rawcmd = 2;
  8690. +                break;
  8691. +            }
  8692. +        } else if ( UDRS->fd_ref ){
  8693. +            FDCS->rawcmd = 2;
  8694. +            break;
  8695. +        }
  8696. +    }
  8697. +
  8698. +    if(FDCS->reset)
  8699. +        return -EIO;
  8700. +
  8701. +    ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
  8702. +    if (ret) {
  8703. +        raw_cmd_free(&my_raw_cmd);
  8704. +        return ret;
  8705. +    }
  8706. +    
  8707. +    raw_cmd = my_raw_cmd;
  8708. +    cont = &raw_cmd_cont;
  8709. +    ret=wait_til_done(floppy_start,1);
  8710. +#ifdef DCL_DEBUG
  8711. +    if (DP->flags & FD_DEBUG){
  8712. +        DPRINT("calling disk change from raw_cmd ioctl\n");
  8713. +    }
  8714. +#endif
  8715. +
  8716. +    if (ret != -EINTR && FDCS->reset)
  8717. +        ret = -EIO;
  8718. +
  8719. +    DRS->track = NO_TRACK;
  8720. +
  8721. +    ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
  8722. +    if(!ret)
  8723. +        ret = ret2;
  8724. +    raw_cmd_free(&my_raw_cmd);
  8725. +    return ret;
  8726. +}
  8727. +
  8728. +static int invalidate_drive(kdev_t rdev)
  8729. +{
  8730. +    /* invalidate the buffer track to force a reread */
  8731. +    set_bit( DRIVE(rdev), &fake_change);
  8732. +    process_fd_request();
  8733. +    check_disk_change(rdev);
  8734. +    return 0;
  8735. +}
  8736. +
  8737. +
  8738. +static inline void clear_write_error(int drive)
  8739. +{
  8740. +    CLEARSTRUCT(UDRWE);
  8741. +}
  8742. +
  8743. +static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
  8744. +                int drive, int type, kdev_t device)
  8745. +{
  8746. +    int cnt;
  8747. +
  8748. +    /* sanity checking for parameters.*/
  8749. +    if (g->sect <= 0 ||
  8750. +        g->head <= 0 ||
  8751. +        g->track <= 0 ||
  8752. +        g->track > UDP->tracks>>STRETCH(g) ||
  8753. +        /* check if reserved bits are set */
  8754. +        (g->stretch&~(FD_STRETCH|FD_SWAPSIDES)) != 0)
  8755. +        return -EINVAL;
  8756. +    if (type) {
  8757. +        if (!suser())
  8758. +            return -EPERM;
  8759. +        LOCK_FDC(drive,1);
  8760. +        for (cnt = 0; cnt < N_DRIVE; cnt++){
  8761. +            if (ITYPE(drive_state[cnt].fd_device) == type &&
  8762. +                drive_state[cnt].fd_ref)
  8763. +                set_bit(drive, &fake_change);
  8764. +        }
  8765. +        floppy_type[type] = *g;
  8766. +        floppy_type[type].name="user format";
  8767. +        for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
  8768. +        floppy_sizes[cnt]= floppy_sizes[cnt+0x80]=
  8769. +                   floppy_type[type].size>>1;
  8770. +        process_fd_request();
  8771. +        for ( cnt = 0; cnt < N_DRIVE; cnt++){
  8772. +            if (ITYPE(drive_state[cnt].fd_device) == type &&
  8773. +                drive_state[cnt].fd_ref)
  8774. +                check_disk_change(
  8775. +                    MKDEV(FLOPPY_MAJOR,
  8776. +                          drive_state[cnt].fd_device));
  8777. +        }
  8778. +    } else {
  8779. +        LOCK_FDC(drive,1);
  8780. +        if ( cmd != FDDEFPRM )
  8781. +            /* notice a disk change immediately, else
  8782. +             * we loose our settings immediately*/
  8783. +            CALL(poll_drive(1, FD_RAW_NEED_DISK));
  8784. +            user_params[drive] = *g;
  8785. +            if (buffer_drive == drive)
  8786. +                SUPBOUND(buffer_max, user_params[drive].sect);
  8787. +            current_type[drive] = &user_params[drive];
  8788. +            floppy_sizes[drive] = user_params[drive].size >> 1;
  8789. +            if (cmd == FDDEFPRM)
  8790. +                DRS->keep_data = -1;
  8791. +            else
  8792. +                DRS->keep_data = 1;
  8793. +            /* invalidation. Invalidate only when needed, i.e.
  8794. +             * when there are already sectors in the buffer cache
  8795. +             * whose number will change. This is useful, because
  8796. +             * mtools often changes the geometry of the disk after
  8797. +             * looking at the boot block */
  8798. +            if (DRS->maxblock > user_params[drive].sect || DRS->maxtrack)
  8799. +                invalidate_drive(device);
  8800. +            else
  8801. +                process_fd_request();
  8802. +    }
  8803. +    return 0;
  8804. +}            
  8805. +            
  8806. +/* handle obsolete ioctl's */
  8807. +static struct translation_entry {
  8808. +    int newcmd;
  8809. +    int oldcmd;
  8810. +    int oldsize; /* size of 0x00xx-style ioctl. Reflects old structures, thus
  8811. +              * use numeric values. NO SIZEOFS */
  8812. +} translation_table[]= {
  8813. +    {FDCLRPRM,          0,  0},
  8814. +    {FDSETPRM,          1, 28},
  8815. +    {FDDEFPRM,          2, 28},
  8816. +    {FDGETPRM,          3, 28},
  8817. +    {FDMSGON,           4,  0},
  8818. +    {FDMSGOFF,          5,  0},
  8819. +    {FDFMTBEG,          6,  0},
  8820. +    {FDFMTTRK,          7, 12},
  8821. +    {FDFMTEND,          8,  0},
  8822. +    {FDSETEMSGTRESH,   10,  0},
  8823. +    {FDFLUSH,          11,  0},
  8824. +    {FDSETMAXERRS,     12, 20},
  8825. +    {OLDFDRAWCMD,      30,  0},
  8826. +    {FDGETMAXERRS,     14, 20},
  8827. +    {FDGETDRVTYP,      16, 16},
  8828. +    {FDSETDRVPRM,      20, 88},
  8829. +    {FDGETDRVPRM,      21, 88},
  8830. +    {FDGETDRVSTAT,     22, 52},
  8831. +    {FDPOLLDRVSTAT,    23, 52},
  8832. +    {FDRESET,          24,  0},
  8833. +    {FDGETFDCSTAT,     25, 40},
  8834. +    {FDWERRORCLR,      27,  0},
  8835. +    {FDWERRORGET,      28, 24},
  8836. +    {FDRAWCMD,          0,  0},
  8837. +    {FDEJECT,           0,  0},
  8838. +    {FDTWADDLE,        40,  0} };
  8839. +
  8840. +static inline int normalize_0x02xx_ioctl(int *cmd, int *size)
  8841. +{
  8842. +    int i;
  8843. +
  8844. +    for (i=0; i < ARRAY_SIZE(translation_table); i++) {
  8845. +        if ((*cmd & 0xffff) == (translation_table[i].newcmd & 0xffff)){
  8846. +            *size = _IOC_SIZE(*cmd);
  8847. +            *cmd = translation_table[i].newcmd;
  8848. +            if (*size > _IOC_SIZE(*cmd)) {
  8849. +                printk("ioctl not yet supported\n");
  8850. +                return -EFAULT;
  8851. +            }
  8852. +            return 0;
  8853. +        }
  8854. +    }
  8855. +    return -EINVAL;
  8856. +}
  8857. +
  8858. +static inline int xlate_0x00xx_ioctl(int *cmd, int *size)
  8859. +{
  8860. +    int i;
  8861. +    /* old ioctls' for kernels <= 1.3.33 */
  8862. +    /* When the next even release will come around, we'll start
  8863. +     * warning against these.
  8864. +     * When the next odd release will come around, we'll fail with
  8865. +     * -EINVAL */
  8866. +    if(strcmp(system_utsname.version, "1.4.0") >= 0)
  8867. +        printk("obsolete floppy ioctl %x\n", *cmd);
  8868. +    if((system_utsname.version[0] == '1' &&
  8869. +        strcmp(system_utsname.version, "1.5.0") >= 0) ||
  8870. +       (system_utsname.version[0] >= '2' &&
  8871. +        strcmp(system_utsname.version, "2.1.0") >= 0))
  8872. +        return -EINVAL;
  8873. +    for (i=0; i < ARRAY_SIZE(translation_table); i++) {
  8874. +        if (*cmd == translation_table[i].oldcmd) {
  8875. +            *size = translation_table[i].oldsize;
  8876. +            *cmd = translation_table[i].newcmd;
  8877. +            return 0;
  8878. +        }
  8879. +    }
  8880. +    return -EINVAL;
  8881. +}
  8882. +
  8883. +static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
  8884. +            unsigned long param)
  8885. +{
  8886. +#define IOCTL_MODE_BIT 8
  8887. +#define OPEN_WRITE_BIT 16
  8888. +#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
  8889. +#define OUT(c,x) case c: outparam = (const char *) (x); break
  8890. +#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
  8891. +
  8892. +    int i,drive,type;
  8893. +    kdev_t device;
  8894. +    int ret;
  8895. +    int size;
  8896. +    union inparam {
  8897. +        struct floppy_struct g; /* geometry */
  8898. +        struct format_descr f;
  8899. +        struct floppy_max_errors max_errors;
  8900. +        struct floppy_drive_params dp;
  8901. +    } inparam; /* parameters coming from user space */
  8902. +    const char *outparam; /* parameters passed back to user space */
  8903. +
  8904. +    device = inode->i_rdev;
  8905. +    switch (cmd) {
  8906. +        RO_IOCTLS(device,param);
  8907. +    }
  8908. +    type = TYPE(device);
  8909. +    drive = DRIVE(device);
  8910. +
  8911. +    /* convert compatibility eject ioctls into floppy eject ioctl.
  8912. +     * We do this in order to provide a means to eject floppy disks before
  8913. +     * installing the new fdutils package */
  8914. +    if(cmd == CDROMEJECT || /* CD-ROM eject */
  8915. +       cmd == 0x6470 /* SunOS floppy eject */) {
  8916. +           DPRINT("obsolete eject ioctl\n");
  8917. +           DPRINT("please use floppycontrol --eject\n");
  8918. +           cmd = FDEJECT;
  8919. +    }
  8920. +
  8921. +    /* convert the old style command into a new style command */
  8922. +    if ((cmd & 0xff00) == 0x0200) {
  8923. +        ECALL(normalize_0x02xx_ioctl(&cmd, &size));
  8924. +    } else if ((cmd & 0xff00) == 0x0000) {
  8925. +        ECALL(xlate_0x00xx_ioctl(&cmd, &size));
  8926. +    } else
  8927. +        return -EINVAL;
  8928. +
  8929. +    /* permission checks */
  8930. +    if (((cmd & 0x80) && !suser()) ||
  8931. +         ((cmd & 0x40) && !IOCTL_ALLOWED))
  8932. +        return -EPERM;
  8933. +
  8934. +    /* verify writability of result, and fail early */
  8935. +    if (_IOC_DIR(cmd) & _IOC_READ)
  8936. +        ECALL(verify_area(VERIFY_WRITE,(void *) param, size));
  8937. +
  8938. +    /* copyin */
  8939. +    CLEARSTRUCT(&inparam);
  8940. +    if (_IOC_DIR(cmd) & _IOC_WRITE)
  8941. +        ECALL(fd_copyin((void *)param, &inparam, size))
  8942. +
  8943. +    switch (cmd) {
  8944. +        case FDEJECT:
  8945. +            if (UDRS->fd_ref != 1)
  8946. +                /* somebody else has this drive open */
  8947. +                return -EBUSY;
  8948. +            LOCK_FDC(drive,1);
  8949. +
  8950. +            /* do the actual eject. Fails on
  8951. +             * non-Sparc architectures */
  8952. +            ret=fd_eject(UNIT(drive));
  8953. +
  8954. +            USETF(FD_DISK_CHANGED);
  8955. +            USETF(FD_VERIFY);
  8956. +            process_fd_request();
  8957. +            return ret;
  8958. +        case FDCLRPRM:
  8959. +            LOCK_FDC(drive,1);
  8960. +            current_type[drive] = NULL;
  8961. +            floppy_sizes[drive] = MAX_DISK_SIZE;
  8962. +            UDRS->keep_data = 0;
  8963. +            return invalidate_drive(device);
  8964. +        case FDSETPRM:
  8965. +        case FDDEFPRM:
  8966. +            return set_geometry(cmd, & inparam.g,
  8967. +                        drive, type, device);
  8968. +        case FDGETPRM:
  8969. +            LOCK_FDC(drive,1);
  8970. +            CALL(poll_drive(1,0));
  8971. +            process_fd_request();
  8972. +            if (type)
  8973. +                outparam = (char *) &floppy_type[type];
  8974. +            else
  8975. +                outparam = (char *) current_type[drive];
  8976. +            if(!outparam)
  8977. +                return -ENODEV;
  8978. +            break;
  8979. +
  8980. +        case FDMSGON:
  8981. +            UDP->flags |= FTD_MSG;
  8982. +            return 0;
  8983. +        case FDMSGOFF:
  8984. +            UDP->flags &= ~FTD_MSG;
  8985. +            return 0;
  8986. +
  8987. +        case FDFMTBEG:
  8988. +            LOCK_FDC(drive,1);
  8989. +            CALL(poll_drive(1, FD_RAW_NEED_DISK));
  8990. +            ret = UDRS->flags;
  8991. +            process_fd_request();
  8992. +            if(ret & FD_VERIFY)
  8993. +                return -ENODEV;
  8994. +            if(!(ret & FD_DISK_WRITABLE))
  8995. +                return -EROFS;
  8996. +            return 0;
  8997. +        case FDFMTTRK:
  8998. +            if (UDRS->fd_ref != 1)
  8999. +                return -EBUSY;
  9000. +            return do_format(device, &inparam.f);
  9001. +        case FDFMTEND:
  9002. +        case FDFLUSH:
  9003. +            LOCK_FDC(drive,1);
  9004. +            return invalidate_drive(device);
  9005. +
  9006. +        case FDSETEMSGTRESH:
  9007. +            UDP->max_errors.reporting =
  9008. +            (unsigned short) (param & 0x0f);
  9009. +            return 0;
  9010. +        OUT(FDGETMAXERRS, &UDP->max_errors);
  9011. +        IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
  9012. +
  9013. +        case FDGETDRVTYP:
  9014. +            outparam = drive_name(type,drive);
  9015. +            SUPBOUND(size,strlen(outparam)+1);
  9016. +            break;
  9017. +
  9018. +        IN(FDSETDRVPRM, UDP, dp);
  9019. +        OUT(FDGETDRVPRM, UDP);
  9020. +
  9021. +        case FDPOLLDRVSTAT:
  9022. +            LOCK_FDC(drive,1);
  9023. +            CALL(poll_drive(1, FD_RAW_NEED_DISK));
  9024. +            process_fd_request();
  9025. +            /* fall through */
  9026. +        OUT(FDGETDRVSTAT, UDRS);
  9027. +
  9028. +        case FDRESET:
  9029. +            return user_reset_fdc(drive, (int)param, 1);
  9030. +
  9031. +        OUT(FDGETFDCSTAT,UFDCS);
  9032. +
  9033. +        case FDWERRORCLR:
  9034. +            CLEARSTRUCT(UDRWE);
  9035. +            return 0;
  9036. +        OUT(FDWERRORGET,UDRWE);
  9037. +
  9038. +        case OLDFDRAWCMD:
  9039. +        case FDRAWCMD:
  9040. +            if (type)
  9041. +                return -EINVAL;
  9042. +            LOCK_FDC(drive,1);
  9043. +            set_floppy(device);
  9044. +            CALL(i = raw_cmd_ioctl(cmd,(void *) param));
  9045. +            process_fd_request();
  9046. +            return i;
  9047. +        
  9048. +        case FDTWADDLE:
  9049. +            LOCK_FDC(drive,1);
  9050. +            twaddle();
  9051. +            process_fd_request();
  9052. +            return 0;
  9053. +
  9054. +        default:
  9055. +            return -EINVAL;
  9056. +    }
  9057. +
  9058. +    if (_IOC_DIR(cmd) & _IOC_READ)
  9059. +        return fd_copyout((void *)param, outparam, size);
  9060. +    else
  9061. +        return 0;
  9062. +#undef IOCTL_ALLOWED
  9063. +#undef OUT
  9064. +#undef IN
  9065. +}
  9066. +
  9067. +static void config_types(void)
  9068. +{
  9069. +    int first=1;
  9070. +    int drive;
  9071. +
  9072. +    /* read drive info out of physical CMOS */
  9073. +    drive=0;
  9074. +    if (!UDP->cmos )
  9075. +        UDP->cmos= FLOPPY0_TYPE;
  9076. +    drive=1;
  9077. +    if (!UDP->cmos && FLOPPY1_TYPE)
  9078. +        UDP->cmos = FLOPPY1_TYPE;
  9079. +
  9080. +    /* XXX */
  9081. +    /* additional physical CMOS drive detection should go here */
  9082. +
  9083. +    for (drive=0; drive < N_DRIVE; drive++){
  9084. +        if (UDP->cmos >= 16)
  9085. +            UDP->cmos = 0;
  9086. +        if (UDP->cmos >= 0 && UDP->cmos <= NUMBER(default_drive_params))
  9087. +            memcpy((char *) UDP,
  9088. +                   (char *) (&default_drive_params[(int)UDP->cmos].params),
  9089. +                   sizeof(struct floppy_drive_params));
  9090. +        if (UDP->cmos){
  9091. +            if (first)
  9092. +                printk(KERN_INFO "Floppy drive(s): ");
  9093. +            else
  9094. +                printk(", ");
  9095. +            first=0;
  9096. +            if (UDP->cmos > 0 ){
  9097. +                allowed_drive_mask |= 1 << drive;
  9098. +                printk("fd%d is %s", drive,
  9099. +                    default_drive_params[(int)UDP->cmos].name);
  9100. +            } else
  9101. +                printk("fd%d is unknown type %d",drive,
  9102. +                       (unsigned int)UDP->cmos);
  9103. +        }
  9104. +    }
  9105. +    if(!first)
  9106. +        printk("\n");
  9107. +}
  9108. +
  9109. +static int floppy_read(struct inode * inode, struct file * filp,
  9110. +               char * buf, int count)
  9111. +{
  9112. +    int drive = DRIVE(inode->i_rdev);
  9113. +
  9114. +    check_disk_change(inode->i_rdev);
  9115. +    if (UTESTF(FD_DISK_CHANGED))
  9116. +        return -ENXIO;
  9117. +    return block_read(inode, filp, buf, count);
  9118. +}
  9119. +
  9120. +static int floppy_write(struct inode * inode, struct file * filp,
  9121. +                const char * buf, int count)
  9122. +{
  9123. +    int block;
  9124. +    int ret;
  9125. +    int drive = DRIVE(inode->i_rdev);
  9126. +
  9127. +    if (!UDRS->maxblock)
  9128. +        UDRS->maxblock=1;/* make change detectable */
  9129. +    check_disk_change(inode->i_rdev);
  9130. +    if (UTESTF(FD_DISK_CHANGED))
  9131. +        return -ENXIO;
  9132. +    if (!UTESTF(FD_DISK_WRITABLE))
  9133. +        return -EROFS;
  9134. +    block = (filp->f_pos + count) >> 9;
  9135. +    INFBOUND(UDRS->maxblock, block);
  9136. +    ret= block_write(inode, filp, buf, count);
  9137. +    return ret;
  9138. +}
  9139. +
  9140. +static void floppy_release(struct inode * inode, struct file * filp)
  9141. +{
  9142. +    int drive;
  9143. +
  9144. +    drive = DRIVE(inode->i_rdev);
  9145. +
  9146. +    if( !filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
  9147. +        /* if the file is mounted OR (writable now AND writable at
  9148. +         * open time) Linus: Does this cover all cases? */
  9149. +        block_fsync(inode,filp);
  9150. +
  9151. +    if (UDRS->fd_ref < 0)
  9152. +        UDRS->fd_ref=0;
  9153. +    else if (!UDRS->fd_ref--) {
  9154. +        DPRINT("floppy_release with fd_ref == 0");
  9155. +        UDRS->fd_ref = 0;
  9156. +    }
  9157. +    floppy_release_irq_and_dma();
  9158. +}
  9159. +
  9160. +/*
  9161. + * floppy_open check for aliasing (/dev/fd0 can be the same as
  9162. + * /dev/PS0 etc), and disallows simultaneous access to the same
  9163. + * drive with different device numbers.
  9164. + */
  9165. +#define RETERR(x) do{floppy_release(inode,filp); return -(x);}while(0)
  9166. +
  9167. +static int floppy_open(struct inode * inode, struct file * filp)
  9168. +{
  9169. +    int drive;
  9170. +    int old_dev;
  9171. +    int try;
  9172. +    char *tmp;
  9173. +
  9174. +    if (!filp) {
  9175. +        DPRINT("Weird, open called with filp=0\n");
  9176. +        return -EIO;
  9177. +    }
  9178. +
  9179. +    drive = DRIVE(inode->i_rdev);
  9180. +    if (drive >= N_DRIVE ||
  9181. +        !( allowed_drive_mask & ( 1 << drive)) ||
  9182. +        fdc_state[FDC(drive)].version == FDC_NONE)
  9183. +        return -ENXIO;
  9184. +
  9185. +    if (TYPE(inode->i_rdev) >= NUMBER(floppy_type))
  9186. +        return -ENXIO;
  9187. +    old_dev = UDRS->fd_device;
  9188. +    if (UDRS->fd_ref && old_dev != MINOR(inode->i_rdev))
  9189. +        return -EBUSY;
  9190. +
  9191. +    if(!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){
  9192. +        USETF(FD_DISK_CHANGED);
  9193. +        USETF(FD_VERIFY);
  9194. +    }
  9195. +
  9196. +    if(UDRS->fd_ref == -1 ||
  9197. +       (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
  9198. +        return -EBUSY;
  9199. +
  9200. +    if (floppy_grab_irq_and_dma())
  9201. +        return -EBUSY;
  9202. +
  9203. +    if (filp->f_flags & O_EXCL)
  9204. +        UDRS->fd_ref = -1;
  9205. +    else
  9206. +        UDRS->fd_ref++;
  9207. +
  9208. +    if (!floppy_track_buffer){
  9209. +        /* if opening an ED drive, reserve a big buffer,
  9210. +         * else reserve a small one */
  9211. +        if ((UDP->cmos == 6) || (UDP->cmos == 5))
  9212. +            try = 64; /* Only 48 actually useful */
  9213. +        else
  9214. +            try = 32; /* Only 24 actually useful */
  9215. +
  9216. +        tmp=(char *)fd_dma_mem_alloc(1024 * try);
  9217. +        if (!tmp) {
  9218. +            try >>= 1; /* buffer only one side */
  9219. +            INFBOUND(try, 16);
  9220. +            tmp= (char *)fd_dma_mem_alloc(1024*try);
  9221. +        }
  9222. +        if (!tmp) {
  9223. +            DPRINT("Unable to allocate DMA memory\n");
  9224. +            RETERR(ENXIO);
  9225. +        }
  9226. +        if (floppy_track_buffer)
  9227. +            fd_dma_mem_free((unsigned long)tmp,try*1024);
  9228. +        else {
  9229. +            buffer_min = buffer_max = -1;
  9230. +            floppy_track_buffer = tmp;
  9231. +            max_buffer_sectors = try;
  9232. +        }
  9233. +    }
  9234. +
  9235. +    UDRS->fd_device = MINOR(inode->i_rdev);
  9236. +    if (old_dev != -1 && old_dev != MINOR(inode->i_rdev)) {
  9237. +        if (buffer_drive == drive)
  9238. +            buffer_track = -1;
  9239. +        invalidate_buffers(MKDEV(FLOPPY_MAJOR,old_dev));
  9240. +    }
  9241. +
  9242. +    /* Allow ioctls if we have write-permissions even if read-only open */
  9243. +    if ((filp->f_mode & 2) || (permission(inode,2) == 0))
  9244. +        filp->f_mode |= IOCTL_MODE_BIT;
  9245. +    if (filp->f_mode & 2)
  9246. +        filp->f_mode |= OPEN_WRITE_BIT;
  9247. +
  9248. +    if (UFDCS->rawcmd == 1)
  9249. +           UFDCS->rawcmd = 2;
  9250. +
  9251. +    if (filp->f_flags & O_NDELAY)
  9252. +        return 0;
  9253. +    if (filp->f_mode & 3) {
  9254. +        UDRS->last_checked = 0;
  9255. +        check_disk_change(inode->i_rdev);
  9256. +        if (UTESTF(FD_DISK_CHANGED))
  9257. +            RETERR(ENXIO);
  9258. +    }
  9259. +    if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE)))
  9260. +        RETERR(EROFS);
  9261. +    return 0;
  9262. +#undef RETERR
  9263. +}
  9264. +
  9265. +/*
  9266. + * Check if the disk has been changed or if a change has been faked.
  9267. + */
  9268. +static int check_floppy_change(kdev_t dev)
  9269. +{
  9270. +    int drive = DRIVE( dev );
  9271. +
  9272. +    if (MAJOR(dev) != MAJOR_NR) {
  9273. +        DPRINT("check_floppy_change: not a floppy\n");
  9274. +        return 0;
  9275. +    }
  9276. +
  9277. +    if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
  9278. +        return 1;
  9279. +
  9280. +    if (UDP->checkfreq < jiffies - UDRS->last_checked){
  9281. +        lock_fdc(drive,0);
  9282. +        poll_drive(0,0);
  9283. +        process_fd_request();
  9284. +    }
  9285. +
  9286. +    if(UTESTF(FD_DISK_CHANGED) ||
  9287. +       UTESTF(FD_VERIFY) ||
  9288. +       test_bit(drive, &fake_change) ||
  9289. +       (!TYPE(dev) && !current_type[drive]))
  9290. +        return 1;
  9291. +    return 0;
  9292. +}
  9293. +
  9294. +/* revalidate the floppy disk, i.e. trigger format autodetection by reading
  9295. + * the bootblock (block 0). "Autodetection" is also needed to check whether
  9296. + * there is a disk in the drive at all... Thus we also do it for fixed
  9297. + * geometry formats */
  9298. +static int floppy_revalidate(kdev_t dev)
  9299. +{
  9300. +#define NO_GEOM (!current_type[drive] && !TYPE(dev))
  9301. +    struct buffer_head * bh;
  9302. +    int drive=DRIVE(dev);
  9303. +    int cf;
  9304. +
  9305. +    if(UTESTF(FD_DISK_CHANGED) ||
  9306. +       UTESTF(FD_VERIFY) ||
  9307. +       test_bit(drive, &fake_change) ||
  9308. +       NO_GEOM){
  9309. +        lock_fdc(drive,0);
  9310. +        cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
  9311. +        if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)){
  9312. +            process_fd_request(); /* already done by another thread */
  9313. +            return 0;
  9314. +        }
  9315. +        UDRS->maxblock = 0;
  9316. +        UDRS->maxtrack = 0;
  9317. +        if (buffer_drive == drive)
  9318. +            buffer_track = -1;
  9319. +        clear_bit(drive, &fake_change);
  9320. +        UCLEARF(FD_DISK_CHANGED);
  9321. +        if (cf)
  9322. +            UDRS->generation++;
  9323. +        if (NO_GEOM){
  9324. +            /* auto-sensing */
  9325. +            int size = floppy_blocksizes[MINOR(dev)];
  9326. +            if (!size)
  9327. +                size = 1024;
  9328. +            if (!(bh = getblk(dev,0,size))){
  9329. +                process_fd_request();
  9330. +                return 1;
  9331. +            }
  9332. +            if ( bh && !buffer_uptodate(bh))
  9333. +                ll_rw_block(READ, 1, &bh);
  9334. +            process_fd_request();
  9335. +            wait_on_buffer(bh);
  9336. +            brelse(bh);
  9337. +            return 0;
  9338. +        }
  9339. +        if (cf)
  9340. +            poll_drive(0, FD_RAW_NEED_DISK);
  9341. +        process_fd_request();
  9342. +    }
  9343. +    return 0;
  9344. +}
  9345. +
  9346. +static struct file_operations floppy_fops = {
  9347. +    NULL,            /* lseek - default */
  9348. +    floppy_read,        /* read - general block-dev read */
  9349. +    floppy_write,        /* write - general block-dev write */
  9350. +    NULL,                   /* readdir - bad */
  9351. +    NULL,            /* select */
  9352. +    fd_ioctl,        /* ioctl */
  9353. +    NULL,            /* mmap */
  9354. +    floppy_open,        /* open */
  9355. +    floppy_release,        /* release */
  9356. +    block_fsync,        /* fsync */
  9357. +    NULL,            /* fasync */
  9358. +    check_floppy_change,    /* media_change */
  9359. +    floppy_revalidate,    /* revalidate */
  9360. +};
  9361. +
  9362. +/*
  9363. + * Floppy Driver initialization
  9364. + * =============================
  9365. + */
  9366. +
  9367. +/* Determine the floppy disk controller type */
  9368. +/* This routine was written by David C. Niemi */
  9369. +static char get_fdc_version(void)
  9370. +{
  9371. +    int r;
  9372. +
  9373. +    output_byte(FD_DUMPREGS);    /* 82072 and better know DUMPREGS */
  9374. +    if (FDCS->reset)
  9375. +        return FDC_NONE;
  9376. +    if ((r = result()) <= 0x00)
  9377. +        return FDC_NONE;    /* No FDC present ??? */
  9378. +    if ((r==1) && (reply_buffer[0] == 0x80)){
  9379. +        printk(KERN_INFO "FDC %d is an 8272A\n",fdc);
  9380. +        return FDC_8272A;    /* 8272a/765 don't know DUMPREGS */
  9381. +    }
  9382. +    if (r != 10) {
  9383. +        printk("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
  9384. +               fdc, r);
  9385. +        return FDC_UNKNOWN;
  9386. +    }
  9387. +
  9388. +    if(!fdc_configure()) {
  9389. +        printk(KERN_INFO "FDC %d is an 82072\n",fdc);
  9390. +        return FDC_82072;       /* 82072 doesn't know CONFIGURE */
  9391. +    }
  9392. +
  9393. +    output_byte(FD_PERPENDICULAR);
  9394. +    if(need_more_output() == MORE_OUTPUT) {
  9395. +        output_byte(0);
  9396. +    } else {
  9397. +        printk(KERN_INFO "FDC %d is an 82072A\n", fdc);
  9398. +        return FDC_82072A;    /* 82072A as found on Sparcs. */
  9399. +    }
  9400. +
  9401. +    output_byte(FD_UNLOCK);
  9402. +    r = result();
  9403. +    if ((r == 1) && (reply_buffer[0] == 0x80)){
  9404. +        printk(KERN_INFO "FDC %d is a pre-1991 82077\n", fdc);
  9405. +        return FDC_82077_ORIG;    /* Pre-1991 82077, doesn't know
  9406. +                     * LOCK/UNLOCK */
  9407. +    }
  9408. +    if ((r != 1) || (reply_buffer[0] != 0x00)) {
  9409. +        printk("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
  9410. +               fdc, r);
  9411. +        return FDC_UNKNOWN;
  9412. +    }
  9413. +    output_byte(FD_PARTID);
  9414. +    r = result();
  9415. +    if (r != 1) {
  9416. +        printk("FDC %d init: PARTID: unexpected return of %d bytes.\n",
  9417. +               fdc, r);
  9418. +        return FDC_UNKNOWN;
  9419. +    }
  9420. +    if (reply_buffer[0] == 0x80) {
  9421. +        printk(KERN_INFO "FDC %d is a post-1991 82077\n",fdc);
  9422. +        return FDC_82077;    /* Revised 82077AA passes all the tests */
  9423. +    }
  9424. +    switch (reply_buffer[0] >> 5) {
  9425. +        case 0x0:
  9426. +            /* Either a 82078-1 or a 82078SL running at 5Volt */
  9427. +            printk(KERN_INFO "FDC %d is an 82078.\n",fdc);
  9428. +            return FDC_82078;
  9429. +        case 0x1:
  9430. +            printk(KERN_INFO "FDC %d is a 44pin 82078\n",fdc);
  9431. +            return FDC_82078;
  9432. +        case 0x2:
  9433. +            printk(KERN_INFO "FDC %d is a S82078B\n", fdc);
  9434. +            return FDC_S82078B;
  9435. +        case 0x3:
  9436. +            printk(KERN_INFO "FDC %d is a National Semiconductor PC87306\n", fdc);
  9437. +            return FDC_87306;
  9438. +        default:
  9439. +            printk(KERN_INFO "FDC %d init: 82078 variant with unknown PARTID=%d.\n",
  9440. +                   fdc, reply_buffer[0] >> 5);
  9441. +            return FDC_82078_UNKN;
  9442. +    }
  9443. +} /* get_fdc_version */
  9444. +
  9445. +/* lilo configuration */
  9446. +
  9447. +/* we make the invert_dcl function global. One day, somebody might
  9448. + * want to centralize all thinkpad related options into one lilo option,
  9449. + * there are just so many thinkpad related quirks!
  9450. + */
  9451. +void floppy_invert_dcl(int *ints,int param)
  9452. +{
  9453. +    int i;
  9454. +
  9455. +    for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
  9456. +        if (param)
  9457. +            default_drive_params[i].params.flags |= 0x80;
  9458. +        else
  9459. +            default_drive_params[i].params.flags &= ~0x80;
  9460. +    }
  9461. +    DPRINT("Configuring drives for inverted dcl\n");
  9462. +}
  9463. +
  9464. +static void daring(int *ints,int param)
  9465. +{
  9466. +    int i;
  9467. +
  9468. +    for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
  9469. +        if (param){
  9470. +            default_drive_params[i].params.select_delay = 0;
  9471. +            default_drive_params[i].params.flags |= FD_SILENT_DCL_CLEAR;
  9472. +        } else {
  9473. +            default_drive_params[i].params.select_delay = 2*HZ/100;
  9474. +            default_drive_params[i].params.flags &= ~FD_SILENT_DCL_CLEAR;
  9475. +        }
  9476. +    }
  9477. +    DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
  9478. +}
  9479. +
  9480. +static void set_cmos(int *ints, int dummy)
  9481. +{
  9482. +    int current_drive=0;
  9483. +
  9484. +    if (ints[0] != 2) {
  9485. +        DPRINT("wrong number of parameters for cmos\n");
  9486. +        return;
  9487. +    }
  9488. +    current_drive = ints[1];
  9489. +    if (current_drive < 0 || current_drive >= 8) {
  9490. +        DPRINT("bad drive for set_cmos\n");
  9491. +        return;
  9492. +    }
  9493. +    if (current_drive >= 4 && !FDC2)
  9494. +        FDC2 = 0x370;
  9495. +    if (ints[2] <= 0 ||
  9496. +        (ints[2] >= NUMBER(default_drive_params) && ints[2] != 16)){
  9497. +        DPRINT("bad cmos code %d\n", ints[2]);
  9498. +        return;
  9499. +    }
  9500. +    DP->cmos = ints[2];
  9501. +    DPRINT("setting cmos code to %d\n", ints[2]);
  9502. +}
  9503. +
  9504. +static struct param_table {
  9505. +    const char *name;
  9506. +    void (*fn)(int *ints, int param);
  9507. +    int *var;
  9508. +    int def_param;
  9509. +} config_params[]={
  9510. +    { "allowed_drive_mask", 0, &allowed_drive_mask, 0xff },
  9511. +    { "all_drives", 0, &allowed_drive_mask, 0xff },
  9512. +    { "asus_pci", 0, &allowed_drive_mask, 0x33 },
  9513. +
  9514. +    { "daring", daring, 0, 1 },
  9515. +
  9516. +    { "two_fdc", 0, &FDC2, 0x370 },
  9517. +    { "one_fdc", 0, &FDC2, 0 },
  9518. +
  9519. +    { "thinkpad", floppy_invert_dcl, 0, 1 },
  9520. +
  9521. +    { "nodma", 0, &use_virtual_dma, 1 },
  9522. +    { "omnibook", 0, &use_virtual_dma, 1 },
  9523. +    { "dma", 0, &use_virtual_dma, 0 },
  9524. +
  9525. +    { "fifo_depth", 0, &fifo_depth, 0xa },
  9526. +    { "nofifo", 0, &no_fifo, 0x20 },
  9527. +    { "usefifo", 0, &no_fifo, 0 },
  9528. +
  9529. +    { "cmos", set_cmos, 0, 0 },
  9530. +    
  9531. +    { "unexpected_interrupts", 0, &print_unex, 1 },
  9532. +    { "no_unexpected_interrupts", 0, &print_unex, 0 },
  9533. +    { "L40SX", 0, &print_unex, 0 } };
  9534. +
  9535. +#define FLOPPY_SETUP
  9536. +void floppy_setup(char *str, int *ints)
  9537. +{
  9538. +    int i;
  9539. +    int param;
  9540. +    if (str)
  9541. +        for (i=0; i< ARRAY_SIZE(config_params); i++){
  9542. +            if (strcmp(str,config_params[i].name) == 0){
  9543. +                if (ints[0])
  9544. +                    param = ints[1];
  9545. +                else
  9546. +                    param = config_params[i].def_param;
  9547. +                if(config_params[i].fn)
  9548. +                    config_params[i].fn(ints,param);
  9549. +                if(config_params[i].var) {
  9550. +                    DPRINT("%s=%d\n", str, param);
  9551. +                    *config_params[i].var = param;
  9552. +                }
  9553. +                return;
  9554. +            }
  9555. +        }
  9556. +    if (str) {
  9557. +        DPRINT("unknown floppy option [%s]\n", str);
  9558. +
  9559. +        DPRINT("allowed options are:");
  9560. +        for (i=0; i< ARRAY_SIZE(config_params); i++)
  9561. +            printk(" %s",config_params[i].name);
  9562. +        printk("\n");
  9563. +    } else
  9564. +        DPRINT("botched floppy option\n");
  9565. +    DPRINT("Read linux/arch/arm/drivers/block/README.fd\n");
  9566. +}
  9567. +
  9568. +int floppy_init(void)
  9569. +{
  9570. +    int i,unit,drive;
  9571. +    int have_no_fdc = -EIO;
  9572. +
  9573. +    raw_cmd = NULL;
  9574. +
  9575. +    if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
  9576. +        printk("Unable to get major %d for floppy\n",MAJOR_NR);
  9577. +        return -EBUSY;
  9578. +    }
  9579. +
  9580. +    for(i=0; i<256; i++)
  9581. +        if (ITYPE(i))
  9582. +            floppy_sizes[i] = floppy_type[ITYPE(i)].size >> 1;
  9583. +        else
  9584. +            floppy_sizes[i] = MAX_DISK_SIZE;
  9585. +
  9586. +    blk_size[MAJOR_NR] = floppy_sizes;
  9587. +    blksize_size[MAJOR_NR] = floppy_blocksizes;
  9588. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  9589. +    reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
  9590. +    config_types();
  9591. +
  9592. +    for (i = 0 ; i < N_FDC ; i++) {
  9593. +        fdc = i;
  9594. +        CLEARSTRUCT(FDCS);
  9595. +        FDCS->dtr = -1;
  9596. +        FDCS->dor = 0x4;
  9597. +    }
  9598. +
  9599. +    fdc_state[0].address = FDC1;
  9600. +#if N_FDC > 1
  9601. +    fdc_state[1].address = FDC2;
  9602. +#endif
  9603. +
  9604. +    if(floppy_grab_irq_and_dma()){
  9605. +        unregister_blkdev(MAJOR_NR,"fd");
  9606. +        return -EBUSY;
  9607. +    }
  9608. +
  9609. +    /* initialise drive state */
  9610. +    for (drive = 0; drive < N_DRIVE ; drive++) {
  9611. +        CLEARSTRUCT(UDRS);
  9612. +        CLEARSTRUCT(UDRWE);
  9613. +        UDRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE | FD_DISK_CHANGED;
  9614. +        UDRS->fd_device = -1;
  9615. +        floppy_track_buffer = NULL;
  9616. +        max_buffer_sectors = 0;
  9617. +    }
  9618. +
  9619. +    for (i = 0 ; i < N_FDC ; i++) {
  9620. +        fdc = i;
  9621. +        FDCS->driver_version = FD_DRIVER_VERSION;
  9622. +        for(unit=0; unit<4; unit++)
  9623. +            FDCS->track[unit] = 0;
  9624. +        if (FDCS->address == -1 )
  9625. +            continue;
  9626. +        FDCS->rawcmd = 2;
  9627. +        if (user_reset_fdc(-1,FD_RESET_ALWAYS,0)){
  9628. +            FDCS->address = -1;
  9629. +            FDCS->version = FDC_NONE;
  9630. +            continue;
  9631. +        }
  9632. +        /* Try to determine the floppy controller type */
  9633. +        FDCS->version = get_fdc_version();
  9634. +        if (FDCS->version == FDC_NONE){
  9635. +            FDCS->address = -1;
  9636. +            continue;
  9637. +        }
  9638. +
  9639. +        request_region(FDCS->address, 6, "floppy");
  9640. +        request_region(FDCS->address+7, 1, "floppy DIR");
  9641. +        /* address + 6 is reserved, and may be taken by IDE.
  9642. +         * Unfortunately, Adaptec doesn't know this :-(, */
  9643. +
  9644. +        have_no_fdc = 0;
  9645. +        /* Not all FDCs seem to be able to handle the version command
  9646. +         * properly, so force a reset for the standard FDC clones,
  9647. +         * to avoid interrupt garbage.
  9648. +         */
  9649. +        user_reset_fdc(-1,FD_RESET_ALWAYS,0);
  9650. +    }
  9651. +    fdc=0;
  9652. +    del_timer(&fd_timeout);
  9653. +    current_drive = 0;
  9654. +    floppy_release_irq_and_dma();
  9655. +    initialising=0;
  9656. +    if (have_no_fdc) {
  9657. +        DPRINT("no floppy controllers found\n");
  9658. +        unregister_blkdev(MAJOR_NR,"fd");
  9659. +    }
  9660. +    return have_no_fdc;
  9661. +}
  9662. +
  9663. +static int floppy_grab_irq_and_dma(void)
  9664. +{
  9665. +    int i;
  9666. +    unsigned long flags;
  9667. +
  9668. +    INT_OFF;
  9669. +    if (usage_count++){
  9670. +        INT_ON;
  9671. +        return 0;
  9672. +    }
  9673. +    INT_ON;
  9674. +    MOD_INC_USE_COUNT;
  9675. +    for(i=0; i< N_FDC; i++){
  9676. +        if (fdc_state[i].address != -1){
  9677. +            fdc = i;
  9678. +            reset_fdc_info(1);
  9679. +            arm_set_dor(FDCS->dor);
  9680. +        }
  9681. +    }
  9682. +    fdc = 0;
  9683. +    set_dor(0, ~0, 8);  /* avoid immediate interrupt */
  9684. +
  9685. +    if (fd_request_irq()) {
  9686. +        DPRINT("Unable to grab IRQ%d for the floppy driver\n",
  9687. +            FLOPPY_IRQ);
  9688. +        MOD_DEC_USE_COUNT;
  9689. +        usage_count--;
  9690. +        return -1;
  9691. +    }
  9692. +    if (fd_request_dma()) {
  9693. +        DPRINT("Unable to grab DMA%d for the floppy driver\n",
  9694. +            FLOPPY_DMA);
  9695. +        fd_free_irq();
  9696. +        MOD_DEC_USE_COUNT;
  9697. +        usage_count--;
  9698. +        return -1;
  9699. +    }
  9700. +    for(fdc = 0; fdc < N_FDC ; fdc++)
  9701. +        if(FDCS->address != -1)
  9702. +            arm_set_dor(FDCS->dor);
  9703. +    fdc = 0;
  9704. +    fd_enable_irq();
  9705. +    return 0;
  9706. +}
  9707. +
  9708. +static void floppy_release_irq_and_dma(void)
  9709. +{
  9710. +#ifdef FLOPPY_SANITY_CHECK
  9711. +    int drive;
  9712. +#endif
  9713. +    long tmpsize;
  9714. +    unsigned long tmpaddr;
  9715. +    unsigned long flags;
  9716. +
  9717. +    INT_OFF;
  9718. +    if (--usage_count){
  9719. +        INT_ON;
  9720. +        return;
  9721. +    }
  9722. +    INT_ON;
  9723. +    fd_disable_dma();
  9724. +    fd_free_dma();
  9725. +    fd_disable_irq();
  9726. +    fd_free_irq();
  9727. +
  9728. +    set_dor(0, ~0, 8);
  9729. +#if N_FDC > 1
  9730. +    set_dor(1, ~8, 0);
  9731. +#endif
  9732. +    floppy_enable_hlt();
  9733. +
  9734. +    if (floppy_track_buffer && max_buffer_sectors) {
  9735. +        tmpsize = max_buffer_sectors*1024;
  9736. +        tmpaddr = (unsigned long)floppy_track_buffer;
  9737. +        floppy_track_buffer = NULL;
  9738. +        max_buffer_sectors = 0;
  9739. +        buffer_min = buffer_max = -1;
  9740. +        fd_dma_mem_free(tmpaddr, tmpsize);
  9741. +    }
  9742. +
  9743. +#ifdef FLOPPY_SANITY_CHECK
  9744. +    for(drive=0; drive < N_FDC * 4; drive++)
  9745. +        if( motor_off_timer[drive].next )
  9746. +            printk("motor off timer %d still active\n", drive);
  9747. +
  9748. +    if(fd_timeout.next)
  9749. +        printk("floppy timer still active:%s\n", timeout_message);
  9750. +    if (fd_timer.next)
  9751. +        printk("auxiliary floppy timer still active\n");
  9752. +    if(floppy_tq.sync)
  9753. +        printk("task queue still active\n");
  9754. +#endif
  9755. +    MOD_DEC_USE_COUNT;
  9756. +}
  9757. +
  9758. +
  9759. +#ifdef MODULE
  9760. +
  9761. +extern char *get_options(char *str, int *ints);
  9762. +
  9763. +char *floppy=NULL;
  9764. +
  9765. +static void parse_floppy_cfg_string(char *cfg)
  9766. +{
  9767. +    char *ptr;
  9768. +    int ints[11];
  9769. +
  9770. +    while(*cfg) {
  9771. +        for(ptr = cfg;*cfg && *cfg != ' ' && *cfg != '\t'; cfg++);
  9772. +        if(*cfg) {
  9773. +            *cfg = '\0';
  9774. +            cfg++;
  9775. +        }
  9776. +        if(*ptr)
  9777. +            floppy_setup(get_options(ptr,ints),ints);
  9778. +    }
  9779. +}
  9780. +
  9781. +static void mod_setup(char *pattern, void (*setup)(char *, int *))
  9782. +{
  9783. +    unsigned long i;
  9784. +    char c;
  9785. +    int j;
  9786. +    int match;
  9787. +    char buffer[100];
  9788. +    int ints[11];
  9789. +    int length = strlen(pattern)+1;
  9790. +
  9791. +    match=0;
  9792. +    j=1;
  9793. +
  9794. +    for(i=current->mm->env_start; i< current->mm->env_end; i ++){
  9795. +        c= get_fs_byte(i);
  9796. +        if(match){
  9797. +            if(j==99)
  9798. +                c='\0';
  9799. +            buffer[j] = c;
  9800. +            if(!c || c == ' ' || c == '\t'){
  9801. +                if(j){
  9802. +                    buffer[j] = '\0';
  9803. +                    setup(get_options(buffer,ints),ints);
  9804. +                }
  9805. +                j=0;
  9806. +            } else
  9807. +                j++;
  9808. +            if(!c)
  9809. +                break;
  9810. +            continue;
  9811. +        }
  9812. +        if( (!j && !c) || ( j && c == pattern[j-1]))
  9813. +            j++;
  9814. +        else
  9815. +            j=0;
  9816. +        if(j==length){
  9817. +            match=1;
  9818. +            j=0;
  9819. +        }
  9820. +    }
  9821. +}
  9822. +
  9823. +
  9824. +#ifdef __cplusplus
  9825. +extern "C" {
  9826. +#endif
  9827. +int init_module(void)
  9828. +{
  9829. +    printk(KERN_INFO "inserting floppy driver for %s\n", kernel_version);
  9830. +
  9831. +    if(floppy)
  9832. +        parse_floppy_cfg_string(floppy);
  9833. +    else
  9834. +        mod_setup("floppy=", floppy_setup);
  9835. +
  9836. +    return floppy_init();
  9837. +}
  9838. +
  9839. +void cleanup_module(void)
  9840. +{
  9841. +    int fdc, dummy;
  9842. +
  9843. +    for(fdc=0; fdc<2; fdc++)
  9844. +        if (FDCS->address != -1){
  9845. +            release_region(FDCS->address, 6);
  9846. +            release_region(FDCS->address+7, 1);
  9847. +        }
  9848. +
  9849. +    unregister_blkdev(MAJOR_NR, "fd");
  9850. +
  9851. +    blk_dev[MAJOR_NR].request_fn = 0;
  9852. +    /* eject disk, if any */
  9853. +    dummy = fd_eject(0);
  9854. +}
  9855. +
  9856. +#ifdef __cplusplus
  9857. +}
  9858. +#endif
  9859. +
  9860. +#else
  9861. +/* eject the boot floppy (if we need the drive for a different root floppy) */
  9862. +/* This should only be called at boot time when we're sure that there's no
  9863. + * resource contention. */
  9864. +void floppy_eject(void)
  9865. +{
  9866. +    int dummy;
  9867. +    floppy_grab_irq_and_dma();
  9868. +    lock_fdc(MAXTIMEOUT,0);
  9869. +    dummy=fd_eject(0);
  9870. +    process_fd_request();
  9871. +    floppy_release_irq_and_dma();
  9872. +}
  9873. +#endif
  9874. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/floppydma.S linux/arch/arm/drivers/block/floppydma.S
  9875. --- linux.orig/arch/arm/drivers/block/floppydma.S    Thu Jan  1 01:00:00 1970
  9876. +++ linux/arch/arm/drivers/block/floppydma.S    Sat Jun 22 21:55:21 1996
  9877. @@ -0,0 +1,74 @@
  9878. +/*
  9879. + * linux/arch/arm/lib/floppydma.S
  9880. + *
  9881. + * Copyright (C) 1995, 1996 Russell King
  9882. + */
  9883. +
  9884. +#include <asm/assembler.h>
  9885. +        .text
  9886. +
  9887. +LC0:        .word    _floppyfiq_len
  9888. +
  9889. +        .global    _floppy_fiqin_start
  9890. +        .global    _floppy_fiqin_end
  9891. +_floppy_fiqin_start:
  9892. +        subs    r9, r9, #1
  9893. +        ldrgtb    r12, [r11, #-4]
  9894. +        ldrleb    r12, [r11], #0
  9895. +        strb    r12, [r10], #1
  9896. +        subs    pc, lr, #4
  9897. +_floppy_fiqin_end:
  9898. +
  9899. +        .global    _floppy_fiqout_start
  9900. +        .global    _floppy_fiqout_end
  9901. +_floppy_fiqout_start:
  9902. +        subs    r9, r9, #1
  9903. +        ldrgeb    r12, [r10], #1
  9904. +        movlt    r12, #0
  9905. +        strleb    r12, [r11], #0
  9906. +        subles    pc, lr, #4
  9907. +        strb    r12, [r11, #-4]
  9908. +        subs    pc, lr, #4
  9909. +_floppy_fiqout_end:
  9910. +
  9911. +@ Params:
  9912. +@ r0 = length
  9913. +@ r1 = address
  9914. +@ r2 = floppy port
  9915. +@ Puts these into R9_fiq, R10_fiq, R11_fiq
  9916. +        .global    _floppy_fiqsetup
  9917. +_floppy_fiqsetup:
  9918. +        mov    ip, sp
  9919. +        stmfd    sp!, {fp, ip, lr, pc}
  9920. +        sub    fp, ip, #4
  9921. +        mov    r3, pc
  9922. +        teqp    pc, #0x0c000001        @ disable FIQs, IRQs, FIQ mode
  9923. +        mov    r0, r0            @ NOP
  9924. +        mov    r9, r0
  9925. +        mov    r10, r1
  9926. +        mov    r11, r2
  9927. +        teqp    r3, #0            @ back to normal
  9928. +        mov    r0, r0            @ NOP
  9929. +        ldmea    fp, {fp, sp, pc}^
  9930. +
  9931. +        .global    _floppy_fiqresidual
  9932. +_floppy_fiqresidual:
  9933. +        mov    ip, sp
  9934. +        stmfd    sp!, {fp, ip, lr, pc}
  9935. +        sub    fp, ip, #4
  9936. +        mov    r3, pc
  9937. +        teqp    pc, #0x0c000001        @ disable FIQs, IRQs, FIQ mode
  9938. +        mov    r0, r0            @ NOP
  9939. +        mov    r0, r9
  9940. +        teqp    r3, #0
  9941. +        mov    r0, r0            @ NOP
  9942. +        ldmea    fp, {fp, sp, pc}^
  9943. +        .data
  9944. +
  9945. +        .global    _floppyfiq_len
  9946. +        .global    _floppyfiq_to
  9947. +        .global    _floppyfiq_from
  9948. +
  9949. +_floppyfiq_len:    .word    0
  9950. +_floppyfiq_to:    .word    0
  9951. +_floppyfiq_from:    .word    0
  9952. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/genhd.c linux/arch/arm/drivers/block/genhd.c
  9953. --- linux.orig/arch/arm/drivers/block/genhd.c    Thu Jan  1 01:00:00 1970
  9954. +++ linux/arch/arm/drivers/block/genhd.c    Sun Aug 25 15:34:39 1996
  9955. @@ -0,0 +1,401 @@
  9956. +/*
  9957. + *  Code extracted from
  9958. + *  linux/kernel/hd.c
  9959. + *
  9960. + *  Copyright (C) 1991, 1992  Linus Torvalds
  9961. + *
  9962. + *
  9963. + *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  9964. + *  in the early extended-partition checks and added DM partitions
  9965. + *
  9966. + *  Support for DiskManager v6.0x added by Mark Lord,
  9967. + *  with information provided by OnTrack.  This now works for linux fdisk
  9968. + *  and LILO, as well as loadlin and bootln.  Note that disks other than
  9969. + *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
  9970. + *
  9971. + *  More flexible handling of extended partitions - aeb, 950831
  9972. + *
  9973. + *  Modifications Copyright (C) 1995, 1996 Russell King
  9974. + *
  9975. + *  Origional from linux/drivers/genhd.c
  9976. + *
  9977. + *  Altered to find image files on ADFS-formatted hard drives.
  9978. + */
  9979. +
  9980. +#include <linux/config.h>
  9981. +#include <linux/fs.h>
  9982. +#include <linux/genhd.h>
  9983. +#include <linux/kernel.h>
  9984. +#include <linux/major.h>
  9985. +#include <linux/string.h>
  9986. +#ifdef CONFIG_BLK_DEV_INITRD
  9987. +#include <linux/blk.h>
  9988. +#endif
  9989. +
  9990. +#include <asm/system.h>
  9991. +
  9992. +/*
  9993. + * Many architectures don't like unaligned accesses, which is
  9994. + * frequently the case with the nr_sects and start_sect partition
  9995. + * table entries.
  9996. + */
  9997. +#include <asm/unaligned.h>
  9998. +
  9999. +#define SYS_IND(p)    get_unaligned(&p->sys_ind)
  10000. +#define NR_SECTS(p)    get_unaligned(&p->nr_sects)
  10001. +#define START_SECT(p)    get_unaligned(&p->start_sect)
  10002. +
  10003. +
  10004. +struct gendisk *gendisk_head;
  10005. +
  10006. +static int current_minor;
  10007. +extern int *blk_size[];
  10008. +extern void rd_load(void);
  10009. +extern void initrd_load(void);
  10010. +
  10011. +extern int chr_dev_init(void);
  10012. +extern int blk_dev_init(void);
  10013. +extern int scsi_dev_init(void);
  10014. +extern int net_dev_init(void);
  10015. +
  10016. +/*
  10017. + * disk_name() is used by genhd.c and md.c.
  10018. + * It formats the devicename of the indicated disk
  10019. + * into the supplied buffer, and returns a pointer
  10020. + * to that same buffer (for convenience).
  10021. + */
  10022. +char *disk_name (struct gendisk *hd, int minor, char *buf)
  10023. +{
  10024. +    unsigned int part;
  10025. +    const char *maj = hd->major_name;
  10026. +    char unit = (minor >> hd->minor_shift) + 'a';
  10027. +
  10028. +#ifdef CONFIG_BLK_DEV_IDE
  10029. +    /*
  10030. +     * IDE devices use multiple major numbers, but the drives
  10031. +     * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
  10032. +     * This requires special handling here.
  10033. +     */
  10034. +    switch (hd->major) {
  10035. +        case IDE3_MAJOR:
  10036. +            unit += 2;
  10037. +        case IDE2_MAJOR:
  10038. +            unit += 2;
  10039. +        case IDE1_MAJOR:
  10040. +            unit += 2;
  10041. +        case IDE0_MAJOR:
  10042. +            maj = "hd";
  10043. +    }
  10044. +#endif
  10045. +    part = minor & ((1 << hd->minor_shift) - 1);
  10046. +    if (part)
  10047. +        sprintf(buf, "%s%c%d", maj, unit, part);
  10048. +    else
  10049. +        sprintf(buf, "%s%c", maj, unit);
  10050. +    return buf;
  10051. +}
  10052. +
  10053. +void add_partition (struct gendisk *hd, int minor, int start, int size)
  10054. +{
  10055. +    char buf[8];
  10056. +    hd->part[minor].start_sect = start;
  10057. +    hd->part[minor].nr_sects   = size;
  10058. +    printk(" %s", disk_name(hd, minor, buf));
  10059. +}
  10060. +
  10061. +static inline int is_extended_partition(struct partition *p)
  10062. +{
  10063. +    return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
  10064. +        SYS_IND(p) == LINUX_EXTENDED_PARTITION);
  10065. +}
  10066. +
  10067. +#ifdef CONFIG_MSDOS_PARTITION
  10068. +/*
  10069. + * Create devices for each logical partition in an extended partition.
  10070. + * The logical partitions form a linked list, with each entry being
  10071. + * a partition table with two entries.  The first entry
  10072. + * is the real data partition (with a start relative to the partition
  10073. + * table start).  The second is a pointer to the next logical partition
  10074. + * (with a start relative to the entire extended partition).
  10075. + * We do not create a Linux partition for the partition tables, but
  10076. + * only for the actual data partitions.
  10077. + */
  10078. +
  10079. +static void extended_partition(struct gendisk *hd, kdev_t dev)
  10080. +{
  10081. +    struct buffer_head *bh;
  10082. +    struct partition *p;
  10083. +    unsigned long first_sector, first_size, this_sector, this_size;
  10084. +    int mask = (1 << hd->minor_shift) - 1;
  10085. +    int i;
  10086. +
  10087. +    first_sector = hd->part[MINOR(dev)].start_sect;
  10088. +    first_size = hd->part[MINOR(dev)].nr_sects;
  10089. +    this_sector = first_sector;
  10090. +
  10091. +    while (1) {
  10092. +        if ((current_minor & mask) == 0)
  10093. +            return;
  10094. +        if (!(bh = bread(dev,0,1024)))
  10095. +            return;
  10096. +      /*
  10097. +       * This block is from a device that we're about to stomp on.
  10098. +       * So make sure nobody thinks this block is usable.
  10099. +       */
  10100. +        bh->b_state = 0;
  10101. +
  10102. +        if (*(unsigned short *) (bh->b_data+510) != 0xAA55)
  10103. +            goto done;
  10104. +
  10105. +        p = (struct partition *) (0x1BE + bh->b_data);
  10106. +
  10107. +        this_size = hd->part[MINOR(dev)].nr_sects;
  10108. +
  10109. +        /*
  10110. +         * Usually, the first entry is the real data partition,
  10111. +         * the 2nd entry is the next extended partition, or empty,
  10112. +         * and the 3rd and 4th entries are unused.
  10113. +         * However, DRDOS sometimes has the extended partition as
  10114. +         * the first entry (when the data partition is empty),
  10115. +         * and OS/2 seems to use all four entries.
  10116. +         */
  10117. +
  10118. +        /* 
  10119. +         * First process the data partition(s)
  10120. +         */
  10121. +        for (i=0; i<4; i++, p++) {
  10122. +            if (!NR_SECTS(p) || is_extended_partition(p))
  10123. +              continue;
  10124. +
  10125. +            /* Check the 3rd and 4th entries -
  10126. +               these sometimes contain random garbage */
  10127. +            if (i >= 2
  10128. +            && START_SECT(p) + NR_SECTS(p) > this_size
  10129. +            && (this_sector + START_SECT(p) < first_sector ||
  10130. +                this_sector + START_SECT(p) + NR_SECTS(p) >
  10131. +                 first_sector + first_size))
  10132. +              continue;
  10133. +
  10134. +            add_partition(hd, current_minor, this_sector+START_SECT(p), NR_SECTS(p));
  10135. +            current_minor++;
  10136. +            if ((current_minor & mask) == 0)
  10137. +              goto done;
  10138. +        }
  10139. +        /*
  10140. +         * Next, process the (first) extended partition, if present.
  10141. +         * (So far, there seems to be no reason to make
  10142. +         *  extended_partition()  recursive and allow a tree
  10143. +         *  of extended partitions.)
  10144. +         * It should be a link to the next logical partition.
  10145. +         * Create a minor for this just long enough to get the next
  10146. +         * partition table.  The minor will be reused for the next
  10147. +         * data partition.
  10148. +         */
  10149. +        p -= 4;
  10150. +        for (i=0; i<4; i++, p++)
  10151. +          if(NR_SECTS(p) && is_extended_partition(p))
  10152. +            break;
  10153. +        if (i == 4)
  10154. +          goto done;     /* nothing left to do */
  10155. +
  10156. +        hd->part[current_minor].nr_sects = NR_SECTS(p);
  10157. +        hd->part[current_minor].start_sect = first_sector + START_SECT(p);
  10158. +        this_sector = first_sector + START_SECT(p);
  10159. +        dev = MKDEV(hd->major, current_minor);
  10160. +        brelse(bh);
  10161. +    }
  10162. +done:
  10163. +    brelse(bh);
  10164. +}
  10165. +
  10166. +static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
  10167. +{
  10168. +    int i, minor = current_minor;
  10169. +    struct buffer_head *bh;
  10170. +    struct partition *p;
  10171. +    unsigned char *data;
  10172. +    int mask = (1 << hd->minor_shift) - 1;
  10173. +
  10174. +    if (!(bh = bread(dev,0,1024))) {
  10175. +        printk(" unable to read partition table\n");
  10176. +        return -1;
  10177. +    }
  10178. +    data = bh->b_data;
  10179. +    /* In some cases we modify the geometry    */
  10180. +    /*  of the drive (below), so ensure that   */ 
  10181. +    /*  nobody else tries to re-use this data. */
  10182. +    bh->b_state = 0;
  10183. +
  10184. +    if (*(unsigned short *)  (0x1fe + data) != 0xAA55) {
  10185. +        brelse(bh);
  10186. +        return 0;
  10187. +    }
  10188. +    printk (" [DOS]");
  10189. +    p = (struct partition *) (0x1be + data);
  10190. +
  10191. +    current_minor += 4;
  10192. +    for (i=1 ; i<=4 ; minor++, i++, p++) {
  10193. +        if(!NR_SECTS(p))
  10194. +            continue;
  10195. +        add_partition(hd, minor, first_sector+START_SECT(p), NR_SECTS(p));
  10196. +        if (is_extended_partition(p)) {
  10197. +            printk(" <");
  10198. +            /*
  10199. +             * If we are rereading the partition table, we need
  10200. +             * to set the size of the partition so that we will
  10201. +             * be able to bread the block containing the extended
  10202. +             * partition info.
  10203. +             */
  10204. +            hd->sizes[minor] = hd->part[minor].nr_sects
  10205. +                >> (BLOCK_SIZE_BITS - 9);
  10206. +            extended_partition(hd, MKDEV(hd->major, minor));
  10207. +            printk(" >");
  10208. +            /* prevent someone doing mkfs or mkswap on an
  10209. +               extended partition, but leave room for LILO */
  10210. +            if (hd->part[minor].nr_sects > 2)
  10211. +                hd->part[minor].nr_sects = 2;
  10212. +        }
  10213. +    }
  10214. +    /*
  10215. +     *  Check for old-style Disk Manager partition table
  10216. +     */
  10217. +    if (*(unsigned short *) (data+0xfc) == 0x55AA) {
  10218. +        p = (struct partition *) (0x1be + data);
  10219. +        for (i = 4 ; i < 16 ; i++, current_minor++) {
  10220. +            p--;
  10221. +            if ((current_minor & mask) == 0)
  10222. +                break;
  10223. +            if (!(START_SECT(p) && NR_SECTS(p)))
  10224. +                continue;
  10225. +            add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
  10226. +        }
  10227. +    }
  10228. +    printk("\n");
  10229. +    brelse(bh);
  10230. +    return 1;
  10231. +}
  10232. +
  10233. +#endif /* CONFIG_MSDOS_PARTITION */
  10234. +
  10235. +extern int adfspart_initdev (struct gendisk *hd, kdev_t dev, int first_sector, int minor);
  10236. +
  10237. +static void check_partition(struct gendisk *hd, kdev_t dev)
  10238. +{
  10239. +    static int first_time = 1;
  10240. +    unsigned long first_sector;
  10241. +    char buf[8];
  10242. +
  10243. +    if (first_time)
  10244. +        printk("Partition check:\n");
  10245. +    first_time = 0;
  10246. +    first_sector = hd->part[MINOR(dev)].start_sect;
  10247. +
  10248. +    /*
  10249. +     * This is a kludge to allow the partition check to be
  10250. +     * skipped for specific drives (e.g. IDE cd-rom drives)
  10251. +     */
  10252. +    if ((int)first_sector == -1) {
  10253. +        hd->part[MINOR(dev)].start_sect = 0;
  10254. +        return;
  10255. +    }
  10256. +
  10257. +    printk(" %s:", disk_name(hd, MINOR(dev), buf));
  10258. +
  10259. +    if (adfspart_initdev (hd, dev, first_sector, current_minor))
  10260. +        return;
  10261. +
  10262. +#ifdef CONFIG_MSDOS_PARTITION
  10263. +    if (msdos_partition(hd, dev, first_sector))
  10264. +        return;
  10265. +#endif
  10266. +    printk(" unknown partition table\n");
  10267. +}
  10268. +
  10269. +/*
  10270. + * This function is used to re-read partition tables for removable disks.
  10271. + * Much of the cleanup from the old partition tables should have already been
  10272. + * done
  10273. + */
  10274. +
  10275. +/*
  10276. + * This function will re-read the partition tables for a given device,
  10277. + * and set things back up again.  There are some important caveats,
  10278. + * however.  You must ensure that no one is using the device, and no one
  10279. + * can start using the device while this function is being executed.
  10280. + */
  10281. +void resetup_one_dev(struct gendisk *dev, int drive)
  10282. +{
  10283. +    int i;
  10284. +    int first_minor    = drive << dev->minor_shift;
  10285. +    int end_minor    = first_minor + dev->max_p;
  10286. +
  10287. +    blk_size[dev->major] = NULL;
  10288. +    current_minor = 1 + first_minor;
  10289. +    check_partition(dev, MKDEV(dev->major, first_minor));
  10290. +
  10291. +    /*
  10292. +     * We need to set the sizes array before we will be able to access
  10293. +     * any of the partitions on this device.
  10294. +     */
  10295. +    if (dev->sizes != NULL) {    /* optional safeguard in ll_rw_blk.c */
  10296. +        for (i = first_minor; i < end_minor; i++)
  10297. +            dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
  10298. +        blk_size[dev->major] = dev->sizes;
  10299. +    }
  10300. +}
  10301. +
  10302. +static void setup_dev(struct gendisk *dev)
  10303. +{
  10304. +    int i, drive;
  10305. +    int end_minor    = dev->max_nr * dev->max_p;
  10306. +
  10307. +    blk_size[dev->major] = NULL;
  10308. +    for (i = 0 ; i < end_minor; i++) {
  10309. +        dev->part[i].start_sect = 0;
  10310. +        dev->part[i].nr_sects = 0;
  10311. +    }
  10312. +    dev->init(dev);
  10313. +    for (drive=0 ; drive < dev->nr_real ; drive++) {
  10314. +        int first_minor = drive << dev->minor_shift;
  10315. +        current_minor = 1 + first_minor;
  10316. +        check_partition(dev, MKDEV(dev->major, first_minor));
  10317. +    }
  10318. +    if (dev->sizes != NULL) {    /* optional safeguard in ll_rw_blk.c */
  10319. +        for (i = 0; i < end_minor; i++)
  10320. +            dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
  10321. +        blk_size[dev->major] = dev->sizes;
  10322. +    }
  10323. +}
  10324. +
  10325. +void device_setup(void)
  10326. +{
  10327. +    extern void console_map_init(void);
  10328. +    extern void adfsimg_init (void);
  10329. +    struct gendisk *p;
  10330. +    int nr=0;
  10331. +
  10332. +    chr_dev_init();
  10333. +    blk_dev_init();
  10334. +    sti();
  10335. +#ifdef CONFIG_SCSI
  10336. +    scsi_dev_init();
  10337. +#endif
  10338. +#ifdef CONFIG_INET
  10339. +    net_dev_init();
  10340. +#endif
  10341. +    console_map_init();
  10342. +#ifdef CONFIG_BLK_DEV_IMG
  10343. +    adfsimg_init ();
  10344. +#endif
  10345. +    for (p = gendisk_head ; p ; p=p->next) {
  10346. +        setup_dev(p);
  10347. +        nr += p->nr_real;
  10348. +    }
  10349. +#ifdef CONFIG_BLK_DEV_RAM
  10350. +#ifdef CONFIG_BLK_DEV_INITRD
  10351. +    if (initrd_start && mount_initrd) initrd_load();
  10352. +    else
  10353. +#endif
  10354. +    rd_load();
  10355. +#endif
  10356. +}
  10357. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/hd.c linux/arch/arm/drivers/block/hd.c
  10358. --- linux.orig/arch/arm/drivers/block/hd.c    Thu Jan  1 01:00:00 1970
  10359. +++ linux/arch/arm/drivers/block/hd.c    Tue Apr 23 23:18:07 1996
  10360. @@ -0,0 +1,1137 @@
  10361. +/*
  10362. + *  linux/arch/arm/drivers/block/hd.c
  10363. + *   [ origional file: linux/drivers/block/hd.c ]
  10364. + *
  10365. + *  Copyright (C) 1991, 1992  Linus Torvalds
  10366. + *  Modified 1995  Russell King for ARM processor.
  10367. + */
  10368. +
  10369. +/*
  10370. + * This is the low-level hd interrupt support. It traverses the
  10371. + * request-list, using interrupts to jump between functions. As
  10372. + * all the functions are called within interrupts, we may not
  10373. + * sleep. Special care is recommended.
  10374. + * 
  10375. + *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
  10376. + *
  10377. + *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  10378. + *  in the early extended-partition checks and added DM partitions
  10379. + *
  10380. + *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
  10381. + *  and general streamlining by mlord@bnr.ca (Mark Lord).
  10382. + */
  10383. +
  10384. +#define DEFAULT_MULT_COUNT  0    /* set to 0 to disable multiple mode at boot */
  10385. +#define DEFAULT_UNMASK_INTR 0    /* set to 0 to *NOT* unmask irq's more often */
  10386. +
  10387. +#include <asm/irq.h>
  10388. +#include <linux/errno.h>
  10389. +#include <linux/signal.h>
  10390. +#include <linux/sched.h>
  10391. +#include <linux/timer.h>
  10392. +#include <linux/fs.h>
  10393. +#include <linux/kernel.h>
  10394. +#include <linux/hdreg.h>
  10395. +#include <linux/genhd.h>
  10396. +#include <linux/malloc.h>
  10397. +#include <linux/string.h>
  10398. +#include <linux/ioport.h>
  10399. +
  10400. +#define REALLY_SLOW_IO
  10401. +#include <asm/system.h>
  10402. +#include <asm/io.h>
  10403. +#include <asm/segment.h>
  10404. +
  10405. +#define MAJOR_NR HD_MAJOR
  10406. +#include <linux/blk.h>
  10407. +
  10408. +#undef  HD_IRQ
  10409. +#define HD_IRQ 11
  10410. +
  10411. +static int revalidate_hddisk(kdev_t, int);
  10412. +
  10413. +#define    HD_DELAY    0
  10414. +
  10415. +#define MAX_ERRORS     16    /* Max read/write errors/sector */
  10416. +#define RESET_FREQ      8    /* Reset controller every 8th retry */
  10417. +#define RECAL_FREQ      4    /* Recalibrate every 4th retry */
  10418. +#define MAX_HD        2
  10419. +
  10420. +#define STAT_OK        (READY_STAT|SEEK_STAT)
  10421. +#define OK_STATUS(s)    (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
  10422. +
  10423. +static void recal_intr(void);
  10424. +static void bad_rw_intr(void);
  10425. +
  10426. +static char recalibrate[MAX_HD] =;
  10427. +static char special_op[MAX_HD];
  10428. +static int access_count[MAX_HD];
  10429. +static char busy[MAX_HD];
  10430. +static struct wait_queue * busy_wait;
  10431. +
  10432. +static int reset;
  10433. +static int hd_error;
  10434. +
  10435. +/*
  10436. + *  This struct defines the HD's and their types.
  10437. + */
  10438. +struct hd_i_struct {
  10439. +    unsigned int head,sect,cyl,wpcom,lzone,ctl;
  10440. +    };
  10441. +static struct hd_driveid *hd_ident_info[MAX_HD];
  10442. +    
  10443. +#ifdef HD_TYPE
  10444. +static struct hd_i_struct hd_info[] = { HD_TYPE };
  10445. +struct hd_i_struct bios_info[] = { HD_TYPE };
  10446. +static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
  10447. +#else
  10448. +static struct hd_i_struct hd_info[];
  10449. +struct hd_i_struct bios_info[];
  10450. +static int NR_HD;
  10451. +#endif
  10452. +
  10453. +static struct hd_struct hd[MAX_HD<<6];
  10454. +static int hd_sizes[MAX_HD<<6];
  10455. +static int hd_blocksizes[MAX_HD<<6];
  10456. +static int hd_hardsectsizes[MAX_HD<<6];
  10457. +
  10458. +#if (HD_DELAY > 0)
  10459. +unsigned long last_req;
  10460. +
  10461. +unsigned long read_timer(void)
  10462. +{
  10463. +    unsigned long t, flags;
  10464. +    int i;
  10465. +
  10466. +    save_flags_cli (flags);
  10467. +    t = jiffies * 11932;
  10468. +        outb_p(0, 0x43);
  10469. +    i = inb_p(0x40);
  10470. +    i |= inb(0x40) << 8;
  10471. +    restore_flags(flags);
  10472. +    return(t - i);
  10473. +}
  10474. +#endif
  10475. +
  10476. +void hd_setup(char *str, int *ints)
  10477. +{
  10478. +    int hdind = 0;
  10479. +
  10480. +    if (ints[0] != 3)
  10481. +        return;
  10482. +    if (bios_info[0].head != 0)
  10483. +        hdind=1;
  10484. +    bios_info[hdind].head  = hd_info[hdind].head = ints[2];
  10485. +    bios_info[hdind].sect  = hd_info[hdind].sect = ints[3];
  10486. +    bios_info[hdind].cyl   = hd_info[hdind].cyl = ints[1];
  10487. +    bios_info[hdind].wpcom = hd_info[hdind].wpcom = 0;
  10488. +    bios_info[hdind].lzone = hd_info[hdind].lzone = ints[1];
  10489. +    bios_info[hdind].ctl   = hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
  10490. +    NR_HD = hdind+1;
  10491. +}
  10492. +
  10493. +static void dump_status (const char *msg, unsigned int stat)
  10494. +{
  10495. +    unsigned long flags;
  10496. +    char devc;
  10497. +
  10498. +    devc = CURRENT ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
  10499. +    save_flags (flags);
  10500. +    sti();
  10501. +    printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
  10502. +    if (stat & BUSY_STAT)    printk("Busy ");
  10503. +    if (stat & READY_STAT)    printk("DriveReady ");
  10504. +    if (stat & WRERR_STAT)    printk("WriteFault ");
  10505. +    if (stat & SEEK_STAT)    printk("SeekComplete ");
  10506. +    if (stat & DRQ_STAT)    printk("DataRequest ");
  10507. +    if (stat & ECC_STAT)    printk("CorrectedError ");
  10508. +    if (stat & INDEX_STAT)    printk("Index ");
  10509. +    if (stat & ERR_STAT)    printk("Error ");
  10510. +    printk("}\n");
  10511. +    if ((stat & ERR_STAT) == 0) {
  10512. +        hd_error = 0;
  10513. +    } else {
  10514. +        hd_error = inb(HD_ERROR);
  10515. +        printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
  10516. +        if (hd_error & BBD_ERR)        printk("BadSector ");
  10517. +        if (hd_error & ECC_ERR)        printk("UncorrectableError ");
  10518. +        if (hd_error & ID_ERR)        printk("SectorIdNotFound ");
  10519. +        if (hd_error & ABRT_ERR)    printk("DriveStatusError ");
  10520. +        if (hd_error & TRK0_ERR)    printk("TrackZeroNotFound ");
  10521. +        if (hd_error & MARK_ERR)    printk("AddrMarkNotFound ");
  10522. +        printk("}");
  10523. +        if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
  10524. +            printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
  10525. +                inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
  10526. +            if (CURRENT)
  10527. +                printk(", sector=%ld", CURRENT->sector);
  10528. +        }
  10529. +        printk("\n");
  10530. +    }
  10531. +    restore_flags (flags);
  10532. +}
  10533. +
  10534. +void check_status(void)
  10535. +{
  10536. +    int i = inb_p(HD_STATUS);
  10537. +
  10538. +    if (!OK_STATUS(i)) {
  10539. +        dump_status("check_status", i);
  10540. +        bad_rw_intr();
  10541. +    }
  10542. +}
  10543. +
  10544. +static int controller_busy(void)
  10545. +{
  10546. +    int retries = 100000;
  10547. +    unsigned char status;
  10548. +
  10549. +    do {
  10550. +        status = inb_p(HD_STATUS);
  10551. +    } while ((status & BUSY_STAT) && --retries);
  10552. +    return status;
  10553. +}
  10554. +
  10555. +static int status_ok(void)
  10556. +{
  10557. +    unsigned char status = inb_p(HD_STATUS);
  10558. +
  10559. +    if (status & BUSY_STAT)
  10560. +        return 1;    /* Ancient, but does it make sense??? */
  10561. +    if (status & WRERR_STAT)
  10562. +        return 0;
  10563. +    if (!(status & READY_STAT))
  10564. +        return 0;
  10565. +    if (!(status & SEEK_STAT))
  10566. +        return 0;
  10567. +    return 1;
  10568. +}
  10569. +
  10570. +static int controller_ready(unsigned int drive, unsigned int head)
  10571. +{
  10572. +    int retry = 100;
  10573. +
  10574. +    do {
  10575. +        if (controller_busy() & BUSY_STAT)
  10576. +            return 0;
  10577. +        outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
  10578. +        if (status_ok())
  10579. +            return 1;
  10580. +    } while (--retry);
  10581. +    return 0;
  10582. +}
  10583. +
  10584. +static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
  10585. +        unsigned int head,unsigned int cyl,unsigned int cmd,
  10586. +        void (*intr_addr)(void))
  10587. +{
  10588. +    unsigned short port;
  10589. +
  10590. +#if (HD_DELAY > 0)
  10591. +    while (read_timer() - last_req < HD_DELAY)
  10592. +        /* nothing */;
  10593. +#endif
  10594. +    if (reset)
  10595. +        return;
  10596. +    if (!controller_ready(drive, head)) {
  10597. +        reset = 1;
  10598. +        return;
  10599. +    }
  10600. +    SET_INTR(intr_addr);
  10601. +    outb_p(hd_info[drive].ctl,HD_CMD);
  10602. +    port=HD_DATA;
  10603. +    outb_p(hd_info[drive].wpcom>>2,++port);
  10604. +    outb_p(nsect,++port);
  10605. +    outb_p(sect,++port);
  10606. +    outb_p(cyl,++port);
  10607. +    outb_p(cyl>>8,++port);
  10608. +    outb_p(0xA0|(drive<<4)|head,++port);
  10609. +    outb_p(cmd,++port);
  10610. +}
  10611. +
  10612. +static void hd_request (void);
  10613. +static unsigned int identified  [MAX_HD]; /* 1 = drive ID already displayed   */
  10614. +static unsigned int unmask_intr [MAX_HD]; /* 1 = unmask IRQs during I/O       */
  10615. +static unsigned int max_mult    [MAX_HD]; /* max sectors for MultMode         */
  10616. +static unsigned int mult_req    [MAX_HD]; /* requested MultMode count         */
  10617. +static unsigned int mult_count  [MAX_HD]; /* currently enabled MultMode count */
  10618. +static struct request WCURRENT;
  10619. +
  10620. +static void fixstring (unsigned char *s, int bytecount)
  10621. +{
  10622. +    unsigned char *p, *end = &s[bytecount &= ~1];    /* bytecount must be even */
  10623. +
  10624. +    /* convert from big-endian to little-endian */
  10625. +    for (p = end ; p != s;) {
  10626. +        unsigned short *pp = (unsigned short *) (p -= 2);
  10627. +        *pp = (*pp >> 8) | (*pp << 8);
  10628. +    }
  10629. +
  10630. +    /* strip leading blanks */
  10631. +    while (s != end && *s == ' ')
  10632. +        ++s;
  10633. +
  10634. +    /* compress internal blanks and strip trailing blanks */
  10635. +    while (s != end && *s) {
  10636. +        if (*s++ != ' ' || (s != end && *s && *s != ' '))
  10637. +            *p++ = *(s-1);
  10638. +    }
  10639. +
  10640. +    /* wipe out trailing garbage */
  10641. +    while (p != end)
  10642. +        *p++ = '\0';
  10643. +}
  10644. +
  10645. +static void identify_intr(void)
  10646. +{
  10647. +    unsigned int dev = DEVICE_NR(CURRENT->rq_dev);
  10648. +    unsigned short stat = inb_p(HD_STATUS);
  10649. +    struct hd_driveid *id = hd_ident_info[dev];
  10650. +
  10651. +    if (unmask_intr[dev])
  10652. +        sti();
  10653. +    if (stat & (BUSY_STAT|ERR_STAT)) {
  10654. +        printk ("  hd%c: non-IDE device, %dMB, CHS=%d/%d/%d\n", dev+'a',
  10655. +            hd_info[dev].cyl*hd_info[dev].head*hd_info[dev].sect / 2048,
  10656. +            hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect);
  10657. +        if (id != NULL) {
  10658. +            hd_ident_info[dev] = NULL;
  10659. +            kfree_s (id, 512);
  10660. +        }
  10661. +    } else {
  10662. +        insw(HD_DATA, id, 256); /* get ID info */
  10663. +        max_mult[dev] = id->max_multsect;
  10664. +        if ((id->field_valid&1) && id->cur_cyls && id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
  10665. +            /*
  10666. +             * Extract the physical drive geometry for our use.
  10667. +             * Note that we purposely do *not* update the bios_info.
  10668. +             * This way, programs that use it (like fdisk) will 
  10669. +             * still have the same logical view as the BIOS does,
  10670. +             * which keeps the partition table from being screwed.
  10671. +             */
  10672. +            hd_info[dev].cyl  = id->cur_cyls;
  10673. +            hd_info[dev].head = id->cur_heads;
  10674. +            hd_info[dev].sect = id->cur_sectors; 
  10675. +        }
  10676. +        fixstring (id->serial_no, sizeof(id->serial_no));
  10677. +        fixstring (id->fw_rev, sizeof(id->fw_rev));
  10678. +        fixstring (id->model, sizeof(id->model));
  10679. +        printk ("  hd%c: %.40s, %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n",
  10680. +            dev+'a', id->model, id->cyls*id->heads*id->sectors/2048,
  10681. +            id->buf_size/2, bios_info[dev].cyl, bios_info[dev].head,
  10682. +            bios_info[dev].sect, id->max_multsect);
  10683. +        /*
  10684. +         * Early model Quantum drives go weird at this point,
  10685. +         *   but doing a recalibrate seems to "fix" them.
  10686. +         * (Doing a full reset confuses some other model Quantums)
  10687. +         */
  10688. +        if (!strncmp(id->model, "QUANTUM", 7))
  10689. +            special_op[dev] = recalibrate[dev] = 1;
  10690. +    }
  10691. +#if (HD_DELAY > 0)
  10692. +    last_req = read_timer();
  10693. +#endif
  10694. +    hd_request();
  10695. +    return;
  10696. +}
  10697. +
  10698. +static void set_multmode_intr(void)
  10699. +{
  10700. +    unsigned int dev = DEVICE_NR(CURRENT->rq_dev), stat = inb_p(HD_STATUS);
  10701. +
  10702. +    if (unmask_intr[dev])
  10703. +        sti();
  10704. +    if (stat & (BUSY_STAT|ERR_STAT)) {
  10705. +        mult_req[dev] = mult_count[dev] = 0;
  10706. +        dump_status("set multmode failed", stat);
  10707. +    } else {
  10708. +        if ((mult_count[dev] = mult_req[dev]))
  10709. +            printk ("  hd%c: enabled %d-sector multiple mode\n",
  10710. +                dev+'a', mult_count[dev]);
  10711. +        else
  10712. +            printk ("  hd%c: disabled multiple mode\n", dev+'a');
  10713. +    }
  10714. +#if (HD_DELAY > 0)
  10715. +    last_req = read_timer();
  10716. +#endif
  10717. +    hd_request();
  10718. +    return;
  10719. +}
  10720. +
  10721. +static int drive_busy(void)
  10722. +{
  10723. +    unsigned int i;
  10724. +    unsigned char c;
  10725. +
  10726. +    for (i = 0; i < 500000 ; i++) {
  10727. +        c = inb_p(HD_STATUS);
  10728. +        if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
  10729. +            return 0;
  10730. +    }
  10731. +    dump_status("reset timed out", c);
  10732. +    return 1;
  10733. +}
  10734. +
  10735. +static void reset_controller(void)
  10736. +{
  10737. +    int    i;
  10738. +
  10739. +    outb_p(4,HD_CMD);
  10740. +    for(i = 0; i < 1000; i++) barrier();
  10741. +    outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
  10742. +    for(i = 0; i < 1000; i++) barrier();
  10743. +    if (drive_busy())
  10744. +        printk("hd: controller still busy\n");
  10745. +    else if ((hd_error = inb(HD_ERROR)) != 1)
  10746. +        printk("hd: controller reset failed: %02x\n",hd_error);
  10747. +}
  10748. +
  10749. +static void reset_hd(void)
  10750. +{
  10751. +    static int i;
  10752. +
  10753. +repeat:
  10754. +    if (reset) {
  10755. +        reset = 0;
  10756. +        i = -1;
  10757. +        reset_controller();
  10758. +    } else {
  10759. +        check_status();
  10760. +        if (reset)
  10761. +            goto repeat;
  10762. +    }
  10763. +    if (++i < NR_HD) {
  10764. +        special_op[i] = recalibrate[i] = 1;
  10765. +        if (unmask_intr[i]) {
  10766. +            unmask_intr[i] = DEFAULT_UNMASK_INTR;
  10767. +            printk("hd%c: reset irq-unmasking to %d\n",i+'a',
  10768. +                DEFAULT_UNMASK_INTR);
  10769. +        }
  10770. +        if (mult_req[i] || mult_count[i]) {
  10771. +            mult_count[i] = 0;
  10772. +            mult_req[i] = DEFAULT_MULT_COUNT;
  10773. +            printk("hd%c: reset multiple mode to %d\n",i+'a',
  10774. +                DEFAULT_MULT_COUNT);
  10775. +        }
  10776. +        hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
  10777. +            hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
  10778. +        if (reset)
  10779. +            goto repeat;
  10780. +    } else
  10781. +        hd_request();
  10782. +}
  10783. +
  10784. +/*
  10785. + * Ok, don't know what to do with the unexpected interrupts: on some machines
  10786. + * doing a reset and a retry seems to result in an eternal loop. Right now I
  10787. + * ignore it, and just set the timeout.
  10788. + *
  10789. + * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
  10790. + * drive enters "idle", "standby", or "sleep" mode, so if the status looks
  10791. + * "good", we just ignore the interrupt completely.
  10792. + */
  10793. +void unexpected_hd_interrupt(void)
  10794. +{
  10795. +    unsigned int stat = inb_p(HD_STATUS);
  10796. +
  10797. +    if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
  10798. +        dump_status ("unexpected interrupt", stat);
  10799. +        SET_TIMER;
  10800. +    }
  10801. +}
  10802. +
  10803. +/*
  10804. + * bad_rw_intr() now tries to be a bit smarter and does things
  10805. + * according to the error returned by the controller.
  10806. + * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
  10807. + */
  10808. +static void bad_rw_intr(void)
  10809. +{
  10810. +    int dev;
  10811. +
  10812. +    if (!CURRENT)
  10813. +        return;
  10814. +    dev = DEVICE_NR(CURRENT->rq_dev);
  10815. +    if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
  10816. +        end_request(0);
  10817. +        special_op[dev] = recalibrate[dev] = 1;
  10818. +    } else if (CURRENT->errors % RESET_FREQ == 0)
  10819. +        reset = 1;
  10820. +    else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
  10821. +        special_op[dev] = recalibrate[dev] = 1;
  10822. +    /* Otherwise just retry */
  10823. +}
  10824. +
  10825. +static inline int wait_DRQ(void)
  10826. +{
  10827. +    int retries = 100000, stat;
  10828. +
  10829. +    while (--retries > 0)
  10830. +        if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
  10831. +            return 0;
  10832. +    dump_status("wait_DRQ", stat);
  10833. +    return -1;
  10834. +}
  10835. +
  10836. +static void read_intr(void)
  10837. +{
  10838. +    unsigned int dev = DEVICE_NR(CURRENT->rq_dev);
  10839. +    int i, retries = 100000, msect = mult_count[dev], nsect;
  10840. +
  10841. +    if (unmask_intr[dev])
  10842. +        sti();            /* permit other IRQs during xfer */
  10843. +    do {
  10844. +        i = (unsigned) inb_p(HD_STATUS);
  10845. +        if (i & BUSY_STAT)
  10846. +            continue;
  10847. +        if (!OK_STATUS(i))
  10848. +            break;
  10849. +        if (i & DRQ_STAT)
  10850. +            goto ok_to_read;
  10851. +    } while (--retries > 0);
  10852. +    dump_status("read_intr", i);
  10853. +    bad_rw_intr();
  10854. +    hd_request();
  10855. +    return;
  10856. +ok_to_read:
  10857. +    if (msect) {
  10858. +        if ((nsect = CURRENT->current_nr_sectors) > msect)
  10859. +            nsect = msect;
  10860. +        msect -= nsect;
  10861. +    } else
  10862. +        nsect = 1;
  10863. +    insw(HD_DATA,CURRENT->buffer,nsect<<8);
  10864. +    CURRENT->sector += nsect;
  10865. +    CURRENT->buffer += nsect<<9;
  10866. +    CURRENT->errors = 0;
  10867. +    i = (CURRENT->nr_sectors -= nsect);
  10868. +
  10869. +#ifdef DEBUG
  10870. +    printk("hd%c: read: sectors(%ld-%ld), remaining=%ld, buffer=0x%08lx\n",
  10871. +        dev+'a', CURRENT->sector, CURRENT->sector+nsect,
  10872. +        CURRENT->nr_sectors, (unsigned long) CURRENT->buffer+(nsect<<9));
  10873. +#endif
  10874. +    if ((CURRENT->current_nr_sectors -= nsect) <= 0)
  10875. +        end_request(1);
  10876. +    if (i > 0) {
  10877. +        if (msect)
  10878. +            goto ok_to_read;
  10879. +        SET_INTR(&read_intr);
  10880. +        return;
  10881. +    }
  10882. +    (void) inb_p(HD_STATUS);
  10883. +#if (HD_DELAY > 0)
  10884. +    last_req = read_timer();
  10885. +#endif
  10886. +    if (CURRENT)
  10887. +        hd_request();
  10888. +    return;
  10889. +}
  10890. +
  10891. +static inline void multwrite (unsigned int dev)
  10892. +{
  10893. +    unsigned int mcount = mult_count[dev];
  10894. +
  10895. +    while (mcount--) {
  10896. +        outsw(HD_DATA,WCURRENT.buffer,256);
  10897. +        if (!--WCURRENT.nr_sectors)
  10898. +            return;
  10899. +        WCURRENT.buffer += 512;
  10900. +        if (!--WCURRENT.current_nr_sectors) {
  10901. +            WCURRENT.bh = WCURRENT.bh->b_reqnext;
  10902. +            if (WCURRENT.bh == NULL)
  10903. +                panic("buffer list corrupted\n");
  10904. +            WCURRENT.current_nr_sectors = WCURRENT.bh->b_size>>9;
  10905. +            WCURRENT.buffer             = WCURRENT.bh->b_data;
  10906. +        }
  10907. +    }
  10908. +}
  10909. +
  10910. +static void multwrite_intr(void)
  10911. +{
  10912. +    int i;
  10913. +    unsigned int dev = DEVICE_NR(WCURRENT.rq_dev);
  10914. +
  10915. +    if (unmask_intr[dev])
  10916. +        sti();
  10917. +    if (OK_STATUS(i=inb_p(HD_STATUS))) {
  10918. +        if (i & DRQ_STAT) {
  10919. +            if (WCURRENT.nr_sectors) {
  10920. +                multwrite(dev);
  10921. +                SET_INTR(&multwrite_intr);
  10922. +                return;
  10923. +            }
  10924. +        } else {
  10925. +            if (!WCURRENT.nr_sectors) {    /* all done? */
  10926. +                for (i = CURRENT->nr_sectors; i > 0;){
  10927. +                    i -= CURRENT->current_nr_sectors;
  10928. +                    end_request(1);
  10929. +                }
  10930. +#if (HD_DELAY > 0)
  10931. +                last_req = read_timer();
  10932. +#endif
  10933. +                if (CURRENT)
  10934. +                    hd_request();
  10935. +                return;
  10936. +            }
  10937. +        }
  10938. +    }
  10939. +    dump_status("multwrite_intr", i);
  10940. +    bad_rw_intr();
  10941. +    hd_request();
  10942. +}
  10943. +
  10944. +static void write_intr(void)
  10945. +{
  10946. +    int i;
  10947. +    int retries = 100000;
  10948. +
  10949. +    if (unmask_intr[DEVICE_NR(WCURRENT.rq_dev)])
  10950. +        sti();
  10951. +    do {
  10952. +        i = (unsigned) inb_p(HD_STATUS);
  10953. +        if (i & BUSY_STAT)
  10954. +            continue;
  10955. +        if (!OK_STATUS(i))
  10956. +            break;
  10957. +        if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
  10958. +            goto ok_to_write;
  10959. +    } while (--retries > 0);
  10960. +    dump_status("write_intr", i);
  10961. +    bad_rw_intr();
  10962. +    hd_request();
  10963. +    return;
  10964. +ok_to_write:
  10965. +    CURRENT->sector++;
  10966. +    i = --CURRENT->nr_sectors;
  10967. +    --CURRENT->current_nr_sectors;
  10968. +    CURRENT->buffer += 512;
  10969. +    if (!i || (CURRENT->bh && !SUBSECTOR(i)))
  10970. +        end_request(1);
  10971. +    if (i > 0) {
  10972. +        SET_INTR(&write_intr);
  10973. +        outsw(HD_DATA,CURRENT->buffer,256);
  10974. +        sti();
  10975. +    } else {
  10976. +#if (HD_DELAY > 0)
  10977. +        last_req = read_timer();
  10978. +#endif
  10979. +        hd_request();
  10980. +    }
  10981. +    return;
  10982. +}
  10983. +
  10984. +static void recal_intr(void)
  10985. +{
  10986. +    check_status();
  10987. +#if (HD_DELAY > 0)
  10988. +    last_req = read_timer();
  10989. +#endif
  10990. +    hd_request();
  10991. +}
  10992. +
  10993. +/*
  10994. + * This is another of the error-routines I don't know what to do with. The
  10995. + * best idea seems to just set reset, and start all over again.
  10996. + */
  10997. +static void hd_times_out(void)
  10998. +{
  10999. +    unsigned int dev;
  11000. +
  11001. +    DEVICE_INTR = NULL;
  11002. +    if (!CURRENT)
  11003. +        return;
  11004. +    disable_irq(HD_IRQ);
  11005. +    sti();
  11006. +    reset = 1;
  11007. +    dev = DEVICE_NR(CURRENT->rq_dev);
  11008. +    printk("hd%c: timeout\n", dev+'a');
  11009. +    if (++CURRENT->errors >= MAX_ERRORS) {
  11010. +#ifdef DEBUG
  11011. +        printk("hd%c: too many errors\n", dev+'a');
  11012. +#endif
  11013. +        end_request(0);
  11014. +    }
  11015. +    cli();
  11016. +    hd_request();
  11017. +    enable_irq(HD_IRQ);
  11018. +}
  11019. +
  11020. +int do_special_op (unsigned int dev)
  11021. +{
  11022. +    if (recalibrate[dev]) {
  11023. +        recalibrate[dev] = 0;
  11024. +        hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
  11025. +        return reset;
  11026. +    }
  11027. +    if (!identified[dev]) {
  11028. +        identified[dev]  = 1;
  11029. +        unmask_intr[dev] = DEFAULT_UNMASK_INTR;
  11030. +        mult_req[dev]    = DEFAULT_MULT_COUNT;
  11031. +        hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
  11032. +        return reset;
  11033. +    }
  11034. +    if (mult_req[dev] != mult_count[dev]) {
  11035. +        hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
  11036. +        return reset;
  11037. +    }
  11038. +    if (hd_info[dev].head > 16) {
  11039. +        printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
  11040. +        end_request(0);
  11041. +    }
  11042. +    special_op[dev] = 0;
  11043. +    return 1;
  11044. +}
  11045. +
  11046. +/*
  11047. + * The driver enables interrupts as much as possible.  In order to do this,
  11048. + * (a) the device-interrupt is disabled before entering hd_request(),
  11049. + * and (b) the timeout-interrupt is disabled before the sti().
  11050. + *
  11051. + * Interrupts are still masked (by default) whenever we are exchanging
  11052. + * data/cmds with a drive, because some drives seem to have very poor
  11053. + * tolerance for latency during I/O.  For devices which don't suffer from
  11054. + * that problem (most don't), the unmask_intr[] flag can be set to unmask
  11055. + * other interrupts during data/cmd transfers (by defining DEFAULT_UNMASK_INTR
  11056. + * to 1, or by using "hdparm -u1 /dev/hd?" from the shell).
  11057. + */
  11058. +static void hd_request(void)
  11059. +{
  11060. +    unsigned int dev, block, nsect, sec, track, head, cyl;
  11061. +
  11062. +    if (CURRENT && CURRENT->rq_status == RQ_INACTIVE) return;
  11063. +    if (DEVICE_INTR)
  11064. +        return;
  11065. +repeat:
  11066. +    timer_active &= ~(1<<HD_TIMER);
  11067. +    sti();
  11068. +    INIT_REQUEST;
  11069. +    if (reset) {
  11070. +        cli();
  11071. +        reset_hd();
  11072. +        return;
  11073. +    }
  11074. +    dev = MINOR(CURRENT->rq_dev);
  11075. +    block = CURRENT->sector;
  11076. +    nsect = CURRENT->nr_sectors;
  11077. +    if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
  11078. +#ifdef DEBUG
  11079. +        if (dev >= (NR_HD<<6))
  11080. +            printk("hd: bad minor number: device=%s\n",
  11081. +                   kdevname(CURRENT->rq_dev));
  11082. +        else
  11083. +            printk("hd%c: bad access: block=%d, count=%d\n",
  11084. +                (MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);
  11085. +#endif
  11086. +        end_request(0);
  11087. +        goto repeat;
  11088. +    }
  11089. +    block += hd[dev].start_sect;
  11090. +    dev >>= 6;
  11091. +    if (special_op[dev]) {
  11092. +        if (do_special_op(dev))
  11093. +            goto repeat;
  11094. +        return;
  11095. +    }
  11096. +    sec   = block % hd_info[dev].sect + 1;
  11097. +    track = block / hd_info[dev].sect;
  11098. +    head  = track % hd_info[dev].head;
  11099. +    cyl   = track / hd_info[dev].head;
  11100. +#ifdef DEBUG
  11101. +    printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
  11102. +        dev+'a', (CURRENT->cmd == READ)?"read":"writ",
  11103. +        cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
  11104. +#endif
  11105. +    if (!unmask_intr[dev])
  11106. +        cli();
  11107. +    if (CURRENT->cmd == READ) {
  11108. +        unsigned int cmd = mult_count[dev] > 1 ? WIN_MULTREAD : WIN_READ;
  11109. +        hd_out(dev,nsect,sec,head,cyl,cmd,&read_intr);
  11110. +        if (reset)
  11111. +            goto repeat;
  11112. +        return;
  11113. +    }
  11114. +    if (CURRENT->cmd == WRITE) {
  11115. +printk ("hd%c: write disabled\n", (MINOR(CURRENT->rq_dev)>>6)+'a');
  11116. +end_request (0);
  11117. +goto repeat;
  11118. +        if (mult_count[dev])
  11119. +            hd_out(dev,nsect,sec,head,cyl,WIN_MULTWRITE,&multwrite_intr);
  11120. +        else
  11121. +            hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
  11122. +        if (reset)
  11123. +            goto repeat;
  11124. +        if (wait_DRQ()) {
  11125. +            bad_rw_intr();
  11126. +            goto repeat;
  11127. +        }
  11128. +        if (mult_count[dev]) {
  11129. +            WCURRENT = *CURRENT;
  11130. +            multwrite(dev);
  11131. +        } else
  11132. +            outsw(HD_DATA,CURRENT->buffer,256);
  11133. +        return;
  11134. +    }
  11135. +    panic("unknown hd-command");
  11136. +}
  11137. +
  11138. +static void do_hd_request (void)
  11139. +{
  11140. +    disable_irq(HD_IRQ);
  11141. +    hd_request();
  11142. +    enable_irq(HD_IRQ);
  11143. +}
  11144. +
  11145. +static int hd_ioctl(struct inode * inode, struct file * file,
  11146. +    unsigned int cmd, unsigned long arg)
  11147. +{
  11148. +    struct hd_geometry *loc = (struct hd_geometry *) arg;
  11149. +    int dev, err;
  11150. +    unsigned long flags;
  11151. +
  11152. +    if ((!inode) || !(inode->i_rdev))
  11153. +        return -EINVAL;
  11154. +    dev = DEVICE_NR(inode->i_rdev);
  11155. +    if (dev >= NR_HD)
  11156. +        return -EINVAL;
  11157. +    switch (cmd) {
  11158. +        case HDIO_GETGEO:
  11159. +            if (!loc)  return -EINVAL;
  11160. +            err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
  11161. +            if (err)
  11162. +                return err;
  11163. +            put_user(bios_info[dev].head,
  11164. +                (char *) &loc->heads);
  11165. +            put_user(bios_info[dev].sect,
  11166. +                (char *) &loc->sectors);
  11167. +            put_user(bios_info[dev].cyl,
  11168. +                (short *) &loc->cylinders);
  11169. +            put_user(hd[MINOR(inode->i_rdev)].start_sect,
  11170. +                (long *) &loc->start);
  11171. +            return 0;
  11172. +        case BLKRASET:
  11173. +            if(!suser())  return -EACCES;
  11174. +            if(arg > 0xff) return -EINVAL;
  11175. +            read_ahead[MAJOR(inode->i_rdev)] = arg;
  11176. +            return 0;
  11177. +        case BLKRAGET:
  11178. +            if (!arg)  return -EINVAL;
  11179. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  11180. +            if (err)
  11181. +                return err;
  11182. +            put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
  11183. +            return 0;
  11184. +             case BLKGETSIZE:   /* Return device size */
  11185. +            if (!arg)  return -EINVAL;
  11186. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  11187. +            if (err)
  11188. +                return err;
  11189. +            put_user(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
  11190. +            return 0;
  11191. +        case BLKFLSBUF:
  11192. +            if(!suser())  return -EACCES;
  11193. +            fsync_dev(inode->i_rdev);
  11194. +            invalidate_buffers(inode->i_rdev);
  11195. +            return 0;
  11196. +
  11197. +        case BLKRRPART: /* Re-read partition tables */
  11198. +            return revalidate_hddisk(inode->i_rdev, 1);
  11199. +
  11200. +        case HDIO_SET_UNMASKINTR:
  11201. +            if (!suser()) return -EACCES;
  11202. +            if ((arg > 1) || (MINOR(inode->i_rdev) & 0x3F))
  11203. +                return -EINVAL;
  11204. +            unmask_intr[dev] = arg;
  11205. +            return 0;
  11206. +
  11207. +                case HDIO_GET_UNMASKINTR:
  11208. +            if (!arg)  return -EINVAL;
  11209. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  11210. +            if (err)
  11211. +                return err;
  11212. +            put_user(unmask_intr[dev], (long *) arg);
  11213. +            return 0;
  11214. +
  11215. +                case HDIO_GET_MULTCOUNT:
  11216. +            if (!arg)  return -EINVAL;
  11217. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  11218. +            if (err)
  11219. +                return err;
  11220. +            put_user(mult_count[dev], (long *) arg);
  11221. +            return 0;
  11222. +
  11223. +        case HDIO_SET_MULTCOUNT:
  11224. +            if (!suser()) return -EACCES;
  11225. +            if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
  11226. +            save_flags(flags);
  11227. +            cli();    /* a prior request might still be in progress */
  11228. +            if (arg > max_mult[dev])
  11229. +                err = -EINVAL;    /* out of range for device */
  11230. +            else if (mult_req[dev] != mult_count[dev]) {
  11231. +                special_op[dev] = 1;
  11232. +                err = -EBUSY;    /* busy, try again */
  11233. +            } else {
  11234. +                mult_req[dev] = arg;
  11235. +                special_op[dev] = 1;
  11236. +                err = 0;
  11237. +            }
  11238. +            restore_flags(flags);
  11239. +            return err;
  11240. +
  11241. +        case HDIO_GET_IDENTITY:
  11242. +            if (!arg)  return -EINVAL;
  11243. +            if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
  11244. +            if (hd_ident_info[dev] == NULL)  return -ENOMSG;
  11245. +            err = verify_area(VERIFY_WRITE, (char *) arg, sizeof(struct hd_driveid));
  11246. +            if (err)
  11247. +                return err;
  11248. +            memcpy_tofs((char *)arg, (char *) hd_ident_info[dev], sizeof(struct hd_driveid));
  11249. +            return 0;
  11250. +
  11251. +        RO_IOCTLS(inode->i_rdev,arg);
  11252. +        default:
  11253. +            return -EINVAL;
  11254. +    }
  11255. +}
  11256. +
  11257. +static int hd_open(struct inode * inode, struct file * filp)
  11258. +{
  11259. +    int target;
  11260. +    target =  DEVICE_NR(inode->i_rdev);
  11261. +
  11262. +    if (target >= NR_HD)
  11263. +        return -ENODEV;
  11264. +    while (busy[target])
  11265. +        sleep_on(&busy_wait);
  11266. +    access_count[target]++;
  11267. +    return 0;
  11268. +}
  11269. +
  11270. +/*
  11271. + * Releasing a block device means we sync() it, so that it can safely
  11272. + * be forgotten about...
  11273. + */
  11274. +static void hd_release(struct inode * inode, struct file * file)
  11275. +{
  11276. +        int target;
  11277. +    sync_dev(inode->i_rdev);
  11278. +
  11279. +    target =  DEVICE_NR(inode->i_rdev);
  11280. +    access_count[target]--;
  11281. +
  11282. +}
  11283. +
  11284. +static void hd_geninit(struct gendisk *);
  11285. +
  11286. +static struct gendisk hd_gendisk = {
  11287. +    MAJOR_NR,    /* Major number */    
  11288. +    "hd",        /* Major name */
  11289. +    6,        /* Bits to shift to get real from partition */
  11290. +    1 << 6,        /* Number of partitions per real */
  11291. +    MAX_HD,        /* maximum number of real */
  11292. +    hd_geninit,    /* init function */
  11293. +    hd,        /* hd struct */
  11294. +    hd_sizes,    /* block sizes */
  11295. +    0,        /* number */
  11296. +    (void *) bios_info,    /* internal */
  11297. +    NULL        /* next */
  11298. +};
  11299. +    
  11300. +static void hd_interrupt(int irq, struct pt_regs *regs)
  11301. +{
  11302. +    void (*handler)(void) = DEVICE_INTR;
  11303. +
  11304. +    DEVICE_INTR = NULL;
  11305. +    timer_active &= ~(1<<HD_TIMER);
  11306. +    if (!handler)
  11307. +        handler = unexpected_hd_interrupt;
  11308. +    handler();
  11309. +    sti();
  11310. +}
  11311. +
  11312. +/*
  11313. + * Since we find out the physical drive geometry, we don't touch that.
  11314. + * We only alter the logical disk geometry that is passed to user programs.
  11315. + * [as per PC Linux].
  11316. + */
  11317. +void hd_set_geometry (kdev_t dev, unsigned char secspertrack, unsigned char heads,
  11318. +        unsigned long discsize, unsigned int secsize)
  11319. +{
  11320. +    int minor = MINOR(dev);
  11321. +    int drv = minor >> 6;
  11322. +
  11323. +    if (bios_info[drv].cyl == 1) {
  11324. +    bios_info[drv].cyl = discsize / (secspertrack * heads * secsize);
  11325. +    bios_info[drv].head = heads;
  11326. +    bios_info[drv].wpcom = -1;
  11327. +    bios_info[drv].ctl = 8;
  11328. +    bios_info[drv].lzone = bios_info[drv].cyl - 1;
  11329. +    bios_info[drv].sect = secspertrack;
  11330. +    }
  11331. +    hd[minor].start_sect = 0;
  11332. +    hd[minor].nr_sects = discsize / secsize;
  11333. +}
  11334. +
  11335. +/*
  11336. + * This is the harddisk IRQ description. The SA_INTERRUPT in sa_flags
  11337. + * means we run the IRQ-handler with interrupts disabled: this is bad for
  11338. + * interrupt latency, but anything else has led to problems on some
  11339. + * machines...
  11340. + *
  11341. + * We enable interrupts in some of the routines after making sure it's
  11342. + * safe.
  11343. + */
  11344. +static void hd_geninit(struct gendisk *dev)
  11345. +{
  11346. +    int i;
  11347. +
  11348. +    if (!NR_HD) {
  11349. +        int drive;
  11350. +        extern int number_ide_drives;
  11351. +        /*
  11352. +         * Default settings
  11353. +         *
  11354. +         * If we don't know anything about the drive, then set it
  11355. +         * so that we have enough to read the boot sector of the
  11356. +         * ADFS drive.  This means that you *MUST* specify the
  11357. +         * drive parameters of *all* drives if you have one IDE
  11358. +         * drive that is not ADFS formatted.
  11359. +         */
  11360. +        for (drive=0 ; drive<2 ; drive++) {
  11361. +            bios_info[drive].cyl   = hd_info[drive].cyl = 1;
  11362. +            bios_info[drive].head  = hd_info[drive].head = 1;
  11363. +            bios_info[drive].wpcom = hd_info[drive].wpcom = -1;
  11364. +            bios_info[drive].ctl   = hd_info[drive].ctl = 8;
  11365. +            bios_info[drive].lzone = hd_info[drive].lzone = 1;
  11366. +            bios_info[drive].sect  = hd_info[drive].sect = 17;
  11367. +        }
  11368. +
  11369. +        /*
  11370. +         * We only set this to the one that the host OS gave us
  11371. +         * if the user has not defined any types.
  11372. +         */
  11373. +        NR_HD = number_ide_drives;
  11374. +    }
  11375. +
  11376. +    i = NR_HD;
  11377. +    while (i-- > 0) {
  11378. +        /*
  11379. +         * The newer E-IDE BIOSs handle drives larger than 1024
  11380. +         * cylinders by increasing the number of logical heads
  11381. +         * to keep the number of logical cylinders below the
  11382. +         * sacred INT13 limit of 1024 (10 bits).  If that is
  11383. +         * what's happening here, we'll find out and correct
  11384. +         * it later when "identifying" the drive.
  11385. +         */
  11386. +        hd[i<<6].nr_sects = bios_info[i].head *
  11387. +                bios_info[i].sect * bios_info[i].cyl;
  11388. +        hd_ident_info[i] = (struct hd_driveid *) kmalloc(512,GFP_KERNEL);
  11389. +        special_op[i] = 1;
  11390. +    }
  11391. +    if (NR_HD) {
  11392. +        if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd")) {
  11393. +            printk("hd: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
  11394. +            NR_HD = 0;
  11395. +        } else {
  11396. +            request_region(HD_DATA, 8, "hd");
  11397. +            request_region(HD_CMD, 1, "hd(cmd)");
  11398. +        }
  11399. +    }
  11400. +    hd_gendisk.nr_real = NR_HD;
  11401. +
  11402. +    for (i = 0; i < (MAX_HD << 6); i++) {
  11403. +        hd_blocksizes[i] = 1024;
  11404. +        hd_hardsectsizes[i] = 512;
  11405. +    }
  11406. +    blksize_size[MAJOR_NR] = hd_blocksizes;
  11407. +    hardsect_size[MAJOR_NR] = hd_hardsectsizes;
  11408. +}
  11409. +
  11410. +static struct file_operations hd_fops = {
  11411. +    NULL,            /* lseek - default */
  11412. +    block_read,        /* read - general block-dev read */
  11413. +    block_write,        /* write - general block-dev write */
  11414. +    NULL,            /* readdir - bad */
  11415. +    NULL,            /* select */
  11416. +    hd_ioctl,        /* ioctl */
  11417. +    NULL,            /* mmap */
  11418. +    hd_open,        /* open */
  11419. +    hd_release,        /* release */
  11420. +    block_fsync        /* fsync */
  11421. +};
  11422. +
  11423. +int hd_init(void)
  11424. +{
  11425. +    if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
  11426. +        printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);
  11427. +        return -1;
  11428. +    }
  11429. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  11430. +    read_ahead[MAJOR_NR] = 8;        /* 8 sector (4kB) read-ahead */
  11431. +    hd_gendisk.next = gendisk_head;
  11432. +    gendisk_head = &hd_gendisk;
  11433. +    timer_table[HD_TIMER].fn = hd_times_out;
  11434. +    return 0;
  11435. +}
  11436. +
  11437. +#define DEVICE_BUSY busy[target]
  11438. +#define USAGE access_count[target]
  11439. +#define CAPACITY (bios_info[target].head*bios_info[target].sect*bios_info[target].cyl)
  11440. +/* We assume that the the bios parameters do not change, so the disk capacity
  11441. +   will not change */
  11442. +#undef MAYBE_REINIT
  11443. +#define GENDISK_STRUCT hd_gendisk
  11444. +
  11445. +/*
  11446. + * This routine is called to flush all partitions and partition tables
  11447. + * for a changed scsi disk, and then re-read the new partition table.
  11448. + * If we are revalidating a disk because of a media change, then we
  11449. + * enter with usage == 0.  If we are using an ioctl, we automatically have
  11450. + * usage == 1 (we need an open channel to use an ioctl :-), so this
  11451. + * is our limit.
  11452. + */
  11453. +static int revalidate_hddisk(kdev_t dev, int maxusage)
  11454. +{
  11455. +    int target;
  11456. +    struct gendisk * gdev;
  11457. +    int max_p;
  11458. +    int start;
  11459. +    int i;
  11460. +    long flags;
  11461. +
  11462. +    target = DEVICE_NR(dev);
  11463. +    gdev = &GENDISK_STRUCT;
  11464. +
  11465. +    save_flags_cli (flags);
  11466. +    if (DEVICE_BUSY || USAGE > maxusage) {
  11467. +        restore_flags(flags);
  11468. +        return -EBUSY;
  11469. +    };
  11470. +    DEVICE_BUSY = 1;
  11471. +    restore_flags(flags);
  11472. +
  11473. +    max_p = gdev->max_p;
  11474. +    start = target << gdev->minor_shift;
  11475. +
  11476. +    for (i=max_p - 1; i >=0 ; i--) {
  11477. +        int minor = start + i;
  11478. +        kdev_t devi = MKDEV(MAJOR_NR, minor);
  11479. +        sync_dev(devi);
  11480. +        invalidate_inodes(devi);
  11481. +        invalidate_buffers(devi);
  11482. +        gdev->part[minor].start_sect = 0;
  11483. +        gdev->part[minor].nr_sects = 0;
  11484. +    };
  11485. +
  11486. +#ifdef MAYBE_REINIT
  11487. +    MAYBE_REINIT;
  11488. +#endif
  11489. +
  11490. +    gdev->part[start].nr_sects = CAPACITY;
  11491. +    resetup_one_dev(gdev, target);
  11492. +
  11493. +    DEVICE_BUSY = 0;
  11494. +    wake_up(&busy_wait);
  11495. +    return 0;
  11496. +}
  11497. +
  11498. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/ide-ics.c linux/arch/arm/drivers/block/ide-ics.c
  11499. --- linux.orig/arch/arm/drivers/block/ide-ics.c    Thu Jan  1 01:00:00 1970
  11500. +++ linux/arch/arm/drivers/block/ide-ics.c    Sun Jun 16 19:37:45 1996
  11501. @@ -0,0 +1,88 @@
  11502. +/*
  11503. + * linux/arch/arm/drivers/block/ide-ics.c
  11504. + *
  11505. + * Copyright (c) 1996 Russell King.
  11506. + *
  11507. + * Changelog:
  11508. + *  08-06-1996    RMK    Created
  11509. + */
  11510. +
  11511. +#ifdef MODULE
  11512. +#include <linux/module.h>
  11513. +#include <linux/version.h>
  11514. +#endif
  11515. +#include <linux/errno.h>
  11516. +
  11517. +#include <asm/ecard.h>
  11518. +
  11519. +static const int icside_prods[] = {};
  11520. +static const int icside_manus[] = {};
  11521. +
  11522. +#ifndef MODULE
  11523. +
  11524. +int icside_init (void)
  11525. +{
  11526. +    struct expansion_card *ec;
  11527. +    unsigned long port;
  11528. +    int i;
  11529. +
  11530. +    while (1) {
  11531. +    if ((ec = ecard_find (0, sizeof (icside_prods) / sizeof (int), icside_prods, icside_manus))
  11532. +        == NULL)
  11533. +        break;
  11534. +
  11535. +    port = ((unsigned long)ecard_address (ec->slot_no, ECARD_MEMC, 0)) >> 2;
  11536. +
  11537. +    ecard_claim (ec);
  11538. +
  11539. +    i = ide_register_port (port, ec->irq, 16);
  11540. +    if (i < 0)
  11541. +        return i;
  11542. +    }
  11543. +    return 0;
  11544. +}
  11545. +
  11546. +#else
  11547. +static struct expansion_card *ec[MAX_ECARDS];
  11548. +
  11549. +int init_module (void)
  11550. +{
  11551. +    int i, j = 0;
  11552. +
  11553. +    for (i = 0; i < MAX_ECARDS; i++)
  11554. +    ec[i] = NULL;
  11555. +
  11556. +    while (1) {
  11557. +    unsigned long port;
  11558. +    if ((ec[j] = ecard_find (0, sizeof (icside_prods) / sizeof (int), icside_prods, icside_manus))
  11559. +        == NULL)
  11560. +        break;
  11561. +
  11562. +    port = ((unsigned long)ecard_address (ec[j]->slot_no, ECARD_MEMC, 0)) >> 2;
  11563. +
  11564. +    ecard_claim (ec[j]);
  11565. +
  11566. +    i = ide_register_port (port, ec[j]->irq, 16);
  11567. +    if (i < 0)
  11568. +        return i;
  11569. +    j ++;
  11570. +    }
  11571. +    return 0;
  11572. +}
  11573. +
  11574. +void cleanup_module (void)
  11575. +{
  11576. +    int i;
  11577. +    
  11578. +    for (i = 0; i < MAX_ECARDS; i++)
  11579. +    if (ec[i]) {
  11580. +        unsigned long port;
  11581. +        port = ((unsigned long)ecard_address (ec[i]->slot_no, ECARD_MEMC, 0)) >> 2;
  11582. +
  11583. +        ide_unregister_port (port, ec[i]->irq, 16);
  11584. +        ecard_release (ec[i]);
  11585. +        ec[i] = NULL;
  11586. +    }
  11587. +}
  11588. +#endif
  11589. +
  11590. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/ide.c linux/arch/arm/drivers/block/ide.c
  11591. --- linux.orig/arch/arm/drivers/block/ide.c    Thu Jan  1 01:00:00 1970
  11592. +++ linux/arch/arm/drivers/block/ide.c    Sat Aug 17 23:23:26 1996
  11593. @@ -0,0 +1,3384 @@
  11594. +/*
  11595. + *  linux/drivers/block/ide.c    Version 5.51  Aug  10, 1996
  11596. + *
  11597. + *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  11598. + */
  11599. +#define _IDE_C        /* needed by <linux/blk.h> */
  11600. +
  11601. +/*
  11602. + *  Maintained by Mark Lord  <mlord@pobox.com>
  11603. + *            and Gadi Oxman <gadio@netvision.net.il>
  11604. + *
  11605. + * This is the multiple IDE interface driver, as evolved from hd.c.
  11606. + * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
  11607. + * There can be up to two drives per interface, as per the ATA-2 spec.
  11608. + *
  11609. + * Primary:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
  11610. + * Secondary:  ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
  11611. + * Tertiary:   ide2, port 0x???; major=33; hde is minor=0; hdf is minor=64
  11612. + * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64
  11613. + *
  11614. + * It is easy to extend ide.c to handle more than four interfaces:
  11615. + *
  11616. + *    Change the MAX_HWIFS constant in ide.h.
  11617. + *
  11618. + *    Define some new major numbers (in major.h), and insert them into
  11619. + *    the ide_hwif_to_major table in ide.c.
  11620. + *
  11621. + *    Fill in the extra values for the new interfaces into the two tables
  11622. + *    inside ide.c:  default_io_base[]  and  default_irqs[].
  11623. + *
  11624. + *    Create the new request handlers by cloning "do_ide3_request()"
  11625. + *    for each new interface, and add them to the switch statement
  11626. + *    in the ide_init() function in ide.c.
  11627. + *
  11628. + *    Recompile, create the new /dev/ entries, and it will probably work.
  11629. + *
  11630. + *  From hd.c:
  11631. + *  |
  11632. + *  | It traverses the request-list, using interrupts to jump between functions.
  11633. + *  | As nearly all functions can be called within interrupts, we may not sleep.
  11634. + *  | Special care is recommended.  Have Fun!
  11635. + *  |
  11636. + *  | modified by Drew Eckhardt to check nr of hd's from the CMOS.
  11637. + *  |
  11638. + *  | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  11639. + *  | in the early extended-partition checks and added DM partitions.
  11640. + *  |
  11641. + *  | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
  11642. + *  |
  11643. + *  | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
  11644. + *  | and general streamlining by Mark Lord (mlord@pobox.com).
  11645. + *
  11646. + *  October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
  11647. + *
  11648. + *    Mark Lord    (mlord@pobox.com)        (IDE Perf.Pkg)
  11649. + *    Delman Lee    (delman@mipg.upenn.edu)        ("Mr. atdisk2")
  11650. + *    Scott Snyder    (snyder@fnald0.fnal.gov)    (ATAPI IDE cd-rom)
  11651. + *
  11652. + *  This was a rewrite of just about everything from hd.c, though some original
  11653. + *  code is still sprinkled about.  Think of it as a major evolution, with
  11654. + *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
  11655. + *
  11656. + *  Version 1.0 ALPHA    initial code, primary i/f working okay
  11657. + *  Version 1.3 BETA    dual i/f on shared irq tested & working!
  11658. + *  Version 1.4 BETA    added auto probing for irq(s)
  11659. + *  Version 1.5 BETA    added ALPHA (untested) support for IDE cd-roms,
  11660. + *  ...
  11661. + *  Version 3.5        correct the bios_cyl field if it's too small
  11662. + *  (linux 1.1.76)     (to help fdisk with brain-dead BIOSs)
  11663. + *  Version 3.6        cosmetic corrections to comments and stuff
  11664. + *  (linux 1.1.77)    reorganise probing code to make it understandable
  11665. + *            added halfway retry to probing for drive identification
  11666. + *            added "hdx=noprobe" command line option
  11667. + *            allow setting multmode even when identification fails
  11668. + *  Version 3.7        move set_geometry=1 from do_identify() to ide_init()
  11669. + *            increase DRQ_WAIT to eliminate nuisance messages
  11670. + *            wait for DRQ_STAT instead of DATA_READY during probing
  11671. + *              (courtesy of Gary Thomas gary@efland.UU.NET)
  11672. + *  Version 3.8        fixed byte-swapping for confused Mitsumi cdrom drives
  11673. + *            update of ide-cd.c from Scott, allows blocksize=1024
  11674. + *            cdrom probe fixes, inspired by jprang@uni-duisburg.de
  11675. + *  Version 3.9        don't use LBA if lba_capacity looks funny
  11676. + *            correct the drive capacity calculations
  11677. + *            fix probing for old Seagates without IDE_ALTSTATUS_REG
  11678. + *            fix byte-ordering for some NEC cdrom drives
  11679. + *  Version 3.10    disable multiple mode by default; was causing trouble
  11680. + *  Version 3.11    fix mis-identification of old WD disks as cdroms
  11681. + *  Version 3,12    simplify logic for selecting initial mult_count
  11682. + *              (fixes problems with buggy WD drives)
  11683. + *  Version 3.13    remove excess "multiple mode disabled" messages
  11684. + *  Version 3.14    fix ide_error() handling of BUSY_STAT
  11685. + *            fix byte-swapped cdrom strings (again.. arghh!)
  11686. + *            ignore INDEX bit when checking the ALTSTATUS reg
  11687. + *  Version 3.15    add SINGLE_THREADED flag for use with dual-CMD i/f
  11688. + *            ignore WRERR_STAT for non-write operations
  11689. + *            added vlb_sync support for DC-2000A & others,
  11690. + *             (incl. some Promise chips), courtesy of Frank Gockel
  11691. + *  Version 3.16    convert vlb_32bit and vlb_sync into runtime flags
  11692. + *            add ioctls to get/set VLB flags (HDIO_[SG]ET_CHIPSET)
  11693. + *            rename SINGLE_THREADED to SUPPORT_SERIALIZE,
  11694. + *            add boot flag to "serialize" operation for CMD i/f
  11695. + *            add optional support for DTC2278 interfaces,
  11696. + *             courtesy of andy@cercle.cts.com (Dyan Wile).
  11697. + *            add boot flag to enable "dtc2278" probe
  11698. + *            add probe to avoid EATA (SCSI) interfaces,
  11699. + *             courtesy of neuffer@goofy.zdv.uni-mainz.de.
  11700. + *  Version 4.00    tidy up verify_area() calls - heiko@colossus.escape.de
  11701. + *            add flag to ignore WRERR_STAT for some drives
  11702. + *             courtesy of David.H.West@um.cc.umich.edu
  11703. + *            assembly syntax tweak to vlb_sync
  11704. + *            removable drive support from scuba@cs.tu-berlin.de
  11705. + *            add transparent support for DiskManager-6.0x "Dynamic
  11706. + *             Disk Overlay" (DDO), most of this is in genhd.c
  11707. + *            eliminate "multiple mode turned off" message at boot
  11708. + *  Version 4.10    fix bug in ioctl for "hdparm -c3"
  11709. + *            fix DM6:DDO support -- now works with LILO, fdisk, ...
  11710. + *            don't treat some naughty WD drives as removable
  11711. + *  Version 4.11    updated DM6 support using info provided by OnTrack
  11712. + *  Version 5.00    major overhaul, multmode setting fixed, vlb_sync fixed
  11713. + *            added support for 3rd/4th/alternative IDE ports
  11714. + *            created ide.h; ide-cd.c now compiles separate from ide.c
  11715. + *            hopefully fixed infinite "unexpected_intr" from cdroms
  11716. + *            zillions of other changes and restructuring
  11717. + *            somehow reduced overall memory usage by several kB
  11718. + *            probably slowed things down slightly, but worth it
  11719. + *  Version 5.01    AT LAST!!  Finally understood why "unexpected_intr"
  11720. + *             was happening at various times/places:  whenever the
  11721. + *             ide-interface's ctl_port was used to "mask" the irq,
  11722. + *             it also would trigger an edge in the process of masking
  11723. + *             which would result in a self-inflicted interrupt!!
  11724. + *             (such a stupid way to build a hardware interrupt mask).
  11725. + *             This is now fixed (after a year of head-scratching).
  11726. + *  Version 5.02    got rid of need for {enable,disable}_irq_list()
  11727. + *  Version 5.03    tune-ups, comments, remove "busy wait" from drive resets
  11728. + *            removed PROBE_FOR_IRQS option -- no longer needed
  11729. + *            OOOPS!  fixed "bad access" bug for 2nd drive on an i/f
  11730. + *  Version 5.04    changed "ira %d" to "irq %d" in DEBUG message
  11731. + *            added more comments, cleaned up unexpected_intr()
  11732. + *            OOOPS!  fixed null pointer problem in ide reset code
  11733. + *            added autodetect for Triton chipset -- no effect yet
  11734. + *  Version 5.05    OOOPS!  fixed bug in revalidate_disk()
  11735. + *            OOOPS!  fixed bug in ide_do_request()
  11736. + *            added ATAPI reset sequence for cdroms
  11737. + *  Version 5.10    added Bus-Mastered DMA support for Triton Chipset
  11738. + *            some (mostly) cosmetic changes
  11739. + *  Version 5.11    added ht6560b support by malafoss@snakemail.hut.fi
  11740. + *            reworked PCI scanning code
  11741. + *            added automatic RZ1000 detection/support
  11742. + *            added automatic PCI CMD640 detection/support
  11743. + *            added option for VLB CMD640 support
  11744. + *            tweaked probe to find cdrom on hdb with disks on hda,hdc
  11745. + *  Version 5.12    some performance tuning
  11746. + *            added message to alert user to bad /dev/hd[cd] entries
  11747. + *            OOOPS!  fixed bug in atapi reset
  11748. + *            driver now forces "serialize" again for all cmd640 chips
  11749. + *            noticed REALLY_SLOW_IO had no effect, moved it to ide.c
  11750. + *            made do_drive_cmd() into public ide_do_drive_cmd()
  11751. + *  Version 5.13    fixed typo ('B'), thanks to houston@boyd.geog.mcgill.ca
  11752. + *            fixed ht6560b support
  11753. + *  Version 5.13b (sss)    fix problem in calling ide_cdrom_setup()
  11754. + *            don't bother invalidating nonexistent partitions
  11755. + *  Version 5.14    fixes to cmd640 support.. maybe it works now(?)
  11756. + *            added & tested full EZ-DRIVE support -- don't use LILO!
  11757. + *            don't enable 2nd CMD640 PCI port during init - conflict
  11758. + *  Version 5.15    bug fix in init_cmd640_vlb()
  11759. + *            bug fix in interrupt sharing code
  11760. + *  Version 5.16    ugh.. fix "serialize" support, broken in 5.15
  11761. + *            remove "Huh?" from cmd640 code
  11762. + *            added qd6580 interface speed select from Colten Edwards
  11763. + *  Version 5.17    kludge around bug in BIOS32 on Intel triton motherboards
  11764. + *  Version 5.18    new CMD640 code, moved to cmd640.c, #include'd for now
  11765. + *            new UMC8672 code, moved to umc8672.c, #include'd for now
  11766. + *            disallow turning on DMA when h/w not capable of DMA
  11767. + *  Version 5.19    fix potential infinite timeout on resets
  11768. + *            extend reset poll into a general purpose polling scheme
  11769. + *            add atapi tape drive support from Gadi Oxman
  11770. + *            simplify exit from _intr routines -- no IDE_DO_REQUEST
  11771. + *  Version 5.20    leave current rq on blkdev request list during I/O
  11772. + *            generalized ide_do_drive_cmd() for tape/cdrom driver use
  11773. + *  Version 5.21    fix nasty cdrom/tape bug (ide_preempt was messed up)
  11774. + *  Version 5.22    fix ide_xlate_1024() to work with/without drive->id
  11775. + *  Version 5.23    miscellaneous touch-ups
  11776. + *  Version 5.24    fix #if's for SUPPORT_CMD640
  11777. + *  Version 5.25    more touch-ups, fix cdrom resets, ...
  11778. + *            cmd640.c now configs/compiles separate from ide.c
  11779. + *  Version 5.26    keep_settings now maintains the using_dma flag
  11780. + *            fix [EZD] remap message to only output at boot time
  11781. + *            fix "bad /dev/ entry" message to say hdc, not hdc0
  11782. + *            fix ide_xlate_1024() to respect user specified CHS
  11783. + *            use CHS from partn table if it looks translated
  11784. + *            re-merged flags chipset,vlb_32bit,vlb_sync into io_32bit
  11785. + *            keep track of interface chipset type, when known
  11786. + *            add generic PIO mode "tuneproc" mechanism
  11787. + *            fix cmd640_vlb option
  11788. + *            fix ht6560b support (was completely broken)
  11789. + *            umc8672.c now configures/compiles separate from ide.c
  11790. + *            move dtc2278 support to dtc2278.c
  11791. + *            move ht6560b support to ht6560b.c
  11792. + *            move qd6580  support to qd6580.c
  11793. + *            add  ali14xx support in ali14xx.c
  11794. + * Version 5.27        add [no]autotune parameters to help cmd640
  11795. + *            move rz1000  support to rz1000.c
  11796. + * Version 5.28        #include "ide_modes.h"
  11797. + *            fix disallow_unmask: now per-interface "no_unmask" bit
  11798. + *            force io_32bit to be the same on drive pairs of dtc2278
  11799. + *            improved IDE tape error handling, and tape DMA support
  11800. + *            bugfix in ide_do_drive_cmd() for cdroms + serialize
  11801. + * Version 5.29        fixed non-IDE check for too many physical heads
  11802. + *            don't use LBA if capacity is smaller than CHS
  11803. + * Version 5.30        remove real_devices kludge, formerly used by genhd.c
  11804. + * Version 5.32        change "KB" to "kB"
  11805. + *            fix serialize (was broken in kernel 1.3.72)
  11806. + *            add support for "hdparm -I"
  11807. + *            use common code for disk/tape/cdrom IDE_DRIVE_CMDs
  11808. + *            add support for Promise DC4030VL caching card
  11809. + *            improved serialize support
  11810. + *            put partition check back into alphabetical order
  11811. + *            add config option for PCMCIA baggage
  11812. + *            try to make PCMCIA support safer to use
  11813. + *            improve security on ioctls(): all are suser() only
  11814. + * Version 5.33        improve handling of HDIO_DRIVE_CMDs that read data
  11815. + * Version 5.34        fix irq-sharing problem from 5.33
  11816. + *            fix cdrom ioctl problem from 5.33
  11817. + * Version 5.35        cosmetic changes
  11818. + *            fix cli() problem in try_to_identify()
  11819. + * Version 5.36        fixes to optional PCMCIA support
  11820. + * Version 5.37        don't use DMA when "noautotune" is specified
  11821. + * Version 5.37a (go)    fix shared irq probing (was broken in kernel 1.3.72)
  11822. + *            call unplug_device() from ide_do_drive_cmd()
  11823. + * Version 5.38        add "hdx=none" option, courtesy of Joel Maslak
  11824. + *            mask drive irq after use, if sharing with another hwif
  11825. + *            add code to help debug weird cmd640 problems
  11826. + * Version 5.39        fix horrible error in earlier irq sharing "fix"
  11827. + * Version 5.40        fix serialization -- was broken in 5.39
  11828. + *            help sharing by masking device irq after probing
  11829. + * Version 5.41        more fixes to irq sharing/serialize detection
  11830. + *            disable io_32bit by default on drive reset
  11831. + * Version 5.42        simplify irq-masking after probe
  11832. + *            fix NULL pointer deref in save_match()
  11833. + * Version 5.43        Ugh.. unexpected_intr is back: try to exterminate it
  11834. + * Version 5.44        Fix for "irq probe failed" on cmd640
  11835. + *            change path on message regarding MAKEDEV.ide
  11836. + *            add a throttle to the unexpected_intr() messages
  11837. + * Version 5.45        fix ugly parameter parsing bugs (thanks Derek)
  11838. + *            include Gadi's magic fix for cmd640 unexpected_intr
  11839. + *            include mc68000 patches from Geert Uytterhoeven
  11840. + *            add Gadi's fix for PCMCIA cdroms
  11841. + * Version 5.46        remove the mc68000 #ifdefs for 2.0.x
  11842. + * Version 5.47        fix set_tune race condition
  11843. + *            fix bug in earlier PCMCIA cdrom update
  11844. + * Version 5.48        if def'd, invoke CMD640_DUMP_REGS when irq probe fails
  11845. + *            lengthen the do_reset1() pulse, for laptops
  11846. + *            add idebus=xx parameter for cmd640 and ali chipsets
  11847. + *            no_unmask flag now per-drive instead of per-hwif
  11848. + *            fix tune_req so that it gets done immediately
  11849. + *            fix missing restore_flags() in ide_ioctl
  11850. + *            prevent use of io_32bit on cmd640 with no prefetch
  11851. + * Version 5.49        fix minor quirks in probing routines
  11852. + * Version 5.50        allow values as small as 20 for idebus=
  11853. + * Version 5.51        force non io_32bit in drive_cmd_intr()
  11854. + *            change delay_10ms() to delay_50ms() to fix problems
  11855. + *
  11856. + *--------------------------------------------------------------------------------
  11857. + *  Ported to ARM architecture by Russell King (rmk92@ecs.soton.ac.uk)
  11858. + *--------------------------------------------------------------------------------
  11859. + *  Some additional driver compile-time options are in ide.h
  11860. + *
  11861. + *  To do, in likely order of completion:
  11862. + *    - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
  11863. + */
  11864. +
  11865. +#undef REALLY_SLOW_IO        /* most systems can safely undef this */
  11866. +
  11867. +#include <linux/config.h>
  11868. +#include <linux/types.h>
  11869. +#include <linux/string.h>
  11870. +#include <linux/kernel.h>
  11871. +#include <linux/delay.h>
  11872. +#include <linux/timer.h>
  11873. +#include <linux/mm.h>
  11874. +#include <linux/ioport.h>
  11875. +#include <linux/interrupt.h>
  11876. +#include <linux/major.h>
  11877. +#include <linux/blkdev.h>
  11878. +#include <linux/errno.h>
  11879. +#include <linux/hdreg.h>
  11880. +#include <linux/genhd.h>
  11881. +#include <linux/malloc.h>
  11882. +
  11883. +#include <asm/byteorder.h>
  11884. +#include <asm/irq.h>
  11885. +#include <asm/segment.h>
  11886. +#include <asm/io.h>
  11887. +
  11888. +#ifdef CONFIG_PCI
  11889. +#include <linux/bios32.h>
  11890. +#include <linux/pci.h>
  11891. +#endif /* CONFIG_PCI */
  11892. +
  11893. +#include "ide.h"
  11894. +#include "ide_modes.h"
  11895. +
  11896. +#define IS_PROMISE_DRIVE (0)    /* auto-NULLs out Promise code */
  11897. +
  11898. +static const byte    ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR};
  11899. +static const unsigned long default_io_base[MAX_HWIFS] = {0x1f0};
  11900. +static const byte    default_irqs[MAX_HWIFS]     = {11};
  11901. +static int    idebus_parameter; /* holds the "idebus=" parameter */
  11902. +static int    system_bus_speed; /* holds what we think is VESA/PCI bus speed */
  11903. +
  11904. +/*
  11905. + * This is declared extern in ide.h, for access by other IDE modules:
  11906. + */
  11907. +ide_hwif_t    ide_hwifs[MAX_HWIFS];    /* master data repository */
  11908. +
  11909. +#if (DISK_RECOVERY_TIME > 0)
  11910. +#error DISK_RECOVERY_TIME is not supported on the ARM.
  11911. +/*
  11912. + * For really screwy hardware (hey, at least it *can* be used with Linux)
  11913. + * we can enforce a minimum delay time between successive operations.
  11914. + */
  11915. +static unsigned long read_timer(void)
  11916. +{
  11917. +    unsigned long t, flags;
  11918. +    int i;
  11919. +
  11920. +    save_flags(flags);
  11921. +    cli();
  11922. +    t = jiffies * 11932;
  11923. +        outb_p(0, 0x43);
  11924. +    i = inb_p(0x40);
  11925. +    i |= inb(0x40) << 8;
  11926. +    restore_flags(flags);
  11927. +    return (t - i);
  11928. +}
  11929. +
  11930. +static void set_recovery_timer (ide_hwif_t *hwif)
  11931. +{
  11932. +    hwif->last_time = read_timer();
  11933. +}
  11934. +#define SET_RECOVERY_TIMER(drive) set_recovery_timer (drive)
  11935. +
  11936. +#else
  11937. +
  11938. +#define SET_RECOVERY_TIMER(drive)
  11939. +
  11940. +#endif /* DISK_RECOVERY_TIME */
  11941. +
  11942. +
  11943. +/*
  11944. + * Do not even *think* about calling this!
  11945. + */
  11946. +static void init_hwif_data (unsigned int index)
  11947. +{
  11948. +    byte *p;
  11949. +    unsigned int unit;
  11950. +    ide_hwif_t *hwif = &ide_hwifs[index];
  11951. +
  11952. +    /* bulk initialize hwif & drive info with zeros */
  11953. +    p = ((byte *) hwif) + sizeof(ide_hwif_t);
  11954. +    do {
  11955. +        *--p = 0;
  11956. +    } while (p > (byte *) hwif);
  11957. +
  11958. +    /* fill in any non-zero initial values */
  11959. +    hwif->index     = index;
  11960. +    hwif->noprobe    = (index > 1);
  11961. +    hwif->io.io_base    = default_io_base[index];
  11962. +    hwif->io.ctl_port    = hwif->io.io_base ? hwif->io.io_base+0x206 : 0x000;
  11963. +    hwif->io.io_size    = 1;
  11964. +#ifdef CONFIG_BLK_DEV_HD
  11965. +    if (hwif->io_base == HD_DATA)
  11966. +        hwif->noprobe = 1; /* may be overridden by ide_setup() */
  11967. +#endif /* CONFIG_BLK_DEV_HD */
  11968. +    hwif->major    = ide_hwif_to_major[index];
  11969. +    hwif->name[0]    = 'i';
  11970. +    hwif->name[1]    = 'd';
  11971. +    hwif->name[2]    = 'e';
  11972. +    hwif->name[3]    = '0' + index;
  11973. +#ifdef CONFIG_BLK_DEV_IDETAPE
  11974. +    hwif->tape_drive = NULL;
  11975. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  11976. +    for (unit = 0; unit < MAX_DRIVES; ++unit) {
  11977. +        ide_drive_t *drive = &hwif->drives[unit];
  11978. +
  11979. +        drive->select.all        = (unit<<4)|0xa0;
  11980. +        drive->hwif            = hwif;
  11981. +        drive->ctl            = 0x08;
  11982. +        drive->ready_stat        = READY_STAT;
  11983. +        drive->bad_wstat        = BAD_W_STAT;
  11984. +        drive->special.b.recalibrate    = 1;
  11985. +        drive->special.b.set_geometry    = 1;
  11986. +        drive->name[0]            = 'h';
  11987. +        drive->name[1]            = 'd';
  11988. +        drive->name[2]            = 'a' + (index * MAX_DRIVES) + unit;
  11989. +    }
  11990. +}
  11991. +
  11992. +/*
  11993. + * init_ide_data() sets reasonable default values into all fields
  11994. + * of all instances of the hwifs and drives, but only on the first call.
  11995. + * Subsequent calls have no effect (they don't wipe out anything).
  11996. + *
  11997. + * This routine is normally called at driver initialization time,
  11998. + * but may also be called MUCH earlier during kernel "command-line"
  11999. + * parameter processing.  As such, we cannot depend on any other parts
  12000. + * of the kernel (such as memory allocation) to be functioning yet.
  12001. + *
  12002. + * This is too bad, as otherwise we could dynamically allocate the
  12003. + * ide_drive_t structs as needed, rather than always consuming memory
  12004. + * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
  12005. + */
  12006. +#define MAGIC_COOKIE 0x12345678
  12007. +static void init_ide_data (void)
  12008. +{
  12009. +    unsigned int index;
  12010. +    static unsigned long magic_cookie = MAGIC_COOKIE;
  12011. +
  12012. +    if (magic_cookie != MAGIC_COOKIE)
  12013. +        return;        /* already initialized */
  12014. +    magic_cookie = 0;
  12015. +
  12016. +    for (index = 0; index < MAX_HWIFS; ++index)
  12017. +        init_hwif_data(index);
  12018. +
  12019. +    idebus_parameter = 0;
  12020. +    system_bus_speed = 0;
  12021. +}
  12022. +
  12023. +/*
  12024. + * ide_system_bus_speed() returns what we think is the system VESA/PCI
  12025. + * bus speed (in Mhz).  This is used for calculating interface PIO timings.
  12026. + * The default is 40 for known PCI systems, 50 otherwise.
  12027. + * The "idebus=xx" parameter can be used to override this value.
  12028. + * The actual value to be used is computed/displayed the first time through.
  12029. + */
  12030. +int ide_system_bus_speed (void)
  12031. +{
  12032. +    if (!system_bus_speed) {
  12033. +        if (idebus_parameter)
  12034. +        system_bus_speed = idebus_parameter;    /* user supplied value */
  12035. +#ifdef CONFIG_PCI
  12036. +        else if (pcibios_present())
  12037. +            system_bus_speed = 40;  /* safe default value for PCI */
  12038. +#endif /* CONFIG_PCI */
  12039. +        else
  12040. +            system_bus_speed = 50;    /* safe default value for VESA and PCI */
  12041. +        printk("ide: Assuming %dMhz system bus speed for PIO modes; override with idebus=xx\n", system_bus_speed);
  12042. +    }
  12043. +    return system_bus_speed;
  12044. +}
  12045. +
  12046. +/*
  12047. + * This is used for most PIO data transfers *from* the IDE interface
  12048. + */
  12049. +void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
  12050. +{
  12051. +    unsigned long io_base  = HWIF(drive)->io.io_base;
  12052. +    unsigned long data_reg = io_base+HWIF(drive)->io.io_size*IDE_DATA_OFFSET;
  12053. +
  12054. +    insw(data_reg, buffer, wcount<<1);
  12055. +}
  12056. +
  12057. +/*
  12058. + * This is used for most PIO data transfers *to* the IDE interface
  12059. + */
  12060. +void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
  12061. +{
  12062. +    unsigned long io_base  = HWIF(drive)->io.io_base;
  12063. +    unsigned long data_reg = io_base+HWIF(drive)->io.io_size*IDE_DATA_OFFSET;
  12064. +
  12065. +    outsw(data_reg, buffer, wcount<<1);
  12066. +}
  12067. +
  12068. +/*
  12069. + * This should get invoked any time we exit the driver to
  12070. + * wait for an interrupt response from a drive.  handler() points
  12071. + * at the appropriate code to handle the next interrupt, and a
  12072. + * timer is started to prevent us from waiting forever in case
  12073. + * something goes wrong (see the timer_expiry() handler later on).
  12074. + */
  12075. +void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout)
  12076. +{
  12077. +    ide_hwgroup_t *hwgroup = HWGROUP(drive);
  12078. +#ifdef DEBUG
  12079. +    if (hwgroup->handler != NULL) {
  12080. +        printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
  12081. +            drive->name, hwgroup->handler, handler);
  12082. +    }
  12083. +#endif
  12084. +    hwgroup->handler       = handler;
  12085. +    hwgroup->timer.expires = jiffies + timeout;
  12086. +    add_timer(&(hwgroup->timer));
  12087. +}
  12088. +
  12089. +/*
  12090. + * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
  12091. + * value for this drive (from its reported identification information).
  12092. + *
  12093. + * Returns:    1 if lba_capacity looks sensible
  12094. + *        0 otherwise
  12095. + */
  12096. +static int lba_capacity_is_ok (struct hd_driveid *id)
  12097. +{
  12098. +    unsigned long lba_sects   = id->lba_capacity;
  12099. +    unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
  12100. +    unsigned long _10_percent = chs_sects / 10;
  12101. +
  12102. +    /* perform a rough sanity check on lba_sects:  within 10% is "okay" */
  12103. +    if ((lba_sects - chs_sects) < _10_percent)
  12104. +        return 1;    /* lba_capacity is good */
  12105. +
  12106. +    /* some drives have the word order reversed */
  12107. +    lba_sects = (lba_sects << 16) | (lba_sects >> 16);
  12108. +    if ((lba_sects - chs_sects) < _10_percent) {
  12109. +        id->lba_capacity = lba_sects;    /* fix it */
  12110. +        return 1;    /* lba_capacity is (now) good */
  12111. +    }
  12112. +    return 0;    /* lba_capacity value is bad */
  12113. +}
  12114. +
  12115. +/*
  12116. + * current_capacity() returns the capacity (in sectors) of a drive
  12117. + * according to its current geometry/LBA settings.
  12118. + */
  12119. +static unsigned long current_capacity (ide_drive_t  *drive)
  12120. +{
  12121. +    struct hd_driveid *id = drive->id;
  12122. +    unsigned long capacity = drive->cyl * drive->head * drive->sect;
  12123. +
  12124. +    if (!drive->present)
  12125. +        return 0;
  12126. +    if (drive->media != ide_disk)
  12127. +        return 0x7fffffff;    /* cdrom or tape */
  12128. +    drive->select.b.lba = 0;
  12129. +    /* Determine capacity, and use LBA if the drive properly supports it */
  12130. +    if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
  12131. +        if (id->lba_capacity >= capacity) {
  12132. +            capacity = id->lba_capacity;
  12133. +            drive->select.b.lba = 1;
  12134. +        }
  12135. +    }
  12136. +    return (capacity - drive->sect0);
  12137. +}
  12138. +
  12139. +/*
  12140. + * ide_geninit() is called exactly *once* for each major, from genhd.c,
  12141. + * at the beginning of the initial partition check for the drives.
  12142. + */
  12143. +static void ide_geninit (struct gendisk *gd)
  12144. +{
  12145. +    unsigned int unit;
  12146. +    ide_hwif_t *hwif = gd->real_devices;
  12147. +
  12148. +    for (unit = 0; unit < gd->nr_real; ++unit) {
  12149. +        ide_drive_t *drive = &hwif->drives[unit];
  12150. +#ifdef CONFIG_BLK_DEV_IDECD
  12151. +        if (drive->present && drive->media == ide_cdrom)
  12152. +            ide_cdrom_setup(drive);
  12153. +#endif /* CONFIG_BLK_DEV_IDECD */
  12154. +#ifdef CONFIG_BLK_DEV_IDETAPE
  12155. +        if (drive->present && drive->media == ide_tape)
  12156. +            idetape_setup(drive);
  12157. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  12158. +        drive->part[0].nr_sects = current_capacity(drive);
  12159. +        if (!drive->present || drive->media != ide_disk) {
  12160. +            drive->part[0].start_sect = -1; /* skip partition check */
  12161. +        }
  12162. +    }
  12163. +}
  12164. +
  12165. +/*
  12166. + * init_gendisk() (as opposed to ide_geninit) is called for each major device,
  12167. + * after probing for drives, to allocate partition tables and other data
  12168. + * structures needed for the routines in genhd.c.  ide_geninit() gets called
  12169. + * somewhat later, during the partition check.
  12170. + */
  12171. +static void init_gendisk (ide_hwif_t *hwif)
  12172. +{
  12173. +    struct gendisk *gd, **gdp;
  12174. +    unsigned int unit, units, minors;
  12175. +    int *bs, *hs;
  12176. +
  12177. +    /* figure out maximum drive number on the interface */
  12178. +    for (units = MAX_DRIVES; units > 0; --units) {
  12179. +        if (hwif->drives[units-1].present)
  12180. +            break;
  12181. +    }
  12182. +    minors    = units * (1<<PARTN_BITS);
  12183. +    gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
  12184. +    gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
  12185. +    gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
  12186. +    bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
  12187. +    hs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
  12188. +
  12189. +    memset(gd->part, 0, minors * sizeof(struct hd_struct));
  12190. +
  12191. +    /* cdroms and msdos f/s are examples of non-1024 blocksizes */
  12192. +    blksize_size[hwif->major] = bs;
  12193. +    hardsect_size[hwif->major] = hs;
  12194. +    for (unit = 0; unit < minors; ++unit) {
  12195. +        *bs++ = BLOCK_SIZE;
  12196. +        *hs++ = SECTOR_WORDS << 2;
  12197. +    }
  12198. +
  12199. +    for (unit = 0; unit < units; ++unit)
  12200. +        hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
  12201. +
  12202. +    gd->major    = hwif->major;        /* our major device number */
  12203. +    gd->major_name    = IDE_MAJOR_NAME;    /* treated special in genhd.c */
  12204. +    gd->minor_shift    = PARTN_BITS;        /* num bits for partitions */
  12205. +    gd->max_p    = 1<<PARTN_BITS;    /* 1 + max partitions / drive */
  12206. +    gd->max_nr    = units;        /* max num real drives */
  12207. +    gd->nr_real    = units;        /* current num real drives */
  12208. +    gd->init    = ide_geninit;        /* initialization function */
  12209. +    gd->real_devices= hwif;            /* ptr to internal data */
  12210. +    gd->next    = NULL;            /* linked list of major devs */
  12211. +
  12212. +    for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) ;
  12213. +    hwif->gd = *gdp = gd;            /* link onto tail of list */
  12214. +}
  12215. +
  12216. +static void do_reset1 (ide_drive_t *, int);        /* needed below */
  12217. +
  12218. +#ifdef CONFIG_BLK_DEV_IDEATAPI
  12219. +/*
  12220. + * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
  12221. + * during an atapi drive reset operation. If the drive has not yet responded,
  12222. + * and we have not yet hit our maximum waiting time, then the timer is restarted
  12223. + * for another 50ms.
  12224. + */
  12225. +static void atapi_reset_pollfunc (ide_drive_t *drive)
  12226. +{
  12227. +    ide_hwgroup_t *hwgroup = HWGROUP(drive);
  12228. +    byte stat;
  12229. +
  12230. +    OUT_BYTE (drive->select.all, IDE_SELECT_REG);
  12231. +    udelay (10);
  12232. +
  12233. +    if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
  12234. +        printk("%s: ATAPI reset complete\n", drive->name);
  12235. +    } else {
  12236. +        if (jiffies < hwgroup->poll_timeout) {
  12237. +            ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
  12238. +            return;    /* continue polling */
  12239. +        }
  12240. +        hwgroup->poll_timeout = 0;    /* end of polling */
  12241. +        printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
  12242. +        do_reset1 (drive, 1);    /* do it the old fashioned way */
  12243. +    }
  12244. +    hwgroup->poll_timeout = 0;    /* done polling */
  12245. +}
  12246. +#endif /* CONFIG_BLK_DEV_IDEATAPI */
  12247. +
  12248. +/*
  12249. + * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
  12250. + * during an ide reset operation. If the drives have not yet responded,
  12251. + * and we have not yet hit our maximum waiting time, then the timer is restarted
  12252. + * for another 50ms.
  12253. + */
  12254. +static void reset_pollfunc (ide_drive_t *drive)
  12255. +{
  12256. +    ide_hwgroup_t *hwgroup = HWGROUP(drive);
  12257. +    ide_hwif_t *hwif = HWIF(drive);
  12258. +    byte tmp;
  12259. +
  12260. +    if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
  12261. +        if (jiffies < hwgroup->poll_timeout) {
  12262. +            ide_set_handler (drive, &reset_pollfunc, HZ/20);
  12263. +            return;    /* continue polling */
  12264. +        }
  12265. +        printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
  12266. +    } else  {
  12267. +        printk("%s: reset: ", hwif->name);
  12268. +        if ((tmp = GET_ERR()) == 1)
  12269. +            printk("success\n");
  12270. +        else {
  12271. +#if FANCY_STATUS_DUMPS
  12272. +            printk("master: ");
  12273. +            switch (tmp & 0x7f) {
  12274. +                case 1: printk("passed");
  12275. +                    break;
  12276. +                case 2: printk("formatter device error");
  12277. +                    break;
  12278. +                case 3: printk("sector buffer error");
  12279. +                    break;
  12280. +                case 4: printk("ECC circuitry error");
  12281. +                    break;
  12282. +                case 5: printk("controlling MPU error");
  12283. +                    break;
  12284. +                default:printk("error (0x%02x?)", tmp);
  12285. +            }
  12286. +            if (tmp & 0x80)
  12287. +                printk("; slave: failed");
  12288. +            printk("\n");
  12289. +#else
  12290. +            printk("failed\n");
  12291. +#endif /* FANCY_STATUS_DUMPS */
  12292. +        }
  12293. +    }
  12294. +    hwgroup->poll_timeout = 0;    /* done polling */
  12295. +}
  12296. +
  12297. +/*
  12298. + * do_reset1() attempts to recover a confused drive by resetting it.
  12299. + * Unfortunately, resetting a disk drive actually resets all devices on
  12300. + * the same interface, so it can really be thought of as resetting the
  12301. + * interface rather than resetting the drive.
  12302. + *
  12303. + * ATAPI devices have their own reset mechanism which allows them to be
  12304. + * individually reset without clobbering other devices on the same interface.
  12305. + *
  12306. + * Unfortunately, the IDE interface does not generate an interrupt to let
  12307. + * us know when the reset operation has finished, so we must poll for this.
  12308. + * Equally poor, though, is the fact that this may a very long time to complete,
  12309. + * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
  12310. + * we set a timer to poll at 50ms intervals.
  12311. + */
  12312. +static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
  12313. +{
  12314. +    unsigned int unit;
  12315. +    unsigned long flags;
  12316. +    ide_hwif_t *hwif = HWIF(drive);
  12317. +    ide_hwgroup_t *hwgroup = HWGROUP(drive);
  12318. +
  12319. +    save_flags(flags);
  12320. +    cli();        /* Why ? */
  12321. +
  12322. +#ifdef CONFIG_BLK_DEV_IDEATAPI
  12323. +    /* For an ATAPI device, first try an ATAPI SRST. */
  12324. +    if (drive->media != ide_disk) {
  12325. +        if (!do_not_try_atapi) {
  12326. +            if (!drive->keep_settings) {
  12327. +                drive->unmask = 0;
  12328. +                drive->io_32bit = 0;
  12329. +            }
  12330. +            OUT_BYTE (drive->select.all, IDE_SELECT_REG);
  12331. +            udelay (20);
  12332. +            OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
  12333. +            hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
  12334. +            ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
  12335. +            restore_flags (flags);
  12336. +            return;
  12337. +        }
  12338. +    }
  12339. +#endif /* CONFIG_BLK_DEV_IDEATAPI */
  12340. +
  12341. +    /*
  12342. +     * First, reset any device state data we were maintaining
  12343. +     * for any of the drives on this interface.
  12344. +     */
  12345. +    for (unit = 0; unit < MAX_DRIVES; ++unit) {
  12346. +        ide_drive_t *rdrive = &hwif->drives[unit];
  12347. +        rdrive->special.all = 0;
  12348. +        rdrive->special.b.set_geometry = 1;
  12349. +        rdrive->special.b.recalibrate  = 1;
  12350. +        if (OK_TO_RESET_CONTROLLER)
  12351. +            rdrive->mult_count = 0;
  12352. +        if (!rdrive->keep_settings) {
  12353. +            rdrive->mult_req = 0;
  12354. +            rdrive->unmask = 0;
  12355. +            rdrive->io_32bit = 0;
  12356. +            if (rdrive->using_dma) {
  12357. +                rdrive->using_dma = 0;
  12358. +                printk("%s: disabled DMA\n", rdrive->name);
  12359. +            }
  12360. +        }
  12361. +        if (rdrive->mult_req != rdrive->mult_count)
  12362. +            rdrive->special.b.set_multmode = 1;
  12363. +    }
  12364. +
  12365. +#if OK_TO_RESET_CONTROLLER
  12366. +    /*
  12367. +     * Note that we also set nIEN while resetting the device,
  12368. +     * to mask unwanted interrupts from the interface during the reset.
  12369. +     * However, due to the design of PC hardware, this will cause an
  12370. +     * immediate interrupt due to the edge transition it produces.
  12371. +     * This single interrupt gives us a "fast poll" for drives that
  12372. +     * recover from reset very quickly, saving us the first 50ms wait time.
  12373. +     */
  12374. +    OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);    /* set SRST and nIEN */
  12375. +    udelay(10);            /* more than enough time */
  12376. +    OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);    /* clear SRST, leave nIEN */
  12377. +    udelay(10);            /* more than enough time */
  12378. +    hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
  12379. +    ide_set_handler (drive, &reset_pollfunc, HZ/20);
  12380. +#endif    /* OK_TO_RESET_CONTROLLER */
  12381. +
  12382. +    restore_flags (flags);
  12383. +}
  12384. +
  12385. +/*
  12386. + * ide_do_reset() is the entry point to the drive/interface reset code.
  12387. + */
  12388. +void ide_do_reset (ide_drive_t *drive)
  12389. +{
  12390. +    do_reset1 (drive, 0);
  12391. +#ifdef CONFIG_BLK_DEV_IDETAPE
  12392. +    if (drive->media == ide_tape)
  12393. +        drive->tape.reset_issued=1;
  12394. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  12395. +}
  12396. +
  12397. +/*
  12398. + * Clean up after success/failure of an explicit drive cmd
  12399. + */
  12400. +void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
  12401. +{
  12402. +    unsigned long flags;
  12403. +    struct request *rq = HWGROUP(drive)->rq;
  12404. +
  12405. +    if (rq->cmd == IDE_DRIVE_CMD) {
  12406. +        byte *args = (byte *) rq->buffer;
  12407. +        rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
  12408. +        if (args) {
  12409. +            args[0] = stat;
  12410. +            args[1] = err;
  12411. +            args[2] = IN_BYTE(IDE_NSECTOR_REG);
  12412. +        }
  12413. +    }
  12414. +    save_flags(flags);
  12415. +    cli();
  12416. +    blk_dev[MAJOR(rq->rq_dev)].current_request = rq->next;
  12417. +    HWGROUP(drive)->rq = NULL;
  12418. +    rq->rq_status = RQ_INACTIVE;
  12419. +    if (rq->sem != NULL)
  12420. +        up(rq->sem);
  12421. +    restore_flags(flags);
  12422. +}
  12423. +
  12424. +/*
  12425. + * Error reporting, in human readable form (luxurious, but a memory hog).
  12426. + */
  12427. +byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
  12428. +{
  12429. +    unsigned long flags;
  12430. +    byte err = 0;
  12431. +
  12432. +    save_flags (flags);
  12433. +    sti();
  12434. +    printk("%s: %s: status=0x%02x", drive->name, msg, stat);
  12435. +#if FANCY_STATUS_DUMPS
  12436. +    if (drive->media == ide_disk) {
  12437. +        printk(" { ");
  12438. +        if (stat & BUSY_STAT)
  12439. +            printk("Busy ");
  12440. +        else {
  12441. +            if (stat & READY_STAT)    printk("DriveReady ");
  12442. +            if (stat & WRERR_STAT)    printk("DeviceFault ");
  12443. +            if (stat & SEEK_STAT)    printk("SeekComplete ");
  12444. +            if (stat & DRQ_STAT)    printk("DataRequest ");
  12445. +            if (stat & ECC_STAT)    printk("CorrectedError ");
  12446. +            if (stat & INDEX_STAT)    printk("Index ");
  12447. +            if (stat & ERR_STAT)    printk("Error ");
  12448. +        }
  12449. +        printk("}");
  12450. +    }
  12451. +#endif    /* FANCY_STATUS_DUMPS */
  12452. +    printk("\n");
  12453. +    if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
  12454. +        err = GET_ERR();
  12455. +        printk("%s: %s: error=0x%02x", drive->name, msg, err);
  12456. +#if FANCY_STATUS_DUMPS
  12457. +        if (drive->media == ide_disk) {
  12458. +            printk(" { ");
  12459. +            if (err & BBD_ERR)    printk("BadSector ");
  12460. +            if (err & ECC_ERR)    printk("UncorrectableError ");
  12461. +            if (err & ID_ERR)    printk("SectorIdNotFound ");
  12462. +            if (err & ABRT_ERR)    printk("DriveStatusError ");
  12463. +            if (err & TRK0_ERR)    printk("TrackZeroNotFound ");
  12464. +            if (err & MARK_ERR)    printk("AddrMarkNotFound ");
  12465. +            printk("}");
  12466. +            if (err & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
  12467. +                byte cur = IN_BYTE(IDE_SELECT_REG);
  12468. +                if (cur & 0x40) {    /* using LBA? */
  12469. +                    printk(", LBAsect=%ld", (unsigned long)
  12470. +                     ((cur&0xf)<<24)
  12471. +                     |(IN_BYTE(IDE_HCYL_REG)<<16)
  12472. +                     |(IN_BYTE(IDE_LCYL_REG)<<8)
  12473. +                     | IN_BYTE(IDE_SECTOR_REG));
  12474. +                } else {
  12475. +                    printk(", CHS=%d/%d/%d",
  12476. +                     (IN_BYTE(IDE_HCYL_REG)<<8) +
  12477. +                      IN_BYTE(IDE_LCYL_REG),
  12478. +                      cur & 0xf,
  12479. +                      IN_BYTE(IDE_SECTOR_REG));
  12480. +                }
  12481. +                if (HWGROUP(drive)->rq)
  12482. +                    printk(", sector=%ld", HWGROUP(drive)->rq->sector);
  12483. +            }
  12484. +        }
  12485. +#endif    /* FANCY_STATUS_DUMPS */
  12486. +        printk("\n");
  12487. +    }
  12488. +    restore_flags (flags);
  12489. +    return err;
  12490. +}
  12491. +
  12492. +/*
  12493. + * try_to_flush_leftover_data() is invoked in response to a drive
  12494. + * unexpectedly having its DRQ_STAT bit set.  As an alternative to
  12495. + * resetting the drive, this routine tries to clear the condition
  12496. + * by read a sector's worth of data from the drive.  Of course,
  12497. + * this may not help if the drive is *waiting* for data from *us*.
  12498. + */
  12499. +static void try_to_flush_leftover_data (ide_drive_t *drive)
  12500. +{
  12501. +    int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
  12502. +
  12503. +    while (i > 0) {
  12504. +        unsigned long buffer[16];
  12505. +        unsigned int wcount = (i > 16) ? 16 : i;
  12506. +        i -= wcount;
  12507. +        ide_input_data (drive, buffer, wcount);
  12508. +    }
  12509. +}
  12510. +
  12511. +/*
  12512. + * ide_error() takes action based on the error returned by the controller.
  12513. + */
  12514. +void ide_error (ide_drive_t *drive, const char *msg, byte stat)
  12515. +{
  12516. +    struct request *rq;
  12517. +    byte err;
  12518. +
  12519. +    err = ide_dump_status(drive, msg, stat);
  12520. +    if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL)
  12521. +        return;
  12522. +    /* retry only "normal" I/O: */
  12523. +    if (rq->cmd == IDE_DRIVE_CMD) {
  12524. +        rq->errors = 1;
  12525. +        ide_end_drive_cmd(drive, stat, err);
  12526. +        return;
  12527. +    }
  12528. +    if (stat & BUSY_STAT) {        /* other bits are useless when BUSY */
  12529. +        rq->errors |= ERROR_RESET;
  12530. +    } else {
  12531. +        if (drive->media == ide_disk && (stat & ERR_STAT)) {
  12532. +            /* err has different meaning on cdrom and tape */
  12533. +            if (err & (BBD_ERR | ECC_ERR))    /* retries won't help these */
  12534. +                rq->errors = ERROR_MAX;
  12535. +            else if (err & TRK0_ERR)    /* help it find track zero */
  12536. +                rq->errors |= ERROR_RECAL;
  12537. +        }
  12538. +        if ((stat & DRQ_STAT) && rq->cmd != WRITE)
  12539. +            try_to_flush_leftover_data(drive);
  12540. +    }
  12541. +    if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
  12542. +        rq->errors |= ERROR_RESET;    /* Mmmm.. timing problem */
  12543. +
  12544. +    if (rq->errors >= ERROR_MAX) {
  12545. +#ifdef CONFIG_BLK_DEV_IDETAPE
  12546. +        if (drive->media == ide_tape) {
  12547. +            rq->errors = 0;
  12548. +            idetape_end_request(0, HWGROUP(drive));
  12549. +        }
  12550. +        else
  12551. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  12552. +         ide_end_request(0, HWGROUP(drive));
  12553. +    }
  12554. +    else {
  12555. +        if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
  12556. +            ++rq->errors;
  12557. +            ide_do_reset(drive);
  12558. +            return;
  12559. +        } else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
  12560. +            drive->special.b.recalibrate = 1;
  12561. +        ++rq->errors;
  12562. +    }
  12563. +}
  12564. +
  12565. +/*
  12566. + * read_intr() is the handler for disk read/multread interrupts
  12567. + */
  12568. +static void read_intr (ide_drive_t *drive)
  12569. +{
  12570. +    byte stat;
  12571. +    int i;
  12572. +    unsigned int msect, nsect;
  12573. +    struct request *rq;
  12574. +
  12575. +    if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
  12576. +        ide_error(drive, "read_intr", stat);
  12577. +        return;
  12578. +    }
  12579. +    msect = drive->mult_count;
  12580. +read_next:
  12581. +    rq = HWGROUP(drive)->rq;
  12582. +    if (msect) {
  12583. +        if ((nsect = rq->current_nr_sectors) > msect)
  12584. +            nsect = msect;
  12585. +        msect -= nsect;
  12586. +    } else
  12587. +        nsect = 1;
  12588. +    ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
  12589. +#ifdef DEBUG
  12590. +    printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
  12591. +        drive->name, rq->sector, rq->sector+nsect-1,
  12592. +        (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
  12593. +#endif
  12594. +    rq->sector += nsect;
  12595. +    rq->buffer += nsect<<9;
  12596. +    rq->errors = 0;
  12597. +    i = (rq->nr_sectors -= nsect);
  12598. +    if ((rq->current_nr_sectors -= nsect) <= 0)
  12599. +        ide_end_request(1, HWGROUP(drive));
  12600. +    if (i > 0) {
  12601. +        if (msect)
  12602. +            goto read_next;
  12603. +        ide_set_handler (drive, &read_intr, WAIT_CMD);
  12604. +    }
  12605. +}
  12606. +
  12607. +/*
  12608. + * write_intr() is the handler for disk write interrupts
  12609. + */
  12610. +static void write_intr (ide_drive_t *drive)
  12611. +{
  12612. +    byte stat;
  12613. +    int i;
  12614. +    ide_hwgroup_t *hwgroup = HWGROUP(drive);
  12615. +    struct request *rq = hwgroup->rq;
  12616. +
  12617. +    if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
  12618. +#ifdef DEBUG
  12619. +        printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
  12620. +            drive->name, rq->sector, (unsigned long) rq->buffer,
  12621. +            rq->nr_sectors-1);
  12622. +#endif
  12623. +        if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) {
  12624. +            rq->sector++;
  12625. +            rq->buffer += 512;
  12626. +            rq->errors = 0;
  12627. +            i = --rq->nr_sectors;
  12628. +            --rq->current_nr_sectors;
  12629. +            if (rq->current_nr_sectors <= 0)
  12630. +                ide_end_request(1, hwgroup);
  12631. +            if (i > 0) {
  12632. +                ide_output_data (drive, rq->buffer, SECTOR_WORDS);
  12633. +                ide_set_handler (drive, &write_intr, WAIT_CMD);
  12634. +            }
  12635. +            return;
  12636. +        }
  12637. +    }
  12638. +    ide_error(drive, "write_intr", stat);
  12639. +}
  12640. +
  12641. +/*
  12642. + * ide_multwrite() transfers a block of up to mcount sectors of data
  12643. + * to a drive as part of a disk multiple-sector write operation.
  12644. + */
  12645. +void ide_multwrite (ide_drive_t *drive, unsigned int mcount)
  12646. +{
  12647. +    struct request *rq = &HWGROUP(drive)->wrq;
  12648. +
  12649. +    do {
  12650. +        unsigned int nsect = rq->current_nr_sectors;
  12651. +        if (nsect > mcount)
  12652. +            nsect = mcount;
  12653. +        mcount -= nsect;
  12654. +
  12655. +        ide_output_data(drive, rq->buffer, nsect<<7);
  12656. +#ifdef DEBUG
  12657. +        printk("%s: multwrite: sector %ld, buffer=0x%08lx, count=%d, remaining=%ld\n",
  12658. +            drive->name, rq->sector, (unsigned long) rq->buffer,
  12659. +            nsect, rq->nr_sectors - nsect);
  12660. +#endif
  12661. +        if ((rq->nr_sectors -= nsect) <= 0)
  12662. +            break;
  12663. +        if ((rq->current_nr_sectors -= nsect) == 0) {
  12664. +            if ((rq->bh = rq->bh->b_reqnext) != NULL) {
  12665. +                rq->current_nr_sectors = rq->bh->b_size>>9;
  12666. +                rq->buffer             = rq->bh->b_data;
  12667. +            } else {
  12668. +                panic("%s: buffer list corrupted\n", drive->name);
  12669. +                break;
  12670. +            }
  12671. +        } else {
  12672. +            rq->buffer += nsect << 9;
  12673. +        }
  12674. +    } while (mcount);
  12675. +}
  12676. +
  12677. +/*
  12678. + * multwrite_intr() is the handler for disk multwrite interrupts
  12679. + */
  12680. +static void multwrite_intr (ide_drive_t *drive)
  12681. +{
  12682. +    byte stat;
  12683. +    int i;
  12684. +    ide_hwgroup_t *hwgroup = HWGROUP(drive);
  12685. +    struct request *rq = &hwgroup->wrq;
  12686. +
  12687. +    if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
  12688. +        if (stat & DRQ_STAT) {
  12689. +            if (rq->nr_sectors) {
  12690. +                ide_multwrite(drive, drive->mult_count);
  12691. +                ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
  12692. +                return;
  12693. +            }
  12694. +        } else {
  12695. +            if (!rq->nr_sectors) {    /* all done? */
  12696. +                rq = hwgroup->rq;
  12697. +                for (i = rq->nr_sectors; i > 0;){
  12698. +                    i -= rq->current_nr_sectors;
  12699. +                    ide_end_request(1, hwgroup);
  12700. +                }
  12701. +                return;
  12702. +            }
  12703. +        }
  12704. +    }
  12705. +    ide_error(drive, "multwrite_intr", stat);
  12706. +}
  12707. +
  12708. +/*
  12709. + * Issue a simple drive command
  12710. + * The drive must be selected beforehand.
  12711. + */
  12712. +static void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
  12713. +{
  12714. +    ide_set_handler (drive, handler, WAIT_CMD);
  12715. +    OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
  12716. +    OUT_BYTE(nsect,IDE_NSECTOR_REG);
  12717. +    OUT_BYTE(cmd,IDE_COMMAND_REG);
  12718. +}
  12719. +
  12720. +/*
  12721. + * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  12722. + */
  12723. +static void set_multmode_intr (ide_drive_t *drive)
  12724. +{
  12725. +    byte stat = GET_STAT();
  12726. +
  12727. +    sti();
  12728. +    if (OK_STAT(stat,READY_STAT,BAD_STAT)) {
  12729. +        drive->mult_count = drive->mult_req;
  12730. +    } else {
  12731. +        drive->mult_req = drive->mult_count = 0;
  12732. +        drive->special.b.recalibrate = 1;
  12733. +        (void) ide_dump_status(drive, "set_multmode", stat);
  12734. +    }
  12735. +}
  12736. +
  12737. +/*
  12738. + * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  12739. + */
  12740. +static void set_geometry_intr (ide_drive_t *drive)
  12741. +{
  12742. +    byte stat = GET_STAT();
  12743. +
  12744. +    sti();
  12745. +    if (!OK_STAT(stat,READY_STAT,BAD_STAT))
  12746. +        ide_error(drive, "set_geometry_intr", stat);
  12747. +}
  12748. +
  12749. +/*
  12750. + * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  12751. + */
  12752. +static void recal_intr (ide_drive_t *drive)
  12753. +{
  12754. +    byte stat = GET_STAT();
  12755. +
  12756. +    sti();
  12757. +    if (!OK_STAT(stat,READY_STAT,BAD_STAT))
  12758. +        ide_error(drive, "recal_intr", stat);
  12759. +}
  12760. +
  12761. +/*
  12762. + * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
  12763. + */
  12764. +static void drive_cmd_intr (ide_drive_t *drive)
  12765. +{
  12766. +    struct request *rq = HWGROUP(drive)->rq;
  12767. +    byte *args = (byte *) rq->buffer;
  12768. +    byte stat = GET_STAT();
  12769. +
  12770. +    sti();
  12771. +    if ((stat & DRQ_STAT) && args && args[3]) {
  12772. +        byte io_32bit = drive->io_32bit;
  12773. +        drive->io_32bit = 0;
  12774. +        ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
  12775. +        drive->io_32bit = io_32bit;
  12776. +        stat = GET_STAT();
  12777. +    }
  12778. +    if (OK_STAT(stat,READY_STAT,BAD_STAT))
  12779. +        ide_end_drive_cmd (drive, stat, GET_ERR());
  12780. +    else
  12781. +        ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
  12782. +}
  12783. +
  12784. +/*
  12785. + * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
  12786. + * commands to a drive.  It used to do much more, but has been scaled back.
  12787. + */
  12788. +static inline void do_special (ide_drive_t *drive)
  12789. +{
  12790. +    special_t *s = &drive->special;
  12791. +
  12792. +#ifdef DEBUG
  12793. +    printk("%s: do_special: 0x%02x\n", drive->name, s->all);
  12794. +#endif
  12795. +    if (s->b.set_geometry) {
  12796. +        s->b.set_geometry = 0;
  12797. +        if (drive->media == ide_disk) {
  12798. +            OUT_BYTE(drive->sect,IDE_SECTOR_REG);
  12799. +            OUT_BYTE(drive->cyl,IDE_LCYL_REG);
  12800. +            OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG);
  12801. +            OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG);
  12802. +            if (!IS_PROMISE_DRIVE)
  12803. +                ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr);
  12804. +        }
  12805. +    } else if (s->b.recalibrate) {
  12806. +        s->b.recalibrate = 0;
  12807. +        if (drive->media == ide_disk && !IS_PROMISE_DRIVE)
  12808. +            ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
  12809. +    } else if (s->b.set_tune) {
  12810. +        ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
  12811. +        s->b.set_tune = 0;
  12812. +        if (tuneproc != NULL)
  12813. +            tuneproc(drive, drive->tune_req);
  12814. +    } else if (s->b.set_multmode) {
  12815. +        s->b.set_multmode = 0;
  12816. +        if (drive->media == ide_disk) {
  12817. +            if (drive->id && drive->mult_req > drive->id->max_multsect)
  12818. +                drive->mult_req = drive->id->max_multsect;
  12819. +            if (!IS_PROMISE_DRIVE)
  12820. +                ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr);
  12821. +        } else
  12822. +            drive->mult_req = 0;
  12823. +    } else if (s->all) {
  12824. +        int special = s->all;
  12825. +        s->all = 0;
  12826. +        printk("%s: bad special flag: 0x%02x\n", drive->name, special);
  12827. +    }
  12828. +}
  12829. +
  12830. +/*
  12831. + * This routine busy-waits for the drive status to be not "busy".
  12832. + * It then checks the status for all of the "good" bits and none
  12833. + * of the "bad" bits, and if all is okay it returns 0.  All other
  12834. + * cases return 1 after invoking ide_error() -- caller should just return.
  12835. + *
  12836. + * This routine should get fixed to not hog the cpu during extra long waits..
  12837. + * That could be done by busy-waiting for the first jiffy or two, and then
  12838. + * setting a timer to wake up at half second intervals thereafter,
  12839. + * until timeout is achieved, before timing out.
  12840. + */
  12841. +int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
  12842. +{
  12843. +    byte stat;
  12844. +    unsigned long flags;
  12845. +
  12846. +test:
  12847. +    udelay(1);    /* spec allows drive 400ns to change "BUSY" */
  12848. +    if (OK_STAT((stat = GET_STAT()), good, bad))
  12849. +        return 0;    /* fast exit for most frequent case */
  12850. +    if (!(stat & BUSY_STAT)) {
  12851. +        ide_error(drive, "status error", stat);
  12852. +        return 1;
  12853. +    }
  12854. +
  12855. +    save_flags(flags);
  12856. +    sti();
  12857. +    timeout += jiffies;
  12858. +    do {
  12859. +        if (!((stat = GET_STAT()) & BUSY_STAT)) {
  12860. +            restore_flags(flags);
  12861. +            goto test;
  12862. +        }
  12863. +    } while (jiffies <= timeout);
  12864. +
  12865. +    restore_flags(flags);
  12866. +    ide_error(drive, "status timeout", GET_STAT());
  12867. +    return 1;
  12868. +}
  12869. +
  12870. +/*
  12871. + * do_rw_disk() issues READ and WRITE commands to a disk,
  12872. + * using LBA if supported, or CHS otherwise, to address sectors.
  12873. + * It also takes care of issuing special DRIVE_CMDs.
  12874. + */
  12875. +static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
  12876. +{
  12877. +    ide_hwif_t *hwif = HWIF(drive);
  12878. +    unsigned long io_base = hwif->io.io_base;
  12879. +    unsigned long io_size = hwif->io.io_size;
  12880. +#ifdef CONFIG_BLK_DEV_PROMISE
  12881. +    int use_promise_io = 0;
  12882. +#endif /* CONFIG_BLK_DEV_PROMISE */
  12883. +
  12884. +    OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
  12885. +    OUT_BYTE(rq->nr_sectors,io_base+io_size*IDE_NSECTOR_OFFSET);
  12886. +#ifdef CONFIG_BLK_DEV_PROMISE
  12887. +    if (IS_PROMISE_DRIVE) {
  12888. +        if (hwif->is_promise2 || rq->cmd == READ) {
  12889. +            use_promise_io = 1;
  12890. +        }
  12891. +    }
  12892. +    if (drive->select.b.lba || use_promise_io) {
  12893. +#else /* !CONFIG_BLK_DEV_PROMISE */
  12894. +    if (drive->select.b.lba) {
  12895. +#endif /* CONFIG_BLK_DEV_PROMISE */
  12896. +#ifdef DEBUG
  12897. +        printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
  12898. +            drive->name, (rq->cmd==READ)?"read":"writ",
  12899. +            block, rq->nr_sectors, (unsigned long) rq->buffer);
  12900. +#endif
  12901. +        OUT_BYTE(block,io_base+io_size*IDE_SECTOR_OFFSET);
  12902. +        OUT_BYTE(block>>=8,io_base+io_size*IDE_LCYL_OFFSET);
  12903. +        OUT_BYTE(block>>=8,io_base+io_size*IDE_HCYL_OFFSET);
  12904. +        OUT_BYTE(((block>>8)&0x0f)|drive->select.all,io_base+io_size*IDE_SELECT_OFFSET);
  12905. +    } else {
  12906. +        unsigned int sect,head,cyl,track;
  12907. +        track = block / drive->sect;
  12908. +        sect  = block % drive->sect + 1;
  12909. +        OUT_BYTE(sect,io_base+io_size*IDE_SECTOR_OFFSET);
  12910. +        head  = track % drive->head;
  12911. +        cyl   = track / drive->head;
  12912. +        OUT_BYTE(cyl,io_base+io_size*IDE_LCYL_OFFSET);
  12913. +        OUT_BYTE(cyl>>8,io_base+io_size*IDE_HCYL_OFFSET);
  12914. +        OUT_BYTE(head|drive->select.all,io_base+io_size*IDE_SELECT_OFFSET);
  12915. +#ifdef DEBUG
  12916. +        printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
  12917. +            drive->name, (rq->cmd==READ)?"read":"writ", cyl,
  12918. +            head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
  12919. +#endif
  12920. +    }
  12921. +#ifdef CONFIG_BLK_DEV_PROMISE
  12922. +    if (use_promise_io) {
  12923. +        do_promise_io (drive, rq);
  12924. +        return;
  12925. +    }
  12926. +#endif /* CONFIG_BLK_DEV_PROMISE */
  12927. +    if (rq->cmd == READ) {
  12928. +        ide_set_handler(drive, &read_intr, WAIT_CMD);
  12929. +        OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, io_base+io_size*IDE_COMMAND_OFFSET);
  12930. +        return;
  12931. +    }
  12932. +    if (rq->cmd == WRITE) {
  12933. +        OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, io_base+io_size*IDE_COMMAND_OFFSET);
  12934. +        if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
  12935. +            printk("%s: no DRQ after issuing %s\n", drive->name,
  12936. +                drive->mult_count ? "MULTWRITE" : "WRITE");
  12937. +            return;
  12938. +        }
  12939. +        if (!drive->unmask)
  12940. +            cli();
  12941. +        if (drive->mult_count) {
  12942. +            HWGROUP(drive)->wrq = *rq; /* scratchpad */
  12943. +            ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
  12944. +            ide_multwrite(drive, drive->mult_count);
  12945. +        } else {
  12946. +            ide_set_handler (drive, &write_intr, WAIT_CMD);
  12947. +            ide_output_data(drive, rq->buffer, SECTOR_WORDS);
  12948. +        }
  12949. +        return;
  12950. +    }
  12951. +    printk("%s: bad command: %d\n", drive->name, rq->cmd);
  12952. +    ide_end_request(0, HWGROUP(drive));
  12953. +}
  12954. +
  12955. +/*
  12956. + * execute_drive_cmd() issues a special drive command,
  12957. + * usually initiated by ioctl() from the external hdparm program.
  12958. + */
  12959. +static void execute_drive_cmd (ide_drive_t *drive, struct request *rq)
  12960. +{
  12961. +    ide_hwif_t *hwif = HWIF(drive);
  12962. +    unsigned long io_base = hwif->io.io_base;
  12963. +    unsigned long io_size = hwif->io.io_size;
  12964. +    byte *args = rq->buffer;
  12965. +    if (args) {
  12966. +#ifdef DEBUG
  12967. +        printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n",
  12968. +         drive->name, args[0], args[1], args[2], args[3]);
  12969. +#endif
  12970. +        OUT_BYTE(args[2],io_base+io_size*IDE_FEATURE_OFFSET);
  12971. +        ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
  12972. +        return;
  12973. +    } else {
  12974. +        /*
  12975. +         * NULL is actually a valid way of waiting for
  12976. +         * all current requests to be flushed from the queue.
  12977. +         */
  12978. +#ifdef DEBUG
  12979. +        printk("%s: DRIVE_CMD (null)\n", drive->name);
  12980. +#endif
  12981. +        ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
  12982. +        return;
  12983. +    }
  12984. +}
  12985. +
  12986. +/*
  12987. + * do_request() initiates handling of a new I/O request
  12988. + */
  12989. +static inline void do_request (ide_hwif_t *hwif, struct request *rq)
  12990. +{
  12991. +    unsigned int minor, unit;
  12992. +    unsigned long block, blockend;
  12993. +    ide_drive_t *drive;
  12994. +
  12995. +    sti();
  12996. +#ifdef DEBUG
  12997. +    printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
  12998. +#endif
  12999. +    minor = MINOR(rq->rq_dev);
  13000. +    unit = minor >> PARTN_BITS;
  13001. +    if (MAJOR(rq->rq_dev) != hwif->major || unit >= MAX_DRIVES) {
  13002. +        printk("%s: bad device number: %s\n",
  13003. +               hwif->name, kdevname(rq->rq_dev));
  13004. +        goto kill_rq;
  13005. +    }
  13006. +    drive = &hwif->drives[unit];
  13007. +#ifdef DEBUG
  13008. +    if (rq->bh && !buffer_locked(rq->bh)) {
  13009. +        printk("%s: block not locked\n", drive->name);
  13010. +        goto kill_rq;
  13011. +    }
  13012. +#endif
  13013. +    block    = rq->sector;
  13014. +    blockend = block + rq->nr_sectors;
  13015. +    if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
  13016. +        printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
  13017. +         (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
  13018. +        goto kill_rq;
  13019. +    }
  13020. +    block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
  13021. +#if FAKE_FDISK_FOR_EZDRIVE
  13022. +    if (block == 0 && drive->remap_0_to_1)
  13023. +        block = 1;  /* redirect MBR access to EZ-Drive partn table */
  13024. +#endif /* FAKE_FDISK_FOR_EZDRIVE */
  13025. +    ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
  13026. +#if (DISK_RECOVERY_TIME > 0)
  13027. +    while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
  13028. +#endif
  13029. +
  13030. +#ifdef CONFIG_BLK_DEV_IDETAPE
  13031. +    POLL_HWIF_TAPE_DRIVE;    /* macro from ide-tape.h */
  13032. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  13033. +
  13034. +    SELECT_DRIVE(hwif,drive);
  13035. +    if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
  13036. +        printk("%s: drive not ready for command\n", drive->name);
  13037. +        return;
  13038. +    }
  13039. +
  13040. +    if (!drive->special.all) {
  13041. +        if (rq->cmd == IDE_DRIVE_CMD) {
  13042. +            execute_drive_cmd(drive, rq);
  13043. +            return;
  13044. +        }
  13045. +#ifdef CONFIG_BLK_DEV_IDEATAPI
  13046. +        switch (drive->media) {
  13047. +            case ide_disk:
  13048. +                do_rw_disk (drive, rq, block);
  13049. +                return;
  13050. +#ifdef CONFIG_BLK_DEV_IDECD
  13051. +            case ide_cdrom:
  13052. +                ide_do_rw_cdrom (drive, block);
  13053. +                return;
  13054. +#endif /* CONFIG_BLK_DEV_IDECD */
  13055. +#ifdef CONFIG_BLK_DEV_IDETAPE
  13056. +            case ide_tape:
  13057. +                idetape_do_request (drive, rq, block);
  13058. +                return;
  13059. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  13060. +
  13061. +            default:
  13062. +                printk("%s: media type %d not supported\n",
  13063. +                    drive->name, drive->media);
  13064. +                goto kill_rq;
  13065. +        }
  13066. +#else
  13067. +        do_rw_disk (drive, rq, block); /* simpler and faster */
  13068. +        return;
  13069. +#endif /* CONFIG_BLK_DEV_IDEATAPI */;
  13070. +    }
  13071. +    do_special(drive);
  13072. +    return;
  13073. +kill_rq:
  13074. +    ide_end_request(0, hwif->hwgroup);
  13075. +}
  13076. +
  13077. +/*
  13078. + * The driver enables interrupts as much as possible.  In order to do this,
  13079. + * (a) the device-interrupt is always masked before entry, and
  13080. + * (b) the timeout-interrupt is always disabled before entry.
  13081. + *
  13082. + * If we enter here from, say irq14, and then start a new request for irq15,
  13083. + * (possible with "serialize" option) then we cannot ensure that we exit
  13084. + * before the irq15 hits us. So, we must be careful not to let this bother us.
  13085. + *
  13086. + * Interrupts are still masked (by default) whenever we are exchanging
  13087. + * data/cmds with a drive, because some drives seem to have very poor
  13088. + * tolerance for latency during I/O.  For devices which don't suffer from
  13089. + * this problem (most don't), the unmask flag can be set using the "hdparm"
  13090. + * utility, to permit other interrupts during data/cmd transfers.
  13091. + */
  13092. +void ide_do_request (ide_hwgroup_t *hwgroup)
  13093. +{
  13094. +    cli();    /* paranoia */
  13095. +    if (hwgroup->handler != NULL) {
  13096. +        printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name);
  13097. +        return;
  13098. +    }
  13099. +    do {
  13100. +        ide_hwif_t *hwif = hwgroup->hwif;
  13101. +        struct request *rq;
  13102. +        if ((rq = hwgroup->rq) == NULL) {
  13103. +            if (hwif->sharing_irq && hwgroup->drive) /* set nIEN */
  13104. +                OUT_BYTE(hwgroup->drive->ctl|2,hwif->io.ctl_port);
  13105. +            /*
  13106. +             * hwgroup->next_hwif is different from hwgroup->hwif
  13107. +             * only when a request is inserted using "ide_next".
  13108. +             * This saves wear and tear on IDE tapes.
  13109. +             */
  13110. +            hwif = hwgroup->next_hwif;
  13111. +            do {
  13112. +                rq = blk_dev[hwif->major].current_request;
  13113. +                if (rq != NULL && rq->rq_status != RQ_INACTIVE)
  13114. +                    goto got_rq;
  13115. +            } while ((hwif = hwif->next) != hwgroup->next_hwif);
  13116. +            return;        /* no work left for this hwgroup */
  13117. +        }
  13118. +    got_rq:    
  13119. +        do_request(hwgroup->hwif = hwgroup->next_hwif = hwif, hwgroup->rq = rq);
  13120. +        cli();
  13121. +    } while (hwgroup->handler == NULL);
  13122. +}
  13123. +
  13124. +/*
  13125. + * do_hwgroup_request() invokes ide_do_request() after first masking
  13126. + * all possible interrupts for the current hwgroup.  This prevents race
  13127. + * conditions in the event that an unexpected interrupt occurs while
  13128. + * we are in the driver.
  13129. + *
  13130. + * Note that when an interrupt is used to reenter the driver, the first level
  13131. + * handler will already have masked the irq that triggered, but any other ones
  13132. + * for the hwgroup will still be unmasked.  The driver tries to be careful
  13133. + * about such things.
  13134. + */
  13135. +static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
  13136. +{
  13137. +    if (hwgroup->handler == NULL) {
  13138. +        ide_hwif_t *hgif = hwgroup->hwif;
  13139. +        ide_hwif_t *hwif = hgif;
  13140. +        do {
  13141. +            disable_irq(hwif->irq);
  13142. +        } while ((hwif = hwif->next) != hgif);
  13143. +        ide_do_request (hwgroup);
  13144. +        do {
  13145. +            enable_irq(hwif->irq);
  13146. +        } while ((hwif = hwif->next) != hgif);
  13147. +    }
  13148. +}
  13149. +
  13150. +static void do_ide0_request (void)    /* invoked with cli() */
  13151. +{
  13152. +    do_hwgroup_request (ide_hwifs[0].hwgroup);
  13153. +}
  13154. +
  13155. +#if MAX_HWIFS > 1
  13156. +static void do_ide1_request (void)    /* invoked with cli() */
  13157. +{
  13158. +    do_hwgroup_request (ide_hwifs[1].hwgroup);
  13159. +}
  13160. +#endif
  13161. +
  13162. +#if MAX_HWIFS > 2
  13163. +static void do_ide2_request (void)    /* invoked with cli() */
  13164. +{
  13165. +    do_hwgroup_request (ide_hwifs[2].hwgroup);
  13166. +}
  13167. +#endif
  13168. +
  13169. +#if MAX_HWIFS > 3
  13170. +static void do_ide3_request (void)    /* invoked with cli() */
  13171. +{
  13172. +    do_hwgroup_request (ide_hwifs[3].hwgroup);
  13173. +}
  13174. +#endif
  13175. +
  13176. +static void timer_expiry (unsigned long data)
  13177. +{
  13178. +    ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
  13179. +    ide_drive_t   *drive   = hwgroup->drive;
  13180. +    unsigned long flags;
  13181. +
  13182. +    save_flags(flags);
  13183. +    cli();
  13184. +
  13185. +    if (hwgroup->poll_timeout != 0) { /* polling in progress? */
  13186. +        ide_handler_t *handler = hwgroup->handler;
  13187. +        hwgroup->handler = NULL;
  13188. +        handler(drive);
  13189. +    } else if (hwgroup->handler == NULL) {     /* not waiting for anything? */
  13190. +        sti(); /* drive must have responded just as the timer expired */
  13191. +        printk("%s: marginal timeout\n", drive->name);
  13192. +    } else {
  13193. +        hwgroup->handler = NULL;    /* abort the operation */
  13194. +        if (hwgroup->hwif->dmaproc)
  13195. +            (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
  13196. +        ide_error(drive, "irq timeout", GET_STAT());
  13197. +    }
  13198. +    if (hwgroup->handler == NULL)
  13199. +        do_hwgroup_request (hwgroup);
  13200. +    restore_flags(flags);
  13201. +}
  13202. +
  13203. +/*
  13204. + * There's nothing really useful we can do with an unexpected interrupt,
  13205. + * other than reading the status register (to clear it), and logging it.
  13206. + * There should be no way that an irq can happen before we're ready for it,
  13207. + * so we needn't worry much about losing an "important" interrupt here.
  13208. + *
  13209. + * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
  13210. + * drive enters "idle", "standby", or "sleep" mode, so if the status looks
  13211. + * "good", we just ignore the interrupt completely.
  13212. + *
  13213. + * This routine assumes cli() is in effect when called.
  13214. + *
  13215. + * If an unexpected interrupt happens on irq15 while we are handling irq14
  13216. + * and if the two interfaces are "serialized" (CMD640), then it looks like
  13217. + * we could screw up by interfering with a new request being set up for irq15.
  13218. + *
  13219. + * In reality, this is a non-issue.  The new command is not sent unless the
  13220. + * drive is ready to accept one, in which case we know the drive is not
  13221. + * trying to interrupt us.  And ide_set_handler() is always invoked before
  13222. + * completing the issuance of any new drive command, so we will not be
  13223. + * accidently invoked as a result of any valid command completion interrupt.
  13224. + *
  13225. + */
  13226. +static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
  13227. +{
  13228. +    byte stat;
  13229. +    unsigned int unit;
  13230. +    ide_hwif_t *hwif = hwgroup->hwif;
  13231. +
  13232. +    /*
  13233. +     * handle the unexpected interrupt
  13234. +     */
  13235. +    do {
  13236. +        if (hwif->irq == irq) {
  13237. +            for (unit = 0; unit < MAX_DRIVES; ++unit) {
  13238. +                ide_drive_t *drive = &hwif->drives[unit];
  13239. +                if (!drive->present)
  13240. +                    continue;
  13241. +                SELECT_DRIVE(hwif,drive);
  13242. +                udelay(100);  /* Ugly, but wait_stat() may not be safe here */
  13243. +                if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) {
  13244. +                    /* Try to not flood the console with msgs */
  13245. +                    static unsigned long last_msgtime = 0;
  13246. +                    if ((last_msgtime + (HZ/2)) < jiffies) {
  13247. +                        last_msgtime = jiffies;
  13248. +                        (void) ide_dump_status(drive, "unexpected_intr", stat);
  13249. +                    }
  13250. +                }
  13251. +                if ((stat & DRQ_STAT))
  13252. +                    try_to_flush_leftover_data(drive);
  13253. +            }
  13254. +        }
  13255. +    } while ((hwif = hwif->next) != hwgroup->hwif);
  13256. +    SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */
  13257. +    udelay(100);  /* Ugly, but wait_stat() may not be safe here */
  13258. +}
  13259. +
  13260. +/*
  13261. + * entry point for all interrupts, caller does cli() for us
  13262. + */
  13263. +void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
  13264. +{
  13265. +    ide_hwgroup_t *hwgroup = dev_id;
  13266. +    ide_handler_t *handler;
  13267. +
  13268. +    if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) {
  13269. +        ide_drive_t *drive = hwgroup->drive;
  13270. +        hwgroup->handler = NULL;
  13271. +        del_timer(&(hwgroup->timer));
  13272. +        if (drive->unmask)
  13273. +            sti();
  13274. +        handler(drive);
  13275. +        cli();    /* this is necessary, as next rq may be different irq */
  13276. +        if (hwgroup->handler == NULL) {
  13277. +            SET_RECOVERY_TIMER(HWIF(drive));
  13278. +            ide_do_request(hwgroup);
  13279. +        }
  13280. +    } else {
  13281. +        unexpected_intr(irq, hwgroup);
  13282. +    }
  13283. +    cli();
  13284. +}
  13285. +
  13286. +/*
  13287. + * get_info_ptr() returns the (ide_drive_t *) for a given device number.
  13288. + * It returns NULL if the given device number does not match any present drives.
  13289. + */
  13290. +static ide_drive_t *get_info_ptr (kdev_t i_rdev)
  13291. +{
  13292. +    int        major = MAJOR(i_rdev);
  13293. +    unsigned int    h;
  13294. +
  13295. +    for (h = 0; h < MAX_HWIFS; ++h) {
  13296. +        ide_hwif_t  *hwif = &ide_hwifs[h];
  13297. +        if (hwif->present && major == hwif->major) {
  13298. +            unsigned unit = DEVICE_NR(i_rdev);
  13299. +            if (unit < MAX_DRIVES) {
  13300. +                ide_drive_t *drive = &hwif->drives[unit];
  13301. +                if (drive->present)
  13302. +                    return drive;
  13303. +            } else if (major == IDE0_MAJOR && unit < 4) {
  13304. +                printk("ide: probable bad entry for /dev/hd%c\n", 'a'+unit);
  13305. +                printk("ide: to fix it, run:  /usr/src/linux/scripts/MAKEDEV.ide\n");
  13306. +            }
  13307. +            break;
  13308. +        }
  13309. +    }
  13310. +    return NULL;
  13311. +}
  13312. +
  13313. +/*
  13314. + * This function is intended to be used prior to invoking ide_do_drive_cmd().
  13315. + */
  13316. +void ide_init_drive_cmd (struct request *rq)
  13317. +{
  13318. +    rq->buffer = NULL;
  13319. +    rq->cmd = IDE_DRIVE_CMD;
  13320. +    rq->sector = 0;
  13321. +    rq->nr_sectors = 0;
  13322. +    rq->current_nr_sectors = 0;
  13323. +    rq->sem = NULL;
  13324. +    rq->bh = NULL;
  13325. +    rq->bhtail = NULL;
  13326. +    rq->next = NULL;
  13327. +
  13328. +#if 0    /* these are done each time through ide_do_drive_cmd() */
  13329. +    rq->errors = 0;
  13330. +    rq->rq_status = RQ_ACTIVE;
  13331. +    rq->rq_dev = ????;
  13332. +#endif
  13333. +}
  13334. +
  13335. +/*
  13336. + * This function issues a special IDE device request
  13337. + * onto the request queue.
  13338. + *
  13339. + * If action is ide_wait, then then rq is queued at the end of
  13340. + * the request queue, and the function sleeps until it has been
  13341. + * processed.  This is for use when invoked from an ioctl handler.
  13342. + *
  13343. + * If action is ide_preempt, then the rq is queued at the head of
  13344. + * the request queue, displacing the currently-being-processed
  13345. + * request and this function returns immediately without waiting
  13346. + * for the new rq to be completed.  This is VERY DANGEROUS, and is
  13347. + * intended for careful use by the ATAPI tape/cdrom driver code.
  13348. + *
  13349. + * If action is ide_next, then the rq is queued immediately after
  13350. + * the currently-being-processed-request (if any), and the function
  13351. + * returns without waiting for the new rq to be completed.  As above,
  13352. + * This is VERY DANGEROUS, and is intended for careful use by the
  13353. + * ATAPI tape/cdrom driver code.
  13354. + *
  13355. + * If action is ide_end, then the rq is queued at the end of the
  13356. + * request queue, and the function returns immediately without waiting
  13357. + * for the new rq to be completed. This is again intended for careful
  13358. + * use by the ATAPI tape/cdrom driver code. (Currently used by ide-tape.c,
  13359. + * when operating in the pipelined operation mode).
  13360. + */
  13361. +int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
  13362. +{
  13363. +    unsigned long flags;
  13364. +    unsigned int major = HWIF(drive)->major;
  13365. +    struct request *cur_rq;
  13366. +    struct blk_dev_struct *bdev = &blk_dev[major];
  13367. +    struct semaphore sem = MUTEX_LOCKED;
  13368. +
  13369. +    if (IS_PROMISE_DRIVE && rq->buffer != NULL)
  13370. +        return -ENOSYS;  /* special drive cmds not supported */
  13371. +    rq->errors = 0;
  13372. +    rq->rq_status = RQ_ACTIVE;
  13373. +    rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
  13374. +    if (action == ide_wait)
  13375. +        rq->sem = &sem;
  13376. +    unplug_device(bdev);
  13377. +
  13378. +    save_flags(flags);
  13379. +    cli();
  13380. +    if (action == ide_next)
  13381. +        HWGROUP(drive)->next_hwif = HWIF(drive);
  13382. +    cur_rq = bdev->current_request;
  13383. +
  13384. +    if (cur_rq == NULL || action == ide_preempt) {
  13385. +        rq->next = cur_rq;
  13386. +        bdev->current_request = rq;
  13387. +        if (action == ide_preempt) {
  13388. +            HWGROUP(drive)->rq = NULL;
  13389. +        } else
  13390. +        if (HWGROUP(drive)->rq == NULL) {  /* is this necessary (?) */
  13391. +            bdev->request_fn();
  13392. +            cli();
  13393. +        }
  13394. +    } else {
  13395. +        if (action == ide_wait || action == ide_end) {
  13396. +            while (cur_rq->next != NULL)    /* find end of list */
  13397. +                cur_rq = cur_rq->next;
  13398. +        }
  13399. +        rq->next = cur_rq->next;
  13400. +        cur_rq->next = rq;
  13401. +    }
  13402. +    if (action == ide_wait  && rq->rq_status != RQ_INACTIVE)
  13403. +        down(&sem);    /* wait for it to be serviced */
  13404. +    restore_flags(flags);
  13405. +    return rq->errors ? -EIO : 0;    /* return -EIO if errors */
  13406. +}
  13407. +
  13408. +static int ide_open(struct inode * inode, struct file * filp)
  13409. +{
  13410. +    ide_drive_t *drive;
  13411. +    unsigned long flags;
  13412. +
  13413. +    if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
  13414. +        return -ENXIO;
  13415. +    save_flags(flags);
  13416. +    cli();
  13417. +    while (drive->busy)
  13418. +        sleep_on(&drive->wqueue);
  13419. +    drive->usage++;
  13420. +    restore_flags(flags);
  13421. +#ifdef CONFIG_BLK_DEV_IDECD
  13422. +    if (drive->media == ide_cdrom)
  13423. +        return ide_cdrom_open (inode, filp, drive);
  13424. +#endif    /* CONFIG_BLK_DEV_IDECD */
  13425. +#ifdef CONFIG_BLK_DEV_IDETAPE
  13426. +    if (drive->media == ide_tape)
  13427. +        return idetape_blkdev_open (inode, filp, drive);
  13428. +#endif    /* CONFIG_BLK_DEV_IDETAPE */
  13429. +    if (drive->removable) {
  13430. +        byte door_lock[] = {WIN_DOORLOCK,0,0,0};
  13431. +        struct request rq;
  13432. +        check_disk_change(inode->i_rdev);
  13433. +        ide_init_drive_cmd (&rq);
  13434. +        rq.buffer = door_lock;
  13435. +        /*
  13436. +         * Ignore the return code from door_lock,
  13437. +         * since the open() has already succeeded,
  13438. +         * and the door_lock is irrelevant at this point.
  13439. +         */
  13440. +        (void) ide_do_drive_cmd(drive, &rq, ide_wait);
  13441. +    }
  13442. +    return 0;
  13443. +}
  13444. +
  13445. +/*
  13446. + * Releasing a block device means we sync() it, so that it can safely
  13447. + * be forgotten about...
  13448. + */
  13449. +static void ide_release(struct inode * inode, struct file * file)
  13450. +{
  13451. +    ide_drive_t *drive;
  13452. +
  13453. +    if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {
  13454. +        fsync_dev(inode->i_rdev);
  13455. +        drive->usage--;
  13456. +#ifdef CONFIG_BLK_DEV_IDECD
  13457. +        if (drive->media == ide_cdrom) {
  13458. +            ide_cdrom_release (inode, file, drive);
  13459. +            return;
  13460. +        }
  13461. +#endif    /* CONFIG_BLK_DEV_IDECD */
  13462. +#ifdef CONFIG_BLK_DEV_IDETAPE
  13463. +        if (drive->media == ide_tape) {
  13464. +            idetape_blkdev_release (inode, file, drive);
  13465. +            return;
  13466. +        }
  13467. +#endif    /* CONFIG_BLK_DEV_IDETAPE */
  13468. +        if (drive->removable && !drive->usage) {
  13469. +            byte door_unlock[] = {WIN_DOORUNLOCK,0,0,0};
  13470. +            struct request rq;
  13471. +            invalidate_buffers(inode->i_rdev);
  13472. +            ide_init_drive_cmd (&rq);
  13473. +            rq.buffer = door_unlock;
  13474. +            (void) ide_do_drive_cmd(drive, &rq, ide_wait);
  13475. +        }
  13476. +    }
  13477. +}
  13478. +
  13479. +/*
  13480. + * This routine is called to flush all partitions and partition tables
  13481. + * for a changed disk, and then re-read the new partition table.
  13482. + * If we are revalidating a disk because of a media change, then we
  13483. + * enter with usage == 0.  If we are using an ioctl, we automatically have
  13484. + * usage == 1 (we need an open channel to use an ioctl :-), so this
  13485. + * is our limit.
  13486. + */
  13487. +static int revalidate_disk(kdev_t i_rdev)
  13488. +{
  13489. +    ide_drive_t *drive;
  13490. +    unsigned int p, major, minor;
  13491. +    long flags;
  13492. +
  13493. +    if ((drive = get_info_ptr(i_rdev)) == NULL)
  13494. +        return -ENODEV;
  13495. +
  13496. +    major = MAJOR(i_rdev);
  13497. +    minor = drive->select.b.unit << PARTN_BITS;
  13498. +    save_flags(flags);
  13499. +    cli();
  13500. +    if (drive->busy || (drive->usage > 1)) {
  13501. +        restore_flags(flags);
  13502. +        return -EBUSY;
  13503. +    };
  13504. +    drive->busy = 1;
  13505. +    restore_flags(flags);
  13506. +
  13507. +    for (p = 0; p < (1<<PARTN_BITS); ++p) {
  13508. +        if (drive->part[p].nr_sects > 0) {
  13509. +            kdev_t devp = MKDEV(major, minor+p);
  13510. +            sync_dev           (devp);
  13511. +            invalidate_inodes  (devp);
  13512. +            invalidate_buffers (devp);
  13513. +        }
  13514. +        drive->part[p].start_sect = 0;
  13515. +        drive->part[p].nr_sects   = 0;
  13516. +    };
  13517. +
  13518. +    drive->part[0].nr_sects = current_capacity(drive);
  13519. +    if (drive->media != ide_disk)
  13520. +        drive->part[0].start_sect = -1;
  13521. +    resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit);
  13522. +
  13523. +    drive->busy = 0;
  13524. +    wake_up(&drive->wqueue);
  13525. +    return 0;
  13526. +}
  13527. +
  13528. +static int write_fs_long (unsigned long useraddr, long value)
  13529. +{
  13530. +    int err;
  13531. +
  13532. +    if (NULL == (long *)useraddr)
  13533. +        return -EINVAL;
  13534. +    if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
  13535. +        return err;
  13536. +    put_user((unsigned)value, (long *) useraddr);
  13537. +    return 0;
  13538. +}
  13539. +
  13540. +static int ide_ioctl (struct inode *inode, struct file *file,
  13541. +            unsigned int cmd, unsigned long arg)
  13542. +{
  13543. +    int err;
  13544. +    ide_drive_t *drive;
  13545. +    unsigned long flags;
  13546. +    struct request rq;
  13547. +
  13548. +    if (!inode || !(inode->i_rdev))
  13549. +        return -EINVAL;
  13550. +    if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
  13551. +        return -ENODEV;
  13552. +    ide_init_drive_cmd (&rq);
  13553. +    switch (cmd) {
  13554. +        case HDIO_GETGEO:
  13555. +        {
  13556. +            struct hd_geometry *loc = (struct hd_geometry *) arg;
  13557. +            if (!loc || drive->media != ide_disk) return -EINVAL;
  13558. +            err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
  13559. +            if (err) return err;
  13560. +            put_user(drive->bios_head, (byte *) &loc->heads);
  13561. +            put_user(drive->bios_sect, (byte *) &loc->sectors);
  13562. +            put_user(drive->bios_cyl, (unsigned short *) &loc->cylinders);
  13563. +            put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
  13564. +                (unsigned long *) &loc->start);
  13565. +            return 0;
  13566. +        }
  13567. +        case BLKFLSBUF:
  13568. +            if (!suser()) return -EACCES;
  13569. +            fsync_dev(inode->i_rdev);
  13570. +            invalidate_buffers(inode->i_rdev);
  13571. +            return 0;
  13572. +
  13573. +        case BLKRASET:
  13574. +            if (!suser()) return -EACCES;
  13575. +            if(arg > 0xff) return -EINVAL;
  13576. +            read_ahead[MAJOR(inode->i_rdev)] = arg;
  13577. +            return 0;
  13578. +
  13579. +        case BLKRAGET:
  13580. +            return write_fs_long(arg, read_ahead[MAJOR(inode->i_rdev)]);
  13581. +
  13582. +         case BLKGETSIZE:   /* Return device size */
  13583. +            return write_fs_long(arg, drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects);
  13584. +        case BLKRRPART: /* Re-read partition tables */
  13585. +            if (!suser()) return -EACCES;
  13586. +            return revalidate_disk(inode->i_rdev);
  13587. +
  13588. +        case HDIO_GET_KEEPSETTINGS:
  13589. +            return write_fs_long(arg, drive->keep_settings);
  13590. +
  13591. +        case HDIO_GET_UNMASKINTR:
  13592. +            return write_fs_long(arg, drive->unmask);
  13593. +
  13594. +        case HDIO_GET_DMA:
  13595. +            return write_fs_long(arg, drive->using_dma);
  13596. +
  13597. +        case HDIO_GET_32BIT:
  13598. +            return write_fs_long(arg, drive->io_32bit);
  13599. +
  13600. +        case HDIO_GET_MULTCOUNT:
  13601. +            return write_fs_long(arg, drive->mult_count);
  13602. +
  13603. +        case HDIO_GET_IDENTITY:
  13604. +            if (!arg || (MINOR(inode->i_rdev) & PARTN_MASK))
  13605. +                return -EINVAL;
  13606. +            if (drive->id == NULL)
  13607. +                return -ENOMSG;
  13608. +            err = verify_area(VERIFY_WRITE, (char *)arg, sizeof(*drive->id));
  13609. +            if (!err)
  13610. +                memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id));
  13611. +            return err;
  13612. +
  13613. +            case HDIO_GET_NOWERR:
  13614. +            return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT);
  13615. +
  13616. +        case HDIO_SET_DMA:
  13617. +            if (!suser()) return -EACCES;
  13618. +#ifdef CONFIG_BLK_DEV_IDECD
  13619. +            if (drive->media == ide_cdrom)
  13620. +                return -EPERM;
  13621. +#endif /* CONFIG_BLK_DEV_IDECD */
  13622. +            if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
  13623. +                return -EPERM;
  13624. +        case HDIO_SET_KEEPSETTINGS:
  13625. +        case HDIO_SET_UNMASKINTR:
  13626. +        case HDIO_SET_NOWERR:
  13627. +            if (arg > 1)
  13628. +                return -EINVAL;
  13629. +        case HDIO_SET_32BIT:
  13630. +            if (!suser()) return -EACCES;
  13631. +            if ((MINOR(inode->i_rdev) & PARTN_MASK))
  13632. +                return -EINVAL;
  13633. +            save_flags(flags);
  13634. +            cli();
  13635. +            switch (cmd) {
  13636. +                case HDIO_SET_DMA:
  13637. +                    if (!(HWIF(drive)->dmaproc)) {
  13638. +                        restore_flags(flags);
  13639. +                        return -EPERM;
  13640. +                    }
  13641. +                    drive->using_dma = arg;
  13642. +                    break;
  13643. +                case HDIO_SET_KEEPSETTINGS:
  13644. +                    drive->keep_settings = arg;
  13645. +                    break;
  13646. +                case HDIO_SET_UNMASKINTR:
  13647. +                    if (arg && drive->no_unmask) {
  13648. +                        restore_flags(flags);
  13649. +                        return -EPERM;
  13650. +                    }
  13651. +                    drive->unmask = arg;
  13652. +                    break;
  13653. +                case HDIO_SET_NOWERR:
  13654. +                    drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
  13655. +                    break;
  13656. +                case HDIO_SET_32BIT:
  13657. +                    if (arg > 1) {
  13658. +                        restore_flags (flags);
  13659. +                        return -EINVAL;
  13660. +                    }
  13661. +                    if (arg && drive->no_io_32bit) {
  13662. +                        restore_flags(flags);
  13663. +                        return -EPERM;
  13664. +                    }
  13665. +                    drive->io_32bit = arg;
  13666. +#ifdef CONFIG_BLK_DEV_DTC2278
  13667. +                    if (HWIF(drive)->chipset == ide_dtc2278)
  13668. +                        HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
  13669. +#endif /* CONFIG_BLK_DEV_DTC2278 */
  13670. +                    break;
  13671. +            }
  13672. +            restore_flags(flags);
  13673. +            return 0;
  13674. +
  13675. +        case HDIO_SET_MULTCOUNT:
  13676. +            if (!suser()) return -EACCES;
  13677. +            if (MINOR(inode->i_rdev) & PARTN_MASK)
  13678. +                return -EINVAL;
  13679. +            if (drive->id && arg > drive->id->max_multsect)
  13680. +                return -EINVAL;
  13681. +            save_flags(flags);
  13682. +            cli();
  13683. +            if (drive->special.b.set_multmode) {
  13684. +                restore_flags(flags);
  13685. +                return -EBUSY;
  13686. +            }
  13687. +            drive->mult_req = arg;
  13688. +            drive->special.b.set_multmode = 1;
  13689. +            restore_flags(flags);
  13690. +            (void) ide_do_drive_cmd (drive, &rq, ide_wait);
  13691. +            return (drive->mult_count == arg) ? 0 : -EIO;
  13692. +
  13693. +        case HDIO_DRIVE_CMD:
  13694. +        {
  13695. +            byte args[4], *argbuf = args;
  13696. +            int argsize = 4;
  13697. +            if (!suser()) return -EACCES;
  13698. +            if (NULL == (void *) arg) {
  13699. +                err = ide_do_drive_cmd(drive, &rq, ide_wait);
  13700. +            } else if (!(err = verify_area(VERIFY_READ,(void *)arg, 4))) {
  13701. +                memcpy_fromfs(args, (void *)arg, 4);
  13702. +                if (args[3]) {
  13703. +                    argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
  13704. +                    argbuf = kmalloc(argsize, GFP_KERNEL);
  13705. +                    if (argbuf == NULL)
  13706. +                        return -ENOMEM;
  13707. +                    argbuf[0] = args[0];
  13708. +                    argbuf[1] = args[1];
  13709. +                    argbuf[2] = args[2];
  13710. +                    argbuf[3] = args[3];
  13711. +                }
  13712. +                if (!(err = verify_area(VERIFY_WRITE,(void *)arg, argsize))) {
  13713. +                    rq.buffer = argbuf;
  13714. +                    err = ide_do_drive_cmd(drive, &rq, ide_wait);
  13715. +                    memcpy_tofs((void *)arg, argbuf, argsize);
  13716. +                }
  13717. +                if (argsize > 4)
  13718. +                    kfree(argbuf);
  13719. +            }
  13720. +            return err;
  13721. +        }
  13722. +        case HDIO_SET_PIO_MODE:
  13723. +            if (!suser()) return -EACCES;
  13724. +            if (MINOR(inode->i_rdev) & PARTN_MASK)
  13725. +                return -EINVAL;
  13726. +            if (!HWIF(drive)->tuneproc)
  13727. +                return -ENOSYS;
  13728. +            save_flags(flags);
  13729. +            cli();
  13730. +            if (drive->special.b.set_tune) {
  13731. +                restore_flags(flags);
  13732. +                return -EBUSY;
  13733. +            }
  13734. +            drive->tune_req = (byte) arg;
  13735. +            drive->special.b.set_tune = 1;
  13736. +            restore_flags(flags);
  13737. +            (void) ide_do_drive_cmd (drive, &rq, ide_wait);
  13738. +            return 0;
  13739. +
  13740. +        RO_IOCTLS(inode->i_rdev, arg);
  13741. +
  13742. +        default:
  13743. +#ifdef CONFIG_BLK_DEV_IDECD
  13744. +            if (drive->media == ide_cdrom)
  13745. +                return ide_cdrom_ioctl(drive, inode, file, cmd, arg);
  13746. +#endif /* CONFIG_BLK_DEV_IDECD */
  13747. +#ifdef CONFIG_BLK_DEV_IDETAPE
  13748. +            if (drive->media == ide_tape)
  13749. +                return idetape_blkdev_ioctl(drive, inode, file, cmd, arg);
  13750. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  13751. +            return -EPERM;
  13752. +    }
  13753. +}
  13754. +
  13755. +static int ide_check_media_change (kdev_t i_rdev)
  13756. +{
  13757. +    ide_drive_t *drive;
  13758. +
  13759. +    if ((drive = get_info_ptr(i_rdev)) == NULL)
  13760. +        return -ENODEV;
  13761. +#ifdef CONFIG_BLK_DEV_IDECD
  13762. +    if (drive->media == ide_cdrom)
  13763. +        return ide_cdrom_check_media_change (drive);
  13764. +#endif    /* CONFIG_BLK_DEV_IDECD */
  13765. +    if (drive->removable) /* for disks */
  13766. +        return 1;    /* always assume it was changed */
  13767. +    return 0;
  13768. +}
  13769. +
  13770. +void ide_fixstring (byte *s, const int bytecount, const int byteswap)
  13771. +{
  13772. +    byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
  13773. +
  13774. +    if (byteswap) {
  13775. +        /* convert from big-endian to host byte order */
  13776. +        for (p = end ; p != s;) {
  13777. +            unsigned short *pp = (unsigned short *) (p -= 2);
  13778. +            *pp = ntohs(*pp);
  13779. +        }
  13780. +    }
  13781. +
  13782. +    /* strip leading blanks */
  13783. +    while (s != end && *s == ' ')
  13784. +        ++s;
  13785. +
  13786. +    /* compress internal blanks and strip trailing blanks */
  13787. +    while (s != end && *s) {
  13788. +        if (*s++ != ' ' || (s != end && *s && *s != ' '))
  13789. +            *p++ = *(s-1);
  13790. +    }
  13791. +
  13792. +    /* wipe out trailing garbage */
  13793. +    while (p != end)
  13794. +        *p++ = '\0';
  13795. +}
  13796. +
  13797. +static inline void do_identify (ide_drive_t *drive, byte cmd)
  13798. +{
  13799. +    int bswap;
  13800. +    struct hd_driveid *id;
  13801. +    unsigned long capacity, check;
  13802. +
  13803. +    id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL);
  13804. +    ide_input_data(drive, id, SECTOR_WORDS);    /* read 512 bytes of id info */
  13805. +    sti();
  13806. +
  13807. +    /*
  13808. +     * EATA SCSI controllers do a hardware ATA emulation:  ignore them
  13809. +     */
  13810. +    if ((id->model[0] == 'P' && id->model[1] == 'M')
  13811. +     || (id->model[0] == 'S' && id->model[1] == 'K')) {
  13812. +        printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
  13813. +        drive->present = 0;
  13814. +        return;
  13815. +    }
  13816. +
  13817. +    /*
  13818. +     *  WIN_IDENTIFY returns little-endian info,
  13819. +     *  WIN_PIDENTIFY *usually* returns little-endian info.
  13820. +     */
  13821. +    bswap = 1;
  13822. +    if (cmd == WIN_PIDENTIFY) {
  13823. +        if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
  13824. +         || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
  13825. +         || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
  13826. +            bswap = 0;    /* Vertos drives may still be weird */
  13827. +    }
  13828. +    ide_fixstring (id->model,     sizeof(id->model),     bswap);
  13829. +    ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
  13830. +    ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
  13831. +
  13832. +#ifdef CONFIG_BLK_DEV_IDEATAPI
  13833. +    /*
  13834. +     * Check for an ATAPI device
  13835. +     */
  13836. +    if (cmd == WIN_PIDENTIFY) {
  13837. +        byte type = (id->config >> 8) & 0x1f;
  13838. +        printk("%s: %s, ATAPI ", drive->name, id->model);
  13839. +#ifdef CONFIG_BLK_DEV_PROMISE
  13840. +        if (HWIF(drive)->is_promise2) {
  13841. +            printk(" -- not supported on 2nd Promise port\n");
  13842. +            drive->present = 0;
  13843. +            return;
  13844. +        }
  13845. +#endif /* CONFIG_BLK_DEV_PROMISE */
  13846. +        switch (type) {
  13847. +            case 0:        /* Early cdrom models used zero */
  13848. +            case 5:
  13849. +#ifdef CONFIG_BLK_DEV_IDECD
  13850. +                printk ("CDROM drive\n");
  13851. +                drive->media = ide_cdrom;
  13852. +                 drive->present = 1;
  13853. +                drive->removable = 1;
  13854. +                return;
  13855. +#else
  13856. +                printk ("CDROM ");
  13857. +                break;
  13858. +#endif /* CONFIG_BLK_DEV_IDECD */
  13859. +            case 1:
  13860. +#ifdef CONFIG_BLK_DEV_IDETAPE
  13861. +                printk ("TAPE drive");
  13862. +                if (idetape_identify_device (drive,id)) {
  13863. +                    drive->media = ide_tape;
  13864. +                    drive->present = 1;
  13865. +                    drive->removable = 1;
  13866. +                    if (drive->autotune != 2 && HWIF(drive)->dmaproc != NULL) {
  13867. +                        if (!HWIF(drive)->dmaproc(ide_dma_check, drive))
  13868. +                            printk(", DMA");
  13869. +                    }
  13870. +                    printk("\n");
  13871. +                }
  13872. +                else {
  13873. +                    drive->present = 0;
  13874. +                    printk ("\nide-tape: the tape is not supported by this version of the driver\n");
  13875. +                }
  13876. +                return;
  13877. +#else
  13878. +                printk ("TAPE ");
  13879. +                break;
  13880. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  13881. +            default:
  13882. +                drive->present = 0;
  13883. +                printk("Type %d - Unknown device\n", type);
  13884. +                return;
  13885. +        }
  13886. +        drive->present = 0;
  13887. +        printk("- not supported by this kernel\n");
  13888. +        return;
  13889. +    }
  13890. +#endif /* CONFIG_BLK_DEV_IDEATAPI */
  13891. +
  13892. +    /* check for removable disks (eg. SYQUEST), ignore 'WD' drives */
  13893. +    if (id->config & (1<<7)) {    /* removable disk ? */
  13894. +        if (id->model[0] != 'W' || id->model[1] != 'D')
  13895. +            drive->removable = 1;
  13896. +    }
  13897. +
  13898. +    /* SunDisk drives: treat as non-removable, force one unit */
  13899. +    if (id->model[0] == 'S' && id->model[1] == 'u') {
  13900. +        drive->removable = 0;
  13901. +        if (drive->select.all & (1<<4)) {
  13902. +            drive->present = 0;
  13903. +            return;
  13904. +        }
  13905. +    }
  13906. +
  13907. +    drive->media = ide_disk;
  13908. +    /* Extract geometry if we did not already have one for the drive */
  13909. +    if (!drive->present) {
  13910. +        drive->present = 1;
  13911. +        drive->cyl     = drive->bios_cyl  = id->cyls;
  13912. +        drive->head    = drive->bios_head = id->heads;
  13913. +        drive->sect    = drive->bios_sect = id->sectors;
  13914. +    }
  13915. +    /* Handle logical geometry translation by the drive */
  13916. +    if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads
  13917. +     && (id->cur_heads <= 16) && id->cur_sectors)
  13918. +    {
  13919. +        /*
  13920. +         * Extract the physical drive geometry for our use.
  13921. +         * Note that we purposely do *not* update the bios info.
  13922. +         * This way, programs that use it (like fdisk) will
  13923. +         * still have the same logical view as the BIOS does,
  13924. +         * which keeps the partition table from being screwed.
  13925. +         *
  13926. +         * An exception to this is the cylinder count,
  13927. +         * which we reexamine later on to correct for 1024 limitations.
  13928. +         */
  13929. +        drive->cyl  = id->cur_cyls;
  13930. +        drive->head = id->cur_heads;
  13931. +        drive->sect = id->cur_sectors;
  13932. +
  13933. +        /* check for word-swapped "capacity" field in id information */
  13934. +        capacity = drive->cyl * drive->head * drive->sect;
  13935. +        check = (id->cur_capacity0 << 16) | id->cur_capacity1;
  13936. +        if (check == capacity) {    /* was it swapped? */
  13937. +            /* yes, bring it into little-endian order: */
  13938. +            id->cur_capacity0 = (capacity >>  0) & 0xffff;
  13939. +            id->cur_capacity1 = (capacity >> 16) & 0xffff;
  13940. +        }
  13941. +    }
  13942. +    /* Use physical geometry if what we have still makes no sense */
  13943. +    if ((!drive->head || drive->head > 16) && id->heads && id->heads <= 16) {
  13944. +        drive->cyl  = id->cyls;
  13945. +        drive->head = id->heads;
  13946. +        drive->sect = id->sectors;
  13947. +    }
  13948. +    /* Correct the number of cyls if the bios value is too small */
  13949. +    if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) {
  13950. +        if (drive->cyl > drive->bios_cyl)
  13951. +            drive->bios_cyl = drive->cyl;
  13952. +    }
  13953. +
  13954. +    (void) current_capacity (drive); /* initialize LBA selection */
  13955. +
  13956. +    printk ("%s: %.40s, %ldMB w/%dkB Cache, %sCHS=%d/%d/%d",
  13957. +     drive->name, id->model, current_capacity(drive)/2048L, id->buf_size/2,
  13958. +     drive->select.b.lba ? "LBA, " : "",
  13959. +     drive->bios_cyl, drive->bios_head, drive->bios_sect);
  13960. +
  13961. +    drive->mult_count = 0;
  13962. +    if (id->max_multsect) {
  13963. +        drive->mult_req = INITIAL_MULT_COUNT;
  13964. +        if (drive->mult_req > id->max_multsect)
  13965. +            drive->mult_req = id->max_multsect;
  13966. +        if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
  13967. +            drive->special.b.set_multmode = 1;
  13968. +    }
  13969. +    if (drive->autotune != 2 && HWIF(drive)->dmaproc != NULL) {
  13970. +        if (!(HWIF(drive)->dmaproc(ide_dma_check, drive)))
  13971. +            printk(", DMA");
  13972. +    }
  13973. +    printk("\n");
  13974. +}
  13975. +
  13976. +/*
  13977. + * Delay for *at least* 50ms.  As we don't know how much time is left
  13978. + * until the next tick occurs, we wait an extra tick to be safe.
  13979. + * This is used only during the probing/polling for drives at boot time.
  13980. + */
  13981. +static void delay_50ms (void)
  13982. +{
  13983. +    unsigned long timer = jiffies + (HZ + 19)/20 + 1;
  13984. +    while (timer > jiffies);
  13985. +}
  13986. +
  13987. +/*
  13988. + * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive
  13989. + * and waits for a response.  It also monitors irqs while this is
  13990. + * happening, in hope of automatically determining which one is
  13991. + * being used by the interface.
  13992. + *
  13993. + * Returns:    0  device was identified
  13994. + *        1  device timed-out (no response to identify request)
  13995. + *        2  device aborted the command (refused to identify itself)
  13996. + */
  13997. +static int try_to_identify (ide_drive_t *drive, byte cmd)
  13998. +{
  13999. +    int hd_status, rc;
  14000. +    unsigned long timeout;
  14001. +    int irqs = 0;
  14002. +
  14003. +    if (!HWIF(drive)->irq) {        /* already got an IRQ? */
  14004. +        probe_irq_off(probe_irq_on());    /* clear dangling irqs */
  14005. +        irqs = probe_irq_on();        /* start monitoring irqs */
  14006. +        OUT_BYTE(drive->ctl,IDE_CONTROL_REG);    /* enable device irq */
  14007. +    }
  14008. +
  14009. +    delay_50ms();                /* take a deep breath */
  14010. +    if ((IN_BYTE(IDE_ALTSTATUS_REG) ^ IN_BYTE(IDE_STATUS_REG)) & ~INDEX_STAT) {
  14011. +        printk("%s: probing with STATUS instead of ALTSTATUS\n", drive->name);
  14012. +        hd_status = IDE_STATUS_REG;    /* ancient Seagate drives */
  14013. +    } else
  14014. +        hd_status = IDE_ALTSTATUS_REG;    /* use non-intrusive polling */
  14015. +
  14016. +#if CONFIG_BLK_DEV_PROMISE
  14017. +    if (IS_PROMISE_DRIVE) {
  14018. +        if (promise_cmd(drive,PROMISE_IDENTIFY)) {
  14019. +            if (irqs)
  14020. +                (void) probe_irq_off(irqs);
  14021. +            return 1;
  14022. +        }
  14023. +    } else
  14024. +#endif /* CONFIG_BLK_DEV_PROMISE */
  14025. +        OUT_BYTE(cmd,IDE_COMMAND_REG);        /* ask drive for ID */
  14026. +    timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
  14027. +    timeout += jiffies;
  14028. +    do {
  14029. +        if (jiffies > timeout) {
  14030. +            if (irqs)
  14031. +                (void) probe_irq_off(irqs);
  14032. +            return 1;    /* drive timed-out */
  14033. +        }
  14034. +        delay_50ms();        /* give drive a breather */
  14035. +    } while (IN_BYTE(hd_status) & BUSY_STAT);
  14036. +
  14037. +    delay_50ms();        /* wait for IRQ and DRQ_STAT */
  14038. +    if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
  14039. +        unsigned long flags;
  14040. +        save_flags(flags);
  14041. +        cli();            /* some systems need this */
  14042. +        do_identify(drive, cmd); /* drive returned ID */
  14043. +        rc = 0;            /* drive responded with ID */
  14044. +        (void) GET_STAT();    /* clear drive IRQ */
  14045. +        restore_flags(flags);
  14046. +    } else
  14047. +        rc = 2;            /* drive refused ID */
  14048. +    if (!HWIF(drive)->irq) {
  14049. +        irqs = probe_irq_off(irqs);    /* get our irq number */
  14050. +        if (irqs > 0) {
  14051. +            HWIF(drive)->irq = irqs; /* save it for later */
  14052. +            irqs = probe_irq_on();
  14053. +            OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */
  14054. +            udelay(5);
  14055. +            (void) probe_irq_off(irqs);
  14056. +            (void) probe_irq_off(probe_irq_on()); /* clear self-inflicted irq */
  14057. +            (void) GET_STAT();    /* clear drive IRQ */
  14058. +
  14059. +        } else {    /* Mmmm.. multiple IRQs.. don't know which was ours */
  14060. +            printk("%s: IRQ probe failed (%d)\n", drive->name, irqs);
  14061. +#ifdef CONFIG_BLK_DEV_CMD640
  14062. +#ifdef CMD640_DUMP_REGS
  14063. +            if (HWIF(drive)->chipset == ide_cmd640) {
  14064. +                printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
  14065. +                CMD640_DUMP_REGS;
  14066. +            }
  14067. +#endif /* CMD640_DUMP_REGS */
  14068. +#endif /* CONFIG_BLK_DEV_CMD640 */
  14069. +        }
  14070. +    }
  14071. +    return rc;
  14072. +}
  14073. +
  14074. +/*
  14075. + * do_probe() has the difficult job of finding a drive if it exists,
  14076. + * without getting hung up if it doesn't exist, without trampling on
  14077. + * ethernet cards, and without leaving any IRQs dangling to haunt us later.
  14078. + *
  14079. + * If a drive is "known" to exist (from CMOS or kernel parameters),
  14080. + * but does not respond right away, the probe will "hang in there"
  14081. + * for the maximum wait time (about 30 seconds), otherwise it will
  14082. + * exit much more quickly.
  14083. + *
  14084. + * Returns:    0  device was identified
  14085. + *        1  device timed-out (no response to identify request)
  14086. + *        2  device aborted the command (refused to identify itself)
  14087. + *        3  bad status from device (possible for ATAPI drives)
  14088. + *        4  probe was not attempted because failure was obvious
  14089. + */
  14090. +static int do_probe (ide_drive_t *drive, byte cmd)
  14091. +{
  14092. +    int rc;
  14093. +    ide_hwif_t *hwif = HWIF(drive);
  14094. +#ifdef CONFIG_BLK_DEV_IDEATAPI
  14095. +    if (drive->present) {    /* avoid waiting for inappropriate probes */
  14096. +        if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
  14097. +            return 4;
  14098. +    }
  14099. +#endif    /* CONFIG_BLK_DEV_IDEATAPI */
  14100. +#ifdef DEBUG
  14101. +    printk("probing for %s: present=%d, media=%d, probetype=%s\n",
  14102. +        drive->name, drive->present, drive->media,
  14103. +        (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
  14104. +#endif
  14105. +    SELECT_DRIVE(hwif,drive);
  14106. +    OUT_BYTE(drive->select.all,IDE_SELECT_REG);    /* select target drive */
  14107. +    delay_50ms();
  14108. +    if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
  14109. +        OUT_BYTE(0xa0,IDE_SELECT_REG);    /* exit with drive0 selected */
  14110. +        delay_50ms();        /* allow BUSY_STAT to assert & clear */
  14111. +        return 3;    /* no i/f present: avoid killing ethernet cards */
  14112. +    }
  14113. +
  14114. +    if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT)
  14115. +     || drive->present || cmd == WIN_PIDENTIFY)
  14116. +    {
  14117. +        if ((rc = try_to_identify(drive,cmd)))   /* send cmd and wait */
  14118. +            rc = try_to_identify(drive,cmd); /* failed: try again */
  14119. +        if (rc == 1)
  14120. +            printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT());
  14121. +        (void) GET_STAT();        /* ensure drive irq is clear */
  14122. +    } else {
  14123. +        rc = 3;                /* not present or maybe ATAPI */
  14124. +    }
  14125. +    if (drive->select.b.unit != 0) {
  14126. +        OUT_BYTE(0xa0,IDE_SELECT_REG);    /* exit with drive0 selected */
  14127. +        delay_50ms();
  14128. +        (void) GET_STAT();        /* ensure drive irq is clear */
  14129. +    }
  14130. +    return rc;
  14131. +}
  14132. +
  14133. +/*
  14134. + * probe_for_drive() tests for existence of a given drive using do_probe().
  14135. + *
  14136. + * Returns:    0  no device was found
  14137. + *        1  device was found (note: drive->present might still be 0)
  14138. + */
  14139. +static inline byte probe_for_drive (ide_drive_t *drive)
  14140. +{
  14141. +    if (drive->noprobe)            /* skip probing? */
  14142. +        return drive->present;
  14143. +    if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
  14144. +#ifdef CONFIG_BLK_DEV_IDEATAPI
  14145. +        (void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
  14146. +#endif    /* CONFIG_BLK_DEV_IDEATAPI */
  14147. +    }
  14148. +    if (!drive->present)
  14149. +        return 0;            /* drive not found */
  14150. +    if (drive->id == NULL) {        /* identification failed? */
  14151. +        if (drive->media == ide_disk) {
  14152. +            printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",
  14153. +             drive->name, drive->cyl, drive->head, drive->sect);
  14154. +        }
  14155. +#ifdef CONFIG_BLK_DEV_IDECD
  14156. +        else if (drive->media == ide_cdrom) {
  14157. +            printk("%s: ATAPI cdrom (?)\n", drive->name);
  14158. +        }
  14159. +#endif    /* CONFIG_BLK_DEV_IDECD */
  14160. +        else {
  14161. +            drive->present = 0;    /* nuke it */
  14162. +        }
  14163. +    }
  14164. +    return 1;    /* drive was found */
  14165. +}
  14166. +
  14167. +/*
  14168. + * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
  14169. + * controller that is BIOS compatible with ST-506, and thus showing up in our
  14170. + * BIOS table, but not register compatible, and therefore not present in CMOS.
  14171. + *
  14172. + * Furthermore, we will assume that our ST-506 drives <if any> are the primary
  14173. + * drives in the system -- the ones reflected as drive 1 or 2.  The first
  14174. + * drive is stored in the high nibble of CMOS byte 0x12, the second in the low
  14175. + * nibble.  This will be either a 4 bit drive type or 0xf indicating use byte
  14176. + * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value
  14177. + * means we have an AT controller hard disk for that drive.
  14178. + *
  14179. + * Of course, there is no guarantee that either drive is actually on the
  14180. + * "primary" IDE interface, but we don't bother trying to sort that out here.
  14181. + * If a drive is not actually on the primary interface, then these parameters
  14182. + * will be ignored.  This results in the user having to supply the logical
  14183. + * drive geometry as a boot parameter for each drive not on the primary i/f.
  14184. + *
  14185. + * The only "perfect" way to handle this would be to modify the setup.[cS] code
  14186. + * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
  14187. + * for us during initialization.  I have the necessary docs -- any takers?  -ml
  14188. + */
  14189. +static void probe_cmos_for_drives (ide_hwif_t *hwif)
  14190. +{
  14191. +#ifdef __i386__
  14192. +    extern struct drive_info_struct drive_info;
  14193. +    byte cmos_disks, *BIOS = (byte *) &drive_info;
  14194. +    int unit;
  14195. +
  14196. +#ifdef CONFIG_BLK_DEV_PROMISE
  14197. +    if (hwif->is_promise2)
  14198. +        return;
  14199. +#endif /* CONFIG_BLK_DEV_PROMISE */
  14200. +    outb_p(0x12,0x70);        /* specify CMOS address 0x12 */
  14201. +    cmos_disks = inb_p(0x71);    /* read the data from 0x12 */
  14202. +    /* Extract drive geometry from CMOS+BIOS if not already setup */
  14203. +    for (unit = 0; unit < MAX_DRIVES; ++unit) {
  14204. +        ide_drive_t *drive = &hwif->drives[unit];
  14205. +        if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) {
  14206. +            drive->cyl   = drive->bios_cyl  = *(unsigned short *)BIOS;
  14207. +            drive->head  = drive->bios_head = *(BIOS+2);
  14208. +            drive->sect  = drive->bios_sect = *(BIOS+14);
  14209. +            drive->ctl   = *(BIOS+8);
  14210. +            drive->present = 1;
  14211. +        }
  14212. +        BIOS += 16;
  14213. +    }
  14214. +#endif
  14215. +}
  14216. +
  14217. +/*
  14218. + * This routine only knows how to look for drive units 0 and 1
  14219. + * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
  14220. + */
  14221. +static void probe_hwif (ide_hwif_t *hwif)
  14222. +{
  14223. +    unsigned int unit;
  14224. +
  14225. +    if (hwif->noprobe)
  14226. +        return;
  14227. +    if (hwif->io.io_base == HD_DATA)
  14228. +        probe_cmos_for_drives (hwif);
  14229. +#if CONFIG_BLK_DEV_PROMISE
  14230. +    if (!hwif->is_promise2 &&
  14231. +       (check_region(hwif->io_base,8) || check_region(hwif->ctl_port,1))) {
  14232. +#else
  14233. +    if (check_region(hwif->io.io_base,8) || check_region(hwif->io.ctl_port,1)) {
  14234. +#endif /* CONFIG_BLK_DEV_PROMISE */
  14235. +        int msgout = 0;
  14236. +        for (unit = 0; unit < MAX_DRIVES; ++unit) {
  14237. +            ide_drive_t *drive = &hwif->drives[unit];
  14238. +            if (drive->present) {
  14239. +                drive->present = 0;
  14240. +                printk("%s: ERROR, PORTS ALREADY IN USE\n", drive->name);
  14241. +                msgout = 1;
  14242. +            }
  14243. +        }
  14244. +        if (!msgout)
  14245. +            printk("%s: ports already in use, skipping probe\n", hwif->name);
  14246. +    } else {
  14247. +        unsigned long flags;
  14248. +        save_flags(flags);
  14249. +
  14250. +        sti();    /* needed for jiffies and irq probing */
  14251. +        /*
  14252. +         * Second drive should only exist if first drive was found,
  14253. +         * but a lot of cdrom drives are configured as single slaves.
  14254. +         */
  14255. +        for (unit = 0; unit < MAX_DRIVES; ++unit) {
  14256. +            ide_drive_t *drive = &hwif->drives[unit];
  14257. +            (void) probe_for_drive (drive);
  14258. +            if (drive->present && drive->media == ide_disk) {
  14259. +                if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
  14260. +                    printk("%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
  14261. +                     drive->name, drive->head);
  14262. +                    drive->present = 0;
  14263. +                }
  14264. +            }
  14265. +            if (drive->present && !hwif->present) {
  14266. +                hwif->present = 1;
  14267. +                request_region(hwif->io.io_base,  8, hwif->name);
  14268. +                request_region(hwif->io.ctl_port, 1, hwif->name);
  14269. +            }
  14270. +        }
  14271. +        restore_flags(flags);
  14272. +        for (unit = 0; unit < MAX_DRIVES; ++unit) {
  14273. +            ide_drive_t *drive = &hwif->drives[unit];
  14274. +            if (drive->present && drive->media != ide_tape) {
  14275. +                ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
  14276. +                if (tuneproc != NULL && drive->autotune == 1)
  14277. +                    tuneproc(drive, 255);   /* auto-tune PIO mode */
  14278. +            }
  14279. +        }
  14280. +    }
  14281. +}
  14282. +
  14283. +/*
  14284. + * stridx() returns the offset of c within s,
  14285. + * or -1 if c is '\0' or not found within s.
  14286. + */
  14287. +static int stridx (const char *s, char c)
  14288. +{
  14289. +    char *i = strchr(s, c);
  14290. +    return (i && c) ? i - s : -1;
  14291. +}
  14292. +
  14293. +/*
  14294. + * match_parm() does parsing for ide_setup():
  14295. + *
  14296. + * 1. the first char of s must be '='.
  14297. + * 2. if the remainder matches one of the supplied keywords,
  14298. + *     the index (1 based) of the keyword is negated and returned.
  14299. + * 3. if the remainder is a series of no more than max_vals numbers
  14300. + *     separated by commas, the numbers are saved in vals[] and a
  14301. + *     count of how many were saved is returned.  Base10 is assumed,
  14302. + *     and base16 is allowed when prefixed with "0x".
  14303. + * 4. otherwise, zero is returned.
  14304. + */
  14305. +static int match_parm (char *s, const char *keywords[], int vals[], int max_vals)
  14306. +{
  14307. +    static const char *decimal = "0123456789";
  14308. +    static const char *hex = "0123456789abcdef";
  14309. +    int i, n;
  14310. +
  14311. +    if (*s++ == '=') {
  14312. +        /*
  14313. +         * Try matching against the supplied keywords,
  14314. +         * and return -(index+1) if we match one
  14315. +         */
  14316. +        if (keywords != NULL) {
  14317. +            for (i = 0; *keywords != NULL; ++i) {
  14318. +                if (!strcmp(s, *keywords++))
  14319. +                    return -(i+1);
  14320. +            }
  14321. +        }
  14322. +        /*
  14323. +         * Look for a series of no more than "max_vals"
  14324. +         * numeric values separated by commas, in base10,
  14325. +         * or base16 when prefixed with "0x".
  14326. +         * Return a count of how many were found.
  14327. +         */
  14328. +        for (n = 0; (i = stridx(decimal, *s)) >= 0;) {
  14329. +            vals[n] = i;
  14330. +            while ((i = stridx(decimal, *++s)) >= 0)
  14331. +                vals[n] = (vals[n] * 10) + i;
  14332. +            if (*s == 'x' && !vals[n]) {
  14333. +                while ((i = stridx(hex, *++s)) >= 0)
  14334. +                    vals[n] = (vals[n] * 0x10) + i;
  14335. +            }
  14336. +            if (++n == max_vals)
  14337. +                break;
  14338. +            if (*s == ',')
  14339. +                ++s;
  14340. +        }
  14341. +        if (!*s)
  14342. +            return n;
  14343. +    }
  14344. +    return 0;    /* zero = nothing matched */
  14345. +}
  14346. +
  14347. +/*
  14348. + * ide_setup() gets called VERY EARLY during initialization,
  14349. + * to handle kernel "command line" strings beginning with "hdx="
  14350. + * or "ide".  Here is the complete set currently supported:
  14351. + *
  14352. + * "hdx="  is recognized for all "x" from "a" to "h", such as "hdc".
  14353. + * "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
  14354. + *
  14355. + * "hdx=noprobe"    : drive may be present, but do not probe for it
  14356. + * "hdx=none"        : drive is NOT present, ignore cmos and do not probe
  14357. + * "hdx=nowerr"        : ignore the WRERR_STAT bit on this drive
  14358. + * "hdx=cdrom"        : drive is present, and is a cdrom drive
  14359. + * "hdx=cyl,head,sect"    : disk drive is present, with specified geometry
  14360. + * "hdx=autotune"    : driver will attempt to tune interface speed
  14361. + *                to the fastest PIO mode supported,
  14362. + *                if possible for this drive only.
  14363. + *                Not fully supported by all chipset types,
  14364. + *                and quite likely to cause trouble with
  14365. + *                older/odd IDE drives.
  14366. + *
  14367. + * "idebus=xx"        : inform IDE driver of VESA/PCI bus speed in Mhz,
  14368. + *                where "xx" is between 20 and 66 inclusive,
  14369. + *                used when tuning chipset PIO modes.
  14370. + *                For PCI bus, 25 is correct for a P75 system,
  14371. + *                30 is correct for P90,P120,P180 systems,
  14372. + *                and 33 is used for P100,P133,P166 systems.
  14373. + *                If in doubt, use idebus=33 for PCI.
  14374. + *                As for VLB, it is safest to not specify it.
  14375. + *
  14376. + * "idex=noprobe"    : do not attempt to access/use this interface
  14377. + * "idex=base"        : probe for an interface at the addr specified,
  14378. + *                where "base" is usually 0x1f0 or 0x170
  14379. + *                and "ctl" is assumed to be "base"+0x206
  14380. + * "idex=base,ctl"    : specify both base and ctl
  14381. + * "idex=base,ctl,irq"    : specify base, ctl, and irq number
  14382. + * "idex=autotune"    : driver will attempt to tune interface speed
  14383. + *                to the fastest PIO mode supported,
  14384. + *                for all drives on this interface.
  14385. + *                Not fully supported by all chipset types,
  14386. + *                and quite likely to cause trouble with
  14387. + *                older/odd IDE drives.
  14388. + * "idex=noautotune"    : driver will NOT attempt to tune interface speed
  14389. + *                This is the default for most chipsets,
  14390. + *                except the cmd640.
  14391. + * "idex=serialize"    : do not overlap operations on idex and ide(x^1)
  14392. + *
  14393. + * The following are valid ONLY on ide0,
  14394. + * and the defaults for the base,ctl ports must not be altered.
  14395. + *
  14396. + * "ide0=dtc2278"    : probe/support DTC2278 interface
  14397. + * "ide0=ht6560b"    : probe/support HT6560B interface
  14398. + * "ide0=cmd640_vlb"    : *REQUIRED* for VLB cards with the CMD640 chip
  14399. + *              (not for PCI -- automatically detected)
  14400. + * "ide0=qd6580"    : probe/support qd6580 interface
  14401. + * "ide0=ali14xx"    : probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
  14402. + * "ide0=umc8672"    : probe/support umc8672 chipsets
  14403. + */
  14404. +void ide_setup (char *s)
  14405. +{
  14406. +    int i, vals[3];
  14407. +    ide_hwif_t *hwif;
  14408. +    ide_drive_t *drive;
  14409. +    unsigned int hw, unit;
  14410. +    const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
  14411. +    const char max_hwif  = '0' + (MAX_HWIFS - 1);
  14412. +
  14413. +    printk("ide_setup: %s", s);
  14414. +    init_ide_data ();
  14415. +
  14416. +    /*
  14417. +     * Look for drive options:  "hdx="
  14418. +     */
  14419. +    if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
  14420. +        const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
  14421. +                "serialize", "autotune", "noautotune", NULL};
  14422. +        unit = s[2] - 'a';
  14423. +        hw   = unit / MAX_DRIVES;
  14424. +        unit = unit % MAX_DRIVES;
  14425. +        hwif = &ide_hwifs[hw];
  14426. +        drive = &hwif->drives[unit];
  14427. +        switch (match_parm(&s[3], hd_words, vals, 3)) {
  14428. +            case -1: /* "none" */
  14429. +                drive->nobios = 1;  /* drop into "noprobe" */
  14430. +            case -2: /* "noprobe" */
  14431. +                drive->noprobe = 1;
  14432. +                goto done;
  14433. +            case -3: /* "nowerr" */
  14434. +                drive->bad_wstat = BAD_R_STAT;
  14435. +                hwif->noprobe = 0;
  14436. +                goto done;
  14437. +            case -4: /* "cdrom" */
  14438. +                drive->present = 1;
  14439. +                drive->media = ide_cdrom;
  14440. +                hwif->noprobe = 0;
  14441. +                goto done;
  14442. +            case -5: /* "serialize" */
  14443. +                printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
  14444. +                goto do_serialize;
  14445. +            case -6: /* "autotune" */
  14446. +                drive->autotune = 1;
  14447. +                goto done;
  14448. +            case -7: /* "noautotune" */
  14449. +                drive->autotune = 2;
  14450. +                goto done;
  14451. +            case 3: /* cyl,head,sect */
  14452. +                drive->media    = ide_disk;
  14453. +                drive->cyl    = drive->bios_cyl  = vals[0];
  14454. +                drive->head    = drive->bios_head = vals[1];
  14455. +                drive->sect    = drive->bios_sect = vals[2];
  14456. +                drive->present    = 1;
  14457. +                drive->forced_geom = 1;
  14458. +                hwif->noprobe = 0;
  14459. +                goto done;
  14460. +            default:
  14461. +                goto bad_option;
  14462. +        }
  14463. +    }
  14464. +
  14465. +    if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
  14466. +        goto bad_option;
  14467. +    /*
  14468. +     * Look for bus speed option:  "idebus="
  14469. +     */
  14470. +    if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') {
  14471. +        if (match_parm(&s[6], NULL, vals, 1) != 1)
  14472. +            goto bad_option;
  14473. +        if (vals[0] >= 20 && vals[0] <= 66)
  14474. +            idebus_parameter = vals[0];
  14475. +        else
  14476. +            printk(" -- BAD BUS SPEED! Expected value from 20 to 66");
  14477. +        goto done;
  14478. +    }
  14479. +    /*
  14480. +     * Look for interface options:  "idex="
  14481. +     */
  14482. +    if (s[3] >= '0' && s[3] <= max_hwif) {
  14483. +        /*
  14484. +         * Be VERY CAREFUL changing this: note hardcoded indexes below
  14485. +         */
  14486. +        const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune",
  14487. +            "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL};
  14488. +        hw = s[3] - '0';
  14489. +        hwif = &ide_hwifs[hw];
  14490. +        i = match_parm(&s[4], ide_words, vals, 3);
  14491. +
  14492. +        /*
  14493. +         * Cryptic check to ensure chipset not already set for hwif:
  14494. +         */
  14495. +        if (i > 0 || i <= -5) {
  14496. +            if (hwif->chipset != ide_unknown)
  14497. +                goto bad_option;
  14498. +            if (i <= -5) {
  14499. +                if (ide_hwifs[1].chipset != ide_unknown)
  14500. +                    goto bad_option;
  14501. +                /*
  14502. +                 * Interface keywords work only for ide0:
  14503. +                 */
  14504. +                if (hw != 0)
  14505. +                    goto bad_hwif;
  14506. +            }
  14507. +        }
  14508. +
  14509. +        switch (i) {
  14510. +#ifdef CONFIG_BLK_DEV_PROMISE
  14511. +            case -11: /* "dc4030" */
  14512. +            {
  14513. +                setup_dc4030(hwif);
  14514. +                goto done;
  14515. +            }
  14516. +#endif /* CONFIG_BLK_DEV_PROMISE */
  14517. +            case -4: /* "noautotune" */
  14518. +                hwif->drives[0].autotune = 2;
  14519. +                hwif->drives[1].autotune = 2;
  14520. +                goto done;
  14521. +            case -3: /* "autotune" */
  14522. +                hwif->drives[0].autotune = 1;
  14523. +                hwif->drives[1].autotune = 1;
  14524. +                goto done;
  14525. +            case -2: /* "serialize" */
  14526. +            do_serialize:
  14527. +                ide_hwifs[hw].serialized = 1;   /* serialize */
  14528. +                ide_hwifs[hw^1].serialized = 1; /* with mate */
  14529. +                goto done;
  14530. +
  14531. +            case -1: /* "noprobe" */
  14532. +                hwif->noprobe = 1;
  14533. +                goto done;
  14534. +
  14535. +            case 1:    /* base */
  14536. +                vals[1] = vals[0] + 0x206; /* default ctl */
  14537. +            case 2: /* base,ctl */
  14538. +                vals[2] = 0;    /* default irq = probe for it */
  14539. +            case 3: /* base,ctl,irq */
  14540. +                hwif->io.io_base  = vals[0];
  14541. +                hwif->io.ctl_port = vals[1];
  14542. +                hwif->io.io_size  = 1;
  14543. +                hwif->irq      = vals[2];
  14544. +                hwif->noprobe  = 0;
  14545. +                hwif->chipset  = ide_generic;
  14546. +                goto done;
  14547. +
  14548. +            case 0: goto bad_option;
  14549. +            default:
  14550. +                printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n");
  14551. +                return;
  14552. +        }
  14553. +    }
  14554. +bad_option:
  14555. +    printk(" -- BAD OPTION\n");
  14556. +    return;
  14557. +bad_hwif:
  14558. +    printk("-- NOT SUPPORTED ON ide%d", hw);
  14559. +done:
  14560. +    printk("\n");
  14561. +}
  14562. +
  14563. +/*
  14564. + * This routine is called from the partition-table code in genhd.c
  14565. + * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
  14566. + *
  14567. + * The second parameter, "xparm", determines exactly how the translation 
  14568. + * will be handled:
  14569. + *         0 = convert to CHS with fewer than 1024 cyls
  14570. + *            using the same method as Ontrack DiskManager.
  14571. + *         1 = same as "0", plus offset everything by 63 sectors.
  14572. + *        -1 = similar to "0", plus redirect sector 0 to sector 1.
  14573. + *        >1 = convert to a CHS geometry with "xparm" heads.
  14574. + *
  14575. + * Returns 0 if the translation was not possible, if the device was not 
  14576. + * an IDE disk drive, or if a geometry was "forced" on the commandline.
  14577. + * Returns 1 if the geometry translation was successful.
  14578. + */
  14579. +int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
  14580. +{
  14581. +    ide_drive_t *drive;
  14582. +    static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
  14583. +    const byte *heads = head_vals;
  14584. +    unsigned long tracks;
  14585. +
  14586. +    if ((drive = get_info_ptr(i_rdev)) == NULL || drive->forced_geom)
  14587. +        return 0;
  14588. +
  14589. +    if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63)
  14590. +        return 0;        /* we already have a translation */
  14591. +
  14592. +    printk("%s ", msg);
  14593. +
  14594. +    if (drive->id) {
  14595. +        drive->cyl  = drive->id->cyls;
  14596. +        drive->head = drive->id->heads;
  14597. +        drive->sect = drive->id->sectors;
  14598. +    }
  14599. +    drive->bios_cyl  = drive->cyl;
  14600. +    drive->bios_head = drive->head;
  14601. +    drive->bios_sect = drive->sect;
  14602. +    drive->special.b.set_geometry = 1;
  14603. +
  14604. +    tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
  14605. +    drive->bios_sect = 63;
  14606. +    if (xparm > 1) {
  14607. +        drive->bios_head = xparm;
  14608. +        drive->bios_cyl = tracks / drive->bios_head;
  14609. +    } else {
  14610. +        while (drive->bios_cyl >= 1024) {
  14611. +            drive->bios_head = *heads;
  14612. +            drive->bios_cyl = tracks / drive->bios_head;
  14613. +            if (0 == *++heads)
  14614. +                break;
  14615. +        }
  14616. +#if FAKE_FDISK_FOR_EZDRIVE
  14617. +        if (xparm == -1) {
  14618. +            drive->remap_0_to_1 = 1;
  14619. +            msg = "0->1";
  14620. +        } else
  14621. +#endif /* FAKE_FDISK_FOR_EZDRIVE */
  14622. +        if (xparm == 1) {
  14623. +            drive->sect0 = 63;
  14624. +            drive->bios_cyl = (tracks - 1) / drive->bios_head;
  14625. +            msg = "+63";
  14626. +        }
  14627. +        printk("[remap %s] ", msg);
  14628. +    }
  14629. +    drive->part[0].nr_sects = current_capacity(drive);
  14630. +    printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
  14631. +    return 1;
  14632. +}
  14633. +
  14634. +#if MAX_HWIFS > 1
  14635. +/*
  14636. + * save_match() is used to simplify logic in init_irq() below.
  14637. + *
  14638. + * A loophole here is that we may not know about a particular
  14639. + * hwif's irq until after that hwif is actually probed/initialized..
  14640. + * This could be a problem for the case where an hwif is on a
  14641. + * dual interface that requires serialization (eg. cmd640) and another
  14642. + * hwif using one of the same irqs is initialized beforehand.
  14643. + *
  14644. + * This routine detects and reports such situations, but does not fix them.
  14645. + */
  14646. +static void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
  14647. +{
  14648. +    ide_hwif_t *m = *match;
  14649. +
  14650. +    if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
  14651. +        if (!new->hwgroup)
  14652. +            return;
  14653. +        printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name);
  14654. +    }
  14655. +    if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
  14656. +        *match = new;
  14657. +}
  14658. +#endif /* MAX_HWIFS > 1 */
  14659. +
  14660. +/*
  14661. + * This routine sets up the irq for an ide interface, and creates a new
  14662. + * hwgroup for the irq/hwif if none was previously assigned.
  14663. + *
  14664. + * Much of the code is for correctly detecting/handling irq sharing
  14665. + * and irq serialization situations.  This is somewhat complex because
  14666. + * it handles static as well as dynamic (PCMCIA) IDE interfaces.
  14667. + *
  14668. + * The SA_INTERRUPT in sa_flags means ide_intr() is always entered with
  14669. + * interrupts completely disabled.  This can be bad for interrupt latency,
  14670. + * but anything else has led to problems on some machines.  We re-enable
  14671. + * interrupts as much as we can safely do in most places.
  14672. + */
  14673. +static int init_irq (ide_hwif_t *hwif)
  14674. +{
  14675. +    unsigned long flags;
  14676. +#if MAX_HWIFS > 1
  14677. +    unsigned int index;
  14678. +#endif /* MAX_HWIFS > 1 */
  14679. +    ide_hwgroup_t *hwgroup;
  14680. +    ide_hwif_t *match = NULL;
  14681. +
  14682. +    save_flags(flags);
  14683. +    cli();
  14684. +
  14685. +    hwif->hwgroup = NULL;
  14686. +#if MAX_HWIFS > 1
  14687. +    /*
  14688. +     * Group up with any other hwifs that share our irq(s).
  14689. +     */
  14690. +    for (index = 0; index < MAX_HWIFS; index++) {
  14691. +        ide_hwif_t *h = &ide_hwifs[index];
  14692. +        if (h->hwgroup) {  /* scan only initialized hwif's */
  14693. +            if (hwif->irq == h->irq) {
  14694. +                hwif->sharing_irq = h->sharing_irq = 1;
  14695. +                save_match(hwif, h, &match);
  14696. +            }
  14697. +            if (hwif->serialized) {
  14698. +                ide_hwif_t *mate = &ide_hwifs[hwif->index^1];
  14699. +                if (index == mate->index || h->irq == mate->irq)
  14700. +                    save_match(hwif, h, &match);
  14701. +            }
  14702. +            if (h->serialized) {
  14703. +                ide_hwif_t *mate = &ide_hwifs[h->index^1];
  14704. +                if (hwif->irq == mate->irq)
  14705. +                    save_match(hwif, h, &match);
  14706. +            }
  14707. +        }
  14708. +    }
  14709. +#endif /* MAX_HWIFS > 1 */
  14710. +    /*
  14711. +     * If we are still without a hwgroup, then form a new one
  14712. +     */
  14713. +    if (match) {
  14714. +        hwgroup = match->hwgroup;
  14715. +    } else {
  14716. +        hwgroup = kmalloc(sizeof(ide_hwgroup_t), GFP_KERNEL);
  14717. +        hwgroup->hwif      = hwgroup->next_hwif = hwif->next = hwif;
  14718. +        hwgroup->rq      = NULL;
  14719. +        hwgroup->handler = NULL;
  14720. +        if (hwif->drives[0].present)
  14721. +            hwgroup->drive = &hwif->drives[0];
  14722. +        else
  14723. +            hwgroup->drive = &hwif->drives[1];
  14724. +        hwgroup->poll_timeout = 0;
  14725. +        init_timer(&hwgroup->timer);
  14726. +        hwgroup->timer.function = &timer_expiry;
  14727. +        hwgroup->timer.data = (unsigned long) hwgroup;
  14728. +    }
  14729. +
  14730. +    /*
  14731. +     * Allocate the irq, if not already obtained for another hwif
  14732. +     */
  14733. +    if (!match || match->irq != hwif->irq) {
  14734. +        if (request_irq(hwif->irq, ide_intr, SA_INTERRUPT, hwif->name, hwgroup)) {
  14735. +            if (!match)
  14736. +                kfree(hwgroup);
  14737. +            restore_flags(flags);
  14738. +            return 1;
  14739. +        }
  14740. +    }
  14741. +
  14742. +    /*
  14743. +     * Everything is okay, so link us into the hwgroup
  14744. +     */
  14745. +    hwif->hwgroup = hwgroup;
  14746. +    hwif->next = hwgroup->hwif->next;
  14747. +    hwgroup->hwif->next = hwif;
  14748. +
  14749. +    restore_flags(flags);    /* safe now that hwif->hwgroup is set up */
  14750. +
  14751. +    printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
  14752. +        hwif->io.io_base, hwif->io.io_base+7, hwif->io.ctl_port, hwif->irq);
  14753. +    if (match)
  14754. +        printk(" (%sed with %s)", hwif->sharing_irq ? "shar" : "serializ", match->name);
  14755. +    printk("\n");
  14756. +    return 0;
  14757. +}
  14758. +
  14759. +static struct file_operations ide_fops = {
  14760. +    NULL,            /* lseek - default */
  14761. +    block_read,        /* read - general block-dev read */
  14762. +    block_write,        /* write - general block-dev write */
  14763. +    NULL,            /* readdir - bad */
  14764. +    NULL,            /* select */
  14765. +    ide_ioctl,        /* ioctl */
  14766. +    NULL,            /* mmap */
  14767. +    ide_open,        /* open */
  14768. +    ide_release,        /* release */
  14769. +    block_fsync        /* fsync */
  14770. +    ,NULL,            /* fasync */
  14771. +    ide_check_media_change,    /* check_media_change */
  14772. +    revalidate_disk        /* revalidate */
  14773. +};
  14774. +
  14775. +/*
  14776. + * ide_init_pci() finds/initializes "known" PCI IDE interfaces
  14777. + *
  14778. + * This routine should ideally be using pcibios_find_class() to find
  14779. + * all IDE interfaces, but that function causes some systems to "go weird".
  14780. + */
  14781. +static void probe_for_hwifs (void)
  14782. +{
  14783. +}
  14784. +
  14785. +static int hwif_init (int h)
  14786. +{
  14787. +    ide_hwif_t *hwif = &ide_hwifs[h];
  14788. +    void (*rfn)(void);
  14789. +    
  14790. +    if (!hwif->present)
  14791. +        return 0;
  14792. +    if (!hwif->irq) {
  14793. +        if (!(hwif->irq = default_irqs[h])) {
  14794. +            printk("%s: DISABLED, NO IRQ\n", hwif->name);
  14795. +            return (hwif->present = 0);
  14796. +        }
  14797. +    }
  14798. +#ifdef CONFIG_BLK_DEV_HD
  14799. +    if (hwif->irq == HD_IRQ && hwif->io_base != HD_DATA) {
  14800. +        printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
  14801. +        return (hwif->present = 0);
  14802. +    }
  14803. +#endif /* CONFIG_BLK_DEV_HD */
  14804. +    
  14805. +    hwif->present = 0; /* we set it back to 1 if all is ok below */
  14806. +    switch (hwif->major) {
  14807. +    case IDE0_MAJOR: rfn = &do_ide0_request; break;
  14808. +#if MAX_HWIFS > 1
  14809. +    case IDE1_MAJOR: rfn = &do_ide1_request; break;
  14810. +#endif
  14811. +#if MAX_HWIFS > 2
  14812. +    case IDE2_MAJOR: rfn = &do_ide2_request; break;
  14813. +#endif
  14814. +#if MAX_HWIFS > 3
  14815. +    case IDE3_MAJOR: rfn = &do_ide3_request; break;
  14816. +#endif
  14817. +    default:
  14818. +        printk("%s: request_fn NOT DEFINED\n", hwif->name);
  14819. +        return (hwif->present = 0);
  14820. +    }
  14821. +    if (register_blkdev (hwif->major, hwif->name, &ide_fops)) {
  14822. +        printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
  14823. +    } else if (init_irq (hwif)) {
  14824. +        printk("%s: UNABLE TO GET IRQ %d\n", hwif->name, hwif->irq);
  14825. +        (void) unregister_blkdev (hwif->major, hwif->name);
  14826. +    } else {
  14827. +        init_gendisk(hwif);
  14828. +        blk_dev[hwif->major].request_fn = rfn;
  14829. +        read_ahead[hwif->major] = 8;    /* (4kB) */
  14830. +        hwif->present = 1;    /* success */
  14831. +    }
  14832. +    return hwif->present;
  14833. +}
  14834. +
  14835. +/*
  14836. + * This is gets invoked once during initialization, to set *everything* up
  14837. + */
  14838. +int ide_init (void)
  14839. +{
  14840. +    int index;
  14841. +
  14842. +    init_ide_data ();
  14843. +    /*
  14844. +     * Probe for special "known" interface chipsets
  14845. +     */
  14846. +    probe_for_hwifs ();
  14847. +
  14848. +    /*
  14849. +     * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
  14850. +     */
  14851. +    for (index = 0; index < MAX_HWIFS; ++index)
  14852. +        probe_hwif (&ide_hwifs[index]);
  14853. +    for (index = 0; index < MAX_HWIFS; ++index)
  14854. +        hwif_init (index);
  14855. +
  14856. +#ifdef CONFIG_BLK_DEV_IDETAPE
  14857. +    idetape_register_chrdev();    /* Register character device interface to the ide tape */
  14858. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  14859. +    
  14860. +    return 0;
  14861. +}
  14862. +
  14863. +#ifdef CONFIG_BLK_DEV_IDE_PCMCIA
  14864. +int ide_register(int io_base, int ctl_port, int irq)
  14865. +{
  14866. +    int index, i, rc = -1;
  14867. +    ide_hwif_t *hwif;
  14868. +    ide_drive_t *drive;
  14869. +    unsigned long flags;
  14870. +
  14871. +    save_flags(flags);
  14872. +    cli();
  14873. +    for (index = 0; index < MAX_HWIFS; ++index) {
  14874. +        hwif = &ide_hwifs[index];
  14875. +        if (hwif->present) {
  14876. +            if (hwif->io_base == io_base || hwif->ctl_port == ctl_port)
  14877. +                break; /* this ide port already exists */
  14878. +        } else {
  14879. +            hwif->io_base = io_base;
  14880. +            hwif->ctl_port = ctl_port;
  14881. +            hwif->irq = irq;
  14882. +            hwif->noprobe = 0;
  14883. +            probe_hwif(hwif);
  14884. +            if (!hwif_init(index))
  14885. +                break;
  14886. +            for (i = 0; i < hwif->gd->nr_real; i++) {
  14887. +                drive = &hwif->drives[i];
  14888. +                revalidate_disk(MKDEV(hwif->major, i<<PARTN_BITS));
  14889. +#ifdef CONFIG_BLK_DEV_IDECD
  14890. +                if (drive->present && drive->media == ide_cdrom)
  14891. +                    ide_cdrom_setup(drive);
  14892. +#endif /* CONFIG_BLK_DEV_IDECD */
  14893. +            }
  14894. +            rc = index;
  14895. +            break;
  14896. +        }
  14897. +    }
  14898. +    restore_flags(flags);
  14899. +    return rc;
  14900. +}
  14901. +
  14902. +void ide_unregister (unsigned int index)
  14903. +{
  14904. +    struct gendisk *gd, **gdp;
  14905. +    ide_hwif_t *hwif, *g;
  14906. +    ide_hwgroup_t *hwgroup;
  14907. +    int irq_count = 0;
  14908. +    unsigned long flags;
  14909. +
  14910. +    if (index >= MAX_HWIFS)
  14911. +        return;
  14912. +    save_flags(flags);
  14913. +    cli();
  14914. +    hwif = &ide_hwifs[index];
  14915. +    if (!hwif->present || hwif->drives[0].busy || hwif->drives[1].busy) {
  14916. +        restore_flags(flags);
  14917. +        return;
  14918. +    }
  14919. +    hwif->present = 0;
  14920. +    hwgroup = hwif->hwgroup;
  14921. +
  14922. +    /*
  14923. +     * free the irq if we were the only hwif using it
  14924. +     */
  14925. +    g = hwgroup->hwif;
  14926. +    do {
  14927. +        if (g->irq == hwif->irq)
  14928. +            ++irq_count;
  14929. +        g = g->next;
  14930. +    } while (g != hwgroup->hwif);
  14931. +    if (irq_count == 1)
  14932. +        free_irq(hwif->irq, hwgroup);
  14933. +
  14934. +    /*
  14935. +     * Note that we only release the standard ports,
  14936. +     * and do not even try to handle any extra ports
  14937. +     * allocated for weird IDE interface chipsets.
  14938. +     */
  14939. +    release_region(hwif->io_base, 8);
  14940. +    release_region(hwif->ctl_port, 1);
  14941. +
  14942. +    /*
  14943. +     * Remove us from the hwgroup, and free
  14944. +     * the hwgroup if we were the only member
  14945. +     */
  14946. +    while (hwgroup->hwif->next != hwif)
  14947. +        hwgroup->hwif = hwgroup->hwif->next;
  14948. +    hwgroup->hwif->next = hwif->next;
  14949. +    if (hwgroup->hwif == hwif)
  14950. +        hwgroup->hwif = hwif->next;
  14951. +    if (hwgroup->next_hwif == hwif)
  14952. +        hwgroup->next_hwif = hwif->next;
  14953. +    if (hwgroup->hwif == hwif)
  14954. +        kfree(hwgroup);
  14955. +
  14956. +    /*
  14957. +     * Remove us from the kernel's knowledge
  14958. +     */
  14959. +    unregister_blkdev(hwif->major, hwif->name);
  14960. +    kfree(blksize_size[hwif->major]);
  14961. +    blk_dev[hwif->major].request_fn = NULL;
  14962. +    blksize_size[hwif->major] = NULL;
  14963. +    for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
  14964. +        if (*gdp == hwif->gd)
  14965. +            break;
  14966. +    if (*gdp == NULL)
  14967. +        printk("gd not in disk chain!\n");
  14968. +    else {
  14969. +        gd = *gdp; *gdp = gd->next;
  14970. +        kfree(gd->sizes);
  14971. +        kfree(gd->part);
  14972. +        kfree(gd);
  14973. +    }
  14974. +    init_hwif_data (index);    /* restore hwif data to pristine status */
  14975. +    restore_flags(flags);
  14976. +}
  14977. +#endif /* CONFIG_BLK_DEV_IDE_PCMCIA */
  14978. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/ide.h linux/arch/arm/drivers/block/ide.h
  14979. --- linux.orig/arch/arm/drivers/block/ide.h    Thu Jan  1 01:00:00 1970
  14980. +++ linux/arch/arm/drivers/block/ide.h    Sat Sep  7 10:26:07 1996
  14981. @@ -0,0 +1,678 @@
  14982. +/*
  14983. + *  linux/drivers/block/ide.h
  14984. + *
  14985. + *  Copyright (C) 1994, 1995  Linus Torvalds & authors
  14986. + */
  14987. +
  14988. +#include <linux/config.h>
  14989. +
  14990. +/*
  14991. + * This is the multiple IDE interface driver, as evolved from hd.c.  
  14992. + * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
  14993. + * There can be up to two drives per interface, as per the ATA-2 spec.
  14994. + *
  14995. + * Primary i/f:    ide0: major=3;  (hda)         minor=0; (hdb)         minor=64
  14996. + * Secondary i/f:  ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
  14997. + * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
  14998. + * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
  14999. + */
  15000. +
  15001. +/******************************************************************************
  15002. + * IDE driver configuration options (play with these as desired):
  15003. + * 
  15004. + * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
  15005. + */
  15006. +#undef REALLY_FAST_IO            /* define if ide ports are perfect */
  15007. +#define INITIAL_MULT_COUNT    0    /* off=0; on=2,4,8,16,32, etc.. */
  15008. +
  15009. +#ifndef DISK_RECOVERY_TIME        /* off=0; on=access_delay_time */
  15010. +#define DISK_RECOVERY_TIME    0    /*  for hardware that needs it */
  15011. +#endif
  15012. +#ifndef OK_TO_RESET_CONTROLLER        /* 1 needed for good error recovery */
  15013. +#define OK_TO_RESET_CONTROLLER    1    /* 0 for use with AH2372A/B interface */
  15014. +#endif
  15015. +#ifndef FAKE_FDISK_FOR_EZDRIVE        /* 1 to help linux fdisk with EZDRIVE */
  15016. +#define FAKE_FDISK_FOR_EZDRIVE     1    /* 0 to reduce kernel size */
  15017. +#endif
  15018. +#ifndef FANCY_STATUS_DUMPS        /* 1 for human-readable drive errors */
  15019. +#define FANCY_STATUS_DUMPS    1    /* 0 to reduce kernel size */
  15020. +#endif
  15021. +
  15022. +#if defined(CONFIG_BLK_DEV_IDECD) || defined(CONFIG_BLK_DEV_IDETAPE)
  15023. +#define CONFIG_BLK_DEV_IDEATAPI 1
  15024. +#endif
  15025. +
  15026. +/*
  15027. + * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
  15028. + */
  15029. +#define IDE_DRIVE_CMD        99    /* (magic) undef to reduce kernel size*/
  15030. +
  15031. +/*
  15032. + *  "No user-serviceable parts" beyond this point  :)
  15033. + *****************************************************************************/
  15034. +
  15035. +typedef unsigned char    byte;    /* used everywhere */
  15036. +
  15037. +/*
  15038. + * Probably not wise to fiddle with these
  15039. + */
  15040. +#define ERROR_MAX    8    /* Max read/write errors per sector */
  15041. +#define ERROR_RESET    3    /* Reset controller every 4th retry */
  15042. +#define ERROR_RECAL    1    /* Recalibrate every 2nd retry */
  15043. +
  15044. +/*
  15045. + * Ensure that various configuration flags have compatible settings
  15046. + */
  15047. +#ifdef REALLY_SLOW_IO
  15048. +#undef REALLY_FAST_IO
  15049. +#endif
  15050. +
  15051. +/*
  15052. + * Definitions for accessing IDE controller registers
  15053. + */
  15054. +
  15055. +#define HWIF(drive)        ((ide_hwif_t *)((drive)->hwif))
  15056. +#define HWGROUP(drive)        ((ide_hwgroup_t *)(HWIF(drive)->hwgroup))
  15057. +
  15058. +#define IDE_DATA_OFFSET        (0)
  15059. +#define IDE_ERROR_OFFSET    (1)
  15060. +#define IDE_NSECTOR_OFFSET    (2)
  15061. +#define IDE_SECTOR_OFFSET    (3)
  15062. +#define IDE_LCYL_OFFSET        (4)
  15063. +#define IDE_HCYL_OFFSET        (5)
  15064. +#define IDE_SELECT_OFFSET    (6)
  15065. +#define IDE_STATUS_OFFSET    (7)
  15066. +#define IDE_FEATURE_OFFSET    IDE_ERROR_OFFSET
  15067. +#define IDE_COMMAND_OFFSET    IDE_STATUS_OFFSET
  15068. +
  15069. +#define IDE_DATA_REG        (HWIF(drive)->io.io_base+HWIF(drive)->io.io_size*IDE_DATA_OFFSET)
  15070. +#define IDE_ERROR_REG        (HWIF(drive)->io.io_base+HWIF(drive)->io.io_size*IDE_ERROR_OFFSET)
  15071. +#define IDE_NSECTOR_REG        (HWIF(drive)->io.io_base+HWIF(drive)->io.io_size*IDE_NSECTOR_OFFSET)
  15072. +#define IDE_SECTOR_REG        (HWIF(drive)->io.io_base+HWIF(drive)->io.io_size*IDE_SECTOR_OFFSET)
  15073. +#define IDE_LCYL_REG        (HWIF(drive)->io.io_base+HWIF(drive)->io.io_size*IDE_LCYL_OFFSET)
  15074. +#define IDE_HCYL_REG        (HWIF(drive)->io.io_base+HWIF(drive)->io.io_size*IDE_HCYL_OFFSET)
  15075. +#define IDE_SELECT_REG        (HWIF(drive)->io.io_base+HWIF(drive)->io.io_size*IDE_SELECT_OFFSET)
  15076. +#define IDE_STATUS_REG        (HWIF(drive)->io.io_base+HWIF(drive)->io.io_size*IDE_STATUS_OFFSET)
  15077. +#define IDE_CONTROL_REG        (HWIF(drive)->io.ctl_port)
  15078. +#define IDE_FEATURE_REG        IDE_ERROR_REG
  15079. +#define IDE_COMMAND_REG        IDE_STATUS_REG
  15080. +#define IDE_ALTSTATUS_REG    IDE_CONTROL_REG
  15081. +
  15082. +#ifdef REALLY_FAST_IO
  15083. +#define OUT_BYTE(b,p)        outb((b),(p))
  15084. +#define IN_BYTE(p)        (byte)inb(p)
  15085. +#else
  15086. +#define OUT_BYTE(b,p)        outb_p((b),(p))
  15087. +#define IN_BYTE(p)        (byte)inb_p(p)
  15088. +#endif /* REALLY_FAST_IO */
  15089. +
  15090. +#define GET_ERR()        IN_BYTE(IDE_ERROR_REG)
  15091. +#define GET_STAT()        IN_BYTE(IDE_STATUS_REG)
  15092. +#define OK_STAT(stat,good,bad)    (((stat)&((good)|(bad)))==(good))
  15093. +#define BAD_R_STAT        (BUSY_STAT   | ERR_STAT)
  15094. +#define BAD_W_STAT        (BAD_R_STAT  | WRERR_STAT)
  15095. +#define BAD_STAT        (BAD_R_STAT  | DRQ_STAT)
  15096. +#define DRIVE_READY        (READY_STAT  | SEEK_STAT)
  15097. +#define DATA_READY        (DRIVE_READY | DRQ_STAT)
  15098. +
  15099. +/*
  15100. + * Some more useful definitions
  15101. + */
  15102. +#define IDE_MAJOR_NAME    "ide"    /* the same for all i/f; see also genhd.c */
  15103. +#define MAJOR_NAME    IDE_MAJOR_NAME
  15104. +#define PARTN_BITS    6    /* number of minor dev bits for partitions */
  15105. +#define PARTN_MASK    ((1<<PARTN_BITS)-1)    /* a useful bit mask */
  15106. +#define MAX_DRIVES    2    /* per interface; 2 assumed by lots of code */
  15107. +#ifndef MAX_HWIFS
  15108. +#define MAX_HWIFS    4    /* an arbitrary, but realistic limit */
  15109. +#endif
  15110. +#define SECTOR_WORDS    (512 / 4)    /* number of 32bit words per sector */
  15111. +
  15112. +/*
  15113. + * Timeouts for various operations:
  15114. + */
  15115. +#define WAIT_DRQ    (5*HZ/100)    /* 50msec - spec allows up to 20ms */
  15116. +#ifdef CONFIG_APM
  15117. +#define WAIT_READY    (5*HZ)        /* 5sec - some laptops are very slow */
  15118. +#else
  15119. +#define WAIT_READY    (3*HZ/100)    /* 30msec - should be instantaneous */
  15120. +#endif /* CONFIG_APM */
  15121. +#define WAIT_PIDENTIFY    (1*HZ)    /* 1sec   - should be less than 3ms (?) */
  15122. +#define WAIT_WORSTCASE    (30*HZ)    /* 30sec  - worst case when spinning up */
  15123. +#define WAIT_CMD    (10*HZ)    /* 10sec  - maximum wait for an IRQ to happen */
  15124. +
  15125. +#define SELECT_DRIVE(hwif,drive)  OUT_BYTE((drive)->select.all, hwif->io.io_base+hwif->io.io_size * IDE_SELECT_OFFSET);
  15126. +
  15127. +#ifdef CONFIG_BLK_DEV_IDETAPE
  15128. +#include "ide-tape.h"
  15129. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  15130. +
  15131. +#ifdef CONFIG_BLK_DEV_IDECD
  15132. +
  15133. +struct atapi_request_sense {
  15134. +    unsigned char error_code : 7;
  15135. +    unsigned char valid      : 1;
  15136. +    byte reserved1;
  15137. +    unsigned char sense_key  : 4;
  15138. +    unsigned char reserved2  : 1;
  15139. +    unsigned char ili        : 1;
  15140. +    unsigned char reserved3  : 2;
  15141. +    byte info[4];
  15142. +    byte sense_len;
  15143. +    byte command_info[4];
  15144. +    byte asc;
  15145. +    byte ascq;
  15146. +    byte fru;
  15147. +    byte sense_key_specific[3];
  15148. +};
  15149. +
  15150. +struct packet_command {
  15151. +    char *buffer;
  15152. +    int buflen;
  15153. +    int stat;
  15154. +    struct atapi_request_sense *sense_data;
  15155. +    unsigned char c[12];
  15156. +};
  15157. +
  15158. +
  15159. +/* Structure of a MSF cdrom address. */
  15160. +struct atapi_msf {
  15161. +    byte reserved;
  15162. +    byte minute;
  15163. +    byte second;
  15164. +    byte frame;
  15165. +};
  15166. +
  15167. +
  15168. +/* Space to hold the disk TOC. */
  15169. +
  15170. +#define MAX_TRACKS 99
  15171. +struct atapi_toc_header {
  15172. +    unsigned short toc_length;
  15173. +    byte first_track;
  15174. +    byte last_track;
  15175. +};
  15176. +
  15177. +struct atapi_toc_entry {
  15178. +    byte reserved1;
  15179. +    unsigned control : 4;
  15180. +    unsigned adr     : 4;
  15181. +    byte track;
  15182. +    byte reserved2;
  15183. +    union {
  15184. +        unsigned lba;
  15185. +        struct atapi_msf msf;
  15186. +    } addr;
  15187. +};
  15188. +
  15189. +struct atapi_toc {
  15190. +    int    last_session_lba;
  15191. +    int    xa_flag;
  15192. +    unsigned capacity;
  15193. +    struct atapi_toc_header hdr;
  15194. +    struct atapi_toc_entry  ent[MAX_TRACKS+1];
  15195. +      /* One extra for the leadout. */
  15196. +};
  15197. +
  15198. +
  15199. +/* This structure is annoyingly close to, but not identical with,
  15200. +   the cdrom_subchnl structure from cdrom.h. */
  15201. +struct atapi_cdrom_subchnl 
  15202. +{
  15203. +    u_char  acdsc_reserved;
  15204. +    u_char  acdsc_audiostatus;
  15205. +    u_short acdsc_length;
  15206. +    u_char  acdsc_format;
  15207. +
  15208. +    u_char  acdsc_adr:    4;
  15209. +    u_char  acdsc_ctrl:    4;
  15210. +    u_char  acdsc_trk;
  15211. +    u_char  acdsc_ind;
  15212. +    union {
  15213. +        struct atapi_msf msf;
  15214. +        int    lba;
  15215. +    } acdsc_absaddr;
  15216. +    union {
  15217. +        struct atapi_msf msf;
  15218. +        int    lba;
  15219. +    } acdsc_reladdr;
  15220. +};
  15221. +
  15222. +
  15223. +/* Extra per-device info for cdrom drives. */
  15224. +struct cdrom_info {
  15225. +
  15226. +    /* Buffer for table of contents.  NULL if we haven't allocated
  15227. +       a TOC buffer for this device yet. */
  15228. +
  15229. +    struct atapi_toc *toc;
  15230. +
  15231. +    /* Sector buffer.  If a read request wants only the first part
  15232. +       of a cdrom block, we cache the rest of the block here,
  15233. +       in the expectation that that data is going to be wanted soon.
  15234. +       SECTOR_BUFFERED is the number of the first buffered sector,
  15235. +       and NSECTORS_BUFFERED is the number of sectors in the buffer.
  15236. +       Before the buffer is allocated, we should have
  15237. +       SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */
  15238. +
  15239. +    unsigned long sector_buffered;
  15240. +    unsigned long nsectors_buffered;
  15241. +    char *sector_buffer;
  15242. +
  15243. +    /* The result of the last successful request sense command
  15244. +       on this device. */
  15245. +    struct atapi_request_sense sense_data;
  15246. +};
  15247. +
  15248. +#endif /* CONFIG_BLK_DEV_IDECD */
  15249. +
  15250. +/*
  15251. + * Now for the data we need to maintain per-drive:  ide_drive_t
  15252. + */
  15253. +
  15254. +typedef enum {ide_disk, ide_cdrom, ide_tape} ide_media_t;
  15255. +
  15256. +typedef union {
  15257. +    unsigned all            : 8;    /* all of the bits together */
  15258. +    struct {
  15259. +        unsigned set_geometry    : 1;    /* respecify drive geometry */
  15260. +        unsigned recalibrate    : 1;    /* seek to cyl 0      */
  15261. +        unsigned set_multmode    : 1;    /* set multmode count */
  15262. +        unsigned set_tune    : 1;    /* tune interface for drive */
  15263. +        unsigned reserved    : 4;    /* unused */
  15264. +        } b;
  15265. +    } special_t;
  15266. +
  15267. +typedef union {
  15268. +    unsigned all            : 8;    /* all of the bits together */
  15269. +    struct {
  15270. +        unsigned head        : 4;    /* always zeros here */
  15271. +        unsigned unit        : 1;    /* drive select number, 0 or 1 */
  15272. +        unsigned bit5        : 1;    /* always 1 */
  15273. +        unsigned lba        : 1;    /* using LBA instead of CHS */
  15274. +        unsigned bit7        : 1;    /* always 1 */
  15275. +    } b;
  15276. +    } select_t;
  15277. +
  15278. +typedef struct ide_drive_s {
  15279. +    special_t    special;    /* special action flags */
  15280. +    unsigned present    : 1;    /* drive is physically present */
  15281. +    unsigned noprobe     : 1;    /* from:  hdx=noprobe */
  15282. +    unsigned keep_settings  : 1;    /* restore settings after drive reset */
  15283. +    unsigned busy        : 1;    /* currently doing revalidate_disk() */
  15284. +    unsigned removable    : 1;    /* 1 if need to do check_media_change */
  15285. +    unsigned using_dma    : 1;    /* disk is using dma for read/write */
  15286. +    unsigned forced_geom    : 1;    /* 1 if hdx=c,h,s was given at boot */
  15287. +    unsigned unmask        : 1;    /* flag: okay to unmask other irqs */
  15288. +    unsigned no_unmask    : 1;    /* disallow setting unmask bit */
  15289. +    unsigned no_io_32bit    : 1;    /* disallow enabling 32bit I/O */
  15290. +    unsigned nobios        : 1;    /* flag: do not probe bios for drive */
  15291. +    unsigned autotune    : 2;    /* 1=autotune, 2=noautotune, 0=default */
  15292. +#if FAKE_FDISK_FOR_EZDRIVE
  15293. +    unsigned remap_0_to_1    : 1;    /* flag: partitioned with ezdrive */
  15294. +#endif /* FAKE_FDISK_FOR_EZDRIVE */
  15295. +    ide_media_t    media;        /* disk, cdrom, tape */
  15296. +    select_t    select;        /* basic drive/head select reg value */
  15297. +    byte        ctl;        /* "normal" value for IDE_CONTROL_REG */
  15298. +    byte        ready_stat;    /* min status value for drive ready */
  15299. +    byte        mult_count;    /* current multiple sector setting */
  15300. +    byte         mult_req;    /* requested multiple sector setting */
  15301. +    byte        tune_req;    /* requested drive pio setting */
  15302. +    byte        io_32bit;    /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
  15303. +    byte        bad_wstat;    /* used for ignoring WRERR_STAT */
  15304. +    byte        sect0;        /* offset of first sector for DM6:DDO */
  15305. +    byte         usage;        /* current "open()" count for drive */
  15306. +    byte         head;        /* "real" number of heads */
  15307. +    byte        sect;        /* "real" sectors per track */
  15308. +    byte        bios_head;    /* BIOS/fdisk/LILO number of heads */
  15309. +    byte        bios_sect;    /* BIOS/fdisk/LILO sectors per track */
  15310. +    unsigned short    bios_cyl;    /* BIOS/fdisk/LILO number of cyls */
  15311. +    unsigned short    cyl;        /* "real" number of cyls */
  15312. +    void          *hwif;    /* actually (ide_hwif_t *) */
  15313. +    struct wait_queue *wqueue;    /* used to wait for drive in open() */
  15314. +    struct hd_driveid *id;        /* drive model identification info */
  15315. +    struct hd_struct  *part;    /* drive partition table */
  15316. +    char        name[4];    /* drive name, such as "hda" */
  15317. +#ifdef CONFIG_BLK_DEV_IDECD
  15318. +    struct cdrom_info cdrom_info;    /* for ide-cd.c */
  15319. +#endif /* CONFIG_BLK_DEV_IDECD */
  15320. +#ifdef CONFIG_BLK_DEV_IDETAPE
  15321. +    idetape_tape_t    tape;        /* for ide-tape.c */
  15322. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  15323. +    } ide_drive_t;
  15324. +
  15325. +typedef struct hwreg_s {
  15326. +    unsigned long    io_base;
  15327. +    unsigned long    io_size;    /* 1 = normal, 16 = ICS ide */
  15328. +    unsigned long    ctl_port;
  15329. +    } hwreg_t;
  15330. +/*
  15331. + * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
  15332. + *
  15333. + * The caller is assumed to have selected the drive and programmed the drive's
  15334. + * sector address using CHS or LBA.  All that remains is to prepare for DMA
  15335. + * and then issue the actual read/write DMA/PIO command to the drive.
  15336. + *
  15337. + * Returns 0 if all went well.
  15338. + * Returns 1 if DMA read/write could not be started, in which case the caller
  15339. + * should either try again later, or revert to PIO for the current request.
  15340. + */
  15341. +typedef enum {    ide_dma_read = 0,    ide_dma_write = 1,
  15342. +        ide_dma_abort = 2,    ide_dma_check = 3,
  15343. +        ide_dma_status_bad = 4,    ide_dma_transferred = 5,
  15344. +        ide_dma_begin = 6 }
  15345. +    ide_dma_action_t;
  15346. +
  15347. +typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
  15348. +
  15349. +
  15350. +/*
  15351. + * An ide_tuneproc_t() is used to set the speed of an IDE interface
  15352. + * to a particular PIO mode.  The "byte" parameter is used
  15353. + * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
  15354. + * indicates that the interface driver should "auto-tune" the PIO mode
  15355. + * according to the drive capabilities in drive->id;
  15356. + *
  15357. + * Not all interface types support tuning, and not all of those
  15358. + * support all possible PIO settings.  They may silently ignore
  15359. + * or round values as they see fit.
  15360. + */
  15361. +typedef void (ide_tuneproc_t)(ide_drive_t *, byte);
  15362. +
  15363. +/*
  15364. + * This is used to provide HT6560B & PROMISE interface support.
  15365. + */
  15366. +typedef void (ide_selectproc_t) (ide_drive_t *);
  15367. +
  15368. +/*
  15369. + * hwif_chipset_t is used to keep track of the specific hardware
  15370. + * chipset used by each IDE interface, if known.
  15371. + */
  15372. +typedef enum {    ide_unknown,    ide_generic,    ide_triton,
  15373. +        ide_cmd640,    ide_dtc2278,    ide_ali14xx,
  15374. +        ide_qd6580,    ide_umc8672,    ide_ht6560b,
  15375. +        ide_promise }
  15376. +    hwif_chipset_t;
  15377. +
  15378. +typedef struct hwif_s {
  15379. +    struct hwif_s    *next;        /* for linked-list in ide_hwgroup_t */
  15380. +    void        *hwgroup;    /* actually (ide_hwgroup_t *) */
  15381. +    hwreg_t        io;
  15382. +    ide_drive_t    drives[MAX_DRIVES];    /* drive info */
  15383. +    struct gendisk    *gd;        /* gendisk structure */
  15384. +    ide_tuneproc_t    *tuneproc;    /* routine to tune PIO mode for drives */
  15385. +#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PROMISE)
  15386. +    ide_selectproc_t *selectproc;    /* tweaks hardware to select drive */
  15387. +#endif
  15388. +    ide_dmaproc_t    *dmaproc;    /* dma read/write/abort routine */
  15389. +    unsigned long    *dmatable;    /* dma physical region descriptor table */
  15390. +    unsigned short    dma_base;    /* base addr for dma ports (triton) */
  15391. +    byte        irq;        /* our irq number */
  15392. +    byte        major;        /* our major number */
  15393. +    char         name[5];    /* name of interface, eg. "ide0" */
  15394. +    byte        index;        /* 0 for ide0; 1 for ide1; ... */
  15395. +    hwif_chipset_t    chipset;    /* sub-module for tuning.. */
  15396. +    unsigned    noprobe    : 1;    /* don't probe for this interface */
  15397. +    unsigned    present    : 1;    /* this interface exists */
  15398. +    unsigned    serialized : 1;    /* serialized operation with mate hwif */
  15399. +    unsigned    sharing_irq: 1;    /* 1 = sharing irq with another hwif */
  15400. +#ifdef CONFIG_BLK_DEV_PROMISE
  15401. +    unsigned    is_promise2: 1;    /* 2nd i/f on promise DC4030 */
  15402. +#endif /* CONFIG_BLK_DEV_PROMISE */
  15403. +#if (DISK_RECOVERY_TIME > 0)
  15404. +    unsigned long    last_time;    /* time when previous rq was done */
  15405. +#endif
  15406. +#ifdef CONFIG_BLK_DEV_IDECD
  15407. +    struct request request_sense_request;    /* from ide-cd.c */
  15408. +    struct packet_command request_sense_pc;    /* from ide-cd.c */
  15409. +#endif /* CONFIG_BLK_DEV_IDECD */
  15410. +#ifdef CONFIG_BLK_DEV_IDETAPE
  15411. +    ide_drive_t    *tape_drive;    /* Pointer to the tape on this interface */
  15412. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  15413. +    } ide_hwif_t;
  15414. +
  15415. +/*
  15416. + *  internal ide interrupt handler type
  15417. + */
  15418. +typedef void (ide_handler_t)(ide_drive_t *);
  15419. +
  15420. +typedef struct hwgroup_s {
  15421. +    ide_handler_t        *handler;/* irq handler, if active */
  15422. +    ide_drive_t        *drive;    /* current drive */
  15423. +    ide_hwif_t        *hwif;    /* ptr to current hwif in linked-list */
  15424. +    ide_hwif_t        *next_hwif; /* next selected hwif (for tape) */
  15425. +    struct request        *rq;    /* current request */
  15426. +    struct timer_list    timer;    /* failsafe timer */
  15427. +    struct request        wrq;    /* local copy of current write rq */
  15428. +    unsigned long        poll_timeout;    /* timeout value during long polls */
  15429. +    } ide_hwgroup_t;
  15430. +
  15431. +/*
  15432. + * ide_hwifs[] is the master data structure used to keep track
  15433. + * of just about everything in ide.c.  Whenever possible, routines
  15434. + * should be using pointers to a drive (ide_drive_t *) or
  15435. + * pointers to a hwif (ide_hwif_t *), rather than indexing this
  15436. + * structure directly (the allocation/layout may change!).
  15437. + *
  15438. + */
  15439. +#ifndef _IDE_C
  15440. +extern    ide_hwif_t    ide_hwifs[];        /* master data repository */
  15441. +#endif
  15442. +
  15443. +/*
  15444. + * One final include file, which references some of the data/defns from above
  15445. + */
  15446. +#define IDE_DRIVER    /* "parameter" for blk.h */
  15447. +#include <linux/blk.h>
  15448. +
  15449. +#if (DISK_RECOVERY_TIME > 0)
  15450. +void ide_set_recovery_timer (ide_hwif_t *);
  15451. +#define SET_RECOVERY_TIMER(drive) ide_set_recovery_timer (drive)
  15452. +#else
  15453. +#define SET_RECOVERY_TIMER(drive)
  15454. +#endif
  15455. +
  15456. +/*
  15457. + * This is used for (nearly) all data transfers from the IDE interface
  15458. + */
  15459. +void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
  15460. +
  15461. +/*
  15462. + * This is used for (nearly) all data transfers to the IDE interface
  15463. + */
  15464. +void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
  15465. +
  15466. +/*
  15467. + * This is used on exit from the driver, to designate the next irq handler
  15468. + * and also to start the safety timer.
  15469. + */
  15470. +void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout);
  15471. +
  15472. +/*
  15473. + * Error reporting, in human readable form (luxurious, but a memory hog).
  15474. + */
  15475. +byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat);
  15476. +
  15477. +/*
  15478. + * ide_error() takes action based on the error returned by the controller.
  15479. + * The calling function must return afterwards, to restart the request.
  15480. + */
  15481. +void ide_error (ide_drive_t *drive, const char *msg, byte stat);
  15482. +
  15483. +/*
  15484. + * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
  15485. + * removing leading/trailing blanks and compressing internal blanks.
  15486. + * It is primarily used to tidy up the model name/number fields as
  15487. + * returned by the WIN_[P]IDENTIFY commands.
  15488. + */
  15489. +void ide_fixstring (byte *s, const int bytecount, const int byteswap);
  15490. +
  15491. +/*
  15492. + * This routine busy-waits for the drive status to be not "busy".
  15493. + * It then checks the status for all of the "good" bits and none
  15494. + * of the "bad" bits, and if all is okay it returns 0.  All other
  15495. + * cases return 1 after invoking ide_error() -- caller should return.
  15496. + *
  15497. + */
  15498. +int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
  15499. +
  15500. +/*
  15501. + * This routine is called from the partition-table code in genhd.c
  15502. + * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
  15503. + *
  15504. + * The second parameter, "xparm", determines exactly how the translation
  15505. + * will be handled:
  15506. + *         0 = convert to CHS with fewer than 1024 cyls
  15507. + *            using the same method as Ontrack DiskManager.
  15508. + *         1 = same as "0", plus offset everything by 63 sectors.
  15509. + *        -1 = similar to "0", plus redirect sector 0 to sector 1.
  15510. + *        >1 = convert to a CHS geometry with "xparm" heads.
  15511. + *
  15512. + * Returns 0 if the translation was not possible, if the device was not
  15513. + * an IDE disk drive, or if a geometry was "forced" on the commandline.
  15514. + * Returns 1 if the geometry translation was successful.
  15515. + */
  15516. +int ide_xlate_1024 (kdev_t, int, const char *);
  15517. +
  15518. +/*
  15519. + * Start a reset operation for an IDE interface.
  15520. + * The caller should return immediately after invoking this.
  15521. + */
  15522. +void ide_do_reset (ide_drive_t *);
  15523. +
  15524. +/*
  15525. + * This function is intended to be used prior to invoking ide_do_drive_cmd().
  15526. + */
  15527. +void ide_init_drive_cmd (struct request *rq);
  15528. +
  15529. +/*
  15530. + * "action" parameter type for ide_do_drive_cmd() below.
  15531. + */
  15532. +typedef enum
  15533. +    {ide_wait,    /* insert rq at end of list, and wait for it */
  15534. +     ide_next,    /* insert rq immediately after current request */
  15535. +     ide_preempt,    /* insert rq in front of current request */
  15536. +     ide_end}    /* insert rq at end of list, but don't wait for it */
  15537. + ide_action_t;
  15538. +
  15539. +/*
  15540. + * This function issues a special IDE device request
  15541. + * onto the request queue.
  15542. + *
  15543. + * If action is ide_wait, then then rq is queued at the end of
  15544. + * the request queue, and the function sleeps until it has been
  15545. + * processed.  This is for use when invoked from an ioctl handler.
  15546. + *
  15547. + * If action is ide_preempt, then the rq is queued at the head of
  15548. + * the request queue, displacing the currently-being-processed
  15549. + * request and this function returns immediately without waiting
  15550. + * for the new rq to be completed.  This is VERY DANGEROUS, and is
  15551. + * intended for careful use by the ATAPI tape/cdrom driver code.
  15552. + *
  15553. + * If action is ide_next, then the rq is queued immediately after
  15554. + * the currently-being-processed-request (if any), and the function
  15555. + * returns without waiting for the new rq to be completed.  As above,
  15556. + * This is VERY DANGEROUS, and is intended for careful use by the
  15557. + * ATAPI tape/cdrom driver code.
  15558. + *
  15559. + * If action is ide_end, then the rq is queued at the end of the
  15560. + * request queue, and the function returns immediately without waiting
  15561. + * for the new rq to be completed. This is again intended for careful
  15562. + * use by the ATAPI tape/cdrom driver code. (Currently used by ide-tape.c,
  15563. + * when operating in the pipelined operation mode).
  15564. + */
  15565. +int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
  15566. +
  15567. +/*
  15568. + * Clean up after success/failure of an explicit drive cmd.
  15569. + * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
  15570. + */
  15571. +void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
  15572. +
  15573. +/*
  15574. + * ide_system_bus_speed() returns what we think is the system VESA/PCI
  15575. + * bus speed (in Mhz).  This is used for calculating interface PIO timings.
  15576. + * The default is 40 for known PCI systems, 50 otherwise.
  15577. + * The "idebus=xx" parameter can be used to override this value.
  15578. + */
  15579. +int ide_system_bus_speed (void);
  15580. +
  15581. +/*
  15582. + * ide_multwrite() transfers a block of up to mcount sectors of data
  15583. + * to a drive as part of a disk multwrite operation.
  15584. + */
  15585. +void ide_multwrite (ide_drive_t *drive, unsigned int mcount);
  15586. +
  15587. +#ifdef CONFIG_BLK_DEV_IDECD
  15588. +/*
  15589. + * These are routines in ide-cd.c invoked from ide.c
  15590. + */
  15591. +void ide_do_rw_cdrom (ide_drive_t *, unsigned long);
  15592. +int ide_cdrom_ioctl (ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
  15593. +int ide_cdrom_check_media_change (ide_drive_t *);
  15594. +int ide_cdrom_open (struct inode *, struct file *, ide_drive_t *);
  15595. +void ide_cdrom_release (struct inode *, struct file *, ide_drive_t *);
  15596. +void ide_cdrom_setup (ide_drive_t *);
  15597. +#endif /* CONFIG_BLK_DEV_IDECD */
  15598. +
  15599. +#ifdef CONFIG_BLK_DEV_IDETAPE
  15600. +
  15601. +/*
  15602. + *    Functions in ide-tape.c which are invoked from ide.c:
  15603. + */
  15604. +
  15605. +/*
  15606. + *    idetape_identify_device is called during device probing stage to
  15607. + *    probe for an ide atapi tape drive and to initialize global variables
  15608. + *    in ide-tape.c which provide the link between the character device
  15609. + *    and the corresponding block device.
  15610. + *
  15611. + *    Returns 1 if an ide tape was detected and is supported.
  15612. + *    Returns 0 otherwise.
  15613. + */
  15614. +
  15615. +int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id);
  15616. +
  15617. +/*
  15618. + *    idetape_setup is called a bit later than idetape_identify_device,
  15619. + *    during the search for disk partitions, to initialize various tape
  15620. + *    state variables in ide_drive_t *drive.
  15621. + */
  15622. +
  15623. +void idetape_setup (ide_drive_t *drive);
  15624. +
  15625. +/*
  15626. + *    idetape_do_request is our request function. It is called by ide.c
  15627. + *    to process a new request.
  15628. + */
  15629. +
  15630. +void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block);
  15631. +
  15632. +/*
  15633. + *    idetape_end_request is used to finish servicing a request, and to
  15634. + *    insert a pending pipeline request into the main device queue.
  15635. + */
  15636. +
  15637. +void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup);
  15638. +
  15639. +/*
  15640. + *    Block device interface functions.
  15641. + */
  15642. +
  15643. +int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
  15644. +            unsigned int cmd, unsigned long arg);
  15645. +int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive);
  15646. +void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive);
  15647. +
  15648. +/*
  15649. + *    idetape_register_chrdev initializes the character device interface to
  15650. + *    the ide tape drive.
  15651. + */
  15652. +
  15653. +void idetape_register_chrdev (void);
  15654. +
  15655. +#endif /* CONFIG_BLK_DEV_IDETAPE */
  15656. +
  15657. +#ifdef CONFIG_BLK_DEV_TRITON
  15658. +void ide_init_triton (byte, byte);
  15659. +#endif /* CONFIG_BLK_DEV_TRITON */
  15660. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/ll_rw_blk.c linux/arch/arm/drivers/block/ll_rw_blk.c
  15661. --- linux.orig/arch/arm/drivers/block/ll_rw_blk.c    Thu Jan  1 01:00:00 1970
  15662. +++ linux/arch/arm/drivers/block/ll_rw_blk.c    Sat Aug 17 23:24:17 1996
  15663. @@ -0,0 +1,651 @@
  15664. +/*
  15665. + *  linux/drivers/block/ll_rw_blk.c
  15666. + *
  15667. + * Copyright (C) 1991, 1992 Linus Torvalds
  15668. + * Copyright (C) 1994,      Karl Keyte: Added support for disk statistics
  15669. + */
  15670. +
  15671. +/*
  15672. + * This handles all read/write requests to block devices
  15673. + */
  15674. +#include <linux/sched.h>
  15675. +#include <linux/kernel.h>
  15676. +#include <linux/kernel_stat.h>
  15677. +#include <linux/errno.h>
  15678. +#include <linux/string.h>
  15679. +#include <linux/config.h>
  15680. +#include <linux/locks.h>
  15681. +#include <linux/mm.h>
  15682. +
  15683. +#include <asm/system.h>
  15684. +#include <asm/io.h>
  15685. +#include "blk.h"
  15686. +
  15687. +extern int adfsimg_map (kdev_t *rdev, unsigned long *rsector, unsigned long size);
  15688. +
  15689. +/*
  15690. + * The request-struct contains all necessary data
  15691. + * to load a nr of sectors into memory
  15692. + */
  15693. +static struct request all_requests[NR_REQUEST];
  15694. +
  15695. +/*
  15696. + * The "disk" task queue is used to start the actual requests
  15697. + * after a plug
  15698. + */
  15699. +DECLARE_TASK_QUEUE(tq_disk);
  15700. +
  15701. +/* 
  15702. + * used to wait on when there are no free requests
  15703. + */
  15704. +struct wait_queue * wait_for_request;
  15705. +
  15706. +/* This specifies how many sectors to read ahead on the disk.  */
  15707. +
  15708. +int read_ahead[MAX_BLKDEV];
  15709. +
  15710. +/* blk_dev_struct is:
  15711. + *    *request_fn
  15712. + *    *current_request
  15713. + */
  15714. +struct blk_dev_struct blk_dev[MAX_BLKDEV]; /* initialized by blk_dev_init() */
  15715. +
  15716. +/*
  15717. + * blk_size contains the size of all block-devices in units of 1024 byte
  15718. + * sectors:
  15719. + *
  15720. + * blk_size[MAJOR][MINOR]
  15721. + *
  15722. + * if (!blk_size[MAJOR]) then no minor size checking is done.
  15723. + */
  15724. +int * blk_size[MAX_BLKDEV];
  15725. +
  15726. +/*
  15727. + * blksize_size contains the size of all block-devices:
  15728. + *
  15729. + * blksize_size[MAJOR][MINOR]
  15730. + *
  15731. + * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
  15732. + */
  15733. +int * blksize_size[MAX_BLKDEV];
  15734. +
  15735. +/*
  15736. + * hardsect_size contains the size of the hardware sector of a device.
  15737. + *
  15738. + * hardsect_size[MAJOR][MINOR]
  15739. + *
  15740. + * if (!hardsect_size[MAJOR])
  15741. + *        then 512 bytes is assumed.
  15742. + * else
  15743. + *        sector_size is hardsect_size[MAJOR][MINOR]
  15744. + * This is currently set by some scsi device and read by the msdos fs driver
  15745. + * This might be a some uses later.
  15746. + */
  15747. +int * hardsect_size[MAX_BLKDEV];
  15748. +
  15749. +/*
  15750. + * remove the plug and let it rip..
  15751. + */
  15752. +void unplug_device(void * data)
  15753. +{
  15754. +    struct blk_dev_struct * dev = (struct blk_dev_struct *) data;
  15755. +    unsigned long flags;
  15756. +
  15757. +    save_flags_cli(flags);
  15758. +    if (dev->current_request == &dev->plug) {
  15759. +        struct request * next = dev->plug.next;
  15760. +        dev->current_request = next;
  15761. +        if (next) {
  15762. +            dev->plug.next = NULL;
  15763. +            (dev->request_fn)();
  15764. +        }
  15765. +    }
  15766. +    restore_flags(flags);
  15767. +}
  15768. +
  15769. +/*
  15770. + * "plug" the device if there are no outstanding requests: this will
  15771. + * force the transfer to start only after we have put all the requests
  15772. + * on the list.
  15773. + *
  15774. + * This is called with interrupts off and no requests on the queue.
  15775. + */
  15776. +static inline void plug_device(struct blk_dev_struct * dev)
  15777. +{
  15778. +    dev->current_request = &dev->plug;
  15779. +    queue_task_irq_off(&dev->plug_tq, &tq_disk);
  15780. +}
  15781. +
  15782. +/*
  15783. + * look for a free request in the first N entries.
  15784. + * NOTE: interrupts must be disabled on the way in, and will still
  15785. + *       be disabled on the way out.
  15786. + */
  15787. +static inline struct request * get_request(int n, kdev_t dev)
  15788. +{
  15789. +    static struct request *prev_found = NULL, *prev_limit = NULL;
  15790. +    register struct request *req, *limit;
  15791. +
  15792. +    if (n <= 0)
  15793. +        panic("get_request(%d): impossible!\n", n);
  15794. +
  15795. +    limit = all_requests + n;
  15796. +    if (limit != prev_limit) {
  15797. +        prev_limit = limit;
  15798. +        prev_found = all_requests;
  15799. +    }
  15800. +    req = prev_found;
  15801. +    for (;;) {
  15802. +        req = ((req > all_requests) ? req : limit) - 1;
  15803. +        if (req->rq_status == RQ_INACTIVE)
  15804. +            break;
  15805. +        if (req == prev_found)
  15806. +            return NULL;
  15807. +    }
  15808. +    prev_found = req;
  15809. +    req->rq_status = RQ_ACTIVE;
  15810. +    req->rq_dev = dev;
  15811. +    return req;
  15812. +}
  15813. +
  15814. +/*
  15815. + * wait until a free request in the first N entries is available.
  15816. + */
  15817. +static struct request * __get_request_wait(int n, kdev_t dev)
  15818. +{
  15819. +    register struct request *req;
  15820. +    struct wait_queue wait = { current, NULL };
  15821. +
  15822. +    add_wait_queue(&wait_for_request, &wait);
  15823. +    for (;;) {
  15824. +        current->state = TASK_UNINTERRUPTIBLE;
  15825. +        cli();
  15826. +        req = get_request(n, dev);
  15827. +        sti();
  15828. +        if (req)
  15829. +            break;
  15830. +        run_task_queue(&tq_disk);
  15831. +        schedule();
  15832. +    }
  15833. +    remove_wait_queue(&wait_for_request, &wait);
  15834. +    current->state = TASK_RUNNING;
  15835. +    return req;
  15836. +}
  15837. +
  15838. +static inline struct request * get_request_wait(int n, kdev_t dev)
  15839. +{
  15840. +    register struct request *req;
  15841. +
  15842. +    cli();
  15843. +    req = get_request(n, dev);
  15844. +    sti();
  15845. +    if (req)
  15846. +        return req;
  15847. +    return __get_request_wait(n, dev);
  15848. +}
  15849. +
  15850. +/* RO fail safe mechanism */
  15851. +
  15852. +static long ro_bits[MAX_BLKDEV][8];
  15853. +
  15854. +int is_read_only(kdev_t dev)
  15855. +{
  15856. +    int minor,major;
  15857. +
  15858. +    major = MAJOR(dev);
  15859. +    minor = MINOR(dev);
  15860. +    if (major < 0 || major >= MAX_BLKDEV) return 0;
  15861. +    return ro_bits[major][minor >> 5] & (1 << (minor & 31));
  15862. +}
  15863. +
  15864. +void set_device_ro(kdev_t dev,int flag)
  15865. +{
  15866. +    int minor,major;
  15867. +
  15868. +    major = MAJOR(dev);
  15869. +    minor = MINOR(dev);
  15870. +    if (major < 0 || major >= MAX_BLKDEV) return;
  15871. +    if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
  15872. +    else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
  15873. +}
  15874. +
  15875. +static inline void drive_stat_acct(int cmd, unsigned long nr_sectors,
  15876. +                    short disk_index)
  15877. +{
  15878. +    kstat.dk_drive[disk_index]++;
  15879. +    if (cmd == READ) {
  15880. +        kstat.dk_drive_rio[disk_index]++;
  15881. +        kstat.dk_drive_rblk[disk_index] += nr_sectors;
  15882. +    } else if (cmd == WRITE) {
  15883. +        kstat.dk_drive_wio[disk_index]++;
  15884. +        kstat.dk_drive_wblk[disk_index] += nr_sectors;
  15885. +    } else
  15886. +        printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n");
  15887. +}
  15888. +
  15889. +/*
  15890. + * add-request adds a request to the linked list.
  15891. + * It disables interrupts so that it can muck with the
  15892. + * request-lists in peace.
  15893. + *
  15894. + * By this point, req->cmd is always either READ/WRITE, never READA/WRITEA,
  15895. + * which is important for drive_stat_acct() above.
  15896. + */
  15897. +
  15898. +void add_request(struct blk_dev_struct * dev, struct request * req)
  15899. +{
  15900. +    struct request * tmp;
  15901. +    short         disk_index;
  15902. +
  15903. +    switch (MAJOR(req->rq_dev)) {
  15904. +        case SCSI_DISK_MAJOR:
  15905. +            disk_index = (MINOR(req->rq_dev) & 0x0070) >> 4;
  15906. +            if (disk_index < 4)
  15907. +                drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
  15908. +            break;
  15909. +        case IDE0_MAJOR:    /* same as HD_MAJOR */
  15910. +        case XT_DISK_MAJOR:
  15911. +            disk_index = (MINOR(req->rq_dev) & 0x0040) >> 6;
  15912. +            drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
  15913. +            break;
  15914. +        case IDE1_MAJOR:
  15915. +            disk_index = ((MINOR(req->rq_dev) & 0x0040) >> 6) + 2;
  15916. +            drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
  15917. +        default:
  15918. +            break;
  15919. +    }
  15920. +
  15921. +    req->next = NULL;
  15922. +    cli();
  15923. +    if (req->bh)
  15924. +        mark_buffer_clean(req->bh);
  15925. +    if (!(tmp = dev->current_request)) {
  15926. +        dev->current_request = req;
  15927. +        (dev->request_fn)();
  15928. +        sti();
  15929. +        return;
  15930. +    }
  15931. +    for ( ; tmp->next ; tmp = tmp->next) {
  15932. +        if ((IN_ORDER(tmp,req) ||
  15933. +            !IN_ORDER(tmp,tmp->next)) &&
  15934. +            IN_ORDER(req,tmp->next))
  15935. +            break;
  15936. +    }
  15937. +    req->next = tmp->next;
  15938. +    tmp->next = req;
  15939. +
  15940. +/* for SCSI devices, call request_fn unconditionally */
  15941. +    if (scsi_blk_major(MAJOR(req->rq_dev)))
  15942. +        (dev->request_fn)();
  15943. +
  15944. +    sti();
  15945. +}
  15946. +
  15947. +static void make_request(int major,int rw, struct buffer_head * bh)
  15948. +{
  15949. +    unsigned int sector, count;
  15950. +    struct request * req;
  15951. +    int rw_ahead, max_req;
  15952. +
  15953. +    count = bh->b_size >> 9;
  15954. +    sector = bh->b_rsector;
  15955. +
  15956. +    /* Uhhuh.. Nasty dead-lock possible here.. */
  15957. +    if (buffer_locked(bh))
  15958. +        return;
  15959. +    /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */
  15960. +
  15961. +    lock_buffer(bh);
  15962. +
  15963. +    if (blk_size[major])
  15964. +        if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) {
  15965. +            bh->b_state &= (1 << BH_Lock) | (1 << BH_FreeOnIO);
  15966. +            /* This may well happen - the kernel calls bread()
  15967. +               without checking the size of the device, e.g.,
  15968. +               when mounting a device. */
  15969. +            printk(KERN_INFO
  15970. +                "attempt to access beyond end of device\n");
  15971. +            printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n",
  15972. +                kdevname(bh->b_rdev), rw,
  15973. +                (sector + count)>>1,
  15974. +                blk_size[major][MINOR(bh->b_rdev)]);
  15975. +            unlock_buffer(bh);
  15976. +            return;
  15977. +        }
  15978. +
  15979. +    rw_ahead = 0;    /* normal case; gets changed below for READA/WRITEA */
  15980. +    switch (rw) {
  15981. +        case READA:
  15982. +            rw_ahead = 1;
  15983. +            rw = READ;    /* drop into READ */
  15984. +        case READ:
  15985. +            if (buffer_uptodate(bh)) {
  15986. +                unlock_buffer(bh); /* Hmmph! Already have it */
  15987. +                return;
  15988. +            }
  15989. +            kstat.pgpgin++;
  15990. +            max_req = NR_REQUEST;    /* reads take precedence */
  15991. +            break;
  15992. +        case WRITEA:
  15993. +            rw_ahead = 1;
  15994. +            rw = WRITE;    /* drop into WRITE */
  15995. +        case WRITE:
  15996. +            if (!buffer_dirty(bh)) {
  15997. +                unlock_buffer(bh); /* Hmmph! Nothing to write */
  15998. +                return;
  15999. +            }
  16000. +            /* We don't allow the write-requests to fill up the
  16001. +             * queue completely:  we want some room for reads,
  16002. +             * as they take precedence. The last third of the
  16003. +             * requests are only for reads.
  16004. +             */
  16005. +            kstat.pgpgout++;
  16006. +            max_req = (NR_REQUEST * 2) / 3;
  16007. +            break;
  16008. +        default:
  16009. +            printk(KERN_ERR "make_request: bad block dev cmd,"
  16010. +                " must be R/W/RA/WA\n");
  16011. +            unlock_buffer(bh);
  16012. +            return;
  16013. +    }
  16014. +    /* look for a free request. */
  16015. +    if (major == ADFSIMG_MAJOR)
  16016. +        max_req = (max_req * 2) / 3;
  16017. +    /*
  16018. +     * Try to coalesce the new request with old requests
  16019. +     */
  16020. +    cli();
  16021. +    req = blk_dev[major].current_request;
  16022. +    if (!req) {
  16023. +        /* MD and loop can't handle plugging without deadlocking */
  16024. +        if (major != MD_MAJOR && major != LOOP_MAJOR && major != ADFSIMG_MAJOR)
  16025. +            plug_device(blk_dev + major);
  16026. +    } else switch (major) {
  16027. +         case IDE0_MAJOR:    /* same as HD_MAJOR */
  16028. +         case IDE1_MAJOR:
  16029. +         case FLOPPY_MAJOR:
  16030. +         case IDE2_MAJOR:
  16031. +         case IDE3_MAJOR:
  16032. +         case XT_DISK_MAJOR:
  16033. +         case ADFSIMG_MAJOR:
  16034. +        /*
  16035. +         * The scsi disk and cdrom drivers completely remove the request
  16036. +         * from the queue when they start processing an entry.  For this
  16037. +         * reason it is safe to continue to add links to the top entry for
  16038. +         * those devices.
  16039. +         *
  16040. +         * All other drivers need to jump over the first entry, as that
  16041. +         * entry may be busy being processed and we thus can't change it.
  16042. +         */
  16043. +        req = req->next;
  16044. +        if (!req)
  16045. +            break;
  16046. +        /* fall through */
  16047. +
  16048. +         case SCSI_DISK_MAJOR:
  16049. +         case SCSI_CDROM_MAJOR:
  16050. +
  16051. +        do {
  16052. +            if (req->sem)
  16053. +                continue;
  16054. +            if (req->cmd != rw)
  16055. +                continue;
  16056. +            if (req->nr_sectors >= 244)
  16057. +                continue;
  16058. +            if (req->rq_dev != bh->b_rdev)
  16059. +                continue;
  16060. +            /* Can we add it to the end of this request? */
  16061. +            if (req->sector + req->nr_sectors == sector) {
  16062. +                req->bhtail->b_reqnext = bh;
  16063. +                req->bhtail = bh;
  16064. +            /* or to the beginning? */
  16065. +            } else if (req->sector - count == sector) {
  16066. +                bh->b_reqnext = req->bh;
  16067. +                req->bh = bh;
  16068. +                req->buffer = bh->b_data;
  16069. +                req->current_nr_sectors = count;
  16070. +                req->sector = sector;
  16071. +            } else
  16072. +                continue;
  16073. +
  16074. +            req->nr_sectors += count;
  16075. +            mark_buffer_clean(bh);
  16076. +                sti();
  16077. +                return;
  16078. +        } while ((req = req->next) != NULL);
  16079. +    }
  16080. +
  16081. +/* find an unused request. */
  16082. +    req = get_request(max_req, bh->b_rdev);
  16083. +    sti();
  16084. +
  16085. +/* if no request available: if rw_ahead, forget it; otherwise try again blocking.. */
  16086. +    if (!req) {
  16087. +        if (rw_ahead) {
  16088. +            unlock_buffer(bh);
  16089. +            return;
  16090. +        }
  16091. +        req = __get_request_wait(max_req, bh->b_rdev);
  16092. +    }
  16093. +
  16094. +/* fill up the request-info, and add it to the queue */
  16095. +    req->cmd = rw;
  16096. +    req->errors = 0;
  16097. +    req->sector = sector;
  16098. +    req->nr_sectors = count;
  16099. +    req->current_nr_sectors = count;
  16100. +    req->buffer = bh->b_data;
  16101. +    req->sem = NULL;
  16102. +    req->bh = bh;
  16103. +    req->bhtail = bh;
  16104. +    req->next = NULL;
  16105. +    add_request(major+blk_dev,req);
  16106. +}
  16107. +
  16108. +/* This function can be used to request a number of buffers from a block
  16109. +   device. Currently the only restriction is that all buffers must belong to
  16110. +   the same device */
  16111. +
  16112. +void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
  16113. +{
  16114. +    unsigned int major;
  16115. +    int correct_size;
  16116. +    struct blk_dev_struct * dev;
  16117. +    int i;
  16118. +
  16119. +    /* Make sure that the first block contains something reasonable */
  16120. +    while (!*bh) {
  16121. +        bh++;
  16122. +        if (--nr <= 0)
  16123. +            return;
  16124. +    }
  16125. +
  16126. +    dev = NULL;
  16127. +    if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV)
  16128. +        dev = blk_dev + major;
  16129. +    if (!dev || !dev->request_fn) {
  16130. +        printk(KERN_ERR
  16131. +    "ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n",
  16132. +        kdevname(bh[0]->b_dev), bh[0]->b_blocknr);
  16133. +        goto sorry;
  16134. +    }
  16135. +
  16136. +    /* Determine correct block size for this device.  */
  16137. +    correct_size = BLOCK_SIZE;
  16138. +    if (blksize_size[major]) {
  16139. +        i = blksize_size[major][MINOR(bh[0]->b_dev)];
  16140. +        if (i)
  16141. +            correct_size = i;
  16142. +    }
  16143. +
  16144. +    /* Verify requested block sizes.  */
  16145. +    for (i = 0; i < nr; i++) {
  16146. +        if (bh[i] && bh[i]->b_size != correct_size) {
  16147. +            printk(KERN_NOTICE "ll_rw_block: device %s: "
  16148. +                   "only %d-char blocks implemented (%lu)\n",
  16149. +                   kdevname(bh[0]->b_dev),
  16150. +                   correct_size, bh[i]->b_size);
  16151. +            goto sorry;
  16152. +        }
  16153. +
  16154. +        /* Md remaps blocks now */
  16155. +        bh[i]->b_rdev = bh[i]->b_dev;
  16156. +        bh[i]->b_rsector=bh[i]->b_blocknr*(bh[i]->b_size >> 9);
  16157. +#ifdef CONFIG_BLK_DEV_MD
  16158. +        if (major==MD_MAJOR &&
  16159. +            md_map (MINOR(bh[i]->b_dev), &bh[i]->b_rdev,
  16160. +                &bh[i]->b_rsector, bh[i]->b_size >> 9)) {
  16161. +            printk (KERN_ERR
  16162. +                "Bad md_map in ll_rw_block\n");
  16163. +            goto sorry;
  16164. +        }
  16165. +#endif
  16166. +    }
  16167. +
  16168. +    if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) {
  16169. +        printk(KERN_NOTICE "Can't write to read-only device %s\n",
  16170. +               kdevname(bh[0]->b_dev));
  16171. +        goto sorry;
  16172. +    }
  16173. +
  16174. +    for (i = 0; i < nr; i++) {
  16175. +        if (bh[i]) {
  16176. +            set_bit(BH_Req, &bh[i]->b_state);
  16177. +
  16178. +            make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]);
  16179. +        }
  16180. +    }
  16181. +    return;
  16182. +
  16183. +      sorry:
  16184. +    for (i = 0; i < nr; i++) {
  16185. +        if (bh[i]) {
  16186. +            clear_bit(BH_Dirty, &bh[i]->b_state);
  16187. +            clear_bit(BH_Uptodate, &bh[i]->b_state);
  16188. +        }
  16189. +    }
  16190. +    return;
  16191. +}
  16192. +
  16193. +void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf)
  16194. +{
  16195. +    int i, j;
  16196. +    int buffersize;
  16197. +    unsigned long rsector;
  16198. +    kdev_t rdev;
  16199. +    struct request * req[8];
  16200. +    unsigned int major = MAJOR(dev);
  16201. +    struct semaphore sem = MUTEX_LOCKED;
  16202. +
  16203. +    if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
  16204. +        printk(KERN_NOTICE "ll_rw_swap_file: trying to swap to"
  16205. +                    " nonexistent block-device\n");
  16206. +        return;
  16207. +    }
  16208. +    switch (rw) {
  16209. +        case READ:
  16210. +            break;
  16211. +        case WRITE:
  16212. +            if (is_read_only(dev)) {
  16213. +                printk(KERN_NOTICE
  16214. +                    "Can't swap to read-only device %s\n",
  16215. +                    kdevname(dev));
  16216. +                return;
  16217. +            }
  16218. +            break;
  16219. +        default:
  16220. +            panic("ll_rw_swap: bad block dev cmd, must be R/W");
  16221. +    }
  16222. +    buffersize = PAGE_SIZE / nb;
  16223. +
  16224. +    for (j=0, i=0; i<nb;)
  16225. +    {
  16226. +        for (; j < 8 && i < nb; j++, i++, buf += buffersize)
  16227. +        {
  16228. +            rdev = dev;
  16229. +            rsector = (b[i] * buffersize) >> 9;
  16230. +#ifdef CONFIG_BLK_DEV_MD
  16231. +            if (major==MD_MAJOR &&
  16232. +                md_map (MINOR(dev), &rdev,
  16233. +                &rsector, buffersize >> 9)) {
  16234. +                printk (KERN_ERR
  16235. +                    "Bad md_map in ll_rw_swap_file\n");
  16236. +                return;
  16237. +            }
  16238. +#endif
  16239. +            if (j == 0) {
  16240. +                req[j] = get_request_wait(NR_REQUEST, rdev);
  16241. +            } else {
  16242. +                cli();
  16243. +                req[j] = get_request(NR_REQUEST, rdev);
  16244. +                sti();
  16245. +                if (req[j] == NULL)
  16246. +                    break;
  16247. +            }
  16248. +            req[j]->cmd = rw;
  16249. +            req[j]->errors = 0;
  16250. +            req[j]->sector = rsector;
  16251. +            req[j]->nr_sectors = buffersize >> 9;
  16252. +            req[j]->current_nr_sectors = buffersize >> 9;
  16253. +            req[j]->buffer = buf;
  16254. +            req[j]->sem = &sem;
  16255. +            req[j]->bh = NULL;
  16256. +            req[j]->next = NULL;
  16257. +            add_request(MAJOR(rdev)+blk_dev,req[j]);
  16258. +        }
  16259. +        run_task_queue(&tq_disk);
  16260. +        while (j > 0) {
  16261. +            j--;
  16262. +            down(&sem);
  16263. +        }
  16264. +    }
  16265. +}
  16266. +
  16267. +int blk_dev_init(void)
  16268. +{
  16269. +    struct request * req;
  16270. +    struct blk_dev_struct *dev;
  16271. +
  16272. +    for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) {
  16273. +        dev->request_fn      = NULL;
  16274. +        dev->current_request = NULL;
  16275. +        dev->plug.rq_status  = RQ_INACTIVE;
  16276. +        dev->plug.cmd        = -1;
  16277. +        dev->plug.next       = NULL;
  16278. +        dev->plug_tq.routine = &unplug_device;
  16279. +        dev->plug_tq.data    = dev;
  16280. +    }
  16281. +
  16282. +    req = all_requests + NR_REQUEST;
  16283. +    while (--req >= all_requests) {
  16284. +        req->rq_status = RQ_INACTIVE;
  16285. +        req->next = NULL;
  16286. +    }
  16287. +    memset(ro_bits,0,sizeof(ro_bits));
  16288. +#ifdef CONFIG_BLK_DEV_RAM
  16289. +    rd_init();
  16290. +#endif
  16291. +#ifdef CONFIG_BLK_DEV_LOOP
  16292. +    loop_init();
  16293. +#endif
  16294. +#ifdef CONFIG_BLK_DEV_IDE
  16295. +    ide_init();        /* this MUST precede hd_init */
  16296. +#endif
  16297. +#ifdef CONFIG_BLK_DEV_HD
  16298. +    hd_init();
  16299. +#endif
  16300. +#ifdef CONFIG_BLK_DEV_XD
  16301. +    xd_init();
  16302. +#endif
  16303. +#ifdef CONFIG_BLK_DEV_FD
  16304. +    floppy_init();
  16305. +#else
  16306. +#ifndef CONFIG_ARCH_ARC
  16307. +    outb_p(0xc, 0x3f2);
  16308. +#endif
  16309. +#endif
  16310. +#ifdef CONFIG_BLK_DEV_MD
  16311. +    md_init();
  16312. +#endif CONFIG_BLK_DEV_MD
  16313. +    return 0;
  16314. +}
  16315. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/mfm.S linux/arch/arm/drivers/block/mfm.S
  16316. --- linux.orig/arch/arm/drivers/block/mfm.S    Thu Jan  1 01:00:00 1970
  16317. +++ linux/arch/arm/drivers/block/mfm.S    Sat Sep  7 21:09:58 1996
  16318. @@ -0,0 +1,159 @@
  16319. +@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400
  16320. +@   motherboard on ST506 podules.
  16321. +@ (c) David Alan Gilbert (gilbertd@cs.man.ac.uk) 1996
  16322. +
  16323. +#include <asm/assembler.h>
  16324. +_hdc63463_irqdata:
  16325. +@ Controller base address
  16326. +  .global _hdc63463_baseaddress
  16327. +_hdc63463_baseaddress:
  16328. +  .word 0
  16329. +
  16330. +  .global _hdc63463_irqpolladdress
  16331. +_hdc63463_irqpolladdress:
  16332. +  .word 0
  16333. +  .global _hdc63463_irqpollmask
  16334. +_hdc63463_irqpollmask:
  16335. +  .word 0
  16336. +
  16337. +@ where to read/write data  from the kernel data space
  16338. +  .global _hdc63463_dataptr
  16339. +_hdc63463_dataptr:
  16340. +  .word 0
  16341. +
  16342. +@ Number of bytes left to transfer
  16343. +  .global _hdc63463_dataleft
  16344. +_hdc63463_dataleft:
  16345. +  .word 0
  16346. +
  16347. +@ -------------------------------------------------------------------------
  16348. +@ hdc63463_writedma: DMA from host to controller
  16349. +@  internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
  16350. +@                      r3=data ptr, r4=data left, r5,r6=temporary
  16351. +  .global _hdc63463_writedma
  16352. +_hdc63463_writedma:
  16353. +  stmfd sp!,{r4-r7}
  16354. +  adr r5,_hdc63463_irqdata
  16355. +  ldmia r5,{r0,r1,r2,r3,r4}
  16356. +
  16357. +
  16358. +writedma_again:
  16359. +
  16360. +  @ test number of remaining bytes to transfer
  16361. +  cmp r4,#0
  16362. +  beq writedma_end
  16363. +  bmi writedma_end
  16364. +
  16365. +  @ Check the hdc is interrupting
  16366. +  ldrb r5,[r1,#0]
  16367. +  tst r5,r2
  16368. +  beq writedma_end
  16369. +
  16370. +  @ Transfer a block of upto 256 bytes
  16371. +  cmp r4,#256
  16372. +  movlt r7,r4
  16373. +  movge r7,#256
  16374. +
  16375. +  @ Check the hdc is still busy and command has not ended and no errors
  16376. +  ldr r5,[r0,#32]     @ Status reg - 16 bit - its the top few bits which are status
  16377. +  tst r5,#0x3c00        @ Test for things which should be off
  16378. +  bne writedma_end
  16379. +  and r5,r5,#0x8000        @ This is test for things which should be on: Busy
  16380. +  cmp r5,#0x8000
  16381. +  bne writedma_end 
  16382. +
  16383. +  @ Bytes remaining at end
  16384. +  sub r4,r4,r7
  16385. +
  16386. +  @ HDC Write register location
  16387. +  add r0,r0,#32+8
  16388. +
  16389. +writedma_loop:
  16390. +  @ OK - pretty sure we should be doing this
  16391. +
  16392. +  ldr r5,[r3],#4          @ Get a word to be written
  16393. +  @ get bottom half to be sent first
  16394. +  mov r6,r5,lsl#16        @ Separate the first 2 bytes
  16395. +  orr r2,r6,r6,lsr #16    @ Duplicate them in the bottom half of the word
  16396. +  @ now the top half
  16397. +  mov r6,r5,lsr#16        @ Get 2nd 2 bytes
  16398. +  orr r6,r6,r6,lsl#16     @ Duplicate
  16399. +  @str r6,[r0]       @ to hdc
  16400. +  stmia r0,{r2,r6}
  16401. +  subs r7,r7,#4           @ Dec. number of bytes left
  16402. +  bne writedma_loop
  16403. +
  16404. +  @ If we were too slow we had better go through again - DAG - took out with new interrupt routine
  16405. +  @ sub r0,r0,#32+8
  16406. +  @ adr r2,_hdc63463_irqdata
  16407. +  @ ldr r2,[r2,#8]
  16408. +  @ b writedma_again
  16409. +
  16410. +writedma_end:
  16411. +  adr r5,_hdc63463_irqdata+12
  16412. +  stmia r5,{r3,r4}
  16413. +  ldmfd sp!,{r4-r7}
  16414. +  RETINSTR(mov,pc,lr)
  16415. +
  16416. +@ -------------------------------------------------------------------------
  16417. +@ hdc63463_readdma: DMA from controller to host
  16418. +@  internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
  16419. +@                      r3=data ptr, r4=data left, r5,r6=temporary
  16420. +  .global _hdc63463_readdma
  16421. +_hdc63463_readdma:
  16422. +  stmfd sp!,{r4-r7}
  16423. +  adr r5,_hdc63463_irqdata
  16424. +  ldmia r5,{r0,r1,r2,r3,r4}
  16425. +
  16426. +readdma_again:
  16427. +  @ test number of remaining bytes to transfer
  16428. +  cmp r4,#0
  16429. +  beq readdma_end
  16430. +  bmi readdma_end
  16431. +
  16432. +  @ Check the hdc is interrupting
  16433. +  ldrb r5,[r1,#0]
  16434. +  tst r5,r2
  16435. +  beq readdma_end
  16436. +
  16437. +  @ Check the hdc is still busy and command has not ended and no errors
  16438. +  ldr r5,[r0,#32]     @ Status reg - 16 bit - its the top few bits which are status
  16439. +  tst r5,#0x3c00      @ Test for things which should be off
  16440. +  bne readdma_end
  16441. +  and r5,r5,#0x8000        @ This is test for things which should be on: Busy
  16442. +  cmp r5,#0x8000
  16443. +  bne readdma_end 
  16444. +
  16445. +  @ Transfer a block of upto 256 bytes
  16446. +  cmp r4,#256
  16447. +  movlt r7,r4
  16448. +  movge r7,#256
  16449. +
  16450. +  @ Bytes remaining at end
  16451. +  sub r4,r4,r7
  16452. +
  16453. +  @ Set a pointer to the data register in the HDC
  16454. +  add r0,r0,#8
  16455. +readdma_loop:
  16456. +  @ OK - pretty sure we should be doing this
  16457. +  ldmia r0,{r5,r6}
  16458. +  mov r5,r5,lsl#16
  16459. +  mov r6,r6,lsl#16
  16460. +  orr r6,r6,r5,lsr #16
  16461. +  str r6,[r3],#4
  16462. +  subs r7,r7,#4        @ Decrement bytes to go
  16463. +  bne readdma_loop
  16464. +
  16465. +  @ Try reading multiple blocks - if this was fast enough then I dont think
  16466. +  @ this should help - NO taken out DAG - new interrupt handler has
  16467. +  @ non-consecutive memory blocks
  16468. +  @ sub r0,r0,#8
  16469. +  @ b readdma_again
  16470. +
  16471. +readdma_end:
  16472. +  adr r5,_hdc63463_irqdata+12
  16473. +  stmia r5,{r3,r4}
  16474. +  ldmfd sp!,{r4-r7}
  16475. +  RETINSTR(mov,pc,lr)
  16476. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/block/mfmhd.c linux/arch/arm/drivers/block/mfmhd.c
  16477. --- linux.orig/arch/arm/drivers/block/mfmhd.c    Thu Jan  1 01:00:00 1970
  16478. +++ linux/arch/arm/drivers/block/mfmhd.c    Sat Sep  7 21:09:09 1996
  16479. @@ -0,0 +1,1379 @@
  16480. +/*
  16481. + * linux/arch/arm/drivers/block/mfmhd.c
  16482. + *
  16483. + * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd@cs.man.ac.uk)
  16484. + *
  16485. + * MFM hard drive code [experimental]
  16486. + */
  16487. +
  16488. +/*
  16489. + * Change list:
  16490. + *
  16491. + *  3/2/96:DAG: Started a change list :-)
  16492. + *              Set the hardsect_size pointers up since we are running 256 byte
  16493. + *                sectors
  16494. + *              Added DMA code, put it into the rw_intr
  16495. + *              Moved RCAL out of generic interrupt code - don't want to do it
  16496. + *                while DMA'ing - its now in individual handlers.
  16497. + *              Took interrupt handlers off task queue lists and called
  16498. + *                directly - not sure of implications.
  16499. + *
  16500. + * 18/2/96:DAG: Well its reading OK I think, well enough for image file code
  16501. + *              to find the image file; but now I've discovered that I actually
  16502. + *              have to put some code in for image files.
  16503. + *
  16504. + *              Added stuff for image files; seems to work, but I've not
  16505. + *              got a multisegment image file (I don't think!).
  16506. + *              Put in a hack (yep a real hack) for multiple cylinder reads.
  16507. + *              Not convinced its working.
  16508. + *
  16509. + *  5/4/96:DAG: Added asm/hardware.h and use IOC_ macros
  16510. + *              Rewrote dma code in mfm.S (again!) - now takes a word at a time
  16511. + *              from main RAM for speed; still doesn't feel speedy!
  16512. + *
  16513. + * 20/4/96:DAG: After rewriting mfm.S a heck of a lot of times and speeding
  16514. + *              things up, I've finally figured out why its so damn slow.
  16515. + *              Linux is only reading a block at a time, and so you never
  16516. + *              get more than 1K per disc revoloution ~=60K/second.
  16517. + *
  16518. + * 27/4/96:DAG: On Russell's advice I change ll_rw_blk.c to ask it to
  16519. + *              join adjacent blocks together. Everything falls flat on its
  16520. + *              face.
  16521. + *              Four hours of debugging later; I hadn't realised that
  16522. + *              ll_rw_blk would be so generous as to join blocks whose
  16523. + *              results aren't going into consecutive buffers.
  16524. + * 
  16525. + *              OK; severe rehacking of mfm_rw_interrupt; now end_request's
  16526. + *              as soon as its DMA'd each request.  Odd thing is that
  16527. + *              we are sometimes getting interrupts where we are not transferring
  16528. + *              any data; why? Is that what happens when you miss? I doubt
  16529. + *              it; are we too fast? No - its just at command ends. Got 240K/s
  16530. + *              better than before, but RiscOS hits 480K/s
  16531. + *
  16532. + * 25/6/96:RMK: Fixed init code to allow the MFM podule to work.  Increased the
  16533. + *              number of errors for my Miniscribe drive (8425).
  16534. + *
  16535. + * 30/6/96:DAG: Russell suggested that a check drive 0 might turn the LEDs off
  16536. + *              - so in request_done just before it clears Busy it sends a
  16537. + *              check drive 0 - and the LEDs go off!!!!
  16538. + *
  16539. + *              Added test for mainboard controller. - Removes need for separate
  16540. + *              define.
  16541. + *
  16542. + * 13/7/96:DAG: Changed hardware sectore size to 512 in attempt to make
  16543. + *              IM drivers work.
  16544. + * 21/7/96:DAG: Took out old image file stuff (accessing it now produces an IO
  16545. + *              error.)
  16546. + *
  16547. + * 17/8/96:DAG: Ran through indent -kr -i8; evil - all my nice 2 character indents
  16548. + *              gone :-( Hand modified afterwards.
  16549. + *        Took out last remains of the older image map system.
  16550. + */
  16551. +
  16552. +#ifdef MODULE
  16553. +#include <linux/module.h>
  16554. +#include <linux/version.h>
  16555. +#endif
  16556. +
  16557. +#include <linux/config.h>
  16558. +#include <linux/sched.h>
  16559. +#include <linux/fs.h>
  16560. +#include <linux/interrupt.h>
  16561. +#include <linux/kernel.h>
  16562. +#include <linux/timer.h>
  16563. +#include <linux/tqueue.h>
  16564. +#include <linux/mm.h>
  16565. +
  16566. +#include <linux/errno.h>
  16567. +#include <linux/genhd.h>
  16568. +#include <linux/major.h>
  16569. +#include <linux/xd.h>
  16570. +
  16571. +#include <asm/system.h>
  16572. +#include <asm/io.h>
  16573. +#include <asm/irq-no.h>
  16574. +#include <asm/segment.h>
  16575. +#include <asm/delay.h>
  16576. +#include <asm/dma.h>
  16577. +#include <asm/hardware.h>
  16578. +
  16579. +#include <asm/ecard.h>
  16580. +
  16581. +static int lastspecifieddrive;
  16582. +static unsigned Busy;
  16583. +
  16584. +static unsigned int PartFragRead;    /* The number of sectors which have been read
  16585. +                       during a partial read split over two
  16586. +                       cylinders.  If 0 it means a partial
  16587. +                       read did not occur. */
  16588. +
  16589. +static unsigned int PartFragRead_RestartBlock;    /* Where to restart on a split access */
  16590. +static unsigned int PartFragRead_SectorsLeft;    /* Where to restart on a split access */
  16591. +
  16592. +static int Sectors256LeftInCurrent;    /* i.e. 256 byte sectors left in current */
  16593. +static int SectorsLeftInRequest;    /* i.e. blocks left in the thing mfm_request was called for */
  16594. +static int Copy_Sector;        /* The 256 byte sector we are currently at - fragments need to know 
  16595. +                   where to take over */
  16596. +static char *Copy_buffer;
  16597. +#define MFM_DISK_MAJOR    13
  16598. +#undef  XT_DISK_MAJOR
  16599. +#define XT_DISK_MAJOR    -1
  16600. +#define MAJOR_NR    MFM_DISK_MAJOR
  16601. +#include "blk.h"
  16602. +
  16603. +XD_INFO mfm_info[XD_MAXDRIVES];
  16604. +
  16605. +/*#define DEBUG */
  16606. +
  16607. +#define MFM_COMMAND (mfm_addr + 0)
  16608. +#define MFM_DATAOUT (mfm_addr + 1)
  16609. +#define MFM_STATUS  (mfm_addr + 8)
  16610. +#define MFM_DATAIN  (mfm_addr + 9)
  16611. +
  16612. +static void mfm_geninit(struct gendisk *dev);
  16613. +static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg);
  16614. +static int mfm_open(struct inode *inode, struct file *file);
  16615. +static void mfm_release(struct inode *inode, struct file *file);
  16616. +static void mfm_interrupt_handler(int, struct pt_regs *);
  16617. +static void mfm_seek(void);
  16618. +static void mfm_unexpected_interrupt(void);
  16619. +static void mfm_rerequest(void);
  16620. +static void mfm_request(void);
  16621. +static int mfm_reread_partitions(int dev);
  16622. +static void mfm_specify(void);
  16623. +
  16624. +static void issue_request(int dev, unsigned int block, unsigned int nsect,
  16625. +              struct request *req);
  16626. +#define mfm_init xd_init
  16627. +#define mfm_setup xd_setup
  16628. +
  16629. +static struct hd_struct mfm[XD_MAXDRIVES << 6];
  16630. +static int mfm_sizes[XD_MAXDRIVES << 6], mfm_access[XD_MAXDRIVES] =
  16631. +{0, 0};
  16632. +static int mfm_blocksizes[XD_MAXDRIVES << 6];
  16633. +static unsigned char mfm_valid[XD_MAXDRIVES] =
  16634. +{-1,};
  16635. +static struct wait_queue *mfm_wait_open = NULL;
  16636. +
  16637. +static int mfm_irq;        /* Interrupt number */
  16638. +static int mfm_addr;        /* Controller address */
  16639. +static unsigned char *mfm_IRQPollLoc;    /* Address to read for IRQ information */
  16640. +static char mfm_IRQMask;    /* AND with *mfm_IRQPollLoc to find if there is an interrupt */
  16641. +static int mfm_drives = 0;    /* drives available */
  16642. +static int mfm_status = 0;    /* interrupt status */
  16643. +static int *errors;
  16644. +
  16645. +static struct rawcmd {
  16646. +    unsigned int flags;
  16647. +    unsigned int dev;
  16648. +    unsigned int cylinder;
  16649. +    unsigned int head;
  16650. +    unsigned int sector;
  16651. +    unsigned int cmdtype;
  16652. +    unsigned int cmdcode;
  16653. +    unsigned char cmddata[16];
  16654. +    unsigned int cmdlen;
  16655. +} raw_cmd;
  16656. +
  16657. +#define NEED_SEEK 1
  16658. +unsigned char result[16];
  16659. +unsigned char resultlen;
  16660. +
  16661. +static struct cont {
  16662. +    void (*interrupt) (void);    /* interrupt handler */
  16663. +    void (*error) (void);    /* error handler */
  16664. +    void (*redo) (void);    /* redo handler */
  16665. +    void (*done) (int st);    /* done handler */
  16666. +} *cont = NULL;
  16667. +
  16668. +static struct drvparam {
  16669. +    int cylinder;
  16670. +    unsigned int nocylinders;
  16671. +    unsigned int lowcurrentcylinder;
  16672. +    unsigned int precompcylinder;
  16673. +    unsigned char noheads;
  16674. +    unsigned char nosectors;
  16675. +    struct {
  16676. +        char recal;
  16677. +        char report;
  16678. +        char abort;
  16679. +    } errors;
  16680. +} mfm_drive_param[8] = {
  16681. +    { -1, 616, 616, 129, 4, 32, { 0, 0, 4 } },
  16682. +    { -1, 616, 616, 129, 4, 32, { 0, 0, 4 } },
  16683. +    { -1, 616, 616, 129, 4, 32, { 0, 0, 4 } },
  16684. +    { -1, 616, 616, 129, 4, 32, { 0, 0, 4 } },
  16685. +    { -1, 616, 616, 129, 4, 32, { 0, 0, 4 } },
  16686. +    { -1, 616, 616, 129, 4, 32, { 0, 0, 4 } },
  16687. +    { -1, 616, 616, 129, 4, 32, { 0, 0, 4 } },
  16688. +    { -1, 616, 616, 129, 4, 32, { 0, 0, 4 } }
  16689. +};
  16690. +
  16691. +#define MFM_DRV_PARAM mfm_drive_param[raw_cmd.dev]
  16692. +
  16693. +struct tq_struct mfm_tq =
  16694. +{0, 0, (void (*)(void *)) mfm_unexpected_interrupt, 0};
  16695. +
  16696. +#define NO_TRACK -1
  16697. +#define NEED_1_RECAL -2
  16698. +#define NEED_2_RECAL -3
  16699. +
  16700. +int mfm_sectsizes[256];        /* We have to do this because we don't have 512 byte sectors */
  16701. +
  16702. +/* Stuff from the assembly routines */
  16703. +extern unsigned int hdc63463_baseaddress;    /* Controller base address */
  16704. +extern unsigned int hdc63463_irqpolladdress;    /* Address to read to test for int */
  16705. +extern unsigned int hdc63463_irqpollmask;    /* Mask for irq register */
  16706. +extern unsigned int hdc63463_dataptr;    /* Pointer to kernel data space to DMA */
  16707. +extern int hdc63463_dataleft;    /* Number of bytes left to transfer */
  16708. +
  16709. +#if 0
  16710. +extern int number_mfm_drives;    /* in setup.c */
  16711. +#else
  16712. +int number_mfm_drives = 1;
  16713. +#endif
  16714. +/* ------------------------------------------------------------------------------------------ */
  16715. +/*
  16716. + * From the HD63463 data sheet from Hitachi Ltd.
  16717. + */
  16718. +
  16719. +#define CMD_ABT        0xF0    /* Abort */
  16720. +#define CMD_SPC        0xE8    /* Specify */
  16721. +#define CMD_TST        0xE0    /* Test */
  16722. +#define CMD_RCLB    0xC8    /* Recalibrate */
  16723. +#define CMD_SEK        0xC0    /* Seek */
  16724. +#define CMD_WFS        0xAB    /* Write Format Skew */
  16725. +#define CMD_WFM        0xA3    /* Write Format */
  16726. +#define CMD_MTB        0x90    /* Memory to buffer */
  16727. +#define CMD_CMPD    0x88    /* Compare data */
  16728. +#define CMD_WD        0x87    /* Write data */
  16729. +#define CMD_RED        0x70    /* Read erroneous data */
  16730. +#define CMD_RIS        0x68    /* Read ID skew */
  16731. +#define CMD_FID        0x61    /* Find ID */
  16732. +#define CMD_RID        0x60    /* Read ID */
  16733. +#define CMD_BTM        0x50    /* Buffer to memory */
  16734. +#define CMD_CKD        0x48    /* Check data */
  16735. +#define CMD_RD        0x40    /* Read data */
  16736. +#define CMD_OPBW    0x38    /* Open buffer write */
  16737. +#define CMD_OPBR    0x30    /* Open buffer read */
  16738. +#define CMD_CKV        0x28    /* Check drive */
  16739. +#define CMD_CKE        0x20    /* Check ECC */
  16740. +#define CMD_POD        0x18    /* Polling disable */
  16741. +#define CMD_POL        0x10    /* Polling enable */
  16742. +#define CMD_RCAL    0x08    /* Recall */
  16743. +
  16744. +#define STAT_BSY    0x8000    /* Busy */
  16745. +#define STAT_CPR    0x4000    /* Command Parameter Rejection */
  16746. +#define STAT_CED    0x2000    /* Command end */
  16747. +#define STAT_SED    0x1000    /* Seek end */
  16748. +#define STAT_DER    0x0800    /* Drive error */
  16749. +#define STAT_ABN    0x0400    /* Abnormal end */
  16750. +#define STAT_POL    0x0200    /* Polling */
  16751. +
  16752. +/* ------------------------------------------------------------------------------------------ */
  16753. +#ifdef DEBUG
  16754. +static void console_printf(const char *fmt,...)
  16755. +{
  16756. +    static char buffer[2048];    /* Arbitary! */
  16757. +    extern void console_print(const char *);
  16758. +    va_list ap;
  16759. +    int flags;
  16760. +
  16761. +    save_flags(flags);
  16762. +    cli();
  16763. +
  16764. +    va_start(ap, fmt);
  16765. +
  16766. +    vsprintf(buffer, fmt, ap);
  16767. +
  16768. +    console_print(buffer);
  16769. +
  16770. +    va_end(fmt);
  16771. +
  16772. +    restore_flags(flags);
  16773. +};    /* console_printf */
  16774. +#endif
  16775. +
  16776. +/* ------------------------------------------------------------------------------------------ */
  16777. +
  16778. +static struct gendisk mfm_gendisk =
  16779. +{
  16780. +    MAJOR_NR,        /* Major number */
  16781. +    "mfm",            /* Major name */
  16782. +    6,            /* Bits to shift to get real from partition */
  16783. +    1 << 6,            /* Number of partitions per real */
  16784. +    XD_MAXDRIVES,        /* maximum number of real */
  16785. +    mfm_geninit,        /* init function */
  16786. +    mfm,            /* hd struct */
  16787. +    mfm_sizes,        /* block sizes */
  16788. +    0,            /* number */
  16789. +    (void *) mfm_info,    /* internal */
  16790. +    NULL            /* next */
  16791. +};
  16792. +
  16793. +static struct file_operations mfm_fops =
  16794. +{
  16795. +    NULL,            /* lseek - default */
  16796. +    block_read,        /* read - general block-dev read */
  16797. +    block_write,        /* write - general block-dev write */
  16798. +    NULL,            /* readdir - bad */
  16799. +    NULL,            /* select */
  16800. +    mfm_ioctl,        /* ioctl */
  16801. +    NULL,            /* mmap */
  16802. +    mfm_open,        /* open */
  16803. +    mfm_release,        /* release */
  16804. +    block_fsync        /* fsync */
  16805. +};
  16806. +
  16807. +static struct expansion_card *ecs;
  16808. +static const int mfm_prods[] = {0x000b};
  16809. +static const int mfm_manus[] = {0x0000};
  16810. +
  16811. +/* See if there is a controller at the address presently set in mfm_addr */
  16812. +static int CheckController(void)
  16813. +{
  16814. +    int result;
  16815. +
  16816. +    /* Send any command */
  16817. +    outw(CMD_SEK, MFM_COMMAND);
  16818. +
  16819. +    /* experimentation shows that at least BSY or CPR should be on if
  16820. +       the controller exists. On my 310 this returns 0 */
  16821. +    result = (inw(MFM_STATUS) & 0xc000) != 0;
  16822. +
  16823. +    /* If we did find it we have got to clean up */
  16824. +    if (result) {
  16825. +        /* Wait until the busy flag disappears */
  16826. +        while (inw(MFM_STATUS) & STAT_BSY);
  16827. +
  16828. +        outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
  16829. +    }
  16830. +    return result;
  16831. +};                /* CheckController */
  16832. +
  16833. +
  16834. +int mfm_init(void)
  16835. +{
  16836. +    unsigned int i;
  16837. +    /* DAG */
  16838. +    mfm_irq = IRQ_HARDDISK;
  16839. +    mfm_addr = (0x32d0000 >> 2);    /* Motherboard HDC address  - thats medium (as RiscOS)
  16840. +                       used to be slow */
  16841. +    mfm_IRQPollLoc = &(IOC_IRQSTATB);    /* was  ioc+0x2 */
  16842. +    mfm_IRQMask = 0x08;    /* IL3 pin */
  16843. +    printk("mfm: Looking for onboard controller.....\n");
  16844. +    if (!CheckController()) {
  16845. +        printk("mfm: Hmm - no onboard controller - lets try podules....\n");
  16846. +        ecs = ecard_find(0, sizeof(mfm_prods), mfm_prods, mfm_manus);
  16847. +        if (!ecs)
  16848. +            return -1;
  16849. +
  16850. +        mfm_irq = ecs->irq;
  16851. +        mfm_addr = ((int) ecard_address(ecs->slot_no, ECARD_IOC, ECARD_MEDIUM) + 0x2000) >> 2;
  16852. +        mfm_IRQMask = 0x08;
  16853. +        mfm_IRQPollLoc = (unsigned char *) ((int) ecard_address(ecs->slot_no, ECARD_IOC, ECARD_MEDIUM) + 0x3000);
  16854. +
  16855. +        ecard_claim(ecs);
  16856. +    };
  16857. +
  16858. +    /* Stuff for the assembler routines to get to */
  16859. +    hdc63463_baseaddress = (unsigned int) (mfm_addr << 2);
  16860. +    hdc63463_irqpolladdress = (int) mfm_IRQPollLoc;
  16861. +    hdc63463_irqpollmask = mfm_IRQMask;
  16862. +
  16863. +    printk("mfm: controller found at address %X, interrupt %d\n", mfm_addr << 2, mfm_irq);
  16864. +
  16865. +    if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) {
  16866. +        printk("mfm_init: unable to get major number %d\n", MAJOR_NR);
  16867. +        return -1;
  16868. +    }
  16869. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  16870. +    read_ahead[MAJOR_NR] = 8;    /* 8 sector (4kB?) read ahread */
  16871. +
  16872. +    /* This stops MSDOS trying to mount it - but ll_rw_blk has tons of >>9
  16873. +       presuming 512 byte sectors - its upto us to fix it! */
  16874. +    hardsect_size[MAJOR_NR] = mfm_sectsizes;
  16875. +
  16876. +    /* OK - well actually I'm going to leave it at 512 - this lets the
  16877. +       adfs image drivers work */
  16878. +    for (i = 0; i < 256; i++)
  16879. +        mfm_sectsizes[i] = 512;
  16880. +
  16881. +#ifndef MODULE
  16882. +    mfm_gendisk.next = gendisk_head;
  16883. +    gendisk_head = &mfm_gendisk;
  16884. +#endif
  16885. +
  16886. +    Busy = 0;
  16887. +    lastspecifieddrive = -1;
  16888. +
  16889. +    return 0;
  16890. +}
  16891. +
  16892. +/* DAG: Gets called by the genhd code to set up the number of sectors etc. */
  16893. +void xd_set_geometry(int dev, unsigned char secsptrack, unsigned char heads,
  16894. +             unsigned long discsize, unsigned int secsize)
  16895. +{
  16896. +    dev = MINOR(dev);
  16897. +    /* The HD version checks to see if the number of cylinders are unset */
  16898. +    /* and then causes them to be set... */
  16899. +    /* Need to set up the precomp etc. */
  16900. +    if (mfm_info[dev >> 6].cylinders == 1) {
  16901. +        mfm_info[dev >> 6].sectors = secsptrack;
  16902. +        mfm_info[dev >> 6].heads = heads;
  16903. +        mfm_info[dev >> 6].cylinders = discsize / (secsptrack * heads * secsize);
  16904. +
  16905. +        mfm_drive_param[dev >> 6].nosectors = secsptrack;
  16906. +        mfm_drive_param[dev >> 6].noheads = heads;
  16907. +        mfm_drive_param[dev >> 6].nocylinders = discsize / (secsptrack * heads * secsize);
  16908. +
  16909. +        printk("mfm%c: %d cylinders, %d heads, %d sectors secsize=%d (%ld total blocks)\n", 'a' + (dev >> 6),
  16910. +               mfm_info[dev >> 6].cylinders, heads, secsptrack, secsize, discsize);
  16911. +
  16912. +        /* Should probably do a specify command here.... */
  16913. +        if ((heads < 1) || (mfm_drive_param[dev >> 6].nocylinders > 1024)) {
  16914. +            printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + (dev >> 6));
  16915. +
  16916. +            /* These values are fairly arbitary, but are there so that if your
  16917. +            lucky you can pick apart your disc to find out what is going on -
  16918. +            I reckon these figures won't hurt MOST drives */
  16919. +            mfm_info[dev >> 6].sectors = 32;
  16920. +            mfm_info[dev >> 6].heads = 4;
  16921. +            mfm_info[dev >> 6].cylinders = 512;
  16922. +
  16923. +            mfm_drive_param[dev >> 6].nosectors = 32;
  16924. +            mfm_drive_param[dev >> 6].noheads = 4;
  16925. +            mfm_drive_param[dev >> 6].nocylinders = 512;
  16926. +        };
  16927. +        mfm_specify();
  16928. +    };
  16929. +
  16930. +    mfm[dev].start_sect = 0;
  16931. +    /* This is 512 byte sectors - I want 256 but where does this get set for image files? */
  16932. +    mfm[dev].nr_sects = (discsize / secsize) / 2;    
  16933. +
  16934. +}
  16935. +
  16936. +static int mfm_initdrives(void)
  16937. +{
  16938. +    mfm_info[0].heads = 4;
  16939. +    mfm_info[0].cylinders = 1;    /* its going to have to figure it out from the drive */
  16940. +    mfm_info[0].sectors = 32;
  16941. +    mfm_info[0].control = 0;
  16942. +    mfm_info[1].heads = 4;
  16943. +    mfm_info[1].cylinders = 1;    /* its going to have to figure it out from the drive */
  16944. +    mfm_info[1].sectors = 32;
  16945. +    mfm_info[1].control = 0;
  16946. +    if (number_mfm_drives > XD_MAXDRIVES) {
  16947. +        number_mfm_drives = XD_MAXDRIVES;
  16948. +        printk("No. of ADFS MFM drives is greater than XD_MAXDRIVES - you can't have that many!\n");
  16949. +    };
  16950. +    return number_mfm_drives;
  16951. +}
  16952. +
  16953. +static void mfm_geninit(struct gendisk *dev)
  16954. +{
  16955. +    int i;
  16956. +
  16957. +    mfm_drives = mfm_initdrives();
  16958. +    printk("mfm: detected %d hard drive%s\n", mfm_drives, mfm_drives == 1 ? "" : "s");
  16959. +    for (i = 0; i < mfm_drives; i++)
  16960. +        printk("mfm%d: heads = %d, cylinders = %d, sectors = %d\n", i,
  16961. +               mfm_info[i].heads, mfm_info[i].cylinders, mfm_info[i].sectors);
  16962. +
  16963. +    if (request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk"))
  16964. +        printk("mfm: unable to get IRQ%d\n", mfm_irq);
  16965. +
  16966. +    if (mfm_addr != (0x32d0000 >> 2))
  16967. +        outw(0x80, mfm_addr + (0x1000 >> 2));    /* Required to enable IRQs from MFM podule */
  16968. +
  16969. +    for (i = 0; i < mfm_drives; i++) {
  16970. +        mfm[i << 6].nr_sects = mfm_info[i].heads * mfm_info[i].cylinders *
  16971. +            mfm_info[i].sectors;
  16972. +        mfm[i << 6].start_sect = 0;
  16973. +        mfm_valid[i] = 1;
  16974. +    }
  16975. +    mfm_gendisk.nr_real = mfm_drives;
  16976. +
  16977. +    for (i = 0; i < (XD_MAXDRIVES << 6); i++)
  16978. +        mfm_blocksizes[i] = 1024;    /* Can't increase this - if you do all hell breaks loose */
  16979. +    blksize_size[MAJOR_NR] = mfm_blocksizes;
  16980. +}
  16981. +
  16982. +static int mfm_open(struct inode *inode, struct file *file)
  16983. +{
  16984. +    int dev = DEVICE_NR(MINOR(inode->i_rdev));
  16985. +
  16986. +    if ((dev) < mfm_drives) {
  16987. +        while (!mfm_valid[dev])
  16988. +            sleep_on(&mfm_wait_open);
  16989. +
  16990. +        mfm_access[dev]++;
  16991. +
  16992. +        return (0);
  16993. +    } else
  16994. +        return (-ENODEV);
  16995. +}
  16996. +
  16997. +static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)
  16998. +{
  16999. +    XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg;
  17000. +    int dev = DEVICE_NR(MINOR(inode->i_rdev)), err;
  17001. +
  17002. +    if (inode && (dev < mfm_drives))
  17003. +        switch (cmd) {
  17004. +        case HDIO_GETGEO:
  17005. +            if (arg) {
  17006. +                if ((err = verify_area(VERIFY_WRITE, geometry, sizeof(*geometry))))
  17007. +                    return (err);
  17008. +                put_fs_byte(mfm_info[dev].heads, (char *) &geometry->heads);
  17009. +                put_fs_byte(mfm_info[dev].sectors, (char *) &geometry->sectors);
  17010. +                put_fs_word(mfm_info[dev].cylinders, (short *) &geometry->cylinders);
  17011. +                put_fs_long(mfm[MINOR(inode->i_rdev)].start_sect, (long *) &geometry->start);
  17012. +
  17013. +                return (0);
  17014. +            }
  17015. +            break;
  17016. +        case BLKRASET:
  17017. +            if (!suser())
  17018. +                return -EACCES;
  17019. +            if (!inode->i_rdev)
  17020. +                return -EINVAL;
  17021. +            if (arg > 0xff)
  17022. +                return -EINVAL;
  17023. +            read_ahead[MAJOR(inode->i_rdev)] = arg;
  17024. +            return 0;
  17025. +        case BLKGETSIZE:
  17026. +            if (arg) {
  17027. +                if ((err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long))))
  17028. +                     return (err);
  17029. +                put_fs_long(mfm[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
  17030. +
  17031. +                return (0);
  17032. +            }
  17033. +            break;
  17034. +        case BLKFLSBUF:
  17035. +            if (!suser())
  17036. +                return -EACCES;
  17037. +            if (!inode->i_rdev)
  17038. +                return -EINVAL;
  17039. +            fsync_dev(inode->i_rdev);
  17040. +            invalidate_buffers(inode->i_rdev);
  17041. +            return 0;
  17042. +
  17043. +        case BLKRRPART:
  17044. +            return (mfm_reread_partitions(inode->i_rdev));
  17045. +            RO_IOCTLS(inode->i_rdev, arg);
  17046. +        }
  17047. +    return (-EINVAL);
  17048. +}
  17049. +
  17050. +static void mfm_release(struct inode *inode, struct file *file)
  17051. +{
  17052. +    int dev = DEVICE_NR(MINOR(inode->i_rdev));
  17053. +
  17054. +    if (dev < mfm_drives) {
  17055. +        sync_dev(dev);
  17056. +        mfm_access[dev]--;
  17057. +    }
  17058. +}
  17059. +
  17060. +static int mfm_reread_partitions(int dev)
  17061. +{
  17062. +    int target = DEVICE_NR(MINOR(dev)), start = target << mfm_gendisk.minor_shift,
  17063. +     partition;
  17064. +
  17065. +    cli();
  17066. +
  17067. +    mfm_valid[target] = (mfm_access[target] != 1);
  17068. +
  17069. +    sti();
  17070. +
  17071. +    if (mfm_valid[target])
  17072. +        return -EBUSY;
  17073. +
  17074. +    for (partition = mfm_gendisk.max_p - 1; partition >= 0; partition--) {
  17075. +        sync_dev(MAJOR_NR << 8 | start | partition);
  17076. +        invalidate_inodes(MAJOR_NR << 8 | start | partition);
  17077. +        invalidate_buffers(MAJOR_NR << 8 | start | partition);
  17078. +        mfm_gendisk.part[start + partition].start_sect = 0;
  17079. +        mfm_gendisk.part[start + partition].nr_sects = 0;
  17080. +    };
  17081. +
  17082. +    mfm_gendisk.part[start].nr_sects = mfm_info[target].heads *
  17083. +        mfm_info[target].cylinders * mfm_info[target].sectors;
  17084. +    resetup_one_dev(&mfm_gendisk, target);
  17085. +
  17086. +    mfm_valid[target] = 1;
  17087. +    wake_up(&mfm_wait_open);
  17088. +
  17089. +    return 0;
  17090. +}
  17091. +
  17092. +static void print_status(void)
  17093. +{
  17094. +    char *error;
  17095. +    static char *errors[] = {
  17096. +         "no error",
  17097. +     "command aborted",
  17098. +     "invalid command",
  17099. +     "parameter error",
  17100. +     "not initialised",
  17101. +     "rejected TEST",
  17102. +     "no useld",
  17103. +     "write fault",
  17104. +     "not ready",
  17105. +     "no scp",
  17106. +     "in seek",
  17107. +     "invalid NCA",
  17108. +     "invalid step rate",
  17109. +     "seek error",
  17110. +     "over run",
  17111. +     "invalid PHA",
  17112. +     "data field EEC error",
  17113. +     "data field CRC error",
  17114. +     "error corrected",
  17115. +     "data field fatal error",
  17116. +     "no data am",
  17117. +     "not hit",
  17118. +     "ID field CRC error",
  17119. +     "time over",
  17120. +     "no ID am",
  17121. +     "not writable"
  17122. +    };
  17123. +    if (result[1] < 0x65)
  17124. +        error = errors[result[1] >> 2];
  17125. +    else
  17126. +        error = "unknown";
  17127. +    printk("(");
  17128. +    if (mfm_status & STAT_BSY) printk("BSY ");
  17129. +    if (mfm_status & STAT_CPR) printk("CPR ");
  17130. +    if (mfm_status & STAT_CED) printk("CED ");
  17131. +    if (mfm_status & STAT_SED) printk("SED ");
  17132. +    if (mfm_status & STAT_DER) printk("DER ");
  17133. +    if (mfm_status & STAT_ABN) printk("ABN ");
  17134. +    if (mfm_status & STAT_POL) printk("POL ");
  17135. +    printk(") SSB = %X (%s)\n", result[1], error);
  17136. +
  17137. +}
  17138. +
  17139. +/* ------------------------------------------------------------------------------------- */
  17140. +
  17141. +static void issue_command(int command, unsigned char *cmdb, int len)
  17142. +{
  17143. +    int status;
  17144. +#ifdef DEBUG
  17145. +    int i;
  17146. +    console_printf("issue_command: %02X: ", command);
  17147. +    for (i = 0; i < len; i++)
  17148. +        console_printf("%02X ", cmdb[i]);
  17149. +    console_printf("\n");
  17150. +#endif
  17151. +
  17152. +    do {
  17153. +        status = inw(MFM_STATUS);
  17154. +    } while (status & (STAT_BSY | STAT_POL));
  17155. +#ifdef DEBUG
  17156. +    console_printf("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8);
  17157. +#endif
  17158. +    if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) {
  17159. +        outw(CMD_RCAL, MFM_COMMAND);
  17160. +        while (inw(MFM_STATUS) & STAT_BSY);
  17161. +    }
  17162. +    status = inw(MFM_STATUS);
  17163. +#ifdef DEBUG
  17164. +    console_printf("issue_command: status before parameter issue: %02X:\n ", status >> 8);
  17165. +#endif
  17166. +    while (len > 0) {
  17167. +        outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT);
  17168. +        len -= 2;
  17169. +        cmdb += 2;
  17170. +    }
  17171. +    status = inw(MFM_STATUS);
  17172. +#ifdef DEBUG
  17173. +    console_printf("issue_command: status before command issue: %02X:\n ", status >> 8);
  17174. +#endif
  17175. +    outw(command, MFM_COMMAND);
  17176. +    status = inw(MFM_STATUS);
  17177. +#ifdef DEBUG
  17178. +    console_printf("issue_command: status immediatly after command issue: %02X:\n ", status >> 8);
  17179. +#endif
  17180. +}
  17181. +
  17182. +static void wait_for_completion(void)
  17183. +{
  17184. +    while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
  17185. +}
  17186. +
  17187. +/* ------------------------------------------------------------------------------------- */
  17188. +
  17189. +static void mfm_rw_intr(void)
  17190. +{
  17191. +    int old_status;        /* Holds status on entry, we read to see if the command just finished */
  17192. +#ifdef DEBUG
  17193. +    console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft);
  17194. +    print_status();
  17195. +#endif
  17196. +
  17197. +    if (mfm_status & (STAT_DER | STAT_ABN)) {
  17198. +        /* Something has gone wrong - lets try that again */
  17199. +        outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
  17200. +        if (cont) {
  17201. +#ifdef DEBUG
  17202. +            console_printf("mfm_rw_intr: DER/ABN err\n");
  17203. +#endif
  17204. +            cont->error();
  17205. +            cont->redo();
  17206. +        };
  17207. +        return;
  17208. +    };
  17209. +
  17210. +    /* OK so what ever happend its not an error, now I reckon we are left between
  17211. +       a choice of command end or some data which is ready to be collected */
  17212. +    /* I think we have to transfer data while the interrupt line is on and its
  17213. +       not any other type of interrupt */
  17214. +    if (CURRENT->cmd == WRITE) {
  17215. +        extern void hdc63463_writedma(void);
  17216. +        if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
  17217. +            printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n");
  17218. +            if (cont) {
  17219. +                cont->error();
  17220. +                cont->redo();
  17221. +            };
  17222. +            return;
  17223. +        };
  17224. +        hdc63463_writedma();
  17225. +    } else {
  17226. +        extern void hdc63463_readdma(void);
  17227. +        if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
  17228. +            printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n");
  17229. +            if (cont) {
  17230. +                cont->error();
  17231. +                cont->redo();
  17232. +            };
  17233. +            return;
  17234. +        };
  17235. +#ifdef DEBUG
  17236. +        console_printf("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr);
  17237. +#endif
  17238. +        hdc63463_readdma();
  17239. +    };            /* Read */
  17240. +
  17241. +    if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) {
  17242. +        /* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */
  17243. +        /* Ah - well looking at the status its just when we get command end; so no problem */
  17244. +        /*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n",
  17245. +           hdc63463_dataptr,Copy_buffer+256);
  17246. +           print_status(); */
  17247. +    } else {
  17248. +        Sectors256LeftInCurrent--;
  17249. +        Copy_buffer += 256;
  17250. +        Copy_Sector++;
  17251. +
  17252. +        /* We have come to the end of this request */
  17253. +        if (!Sectors256LeftInCurrent) {
  17254. +#ifdef DEBUG
  17255. +            console_printf("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n",
  17256. +                       CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors);
  17257. +#endif
  17258. +
  17259. +            CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
  17260. +            CURRENT->sector += CURRENT->current_nr_sectors;
  17261. +            SectorsLeftInRequest -= CURRENT->current_nr_sectors;
  17262. +
  17263. +            end_request(1);
  17264. +            if (SectorsLeftInRequest) {
  17265. +                hdc63463_dataptr = (unsigned int) CURRENT->buffer;
  17266. +                Copy_buffer = CURRENT->buffer;
  17267. +                Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
  17268. +                errors = &(CURRENT->errors);
  17269. +                /* These should match the present calculations of the next logical sector
  17270. +                   on the device
  17271. +                   Copy_Sector=CURRENT->sector*2; */
  17272. +
  17273. +                if (Copy_Sector != CURRENT->sector * 2)
  17274. +#ifdef DEBUG
  17275. +                    console_printf("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n",
  17276. +                    Copy_Sector, CURRENT->sector * 2);
  17277. +#else
  17278. +                    printk("mfm: Copy_Sector mismatch! Eek!\n");
  17279. +#endif
  17280. +            };    /* CURRENT */
  17281. +        };    /* Sectors256LeftInCurrent */
  17282. +    };
  17283. +
  17284. +    old_status = mfm_status;
  17285. +    mfm_status = inw(MFM_STATUS);
  17286. +    if (mfm_status & (STAT_DER | STAT_ABN)) {
  17287. +        /* Something has gone wrong - lets try that again */
  17288. +        if (cont) {
  17289. +#ifdef DEBUG
  17290. +            console_printf("mfm_rw_intr: DER/ABN error\n");
  17291. +#endif
  17292. +            cont->error();
  17293. +            cont->redo();
  17294. +        };
  17295. +        return;
  17296. +    };
  17297. +
  17298. +    /* If this code wasn't entered due to command_end but there is
  17299. +       now a command end we must read the command results out. If it was
  17300. +       entered like this then mfm_interrupt_handler would have done the
  17301. +       job. */
  17302. +    if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) &&
  17303. +        ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) {
  17304. +        int len = 0;
  17305. +        while (len < 16) {
  17306. +            int in;
  17307. +            in = inw(MFM_DATAIN);
  17308. +            result[len++] = in >> 8;
  17309. +            result[len++] = in;
  17310. +        };
  17311. +    };            /* Result read */
  17312. +
  17313. +    /*console_printf ("mfm_rw_intr nearexit [%02X]\n", (unsigned int)*mfm_IRQPollLoc); */
  17314. +
  17315. +    /* If end of command move on */
  17316. +    if (mfm_status & (STAT_CED)) {
  17317. +        outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
  17318. +        /* End of command - trigger the next command */
  17319. +        if (cont) {
  17320. +            cont->done(1);
  17321. +        }
  17322. +#ifdef DEBUG
  17323. +        console_printf("mfm_rw_intr: returned from cont->done\n");
  17324. +#endif
  17325. +    } else {
  17326. +        /* Its going to generate another interrupt */
  17327. +        SET_INTR(mfm_rw_intr);
  17328. +    };
  17329. +}
  17330. +
  17331. +static void mfm_setup_rw(void)
  17332. +{
  17333. +#ifdef DEBUG
  17334. +    console_printf("setting up for rw...\n");
  17335. +#endif
  17336. +#if 1
  17337. +    SET_INTR(mfm_rw_intr);
  17338. +    issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);
  17339. +#else
  17340. +    if (cont) {
  17341. +        cont->done(0);
  17342. +        cont->redo();
  17343. +    }
  17344. +#endif
  17345. +}
  17346. +
  17347. +static void mfm_recal_intr(void)
  17348. +{
  17349. +#ifdef DEBUG
  17350. +    console_printf("recal intr - status = ");
  17351. +    print_status();
  17352. +#endif
  17353. +    outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
  17354. +    if (mfm_status & (STAT_DER | STAT_ABN)) {
  17355. +        printk("recal failed\n");
  17356. +        MFM_DRV_PARAM.cylinder = NEED_2_RECAL;
  17357. +        if (cont) {
  17358. +            cont->error();
  17359. +            cont->redo();
  17360. +        }
  17361. +        return;
  17362. +    }
  17363. +    /* Thats seek end - we are finished */
  17364. +    if (mfm_status & STAT_SED) {
  17365. +        issue_command(CMD_POD, NULL, 0);
  17366. +        MFM_DRV_PARAM.cylinder = 0;
  17367. +        mfm_seek();
  17368. +        return;
  17369. +    }
  17370. +    /* Command end without seek end (see data sheet p.20) for parallel seek
  17371. +       - we have to send a POL command to wait for the seek */
  17372. +    if (mfm_status & STAT_CED) {
  17373. +        SET_INTR(mfm_recal_intr);
  17374. +        issue_command(CMD_POL, NULL, 0);
  17375. +        return;
  17376. +    }
  17377. +    printk("recal: unknown status\n");
  17378. +}
  17379. +
  17380. +static void mfm_seek_intr(void)
  17381. +{
  17382. +#ifdef DEBUG
  17383. +    console_printf("seek intr - status = ");
  17384. +    print_status();
  17385. +#endif
  17386. +    outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
  17387. +    if (mfm_status & (STAT_DER | STAT_ABN)) {
  17388. +        printk("seek failed\n");
  17389. +        MFM_DRV_PARAM.cylinder = NEED_2_RECAL;
  17390. +        if (cont) {
  17391. +            cont->error();
  17392. +            cont->redo();
  17393. +        }
  17394. +        return;
  17395. +    }
  17396. +    if (mfm_status & STAT_SED) {
  17397. +        issue_command(CMD_POD, NULL, 0);
  17398. +        MFM_DRV_PARAM.cylinder = raw_cmd.cylinder;
  17399. +        mfm_seek();
  17400. +        return;
  17401. +    }
  17402. +    if (mfm_status & STAT_CED) {
  17403. +        SET_INTR(mfm_seek_intr);
  17404. +        issue_command(CMD_POL, NULL, 0);
  17405. +        return;
  17406. +    }
  17407. +    printk("seek: unknown status\n");
  17408. +}
  17409. +
  17410. +static void mfm_specify(void)
  17411. +{
  17412. +    /* IDEA2 seems to work better - its what RiscOS sets my
  17413. +       disc to - on its SECOND call to specify! */
  17414. +#define IDEA2
  17415. +    unsigned char cmdb[16];
  17416. +#ifdef DEBUG
  17417. +    console_printf("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive);
  17418. +#endif
  17419. +    cmdb[0] = 0x1F;        /* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */
  17420. +    cmdb[1] = 0xC3;        /* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */
  17421. +#ifndef IDEA2
  17422. +    cmdb[2] = 0x16;        /* OM2 - SL - step pulse low */
  17423. +#else
  17424. +    cmdb[2] = 0;        /* OM2 - SL - step pulse low */
  17425. +#endif
  17426. +    cmdb[3] = (number_mfm_drives == 1) ? 0x02 : 0x06;    /* 1 or 2 drives */
  17427. +    cmdb[4] = 0xFC | ((MFM_DRV_PARAM.nocylinders - 1) >> 8);    /* RW time over/high part of number of cylinders */
  17428. +    cmdb[5] = MFM_DRV_PARAM.nocylinders - 1;    /* low part of number of cylinders */
  17429. +    cmdb[6] = MFM_DRV_PARAM.noheads - 1;    /* Number of heads */
  17430. +    cmdb[7] = MFM_DRV_PARAM.nosectors - 1;    /* Number of sectors */
  17431. +#ifndef IDEA2
  17432. +    cmdb[8] = 0xA9;        /* Step pulse high=21, Record Length=001 (256 bytes) */
  17433. +#else
  17434. +    cmdb[8] = 0x21;        /* Step pulse high=4, Record Length=001 (256 bytes) */
  17435. +#endif
  17436. +    cmdb[9] = 0x0A;        /* gap length 1 */
  17437. +    cmdb[10] = 0x0D;    /* gap length 2 */
  17438. +    cmdb[11] = 0x0C;    /* gap length 3 */
  17439. +    /* DAG: Note my data sheet shows precomp and low current the other way around */
  17440. +    cmdb[12] = (MFM_DRV_PARAM.precompcylinder - 1) >> 8;    /* pre comp cylinder */
  17441. +    cmdb[13] = MFM_DRV_PARAM.precompcylinder - 1;
  17442. +    cmdb[14] = (MFM_DRV_PARAM.lowcurrentcylinder - 1) >> 8;        /* Low current cylinder */
  17443. +    cmdb[15] = MFM_DRV_PARAM.lowcurrentcylinder - 1;
  17444. +
  17445. +    issue_command(CMD_SPC, cmdb, 16);
  17446. +    /* Ensure that we will do another specify if we move to the other drive */
  17447. +    lastspecifieddrive = raw_cmd.dev;
  17448. +    wait_for_completion();
  17449. +}
  17450. +
  17451. +static void mfm_seek(void)
  17452. +{
  17453. +    unsigned char cmdb[4];
  17454. +#ifdef DEBUG
  17455. +    console_printf("seeking...\n");
  17456. +#endif
  17457. +    if (MFM_DRV_PARAM.cylinder < 0) {
  17458. +        SET_INTR(mfm_recal_intr);
  17459. +#ifdef DEBUG
  17460. +        console_printf("mfm_seek: about to call specify\n");
  17461. +#endif
  17462. +        mfm_specify();    /* DAG added this */
  17463. +
  17464. +        cmdb[0] = raw_cmd.dev + 1;
  17465. +        cmdb[1] = 0;    /*raw_cmd.head; */
  17466. +
  17467. +        issue_command(CMD_RCLB, cmdb, 2);
  17468. +        return;
  17469. +    }
  17470. +    /*mfm_specify(); *//* DAG took this out */
  17471. +    if (MFM_DRV_PARAM.cylinder != raw_cmd.cylinder) {
  17472. +        cmdb[0] = raw_cmd.dev + 1;
  17473. +        cmdb[1] = 0;    /* raw_cmd.head; DAG: My data sheet says this should be 0 */
  17474. +        cmdb[2] = raw_cmd.cylinder >> 8;
  17475. +        cmdb[3] = raw_cmd.cylinder;
  17476. +
  17477. +        SET_INTR(mfm_seek_intr);
  17478. +        issue_command(CMD_SEK, cmdb, 4);
  17479. +    } else
  17480. +        mfm_setup_rw();
  17481. +}
  17482. +
  17483. +static void mfm_initialise(void)
  17484. +{
  17485. +#ifdef DEBUG
  17486. +    console_printf("init...\n");
  17487. +#endif
  17488. +    if (raw_cmd.flags & NEED_SEEK)
  17489. +        mfm_seek();
  17490. +    else
  17491. +        mfm_setup_rw();
  17492. +}
  17493. +
  17494. +/* ------------------------------------------------------------------------------------- */
  17495. +
  17496. +static void request_done(int uptodate)
  17497. +{
  17498. +#ifdef DEBUG
  17499. +    console_printf("mfm:request_done\n");
  17500. +#endif
  17501. +    if (uptodate) {
  17502. +        unsigned char block[2] = {0, 0};
  17503. +
  17504. +        /* Apparently worked - lets check bytes left to DMA */
  17505. +        if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) {
  17506. +            printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256);
  17507. +            end_request(0);
  17508. +            Busy = 0;
  17509. +        };
  17510. +        /* Potentially this means that we've done; but we might be doing
  17511. +           a partial access, (over two cylinders) or we may have a number
  17512. +           of fragments in an image file.  First lets deal with partial accesss
  17513. +         */
  17514. +        if (PartFragRead) {
  17515. +            /* Yep - a partial access */
  17516. +
  17517. +            /* and issue the remainder */
  17518. +            issue_request(MINOR(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT);
  17519. +            return;
  17520. +        };
  17521. +
  17522. +        /* ah well - perhaps there is another fragment to go */
  17523. +
  17524. +        /* Increment pointers/counts to start of next fragment */
  17525. +        if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n");
  17526. +
  17527. +        /* No - its the end of the line */
  17528. +        /* end_request's should have happened at the end of sector DMAs */
  17529. +        /* Turns Drive LEDs off - may slow it down? */
  17530. +        issue_command(CMD_CKV, block, 2);
  17531. +
  17532. +        Busy = 0;
  17533. +#ifdef DEBUG
  17534. +        console_printf("request_done: About to mfm_request\n");
  17535. +#endif
  17536. +        /* Next one please */
  17537. +        mfm_request();    /* Moved from mfm_rw_intr */
  17538. +#ifdef DEBUG
  17539. +        console_printf("request_done: returned from mfm_request\n");
  17540. +#endif
  17541. +    } else {
  17542. +        end_request(0);
  17543. +        Busy = 0;
  17544. +    }
  17545. +}
  17546. +
  17547. +static void error_handler(void)
  17548. +{
  17549. +    int i;
  17550. +    printk("error detected... status = ");
  17551. +    print_status();
  17552. +    (*errors)++;
  17553. +    if (*errors > MFM_DRV_PARAM.errors.abort)
  17554. +        cont->done(0);
  17555. +    if (*errors > MFM_DRV_PARAM.errors.recal)
  17556. +        MFM_DRV_PARAM.cylinder = NEED_2_RECAL;
  17557. +}
  17558. +
  17559. +static void rw_interrupt(void)
  17560. +{
  17561. +    printk("rw_interrupt\n");
  17562. +}
  17563. +
  17564. +static struct cont rw_cont =
  17565. +{
  17566. +    rw_interrupt,
  17567. +    error_handler,
  17568. +    mfm_rerequest,
  17569. +    request_done
  17570. +};
  17571. +
  17572. +/*
  17573. + * Actually gets round to issuing the request - note everything at this
  17574. + * point is in 256 byte sectors not Linux 512 byte blocks
  17575. + */
  17576. +static void issue_request(int dev, unsigned int block, unsigned int nsect,
  17577. +              struct request *req)
  17578. +{
  17579. +    int track, start_head, start_sector;
  17580. +    int sectors_to_next_cyl;
  17581. +
  17582. +    dev >>= 6;
  17583. +
  17584. +    track = block / mfm_info[dev].sectors;
  17585. +    start_sector = block % mfm_info[dev].sectors;
  17586. +    start_head = track % mfm_info[dev].heads;
  17587. +
  17588. +    /* First get the number of whole tracks which are free before the next
  17589. +       track */
  17590. +    sectors_to_next_cyl = (mfm_info[dev].heads - (start_head + 1)) * mfm_info[dev].sectors;
  17591. +    /* Then add in the number of sectors left on this track */
  17592. +    sectors_to_next_cyl += (mfm_info[dev].sectors - start_sector);
  17593. +
  17594. +#ifdef DEBUG
  17595. +    console_printf("issue_request: mfm_info[dev].sectors=%d track=%d\n", mfm_info[dev].sectors, track);
  17596. +#endif
  17597. +
  17598. +    raw_cmd.flags = NEED_SEEK;
  17599. +    raw_cmd.dev = dev;
  17600. +    raw_cmd.sector = start_sector;
  17601. +    raw_cmd.head = start_head;
  17602. +    raw_cmd.cylinder = track / mfm_info[dev].heads;
  17603. +    raw_cmd.cmdtype = CURRENT->cmd;
  17604. +    raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD;
  17605. +    raw_cmd.cmddata[0] = dev + 1;    /* DAG: +1 to get US */
  17606. +    raw_cmd.cmddata[1] = raw_cmd.head;
  17607. +    raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8;
  17608. +    raw_cmd.cmddata[3] = raw_cmd.cylinder;
  17609. +    raw_cmd.cmddata[4] = raw_cmd.head;
  17610. +    raw_cmd.cmddata[5] = raw_cmd.sector;
  17611. +
  17612. +    /* Was == and worked - how the heck??? */
  17613. +    if (lastspecifieddrive != raw_cmd.dev) {
  17614. +        mfm_specify();
  17615. +    };
  17616. +
  17617. +    if (nsect <= sectors_to_next_cyl) {
  17618. +        raw_cmd.cmddata[6] = nsect >> 8;
  17619. +        raw_cmd.cmddata[7] = nsect;
  17620. +        PartFragRead = 0;    /* All in one */
  17621. +        PartFragRead_SectorsLeft = 0;    /* Must set this - used in DMA calcs */
  17622. +    } else {
  17623. +        raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8;
  17624. +        raw_cmd.cmddata[7] = sectors_to_next_cyl;
  17625. +        PartFragRead = sectors_to_next_cyl;    /* only do this many this time */
  17626. +        PartFragRead_RestartBlock = block + sectors_to_next_cyl;    /* Where to restart from */
  17627. +        PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl;
  17628. +    };
  17629. +    raw_cmd.cmdlen = 8;
  17630. +
  17631. +    /* Setup DMA pointers */
  17632. +    hdc63463_dataptr = (unsigned int) Copy_buffer;
  17633. +    hdc63463_dataleft = nsect * 256;    /* Better way? */
  17634. +
  17635. +
  17636. +#ifdef DEBUG
  17637. +    console_printf("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
  17638. +         raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ",
  17639. +               raw_cmd.cylinder,
  17640. +               raw_cmd.head,
  17641. +        raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT);
  17642. +#endif
  17643. +    cont = &rw_cont;
  17644. +    errors = &(CURRENT->errors);
  17645. +    mfm_tq.routine = (void (*)(void *)) mfm_initialise;
  17646. +    queue_task(&mfm_tq, &tq_immediate);
  17647. +    mark_bh(IMMEDIATE_BH);
  17648. +};                /* issue_request */
  17649. +
  17650. +static void mfm_rerequest(void)
  17651. +{
  17652. +    /* Called when an error has just happened - need to trick mfm_request
  17653. +       into thinking we weren't busy */
  17654. +    /* Turn off ints - mfm_request expects no interrupts anyway */
  17655. +#ifdef DEBUG
  17656. +    console_printf("mfm_rerequest\n");
  17657. +#endif
  17658. +    cli();
  17659. +    Busy = 0;
  17660. +    mfm_request();
  17661. +};
  17662. +
  17663. +static void mfm_request(void)
  17664. +{
  17665. +    unsigned int dev, block, nsect;
  17666. +
  17667. +#ifdef DEBUG
  17668. +    console_printf("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy);
  17669. +#endif
  17670. +    if (!CURRENT) {
  17671. +#ifdef DEBUG
  17672. +        console_printf("mfm_request: Exited due to NULL Current 1\n");
  17673. +#endif
  17674. +        return;
  17675. +    };
  17676. +    if (CURRENT->rq_status == RQ_INACTIVE) {
  17677. +        /* Hmm - seems to be happening a lot on 1.3.45 */
  17678. +        /*console_printf("mfm_request: Exited due to INACTIVE Current\n"); */
  17679. +        return;
  17680. +    };
  17681. +
  17682. +    /* If we are still processing then return; we will get called again */
  17683. +    if (Busy) {
  17684. +        /* Again seems to be common in 1.3.45 */
  17685. +        /*console_printf("mfm_request: Exiting due to busy\n"); */
  17686. +        return;
  17687. +    };
  17688. +    Busy = 1;
  17689. +#if 0
  17690. +    if (CURRENT && CURRENT->rq_dev < 0) {
  17691. +        console_printf("mfm_request: exit due to (CURRENT && CURRENT->rq_dev < 0)\n");
  17692. +        Busy = 0;
  17693. +        return;
  17694. +    };
  17695. +#endif
  17696. +
  17697. +    while (1) {
  17698. +#ifdef DEBUG
  17699. +        console_printf("mfm_request: loop start\n");
  17700. +#endif
  17701. +        /* DAG: I wonder if there wshould be a store flags here? */
  17702. +        sti();
  17703. +
  17704. +#ifdef DEBUG
  17705. +        console_printf("mfm_request: before INIT_REQUEST\n");
  17706. +#endif
  17707. +        if (!CURRENT) {
  17708. +            printk("mfm_request: Exiting due to !CURRENT (pre)\n");
  17709. +            Busy = 0;
  17710. +            return;
  17711. +        };
  17712. +
  17713. +        INIT_REQUEST;
  17714. +
  17715. +        /* DAG: Should this be here - e.g. if we run out of valid requests */
  17716. +        if (!CURRENT) {
  17717. +            printk("mfm_request: Exiting due to !CURRENT (post)\n");
  17718. +            Busy = 0;
  17719. +            return;
  17720. +        };
  17721. +
  17722. +#ifdef DEBUG
  17723. +        console_printf("mfm_request:                 before arg extraction\n");
  17724. +#endif
  17725. +        dev = MINOR(CURRENT->rq_dev);
  17726. +        Copy_buffer = CURRENT->buffer;
  17727. +
  17728. +        block = CURRENT->sector;
  17729. +        nsect = CURRENT->nr_sectors;
  17730. +        SectorsLeftInRequest = nsect;
  17731. +        Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
  17732. +        Copy_buffer = CURRENT->buffer;
  17733. +        Copy_Sector = CURRENT->sector * 2;
  17734. +
  17735. +#ifdef DEBUG
  17736. +        /*if ((dev>>6)==1) */ console_printf("mfm_request:                                raw vals: dev=%d (block=512 bytes) block=%d nblocks=%d\n", dev, block, nsect);
  17737. +#endif
  17738. +
  17739. +        /* DAG: Linux doesn't cope with this - even though it has an array telling
  17740. +           it the hardware block size - silly */
  17741. +        block *= 2;    /* Now in 256 byte sectors */
  17742. +        nsect *= 2;    /* Ditto */
  17743. +
  17744. +        if (dev >= (mfm_drives << 6) ||
  17745. +            block >= (mfm[dev].nr_sects * 2) || ((block + nsect) > (mfm[dev].nr_sects * 2))) {
  17746. +            printk("mfm: oops dev=0x%04x mfm_drives=%d block=%d mfm[dev].nr_sects=%ld nsect=%d\n",
  17747. +            dev, mfm_drives, block, mfm[dev].nr_sects, nsect);
  17748. +            if (dev >= (mfm_drives << 6))
  17749. +                printk("mfm: bad minor number: device=0x%04x\n", CURRENT->rq_dev);
  17750. +            else
  17751. +                printk("mfm%c: bad access: block=%d, count=%d\n", (dev >> 6) + 'a',
  17752. +                       block, nsect);
  17753. +            printk("mfm: continue 1\n");
  17754. +            end_request(0);
  17755. +            Busy = 0;
  17756. +            continue;
  17757. +        }
  17758. +        block += mfm[dev].start_sect;
  17759. +
  17760. +        if (dev & 0x3f) {
  17761. +            printk("mfm: Accessing old image file - not allowed!\n");
  17762. +            end_request(0);
  17763. +            Busy = 0;
  17764. +            continue;
  17765. +        }
  17766. +#ifdef DEBUG
  17767. +        console_printf("mfm_request: block after offset=%d\n", block);
  17768. +#endif
  17769. +
  17770. +        if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) {
  17771. +            printk("unknown mfm-command %d\n", CURRENT->cmd);
  17772. +            end_request(0);
  17773. +            Busy = 0;
  17774. +            printk("mfm: continue 4\n");
  17775. +            continue;
  17776. +        }
  17777. +        issue_request(dev, block, nsect, CURRENT);
  17778. +
  17779. +        break;
  17780. +    }
  17781. +#ifdef DEBUG
  17782. +    console_printf("mfm_request: Dropping out bottom\n");
  17783. +#endif
  17784. +}
  17785. +
  17786. +static void do_mfm_request(void)
  17787. +{
  17788. +#ifdef DEBUG
  17789. +    console_printf("do_mfm_request: about to mfm_request\n");
  17790. +#endif
  17791. +    mfm_request();
  17792. +}
  17793. +
  17794. +static void mfm_unexpected_interrupt(void)
  17795. +{
  17796. +    printk("mfm: unexpected interrupt - status = ");
  17797. +    print_status();
  17798. +    while (1);
  17799. +}
  17800. +
  17801. +static void mfm_interrupt_handler(int unused, struct pt_regs *regs)
  17802. +{
  17803. +    int i;
  17804. +    void (*handler) (void) = DEVICE_INTR;
  17805. +
  17806. +#ifdef DEBUG
  17807. +    console_printf("mfm_interrupt_handler (handler=0x%p)\n", handler);
  17808. +#endif
  17809. +    CLEAR_INTR;
  17810. +    mfm_status = inw(MFM_STATUS);
  17811. +
  17812. +    /* If CPR (Command Parameter Reject) and not busy it means that the command
  17813. +       has some return message to give us */
  17814. +    if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) {
  17815. +        int len = 0;
  17816. +        while (len < 16) {
  17817. +            int in;
  17818. +            in = inw(MFM_DATAIN);
  17819. +            result[len++] = in >> 8;
  17820. +            result[len++] = in;
  17821. +        }
  17822. +    }
  17823. +    if (!handler) {
  17824. +        outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
  17825. +        mfm_unexpected_interrupt();
  17826. +        return;
  17827. +    }
  17828. +    handler();
  17829. +}
  17830. +
  17831. +/* DAG: Called presumably to accept command line parameters */
  17832. +/* Ignore for the moment! */
  17833. +void mfm_setup(char *str, int *ints)
  17834. +{
  17835. +    return;
  17836. +}
  17837. +
  17838. +#ifdef MODULE
  17839. +
  17840. +int init_module(void)
  17841. +{
  17842. +    mfm_init();
  17843. +    mfm_geninit(&mfm_gendisk);
  17844. +    return 0;
  17845. +}
  17846. +
  17847. +void cleanup_module(void)
  17848. +{
  17849. +    if (ecs) {
  17850. +        if (mfm_addr != (0x32d0000 >> 2))
  17851. +            outw(0, mfm_addr + (0x1000 >> 2));    /* Required to enable IRQs from MFM podule */
  17852. +        free_irq(mfm_irq);
  17853. +        unregister_blkdev(MAJOR_NR, "mfm");
  17854. +        ecard_release(ecs);
  17855. +    }
  17856. +}
  17857. +
  17858. +#endif
  17859. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/Config.in linux/arch/arm/drivers/char/Config.in
  17860. --- linux.orig/arch/arm/drivers/char/Config.in    Thu Jan  1 01:00:00 1970
  17861. +++ linux/arch/arm/drivers/char/Config.in    Tue Jul 30 17:45:42 1996
  17862. @@ -0,0 +1,29 @@
  17863. +#
  17864. +# Character device configuration
  17865. +#
  17866. +mainmenu_option next_comment
  17867. +comment 'Character devices'
  17868. +
  17869. +bool 'Echo console messages on /dev/ttyS0' CONFIG_SERIAL_ECHO
  17870. +tristate 'Standard/generic serial support' CONFIG_SERIAL
  17871. +if [ $CONFIG_SERIAL != 'n' ]; then
  17872. +  tristate 'Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL
  17873. +  tristate 'Dual serial port support' CONFIG_DUALSP_SERIAL
  17874. +fi
  17875. +tristate 'Parallel printer support' CONFIG_PRINTER
  17876. +
  17877. +bool 'Mouse support' CONFIG_MOUSE
  17878. +if [ "$CONFIG_MOUSE" = "y" ]; then
  17879. +  tristate 'Keyboard mouse (pre-RiscPC)' CONFIG_KBDMOUSE
  17880. +fi
  17881. +
  17882. +bool 'Support for user misc device modules' CONFIG_UMISC
  17883. +
  17884. +bool 'Watchdog Timer Support'   CONFIG_WATCHDOG
  17885. +if [ "$CONFIG_WATCHDOG" != "n" ]; then
  17886. +  bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
  17887. +  define_bool CONFIG_SOFT_WATCHDOG y
  17888. +fi
  17889. +#bool 'Enhanced Real Time Clock Support' CONFIG_RTC
  17890. +endmenu
  17891. +
  17892. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/Makefile linux/arch/arm/drivers/char/Makefile
  17893. --- linux.orig/arch/arm/drivers/char/Makefile    Thu Jan  1 01:00:00 1970
  17894. +++ linux/arch/arm/drivers/char/Makefile    Tue Jul 30 17:39:37 1996
  17895. @@ -0,0 +1,149 @@
  17896. +#
  17897. +# Makefile for the kernel character device drivers.
  17898. +#
  17899. +# Note! Dependencies are done automagically by 'make dep', which also
  17900. +# removes any old dependencies. DON'T put your own dependencies here
  17901. +# unless it's something special (ie not a .c file).
  17902. +#
  17903. +# Note 2! The CFLAGS definitions are now inherited from the
  17904. +# parent makes..
  17905. +#
  17906. +
  17907. +#
  17908. +# This file contains the font map for the default font
  17909. +#
  17910. +
  17911. +FONTMAPFILE = cp437.uni
  17912. +
  17913. +# Links to make
  17914. +
  17915. +LK = conmakehash.c consolemap.c consolemap.h cp437.uni \
  17916. +     kbd_kern.h lp.c random.c tty_ioctl.c softdog.c
  17917. +
  17918. +all: links first_rule
  17919. +
  17920. +L_TARGET := char.a
  17921. +M_OBJS   :=
  17922. +L_OBJS   := tty_io.o n_tty.o console.o keyboard.o \
  17923. +        tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \
  17924. +        defkeymap.o consolemap.o selection.o
  17925. +
  17926. +# architecture options
  17927. +ifeq ($(MACHINE),a5k)
  17928. +  ifeq ($(CONFIG_SERIAL),y)
  17929. +    SL=y
  17930. +  else
  17931. +    ifeq ($(CONFIG_SERIAL),m)
  17932. +      SM=m
  17933. +    endif
  17934. +  endif
  17935. +else
  17936. +  ifeq ($(MACHINE),arc)
  17937. +    ifeq ($(CONFIG_SERIAL),y)
  17938. +      LX_OBJS += serial6850.o
  17939. +    else
  17940. +      ifeq ($(CONFIG_SERIAL),m)
  17941. +        LX_OBJS += serial6850.o
  17942. +      endif
  17943. +    endif
  17944. +  endif
  17945. +endif
  17946. +
  17947. +# Common dependencies
  17948. +
  17949. +ifeq ($(CONFIG_ATOMWIDE_SERIAL),y)
  17950. +  L_OBJS += serial-atomwide.o
  17951. +  SL=y
  17952. +else
  17953. +  ifeq ($(CONFIG_ATOMWIDE_SERIAL),m)
  17954. +    M_OBJS += serial-atomwide.o
  17955. +    SM=m
  17956. +  endif
  17957. +endif
  17958. +
  17959. +ifeq ($(CONFIG_DUALSP_SERIAL),y)
  17960. +  L_OBJS += serial-dualsp.o
  17961. +  SL=y
  17962. +else
  17963. +  ifeq ($(CONFIG_DUALSP_SERIAL),m)
  17964. +    M_OBJS += serial-dualsp.o
  17965. +    SM=m
  17966. +  endif
  17967. +endif
  17968. +
  17969. +ifdef SL
  17970. +  L_OBJS += serial.o
  17971. +else
  17972. +  ifdef SM
  17973. +    M_OBJS += serial.o
  17974. +  endif
  17975. +endif
  17976. +
  17977. +ifeq ($(CONFIG_PRINTER),y)
  17978. +  L_OBJS += lp.o
  17979. +else
  17980. +  ifeq ($(CONFIG_PRINTER),m)
  17981. +    M_OBJS += lp.o
  17982. +  endif
  17983. +endif
  17984. +
  17985. +ifeq ($(CONFIG_UMISC),y)
  17986. +# To support third-party modules, msic.c must reside in the kernel
  17987. +M = y
  17988. +endif
  17989. +
  17990. +ifeq ($(CONFIG_KBDMOUSE),y)
  17991. +  M = y
  17992. +  L_OBJS += kbdmouse.o
  17993. +else
  17994. +  ifeq ($(CONFIG_KBDMOUSE),m)
  17995. +    MM = m
  17996. +    M_OBJS += kbdmouse.o
  17997. +  endif
  17998. +endif
  17999. +
  18000. +ifeq ($(CONFIG_SOFT_WATCHDOG),y)
  18001. +M = y
  18002. +L_OBJS += softdog.o
  18003. +else
  18004. +  ifeq ($(CONFIG_SOFT_WATCHDOG),m)
  18005. +  M_OBJS += softdog.o
  18006. +  MM = m
  18007. +  endif
  18008. +endif
  18009. +
  18010. +ifdef M
  18011. +  L_OBJS += misc.o
  18012. +else
  18013. +  ifdef MM
  18014. +    M_OBJS += misc.o
  18015. +  endif
  18016. +endif
  18017. +
  18018. +include $(TOPDIR)/Rules.make
  18019. +
  18020. +fastdep: links uni_hash.tbl
  18021. +
  18022. +conmakehash: conmakehash.c
  18023. +    $(HOSTCC) -o conmakehash conmakehash.c
  18024. +
  18025. +uni_hash.tbl: $(FONTMAPFILE) conmakehash
  18026. +    ./conmakehash $(FONTMAPFILE) > uni_hash.tbl
  18027. +
  18028. +.PHONY: links
  18029. +links:
  18030. +    -@for f in $(LK); do \
  18031. +        if [ ! -e $$f ]; then \
  18032. +            echo "ln -s ../../../../drivers/char/$$f .";\
  18033. +            ln -s ../../../../drivers/char/$$f .; \
  18034. +        fi \
  18035. +    done
  18036. +
  18037. +mrproper:
  18038. +    -@for f in $(LK); do \
  18039. +        if [ -L $$f ]; then \
  18040. +            echo $(RM) $$f; \
  18041. +            $(RM) $$f; \
  18042. +        fi; \
  18043. +    done
  18044. +    $(RM) conmakehash
  18045. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/console/font.h linux/arch/arm/drivers/char/console/font.h
  18046. --- linux.orig/arch/arm/drivers/char/console/font.h    Thu Jan  1 01:00:00 1970
  18047. +++ linux/arch/arm/drivers/char/console/font.h    Sat Apr 20 14:37:42 1996
  18048. @@ -0,0 +1,102 @@
  18049. +/*
  18050. + * Font definition
  18051. + */
  18052. +const unsigned char cmap_80[][8]= {
  18053. +    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*   */
  18054. +    {0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00}, /* ! */
  18055. +    {0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00}, /* " */
  18056. +    {0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, /* # */
  18057. +    {0x0C, 0x3F, 0x68, 0x3E, 0x0B, 0x7E, 0x18, 0x00}, /* $ */
  18058. +    {0x60, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x06, 0x00}, /* % */
  18059. +    {0x38, 0x6C, 0x6C, 0x38, 0x6D, 0x66, 0x3B, 0x00}, /* & */
  18060. +    {0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ' */
  18061. +    {0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00}, /* ( */
  18062. +    {0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00}, /* ) */
  18063. +    {0x00, 0x18, 0x7E, 0x3C, 0x7E, 0x18, 0x00, 0x00}, /* * */
  18064. +    {0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00}, /* + */
  18065. +    {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30}, /* , */
  18066. +    {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, /* - */
  18067. +    {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}, /* . */
  18068. +    {0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00}, /* / */
  18069. +    {0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x3C, 0x00}, /* 0 */
  18070. +    {0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00}, /* 1 */
  18071. +    {0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00}, /* 2 */
  18072. +    {0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00}, /* 3 */
  18073. +    {0x0C, 0x1C, 0x3C, 0x6C, 0x7E, 0x0C, 0x0C, 0x00}, /* 4 */
  18074. +    {0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00}, /* 5 */
  18075. +    {0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00}, /* 6 */
  18076. +    {0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00}, /* 7 */
  18077. +    {0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00}, /* 8 */
  18078. +    {0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00}, /* 9 */
  18079. +    {0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00}, /* : */
  18080. +    {0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30}, /* ; */
  18081. +    {0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00}, /* < */
  18082. +    {0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00}, /* = */ 
  18083. +    {0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00}, /* > */
  18084. +    {0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00}, /* ? */
  18085. +    {0x3C, 0x66, 0x6E, 0x6A, 0x6E, 0x60, 0x3C, 0x00}, /* @ */
  18086. +    {0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00}, /* A */
  18087. +    {0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00}, /* B */
  18088. +    {0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00}, /* C */
  18089. +    {0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00}, /* D */
  18090. +    {0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00}, /* E */
  18091. +    {0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00}, /* F */
  18092. +    {0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00}, /* G */
  18093. +    {0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00}, /* H */
  18094. +    {0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00}, /* I */
  18095. +    {0x3E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00}, /* J */
  18096. +    {0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00}, /* K */
  18097. +    {0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00}, /* L */
  18098. +    {0x63, 0x77, 0x7F, 0x6B, 0x6B, 0x63, 0x63, 0x00}, /* M */
  18099. +    {0x66, 0x66, 0x76, 0x7E, 0x6E, 0x66, 0x66, 0x00}, /* N */
  18100. +    {0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, /* O */
  18101. +    {0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00}, /* P */
  18102. +    {0x3C, 0x66, 0x66, 0x66, 0x6A, 0x6C, 0x36, 0x00}, /* Q */
  18103. +    {0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00}, /* R */
  18104. +    {0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00}, /* S */
  18105. +    {0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, /* T */
  18106. +    {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, /* U */
  18107. +    {0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00}, /* V */
  18108. +    {0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x77, 0x63, 0x00}, /* W */
  18109. +    {0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00}, /* X */
  18110. +    {0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00}, /* Y */
  18111. +    {0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00}, /* Z */
  18112. +    {0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7C, 0x00}, /* [ */
  18113. +    {0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00}, /* \ */
  18114. +    {0x3E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x00}, /* ] */
  18115. +    {0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ^ */
  18116. +    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, /* _ */
  18117. +    {0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ` */
  18118. +    {0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00}, /* a */
  18119. +    {0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00}, /* b */
  18120. +    {0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00}, /* c */
  18121. +    {0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00}, /* d */
  18122. +    {0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00}, /* e */
  18123. +    {0x1C, 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x00}, /* f */
  18124. +    {0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x3C}, /* g */
  18125. +    {0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00}, /* h */
  18126. +    {0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00}, /* i */
  18127. +    {0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x70}, /* j */
  18128. +    {0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00}, /* k */
  18129. +    {0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00}, /* l */
  18130. +    {0x00, 0x00, 0x36, 0x7F, 0x6B, 0x6B, 0x63, 0x00}, /* m */
  18131. +    {0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00}, /* n */
  18132. +    {0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00}, /* o */
  18133. +    {0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60}, /* p */
  18134. +    {0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x07}, /* q */
  18135. +    {0x00, 0x00, 0x6C, 0x76, 0x60, 0x60, 0x60, 0x00}, /* r */
  18136. +    {0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00}, /* s */
  18137. +    {0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x1C, 0x00}, /* t */
  18138. +    {0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00}, /* u */
  18139. +    {0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00}, /* v */
  18140. +    {0x00, 0x00, 0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00}, /* w */
  18141. +    {0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00}, /* x */
  18142. +    {0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x3C}, /* y */
  18143. +    {0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00}, /* z */
  18144. +    {0x0C, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0C, 0x00}, /* { */
  18145. +    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, /* | */
  18146. +    {0x30, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x30, 0x00}, /* } */
  18147. +    {0x31, 0x6B, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ~ */
  18148. +    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}  /*  */
  18149. +};
  18150. +
  18151. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/console/serialecho.c linux/arch/arm/drivers/char/console/serialecho.c
  18152. --- linux.orig/arch/arm/drivers/char/console/serialecho.c    Thu Jan  1 01:00:00 1970
  18153. +++ linux/arch/arm/drivers/char/console/serialecho.c    Fri May 10 13:34:51 1996
  18154. @@ -0,0 +1,116 @@
  18155. +/*
  18156. + * linux/arch/arm/drivers/char/serialecho.c
  18157. + *
  18158. + * Serial echoing for kernel console messages.
  18159. + */
  18160. +#if defined (CONFIG_ARCH_A5K) || defined (CONFIG_ARCH_RPC)
  18161. +
  18162. +#include <linux/serial_reg.h>
  18163. +
  18164. +extern int serial_echo_init (int base);
  18165. +extern int serial_echo_print (const char *s);
  18166. +
  18167. +/*
  18168. + * this defines the address for the port to which printk echoing is done
  18169. + *  when CONFIG_SERIAL_ECHO is defined
  18170. + */
  18171. +#define SERIAL_ECHO_PORT    0x3f8    /* internal serial port */
  18172. +
  18173. +static int serial_echo_port = 0;
  18174. +
  18175. +#define serial_echo_outb(v,a) outb((v),(a)+serial_echo_port)
  18176. +#define serial_echo_inb(a)    inb((a)+serial_echo_port)
  18177. +
  18178. +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
  18179. +
  18180. +/* wait for the transmitter & holding register to empty */
  18181. +#define WAIT_FOR_XMITR \
  18182. + do { \
  18183. +    lsr = serial_echo_inb (UART_LSR); \
  18184. + } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
  18185. +
  18186. +/*
  18187. + * These two functions abstract the actual communications with the
  18188. + * debug port.  This is so we can change the underlying communications
  18189. + * mechanism without modifying the rest of the code.
  18190. + */
  18191. +int serial_echo_print (const char *s)
  18192. +{
  18193. +    int lsr, ier;
  18194. +    int i;
  18195. +
  18196. +    if (!serial_echo_port)
  18197. +    return;
  18198. +
  18199. +    /*
  18200. +     * First save the IER then disable interrupts
  18201. +     */
  18202. +    ier = serial_echo_inb (UART_IER);
  18203. +    serial_echo_outb (0x00, UART_IER);
  18204. +
  18205. +    /*
  18206. +     * Now do each character
  18207. +     */
  18208. +    for (i = 0; *s; i++, s++) {
  18209. +    WAIT_FOR_XMITR;
  18210. +
  18211. +    /* send the character out. */
  18212. +    serial_echo_outb (*s, UART_TX);
  18213. +
  18214. +    /* if a LF, also do CR... */
  18215. +    if (*s == 10) {
  18216. +        WAIT_FOR_XMITR;
  18217. +        serial_echo_outb (13, UART_TX);
  18218. +    }
  18219. +    }
  18220. +
  18221. +    /*
  18222. +     * Finally, wait for transmitter & holding register to empty
  18223. +     *  and restore the IER.
  18224. +     */
  18225. +    WAIT_FOR_XMITR;
  18226. +    serial_echo_outb (ier, UART_IER);
  18227. +
  18228. +    return 0;
  18229. +}
  18230. +
  18231. +int serial_echo_init (int base)
  18232. +{
  18233. +    int comstat, hi, lo;
  18234. +
  18235. +    if (base != 0x3f8) {
  18236. +    serial_echo_port = 0;
  18237. +    return 0;
  18238. +    } else
  18239. +    serial_echo_port = base;
  18240. +
  18241. +    /*
  18242. +     * Read the Divisor Latch
  18243. +     */
  18244. +    comstat = serial_echo_inb (UART_LCR);
  18245. +    serial_echo_outb (comstat | UART_LCR_DLAB, UART_LCR);
  18246. +    hi = serial_echo_inb (UART_DLM);
  18247. +    lo = serial_echo_outb (UART_DLL);
  18248. +    serial_echo_outb (comstat);
  18249. +
  18250. +    /*
  18251. +     * now do a hardwired init
  18252. +     */
  18253. +    serial_echo_outb (0x03, UART_LCR); /* No parity, 8 bits, 1 stop */
  18254. +    serial_echo_outb (0x83, UART_LCR); /* Access divisor latch */
  18255. +    serial_echo_outb (0x00, UART_DLM); /* 9600 baud */
  18256. +    serial_echo_outb (0x0c, UART_DLL); /* Done with divisor */
  18257. +
  18258. +    /*
  18259. +     * Prior to disabling interrupts, read the LSR and RBR
  18260. +     * registers
  18261. +     */
  18262. +    comstat = serial_echo_inb (UART_LSR); /* COM? LSR */
  18263. +    comstat = serial_echo_inb (UART_RX);  /* COM? RBR */
  18264. +    serial_echo_outb (0x00, UART_IER);    /* Disable all interrupts */
  18265. +
  18266. +    return 0;
  18267. +}
  18268. +
  18269. +#endif
  18270. +
  18271. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/console.c linux/arch/arm/drivers/char/console.c
  18272. --- linux.orig/arch/arm/drivers/char/console.c    Thu Jan  1 01:00:00 1970
  18273. +++ linux/arch/arm/drivers/char/console.c    Fri Sep  6 21:11:28 1996
  18274. @@ -0,0 +1,2339 @@
  18275. +/*
  18276. + * linux/arch/arm/drivers/char/console.c
  18277. + *
  18278. + * Modifications (C) 1995, 1996 Russell King
  18279. + */
  18280. +
  18281. +/*
  18282. + * This module exports the console io functions:
  18283. + *
  18284. + *  'int           vcd_init (struct vt *vt, int kmallocok, unsigned long *kmem)'
  18285. + *  'unsigned long vcd_pre_init (unsigned long kmem, struct vt *vt)'
  18286. + *  'void          vcd_disallocate (struct vt *vt)'
  18287. + *  'int           vcd_resize (unsigned long lines, unsigned long cols)'
  18288. + *  'void          vcd_blankscreen (int nopowersave)'
  18289. + *  'void          vcd_unblankscreen (void)'
  18290. + *  'void          vcd_savestate (const struct vt *vt, int blanked)'
  18291. + *  'void          vcd_restorestate (const struct vt *vt)'
  18292. + *  'void          vcd_setup_graphics (const struct vt *vt)'
  18293. + *  'int           vcd_write (const struct vt *vt, int from_user, const unsigned char *buf, int count)'
  18294. + *  'int           vcd_ioctl (const struct vt *vt, int cmd, unsigned long arg)'
  18295. + *
  18296. + *
  18297. + *    'int vc_allocate(unsigned int console)'
  18298. + *    'int vc_cons_allocated (unsigned int console)'
  18299. + *    'int vc_resize(unsigned long lines,unsigned long cols)'
  18300. + *    'void vc_disallocate(unsigned int currcons)'
  18301. + *
  18302. + *    'unsigned long con_init(unsigned long)'
  18303. + * S    'int con_open(struct tty_struct *tty,struct file *filp)'
  18304. + * S    'void con_write(struct tty_struct *tty)'
  18305. + * S    'void console_print(const char *b)'
  18306. + *    'void update_screen(int new_console)'
  18307. + *
  18308. + *    'void blank_screen(void)'
  18309. + *    'void unblank_screen(void)'
  18310. + *    'void scrollback(int lines)'            *
  18311. + *    'void scrollfront(int lines)'            *
  18312. + *    'int do_screendump(int arg)'
  18313. + *
  18314. + *    'int con_get_font(char *)'
  18315. + *    'int con_set_font(char *)'
  18316. + *    'int con_get_trans(char *)'
  18317. + *    'int con_set_trans(char *)'
  18318. + *
  18319. + *    'int mouse_reporting(void)'
  18320. + */
  18321. +
  18322. +#define BLANK 0x0020
  18323. +/* A bitmap for codes <32. A bit of 1 indicates that the code
  18324. + * corresponding to that bit number invokes a special action
  18325. + * (such as cursor movement) and should not be displayed as a
  18326. + * glyph unless the disp_ctrl mode is explicitly enabled.
  18327. + */
  18328. +#define CTRL_ACTION 0x0d00ff81
  18329. +#define CTRL_ALWAYS 0x0800f501  /* Cannot be overriden by disp_ctrl */
  18330. +#include <linux/config.h>
  18331. +#include <linux/sched.h>
  18332. +#include <linux/timer.h>
  18333. +#include <linux/interrupt.h>
  18334. +#include <linux/tty.h>
  18335. +#include <linux/tty_flip.h>
  18336. +#include <linux/kernel.h>
  18337. +#include <linux/errno.h>
  18338. +#include <linux/kd.h>
  18339. +#include <linux/major.h>
  18340. +#include <linux/mm.h>
  18341. +#include <linux/malloc.h>
  18342. +
  18343. +#include <asm/segment.h>
  18344. +#include <asm/irq-no.h>
  18345. +
  18346. +#define DEBUG
  18347. +
  18348. +#include "kbd_kern.h"
  18349. +#include "consolemap.h"
  18350. +#include "vt_kern.h"
  18351. +#include "selection.h"
  18352. +
  18353. +#define set_kbd(x) set_vc_kbd_mode (vt->kbd, x)
  18354. +#define clr_kbd(x) clr_vc_kbd_mode (vt->kbd, x)
  18355. +#define is_kbd(x)  vc_kbd_mode (vt->kbd, x)
  18356. +
  18357. +#define decarm        VC_REPEAT
  18358. +#define decckm        VC_CKMODE
  18359. +#define kbdapplic    VC_APPLIC
  18360. +#define lnm        VC_CRLF
  18361. +
  18362. +/*
  18363. + * this is what the terminal answers to a ESC-Z or csi0c query.
  18364. + */
  18365. +#define VT100ID "\033[?1;2c"
  18366. +#define VT102ID "\033[?6c"
  18367. +
  18368. +extern int setup_arm_irq(int, struct irqaction *);
  18369. +
  18370. +int bytes_per_char_h, bytes_per_char_v, video_num_columns;
  18371. +
  18372. +/*
  18373. + * routines to load custom translation table, EGA/VGA font and
  18374. + * VGA colour palette from console.c
  18375. + */
  18376. +extern int con_set_trans_old(unsigned char * table);
  18377. +extern int con_get_trans_old(unsigned char * table);
  18378. +extern int con_set_trans_new(unsigned short * table);
  18379. +extern int con_get_trans_new(unsigned short * table);
  18380. +extern void con_clear_unimap(struct unimapinit *ui);
  18381. +extern int con_set_unimap(ushort ct, struct unipair *list);
  18382. +extern int con_get_unimap(ushort ct, ushort *uct, struct unipair *list);
  18383. +extern void con_set_default_unimap(void);
  18384. +extern int con_set_font(char * fontmap);
  18385. +extern int con_get_font(char * fontmap);
  18386. +
  18387. +
  18388. +/* ARM Extensions */
  18389. +extern void ll_write_char(unsigned long ps, unsigned long chinfo);
  18390. +extern void memc_write (int reg, int val);
  18391. +extern void vidc_write (int reg, int val);
  18392. +extern void memsetl (void *ptr, unsigned long word, int length);
  18393. +extern void map_screen_mem (unsigned long vid_base, int remap);
  18394. +static void ll_erase (const struct vt * const vt, unsigned char sx, unsigned char sy,
  18395. +            unsigned char cx, unsigned char cy);
  18396. +
  18397. +#include <linux/ctype.h>
  18398. +
  18399. +#ifndef MIN
  18400. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  18401. +#endif
  18402. +
  18403. +static void gotoxy (const struct vt * const vt, int new_x, int new_y);
  18404. +static inline void set_cursor (const struct vt * const vt);
  18405. +extern void reset_vc(const struct vt * const vt);
  18406. +extern void register_console(void (*proc)(const char *));
  18407. +extern void compute_shiftstate(void);
  18408. +extern void con_reset_palette (const struct vt * const vt);
  18409. +extern void con_set_palette (const struct vt * const vt);
  18410. +
  18411. +static int can_do_color = 1;
  18412. +static int printable;                /* Is console ready for printing? */
  18413. +
  18414. +#define console_charmask 0xff
  18415. +#ifndef console_charmask
  18416. +static unsigned short console_charmask = 0x0ff;
  18417. +#endif
  18418. +
  18419. +#include "console/font.h"
  18420. +
  18421. +static const unsigned long palette_1[] = {
  18422. +    0x1000,        /* Black   */
  18423. +    0x1fff,        /* White   */
  18424. +    0x1000,        /* Black   */
  18425. +    0x1000,        /* Black   */
  18426. +    0x1000,        /* Black   */
  18427. +    0x1000,        /* Black   */
  18428. +    0x1000,        /* Black   */
  18429. +    0x1000,        /* Black   */
  18430. +    0x1000,        /* Black   */
  18431. +    0x1000,        /* Black   */
  18432. +    0x1000,        /* Black   */
  18433. +    0x1000,        /* Black   */
  18434. +    0x1000,        /* Black   */
  18435. +    0x1000,        /* Black   */
  18436. +    0x1000,        /* Black   */
  18437. +    0x1000,        /* Black   */
  18438. +    0x1000,        /* Black   */
  18439. +    0x1000,        /* Black   */
  18440. +    0x1000,        /* Black   */
  18441. +    0x1000        /* Black   */
  18442. +};
  18443. +
  18444. +static const unsigned long palette_4[] = {
  18445. +    0x1000,        /* Black   */
  18446. +    0x100c,        /* Red     */
  18447. +    0x10c0,        /* Green   */
  18448. +    0x10cc,        /* Yellow  */
  18449. +    0x1c00,        /* Blue    */
  18450. +    0x1c0c,        /* Magenta */
  18451. +    0x1cc0,        /* Cyan    */
  18452. +    0x1ccc,        /* White   */
  18453. +    0x1000,
  18454. +    0x100f,
  18455. +    0x10f0,
  18456. +    0x10ff,
  18457. +    0x1f00,
  18458. +    0x1f0F,
  18459. +    0x1ff0,
  18460. +    0x1fff,
  18461. +    0x1000,        /* Black   */
  18462. +    0x1000,        /* Black   */
  18463. +    0x1000
  18464. +};
  18465. +
  18466. +static const unsigned long palette_8[] = {
  18467. +    0x1000,
  18468. +    0x1111,
  18469. +    0x1222,
  18470. +    0x1333,
  18471. +    0x1400,
  18472. +    0x1511,
  18473. +    0x1622,
  18474. +    0x1733,
  18475. +    0x1004,
  18476. +    0x1115,
  18477. +    0x1226,
  18478. +    0x1337,
  18479. +    0x1404,
  18480. +    0x1515,
  18481. +    0x1626,
  18482. +    0x1737,
  18483. +    0x1000,        /* Black   */
  18484. +    0x1000,        /* Black   */
  18485. +    0x1000
  18486. +};
  18487. +
  18488. +static const unsigned long *default_palette_entries = palette_4;
  18489. +
  18490. +static const unsigned char color_1[] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 };
  18491. +static const unsigned char color_4[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 };
  18492. +static const unsigned char color_8[] = {0x00, 0x18, 0x60, 0x78, 0x84, 0x9C, 0xE4, 0xFC,
  18493. +                    0x00, 0x1B, 0x63, 0x7B, 0x87, 0x9F, 0xE7, 0xFF};
  18494. +static const unsigned char *color_table = color_4;
  18495. +
  18496. +/*===================================================================================*/
  18497. +
  18498. +#ifdef CONFIG_SERIAL_ECHO
  18499. +#include "console/serialecho.c"
  18500. +#endif
  18501. +
  18502. +#ifdef DEBUG
  18503. +static int vcd_validate (struct con_struct *vcd, const char *msg)
  18504. +{
  18505. +    unsigned long old_origin, old_pos, w = 0;
  18506. +
  18507. +    old_origin = vcd->screen.origin;
  18508. +    if (vcd->screen.origin < 0x01f80000 || vcd->screen.origin > 0x02000000) {
  18509. +    vcd->screen.origin = 0x02000000;
  18510. +    w = 1;
  18511. +    }
  18512. +    old_pos = vcd->screen.pos;
  18513. +    if (vcd->screen.pos < 0x01f80000 || vcd->screen.pos > 0x02080000) {
  18514. +    vcd->screen.pos = 0x02000000;
  18515. +    w = 1;
  18516. +    }
  18517. +    if (w)
  18518. +    printk ("*** CONSOLE ERROR: %s: (%p): origin = %08lX pos = %08lX ***\n", msg, vcd, old_origin, old_pos);
  18519. +    return w;
  18520. +}
  18521. +#endif
  18522. +
  18523. +void no_scroll(char *str, int *ints)
  18524. +{
  18525. +}
  18526. +
  18527. +static unsigned long __real_origin;
  18528. +static unsigned long __origin;        /* Offset of currently displayed screen */
  18529. +
  18530. +static void __set_origin(unsigned long offset)
  18531. +{
  18532. +    unsigned long flags;
  18533. +
  18534. +    clear_selection ();
  18535. +
  18536. +    save_flags_cli (flags);
  18537. +    __origin = offset;
  18538. +
  18539. +    memc_write(0, offset >> 2);
  18540. +    memc_write(1, 0);
  18541. +    memc_write(2, vtdata.screen.memmask >> 2);
  18542. +    restore_flags(flags);
  18543. +}
  18544. +
  18545. +void scrollback(int lines)
  18546. +{
  18547. +}
  18548. +
  18549. +void scrollfront(int lines)
  18550. +{
  18551. +}
  18552. +
  18553. +static void set_origin (const struct vt * const vt)
  18554. +{
  18555. +    if (vtdata.fgconsole != vt || vt->vtd->vc_mode == KD_GRAPHICS)
  18556. +    return;
  18557. +    __real_origin = vt->vcd->screen.origin - vtdata.screen.memstart;
  18558. +    if (__real_origin > vtdata.screen.memmask)
  18559. +    __real_origin -= vtdata.screen.memmask + 1;
  18560. +    __set_origin(__real_origin);
  18561. +}
  18562. +
  18563. +/* -------------------------------------------------------------------------------
  18564. + * Cursor
  18565. + * ------------------------------------------------------------------------------- */
  18566. +
  18567. +static char cursor_on = 0;
  18568. +static unsigned long cp;
  18569. +
  18570. +static void put_cursor(char on_off,unsigned long newcp)
  18571. +{
  18572. +    static char con;
  18573. +    unsigned long cp_p = cp;
  18574. +    int c = vtdata.screen.bytespercharh == 8 ? color_table[15] : 0x11 * color_table[15];
  18575. +    int i;
  18576. +
  18577. +    if (vtdata.fgconsole->vtd->vc_mode == KD_GRAPHICS)
  18578. +    return;
  18579. +
  18580. +    cp = newcp;
  18581. +
  18582. +    if (con != on_off) {
  18583. +    if (cp_p != -1)
  18584. +        for (i = 0; i < vtdata.screen.bytespercharh; i++)
  18585. +        ((unsigned char*)cp_p)[i]^=c;
  18586. +    con = on_off;
  18587. +    }
  18588. +}
  18589. +
  18590. +static void vsync_irq(int irq, void *dev_id, struct pt_regs *regs)
  18591. +{
  18592. +    static char cursor_flash;
  18593. +
  18594. +    if(++cursor_flash==16) {
  18595. +    cursor_flash=0;
  18596. +    cursor_on = cursor_on ? 0 : 1;
  18597. +    if (vtdata.fgconsole->vcd->screen.cursoron > 0)
  18598. +        put_cursor(cursor_on,cp);
  18599. +    }
  18600. +}
  18601. +
  18602. +static void hide_cursor(void)
  18603. +{
  18604. +    put_cursor (0, -1);
  18605. +}
  18606. +
  18607. +static void set_cursor (const struct vt * const vt)
  18608. +{
  18609. +    unsigned long flags;
  18610. +
  18611. +    if (vt != vtdata.fgconsole || vt->vtd->vc_mode == KD_GRAPHICS)
  18612. +    return;
  18613. +
  18614. +    if(__real_origin != __origin)
  18615. +    __set_origin (__real_origin);
  18616. +
  18617. +    save_flags_cli (flags);
  18618. +    if (vt->vcd->deccm) {
  18619. +#ifdef DEBUG
  18620. +        vcd_validate (vt->vcd, "set_cursor");
  18621. +#endif
  18622. +    cp = vt->vcd->screen.pos + vtdata.numcolumns *
  18623. +            vtdata.screen.bytespercharh * (vtdata.screen.bytespercharv - 1);
  18624. +    } else
  18625. +    hide_cursor();
  18626. +    restore_flags(flags);
  18627. +}
  18628. +
  18629. +static void vcd_removecursors (const struct vt *vt)
  18630. +{
  18631. +    unsigned long flags;
  18632. +
  18633. +    save_flags_cli (flags);
  18634. +
  18635. +    if (--vt->vcd->screen.cursoron == 0 && vtdata.fgconsole == vt)
  18636. +    put_cursor (0, cp);
  18637. +
  18638. +    restore_flags (flags);
  18639. +}
  18640. +
  18641. +static void vcd_restorecursors(const struct vt *vt)
  18642. +{
  18643. +    unsigned long flags;
  18644. +
  18645. +    save_flags_cli (flags);
  18646. +
  18647. +    if (++vt->vcd->screen.cursoron == 1 && cursor_on && vtdata.fgconsole == vt)
  18648. +    put_cursor (1, cp);
  18649. +
  18650. +    restore_flags (flags);
  18651. +}
  18652. +
  18653. +/* -----------------------------------------------------------------------------------------
  18654. + * VC stuff
  18655. + * ----------------------------------------------------------------------------------------- */
  18656. +/*
  18657. + * gotoxy() must verify all boundaries, because the arguments
  18658. + * might also be negative. If a given position is out of
  18659. + * bounds, the cursor is placed at the nearest margin.
  18660. + */
  18661. +static void gotoxy (const struct vt * const vt, int new_x, int new_y)
  18662. +{
  18663. +    struct con_struct *vcd = vt->vcd;
  18664. +    int min_y, max_y;
  18665. +
  18666. +    if (new_x < 0)
  18667. +    vcd->curstate.x = 0;
  18668. +    else
  18669. +    if (new_x >= vtdata.numcolumns)
  18670. +    vcd->curstate.x = vtdata.numcolumns - 1;
  18671. +    else
  18672. +    vcd->curstate.x = new_x;
  18673. +
  18674. +    if (vcd->decom) {
  18675. +    new_y += vcd->top;
  18676. +    min_y = vcd->top;
  18677. +    max_y = vcd->bottom;
  18678. +    } else {
  18679. +    min_y = 0;
  18680. +    max_y = vtdata.numrows;
  18681. +    }
  18682. +
  18683. +    if (new_y < min_y)
  18684. +    vcd->curstate.y = min_y;
  18685. +    else if (new_y >= max_y)
  18686. +    vcd->curstate.y = max_y - 1;
  18687. +    else
  18688. +    vcd->curstate.y = new_y;
  18689. +
  18690. +    vcd->screen.pos = vcd->screen.origin +
  18691. +            vcd->curstate.y * vtdata.screen.sizerow +
  18692. +            vcd->curstate.x * vtdata.screen.bytespercharh;
  18693. +    vcd->buffer.pos = vcd->curstate.y * vtdata.buffer.sizerow +
  18694. +                vcd->curstate.x;
  18695. +    vcd->need_wrap = 0;
  18696. +#ifdef DEBUG
  18697. +    vcd_validate (vcd, "gotoxy");
  18698. +#endif
  18699. +}
  18700. +
  18701. +/* for absolute user moves, when decom is set */
  18702. +static void gotoxay (const struct vt * const vt, int new_x, int new_y)
  18703. +{
  18704. +    gotoxy(vt, new_x, vt->vcd->decom ? (vt->vcd->top+new_y) : new_y);
  18705. +}
  18706. +
  18707. +/* --------------------------------------------------------------------------------
  18708. + * Screen scrolling
  18709. + * -------------------------------------------------------------------------------- */
  18710. +
  18711. +static void scrollup (const struct vt * const vt, unsigned int t, unsigned int b, unsigned int l)
  18712. +{
  18713. +    struct con_struct *vcd = vt->vcd;
  18714. +    int old_top, new_top, old_end, new_end, displayed;
  18715. +
  18716. +    if (b > vtdata.numrows || t >= b || l == 0)
  18717. +    return;
  18718. +
  18719. +    displayed = vtdata.fgconsole == vt;
  18720. +
  18721. +    if (t == 0 && b == vtdata.numrows && displayed) {
  18722. +    /*
  18723. +     * we can hardware scroll...
  18724. +     */
  18725. +    memsetl ((void *)(vcd->screen.origin + vtdata.screen.sizerow * vtdata.numrows),
  18726. +        vcd->cached_backcolwrd, l * vtdata.screen.sizerow);
  18727. +
  18728. +    vcd->screen.pos -= vcd->screen.origin;
  18729. +    vcd->screen.origin += l * vtdata.screen.sizerow;
  18730. +    if (vcd->screen.origin >= vtdata.screen.memend)
  18731. +        vcd->screen.origin = vcd->screen.origin - vtdata.screen.memend + vtdata.screen.memstart;
  18732. +    vcd->screen.pos += vcd->screen.origin;
  18733. +    set_origin (vt);
  18734. +    displayed = 0;
  18735. +    }
  18736. +    
  18737. +    old_top = t;
  18738. +    new_top = old_top + l;
  18739. +    old_end = b - l;
  18740. +    new_end = b;
  18741. +
  18742. +    if (new_top < new_end) { /* we have something to move */
  18743. +    memmove (vcd->buffer.buffer + old_top * vtdata.buffer.sizerow,
  18744. +         vcd->buffer.buffer + new_top * vtdata.buffer.sizerow,
  18745. +         (new_end - new_top) * vtdata.buffer.sizerow * 4);
  18746. +
  18747. +    if (displayed)
  18748. +        memmove ((void *)(vcd->screen.origin + old_top * vtdata.screen.sizerow),
  18749. +             (void *)(vcd->screen.origin + new_top * vtdata.screen.sizerow),
  18750. +             (new_end - new_top) * vtdata.screen.sizerow);
  18751. +    }
  18752. +
  18753. +    if (old_end < new_end) {
  18754. +    if (old_end < old_top)
  18755. +        old_end = old_top;
  18756. +    memsetl (vcd->buffer.buffer + old_end * vtdata.buffer.sizerow,
  18757. +            vcd->combined_state | 32, (new_end - old_end) * vtdata.buffer.sizerow * 4);
  18758. +
  18759. +    if (displayed)
  18760. +        memsetl ((void *)(vcd->screen.origin + old_end * vtdata.screen.sizerow),
  18761. +            vcd->cached_backcolwrd, (new_end - old_end) * vtdata.screen.sizerow);
  18762. +    }
  18763. +}
  18764. +
  18765. +static void scrolldown (const struct vt * const vt, unsigned int t, unsigned int b, unsigned int l)
  18766. +{
  18767. +    struct con_struct *vcd = vt->vcd;
  18768. +    int old_top, new_top, old_end, new_end, displayed;
  18769. +
  18770. +    if (b > vtdata.numrows || t >= b)
  18771. +    return;
  18772. +
  18773. +    displayed = vtdata.fgconsole == vt;
  18774. +
  18775. +    if (t == 0 && b == vtdata.numrows && displayed) {
  18776. +    /*
  18777. +     * we can hardware scroll...
  18778. +     */
  18779. +    vcd->screen.pos -= vcd->screen.origin;
  18780. +    vcd->screen.origin -= l * vtdata.screen.sizerow;
  18781. +    if (vcd->screen.origin < vtdata.screen.memstart)
  18782. +        vcd->screen.origin = vcd->screen.origin - vtdata.screen.memstart + vtdata.screen.memend;
  18783. +    vcd->screen.pos += vcd->screen.origin;
  18784. +    memsetl ((void *)vcd->screen.origin, vcd->cached_backcolwrd, l * vtdata.screen.sizerow);
  18785. +    set_origin (vt);
  18786. +    displayed = 0;
  18787. +    }
  18788. +
  18789. +    new_top = t;
  18790. +    old_top = new_top + l;
  18791. +    new_end = b - l;
  18792. +    old_end = b;
  18793. +
  18794. +    if (new_top < new_end) { /* we have something to move */
  18795. +    memmove (vcd->buffer.buffer + old_top * vtdata.buffer.sizerow,
  18796. +         vcd->buffer.buffer + new_top * vtdata.buffer.sizerow,
  18797. +         (new_end - new_top) * vtdata.buffer.sizerow * 4);
  18798. +
  18799. +    if (displayed)
  18800. +        memmove ((void *)(vcd->screen.origin + old_top * vtdata.screen.sizerow),
  18801. +             (void *)(vcd->screen.origin + new_top * vtdata.screen.sizerow),
  18802. +             (new_end - new_top) * vtdata.screen.sizerow);
  18803. +    }
  18804. +
  18805. +    if (new_top < old_top) { /* we have something to clear */
  18806. +    if (old_top > old_end)
  18807. +        old_top = old_end;
  18808. +    memsetl (vcd->buffer.buffer + new_top * vtdata.buffer.sizerow,
  18809. +            vcd->combined_state | 32, (old_top - new_top) * vtdata.buffer.sizerow * 4);
  18810. +
  18811. +    if (displayed)
  18812. +        memsetl ((void *)(vcd->screen.origin + new_top * vtdata.screen.sizerow),
  18813. +                vcd->cached_backcolwrd, (old_top - new_top) * vtdata.screen.sizerow);
  18814. +    }
  18815. +}
  18816. +
  18817. +static void csi_J (const struct vt * const vt, int vpar)
  18818. +{
  18819. +    unsigned char endx, endy;
  18820. +    unsigned char startx, starty;
  18821. +
  18822. +    switch (vpar) {
  18823. +    case 0: /* erase from cursor to bottom of screen (including char at (x, y) */
  18824. +    startx = vt->vcd->curstate.x;
  18825. +    starty = vt->vcd->curstate.y;
  18826. +    endx   = vtdata.numcolumns - 1;
  18827. +    endy   = vtdata.numrows - 1;
  18828. +    break;
  18829. +    case 1: /* erase from top of screen to cursor (including char at (x, y) */
  18830. +    startx = 0;
  18831. +    starty = 0;
  18832. +    endx   = vt->vcd->curstate.x;
  18833. +    endy   = vt->vcd->curstate.y;
  18834. +    break;
  18835. +    case 2: /* erase entire screen */
  18836. +    startx = 0;
  18837. +    starty = 0;
  18838. +    endx   = vtdata.numcolumns - 1;
  18839. +    endy   = vtdata.numrows - 1;
  18840. +#if TODO
  18841. +    origin = video_mem_base;
  18842. +    set_origin (currcons);
  18843. +    gotoxy (currcons, x, y);
  18844. +#endif
  18845. +    break;
  18846. +    default:
  18847. +    return;
  18848. +    }
  18849. +    ll_erase (vt, startx, starty, endx, endy);
  18850. +    /*vt->vcd->need_wrap = 0; why? We don't move the cursor... */
  18851. +}
  18852. +
  18853. +static void csi_K (const struct vt * const vt, int vpar)
  18854. +{
  18855. +    unsigned char endx;
  18856. +    unsigned char startx;
  18857. +
  18858. +    switch(vpar) {
  18859. +    case 0: /* erase from cursor to end of line */
  18860. +    startx = vt->vcd->curstate.x;
  18861. +    endx   = vtdata.numcolumns - 1;
  18862. +    break;
  18863. +    case 1: /* erase from beginning of line to cursor */
  18864. +    startx = 0;
  18865. +    endx   = vt->vcd->curstate.x;
  18866. +    break;
  18867. +    case 2: /* erase entire line */
  18868. +    startx = 0;
  18869. +    endx   = vtdata.numcolumns - 1;
  18870. +    break;
  18871. +    default:
  18872. +    return;
  18873. +    }
  18874. +    ll_erase (vt, startx, vt->vcd->curstate.y, endx, vt->vcd->curstate.y);
  18875. +    /*vt->vcd->need_wrap = 0; why? We don't move the cursor... */
  18876. +}
  18877. +
  18878. +static void csi_X (const struct vt * const vt, int vpar) /* erase the following vpar positions */
  18879. +{                             /* not vt100? */
  18880. +    unsigned char countx, county;
  18881. +    unsigned char startx, starty;
  18882. +
  18883. +    if (!vpar)
  18884. +    vpar++;
  18885. +
  18886. +    startx = vt->vcd->curstate.x;
  18887. +    starty = vt->vcd->curstate.y;
  18888. +    countx = 0;
  18889. +    county = 0;
  18890. +#if TODO
  18891. +    ll_erase(currcons,startx,starty,countx,county);
  18892. +#endif
  18893. +    /*vt->vcd->need_wrap = 0; why? We don't move the cursor... */
  18894. +}
  18895. +
  18896. +static void update_attr (const struct vt * const vt)
  18897. +{
  18898. +    vt->vcd->combined_state = (vt->vcd->curstate.flags << 24) |
  18899. +                  (vt->vcd->curstate.backcol << 16) |
  18900. +                  (vt->vcd->curstate.forecol << 8);
  18901. +    switch (vtdata.screen.bitsperpix) {
  18902. +    case 1:
  18903. +    vt->vcd->cached_backcolwrd = 0;
  18904. +    break;
  18905. +    default:
  18906. +    case 4:
  18907. +    vt->vcd->cached_backcolwrd = 0x11111111 * vt->vcd->curstate.backcol;
  18908. +    break;
  18909. +    case 8:
  18910. +    vt->vcd->cached_backcolwrd = 0x01010101 * vt->vcd->curstate.backcol;
  18911. +    break;
  18912. +    }
  18913. +}
  18914. +
  18915. +static void default_attr (const struct vt * const vt)
  18916. +{
  18917. +    vt->vcd->curstate.flags &= ~(FLG_INVERSE|FLG_FLASH|FLG_UNDERLINE|FLG_ITALIC|FLG_BOLD);
  18918. +    vt->vcd->curstate.forecol = vt->vcd->def_forecol;
  18919. +    vt->vcd->curstate.backcol = vt->vcd->def_backcol;
  18920. +}
  18921. +
  18922. +static int csi_m (const struct vt * const vt)
  18923. +{
  18924. +    struct con_struct *vcd = vt->vcd;
  18925. +    int i;
  18926. +
  18927. +    for (i = 0; i <= vcd->npar; i++) {
  18928. +    switch (vcd->par[i]) {
  18929. +    case 0:
  18930. +        default_attr (vt);
  18931. +        break;
  18932. +    case 1:
  18933. +        vcd->curstate.flags |= FLG_BOLD;
  18934. +        break;    /* Bold */
  18935. +    case 2:
  18936. +        vcd->curstate.flags &= ~FLG_BOLD;
  18937. +        break;    /* Feint */
  18938. +    case 3:
  18939. +        vcd->curstate.flags |= FLG_ITALIC;
  18940. +        break;    /* Italic */
  18941. +    case 4:
  18942. +        vcd->curstate.flags |= FLG_UNDERLINE;
  18943. +        break;    /* Underline */
  18944. +    case 5:
  18945. +    case 6:
  18946. +        vcd->curstate.flags |= FLG_FLASH;
  18947. +        break;    /* Flash */
  18948. +    case 7:
  18949. +        vcd->curstate.flags |= FLG_INVERSE;
  18950. +        break;    /* Inverse chars */
  18951. +
  18952. +    case 10:
  18953. +        /* ANSI X3.64-1979 (SCO-ish?)
  18954. +         * Select primary font, don't display
  18955. +         * control chars if defined, don't set
  18956. +         * bit 8 on output.
  18957. +         */
  18958. +        vcd->translate = set_translate(vcd->curstate.flags & FLG_CHRSET
  18959. +                ? vcd->curstate.G1_charset
  18960. +                : vcd->curstate.G0_charset);
  18961. +        vcd->disp_ctrl = 0;
  18962. +        vcd->toggle_meta = 0;
  18963. +        return 1;
  18964. +    case 11:
  18965. +        /* ANSI X3.64-1979 (SCO-ish?)
  18966. +         * Select first alternate font, let's
  18967. +         * chars < 32 be displayed as ROM chars.
  18968. +         */
  18969. +        vcd->translate = set_translate(IBMPC_MAP);
  18970. +        vcd->disp_ctrl = 1;
  18971. +        vcd->toggle_meta = 0;
  18972. +        return 1;
  18973. +    case 12:
  18974. +        /* ANSI X3.64-1979 (SCO-ish?)
  18975. +         * Select second alternate font, toggle
  18976. +         * high bit before displaying as ROM char.
  18977. +         */
  18978. +        vcd->translate = set_translate(IBMPC_MAP);
  18979. +        vcd->disp_ctrl = 1;
  18980. +        vcd->toggle_meta = 1;
  18981. +        return 1;
  18982. +    case 21:
  18983. +    case 22:
  18984. +        vcd->curstate.flags &= ~FLG_BOLD;
  18985. +        break;
  18986. +    case 24:
  18987. +        vcd->curstate.flags &= ~FLG_UNDERLINE;
  18988. +        break;
  18989. +    case 25:
  18990. +        vcd->curstate.flags &= ~FLG_FLASH;
  18991. +        break;
  18992. +    case 27:
  18993. +        vcd->curstate.flags &= ~FLG_INVERSE;
  18994. +        break;
  18995. +    case 30:
  18996. +    case 31:
  18997. +    case 32:
  18998. +    case 33:
  18999. +    case 34:
  19000. +    case 35:
  19001. +    case 36:
  19002. +    case 37:
  19003. +        vcd->curstate.forecol = color_table[vcd->par[i]-30];
  19004. +        break;                        /* Foreground colour */
  19005. +    case 38:
  19006. +        vcd->curstate.forecol = vcd->def_forecol;
  19007. +        vcd->curstate.flags &= ~FLG_UNDERLINE;
  19008. +        break;
  19009. +    case 39:
  19010. +        vcd->curstate.forecol = vcd->def_forecol;
  19011. +        vcd->curstate.flags &= ~FLG_UNDERLINE;
  19012. +        break;                        /* Default foreground colour */
  19013. +    case 40:
  19014. +    case 41:
  19015. +    case 42:
  19016. +    case 43:
  19017. +    case 44:
  19018. +    case 45:
  19019. +    case 46:
  19020. +    case 47:
  19021. +        vcd->curstate.backcol = color_table[vcd->par[i]-40];
  19022. +        break;                        /* Background colour */
  19023. +    case 49:
  19024. +        vcd->curstate.backcol = vcd->def_backcol;
  19025. +        break;                        /* Default background colour */
  19026. +    }
  19027. +    }
  19028. +    update_attr (vt);
  19029. +    return 0;
  19030. +}
  19031. +
  19032. +static void respond_string (char *p, struct tty_struct *tty)
  19033. +{
  19034. +    while (*p)
  19035. +    tty_insert_flip_char (tty, *p++, 0);
  19036. +    tty_schedule_flip (tty);
  19037. +}
  19038. +
  19039. +static void cursor_report (const struct vt *vt)
  19040. +{
  19041. +    char buf[40];
  19042. +
  19043. +    sprintf (buf, "\033[%d;%dR", vt->vcd->curstate.y + (vt->vcd->decom ? vt->vcd->top + 1 : 1),
  19044. +                     vt->vcd->curstate.x + 1);
  19045. +    respond_string (buf, *vt->tty);
  19046. +}
  19047. +
  19048. +static void status_report (struct tty_struct *tty)
  19049. +{
  19050. +    respond_string ("\033[0n", tty);
  19051. +}
  19052. +
  19053. +static void respond_ID (struct tty_struct *tty)
  19054. +{
  19055. +    respond_string(VT102ID, tty);
  19056. +}
  19057. +
  19058. +void mouse_report (struct tty_struct *tty, int butt, int mrx, int mry)
  19059. +{
  19060. +    char buf[8];
  19061. +
  19062. +    sprintf (buf,"\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
  19063. +    (char)('!'+mry));
  19064. +    respond_string(buf, tty);
  19065. +}
  19066. +
  19067. +/* invoked by ioctl(TIOCLINUX) */
  19068. +int mouse_reporting (void)
  19069. +{
  19070. +    return vtdata.fgconsole->vcd->report_mouse;
  19071. +}
  19072. +
  19073. +static inline unsigned long *bufferpos (const struct vt * const vt, int offset)
  19074. +{
  19075. +    return vt->vcd->buffer.buffer + offset;
  19076. +}
  19077. +
  19078. +static inline unsigned long screenpos (const struct vt * const vt, int offset)
  19079. +{
  19080. +    int hx, hy;
  19081. +
  19082. +    hx = offset % vtdata.numcolumns;
  19083. +    hy = offset / vtdata.numcolumns;
  19084. +    return vt->vcd->screen.origin + hy * vtdata.screen.sizerow + hx * vtdata.screen.bytespercharh;
  19085. +}
  19086. +
  19087. +void invert_screen (const struct vt * const vt, int offset, int count)
  19088. +{
  19089. +    int i;
  19090. +    unsigned long *buffer = vt->vcd->buffer.buffer + offset;
  19091. +    unsigned long p, pp;
  19092. +
  19093. +    for (i = 0; i <= count; i++)
  19094. +    buffer[i] ^= FLG_INVERSE << 24;
  19095. +
  19096. +    if (vt == vtdata.fgconsole) {
  19097. +    int hx, hy, hex, hey;
  19098. +
  19099. +    hx = offset % vtdata.numcolumns;
  19100. +    hy = offset / vtdata.numcolumns;
  19101. +    hex = (offset + count) % vtdata.numcolumns;
  19102. +    hey = (offset + count) / vtdata.numcolumns;
  19103. +
  19104. +    p = vt->vcd->screen.origin + hy * vtdata.screen.sizerow;
  19105. +    for (;hy <= hey; hy ++) {
  19106. +        pp = p + hx * vtdata.screen.bytespercharh;
  19107. +        for (; hx < ((hy == hey) ? hex + 1 : vtdata.numcolumns); hx ++) {
  19108. +        ll_write_char (pp, *buffer++);
  19109. +        pp += vtdata.screen.bytespercharh;
  19110. +        }
  19111. +        hx = 0;
  19112. +        p += vtdata.screen.sizerow;
  19113. +    }    
  19114. +    }
  19115. +}
  19116. +
  19117. +void complement_pos (const struct vt * const vt, int offset)
  19118. +{
  19119. +    static unsigned long p = 0;
  19120. +    static unsigned long old = 0;
  19121. +    unsigned long complement = 0;
  19122. +
  19123. +    switch (vtdata.screen.bitsperpix) {
  19124. +    case 4:
  19125. +    complement = 0x00070700;
  19126. +    break;
  19127. +    case 8:
  19128. +    complement = 0x00fcfc00;
  19129. +    break;
  19130. +    }
  19131. +
  19132. +    if (p)
  19133. +    ll_write_char (p, old);
  19134. +    if (offset == -1)
  19135. +    p = 0;
  19136. +    else {
  19137. +    p = screenpos (vt, offset);
  19138. +    old = vt->vcd->buffer.buffer[offset];
  19139. +    ll_write_char (p, old ^ complement);
  19140. +    }
  19141. +}
  19142. +
  19143. +unsigned long screen_word (const struct vt * const vt, int offset)
  19144. +{
  19145. +    return *bufferpos (vt, offset);
  19146. +}
  19147. +
  19148. +int scrw2glyph (unsigned long scr_word)
  19149. +{
  19150. +    return scr_word & 255;
  19151. +}
  19152. +
  19153. +unsigned long *screen_pos (const struct vt * const vt, int offset)
  19154. +{
  19155. +    return bufferpos (vt, offset);
  19156. +}
  19157. +
  19158. +void getconsxy (const struct vt * const vt, char *p)
  19159. +{
  19160. +    p[0] = vt->vcd->curstate.x;
  19161. +    p[1] = vt->vcd->curstate.y;
  19162. +}
  19163. +
  19164. +void putconsxy (const struct vt * const vt, char *p)
  19165. +{
  19166. +    gotoxy (vt, p[0], p[1]);
  19167. +    set_cursor (vt);
  19168. +}
  19169. +
  19170. +static void set_mode (const struct vt * const vt, int on_off)
  19171. +{
  19172. +    struct con_struct *vcd = vt->vcd;
  19173. +    int i;
  19174. +
  19175. +    for (i = 0; i <= vcd->npar; i++)
  19176. +    if (vcd->ques)
  19177. +        switch(vcd->par[i]) {    /* DEC private modes set/reset */
  19178. +        case 1:            /* Cursor keys send ^[Ox/^[[x */
  19179. +        if (on_off)
  19180. +            set_kbd(decckm);
  19181. +        else
  19182. +            clr_kbd(decckm);
  19183. +        break;
  19184. +        case 3:         /* 80/132 mode switch unimplemented */
  19185. +        vcd->deccolm = on_off;
  19186. +        csi_J (vt, 2);
  19187. +        gotoxy (vt, 0, 0);
  19188. +        break;
  19189. +        case 5:        /* Inverted screen on/off */
  19190. +        if (vcd->decscnm != on_off) {
  19191. +            vcd->decscnm = on_off;
  19192. +            invert_screen (vt, 0, vtdata.screen.totsize);
  19193. +            update_attr (vt);
  19194. +        }
  19195. +        break;
  19196. +        case 6:        /* Origin relative/absolute */
  19197. +        vcd->decom = on_off;
  19198. +        gotoxay (vt, 0, 0);
  19199. +        break;
  19200. +        case 7:        /* Autowrap on/off */
  19201. +        vcd->decawm = on_off;
  19202. +        break;
  19203. +        case 8:        /* Autorepeat on/off */
  19204. +        if (on_off)
  19205. +            set_kbd(decarm);
  19206. +        else
  19207. +            clr_kbd(decarm);
  19208. +        break;
  19209. +        case 9:
  19210. +        vcd->report_mouse = on_off ? 1 : 0;
  19211. +        break;
  19212. +        case 25:        /* Cursor on/off */
  19213. +        vcd->deccm = on_off;
  19214. +        set_cursor (vt);
  19215. +        break;
  19216. +        case 1000:
  19217. +        vcd->report_mouse = on_off ? 2 : 0;
  19218. +        break;
  19219. +        }
  19220. +    else
  19221. +        switch(vcd->par[i]) {    /* ANSI modes set/reset */
  19222. +        case 3:            /* Monitor (display ctrls) */
  19223. +        vcd->disp_ctrl = on_off;
  19224. +        break;
  19225. +        case 4:            /* Insert mode on/off */
  19226. +        vcd->decim = on_off;
  19227. +        break;
  19228. +        case 20:            /* Lf, Enter = CrLf/Lf */
  19229. +        if (on_off)
  19230. +            set_kbd(lnm);
  19231. +        else
  19232. +            clr_kbd(lnm);
  19233. +        break;
  19234. +        }
  19235. +}
  19236. +
  19237. +static void setterm_command (const struct vt * const vt)
  19238. +{
  19239. +    switch (vt->vcd->par[0]) {
  19240. +    case 1: /* Set colour for underline mode (implemented as an underline) */
  19241. +    break;
  19242. +    case 2: /* set colour for half intensity mode (implemented as half) */
  19243. +    break;
  19244. +    case 8:
  19245. +    vt->vcd->def_forecol = vt->vcd->curstate.forecol;
  19246. +    vt->vcd->def_backcol = vt->vcd->curstate.backcol;
  19247. +    break;
  19248. +    case 9:
  19249. +    vtdata.screen.blankinterval = ((vt->vcd->par[1] < 60) ? vt->vcd->par[1] : 60) * 60 * HZ;
  19250. +    vt_pokeblankedconsole ();
  19251. +    break;
  19252. +    }
  19253. +}
  19254. +
  19255. +static void insert_char (const struct vt * const vt)
  19256. +{
  19257. +    register unsigned char *c,*cc;
  19258. +    register unsigned int row;
  19259. +    register int mcol, bpr, n = 1;
  19260. +
  19261. +    /*
  19262. +     * Should really convert this to memmoves...
  19263. +     */
  19264. +    if (vtdata.fgconsole == vt) {
  19265. +    c = (unsigned char *)vt->vcd->screen.pos;
  19266. +    cc = (unsigned char *)c + vtdata.screen.bytespercharh * n;
  19267. +    mcol = (vtdata.numcolumns - vt->vcd->curstate.x - n) * vtdata.screen.bytespercharh - 1;
  19268. +    bpr = vtdata.numcolumns * vtdata.screen.bytespercharh;
  19269. +
  19270. +    for (row = vtdata.screen.bytespercharv; row > 0; row --) {
  19271. +        register int col;
  19272. +        for(col = mcol; col >= 0; col--)
  19273. +        cc[col] = c[col];
  19274. +        for (col = n * vtdata.screen.bytespercharh - 1; col >= 0; col --)
  19275. +        c[col] = 0x11 * vt->vcd->curstate.backcol;
  19276. +        c += bpr;
  19277. +        cc += bpr;
  19278. +    }
  19279. +    }
  19280. +
  19281. +    if (vt->vcd->curstate.x < vtdata.numcolumns - n)
  19282. +    memmove ((void *)vt->vcd->buffer.buffer + (vt->vcd->curstate.y * vtdata.numcolumns + vt->vcd->curstate.x + n),
  19283. +         (void *)vt->vcd->buffer.buffer + (vt->vcd->curstate.y * vtdata.numcolumns + vt->vcd->curstate.x),
  19284. +         (vtdata.numcolumns - vt->vcd->curstate.x - n) * 4);
  19285. +    memsetl ((void *)vt->vcd->buffer.buffer + (vt->vcd->curstate.y * vtdata.numcolumns + vt->vcd->curstate.x),
  19286. +        vt->vcd->combined_state | 32, n * 4);
  19287. +}
  19288. +
  19289. +static inline void insert_line (const struct vt * const vt, int n)
  19290. +{
  19291. +    scrolldown (vt, vt->vcd->curstate.y, vt->vcd->bottom, n);
  19292. +/*  vt->vcd->need_wrap = 0; why? We haven't moved the cursor. */
  19293. +}
  19294. +
  19295. +static void delete_char (const struct vt * const vt)
  19296. +{
  19297. +    register unsigned char *c, *cc;
  19298. +    register unsigned int  row;
  19299. +    register int mcol, bpr, n = 1;
  19300. +
  19301. +    /*
  19302. +     * Should really convert this to memmoves...
  19303. +     */
  19304. +    if (vtdata.fgconsole == vt) {
  19305. +    c = (unsigned char *)vt->vcd->screen.pos;
  19306. +    cc = (unsigned char *)c + vtdata.screen.bytespercharh * n;
  19307. +    mcol = vtdata.screen.bytespercharh * (vtdata.numcolumns - vt->vcd->curstate.x - n);
  19308. +    bpr = vtdata.numcolumns * vtdata.screen.bytespercharh;
  19309. +
  19310. +    for (row = vtdata.screen.bytespercharv; row > 0; row --) {
  19311. +        register int col;
  19312. +        
  19313. +        for (col = 0; col < mcol; col++)
  19314. +        c[col] = cc[col];
  19315. +        for (; col < mcol + n * vtdata.screen.bytespercharh - 1; col ++)
  19316. +        c[col] = 0x11 * vt->vcd->curstate.backcol;
  19317. +        c += bpr;
  19318. +        cc += bpr;
  19319. +    }
  19320. +    }
  19321. +
  19322. +    if (vt->vcd->curstate.x != vtdata.numcolumns - 1)
  19323. +    memmove ((void *)vt->vcd->buffer.buffer + (vt->vcd->curstate.y * vtdata.numcolumns + vt->vcd->curstate.x),
  19324. +         (void *)vt->vcd->buffer.buffer + (vt->vcd->curstate.y * vtdata.numcolumns + vt->vcd->curstate.x + n),
  19325. +         (vtdata.numcolumns - vt->vcd->curstate.x - n) * 4);
  19326. +    memsetl ((void *)vt->vcd->buffer.buffer + ((vt->vcd->curstate.y + 1) * vtdata.numcolumns - n),
  19327. +            vt->vcd->combined_state | 32, n * 4);
  19328. +}
  19329. +
  19330. +static void delete_line (const struct vt * const vt, int n)
  19331. +{
  19332. +    scrollup (vt, vt->vcd->curstate.y, vt->vcd->bottom, n);
  19333. +/*  vt->vcd->need_wrap = 0; why? we haven't moved the cursor. */
  19334. +}
  19335. +
  19336. +static void csi_at (const struct vt * const vt, int nr)
  19337. +{
  19338. +    if (nr > vtdata.numcolumns - vt->vcd->curstate.x)
  19339. +    nr = vtdata.numcolumns - vt->vcd->curstate.x;
  19340. +    else
  19341. +    if (!nr)
  19342. +    nr = 1;
  19343. +    while (nr--)
  19344. +    insert_char (vt);
  19345. +}
  19346. +
  19347. +static void csi_L (const struct vt * const vt, int nr)
  19348. +{
  19349. +    if (nr > vtdata.numrows - vt->vcd->curstate.y)
  19350. +    nr = vtdata.numrows - vt->vcd->curstate.y;
  19351. +    else
  19352. +    if (!nr)
  19353. +    nr = 1;
  19354. +    insert_line (vt, nr);
  19355. +}
  19356. +
  19357. +static void csi_P (const struct vt * const vt, int nr)
  19358. +{
  19359. +    if (nr > vtdata.numcolumns)
  19360. +    nr = vtdata.numcolumns;
  19361. +    else
  19362. +    if (!nr)
  19363. +    nr = 1;
  19364. +    while (nr--)
  19365. +    delete_char (vt);
  19366. +}
  19367. +
  19368. +static void csi_M (const struct vt * const vt, int nr)
  19369. +{
  19370. +    if (nr > vtdata.numrows)
  19371. +    nr = vtdata.numrows;
  19372. +    else
  19373. +    if (!nr)
  19374. +    nr = 1;
  19375. +    delete_line (vt, nr);
  19376. +}
  19377. +
  19378. +enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
  19379. +    EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
  19380. +    ESpalette };
  19381. +
  19382. +static void reset_terminal (const struct vt * const vt, int initialising)
  19383. +{
  19384. +    struct con_struct *vcd;
  19385. +
  19386. +    vcd = vt->vcd;
  19387. +
  19388. +    vcd->top            = 0;
  19389. +    vcd->bottom            = vtdata.numrows;
  19390. +    vcd->state            = ESnormal;
  19391. +    vcd->ques            = 0;
  19392. +    vcd->translate        = set_translate (LAT1_MAP);
  19393. +    vcd->curstate.G0_charset    = LAT1_MAP;
  19394. +    vcd->curstate.G1_charset    = GRAF_MAP;
  19395. +    vcd->curstate.flags        = 0;
  19396. +    vcd->need_wrap        = 0;
  19397. +    vcd->report_mouse        = 0;
  19398. +    vcd->utf            = 0;
  19399. +    vcd->utf_count        = 0;
  19400. +    vcd->disp_ctrl        = 0;
  19401. +    vcd->toggle_meta        = 0;
  19402. +    vcd->decscnm        = 0;
  19403. +    vcd->decom            = 0;
  19404. +    vcd->decawm            = 1;
  19405. +    vcd->deccm            = 1;
  19406. +    vcd->decim            = 0;
  19407. +    vcd->curstate.forecol    = color_table[7];
  19408. +    vcd->curstate.backcol    = color_table[0];
  19409. +    vcd->def_forecol        = color_table[7];
  19410. +    vcd->def_backcol        = color_table[0];
  19411. +    vcd->tab_stop[0]        = 0x01010100;
  19412. +    vcd->tab_stop[1]        =
  19413. +    vcd->tab_stop[2]        =
  19414. +    vcd->tab_stop[3]        =
  19415. +    vcd->tab_stop[4]        = 0x01010101;
  19416. +
  19417. +    set_kbd (decarm);
  19418. +    clr_kbd (decckm);
  19419. +    clr_kbd(kbdapplic);
  19420. +    clr_kbd(lnm);
  19421. +
  19422. +    vt->kbd->lockstate        = 0;
  19423. +    vt->kbd->ledmode        = LED_SHOW_FLAGS;
  19424. +    vt->kbd->ledflagstate    = vt->kbd->default_ledflagstate;
  19425. +    if (!initialising)
  19426. +    set_leds ();
  19427. +
  19428. +    if (vcd->screen.palette_entries) {
  19429. +    kfree (vcd->screen.palette_entries);
  19430. +    vcd->screen.palette_entries = 0;
  19431. +    }
  19432. +
  19433. +    gotoxy (vt, 0, 0);
  19434. +    vcd->savedstate = vcd->curstate;
  19435. +    update_attr (vt);
  19436. +
  19437. +    if (!initialising)
  19438. +    csi_J (vt, 2);
  19439. +}
  19440. +
  19441. +void console_print(const char *b)
  19442. +{
  19443. +    static int printing = 0;
  19444. +    struct vt *vt = vtdata.fgconsole;
  19445. +    struct con_struct * const vcd = vt->vcd;
  19446. +    unsigned long character, bufpos;
  19447. +    unsigned char c;
  19448. +
  19449. +#ifdef DEBUG
  19450. +    vcd_validate (vcd, "console_print entry");
  19451. +#endif
  19452. +
  19453. +    if (!printable || printing || vt->vtd->vc_mode == KD_GRAPHICS)
  19454. +    return;  /* console not yet initialized */
  19455. +    printing = 1;
  19456. +
  19457. +    if (!vt_allocated(vtdata.fgconsole)) {
  19458. +    /* impossible */
  19459. +      printk ("console_print: tty %d not allocated ??\n", vtdata.fgconsole->num);
  19460. +      printing = 0;
  19461. +      return;
  19462. +    }
  19463. +
  19464. +#ifdef CONFIG_SERIAL_ECHO
  19465. +    serial_echo_print (b);
  19466. +#endif
  19467. +
  19468. +    vcd_removecursors (vt);
  19469. +    bufpos = vcd->buffer.pos;
  19470. +
  19471. +    while ((c = *b++) != 0) {
  19472. +    if (c == 10 || c == 13 || vcd->need_wrap) {
  19473. +        vcd->screen.pos -= vcd->curstate.x * vtdata.screen.bytespercharh;
  19474. +        bufpos -= vcd->curstate.x;
  19475. +
  19476. +        vcd->need_wrap = vcd->curstate.x = 0;
  19477. +
  19478. +        if (vcd->curstate.y + 1 == vcd->bottom)
  19479. +        scrollup (vt, vt->vcd->top, vt->vcd->bottom, 1);
  19480. +        else
  19481. +        if (vcd->curstate.y < vtdata.numrows - 1) {
  19482. +        vcd->curstate.y ++;
  19483. +        vcd->screen.pos += vtdata.screen.sizerow;
  19484. +        bufpos += vtdata.buffer.sizerow;
  19485. +        }
  19486. +        if (c == 10 || c == 13)
  19487. +        continue;
  19488. +    }
  19489. +
  19490. +    vcd->buffer.buffer[bufpos] = character = vcd->combined_state | (c & 255);
  19491. +    ll_write_char (vcd->screen.pos, character);
  19492. +
  19493. +    if (vcd->curstate.x == vtdata.numcolumns - 1) {
  19494. +        vcd->need_wrap = 1;
  19495. +        continue;
  19496. +    }
  19497. +    vcd->curstate.x++;
  19498. +    vcd->screen.pos += vtdata.screen.bytespercharh;
  19499. +    bufpos ++;
  19500. +    }
  19501. +    vcd->buffer.pos = bufpos;
  19502. +    set_cursor (vt);
  19503. +    vcd_restorecursors (vt);
  19504. +
  19505. +    vt_pokeblankedconsole ();
  19506. +    printing = 0;
  19507. +#ifdef DEBUG
  19508. +    vcd_validate (vt->vcd, "console_print exit");
  19509. +#endif
  19510. +}
  19511. +#if 0
  19512. +static void con_setsize (unsigned long rows, unsigned long cols)
  19513. +{
  19514. +    vtdata.numcolumns     = cols;
  19515. +    vtdata.numrows        = rows;
  19516. +    vtdata.screen.sizerow = cols * vtdata.screen.bytespercharh * vtdata.screen.bytespercharv;
  19517. +    vtdata.screen.totsize = vtdata.screen.sizerow * rows;
  19518. +    vtdata.buffer.sizerow = cols;
  19519. +    vtdata.buffer.totsize = vtdata.buffer.sizerow * rows;
  19520. +}
  19521. +#endif
  19522. +
  19523. +void update_scrmem (const struct vt * const vt, int start, int length)
  19524. +{
  19525. +    unsigned long p, pp, sx, sy, ex, ey;
  19526. +    unsigned long *buffer;
  19527. +
  19528. +    sy = start / vtdata.numcolumns;
  19529. +    sx = start % vtdata.numcolumns;
  19530. +    length += start;
  19531. +    ey = length / vtdata.numcolumns;
  19532. +    ex = length % vtdata.numcolumns;
  19533. +
  19534. +    if (ey > vtdata.numrows)
  19535. +    ey = vtdata.numrows;
  19536. +
  19537. +    p = vt->vcd->screen.origin + sy * vtdata.screen.sizerow;
  19538. +    buffer = vt->vcd->buffer.buffer + start;
  19539. +
  19540. +    if (ey > sy) {
  19541. +    for (; sy < ey; sy++) {
  19542. +        pp = p + sx * vtdata.screen.bytespercharh;
  19543. +        for (; sx < vtdata.numcolumns; sx++) {
  19544. +        ll_write_char (pp, *buffer);
  19545. +        pp += vtdata.screen.bytespercharh;
  19546. +        buffer ++;
  19547. +        }
  19548. +        p += vtdata.screen.sizerow;
  19549. +        sx = 0;
  19550. +    }
  19551. +    }
  19552. +
  19553. +    if (ey == sy && ex) {
  19554. +    for (; sx < ex; sx++) {
  19555. +        ll_write_char (p, *buffer);
  19556. +        p += vtdata.screen.bytespercharh;
  19557. +        buffer ++;
  19558. +    }
  19559. +    }
  19560. +}
  19561. +
  19562. +void set_scrmem (const struct vt * const vt, long offset)
  19563. +{
  19564. +    unsigned long p, pp, my, by;
  19565. +    unsigned long *buffer;
  19566. +    int i;
  19567. +
  19568. +    p = vt->vcd->screen.origin;
  19569. +    buffer = vt->vcd->buffer.buffer;
  19570. +
  19571. +    by = vtdata.screen.sizerow;
  19572. +    for (my = vtdata.numrows; my > 0; my--) {
  19573. +    int mx, bx = vtdata.screen.bytespercharh;
  19574. +    pp = p;
  19575. +    mx = vtdata.numcolumns;
  19576. +    while (mx > 8) {
  19577. +        mx -= 8;
  19578. +        ll_write_char (pp, *buffer++); pp += bx;
  19579. +        ll_write_char (pp, *buffer++); pp += bx;
  19580. +        ll_write_char (pp, *buffer++); pp += bx;
  19581. +        ll_write_char (pp, *buffer++); pp += bx;
  19582. +        ll_write_char (pp, *buffer++); pp += bx;
  19583. +        ll_write_char (pp, *buffer++); pp += bx;
  19584. +        ll_write_char (pp, *buffer++); pp += bx;
  19585. +        ll_write_char (pp, *buffer++); pp += bx;
  19586. +    }
  19587. +    while (mx > 0) {
  19588. +        mx -= 1;
  19589. +        ll_write_char (pp, *buffer++); pp += bx;
  19590. +    }
  19591. +    p += by;
  19592. +    }
  19593. +    pp = vt->vcd->screen.origin + ((vtdata.screen.totsize + 0x7FFF) & PAGE_MASK);
  19594. +    while (p < pp) {
  19595. +    *(unsigned long *)p = 0;
  19596. +    p += 4;
  19597. +    }
  19598. +    if (!vt->vcd->screen.palette_entries || vt->vtd->vc_mode != KD_GRAPHICS)
  19599. +    for (i = 0; i < 17; i++)
  19600. +        vidc_write(i << 2, default_palette_entries[i]);
  19601. +    else
  19602. +    for (i = 0; i < 17; i++)
  19603. +        vidc_write(i << 2, vt->vcd->screen.palette_entries[i] & 0x1fff);
  19604. +}
  19605. +
  19606. +/*
  19607. + * PIO_FONT support
  19608. + */
  19609. +int con_set_font (char *arg)
  19610. +{
  19611. +    return -EINVAL;
  19612. +}
  19613. +
  19614. +int con_get_font (char *arg)
  19615. +{
  19616. +    return -EINVAL;
  19617. +}
  19618. +
  19619. +void con_reset_palette (const struct vt * const vt)
  19620. +{
  19621. +}
  19622. +
  19623. +void con_set_palette (const struct vt * const vt)
  19624. +{
  19625. +    int i;
  19626. +    if (vt->vtd->vc_mode == KD_GRAPHICS && vt->vcd->screen.palette_entries)
  19627. +    for (i = 0; i < 17; i++)
  19628. +        vidc_write (i << 2, vt->vcd->screen.palette_entries[i] & 0x1fff);
  19629. +    else
  19630. +    for (i = 0; i < 17; i++)
  19631. +        vidc_write (i << 2, default_palette_entries[i]);
  19632. +}
  19633. +
  19634. +/* == arm specific console code ============================================================== */
  19635. +
  19636. +int do_screendump(int arg)
  19637. +{
  19638. +    char *buf = (char *)arg;
  19639. +    int l;
  19640. +    if (!suser())
  19641. +    return -EPERM;
  19642. +    l = verify_area (VERIFY_WRITE, buf, 2);
  19643. +    if (l)
  19644. +    return l;
  19645. +    return -ENOSYS;
  19646. +}
  19647. +
  19648. +static void ll_erase (const struct vt *vt, unsigned char sx, unsigned char sy,
  19649. +                      unsigned char ex, unsigned char ey)
  19650. +{
  19651. +    int displayed;
  19652. +
  19653. +    displayed = vt == vtdata.fgconsole;
  19654. +    ex += 1;
  19655. +
  19656. +    if (sx != 0) {
  19657. +    /* erase to end of line */
  19658. +    int c, i;
  19659. +    if (sy == ey)
  19660. +        c = ex - sx;
  19661. +    else
  19662. +        c = vtdata.numcolumns - sx;
  19663. +
  19664. +    if (sx + c > vtdata.numcolumns + 1)
  19665. +        c = vtdata.numcolumns - sx;
  19666. +
  19667. +    memsetl (vt->vcd->buffer.buffer + (sx + sy * vtdata.buffer.sizerow),
  19668. +        vt->vcd->combined_state | 32, 4 * c);
  19669. +
  19670. +    if (displayed)
  19671. +        for (i = vtdata.screen.bytespercharv - 1; i >= 0; i --)
  19672. +        memset ((void *)(vt->vcd->screen.origin + sx * vtdata.screen.bytespercharh +
  19673. +            sy * vtdata.screen.sizerow + i * vtdata.numcolumns *
  19674. +            vtdata.screen.bytespercharh), vt->vcd->cached_backcolwrd,
  19675. +            c * vtdata.screen.bytespercharh);
  19676. +    sy ++;
  19677. +    }
  19678. +    if (sy < ey || (sy == ey && ex == vtdata.numcolumns - 1)) {
  19679. +    /* erase all lines from sy to ey (not inclusive) */
  19680. +    int c;
  19681. +
  19682. +    c = ey - sy;
  19683. +    if (c == 0)
  19684. +        c ++;
  19685. +
  19686. +    memsetl (vt->vcd->buffer.buffer + sy * vtdata.buffer.sizerow,
  19687. +        vt->vcd->combined_state | 32, 4 * c * vtdata.buffer.sizerow);
  19688. +
  19689. +    if (displayed)
  19690. +        memset ((void *)(vt->vcd->screen.origin + sy * vtdata.screen.sizerow),
  19691. +        vt->vcd->cached_backcolwrd, c * vtdata.screen.sizerow);
  19692. +    sy += c;
  19693. +    }
  19694. +    if (sy == ey) {
  19695. +    int i;
  19696. +
  19697. +    memsetl (vt->vcd->buffer.buffer + sy * vtdata.buffer.sizerow,
  19698. +        vt->vcd->combined_state | 32, 4 * ex);
  19699. +
  19700. +    if (displayed)
  19701. +        for (i = vtdata.screen.bytespercharv - 1; i >= 0; i--)
  19702. +        memset ((void *)(vt->vcd->screen.origin + sy * vtdata.screen.sizerow + i *
  19703. +                vtdata.numcolumns * vtdata.screen.bytespercharh),
  19704. +            vt->vcd->cached_backcolwrd, ex * vtdata.screen.bytespercharh);
  19705. +    }
  19706. +}
  19707. +
  19708. +/*===============================================================================================*/
  19709. +
  19710. +static int vcd_write_utf (struct con_struct *vcd, int c)
  19711. +{
  19712. +    /* Combine UTF-8 into Unicode */
  19713. +    /* Incomplete characters silently ignored */
  19714. +    if (c < 0x80) {
  19715. +    vcd->utf_count = 0;
  19716. +    return c;
  19717. +    }
  19718. +
  19719. +    if (vcd->utf_count > 0 && (c & 0xc0) == 0x80) {
  19720. +    vcd->utf_char = (vcd->utf_char << 6) | (c & 0x3f);
  19721. +    if (--vcd->utf_count == 0)
  19722. +        return vcd->utf_char;
  19723. +    else
  19724. +        return -1;
  19725. +    } else {
  19726. +    unsigned int count, chr;
  19727. +    if ((c & 0xe0) == 0xc0) {
  19728. +        count = 1;
  19729. +        chr = (c & 0x1f);
  19730. +    } else if ((c & 0xf0) == 0xe0) {
  19731. +        count = 2;
  19732. +        chr = (c & 0x0f);
  19733. +    } else if ((c & 0xf8) == 0xf0) {
  19734. +        count = 3;
  19735. +        chr = (c & 0x07);
  19736. +    } else if ((c & 0xfc) == 0xf8) {
  19737. +        count = 4;
  19738. +        chr = (c & 0x03);
  19739. +    } else if ((c & 0xfe) == 0xfc) {
  19740. +        count = 5;
  19741. +        chr = (c & 0x01);
  19742. +    } else {
  19743. +        count = 0;
  19744. +        chr = 0;
  19745. +    }
  19746. +    vcd->utf_count = count;
  19747. +    vcd->utf_char = chr;
  19748. +    return -1;
  19749. +    }
  19750. +}
  19751. +
  19752. +static void vcd_write_char (const struct vt * const vt, unsigned int c)
  19753. +{
  19754. +    struct con_struct * const vcd = vt->vcd;
  19755. +    unsigned long character, bufpos;
  19756. +
  19757. +    if (c & ~console_charmask)
  19758. +    return;
  19759. +
  19760. +    bufpos = vcd->buffer.pos;
  19761. +
  19762. +    if (vcd->need_wrap) {
  19763. +    vcd->screen.pos -= vcd->curstate.x * vtdata.screen.bytespercharh;
  19764. +    bufpos -= vcd->curstate.x;
  19765. +
  19766. +    vcd->need_wrap = vcd->curstate.x = 0;
  19767. +
  19768. +    if (vcd->curstate.y + 1 == vcd->bottom)
  19769. +        scrollup (vt, vt->vcd->top, vt->vcd->bottom, 1);
  19770. +    else
  19771. +    if (vcd->curstate.y + 1 < vtdata.numrows) {
  19772. +        vcd->curstate.y ++;
  19773. +        vcd->screen.pos += vtdata.screen.sizerow;
  19774. +        bufpos += vtdata.buffer.sizerow;
  19775. +    }
  19776. +    }
  19777. +
  19778. +    if (vcd->decim)
  19779. +    insert_char (vt);
  19780. +
  19781. +    /*
  19782. +     * write character to buffer and screen
  19783. +     */
  19784. +    vcd->buffer.buffer[bufpos] = character = vcd->combined_state | (c & 255);
  19785. +
  19786. +    if (vtdata.fgconsole == vt)
  19787. +    ll_write_char (vcd->screen.pos, character);
  19788. +
  19789. +    if (vcd->curstate.x + 1 == vtdata.numcolumns)
  19790. +    vcd->need_wrap = vcd->decawm;
  19791. +    else {
  19792. +    vcd->curstate.x ++;
  19793. +    vcd->screen.pos += vtdata.screen.bytespercharh;
  19794. +    bufpos += 1;
  19795. +    }
  19796. +    vcd->buffer.pos = bufpos;
  19797. +}
  19798. +
  19799. +static int vcd_write_ctrl (const struct vt *vt, unsigned int c)
  19800. +{
  19801. +    struct con_struct *vcd = vt->vcd;
  19802. +    /*
  19803. +     *  Control characters can be used in the _middle_
  19804. +     *  of an escape sequence.
  19805. +     */
  19806. +    switch(c) {
  19807. +    case 7:
  19808. +    vt_mksound (0x637, 72, HZ/8);
  19809. +    return 0;
  19810. +    case 8:
  19811. +    if (vcd->need_wrap)
  19812. +        vcd->need_wrap = 0;
  19813. +    else
  19814. +    if (vcd->curstate.x) {
  19815. +        vcd->curstate.x --;
  19816. +        vcd->screen.pos -= vtdata.screen.bytespercharh;
  19817. +        vcd->buffer.pos -= 1;
  19818. +        vcd->need_wrap = 0;
  19819. +    }
  19820. +    return 0;
  19821. +    case 9:
  19822. +    vcd->screen.pos -= vcd->curstate.x * vtdata.screen.bytespercharh;
  19823. +    vcd->buffer.pos -= vcd->curstate.x;
  19824. +    while (vcd->curstate.x < vtdata.numcolumns - 1) {
  19825. +        vcd->curstate.x++;
  19826. +        if (vcd->tab_stop[vcd->curstate.x >> 5] & (1 << (vcd->curstate.x & 31)))
  19827. +        break;
  19828. +    }
  19829. +    vcd->screen.pos += vcd->curstate.x * vtdata.screen.bytespercharh;
  19830. +    vcd->buffer.pos += vcd->curstate.x;
  19831. +    return 0;
  19832. +    case 10:
  19833. +    case 11:
  19834. +    case 12:
  19835. +    if (vcd->curstate.y + 1 == vcd->bottom)
  19836. +        scrollup (vt, vt->vcd->top, vt->vcd->bottom, 1);
  19837. +    else
  19838. +    if (vcd->curstate.y < vtdata.numrows - 1) {
  19839. +        vcd->curstate.y ++;
  19840. +        vcd->screen.pos += vtdata.screen.sizerow;
  19841. +        vcd->buffer.pos += vtdata.buffer.sizerow;
  19842. +    }
  19843. +    vcd->need_wrap = 0;
  19844. +    if (!is_kbd(lnm))
  19845. +        return 0;
  19846. +    case 13:
  19847. +    vcd->screen.pos -= vcd->curstate.x * vtdata.screen.bytespercharh;
  19848. +    vcd->buffer.pos -= vcd->curstate.x;
  19849. +    vcd->curstate.x = vcd->need_wrap = 0;
  19850. +    return 0;
  19851. +    case 14:
  19852. +    vcd->curstate.flags |= FLG_CHRSET;
  19853. +    vcd->disp_ctrl = 1;
  19854. +    vcd->translate = set_translate(vcd->curstate.G1_charset);
  19855. +    return 1;
  19856. +    case 15:
  19857. +    vcd->curstate.flags &= ~FLG_CHRSET;
  19858. +    vcd->disp_ctrl = 0;
  19859. +    vcd->translate = set_translate(vcd->curstate.G0_charset);
  19860. +    return 1;
  19861. +    case 24:
  19862. +    case 26:
  19863. +    vcd->state = ESnormal;
  19864. +    return 0;
  19865. +    case 27:
  19866. +    vcd->state = ESesc;
  19867. +    return 0;
  19868. +    case 127:
  19869. +    /* ignored */
  19870. +    return 0;
  19871. +    case 128+27:
  19872. +    vcd->state = ESsquare;
  19873. +    return 0;
  19874. +    }
  19875. +
  19876. +    switch(vcd->state) {
  19877. +    case ESesc:
  19878. +    vcd->state = ESnormal;
  19879. +    switch (c) {
  19880. +    case '[':
  19881. +        vcd->state = ESsquare;
  19882. +        return 0;
  19883. +    case '%':
  19884. +        vcd->state = ESpercent;
  19885. +        return 0;
  19886. +    case 'E':
  19887. +        vcd->screen.pos -= vcd->curstate.x * vtdata.screen.bytespercharh;
  19888. +        vcd->buffer.pos -= vcd->curstate.x;
  19889. +        vcd->curstate.x = vcd->need_wrap = 0;
  19890. +    case 'D':
  19891. +        if (vcd->curstate.y + 1 == vcd->bottom)
  19892. +        scrollup (vt, vt->vcd->top, vt->vcd->bottom, 1);
  19893. +        else
  19894. +        if (vcd->curstate.y < vtdata.numrows - 1) {
  19895. +        vcd->curstate.y ++;
  19896. +        vcd->screen.pos += vtdata.screen.sizerow;
  19897. +        vcd->buffer.pos += vtdata.buffer.sizerow;
  19898. +        }
  19899. +        /* vcd->need_wrap = 0; why should we reset this when the x position is the same? */
  19900. +        return 0;
  19901. +    case 'M':
  19902. +        if (vcd->curstate.y == vcd->top)
  19903. +        scrolldown (vt, vt->vcd->top, vt->vcd->bottom, 1);
  19904. +        else
  19905. +        if (vcd->curstate.y > 0) {
  19906. +        vcd->curstate.y --;
  19907. +        vcd->screen.pos -= vtdata.screen.sizerow;
  19908. +        vcd->buffer.pos -= vtdata.buffer.sizerow;
  19909. +        }
  19910. +        /* vcd->need_wrap = 0; why should we reset this when the x position is the same? */
  19911. +        return 0;
  19912. +    case 'H':
  19913. +        vcd->tab_stop[vcd->curstate.x >> 5] |= (1 << (vcd->curstate.x & 31));
  19914. +        return 0;
  19915. +    case 'Z':
  19916. +        respond_ID (*vt->tty);
  19917. +        return 0;
  19918. +    case '7':
  19919. +        vcd->savedstate = vcd->curstate;
  19920. +        return 0;
  19921. +    case '8':
  19922. +        vcd->curstate = vcd->savedstate;
  19923. +        update_attr (vt);
  19924. +        return 1;
  19925. +    case '(':
  19926. +        vcd->state = ESsetG0;
  19927. +        return 0;
  19928. +    case ')':
  19929. +        vcd->state = ESsetG1;
  19930. +        return 0;
  19931. +    case '#':
  19932. +        vcd->state = EShash;
  19933. +        return 0;
  19934. +    case 'c':
  19935. +        reset_terminal (vt, 0);
  19936. +        return 0;
  19937. +    case '>': /* Numeric keypad */
  19938. +        clr_kbd (kbdapplic);
  19939. +        return 0;
  19940. +    case '=': /* Appl. keypad */
  19941. +        set_kbd (kbdapplic);
  19942. +        return 0;
  19943. +    }
  19944. +    return 0;
  19945. +    case ESnonstd:
  19946. +    vcd->state = ESnormal;
  19947. +    switch (c) {
  19948. +    case 'P': /* palette escape sequence */
  19949. +        for (vcd->npar = 0; vcd->npar < NPAR; vcd->npar++)
  19950. +        vcd->par[vcd->npar] = 0;
  19951. +        vcd->npar = 0 ;
  19952. +        vcd->state = ESpalette;
  19953. +        return 0;
  19954. +    case 'R': /* reset palette */
  19955. +        con_reset_palette (vt);
  19956. +    default:
  19957. +        return 0;
  19958. +    }
  19959. +    case ESpalette:
  19960. +    if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
  19961. +        vcd->par[vcd->npar++] = (c > '9' ? (c & 0xDF) - 'A' + 10 : c - '0');
  19962. +        if (vcd->npar == 7) {
  19963. +#if TODO
  19964. +        int i = par[0]*3, j = 1;
  19965. +        palette[i] = 16*par[j++];
  19966. +        palette[i++] += par[j++];
  19967. +        palette[i] = 16*par[j++];
  19968. +        palette[i++] += par[j++];
  19969. +        palette[i] = 16*par[j++];
  19970. +        palette[i++] += par[j];
  19971. +#endif
  19972. +        con_set_palette (vt);
  19973. +        vcd->state = ESnormal;
  19974. +        }
  19975. +    } else
  19976. +        vcd->state = ESnormal;
  19977. +    return 0;
  19978. +    case ESsquare:
  19979. +    for (vcd->npar = 0; vcd->npar < NPAR; vcd->npar++)
  19980. +        vcd->par[vcd->npar] = 0;
  19981. +    vcd->npar = 0;
  19982. +    vcd->state = ESgetpars;
  19983. +    if (c == '[') { /* Function key */
  19984. +        vcd->state = ESfunckey;
  19985. +        return 0;
  19986. +    }
  19987. +
  19988. +    vcd->ques = (c == '?');
  19989. +    if (vcd->ques)
  19990. +        return 0;
  19991. +    case ESgetpars:
  19992. +    if (c == ';' && vcd->npar < NPAR - 1) {
  19993. +        vcd->npar ++;
  19994. +        return 0;
  19995. +    } else
  19996. +    if (c >= '0' && c <= '9') {
  19997. +        vcd->par[vcd->npar] = vcd->par[vcd->npar] * 10 + c - '0';
  19998. +        return 0;
  19999. +    } else
  20000. +        vcd->state = ESgotpars;
  20001. +    case ESgotpars:
  20002. +    vcd->state=ESnormal;
  20003. +    switch (c) {
  20004. +    case 'h':
  20005. +        set_mode(vt, 1);
  20006. +        return 0;
  20007. +    case 'l':
  20008. +        set_mode(vt, 0);
  20009. +        return 0;
  20010. +    case 'n':
  20011. +        if (!vcd->ques) {
  20012. +        if (vcd->par[0] == 5)
  20013. +            status_report (*vt->tty);
  20014. +        else
  20015. +        if (vcd->par[0] == 6)
  20016. +            cursor_report (vt);
  20017. +        }
  20018. +        return 0;
  20019. +    }
  20020. +    if (vcd->ques) {
  20021. +        vcd->ques = 0;
  20022. +        return 0;
  20023. +    }
  20024. +    switch(c) {
  20025. +    case 'G':
  20026. +    case '`':
  20027. +        if (vcd->par[0])
  20028. +        vcd->par[0]--;
  20029. +        gotoxy (vt, vcd->par[0], vcd->curstate.y);
  20030. +        return 0;
  20031. +    case 'A':
  20032. +        if (!vcd->par[0])
  20033. +        vcd->par[0]++;
  20034. +        gotoxy (vt, vcd->curstate.x, vcd->curstate.y - vcd->par[0]);
  20035. +        return 0;
  20036. +    case 'B':
  20037. +    case 'e':
  20038. +        if (!vcd->par[0])
  20039. +        vcd->par[0]++;
  20040. +        gotoxy (vt, vcd->curstate.x, vcd->curstate.y + vcd->par[0]);
  20041. +        return 0;
  20042. +    case 'C':
  20043. +    case 'a':
  20044. +        if (!vcd->par[0])
  20045. +        vcd->par[0]++;
  20046. +        gotoxy (vt, vcd->curstate.x + vcd->par[0], vcd->curstate.y);
  20047. +        return 0;
  20048. +    case 'D':
  20049. +        if (!vcd->par[0])
  20050. +        vcd->par[0]++;
  20051. +        gotoxy (vt, vcd->curstate.x - vcd->par[0], vcd->curstate.y);
  20052. +        return 0;
  20053. +    case 'E':
  20054. +        if (!vcd->par[0])
  20055. +        vcd->par[0]++;
  20056. +        gotoxy (vt, 0, vcd->curstate.y + vcd->par[0]);
  20057. +        return 0;
  20058. +    case 'F':
  20059. +        if (!vcd->par[0])
  20060. +        vcd->par[0]++;
  20061. +        gotoxy (vt, 0, vcd->curstate.y - vcd->par[0]);
  20062. +        return 0;
  20063. +    case 'd':
  20064. +        if (vcd->par[0])
  20065. +        vcd->par[0]--;
  20066. +        gotoxay (vt, vcd->curstate.x, vcd->par[0]);
  20067. +        return 0;
  20068. +    case 'H':
  20069. +    case 'f':
  20070. +        if (vcd->par[0])
  20071. +        vcd->par[0]--;
  20072. +        if (vcd->par[1])
  20073. +        vcd->par[1]--;
  20074. +        gotoxay (vt, vcd->par[1], vcd->par[0]);
  20075. +        return 0;
  20076. +    case 'J':
  20077. +        csi_J (vt, vcd->par[0]);
  20078. +        return 0;
  20079. +    case 'K':
  20080. +        csi_K (vt, vcd->par[0]);
  20081. +        return 0;
  20082. +    case 'L':
  20083. +        csi_L (vt, vcd->par[0]);
  20084. +        return 0;
  20085. +    case 'M':
  20086. +        csi_M (vt, vcd->par[0]);
  20087. +        return 0;
  20088. +    case 'P':
  20089. +        csi_P (vt, vcd->par[0]);
  20090. +        return 0;
  20091. +    case 'c':
  20092. +        if (!vcd->par[0])
  20093. +        respond_ID(*vt->tty);
  20094. +        return 0;
  20095. +    case 'g':
  20096. +        if (!vcd->par[0])
  20097. +        vcd->tab_stop[vcd->curstate.x >> 5] &= ~(1 << (vcd->curstate.x & 31));
  20098. +        else
  20099. +        if (vcd->par[0] == 3) {
  20100. +        vcd->tab_stop[0] =
  20101. +        vcd->tab_stop[1] =
  20102. +        vcd->tab_stop[2] =
  20103. +        vcd->tab_stop[3] =
  20104. +        vcd->tab_stop[4] = 0;
  20105. +        }
  20106. +        return 0;
  20107. +    case 'm':
  20108. +        return csi_m (vt);
  20109. +    case 'q': /* DECLL - but only 3 leds */
  20110. +        /* map 0,1,2,3 to 0,1,2,4 */
  20111. +        if (vcd->par[0] < 4)
  20112. +          setledstate(vt->kbd, (vcd->par[0] < 3 ? vcd->par[0] : 4));
  20113. +        return 0;
  20114. +    case 'r':
  20115. +        if (!vcd->par[0])
  20116. +        vcd->par[0]++;
  20117. +        if (!vcd->par[1])
  20118. +        vcd->par[1] = vtdata.numrows;
  20119. +        if (vcd->par[0] < vcd->par[1] && vcd->par[1] <= vtdata.numrows) {
  20120. +        vcd->top = vcd->par[0] - 1;
  20121. +        vcd->bottom = vcd->par[1];
  20122. +        gotoxay (vt, 0, 0);
  20123. +        }
  20124. +        return 0;
  20125. +    case 's':
  20126. +        vcd->savedstate = vcd->curstate;
  20127. +        return 0;
  20128. +    case 'u':
  20129. +        vcd->curstate = vcd->savedstate;
  20130. +        update_attr (vt);
  20131. +        return 1;
  20132. +    case 'X':
  20133. +        csi_X (vt, vcd->par[0]);
  20134. +        return 0;
  20135. +    case '@':
  20136. +        csi_at (vt, vcd->par[0]);
  20137. +        return 0;
  20138. +    case ']': /* setterm functions */
  20139. +        setterm_command (vt);
  20140. +        return 0;
  20141. +    }
  20142. +    return 0;
  20143. +    case ESpercent:
  20144. +    vcd->state = ESnormal;
  20145. +    switch (c) {
  20146. +    case '@': /* defined in ISO 2022 */
  20147. +        vcd->utf = 0;
  20148. +        return 0;
  20149. +    case 'G': /* prelim official escape code */
  20150. +    case '8': /* retained for compatibility */
  20151. +        vcd->utf = 1;
  20152. +        return 0;
  20153. +    }
  20154. +    return 0;
  20155. +    case ESfunckey:
  20156. +    vcd->state = ESnormal;
  20157. +    return 0;
  20158. +    case EShash:
  20159. +    vcd->state = ESnormal;
  20160. +    if (c == '8') {
  20161. +        /* DEC screen alignment test. kludge :-) */
  20162. +    }
  20163. +    return 0;
  20164. +    case ESsetG0:
  20165. +    vcd->state = ESnormal;
  20166. +    if (c == '0')
  20167. +        vcd->curstate.G0_charset = GRAF_MAP;
  20168. +    else
  20169. +    if (c == 'B')
  20170. +        vcd->curstate.G0_charset = LAT1_MAP;
  20171. +    else
  20172. +    if (c == 'U')
  20173. +        vcd->curstate.G0_charset = IBMPC_MAP;
  20174. +    else
  20175. +    if (c == 'K')
  20176. +        vcd->curstate.G0_charset = USER_MAP;
  20177. +    if ((vcd->curstate.flags & FLG_CHRSET) == 0) {
  20178. +        vcd->translate = set_translate(vcd->curstate.G0_charset);
  20179. +        return 1;
  20180. +    }
  20181. +    return 0;
  20182. +    case ESsetG1:
  20183. +    vcd->state = ESnormal;
  20184. +    if (c == '0')
  20185. +        vcd->curstate.G1_charset = GRAF_MAP;
  20186. +    else
  20187. +    if (c == 'B')
  20188. +        vcd->curstate.G1_charset = LAT1_MAP;
  20189. +    else
  20190. +    if (c == 'U')
  20191. +        vcd->curstate.G1_charset = IBMPC_MAP;
  20192. +    else
  20193. +    if (c == 'K')
  20194. +        vcd->curstate.G1_charset = USER_MAP;
  20195. +    if (vcd->curstate.flags & FLG_CHRSET) {
  20196. +        vcd->translate = set_translate(vcd->curstate.G1_charset);
  20197. +        return 1;
  20198. +    }
  20199. +    return 0;
  20200. +    default:
  20201. +    vcd->state = ESnormal;
  20202. +    }
  20203. +    return 0;
  20204. +}
  20205. +
  20206. +/*===============================================================================================*/
  20207. +
  20208. +int vcd_init (struct vt *vt, int kmallocok, unsigned long *kmem)
  20209. +{
  20210. +    memset (vt->vcd, 0, sizeof (*vt->vcd));
  20211. +    
  20212. +    vt->vcd->screen.origin    = vtdata.screen.memstart;
  20213. +    if (kmallocok) {
  20214. +    vt->vcd->buffer.buffer    = kmalloc (vtdata.buffer.totsize * sizeof (unsigned long), GFP_KERNEL);
  20215. +    if (!vt->vcd->buffer.buffer)
  20216. +        return -ENOMEM;
  20217. +    vt->vcd->buffer.kmalloced = 1;
  20218. +    } else {
  20219. +    vt->vcd->buffer.buffer    = (unsigned long *) *kmem;
  20220. +    *kmem += vtdata.buffer.totsize * sizeof (unsigned long);
  20221. +    }
  20222. +
  20223. +    vt->vtd->paste_wait        = NULL;
  20224. +    vt->vcd->screen.cursoron    = (kmem ? 1 : 0);
  20225. +    vt->vcd->screen.palette_entries = NULL;
  20226. +    reset_terminal (vt, (kmem ? 1 : 0));
  20227. +
  20228. +    return 0;
  20229. +}
  20230. +
  20231. +static struct irqaction vsyncirq = { vsync_irq, 0, 0, "vsync", NULL, NULL };
  20232. +    
  20233. +unsigned long vcd_pre_init (unsigned long kmem, struct vt *vt)
  20234. +{
  20235. +    int colours, i;
  20236. +
  20237. +    /* Use ORIG_VIDEO_MODE */
  20238. +    vtdata.screen.bytespercharh = bytes_per_char_h;
  20239. +    vtdata.screen.bytespercharv = bytes_per_char_v;
  20240. +    video_num_columns = vtdata.numcolumns;
  20241. +    vtdata.screen.sizerow  = (vtdata.numcolumns *
  20242. +                vtdata.screen.bytespercharh * vtdata.screen.bytespercharv);
  20243. +    vtdata.screen.totsize  = vtdata.screen.sizerow * vtdata.numrows;
  20244. +    vtdata.screen.memmask  = (vtdata.screen.totsize - 1) | (PAGE_SIZE-1);
  20245. +    vtdata.screen.memend   = 0x02000000;
  20246. +    vtdata.screen.memstart = vtdata.screen.memend - vtdata.screen.memmask - 1;
  20247. +    vtdata.buffer.sizerow  = vtdata.numcolumns;
  20248. +    vtdata.buffer.totsize  = vtdata.numcolumns * vtdata.numrows;
  20249. +
  20250. +    map_screen_mem (vtdata.screen.memstart, 1);
  20251. +
  20252. +    switch (vtdata.screen.bytespercharh) {
  20253. +    case 1:
  20254. +    default_palette_entries = palette_1;
  20255. +    color_table = color_1;
  20256. +    can_do_color = 0;
  20257. +    vtdata.screen.bitsperpix = 1;
  20258. +    colours = 1;
  20259. +    break;
  20260. +    default:
  20261. +    case 4:
  20262. +    default_palette_entries = palette_4;
  20263. +    color_table = color_4;
  20264. +    can_do_color = 1;
  20265. +    vtdata.screen.bitsperpix = 4;
  20266. +    colours = 16;
  20267. +    break;
  20268. +    case 8:
  20269. +    default_palette_entries = palette_8;
  20270. +    color_table = color_8;
  20271. +    can_do_color = 1;
  20272. +    vtdata.screen.bitsperpix = 8;
  20273. +    colours = 256;
  20274. +    break;
  20275. +    }
  20276. +
  20277. +    for (i = 0; i < 17; i++)
  20278. +    vidc_write (i << 2, default_palette_entries[i]);
  20279. +
  20280. +    vcd_init (vt, 0, &kmem);
  20281. +
  20282. +    vt->vcd->screen.cursoron = 1;
  20283. +
  20284. +    set_origin (vt);
  20285. +
  20286. +    gotoxy (vt, ORIG_X, ORIG_Y);
  20287. +    csi_J (vt, 0);
  20288. +    printable = 1;
  20289. +
  20290. +#ifdef CONFIG_SERIAL_ECHO
  20291. +    serial_echo_init (SERIAL_ECHO_PORT);
  20292. +#endif
  20293. +
  20294. +    printk ("Console: %s %s %dx%dx%d, %d virtual console%s (max %d)\n",
  20295. +    can_do_color ? "colour" : "mono",
  20296. +    "A-series",
  20297. +      vtdata.numcolumns,
  20298. +      vtdata.numrows,
  20299. +      colours,
  20300. +      MIN_NR_CONSOLES,
  20301. +      (MIN_NR_CONSOLES == 1) ? "":"s",
  20302. +      MAX_NR_CONSOLES);
  20303. +
  20304. +    register_console (console_print);
  20305. +
  20306. +    if (setup_arm_irq(IRQ_VSYNCPULSE, &vsyncirq))
  20307. +    panic ("Unable to get VSYNC irq for console\n");
  20308. +
  20309. +    return kmem;
  20310. +}
  20311. +
  20312. +void vcd_disallocate (struct vt *vt)
  20313. +{
  20314. +    if (vt->vcd && vt->vcd->buffer.kmalloced) {
  20315. +    kfree (vt->vcd->buffer.buffer);
  20316. +    vt->vcd->buffer.buffer = NULL;
  20317. +    vt->vcd->buffer.kmalloced = 0;
  20318. +    }
  20319. +}
  20320. +
  20321. +int vcd_resize(unsigned long lines, unsigned long cols)
  20322. +{/* TODO */
  20323. +    return -ENOMEM;
  20324. +}
  20325. +
  20326. +void vcd_blankscreen(int nopowersave)
  20327. +{
  20328. +    int i;
  20329. +
  20330. +    /* DISABLE VIDEO */
  20331. +    for (i = 0; i < 17; i++)
  20332. +    vidc_write(i<<2, 0);
  20333. +}
  20334. +
  20335. +void vcd_unblankscreen (void)
  20336. +{
  20337. +    int i;
  20338. +    if (!vtdata.fgconsole->vcd->screen.palette_entries ||
  20339. +        vtdata.fgconsole->vtd->vc_mode != KD_GRAPHICS)
  20340. +    for(i=0; i<17; i++)
  20341. +        vidc_write(i<<2, default_palette_entries[i]);
  20342. +    else
  20343. +    for(i=0; i<17; i++)
  20344. +        vidc_write(i<<2, vtdata.fgconsole->vcd->screen.palette_entries[i] & 0x1fff);
  20345. +}
  20346. +
  20347. +static unsigned long old_origin;
  20348. +
  20349. +void vcd_savestate (const struct vt *vt, int blanked)
  20350. +{
  20351. +    clear_selection ();
  20352. +    vcd_removecursors (vt);
  20353. +
  20354. +    old_origin = vt->vcd->screen.origin;
  20355. +
  20356. +    if (blanked)
  20357. +    vtdata.blanked = NULL;
  20358. +#ifdef DEBUG
  20359. +    vcd_validate (vt->vcd, "vcd_savestate");
  20360. +#endif
  20361. +}
  20362. +
  20363. +void vcd_restorestate (const struct vt *vt)
  20364. +{
  20365. +    int text_mode;
  20366. +#ifdef DEBUG
  20367. +    unsigned long o_orig, o_pos;
  20368. +#endif
  20369. +    /*
  20370. +     * Reset the origin on this VT to be the same as the previous.
  20371. +     * This way we don't get any jumps when we change VT's.
  20372. +     */
  20373. +    text_mode = vt->vtd->vc_mode == KD_TEXT ? 1 : 0;
  20374. +#ifdef DEBUG
  20375. +    o_orig = vt->vcd->screen.origin;
  20376. +    o_pos = vt->vcd->screen.pos;
  20377. +#endif
  20378. +    vt->vcd->screen.pos -= vt->vcd->screen.origin;
  20379. +    if (text_mode) {
  20380. +    vt->vcd->screen.origin = old_origin;
  20381. +    set_scrmem (vt, 0);
  20382. +    } else
  20383. +    vt->vcd->screen.origin = 0x02000000;
  20384. +    vt->vcd->screen.pos += vt->vcd->screen.origin;
  20385. +#ifdef DEBUG
  20386. +    if (vcd_validate (vt->vcd, "vcd_restorestate")) {
  20387. +    printk ("old_origin = %08lX; old_pos = %08lX; new_origin = %08lX\n", o_orig, o_pos, old_origin);
  20388. +    }
  20389. +#endif
  20390. +    set_origin (vt);
  20391. +    set_cursor (vt);
  20392. +    if (text_mode)
  20393. +    vcd_restorecursors (vt);
  20394. +    set_leds ();
  20395. +}
  20396. +
  20397. +void vcd_setup_graphics (const struct vt *vt)
  20398. +{
  20399. +    clear_selection ();
  20400. +    vcd_removecursors (vt);
  20401. +
  20402. +    __real_origin = 0;
  20403. +    __set_origin (0);
  20404. +}
  20405. +
  20406. +int vcd_write (const struct vt *vt, int from_user, const unsigned char *buf, int count)
  20407. +{
  20408. +    int strt_count = count;
  20409. +    unsigned short *cached_trans;
  20410. +    unsigned int cached_ctrls;
  20411. +    register struct con_struct *vcd;
  20412. +
  20413. +    if (from_user && get_fs () == KERNEL_DS)
  20414. +    from_user = 0;
  20415. +
  20416. +    vcd = vt->vcd;
  20417. +
  20418. +#ifdef DEBUG
  20419. +    vcd_validate (vcd, "vcd_write entry");
  20420. +#endif
  20421. +
  20422. +    vcd_removecursors (vt);
  20423. +    if (vt == vtdata.select.vt)
  20424. +    clear_selection();
  20425. +
  20426. +    disable_bh (KEYBOARD_BH);
  20427. +recache:
  20428. +    cached_ctrls = vcd->disp_ctrl ? CTRL_ALWAYS : CTRL_ACTION;
  20429. +    cached_trans = vcd->translate + (vcd->toggle_meta ? 0x80 : 0);
  20430. +
  20431. +    while (!(*vt->tty)->stopped && count) {
  20432. +    int tc, c;
  20433. +    __asm__("teq    %3, #0
  20434. +    ldreqb    %0, [%1], #1
  20435. +    ldrnebt    %0, [%1], #1" : "=r" (c), "=&r" (buf) : "1" (buf), "r" (from_user));
  20436. +    count --;
  20437. +
  20438. +    if (vcd->utf) {
  20439. +        if ((tc = vcd_write_utf (vcd, c)) < 0)
  20440. +        continue;
  20441. +        c = tc;
  20442. +    } else
  20443. +        tc = cached_trans[c];
  20444. +
  20445. +    if (vcd->state == ESnormal && tc && (c != 127 || vcd->disp_ctrl)) {
  20446. +        if (c >= 32 || (!vcd->utf && !(cached_ctrls & (1 << c)))) { /* ok */
  20447. +        tc = conv_uni_to_pc (tc);
  20448. +        if (tc + 4 == 0)
  20449. +            tc = conv_uni_to_pc (0xfffd);
  20450. +        else
  20451. +        if (tc + 3 == 0)
  20452. +            tc = c;
  20453. +
  20454. +        vcd_write_char (vt, tc);
  20455. +        continue;
  20456. +        }
  20457. +    }
  20458. +
  20459. +    if (vcd_write_ctrl (vt, c))
  20460. +        goto recache;
  20461. +    else
  20462. +        continue;
  20463. +    }
  20464. +    if (vt->vtd->vc_mode != KD_GRAPHICS)
  20465. +    set_cursor (vt);
  20466. +    enable_bh(KEYBOARD_BH);
  20467. +    vcd_restorecursors (vt);
  20468. +#ifdef DEBUG
  20469. +    vcd_validate (vcd, "vcd_write exit");
  20470. +#endif
  20471. +    return strt_count - count;
  20472. +}
  20473. +
  20474. +int vcd_ioctl (const struct vt *vt, int cmd, unsigned long arg)
  20475. +{
  20476. +    int i;
  20477. +    switch (cmd) {
  20478. +    case VT_GETPALETTE: {
  20479. +    unsigned long pix, num, *val;
  20480. +        
  20481. +    i = verify_area (VERIFY_READ, (void *)arg, 12);
  20482. +    if (i)
  20483. +        return i;
  20484. +    pix = get_user ((unsigned long *)arg);
  20485. +    num = get_user ((unsigned long *)(arg + 4));
  20486. +    val = (unsigned long *) get_user ((unsigned long *)(arg + 8));
  20487. +
  20488. +    if (pix > 18 || pix + num > 19 || num < 1)
  20489. +        return -EINVAL;
  20490. +
  20491. +    i = verify_area (VERIFY_WRITE, val, num * sizeof (unsigned long));
  20492. +    if (i)
  20493. +        return i;
  20494. +
  20495. +    if (vt->vcd->screen.palette_entries)
  20496. +        for (i = pix; i < pix + num; i++)
  20497. +        *val++ = vt->vcd->screen.palette_entries[i] & 0x1fff;
  20498. +    else
  20499. +        for (i = pix; i < pix + num; i++)
  20500. +        *val++ = default_palette_entries[i] & 0x1fff;
  20501. +    return 0;
  20502. +        }
  20503. +    case VT_SETPALETTE: {
  20504. +    unsigned long pix, num, *val;
  20505. +
  20506. +    i = verify_area (VERIFY_READ, (void *)arg, 12);
  20507. +    if (i)
  20508. +        return i;
  20509. +
  20510. +    pix = get_user ((unsigned long *)arg);
  20511. +    num = get_user ((unsigned long *)(arg + 4));
  20512. +    val = (unsigned long *) get_user ((unsigned long *)(arg + 8));
  20513. +
  20514. +    if (pix > 18 || pix + num > 19 || num < 1)
  20515. +        return -EINVAL;
  20516. +
  20517. +    i = verify_area (VERIFY_READ, val, num * sizeof (unsigned long));
  20518. +    if (i)
  20519. +        return i;
  20520. +
  20521. +    if (!vt->vcd->screen.palette_entries) {
  20522. +        vt->vcd->screen.palette_entries = kmalloc (sizeof (unsigned long) * 19, GFP_KERNEL);
  20523. +        if (!vt->vcd->screen.palette_entries)
  20524. +        return -ENOMEM;
  20525. +        for (i = 0; i < 19; i++)
  20526. +        vt->vcd->screen.palette_entries[i] = default_palette_entries[i];
  20527. +    }
  20528. +
  20529. +    for (i = pix; i < pix + num; i++) {
  20530. +        vt->vcd->screen.palette_entries[i] = *val++;
  20531. +        vidc_write (i << 2, vt->vcd->screen.palette_entries[i] & 0x1fff);
  20532. +    }
  20533. +    return 0;
  20534. +    }
  20535. +
  20536. +    case PIO_FONT:
  20537. +    if (vt->vtd->vc_mode != KD_TEXT)
  20538. +        return -EINVAL;
  20539. +    return con_set_font((char *)arg);
  20540. +    /* con_set_font() defined in console.c */
  20541. +
  20542. +    case GIO_FONT:
  20543. +    if (vt->vtd->vc_mode != KD_TEXT)
  20544. +        return -EINVAL;
  20545. +    return con_get_font((char *)arg);
  20546. +    /* con_get_font() defined in console.c */
  20547. +
  20548. +    case PIO_SCRNMAP:
  20549. +    return con_set_trans_old ((char *)arg);
  20550. +
  20551. +    case GIO_SCRNMAP:
  20552. +    return con_get_trans_old((char *)arg);
  20553. +
  20554. +    case PIO_UNISCRNMAP:
  20555. +    return con_set_trans_new((short *)arg);
  20556. +
  20557. +    case GIO_UNISCRNMAP:
  20558. +    return con_get_trans_new((short *)arg);
  20559. +
  20560. +    case PIO_UNIMAPCLR: {
  20561. +    struct unimapinit ui;
  20562. +
  20563. +    i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapinit));
  20564. +    if (i)
  20565. +        return i;
  20566. +    memcpy_fromfs(&ui, (void *)arg, sizeof(struct unimapinit));
  20567. +    con_clear_unimap(&ui);
  20568. +    return 0;
  20569. +    }
  20570. +
  20571. +    case PIO_UNIMAP: {
  20572. +    i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapdesc));
  20573. +    if (i == 0) {
  20574. +        struct unimapdesc *ud;
  20575. +        u_short ct;
  20576. +        struct unipair *list;
  20577. +
  20578. +        ud = (struct unimapdesc *) arg;
  20579. +        ct = get_fs_word(&ud->entry_ct);
  20580. +        list = (struct unipair *) get_fs_long(&ud->entries);
  20581. +
  20582. +        i = verify_area(VERIFY_READ, (void *) list,
  20583. +            ct*sizeof(struct unipair));
  20584. +        if (!i)
  20585. +        return con_set_unimap(ct, list);
  20586. +    }
  20587. +    return i;
  20588. +    }
  20589. +
  20590. +    case GIO_UNIMAP: {
  20591. +    i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct unimapdesc));
  20592. +    if (i == 0) {
  20593. +        struct unimapdesc *ud;
  20594. +        u_short ct;
  20595. +        struct unipair *list;
  20596. +
  20597. +        ud = (struct unimapdesc *) arg;
  20598. +        ct = get_fs_word(&ud->entry_ct);
  20599. +        list = (struct unipair *) get_fs_long(&ud->entries);
  20600. +        if (ct)
  20601. +        i = verify_area(VERIFY_WRITE, (void *) list,
  20602. +            ct*sizeof(struct unipair));
  20603. +        if (!i)
  20604. +        return con_get_unimap(ct, &(ud->entry_ct), list);
  20605. +    }
  20606. +    return i;
  20607. +    }
  20608. +
  20609. +    default:
  20610. +    return -ENOIOCTLCMD;
  20611. +    }
  20612. +}
  20613. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/cp437.uni linux/arch/arm/drivers/char/cp437.uni
  20614. --- linux.orig/arch/arm/drivers/char/cp437.uni    Thu Jan  1 01:00:00 1970
  20615. +++ linux/arch/arm/drivers/char/cp437.uni    Thu Jul 18 22:32:15 1996
  20616. @@ -0,0 +1,291 @@
  20617. +#
  20618. +# Unicode table for IBM Codepage 437.  Note that there are many more
  20619. +# substitutions that could be conceived (for example, thick-line
  20620. +# graphs probably should be replaced with double-line ones, accented
  20621. +# Latin characters should replaced with their nonaccented versions,
  20622. +# and some upper case Greek characters could be replaced by Latin), however,
  20623. +# I have limited myself to the Unicodes used by the kernel ISO 8859-1,
  20624. +# DEC VT, and IBM CP 437 tables.
  20625. +#
  20626. +# --------------------------------
  20627. +#
  20628. +# Basic IBM dingbats, some of which will never have a purpose clear
  20629. +# to mankind
  20630. +#
  20631. +0x00    U+0000
  20632. +0x01    U+263a
  20633. +0x02    U+263b
  20634. +0x03    U+2665
  20635. +0x04    U+2666 U+25c6
  20636. +0x05    U+2663
  20637. +0x06    U+2660
  20638. +0x07    U+2022
  20639. +0x08    U+25d8
  20640. +0x09    U+25cb
  20641. +0x0a    U+25d9
  20642. +0x0b    U+2642
  20643. +0x0c    U+2640
  20644. +0x0d    U+266a
  20645. +0x0e    U+266b
  20646. +0x0f    U+263c
  20647. +0x10    U+25b6 U+25ba
  20648. +0x11    U+25c0 U+25c4
  20649. +0x12    U+2195
  20650. +0x13    U+203c
  20651. +0x14    U+00b6
  20652. +0x15    U+00a7
  20653. +0x16    U+25ac
  20654. +0x17    U+21a8
  20655. +0x18    U+2191
  20656. +0x19    U+2193
  20657. +0x1a    U+2192
  20658. +0x1b    U+2190
  20659. +0x1c    U+221f
  20660. +0x1d    U+2194
  20661. +0x1e    U+25b2
  20662. +0x1f    U+25bc
  20663. +#
  20664. +# The ASCII range is identity-mapped, but some of the characters also
  20665. +# have to act as substitutes, especially the upper-case characters.
  20666. +#
  20667. +0x20    U+0020
  20668. +0x21    U+0021
  20669. +0x22    U+0022 U+00a8
  20670. +0x23    U+0023
  20671. +0x24    U+0024
  20672. +0x25    U+0025
  20673. +0x26    U+0026
  20674. +0x27    U+0027
  20675. +0x28    U+0028
  20676. +0x29    U+0029
  20677. +0x2a    U+002a
  20678. +0x2b    U+002b
  20679. +0x2c    U+002c U+00b8
  20680. +0x2d    U+002d U+00ad
  20681. +0x2e    U+002e
  20682. +0x2f    U+002f
  20683. +0x30    U+0030
  20684. +0x31    U+0031
  20685. +0x32    U+0032
  20686. +0x33    U+0033
  20687. +0x34    U+0034
  20688. +0x35    U+0035
  20689. +0x36    U+0036
  20690. +0x37    U+0037
  20691. +0x38    U+0038
  20692. +0x39    U+0039
  20693. +0x3a    U+003a
  20694. +0x3b    U+003b
  20695. +0x3c    U+003c
  20696. +0x3d    U+003d
  20697. +0x3e    U+003e
  20698. +0x3f    U+003f
  20699. +0x40    U+0040
  20700. +0x41    U+0041 U+00c0 U+00c1 U+00c2 U+00c3
  20701. +0x42    U+0042
  20702. +0x43    U+0043 U+00a9
  20703. +0x44    U+0044
  20704. +0x45    U+0045 U+00c8 U+00ca U+00cb
  20705. +0x46    U+0046
  20706. +0x47    U+0047
  20707. +0x48    U+0048
  20708. +0x49    U+0049 U+00cc U+00cd U+00ce U+00cf
  20709. +0x4a    U+004a
  20710. +0x4b    U+004b U+212a
  20711. +0x4c    U+004c
  20712. +0x4d    U+004d
  20713. +0x4e    U+004e
  20714. +0x4f    U+004f U+00d2 U+00d3 U+00d4 U+00d5
  20715. +0x50    U+0050
  20716. +0x51    U+0051
  20717. +0x52    U+0052 U+00ae
  20718. +0x53    U+0053
  20719. +0x54    U+0054
  20720. +0x55    U+0055 U+00d9 U+00da U+00db
  20721. +0x56    U+0056
  20722. +0x57    U+0057
  20723. +0x58    U+0058
  20724. +0x59    U+0059 U+00dd
  20725. +0x5a    U+005a
  20726. +0x5b    U+005b
  20727. +0x5c    U+005c
  20728. +0x5d    U+005d
  20729. +0x5e    U+005e
  20730. +0x5f    U+005f U+f804
  20731. +0x60    U+0060
  20732. +0x61    U+0061 U+00e3
  20733. +0x62    U+0062
  20734. +0x63    U+0063
  20735. +0x64    U+0064
  20736. +0x65    U+0065
  20737. +0x66    U+0066
  20738. +0x67    U+0067
  20739. +0x68    U+0068
  20740. +0x69    U+0069
  20741. +0x6a    U+006a
  20742. +0x6b    U+006b
  20743. +0x6c    U+006c
  20744. +0x6d    U+006d
  20745. +0x6e    U+006e
  20746. +0x6f    U+006f U+00f5
  20747. +0x70    U+0070
  20748. +0x71    U+0071
  20749. +0x72    U+0072
  20750. +0x73    U+0073
  20751. +0x74    U+0074
  20752. +0x75    U+0075
  20753. +0x76    U+0076
  20754. +0x77    U+0077
  20755. +0x78    U+0078 U+00d7
  20756. +0x79    U+0079 U+00fd
  20757. +0x7a    U+007a
  20758. +0x7b    U+007b
  20759. +0x7c    U+007c U+00a5
  20760. +0x7d    U+007d
  20761. +0x7e    U+007e
  20762. +#
  20763. +# Okay, what on Earth is this one supposed to be used for?
  20764. +#
  20765. +0x7f    U+2302
  20766. +#
  20767. +# Non-English characters, mostly lower case letters...
  20768. +#
  20769. +0x80    U+00c7
  20770. +0x81    U+00fc
  20771. +0x82    U+00e9
  20772. +0x83    U+00e2
  20773. +0x84    U+00e4
  20774. +0x85    U+00e0
  20775. +0x86    U+00e5
  20776. +0x87    U+00e7
  20777. +0x88    U+00ea
  20778. +0x89    U+00eb
  20779. +0x8a    U+00e8
  20780. +0x8b    U+00ef
  20781. +0x8c    U+00ee
  20782. +0x8d    U+00ec
  20783. +0x8e    U+00c4
  20784. +0x8f    U+00c5 U+212b
  20785. +0x90    U+00c9
  20786. +0x91    U+00e6
  20787. +0x92    U+00c6
  20788. +0x93    U+00f4
  20789. +0x94    U+00f6
  20790. +0x95    U+00f2
  20791. +0x96    U+00fb
  20792. +0x97    U+00f9
  20793. +0x98    U+00ff
  20794. +0x99    U+00d6
  20795. +0x9a    U+00dc
  20796. +0x9b    U+00a2
  20797. +0x9c    U+00a3
  20798. +0x9d    U+00a5
  20799. +0x9e    U+20a7
  20800. +0x9f    U+0192
  20801. +0xa0    U+00e1
  20802. +0xa1    U+00ed
  20803. +0xa2    U+00f3
  20804. +0xa3    U+00fa
  20805. +0xa4    U+00f1
  20806. +0xa5    U+00d1
  20807. +0xa6    U+00aa
  20808. +0xa7    U+00ba
  20809. +0xa8    U+00bf
  20810. +0xa9    U+2310
  20811. +0xaa    U+00ac
  20812. +0xab    U+00bd
  20813. +0xac    U+00bc
  20814. +0xad    U+00a1
  20815. +0xae    U+00ab
  20816. +0xaf    U+00bb
  20817. +#
  20818. +# Block graphics
  20819. +#
  20820. +0xb0    U+2591
  20821. +0xb1    U+2592
  20822. +0xb2    U+2593
  20823. +0xb3    U+2502
  20824. +0xb4    U+2524
  20825. +0xb5    U+2561
  20826. +0xb6    U+2562
  20827. +0xb7    U+2556
  20828. +0xb8    U+2555
  20829. +0xb9    U+2563
  20830. +0xba    U+2551
  20831. +0xbb    U+2557
  20832. +0xbc    U+255d
  20833. +0xbd    U+255c
  20834. +0xbe    U+255b
  20835. +0xbf    U+2510
  20836. +0xc0    U+2514
  20837. +0xc1    U+2534
  20838. +0xc2    U+252c
  20839. +0xc3    U+251c
  20840. +0xc4    U+2500
  20841. +0xc5    U+253c
  20842. +0xc6    U+255e
  20843. +0xc7    U+255f
  20844. +0xc8    U+255a
  20845. +0xc9    U+2554
  20846. +0xca    U+2569
  20847. +0xcb    U+2566
  20848. +0xcc    U+2560
  20849. +0xcd    U+2550
  20850. +0xce    U+256c
  20851. +0xcf    U+2567
  20852. +0xd0    U+2568
  20853. +0xd1    U+2564
  20854. +0xd2    U+2565
  20855. +0xd3    U+2559
  20856. +0xd4    U+2558
  20857. +0xd5    U+2552
  20858. +0xd6    U+2553
  20859. +0xd7    U+256b
  20860. +0xd8    U+256a
  20861. +0xd9    U+2518
  20862. +0xda    U+250c
  20863. +0xdb    U+2588
  20864. +0xdc    U+2584
  20865. +0xdd    U+258c
  20866. +0xde    U+2590
  20867. +0xdf    U+2580
  20868. +#
  20869. +# Greek letters and mathematical symbols
  20870. +#
  20871. +0xe0    U+03b1
  20872. +0xe1    U+03b2 U+00df
  20873. +0xe2    U+0393
  20874. +0xe3    U+03c0
  20875. +0xe4    U+03a3
  20876. +0xe5    U+03c3
  20877. +0xe6    U+00b5 U+03bc
  20878. +0xe7    U+03c4
  20879. +0xe8    U+03a6 U+00d8
  20880. +0xe9    U+0398
  20881. +0xea    U+03a9 U+2126
  20882. +0xeb    U+03b4
  20883. +0xec    U+221e
  20884. +0xed    U+03c6 U+00f8
  20885. +0xee    U+03b5
  20886. +0xef    U+2229
  20887. +0xf0    U+2261
  20888. +0xf1    U+00b1
  20889. +0xf2    U+2265
  20890. +0xf3    U+2264
  20891. +0xf4    U+2320
  20892. +0xf5    U+2321
  20893. +0xf6    U+00f7
  20894. +0xf7    U+2248
  20895. +0xf8    U+00b0
  20896. +0xf9    U+2219
  20897. +0xfa    U+00b7
  20898. +0xfb    U+221a
  20899. +0xfc    U+207f
  20900. +0xfd    U+00b2
  20901. +#
  20902. +# Square bullet, non-spacing blank
  20903. +# Mapping U+fffd to the square bullet means it is the substitution
  20904. +# character
  20905. +# 
  20906. +0xfe    U+25a0 U+fffd
  20907. +0xff    U+00a0
  20908. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/defkeymap.c linux/arch/arm/drivers/char/defkeymap.c
  20909. --- linux.orig/arch/arm/drivers/char/defkeymap.c    Thu Jan  1 01:00:00 1970
  20910. +++ linux/arch/arm/drivers/char/defkeymap.c    Sun Mar  3 12:31:45 1996
  20911. @@ -0,0 +1,337 @@
  20912. +/*
  20913. + * linux/arch/arm/drivers/char/defkeymap.c
  20914. + *
  20915. + * Copyright (C) 1995, 1996 Russell King
  20916. + */
  20917. +
  20918. +#include <linux/types.h>
  20919. +#include <linux/keyboard.h>
  20920. +#include <linux/kd.h>
  20921. +
  20922. +/* Normal (maps 1:1 with no processing) */
  20923. +#define KTn    0xF0
  20924. +/* Function keys */
  20925. +#define KTf    0xF1
  20926. +/* Special (Performs special house-keeping funcs) */
  20927. +#define KTs    0xF2
  20928. +#define KIGNORE        K(KTs, 0)    /* Ignore */
  20929. +#define KENTER        K(KTs, 1)    /* Enter */
  20930. +#define KREGS        K(KTs, 2)    /* Regs */
  20931. +#define KMEM        K(KTs, 3)    /* Mem */
  20932. +#define KSTAT        K(KTs, 4)    /* State */
  20933. +#define KINTR        K(KTs, 5)    /* Intr */
  20934. +#define Ksl    6    /* Last console */
  20935. +#define KCAPSLK        K(KTs, 7)    /* Caps lock */
  20936. +#define KNUMLK        K(KTs, 8)    /* Num-lock */
  20937. +#define KSCRLLK        K(KTs, 9)    /* Scroll-lock */
  20938. +#define KSCRLFOR    K(KTs,10)    /* Scroll forward */
  20939. +#define KSCRLBAK    K(KTs,11)    /* Scroll back */
  20940. +#define KREBOOT        K(KTs,12)    /* Reboot */
  20941. +#define KCAPSON        K(KTs,13)    /* Caps on */
  20942. +#define KCOMPOSE    K(KTs,14)    /* Compose */
  20943. +#define KSAK        K(KTs,15)    /* SAK */
  20944. +#define CONS_DEC    K(KTs,16)    /* Dec console */
  20945. +#define CONS_INC    K(KTs,17)    /* Incr console */
  20946. +#define KFLOPPY        K(KTs,18)    /* Floppy */
  20947. +/* Key pad (0-9 = digits, 10=+, 11=-, 12=*, 13=/, 14=enter, 16=., 17=# */
  20948. +#define KTp    0xF3
  20949. +#define KPAD_0        K(KTp, 0 )
  20950. +#define KPAD_1      K(KTp, 1 )
  20951. +#define KPAD_2        K(KTp, 2 )
  20952. +#define KPAD_3        K(KTp, 3 )
  20953. +#define KPAD_4        K(KTp, 4 )
  20954. +#define KPAD_5        K(KTp, 5 )
  20955. +#define KPAD_6        K(KTp, 6 )
  20956. +#define KPAD_7        K(KTp, 7 )
  20957. +#define KPAD_8        K(KTp, 8 )
  20958. +#define KPAD_9        K(KTp, 9 )
  20959. +#define KPAD_PL        K(KTp,10 )
  20960. +#define KPAD_MI        K(KTp,11 )
  20961. +#define KPAD_ML        K(KTp,12 )
  20962. +#define KPAD_DV        K(KTp,13 )
  20963. +#define KPAD_EN        K(KTp,14 )
  20964. +#define KPAD_DT        K(KTp,16 )
  20965. +#define KPAD_HS        K(KTp,18 )
  20966. +/* Console switching */
  20967. +#define KCn    0xF5
  20968. +/* Cursor */
  20969. +#define KTc    0xF6
  20970. +#define Kcd    0    /* Cursor down */
  20971. +#define Kcl    1    /* Cursor left */
  20972. +#define Kcr    2    /* Cursor right */
  20973. +#define Kcu    3    /* Cursor up */
  20974. +/* Shift/alt modifiers etc */
  20975. +#define KMd    0xF7
  20976. +#define KSHIFT        K(KMd, 0 )
  20977. +#define KALTGR        K(KMd, 1 )
  20978. +#define KCTRL        K(KMd, 2 )
  20979. +#define KALT        K(KMd, 3 )
  20980. +/* Meta */
  20981. +#define KMt    0xF8
  20982. +#define KAs    0xF9
  20983. +#define KPADA_0        K(KAs, 0 )
  20984. +#define KPADA_1        K(KAs, 1 )
  20985. +#define KPADA_2        K(KAs, 2 )
  20986. +#define KPADA_3        K(KAs, 3 )
  20987. +#define KPADA_4        K(KAs, 4 )
  20988. +#define KPADA_5        K(KAs, 5 )
  20989. +#define KPADA_6        K(KAs, 6 )
  20990. +#define KPADA_7        K(KAs, 7 )
  20991. +#define KPADA_8        K(KAs, 8 )
  20992. +#define KPADA_9        K(KAs, 9 )
  20993. +#define KPADB_0        K(KAs,10 )
  20994. +#define KPADB_1        K(KAs,11 )
  20995. +#define KPADB_2        K(KAs,12 )
  20996. +#define KPADB_3        K(KAs,13 )
  20997. +#define KPADB_4        K(KAs,14 )
  20998. +#define KPADB_5        K(KAs,15 )
  20999. +#define KPADB_6        K(KAs,16 )
  21000. +#define KPADB_7        K(KAs,17 )
  21001. +#define KPADB_8        K(KAs,18 )
  21002. +#define KPADB_9        K(KAs,19 )
  21003. +/* Locking keys */
  21004. +#define KLk    0xFA
  21005. +/* Letters */
  21006. +#define KTl    0xFB
  21007. +
  21008. +u_short plain_map[]=
  21009. +{
  21010. +  K(KTn, 27),K(KTf,  0),K(KTf,  1),K(KTf,  2 ),K(KTf,  3),K(KTf,  4),K(KTf,  5 ),K(KTf,  6),
  21011. +  K(KTf,  7),K(KTf,  8),K(KTf,  9),K(KTf, 10 ),K(KTf, 11),KIGNORE   ,KSCRLLK    ,KINTR     ,
  21012. +  K(KTn,'`'),K(KTn,'1'),K(KTn,'2'),K(KTn,'3' ),K(KTn,'4'),K(KTn,'5'),K(KTn,'6' ),K(KTn,'7'),
  21013. +  K(KTn,'8'),K(KTn,'9'),K(KTn,'0'),K(KTn,'-' ),K(KTn,'='),K(KTn,'£'),K(KTn,127 ),K(KTf,21 ),
  21014. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,K(KTn,  9 ),K(KTl,'q'),
  21015. +  K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
  21016. +  K(KTl,'p'),K(KTn,'['),K(KTn,']'),K(KTn,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  21017. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTl,'a'),K(KTl,'s'),K(KTl,'d' ),K(KTl,'f'),
  21018. +  K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),K(KTn,';'),K(KTn,'\''),KENTER    ,
  21019. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTl,'z' ),K(KTl,'x'),
  21020. +  K(KTl,'c'),K(KTl,'v'),K(KTl,'b'),K(KTl,'n' ),K(KTl,'m'),K(KTn,','),K(KTn,'.' ),K(KTn,'/'),
  21021. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn,' '),
  21022. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  21023. +};
  21024. +
  21025. +u_short shift_map[]=
  21026. +{
  21027. +  K(KTn, 27),K(KTf, 10),K(KTf, 11),K(KTf, 12 ),K(KTf, 13),K(KTf, 14),K(KTf, 15 ),K(KTf, 16),
  21028. +  K(KTf, 17),K(KTf, 18),K(KTf, 19),K(KTf, 20 ),K(KTf, 21),KIGNORE   ,KMEM       ,KINTR     ,
  21029. +  K(KTn,'~'),K(KTn,'!'),K(KTn,'@'),K(KTn,'#' ),K(KTn,'$'),K(KTn,'%'),K(KTn,'^' ),K(KTn,'&'),
  21030. +  K(KTn,'*'),K(KTn,'('),K(KTn,')'),K(KTn,'_' ),K(KTn,'+'),K(KTn,'¤'),K(KTn,127 ),K(KTf,21 ),
  21031. +  K(KTf,20 ),KSCRLBAK  ,KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,K(KTn,  9 ),K(KTl,'Q'),
  21032. +  K(KTl,'W'),K(KTl,'E'),K(KTl,'R'),K(KTl,'T' ),K(KTl,'Y'),K(KTl,'U'),K(KTl,'I' ),K(KTl,'O'),
  21033. +  K(KTl,'P'),K(KTn,'{'),K(KTn,'}'),K(KTn,'|' ),K(KTf,22 ),K(KTf,23 ),KSCRLFOR   ,KPAD_7    ,
  21034. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTl,'A'),K(KTl,'S'),K(KTl,'D' ),K(KTl,'F'),
  21035. +  K(KTl,'G'),K(KTl,'H'),K(KTl,'J'),K(KTl,'K' ),K(KTl,'L'),K(KTn,':'),K(KTn,'"' ),KENTER    ,
  21036. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTl,'Z' ),K(KTl,'X'),
  21037. +  K(KTl,'C'),K(KTl,'V'),K(KTl,'B'),K(KTl,'N' ),K(KTl,'M'),K(KTn,'<'),K(KTn,'>' ),K(KTn,'?'),
  21038. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn,' '),
  21039. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  21040. +};
  21041. +
  21042. +u_short altgr_map[]=
  21043. +{
  21044. +  KIGNORE   ,K(KCn,12 ),K(KCn,13 ),K(KCn,14  ),K(KCn,15 ),K(KCn,16 ),K(KCn,17  ),K(KCn, 18),
  21045. +  K(KCn, 19),K(KCn,20 ),K(KCn,21 ),K(KCn,22  ),K(KCn,23 ),KIGNORE   ,KREGS      ,KINTR     ,
  21046. +  KIGNORE   ,KIGNORE   ,K(KTn,'@'),KIGNORE    ,K(KTn,'$'),KIGNORE   ,KIGNORE    ,K(KTn,'{'),
  21047. +  K(KTn,'['),K(KTn,']'),K(KTn,'}'),K(KTn,'\\'),KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,21 ),
  21048. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KTl,'q'),
  21049. +  K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
  21050. +  K(KTl,'p'),KIGNORE   ,K(KTn,'~'),KIGNORE    ,K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPADB_7   ,
  21051. +  KPADB_8   ,KPADB_9   ,KPAD_MI   ,KCTRL      ,K(KAs,20 ),K(KTl,'s'),K(KAs,23  ),K(KAs,25 ),
  21052. +  K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),KIGNORE   ,KIGNORE    ,KENTER    ,
  21053. +  KPADB_4   ,KPADB_5   ,KPADB_6   ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTl,'z' ),K(KTl,'x'),
  21054. +  K(KAs,22 ),K(KTl,'v'),K(KTl,21 ),K(KTl,'n' ),K(KTl,'m'),KIGNORE   ,KIGNORE    ,KIGNORE   ,
  21055. +  KSHIFT    ,K(KTc,Kcu),KPADB_1   ,KPADB_2    ,KPADB_3   ,KCAPSLK   ,KALT       ,KIGNORE   ,
  21056. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPADB_0   ,KPAD_DT    ,KPAD_EN
  21057. +};
  21058. +
  21059. +u_short ctrl_map[]=
  21060. +{
  21061. +  KIGNORE   ,K(KTf,  0),K(KTf,  1),K(KTf,  2 ),K(KTf,  3),K(KTf,  4),K(KTf, 5  ),K(KTf,  6),
  21062. +  K(KTf,  7),K(KTf,  8),K(KTf,  9),K(KTf, 10 ),K(KTf, 11),KIGNORE   ,KSTAT      ,KINTR     ,
  21063. +  KIGNORE   ,K(KTn, 1 ),K(KTn, 2 ),K(KTn, 3  ),K(KTn, 4 ),K(KTn, 5 ),K(KTn, 6  ),K(KTn, 7 ),
  21064. +  K(KTn, 8 ),K(KTn, 9 ),K(KTn, 0 ),K(KTn,31  ),KIGNORE   ,KIGNORE   ,K(KTn, 8  ),K(KTf,21 ),
  21065. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KTn,17 ),
  21066. +  K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20  ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9  ),K(KTn,15 ),
  21067. +  K(KTn,16 ),K(KTn,27 ),K(KTn,29 ),K(KTn,28  ),K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  21068. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4  ),K(KTn, 6 ),
  21069. +  K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11  ),K(KTn,12 ),KIGNORE   ,K(KTn, 7  ),KENTER    ,
  21070. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTn,26  ),K(KTn,24 ),
  21071. +  K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14  ),K(KTn,13 ),KIGNORE   ,KCOMPOSE   ,K(KTn,127),
  21072. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn, 0 ),
  21073. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  21074. +};
  21075. +
  21076. +u_short shift_ctrl_map[]=
  21077. +{
  21078. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,
  21079. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KFLOPPY    ,KINTR     ,
  21080. +  KIGNORE   ,KIGNORE   ,K(KTn, 0 ),KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,
  21081. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,K(KTn,31  ),KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,21 ),
  21082. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KTn,17 ),
  21083. +  K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20  ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9  ),K(KTn,15 ),
  21084. +  K(KTn,16 ),KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  21085. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4  ),K(KTn, 6 ),
  21086. +  K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11  ),K(KTn,12 ),KIGNORE   ,K(KTn, 7  ),KENTER    ,
  21087. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTn,26  ),K(KTn,24 ),
  21088. +  K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14  ),K(KTn,13 ),KIGNORE   ,KIGNORE    ,KIGNORE   ,
  21089. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn, 0 ),
  21090. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  21091. +};
  21092. +
  21093. +u_short alt_map[]=
  21094. +{
  21095. +  K(KMt,27 ),K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2  ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5  ),K(KCn, 6 ),
  21096. +  K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10  ),K(KCn,11 ),KIGNORE   ,KSCRLLK    ,KINTR     ,
  21097. +  K(KMt,'`'),K(KMt,'1'),K(KMt,'2'),K(KMt,'3' ),K(KMt,'4'),K(KMt,'5'),K(KMt,'6' ),K(KMt,'7'),
  21098. +  K(KMt,'8'),K(KMt,'9'),K(KMt,'0'),K(KMt,'-' ),K(KMt,'='),K(KMt,'£'),K(KMt,127 ),K(KTf,21 ),
  21099. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,K(KMt, 9  ),K(KMt,'q'),
  21100. +  K(KMt,'w'),K(KMt,'e'),K(KMt,'r'),K(KMt,'t' ),K(KMt,'y'),K(KMt,'u'),K(KMt,'i' ),K(KMt,'o'),
  21101. +  K(KMt,'p'),K(KMt,'['),K(KMt,']'),K(KMt,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPADA_7   ,
  21102. +  KPADA_8   ,KPADA_9   ,KPAD_MI   ,KCTRL      ,K(KMt,'a'),K(KMt,'s'),K(KMt,'d' ),K(KMt,'f'),
  21103. +  K(KMt,'g'),K(KMt,'h'),K(KMt,'j'),K(KMt,'k' ),K(KMt,'l'),K(KMt,';'),K(KMt,'\''),K(KMt,13 ),
  21104. +  KPADA_4   ,KPADA_5   ,KPADA_6   ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KMt,'z' ),K(KMt,'x'),
  21105. +  K(KMt,'c'),K(KMt,'v'),K(KMt,'b'),K(KMt,'n' ),K(KMt,'m'),K(KMt,','),K(KMt,'.' ),KIGNORE   ,
  21106. +  KSHIFT    ,K(KTc,Kcu),KPADA_1   ,KPADA_2    ,KPADA_3   ,KCAPSLK   ,KALT       ,K(KMt,' '),
  21107. +  KALTGR    ,KCTRL     ,CONS_DEC  ,K(KTc,Kcd ),CONS_INC  ,KPADA_0   ,KPAD_DT    ,KPAD_EN
  21108. +};
  21109. +
  21110. +u_short ctrl_alt_map[]=
  21111. +{
  21112. +  KIGNORE   ,K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2  ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5  ),K(KCn, 6 ),
  21113. +  K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10  ),K(KCn,11 ),KIGNORE   ,KIGNORE    ,KINTR     ,
  21114. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,
  21115. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,21 ),
  21116. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KMt,17 ),
  21117. +  K(KMt,23 ),K(KMt, 5 ),K(KMt,18 ),K(KMt,20  ),K(KMt,25 ),K(KMt,21 ),K(KMt, 9  ),K(KMt,15 ),
  21118. +  K(KMt,16 ),KIGNORE   ,KIGNORE   ,KIGNORE    ,KREBOOT   ,K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  21119. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KMt, 1 ),K(KMt,19 ),K(KMt, 4  ),K(KMt, 6 ),
  21120. +  K(KMt, 7 ),K(KMt, 8 ),K(KMt,10 ),K(KMt,11  ),K(KMt,12 ),KIGNORE   ,KIGNORE    ,KENTER    ,
  21121. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KMt,26  ),K(KMt,24 ),
  21122. +  K(KMt, 3 ),K(KMt,22 ),K(KMt, 2 ),K(KMt,14  ),K(KMt,13 ),KIGNORE   ,KIGNORE    ,KIGNORE   ,
  21123. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,KIGNORE   ,
  21124. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KREBOOT    ,KPAD_EN
  21125. +};
  21126. +
  21127. +ushort *key_maps[MAX_NR_KEYMAPS] = {
  21128. +    plain_map, shift_map, altgr_map, 0,
  21129. +    ctrl_map, shift_ctrl_map, 0, 0,
  21130. +    alt_map, 0, 0, 0,
  21131. +    ctrl_alt_map,    0
  21132. +};
  21133. +
  21134. +unsigned int keymap_count = 7;
  21135. +
  21136. +/*
  21137. + * Philosophy: most people do not define more strings, but they who do
  21138. + * often want quite a lot of string space. So, we statically allocate
  21139. + * the default and allocate dynamically in chunks of 512 bytes.
  21140. + */
  21141. +
  21142. +char func_buf[] = {
  21143. +    '\033', '[', '[', 'A', 0,
  21144. +    '\033', '[', '[', 'B', 0,
  21145. +    '\033', '[', '[', 'C', 0,
  21146. +    '\033', '[', '[', 'D', 0,
  21147. +    '\033', '[', '[', 'E', 0,
  21148. +    '\033', '[', '1', '7', '~', 0,
  21149. +    '\033', '[', '1', '8', '~', 0,
  21150. +    '\033', '[', '1', '9', '~', 0,
  21151. +    '\033', '[', '2', '0', '~', 0,
  21152. +    '\033', '[', '2', '1', '~', 0,
  21153. +    '\033', '[', '2', '3', '~', 0,
  21154. +    '\033', '[', '2', '4', '~', 0,
  21155. +    '\033', '[', '2', '5', '~', 0,
  21156. +    '\033', '[', '2', '6', '~', 0,
  21157. +    '\033', '[', '2', '8', '~', 0,
  21158. +    '\033', '[', '2', '9', '~', 0,
  21159. +    '\033', '[', '3', '1', '~', 0,
  21160. +    '\033', '[', '3', '2', '~', 0,
  21161. +    '\033', '[', '3', '3', '~', 0,
  21162. +    '\033', '[', '3', '4', '~', 0,
  21163. +    '\033', '[', '1', '~', 0,
  21164. +    '\033', '[', '2', '~', 0,
  21165. +    '\033', '[', '3', '~', 0,
  21166. +    '\033', '[', '4', '~', 0,
  21167. +    '\033', '[', '5', '~', 0,
  21168. +    '\033', '[', '6', '~', 0,
  21169. +    '\033', '[', 'M', 0,
  21170. +    '\033', '[', 'P', 0,
  21171. +};
  21172. +
  21173. +char *funcbufptr = func_buf;
  21174. +int funcbufsize = sizeof(func_buf);
  21175. +int funcbufleft = 0;          /* space left */
  21176. +
  21177. +char *func_table[MAX_NR_FUNC] = {
  21178. +    func_buf + 0,
  21179. +    func_buf + 5,
  21180. +    func_buf + 10,
  21181. +    func_buf + 15,
  21182. +    func_buf + 20,
  21183. +    func_buf + 25,
  21184. +    func_buf + 31,
  21185. +    func_buf + 37,
  21186. +    func_buf + 43,
  21187. +    func_buf + 49,
  21188. +    func_buf + 55,
  21189. +    func_buf + 61,
  21190. +    func_buf + 67,
  21191. +    func_buf + 73,
  21192. +    func_buf + 79,
  21193. +    func_buf + 85,
  21194. +    func_buf + 91,
  21195. +    func_buf + 97,
  21196. +    func_buf + 103,
  21197. +    func_buf + 109,
  21198. +    func_buf + 115,
  21199. +    func_buf + 120,
  21200. +    func_buf + 125,
  21201. +    func_buf + 130,
  21202. +    func_buf + 135,
  21203. +    func_buf + 140,
  21204. +    func_buf + 145,
  21205. +    0,
  21206. +    0,
  21207. +    func_buf + 149,
  21208. +    0,
  21209. +};
  21210. +
  21211. +struct kbdiacr accent_table[MAX_DIACR] = {
  21212. +    {'`', 'A', '\300'},    {'`', 'a', '\340'},
  21213. +    {'\'', 'A', '\301'},    {'\'', 'a', '\341'},
  21214. +    {'^', 'A', '\302'},    {'^', 'a', '\342'},
  21215. +    {'~', 'A', '\303'},    {'~', 'a', '\343'},
  21216. +    {'"', 'A', '\304'},    {'"', 'a', '\344'},
  21217. +    {'O', 'A', '\305'},    {'o', 'a', '\345'},
  21218. +    {'0', 'A', '\305'},    {'0', 'a', '\345'},
  21219. +    {'A', 'A', '\305'},    {'a', 'a', '\345'},
  21220. +    {'A', 'E', '\306'},    {'a', 'e', '\346'},
  21221. +    {',', 'C', '\307'},    {',', 'c', '\347'},
  21222. +    {'`', 'E', '\310'},    {'`', 'e', '\350'},
  21223. +    {'\'', 'E', '\311'},    {'\'', 'e', '\351'},
  21224. +    {'^', 'E', '\312'},    {'^', 'e', '\352'},
  21225. +    {'"', 'E', '\313'},    {'"', 'e', '\353'},
  21226. +    {'`', 'I', '\314'},    {'`', 'i', '\354'},
  21227. +    {'\'', 'I', '\315'},    {'\'', 'i', '\355'},
  21228. +    {'^', 'I', '\316'},    {'^', 'i', '\356'},
  21229. +    {'"', 'I', '\317'},    {'"', 'i', '\357'},
  21230. +    {'-', 'D', '\320'},    {'-', 'd', '\360'},
  21231. +    {'~', 'N', '\321'},    {'~', 'n', '\361'},
  21232. +    {'`', 'O', '\322'},    {'`', 'o', '\362'},
  21233. +    {'\'', 'O', '\323'},    {'\'', 'o', '\363'},
  21234. +    {'^', 'O', '\324'},    {'^', 'o', '\364'},
  21235. +    {'~', 'O', '\325'},    {'~', 'o', '\365'},
  21236. +    {'"', 'O', '\326'},    {'"', 'o', '\366'},
  21237. +    {'/', 'O', '\330'},    {'/', 'o', '\370'},
  21238. +    {'`', 'U', '\331'},    {'`', 'u', '\371'},
  21239. +    {'\'', 'U', '\332'},    {'\'', 'u', '\372'},
  21240. +    {'^', 'U', '\333'},    {'^', 'u', '\373'},
  21241. +    {'"', 'U', '\334'},    {'"', 'u', '\374'},
  21242. +    {'\'', 'Y', '\335'},    {'\'', 'y', '\375'},
  21243. +    {'T', 'H', '\336'},    {'t', 'h', '\376'},
  21244. +    {'s', 's', '\337'},    {'"', 'y', '\377'},
  21245. +    {'s', 'z', '\337'},    {'i', 'j', '\377'},
  21246. +};
  21247. +
  21248. +unsigned int accent_table_size = 68;
  21249. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/diacr.h linux/arch/arm/drivers/char/diacr.h
  21250. --- linux.orig/arch/arm/drivers/char/diacr.h    Thu Jan  1 01:00:00 1970
  21251. +++ linux/arch/arm/drivers/char/diacr.h    Thu Aug  8 23:34:50 1996
  21252. @@ -0,0 +1,8 @@
  21253. +#ifndef _DIACR_H
  21254. +#define _DIACR_H
  21255. +#include <linux/kd.h>
  21256. +
  21257. +extern struct kbdiacr accent_table[];
  21258. +extern unsigned int accent_table_size;
  21259. +
  21260. +#endif /* _DIACR_H */
  21261. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/kbd_kern.h linux/arch/arm/drivers/char/kbd_kern.h
  21262. --- linux.orig/arch/arm/drivers/char/kbd_kern.h    Thu Jan  1 01:00:00 1970
  21263. +++ linux/arch/arm/drivers/char/kbd_kern.h    Sat Sep  7 10:31:12 1996
  21264. @@ -0,0 +1,131 @@
  21265. +#ifndef _KBD_KERN_H
  21266. +#define _KBD_KERN_H
  21267. +
  21268. +#include <linux/interrupt.h>
  21269. +#include <linux/keyboard.h>
  21270. +
  21271. +extern int shift_state;
  21272. +extern char *func_table[MAX_NR_FUNC];
  21273. +extern char func_buf[];
  21274. +extern char *funcbufptr;
  21275. +extern int funcbufsize, funcbufleft;
  21276. +
  21277. +#ifndef _VT_KERN_H
  21278. +#include "vt_kern.h"
  21279. +#endif
  21280. +
  21281. +extern void compute_shiftstate (void);
  21282. +extern int kbd_struct_init (struct vt *vt, int init);
  21283. +extern int kbd_ioctl (struct vt *vt, int cmd, unsigned long arg);
  21284. +extern int kbd_init (void);
  21285. +
  21286. +/*
  21287. + * kbd->xxx contains the VC-local things (flag settings etc..)
  21288. + *
  21289. + * Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h
  21290. + *       The code in KDGETLED / KDSETLED depends on the internal and
  21291. + *       external order being the same.
  21292. + *
  21293. + * Note: lockstate is used as index in the array key_map.
  21294. + */
  21295. +struct kbd_struct {
  21296. +
  21297. +    unsigned char lockstate;
  21298. +/* 8 modifiers - the names do not have any meaning at all;
  21299. +   they can be associated to arbitrarily chosen keys */
  21300. +#define VC_SHIFTLOCK    KG_SHIFT    /* shift lock mode */
  21301. +#define VC_ALTGRLOCK    KG_ALTGR    /* altgr lock mode */
  21302. +#define VC_CTRLLOCK    KG_CTRL     /* control lock mode */
  21303. +#define VC_ALTLOCK    KG_ALT      /* alt lock mode */
  21304. +#define VC_SHIFTLLOCK    KG_SHIFTL    /* shiftl lock mode */
  21305. +#define VC_SHIFTRLOCK    KG_SHIFTR    /* shiftr lock mode */
  21306. +#define VC_CTRLLLOCK    KG_CTRLL     /* ctrll lock mode */
  21307. +#define VC_CTRLRLOCK    KG_CTRLR     /* ctrlr lock mode */
  21308. +    unsigned char slockstate;     /* for `sticky' Shift, Ctrl, etc. */
  21309. +
  21310. +    unsigned char ledmode:2;     /* one 2-bit value */
  21311. +#define LED_SHOW_FLAGS 0        /* traditional state */
  21312. +#define LED_SHOW_IOCTL 1        /* only change leds upon ioctl */
  21313. +#define LED_SHOW_MEM 2          /* `heartbeat': peek into memory */
  21314. +
  21315. +    unsigned char ledflagstate:3;    /* flags, not lights */
  21316. +    unsigned char default_ledflagstate:3;
  21317. +#define VC_SCROLLOCK    0    /* scroll-lock mode */
  21318. +#define VC_NUMLOCK    1    /* numeric lock mode */
  21319. +#define VC_CAPSLOCK    2    /* capslock mode */
  21320. +
  21321. +    unsigned char kbdmode:2;    /* one 2-bit value */
  21322. +#define VC_XLATE    0    /* translate keycodes using keymap */
  21323. +#define VC_MEDIUMRAW    1    /* medium raw (keycode) mode */
  21324. +#define VC_RAW        2    /* raw (scancode) mode */
  21325. +#define VC_UNICODE    3    /* Unicode mode */
  21326. +
  21327. +    unsigned char modeflags:5;
  21328. +#define VC_APPLIC    0    /* application key mode */
  21329. +#define VC_CKMODE    1    /* cursor key mode */
  21330. +#define VC_REPEAT    2    /* keyboard repeat */
  21331. +#define VC_CRLF        3    /* 0 - enter sends CR, 1 - enter sends CRLF */
  21332. +#define VC_META        4    /* 0 - meta, 1 - meta=prefix with ESC */
  21333. +};
  21334. +
  21335. +extern unsigned char getledstate(void);
  21336. +extern void setledstate(struct kbd_struct *kbd, unsigned int led);
  21337. +
  21338. +extern inline void set_leds(void)
  21339. +{
  21340. +    mark_bh(KEYBOARD_BH);
  21341. +}
  21342. +
  21343. +extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
  21344. +{
  21345. +    return ((kbd->modeflags >> flag) & 1);
  21346. +}
  21347. +
  21348. +extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
  21349. +{
  21350. +    return ((kbd->ledflagstate >> flag) & 1);
  21351. +}
  21352. +
  21353. +extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
  21354. +{
  21355. +    kbd->modeflags |= 1 << flag;
  21356. +}
  21357. +
  21358. +extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
  21359. +{
  21360. +    kbd->ledflagstate |= 1 << flag;
  21361. +}
  21362. +
  21363. +extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
  21364. +{
  21365. +    kbd->modeflags &= ~(1 << flag);
  21366. +}
  21367. +
  21368. +extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
  21369. +{
  21370. +    kbd->ledflagstate &= ~(1 << flag);
  21371. +}
  21372. +
  21373. +extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
  21374. +{
  21375. +    kbd->lockstate ^= 1 << flag;
  21376. +}
  21377. +
  21378. +extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
  21379. +{
  21380. +    kbd->slockstate ^= 1 << flag;
  21381. +}
  21382. +
  21383. +extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
  21384. +{
  21385. +    kbd->modeflags ^= 1 << flag;
  21386. +}
  21387. +
  21388. +extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
  21389. +{
  21390. +    kbd->ledflagstate ^= 1 << flag;
  21391. +}
  21392. +
  21393. +#define U(x) ((x) ^ 0xf000)
  21394. +
  21395. +#endif
  21396. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/kbdmouse.c linux/arch/arm/drivers/char/kbdmouse.c
  21397. --- linux.orig/arch/arm/drivers/char/kbdmouse.c    Thu Jan  1 01:00:00 1970
  21398. +++ linux/arch/arm/drivers/char/kbdmouse.c    Tue Jul  2 09:47:58 1996
  21399. @@ -0,0 +1,178 @@
  21400. +/*
  21401. + * linux/arch/arm/drivers/char/kbdmouse.c
  21402. + *
  21403. + * Copyright (C) 1995, 1996 Russell King
  21404. + *
  21405. + * Medium-level interface for quadrature mouse connected to the keyboard.
  21406. + */
  21407. +
  21408. +#include <linux/module.h>
  21409. +
  21410. +#include <linux/kernel.h>
  21411. +#include <linux/sched.h>
  21412. +#include <linux/signal.h>
  21413. +#include <linux/errno.h>
  21414. +#include <linux/mm.h>
  21415. +#include <linux/miscdevice.h>
  21416. +#include <linux/random.h>
  21417. +
  21418. +#include <asm/system.h>
  21419. +#include <asm/segment.h>
  21420. +
  21421. +char   mouse_buttons;
  21422. +int    mouse_dxpos;
  21423. +int    mouse_dypos;
  21424. +int    mouse_present;
  21425. +char   mouse_ready;
  21426. +char   mouse_active;
  21427. +struct wait_queue *mouse_wait;
  21428. +struct fasync_struct *fasyncptr;
  21429. +
  21430. +static int fasync_mouse(struct inode *inode, struct file *filp, int on)
  21431. +{
  21432. +    int retval;
  21433. +
  21434. +    retval = fasync_helper(inode, filp, on, &fasyncptr);
  21435. +    if (retval < 0)
  21436. +    return retval;
  21437. +    return 0;
  21438. +}
  21439. +
  21440. +static void close_mouse(struct inode *inode, struct file *file)
  21441. +{
  21442. +    fasync_mouse (inode, file, 0);
  21443. +    if (--mouse_active)
  21444. +    return;
  21445. +    mouse_ready = 0;
  21446. +
  21447. +    MOD_DEC_USE_COUNT;
  21448. +}
  21449. +
  21450. +static int open_mouse(struct inode *inode,struct file *file)
  21451. +{
  21452. +    unsigned long flags;
  21453. +
  21454. +    if (!mouse_present)
  21455. +    return -EINVAL;
  21456. +    if (mouse_active++)
  21457. +    return 0;
  21458. +
  21459. +    save_flags_cli (flags);
  21460. +    mouse_active  = 1;
  21461. +    mouse_ready   = 0;
  21462. +    mouse_dxpos   = 0;
  21463. +    mouse_dypos   = 0;
  21464. +    mouse_buttons = 0;
  21465. +    restore_flags (flags);
  21466. +
  21467. +    MOD_INC_USE_COUNT;
  21468. +
  21469. +    return 0;
  21470. +}
  21471. +
  21472. +static int write_mouse(struct inode *inode,struct file *file,const char *buffer,int count)
  21473. +{
  21474. +    return -EINVAL;
  21475. +}
  21476. +
  21477. +static int read_mouse(struct inode *inode,struct file *file,char *buffer,int count)
  21478. +{
  21479. +    unsigned long flags;
  21480. +    int dxpos, dypos, i, buttons;
  21481. +
  21482. +    if (count < 3)
  21483. +    return -EINVAL;
  21484. +    if ((i = verify_area(VERIFY_WRITE, buffer, count)))
  21485. +    return i;
  21486. +    if (!mouse_ready)
  21487. +    return -EAGAIN;
  21488. +
  21489. +    save_flags_cli (flags);
  21490. +
  21491. +    dxpos = mouse_dxpos;
  21492. +    dypos = mouse_dypos;
  21493. +    buttons = mouse_buttons ^ 7;
  21494. +
  21495. +    if (dxpos < -127)
  21496. +    dxpos =- 127;
  21497. +    if (dxpos > 127)
  21498. +    dxpos = 127;
  21499. +    if (dypos <- 127)
  21500. +    dypos =- 127;
  21501. +    if (dypos > 127)
  21502. +    dypos = 127;
  21503. +
  21504. +    mouse_dxpos -= dxpos;
  21505. +    mouse_dypos -= dypos;
  21506. +    mouse_ready = 0;
  21507. +
  21508. +    restore_flags (flags);
  21509. +
  21510. +    put_fs_byte ((char) buttons | 0x80, buffer);
  21511. +    put_fs_byte ((char) dxpos, buffer + 1);
  21512. +    put_fs_byte ((char) dypos, buffer + 2);
  21513. +    for(i = 3; i < count; i++)
  21514. +    put_fs_byte (0x00, buffer + i);
  21515. +
  21516. +    return i;
  21517. +}
  21518. +
  21519. +static int select_mouse(struct inode *inode,struct file *file,int sel_type,select_table *wait)
  21520. +{
  21521. +    if (sel_type == SEL_IN) {
  21522. +    if (mouse_ready)
  21523. +        return 1;
  21524. +    select_wait (&mouse_wait,wait);
  21525. +    }
  21526. +    return 0;
  21527. +}
  21528. +
  21529. +struct file_operations kbd_mouse_fops=
  21530. +{
  21531. +    NULL,            /* mouse_seek */
  21532. +    read_mouse,
  21533. +    write_mouse,
  21534. +    NULL,            /* mouse_readdir */
  21535. +    select_mouse,
  21536. +    NULL,            /* mouse_ioctl */
  21537. +    NULL,            /* mouse_mmap */
  21538. +    open_mouse,
  21539. +    close_mouse,
  21540. +    NULL,
  21541. +    fasync_mouse,
  21542. +};
  21543. +
  21544. +static struct miscdevice kbd_mouse = {
  21545. +    6, "kbdmouse", &kbd_mouse_fops, NULL, NULL
  21546. +};
  21547. +
  21548. +int arch_mouse_init(void)
  21549. +{
  21550. +    unsigned long flags;
  21551. +
  21552. +    save_flags_cli (flags);
  21553. +
  21554. +    mouse_buttons=0;
  21555. +    mouse_dxpos  =0;
  21556. +    mouse_dypos  =0;
  21557. +    mouse_present=1;
  21558. +    mouse_ready  =0;
  21559. +    mouse_active =0;
  21560. +    mouse_wait   =NULL;
  21561. +
  21562. +    restore_flags (flags);
  21563. +    misc_register (&kbd_mouse);
  21564. +    return 0;
  21565. +}
  21566. +
  21567. +#ifdef MODULE
  21568. +int init_module(void)
  21569. +{
  21570. +    return arch_mouse_init();
  21571. +}
  21572. +
  21573. +void cleanup_module(void)
  21574. +{
  21575. +    misc_deregister (&kbd_mouse);
  21576. +}
  21577. +#endif
  21578. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/keyboard.c linux/arch/arm/drivers/char/keyboard.c
  21579. --- linux.orig/arch/arm/drivers/char/keyboard.c    Thu Jan  1 01:00:00 1970
  21580. +++ linux/arch/arm/drivers/char/keyboard.c    Sat Aug 24 18:34:06 1996
  21581. @@ -0,0 +1,1769 @@
  21582. +/*
  21583. + * linux/arch/arm/drivers/block/keyboard.c
  21584. + *
  21585. + * Keyboard driver for Linux using Latin-1.
  21586. + *
  21587. + * Written for linux by Johan Myreen as a translation from
  21588. + * the assembly version by Linus (with diacriticals added)
  21589. + *
  21590. + * Some additional features added by Christoph Niemann (ChN), March 1993
  21591. + *
  21592. + * Loadable keymaps by Risto Kankkunen, May 1993
  21593. + *
  21594. + * Diacriticals redone & other small changes, aeb@cwi.nl, June 93
  21595. + * Added decr/incr_console, dynamic keymaps, unicode support,
  21596. + * dynamic function/string keys, led setting,  Sept 1994
  21597. + * `Sticky' modifier keys, 951006
  21598. + *
  21599. + * Majorly altered for use with arm Russell King (rmk92@ecs.soton.ac.uk).
  21600. + */
  21601. +
  21602. +#define IRQ_KEYBOARDRX 15
  21603. +#define IRQ_KEYBOARDTX 14
  21604. +
  21605. +#define VERSION 104
  21606. +
  21607. +#include <linux/config.h>
  21608. +#include <linux/sched.h>
  21609. +#include <linux/interrupt.h>
  21610. +#include <linux/tty.h>
  21611. +#include <linux/tty_flip.h>
  21612. +#include <linux/mm.h>
  21613. +#include <linux/malloc.h>
  21614. +#include <linux/ptrace.h>
  21615. +#include <linux/signal.h>
  21616. +#include <linux/timer.h>
  21617. +#include <linux/random.h>
  21618. +#include <linux/ctype.h>
  21619. +
  21620. +#include <asm/bitops.h>
  21621. +#include <asm/irq.h>
  21622. +#include <asm/hardware.h>
  21623. +
  21624. +#include "kbd_kern.h"
  21625. +#include "diacr.h"
  21626. +#include "vt_kern.h"
  21627. +
  21628. +#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
  21629. +
  21630. +#define KBD_REPORT_ERR
  21631. +#define KBD_REPORT_UNKN
  21632. +
  21633. +#ifndef KBD_DEFMODE
  21634. +#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
  21635. +#endif
  21636. +
  21637. +#ifndef KBD_DEFLEDS
  21638. +/*
  21639. + * Starts with NumLock off.
  21640. + */
  21641. +#define KBD_DEFLEDS 0
  21642. +#endif
  21643. +
  21644. +#ifndef KBD_DEFLOCK
  21645. +#define KBD_DEFLOCK 0
  21646. +#endif
  21647. +
  21648. +#define REPEAT_TIMEOUT HZ*300/1000
  21649. +#define REPEAT_RATE    HZ*30/1000
  21650. +
  21651. +/*
  21652. + * these are the valid i/o ports we're allowed to change. they map all the
  21653. + * video ports
  21654. + */
  21655. +#define GPFIRST 0x3b4
  21656. +#define GPLAST 0x3df
  21657. +#define GPNUM (GPLAST - GPFIRST + 1)
  21658. +
  21659. +extern ushort *key_maps[];
  21660. +extern unsigned int keymap_count;
  21661. +extern void ctrl_alt_del (void);
  21662. +
  21663. +/*
  21664. + * global state includes the following, and various static variables
  21665. + * in this module: shift_state, diacr, npadch, dead_key_next.
  21666. + * (last console is now a global variable).
  21667. + */
  21668. +
  21669. +/* shift state counters.. */
  21670. +static unsigned char k_down[NR_SHIFT] = {0, };
  21671. +/*
  21672. + * Key down counters
  21673. + */
  21674. +#define BITS_PER_SHORT (8*sizeof (unsigned short))
  21675. +static unsigned short key_down[256/BITS_PER_SHORT] = {0, };
  21676. +
  21677. +extern struct vt *last_console;
  21678. +static struct vt *want_console;
  21679. +static int dead_key_next;
  21680. +/*
  21681. + * In order to retrieve the shift_state (for the mouse server), either
  21682. + * the variable must be global, or a new procedure must be created to
  21683. + * return the value. I chose the former way.
  21684. + */
  21685. +/*static*/ int shift_state;
  21686. +static int npadch            = -1;        /* -1 or number assembled on pad */
  21687. +static unsigned char diacr;
  21688. +static char rep;                /* Flag telling character repeat */
  21689. +static int kbd_repeatkey     = -1;
  21690. +static int kbd_repeattimeout = REPEAT_TIMEOUT;
  21691. +static int kbd_repeatrate    = REPEAT_RATE;
  21692. +static int kbd_id            = -1;
  21693. +static struct wait_queue *kbd_waitq;
  21694. +
  21695. +static struct kbd_struct * kbd = NULL;
  21696. +static struct tty_struct * tty = NULL;
  21697. +
  21698. +extern void compute_shiftstate (void);
  21699. +
  21700. +typedef void (*k_hand)(unsigned char value, char up_flag);
  21701. +typedef void (k_handfn)(unsigned char value, char up_flag);
  21702. +
  21703. +static k_handfn
  21704. +    do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
  21705. +    do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
  21706. +
  21707. +static k_hand key_handler[16] = {
  21708. +    do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
  21709. +    do_meta, do_ascii, do_lock, do_lowercase, do_slock,
  21710. +    do_ignore, do_ignore, do_ignore
  21711. +};
  21712. +
  21713. +typedef void (*void_fnp)(void);
  21714. +typedef void (void_fn)(void);
  21715. +
  21716. +static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
  21717. +    num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
  21718. +    SAK, decr_console, incr_console, spawn_console, show_stack, bare_num;
  21719. +
  21720. +static void_fnp spec_fn_table[] = {
  21721. +    do_null,    enter,        show_ptregs,    show_mem,
  21722. +    show_state,    send_intr,    lastcons,    caps_toggle,
  21723. +    num,        hold,        scroll_forw,    scroll_back,
  21724. +    boot_it,    caps_on,    compose,    SAK,
  21725. +    decr_console,    incr_console,    show_stack,     bare_num
  21726. +};
  21727. +
  21728. +/* maximum values each key_handler can handle */
  21729. +const int max_vals[] = {
  21730. +    255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
  21731. +    NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
  21732. +    255, NR_ASCII - 1, NR_LOCK - 1, 255,
  21733. +    NR_LOCK - 1
  21734. +};
  21735. +
  21736. +const int NR_TYPES = SIZE(max_vals);
  21737. +
  21738. +static void put_queue(int);
  21739. +static unsigned char handle_diacr(unsigned char);
  21740. +
  21741. +/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
  21742. +static struct pt_regs * pt_regs;
  21743. +
  21744. +/*
  21745. + * Many other routines do put_queue, but I think either
  21746. + * they produce ASCII, or they produce some user-assigned
  21747. + * string, and in both cases we might assume that it is
  21748. + * in utf-8 already.
  21749. + */
  21750. +void to_utf8(ushort c) {
  21751. +    if (c < 0x80)
  21752. +    put_queue(c);            /*  0*******  */
  21753. +    else if (c < 0x800) {
  21754. +    put_queue(0xc0 | (c >> 6));     /*  110***** 10******  */
  21755. +    put_queue(0x80 | (c & 0x3f));
  21756. +    } else {
  21757. +    put_queue(0xe0 | (c >> 12));     /*  1110**** 10****** 10******  */
  21758. +    put_queue(0x80 | ((c >> 6) & 0x3f));
  21759. +    put_queue(0x80 | (c & 0x3f));
  21760. +    }
  21761. +     /* uft-8 is defined for words of up to 36 bits,
  21762. +       but we need only 16 bits here */
  21763. +}
  21764. +
  21765. +/*
  21766. + * ARM mouse specifics stuff.
  21767. + *
  21768. + * Since the mouse movements and buttons are part of the
  21769. + * keyboard protocol, we have to handle this part in this
  21770. + * driver.  The mouse specific parts are in arcmouse.c.
  21771. + */
  21772. +#ifdef CONFIG_KBDMOUSE
  21773. +extern struct wait_queue *mouse_wait;
  21774. +extern char        mouse_buttons;
  21775. +extern int        mouse_dxpos;
  21776. +extern int        mouse_dypos;
  21777. +extern char        mouse_ready;
  21778. +#endif
  21779. +/*
  21780. + * Protocol codes to send the keyboard.
  21781. + */
  21782. +/* reset keyboard */
  21783. +#define HRST 0xff
  21784. +/* reset response */
  21785. +#define RAK1 0xfe
  21786. +/* reset response */
  21787. +#define RAK2 0xfd
  21788. +/* Ack for first keyboard pair */
  21789. +#define BACK 0x3f
  21790. +/* Last data byte ack (key scanning + mouse movement scanning) */
  21791. +#define SMAK 0x33
  21792. +/* Last data byte ack (mouse movement scanning) */
  21793. +#define MACK 0x32
  21794. +/* Last data byte ack (key scanning) */
  21795. +#define SACK 0x31
  21796. +/* Last data byte ack (no scanning, mouse data) */
  21797. +#define NACK 0x30
  21798. +/* Request mouse data */
  21799. +#define RQMP 0x22
  21800. +/* nothing */
  21801. +#define PRST 0x21
  21802. +/* Request ID */
  21803. +#define RQID 0x20
  21804. +
  21805. +#define UP_FLAG 0x0100
  21806. +
  21807. +static unsigned char    kbd_sendvala[4];
  21808. +static unsigned char    kbd_sendptri;
  21809. +static unsigned char    kbd_sendptro;
  21810. +static unsigned char    ledstate;
  21811. +static unsigned char    getleds(void);
  21812. +
  21813. +/*
  21814. + * This array converts the scancode that we get from the keyboard to the
  21815. + * real rows/columns on the A5000 keyboard.  This might be keyboard specific...
  21816. + *
  21817. + * It is these values that we use to maintain the key down array.  That way, we
  21818. + * should pick up on the ghost key presses (which is what happens when you press
  21819. + * three keys, and the keyboard thinks you have pressed four!)
  21820. + *
  21821. + * Row 8 (0x80+c) is actually a column with one key per row.  It is isolated from
  21822. + * the other keys, and can't cause these problems (its used for shift, ctrl, alt etc).
  21823. + *
  21824. + * Illegal scancodes are denoted by an 0xff (in other words, we don't know about
  21825. + * them, and can't process them for ghosts).  This does however, cause problems with
  21826. + * autorepeat processing...
  21827. + */
  21828. +static unsigned char scancode_2_colrow[256] = {
  21829. +  0x01, 0x42, 0x32, 0x33, 0x43, 0x56, 0x5a, 0x6c, 0x7c, 0x5c, 0x5b, 0x6b, 0x7b, 0x84, 0x70, 0x60,
  21830. +  0x11, 0x51, 0x62, 0x63, 0x44, 0x54, 0x55, 0x45, 0x46, 0x4a, 0x3c, 0x4b, 0x59, 0x49, 0x69, 0x79,
  21831. +  0x83, 0x40, 0x30, 0x3b, 0x39, 0x38, 0x31, 0x61, 0x72, 0x73, 0x64, 0x74, 0x75, 0x65, 0x66, 0x6a,
  21832. +  0x1c, 0x2c, 0x7a, 0x36, 0x48, 0x68, 0x78, 0x20, 0x2b, 0x29, 0x28, 0x81, 0x71, 0x22, 0x23, 0x34,
  21833. +  0x24, 0x25, 0x35, 0x26, 0x3a, 0x0c, 0x2a, 0x76, 0x10, 0x1b, 0x19, 0x18, 0x82, 0xff, 0x21, 0x12,
  21834. +  0x13, 0x14, 0x04, 0x05, 0x15, 0x16, 0x1a, 0x0a, 0x85, 0x77, 0x00, 0x0b, 0x09, 0x02, 0x80, 0x03,
  21835. +  0x87, 0x86, 0x06, 0x17, 0x27, 0x07, 0x37, 0x08, 0xff,
  21836. +};
  21837. +
  21838. +static unsigned short ghost_down[128/BITS_PER_SHORT];
  21839. +
  21840. +/*
  21841. + * As yet, we don't support setting and getting the
  21842. + * key codes.  I'll have to find out where this is used.
  21843. + */
  21844. +int setkeycode(unsigned int scancode, unsigned int keycode)
  21845. +{
  21846. +#if 0
  21847. +    if (scancode < SC_LIM || scancode > 255 || keycode > 127)
  21848. +        return -EINVAL;
  21849. +    if (scancode < 128)
  21850. +        high_keys[scancode - SC_LIM] = keycode;
  21851. +    else
  21852. +        e0_keys[scancode - 128] = keycode;
  21853. +    return 0;
  21854. +#else
  21855. +    return -EINVAL;
  21856. +#endif
  21857. +}
  21858. +
  21859. +int getkeycode(unsigned int scancode)
  21860. +{
  21861. +#if 0
  21862. +    return
  21863. +        (scancode < SC_LIM || scancode > 255) ? -EINVAL :
  21864. +        (scancode < 128) ? high_keys[scancode - SC_LIM] :
  21865. +        e0_keys[scancode - 128];
  21866. +#else
  21867. +    return -EINVAL;
  21868. +#endif
  21869. +}
  21870. +
  21871. +
  21872. +/* ----------------------------------------------------------------------------------------- */
  21873. +/*
  21874. + * This is the keyboard specific part.
  21875. + */
  21876. +static void key_callback(unsigned long nr)
  21877. +{
  21878. +  rep = 1;
  21879. +  mark_bh (KEYBOARD_BH);
  21880. +}
  21881. +
  21882. +static struct timer_list key_timer =
  21883. +{
  21884. +  NULL, NULL, 0, 0, key_callback
  21885. +};
  21886. +
  21887. +static void kbd_key(unsigned int raw_keycode, int repeat_timeout)
  21888. +{
  21889. +    unsigned int up_flag;
  21890. +    unsigned int keycode;
  21891. +    unsigned char real_keycode;
  21892. +
  21893. +    up_flag = raw_keycode & UP_FLAG;
  21894. +    keycode = raw_keycode & 255;
  21895. +
  21896. +    /*
  21897. +     * Separate out the mouse stuff first
  21898. +     */
  21899. +    if (keycode >= 0x70 && keycode <= 0x72) {
  21900. +#ifdef CONFIG_KBDMOUSE
  21901. +    switch (keycode) {
  21902. +    case 0x70: /* Left mouse button */
  21903. +        if (up_flag)
  21904. +        mouse_buttons &= ~4;
  21905. +        else
  21906. +        mouse_buttons |= 4;
  21907. +        break;
  21908. +
  21909. +    case 0x71: /* Middle mouse button */
  21910. +        if (up_flag)
  21911. +        mouse_buttons &= ~2;
  21912. +        else
  21913. +        mouse_buttons |= 2;
  21914. +        break;
  21915. +
  21916. +    case 0x72:/* Right mouse button */
  21917. +        if (up_flag)
  21918. +        mouse_buttons &= ~1;
  21919. +        else
  21920. +        mouse_buttons |= 1;
  21921. +        break;
  21922. +    default:
  21923. +#ifdef KBD_REPORT_UNKN
  21924. +        printk ("kbd: unknown scancode 0x%04x\n", raw_keycode);
  21925. +#endif
  21926. +        return;
  21927. +    }
  21928. +    add_mouse_randomness (mouse_buttons << 16);
  21929. +    mouse_ready = 1;
  21930. +    wake_up_interruptible (&mouse_wait);
  21931. +#endif
  21932. +    mark_bh (KEYBOARD_BH);
  21933. +    return;
  21934. +    }
  21935. +
  21936. +    if (keycode >= 0x70) {
  21937. +#ifdef KBD_REPORT_UNKN
  21938. +    printk ("kbd: unknown scancode 0x%04x\n", raw_keycode);
  21939. +#endif
  21940. +    return;
  21941. +    }
  21942. +
  21943. +    real_keycode = scancode_2_colrow[keycode];
  21944. +
  21945. +    /*
  21946. +     * We have to work out if we accept this key press as a real key, or
  21947. +     * if it is a ghost.  IE. If you press three keys, the keyboard will think
  21948. +     * that you've pressed a fouth: (@ = key down, # = ghost)
  21949. +     *
  21950. +     *   0 1 2 3 4 5 6 7
  21951. +     *   | | | | | | | |
  21952. +     * 0-+-+-+-+-+-+-+-+-
  21953. +     *   | | | | | | | |
  21954. +     * 1-+-@-+-+-+-@-+-+-
  21955. +     *   | | | | | | | |
  21956. +     * 2-+-+-+-+-+-+-+-+-
  21957. +     *   | | | | | | | |
  21958. +     * 3-+-@-+-+-+-#-+-+-
  21959. +     *   | | | | | | | |
  21960. +     *
  21961. +     * This is what happens when you have a matrix keyboard...
  21962. +     */
  21963. +
  21964. +    if ((real_keycode & 0x80) == 0) {
  21965. +    int rr, kc = (real_keycode >> 4) & 7;
  21966. +    int cc;
  21967. +    unsigned short res, kdownkc;
  21968. +
  21969. +    kdownkc = ghost_down[kc] | (1 << (real_keycode & 15));
  21970. +
  21971. +    for (rr = 0; rr < 128/BITS_PER_SHORT; rr++)
  21972. +        if (rr != kc && (res = ghost_down[rr] & kdownkc)) {
  21973. +            /*
  21974. +         * we have found a second row with at least one key pressed in the
  21975. +             * same column.
  21976. +             */
  21977. +            for (cc = 0; res; res >>= 1)
  21978. +            cc += (res & 1);
  21979. +
  21980. +        if (cc > 1)
  21981. +            return; /* ignore it */
  21982. +        }
  21983. +    if (up_flag)
  21984. +        clear_bit (real_keycode, ghost_down);
  21985. +    else
  21986. +        set_bit (real_keycode, ghost_down);
  21987. +
  21988. +    }
  21989. +
  21990. +    if (kbd_repeatkey == (raw_keycode & ~UP_FLAG) || !up_flag)
  21991. +    kbd_repeatkey = -1;
  21992. +
  21993. +    add_keyboard_randomness (raw_keycode);
  21994. +
  21995. +    /*
  21996. +     * We have to disable interrupts here to prevent the timer from
  21997. +     * being put on the list twice or a key being released during
  21998. +     * the processing of autorepeat
  21999. +     */
  22000. +    del_timer (&key_timer);
  22001. +
  22002. +    tty = *vtdata.fgconsole->tty;
  22003. +    kbd = vtdata.fgconsole->kbd;
  22004. +
  22005. +    if (up_flag) {
  22006. +        rep = 0;
  22007. +    clear_bit (keycode, key_down);
  22008. +    /* don't report an error if key is already up - happens when a ghost key is released */
  22009. +    } else
  22010. +    rep = set_bit (keycode, key_down);
  22011. +
  22012. +    if (kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) {
  22013. +    put_queue (keycode | (up_flag ? 0x80 : 0));
  22014. +    return;
  22015. +    }
  22016. +
  22017. +    /*
  22018. +     * We have to do our own auto-repeat processing...
  22019. +     */
  22020. +    if (!up_flag && repeat_timeout) {
  22021. +        kbd_repeatkey = raw_keycode;
  22022. +    if (vc_kbd_mode(kbd, VC_REPEAT)) {
  22023. +        key_timer.expires = jiffies + repeat_timeout;
  22024. +        add_timer(&key_timer);
  22025. +    }
  22026. +    }
  22027. +
  22028. +    /*
  22029. +     * Repeat a key only if the input buffers are empty or the
  22030. +     * characters get echoed locally.  This makes key repeat
  22031. +     * usable with slow applications and under heavy loads.
  22032. +     */
  22033. +    if (!rep || (vc_kbd_mode (kbd, VC_REPEAT) && tty &&
  22034. +               (L_ECHO(tty) || (tty->driver.chars_in_buffer (tty) == 0)))) {
  22035. +    u_short keysym;
  22036. +    u_char  type;
  22037. +
  22038. +    /* the XOR below used to be an OR */
  22039. +    int     shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
  22040. +    u_short *key_map = key_maps[shift_final];
  22041. +
  22042. +    if (key_map != NULL) {
  22043. +        keysym = key_map[keycode];
  22044. +        type   = KTYP(keysym);
  22045. +
  22046. +        if (type >= 0xf0) {
  22047. +        type -= 0xf0;
  22048. +
  22049. +        if (type == KT_LETTER) {
  22050. +            type = KT_LATIN;
  22051. +            if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
  22052. +            key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
  22053. +            if (key_map)
  22054. +                keysym = key_map[keycode];
  22055. +            }
  22056. +        }
  22057. +        (*key_handler[type])(keysym & 0xff, up_flag ? 0x80 : 0);
  22058. +        if (type != KT_SLOCK)
  22059. +            kbd->slockstate = 0;
  22060. +        } else {
  22061. +        if (!up_flag)
  22062. +            to_utf8(keysym);
  22063. +        }
  22064. +    } else {
  22065. +        /*
  22066. +         * maybe beep?
  22067. +         * we have at least to update shift_state
  22068. +         * how? two almost equivalent choices follow
  22069. +         */
  22070. +#if 1
  22071. +        compute_shiftstate ();
  22072. +#else
  22073. +        keysym = U(plain_map[keycode]);
  22074. +        type   = KTYP(keysym);
  22075. +        if (type == KT_SHIFT)
  22076. +        (*key_handler[type]) (keysym & 0xff, up_flag ? 0x80 : 0);
  22077. +#endif
  22078. +    }
  22079. +    }
  22080. +}
  22081. +
  22082. +static void kbd_sendval(unsigned char val)
  22083. +{
  22084. +    kbd_sendvala[kbd_sendptri] = val;
  22085. +    kbd_sendptri = (kbd_sendptri + 1) & 3;
  22086. +    disable_irq (15);
  22087. +    enable_irq (14);
  22088. +}
  22089. +
  22090. +static void kbd_tx(int irq, void *dev_id, struct pt_regs *regs)
  22091. +{
  22092. +  if(kbd_sendptri != kbd_sendptro) {
  22093. +    IOC_KARTTX = kbd_sendvala[kbd_sendptro];
  22094. +    kbd_sendptro = (kbd_sendptro + 1) & 3;
  22095. +  }
  22096. +  if(kbd_sendptri == kbd_sendptro) {
  22097. +    disable_irq (14);
  22098. +    enable_irq (15);
  22099. +  }
  22100. +}
  22101. +
  22102. +static void kbd_reset(void)
  22103. +{
  22104. +    int i;
  22105. +
  22106. +    for (i = 0; i < NR_SHIFT; i++)
  22107. +    k_down[i] = 0;
  22108. +
  22109. +    for (i = 0; i < 256/BITS_PER_SHORT; i++)
  22110. +    key_down[i] = 0;
  22111. +
  22112. +    for (i = 0; i < 128/BITS_PER_SHORT; i++)
  22113. +    ghost_down[i] = 0;
  22114. +
  22115. +    shift_state = 0;
  22116. +}
  22117. +
  22118. +/*
  22119. + * Keyboard states:
  22120. + *  0 initial reset condition, sent HRST, wait for HRST
  22121. + *  1 Send HRST, wait for HRST acknowledge
  22122. + *  2 Sent RAK1, wait for RAK1
  22123. + *  3 Sent RAK2, wait for RAK2
  22124. + *  4 Sent SMAK, wait for anything
  22125. + *  5 Wait for second keyboard nibble for key pressed
  22126. + *  6 Wait for second keyboard nibble for key released
  22127. + *  7 Wait for second part of mouse data
  22128. + */
  22129. +#define KBD_INITRST    0
  22130. +#define KBD_RAK1    1
  22131. +#define KBD_RAK2    2
  22132. +#define KBD_ID        3
  22133. +#define KBD_IDLE    4
  22134. +#define KBD_KEYDOWN    5
  22135. +#define KBD_KEYUP    6
  22136. +#define KBD_MOUSE    7
  22137. +
  22138. +static void kbd_rx(int irq, void *dev_id, struct pt_regs *regs)
  22139. +{
  22140. +    int keyval;
  22141. +    static signed char kbd_mousedx=0;
  22142. +           signed char kbd_mousedy;
  22143. +    static unsigned char kbd_state=KBD_INITRST;
  22144. +    static unsigned char kbd_keyhigh=0;
  22145. +
  22146. +    pt_regs = regs;
  22147. +
  22148. +    keyval = IOC_KARTRX;
  22149. +
  22150. +    switch(kbd_state) {
  22151. +    case KBD_INITRST: /* hard reset - sent HRST */
  22152. +    if (keyval == HRST) {
  22153. +        kbd_reset ();
  22154. +        kbd_sendval (RAK1);
  22155. +        kbd_state = KBD_RAK1;
  22156. +    } else
  22157. +        goto kbd_wontreset;
  22158. +    break;
  22159. +
  22160. +    case KBD_RAK1:/* Sent RAK1 */
  22161. +    switch (keyval) {
  22162. +    case HRST:
  22163. +        kbd_sendval (RAK1);
  22164. +        kbd_state = KBD_INITRST;
  22165. +        break;
  22166. +    case RAK1:
  22167. +        kbd_sendval (RAK2);
  22168. +        kbd_state = KBD_RAK2;
  22169. +        break;
  22170. +    default:
  22171. +        goto kbd_wontreset;
  22172. +    }
  22173. +    break;
  22174. +
  22175. +    case KBD_RAK2:/* Sent RAK2 */
  22176. +    switch (keyval) {
  22177. +    case HRST:
  22178. +        kbd_sendval (HRST);
  22179. +        kbd_state = KBD_INITRST;
  22180. +        break;
  22181. +    case RAK2:
  22182. +        if (kbd_id == -1) {
  22183. +        kbd_sendval (NACK);
  22184. +        kbd_sendval (RQID);
  22185. +        kbd_state = KBD_ID;
  22186. +        } else {
  22187. +        kbd_sendval (SMAK);
  22188. +        kbd_state = KBD_IDLE;
  22189. +        ledstate  = 0xff;
  22190. +        mark_bh (KEYBOARD_BH);
  22191. +        }
  22192. +        break;
  22193. +    default:
  22194. +        goto kbd_wontreset;
  22195. +    }
  22196. +    break;
  22197. +
  22198. +    case KBD_ID:
  22199. +    if (keyval == HRST) {
  22200. +        kbd_sendval (HRST);
  22201. +        kbd_state = KBD_INITRST;
  22202. +        kbd_id = -2;
  22203. +        wake_up(&kbd_waitq);
  22204. +        break;
  22205. +    } else
  22206. +    if ((keyval & 0xc0) == 0x80) {
  22207. +        kbd_id = keyval & 0x3f;
  22208. +        kbd_sendval (SMAK);
  22209. +        kbd_state = KBD_IDLE;
  22210. +        ledstate  = 0xff;
  22211. +        mark_bh (KEYBOARD_BH);
  22212. +        wake_up(&kbd_waitq);
  22213. +        break;
  22214. +    }
  22215. +    break;
  22216. +
  22217. +    case KBD_IDLE:/* Send SMAK, ready for any reply */
  22218. +    if (keyval == HRST) {
  22219. +        kbd_sendval (HRST);
  22220. +        kbd_state = KBD_INITRST;
  22221. +    } else
  22222. +    if (keyval & 0x80) {
  22223. +        if (!(keyval & 0x40)) {
  22224. +            if (kbd_id == -1)
  22225. +            kbd_id = keyval & 0x3f;
  22226. +        else {
  22227. +            kbd_state = KBD_INITRST;
  22228. +            kbd_sendval (HRST);
  22229. +        }
  22230. +        break;
  22231. +        }
  22232. +        switch (keyval & 0xf0) {
  22233. +        case 0xc0:
  22234. +        kbd_keyhigh = keyval;
  22235. +        kbd_state   = KBD_KEYDOWN;
  22236. +        kbd_sendval (BACK);
  22237. +        break;
  22238. +
  22239. +        case 0xd0:
  22240. +        kbd_keyhigh = keyval;
  22241. +        kbd_state   = KBD_KEYUP;
  22242. +        kbd_sendval (BACK);
  22243. +        break;
  22244. +
  22245. +        default:
  22246. +        kbd_state = KBD_INITRST;
  22247. +        kbd_sendval (HRST);
  22248. +        }
  22249. +    } else {
  22250. +        kbd_mousedx = keyval & 0x40 ? keyval|0x80 : keyval;
  22251. +        kbd_state   = KBD_MOUSE;
  22252. +        kbd_sendval (BACK);
  22253. +    }
  22254. +    break;
  22255. +
  22256. +    case KBD_KEYDOWN:
  22257. +    if ((keyval & 0xf0) != 0xc0)
  22258. +        goto kbd_error;
  22259. +    else {
  22260. +        kbd_state = KBD_IDLE;
  22261. +        kbd_sendval (SMAK);
  22262. +        if (((kbd_keyhigh ^ keyval) & 0xf0) == 0) {
  22263. +        kbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), kbd_repeattimeout);
  22264. +        mark_bh (KEYBOARD_BH);
  22265. +        }
  22266. +    }
  22267. +    break;
  22268. +
  22269. +    case KBD_KEYUP:
  22270. +    if ((keyval & 0xf0) != 0xd0)
  22271. +        goto kbd_error;
  22272. +    else {
  22273. +        kbd_state = KBD_IDLE;
  22274. +        kbd_sendval (SMAK);
  22275. +        if (((kbd_keyhigh ^ keyval) & 0xf0) == 0) {
  22276. +        kbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0) | UP_FLAG, 0);
  22277. +        mark_bh (KEYBOARD_BH);
  22278. +        }
  22279. +    }
  22280. +    break;
  22281. +
  22282. +    case KBD_MOUSE:
  22283. +    if (keyval & 0x80)
  22284. +        goto kbd_error;
  22285. +    else {
  22286. +        kbd_state = KBD_IDLE;
  22287. +        kbd_sendval (SMAK);
  22288. +        kbd_mousedy = (char)(keyval & 0x40 ? keyval | 0x80 : keyval);
  22289. +#ifdef CONFIG_KBDMOUSE
  22290. +        mouse_dypos += (int)kbd_mousedy;
  22291. +        mouse_dxpos += (int)kbd_mousedx;
  22292. +        add_mouse_randomness ((mouse_buttons << 16) + (kbd_mousedy << 8) + kbd_mousedx);
  22293. +        mouse_ready = 1;
  22294. +        wake_up_interruptible (&mouse_wait);
  22295. +#endif
  22296. +        mark_bh (KEYBOARD_BH);
  22297. +    }
  22298. +    break;
  22299. +    }
  22300. +    return;
  22301. +kbd_wontreset:
  22302. +#ifdef KBD_REPORT_ERR
  22303. +    printk ("kbd: keyboard won't reset (kbdstate %d, keyval %02X)\n", kbd_state,
  22304. +        keyval);
  22305. +#endif
  22306. +    kbd_sendval (HRST);
  22307. +    kbd_state = KBD_INITRST;
  22308. +    return;
  22309. +kbd_error:
  22310. +#ifdef KBD_REPORT_ERR
  22311. +    printk ("kbd: keyboard out of sync - resetting\n");
  22312. +#endif
  22313. +    kbd_sendval (HRST);
  22314. +    kbd_state = KBD_INITRST;
  22315. +    return;
  22316. +}
  22317. +
  22318. +/* ----------------------------------------------------------------------------------------- */
  22319. +/*
  22320. + * Here starts a copy of the PC keyboard code from linux/drivers/char/keyboard.c
  22321. + */
  22322. +
  22323. +static void put_queue (int ch)
  22324. +{
  22325. +    wake_up (&keypress_wait);
  22326. +    if (tty) {
  22327. +    tty_insert_flip_char (tty, ch, 0);
  22328. +    tty_schedule_flip (tty);
  22329. +    }
  22330. +}
  22331. +
  22332. +static void puts_queue(char *cp)
  22333. +{
  22334. +    wake_up (&keypress_wait);
  22335. +    if (!tty)
  22336. +    return;
  22337. +
  22338. +    while (*cp)
  22339. +    tty_insert_flip_char (tty, *cp++, 0);
  22340. +    tty_schedule_flip (tty);
  22341. +}
  22342. +
  22343. +static void applkey(int key, char mode)
  22344. +{
  22345. +    static char buf[] = { 0x1b, 'O', 0x00, 0x00};
  22346. +
  22347. +    buf[1] = (mode ? 'O' : '[');
  22348. +    buf[2] = key;
  22349. +    puts_queue(buf);
  22350. +}
  22351. +
  22352. +static void enter(void)
  22353. +{
  22354. +    put_queue (13);
  22355. +    if (vc_kbd_mode(kbd, VC_CRLF))
  22356. +    put_queue (10);
  22357. +}
  22358. +
  22359. +static void caps_toggle(void)
  22360. +{
  22361. +    if(rep)
  22362. +    return;
  22363. +    chg_vc_kbd_led(kbd, VC_CAPSLOCK);
  22364. +}
  22365. +
  22366. +static void caps_on (void)
  22367. +{
  22368. +    if (rep)
  22369. +    return;
  22370. +    set_vc_kbd_led (kbd, VC_CAPSLOCK);
  22371. +}
  22372. +
  22373. +static void show_ptregs (void)
  22374. +{
  22375. +    if (pt_regs)
  22376. +    show_regs (pt_regs);
  22377. +}
  22378. +
  22379. +static void show_stack (void)
  22380. +{
  22381. +    unsigned long *p;
  22382. +    unsigned long *q = (unsigned long *)((int)current->kernel_stack_page + 4096);
  22383. +    int i;
  22384. +    __asm__("mov %0, sp\n\t": "=r" (p));
  22385. +
  22386. +    for(i=0; p < q; p++, i++) {
  22387. +    if(i && !(i & 7))
  22388. +        printk("\n");
  22389. +    printk("%08lX ", *p);
  22390. +    }
  22391. +}
  22392. +
  22393. +static void hold (void)
  22394. +{
  22395. +    if(rep || !tty)
  22396. +    return;
  22397. +
  22398. +    /*
  22399. +     * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
  22400. +     * these routines are also activated by ^S/^Q.
  22401. +     * (And SCROLLOCK can also be set by the KDSKBLED.)
  22402. +     */
  22403. +    if (tty->stopped)
  22404. +    start_tty (tty);
  22405. +    else
  22406. +    stop_tty (tty);
  22407. +}
  22408. +
  22409. +static void num (void)
  22410. +{
  22411. +    if(vc_kbd_mode(kbd,VC_APPLIC))
  22412. +    applkey('P', 1);
  22413. +    else
  22414. +        bare_num ();
  22415. +}
  22416. +
  22417. +/*
  22418. + * Bind this to Shift-NumLock if you work in application keypad mode
  22419. + * but want to be able to change the NumLock flag.
  22420. + * Bind this to NumLock if you prefer that the NumLock key always
  22421. + * changes the NumLock flag.
  22422. + */
  22423. +static void bare_num (void)
  22424. +{
  22425. +    if (!rep)
  22426. +    chg_vc_kbd_led (kbd, VC_NUMLOCK);
  22427. +}
  22428. +
  22429. +static void lastcons (void)
  22430. +{
  22431. +    want_console = last_console;
  22432. +}
  22433. +
  22434. +static void decr_console (void)
  22435. +{
  22436. +    int i;
  22437. +    int fgnum = vtdata.fgconsole->num - 1;
  22438. +
  22439. +    for (i = fgnum - 1; i != fgnum; i--) {
  22440. +    if (i == -1)
  22441. +        i = MAX_NR_CONSOLES - 1;
  22442. +    if (vt_allocated (vt_con_data + i))
  22443. +        break;
  22444. +    }
  22445. +    want_console = vt_con_data + i;
  22446. +}
  22447. +
  22448. +static void incr_console (void)
  22449. +{
  22450. +    int i;
  22451. +    int fgnum = vtdata.fgconsole->num - 1;
  22452. +
  22453. +    for (i = fgnum + 1; i != fgnum; i++) {
  22454. +    if (i == MAX_NR_CONSOLES)
  22455. +        i = 0;
  22456. +    if (vt_allocated (vt_con_data + i))
  22457. +        break;
  22458. +    }
  22459. +    want_console = vt_con_data + i;
  22460. +}
  22461. +
  22462. +static void send_intr (void)
  22463. +{
  22464. +    if (!tty)
  22465. +    return;
  22466. +    tty_insert_flip_char (tty, 0, TTY_BREAK);
  22467. +    tty_schedule_flip (tty);
  22468. +}
  22469. +
  22470. +static void scroll_forw (void)
  22471. +{
  22472. +}
  22473. +
  22474. +static void scroll_back (void)
  22475. +{
  22476. +}
  22477. +
  22478. +static void boot_it (void)
  22479. +{
  22480. +    ctrl_alt_del();
  22481. +}
  22482. +
  22483. +static void compose (void)
  22484. +{
  22485. +    dead_key_next = 1;
  22486. +}
  22487. +
  22488. +static int spawnpid, spawnsig;
  22489. +
  22490. +static void spawn_console (void)
  22491. +{
  22492. +    if (spawnpid)
  22493. +    if (kill_proc (spawnpid, spawnsig, 1))
  22494. +        spawnpid = 0;
  22495. +}
  22496. +
  22497. +static void SAK (void)
  22498. +{
  22499. +    do_SAK(tty);
  22500. +#if 0
  22501. +    /*
  22502. +     * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and
  22503. +     * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK
  22504. +     * handling.
  22505. +     *
  22506. +     * We should do this some day --- the whole point of a secure
  22507. +     * attention key is that it should be guaranteed to always
  22508. +     * work.
  22509. +     */
  22510. +    vt_reset (vtdata.fgconsole);
  22511. +    do_unblank_screen ();    /* not in interrupt routine? */
  22512. +#endif
  22513. +}
  22514. +
  22515. +static void do_ignore (unsigned char value, char up_flag)
  22516. +{
  22517. +}
  22518. +
  22519. +static void do_null (void)
  22520. +{
  22521. +    compute_shiftstate ();
  22522. +}
  22523. +
  22524. +static void do_spec (unsigned char value,char up_flag)
  22525. +{
  22526. +    if (up_flag)
  22527. +    return;
  22528. +    if (value >= SIZE(spec_fn_table))
  22529. +    return;
  22530. +    if (!spec_fn_table[value])
  22531. +    return;
  22532. +    spec_fn_table[value] ();
  22533. +}
  22534. +
  22535. +static void do_lowercase (unsigned char value, char up_flag)
  22536. +{
  22537. +    printk("keyboard.c: do_lowercase was called - impossible\n");
  22538. +}
  22539. +
  22540. +static void do_self(unsigned char value, char up_flag)
  22541. +{
  22542. +    if (up_flag)
  22543. +    return;        /* no action, if this is a key release */
  22544. +
  22545. +    if (diacr)
  22546. +    value = handle_diacr (value);
  22547. +
  22548. +    if (dead_key_next) {
  22549. +    dead_key_next = 0;
  22550. +    diacr = value;
  22551. +    return;
  22552. +    }
  22553. +    put_queue (value);
  22554. +}
  22555. +
  22556. +#define A_GRAVE '`'
  22557. +#define A_ACUTE '\''
  22558. +#define A_CFLEX '^'
  22559. +#define A_TILDE '~'
  22560. +#define A_DIAER '"'
  22561. +static unsigned char ret_diacr[] = {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
  22562. +
  22563. +static void do_dead(unsigned char value, char up_flag)
  22564. +{
  22565. +    if (up_flag)
  22566. +    return;
  22567. +
  22568. +    value = ret_diacr[value];
  22569. +    if (diacr == value) { /* pressed twice */
  22570. +    diacr = 0;
  22571. +    put_queue (value);
  22572. +    return;
  22573. +    }
  22574. +    diacr = value;
  22575. +}
  22576. +
  22577. +static unsigned char handle_diacr(unsigned char ch)
  22578. +{
  22579. +    int d = diacr;
  22580. +    int i;
  22581. +
  22582. +    diacr = 0;
  22583. +    if (ch == ' ')
  22584. +    return d;
  22585. +
  22586. +    for (i = 0; i < accent_table_size; i++) {
  22587. +    if (accent_table[i].diacr == d && accent_table[i].base == ch)
  22588. +        return accent_table[i].result;
  22589. +    }
  22590. +
  22591. +    put_queue (d);
  22592. +    return ch;
  22593. +}
  22594. +
  22595. +static void do_cons(unsigned char value, char up_flag)
  22596. +{
  22597. +    if (up_flag)
  22598. +    return;
  22599. +    want_console = vt_con_data + value;
  22600. +}
  22601. +
  22602. +static void do_fn(unsigned char value, char up_flag)
  22603. +{
  22604. +    if (up_flag)
  22605. +    return;
  22606. +
  22607. +    if (value < SIZE(func_table)) {
  22608. +    if (func_table[value])
  22609. +        puts_queue (func_table[value]);
  22610. +    } else
  22611. +    printk ("do_fn called with value=%d\n",value);
  22612. +}
  22613. +
  22614. +static void do_pad(unsigned char value, char up_flag)
  22615. +{
  22616. +    static char *pad_chars = "0123456789+-*/\015,.?#";
  22617. +    static char *app_map   = "pqrstuvwxylmRQMnn?S";
  22618. +
  22619. +    if (up_flag)
  22620. +    return;
  22621. +
  22622. +    if (vc_kbd_mode (kbd, VC_APPLIC) && !k_down[KG_SHIFT]) {
  22623. +    applkey (app_map[value], 1);
  22624. +    return;
  22625. +    }
  22626. +
  22627. +    if (!vc_kbd_led (kbd,VC_NUMLOCK))
  22628. +    switch (value) {
  22629. +        case 15:
  22630. +        case 16: do_fn (22, 0); return;
  22631. +        case 7:  do_fn (20, 0); return;
  22632. +        case 8:  do_cur( 3, 0); return;
  22633. +        case 9:  do_fn (24, 0); return;
  22634. +        case 4:  do_cur( 1, 0); return;
  22635. +        case 6:  do_cur( 2, 0); return;
  22636. +        case 1:  do_fn (23, 0); return;
  22637. +        case 2:  do_cur( 0, 0); return;
  22638. +        case 3:  do_fn (25, 0); return;
  22639. +        case 5:  applkey('G',vc_kbd_mode(kbd, VC_APPLIC)); return;
  22640. +    }
  22641. +
  22642. +    put_queue (pad_chars[value]);
  22643. +    if (value == 14 && vc_kbd_mode (kbd, VC_CRLF))
  22644. +    put_queue (10);
  22645. +}
  22646. +
  22647. +static void do_cur(unsigned char value, char up_flag)
  22648. +{
  22649. +    static char *cur_chars = "BDCA";
  22650. +
  22651. +    if (up_flag)
  22652. +    return;
  22653. +
  22654. +    applkey (cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
  22655. +}
  22656. +
  22657. +static void do_shift(unsigned char value, char up_flag)
  22658. +{
  22659. +    int old_state = shift_state;
  22660. +
  22661. +    if (rep)
  22662. +    return;
  22663. +
  22664. +    /* Mimic typewriter: a CapsShift key acts like Shift but undoes CapsLock */
  22665. +    if (value == KVAL(K_CAPSSHIFT)) {
  22666. +    value = KVAL(K_SHIFT);
  22667. +    if (!up_flag)
  22668. +        clr_vc_kbd_led (kbd, VC_CAPSLOCK);
  22669. +    }
  22670. +
  22671. +    if(up_flag) {
  22672. +    /* handle the case that two shift or control
  22673. +       keys are depressed simultaneously */
  22674. +    if(k_down[value])
  22675. +        k_down[value]--;
  22676. +    } else
  22677. +    k_down[value]++;
  22678. +
  22679. +    if(k_down[value])
  22680. +    shift_state |= (1 << value);
  22681. +    else
  22682. +    shift_state &= ~ (1 << value);
  22683. +
  22684. +    /* kludge */
  22685. +    if(up_flag && shift_state != old_state && npadch != -1) {
  22686. +    if(kbd->kbdmode == VC_UNICODE)
  22687. +        to_utf8(npadch & 0xffff);
  22688. +    else
  22689. +        put_queue(npadch & 0xff);
  22690. +    npadch = -1;
  22691. +    }
  22692. +}
  22693. +
  22694. +/*
  22695. + * Called after returning from RAW mode or when changing consoles -
  22696. + * recompute k_down[] and shift_state from key_down[]
  22697. + * Maybe called when keymap is undefined so that shift key release is seen
  22698. + */
  22699. +void compute_shiftstate(void)
  22700. +{
  22701. +    int i, j, k, sym, val;
  22702. +
  22703. +    shift_state = 0;
  22704. +    for (i = 0; i < SIZE(k_down); i++)
  22705. +    k_down[i] = 0;
  22706. +
  22707. +    for (i = 0; i < SIZE(key_down); i++)
  22708. +    if (key_down[i]) {            /* skip this short word if zero */
  22709. +        k = i * BITS_PER_SHORT;
  22710. +        for (j = 0; j < BITS_PER_SHORT; j++, k++)
  22711. +        if (test_bit (k, key_down)) {
  22712. +            sym = U(plain_map[k]);
  22713. +            if (KTYP(sym) == KT_SHIFT) {
  22714. +            val = KVAL (sym);
  22715. +            if (val == KVAL(K_CAPSSHIFT))
  22716. +                val = KVAL(K_SHIFT);
  22717. +            k_down[val] ++;
  22718. +            shift_state |= (1 << val);
  22719. +            }
  22720. +        }
  22721. +    }
  22722. +}
  22723. +
  22724. +static void do_meta(unsigned char value, char up_flag)
  22725. +{
  22726. +    if(up_flag)
  22727. +    return;
  22728. +
  22729. +    if(vc_kbd_mode(kbd, VC_META)) {
  22730. +    put_queue ('\033');
  22731. +    put_queue (value);
  22732. +    } else
  22733. +    put_queue (value | 0x80);
  22734. +}
  22735. +
  22736. +static void do_ascii(unsigned char value, char up_flag)
  22737. +{
  22738. +    int base;
  22739. +
  22740. +    if(up_flag)
  22741. +    return;
  22742. +
  22743. +    if(value < 10)
  22744. +    base = 10;
  22745. +    else {
  22746. +    value -= 10;
  22747. +    base = 16;
  22748. +    }
  22749. +
  22750. +    if(npadch == -1)
  22751. +    npadch = value;
  22752. +    else
  22753. +    npadch = npadch * base + value;
  22754. +}
  22755. +
  22756. +static void do_lock (unsigned char value, char up_flag)
  22757. +{
  22758. +    if (up_flag || rep)
  22759. +    return;
  22760. +    chg_vc_kbd_lock (kbd, value);
  22761. +}
  22762. +
  22763. +static void do_slock (unsigned char value, char up_flag)
  22764. +{
  22765. +    if (up_flag || rep)
  22766. +    return;
  22767. +    chg_vc_kbd_slock (kbd, value);
  22768. +}
  22769. +
  22770. +/* --------------------------------------------------------------------------------------- *
  22771. + * Led driver                                           *
  22772. + * --------------------------------------------------------------------------------------- */
  22773. +
  22774. +/*
  22775. + * The leds display either
  22776. + * (i)   The status of NumLock, CapsLock and ScrollLock.
  22777. + * (ii)  Whatever pattern of lights people wait to show using KDSETLED.
  22778. + * (iii) Specified bits of specified words in kernel memory.
  22779. + */
  22780. +
  22781. +static unsigned char ledioctl;
  22782. +
  22783. +unsigned char getledstate(void)
  22784. +{
  22785. +    return ledstate;
  22786. +}
  22787. +
  22788. +void setledstate(struct kbd_struct *kbd, unsigned int led)
  22789. +{
  22790. +    if(!(led & ~7)) {
  22791. +    ledioctl = led;
  22792. +    kbd->ledmode = LED_SHOW_IOCTL;
  22793. +    } else
  22794. +    kbd->ledmode = LED_SHOW_FLAGS;
  22795. +    set_leds();
  22796. +}
  22797. +
  22798. +static struct ledptr
  22799. +{
  22800. +    unsigned int *addr;
  22801. +    unsigned int mask;
  22802. +    unsigned char valid:1;
  22803. +} ledptrs[3];
  22804. +
  22805. +void register_leds(int console, unsigned int led, unsigned int *addr, unsigned int mask)
  22806. +{
  22807. +    struct kbd_struct *kbd = vt_con_data[console].kbd;
  22808. +
  22809. +    if(led < 3) {
  22810. +    ledptrs[led].addr = addr;
  22811. +    ledptrs[led].mask = mask;
  22812. +    ledptrs[led].valid= 1;
  22813. +    kbd->ledmode = LED_SHOW_MEM;
  22814. +    } else
  22815. +    kbd->ledmode = LED_SHOW_FLAGS;
  22816. +}
  22817. +
  22818. +static inline unsigned char getleds(void)
  22819. +{
  22820. +    struct kbd_struct *kbd = vtdata.fgconsole->kbd;
  22821. +    unsigned char leds;
  22822. +
  22823. +    if(kbd->ledmode == LED_SHOW_IOCTL)
  22824. +    return ledioctl;
  22825. +
  22826. +    leds = kbd->ledflagstate;
  22827. +    if (kbd->ledmode == LED_SHOW_MEM) {
  22828. +    if (ledptrs[0].valid) {
  22829. +        if (*ledptrs[0].addr & ledptrs[0].mask)
  22830. +        leds |= 1;
  22831. +        else
  22832. +        leds &= ~1;
  22833. +        }
  22834. +    if (ledptrs[1].valid) {
  22835. +        if (*ledptrs[1].addr & ledptrs[1].mask)
  22836. +        leds |= 2;
  22837. +        else
  22838. +        leds &= ~2;
  22839. +        }
  22840. +    if (ledptrs[2].valid) {
  22841. +        if(*ledptrs[2].addr & ledptrs[2].mask)
  22842. +        leds |= 4;
  22843. +        else
  22844. +        leds &= ~4;
  22845. +        }
  22846. +    }
  22847. +    return leds;
  22848. +}
  22849. +
  22850. +/*
  22851. + * This routine is the bottom half of the keyboard interrupt
  22852. + * routine, and runs with all interrupts enabled.  It does
  22853. + * console changing, led setting, and copy_to_cooked, which can
  22854. + * take a reasonably long time.
  22855. + *
  22856. + * Aside from timing (which isn't really that important for
  22857. + * keyboard interrupts as they happen often), using the software
  22858. + * interrupt routines for this thing allows us to easily mask
  22859. + * this when we don't want any of the above to happen.  Not yet
  22860. + * used, but this allows for easy and efficient race-condition
  22861. + * prevention later on.
  22862. + */
  22863. +static void kbd_bh(void)
  22864. +{
  22865. +    unsigned char leds;
  22866. +
  22867. +    tty = *vtdata.fgconsole->tty;
  22868. +    kbd = vtdata.fgconsole->kbd;
  22869. +
  22870. +    if (rep) {
  22871. +    /*
  22872. +     * This prevents the kbd_key routine from being called
  22873. +     * twice, once by this BH, and once by the interrupt
  22874. +     * routine.  Maybe we should put the key press in a
  22875. +     * buffer or variable, and then call the BH...
  22876. +     */
  22877. +        disable_irq (IRQ_KEYBOARDRX);
  22878. +    if (kbd_repeatkey != -1)
  22879. +        kbd_key (kbd_repeatkey, kbd_repeatrate);
  22880. +    enable_irq (IRQ_KEYBOARDRX);
  22881. +    rep = 0;
  22882. +    }
  22883. +
  22884. +    if (want_console) {
  22885. +    if(want_console != vtdata.fgconsole) {
  22886. +        vt_changeconsole (want_console);
  22887. +        /* we only changed when the console had already
  22888. +         * been allocated - a new console is not created
  22889. +         * in an interrupt routine.
  22890. +         */
  22891. +    }
  22892. +    want_console = NULL;
  22893. +    }
  22894. +
  22895. +    leds = getleds ();
  22896. +    if (leds != ledstate) {
  22897. +    unsigned long flags;
  22898. +    ledstate = leds;
  22899. +    leds = ((leds & (1<<VC_SCROLLOCK))?4:0) | ((leds & (1<<VC_NUMLOCK))?2:0) |
  22900. +           ((leds & (1<<VC_CAPSLOCK))?1:0);
  22901. +
  22902. +    save_flags_cli (flags);
  22903. +    intr_count -= 1;
  22904. +
  22905. +    kbd_sendval (leds);
  22906. +
  22907. +    intr_count += 1;
  22908. +    restore_flags(flags);
  22909. +    }
  22910. +    vt_pokeblankedconsole();
  22911. +}
  22912. +
  22913. +/*
  22914. + * Initialise a kbd struct
  22915. + */
  22916. +int kbd_struct_init (struct vt *vt, int init)
  22917. +{
  22918. +    vt->kbd->ledflagstate      =
  22919. +    vt->kbd->default_ledflagstate = KBD_DEFLEDS;
  22920. +    vt->kbd->ledmode          = LED_SHOW_FLAGS;
  22921. +    vt->kbd->lockstate          = KBD_DEFLOCK;
  22922. +    vt->kbd->slockstate          = 0;
  22923. +    vt->kbd->modeflags          = KBD_DEFMODE;
  22924. +    vt->kbd->kbdmode          = VC_XLATE;
  22925. +    return 0;
  22926. +}
  22927. +
  22928. +int kbd_ioctl (struct vt *vt, int cmd, unsigned long arg)
  22929. +{
  22930. +    asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
  22931. +    int i;
  22932. +
  22933. +    switch (cmd) {
  22934. +    case KDGKBTYPE:
  22935. +    /*
  22936. +     * This is naive.
  22937. +     */
  22938. +    i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned char));
  22939. +    if (!i)
  22940. +        put_user (KB_101, (char *)arg);
  22941. +    return i;
  22942. +
  22943. +    case KDADDIO:
  22944. +    case KDDELIO:
  22945. +    /*
  22946. +     * KDADDIO and KDDELIO may be able to add ports beyond what
  22947. +     * we reject here, but to be safe...
  22948. +     */
  22949. +    if (arg < GPFIRST || arg > GPLAST)
  22950. +        return -EINVAL;
  22951. +    return sys_ioperm (arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
  22952. +
  22953. +    case KDENABIO:
  22954. +    case KDDISABIO:
  22955. +    return sys_ioperm (GPFIRST, GPLAST, (cmd == KDENABIO)) ? -ENXIO : 0;
  22956. +
  22957. +    case KDMAPDISP:
  22958. +    case KDUNMAPDISP:
  22959. +    /*
  22960. +     * These work like a combination of mmap and KDENABIO.
  22961. +     * this could easily be finished.
  22962. +     */
  22963. +    return -EINVAL;
  22964. +
  22965. +    case KDSKBMODE:
  22966. +    switch (arg) {
  22967. +    case K_RAW:
  22968. +        vt->kbd->kbdmode = VC_RAW;
  22969. +        break;
  22970. +    case K_MEDIUMRAW:
  22971. +        vt->kbd->kbdmode = VC_MEDIUMRAW;
  22972. +        break;
  22973. +    case K_XLATE:
  22974. +        vt->kbd->kbdmode = VC_XLATE;
  22975. +        compute_shiftstate ();
  22976. +        break;
  22977. +    case K_UNICODE:
  22978. +        vt->kbd->kbdmode = VC_UNICODE;
  22979. +        compute_shiftstate ();
  22980. +        break;
  22981. +    default:
  22982. +        return -EINVAL;
  22983. +    }
  22984. +    if (tty->ldisc.flush_buffer)
  22985. +        tty->ldisc.flush_buffer (*vt->tty);
  22986. +    return 0;
  22987. +
  22988. +    case KDGKBMODE:
  22989. +    i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned long));
  22990. +    if (!i) {
  22991. +        int ucval;
  22992. +        ucval = ((vt->kbd->kbdmode == VC_RAW) ? K_RAW :
  22993. +             (vt->kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
  22994. +             (vt->kbd->kbdmode == VC_UNICODE) ? K_UNICODE : K_XLATE);
  22995. +        put_user (ucval, (int *)arg);
  22996. +    }
  22997. +    return i;
  22998. +
  22999. +    case KDSKBMETA:
  23000. +    /*
  23001. +     * this could be folded into KDSKBMODE, but for compatibility
  23002. +     * reasons, it is not so easy to fold kDGKBMETA into KDGKBMODE.
  23003. +     */
  23004. +    switch (arg) {
  23005. +    case K_METABIT:
  23006. +        clr_vc_kbd_mode (vt->kbd, VC_META);
  23007. +        break;
  23008. +    case K_ESCPREFIX:
  23009. +        set_vc_kbd_mode (vt->kbd, VC_META);
  23010. +        break;
  23011. +    default:
  23012. +        return -EINVAL;
  23013. +    }
  23014. +    return 0;
  23015. +
  23016. +    case KDGKBMETA:
  23017. +    i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned long));
  23018. +    if (!i) {
  23019. +        int ucval;
  23020. +        ucval = (vc_kbd_mode (vt->kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
  23021. +        put_user (ucval, (int *)arg);
  23022. +    }
  23023. +    return i;
  23024. +
  23025. +    case KDGETKEYCODE: {
  23026. +    struct kbkeycode *const a = (struct kbkeycode *)arg;
  23027. +
  23028. +    i = verify_area (VERIFY_WRITE, a, sizeof (struct kbkeycode));
  23029. +    if (!i) {
  23030. +        unsigned int sc;
  23031. +
  23032. +        sc = get_user (&a->scancode);
  23033. +        i = getkeycode (sc);
  23034. +        if (i > 0)
  23035. +        put_user (i, &a->keycode);
  23036. +        i = 0;
  23037. +    }
  23038. +    return i;
  23039. +        }
  23040. +
  23041. +    case KDSETKEYCODE: {
  23042. +    struct kbkeycode *const a = (struct kbkeycode *)arg;
  23043. +
  23044. +    i = verify_area (VERIFY_READ, a, sizeof (struct kbkeycode));
  23045. +    if (!i) {
  23046. +        unsigned int sc, kc;
  23047. +        sc = get_user (&a->scancode);
  23048. +        kc = get_user (&a->keycode);
  23049. +        i = setkeycode (sc, kc);
  23050. +    }
  23051. +    return i;
  23052. +        }
  23053. +
  23054. +    case KDGKBENT: {
  23055. +    struct kbentry *const a = (struct kbentry *)arg;
  23056. +
  23057. +    i = verify_area (VERIFY_WRITE, a, sizeof (struct kbentry));
  23058. +    if (!i) {
  23059. +        ushort *keymap, val;
  23060. +        u_char s;
  23061. +        i = get_user (&a->kb_index);
  23062. +        if (i >= NR_KEYS)
  23063. +        return -EINVAL;
  23064. +        s = get_user (&a->kb_table);
  23065. +        if (s >= MAX_NR_KEYMAPS)
  23066. +        return -EINVAL;
  23067. +        keymap = key_maps[s];
  23068. +        if (keymap) {
  23069. +        val = U(keymap[i]);
  23070. +        if (vt->kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
  23071. +            val = K_HOLE;
  23072. +        } else
  23073. +        val = (i ? K_HOLE : K_NOSUCHMAP);
  23074. +        put_user (val, &a->kb_value);
  23075. +        i = 0;
  23076. +    }
  23077. +    return i;
  23078. +        }
  23079. +
  23080. +    case KDSKBENT: {
  23081. +    struct kbentry *const a = (struct kbentry *)arg;
  23082. +
  23083. +    i = verify_area (VERIFY_WRITE, a, sizeof (struct kbentry));
  23084. +    if (!i) {
  23085. +        ushort *key_map;
  23086. +        u_char s;
  23087. +        u_short v, ov;
  23088. +
  23089. +        if ((i = get_user(&a->kb_index)) >= NR_KEYS)
  23090. +        return -EINVAL;
  23091. +        if ((s = get_user(&a->kb_table)) >= MAX_NR_KEYMAPS)
  23092. +        return -EINVAL;
  23093. +        v = get_user(&a->kb_value);
  23094. +        if (!i && v == K_NOSUCHMAP) {
  23095. +        /* disallocate map */
  23096. +        key_map = key_maps[s];
  23097. +        if (s && key_map) {
  23098. +            key_maps[s] = 0;
  23099. +            if (key_map[0] == U(K_ALLOCATED)) {
  23100. +            kfree_s(key_map, sizeof(plain_map));
  23101. +            keymap_count--;
  23102. +            }
  23103. +        }
  23104. +        return 0;
  23105. +        }
  23106. +
  23107. +        if (KTYP(v) < NR_TYPES) {
  23108. +        if (KVAL(v) > max_vals[KTYP(v)])
  23109. +            return -EINVAL;
  23110. +        } else
  23111. +        if (kbd->kbdmode != VC_UNICODE)
  23112. +            return -EINVAL;
  23113. +
  23114. +        /* assignment to entry 0 only tests validity of args */
  23115. +        if (!i)
  23116. +        return 0;
  23117. +
  23118. +        if (!(key_map = key_maps[s])) {
  23119. +        int j;
  23120. +            
  23121. +        if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && !suser())
  23122. +            return -EPERM;
  23123. +
  23124. +        key_map = (ushort *) kmalloc(sizeof(plain_map),
  23125. +                         GFP_KERNEL);
  23126. +        if (!key_map)
  23127. +            return -ENOMEM;
  23128. +        key_maps[s] = key_map;
  23129. +        key_map[0] = U(K_ALLOCATED);
  23130. +        for (j = 1; j < NR_KEYS; j++)
  23131. +            key_map[j] = U(K_HOLE);
  23132. +        keymap_count++;
  23133. +        }
  23134. +        ov = U(key_map[i]);
  23135. +        if (v == ov)
  23136. +        return 0;    /* nothing to do */
  23137. +        /*
  23138. +         * Only the Superuser can set or unset the Secure
  23139. +         * Attention Key.
  23140. +         */
  23141. +        if (((ov == K_SAK) || (v == K_SAK)) && !suser())
  23142. +        return -EPERM;
  23143. +        key_map[i] = U(v);
  23144. +        if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
  23145. +        compute_shiftstate();
  23146. +        return 0;
  23147. +    }
  23148. +    return i;
  23149. +        }
  23150. +
  23151. +    case KDGKBSENT: {
  23152. +    struct kbsentry *a = (struct kbsentry *)arg;
  23153. +    char *p;
  23154. +    u_char *q;
  23155. +    int sz;
  23156. +
  23157. +    i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
  23158. +    if (i)
  23159. +        return i;
  23160. +    if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC || i < 0)
  23161. +        return -EINVAL;
  23162. +    sz = sizeof(a->kb_string) - 1; /* sz should have been
  23163. +                      a struct member */
  23164. +    q = a->kb_string;
  23165. +    p = func_table[i];
  23166. +    if(p)
  23167. +        for ( ; *p && sz; p++, sz--)
  23168. +        put_user(*p, q++);
  23169. +    put_user('\0', q);
  23170. +    return ((p && *p) ? -EOVERFLOW : 0);
  23171. +        }
  23172. +
  23173. +    case KDSKBSENT: {
  23174. +    struct kbsentry * const a = (struct kbsentry *)arg;
  23175. +    int delta;
  23176. +    char *first_free, *fj, *fnw;
  23177. +    int j, k, sz;
  23178. +    u_char *p;
  23179. +    char *q;
  23180. +
  23181. +    i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
  23182. +    if (i)
  23183. +        return i;
  23184. +    if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC)
  23185. +        return -EINVAL;
  23186. +    q = func_table[i];
  23187. +
  23188. +    first_free = funcbufptr + (funcbufsize - funcbufleft);
  23189. +    for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) ;
  23190. +    if (j < MAX_NR_FUNC)
  23191. +        fj = func_table[j];
  23192. +    else
  23193. +        fj = first_free;
  23194. +
  23195. +    delta = (q ? -strlen(q) : 1);
  23196. +    sz = sizeof(a->kb_string);     /* sz should have been
  23197. +                       a struct member */
  23198. +    for (p = a->kb_string; get_user(p) && sz; p++,sz--)
  23199. +        delta++;
  23200. +    if (!sz)
  23201. +        return -EOVERFLOW;
  23202. +    if (delta <= funcbufleft) {     /* it fits in current buf */
  23203. +        if (j < MAX_NR_FUNC) {
  23204. +        memmove(fj + delta, fj, first_free - fj);
  23205. +        for (k = j; k < MAX_NR_FUNC; k++)
  23206. +            if (func_table[k])
  23207. +            func_table[k] += delta;
  23208. +        }
  23209. +        if (!q)
  23210. +        func_table[i] = fj;
  23211. +        funcbufleft -= delta;
  23212. +    } else {            /* allocate a larger buffer */
  23213. +        sz = 256;
  23214. +        while (sz < funcbufsize - funcbufleft + delta)
  23215. +        sz <<= 1;
  23216. +        fnw = (char *) kmalloc(sz, GFP_KERNEL);
  23217. +        if(!fnw)
  23218. +        return -ENOMEM;
  23219. +
  23220. +        if (!q)
  23221. +        func_table[i] = fj;
  23222. +        if (fj > funcbufptr)
  23223. +        memmove(fnw, funcbufptr, fj - funcbufptr);
  23224. +        for (k = 0; k < j; k++)
  23225. +        if (func_table[k])
  23226. +            func_table[k] = fnw + (func_table[k] - funcbufptr);
  23227. +
  23228. +        if (first_free > fj) {
  23229. +        memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
  23230. +        for (k = j; k < MAX_NR_FUNC; k++)
  23231. +            if (func_table[k])
  23232. +            func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
  23233. +        }
  23234. +        if (funcbufptr != func_buf)
  23235. +        kfree_s(funcbufptr, funcbufsize);
  23236. +        funcbufptr = fnw;
  23237. +        funcbufleft = funcbufleft - delta + sz - funcbufsize;
  23238. +        funcbufsize = sz;
  23239. +    }
  23240. +    for (p = a->kb_string, q = func_table[i]; ; p++, q++)
  23241. +        if (!(*q = get_user(p)))
  23242. +        break;
  23243. +    return 0;
  23244. +    }
  23245. +
  23246. +    case KDGKBDIACR: {
  23247. +    struct kbdiacrs *a = (struct kbdiacrs *)arg;
  23248. +
  23249. +    i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs));
  23250. +    if (i)
  23251. +        return i;
  23252. +    put_user(accent_table_size, &a->kb_cnt);
  23253. +    memcpy_tofs(a->kbdiacr, accent_table,
  23254. +            accent_table_size*sizeof(struct kbdiacr));
  23255. +    return 0;
  23256. +    }
  23257. +
  23258. +    case KDSKBDIACR: {
  23259. +    struct kbdiacrs *a = (struct kbdiacrs *)arg;
  23260. +    unsigned int ct;
  23261. +
  23262. +    i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
  23263. +    if (i)
  23264. +        return i;
  23265. +    ct = get_user(&a->kb_cnt);
  23266. +    if (ct >= MAX_DIACR)
  23267. +        return -EINVAL;
  23268. +    accent_table_size = ct;
  23269. +    memcpy_fromfs(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr));
  23270. +    return 0;
  23271. +    }
  23272. +
  23273. +    /* the ioctls below read/set the flags usually shown in the leds */
  23274. +    /* don't use them - they will go away without warning */
  23275. +    case KDGKBLED:
  23276. +    i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  23277. +    if (i)
  23278. +        return i;
  23279. +    put_user(vt->kbd->ledflagstate |
  23280. +            (vt->kbd->default_ledflagstate << 4), (char *) arg);
  23281. +    return 0;
  23282. +
  23283. +    case KDSKBLED:
  23284. +    if (arg & ~0x77)
  23285. +        return -EINVAL;
  23286. +    vt->kbd->ledflagstate = (arg & 7);
  23287. +    vt->kbd->default_ledflagstate = ((arg >> 4) & 7);
  23288. +    set_leds ();
  23289. +    return 0;
  23290. +
  23291. +    /* the ioctls below only set the lights, not the functions */
  23292. +    /* for those, see KDGKBLED and KDSKBLED above */
  23293. +    case KDGETLED:
  23294. +    i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  23295. +    if (i)
  23296. +            return i;
  23297. +    put_user(getledstate(), (char *) arg);
  23298. +    return 0;
  23299. +
  23300. +    case KDSETLED:
  23301. +    setledstate(kbd, arg);
  23302. +    return 0;
  23303. +
  23304. +    /*
  23305. +     * A process can indicate its willingness to accept signals
  23306. +     * generated by pressing an appropriate key combination.
  23307. +     * Thus, one can have a daemon that e.g. spawns a new console
  23308. +     * upon a keypess and then changes to it.
  23309. +     * Probably init should be changed to do this (and have a
  23310. +     * field ks (`keyboard signal') in inittab describing the
  23311. +     * desired acion), so that the number of background daemons
  23312. +     * does not increase.
  23313. +     */
  23314. +    case KDSIGACCEPT: {
  23315. +    if (arg < 1 || arg > NSIG || arg == SIGKILL)
  23316. +        return -EINVAL;
  23317. +    spawnpid = current->pid;
  23318. +    spawnsig = arg;
  23319. +    return 0;
  23320. +    }
  23321. +    default:
  23322. +    return -ENOIOCTLCMD;
  23323. +    }
  23324. +}
  23325. +
  23326. +int kbd_init (void)
  23327. +{
  23328. +    unsigned long flags;
  23329. +
  23330. +    save_flags_cli (flags);
  23331. +    if (request_irq (IRQ_KEYBOARDRX, kbd_rx, 0, "keyboard", NULL)!=0)
  23332. +    panic("Could not allocate keyboard receive IRQ!");
  23333. +    if (request_irq (IRQ_KEYBOARDTX, kbd_tx, 0, "keyboard", NULL)!=0)
  23334. +    panic("Could not allocate keyboard transmit IRQ!");
  23335. +    disable_irq (IRQ_KEYBOARDTX);
  23336. +    (void)IOC_KARTRX;
  23337. +    restore_flags (flags);
  23338. +
  23339. +    kbd_sendval (HRST);
  23340. +    init_bh (KEYBOARD_BH, kbd_bh);
  23341. +
  23342. +    current->timeout = jiffies + HZ; /* wait 1s for keyboard to initialise */
  23343. +    interruptible_sleep_on(&kbd_waitq);
  23344. +
  23345. +    printk (KERN_INFO "Keyboard driver installed v%d.%02d. (", VERSION/100, VERSION%100);
  23346. +    if (kbd_id != -1)
  23347. +      printk ("id=%d ", kbd_id);
  23348. +    printk ("English)\n");
  23349. +    return 0;
  23350. +}
  23351. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/mem.c linux/arch/arm/drivers/char/mem.c
  23352. --- linux.orig/arch/arm/drivers/char/mem.c    Thu Jan  1 01:00:00 1970
  23353. +++ linux/arch/arm/drivers/char/mem.c    Sun Jul 28 20:48:00 1996
  23354. @@ -0,0 +1,361 @@
  23355. +/*
  23356. + *  linux/arch/arm/drivers/char/mem.c
  23357. + *
  23358. + *  Copyright (C) 1991, 1992  Linus Torvalds
  23359. + *
  23360. + *  Modifications for ARM Copyright (C) 1995, 1996 Russell King
  23361. + */
  23362. +
  23363. +#include <linux/config.h>
  23364. +#include <linux/types.h>
  23365. +#include <linux/errno.h>
  23366. +#include <linux/sched.h>
  23367. +#include <linux/kernel.h>
  23368. +#include <linux/major.h>
  23369. +#include <linux/tty.h>
  23370. +#include <linux/miscdevice.h>
  23371. +#include <linux/tpqic02.h>
  23372. +#include <linux/malloc.h>
  23373. +#include <linux/mman.h>
  23374. +#include <linux/mm.h>
  23375. +#include <linux/random.h>
  23376. +
  23377. +#include <asm/segment.h>
  23378. +#include <asm/io.h>
  23379. +#include <asm/pgtable.h>
  23380. +
  23381. +#ifdef CONFIG_SOUND
  23382. +void soundcard_init(void);
  23383. +#endif
  23384. +
  23385. +static int read_ram(struct inode * inode, struct file * file, char * buf, int count)
  23386. +{
  23387. +    return -EIO;
  23388. +}
  23389. +
  23390. +static int write_ram(struct inode * inode, struct file * file, const char * buf, int count)
  23391. +{
  23392. +    return -EIO;
  23393. +}
  23394. +
  23395. +static int read_mem(struct inode * inode, struct file * file, char * buf, int count)
  23396. +{
  23397. +    unsigned long p = file->f_pos;
  23398. +
  23399. +    p += PAGE_OFFSET;
  23400. +    if (count < 0)
  23401. +        return -EINVAL;
  23402. +    if (MAP_NR(p) >= MAP_NR(high_memory))
  23403. +        return 0;
  23404. +    if (count > high_memory - p)
  23405. +        count = high_memory - p;
  23406. +    memcpy_tofs(buf,(void *) p,count);
  23407. +    file->f_pos += count;
  23408. +    return count;
  23409. +}
  23410. +
  23411. +static int write_mem(struct inode * inode, struct file * file, const char * buf, int count)
  23412. +{
  23413. +    unsigned long p = file->f_pos;
  23414. +
  23415. +    p += PAGE_OFFSET;
  23416. +    if (count < 0)
  23417. +        return -EINVAL;
  23418. +    if (MAP_NR(p) >= MAP_NR(high_memory))
  23419. +        return 0;
  23420. +    if (count > high_memory - p)
  23421. +        count = high_memory - p;
  23422. +    memcpy_fromfs((void *) p,buf,count);
  23423. +    file->f_pos += count;
  23424. +    return count;
  23425. +}
  23426. +
  23427. +static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_struct * vma)
  23428. +{
  23429. +    if (vma->vm_offset & ~PAGE_MASK)
  23430. +        return -ENXIO;
  23431. +
  23432. +    if (remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
  23433. +        return -EAGAIN;
  23434. +    vma->vm_inode = inode;
  23435. +    inode->i_count++;
  23436. +    return 0;
  23437. +}
  23438. +
  23439. +static int read_kmem(struct inode *inode, struct file *file, char *buf, int count)
  23440. +{
  23441. +    int read1, read2;
  23442. +
  23443. +    read1 = read_mem(inode, file, buf, count);
  23444. +    if (read1 < 0)
  23445. +        return read1;
  23446. +    read2 = vread(buf + read1, (char *) ((unsigned long) file->f_pos), count - read1);
  23447. +    if (read2 < 0)
  23448. +        return read2;
  23449. +    file->f_pos += read2;
  23450. +    return read1 + read2;
  23451. +}
  23452. +
  23453. +static int read_port(struct inode * inode, struct file * file,char * buf, int count)
  23454. +{
  23455. +    unsigned int i = file->f_pos;
  23456. +    char * tmp = buf;
  23457. +
  23458. +    while (count-- > 0 && i < 65536) {
  23459. +        put_user(inb(i),tmp);
  23460. +        i++;
  23461. +        tmp++;
  23462. +    }
  23463. +    file->f_pos = i;
  23464. +    return tmp-buf;
  23465. +}
  23466. +
  23467. +static int write_port(struct inode * inode, struct file * file, const char * buf, int count)
  23468. +{
  23469. +    unsigned int i = file->f_pos;
  23470. +    const char * tmp = buf;
  23471. +
  23472. +    while (count-- > 0 && i < 65536) {
  23473. +        outb(get_user(tmp),i);
  23474. +        i++;
  23475. +        tmp++;
  23476. +    }
  23477. +    file->f_pos = i;
  23478. +    return tmp-buf;
  23479. +}
  23480. +
  23481. +static int read_null(struct inode * node, struct file * file, char * buf, int count)
  23482. +{
  23483. +    return 0;
  23484. +}
  23485. +
  23486. +static int write_null(struct inode * inode, struct file * file, const char * buf, int count)
  23487. +{
  23488. +    return count;
  23489. +}
  23490. +
  23491. +static int read_zero(struct inode * node, struct file * file, char * buf, int count)
  23492. +{
  23493. +    int left;
  23494. +
  23495. +    for (left = count; left > 0; left--) {
  23496. +        put_user(0,buf);
  23497. +        buf++;
  23498. +        if (need_resched)
  23499. +            schedule();
  23500. +    }
  23501. +    return count;
  23502. +}
  23503. +
  23504. +static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_struct * vma)
  23505. +{
  23506. +    if (vma->vm_flags & VM_SHARED)
  23507. +        return -EINVAL;
  23508. +    if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
  23509. +        return -EAGAIN;
  23510. +    return 0;
  23511. +}
  23512. +
  23513. +static int read_full(struct inode * node, struct file * file, char * buf,int count)
  23514. +{
  23515. +    return count;
  23516. +}
  23517. +
  23518. +static int write_full(struct inode * inode, struct file * file, const char * buf, int count)
  23519. +{
  23520. +    return -ENOSPC;
  23521. +}
  23522. +
  23523. +/*
  23524. + * Special lseek() function for /dev/null and /dev/zero.  Most notably, you can fopen()
  23525. + * both devices with "a" now.  This was previously impossible.  SRB.
  23526. + */
  23527. +
  23528. +static int null_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  23529. +{
  23530. +    return file->f_pos=0;
  23531. +}
  23532. +/*
  23533. + * The memory devices use the full 32/64 bits of the offset, and so we cannot
  23534. + * check against negative addresses: they are ok. The return value is weird,
  23535. + * though, in that case (0).
  23536. + *
  23537. + * also note that seeking relative to the "end of file" isn't supported:
  23538. + * it has no meaning, so it returns -EINVAL.
  23539. + */
  23540. +static int memory_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  23541. +{
  23542. +    switch (orig) {
  23543. +        case 0:
  23544. +            file->f_pos = offset;
  23545. +            return file->f_pos;
  23546. +        case 1:
  23547. +            file->f_pos += offset;
  23548. +            return file->f_pos;
  23549. +        default:
  23550. +            return -EINVAL;
  23551. +    }
  23552. +    if (file->f_pos < 0)
  23553. +        return 0;
  23554. +    return file->f_pos;
  23555. +}
  23556. +
  23557. +#define write_kmem    write_mem
  23558. +#define mmap_kmem    mmap_mem
  23559. +#define zero_lseek    null_lseek
  23560. +#define write_zero    write_null
  23561. +
  23562. +static struct file_operations ram_fops = {
  23563. +    memory_lseek,
  23564. +    read_ram,
  23565. +    write_ram,
  23566. +    NULL,        /* ram_readdir */
  23567. +    NULL,        /* ram_select */
  23568. +    NULL,        /* ram_ioctl */
  23569. +    NULL,        /* ram_mmap */
  23570. +    NULL,        /* no special open code */
  23571. +    NULL,        /* no special release code */
  23572. +    NULL        /* fsync */
  23573. +};
  23574. +
  23575. +static struct file_operations mem_fops = {
  23576. +    memory_lseek,
  23577. +    read_mem,
  23578. +    write_mem,
  23579. +    NULL,        /* mem_readdir */
  23580. +    NULL,        /* mem_select */
  23581. +    NULL,        /* mem_ioctl */
  23582. +    mmap_mem,
  23583. +    NULL,        /* no special open code */
  23584. +    NULL,        /* no special release code */
  23585. +    NULL        /* fsync */
  23586. +};
  23587. +
  23588. +static struct file_operations kmem_fops = {
  23589. +    memory_lseek,
  23590. +    read_kmem,
  23591. +    write_kmem,
  23592. +    NULL,        /* kmem_readdir */
  23593. +    NULL,        /* kmem_select */
  23594. +    NULL,        /* kmem_ioctl */
  23595. +    mmap_kmem,
  23596. +    NULL,        /* no special open code */
  23597. +    NULL,        /* no special release code */
  23598. +    NULL        /* fsync */
  23599. +};
  23600. +
  23601. +static struct file_operations null_fops = {
  23602. +    null_lseek,
  23603. +    read_null,
  23604. +    write_null,
  23605. +    NULL,        /* null_readdir */
  23606. +    NULL,        /* null_select */
  23607. +    NULL,        /* null_ioctl */
  23608. +    NULL,        /* null_mmap */
  23609. +    NULL,        /* no special open code */
  23610. +    NULL,        /* no special release code */
  23611. +    NULL        /* fsync */
  23612. +};
  23613. +
  23614. +static struct file_operations port_fops = {
  23615. +    memory_lseek,
  23616. +    read_port,
  23617. +    write_port,
  23618. +    NULL,        /* port_readdir */
  23619. +    NULL,        /* port_select */
  23620. +    NULL,        /* port_ioctl */
  23621. +    NULL,        /* port_mmap */
  23622. +    NULL,        /* no special open code */
  23623. +    NULL,        /* no special release code */
  23624. +    NULL        /* fsync */
  23625. +};
  23626. +
  23627. +static struct file_operations zero_fops = {
  23628. +    zero_lseek,
  23629. +    read_zero,
  23630. +    write_zero,
  23631. +    NULL,        /* zero_readdir */
  23632. +    NULL,        /* zero_select */
  23633. +    NULL,        /* zero_ioctl */
  23634. +    mmap_zero,
  23635. +    NULL,        /* no special open code */
  23636. +    NULL        /* no special release code */
  23637. +};
  23638. +
  23639. +static struct file_operations full_fops = {
  23640. +    memory_lseek,
  23641. +    read_full,
  23642. +    write_full,
  23643. +    NULL,        /* full_readdir */
  23644. +    NULL,        /* full_select */
  23645. +    NULL,        /* full_ioctl */
  23646. +    NULL,        /* full_mmap */
  23647. +    NULL,        /* no special open code */
  23648. +    NULL        /* no special release code */
  23649. +};
  23650. +
  23651. +static int memory_open(struct inode * inode, struct file * filp)
  23652. +{
  23653. +    switch (MINOR(inode->i_rdev)) {
  23654. +        case 0:
  23655. +            filp->f_op = &ram_fops;
  23656. +            break;
  23657. +        case 1:
  23658. +            filp->f_op = &mem_fops;
  23659. +            break;
  23660. +        case 2:
  23661. +            filp->f_op = &kmem_fops;
  23662. +            break;
  23663. +        case 3:
  23664. +            filp->f_op = &null_fops;
  23665. +            break;
  23666. +        case 4:
  23667. +            filp->f_op = &port_fops;
  23668. +            break;
  23669. +        case 5:
  23670. +            filp->f_op = &zero_fops;
  23671. +            break;
  23672. +        case 7:
  23673. +            filp->f_op = &full_fops;
  23674. +            break;
  23675. +        case 8:
  23676. +            filp->f_op = &random_fops;
  23677. +            break;
  23678. +        case 9:
  23679. +            filp->f_op = &urandom_fops;
  23680. +            break;
  23681. +        default:
  23682. +            return -ENXIO;
  23683. +    }
  23684. +    if (filp->f_op && filp->f_op->open)
  23685. +        return filp->f_op->open(inode,filp);
  23686. +    return 0;
  23687. +}
  23688. +
  23689. +static struct file_operations memory_fops = {
  23690. +    NULL,        /* lseek */
  23691. +    NULL,        /* read */
  23692. +    NULL,        /* write */
  23693. +    NULL,        /* readdir */
  23694. +    NULL,        /* select */
  23695. +    NULL,        /* ioctl */
  23696. +    NULL,        /* mmap */
  23697. +    memory_open,    /* just a selector for the real open */
  23698. +    NULL,        /* release */
  23699. +    NULL        /* fsync */
  23700. +};
  23701. +
  23702. +int chr_dev_init(void)
  23703. +{
  23704. +    if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
  23705. +        printk("unable to get major %d for memory devs\n", MEM_MAJOR);
  23706. +    rand_initialize();
  23707. +    tty_init();
  23708. +#ifdef CONFIG_PRINTER
  23709. +    lp_init();
  23710. +#endif
  23711. +#if defined(CONFIG_KBDMOUSE) || defined(CONFIG_SOFT_WATCHDOG)
  23712. +    misc_init();
  23713. +#endif
  23714. +    return 0;
  23715. +}
  23716. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/misc.c linux/arch/arm/drivers/char/misc.c
  23717. --- linux.orig/arch/arm/drivers/char/misc.c    Thu Jan  1 01:00:00 1970
  23718. +++ linux/arch/arm/drivers/char/misc.c    Wed Jul 31 20:26:12 1996
  23719. @@ -0,0 +1,209 @@
  23720. +/*
  23721. + * linux/arch/arm/drivers/char/mouse.c
  23722. + *
  23723. + * Generic misc open routine by Johan Myreen
  23724. + *
  23725. + * Based on code from Linus
  23726. + *
  23727. + * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
  23728. + *   changes incorporated into 0.97pl4
  23729. + *   by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
  23730. + *   See busmouse.c for particulars.
  23731. + *
  23732. + * Made things a lot mode modular - easy to compile in just one or two
  23733. + * of the misc drivers, as they are now completely independent. Linus.
  23734. + *
  23735. + * Support for loadable modules. 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
  23736. + *
  23737. + * Fixed a failing symbol register to free the device registration
  23738. + *        Alan Cox <alan@lxorguk.ukuu.org.uk> 21-Jan-96
  23739. + *
  23740. + * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96
  23741. + *
  23742. + * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96
  23743. + *
  23744. + * Handling of mouse minor numbers for kerneld:
  23745. + *  Idea by Jacques Gelinas <jack@solucorp.qc.ca>,
  23746. + *  adapted by Bjorn Ekwall <bj0rn@blox.se>
  23747. + *  corrected by Alan Cox <alan@lxorguk.ukuu.org.uk>
  23748. + */
  23749. +
  23750. +#include <linux/config.h>
  23751. +#include <linux/module.h>
  23752. +
  23753. +#include <linux/fs.h>
  23754. +#include <linux/errno.h>
  23755. +#include <linux/miscdevice.h>
  23756. +#include <linux/kernel.h>
  23757. +#include <linux/major.h>
  23758. +#include <linux/malloc.h>
  23759. +#include <linux/proc_fs.h>
  23760. +#include <linux/stat.h>
  23761. +
  23762. +#include <linux/tty.h> /* needed by selection.h */
  23763. +#include "vt_kern.h"
  23764. +#include "selection.h" /* export its symbols */
  23765. +#ifdef CONFIG_KERNELD
  23766. +#include <linux/kerneld.h>
  23767. +#endif
  23768. +
  23769. +/*
  23770. + * Head entry for the doubly linked miscdevice list
  23771. + */
  23772. +static struct miscdevice misc_list = { 0, "head", NULL, &misc_list, &misc_list };
  23773. +
  23774. +/*
  23775. + * Assigned numbers, used for dynamic minors
  23776. + */
  23777. +#define DYNAMIC_MINORS 64 /* like dynamic majors */
  23778. +static unsigned char misc_minors[DYNAMIC_MINORS / 8];
  23779. +
  23780. +#ifndef MODULE
  23781. +extern void watchdog_init(void);
  23782. +extern int arch_mouse_init(void);
  23783. +
  23784. +#ifdef CONFIG_PROC_FS
  23785. +static int proc_misc_read(char *buf, char **start, off_t offset, int len, int unused)
  23786. +{
  23787. +    struct miscdevice *p;
  23788. +
  23789. +    len=0;
  23790. +    for (p = misc_list.next; p != &misc_list; p = p->next)
  23791. +        len += sprintf(buf+len, "%3i %s\n",p->minor, p->name ?: "");
  23792. +    return len;
  23793. +}
  23794. +
  23795. +#endif /* PROC_FS */
  23796. +#endif /* !MODULE */
  23797. +
  23798. +static int misc_open(struct inode * inode, struct file * file)
  23799. +{
  23800. +    int minor = MINOR(inode->i_rdev);
  23801. +    struct miscdevice *c = misc_list.next;
  23802. +    file->f_op = NULL;
  23803. +
  23804. +    while ((c != &misc_list) && (c->minor != minor))
  23805. +        c = c->next;
  23806. +    if (c == &misc_list) {
  23807. +#ifdef CONFIG_KERNELD
  23808. +        char modname[20];
  23809. +        sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor);
  23810. +        request_module(modname);
  23811. +        c = misc_list.next;
  23812. +        while ((c != &misc_list) && (c->minor != minor))
  23813. +            c = c->next;
  23814. +        if (c == &misc_list)
  23815. +#endif
  23816. +            return -ENODEV;
  23817. +    }
  23818. +
  23819. +    if ((file->f_op = c->fops))
  23820. +        return file->f_op->open(inode,file);
  23821. +    else
  23822. +        return -ENODEV;
  23823. +}
  23824. +
  23825. +static struct file_operations misc_fops = {
  23826. +        NULL,        /* seek */
  23827. +    NULL,        /* read */
  23828. +    NULL,        /* write */
  23829. +    NULL,        /* readdir */
  23830. +    NULL,        /* select */
  23831. +    NULL,        /* ioctl */
  23832. +    NULL,        /* mmap */
  23833. +        misc_open,
  23834. +        NULL        /* release */
  23835. +};
  23836. +
  23837. +int misc_register(struct miscdevice * misc)
  23838. +{
  23839. +    if (misc->next || misc->prev)
  23840. +        return -EBUSY;
  23841. +    if (misc->minor == MISC_DYNAMIC_MINOR) {
  23842. +        int i = DYNAMIC_MINORS;
  23843. +        while (--i >= 0)
  23844. +            if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
  23845. +                break;
  23846. +        if (i<0) return -EBUSY;
  23847. +        misc->minor = i;
  23848. +    }
  23849. +    if (misc->minor < DYNAMIC_MINORS)
  23850. +        misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
  23851. +    MOD_INC_USE_COUNT;
  23852. +    misc->next = &misc_list;
  23853. +    misc->prev = misc_list.prev;
  23854. +    misc->prev->next = misc;
  23855. +    misc->next->prev = misc;
  23856. +    return 0;
  23857. +}
  23858. +
  23859. +int misc_deregister(struct miscdevice * misc)
  23860. +{
  23861. +    int i = misc->minor;
  23862. +    if (!misc->next || !misc->prev)
  23863. +        return -EINVAL;
  23864. +    MOD_DEC_USE_COUNT;
  23865. +    misc->prev->next = misc->next;
  23866. +    misc->next->prev = misc->prev;
  23867. +    misc->next = NULL;
  23868. +    misc->prev = NULL;
  23869. +    if (i < DYNAMIC_MINORS && i>0) {
  23870. +        misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
  23871. +    }
  23872. +    return 0;
  23873. +}
  23874. +
  23875. +#ifdef MODULE
  23876. +
  23877. +#define misc_init init_module
  23878. +
  23879. +void cleanup_module(void)
  23880. +{
  23881. +    unregister_chrdev(MISC_MAJOR, "misc");
  23882. +}
  23883. +
  23884. +#endif
  23885. +
  23886. +static struct symbol_table misc_syms = {
  23887. +/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
  23888. +#include <linux/symtab_begin.h>
  23889. +    X(misc_register),
  23890. +    X(misc_deregister),
  23891. +#ifndef MODULE
  23892. +    X(set_selection),   /* used by the kmouse module, can only */
  23893. +    X(paste_selection), /* be exported if misc.c is in linked in */
  23894. +#endif
  23895. +#include <linux/symtab_end.h>
  23896. +};
  23897. +
  23898. +int misc_init(void)
  23899. +{
  23900. +#ifndef MODULE
  23901. +#ifdef CONFIG_PROC_FS
  23902. +    proc_register_dynamic(&proc_root, &(struct proc_dir_entry) {
  23903. +        0, 4, "misc",
  23904. +        S_IFREG | S_IRUGO, 1, 0, 0,
  23905. +        0, NULL /* ops -- default to array */,
  23906. +        &proc_misc_read /* get_info */,
  23907. +    });    
  23908. +#endif /* PROC_FS */
  23909. +#ifdef CONFIG_KBDMOUSE
  23910. +    arch_mouse_init();
  23911. +#endif
  23912. +#ifdef CONFIG_SOFT_WATCHDOG
  23913. +    watchdog_init();
  23914. +#endif
  23915. +#endif /* !MODULE */
  23916. +    if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
  23917. +      printk("unable to get major %d for misc devices\n",
  23918. +         MISC_MAJOR);
  23919. +        return -EIO;
  23920. +    }
  23921. +
  23922. +    if(register_symtab(&misc_syms)!=0)
  23923. +    {
  23924. +        unregister_chrdev(MISC_MAJOR, "misc");
  23925. +        return -EIO;
  23926. +    }
  23927. +    return 0;
  23928. +}
  23929. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/n_tty.c linux/arch/arm/drivers/char/n_tty.c
  23930. --- linux.orig/arch/arm/drivers/char/n_tty.c    Thu Jan  1 01:00:00 1970
  23931. +++ linux/arch/arm/drivers/char/n_tty.c    Fri Sep  6 21:12:49 1996
  23932. @@ -0,0 +1,1030 @@
  23933. +/*
  23934. + * n_tty.c --- implements the N_TTY line discipline.
  23935. + * 
  23936. + * This code used to be in tty_io.c, but things are getting hairy
  23937. + * enough that it made sense to split things off.  (The N_TTY
  23938. + * processing has changed so much that it's hardly recognizable,
  23939. + * anyway...)
  23940. + *
  23941. + * Note that the open routine for N_TTY is guaranteed never to return
  23942. + * an error.  This is because Linux will fall back to setting a line
  23943. + * to N_TTY if it can not switch to any other line discipline.  
  23944. + *
  23945. + * Written by Theodore Ts'o, Copyright 1994.
  23946. + * 
  23947. + * This file also contains code originally written by Linus Torvalds,
  23948. + * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
  23949. + * 
  23950. + * This file may be redistributed under the terms of the GNU Public
  23951. + * License.
  23952. + *
  23953. + * Altered for ARM to reduce memory usage.
  23954. + */
  23955. +
  23956. +#include <linux/types.h>
  23957. +#include <linux/major.h>
  23958. +#include <linux/errno.h>
  23959. +#include <linux/signal.h>
  23960. +#include <linux/fcntl.h>
  23961. +#include <linux/sched.h>
  23962. +#include <linux/interrupt.h>
  23963. +#include <linux/tty.h>
  23964. +#include <linux/timer.h>
  23965. +#include <linux/ctype.h>
  23966. +#include <linux/kd.h>
  23967. +#include <linux/mm.h>
  23968. +#include <linux/string.h>
  23969. +#include <linux/malloc.h>
  23970. +
  23971. +#include <asm/segment.h>
  23972. +#include <asm/system.h>
  23973. +#include <asm/bitops.h>
  23974. +
  23975. +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
  23976. +
  23977. +#ifndef MIN
  23978. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  23979. +#endif
  23980. +
  23981. +/* number of characters left in xmit buffer before select has we have room */
  23982. +#define WAKEUP_CHARS 256
  23983. +
  23984. +/*
  23985. + * This defines the low- and high-watermarks for throttling and
  23986. + * unthrottling the TTY driver.  These watermarks are used for
  23987. + * controlling the space in the read buffer.
  23988. + */
  23989. +#define TTY_THRESHOLD_THROTTLE        (N_TTY_BUF_SIZE - 128)
  23990. +#define TTY_THRESHOLD_UNTHROTTLE     128
  23991. +
  23992. +static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
  23993. +{
  23994. +    if (tty->read_cnt < N_TTY_BUF_SIZE) {
  23995. +        tty->read_buf[tty->read_head] = c;
  23996. +        tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
  23997. +        tty->read_cnt++;
  23998. +    }
  23999. +}
  24000. +
  24001. +/*
  24002. + * Flush the input buffer
  24003. + */
  24004. +void n_tty_flush_buffer(struct tty_struct * tty)
  24005. +{
  24006. +    tty->read_head = tty->read_tail = tty->read_cnt = 0;
  24007. +    tty->canon_head = tty->canon_data = tty->erasing = 0;
  24008. +    memset(&tty->read_flags, 0, sizeof tty->read_flags);
  24009. +    
  24010. +    if (!tty->link)
  24011. +        return;
  24012. +
  24013. +    if (tty->driver.unthrottle)
  24014. +        (tty->driver.unthrottle)(tty);
  24015. +    if (tty->link->packet) {
  24016. +        tty->ctrl_status |= TIOCPKT_FLUSHREAD;
  24017. +        wake_up_interruptible(&tty->link->read_wait);
  24018. +    }
  24019. +}
  24020. +
  24021. +/*
  24022. + * Return number of characters buffered to be delivered to user
  24023. + */
  24024. +int n_tty_chars_in_buffer(struct tty_struct *tty)
  24025. +{
  24026. +    return tty->read_cnt;
  24027. +}
  24028. +
  24029. +/*
  24030. + * Perform OPOST processing.  Returns -1 when the output device is
  24031. + * full and the character must be retried.
  24032. + */
  24033. +static int opost(unsigned char c, struct tty_struct *tty)
  24034. +{
  24035. +    int    space, spaces;
  24036. +
  24037. +    space = tty->driver.write_room(tty);
  24038. +    if (!space)
  24039. +        return -1;
  24040. +
  24041. +    if (O_OPOST(tty)) {
  24042. +        switch (c) {
  24043. +        case '\n':
  24044. +            if (O_ONLRET(tty))
  24045. +                tty->column = 0;
  24046. +            if (O_ONLCR(tty)) {
  24047. +                if (space < 2)
  24048. +                    return -1;
  24049. +                tty->driver.put_char(tty, '\r');
  24050. +                tty->column = 0;
  24051. +            }
  24052. +            tty->canon_column = tty->column;
  24053. +            break;
  24054. +        case '\r':
  24055. +            if (O_ONOCR(tty) && tty->column == 0)
  24056. +                return 0;
  24057. +            if (O_OCRNL(tty)) {
  24058. +                c = '\n';
  24059. +                if (O_ONLRET(tty))
  24060. +                    tty->canon_column = tty->column = 0;
  24061. +                break;
  24062. +            }
  24063. +            tty->canon_column = tty->column = 0;
  24064. +            break;
  24065. +        case '\t':
  24066. +            spaces = 8 - (tty->column & 7);
  24067. +            if (O_TABDLY(tty) == XTABS) {
  24068. +                if (space < spaces)
  24069. +                    return -1;
  24070. +                tty->column += spaces;
  24071. +                tty->driver.write(tty, 0, "        ", spaces);
  24072. +                return 0;
  24073. +            }
  24074. +            tty->column += spaces;
  24075. +            break;
  24076. +        case '\b':
  24077. +            if (tty->column > 0)
  24078. +                tty->column--;
  24079. +            break;
  24080. +        default:
  24081. +            if (O_OLCUC(tty))
  24082. +                c = toupper(c);
  24083. +            if (!iscntrl(c))
  24084. +                tty->column++;
  24085. +            break;
  24086. +        }
  24087. +    }
  24088. +    tty->driver.put_char(tty, c);
  24089. +    return 0;
  24090. +}
  24091. +
  24092. +static inline void put_char(unsigned char c, struct tty_struct *tty)
  24093. +{
  24094. +    tty->driver.put_char(tty, c);
  24095. +}
  24096. +
  24097. +/* Must be called only when L_ECHO(tty) is true. */
  24098. +
  24099. +static void echo_char(unsigned char c, struct tty_struct *tty)
  24100. +{
  24101. +    if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
  24102. +        put_char('^', tty);
  24103. +        put_char(c ^ 0100, tty);
  24104. +        tty->column += 2;
  24105. +    } else
  24106. +        opost(c, tty);
  24107. +}
  24108. +
  24109. +static inline void finish_erasing(struct tty_struct *tty)
  24110. +{
  24111. +    if (tty->erasing) {
  24112. +        put_char('/', tty);
  24113. +        tty->column += 2;
  24114. +        tty->erasing = 0;
  24115. +    }
  24116. +}
  24117. +
  24118. +static void eraser(unsigned char c, struct tty_struct *tty)
  24119. +{
  24120. +    enum { ERASE, WERASE, KILL } kill_type;
  24121. +    int head, seen_alnums;
  24122. +
  24123. +    if (tty->read_head == tty->canon_head) {
  24124. +        /* opost('\a', tty); */        /* what do you think? */
  24125. +        return;
  24126. +    }
  24127. +    if (c == ERASE_CHAR(tty))
  24128. +        kill_type = ERASE;
  24129. +    else if (c == WERASE_CHAR(tty))
  24130. +        kill_type = WERASE;
  24131. +    else {
  24132. +        if (!L_ECHO(tty)) {
  24133. +            tty->read_cnt -= ((tty->read_head - tty->canon_head) &
  24134. +                      (N_TTY_BUF_SIZE - 1));
  24135. +            tty->read_head = tty->canon_head;
  24136. +            return;
  24137. +        }
  24138. +        if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
  24139. +            tty->read_cnt -= ((tty->read_head - tty->canon_head) &
  24140. +                      (N_TTY_BUF_SIZE - 1));
  24141. +            tty->read_head = tty->canon_head;
  24142. +            finish_erasing(tty);
  24143. +            echo_char(KILL_CHAR(tty), tty);
  24144. +            /* Add a newline if ECHOK is on and ECHOKE is off. */
  24145. +            if (L_ECHOK(tty))
  24146. +                opost('\n', tty);
  24147. +            return;
  24148. +        }
  24149. +        kill_type = KILL;
  24150. +    }
  24151. +
  24152. +    seen_alnums = 0;
  24153. +    while (tty->read_head != tty->canon_head) {
  24154. +        head = (tty->read_head - 1) & (N_TTY_BUF_SIZE-1);
  24155. +        c = tty->read_buf[head];
  24156. +        if (kill_type == WERASE) {
  24157. +            /* Equivalent to BSD's ALTWERASE. */
  24158. +            if (isalnum(c) || c == '_')
  24159. +                seen_alnums++;
  24160. +            else if (seen_alnums)
  24161. +                break;
  24162. +        }
  24163. +        tty->read_head = head;
  24164. +        tty->read_cnt--;
  24165. +        if (L_ECHO(tty)) {
  24166. +            if (L_ECHOPRT(tty)) {
  24167. +                if (!tty->erasing) {
  24168. +                    put_char('\\', tty);
  24169. +                    tty->column++;
  24170. +                    tty->erasing = 1;
  24171. +                }
  24172. +                echo_char(c, tty);
  24173. +            } else if (kill_type == ERASE && !L_ECHOE(tty)) {
  24174. +                echo_char(ERASE_CHAR(tty), tty);
  24175. +            } else if (c == '\t') {
  24176. +                unsigned int col = tty->canon_column;
  24177. +                unsigned long tail = tty->canon_head;
  24178. +
  24179. +                /* Find the column of the last char. */
  24180. +                while (tail != tty->read_head) {
  24181. +                    c = tty->read_buf[tail];
  24182. +                    if (c == '\t')
  24183. +                        col = (col | 7) + 1;
  24184. +                    else if (iscntrl(c)) {
  24185. +                        if (L_ECHOCTL(tty))
  24186. +                            col += 2;
  24187. +                    } else
  24188. +                        col++;
  24189. +                    tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  24190. +                }
  24191. +
  24192. +                /* should never happen */
  24193. +                if (tty->column > 0x80000000)
  24194. +                    tty->column = 0;
  24195. +
  24196. +                /* Now backup to that column. */
  24197. +                while (tty->column > col) {
  24198. +                    /* Can't use opost here. */
  24199. +                    put_char('\b', tty);
  24200. +                    if (tty->column > 0)
  24201. +                        tty->column--;
  24202. +                }
  24203. +            } else {
  24204. +                if (iscntrl(c) && L_ECHOCTL(tty)) {
  24205. +                    put_char('\b', tty);
  24206. +                    put_char(' ', tty);
  24207. +                    put_char('\b', tty);
  24208. +                    if (tty->column > 0)
  24209. +                        tty->column--;
  24210. +                }
  24211. +                if (!iscntrl(c) || L_ECHOCTL(tty)) {
  24212. +                    put_char('\b', tty);
  24213. +                    put_char(' ', tty);
  24214. +                    put_char('\b', tty);
  24215. +                    if (tty->column > 0)
  24216. +                        tty->column--;
  24217. +                }
  24218. +            }
  24219. +        }
  24220. +        if (kill_type == ERASE)
  24221. +            break;
  24222. +    }
  24223. +    if (tty->read_head == tty->canon_head)
  24224. +        finish_erasing(tty);
  24225. +}
  24226. +
  24227. +static inline void isig(int sig, struct tty_struct *tty, int flush)
  24228. +{
  24229. +    if (tty->pgrp > 0)
  24230. +        kill_pg(tty->pgrp, sig, 1);
  24231. +    if (flush || !L_NOFLSH(tty)) {
  24232. +        n_tty_flush_buffer(tty);
  24233. +        if (tty->driver.flush_buffer)
  24234. +            tty->driver.flush_buffer(tty);
  24235. +    }
  24236. +}
  24237. +
  24238. +static inline void n_tty_receive_break(struct tty_struct *tty)
  24239. +{
  24240. +    if (I_IGNBRK(tty))
  24241. +        return;
  24242. +    if (I_BRKINT(tty)) {
  24243. +        isig(SIGINT, tty, 1);
  24244. +        return;
  24245. +    }
  24246. +    if (I_PARMRK(tty)) {
  24247. +        put_tty_queue('\377', tty);
  24248. +        put_tty_queue('\0', tty);
  24249. +    }
  24250. +    put_tty_queue('\0', tty);
  24251. +    wake_up_interruptible(&tty->read_wait);
  24252. +}
  24253. +
  24254. +static inline void n_tty_receive_overrun(struct tty_struct *tty)
  24255. +{
  24256. +    char buf[64];
  24257. +
  24258. +    tty->num_overrun++;
  24259. +    if (tty->overrun_time < (jiffies - HZ)) {
  24260. +        printk("%s: %d input overrun(s)\n", _tty_name(tty, buf),
  24261. +               tty->num_overrun);
  24262. +        tty->overrun_time = jiffies;
  24263. +        tty->num_overrun = 0;
  24264. +    }
  24265. +}
  24266. +
  24267. +static inline void n_tty_receive_parity_error(struct tty_struct *tty,
  24268. +                          unsigned char c)
  24269. +{
  24270. +    if (I_IGNPAR(tty)) {
  24271. +        return;
  24272. +    }
  24273. +    if (I_PARMRK(tty)) {
  24274. +        put_tty_queue('\377', tty);
  24275. +        put_tty_queue('\0', tty);
  24276. +        put_tty_queue(c, tty);
  24277. +    } else    if (I_INPCK(tty))
  24278. +        put_tty_queue('\0', tty);
  24279. +    else
  24280. +        put_tty_queue(c, tty);
  24281. +    wake_up_interruptible(&tty->read_wait);
  24282. +}
  24283. +
  24284. +static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
  24285. +{
  24286. +    if (tty->raw) {
  24287. +        put_tty_queue(c, tty);
  24288. +        return;
  24289. +    }
  24290. +    
  24291. +    if (tty->stopped && I_IXON(tty) && I_IXANY(tty)) {
  24292. +        start_tty(tty);
  24293. +        return;
  24294. +    }
  24295. +    
  24296. +    if (I_ISTRIP(tty))
  24297. +        c &= 0x7f;
  24298. +    if (I_IUCLC(tty) && L_IEXTEN(tty))
  24299. +        c=tolower(c);
  24300. +
  24301. +    if (tty->closing) {
  24302. +        if (I_IXON(tty)) {
  24303. +            if (c == START_CHAR(tty))
  24304. +                start_tty(tty);
  24305. +            else if (c == STOP_CHAR(tty))
  24306. +                stop_tty(tty);
  24307. +        }
  24308. +        return;
  24309. +    }
  24310. +
  24311. +    /*
  24312. +     * If the previous character was LNEXT, or we know that this
  24313. +     * character is not one of the characters that we'll have to
  24314. +     * handle specially, do shortcut processing to speed things
  24315. +     * up.
  24316. +     */
  24317. +    if (!test_bit(c, &tty->process_char_map) || tty->lnext) {
  24318. +        finish_erasing(tty);
  24319. +        tty->lnext = 0;
  24320. +        if (L_ECHO(tty)) {
  24321. +            if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  24322. +                put_char('\a', tty); /* beep if no space */
  24323. +                return;
  24324. +            }
  24325. +            /* Record the column of first canon char. */
  24326. +            if (tty->canon_head == tty->read_head)
  24327. +                tty->canon_column = tty->column;
  24328. +            echo_char(c, tty);
  24329. +        }
  24330. +        if (I_PARMRK(tty) && c == (unsigned char) '\377')
  24331. +            put_tty_queue(c, tty);
  24332. +        put_tty_queue(c, tty);
  24333. +        return;
  24334. +    }
  24335. +        
  24336. +    if (c == '\r') {
  24337. +        if (I_IGNCR(tty))
  24338. +            return;
  24339. +        if (I_ICRNL(tty))
  24340. +            c = '\n';
  24341. +    } else if (c == '\n' && I_INLCR(tty))
  24342. +        c = '\r';
  24343. +    if (I_IXON(tty)) {
  24344. +        if (c == START_CHAR(tty)) {
  24345. +            start_tty(tty);
  24346. +            return;
  24347. +        }
  24348. +        if (c == STOP_CHAR(tty)) {
  24349. +            stop_tty(tty);
  24350. +            return;
  24351. +        }
  24352. +    }
  24353. +    if (L_ISIG(tty)) {
  24354. +        int signal;
  24355. +        signal = SIGINT;
  24356. +        if (c == INTR_CHAR(tty))
  24357. +            goto send_signal;
  24358. +        signal = SIGQUIT;
  24359. +        if (c == QUIT_CHAR(tty))
  24360. +            goto send_signal;
  24361. +        signal = SIGTSTP;
  24362. +        if (c == SUSP_CHAR(tty)) {
  24363. +send_signal:
  24364. +            isig(signal, tty, 0);
  24365. +            return;
  24366. +        }
  24367. +    }
  24368. +    if (L_ICANON(tty)) {
  24369. +        if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
  24370. +            (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
  24371. +            eraser(c, tty);
  24372. +            return;
  24373. +        }
  24374. +        if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
  24375. +            tty->lnext = 1;
  24376. +            if (L_ECHO(tty)) {
  24377. +                finish_erasing(tty);
  24378. +                if (L_ECHOCTL(tty)) {
  24379. +                    put_char('^', tty);
  24380. +                    put_char('\b', tty);
  24381. +                }
  24382. +            }
  24383. +            return;
  24384. +        }
  24385. +        if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
  24386. +            L_IEXTEN(tty)) {
  24387. +            unsigned long tail = tty->canon_head;
  24388. +
  24389. +            finish_erasing(tty);
  24390. +            echo_char(c, tty);
  24391. +            opost('\n', tty);
  24392. +            while (tail != tty->read_head) {
  24393. +                echo_char(tty->read_buf[tail], tty);
  24394. +                tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  24395. +            }
  24396. +            return;
  24397. +        }
  24398. +        if (c == '\n') {
  24399. +            if (L_ECHO(tty) || L_ECHONL(tty)) {
  24400. +                if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  24401. +                    put_char('\a', tty);
  24402. +                    return;
  24403. +                }
  24404. +                opost('\n', tty);
  24405. +            }
  24406. +            goto handle_newline;
  24407. +        }
  24408. +        if (c == EOF_CHAR(tty)) {
  24409. +                if (tty->canon_head != tty->read_head)
  24410. +                    set_bit(TTY_PUSH, &tty->flags);
  24411. +            c = __DISABLED_CHAR;
  24412. +            goto handle_newline;
  24413. +        }
  24414. +        if ((c == EOL_CHAR(tty)) ||
  24415. +            (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
  24416. +            /*
  24417. +             * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
  24418. +             */
  24419. +            if (L_ECHO(tty)) {
  24420. +                if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  24421. +                    put_char('\a', tty);
  24422. +                    return;
  24423. +                }
  24424. +                /* Record the column of first canon char. */
  24425. +                if (tty->canon_head == tty->read_head)
  24426. +                    tty->canon_column = tty->column;
  24427. +                echo_char(c, tty);
  24428. +            }
  24429. +            /*
  24430. +             * XXX does PARMRK doubling happen for
  24431. +             * EOL_CHAR and EOL2_CHAR?
  24432. +             */
  24433. +            if (I_PARMRK(tty) && c == (unsigned char) '\377')
  24434. +                put_tty_queue(c, tty);
  24435. +
  24436. +        handle_newline:
  24437. +            set_bit(tty->read_head, &tty->read_flags);
  24438. +            put_tty_queue(c, tty);
  24439. +            tty->canon_head = tty->read_head;
  24440. +            tty->canon_data++;
  24441. +            if (tty->fasync)
  24442. +                kill_fasync(tty->fasync, SIGIO);
  24443. +            if (tty->read_wait)
  24444. +                wake_up_interruptible(&tty->read_wait);
  24445. +            return;
  24446. +        }
  24447. +    }
  24448. +    
  24449. +    finish_erasing(tty);
  24450. +    if (L_ECHO(tty)) {
  24451. +        if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  24452. +            put_char('\a', tty); /* beep if no space */
  24453. +            return;
  24454. +        }
  24455. +        if (c == '\n')
  24456. +            opost('\n', tty);
  24457. +        else {
  24458. +            /* Record the column of first canon char. */
  24459. +            if (tty->canon_head == tty->read_head)
  24460. +                tty->canon_column = tty->column;
  24461. +            echo_char(c, tty);
  24462. +        }
  24463. +    }
  24464. +
  24465. +    if (I_PARMRK(tty) && c == (unsigned char) '\377')
  24466. +        put_tty_queue(c, tty);
  24467. +
  24468. +    put_tty_queue(c, tty);
  24469. +}    
  24470. +
  24471. +static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
  24472. +                  char *fp, int count)
  24473. +{
  24474. +    const unsigned char *p;
  24475. +    char *f, flags = 0;
  24476. +    int    i;
  24477. +
  24478. +    if (!tty->read_buf)
  24479. +        return;
  24480. +
  24481. +    if (tty->real_raw) {
  24482. +        i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,
  24483. +                   N_TTY_BUF_SIZE - tty->read_head));
  24484. +        memcpy(tty->read_buf + tty->read_head, cp, i);
  24485. +        tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
  24486. +        tty->read_cnt += i;
  24487. +        cp += i;
  24488. +        count -= i;
  24489. +
  24490. +        i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,
  24491. +                   N_TTY_BUF_SIZE - tty->read_head));
  24492. +        memcpy(tty->read_buf + tty->read_head, cp, i);
  24493. +        tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
  24494. +        tty->read_cnt += i;
  24495. +    } else {
  24496. +        for (i=count, p = cp, f = fp; i; i--, p++) {
  24497. +            if (f)
  24498. +                flags = *f++;
  24499. +            switch (flags) {
  24500. +            case TTY_NORMAL:
  24501. +                n_tty_receive_char(tty, *p);
  24502. +                break;
  24503. +            case TTY_BREAK:
  24504. +                n_tty_receive_break(tty);
  24505. +                break;
  24506. +            case TTY_PARITY:
  24507. +            case TTY_FRAME:
  24508. +                n_tty_receive_parity_error(tty, *p);
  24509. +                break;
  24510. +            case TTY_OVERRUN:
  24511. +                n_tty_receive_overrun(tty);
  24512. +                break;
  24513. +            default:
  24514. +                printk("%s: unknown flag %d\n", tty_name(tty),
  24515. +                       flags);
  24516. +                break;
  24517. +            }
  24518. +        }
  24519. +        if (tty->driver.flush_chars)
  24520. +            tty->driver.flush_chars(tty);
  24521. +    }
  24522. +
  24523. +    if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {
  24524. +        if (tty->fasync)
  24525. +            kill_fasync(tty->fasync, SIGIO);
  24526. +        if (tty->read_wait)
  24527. +            wake_up_interruptible(&tty->read_wait);
  24528. +    }
  24529. +
  24530. +    if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) &&
  24531. +        tty->driver.throttle &&
  24532. +        !set_bit(TTY_THROTTLED, &tty->flags))
  24533. +        tty->driver.throttle(tty);
  24534. +}
  24535. +
  24536. +static int n_tty_receive_room(struct tty_struct *tty)
  24537. +{
  24538. +    int    left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
  24539. +
  24540. +    /*
  24541. +     * If we are doing input canonicalization, and there are no
  24542. +     * pending newlines, let characters through without limit, so
  24543. +     * that erase characters will be handled.  Other excess
  24544. +     * characters will be beeped.
  24545. +     */
  24546. +    if (tty->icanon && !tty->canon_data)
  24547. +        return N_TTY_BUF_SIZE;
  24548. +
  24549. +    if (left > 0)
  24550. +        return left;
  24551. +    return 0;
  24552. +}
  24553. +
  24554. +int is_ignored(int sig)
  24555. +{
  24556. +    return ((current->blocked & (1<<(sig-1))) ||
  24557. +            (current->sig->action[sig-1].sa_handler == SIG_IGN));
  24558. +}
  24559. +
  24560. +static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
  24561. +{
  24562. +    if (!tty)
  24563. +        return;
  24564. +    
  24565. +    tty->icanon = (L_ICANON(tty) != 0);
  24566. +    if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
  24567. +        I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
  24568. +        I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
  24569. +        I_PARMRK(tty)) {
  24570. +        cli();
  24571. +        memset(tty->process_char_map, 0, 256/8);
  24572. +
  24573. +        if (I_IGNCR(tty) || I_ICRNL(tty))
  24574. +            set_bit('\r', &tty->process_char_map);
  24575. +        if (I_INLCR(tty))
  24576. +            set_bit('\n', &tty->process_char_map);
  24577. +
  24578. +        if (L_ICANON(tty)) {
  24579. +            set_bit(ERASE_CHAR(tty), &tty->process_char_map);
  24580. +            set_bit(KILL_CHAR(tty), &tty->process_char_map);
  24581. +            set_bit(EOF_CHAR(tty), &tty->process_char_map);
  24582. +            set_bit('\n', &tty->process_char_map);
  24583. +            set_bit(EOL_CHAR(tty), &tty->process_char_map);
  24584. +            if (L_IEXTEN(tty)) {
  24585. +                set_bit(WERASE_CHAR(tty),
  24586. +                    &tty->process_char_map);
  24587. +                set_bit(LNEXT_CHAR(tty),
  24588. +                    &tty->process_char_map);
  24589. +                set_bit(EOL2_CHAR(tty),
  24590. +                    &tty->process_char_map);
  24591. +                if (L_ECHO(tty))
  24592. +                    set_bit(REPRINT_CHAR(tty),
  24593. +                        &tty->process_char_map);
  24594. +            }
  24595. +        }
  24596. +        if (I_IXON(tty)) {
  24597. +            set_bit(START_CHAR(tty), &tty->process_char_map);
  24598. +            set_bit(STOP_CHAR(tty), &tty->process_char_map);
  24599. +        }
  24600. +        if (L_ISIG(tty)) {
  24601. +            set_bit(INTR_CHAR(tty), &tty->process_char_map);
  24602. +            set_bit(QUIT_CHAR(tty), &tty->process_char_map);
  24603. +            set_bit(SUSP_CHAR(tty), &tty->process_char_map);
  24604. +        }
  24605. +        clear_bit(__DISABLED_CHAR, &tty->process_char_map);
  24606. +        sti();
  24607. +        tty->raw = 0;
  24608. +        tty->real_raw = 0;
  24609. +    } else {
  24610. +        tty->raw = 1;
  24611. +        if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
  24612. +            (I_IGNPAR(tty) || !I_INPCK(tty)) &&
  24613. +            (tty->driver.flags & TTY_DRIVER_REAL_RAW))
  24614. +            tty->real_raw = 1;
  24615. +        else
  24616. +            tty->real_raw = 0;
  24617. +    }
  24618. +}
  24619. +
  24620. +static void n_tty_close(struct tty_struct *tty)
  24621. +{
  24622. +    n_tty_flush_buffer(tty);
  24623. +    if (tty->read_buf) {
  24624. +        kfree_s (tty->read_buf, N_TTY_BUF_SIZE);
  24625. +        tty->read_buf = 0;
  24626. +    }
  24627. +}
  24628. +
  24629. +static int n_tty_open(struct tty_struct *tty)
  24630. +{
  24631. +    if (!tty)
  24632. +        return -EINVAL;
  24633. +
  24634. +    if (!tty->read_buf) {
  24635. +        tty->read_buf = (unsigned char *)
  24636. +            kmalloc (N_TTY_BUF_SIZE, intr_count ? GFP_ATOMIC : GFP_KERNEL);
  24637. +        if (!tty->read_buf)
  24638. +            return -ENOMEM;
  24639. +    }
  24640. +    memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
  24641. +    tty->read_head = tty->read_tail = tty->read_cnt = 0;
  24642. +    tty->canon_head = tty->canon_data = tty->erasing = 0;
  24643. +    tty->column = 0;
  24644. +    memset(tty->read_flags, 0, sizeof(tty->read_flags));
  24645. +    n_tty_set_termios(tty, 0);
  24646. +    tty->minimum_to_wake = 1;
  24647. +    tty->closing = 0;
  24648. +    return 0;
  24649. +}
  24650. +
  24651. +static inline int input_available_p(struct tty_struct *tty, int amt)
  24652. +{
  24653. +    if (L_ICANON(tty)) {
  24654. +        if (tty->canon_data)
  24655. +            return 1;
  24656. +    } else if (tty->read_cnt >= (amt ? amt : 1))
  24657. +        return 1;
  24658. +
  24659. +    return 0;
  24660. +}
  24661. +
  24662. +/*
  24663. + * Helper function to speed up read_chan.  It is only called when
  24664. + * ICANON is off; it copies characters straight from the tty queue to
  24665. + * user space directly.  It can be profitably called twice; once to
  24666. + * drain the space from the tail pointer to the (physical) end of the
  24667. + * buffer, and once to drain the space from the (physical) beginning of
  24668. + * the buffer to head pointer.
  24669. + */
  24670. +static inline void copy_from_read_buf(struct tty_struct *tty,
  24671. +                      unsigned char **b,
  24672. +                      unsigned int *nr)
  24673. +
  24674. +{
  24675. +    int    n;
  24676. +
  24677. +    n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));
  24678. +    if (!n)
  24679. +        return;
  24680. +    memcpy_tofs(*b, &tty->read_buf[tty->read_tail], n);
  24681. +    tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
  24682. +    tty->read_cnt -= n;
  24683. +    *b += n;
  24684. +    *nr -= n;
  24685. +}
  24686. +
  24687. +static int read_chan(struct tty_struct *tty, struct file *file,
  24688. +             unsigned char *buf, unsigned int nr)
  24689. +{
  24690. +    struct wait_queue wait = { current, NULL };
  24691. +    int c;
  24692. +    unsigned char *b = buf;
  24693. +    int minimum, time;
  24694. +    int retval = 0;
  24695. +    int size;
  24696. +
  24697. +do_it_again:
  24698. +
  24699. +    if (!tty->read_buf) {
  24700. +        printk("n_tty_read_chan: called with read_buf == NULL?!?\n");
  24701. +        return -EIO;
  24702. +    }
  24703. +
  24704. +    /* Job control check -- must be done at start and after
  24705. +       every sleep (POSIX.1 7.1.1.4). */
  24706. +    /* NOTE: not yet done after every sleep pending a thorough
  24707. +       check of the logic of this change. -- jlc */
  24708. +    /* don't stop on /dev/console */
  24709. +    if (file->f_inode->i_rdev != CONSOLE_DEV &&
  24710. +        current->tty == tty) {
  24711. +        if (tty->pgrp <= 0)
  24712. +            printk("read_chan: tty->pgrp <= 0!\n");
  24713. +        else if (current->pgrp != tty->pgrp) {
  24714. +            if (is_ignored(SIGTTIN) ||
  24715. +                is_orphaned_pgrp(current->pgrp))
  24716. +                return -EIO;
  24717. +            kill_pg(current->pgrp, SIGTTIN, 1);
  24718. +            return -ERESTARTSYS;
  24719. +        }
  24720. +    }
  24721. +
  24722. +    if (L_ICANON(tty)) {
  24723. +        minimum = time = 0;
  24724. +        current->timeout = (unsigned long) -1;
  24725. +    } else {
  24726. +        time = (HZ / 10) * TIME_CHAR(tty);
  24727. +        minimum = MIN_CHAR(tty);
  24728. +        if (minimum) {
  24729. +              current->timeout = (unsigned long) -1;
  24730. +            if (time)
  24731. +                tty->minimum_to_wake = 1;
  24732. +            else if (!waitqueue_active(&tty->read_wait) ||
  24733. +                 (tty->minimum_to_wake > minimum))
  24734. +                tty->minimum_to_wake = minimum;
  24735. +        } else {
  24736. +            if (time) {
  24737. +                current->timeout = time + jiffies;
  24738. +                time = 0;
  24739. +            } else
  24740. +                current->timeout = 0;
  24741. +            tty->minimum_to_wake = minimum = 1;
  24742. +        }
  24743. +    }
  24744. +
  24745. +    add_wait_queue(&tty->read_wait, &wait);
  24746. +    while (1) {
  24747. +        /* First test for status change. */
  24748. +        if (tty->packet && tty->link->ctrl_status) {
  24749. +            if (b != buf)
  24750. +                break;
  24751. +            put_user(tty->link->ctrl_status, b++);
  24752. +            tty->link->ctrl_status = 0;
  24753. +            break;
  24754. +        }
  24755. +        /* This statement must be first before checking for input
  24756. +           so that any interrupt will set the state back to
  24757. +           TASK_RUNNING. */
  24758. +        current->state = TASK_INTERRUPTIBLE;
  24759. +        
  24760. +        if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
  24761. +            ((minimum - (b - buf)) >= 1))
  24762. +            tty->minimum_to_wake = (minimum - (b - buf));
  24763. +        
  24764. +        if (!input_available_p(tty, 0)) {
  24765. +            if (tty->flags & (1 << TTY_OTHER_CLOSED)) {
  24766. +                retval = -EIO;
  24767. +                break;
  24768. +            }
  24769. +            if (tty_hung_up_p(file))
  24770. +                break;
  24771. +            if (!current->timeout)
  24772. +                break;
  24773. +            if (file->f_flags & O_NONBLOCK) {
  24774. +                retval = -EAGAIN;
  24775. +                break;
  24776. +            }
  24777. +            if (current->signal & ~current->blocked) {
  24778. +                retval = -ERESTARTSYS;
  24779. +                break;
  24780. +            }
  24781. +            schedule();
  24782. +            continue;
  24783. +        }
  24784. +        current->state = TASK_RUNNING;
  24785. +
  24786. +        /* Deal with packet mode. */
  24787. +        if (tty->packet && b == buf) {
  24788. +            put_user(TIOCPKT_DATA, b++);
  24789. +            nr--;
  24790. +        }
  24791. +
  24792. +        if (L_ICANON(tty)) {
  24793. +            while (1) {
  24794. +                int eol;
  24795. +
  24796. +                disable_bh(TQUEUE_BH);
  24797. +                if (!tty->read_cnt) {
  24798. +                    enable_bh(TQUEUE_BH);
  24799. +                    break;
  24800. +                }
  24801. +                eol = clear_bit(tty->read_tail,
  24802. +                        &tty->read_flags);
  24803. +                c = tty->read_buf[tty->read_tail];
  24804. +                tty->read_tail = ((tty->read_tail+1) &
  24805. +                          (N_TTY_BUF_SIZE-1));
  24806. +                tty->read_cnt--;
  24807. +                enable_bh(TQUEUE_BH);
  24808. +                if (!eol) {
  24809. +                    put_user(c, b++);
  24810. +                    if (--nr)
  24811. +                        continue;
  24812. +                    break;
  24813. +                }
  24814. +                if (--tty->canon_data < 0) {
  24815. +                    tty->canon_data = 0;
  24816. +                }
  24817. +                if (c != __DISABLED_CHAR) {
  24818. +                    put_user(c, b++);
  24819. +                    nr--;
  24820. +                }
  24821. +                break;
  24822. +            }
  24823. +        } else {
  24824. +            disable_bh(TQUEUE_BH);
  24825. +            copy_from_read_buf(tty, &b, &nr);
  24826. +            copy_from_read_buf(tty, &b, &nr);
  24827. +            enable_bh(TQUEUE_BH);
  24828. +        }
  24829. +
  24830. +        /* If there is enough space in the read buffer now, let the
  24831. +           low-level driver know. */
  24832. +        if (tty->driver.unthrottle &&
  24833. +            (tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE)
  24834. +            && clear_bit(TTY_THROTTLED, &tty->flags))
  24835. +            tty->driver.unthrottle(tty);
  24836. +
  24837. +        if (b - buf >= minimum || !nr)
  24838. +            break;
  24839. +        if (time)
  24840. +            current->timeout = time + jiffies;
  24841. +    }
  24842. +    remove_wait_queue(&tty->read_wait, &wait);
  24843. +
  24844. +    if (!waitqueue_active(&tty->read_wait))
  24845. +        tty->minimum_to_wake = minimum;
  24846. +
  24847. +    current->state = TASK_RUNNING;
  24848. +    current->timeout = 0;
  24849. +    size = b - buf;
  24850. +    if (size && nr)
  24851. +            clear_bit(TTY_PUSH, &tty->flags);
  24852. +        if (!size && clear_bit(TTY_PUSH, &tty->flags))
  24853. +                goto do_it_again;
  24854. +    if (!size && !retval)
  24855. +            clear_bit(TTY_PUSH, &tty->flags);
  24856. +        return (size ? size : retval);
  24857. +}
  24858. +
  24859. +static int write_chan(struct tty_struct * tty, struct file * file,
  24860. +              const unsigned char * buf, unsigned int nr)
  24861. +{
  24862. +    struct wait_queue wait = { current, NULL };
  24863. +    int c;
  24864. +    const unsigned char *b = buf;
  24865. +    int retval = 0;
  24866. +
  24867. +    /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
  24868. +    if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) {
  24869. +        retval = tty_check_change(tty);
  24870. +        if (retval)
  24871. +            return retval;
  24872. +    }
  24873. +
  24874. +    add_wait_queue(&tty->write_wait, &wait);
  24875. +    while (1) {
  24876. +        current->state = TASK_INTERRUPTIBLE;
  24877. +        if (current->signal & ~current->blocked) {
  24878. +            retval = -ERESTARTSYS;
  24879. +            break;
  24880. +        }
  24881. +        if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
  24882. +            retval = -EIO;
  24883. +            break;
  24884. +        }
  24885. +        if (O_OPOST(tty)) {
  24886. +            while (nr > 0) {
  24887. +                c = get_user(b);
  24888. +                if (opost(c, tty) < 0)
  24889. +                    break;
  24890. +                b++; nr--;
  24891. +            }
  24892. +            if (tty->driver.flush_chars)
  24893. +                tty->driver.flush_chars(tty);
  24894. +        } else {
  24895. +            c = tty->driver.write(tty, 1, b, nr);
  24896. +            b += c;
  24897. +            nr -= c;
  24898. +        }
  24899. +        if (!nr)
  24900. +            break;
  24901. +        if (file->f_flags & O_NONBLOCK) {
  24902. +            retval = -EAGAIN;
  24903. +            break;
  24904. +        }
  24905. +        schedule();
  24906. +    }
  24907. +    current->state = TASK_RUNNING;
  24908. +    remove_wait_queue(&tty->write_wait, &wait);
  24909. +    return (b - buf) ? b - buf : retval;
  24910. +}
  24911. +
  24912. +static int normal_select(struct tty_struct * tty, struct inode * inode,
  24913. +             struct file * file, int sel_type, select_table *wait)
  24914. +{
  24915. +    switch (sel_type) {
  24916. +        case SEL_IN:
  24917. +            if (input_available_p(tty, TIME_CHAR(tty) ? 0 :
  24918. +                          MIN_CHAR(tty)))
  24919. +                return 1;
  24920. +            /* fall through */
  24921. +        case SEL_EX:
  24922. +            if (tty->packet && tty->link->ctrl_status)
  24923. +                return 1;
  24924. +            if (tty->flags & (1 << TTY_OTHER_CLOSED))
  24925. +                return 1;
  24926. +            if (tty_hung_up_p(file))
  24927. +                return 1;
  24928. +            if (!waitqueue_active(&tty->read_wait)) {
  24929. +                if (MIN_CHAR(tty) && !TIME_CHAR(tty))
  24930. +                    tty->minimum_to_wake = MIN_CHAR(tty);
  24931. +                else
  24932. +                    tty->minimum_to_wake = 1;
  24933. +            }
  24934. +            select_wait(&tty->read_wait, wait);
  24935. +            return 0;
  24936. +        case SEL_OUT:
  24937. +            if (tty->driver.chars_in_buffer(tty) < WAKEUP_CHARS)
  24938. +                return 1;
  24939. +            select_wait(&tty->write_wait, wait);
  24940. +            return 0;
  24941. +    }
  24942. +    return 0;
  24943. +}
  24944. +
  24945. +struct tty_ldisc tty_ldisc_N_TTY = {
  24946. +    TTY_LDISC_MAGIC,    /* magic */
  24947. +    0,            /* num */
  24948. +    0,            /* flags */
  24949. +    n_tty_open,        /* open */
  24950. +    n_tty_close,        /* close */
  24951. +    n_tty_flush_buffer,    /* flush_buffer */
  24952. +    n_tty_chars_in_buffer,    /* chars_in_buffer */
  24953. +    read_chan,        /* read */
  24954. +    write_chan,        /* write */
  24955. +    n_tty_ioctl,        /* ioctl */
  24956. +    n_tty_set_termios,    /* set_termios */
  24957. +    normal_select,        /* select */
  24958. +    n_tty_receive_buf,    /* receive_buf */
  24959. +    n_tty_receive_room,    /* receive_room */
  24960. +    0            /* write_wakeup */
  24961. +};
  24962. +
  24963. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/pty.c linux/arch/arm/drivers/char/pty.c
  24964. --- linux.orig/arch/arm/drivers/char/pty.c    Thu Jan  1 01:00:00 1970
  24965. +++ linux/arch/arm/drivers/char/pty.c    Sun Jul  7 12:50:23 1996
  24966. @@ -0,0 +1,324 @@
  24967. +/*
  24968. + *  linux/arch/arm/drivers/char/pty.c
  24969. + *
  24970. + *  Copyright (C) 1991, 1992  Linus Torvalds
  24971. + *
  24972. + *  Modifications for ARM processor Copyright (C) 1995, 1996 Russell King.
  24973. + */
  24974. +
  24975. +/*
  24976. + *    pty.c
  24977. + *
  24978. + * This module exports the following pty function:
  24979. + *
  24980. + *     int  pty_open(struct tty_struct * tty, struct file * filp);
  24981. + */
  24982. +
  24983. +#include <linux/errno.h>
  24984. +#include <linux/sched.h>
  24985. +#include <linux/interrupt.h>
  24986. +#include <linux/tty.h>
  24987. +#include <linux/tty_flip.h>
  24988. +#include <linux/fcntl.h>
  24989. +#include <linux/string.h>
  24990. +#include <linux/major.h>
  24991. +#include <linux/mm.h>
  24992. +#include <linux/malloc.h>
  24993. +
  24994. +#include <asm/segment.h>
  24995. +#include <asm/system.h>
  24996. +#include <asm/bitops.h>
  24997. +
  24998. +struct pty_struct {
  24999. +    int    magic;
  25000. +    struct wait_queue * open_wait;
  25001. +};
  25002. +
  25003. +#define PTY_MAGIC 0x5001
  25004. +
  25005. +#define PTY_BUF_SIZE 4096/2
  25006. +
  25007. +/*
  25008. + * tmp_buf is used as a temporary buffer by pty_write.  We need to
  25009. + * lock it in case the memcpy_fromfs blocks while swapping in a page,
  25010. + * and some other program tries to do a pty write at the same time.
  25011. + * Since the lock will only come under contention when the system is
  25012. + * swapping and available memory is low, it makes sense to share one
  25013. + * buffer across all the PTY's, since it significantly saves memory if
  25014. + * large numbers of PTY's are open.
  25015. + */
  25016. +static unsigned char *tmp_buf;
  25017. +static struct semaphore tmp_buf_sem = MUTEX;
  25018. +
  25019. +struct tty_driver pty_driver, pty_slave_driver;
  25020. +struct tty_driver old_pty_driver, old_pty_slave_driver;
  25021. +static int pty_refcount;
  25022. +
  25023. +static struct tty_struct *pty_table[NR_PTYS];
  25024. +static struct termios *pty_termios[NR_PTYS];
  25025. +static struct termios *pty_termios_locked[NR_PTYS];
  25026. +static struct tty_struct *ttyp_table[NR_PTYS];
  25027. +static struct termios *ttyp_termios[NR_PTYS];
  25028. +static struct termios *ttyp_termios_locked[NR_PTYS];
  25029. +static struct pty_struct pty_state[NR_PTYS];
  25030. +
  25031. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  25032. +
  25033. +static void pty_close(struct tty_struct * tty, struct file * filp)
  25034. +{
  25035. +    if (!tty)
  25036. +        return;
  25037. +    if (tty->driver.subtype == PTY_TYPE_MASTER) {
  25038. +        if (tty->count > 1)
  25039. +            printk("master pty_close: count = %d!!\n", tty->count);
  25040. +    } else {
  25041. +        if (tty->count > 2)
  25042. +            return;
  25043. +    }
  25044. +    wake_up_interruptible(&tty->read_wait);
  25045. +    wake_up_interruptible(&tty->write_wait);
  25046. +    if (!tty->link)
  25047. +        return;
  25048. +    wake_up_interruptible(&tty->link->read_wait);
  25049. +    wake_up_interruptible(&tty->link->write_wait);
  25050. +    set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
  25051. +    if (tty->driver.subtype == PTY_TYPE_MASTER) {
  25052. +        tty_hangup(tty->link);
  25053. +        set_bit(TTY_OTHER_CLOSED, &tty->flags);
  25054. +    }
  25055. +}
  25056. +
  25057. +/*
  25058. + * The unthrottle routine is called by the line discipline to signal
  25059. + * that it can receive more characters.  For PTY's, the TTY_THROTTLED
  25060. + * flag is always set, to force the line discipline to always call the
  25061. + * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
  25062. + * characters in the queue.  This is necessary since each time this
  25063. + * happens, we need to wake up any sleeping processes that could be
  25064. + * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
  25065. + * for the pty buffer to be drained.
  25066. + */
  25067. +static void pty_unthrottle(struct tty_struct * tty)
  25068. +{
  25069. +    struct tty_struct *o_tty = tty->link;
  25070. +
  25071. +    if (!o_tty)
  25072. +        return;
  25073. +
  25074. +    if ((o_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  25075. +        o_tty->ldisc.write_wakeup)
  25076. +        (o_tty->ldisc.write_wakeup)(o_tty);
  25077. +    wake_up_interruptible(&o_tty->write_wait);
  25078. +    set_bit(TTY_THROTTLED, &tty->flags);
  25079. +}
  25080. +
  25081. +static int pty_write(struct tty_struct * tty, int from_user,
  25082. +               const unsigned char *buf, int count)
  25083. +{
  25084. +    struct tty_struct *to = tty->link;
  25085. +    int    c=0, n, r;
  25086. +    char    *temp_buffer;
  25087. +
  25088. +    if (!to || tty->stopped)
  25089. +        return 0;
  25090. +
  25091. +    if (from_user) {
  25092. +        down(&tmp_buf_sem);
  25093. +        temp_buffer = tmp_buf +
  25094. +            ((tty->driver.subtype-1) * PTY_BUF_SIZE);
  25095. +        while (count > 0) {
  25096. +            n = MIN(count, PTY_BUF_SIZE);
  25097. +            memcpy_fromfs(temp_buffer, buf, n);
  25098. +            r = to->ldisc.receive_room(to);
  25099. +            if (r <= 0)
  25100. +                break;
  25101. +            n = MIN(n, r);
  25102. +            to->ldisc.receive_buf(to, temp_buffer, 0, n);
  25103. +            buf += n;  c+= n;
  25104. +            count -= n;
  25105. +        }
  25106. +        up(&tmp_buf_sem);
  25107. +    } else {
  25108. +        c = MIN(count, to->ldisc.receive_room(to));
  25109. +        to->ldisc.receive_buf(to, buf, 0, c);
  25110. +    }
  25111. +
  25112. +    return c;
  25113. +}
  25114. +
  25115. +static int pty_write_room(struct tty_struct *tty)
  25116. +{
  25117. +    struct tty_struct *to = tty->link;
  25118. +
  25119. +    if (!to || tty->stopped)
  25120. +        return 0;
  25121. +
  25122. +    return to->ldisc.receive_room(to);
  25123. +}
  25124. +
  25125. +static int pty_chars_in_buffer(struct tty_struct *tty)
  25126. +{
  25127. +    struct tty_struct *to = tty->link;
  25128. +
  25129. +    if (!to || !to->ldisc.chars_in_buffer)
  25130. +        return 0;
  25131. +
  25132. +    return to->ldisc.chars_in_buffer(to);
  25133. +}
  25134. +
  25135. +static void pty_flush_buffer(struct tty_struct *tty)
  25136. +{
  25137. +    struct tty_struct *to = tty->link;
  25138. +
  25139. +    if (!to)
  25140. +        return;
  25141. +
  25142. +    if (to->ldisc.flush_buffer)
  25143. +        to->ldisc.flush_buffer(to);
  25144. +
  25145. +    if (to->packet) {
  25146. +        tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
  25147. +        wake_up_interruptible(&to->read_wait);
  25148. +    }
  25149. +}
  25150. +
  25151. +int pty_open(struct tty_struct *tty, struct file * filp)
  25152. +{
  25153. +#if PTY_SLAVE_WAITS_ON_OPEN
  25154. +    struct wait_queue wait = { current, NULL };
  25155. +#endif
  25156. +    int    retval;
  25157. +    int    line;
  25158. +    struct    pty_struct *pty;
  25159. +
  25160. +    if (!tty || !tty->link)
  25161. +        return -ENODEV;
  25162. +    line = MINOR(tty->device) - tty->driver.minor_start;
  25163. +    if ((line < 0) || (line >= NR_PTYS))
  25164. +        return -ENODEV;
  25165. +    pty = pty_state + line;
  25166. +    tty->driver_data = pty;
  25167. +
  25168. +    if (!tmp_buf) {
  25169. +        unsigned long page = (unsigned long) kmalloc(PTY_BUF_SIZE*2,GFP_KERNEL);
  25170. +        if (!tmp_buf) {
  25171. +            if (!page)
  25172. +                return -ENOMEM;
  25173. +            tmp_buf = (unsigned char *) page;
  25174. +        } else
  25175. +            kfree((void *)page);
  25176. +    }
  25177. +
  25178. +    clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
  25179. +    wake_up_interruptible(&pty->open_wait);
  25180. +    set_bit(TTY_THROTTLED, &tty->flags);
  25181. +    if (filp->f_flags & O_NDELAY)
  25182. +        return 0;
  25183. +    /*
  25184. +     * If we're opening the master pty, just return.  If we're
  25185. +     * trying to open the slave pty, then we have to wait for the
  25186. +     * master pty to open.
  25187. +     */
  25188. +    if (tty->driver.subtype == PTY_TYPE_MASTER)
  25189. +        return 0;
  25190. +    retval = 0;
  25191. +#if PTY_SLAVE_WAITS_ON_OPEN
  25192. +    add_wait_queue(&pty->open_wait, &wait);
  25193. +    while (1) {
  25194. +        if (current->signal & ~current->blocked) {
  25195. +            retval = -ERESTARTSYS;
  25196. +            break;
  25197. +        }
  25198. +        /*
  25199. +         * Block until the master is open...
  25200. +         */
  25201. +        current->state = TASK_INTERRUPTIBLE;
  25202. +        if (tty->link->count &&
  25203. +            !test_bit(TTY_OTHER_CLOSED, &tty->flags))
  25204. +            break;
  25205. +        schedule();
  25206. +    }
  25207. +    current->state = TASK_RUNNING;
  25208. +    remove_wait_queue(&pty->open_wait, &wait);
  25209. +#else
  25210. +    if (!tty->link->count || test_bit(TTY_OTHER_CLOSED, &tty->flags))
  25211. +        retval = -EPERM;
  25212. +#endif
  25213. +    return retval;
  25214. +}
  25215. +
  25216. +static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios)
  25217. +{
  25218. +    tty->termios->c_cflag &= ~(CSIZE | PARENB);
  25219. +    tty->termios->c_cflag |= (CS8 | CREAD);
  25220. +}
  25221. +
  25222. +int pty_init(void)
  25223. +{
  25224. +    memset(&pty_state, 0, sizeof(pty_state));
  25225. +    memset(&pty_driver, 0, sizeof(struct tty_driver));
  25226. +    pty_driver.magic = TTY_DRIVER_MAGIC;
  25227. +    pty_driver.name = "pty";
  25228. +    pty_driver.major = PTY_MASTER_MAJOR;
  25229. +    pty_driver.minor_start = 0;
  25230. +    pty_driver.num = NR_PTYS;
  25231. +    pty_driver.type = TTY_DRIVER_TYPE_PTY;
  25232. +    pty_driver.subtype = PTY_TYPE_MASTER;
  25233. +    pty_driver.init_termios = tty_std_termios;
  25234. +    pty_driver.init_termios.c_iflag = 0;
  25235. +    pty_driver.init_termios.c_oflag = 0;
  25236. +    pty_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
  25237. +    pty_driver.init_termios.c_lflag = 0;
  25238. +    pty_driver.flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
  25239. +    pty_driver.refcount = &pty_refcount;
  25240. +    pty_driver.table = pty_table;
  25241. +    pty_driver.termios = pty_termios;
  25242. +    pty_driver.termios_locked = pty_termios_locked;
  25243. +    pty_driver.other = &pty_slave_driver;
  25244. +
  25245. +    pty_driver.open = pty_open;
  25246. +    pty_driver.close = pty_close;
  25247. +    pty_driver.write = pty_write;
  25248. +    pty_driver.write_room = pty_write_room;
  25249. +    pty_driver.flush_buffer = pty_flush_buffer;
  25250. +    pty_driver.chars_in_buffer = pty_chars_in_buffer;
  25251. +    pty_driver.unthrottle = pty_unthrottle;
  25252. +    pty_driver.set_termios = pty_set_termios;
  25253. +
  25254. +    pty_slave_driver = pty_driver;
  25255. +    pty_slave_driver.name = "ttyp";
  25256. +    pty_slave_driver.subtype = PTY_TYPE_SLAVE;
  25257. +    pty_slave_driver.major = PTY_SLAVE_MAJOR;
  25258. +    pty_slave_driver.minor_start = 0;
  25259. +    pty_slave_driver.init_termios = tty_std_termios;
  25260. +    pty_slave_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
  25261. +    pty_slave_driver.table = ttyp_table;
  25262. +    pty_slave_driver.termios = ttyp_termios;
  25263. +    pty_slave_driver.termios_locked = ttyp_termios_locked;
  25264. +    pty_slave_driver.other = &pty_driver;
  25265. +
  25266. +    old_pty_driver = pty_driver;
  25267. +    old_pty_driver.major = TTY_MAJOR;
  25268. +    old_pty_driver.minor_start = 128;
  25269. +    old_pty_driver.num = (NR_PTYS > 64) ? 64 : NR_PTYS;
  25270. +    old_pty_driver.other = &old_pty_slave_driver;
  25271. +
  25272. +    old_pty_slave_driver = pty_slave_driver;
  25273. +    old_pty_slave_driver.major = TTY_MAJOR;
  25274. +    old_pty_slave_driver.minor_start = 192;
  25275. +    old_pty_slave_driver.num = (NR_PTYS > 64) ? 64 : NR_PTYS;
  25276. +    old_pty_slave_driver.other = &old_pty_driver;
  25277. +
  25278. +    tmp_buf = 0;
  25279. +
  25280. +    if (tty_register_driver(&pty_driver))
  25281. +        panic("Couldn't register pty driver");
  25282. +    if (tty_register_driver(&pty_slave_driver))
  25283. +        panic("Couldn't register pty slave driver");
  25284. +    if (tty_register_driver(&old_pty_driver))
  25285. +        panic("Couldn't register compat pty driver");
  25286. +    if (tty_register_driver(&old_pty_slave_driver))
  25287. +        panic("Couldn't register compat pty slave driver");
  25288. +
  25289. +    return 0;
  25290. +}
  25291. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/selection.c linux/arch/arm/drivers/char/selection.c
  25292. --- linux.orig/arch/arm/drivers/char/selection.c    Thu Jan  1 01:00:00 1970
  25293. +++ linux/arch/arm/drivers/char/selection.c    Sun Jun 23 11:38:41 1996
  25294. @@ -0,0 +1,298 @@
  25295. +/*
  25296. + * linux/arch/arm/drivers/char/console/selection.c
  25297. + *
  25298. + * This module exports the functions:
  25299. + *
  25300. + *  'int set_selection (const unsigned long arg)'
  25301. + *  'void clear_selection (void)'
  25302. + *  'int paste_selection (struct tty_struct *tty)'
  25303. + *  'int sel_loadlut (const unsigned long arg)'
  25304. + *
  25305. + * Now that /dev/vcs exists, most of this can disappear again.
  25306. + */
  25307. +
  25308. +#include <linux/tty.h>
  25309. +#include <linux/sched.h>
  25310. +#include <linux/mm.h>
  25311. +#include <linux/malloc.h>
  25312. +#include <linux/types.h>
  25313. +
  25314. +#include <asm/segment.h>
  25315. +
  25316. +#include "vt_kern.h"
  25317. +#include "consolemap.h"
  25318. +#include "selection.h"
  25319. +
  25320. +#ifndef MIN
  25321. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  25322. +#endif
  25323. +
  25324. +/* Don't take this from <ctype.h>: 011-015 in the buffer aren't spaces */
  25325. +#define isspace(c)    ((c) == ' ')
  25326. +
  25327. +#define sel_pos(n)    inverse_translate(scrw2glyph(screen_word(vtdata.select.vt, n)))
  25328. +
  25329. +/*
  25330. + * clear_selection, highlight and highlight_pointer can be called
  25331. + * from interrupt (via scrollback/front)
  25332. + */
  25333. +
  25334. +/*
  25335. + * set reverse video on characters s-e of console with selection.
  25336. + */
  25337. +static inline void highlight (const int s, const int e)
  25338. +{
  25339. +    invert_screen (vtdata.select.vt, s, e - s);
  25340. +}
  25341. +
  25342. +/*
  25343. + * use complementary color to show the pointer
  25344. + */
  25345. +static inline void highlight_pointer (const int where)
  25346. +{
  25347. +    complement_pos (vtdata.select.vt, where);
  25348. +}
  25349. +
  25350. +/*
  25351. + * Remove the current selection highlight, if any,
  25352. + * from the console holding selection.
  25353. + */
  25354. +void clear_selection (void)
  25355. +{
  25356. +    highlight_pointer (-1); /* hide the pointer */
  25357. +    if (vtdata.select.start != -1) {
  25358. +    highlight (vtdata.select.start, vtdata.select.end);
  25359. +    vtdata.select.start = -1;
  25360. +    }
  25361. +}
  25362. +
  25363. +/*
  25364. + * User settable table: what characters are to be considered alphabetic?
  25365. + * 256 bits
  25366. + */
  25367. +static u32 inwordLut[8]={
  25368. +  0x00000000, /* control chars     */
  25369. +  0x03FF0000, /* digits            */
  25370. +  0x87FFFFFE, /* uppercase and '_' */
  25371. +  0x07FFFFFE, /* lowercase         */
  25372. +  0x00000000,
  25373. +  0x00000000,
  25374. +  0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
  25375. +  0xFF7FFFFF  /* latin-1 accented letters, not division sign */
  25376. +};
  25377. +
  25378. +static inline int inword (const unsigned char c)
  25379. +{
  25380. +    return (inwordLut[c>>5] >> (c & 31)) & 1;
  25381. +}
  25382. +
  25383. +/*
  25384. + * set inwordLut contents.  Invoked by ioctl().
  25385. + */
  25386. +int sel_loadlut (const unsigned long arg)
  25387. +{
  25388. +    int i = verify_area (VERIFY_READ, (char *) arg, 36);
  25389. +    if (i)
  25390. +    return i;
  25391. +    memcpy_fromfs (inwordLut, (u32 *)(arg + 4), 32);
  25392. +    return 0;
  25393. +}
  25394. +
  25395. +/*
  25396. + * does buffer offset p correspond to character at LH/RH edge of screen?
  25397. + */
  25398. +static inline int atedge (const int p)
  25399. +{
  25400. +    return (!(p % vtdata.numcolumns) || !((p + 1) % vtdata.numcolumns));
  25401. +}
  25402. +
  25403. +/*
  25404. + * constrain v such that v <= u
  25405. + */
  25406. +static inline int limit (const int v, const int u)
  25407. +{
  25408. +    return ((v > u) ? u : v);
  25409. +}
  25410. +
  25411. +/*
  25412. + * set the current selection.  Invoked by ioctl().
  25413. + */
  25414. +int set_selection (const unsigned long arg, struct tty_struct *tty)
  25415. +{
  25416. +    struct vt * vt = vtdata.fgconsole;
  25417. +    int sel_mode, new_sel_start, new_sel_end, spc;
  25418. +    char *bp, *obp;
  25419. +    int i, ps, pe;
  25420. +
  25421. +    vt_do_unblankscreen ();
  25422. +
  25423. +    {
  25424. +    unsigned short *args, xs, ys, xe, ye;
  25425. +
  25426. +    args = (unsigned short *)(arg + 1);
  25427. +    xs = get_user (args ++) - 1;
  25428. +    ys = get_user (args ++) - 1;
  25429. +    xe = get_user (args ++) - 1;
  25430. +    ye = get_user (args ++) - 1;
  25431. +    sel_mode = get_user (args);
  25432. +
  25433. +    xs = limit (xs, vtdata.numcolumns - 1);
  25434. +    ys = limit (ys, vtdata.numrows - 1);
  25435. +    xe = limit (xe, vtdata.numcolumns - 1);
  25436. +    ye = limit (ye, vtdata.numrows - 1);
  25437. +    ps = ys * vtdata.numcolumns + xs;
  25438. +    pe = ye * vtdata.numcolumns + xe;
  25439. +
  25440. +    if (sel_mode == 4) {
  25441. +        /* useful for screendump without selection highlights */
  25442. +        clear_selection ();
  25443. +        return 0;
  25444. +    }
  25445. +
  25446. +    if (vt->vcd->report_mouse && sel_mode & 16) {
  25447. +        mouse_report (tty, sel_mode & 15, xs, ys);
  25448. +        return 0;
  25449. +    }
  25450. +    }
  25451. +
  25452. +    if (ps > pe) { /* make sel_start <= sel_end */
  25453. +    ps ^= pe;
  25454. +    pe ^= ps;
  25455. +    ps ^= pe;
  25456. +    }
  25457. +
  25458. +    if (vt != vtdata.select.vt) {
  25459. +    clear_selection ();
  25460. +    vtdata.select.vt = vt;
  25461. +    }
  25462. +
  25463. +    switch (sel_mode) {
  25464. +    case 0: /* character-by-character selection */
  25465. +    new_sel_start = ps;
  25466. +    new_sel_end = pe;
  25467. +    break;
  25468. +    case 1: /* word-by-word selection */
  25469. +    spc = isspace (sel_pos (ps));
  25470. +    for (new_sel_start = ps; ; ps --) {
  25471. +        if (( spc && !isspace (sel_pos (ps))) ||
  25472. +            (!spc && !inword (sel_pos (ps))))
  25473. +        break;
  25474. +        new_sel_start = ps;
  25475. +        if (!(ps % vtdata.numcolumns))
  25476. +        break;
  25477. +    }
  25478. +    spc = isspace (sel_pos (pe));
  25479. +    for (new_sel_end = pe; ; pe ++) {
  25480. +        if (( spc && !isspace (sel_pos (pe))) ||
  25481. +            (!spc && !inword (sel_pos (pe))))
  25482. +        break;
  25483. +        new_sel_end = pe;
  25484. +        if (!((pe + 1) % vtdata.numcolumns))
  25485. +        break;
  25486. +    }
  25487. +    break;
  25488. +    case 2: /* line-by-line selection */
  25489. +    new_sel_start = ps - ps % vtdata.numcolumns;
  25490. +    new_sel_end = pe + vtdata.numcolumns - pe % vtdata.numcolumns - 1;
  25491. +    break;
  25492. +    case 3:
  25493. +    highlight_pointer (pe);
  25494. +    return 0;
  25495. +    default:
  25496. +    return -EINVAL;
  25497. +    }
  25498. +
  25499. +    /* remove the pointer */
  25500. +    highlight_pointer (-1);
  25501. +
  25502. +    /* select to end of line if on trailing space */
  25503. +    if (new_sel_end > new_sel_start && !atedge(new_sel_end) && isspace(sel_pos(new_sel_end))) {
  25504. +    for (pe = new_sel_end + 1; ; pe ++)
  25505. +        if (!isspace (sel_pos (pe)) || atedge (pe))
  25506. +        break;
  25507. +    if (isspace (sel_pos (pe)))
  25508. +        new_sel_end = pe;
  25509. +    }
  25510. +    if (vtdata.select.start == -1)            /* no current selection */
  25511. +    highlight (new_sel_start, new_sel_end);
  25512. +    else if (new_sel_start == vtdata.select.start) {
  25513. +    if (new_sel_end == vtdata.select.end)        /* no action required */
  25514. +        return 0;
  25515. +    else if (new_sel_end > vtdata.select.end)    /* extend to right */
  25516. +        highlight (vtdata.select.end + 1, new_sel_end);
  25517. +    else                        /* contract from right */
  25518. +        highlight (new_sel_end + 1, vtdata.select.end);
  25519. +    } else if (new_sel_end == vtdata.select.end) {
  25520. +    if (new_sel_start < vtdata.select.start)    /* extend to left */
  25521. +        highlight (new_sel_start, vtdata.select.start - 1);
  25522. +    else                /* contract from left */
  25523. +        highlight (vtdata.select.start, new_sel_start - 1);
  25524. +    } else {    /* some other case; start selection from scratch */
  25525. +    clear_selection ();
  25526. +    highlight (new_sel_start, new_sel_end);
  25527. +    }
  25528. +    vtdata.select.start = new_sel_start;
  25529. +    vtdata.select.end = new_sel_end;
  25530. +
  25531. +    if (vtdata.select.buffer)
  25532. +    kfree (vtdata.select.buffer);
  25533. +    vtdata.select.buffer = kmalloc (vtdata.select.end - vtdata.select.start + 1, GFP_KERNEL);
  25534. +    if (!vtdata.select.buffer) {
  25535. +    printk ("selection: kmalloc() failed\n");
  25536. +    clear_selection ();
  25537. +    return -ENOMEM;
  25538. +    }
  25539. +
  25540. +    obp = bp = vtdata.select.buffer;
  25541. +    for (i = vtdata.select.start; i <= vtdata.select.end; i++) {
  25542. +    *bp = sel_pos (i);
  25543. +    if (!isspace (*bp++))
  25544. +        obp = bp;
  25545. +    if (!((i + 1) % vtdata.numcolumns)) {
  25546. +        /* strip trailing blanks from line and add newline,
  25547. +         * unless non-space at end of line.
  25548. +         */
  25549. +        if (obp != bp) {
  25550. +        bp = obp;
  25551. +        *bp++ = '\r';
  25552. +        }
  25553. +        obp = bp;
  25554. +    }
  25555. +    }
  25556. +    vtdata.select.length = bp - vtdata.select.buffer;
  25557. +    return 0;
  25558. +}
  25559. +
  25560. +/* Insert the contents of the selection buffer into the queue of the
  25561. + * tty associated with the current console. Invoked by ioctl().
  25562. + */
  25563. +int paste_selection (struct tty_struct *tty)
  25564. +{
  25565. +    struct wait_queue wait = { current, NULL };
  25566. +    struct vt_struct *vt = ((struct vt *)tty->driver_data)->vtd;
  25567. +    char *bp = vtdata.select.buffer;
  25568. +    int c = vtdata.select.length;
  25569. +    int l;
  25570. +
  25571. +    if (!bp || !c)
  25572. +    return 0;
  25573. +
  25574. +    vt_do_unblankscreen ();
  25575. +
  25576. +    current->state = TASK_INTERRUPTIBLE;
  25577. +    add_wait_queue (&vt->paste_wait, &wait);
  25578. +
  25579. +    while (c) {
  25580. +    if (test_bit(TTY_THROTTLED, &tty->flags)) {
  25581. +        schedule();
  25582. +        continue;
  25583. +    }
  25584. +    l = MIN(c, tty->ldisc.receive_room(tty));
  25585. +    tty->ldisc.receive_buf(tty, bp, 0, l);
  25586. +    c -= l;
  25587. +    bp += l;
  25588. +    }
  25589. +    current->state = TASK_RUNNING;
  25590. +    return 0;
  25591. +}
  25592. +
  25593. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/selection.h linux/arch/arm/drivers/char/selection.h
  25594. --- linux.orig/arch/arm/drivers/char/selection.h    Thu Jan  1 01:00:00 1970
  25595. +++ linux/arch/arm/drivers/char/selection.h    Fri May 10 21:09:16 1996
  25596. @@ -0,0 +1,22 @@
  25597. +/*
  25598. + * selection.h
  25599. + *
  25600. + * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c
  25601. + */
  25602. +
  25603. +extern void clear_selection (void);
  25604. +extern int set_selection (const unsigned long arg, struct tty_struct *tty);
  25605. +extern int paste_selection (struct tty_struct *tty);
  25606. +extern int sel_loadlut (const unsigned long arg);
  25607. +extern int mouse_reporting (void);
  25608. +extern void mouse_report (struct tty_struct *tty, int butt, int mrx, int mry);
  25609. +
  25610. +extern void vt_do_unblankscreen (void);
  25611. +extern unsigned long *screen_pos (const struct vt *const vt, int offset);
  25612. +extern unsigned long screen_word (const struct vt *const vt, int offset);
  25613. +extern int scrw2glyph (unsigned long scr_word);
  25614. +extern void invert_screen (const struct vt *const vt, int offset, int count);
  25615. +
  25616. +extern void getconsxy (const struct vt *const vt, char *p);
  25617. +extern void putconsxy (const struct vt *const vt, char *p);
  25618. +extern void update_scrmem (const struct vt *const vt, int offset, int length);
  25619. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/serial-atomwide.c linux/arch/arm/drivers/char/serial-atomwide.c
  25620. --- linux.orig/arch/arm/drivers/char/serial-atomwide.c    Thu Jan  1 01:00:00 1970
  25621. +++ linux/arch/arm/drivers/char/serial-atomwide.c    Tue Jul 30 17:49:18 1996
  25622. @@ -0,0 +1,140 @@
  25623. +/*
  25624. + * linux/arch/arm/drivers/char/serial-atomwide.c
  25625. + *
  25626. + * Copyright (c) 1996 Russell King.
  25627. + *
  25628. + * Changelog:
  25629. + *  02-05-1996    RMK    Created
  25630. + *  07-05-1996    RMK    Altered for greater number of cards.
  25631. + *  30-07-1996    RMK    Now uses generic card code.
  25632. + */
  25633. +
  25634. +#if 0
  25635. +#include <linux/module.h>
  25636. +#include <linux/serial.h>
  25637. +#include <linux/errno.h>
  25638. +
  25639. +#include <asm/ecard.h>
  25640. +
  25641. +#define NUM_SERIALS    3 * MAX_ECARDS
  25642. +
  25643. +static const int serial_prods[] = { 0x0090 };
  25644. +static const int serial_manus[] = { 0x0017 };
  25645. +
  25646. +#ifndef MODULE
  25647. +
  25648. +int atomwide_serial_init (void)
  25649. +{
  25650. +    struct expansion_card *ec;
  25651. +    struct serial_struct req;
  25652. +    unsigned long port;
  25653. +    int prt, i;
  25654. +
  25655. +    req.baud_base = 7372800 / 16;
  25656. +
  25657. +    while (1) {
  25658. +
  25659. +    if ((ec = ecard_find (0, sizeof (serial_prods) / sizeof (int), serial_prods, serial_manus))
  25660. +        == NULL)
  25661. +        break;
  25662. +
  25663. +    port = ((unsigned long)ecard_address (ec->slot_no, ECARD_IOC, ECARD_SLOW) + 0x2000) >> 2;
  25664. +
  25665. +    for (prt = 0; prt < 3; prt ++) {
  25666. +        req.irq  = ec->irq;
  25667. +        req.port = port + 0x200 - prt * 0x100;
  25668. +
  25669. +        i = register_pre_init_serial (&req);
  25670. +        if (i < 0)
  25671. +        break;
  25672. +    }
  25673. +
  25674. +    if (prt)
  25675. +        ecard_claim (ec);
  25676. +
  25677. +    if (i < 0)
  25678. +        break;
  25679. +    }
  25680. +
  25681. +    return 0;
  25682. +}
  25683. +
  25684. +#else
  25685. +
  25686. +static int atomwide_serial_lines[NUM_SERIALS];
  25687. +static int atomwide_num_lines;
  25688. +static struct expansion_card *ec[MAX_ECARDS];
  25689. +
  25690. +static inline void atomwide_serial_register (int slot_no, int irq_no)
  25691. +{
  25692. +    struct serial_struct req;
  25693. +    unsigned long port;
  25694. +    int line, prt;
  25695. +    
  25696. +    port = ((unsigned long)ecard_address (slot_no, ECARD_IOC, ECARD_SLOW) + 0x2000) >> 2;
  25697. +
  25698. +    req.baud_base = 7372800 / 16;
  25699. +
  25700. +    for (prt = 0; prt < 3; prt ++) {
  25701. +    req.irq  = irq_no;
  25702. +    req.port = port + 0x200 - prt * 0x100;
  25703. +
  25704. +    line = register_serial (&req);
  25705. +    if (line >= 0)
  25706. +        atomwide_serial_lines[atomwide_num_lines++] = line;
  25707. +    }
  25708. +}
  25709. +
  25710. +int init_module (void)
  25711. +{
  25712. +    int i;
  25713. +
  25714. +    for (i = 0; i < NUM_SERIALS; i ++)
  25715. +    atomwide_serial_lines[i] = -1;
  25716. +
  25717. +    atomwide_num_lines = 0;
  25718. +
  25719. +    for (i = 0; i < MAX_ECARDS; i ++)
  25720. +    ec[i] = NULL;
  25721. +
  25722. +    i = 0;
  25723. +
  25724. +    do {
  25725. +    if ((ec[i] = ecard_find (0, sizeof (serial_prods) / sizeof (int), serial_prods, serial_manus))
  25726. +        == NULL)
  25727. +        break;
  25728. +
  25729. +    ecard_claim (ec[i]);
  25730. +    atomwide_serial_register (ec[i]->slot_no, ec[i]->irq);
  25731. +    i++;
  25732. +    } while (i < MAX_ECARDS);
  25733. +
  25734. +    return i ? 0 : -ENODEV;
  25735. +}
  25736. +
  25737. +void cleanup_module (void)
  25738. +{
  25739. +    int i;
  25740. +    for (i = 0; i < atomwide_num_lines; i++)
  25741. +    unregister_serial (atomwide_serial_lines[i]);
  25742. +
  25743. +    for (i = 0; i < MAX_ECARDS; i++)
  25744. +    if (ec[i]) {
  25745. +        ecard_release (ec[i]);
  25746. +        ec[i] = NULL;
  25747. +    }
  25748. +}
  25749. +#endif
  25750. +
  25751. +#else
  25752. +#define MY_PRODS 0x0090
  25753. +#define MY_MANUS 0x0017
  25754. +#define MY_NUMPORTS 3
  25755. +#define MY_BAUD_BASE (7372800 / 16)
  25756. +#define MY_INIT atomwide_serial_init
  25757. +#define MY_BASE_ADDRESS(ec) \
  25758. +    ((unsigned long)ecard_address ((ec)->slot_no, ECARD_IOC, ECARD_SLOW) + 0x2000) >> 2
  25759. +#define MY_PORT_ADDRESS(port,cardaddr) \
  25760. +    ((cardaddr) + 0x200 - (port) * 0x100)
  25761. +#include "serial-card.c"
  25762. +#endif
  25763. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/serial-card.c linux/arch/arm/drivers/char/serial-card.c
  25764. --- linux.orig/arch/arm/drivers/char/serial-card.c    Thu Jan  1 01:00:00 1970
  25765. +++ linux/arch/arm/drivers/char/serial-card.c    Tue Jul 30 17:05:14 1996
  25766. @@ -0,0 +1,108 @@
  25767. +/*
  25768. + * linux/arch/arm/drivers/char/serial-module.c
  25769. + *
  25770. + * Copyright (c) 1996 Russell King.
  25771. + *
  25772. + * A generic handler of serial expansion cards that use 16550s or
  25773. + * the like.
  25774. + *
  25775. + * Definitions:
  25776. + *  MY_PRODS        Product numbers to identify this card by
  25777. + *  MY_MANUS        Manufacturer numbers to identify this card by
  25778. + *  MY_NUMPORTS        Number of ports per card
  25779. + *  MY_BAUD_BASE    Baud base for the card
  25780. + *  MY_INIT        Initialisation routine name
  25781. + *  MY_BASE_ADDRESS(ec)    Return base address for ports
  25782. + *  MY_PORT_ADDRESS
  25783. + *    (port,cardaddr)    Return address for port using base address
  25784. + *            from above.
  25785. + *
  25786. + * Changelog:
  25787. + *  30-07-1996    RMK    Created
  25788. + */
  25789. +#include <linux/module.h>
  25790. +#include <linux/serial.h>
  25791. +#include <linux/errno.h>
  25792. +#include <asm/ecard.h>
  25793. +
  25794. +#ifndef NUM_SERIALS
  25795. +#define NUM_SERIALS    MY_NUMPORTS * MAX_ECARDS
  25796. +#endif
  25797. +
  25798. +#ifdef MODULE
  25799. +static int __serial_ports[NUM_SERIALS];
  25800. +static int __serial_pcount;
  25801. +static struct expansion_card *expcard[MAX_ECARDS];
  25802. +#define ADD_ECARD(ec,card) expcard[(card)] = (ec)
  25803. +#define ADD_PORT(port) __serial_ports[__serial_pcount++] = (port)
  25804. +#undef MY_INIT
  25805. +#define MY_INIT init_module
  25806. +#else
  25807. +#define ADD_ECARD(ec,card)
  25808. +#define ADD_PORT(port)
  25809. +#endif
  25810. +
  25811. +static const int serial_prods[] = { MY_PRODS };
  25812. +static const int serial_manus[] = { MY_MANUS };
  25813. +
  25814. +static inline int serial_register_onedev (int at_boot, unsigned long port, int irq)
  25815. +{
  25816. +    struct serial_struct req;
  25817. +    int line;
  25818. +
  25819. +    req.baud_base = MY_BAUD_BASE;
  25820. +    req.irq = irq;
  25821. +    req.port = port;
  25822. +
  25823. +    if (at_boot)
  25824. +    line = register_pre_init_serial (&req);
  25825. +    else
  25826. +    line = register_serial (&req);
  25827. +    return line;
  25828. +}
  25829. +
  25830. +int MY_INIT (void)
  25831. +{
  25832. +    int card = 0;
  25833. +    do {
  25834. +    struct expansion_card *ec;
  25835. +    unsigned long cardaddr;
  25836. +    int port;
  25837. +
  25838. +    ec = ecard_find (0, sizeof (serial_prods) / sizeof (int), serial_prods, serial_manus);
  25839. +    if (!ec)
  25840. +        break;
  25841. +
  25842. +    cardaddr = MY_BASE_ADDRESS(ec);
  25843. +
  25844. +    for (port = 0; port < MY_NUMPORTS; port ++) {
  25845. +        int line;
  25846. +
  25847. +        line = serial_register_onedev (1, MY_PORT_ADDRESS(port, cardaddr), ec->irq);
  25848. +        if (line < 0)
  25849. +        break;
  25850. +        ADD_PORT(line);
  25851. +    }
  25852. +
  25853. +    if (port) {
  25854. +        ecard_claim (ec);
  25855. +        ADD_ECARD(ec, card);
  25856. +    } else
  25857. +        break;
  25858. +    } while (++card < MAX_ECARDS);
  25859. +    return card ? 0 : -ENODEV;
  25860. +}
  25861. +
  25862. +#ifdef MODULE
  25863. +void cleanup_module (void)
  25864. +{
  25865. +    int i;
  25866. +
  25867. +    for (i = 0; i < __serial_pcount; i++)
  25868. +    unregister_serial (__serial_port[i]);
  25869. +
  25870. +    for (i = 0; i < MAX_ECARDS; i++)
  25871. +    if (expcard[i])
  25872. +        ecard_release (expcard[i]);
  25873. +}
  25874. +#endif
  25875. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/serial-dualsp.c linux/arch/arm/drivers/char/serial-dualsp.c
  25876. --- linux.orig/arch/arm/drivers/char/serial-dualsp.c    Thu Jan  1 01:00:00 1970
  25877. +++ linux/arch/arm/drivers/char/serial-dualsp.c    Tue Jul 30 17:04:37 1996
  25878. @@ -0,0 +1,19 @@
  25879. +/*
  25880. + * linux/arch/arm/drivers/char/serial-dualsp.c
  25881. + *
  25882. + * Copyright (c) 1996 Russell King.
  25883. + *
  25884. + * Changelog:
  25885. + *  30-07-1996    RMK    Created
  25886. + */
  25887. +#define MY_PRODS 0x00B9
  25888. +#define MY_MANUS 0x003F
  25889. +#define MY_NUMPORTS 2
  25890. +#define MY_BAUD_BASE (3686400 / 16)
  25891. +#define MY_INIT dualsp_serial_init
  25892. +#define MY_BASE_ADDRESS(ec) \
  25893. +    ((unsigned long)ecard_address (ec->slot_no, ECARD_IOC, ECARD_SLOW) + 0x2000) >> 2
  25894. +#define MY_PORT_ADDRESS(port,cardaddress) \
  25895. +    ((cardaddress) + (port) * 8)
  25896. +#include "serial-card.c"
  25897. +
  25898. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/serial.c linux/arch/arm/drivers/char/serial.c
  25899. --- linux.orig/arch/arm/drivers/char/serial.c    Thu Jan  1 01:00:00 1970
  25900. +++ linux/arch/arm/drivers/char/serial.c    Tue Jul 30 17:07:42 1996
  25901. @@ -0,0 +1,2955 @@
  25902. +/*
  25903. + *  linux/arch/arm/drivers/char/serial.c
  25904. + *
  25905. + *  Copyright (C) 1991, 1992  Linus Torvalds
  25906. + *
  25907. + *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
  25908. + *  much more extensible to support other serial cards based on the
  25909. + *  16450/16550A UART's.  Added support for the AST FourPort and the
  25910. + *  Accent Async board.  
  25911. + *
  25912. + *  set_serial_info fixed to set the flags, custom divisor, and uart
  25913. + *     type fields.  Fix suggested by Michael K. Johnson 12/12/92.
  25914. + *
  25915. + *  11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk>
  25916. + *
  25917. + *  03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk>
  25918. + *
  25919. + *  rs_set_termios fixed to look also for changes of the input
  25920. + *    flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
  25921. + *                        Bernd Anhäupl 05/17/96.
  25922. + *
  25923. + * This module exports the following rs232 io functions:
  25924. + *
  25925. + *    int rs_init(void);
  25926. + *     int rs_open(struct tty_struct * tty, struct file * filp)
  25927. + *
  25928. + *  Slight modifications for ARM Copyright (C) 1995, 1996 Russell King
  25929. + */
  25930. +
  25931. +#include <linux/module.h>
  25932. +#include <linux/errno.h>
  25933. +#include <linux/signal.h>
  25934. +#include <linux/sched.h>
  25935. +#include <linux/timer.h>
  25936. +#include <linux/interrupt.h>
  25937. +#include <linux/tty.h>
  25938. +#include <linux/tty_flip.h>
  25939. +#include <linux/serial.h>
  25940. +#include <linux/serial_reg.h>
  25941. +#include <linux/config.h>
  25942. +#include <linux/major.h>
  25943. +#include <linux/string.h>
  25944. +#include <linux/fcntl.h>
  25945. +#include <linux/ptrace.h>
  25946. +#include <linux/ioport.h>
  25947. +#include <linux/mm.h>
  25948. +
  25949. +#include <asm/system.h>
  25950. +#include <asm/io.h>
  25951. +#include <asm/segment.h>
  25952. +#include <asm/bitops.h>
  25953. +
  25954. +static char *serial_name = "Serial driver";
  25955. +static char *serial_version = "4.13";
  25956. +
  25957. +DECLARE_TASK_QUEUE(tq_serial);
  25958. +
  25959. +struct tty_driver serial_driver, callout_driver;
  25960. +static int serial_refcount;
  25961. +
  25962. +/* serial subtype definitions */
  25963. +#define SERIAL_TYPE_NORMAL    1
  25964. +#define SERIAL_TYPE_CALLOUT    2
  25965. +
  25966. +/* number of characters left in xmit buffer before we ask for more */
  25967. +#define WAKEUP_CHARS 256
  25968. +
  25969. +/*
  25970. + * Serial driver configuration section.  Here are the various options:
  25971. + *
  25972. + * CONFIG_HUB6
  25973. + *        Enables support for the venerable Bell Technologies
  25974. + *        HUB6 card.
  25975. + *
  25976. + * SERIAL_PARANOIA_CHECK
  25977. + *         Check the magic number for the async_structure where
  25978. + *         ever possible.
  25979. + */
  25980. +
  25981. +#define SERIAL_PARANOIA_CHECK
  25982. +#define CONFIG_SERIAL_NOPAUSE_IO
  25983. +#define SERIAL_DO_RESTART
  25984. +
  25985. +#undef SERIAL_DEBUG_INTR
  25986. +#undef SERIAL_DEBUG_OPEN
  25987. +#undef SERIAL_DEBUG_FLOW
  25988. +
  25989. +#define RS_STROBE_TIME (10*HZ)
  25990. +#define RS_ISR_PASS_LIMIT 256
  25991. +
  25992. +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
  25993. +
  25994. +#define _INLINE_ inline
  25995. +
  25996. +#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
  25997. +#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
  25998. + kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
  25999. +#else
  26000. +#define DBG_CNT(s)
  26001. +#endif
  26002. +  
  26003. +/*
  26004. + * IRQ_timeout        - How long the timeout should be for each IRQ
  26005. + *                 should be after the IRQ has been active.
  26006. + */
  26007. +
  26008. +static struct async_struct *IRQ_ports[32];
  26009. +static struct rs_multiport_struct rs_multiport[32];
  26010. +static int IRQ_timeout[32];
  26011. +static volatile int rs_irq_triggered;
  26012. +static volatile int rs_triggered;
  26013. +static int rs_wild_int_mask;
  26014. +
  26015. +static void autoconfig(struct async_struct * info);
  26016. +static void change_speed(struct async_struct *info);
  26017. +    
  26018. +/*
  26019. + * This assumes you have a 1.8432 MHz clock for your UART.
  26020. + *
  26021. + * It'd be nice if someone built a serial card with a 24.576 MHz
  26022. + * clock, since the 16550A is capable of handling a top speed of 1.5
  26023. + * megabits/second; but this requires the faster clock.
  26024. + */
  26025. +#define BASE_BAUD ( 1843200 / 16 )
  26026. +
  26027. +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST )
  26028. +
  26029. +struct async_struct rs_table[] = {
  26030. +     /* UART CLK        PORT  IRQ     FLAGS        */
  26031. +#ifndef CONFIG_ARCH_ARC
  26032. +    { 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS },    /* ttyS0 */
  26033. +    { 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS },    /* ttyS1 */
  26034. +#else
  26035. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS2 */
  26036. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS3 */
  26037. +#endif
  26038. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS2 */
  26039. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS3 */
  26040. +
  26041. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS4 */
  26042. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS5 */
  26043. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS6 */
  26044. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS7 */
  26045. +
  26046. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS8 */
  26047. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS9 */
  26048. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS10 */
  26049. +    { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },    /* ttyS11 */
  26050. +    
  26051. +};
  26052. +
  26053. +#define NR_PORTS    (sizeof(rs_table)/sizeof(struct async_struct))
  26054. +
  26055. +static struct tty_struct *serial_table[NR_PORTS];
  26056. +static struct termios *serial_termios[NR_PORTS];
  26057. +static struct termios *serial_termios_locked[NR_PORTS];
  26058. +
  26059. +#ifndef MIN
  26060. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  26061. +#endif
  26062. +
  26063. +/*
  26064. + * tmp_buf is used as a temporary buffer by serial_write.  We need to
  26065. + * lock it in case the memcpy_fromfs blocks while swapping in a page,
  26066. + * and some other program tries to do a serial write at the same time.
  26067. + * Since the lock will only come under contention when the system is
  26068. + * swapping and available memory is low, it makes sense to share one
  26069. + * buffer across all the serial ports, since it significantly saves
  26070. + * memory if large numbers of serial ports are open.
  26071. + */
  26072. +static unsigned char *tmp_buf;
  26073. +static struct semaphore tmp_buf_sem = MUTEX;
  26074. +
  26075. +static inline int serial_paranoia_check(struct async_struct *info,
  26076. +                    kdev_t device, const char *routine)
  26077. +{
  26078. +#ifdef SERIAL_PARANOIA_CHECK
  26079. +    static const char *badmagic =
  26080. +        "Warning: bad magic number for serial struct (%s) in %s\n";
  26081. +    static const char *badinfo =
  26082. +        "Warning: null async_struct for (%s) in %s\n";
  26083. +
  26084. +    if (!info) {
  26085. +        printk(badinfo, kdevname(device), routine);
  26086. +        return 1;
  26087. +    }
  26088. +    if (info->magic != SERIAL_MAGIC) {
  26089. +        printk(badmagic, kdevname(device), routine);
  26090. +        return 1;
  26091. +    }
  26092. +#endif
  26093. +    return 0;
  26094. +}
  26095. +
  26096. +/*
  26097. + * This is used to figure out the divisor speeds and the timeouts
  26098. + */
  26099. +static int baud_table[] = {
  26100. +    0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
  26101. +    9600, 19200, 38400, 57600, 115200, 0 };
  26102. +
  26103. +static inline unsigned int serial_in(struct async_struct *info, int offset)
  26104. +{
  26105. +#ifdef CONFIG_HUB6
  26106. +    if (info->hub6) {
  26107. +    outb(info->hub6 - 1 + offset, info->port);
  26108. +    return inb(info->port+1);
  26109. +    } else
  26110. +#endif
  26111. +    return inb(info->port + offset);
  26112. +}
  26113. +
  26114. +static inline unsigned int serial_inp(struct async_struct *info, int offset)
  26115. +{
  26116. +#ifdef CONFIG_HUB6
  26117. +    if (info->hub6) {
  26118. +    outb(info->hub6 - 1 + offset, info->port);
  26119. +    return inb_p(info->port+1);
  26120. +    } else
  26121. +#endif
  26122. +#ifdef CONFIG_SERIAL_NOPAUSE_IO
  26123. +    return inb(info->port + offset);
  26124. +#else
  26125. +    return inb_p(info->port + offset);
  26126. +#endif
  26127. +}
  26128. +
  26129. +static inline void serial_out(struct async_struct *info, int offset, int value)
  26130. +{
  26131. +#ifdef CONFIG_HUB6
  26132. +    if (info->hub6) {
  26133. +    outb(info->hub6 - 1 + offset, info->port);
  26134. +    outb(value, info->port+1);
  26135. +    } else
  26136. +#endif
  26137. +    outb(value, info->port+offset);
  26138. +}
  26139. +
  26140. +static inline void serial_outp(struct async_struct *info, int offset,
  26141. +                   int value)
  26142. +{
  26143. +#ifdef CONFIG_HUB6
  26144. +    if (info->hub6) {
  26145. +    outb(info->hub6 - 1 + offset, info->port);
  26146. +    outb_p(value, info->port+1);
  26147. +    } else
  26148. +#endif
  26149. +#ifdef CONFIG_SERIAL_NOPAUSE_IO
  26150. +    outb(value, info->port+offset);
  26151. +#else
  26152. +        outb_p(value, info->port+offset);
  26153. +#endif
  26154. +}
  26155. +
  26156. +/*
  26157. + * ------------------------------------------------------------
  26158. + * rs_stop() and rs_start()
  26159. + *
  26160. + * This routines are called before setting or resetting tty->stopped.
  26161. + * They enable or disable transmitter interrupts, as necessary.
  26162. + * ------------------------------------------------------------
  26163. + */
  26164. +static void rs_stop(struct tty_struct *tty)
  26165. +{
  26166. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  26167. +    unsigned long flags;
  26168. +
  26169. +    if (serial_paranoia_check(info, tty->device, "rs_stop"))
  26170. +        return;
  26171. +    
  26172. +    save_flags_cli (flags);
  26173. +    if (info->IER & UART_IER_THRI) {
  26174. +        info->IER &= ~UART_IER_THRI;
  26175. +        serial_out(info, UART_IER, info->IER);
  26176. +    }
  26177. +    restore_flags(flags);
  26178. +}
  26179. +
  26180. +static void rs_start(struct tty_struct *tty)
  26181. +{
  26182. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  26183. +    unsigned long flags;
  26184. +    
  26185. +    if (serial_paranoia_check(info, tty->device, "rs_start"))
  26186. +        return;
  26187. +    
  26188. +    save_flags_cli (flags);
  26189. +    if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
  26190. +        info->IER |= UART_IER_THRI;
  26191. +        serial_out(info, UART_IER, info->IER);
  26192. +    }
  26193. +    restore_flags(flags);
  26194. +}
  26195. +
  26196. +/*
  26197. + * ----------------------------------------------------------------------
  26198. + *
  26199. + * Here starts the interrupt handling routines.  All of the following
  26200. + * subroutines are declared as inline and are folded into
  26201. + * rs_interrupt().  They were separated out for readability's sake.
  26202. + *
  26203. + * Note: rs_interrupt() is a "fast" interrupt, which means that it
  26204. + * runs with interrupts turned off.  People who may want to modify
  26205. + * rs_interrupt() should try to keep the interrupt handler as fast as
  26206. + * possible.  After you are done making modifications, it is not a bad
  26207. + * idea to do:
  26208. + * 
  26209. + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
  26210. + *
  26211. + * and look at the resulting assemble code in serial.s.
  26212. + *
  26213. + *                 - Ted Ts'o (tytso@mit.edu), 7-Mar-93
  26214. + * -----------------------------------------------------------------------
  26215. + */
  26216. +
  26217. +/*
  26218. + * This is the serial driver's interrupt routine while we are probing
  26219. + * for submarines.
  26220. + */
  26221. +static void rs_probe(int irq, void *dev_id, struct pt_regs * regs)
  26222. +{
  26223. +    rs_irq_triggered = irq;
  26224. +    rs_triggered |= 1 << irq;
  26225. +    return;
  26226. +}
  26227. +
  26228. +/*
  26229. + * This routine is used by the interrupt handler to schedule
  26230. + * processing in the software interrupt portion of the driver.
  26231. + */
  26232. +static _INLINE_ void rs_sched_event(struct async_struct *info,
  26233. +                  int event)
  26234. +{
  26235. +    info->event |= 1 << event;
  26236. +    queue_task_irq_off(&info->tqueue, &tq_serial);
  26237. +    mark_bh(SERIAL_BH);
  26238. +}
  26239. +
  26240. +static _INLINE_ void receive_chars(struct async_struct *info,
  26241. +                 int *status)
  26242. +{
  26243. +    struct tty_struct *tty = info->tty;
  26244. +    unsigned char ch;
  26245. +    int ignored = 0;
  26246. +
  26247. +    do {
  26248. +        ch = serial_inp(info, UART_RX);
  26249. +        if (*status & info->ignore_status_mask) {
  26250. +            if (++ignored > 100)
  26251. +                break;
  26252. +            goto ignore_char;
  26253. +        }
  26254. +        if (tty->flip.count >= TTY_FLIPBUF_SIZE)
  26255. +            break;
  26256. +        tty->flip.count++;
  26257. +        if (*status & (UART_LSR_BI)) {
  26258. +#ifdef SERIAL_DEBUG_INTR
  26259. +            printk("handling break....");
  26260. +#endif
  26261. +            *tty->flip.flag_buf_ptr++ = TTY_BREAK;
  26262. +            if (info->flags & ASYNC_SAK)
  26263. +                do_SAK(tty);
  26264. +        } else if (*status & UART_LSR_PE)
  26265. +            *tty->flip.flag_buf_ptr++ = TTY_PARITY;
  26266. +        else if (*status & UART_LSR_FE)
  26267. +            *tty->flip.flag_buf_ptr++ = TTY_FRAME;
  26268. +        else if (*status & UART_LSR_OE) 
  26269. +            *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
  26270. +        else
  26271. +            *tty->flip.flag_buf_ptr++ = 0;
  26272. +        *tty->flip.char_buf_ptr++ = ch;
  26273. +    ignore_char:
  26274. +        *status = serial_inp(info, UART_LSR) & info->read_status_mask;
  26275. +    } while (*status & UART_LSR_DR);
  26276. +    queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
  26277. +#ifdef SERIAL_DEBUG_INTR
  26278. +    printk("DR...");
  26279. +#endif
  26280. +}
  26281. +
  26282. +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
  26283. +{
  26284. +    int count;
  26285. +    
  26286. +    if (info->x_char) {
  26287. +        serial_outp(info, UART_TX, info->x_char);
  26288. +        info->x_char = 0;
  26289. +        if (intr_done)
  26290. +            *intr_done = 0;
  26291. +        return;
  26292. +    }
  26293. +    if ((info->xmit_cnt <= 0) || info->tty->stopped ||
  26294. +        info->tty->hw_stopped) {
  26295. +        info->IER &= ~UART_IER_THRI;
  26296. +        serial_out(info, UART_IER, info->IER);
  26297. +        return;
  26298. +    }
  26299. +    
  26300. +    count = info->xmit_fifo_size;
  26301. +    do {
  26302. +        serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
  26303. +        info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
  26304. +        if (--info->xmit_cnt <= 0)
  26305. +            break;
  26306. +    } while (--count > 0);
  26307. +    
  26308. +    if (info->xmit_cnt < WAKEUP_CHARS)
  26309. +        rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
  26310. +
  26311. +#ifdef SERIAL_DEBUG_INTR
  26312. +    printk("THRE...");
  26313. +#endif
  26314. +    if (intr_done)
  26315. +        *intr_done = 0;
  26316. +
  26317. +    if (info->xmit_cnt <= 0) {
  26318. +        info->IER &= ~UART_IER_THRI;
  26319. +        serial_out(info, UART_IER, info->IER);
  26320. +    }
  26321. +}
  26322. +
  26323. +static _INLINE_ void check_modem_status(struct async_struct *info)
  26324. +{
  26325. +    int    status;
  26326. +    
  26327. +    status = serial_in(info, UART_MSR);
  26328. +
  26329. +    if (status & UART_MSR_ANY_DELTA) {
  26330. +        /* update input line counters */
  26331. +        if (status & UART_MSR_TERI)
  26332. +            info->icount.rng++;
  26333. +        if (status & UART_MSR_DDSR)
  26334. +            info->icount.dsr++;
  26335. +        if (status & UART_MSR_DDCD)
  26336. +            info->icount.dcd++;
  26337. +        if (status & UART_MSR_DCTS)
  26338. +            info->icount.cts++;
  26339. +        wake_up_interruptible(&info->delta_msr_wait);
  26340. +    }
  26341. +
  26342. +    if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
  26343. +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
  26344. +        printk("ttys%d CD now %s...", info->line,
  26345. +               (status & UART_MSR_DCD) ? "on" : "off");
  26346. +#endif        
  26347. +        if (status & UART_MSR_DCD)
  26348. +            wake_up_interruptible(&info->open_wait);
  26349. +        else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  26350. +               (info->flags & ASYNC_CALLOUT_NOHUP))) {
  26351. +#ifdef SERIAL_DEBUG_OPEN
  26352. +            printk("scheduling hangup...");
  26353. +#endif
  26354. +            queue_task_irq_off(&info->tqueue_hangup,
  26355. +                       &tq_scheduler);
  26356. +        }
  26357. +    }
  26358. +    if (info->flags & ASYNC_CTS_FLOW) {
  26359. +        if (info->tty->hw_stopped) {
  26360. +            if (status & UART_MSR_CTS) {
  26361. +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
  26362. +                printk("CTS tx start...");
  26363. +#endif
  26364. +                info->tty->hw_stopped = 0;
  26365. +                info->IER |= UART_IER_THRI;
  26366. +                serial_out(info, UART_IER, info->IER);
  26367. +                rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
  26368. +                return;
  26369. +            }
  26370. +        } else {
  26371. +            if (!(status & UART_MSR_CTS)) {
  26372. +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
  26373. +                printk("CTS tx stop...");
  26374. +#endif
  26375. +                info->tty->hw_stopped = 1;
  26376. +                info->IER &= ~UART_IER_THRI;
  26377. +                serial_out(info, UART_IER, info->IER);
  26378. +            }
  26379. +        }
  26380. +    }
  26381. +}
  26382. +
  26383. +/*
  26384. + * This is the serial driver's generic interrupt routine
  26385. + */
  26386. +static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
  26387. +{
  26388. +    int status;
  26389. +    struct async_struct * info;
  26390. +    int pass_counter = 0;
  26391. +    struct async_struct *end_mark = 0;
  26392. +    int first_multi = 0;
  26393. +    struct rs_multiport_struct *multi;
  26394. +
  26395. +#ifdef SERIAL_DEBUG_INTR
  26396. +    printk("rs_interrupt(%d)...", irq);
  26397. +#endif
  26398. +    
  26399. +    info = IRQ_ports[irq];
  26400. +    if (!info)
  26401. +        return;
  26402. +    
  26403. +    multi = &rs_multiport[irq];
  26404. +    if (multi->port_monitor)
  26405. +        first_multi = inb(multi->port_monitor);
  26406. +
  26407. +    do {
  26408. +        if (!info->tty ||
  26409. +            (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
  26410. +            if (!end_mark)
  26411. +                end_mark = info;
  26412. +            goto next;
  26413. +        }
  26414. +        end_mark = 0;
  26415. +
  26416. +        info->last_active = jiffies;
  26417. +
  26418. +        status = serial_inp(info, UART_LSR) & info->read_status_mask;
  26419. +#ifdef SERIAL_DEBUG_INTR
  26420. +        printk("status = %x...", status);
  26421. +#endif
  26422. +        if (status & UART_LSR_DR)
  26423. +            receive_chars(info, &status);
  26424. +        check_modem_status(info);
  26425. +        if (status & UART_LSR_THRE)
  26426. +            transmit_chars(info, 0);
  26427. +
  26428. +    next:
  26429. +        info = info->next_port;
  26430. +        if (!info) {
  26431. +            info = IRQ_ports[irq];
  26432. +            if (pass_counter++ > RS_ISR_PASS_LIMIT) {
  26433. +#if 0
  26434. +                printk("rs loop break\n");
  26435. +#endif
  26436. +                break;     /* Prevent infinite loops */
  26437. +            }
  26438. +            continue;
  26439. +        }
  26440. +    } while (end_mark != info);
  26441. +    if (multi->port_monitor)
  26442. +        printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
  26443. +               info->irq, first_multi, inb(multi->port_monitor));
  26444. +#ifdef SERIAL_DEBUG_INTR
  26445. +    printk("end.\n");
  26446. +#endif
  26447. +}
  26448. +
  26449. +/*
  26450. + * This is the serial driver's interrupt routine for a single port
  26451. + */
  26452. +static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
  26453. +{
  26454. +    int status;
  26455. +    int pass_counter = 0;
  26456. +    int first_multi = 0;
  26457. +    struct async_struct * info;
  26458. +    struct rs_multiport_struct *multi;
  26459. +    
  26460. +#ifdef SERIAL_DEBUG_INTR
  26461. +    printk("rs_interrupt_single(%d)...", irq);
  26462. +#endif
  26463. +    
  26464. +    info = IRQ_ports[irq];
  26465. +    if (!info || !info->tty)
  26466. +        return;
  26467. +
  26468. +    multi = &rs_multiport[irq];
  26469. +    if (multi->port_monitor)
  26470. +        first_multi = inb(multi->port_monitor);
  26471. +
  26472. +    do {
  26473. +        status = serial_inp(info, UART_LSR) & info->read_status_mask;
  26474. +#ifdef SERIAL_DEBUG_INTR
  26475. +        printk("status = %x...", status);
  26476. +#endif
  26477. +        if (status & UART_LSR_DR)
  26478. +            receive_chars(info, &status);
  26479. +        check_modem_status(info);
  26480. +        if (status & UART_LSR_THRE)
  26481. +            transmit_chars(info, 0);
  26482. +        if (pass_counter++ > RS_ISR_PASS_LIMIT) {
  26483. +#if 0
  26484. +            printk("rs_single loop break.\n");
  26485. +#endif
  26486. +            break;
  26487. +        }
  26488. +    } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
  26489. +    info->last_active = jiffies;
  26490. +    if (multi->port_monitor)
  26491. +        printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
  26492. +               info->irq, first_multi, inb(multi->port_monitor));
  26493. +#ifdef SERIAL_DEBUG_INTR
  26494. +    printk("end.\n");
  26495. +#endif
  26496. +}
  26497. +
  26498. +/*
  26499. + * This is the serial driver's for multiport boards
  26500. + */
  26501. +static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
  26502. +{
  26503. +    int status;
  26504. +    struct async_struct * info;
  26505. +    int pass_counter = 0;
  26506. +    int first_multi= 0;
  26507. +    struct rs_multiport_struct *multi;
  26508. +
  26509. +#ifdef SERIAL_DEBUG_INTR
  26510. +    printk("rs_interrupt_multi(%d)...", irq);
  26511. +#endif
  26512. +    
  26513. +    info = IRQ_ports[irq];
  26514. +    if (!info)
  26515. +        return;
  26516. +    multi = &rs_multiport[irq];
  26517. +    if (!multi->port1) {
  26518. +        /* Should never happen */
  26519. +        printk("rs_interrupt_multi: NULL port1!\n");
  26520. +        return;
  26521. +    }
  26522. +    if (multi->port_monitor)
  26523. +        first_multi = inb(multi->port_monitor);
  26524. +    
  26525. +    while (1) {
  26526. +        if (!info->tty ||
  26527. +            (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
  26528. +            goto next;
  26529. +
  26530. +        info->last_active = jiffies;
  26531. +
  26532. +        status = serial_inp(info, UART_LSR) & info->read_status_mask;
  26533. +#ifdef SERIAL_DEBUG_INTR
  26534. +        printk("status = %x...", status);
  26535. +#endif
  26536. +        if (status & UART_LSR_DR)
  26537. +            receive_chars(info, &status);
  26538. +        check_modem_status(info);
  26539. +        if (status & UART_LSR_THRE)
  26540. +            transmit_chars(info, 0);
  26541. +
  26542. +    next:
  26543. +        info = info->next_port;
  26544. +        if (info)
  26545. +            continue;
  26546. +
  26547. +        info = IRQ_ports[irq];
  26548. +        if (pass_counter++ > RS_ISR_PASS_LIMIT) {
  26549. +#if 1
  26550. +            printk("rs_multi loop break\n");
  26551. +#endif
  26552. +            break;     /* Prevent infinite loops */
  26553. +        }
  26554. +        if (multi->port_monitor)
  26555. +            printk("rs port monitor irq %d: 0x%x, 0x%x\n",
  26556. +                   info->irq, first_multi,
  26557. +                   inb(multi->port_monitor));
  26558. +        if ((inb(multi->port1) & multi->mask1) != multi->match1)
  26559. +            continue;
  26560. +        if (!multi->port2)
  26561. +            break;
  26562. +        if ((inb(multi->port2) & multi->mask2) != multi->match2)
  26563. +            continue;
  26564. +        if (!multi->port3)
  26565. +            break;
  26566. +        if ((inb(multi->port3) & multi->mask3) != multi->match3)
  26567. +            continue;
  26568. +        if (!multi->port4)
  26569. +            break;
  26570. +        if ((inb(multi->port4) & multi->mask4) == multi->match4)
  26571. +            continue;
  26572. +        break;
  26573. +    } 
  26574. +#ifdef SERIAL_DEBUG_INTR
  26575. +    printk("end.\n");
  26576. +#endif
  26577. +}
  26578. +
  26579. +
  26580. +/*
  26581. + * -------------------------------------------------------------------
  26582. + * Here ends the serial interrupt routines.
  26583. + * -------------------------------------------------------------------
  26584. + */
  26585. +
  26586. +/*
  26587. + * This routine is used to handle the "bottom half" processing for the
  26588. + * serial driver, known also the "software interrupt" processing.
  26589. + * This processing is done at the kernel interrupt level, after the
  26590. + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
  26591. + * is where time-consuming activities which can not be done in the
  26592. + * interrupt driver proper are done; the interrupt driver schedules
  26593. + * them using rs_sched_event(), and they get done here.
  26594. + */
  26595. +static void do_serial_bh(void)
  26596. +{
  26597. +    run_task_queue(&tq_serial);
  26598. +}
  26599. +
  26600. +static void do_softint(void *private_)
  26601. +{
  26602. +    struct async_struct    *info = (struct async_struct *) private_;
  26603. +    struct tty_struct    *tty;
  26604. +    
  26605. +    tty = info->tty;
  26606. +    if (!tty)
  26607. +        return;
  26608. +
  26609. +    if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
  26610. +        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  26611. +            tty->ldisc.write_wakeup)
  26612. +            (tty->ldisc.write_wakeup)(tty);
  26613. +        wake_up_interruptible(&tty->write_wait);
  26614. +    }
  26615. +}
  26616. +
  26617. +/*
  26618. + * This routine is called from the scheduler tqueue when the interrupt
  26619. + * routine has signalled that a hangup has occurred.  The path of
  26620. + * hangup processing is:
  26621. + *
  26622. + *     serial interrupt routine -> (scheduler tqueue) ->
  26623. + *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
  26624. + * 
  26625. + */
  26626. +static void do_serial_hangup(void *private_)
  26627. +{
  26628. +    struct async_struct    *info = (struct async_struct *) private_;
  26629. +    struct tty_struct    *tty;
  26630. +    
  26631. +    tty = info->tty;
  26632. +    if (!tty)
  26633. +        return;
  26634. +
  26635. +    tty_hangup(tty);
  26636. +}
  26637. +
  26638. +
  26639. +/*
  26640. + * This subroutine is called when the RS_TIMER goes off.  It is used
  26641. + * by the serial driver to handle ports that do not have an interrupt
  26642. + * (irq=0).  This doesn't work very well for 16450's, but gives barely
  26643. + * passable results for a 16550A.  (Although at the expense of much
  26644. + * CPU overhead).
  26645. + */
  26646. +static void rs_timer(void)
  26647. +{
  26648. +    static unsigned long last_strobe = 0;
  26649. +    struct async_struct *info;
  26650. +    unsigned int    i;
  26651. +
  26652. +    if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
  26653. +        for (i=0; i < 32; i++) {
  26654. +            info = IRQ_ports[i];
  26655. +            if (!info)
  26656. +                continue;
  26657. +            cli();
  26658. +            if (info->next_port) {
  26659. +                do {
  26660. +                    serial_out(info, UART_IER, 0);
  26661. +                    info->IER |= UART_IER_THRI;
  26662. +                    serial_out(info, UART_IER, info->IER);
  26663. +                    info = info->next_port;
  26664. +                } while (info);
  26665. +                if (rs_multiport[i].port1)
  26666. +                    rs_interrupt_multi(i, NULL, NULL);
  26667. +                else
  26668. +                    rs_interrupt(i, NULL, NULL);
  26669. +            } else
  26670. +                rs_interrupt_single(i, NULL, NULL);
  26671. +            sti();
  26672. +        }
  26673. +    }
  26674. +    last_strobe = jiffies;
  26675. +    timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME;
  26676. +    timer_active |= 1 << RS_TIMER;
  26677. +
  26678. +    if (IRQ_ports[0]) {
  26679. +        cli();
  26680. +        rs_interrupt(0, NULL, NULL);
  26681. +        sti();
  26682. +
  26683. +        timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
  26684. +    }
  26685. +}
  26686. +
  26687. +/*
  26688. + * ---------------------------------------------------------------
  26689. + * Low level utility subroutines for the serial driver:  routines to
  26690. + * figure out the appropriate timeout for an interrupt chain, routines
  26691. + * to initialize and startup a serial port, and routines to shutdown a
  26692. + * serial port.  Useful stuff like that.
  26693. + * ---------------------------------------------------------------
  26694. + */
  26695. +
  26696. +/*
  26697. + * Grab all interrupts in preparation for doing an automatic irq
  26698. + * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a
  26699. + * mask of irq's which were grabbed and should therefore be freed
  26700. + * using free_all_interrupts().
  26701. + */
  26702. +static int grab_all_interrupts(int dontgrab)
  26703. +{
  26704. +    int             irq_lines = 0;
  26705. +    int            i, mask;
  26706. +    
  26707. +    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
  26708. +        if (!(mask & dontgrab) && !request_irq(i, rs_probe, SA_INTERRUPT, "serial probe", NULL)) {
  26709. +            irq_lines |= mask;
  26710. +        }
  26711. +    }
  26712. +    return irq_lines;
  26713. +}
  26714. +
  26715. +/*
  26716. + * Release all interrupts grabbed by grab_all_interrupts
  26717. + */
  26718. +static void free_all_interrupts(int irq_lines)
  26719. +{
  26720. +    int    i;
  26721. +    
  26722. +    for (i = 0; i < 16; i++) {
  26723. +        if (irq_lines & (1 << i))
  26724. +            free_irq(i, NULL);
  26725. +    }
  26726. +}
  26727. +
  26728. +/*
  26729. + * This routine figures out the correct timeout for a particular IRQ.
  26730. + * It uses the smallest timeout of all of the serial ports in a
  26731. + * particular interrupt chain.  Now only used for IRQ 0....
  26732. + */
  26733. +static void figure_IRQ_timeout(int irq)
  26734. +{
  26735. +    struct    async_struct    *info;
  26736. +    int    timeout = 60*HZ;    /* 60 seconds === a long time :-) */
  26737. +
  26738. +    info = IRQ_ports[irq];
  26739. +    if (!info) {
  26740. +        IRQ_timeout[irq] = 60*HZ;
  26741. +        return;
  26742. +    }
  26743. +    while (info) {
  26744. +        if (info->timeout < timeout)
  26745. +            timeout = info->timeout;
  26746. +        info = info->next_port;
  26747. +    }
  26748. +    if (!irq)
  26749. +        timeout = timeout / 2;
  26750. +    IRQ_timeout[irq] = timeout ? timeout : 1;
  26751. +}
  26752. +
  26753. +static int startup(struct async_struct * info)
  26754. +{
  26755. +    unsigned short ICP;
  26756. +    unsigned long flags;
  26757. +    int    retval;
  26758. +    void (*handler)(int, void *, struct pt_regs *);
  26759. +    unsigned long page;
  26760. +
  26761. +    page = get_free_page(GFP_KERNEL);
  26762. +    if (!page)
  26763. +        return -ENOMEM;
  26764. +
  26765. +
  26766. +    save_flags_cli(flags);
  26767. +
  26768. +    if (info->flags & ASYNC_INITIALIZED) {
  26769. +        free_page(page);
  26770. +        restore_flags(flags);
  26771. +        return 0;
  26772. +    }
  26773. +
  26774. +    if (!info->port || !info->type) {
  26775. +        if (info->tty)
  26776. +            set_bit(TTY_IO_ERROR, &info->tty->flags);
  26777. +        free_page(page);
  26778. +        restore_flags(flags);
  26779. +        return 0;
  26780. +    }
  26781. +    if (info->xmit_buf)
  26782. +        free_page(page);
  26783. +    else
  26784. +        info->xmit_buf = (unsigned char *) page;
  26785. +
  26786. +#ifdef SERIAL_DEBUG_OPEN
  26787. +    printk("starting up ttys%d (irq %d)...", info->line, info->irq);
  26788. +#endif
  26789. +
  26790. +    /*
  26791. +     * Clear the FIFO buffers and disable them
  26792. +     * (they will be reenabled in change_speed())
  26793. +     */
  26794. +    if (info->type == PORT_16650) {
  26795. +        serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  26796. +                         UART_FCR_CLEAR_XMIT));
  26797. +        info->xmit_fifo_size = 1; /* disabled for now */
  26798. +    } else if (info->type == PORT_16550A) {
  26799. +        serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  26800. +                         UART_FCR_CLEAR_XMIT));
  26801. +        info->xmit_fifo_size = 16;
  26802. +    } else
  26803. +        info->xmit_fifo_size = 1;
  26804. +
  26805. +    /*
  26806. +     * At this point there's no way the LSR could still be 0xFF;
  26807. +     * if it is, then bail out, because there's likely no UART
  26808. +     * here.
  26809. +     */
  26810. +    if (serial_inp(info, UART_LSR) == 0xff) {
  26811. +        restore_flags(flags);
  26812. +        if (suser()) {
  26813. +            if (info->tty)
  26814. +                set_bit(TTY_IO_ERROR, &info->tty->flags);
  26815. +            return 0;
  26816. +        } else
  26817. +            return -ENODEV;
  26818. +    }
  26819. +    
  26820. +    /*
  26821. +     * Allocate the IRQ if necessary
  26822. +     */
  26823. +    if (info->irq && (!IRQ_ports[info->irq] ||
  26824. +              !IRQ_ports[info->irq]->next_port)) {
  26825. +        if (IRQ_ports[info->irq]) {
  26826. +            free_irq(info->irq, NULL);
  26827. +            if (rs_multiport[info->irq].port1)
  26828. +                handler = rs_interrupt_multi;
  26829. +            else
  26830. +                handler = rs_interrupt;
  26831. +        } else 
  26832. +            handler = rs_interrupt_single;
  26833. +
  26834. +        retval = request_irq(info->irq, handler, IRQ_T(info),
  26835. +                     "serial", NULL);
  26836. +        if (retval) {
  26837. +            restore_flags(flags);
  26838. +            if (suser()) {
  26839. +                if (info->tty)
  26840. +                    set_bit(TTY_IO_ERROR,
  26841. +                        &info->tty->flags);
  26842. +                return 0;
  26843. +            } else
  26844. +                return retval;
  26845. +        }
  26846. +    }
  26847. +
  26848. +    /*
  26849. +     * Clear the interrupt registers.
  26850. +     */
  26851. +     /* (void) serial_inp(info, UART_LSR); */   /* (see above) */
  26852. +    (void) serial_inp(info, UART_RX);
  26853. +    (void) serial_inp(info, UART_IIR);
  26854. +    (void) serial_inp(info, UART_MSR);
  26855. +
  26856. +    /*
  26857. +     * Now, initialize the UART 
  26858. +     */
  26859. +    serial_outp(info, UART_LCR, UART_LCR_WLEN8);    /* reset DLAB */
  26860. +    if (info->flags & ASYNC_FOURPORT) {
  26861. +        info->MCR = UART_MCR_DTR | UART_MCR_RTS;
  26862. +        info->MCR_noint = UART_MCR_DTR | UART_MCR_OUT1;
  26863. +    } else {
  26864. +        info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
  26865. +        info->MCR_noint = UART_MCR_DTR | UART_MCR_RTS;
  26866. +    }
  26867. +#if defined(__alpha__) && !defined(CONFIG_PCI)
  26868. +    info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
  26869. +    info->MCR_noint |= UART_MCR_OUT1 | UART_MCR_OUT2;
  26870. +#endif
  26871. +    if (info->irq == 0)
  26872. +        info->MCR = info->MCR_noint;
  26873. +    serial_outp(info, UART_MCR, info->MCR);
  26874. +    
  26875. +    /*
  26876. +     * Finally, enable interrupts
  26877. +     */
  26878. +    info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
  26879. +    serial_outp(info, UART_IER, info->IER);    /* enable interrupts */
  26880. +    
  26881. +    if (info->flags & ASYNC_FOURPORT) {
  26882. +        /* Enable interrupts on the AST Fourport board */
  26883. +        ICP = (info->port & 0xFE0) | 0x01F;
  26884. +        outb_p(0x80, ICP);
  26885. +        (void) inb_p(ICP);
  26886. +    }
  26887. +
  26888. +    /*
  26889. +     * And clear the interrupt registers again for luck.
  26890. +     */
  26891. +    (void)serial_inp(info, UART_LSR);
  26892. +    (void)serial_inp(info, UART_RX);
  26893. +    (void)serial_inp(info, UART_IIR);
  26894. +    (void)serial_inp(info, UART_MSR);
  26895. +
  26896. +    if (info->tty)
  26897. +        clear_bit(TTY_IO_ERROR, &info->tty->flags);
  26898. +    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
  26899. +
  26900. +    /*
  26901. +     * Insert serial port into IRQ chain.
  26902. +     */
  26903. +    info->prev_port = 0;
  26904. +    info->next_port = IRQ_ports[info->irq];
  26905. +    if (info->next_port)
  26906. +        info->next_port->prev_port = info;
  26907. +    IRQ_ports[info->irq] = info;
  26908. +    figure_IRQ_timeout(info->irq);
  26909. +
  26910. +    /*
  26911. +     * Set up serial timers...
  26912. +     */
  26913. +    timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
  26914. +    timer_active |= 1 << RS_TIMER;
  26915. +
  26916. +    /*
  26917. +     * and set the speed of the serial port
  26918. +     */
  26919. +    change_speed(info);
  26920. +
  26921. +    info->flags |= ASYNC_INITIALIZED;
  26922. +    restore_flags(flags);
  26923. +    return 0;
  26924. +}
  26925. +
  26926. +/*
  26927. + * This routine will shutdown a serial port; interrupts are disabled, and
  26928. + * DTR is dropped if the hangup on close termio flag is on.
  26929. + */
  26930. +static void shutdown(struct async_struct * info)
  26931. +{
  26932. +    unsigned long    flags;
  26933. +    int        retval;
  26934. +
  26935. +    if (!(info->flags & ASYNC_INITIALIZED))
  26936. +        return;
  26937. +
  26938. +#ifdef SERIAL_DEBUG_OPEN
  26939. +    printk("Shutting down serial port %d (irq %d)....", info->line,
  26940. +           info->irq);
  26941. +#endif
  26942. +    
  26943. +    save_flags_cli(flags); /* Disable interrupts */
  26944. +
  26945. +    /*
  26946. +     * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
  26947. +     * here so the queue might never be waken up
  26948. +     */
  26949. +    wake_up_interruptible(&info->delta_msr_wait);
  26950. +    
  26951. +    /*
  26952. +     * First unlink the serial port from the IRQ chain...
  26953. +     */
  26954. +    if (info->next_port)
  26955. +        info->next_port->prev_port = info->prev_port;
  26956. +    if (info->prev_port)
  26957. +        info->prev_port->next_port = info->next_port;
  26958. +    else
  26959. +        IRQ_ports[info->irq] = info->next_port;
  26960. +    figure_IRQ_timeout(info->irq);
  26961. +    
  26962. +    /*
  26963. +     * Free the IRQ, if necessary
  26964. +     */
  26965. +    if (info->irq && (!IRQ_ports[info->irq] ||
  26966. +              !IRQ_ports[info->irq]->next_port)) {
  26967. +        if (IRQ_ports[info->irq]) {
  26968. +            free_irq(info->irq, NULL);
  26969. +            retval = request_irq(info->irq, rs_interrupt_single,
  26970. +                         IRQ_T(info), "serial", NULL);
  26971. +            
  26972. +            if (retval)
  26973. +                printk("serial shutdown: request_irq: error %d"
  26974. +                       "  Couldn't reacquire IRQ.\n", retval);
  26975. +        } else
  26976. +            free_irq(info->irq, NULL);
  26977. +    }
  26978. +
  26979. +    if (info->xmit_buf) {
  26980. +        free_page((unsigned long) info->xmit_buf);
  26981. +        info->xmit_buf = 0;
  26982. +    }
  26983. +
  26984. +    info->IER = 0;
  26985. +    serial_outp(info, UART_IER, 0x00);    /* disable all intrs */
  26986. +    if (info->flags & ASYNC_FOURPORT) {
  26987. +        /* reset interrupts on the AST Fourport board */
  26988. +        (void) inb((info->port & 0xFE0) | 0x01F);
  26989. +    }
  26990. +    
  26991. +    if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
  26992. +        info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
  26993. +        info->MCR_noint &= ~(UART_MCR_DTR|UART_MCR_RTS);
  26994. +    }
  26995. +    serial_outp(info, UART_MCR, info->MCR_noint);
  26996. +
  26997. +    /* disable FIFO's */    
  26998. +    serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  26999. +                     UART_FCR_CLEAR_XMIT));
  27000. +    (void)serial_in(info, UART_RX);    /* read data port to reset things */
  27001. +    
  27002. +    if (info->tty)
  27003. +        set_bit(TTY_IO_ERROR, &info->tty->flags);
  27004. +    
  27005. +    info->flags &= ~ASYNC_INITIALIZED;
  27006. +    restore_flags(flags);
  27007. +}
  27008. +
  27009. +/*
  27010. + * This routine is called to set the UART divisor registers to match
  27011. + * the specified baud rate for a serial port.
  27012. + */
  27013. +static void change_speed(struct async_struct *info)
  27014. +{
  27015. +    unsigned short port;
  27016. +    int    quot = 0;
  27017. +    unsigned cflag,cval,fcr;
  27018. +    int    i;
  27019. +
  27020. +    if (!info->tty || !info->tty->termios)
  27021. +        return;
  27022. +    cflag = info->tty->termios->c_cflag;
  27023. +    if (!(port = info->port))
  27024. +        return;
  27025. +    i = cflag & CBAUD;
  27026. +    if (i & CBAUDEX) {
  27027. +        i &= ~CBAUDEX;
  27028. +        if (i < 1 || i > 2) 
  27029. +            info->tty->termios->c_cflag &= ~CBAUDEX;
  27030. +        else
  27031. +            i += 15;
  27032. +    }
  27033. +    if (i == 15) {
  27034. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
  27035. +            i += 1;
  27036. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
  27037. +            i += 2;
  27038. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
  27039. +            quot = info->custom_divisor;
  27040. +    }
  27041. +    if (quot) {
  27042. +        info->timeout = ((info->xmit_fifo_size*HZ*15*quot) /
  27043. +                 info->baud_base) + 2;
  27044. +    } else if (baud_table[i] == 134) {
  27045. +        quot = (2*info->baud_base / 269);
  27046. +        info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
  27047. +    } else if (baud_table[i]) {
  27048. +        quot = info->baud_base / baud_table[i];
  27049. +        info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
  27050. +    } else {
  27051. +        quot = 0;
  27052. +        info->timeout = 0;
  27053. +    }
  27054. +    if (quot) {
  27055. +        info->MCR |= UART_MCR_DTR;
  27056. +        info->MCR_noint |= UART_MCR_DTR;
  27057. +        cli();
  27058. +        serial_out(info, UART_MCR, info->MCR);
  27059. +        sti();
  27060. +    } else {
  27061. +        info->MCR &= ~UART_MCR_DTR;
  27062. +        info->MCR_noint &= ~UART_MCR_DTR;
  27063. +        cli();
  27064. +        serial_out(info, UART_MCR, info->MCR);
  27065. +        sti();
  27066. +        return;
  27067. +    }
  27068. +    /* byte size and parity */
  27069. +    switch (cflag & CSIZE) {
  27070. +        case CS5: cval = 0x00; break;
  27071. +        case CS6: cval = 0x01; break;
  27072. +        case CS7: cval = 0x02; break;
  27073. +        case CS8: cval = 0x03; break;
  27074. +        default: cval = 0x00; break;   /* too keep GCC shut... */
  27075. +    }
  27076. +    if (cflag & CSTOPB) {
  27077. +        cval |= 0x04;
  27078. +    }    
  27079. +    if (cflag & PARENB)
  27080. +        cval |= UART_LCR_PARITY;
  27081. +    if (!(cflag & PARODD))
  27082. +        cval |= UART_LCR_EPAR;
  27083. +    if (info->type == PORT_16550A) {
  27084. +        if ((info->baud_base / quot) < 2400)
  27085. +            fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
  27086. +        else
  27087. +            fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
  27088. +    } else if (info->type == PORT_16650) {
  27089. +        /*
  27090. +         * On the 16650, we disable the FIFOs altogether
  27091. +         * because of a design bug in how the implement
  27092. +         * things.  We could support it by completely changing
  27093. +         * how we handle the interrupt driver, but not today....
  27094. +         *
  27095. +         * N.B.  Because there's no way to set a FIFO trigger
  27096. +         * at 1 char, we'd probably disable at speed below
  27097. +         * 2400 baud anyway...
  27098. +         */
  27099. +        fcr = 0;
  27100. +    } else
  27101. +        fcr = 0;
  27102. +    
  27103. +    /* CTS flow control flag and modem status interrupts */
  27104. +    info->IER &= ~UART_IER_MSI;
  27105. +    if (cflag & CRTSCTS) {
  27106. +        info->flags |= ASYNC_CTS_FLOW;
  27107. +        info->IER |= UART_IER_MSI;
  27108. +    } else
  27109. +        info->flags &= ~ASYNC_CTS_FLOW;
  27110. +    if (cflag & CLOCAL)
  27111. +        info->flags &= ~ASYNC_CHECK_CD;
  27112. +    else {
  27113. +        info->flags |= ASYNC_CHECK_CD;
  27114. +        info->IER |= UART_IER_MSI;
  27115. +    }
  27116. +    serial_out(info, UART_IER, info->IER);
  27117. +
  27118. +    /*
  27119. +     * Set up parity check flag
  27120. +     */
  27121. +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
  27122. +
  27123. +    info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
  27124. +    if (I_INPCK(info->tty))
  27125. +        info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
  27126. +    if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
  27127. +        info->read_status_mask |= UART_LSR_BI;
  27128. +    
  27129. +    info->ignore_status_mask = 0;
  27130. +#if 0
  27131. +    /* This should be safe, but for some broken bits of hardware... */
  27132. +    if (I_IGNPAR(info->tty)) {
  27133. +        info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
  27134. +        info->read_status_mask |= UART_LSR_PE | UART_LSR_FE;
  27135. +    }
  27136. +#endif
  27137. +    if (I_IGNBRK(info->tty)) {
  27138. +        info->ignore_status_mask |= UART_LSR_BI;
  27139. +        info->read_status_mask |= UART_LSR_BI;
  27140. +        /*
  27141. +         * If we're ignore parity and break indicators, ignore 
  27142. +         * overruns too.  (For real raw support).
  27143. +         */
  27144. +        if (I_IGNPAR(info->tty)) {
  27145. +            info->ignore_status_mask |= UART_LSR_OE |
  27146. +                UART_LSR_PE | UART_LSR_FE;
  27147. +            info->read_status_mask |= UART_LSR_OE |
  27148. +                UART_LSR_PE | UART_LSR_FE;
  27149. +        }
  27150. +    }
  27151. +    cli();
  27152. +    serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);    /* set DLAB */
  27153. +    serial_outp(info, UART_DLL, quot & 0xff);    /* LS of divisor */
  27154. +    serial_outp(info, UART_DLM, quot >> 8);        /* MS of divisor */
  27155. +    serial_outp(info, UART_LCR, cval);        /* reset DLAB */
  27156. +    serial_outp(info, UART_FCR, fcr);     /* set fcr */
  27157. +    sti();
  27158. +}
  27159. +
  27160. +static void rs_put_char(struct tty_struct *tty, unsigned char ch)
  27161. +{
  27162. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  27163. +    unsigned long flags;
  27164. +
  27165. +    if (serial_paranoia_check(info, tty->device, "rs_put_char"))
  27166. +        return;
  27167. +
  27168. +    if (!tty || !info->xmit_buf)
  27169. +        return;
  27170. +
  27171. +    save_flags_cli (flags);
  27172. +    if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
  27173. +        restore_flags(flags);
  27174. +        return;
  27175. +    }
  27176. +
  27177. +    info->xmit_buf[info->xmit_head++] = ch;
  27178. +    info->xmit_head &= SERIAL_XMIT_SIZE-1;
  27179. +    info->xmit_cnt++;
  27180. +    restore_flags(flags);
  27181. +}
  27182. +
  27183. +static void rs_flush_chars(struct tty_struct *tty)
  27184. +{
  27185. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  27186. +    unsigned long flags;
  27187. +                
  27188. +    if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
  27189. +        return;
  27190. +
  27191. +    if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
  27192. +        !info->xmit_buf)
  27193. +        return;
  27194. +
  27195. +    save_flags_cli (flags);
  27196. +    info->IER |= UART_IER_THRI;
  27197. +    serial_out(info, UART_IER, info->IER);
  27198. +    restore_flags(flags);
  27199. +}
  27200. +
  27201. +static int rs_write(struct tty_struct * tty, int from_user,
  27202. +            const unsigned char *buf, int count)
  27203. +{
  27204. +    int    c, total = 0;
  27205. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  27206. +    unsigned long flags;
  27207. +                
  27208. +    if (serial_paranoia_check(info, tty->device, "rs_write"))
  27209. +        return 0;
  27210. +
  27211. +    if (!tty || !info->xmit_buf || !tmp_buf)
  27212. +        return 0;
  27213. +        
  27214. +    if (from_user)
  27215. +        down(&tmp_buf_sem);
  27216. +    save_flags(flags);
  27217. +    while (1) {
  27218. +        cli();        
  27219. +        c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
  27220. +                   SERIAL_XMIT_SIZE - info->xmit_head));
  27221. +        if (c <= 0)
  27222. +            break;
  27223. +
  27224. +        if (from_user) {
  27225. +            memcpy_fromfs(tmp_buf, buf, c);
  27226. +            c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
  27227. +                       SERIAL_XMIT_SIZE - info->xmit_head));
  27228. +            memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
  27229. +        } else
  27230. +            memcpy(info->xmit_buf + info->xmit_head, buf, c);
  27231. +        info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
  27232. +        info->xmit_cnt += c;
  27233. +        restore_flags(flags);
  27234. +        buf += c;
  27235. +        count -= c;
  27236. +        total += c;
  27237. +    }
  27238. +    if (from_user)
  27239. +        up(&tmp_buf_sem);
  27240. +    if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
  27241. +        !(info->IER & UART_IER_THRI)) {
  27242. +        info->IER |= UART_IER_THRI;
  27243. +        serial_out(info, UART_IER, info->IER);
  27244. +    }
  27245. +    restore_flags(flags);
  27246. +    return total;
  27247. +}
  27248. +
  27249. +static int rs_write_room(struct tty_struct *tty)
  27250. +{
  27251. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  27252. +    int    ret;
  27253. +                
  27254. +    if (serial_paranoia_check(info, tty->device, "rs_write_room"))
  27255. +        return 0;
  27256. +    ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
  27257. +    if (ret < 0)
  27258. +        ret = 0;
  27259. +    return ret;
  27260. +}
  27261. +
  27262. +static int rs_chars_in_buffer(struct tty_struct *tty)
  27263. +{
  27264. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  27265. +                
  27266. +    if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
  27267. +        return 0;
  27268. +    return info->xmit_cnt;
  27269. +}
  27270. +
  27271. +static void rs_flush_buffer(struct tty_struct *tty)
  27272. +{
  27273. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  27274. +                
  27275. +    if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
  27276. +        return;
  27277. +    cli();
  27278. +    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
  27279. +    sti();
  27280. +    wake_up_interruptible(&tty->write_wait);
  27281. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  27282. +        tty->ldisc.write_wakeup)
  27283. +        (tty->ldisc.write_wakeup)(tty);
  27284. +}
  27285. +
  27286. +/*
  27287. + * ------------------------------------------------------------
  27288. + * rs_throttle()
  27289. + * 
  27290. + * This routine is called by the upper-layer tty layer to signal that
  27291. + * incoming characters should be throttled.
  27292. + * ------------------------------------------------------------
  27293. + */
  27294. +static void rs_throttle(struct tty_struct * tty)
  27295. +{
  27296. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  27297. +#ifdef SERIAL_DEBUG_THROTTLE
  27298. +    char    buf[64];
  27299. +    
  27300. +    printk("throttle %s: %d....\n", _tty_name(tty, buf),
  27301. +           tty->ldisc.chars_in_buffer(tty));
  27302. +#endif
  27303. +
  27304. +    if (serial_paranoia_check(info, tty->device, "rs_throttle"))
  27305. +        return;
  27306. +    
  27307. +    if (I_IXOFF(tty))
  27308. +        info->x_char = STOP_CHAR(tty);
  27309. +
  27310. +    info->MCR &= ~UART_MCR_RTS;
  27311. +    info->MCR_noint &= ~UART_MCR_RTS;
  27312. +    cli();
  27313. +    serial_out(info, UART_MCR, info->MCR);
  27314. +    sti();
  27315. +}
  27316. +
  27317. +static void rs_unthrottle(struct tty_struct * tty)
  27318. +{
  27319. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  27320. +#ifdef SERIAL_DEBUG_THROTTLE
  27321. +    char    buf[64];
  27322. +    
  27323. +    printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
  27324. +           tty->ldisc.chars_in_buffer(tty));
  27325. +#endif
  27326. +
  27327. +    if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
  27328. +        return;
  27329. +    
  27330. +    if (I_IXOFF(tty)) {
  27331. +        if (info->x_char)
  27332. +            info->x_char = 0;
  27333. +        else
  27334. +            info->x_char = START_CHAR(tty);
  27335. +    }
  27336. +    info->MCR |= UART_MCR_RTS;
  27337. +    info->MCR_noint |= UART_MCR_RTS;
  27338. +    cli();
  27339. +    serial_out(info, UART_MCR, info->MCR);
  27340. +    sti();
  27341. +}
  27342. +
  27343. +/*
  27344. + * ------------------------------------------------------------
  27345. + * rs_ioctl() and friends
  27346. + * ------------------------------------------------------------
  27347. + */
  27348. +
  27349. +static int get_serial_info(struct async_struct * info,
  27350. +               struct serial_struct * retinfo)
  27351. +{
  27352. +    struct serial_struct tmp;
  27353. +  
  27354. +    if (!retinfo)
  27355. +        return -EFAULT;
  27356. +    memset(&tmp, 0, sizeof(tmp));
  27357. +    tmp.type = info->type;
  27358. +    tmp.line = info->line;
  27359. +    tmp.port = info->port;
  27360. +    tmp.irq = info->irq;
  27361. +    tmp.flags = info->flags;
  27362. +    tmp.baud_base = info->baud_base;
  27363. +    tmp.close_delay = info->close_delay;
  27364. +    tmp.closing_wait = info->closing_wait;
  27365. +    tmp.custom_divisor = info->custom_divisor;
  27366. +    tmp.hub6 = info->hub6;
  27367. +    memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
  27368. +    return 0;
  27369. +}
  27370. +
  27371. +static int set_serial_info(struct async_struct * info,
  27372. +               struct serial_struct * new_info)
  27373. +{
  27374. +    struct serial_struct new_serial;
  27375. +    struct async_struct old_info;
  27376. +    unsigned int        i,change_irq,change_port;
  27377. +    int             retval = 0;
  27378. +
  27379. +    if (!new_info)
  27380. +        return -EFAULT;
  27381. +    memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
  27382. +    old_info = *info;
  27383. +
  27384. +    change_irq = new_serial.irq != info->irq;
  27385. +    change_port = (new_serial.port != info->port) || (new_serial.hub6 != info->hub6);
  27386. +
  27387. +    if (!suser()) {
  27388. +        if (change_irq || change_port ||
  27389. +            (new_serial.baud_base != info->baud_base) ||
  27390. +            (new_serial.type != info->type) ||
  27391. +            (new_serial.close_delay != info->close_delay) ||
  27392. +            ((new_serial.flags & ~ASYNC_USR_MASK) !=
  27393. +             (info->flags & ~ASYNC_USR_MASK)))
  27394. +            return -EPERM;
  27395. +        info->flags = ((info->flags & ~ASYNC_USR_MASK) |
  27396. +                   (new_serial.flags & ASYNC_USR_MASK));
  27397. +        info->custom_divisor = new_serial.custom_divisor;
  27398. +        goto check_and_exit;
  27399. +    }
  27400. +#if 0
  27401. +    if (new_serial.irq == 2)
  27402. +        new_serial.irq = 9;
  27403. +
  27404. +    if ((new_serial.irq > 15) || (new_serial.port > 0xffff) ||
  27405. +        (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
  27406. +        return -EINVAL;
  27407. +    }
  27408. +#else
  27409. +    if ((new_serial.irq > 31) || (new_serial.type < PORT_UNKNOWN) ||
  27410. +        (new_serial.type > PORT_MAX)) {
  27411. +        return -EINVAL;
  27412. +    }
  27413. +#endif
  27414. +
  27415. +    /* Make sure address is not already in use */
  27416. +    if (new_serial.type) {
  27417. +        for (i = 0 ; i < NR_PORTS; i++)
  27418. +            if ((info != &rs_table[i]) &&
  27419. +                (rs_table[i].port == new_serial.port) &&
  27420. +                rs_table[i].type)
  27421. +                return -EADDRINUSE;
  27422. +    }
  27423. +
  27424. +    if ((change_port || change_irq) && (info->count > 1))
  27425. +        return -EBUSY;
  27426. +
  27427. +    /*
  27428. +     * OK, past this point, all the error checking has been done.
  27429. +     * At this point, we start making changes.....
  27430. +     */
  27431. +
  27432. +    info->baud_base = new_serial.baud_base;
  27433. +    info->flags = ((info->flags & ~ASYNC_FLAGS) |
  27434. +            (new_serial.flags & ASYNC_FLAGS));
  27435. +    info->custom_divisor = new_serial.custom_divisor;
  27436. +    info->type = new_serial.type;
  27437. +    info->close_delay = new_serial.close_delay * HZ/100;
  27438. +    info->closing_wait = new_serial.closing_wait * HZ/100;
  27439. +
  27440. +    release_region(info->port,8);
  27441. +    if (change_port || change_irq) {
  27442. +        /*
  27443. +         * We need to shutdown the serial port at the old
  27444. +         * port/irq combination.
  27445. +         */
  27446. +        shutdown(info);
  27447. +        info->irq = new_serial.irq;
  27448. +        info->port = new_serial.port;
  27449. +        info->hub6 = new_serial.hub6;
  27450. +    }
  27451. +    if(info->type != PORT_UNKNOWN)
  27452. +        request_region(info->port,8,"serial(set)");
  27453. +
  27454. +    
  27455. +check_and_exit:
  27456. +    if (!info->port || !info->type)
  27457. +        return 0;
  27458. +    if (info->flags & ASYNC_INITIALIZED) {
  27459. +        if (((old_info.flags & ASYNC_SPD_MASK) !=
  27460. +             (info->flags & ASYNC_SPD_MASK)) ||
  27461. +            (old_info.custom_divisor != info->custom_divisor))
  27462. +            change_speed(info);
  27463. +    } else
  27464. +        retval = startup(info);
  27465. +    return retval;
  27466. +}
  27467. +
  27468. +
  27469. +/*
  27470. + * get_lsr_info - get line status register info
  27471. + *
  27472. + * Purpose: Let user call ioctl() to get info when the UART physically
  27473. + *         is emptied.  On bus types like RS485, the transmitter must
  27474. + *         release the bus after transmitting. This must be done when
  27475. + *         the transmit shift register is empty, not be done when the
  27476. + *         transmit holding register is empty.  This functionality
  27477. + *         allows an RS485 driver to be written in user space. 
  27478. + */
  27479. +static int get_lsr_info(struct async_struct * info, unsigned int *value)
  27480. +{
  27481. +    unsigned char status;
  27482. +    unsigned int result;
  27483. +
  27484. +    cli();
  27485. +    status = serial_in(info, UART_LSR);
  27486. +    sti();
  27487. +    result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
  27488. +    put_user(result,value);
  27489. +    return 0;
  27490. +}
  27491. +
  27492. +
  27493. +static int get_modem_info(struct async_struct * info, unsigned int *value)
  27494. +{
  27495. +    unsigned char control, status;
  27496. +    unsigned int result;
  27497. +
  27498. +    control = info->MCR;
  27499. +    cli();
  27500. +    status = serial_in(info, UART_MSR);
  27501. +    sti();
  27502. +    result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
  27503. +        | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
  27504. +        | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
  27505. +        | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
  27506. +        | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
  27507. +        | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
  27508. +    put_user(result,value);
  27509. +    return 0;
  27510. +}
  27511. +
  27512. +static int set_modem_info(struct async_struct * info, unsigned int cmd,
  27513. +              unsigned int *value)
  27514. +{
  27515. +    int error;
  27516. +    unsigned int arg;
  27517. +
  27518. +    error = verify_area(VERIFY_READ, value, sizeof(int));
  27519. +    if (error)
  27520. +        return error;
  27521. +    arg = get_user(value);
  27522. +    switch (cmd) {
  27523. +    case TIOCMBIS: 
  27524. +        if (arg & TIOCM_RTS) {
  27525. +            info->MCR |= UART_MCR_RTS;
  27526. +            info->MCR_noint |= UART_MCR_RTS;
  27527. +        }
  27528. +        if (arg & TIOCM_DTR) {
  27529. +            info->MCR |= UART_MCR_DTR;
  27530. +            info->MCR_noint |= UART_MCR_DTR;
  27531. +        }
  27532. +        break;
  27533. +    case TIOCMBIC:
  27534. +        if (arg & TIOCM_RTS) {
  27535. +            info->MCR &= ~UART_MCR_RTS;
  27536. +            info->MCR_noint &= ~UART_MCR_RTS;
  27537. +        }
  27538. +        if (arg & TIOCM_DTR) {
  27539. +            info->MCR &= ~UART_MCR_DTR;
  27540. +            info->MCR_noint &= ~UART_MCR_DTR;
  27541. +        }
  27542. +        break;
  27543. +    case TIOCMSET:
  27544. +        info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR))
  27545. +                 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
  27546. +                 | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
  27547. +        info->MCR_noint = ((info->MCR_noint
  27548. +                    & ~(UART_MCR_RTS | UART_MCR_DTR))
  27549. +                   | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
  27550. +                   | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
  27551. +        break;
  27552. +    default:
  27553. +        return -EINVAL;
  27554. +    }
  27555. +    cli();
  27556. +    serial_out(info, UART_MCR, info->MCR);
  27557. +    sti();
  27558. +    return 0;
  27559. +}
  27560. +
  27561. +static int do_autoconfig(struct async_struct * info)
  27562. +{
  27563. +    int            retval;
  27564. +    
  27565. +    if (!suser())
  27566. +        return -EPERM;
  27567. +    
  27568. +    if (info->count > 1)
  27569. +        return -EBUSY;
  27570. +    
  27571. +    shutdown(info);
  27572. +
  27573. +    cli();
  27574. +    autoconfig(info);
  27575. +    sti();
  27576. +
  27577. +    retval = startup(info);
  27578. +    if (retval)
  27579. +        return retval;
  27580. +    return 0;
  27581. +}
  27582. +
  27583. +
  27584. +/*
  27585. + * This routine sends a break character out the serial port.
  27586. + */
  27587. +static void send_break(    struct async_struct * info, int duration)
  27588. +{
  27589. +    if (!info->port)
  27590. +        return;
  27591. +    current->state = TASK_INTERRUPTIBLE;
  27592. +    current->timeout = jiffies + duration;
  27593. +    cli();
  27594. +    serial_out(info, UART_LCR, serial_inp(info, UART_LCR) | UART_LCR_SBC);
  27595. +    schedule();
  27596. +    serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
  27597. +    sti();
  27598. +}
  27599. +
  27600. +/*
  27601. + * This routine returns a bitfield of "wild interrupts".  Basically,
  27602. + * any unclaimed interrupts which is flapping around.
  27603. + */
  27604. +static int check_wild_interrupts(int doprint)
  27605. +{
  27606. +    int    i, mask;
  27607. +    int    wild_interrupts = 0;
  27608. +    int    irq_lines;
  27609. +    unsigned long timeout;
  27610. +    unsigned long flags;
  27611. +    
  27612. +    /* Turn on interrupts (they may be off) */
  27613. +    save_flags(flags); sti();
  27614. +
  27615. +    irq_lines = grab_all_interrupts(0);
  27616. +    
  27617. +    /*
  27618. +     * Delay for 0.1 seconds -- we use a busy loop since this may 
  27619. +     * occur during the bootup sequence
  27620. +     */
  27621. +    timeout = jiffies+HZ/10;
  27622. +    while (timeout >= jiffies)
  27623. +        ;
  27624. +    
  27625. +    rs_triggered = 0;    /* Reset after letting things settle */
  27626. +
  27627. +    timeout = jiffies+HZ/10;
  27628. +    while (timeout >= jiffies)
  27629. +        ;
  27630. +    
  27631. +    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
  27632. +        if ((rs_triggered & (1 << i)) &&
  27633. +            (irq_lines & (1 << i))) {
  27634. +            wild_interrupts |= mask;
  27635. +            if (doprint)
  27636. +                printk("Wild interrupt?  (IRQ %d)\n", i);
  27637. +        }
  27638. +    }
  27639. +    free_all_interrupts(irq_lines);
  27640. +    restore_flags(flags);
  27641. +    return wild_interrupts;
  27642. +}
  27643. +
  27644. +static int get_multiport_struct(struct async_struct * info,
  27645. +                struct serial_multiport_struct *retinfo)
  27646. +{
  27647. +    struct serial_multiport_struct ret;
  27648. +    struct rs_multiport_struct *multi;
  27649. +    
  27650. +    multi = &rs_multiport[info->irq];
  27651. +
  27652. +    ret.port_monitor = multi->port_monitor;
  27653. +    
  27654. +    ret.port1 = multi->port1;
  27655. +    ret.mask1 = multi->mask1;
  27656. +    ret.match1 = multi->match1;
  27657. +    
  27658. +    ret.port2 = multi->port2;
  27659. +    ret.mask2 = multi->mask2;
  27660. +    ret.match2 = multi->match2;
  27661. +    
  27662. +    ret.port3 = multi->port3;
  27663. +    ret.mask3 = multi->mask3;
  27664. +    ret.match3 = multi->match3;
  27665. +    
  27666. +    ret.port4 = multi->port4;
  27667. +    ret.mask4 = multi->mask4;
  27668. +    ret.match4 = multi->match4;
  27669. +
  27670. +    ret.irq = info->irq;
  27671. +
  27672. +    memcpy_tofs(retinfo,&ret,sizeof(*retinfo));
  27673. +    return 0;
  27674. +    
  27675. +}
  27676. +
  27677. +static int set_multiport_struct(struct async_struct * info,
  27678. +                struct serial_multiport_struct *in_multi)
  27679. +{
  27680. +    struct serial_multiport_struct new_multi;
  27681. +    struct rs_multiport_struct *multi;
  27682. +    int    was_multi, now_multi;
  27683. +    int    retval;
  27684. +    void (*handler)(int, void *, struct pt_regs *);
  27685. +
  27686. +    if (!suser())
  27687. +        return -EPERM;
  27688. +    if (!in_multi)
  27689. +        return -EFAULT;
  27690. +    memcpy_fromfs(&new_multi, in_multi,
  27691. +              sizeof(struct serial_multiport_struct));
  27692. +
  27693. +    if (new_multi.irq != info->irq || info->irq == 0 ||
  27694. +        !IRQ_ports[info->irq])
  27695. +        return -EINVAL;
  27696. +
  27697. +    multi = &rs_multiport[info->irq];
  27698. +    was_multi = (multi->port1 != 0);
  27699. +    
  27700. +    multi->port_monitor = new_multi.port_monitor;
  27701. +    
  27702. +    if (multi->port1)
  27703. +        release_region(multi->port1,1);
  27704. +    multi->port1 = new_multi.port1;
  27705. +    multi->mask1 = new_multi.mask1;
  27706. +    multi->match1 = new_multi.match1;
  27707. +    if (multi->port1)
  27708. +        request_region(multi->port1,1,"serial(multiport1)");
  27709. +
  27710. +    if (multi->port2)
  27711. +        release_region(multi->port2,1);
  27712. +    multi->port2 = new_multi.port2;
  27713. +    multi->mask2 = new_multi.mask2;
  27714. +    multi->match2 = new_multi.match2;
  27715. +    if (multi->port2)
  27716. +        request_region(multi->port2,1,"serial(multiport2)");
  27717. +
  27718. +    if (multi->port3)
  27719. +        release_region(multi->port3,1);
  27720. +    multi->port3 = new_multi.port3;
  27721. +    multi->mask3 = new_multi.mask3;
  27722. +    multi->match3 = new_multi.match3;
  27723. +    if (multi->port3)
  27724. +        request_region(multi->port3,1,"serial(multiport3)");
  27725. +
  27726. +    if (multi->port4)
  27727. +        release_region(multi->port4,1);
  27728. +    multi->port4 = new_multi.port4;
  27729. +    multi->mask4 = new_multi.mask4;
  27730. +    multi->match4 = new_multi.match4;
  27731. +    if (multi->port4)
  27732. +        request_region(multi->port4,1,"serial(multiport4)");
  27733. +
  27734. +    now_multi = (multi->port1 != 0);
  27735. +    
  27736. +    if (IRQ_ports[info->irq]->next_port &&
  27737. +        (was_multi != now_multi)) {
  27738. +        free_irq(info->irq, NULL);
  27739. +        if (now_multi)
  27740. +            handler = rs_interrupt_multi;
  27741. +        else
  27742. +            handler = rs_interrupt;
  27743. +
  27744. +        retval = request_irq(info->irq, handler, IRQ_T(info),
  27745. +                     "serial", NULL);
  27746. +        if (retval) {
  27747. +            printk("Couldn't reallocate serial interrupt "
  27748. +                   "driver!!\n");
  27749. +        }
  27750. +    }
  27751. +
  27752. +    return 0;
  27753. +}
  27754. +
  27755. +static int rs_ioctl(struct tty_struct *tty, struct file * file,
  27756. +            unsigned int cmd, unsigned long arg)
  27757. +{
  27758. +    int error;
  27759. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  27760. +    int retval;
  27761. +    struct async_icount cprev, cnow;    /* kernel counter temps */
  27762. +    struct serial_icounter_struct *p_cuser;    /* user space */
  27763. +
  27764. +    if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
  27765. +        return -ENODEV;
  27766. +
  27767. +    if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
  27768. +        (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
  27769. +        (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) &&
  27770. +        (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
  27771. +        if (tty->flags & (1 << TTY_IO_ERROR))
  27772. +            return -EIO;
  27773. +    }
  27774. +    
  27775. +    switch (cmd) {
  27776. +        case TCSBRK:    /* SVID version: non-zero arg --> no break */
  27777. +            retval = tty_check_change(tty);
  27778. +            if (retval)
  27779. +                return retval;
  27780. +            tty_wait_until_sent(tty, 0);
  27781. +            if (!arg)
  27782. +                send_break(info, HZ/4);    /* 1/4 second */
  27783. +            return 0;
  27784. +        case TCSBRKP:    /* support for POSIX tcsendbreak() */
  27785. +            retval = tty_check_change(tty);
  27786. +            if (retval)
  27787. +                return retval;
  27788. +            tty_wait_until_sent(tty, 0);
  27789. +            send_break(info, arg ? arg*(HZ/10) : HZ/4);
  27790. +            return 0;
  27791. +        case TIOCGSOFTCAR:
  27792. +            error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
  27793. +            if (error)
  27794. +                return error;
  27795. +            put_fs_long(C_CLOCAL(tty) ? 1 : 0,
  27796. +                    (unsigned long *) arg);
  27797. +            return 0;
  27798. +        case TIOCSSOFTCAR:
  27799. +            error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));
  27800. +            if (error)
  27801. +                return error;
  27802. +            arg = get_fs_long((unsigned long *) arg);
  27803. +            tty->termios->c_cflag =
  27804. +                ((tty->termios->c_cflag & ~CLOCAL) |
  27805. +                 (arg ? CLOCAL : 0));
  27806. +            return 0;
  27807. +        case TIOCMGET:
  27808. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  27809. +                sizeof(unsigned int));
  27810. +            if (error)
  27811. +                return error;
  27812. +            return get_modem_info(info, (unsigned int *) arg);
  27813. +        case TIOCMBIS:
  27814. +        case TIOCMBIC:
  27815. +        case TIOCMSET:
  27816. +            return set_modem_info(info, cmd, (unsigned int *) arg);
  27817. +        case TIOCGSERIAL:
  27818. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  27819. +                        sizeof(struct serial_struct));
  27820. +            if (error)
  27821. +                return error;
  27822. +            return get_serial_info(info,
  27823. +                           (struct serial_struct *) arg);
  27824. +        case TIOCSSERIAL:
  27825. +            error = verify_area(VERIFY_READ, (void *) arg,
  27826. +                        sizeof(struct serial_struct));
  27827. +            if (error)
  27828. +                return error; 
  27829. +            return set_serial_info(info,
  27830. +                           (struct serial_struct *) arg);
  27831. +        case TIOCSERCONFIG:
  27832. +            return do_autoconfig(info);
  27833. +
  27834. +        case TIOCSERGWILD:
  27835. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  27836. +                        sizeof(int));
  27837. +            if (error)
  27838. +                return error;
  27839. +            put_fs_long(rs_wild_int_mask, (unsigned long *) arg);
  27840. +            return 0;
  27841. +
  27842. +        case TIOCSERGETLSR: /* Get line status register */
  27843. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  27844. +                sizeof(unsigned int));
  27845. +            if (error)
  27846. +                return error;
  27847. +            else
  27848. +                return get_lsr_info(info, (unsigned int *) arg);
  27849. +
  27850. +        case TIOCSERSWILD:
  27851. +            if (!suser())
  27852. +                return -EPERM;
  27853. +            error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));
  27854. +            if (error)
  27855. +                return error;
  27856. +            rs_wild_int_mask = get_fs_long((unsigned long *) arg);
  27857. +            if (rs_wild_int_mask < 0)
  27858. +                rs_wild_int_mask = check_wild_interrupts(0);
  27859. +            return 0;
  27860. +
  27861. +        case TIOCSERGSTRUCT:
  27862. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  27863. +                        sizeof(struct async_struct));
  27864. +            if (error)
  27865. +                return error;
  27866. +            memcpy_tofs((struct async_struct *) arg,
  27867. +                    info, sizeof(struct async_struct));
  27868. +            return 0;
  27869. +            
  27870. +        case TIOCSERGETMULTI:
  27871. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  27872. +                    sizeof(struct serial_multiport_struct));
  27873. +            if (error)
  27874. +                return error;
  27875. +            return get_multiport_struct(info,
  27876. +                       (struct serial_multiport_struct *) arg);
  27877. +        case TIOCSERSETMULTI:
  27878. +            error = verify_area(VERIFY_READ, (void *) arg,
  27879. +                    sizeof(struct serial_multiport_struct));
  27880. +            if (error)
  27881. +                return error;
  27882. +            return set_multiport_struct(info,
  27883. +                       (struct serial_multiport_struct *) arg);
  27884. +        /*
  27885. +         * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
  27886. +         * - mask passed in arg for lines of interest
  27887. +         *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
  27888. +         * Caller should use TIOCGICOUNT to see which one it was
  27889. +         */
  27890. +        case TIOCMIWAIT:
  27891. +            cli();
  27892. +            cprev = info->icount;    /* note the counters on entry */
  27893. +            sti();
  27894. +            while (1) {
  27895. +                interruptible_sleep_on(&info->delta_msr_wait);
  27896. +                /* see if a signal did it */
  27897. +                if (current->signal & ~current->blocked)
  27898. +                    return -ERESTARTSYS;
  27899. +                cli();
  27900. +                cnow = info->icount;    /* atomic copy */
  27901. +                sti();
  27902. +                if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
  27903. +                    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
  27904. +                    return -EIO; /* no change => error */
  27905. +                if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
  27906. +                     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
  27907. +                     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
  27908. +                     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
  27909. +                    return 0;
  27910. +                }
  27911. +                cprev = cnow;
  27912. +            }
  27913. +            /* NOTREACHED */
  27914. +
  27915. +        /*
  27916. +         * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
  27917. +         * Return: write counters to the user passed counter struct
  27918. +         * NB: both 1->0 and 0->1 transitions are counted except for
  27919. +         *     RI where only 0->1 is counted.
  27920. +         */
  27921. +        case TIOCGICOUNT:
  27922. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  27923. +                sizeof(struct serial_icounter_struct));
  27924. +            if (error)
  27925. +                return error;
  27926. +            cli();
  27927. +            cnow = info->icount;
  27928. +            sti();
  27929. +            p_cuser = (struct serial_icounter_struct *) arg;
  27930. +            put_user(cnow.cts, &p_cuser->cts);
  27931. +            put_user(cnow.dsr, &p_cuser->dsr);
  27932. +            put_user(cnow.rng, &p_cuser->rng);
  27933. +            put_user(cnow.dcd, &p_cuser->dcd);
  27934. +            return 0;
  27935. +
  27936. +        default:
  27937. +            return -ENOIOCTLCMD;
  27938. +        }
  27939. +    return 0;
  27940. +}
  27941. +
  27942. +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
  27943. +{
  27944. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  27945. +
  27946. +    if (   (tty->termios->c_cflag == old_termios->c_cflag)
  27947. +        && (   RELEVANT_IFLAG(tty->termios->c_iflag)
  27948. +            == RELEVANT_IFLAG(old_termios->c_iflag)))
  27949. +      return;
  27950. +
  27951. +    change_speed(info);
  27952. +
  27953. +    if ((old_termios->c_cflag & CRTSCTS) &&
  27954. +        !(tty->termios->c_cflag & CRTSCTS)) {
  27955. +        tty->hw_stopped = 0;
  27956. +        rs_start(tty);
  27957. +    }
  27958. +
  27959. +#if 0
  27960. +    /*
  27961. +     * No need to wake up processes in open wait, since they
  27962. +     * sample the CLOCAL flag once, and don't recheck it.
  27963. +     * XXX  It's not clear whether the current behavior is correct
  27964. +     * or not.  Hence, this may change.....
  27965. +     */
  27966. +    if (!(old_termios->c_cflag & CLOCAL) &&
  27967. +        (tty->termios->c_cflag & CLOCAL))
  27968. +        wake_up_interruptible(&info->open_wait);
  27969. +#endif
  27970. +}
  27971. +
  27972. +/*
  27973. + * ------------------------------------------------------------
  27974. + * rs_close()
  27975. + * 
  27976. + * This routine is called when the serial port gets closed.  First, we
  27977. + * wait for the last remaining data to be sent.  Then, we unlink its
  27978. + * async structure from the interrupt chain if necessary, and we free
  27979. + * that IRQ if nothing is left in the chain.
  27980. + * ------------------------------------------------------------
  27981. + */
  27982. +static void rs_close(struct tty_struct *tty, struct file * filp)
  27983. +{
  27984. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  27985. +    unsigned long flags;
  27986. +    unsigned long timeout;
  27987. +
  27988. +    if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
  27989. +        return;
  27990. +    
  27991. +    save_flags_cli (flags);
  27992. +    
  27993. +    if (tty_hung_up_p(filp)) {
  27994. +        DBG_CNT("before DEC-hung");
  27995. +        MOD_DEC_USE_COUNT;
  27996. +        restore_flags(flags);
  27997. +        return;
  27998. +    }
  27999. +    
  28000. +#ifdef SERIAL_DEBUG_OPEN
  28001. +    printk("rs_close ttys%d, count = %d\n", info->line, info->count);
  28002. +#endif
  28003. +    if ((tty->count == 1) && (info->count != 1)) {
  28004. +        /*
  28005. +         * Uh, oh.  tty->count is 1, which means that the tty
  28006. +         * structure will be freed.  Info->count should always
  28007. +         * be one in these conditions.  If it's greater than
  28008. +         * one, we've got real problems, since it means the
  28009. +         * serial port won't be shutdown.
  28010. +         */
  28011. +        printk("rs_close: bad serial port count; tty->count is 1, "
  28012. +               "info->count is %d\n", info->count);
  28013. +        info->count = 1;
  28014. +    }
  28015. +    if (--info->count < 0) {
  28016. +        printk("rs_close: bad serial port count for ttys%d: %d\n",
  28017. +               info->line, info->count);
  28018. +        info->count = 0;
  28019. +    }
  28020. +    if (info->count) {
  28021. +        DBG_CNT("before DEC-2");
  28022. +        MOD_DEC_USE_COUNT;
  28023. +        restore_flags(flags);
  28024. +        return;
  28025. +    }
  28026. +    info->flags |= ASYNC_CLOSING;
  28027. +    /*
  28028. +     * Save the termios structure, since this port may have
  28029. +     * separate termios for callout and dialin.
  28030. +     */
  28031. +    if (info->flags & ASYNC_NORMAL_ACTIVE)
  28032. +        info->normal_termios = *tty->termios;
  28033. +    if (info->flags & ASYNC_CALLOUT_ACTIVE)
  28034. +        info->callout_termios = *tty->termios;
  28035. +    /*
  28036. +     * Now we wait for the transmit buffer to clear; and we notify 
  28037. +     * the line discipline to only process XON/XOFF characters.
  28038. +     */
  28039. +    tty->closing = 1;
  28040. +    if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
  28041. +        tty_wait_until_sent(tty, info->closing_wait);
  28042. +    /*
  28043. +     * At this point we stop accepting input.  To do this, we
  28044. +     * disable the receive line status interrupts, and tell the
  28045. +     * interrupt driver to stop checking the data ready bit in the
  28046. +     * line status register.
  28047. +     */
  28048. +    info->IER &= ~UART_IER_RLSI;
  28049. +    info->read_status_mask &= ~UART_LSR_DR;
  28050. +    if (info->flags & ASYNC_INITIALIZED) {
  28051. +        serial_out(info, UART_IER, info->IER);
  28052. +        /*
  28053. +         * Before we drop DTR, make sure the UART transmitter
  28054. +         * has completely drained; this is especially
  28055. +         * important if there is a transmit FIFO!
  28056. +         */
  28057. +        timeout = jiffies+HZ;
  28058. +        while (!(serial_inp(info, UART_LSR) & UART_LSR_TEMT)) {
  28059. +            current->state = TASK_INTERRUPTIBLE;
  28060. +            current->timeout = jiffies + info->timeout;
  28061. +            schedule();
  28062. +            if (jiffies > timeout)
  28063. +                break;
  28064. +        }
  28065. +    }
  28066. +    shutdown(info);
  28067. +    if (tty->driver.flush_buffer)
  28068. +        tty->driver.flush_buffer(tty);
  28069. +    if (tty->ldisc.flush_buffer)
  28070. +        tty->ldisc.flush_buffer(tty);
  28071. +    tty->closing = 0;
  28072. +    info->event = 0;
  28073. +    info->tty = 0;
  28074. +    if (info->blocked_open) {
  28075. +        if (info->close_delay) {
  28076. +            current->state = TASK_INTERRUPTIBLE;
  28077. +            current->timeout = jiffies + info->close_delay;
  28078. +            schedule();
  28079. +        }
  28080. +        wake_up_interruptible(&info->open_wait);
  28081. +    }
  28082. +    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
  28083. +             ASYNC_CLOSING);
  28084. +    wake_up_interruptible(&info->close_wait);
  28085. +    MOD_DEC_USE_COUNT;
  28086. +    restore_flags(flags);
  28087. +}
  28088. +
  28089. +/*
  28090. + * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
  28091. + */
  28092. +void rs_hangup(struct tty_struct *tty)
  28093. +{
  28094. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  28095. +    
  28096. +    if (serial_paranoia_check(info, tty->device, "rs_hangup"))
  28097. +        return;
  28098. +    
  28099. +    rs_flush_buffer(tty);
  28100. +    shutdown(info);
  28101. +    info->event = 0;
  28102. +    info->count = 0;
  28103. +    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
  28104. +    info->tty = 0;
  28105. +    wake_up_interruptible(&info->open_wait);
  28106. +}
  28107. +
  28108. +/*
  28109. + * ------------------------------------------------------------
  28110. + * rs_open() and friends
  28111. + * ------------------------------------------------------------
  28112. + */
  28113. +static int block_til_ready(struct tty_struct *tty, struct file * filp,
  28114. +               struct async_struct *info)
  28115. +{
  28116. +    struct wait_queue wait = { current, NULL };
  28117. +    int        retval;
  28118. +    int        do_clocal = 0;
  28119. +
  28120. +    /*
  28121. +     * If the device is in the middle of being closed, then block
  28122. +     * until it's done, and then try again.
  28123. +     */
  28124. +    if (tty_hung_up_p(filp) ||
  28125. +        (info->flags & ASYNC_CLOSING)) {
  28126. +            if (info->flags & ASYNC_CLOSING)
  28127. +                interruptible_sleep_on(&info->close_wait);
  28128. +#ifdef SERIAL_DO_RESTART
  28129. +        if (info->flags & ASYNC_HUP_NOTIFY)
  28130. +            return -EAGAIN;
  28131. +        else
  28132. +            return -ERESTARTSYS;
  28133. +#else
  28134. +        return -EAGAIN;
  28135. +#endif
  28136. +    }
  28137. +
  28138. +    /*
  28139. +     * If this is a callout device, then just make sure the normal
  28140. +     * device isn't being used.
  28141. +     */
  28142. +    if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
  28143. +        if (info->flags & ASYNC_NORMAL_ACTIVE)
  28144. +            return -EBUSY;
  28145. +        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  28146. +            (info->flags & ASYNC_SESSION_LOCKOUT) &&
  28147. +            (info->session != current->session))
  28148. +            return -EBUSY;
  28149. +        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  28150. +            (info->flags & ASYNC_PGRP_LOCKOUT) &&
  28151. +            (info->pgrp != current->pgrp))
  28152. +            return -EBUSY;
  28153. +        info->flags |= ASYNC_CALLOUT_ACTIVE;
  28154. +        return 0;
  28155. +    }
  28156. +    
  28157. +    /*
  28158. +     * If non-blocking mode is set, or the port is not enabled,
  28159. +     * then make the check up front and then exit.
  28160. +     */
  28161. +    if ((filp->f_flags & O_NONBLOCK) ||
  28162. +        (tty->flags & (1 << TTY_IO_ERROR))) {
  28163. +        if (info->flags & ASYNC_CALLOUT_ACTIVE)
  28164. +            return -EBUSY;
  28165. +        info->flags |= ASYNC_NORMAL_ACTIVE;
  28166. +        return 0;
  28167. +    }
  28168. +
  28169. +    if (info->flags & ASYNC_CALLOUT_ACTIVE) {
  28170. +        if (info->normal_termios.c_cflag & CLOCAL)
  28171. +            do_clocal = 1;
  28172. +    } else {
  28173. +        if (tty->termios->c_cflag & CLOCAL)
  28174. +            do_clocal = 1;
  28175. +    }
  28176. +    
  28177. +    /*
  28178. +     * Block waiting for the carrier detect and the line to become
  28179. +     * free (i.e., not in use by the callout).  While we are in
  28180. +     * this loop, info->count is dropped by one, so that
  28181. +     * rs_close() knows when to free things.  We restore it upon
  28182. +     * exit, either normal or abnormal.
  28183. +     */
  28184. +    retval = 0;
  28185. +    add_wait_queue(&info->open_wait, &wait);
  28186. +#ifdef SERIAL_DEBUG_OPEN
  28187. +    printk("block_til_ready before block: ttys%d, count = %d\n",
  28188. +           info->line, info->count);
  28189. +#endif
  28190. +    cli();
  28191. +    if (!tty_hung_up_p(filp))
  28192. +        info->count--;
  28193. +    sti();
  28194. +    info->blocked_open++;
  28195. +    while (1) {
  28196. +        cli();
  28197. +        if (!(info->flags & ASYNC_CALLOUT_ACTIVE))
  28198. +            serial_out(info, UART_MCR,
  28199. +                   serial_inp(info, UART_MCR) |
  28200. +                   (UART_MCR_DTR | UART_MCR_RTS));
  28201. +        sti();
  28202. +        current->state = TASK_INTERRUPTIBLE;
  28203. +        if (tty_hung_up_p(filp) ||
  28204. +            !(info->flags & ASYNC_INITIALIZED)) {
  28205. +#ifdef SERIAL_DO_RESTART
  28206. +            if (info->flags & ASYNC_HUP_NOTIFY)
  28207. +                retval = -EAGAIN;
  28208. +            else
  28209. +                retval = -ERESTARTSYS;    
  28210. +#else
  28211. +            retval = -EAGAIN;
  28212. +#endif
  28213. +            break;
  28214. +        }
  28215. +        if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
  28216. +            !(info->flags & ASYNC_CLOSING) &&
  28217. +            (do_clocal || (serial_in(info, UART_MSR) &
  28218. +                   UART_MSR_DCD)))
  28219. +            break;
  28220. +        if (current->signal & ~current->blocked) {
  28221. +            retval = -ERESTARTSYS;
  28222. +            break;
  28223. +        }
  28224. +#ifdef SERIAL_DEBUG_OPEN
  28225. +        printk("block_til_ready blocking: ttys%d, count = %d\n",
  28226. +               info->line, info->count);
  28227. +#endif
  28228. +        schedule();
  28229. +    }
  28230. +    current->state = TASK_RUNNING;
  28231. +    remove_wait_queue(&info->open_wait, &wait);
  28232. +    if (!tty_hung_up_p(filp))
  28233. +        info->count++;
  28234. +    info->blocked_open--;
  28235. +#ifdef SERIAL_DEBUG_OPEN
  28236. +    printk("block_til_ready after blocking: ttys%d, count = %d\n",
  28237. +           info->line, info->count);
  28238. +#endif
  28239. +    if (retval)
  28240. +        return retval;
  28241. +    info->flags |= ASYNC_NORMAL_ACTIVE;
  28242. +    return 0;
  28243. +}    
  28244. +
  28245. +/*
  28246. + * This routine is called whenever a serial port is opened.  It
  28247. + * enables interrupts for a serial port, linking in its async structure into
  28248. + * the IRQ chain.   It also performs the serial-specific
  28249. + * initialization for the tty structure.
  28250. + */
  28251. +int rs_open(struct tty_struct *tty, struct file * filp)
  28252. +{
  28253. +    struct async_struct    *info;
  28254. +    int             retval, line;
  28255. +    unsigned long        page;
  28256. +
  28257. +    line = MINOR(tty->device) - tty->driver.minor_start;
  28258. +    if ((line < 0) || (line >= NR_PORTS))
  28259. +        return -ENODEV;
  28260. +    info = rs_table + line;
  28261. +    if (serial_paranoia_check(info, tty->device, "rs_open"))
  28262. +        return -ENODEV;
  28263. +
  28264. +#ifdef SERIAL_DEBUG_OPEN
  28265. +    printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
  28266. +           info->count);
  28267. +#endif
  28268. +    info->count++;
  28269. +    tty->driver_data = info;
  28270. +    info->tty = tty;
  28271. +
  28272. +    if (!tmp_buf) {
  28273. +        page = get_free_page(GFP_KERNEL);
  28274. +        if (!page)
  28275. +            return -ENOMEM;
  28276. +        if (tmp_buf)
  28277. +            free_page(page);
  28278. +        else
  28279. +            tmp_buf = (unsigned char *) page;
  28280. +    }
  28281. +    
  28282. +    /*
  28283. +     * Start up serial port
  28284. +     */
  28285. +    retval = startup(info);
  28286. +    if (retval)
  28287. +        return retval;
  28288. +
  28289. +    MOD_INC_USE_COUNT;
  28290. +    retval = block_til_ready(tty, filp, info);
  28291. +    if (retval) {
  28292. +#ifdef SERIAL_DEBUG_OPEN
  28293. +        printk("rs_open returning after block_til_ready with %d\n",
  28294. +               retval);
  28295. +#endif
  28296. +        return retval;
  28297. +    }
  28298. +
  28299. +    if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
  28300. +        if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
  28301. +            *tty->termios = info->normal_termios;
  28302. +        else 
  28303. +            *tty->termios = info->callout_termios;
  28304. +        change_speed(info);
  28305. +    }
  28306. +
  28307. +    info->session = current->session;
  28308. +    info->pgrp = current->pgrp;
  28309. +
  28310. +#ifdef SERIAL_DEBUG_OPEN
  28311. +    printk("rs_open ttys%d successful...", info->line);
  28312. +#endif
  28313. +    return 0;
  28314. +}
  28315. +
  28316. +/*
  28317. + * ---------------------------------------------------------------------
  28318. + * rs_init() and friends
  28319. + *
  28320. + * rs_init() is called at boot-time to initialize the serial driver.
  28321. + * ---------------------------------------------------------------------
  28322. + */
  28323. +
  28324. +/*
  28325. + * This routine prints out the appropriate serial driver version
  28326. + * number, and identifies which options were configured into this
  28327. + * driver.
  28328. + */
  28329. +static void show_serial_version(void)
  28330. +{
  28331. +    printk(KERN_INFO "%s version %s with", serial_name, serial_version);
  28332. +#ifdef CONFIG_HUB6
  28333. +    printk(" HUB-6");
  28334. +#define SERIAL_OPT
  28335. +#endif
  28336. +#ifdef SERIAL_OPT
  28337. +    printk(" enabled\n");
  28338. +#else
  28339. +    printk(" no serial options enabled\n");
  28340. +#endif
  28341. +#undef SERIAL_OPT
  28342. +}
  28343. +
  28344. +/*
  28345. + * This routine is called by do_auto_irq(); it attempts to determine
  28346. + * which interrupt a serial port is configured to use.  It is not
  28347. + * fool-proof, but it works a large part of the time.
  28348. + */
  28349. +static int get_auto_irq(struct async_struct *info)
  28350. +{
  28351. +    unsigned char save_MCR, save_IER, save_ICP=0;
  28352. +    unsigned short ICP=0, port = info->port;
  28353. +    unsigned long timeout;
  28354. +    
  28355. +    /*
  28356. +     * Enable interrupts and see who answers
  28357. +     */
  28358. +    rs_irq_triggered = 0;
  28359. +    cli();
  28360. +    save_IER = serial_inp(info, UART_IER);
  28361. +    save_MCR = serial_inp(info, UART_MCR);
  28362. +    if (info->flags & ASYNC_FOURPORT)  {
  28363. +        serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
  28364. +        serial_outp(info, UART_IER, 0x0f);    /* enable all intrs */
  28365. +        ICP = (port & 0xFE0) | 0x01F;
  28366. +        save_ICP = inb_p(ICP);
  28367. +        outb_p(0x80, ICP);
  28368. +        (void) inb_p(ICP);
  28369. +    } else {
  28370. +        serial_outp(info, UART_MCR,
  28371. +                UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
  28372. +        serial_outp(info, UART_IER, 0x0f);    /* enable all intrs */
  28373. +    }
  28374. +    sti();
  28375. +    /*
  28376. +     * Next, clear the interrupt registers.
  28377. +     */
  28378. +    (void)serial_inp(info, UART_LSR);
  28379. +    (void)serial_inp(info, UART_RX);
  28380. +    (void)serial_inp(info, UART_IIR);
  28381. +    (void)serial_inp(info, UART_MSR);
  28382. +    
  28383. +    timeout = jiffies+2*HZ/100;
  28384. +    while (timeout >= jiffies) {
  28385. +        if (rs_irq_triggered)
  28386. +            break;
  28387. +    }
  28388. +    /*
  28389. +     * Now check to see if we got any business, and clean up.
  28390. +     */
  28391. +    cli();
  28392. +    serial_outp(info, UART_IER, save_IER);
  28393. +    serial_outp(info, UART_MCR, save_MCR);
  28394. +    if (info->flags & ASYNC_FOURPORT)
  28395. +        outb_p(save_ICP, ICP);
  28396. +    sti();
  28397. +    return(rs_irq_triggered);
  28398. +}
  28399. +
  28400. +/*
  28401. + * Calls get_auto_irq() multiple times, to make sure we don't get
  28402. + * faked out by random interrupts
  28403. + */
  28404. +static int do_auto_irq(struct async_struct * info)
  28405. +{
  28406. +    unsigned         port = info->port;
  28407. +    int             irq_lines = 0;
  28408. +    int            irq_try_1 = 0, irq_try_2 = 0;
  28409. +    int            retries;
  28410. +    unsigned long flags;
  28411. +
  28412. +    if (!port)
  28413. +        return 0;
  28414. +
  28415. +    /* Turn on interrupts (they may be off) */
  28416. +    save_flags(flags); sti();
  28417. +
  28418. +    irq_lines = grab_all_interrupts(rs_wild_int_mask);
  28419. +    
  28420. +    for (retries = 0; retries < 5; retries++) {
  28421. +        if (!irq_try_1)
  28422. +            irq_try_1 = get_auto_irq(info);
  28423. +        if (!irq_try_2)
  28424. +            irq_try_2 = get_auto_irq(info);
  28425. +        if (irq_try_1 && irq_try_2) {
  28426. +            if (irq_try_1 == irq_try_2)
  28427. +                break;
  28428. +            irq_try_1 = irq_try_2 = 0;
  28429. +        }
  28430. +    }
  28431. +    restore_flags(flags);
  28432. +    free_all_interrupts(irq_lines);
  28433. +    return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
  28434. +}
  28435. +
  28436. +/*
  28437. + * This routine is called by rs_init() to initialize a specific serial
  28438. + * port.  It determines what type of UART chip this serial port is
  28439. + * using: 8250, 16450, 16550, 16550A.  The important question is
  28440. + * whether or not this UART is a 16550A or not, since this will
  28441. + * determine whether or not we can use its FIFO features or not.
  28442. + */
  28443. +static void autoconfig(struct async_struct * info)
  28444. +{
  28445. +    unsigned char status1, status2, scratch, scratch2;
  28446. +    unsigned port = info->port;
  28447. +    unsigned long flags;
  28448. +
  28449. +    info->type = PORT_UNKNOWN;
  28450. +    
  28451. +    if (!port)
  28452. +        return;
  28453. +
  28454. +    save_flags_cli (flags);
  28455. +    
  28456. +    /*
  28457. +     * Do a simple existence test first; if we fail this, there's
  28458. +     * no point trying anything else.
  28459. +     *
  28460. +     * 0x80 is used as a nonsense port to prevent against false
  28461. +     * positives due to ISA bus float.  The assumption is that
  28462. +     * 0x80 is a non-existent port; which should be safe since
  28463. +     * include/asm/io.h also makes this assumption.
  28464. +     */
  28465. +    scratch = serial_inp(info, UART_IER);
  28466. +    serial_outp(info, UART_IER, 0);
  28467. +    outb(0xff, 0x080);
  28468. +    scratch2 = serial_inp(info, UART_IER);
  28469. +    serial_outp(info, UART_IER, scratch);
  28470. +    if (scratch2) {
  28471. +        restore_flags(flags);
  28472. +        return;        /* We failed; there's nothing here */
  28473. +    }
  28474. +
  28475. +    /* 
  28476. +     * Check to see if a UART is really there.  Certain broken
  28477. +     * internal modems based on the Rockwell chipset fail this
  28478. +     * test, because they apparently don't implement the loopback
  28479. +     * test mode.  So this test is skipped on the COM 1 through
  28480. +     * COM 4 ports.  This *should* be safe, since no board
  28481. +     * manufacturer would be stupid enough to design a board
  28482. +     * that conflicts with COM 1-4 --- we hope!
  28483. +     */
  28484. +    if (!(info->flags & ASYNC_SKIP_TEST)) {
  28485. +        scratch = serial_inp(info, UART_MCR);
  28486. +        serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
  28487. +        scratch2 = serial_inp(info, UART_MSR);
  28488. +        serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
  28489. +        status1 = serial_inp(info, UART_MSR) & 0xF0;
  28490. +        serial_outp(info, UART_MCR, scratch);
  28491. +        serial_outp(info, UART_MSR, scratch2);
  28492. +        if (status1 != 0x90) {
  28493. +            restore_flags(flags);
  28494. +            return;
  28495. +        }
  28496. +    } 
  28497. +    
  28498. +    /*
  28499. +     * If the AUTO_IRQ flag is set, try to do the automatic IRQ
  28500. +     * detection.
  28501. +     */
  28502. +    if (info->flags & ASYNC_AUTO_IRQ)
  28503. +        info->irq = do_auto_irq(info);
  28504. +        
  28505. +    scratch2 = serial_in(info, UART_LCR);
  28506. +    serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
  28507. +    serial_outp(info, UART_EFR, 0);    /* EFR is the same as FCR */
  28508. +    serial_outp(info, UART_LCR, scratch2);
  28509. +    serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
  28510. +    scratch = serial_in(info, UART_IIR) >> 6;
  28511. +    info->xmit_fifo_size = 1;
  28512. +    switch (scratch) {
  28513. +        case 0:
  28514. +            info->type = PORT_16450;
  28515. +            break;
  28516. +        case 1:
  28517. +            info->type = PORT_UNKNOWN;
  28518. +            break;
  28519. +        case 2:
  28520. +            info->type = PORT_16550;
  28521. +            break;
  28522. +        case 3:
  28523. +            serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
  28524. +            if (serial_in(info, UART_EFR) == 0) {
  28525. +                info->type = PORT_16650;
  28526. +                info->xmit_fifo_size = 32;
  28527. +            } else {
  28528. +                info->type = PORT_16550A;
  28529. +                info->xmit_fifo_size = 16;
  28530. +            }
  28531. +            serial_outp(info, UART_LCR, scratch2);
  28532. +            break;
  28533. +    }
  28534. +    if (info->type == PORT_16450) {
  28535. +        scratch = serial_in(info, UART_SCR);
  28536. +        serial_outp(info, UART_SCR, 0xa5);
  28537. +        status1 = serial_in(info, UART_SCR);
  28538. +        serial_outp(info, UART_SCR, 0x5a);
  28539. +        status2 = serial_in(info, UART_SCR);
  28540. +        serial_outp(info, UART_SCR, scratch);
  28541. +
  28542. +        if ((status1 != 0xa5) || (status2 != 0x5a))
  28543. +            info->type = PORT_8250;
  28544. +    }
  28545. +    request_region(info->port,8,"serial(auto)");
  28546. +
  28547. +    /*
  28548. +     * Reset the UART.
  28549. +     */
  28550. +#if defined(__alpha__) && !defined(CONFIG_PCI)
  28551. +    /*
  28552. +     * I wonder what DEC did to the OUT1 and OUT2 lines?
  28553. +     * clearing them results in endless interrupts.
  28554. +     */
  28555. +    serial_outp(info, UART_MCR, 0x0c);
  28556. +#else
  28557. +    serial_outp(info, UART_MCR, 0x00);
  28558. +#endif
  28559. +    serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  28560. +                     UART_FCR_CLEAR_XMIT));
  28561. +    (void)serial_in(info, UART_RX);
  28562. +    
  28563. +    restore_flags(flags);
  28564. +}
  28565. +
  28566. +int register_serial(struct serial_struct *req);
  28567. +void unregister_serial(int line);
  28568. +
  28569. +static struct symbol_table serial_syms = {
  28570. +#include <linux/symtab_begin.h>
  28571. +    X(register_serial),
  28572. +    X(unregister_serial),
  28573. +#include <linux/symtab_end.h>
  28574. +};
  28575. +
  28576. +/*
  28577. + * The serial driver boot-time initialization code!
  28578. + */
  28579. +int rs_init(void)
  28580. +{
  28581. +    int i;
  28582. +    struct async_struct * info;
  28583. +#ifdef CONFIG_ATOMWIDE_SERIAL
  28584. +    extern void atomwide_serial_init (void);
  28585. +
  28586. +    atomwide_serial_init ();
  28587. +#endif
  28588. +    
  28589. +    init_bh(SERIAL_BH, do_serial_bh);
  28590. +    timer_table[RS_TIMER].fn = rs_timer;
  28591. +    timer_table[RS_TIMER].expires = 0;
  28592. +#ifdef CONFIG_AUTO_IRQ
  28593. +    rs_wild_int_mask = check_wild_interrupts(1);
  28594. +#endif
  28595. +
  28596. +    for (i = 0; i < 32; i++) {
  28597. +        IRQ_ports[i] = 0;
  28598. +        IRQ_timeout[i] = 0;
  28599. +        memset(&rs_multiport[i], 0, sizeof(struct rs_multiport_struct));
  28600. +    }
  28601. +    
  28602. +    show_serial_version();
  28603. +
  28604. +    /* Initialize the tty_driver structure */
  28605. +    
  28606. +    memset(&serial_driver, 0, sizeof(struct tty_driver));
  28607. +    serial_driver.magic = TTY_DRIVER_MAGIC;
  28608. +    serial_driver.name = "ttyS";
  28609. +    serial_driver.major = TTY_MAJOR;
  28610. +    serial_driver.minor_start = 64;
  28611. +    serial_driver.num = NR_PORTS;
  28612. +    serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
  28613. +    serial_driver.subtype = SERIAL_TYPE_NORMAL;
  28614. +    serial_driver.init_termios = tty_std_termios;
  28615. +    serial_driver.init_termios.c_cflag =
  28616. +        B9600 | CS8 | CREAD | HUPCL | CLOCAL;
  28617. +    serial_driver.flags = TTY_DRIVER_REAL_RAW;
  28618. +    serial_driver.refcount = &serial_refcount;
  28619. +    serial_driver.table = serial_table;
  28620. +    serial_driver.termios = serial_termios;
  28621. +    serial_driver.termios_locked = serial_termios_locked;
  28622. +
  28623. +    serial_driver.open = rs_open;
  28624. +    serial_driver.close = rs_close;
  28625. +    serial_driver.write = rs_write;
  28626. +    serial_driver.put_char = rs_put_char;
  28627. +    serial_driver.flush_chars = rs_flush_chars;
  28628. +    serial_driver.write_room = rs_write_room;
  28629. +    serial_driver.chars_in_buffer = rs_chars_in_buffer;
  28630. +    serial_driver.flush_buffer = rs_flush_buffer;
  28631. +    serial_driver.ioctl = rs_ioctl;
  28632. +    serial_driver.throttle = rs_throttle;
  28633. +    serial_driver.unthrottle = rs_unthrottle;
  28634. +    serial_driver.set_termios = rs_set_termios;
  28635. +    serial_driver.stop = rs_stop;
  28636. +    serial_driver.start = rs_start;
  28637. +    serial_driver.hangup = rs_hangup;
  28638. +
  28639. +    /*
  28640. +     * The callout device is just like normal device except for
  28641. +     * major number and the subtype code.
  28642. +     */
  28643. +    callout_driver = serial_driver;
  28644. +    callout_driver.name = "cua";
  28645. +    callout_driver.major = TTYAUX_MAJOR;
  28646. +    callout_driver.subtype = SERIAL_TYPE_CALLOUT;
  28647. +
  28648. +    if (tty_register_driver(&serial_driver))
  28649. +        panic("Couldn't register serial driver\n");
  28650. +    if (tty_register_driver(&callout_driver))
  28651. +        panic("Couldn't register callout driver\n");
  28652. +    
  28653. +    for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
  28654. +        info->magic = SERIAL_MAGIC;
  28655. +        info->line = i;
  28656. +        info->tty = 0;
  28657. +        info->type = PORT_UNKNOWN;
  28658. +        info->custom_divisor = 0;
  28659. +        info->close_delay = 5*HZ/10;
  28660. +        info->closing_wait = 30*HZ;
  28661. +        info->x_char = 0;
  28662. +        info->event = 0;
  28663. +        info->count = 0;
  28664. +        info->blocked_open = 0;
  28665. +        info->tqueue.routine = do_softint;
  28666. +        info->tqueue.data = info;
  28667. +        info->tqueue_hangup.routine = do_serial_hangup;
  28668. +        info->tqueue_hangup.data = info;
  28669. +        info->callout_termios =callout_driver.init_termios;
  28670. +        info->normal_termios = serial_driver.init_termios;
  28671. +        info->open_wait = 0;
  28672. +        info->close_wait = 0;
  28673. +        info->delta_msr_wait = 0;
  28674. +        info->icount.cts = info->icount.dsr =
  28675. +            info->icount.rng = info->icount.dcd = 0;
  28676. +        info->next_port = 0;
  28677. +        info->prev_port = 0;
  28678. +#if 0
  28679. +        if (info->irq == 2)
  28680. +            info->irq = 9;
  28681. +#endif
  28682. +        if (info->type == PORT_UNKNOWN) {
  28683. +            if (!(info->flags & ASYNC_BOOT_AUTOCONF))
  28684. +                continue;
  28685. +            autoconfig(info);
  28686. +            if (info->type == PORT_UNKNOWN)
  28687. +                continue;
  28688. +        }
  28689. +        printk(KERN_INFO "tty%02d%s at 0x%04x (irq = %d)", info->line, 
  28690. +               (info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
  28691. +               info->port, info->irq);
  28692. +        switch (info->type) {
  28693. +            case PORT_8250:
  28694. +                printk(" is a 8250\n");
  28695. +                break;
  28696. +            case PORT_16450:
  28697. +                printk(" is a 16450\n");
  28698. +                break;
  28699. +            case PORT_16550:
  28700. +                printk(" is a 16550\n");
  28701. +                break;
  28702. +            case PORT_16550A:
  28703. +                printk(" is a 16550A\n");
  28704. +                break;
  28705. +            case PORT_16650:
  28706. +                printk(" is a 16650\n");
  28707. +                break;
  28708. +            default:
  28709. +                printk("\n");
  28710. +                break;
  28711. +        }
  28712. +    }
  28713. +    register_symtab(&serial_syms);
  28714. +    return 0;
  28715. +}
  28716. +
  28717. +int register_pre_init_serial (struct serial_struct *req)
  28718. +{
  28719. +    int i;
  28720. +    struct async_struct *info;
  28721. +
  28722. +    for (i = 0; i < NR_PORTS; i++) {
  28723. +        if (rs_table[i].port == req->port)
  28724. +            break;
  28725. +    }
  28726. +
  28727. +    if (i == NR_PORTS) {
  28728. +        for (i = 0; i < NR_PORTS; i++)
  28729. +            if (!rs_table[i].port)
  28730. +                break;
  28731. +    }
  28732. +    if (i == NR_PORTS)
  28733. +        return -1;
  28734. +
  28735. +    info = &rs_table[i];
  28736. +    if (info->count) {
  28737. +        printk ("Couldn't configure serial #%d (port=%d, irq=%d): "
  28738. +            "device already open\n", i, req->port, req->irq);
  28739. +        return -1;
  28740. +    }
  28741. +    info->irq = req->irq;
  28742. +    info->port = req->port;
  28743. +    info->baud_base = req->baud_base;
  28744. +    serial_outp (info, UART_IER, 0);
  28745. +    return 0;
  28746. +}
  28747. +
  28748. +/*
  28749. + * register_serial and unregister_serial allows for serial ports to be
  28750. + * configured at run-time, to support PCMCIA modems.
  28751. + */
  28752. +int register_serial(struct serial_struct *req)
  28753. +{
  28754. +    int i;
  28755. +    unsigned long flags;
  28756. +    struct async_struct *info;
  28757. +
  28758. +    save_flags_cli (flags);
  28759. +    for (i = 0; i < NR_PORTS; i++) {
  28760. +        if (rs_table[i].port == req->port)
  28761. +            break;
  28762. +    }
  28763. +    if (i == NR_PORTS) {
  28764. +        for (i = 0; i < NR_PORTS; i++)
  28765. +            if ((rs_table[i].type == PORT_UNKNOWN) &&
  28766. +                (rs_table[i].count == 0))
  28767. +                break;
  28768. +    }
  28769. +    if (i == NR_PORTS) {
  28770. +        restore_flags(flags);
  28771. +        return -1;
  28772. +    }
  28773. +    info = &rs_table[i];
  28774. +    if (rs_table[i].count) {
  28775. +        restore_flags(flags);
  28776. +        printk("Couldn't configure serial #%d (port=%d,irq=%d): "
  28777. +               "device already open\n", i, req->port, req->irq);
  28778. +        return -1;
  28779. +    }
  28780. +    info->irq = req->irq;
  28781. +    info->port = req->port;
  28782. +    if (req->baud_base)    /* rmk: need this to set the baud rate... */
  28783. +        info->baud_base = req->baud_base;
  28784. +    serial_outp(info, UART_IER, 0); /* rmk: need to make sure port is disabled */
  28785. +    info->flags = req->flags;
  28786. +    autoconfig(info);
  28787. +    if (info->type == PORT_UNKNOWN) {
  28788. +        restore_flags(flags);
  28789. +        printk("register_serial(): autoconfig failed\n");
  28790. +        return -1;
  28791. +    }
  28792. +    printk(KERN_INFO "tty%02d at 0x%04x (irq = %d)", info->line, 
  28793. +           info->port, info->irq);
  28794. +    switch (info->type) {
  28795. +    case PORT_8250:
  28796. +        printk(" is a 8250\n"); break;
  28797. +    case PORT_16450:
  28798. +        printk(" is a 16450\n"); break;
  28799. +    case PORT_16550:
  28800. +        printk(" is a 16550\n"); break;
  28801. +    case PORT_16550A:
  28802. +        printk(" is a 16550A\n"); break;
  28803. +    default:
  28804. +        printk("\n"); break;
  28805. +    }
  28806. +    restore_flags(flags);
  28807. +    register_symtab(&serial_syms);
  28808. +    return info->line;
  28809. +}
  28810. +
  28811. +void unregister_serial(int line)
  28812. +{
  28813. +    unsigned long flags;
  28814. +    struct async_struct *info = &rs_table[line];
  28815. +
  28816. +    save_flags_cli (flags);
  28817. +    if (info->tty)
  28818. +        tty_hangup(info->tty);
  28819. +    info->type = PORT_UNKNOWN;
  28820. +    release_region(info->port,8);
  28821. +    printk(KERN_INFO "tty%02d unloaded\n", info->line);
  28822. +    restore_flags(flags);
  28823. +}
  28824. +
  28825. +#ifdef MODULE
  28826. +int init_module(void)
  28827. +{
  28828. +    return rs_init();
  28829. +}
  28830. +
  28831. +void cleanup_module(void)
  28832. +{
  28833. +    unsigned long flags;
  28834. +    int e1, e2;
  28835. +    int i;
  28836. +
  28837. +    /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
  28838. +    save_flags(flags);
  28839. +    cli();
  28840. +    timer_active &= ~(1 << RS_TIMER);
  28841. +    timer_table[RS_TIMER].fn = NULL;
  28842. +    timer_table[RS_TIMER].expires = 0;
  28843. +    if ((e1 = tty_unregister_driver(&serial_driver)))
  28844. +        printk("SERIAL: failed to unregister serial driver (%d)\n",
  28845. +               e1);
  28846. +    if ((e2 = tty_unregister_driver(&callout_driver)))
  28847. +        printk("SERIAL: failed to unregister callout driver (%d)\n",
  28848. +               e2);
  28849. +    restore_flags(flags);
  28850. +
  28851. +    for (i = 0; i < NR_PORTS; i++) {
  28852. +        if (rs_table[i].type != PORT_UNKNOWN)
  28853. +            release_region(rs_table[i].port, 8);
  28854. +    }
  28855. +}
  28856. +#endif /* MODULE */
  28857. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/serial6850.c linux/arch/arm/drivers/char/serial6850.c
  28858. --- linux.orig/arch/arm/drivers/char/serial6850.c    Thu Jan  1 01:00:00 1970
  28859. +++ linux/arch/arm/drivers/char/serial6850.c    Mon Mar 11 21:32:33 1996
  28860. @@ -0,0 +1,23 @@
  28861. +/*
  28862. + * Dummy serial functions
  28863. + *
  28864. + * Copyright (C) 1995, 1996 Russell King
  28865. + */
  28866. +
  28867. +#include <linux/errno.h>
  28868. +#include <linux/sched.h>
  28869. +#include <linux/serial.h>
  28870. +
  28871. +int rs_init (void)
  28872. +{
  28873. +    return 0;
  28874. +}
  28875. +
  28876. +int register_serial (struct serial_struct *dev)
  28877. +{
  28878. +    return -1;
  28879. +}
  28880. +
  28881. +void unregister_serial (int line)
  28882. +{
  28883. +}
  28884. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/tty_io.c linux/arch/arm/drivers/char/tty_io.c
  28885. --- linux.orig/arch/arm/drivers/char/tty_io.c    Thu Jan  1 01:00:00 1970
  28886. +++ linux/arch/arm/drivers/char/tty_io.c    Fri Sep  6 21:20:42 1996
  28887. @@ -0,0 +1,1723 @@
  28888. +/*
  28889. + *  linux/arch/arm/drivers/char/tty_io.c
  28890. + *
  28891. + *  Copyright (C) 1991, 1992  Linus Torvalds
  28892. + *
  28893. + *  Modifications for ARM processor Copright (C) 1995, 1996 Russell King.
  28894. + */
  28895. +
  28896. +/*
  28897. + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
  28898. + * or rs-channels. It also implements echoing, cooked mode etc.
  28899. + *
  28900. + * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
  28901. + *
  28902. + * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
  28903. + * tty_struct and tty_queue structures.  Previously there was a array
  28904. + * of 256 tty_struct's which was statically allocated, and the
  28905. + * tty_queue structures were allocated at boot time.  Both are now
  28906. + * dynamically allocated only when the tty is open.
  28907. + *
  28908. + * Also restructured routines so that there is more of a separation
  28909. + * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
  28910. + * the low-level tty routines (serial.c, pty.c, console.c).  This
  28911. + * makes for cleaner and more compact code.  -TYT, 9/17/92 
  28912. + *
  28913. + * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
  28914. + * which can be dynamically activated and de-activated by the line
  28915. + * discipline handling modules (like SLIP).
  28916. + *
  28917. + * NOTE: pay no attention to the line discipline code (yet); its
  28918. + * interface is still subject to change in this version...
  28919. + * -- TYT, 1/31/92
  28920. + *
  28921. + * Added functionality to the OPOST tty handling.  No delays, but all
  28922. + * other bits should be there.
  28923. + *    -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
  28924. + *
  28925. + * Rewrote canonical mode and added more termios flags.
  28926. + *     -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
  28927. + *
  28928. + * Reorganized FASYNC support so mouse code can share it.
  28929. + *    -- ctm@ardi.com, 9Sep95
  28930. + *
  28931. + * Altered get_free_page to kmalloc's for tty structures to save memory
  28932. + *  on the ARM processor
  28933. + *      -- rmk92@ecs.soton.ac.uk
  28934. + *
  28935. + * New TIOCLINUX variants added.
  28936. + *    -- mj@k332.feld.cvut.cz, 19-Nov-95
  28937. + */
  28938. +
  28939. +#include <linux/config.h>
  28940. +#include <linux/types.h>
  28941. +#include <linux/major.h>
  28942. +#include <linux/errno.h>
  28943. +#include <linux/signal.h>
  28944. +#include <linux/fcntl.h>
  28945. +#include <linux/sched.h>
  28946. +#include <linux/interrupt.h>
  28947. +#include <linux/tty.h>
  28948. +#include <linux/tty_flip.h>
  28949. +#include <linux/timer.h>
  28950. +#include <linux/ctype.h>
  28951. +#include <linux/kd.h>
  28952. +#include <linux/mm.h>
  28953. +#include <linux/string.h>
  28954. +#include <linux/malloc.h>
  28955. +
  28956. +#include <asm/segment.h>
  28957. +#include <asm/system.h>
  28958. +#include <asm/bitops.h>
  28959. +
  28960. +/*#include <linux/scc.h>*/
  28961. +
  28962. +#include "kbd_kern.h"
  28963. +#include "vt_kern.h"
  28964. +#include "selection.h"
  28965. +
  28966. +#ifdef CONFIG_KERNELD
  28967. +#include <linux/kerneld.h>
  28968. +#endif
  28969. +
  28970. +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
  28971. +#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
  28972. +
  28973. +#undef TTY_DEBUG_HANGUP
  28974. +
  28975. +#define TTY_PARANOIA_CHECK
  28976. +#define CHECK_TTY_COUNT
  28977. +
  28978. +/*extern void set_vesa_blanking(const unsigned long arg);*/
  28979. +
  28980. +struct termios tty_std_termios;        /* for the benefit of tty drivers  */
  28981. +struct tty_driver *tty_drivers;        /* linked list of tty drivers */
  28982. +struct tty_ldisc ldiscs[NR_LDISCS];    /* line disc dispatch table    */
  28983. +
  28984. +int kmsg_redirect;
  28985. +struct tty_struct * redirect;
  28986. +struct wait_queue * keypress_wait;
  28987. +
  28988. +static void initialize_tty_struct(struct tty_struct *tty);
  28989. +
  28990. +static int tty_read(struct inode *, struct file *, char *, int);
  28991. +static int tty_write(struct inode *, struct file *, const char *, int);
  28992. +static int tty_select(struct inode *, struct file *, int, select_table *);
  28993. +static int tty_open(struct inode *, struct file *);
  28994. +static void tty_release(struct inode *, struct file *);
  28995. +static int tty_ioctl(struct inode * inode, struct file * file,
  28996. +             unsigned int cmd, unsigned long arg);
  28997. +static int tty_fasync(struct inode * inode, struct file * filp, int on);
  28998. +
  28999. +#ifndef MIN
  29000. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  29001. +#endif
  29002. +
  29003. +/*
  29004. + * These two routines return the name of tty.  tty_name() should NOT
  29005. + * be used in interrupt drivers, since it's not re-entrant.  Use
  29006. + * _tty_name() instead.
  29007. + */
  29008. +char *_tty_name(struct tty_struct *tty, char *buf)
  29009. +{
  29010. +    if (tty)
  29011. +        sprintf(buf, "%s%d", tty->driver.name,
  29012. +            MINOR(tty->device) - tty->driver.minor_start +
  29013. +            tty->driver.name_base);
  29014. +    else
  29015. +        strcpy(buf, "NULL tty");
  29016. +    return buf;
  29017. +}
  29018. +
  29019. +char *tty_name(struct tty_struct *tty)
  29020. +{
  29021. +    static char buf[64];
  29022. +
  29023. +    return(_tty_name(tty, buf));
  29024. +}
  29025. +
  29026. +inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
  29027. +                  const char *routine)
  29028. +{
  29029. +#ifdef TTY_PARANOIA_CHECK
  29030. +    static const char *badmagic =
  29031. +        "Warning: bad magic number for tty struct (%s) in %s\n";
  29032. +    static const char *badtty =
  29033. +        "Warning: null TTY for (%s) in %s\n";
  29034. +
  29035. +    if (!tty) {
  29036. +        printk(badtty, kdevname(device), routine);
  29037. +        return 1;
  29038. +    }
  29039. +    if (tty->magic != TTY_MAGIC) {
  29040. +        printk(badmagic, kdevname(device), routine);
  29041. +        return 1;
  29042. +    }
  29043. +#endif
  29044. +    return 0;
  29045. +}
  29046. +
  29047. +static int check_tty_count(struct tty_struct *tty, const char *routine)
  29048. +{
  29049. +#ifdef CHECK_TTY_COUNT
  29050. +    struct file *f;
  29051. +    int i, count = 0;
  29052. +    
  29053. +    for (f = first_file, i=0; i<nr_files; i++, f = f->f_next) {
  29054. +        if (!f->f_count)
  29055. +            continue;
  29056. +        if (f->private_data == tty) {
  29057. +            count++;
  29058. +        }
  29059. +    }
  29060. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  29061. +        tty->driver.subtype == PTY_TYPE_SLAVE &&
  29062. +        tty->link && tty->link->count)
  29063. +        count++;
  29064. +    if (tty->count != count) {
  29065. +        printk("Warning: dev (%s) tty->count(%d) != #fd's(%d) in %s\n",
  29066. +               kdevname(tty->device), tty->count, count, routine);
  29067. +        return count;
  29068. +       }    
  29069. +#endif
  29070. +    return 0;
  29071. +}
  29072. +
  29073. +int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
  29074. +{
  29075. +    if (disc < N_TTY || disc >= NR_LDISCS)
  29076. +        return -EINVAL;
  29077. +    
  29078. +    if (new_ldisc) {
  29079. +        ldiscs[disc] = *new_ldisc;
  29080. +        ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
  29081. +        ldiscs[disc].num = disc;
  29082. +    } else
  29083. +        memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
  29084. +    
  29085. +    return 0;
  29086. +}
  29087. +
  29088. +/* Set the discipline of a tty line. */
  29089. +static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
  29090. +{
  29091. +    int    retval = 0;
  29092. +    struct    tty_ldisc o_ldisc;
  29093. +
  29094. +    if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
  29095. +        return -EINVAL;
  29096. +#ifdef CONFIG_KERNELD
  29097. +    /* Eduardo Blanco <ejbs@cs.cs.com.uy> */
  29098. +    if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) {
  29099. +        char modname [20];
  29100. +        sprintf(modname, "tty-ldisc-%d", ldisc);
  29101. +        request_module (modname);
  29102. +    }
  29103. +#endif
  29104. +    if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
  29105. +        return -EINVAL;
  29106. +
  29107. +    if (tty->ldisc.num == ldisc)
  29108. +        return 0;    /* We are already in the desired discipline */
  29109. +    o_ldisc = tty->ldisc;
  29110. +
  29111. +    tty_wait_until_sent(tty, 0);
  29112. +    
  29113. +    /* Shutdown the current discipline. */
  29114. +    if (tty->ldisc.close)
  29115. +        (tty->ldisc.close)(tty);
  29116. +
  29117. +    /* Now set up the new line discipline. */
  29118. +    tty->ldisc = ldiscs[ldisc];
  29119. +    tty->termios->c_line = ldisc;
  29120. +    if (tty->ldisc.open)
  29121. +        retval = (tty->ldisc.open)(tty);
  29122. +    if (retval < 0) {
  29123. +        tty->ldisc = o_ldisc;
  29124. +        tty->termios->c_line = tty->ldisc.num;
  29125. +        if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
  29126. +            tty->ldisc = ldiscs[N_TTY];
  29127. +            tty->termios->c_line = N_TTY;
  29128. +            if (tty->ldisc.open) {
  29129. +                int r = tty->ldisc.open(tty);
  29130. +
  29131. +                if (r < 0)
  29132. +                    panic("Couldn't open N_TTY ldisc for "
  29133. +                          "%s --- error %d.",
  29134. +                          tty_name(tty), r);
  29135. +            }
  29136. +        }
  29137. +    }
  29138. +    if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc)
  29139. +        tty->driver.set_ldisc(tty);
  29140. +    return retval;
  29141. +}
  29142. +
  29143. +/*
  29144. + * This routine returns a tty driver structure, given a device number
  29145. + */
  29146. +struct tty_driver *get_tty_driver(kdev_t device)
  29147. +{
  29148. +    int    major, minor;
  29149. +    struct tty_driver *p;
  29150. +    
  29151. +    minor = MINOR(device);
  29152. +    major = MAJOR(device);
  29153. +
  29154. +    for (p = tty_drivers; p; p = p->next) {
  29155. +        if (p->major != major)
  29156. +            continue;
  29157. +        if (minor < p->minor_start)
  29158. +            continue;
  29159. +        if (minor >= p->minor_start + p->num)
  29160. +            continue;
  29161. +        return p;
  29162. +    }
  29163. +    return NULL;
  29164. +}
  29165. +
  29166. +/*
  29167. + * If we try to write to, or set the state of, a terminal and we're
  29168. + * not in the foreground, send a SIGTTOU.  If the signal is blocked or
  29169. + * ignored, go ahead and perform the operation.  (POSIX 7.2)
  29170. + */
  29171. +int tty_check_change(struct tty_struct * tty)
  29172. +{
  29173. +    if (current->tty != tty)
  29174. +        return 0;
  29175. +    if (tty->pgrp <= 0) {
  29176. +        printk("tty_check_change: tty->pgrp <= 0!\n");
  29177. +        return 0;
  29178. +    }
  29179. +    if (current->pgrp == tty->pgrp)
  29180. +        return 0;
  29181. +    if (is_ignored(SIGTTOU))
  29182. +        return 0;
  29183. +    if (is_orphaned_pgrp(current->pgrp))
  29184. +        return -EIO;
  29185. +    (void) kill_pg(current->pgrp,SIGTTOU,1);
  29186. +    return -ERESTARTSYS;
  29187. +}
  29188. +
  29189. +static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count)
  29190. +{
  29191. +    return 0;
  29192. +}
  29193. +
  29194. +static int hung_up_tty_write(struct inode * inode, struct file * file, const char * buf, int count)
  29195. +{
  29196. +    return -EIO;
  29197. +}
  29198. +
  29199. +static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
  29200. +{
  29201. +    return 1;
  29202. +}
  29203. +
  29204. +static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
  29205. +                 unsigned int cmd, unsigned long arg)
  29206. +{
  29207. +    return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
  29208. +}
  29209. +
  29210. +static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  29211. +{
  29212. +    return -ESPIPE;
  29213. +}
  29214. +
  29215. +static struct file_operations tty_fops = {
  29216. +    tty_lseek,
  29217. +    tty_read,
  29218. +    tty_write,
  29219. +    NULL,        /* tty_readdir */
  29220. +    tty_select,
  29221. +    tty_ioctl,
  29222. +    NULL,        /* tty_mmap */
  29223. +    tty_open,
  29224. +    tty_release,
  29225. +    NULL,        /* tty_fsync */
  29226. +    tty_fasync
  29227. +};
  29228. +
  29229. +static struct file_operations hung_up_tty_fops = {
  29230. +    tty_lseek,
  29231. +    hung_up_tty_read,
  29232. +    hung_up_tty_write,
  29233. +    NULL,        /* hung_up_tty_readdir */
  29234. +    hung_up_tty_select,
  29235. +    hung_up_tty_ioctl,
  29236. +    NULL,        /* hung_up_tty_mmap */
  29237. +    NULL,        /* hung_up_tty_open */
  29238. +    tty_release,    /* hung_up_tty_release */
  29239. +    NULL,        /* hung_up_tty_fsync  */
  29240. +    NULL        /* hung_up_tty_fasync */
  29241. +};
  29242. +
  29243. +void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
  29244. +{
  29245. +    int i;
  29246. +    struct file * filp;
  29247. +    struct task_struct *p;
  29248. +
  29249. +    if (!tty)
  29250. +        return;
  29251. +    check_tty_count(tty, "do_tty_hangup");
  29252. +    for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) {
  29253. +        if (!filp->f_count)
  29254. +            continue;
  29255. +        if (filp->private_data != tty)
  29256. +            continue;
  29257. +        if (!filp->f_inode)
  29258. +            continue;
  29259. +        if (filp->f_inode->i_rdev == CONSOLE_DEV)
  29260. +            continue;
  29261. +        if (filp->f_op != &tty_fops)
  29262. +            continue;
  29263. +        tty_fasync(filp->f_inode, filp, 0);
  29264. +        filp->f_op = fops;
  29265. +    }
  29266. +    
  29267. +    if (tty->ldisc.flush_buffer)
  29268. +        tty->ldisc.flush_buffer(tty);
  29269. +    if (tty->driver.flush_buffer)
  29270. +        tty->driver.flush_buffer(tty);
  29271. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  29272. +        tty->ldisc.write_wakeup)
  29273. +        (tty->ldisc.write_wakeup)(tty);
  29274. +    wake_up_interruptible(&tty->write_wait);
  29275. +    wake_up_interruptible(&tty->read_wait);
  29276. +
  29277. +    /*
  29278. +     * Shutdown the current line discipline, and reset it to
  29279. +     * N_TTY.
  29280. +     */
  29281. +    if (tty->ldisc.num != ldiscs[N_TTY].num) {
  29282. +        if (tty->ldisc.close)
  29283. +            (tty->ldisc.close)(tty);
  29284. +        tty->ldisc = ldiscs[N_TTY];
  29285. +        tty->termios->c_line = N_TTY;
  29286. +        if (tty->ldisc.open) {
  29287. +            i = (tty->ldisc.open)(tty);
  29288. +            if (i < 0)
  29289. +                printk("do_tty_hangup: N_TTY open: error %d\n",
  29290. +                       -i);
  29291. +        }
  29292. +    }
  29293. +    
  29294. +     for_each_task(p) {
  29295. +        if ((tty->session > 0) && (p->session == tty->session) &&
  29296. +            p->leader) {
  29297. +            send_sig(SIGHUP,p,1);
  29298. +            send_sig(SIGCONT,p,1);
  29299. +            if (tty->pgrp > 0)
  29300. +                p->tty_old_pgrp = tty->pgrp;
  29301. +        }
  29302. +        if (p->tty == tty)
  29303. +            p->tty = NULL;
  29304. +    }
  29305. +    tty->flags = 0;
  29306. +    tty->session = 0;
  29307. +    tty->pgrp = -1;
  29308. +    tty->ctrl_status = 0;
  29309. +    if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
  29310. +        *tty->termios = tty->driver.init_termios;
  29311. +    if (tty->driver.hangup)
  29312. +        (tty->driver.hangup)(tty);
  29313. +}
  29314. +
  29315. +void tty_hangup(struct tty_struct * tty)
  29316. +{
  29317. +#ifdef TTY_DEBUG_HANGUP
  29318. +    printk("%s hangup...\n", tty_name(tty));
  29319. +#endif
  29320. +    do_tty_hangup(tty, &hung_up_tty_fops);
  29321. +}
  29322. +
  29323. +void tty_vhangup(struct tty_struct * tty)
  29324. +{
  29325. +#ifdef TTY_DEBUG_HANGUP
  29326. +    printk("%s vhangup...\n", tty_name(tty));
  29327. +#endif
  29328. +    do_tty_hangup(tty, &hung_up_tty_fops);
  29329. +}
  29330. +
  29331. +int tty_hung_up_p(struct file * filp)
  29332. +{
  29333. +    return (filp->f_op == &hung_up_tty_fops);
  29334. +}
  29335. +
  29336. +/*
  29337. + * This function is typically called only by the session leader, when
  29338. + * it wants to disassociate itself from its controlling tty.
  29339. + *
  29340. + * It performs the following functions:
  29341. + *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
  29342. + *     (2)  Clears the tty from being controlling the session
  29343. + *     (3)  Clears the controlling tty for all processes in the
  29344. + *         session group.
  29345. + *
  29346. + * The argument on_exit is set to 1 if called when a process is
  29347. + * exiting; it is 0 if called by the ioctl TIOCNOTTY.
  29348. + */
  29349. +void disassociate_ctty(int on_exit)
  29350. +{
  29351. +    struct tty_struct *tty = current->tty;
  29352. +    struct task_struct *p;
  29353. +    int tty_pgrp = -1;
  29354. +
  29355. +    if (tty) {
  29356. +        tty_pgrp = tty->pgrp;
  29357. +        if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY)
  29358. +            tty_vhangup(tty);
  29359. +    } else {
  29360. +        if (current->tty_old_pgrp) {
  29361. +            kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);
  29362. +            kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);
  29363. +        }
  29364. +        return;
  29365. +    }
  29366. +    if (tty_pgrp > 0) {
  29367. +        kill_pg(tty_pgrp, SIGHUP, on_exit);
  29368. +        if (!on_exit)
  29369. +            kill_pg(tty_pgrp, SIGCONT, on_exit);
  29370. +    }
  29371. +
  29372. +    current->tty_old_pgrp = 0;
  29373. +    tty->session = 0;
  29374. +    tty->pgrp = -1;
  29375. +
  29376. +    for_each_task(p)
  29377. +          if (p->session == current->session)
  29378. +            p->tty = NULL;
  29379. +}
  29380. +
  29381. +void wait_for_keypress(void)
  29382. +{
  29383. +    sleep_on(&keypress_wait);
  29384. +}
  29385. +
  29386. +void stop_tty(struct tty_struct *tty)
  29387. +{
  29388. +    if (tty->stopped)
  29389. +        return;
  29390. +    tty->stopped = 1;
  29391. +    if (tty->link && tty->link->packet) {
  29392. +        tty->ctrl_status &= ~TIOCPKT_START;
  29393. +        tty->ctrl_status |= TIOCPKT_STOP;
  29394. +        wake_up_interruptible(&tty->link->read_wait);
  29395. +    }
  29396. +    if (tty->driver.stop)
  29397. +        (tty->driver.stop)(tty);
  29398. +}
  29399. +
  29400. +void start_tty(struct tty_struct *tty)
  29401. +{
  29402. +    if (!tty->stopped)
  29403. +        return;
  29404. +    tty->stopped = 0;
  29405. +    if (tty->link && tty->link->packet) {
  29406. +        tty->ctrl_status &= ~TIOCPKT_STOP;
  29407. +        tty->ctrl_status |= TIOCPKT_START;
  29408. +        wake_up_interruptible(&tty->link->read_wait);
  29409. +    }
  29410. +    if (tty->driver.start)
  29411. +        (tty->driver.start)(tty);
  29412. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  29413. +        tty->ldisc.write_wakeup)
  29414. +        (tty->ldisc.write_wakeup)(tty);
  29415. +    wake_up_interruptible(&tty->write_wait);
  29416. +}
  29417. +
  29418. +static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
  29419. +{
  29420. +    int i;
  29421. +    struct tty_struct * tty;
  29422. +
  29423. +    tty = (struct tty_struct *)file->private_data;
  29424. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_read"))
  29425. +        return -EIO;
  29426. +    if (!tty || (tty->flags & (1 << TTY_IO_ERROR)))
  29427. +        return -EIO;
  29428. +
  29429. +    /* This check not only needs to be done before reading, but also
  29430. +       whenever read_chan() gets woken up after sleeping, so I've
  29431. +       moved it to there.  This should only be done for the N_TTY
  29432. +       line discipline, anyway.  Same goes for write_chan(). -- jlc. */
  29433. +#if 0
  29434. +    if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
  29435. +        (tty->pgrp > 0) &&
  29436. +        (current->tty == tty) &&
  29437. +        (tty->pgrp != current->pgrp))
  29438. +        if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
  29439. +            return -EIO;
  29440. +        else {
  29441. +            (void) kill_pg(current->pgrp, SIGTTIN, 1);
  29442. +            return -ERESTARTSYS;
  29443. +        }
  29444. +#endif
  29445. +    if (tty->ldisc.read)
  29446. +        /* XXX casts are for what kernel-wide prototypes should be. */
  29447. +        i = (tty->ldisc.read)(tty,file,(unsigned char *)buf,(unsigned int)count);
  29448. +    else
  29449. +        i = -EIO;
  29450. +    if (i > 0)
  29451. +        inode->i_atime = CURRENT_TIME;
  29452. +    return i;
  29453. +}
  29454. +
  29455. +/*
  29456. + * Split writes up in sane blocksizes to avoid
  29457. + * denial-of-service type attacks
  29458. + */
  29459. +static inline int do_tty_write(
  29460. +    int (*write)(struct tty_struct *, struct file *, const unsigned char *, unsigned int),
  29461. +    struct inode *inode,
  29462. +    struct tty_struct *tty,
  29463. +    struct file *file,
  29464. +    const unsigned char *buf,
  29465. +    unsigned int count)
  29466. +{
  29467. +    int ret = 0, written = 0;
  29468. +
  29469. +    for (;;) {
  29470. +        unsigned int size = PAGE_SIZE*2;
  29471. +        if (size > count)
  29472. +            size = count;
  29473. +        ret = write(tty, file, buf, size);
  29474. +        if (ret <= 0)
  29475. +            break;
  29476. +        count -= ret;
  29477. +        written += ret;
  29478. +        if (!count)
  29479. +            break;
  29480. +        ret = -ERESTARTSYS;
  29481. +        if (current->signal & ~current->blocked)
  29482. +            break;
  29483. +        if (need_resched)
  29484. +            schedule();
  29485. +    }
  29486. +    if (written) {
  29487. +        inode->i_mtime = CURRENT_TIME;
  29488. +        ret = written;
  29489. +    }
  29490. +    return ret;
  29491. +}
  29492. +
  29493. +
  29494. +static int tty_write(struct inode * inode, struct file * file, const char * buf, int count)
  29495. +{
  29496. +    int is_console;
  29497. +    struct tty_struct * tty;
  29498. +
  29499. +    is_console = (inode->i_rdev == CONSOLE_DEV);
  29500. +
  29501. +    if (is_console && redirect)
  29502. +        tty = redirect;
  29503. +    else
  29504. +        tty = (struct tty_struct *)file->private_data;
  29505. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_write"))
  29506. +        return -EIO;
  29507. +    if (!tty || !tty->driver.write || (tty->flags & (1 << TTY_IO_ERROR)))
  29508. +        return -EIO;
  29509. +#if 0
  29510. +    if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
  29511. +        (current->tty == tty) && (tty->pgrp != current->pgrp)) {
  29512. +        if (is_orphaned_pgrp(current->pgrp))
  29513. +            return -EIO;
  29514. +        if (!is_ignored(SIGTTOU)) {
  29515. +            (void) kill_pg(current->pgrp, SIGTTOU, 1);
  29516. +            return -ERESTARTSYS;
  29517. +        }
  29518. +    }
  29519. +#endif
  29520. +    if (!tty->ldisc.write)
  29521. +        return -EIO;
  29522. +    return do_tty_write(tty->ldisc.write,
  29523. +        inode, tty, file,
  29524. +        (const unsigned char *)buf,
  29525. +        (unsigned int)count);
  29526. +}
  29527. +
  29528. +/*
  29529. + * This is so ripe with races that you should *really* not touch this
  29530. + * unless you know exactly what you are doing. All the changes have to be
  29531. + * made atomically, or there may be incorrect pointers all over the place.
  29532. + */
  29533. +static int init_dev(kdev_t device, struct tty_struct **ret_tty)
  29534. +{
  29535. +    struct tty_struct *tty, **tty_loc, *o_tty, **o_tty_loc;
  29536. +    struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
  29537. +    struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
  29538. +    struct tty_driver *driver;    
  29539. +    int retval;
  29540. +    int idx;
  29541. +
  29542. +    driver = get_tty_driver(device);
  29543. +    if (!driver)
  29544. +        return -ENODEV;
  29545. +
  29546. +    idx = MINOR(device) - driver->minor_start;
  29547. +    tty = o_tty = NULL;
  29548. +    tp = o_tp = NULL;
  29549. +    ltp = o_ltp = NULL;
  29550. +    o_tty_loc = NULL;
  29551. +    o_tp_loc = o_ltp_loc = NULL;
  29552. +
  29553. +    tty_loc = &driver->table[idx];
  29554. +    tp_loc = &driver->termios[idx];
  29555. +    ltp_loc = &driver->termios_locked[idx];
  29556. +
  29557. +repeat:
  29558. +    retval = -EIO;
  29559. +    if (driver->type == TTY_DRIVER_TYPE_PTY &&
  29560. +        driver->subtype == PTY_TYPE_MASTER &&
  29561. +        *tty_loc && (*tty_loc)->count)
  29562. +        goto end_init;
  29563. +    retval = -ENOMEM;
  29564. +    if (!*tty_loc && !tty) {
  29565. +        if (!(tty = (struct tty_struct*) kmalloc(sizeof(struct tty_struct),GFP_KERNEL)))
  29566. +            goto end_init;
  29567. +        initialize_tty_struct(tty);
  29568. +        tty->device = device;
  29569. +        tty->driver = *driver;
  29570. +        goto repeat;
  29571. +    }
  29572. +    if (!*tp_loc && !tp) {
  29573. +        tp = (struct termios *) kmalloc(sizeof(struct termios),
  29574. +                        GFP_KERNEL);
  29575. +        if (!tp)
  29576. +            goto end_init;
  29577. +        *tp = driver->init_termios;
  29578. +        goto repeat;
  29579. +    }
  29580. +    if (!*ltp_loc && !ltp) {
  29581. +        ltp = (struct termios *) kmalloc(sizeof(struct termios),
  29582. +                         GFP_KERNEL);
  29583. +        if (!ltp)
  29584. +            goto end_init;
  29585. +        memset(ltp, 0, sizeof(struct termios));
  29586. +        goto repeat;
  29587. +    }
  29588. +    if (driver->type == TTY_DRIVER_TYPE_PTY) {
  29589. +        o_tty_loc = &driver->other->table[idx];
  29590. +        o_tp_loc = &driver->other->termios[idx];
  29591. +        o_ltp_loc = &driver->other->termios_locked[idx];
  29592. +
  29593. +        if (!*o_tty_loc && !o_tty) {
  29594. +            kdev_t     o_device;
  29595. +            
  29596. +            o_tty = (struct tty_struct *) kmalloc (sizeof(struct tty_struct),
  29597. +                GFP_KERNEL);
  29598. +            if (!o_tty)
  29599. +                goto end_init;
  29600. +            o_device = MKDEV(driver->other->major,
  29601. +                     driver->other->minor_start + idx);
  29602. +            initialize_tty_struct(o_tty);
  29603. +            o_tty->device = o_device;
  29604. +            o_tty->driver = *driver->other;
  29605. +            goto repeat;
  29606. +        }
  29607. +        if (!*o_tp_loc && !o_tp) {
  29608. +            o_tp = (struct termios *)
  29609. +                kmalloc(sizeof(struct termios), GFP_KERNEL);
  29610. +            if (!o_tp)
  29611. +                goto end_init;
  29612. +            *o_tp = driver->other->init_termios;
  29613. +            goto repeat;
  29614. +        }
  29615. +        if (!*o_ltp_loc && !o_ltp) {
  29616. +            o_ltp = (struct termios *)
  29617. +                kmalloc(sizeof(struct termios), GFP_KERNEL);
  29618. +            if (!o_ltp)
  29619. +                goto end_init;
  29620. +            memset(o_ltp, 0, sizeof(struct termios));
  29621. +            goto repeat;
  29622. +        }
  29623. +        
  29624. +    }
  29625. +    /* Now we have allocated all the structures: update all the pointers.. */
  29626. +    if (!*tp_loc) {
  29627. +        *tp_loc = tp;
  29628. +        tp = NULL;
  29629. +    }
  29630. +    if (!*ltp_loc) {
  29631. +        *ltp_loc = ltp;
  29632. +        ltp = NULL;
  29633. +    }
  29634. +    if (!*tty_loc) {
  29635. +        tty->termios = *tp_loc;
  29636. +        tty->termios_locked = *ltp_loc;
  29637. +        *tty_loc = tty;
  29638. +        (*driver->refcount)++;
  29639. +        (*tty_loc)->count++;
  29640. +        if (tty->ldisc.open) {
  29641. +            retval = (tty->ldisc.open)(tty);
  29642. +            if (retval < 0) {
  29643. +                (*tty_loc)->count--;
  29644. +                tty = NULL;
  29645. +                goto end_init;
  29646. +            }
  29647. +        }
  29648. +        tty = NULL;
  29649. +    } else {
  29650. +        if ((*tty_loc)->flags & (1 << TTY_CLOSING)) {
  29651. +            printk("Attempt to open closing tty %s.\n",
  29652. +                   tty_name(*tty_loc));
  29653. +            printk("Ack!!!!  This should never happen!!\n");
  29654. +            return -EINVAL;
  29655. +        }
  29656. +        (*tty_loc)->count++;
  29657. +    }
  29658. +    if (driver->type == TTY_DRIVER_TYPE_PTY) {
  29659. +        if (!*o_tp_loc) {
  29660. +            *o_tp_loc = o_tp;
  29661. +            o_tp = NULL;
  29662. +        }
  29663. +        if (!*o_ltp_loc) {
  29664. +            *o_ltp_loc = o_ltp;
  29665. +            o_ltp = NULL;
  29666. +        }
  29667. +        if (!*o_tty_loc) {
  29668. +            o_tty->termios = *o_tp_loc;
  29669. +            o_tty->termios_locked = *o_ltp_loc;
  29670. +            *o_tty_loc = o_tty;
  29671. +            (*driver->other->refcount)++;
  29672. +            if (o_tty->ldisc.open) {
  29673. +                retval = (o_tty->ldisc.open)(o_tty);
  29674. +                if (retval < 0) {
  29675. +                    (*tty_loc)->count--;
  29676. +                    o_tty = NULL;
  29677. +                    goto end_init;
  29678. +                }
  29679. +            }
  29680. +            o_tty = NULL;
  29681. +        }
  29682. +        (*tty_loc)->link = *o_tty_loc;
  29683. +        (*o_tty_loc)->link = *tty_loc;
  29684. +        if (driver->subtype == PTY_TYPE_MASTER)
  29685. +            (*o_tty_loc)->count++;
  29686. +    }
  29687. +    (*tty_loc)->driver = *driver;
  29688. +    *ret_tty = *tty_loc;
  29689. +    retval = 0;
  29690. +end_init:
  29691. +    if (tty)
  29692. +        kfree_s(tty, sizeof(struct tty_struct));
  29693. +    if (o_tty)
  29694. +        kfree_s(o_tty, sizeof(struct tty_struct));
  29695. +    if (tp)
  29696. +        kfree_s(tp, sizeof(struct termios));
  29697. +    if (o_tp)
  29698. +        kfree_s(o_tp, sizeof(struct termios));
  29699. +    if (ltp)
  29700. +        kfree_s(ltp, sizeof(struct termios));
  29701. +    if (o_ltp)
  29702. +        kfree_s(o_ltp, sizeof(struct termios));
  29703. +    return retval;
  29704. +}
  29705. +
  29706. +/*
  29707. + * Even releasing the tty structures is a tricky business.. We have
  29708. + * to be very careful that the structures are all released at the
  29709. + * same time, as interrupts might otherwise get the wrong pointers.
  29710. + */
  29711. +static void release_dev(struct file * filp)
  29712. +{
  29713. +    struct tty_struct *tty, *o_tty;
  29714. +    struct termios *tp, *o_tp, *ltp, *o_ltp;
  29715. +    struct task_struct **p;
  29716. +    int    idx;
  29717. +    
  29718. +    tty = (struct tty_struct *)filp->private_data;
  29719. +    if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "release_dev"))
  29720. +        return;
  29721. +
  29722. +    check_tty_count(tty, "release_dev");
  29723. +
  29724. +    tty_fasync(filp->f_inode, filp, 0);
  29725. +
  29726. +    tp = tty->termios;
  29727. +    ltp = tty->termios_locked;
  29728. +
  29729. +    idx = MINOR(tty->device) - tty->driver.minor_start;
  29730. +#ifdef TTY_PARANOIA_CHECK
  29731. +    if (idx < 0 || idx >= tty->driver.num) {
  29732. +        printk("release_dev: bad idx when trying to free (%s)\n",
  29733. +               kdevname(tty->device));
  29734. +        return;
  29735. +    }
  29736. +    if (tty != tty->driver.table[idx]) {
  29737. +        printk("release_dev: driver.table[%d] not tty for (%s)\n",
  29738. +               idx, kdevname(tty->device));
  29739. +        return;
  29740. +    }
  29741. +    if (tp != tty->driver.termios[idx]) {
  29742. +        printk("release_dev: driver.termios[%d] not termios for ("
  29743. +               "%s)\n",
  29744. +               idx, kdevname(tty->device));
  29745. +        return;
  29746. +    }
  29747. +    if (ltp != tty->driver.termios_locked[idx]) {
  29748. +        printk("release_dev: driver.termios_locked[%d] not termios_locked for ("
  29749. +               "%s)\n",
  29750. +               idx, kdevname(tty->device));
  29751. +        return;
  29752. +    }
  29753. +#endif
  29754. +
  29755. +#ifdef TTY_DEBUG_HANGUP
  29756. +    printk("release_dev of %s (tty count=%d)...", tty_name(tty),
  29757. +           tty->count);
  29758. +#endif
  29759. +
  29760. +    o_tty = tty->link;
  29761. +    o_tp = (o_tty) ? o_tty->termios : NULL;
  29762. +    o_ltp = (o_tty) ? o_tty->termios_locked : NULL;
  29763. +
  29764. +#ifdef TTY_PARANOIA_CHECK
  29765. +    if (tty->driver.other) {
  29766. +        if (o_tty != tty->driver.other->table[idx]) {
  29767. +            printk("release_dev: other->table[%d] not o_tty for ("
  29768. +                   "%s)\n",
  29769. +                   idx, kdevname(tty->device));
  29770. +            return;
  29771. +        }
  29772. +        if (o_tp != tty->driver.other->termios[idx]) {
  29773. +            printk("release_dev: other->termios[%d] not o_termios for ("
  29774. +                   "%s)\n",
  29775. +                   idx, kdevname(tty->device));
  29776. +            return;
  29777. +        }
  29778. +        if (o_ltp != tty->driver.other->termios_locked[idx]) {
  29779. +            printk("release_dev: other->termios_locked[%d] not o_termios_locked for ("
  29780. +                   "%s)\n",
  29781. +                   idx, kdevname(tty->device));
  29782. +            return;
  29783. +        }
  29784. +
  29785. +        if (o_tty->link != tty) {
  29786. +            printk("release_dev: bad pty pointers\n");
  29787. +            return;
  29788. +        }
  29789. +    }
  29790. +#endif
  29791. +    
  29792. +    if (tty->driver.close)
  29793. +        tty->driver.close(tty, filp);
  29794. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  29795. +        tty->driver.subtype == PTY_TYPE_MASTER) {
  29796. +        if (--tty->link->count < 0) {
  29797. +            printk("release_dev: bad pty slave count (%d) for %s\n",
  29798. +                   tty->count, tty_name(tty));
  29799. +            tty->link->count = 0;
  29800. +        }
  29801. +    }
  29802. +    if (--tty->count < 0) {
  29803. +        printk("release_dev: bad tty->count (%d) for %s\n",
  29804. +               tty->count, tty_name(tty));
  29805. +        tty->count = 0;
  29806. +    }
  29807. +    if (tty->count)
  29808. +        return;
  29809. +
  29810. +    /*
  29811. +     * We're committed; at this point, we must not block!
  29812. +     */
  29813. +    if (o_tty) {
  29814. +        if (o_tty->count)
  29815. +            return;
  29816. +        tty->driver.other->table[idx] = NULL;
  29817. +        tty->driver.other->termios[idx] = NULL;
  29818. +        kfree_s(o_tp, sizeof(struct termios));
  29819. +    }
  29820. +    
  29821. +#ifdef TTY_DEBUG_HANGUP
  29822. +    printk("freeing tty structure...");
  29823. +#endif
  29824. +    tty->flags |= (1 << TTY_CLOSING);
  29825. +
  29826. +    /*
  29827. +     * Make sure there aren't any processes that still think this
  29828. +     * tty is their controlling tty.
  29829. +     */
  29830. +    for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  29831. +        if (*p == 0)
  29832. +            continue;
  29833. +        if ((*p)->tty == tty)
  29834. +            (*p)->tty = NULL;
  29835. +        if (o_tty && (*p)->tty == o_tty)
  29836. +            (*p)->tty = NULL;
  29837. +    }
  29838. +
  29839. +    /*
  29840. +     * Shutdown the current line discipline, and reset it to
  29841. +     * N_TTY.
  29842. +     */
  29843. +    if (tty->ldisc.close)
  29844. +        (tty->ldisc.close)(tty);
  29845. +    tty->ldisc = ldiscs[N_TTY];
  29846. +    tty->termios->c_line = N_TTY;
  29847. +    if (o_tty) {
  29848. +        if (o_tty->ldisc.close)
  29849. +            (o_tty->ldisc.close)(o_tty);
  29850. +        o_tty->ldisc = ldiscs[N_TTY];
  29851. +    }
  29852. +    
  29853. +    tty->driver.table[idx] = NULL;
  29854. +    if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
  29855. +        tty->driver.termios[idx] = NULL;
  29856. +        kfree_s(tp, sizeof(struct termios));
  29857. +    }
  29858. +    if (tty == redirect || o_tty == redirect)
  29859. +        redirect = NULL;
  29860. +    /*
  29861. +     * Make sure that the tty's task queue isn't activated.  If it
  29862. +     * is, take it out of the linked list.
  29863. +     */
  29864. +    cli();
  29865. +    if (tty->flip.tqueue.sync) {
  29866. +        struct tq_struct *tq, *prev;
  29867. +
  29868. +        for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {
  29869. +            if (tq == &tty->flip.tqueue) {
  29870. +                if (prev)
  29871. +                    prev->next = tq->next;
  29872. +                else
  29873. +                    tq_timer = tq->next;
  29874. +                break;
  29875. +            }
  29876. +        }
  29877. +    }
  29878. +    sti();
  29879. +    tty->magic = 0;
  29880. +    (*tty->driver.refcount)--;
  29881. +    kfree_s(tty, sizeof(struct tty_struct));
  29882. +    filp->private_data = 0;
  29883. +    if (o_tty) {
  29884. +        o_tty->magic = 0;
  29885. +        (*o_tty->driver.refcount)--;
  29886. +        kfree_s(o_tty, sizeof(struct tty_struct));
  29887. +    }
  29888. +}
  29889. +
  29890. +/*
  29891. + * tty_open and tty_release keep up the tty count that contains the
  29892. + * number of opens done on a tty. We cannot use the inode-count, as
  29893. + * different inodes might point to the same tty.
  29894. + *
  29895. + * Open-counting is needed for pty masters, as well as for keeping
  29896. + * track of serial lines: DTR is dropped when the last close happens.
  29897. + * (This is not done solely through tty->count, now.  - Ted 1/27/92)
  29898. + *
  29899. + * The termios state of a pty is reset on first open so that
  29900. + * settings don't persist across reuse.
  29901. + */
  29902. +static int tty_open(struct inode * inode, struct file * filp)
  29903. +{
  29904. +    struct tty_struct *tty;
  29905. +    int minor;
  29906. +    int noctty, retval;
  29907. +    kdev_t device;
  29908. +
  29909. +retry_open:
  29910. +    noctty = filp->f_flags & O_NOCTTY;
  29911. +    device = inode->i_rdev;
  29912. +    if (device == TTY_DEV) {
  29913. +        if (!current->tty)
  29914. +            return -ENXIO;
  29915. +        device = current->tty->device;
  29916. +        /* noctty = 1; */
  29917. +    }
  29918. +    if (device == CONSOLE_DEV) {
  29919. +        device = MKDEV(TTY_MAJOR, vtdata.fgconsole->num);
  29920. +        noctty = 1;
  29921. +    }
  29922. +    minor = MINOR(device);
  29923. +    
  29924. +    retval = init_dev(device, &tty);
  29925. +    if (retval)
  29926. +        return retval;
  29927. +    filp->private_data = tty;
  29928. +    check_tty_count(tty, "tty_open");
  29929. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  29930. +        tty->driver.subtype == PTY_TYPE_MASTER)
  29931. +        noctty = 1;
  29932. +#ifdef TTY_DEBUG_HANGUP
  29933. +    printk("opening %s...", tty_name(tty));
  29934. +#endif
  29935. +    if (tty->driver.open)
  29936. +        retval = tty->driver.open(tty, filp);
  29937. +    else
  29938. +        retval = -ENODEV;
  29939. +
  29940. +    if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())
  29941. +        retval = -EBUSY;
  29942. +
  29943. +    if (retval) {
  29944. +#ifdef TTY_DEBUG_HANGUP
  29945. +        printk("error %d in opening %s...", retval, tty_name(tty));
  29946. +#endif
  29947. +
  29948. +        release_dev(filp);
  29949. +        if (retval != -ERESTARTSYS)
  29950. +            return retval;
  29951. +        if (current->signal & ~current->blocked)
  29952. +            return retval;
  29953. +        schedule();
  29954. +        /*
  29955. +         * Need to reset f_op in case a hangup happened.
  29956. +         */
  29957. +        filp->f_op = &tty_fops;
  29958. +        goto retry_open;
  29959. +    }
  29960. +    if (!noctty &&
  29961. +        current->leader &&
  29962. +        !current->tty &&
  29963. +        tty->session == 0) {
  29964. +        current->tty = tty;
  29965. +        current->tty_old_pgrp = 0;
  29966. +        tty->session = current->session;
  29967. +        tty->pgrp = current->pgrp;
  29968. +    }
  29969. +    return 0;
  29970. +}
  29971. +
  29972. +/*
  29973. + * Note that releasing a pty master also releases the child, so
  29974. + * we have to make the redirection checks after that and on both
  29975. + * sides of a pty.
  29976. + */
  29977. +static void tty_release(struct inode * inode, struct file * filp)
  29978. +{
  29979. +    release_dev(filp);
  29980. +}
  29981. +
  29982. +static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
  29983. +{
  29984. +    struct tty_struct * tty;
  29985. +
  29986. +    tty = (struct tty_struct *)filp->private_data;
  29987. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_select"))
  29988. +        return 0;
  29989. +
  29990. +    if (tty->ldisc.select)
  29991. +        return (tty->ldisc.select)(tty, inode, filp, sel_type, wait);
  29992. +    return 0;
  29993. +}
  29994. +
  29995. +/*
  29996. + * fasync_helper() is used by some character device drivers (mainly mice)
  29997. + * to set up the fasync queue. It returns negative on error, 0 if it did
  29998. + * no changes and positive if it added/deleted the entry.
  29999. + */
  30000. +int fasync_helper(struct inode * inode, struct file * filp, int on, struct fasync_struct **fapp)
  30001. +{
  30002. +    struct fasync_struct *fa, **fp;
  30003. +    unsigned long flags;
  30004. +
  30005. +    for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
  30006. +        if (fa->fa_file == filp)
  30007. +            break;
  30008. +    }
  30009. +
  30010. +    if (on) {
  30011. +        if (fa)
  30012. +            return 0;
  30013. +        fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
  30014. +        if (!fa)
  30015. +            return -ENOMEM;
  30016. +        fa->magic = FASYNC_MAGIC;
  30017. +        fa->fa_file = filp;
  30018. +        save_flags_cli (flags);
  30019. +        fa->fa_next = *fapp;
  30020. +        *fapp = fa;
  30021. +        restore_flags(flags);
  30022. +        return 1;
  30023. +    }
  30024. +    if (!fa)
  30025. +        return 0;
  30026. +    save_flags_cli (flags);
  30027. +    *fp = fa->fa_next;
  30028. +    restore_flags(flags);
  30029. +    kfree(fa);
  30030. +    return 1;
  30031. +}
  30032. +
  30033. +static int tty_fasync(struct inode * inode, struct file * filp, int on)
  30034. +{
  30035. +    struct tty_struct * tty;
  30036. +    int retval;
  30037. +
  30038. +    tty = (struct tty_struct *)filp->private_data;
  30039. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync"))
  30040. +        return 0;
  30041. +
  30042. +    retval = fasync_helper(inode, filp, on, &tty->fasync);
  30043. +    if (retval <= 0)
  30044. +        return retval;
  30045. +
  30046. +    if (on) {
  30047. +        if (!waitqueue_active(&tty->read_wait))
  30048. +            tty->minimum_to_wake = 1;
  30049. +        if (filp->f_owner == 0) {
  30050. +            if (tty->pgrp)
  30051. +                filp->f_owner = -tty->pgrp;
  30052. +            else
  30053. +                filp->f_owner = current->pid;
  30054. +        }
  30055. +    } else {
  30056. +        if (!tty->fasync && !waitqueue_active(&tty->read_wait))
  30057. +            tty->minimum_to_wake = N_TTY_BUF_SIZE;
  30058. +    }
  30059. +    return 0;    
  30060. +}
  30061. +
  30062. +#if 0
  30063. +/*
  30064. + * XXX does anyone use this anymore?!?
  30065. + */
  30066. +static int do_get_ps_info(unsigned long arg)
  30067. +{
  30068. +    struct tstruct {
  30069. +        int flag;
  30070. +        int present[NR_TASKS];
  30071. +        struct task_struct tasks[NR_TASKS];
  30072. +    };
  30073. +    struct tstruct *ts = (struct tstruct *)arg;
  30074. +    struct task_struct **p;
  30075. +    char *c, *d;
  30076. +    int i, n = 0;
  30077. +    
  30078. +    i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
  30079. +    if (i)
  30080. +        return i;
  30081. +    for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
  30082. +        if (*p)
  30083. +        {
  30084. +            c = (char *)(*p);
  30085. +            d = (char *)(ts->tasks+n);
  30086. +            for (i=0 ; i<sizeof(struct task_struct) ; i++)
  30087. +                put_user(*c++, d++);
  30088. +            put_user(1, ts->present+n);
  30089. +        }
  30090. +        else    
  30091. +            put_user(0, ts->present+n);
  30092. +    return(0);            
  30093. +}
  30094. +#endif
  30095. +
  30096. +static int tty_ioctl(struct inode * inode, struct file * file,
  30097. +             unsigned int cmd, unsigned long arg)
  30098. +{
  30099. +    int    retval;
  30100. +    struct tty_struct * tty;
  30101. +    struct tty_struct * real_tty;
  30102. +    struct winsize tmp_ws;
  30103. +    pid_t pgrp;
  30104. +    unsigned char    ch;
  30105. +    char    mbz = 0;
  30106. +    
  30107. +    tty = (struct tty_struct *)file->private_data;
  30108. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
  30109. +        return -EINVAL;
  30110. +
  30111. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  30112. +        tty->driver.subtype == PTY_TYPE_MASTER)
  30113. +        real_tty = tty->link;
  30114. +    else
  30115. +        real_tty = tty;
  30116. +
  30117. +    switch (cmd) {
  30118. +        case TIOCSTI:
  30119. +            if ((current->tty != tty) && !suser())
  30120. +                return -EPERM;
  30121. +            retval = verify_area(VERIFY_READ, (void *) arg, 1);
  30122. +            if (retval)
  30123. +                return retval;
  30124. +            ch = get_user((char *) arg);
  30125. +            tty->ldisc.receive_buf(tty, &ch, &mbz, 1);
  30126. +            return 0;
  30127. +        case TIOCGWINSZ:
  30128. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  30129. +                         sizeof (struct winsize));
  30130. +            if (retval)
  30131. +                return retval;
  30132. +            memcpy_tofs((struct winsize *) arg, &tty->winsize,
  30133. +                    sizeof (struct winsize));
  30134. +            return 0;
  30135. +        case TIOCSWINSZ:
  30136. +            retval = verify_area(VERIFY_READ, (void *) arg,
  30137. +                         sizeof (struct winsize));
  30138. +            if (retval)
  30139. +                return retval;            
  30140. +            memcpy_fromfs(&tmp_ws, (struct winsize *) arg,
  30141. +                      sizeof (struct winsize));
  30142. +            if (memcmp(&tmp_ws, &tty->winsize,
  30143. +                   sizeof(struct winsize))) {
  30144. +                if (tty->pgrp > 0)
  30145. +                    kill_pg(tty->pgrp, SIGWINCH, 1);
  30146. +                if ((real_tty->pgrp != tty->pgrp) &&
  30147. +                    (real_tty->pgrp > 0))
  30148. +                    kill_pg(real_tty->pgrp, SIGWINCH, 1);
  30149. +            }
  30150. +            tty->winsize = tmp_ws;
  30151. +            real_tty->winsize = tmp_ws;
  30152. +            return 0;
  30153. +        case TIOCCONS:
  30154. +            if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE) {
  30155. +                if (!suser())
  30156. +                    return -EPERM;
  30157. +                redirect = NULL;
  30158. +                return 0;
  30159. +            }
  30160. +            if (redirect)
  30161. +                return -EBUSY;
  30162. +            redirect = real_tty;
  30163. +            return 0;
  30164. +        case FIONBIO:
  30165. +            retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int));
  30166. +            if (retval)
  30167. +                return retval;
  30168. +            arg = get_user((unsigned int *) arg);
  30169. +            if (arg)
  30170. +                file->f_flags |= O_NONBLOCK;
  30171. +            else
  30172. +                file->f_flags &= ~O_NONBLOCK;
  30173. +            return 0;
  30174. +        case TIOCEXCL:
  30175. +            set_bit(TTY_EXCLUSIVE, &tty->flags);
  30176. +            return 0;
  30177. +        case TIOCNXCL:
  30178. +            clear_bit(TTY_EXCLUSIVE, &tty->flags);
  30179. +            return 0;
  30180. +        case TIOCNOTTY:
  30181. +            if (current->tty != tty)
  30182. +                return -ENOTTY;
  30183. +            if (current->leader)
  30184. +                disassociate_ctty(0);
  30185. +            current->tty = NULL;
  30186. +            return 0;
  30187. +        case TIOCSCTTY:
  30188. +            if (current->leader &&
  30189. +                (current->session == tty->session))
  30190. +                return 0;
  30191. +            /*
  30192. +             * The process must be a session leader and
  30193. +             * not have a controlling tty already.
  30194. +             */
  30195. +            if (!current->leader || current->tty)
  30196. +                return -EPERM;
  30197. +            if (tty->session > 0) {
  30198. +                /*
  30199. +                 * This tty is already the controlling
  30200. +                 * tty for another session group!
  30201. +                 */
  30202. +                if ((arg == 1) && suser()) {
  30203. +                    /*
  30204. +                     * Steal it away
  30205. +                     */
  30206. +                    struct task_struct *p;
  30207. +
  30208. +                    for_each_task(p)
  30209. +                        if (p->tty == tty)
  30210. +                            p->tty = NULL;
  30211. +                } else
  30212. +                    return -EPERM;
  30213. +            }
  30214. +            current->tty = tty;
  30215. +            current->tty_old_pgrp = 0;
  30216. +            tty->session = current->session;
  30217. +            tty->pgrp = current->pgrp;
  30218. +            return 0;
  30219. +        case TIOCGPGRP:
  30220. +            /*
  30221. +             * (tty == real_tty) is a cheap way of
  30222. +             * testing if the tty is NOT a master pty.
  30223. +             */
  30224. +            if (tty == real_tty && current->tty != real_tty)
  30225. +                return -ENOTTY;
  30226. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  30227. +                         sizeof (pid_t));
  30228. +            if (retval)
  30229. +                return retval;
  30230. +            put_user(real_tty->pgrp, (pid_t *) arg);
  30231. +            return 0;
  30232. +        case TIOCSPGRP:
  30233. +            retval = tty_check_change(real_tty);
  30234. +            if (retval == -EIO)
  30235. +                return -ENOTTY;
  30236. +            if (retval)
  30237. +                return retval;
  30238. +            if (!current->tty ||
  30239. +                (current->tty != real_tty) ||
  30240. +                (real_tty->session != current->session))
  30241. +                return -ENOTTY;
  30242. +            pgrp = get_user((pid_t *) arg);
  30243. +            if (pgrp < 0)
  30244. +                return -EINVAL;
  30245. +            if (session_of_pgrp(pgrp) != current->session)
  30246. +                return -EPERM;
  30247. +            real_tty->pgrp = pgrp;
  30248. +            return 0;
  30249. +        case TIOCGETD:
  30250. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  30251. +                         sizeof (int));
  30252. +            if (retval)
  30253. +                return retval;
  30254. +            put_user(tty->ldisc.num, (int *) arg);
  30255. +            return 0;
  30256. +        case TIOCSETD:
  30257. +            retval = tty_check_change(tty);
  30258. +            if (retval)
  30259. +                return retval;
  30260. +            retval = verify_area(VERIFY_READ, (void *) arg,
  30261. +                         sizeof (int));
  30262. +            if (retval)
  30263. +                return retval;
  30264. +            arg = get_user((int *) arg);
  30265. +            return tty_set_ldisc(tty, arg);
  30266. +        case TIOCLINUX:
  30267. +            if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
  30268. +                return -EINVAL;
  30269. +            if (current->tty != tty && !suser())
  30270. +                return -EPERM;
  30271. +            retval = verify_area(VERIFY_READ, (void *) arg, 1);
  30272. +            if (retval)
  30273. +                return retval;
  30274. +            switch (retval = get_user((char *)arg))
  30275. +            {
  30276. +                case 0:
  30277. +                case 8:
  30278. +                case 9:
  30279. +                    printk("TIOCLINUX (0/8/9) ioctl is gone - use /dev/vcs\n");
  30280. +                    return -EINVAL;
  30281. +#if 0
  30282. +                case 1:
  30283. +                    printk("Deprecated TIOCLINUX (1) ioctl\n");
  30284. +                    return do_get_ps_info(arg);
  30285. +#endif
  30286. +                case 2:
  30287. +                    return set_selection(arg, tty);
  30288. +                case 3:
  30289. +                    return paste_selection(tty);
  30290. +                case 4:
  30291. +                    vt_do_unblankscreen ();
  30292. +                    return 0;
  30293. +                case 5:
  30294. +                    return sel_loadlut(arg);
  30295. +                case 6:
  30296. +            /*
  30297. +             * Make it possible to react to Shift+Mousebutton.
  30298. +             * Note that 'shift_state' is an undocumented
  30299. +             * kernel-internal variable; programs not closely
  30300. +             * related to the kernel should not use this.
  30301. +             */
  30302. +                    retval = verify_area(VERIFY_WRITE, (void *) arg, 1);
  30303. +                    if (retval)
  30304. +                        return retval;
  30305. +                    put_user(shift_state,(char *) arg);
  30306. +                    return 0;
  30307. +                case 7:
  30308. +                    retval = verify_area(VERIFY_WRITE, (void *) arg, 1);
  30309. +                    if (retval)
  30310. +                        return retval;
  30311. +                    put_user(mouse_reporting(),(char *) arg);
  30312. +                    return 0;
  30313. +/*                case 10:
  30314. +                    set_vesa_blanking(arg);
  30315. +                    return 0;*/
  30316. +                case 11:    /* set kmsg redirect */
  30317. +                    if (!suser())
  30318. +                        return -EPERM;
  30319. +                    retval = verify_area(VERIFY_READ,
  30320. +                        (void *) arg+1, 1);
  30321. +                    if (retval)
  30322. +                        return retval;
  30323. +                    kmsg_redirect = get_user((char *)arg+1);
  30324. +                    return 0;
  30325. +                case 12:    /* get fg console */
  30326. +                    return vtdata.fgconsole->num;
  30327. +                default: 
  30328. +                    return -EINVAL;
  30329. +            }
  30330. +
  30331. +        case TIOCTTYGSTRUCT:
  30332. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  30333. +                        sizeof(struct tty_struct));
  30334. +            if (retval)
  30335. +                return retval;
  30336. +            memcpy_tofs((struct tty_struct *) arg,
  30337. +                    tty, sizeof(struct tty_struct));
  30338. +            return 0;
  30339. +        default:
  30340. +            if (tty->driver.ioctl) {
  30341. +                retval = (tty->driver.ioctl)(tty, file,
  30342. +                                 cmd, arg);
  30343. +                if (retval != -ENOIOCTLCMD)
  30344. +                    return retval;
  30345. +            }
  30346. +            if (tty->ldisc.ioctl) {
  30347. +                retval = (tty->ldisc.ioctl)(tty, file,
  30348. +                                cmd, arg);
  30349. +                if (retval != -ENOIOCTLCMD)
  30350. +                    return retval;
  30351. +            }
  30352. +            return -EINVAL;
  30353. +        }
  30354. +}
  30355. +
  30356. +
  30357. +/*
  30358. + * This implements the "Secure Attention Key" ---  the idea is to
  30359. + * prevent trojan horses by killing all processes associated with this
  30360. + * tty when the user hits the "Secure Attention Key".  Required for
  30361. + * super-paranoid applications --- see the Orange Book for more details.
  30362. + * 
  30363. + * This code could be nicer; ideally it should send a HUP, wait a few
  30364. + * seconds, then send a INT, and then a KILL signal.  But you then
  30365. + * have to coordinate with the init process, since all processes associated
  30366. + * with the current tty must be dead before the new getty is allowed
  30367. + * to spawn.
  30368. + */
  30369. +void do_SAK( struct tty_struct *tty)
  30370. +{
  30371. +#ifdef TTY_SOFT_SAK
  30372. +    tty_hangup(tty);
  30373. +#else
  30374. +    struct task_struct **p;
  30375. +    int session;
  30376. +    int        i;
  30377. +    struct file    *filp;
  30378. +    
  30379. +    if (!tty)
  30380. +        return;
  30381. +    session  = tty->session;
  30382. +    if (tty->ldisc.flush_buffer)
  30383. +        tty->ldisc.flush_buffer(tty);
  30384. +    if (tty->driver.flush_buffer)
  30385. +        tty->driver.flush_buffer(tty);
  30386. +     for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  30387. +        if (!(*p))
  30388. +            continue;
  30389. +        if (((*p)->tty == tty) ||
  30390. +            ((session > 0) && ((*p)->session == session)))
  30391. +            send_sig(SIGKILL, *p, 1);
  30392. +        else {
  30393. +            for (i=0; i < NR_OPEN; i++) {
  30394. +                filp = (*p)->files->fd[i];
  30395. +                if (filp && (filp->f_op == &tty_fops) &&
  30396. +                    (filp->private_data == tty)) {
  30397. +                    send_sig(SIGKILL, *p, 1);
  30398. +                    break;
  30399. +                }
  30400. +            }
  30401. +        }
  30402. +    }
  30403. +#endif
  30404. +}
  30405. +
  30406. +/*
  30407. + * This routine is called out of the software interrupt to flush data
  30408. + * from the flip buffer to the line discipline.
  30409. + */
  30410. +static void flush_to_ldisc(void *private_)
  30411. +{
  30412. +    struct tty_struct *tty = (struct tty_struct *) private_;
  30413. +    unsigned char    *cp;
  30414. +    char        *fp;
  30415. +    int        count;
  30416. +
  30417. +    if (tty->flip.buf_num) {
  30418. +        cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
  30419. +        fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
  30420. +        tty->flip.buf_num = 0;
  30421. +
  30422. +        cli();
  30423. +        tty->flip.char_buf_ptr = tty->flip.char_buf;
  30424. +        tty->flip.flag_buf_ptr = tty->flip.flag_buf;
  30425. +    } else {
  30426. +        cp = tty->flip.char_buf;
  30427. +        fp = tty->flip.flag_buf;
  30428. +        tty->flip.buf_num = 1;
  30429. +
  30430. +        cli();
  30431. +        tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
  30432. +        tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
  30433. +    }
  30434. +    count = tty->flip.count;
  30435. +    tty->flip.count = 0;
  30436. +    sti();
  30437. +    
  30438. +#if 0
  30439. +    if (count > tty->max_flip_cnt)
  30440. +        tty->max_flip_cnt = count;
  30441. +#endif
  30442. +    tty->ldisc.receive_buf(tty, cp, fp, count);
  30443. +}
  30444. +
  30445. +/*
  30446. + * This subroutine initializes a tty structure.
  30447. + */
  30448. +static void initialize_tty_struct(struct tty_struct *tty)
  30449. +{
  30450. +    memset(tty, 0, sizeof(struct tty_struct));
  30451. +    tty->magic = TTY_MAGIC;
  30452. +    tty->ldisc = ldiscs[N_TTY];
  30453. +    tty->pgrp = -1;
  30454. +    tty->flip.char_buf_ptr = tty->flip.char_buf;
  30455. +    tty->flip.flag_buf_ptr = tty->flip.flag_buf;
  30456. +    tty->flip.tqueue.routine = flush_to_ldisc;
  30457. +    tty->flip.tqueue.data = tty;
  30458. +}
  30459. +
  30460. +/*
  30461. + * The default put_char routine if the driver did not define one.
  30462. + */
  30463. +void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
  30464. +{
  30465. +    tty->driver.write(tty, 0, &ch, 1);
  30466. +}
  30467. +
  30468. +/*
  30469. + * Called by a tty driver to register itself.
  30470. + */
  30471. +int tty_register_driver(struct tty_driver *driver)
  30472. +{
  30473. +    int error;
  30474. +
  30475. +    if (driver->flags & TTY_DRIVER_INSTALLED)
  30476. +        return 0;
  30477. +
  30478. +    error = register_chrdev(driver->major, driver->name, &tty_fops);
  30479. +    if (error < 0)
  30480. +        return error;
  30481. +    else if(driver->major == 0)
  30482. +        driver->major = error;
  30483. +
  30484. +    if (!driver->put_char)
  30485. +        driver->put_char = tty_default_put_char;
  30486. +    
  30487. +    driver->prev = 0;
  30488. +    driver->next = tty_drivers;
  30489. +    if (tty_drivers) tty_drivers->prev = driver;
  30490. +    tty_drivers = driver;
  30491. +    return error;
  30492. +}
  30493. +
  30494. +/*
  30495. + * Called by a tty driver to unregister itself.
  30496. + */
  30497. +int tty_unregister_driver(struct tty_driver *driver)
  30498. +{
  30499. +    int    retval;
  30500. +    struct tty_driver *p;
  30501. +    int    found = 0;
  30502. +    const char *othername = NULL;
  30503. +    
  30504. +    if (*driver->refcount)
  30505. +        return -EBUSY;
  30506. +
  30507. +    for (p = tty_drivers; p; p = p->next) {
  30508. +        if (p == driver)
  30509. +            found++;
  30510. +        else if (p->major == driver->major)
  30511. +            othername = p->name;
  30512. +    }
  30513. +
  30514. +    if (!found)
  30515. +        return -ENOENT;
  30516. +
  30517. +    if (othername == NULL) {
  30518. +        retval = unregister_chrdev(driver->major, driver->name);
  30519. +        if (retval)
  30520. +            return retval;
  30521. +    } else
  30522. +        register_chrdev(driver->major, othername, &tty_fops);
  30523. +
  30524. +    if (driver->prev)
  30525. +        driver->prev->next = driver->next;
  30526. +    else
  30527. +        tty_drivers = driver->next;
  30528. +    
  30529. +    if (driver->next)
  30530. +        driver->next->prev = driver->prev;
  30531. +
  30532. +    return 0;
  30533. +}
  30534. +
  30535. +
  30536. +/*
  30537. + * Initialize the console device. This is called *early*, so
  30538. + * we can't necessarily depend on lots of kernel help here.
  30539. + * Just do some early initializations, and do the complex setup
  30540. + * later.
  30541. + */
  30542. +long console_init(long kmem_start, long kmem_end)
  30543. +{
  30544. +    /* Setup the default TTY line discipline. */
  30545. +    memset(ldiscs, 0, sizeof(ldiscs));
  30546. +    (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
  30547. +
  30548. +    /*
  30549. +     * Set up the standard termios.  Individual tty drivers may 
  30550. +     * deviate from this; this is used as a template.
  30551. +     */
  30552. +    memset(&tty_std_termios, 0, sizeof(struct termios));
  30553. +    memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
  30554. +    tty_std_termios.c_iflag = ICRNL | IXON;
  30555. +    tty_std_termios.c_oflag = OPOST | ONLCR;
  30556. +    tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL;
  30557. +    tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
  30558. +        ECHOCTL | ECHOKE | IEXTEN;
  30559. +
  30560. +    /*
  30561. +     * set up the console device so that later boot sequences can 
  30562. +     * inform about problems etc..
  30563. +     */
  30564. +    return vt_pre_init(kmem_start);
  30565. +}
  30566. +
  30567. +static struct tty_driver dev_tty_driver, dev_console_driver;
  30568. +
  30569. +/*
  30570. + * Ok, now we can initialize the rest of the tty devices and can count
  30571. + * on memory allocations, interrupts etc..
  30572. + */
  30573. +int tty_init(void)
  30574. +{
  30575. +    if (sizeof(struct tty_struct) > PAGE_SIZE)
  30576. +        panic("size of tty structure > PAGE_SIZE!");
  30577. +    vt_post_init ();
  30578. +
  30579. +    /*
  30580. +     * dev_tty_driver and dev_console_driver are actually magic
  30581. +     * devices which get redirected at open time.  Nevertheless,
  30582. +     * we register them so that register_chrdev is called
  30583. +     * appropriately.
  30584. +     */
  30585. +    memset(&dev_tty_driver, 0, sizeof(struct tty_driver));
  30586. +    dev_tty_driver.magic = TTY_DRIVER_MAGIC;
  30587. +    dev_tty_driver.name = "tty";
  30588. +    dev_tty_driver.name_base = 0;
  30589. +    dev_tty_driver.major = TTY_MAJOR;
  30590. +    dev_tty_driver.minor_start = 0;
  30591. +    dev_tty_driver.num = 1;
  30592. +
  30593. +    if (tty_register_driver(&dev_tty_driver))
  30594. +        panic("Couldn't register /dev/tty driver\n");
  30595. +
  30596. +    dev_console_driver = dev_tty_driver;
  30597. +    dev_console_driver.name = "console";
  30598. +    dev_console_driver.major = TTYAUX_MAJOR;
  30599. +
  30600. +    if (tty_register_driver(&dev_console_driver))
  30601. +        panic("Couldn't register /dev/console driver\n");
  30602. +
  30603. +#ifdef CONFIG_SERIAL
  30604. +    rs_init();
  30605. +#endif
  30606. +    pty_init();
  30607. +    vcs_init();
  30608. +    return 0;
  30609. +}
  30610. +
  30611. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/uni_hash.tbl linux/arch/arm/drivers/char/uni_hash.tbl
  30612. --- linux.orig/arch/arm/drivers/char/uni_hash.tbl    Thu Jan  1 01:00:00 1970
  30613. +++ linux/arch/arm/drivers/char/uni_hash.tbl    Thu Jul 18 23:41:22 1996
  30614. @@ -0,0 +1,89 @@
  30615. +/*
  30616. + * uni_hash.tbl
  30617. + *
  30618. + * Do not edit this file; it was automatically generated by
  30619. + *
  30620. + * conmakehash cp437.uni > uni_hash.tbl
  30621. + *
  30622. + */
  30623. +
  30624. +#include <linux/types.h>
  30625. +#include <linux/kd.h>
  30626. +
  30627. +static u8 dfont_unicount[256] = 
  30628. +{
  30629. +      1,   1,   1,   1,   2,   1,   1,   1,
  30630. +      1,   1,   1,   1,   1,   1,   1,   1,
  30631. +      2,   2,   1,   1,   1,   1,   1,   1,
  30632. +      1,   1,   1,   1,   1,   1,   1,   1,
  30633. +      1,   1,   2,   1,   1,   1,   1,   1,
  30634. +      1,   1,   1,   1,   2,   2,   1,   1,
  30635. +      1,   1,   1,   1,   1,   1,   1,   1,
  30636. +      1,   1,   1,   1,   1,   1,   1,   1,
  30637. +      1,   5,   1,   2,   1,   4,   1,   1,
  30638. +      1,   5,   1,   2,   1,   1,   1,   5,
  30639. +      1,   1,   2,   1,   1,   4,   1,   1,
  30640. +      1,   2,   1,   1,   1,   1,   1,   2,
  30641. +      1,   2,   1,   1,   1,   1,   1,   1,
  30642. +      1,   1,   1,   1,   1,   1,   1,   2,
  30643. +      1,   1,   1,   1,   1,   1,   1,   1,
  30644. +      2,   2,   1,   1,   2,   1,   1,   1,
  30645. +      1,   1,   1,   1,   1,   1,   1,   1,
  30646. +      1,   1,   1,   1,   1,   1,   1,   2,
  30647. +      1,   1,   1,   1,   1,   1,   1,   1,
  30648. +      1,   1,   1,   1,   1,   1,   1,   1,
  30649. +      1,   1,   1,   1,   1,   1,   1,   1,
  30650. +      1,   1,   1,   1,   1,   1,   1,   1,
  30651. +      1,   1,   1,   1,   1,   1,   1,   1,
  30652. +      1,   1,   1,   1,   1,   1,   1,   1,
  30653. +      1,   1,   1,   1,   1,   1,   1,   1,
  30654. +      1,   1,   1,   1,   1,   1,   1,   1,
  30655. +      1,   1,   1,   1,   1,   1,   1,   1,
  30656. +      1,   1,   1,   1,   1,   1,   1,   1,
  30657. +      1,   2,   1,   1,   1,   1,   2,   1,
  30658. +      2,   1,   2,   1,   1,   2,   1,   1,
  30659. +      1,   1,   1,   1,   1,   1,   1,   1,
  30660. +      1,   1,   1,   1,   1,   1,   2,   1
  30661. +};
  30662. +
  30663. +static u16 dfont_unitable[297] = 
  30664. +{
  30665. +    0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x25c6, 0x2663, 0x2660,
  30666. +    0x2022, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b,
  30667. +    0x263c, 0x25b6, 0x25ba, 0x25c0, 0x25c4, 0x2195, 0x203c, 0x00b6,
  30668. +    0x00a7, 0x25ac, 0x21a8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221f,
  30669. +    0x2194, 0x25b2, 0x25bc, 0x0020, 0x0021, 0x0022, 0x00a8, 0x0023,
  30670. +    0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b,
  30671. +    0x002c, 0x00b8, 0x002d, 0x00ad, 0x002e, 0x002f, 0x0030, 0x0031,
  30672. +    0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039,
  30673. +    0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041,
  30674. +    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x0042, 0x0043, 0x00a9, 0x0044,
  30675. +    0x0045, 0x00c8, 0x00ca, 0x00cb, 0x0046, 0x0047, 0x0048, 0x0049,
  30676. +    0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x004a, 0x004b, 0x212a, 0x004c,
  30677. +    0x004d, 0x004e, 0x004f, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x0050,
  30678. +    0x0051, 0x0052, 0x00ae, 0x0053, 0x0054, 0x0055, 0x00d9, 0x00da,
  30679. +    0x00db, 0x0056, 0x0057, 0x0058, 0x0059, 0x00dd, 0x005a, 0x005b,
  30680. +    0x005c, 0x005d, 0x005e, 0x005f, 0xf804, 0x0060, 0x0061, 0x00e3,
  30681. +    0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069,
  30682. +    0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x00f5, 0x0070,
  30683. +    0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
  30684. +    0x00d7, 0x0079, 0x00fd, 0x007a, 0x007b, 0x007c, 0x00a5, 0x007d,
  30685. +    0x007e, 0x2302, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0,
  30686. +    0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec,
  30687. +    0x00c4, 0x00c5, 0x212b, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6,
  30688. +    0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3,
  30689. +    0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1,
  30690. +    0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc,
  30691. +    0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524,
  30692. +    0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d,
  30693. +    0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500,
  30694. +    0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560,
  30695. +    0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558,
  30696. +    0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584,
  30697. +    0x258c, 0x2590, 0x2580, 0x03b1, 0x03b2, 0x00df, 0x0393, 0x03c0,
  30698. +    0x03a3, 0x03c3, 0x00b5, 0x03bc, 0x03c4, 0x03a6, 0x00d8, 0x0398,
  30699. +    0x03a9, 0x2126, 0x03b4, 0x221e, 0x03c6, 0x00f8, 0x03b5, 0x2229,
  30700. +    0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
  30701. +    0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0xfffd,
  30702. +    0x00a0
  30703. +};
  30704. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/vc_screen.c linux/arch/arm/drivers/char/vc_screen.c
  30705. --- linux.orig/arch/arm/drivers/char/vc_screen.c    Thu Jan  1 01:00:00 1970
  30706. +++ linux/arch/arm/drivers/char/vc_screen.c    Fri May 10 23:47:14 1996
  30707. @@ -0,0 +1,268 @@
  30708. +/*
  30709. + * linux/arch/arm/drivers/char/vc_screen.c
  30710. + *
  30711. + * Provide access to virtual console memory.
  30712. + * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
  30713. + * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
  30714. + *            [minor: N]
  30715. + *
  30716. + * /dev/vcsaN: idem, but including attributes, and prefixed with
  30717. + *    the 4 bytes lines,columns,x,y (as screendump used to give)
  30718. + *            [minor: N+128]
  30719. + *
  30720. + * This replaces screendump and part of selection, so that the system
  30721. + * administrator can control access using file system permissions.
  30722. + *
  30723. + * aeb@cwi.nl - efter Friedas begravelse - 950211
  30724. + *
  30725. + * Modified by Russell King (01/01/96) [experimental + in development]
  30726. + */
  30727. +
  30728. +#include <linux/kernel.h>
  30729. +#include <linux/major.h>
  30730. +#include <linux/errno.h>
  30731. +#include <linux/tty.h>
  30732. +#include <linux/fs.h>
  30733. +#include <asm/segment.h>
  30734. +
  30735. +#include "vt_kern.h"
  30736. +#include "selection.h"
  30737. +
  30738. +#define HEADER_SIZE    4
  30739. +
  30740. +static inline int vcs_size (struct inode *inode)
  30741. +{
  30742. +    int size = vtdata.numrows * vtdata.numcolumns;
  30743. +
  30744. +    if (MINOR(inode->i_rdev) & 128)
  30745. +    size = sizeof (unsigned long) * size + HEADER_SIZE;
  30746. +    return size;
  30747. +}
  30748. +
  30749. +static int vcs_lseek (struct inode *inode, struct file *file, off_t offset, int orig)
  30750. +{
  30751. +    int size = vcs_size(inode);
  30752. +
  30753. +    switch (orig) {
  30754. +    case 0:
  30755. +    file->f_pos = offset;
  30756. +    break;
  30757. +    case 1:
  30758. +    file->f_pos += offset;
  30759. +    break;
  30760. +    case 2:
  30761. +    file->f_pos = size + offset;
  30762. +    break;
  30763. +    default:
  30764. +    return -EINVAL;
  30765. +    }
  30766. +    if (file->f_pos < 0 || file->f_pos > size)
  30767. +    return -EINVAL;
  30768. +    return file->f_pos;
  30769. +}
  30770. +
  30771. +static int vcs_read (struct inode *inode, struct file *file, char *buf, int count)
  30772. +{
  30773. +    struct vt *vt;
  30774. +    unsigned long p = file->f_pos;
  30775. +    unsigned int cons = MINOR(inode->i_rdev);
  30776. +    int attr, size, read;
  30777. +    char *buf0;
  30778. +    unsigned long *org, d;
  30779. +
  30780. +    attr = (cons & 128);
  30781. +    cons = (cons & 127);
  30782. +
  30783. +    if (cons == 0)
  30784. +    vt = vtdata.fgconsole;
  30785. +    else
  30786. +    vt = vt_con_data + (cons - 1);
  30787. +
  30788. +    if (!vt_allocated (vt))
  30789. +    return -ENXIO;
  30790. +
  30791. +    size = vcs_size(inode);
  30792. +    if (count < 0 || p > size)
  30793. +    return -EINVAL;
  30794. +
  30795. +    if (count > size - p)
  30796. +    count = size - p;
  30797. +
  30798. +    buf0 = buf;
  30799. +    if (!attr) {
  30800. +    org = screen_pos (vt, p);
  30801. +    while (count-- > 0)
  30802. +        put_user (*org++ & 0xff, buf++);
  30803. +    } else {
  30804. +    if (p < HEADER_SIZE) {
  30805. +        char header[HEADER_SIZE];
  30806. +        header[0] = (char) vtdata.numrows;
  30807. +        header[1] = (char) vtdata.numcolumns;
  30808. +        getconsxy (vt, header + 2);
  30809. +        while (p < HEADER_SIZE && count-- > 0)
  30810. +        put_user (header[p++], buf++);
  30811. +    }
  30812. +    p -= HEADER_SIZE;
  30813. +    org = screen_pos (vt, p >> 2);
  30814. +
  30815. +    if (p & 3) {
  30816. +        unsigned long d = *org++;
  30817. +
  30818. +        switch (p & 3) {
  30819. +        case 1:
  30820. +        if (count-- > 0)
  30821. +            put_user ((d >> 8) & 255, buf++);
  30822. +        case 2:
  30823. +        if (count-- > 0)
  30824. +            put_user ((d >> 16) & 255, buf++);
  30825. +        case 3:
  30826. +        if (count-- > 0)
  30827. +            put_user (d >> 24, buf++);
  30828. +        }
  30829. +    }
  30830. +
  30831. +    while (count > 3) {
  30832. +        put_user (*org++, (unsigned long *) buf);
  30833. +        buf += 4;
  30834. +        count -= 4;
  30835. +    }
  30836. +
  30837. +    if (count > 0) {
  30838. +        d = *org;
  30839. +        put_user (d & 0xff, buf++);
  30840. +        if (count > 1)
  30841. +        put_user ((d >> 8) & 0xff, buf++);
  30842. +        if (count > 2)
  30843. +        put_user ((d >> 16) & 0xff, buf++);
  30844. +    }
  30845. +    }
  30846. +    read = buf - buf0;
  30847. +    file->f_pos += read;
  30848. +    return read;
  30849. +}
  30850. +
  30851. +static int vcs_write (struct inode *inode, struct file *file, const char *buf, int count)
  30852. +{
  30853. +    struct vt *vt;
  30854. +    unsigned long p = file->f_pos;
  30855. +    unsigned int cons = MINOR(inode->i_rdev);
  30856. +    int viewed, attr, size, written;
  30857. +    const char *buf0;
  30858. +    unsigned long *org;
  30859. +
  30860. +    attr = (cons & 128);
  30861. +    cons = (cons & 127);
  30862. +
  30863. +    if (cons == 0) {
  30864. +    vt = vtdata.fgconsole;
  30865. +    viewed = 1;
  30866. +    } else {
  30867. +    vt = vt_con_data + (cons - 1);
  30868. +    viewed = 0;
  30869. +    }
  30870. +
  30871. +    if (!vt_allocated (vt))
  30872. +    return -ENXIO;
  30873. +
  30874. +    size = vcs_size(inode);
  30875. +
  30876. +    if (count < 0 || p > size)
  30877. +    return -EINVAL;
  30878. +
  30879. +    if (count > size - p)
  30880. +    count = size - p;
  30881. +
  30882. +    buf0 = buf;
  30883. +    if (!attr) {
  30884. +    org = screen_pos (vt, p);
  30885. +    while (count-- > 0) {
  30886. +        *org = (*org & 0xffffff00) | get_user (buf++);
  30887. +        org++;
  30888. +    }
  30889. +    } else {
  30890. +    if (p < HEADER_SIZE) {
  30891. +        char header[HEADER_SIZE];
  30892. +        getconsxy (vt, header+2);
  30893. +
  30894. +        while (p < HEADER_SIZE && count-- > 0)
  30895. +        header[p++] = get_user (buf++);
  30896. +        if (!viewed)
  30897. +        putconsxy (vt, header + 2);
  30898. +    }
  30899. +    p -= HEADER_SIZE;
  30900. +    org = screen_pos (vt, p >> 2);
  30901. +
  30902. +    if (p & 3) {
  30903. +        unsigned long d = *org;
  30904. +
  30905. +        switch (p & 3) {
  30906. +        case 1:
  30907. +        if (count-- > 0)
  30908. +                d = (d & 0xffff00ff) | (get_user (buf++) << 8);
  30909. +        case 2:
  30910. +        if (count-- > 0)
  30911. +                d = (d & 0xff00ffff) | (get_user (buf++) << 16);
  30912. +        case 3:
  30913. +        if (count-- > 0)
  30914. +                d = (d & 0x00ffffff) | (get_user (buf++) << 24);
  30915. +        }
  30916. +        *org ++ = d;
  30917. +    }
  30918. +
  30919. +    while (count > 3) {
  30920. +        *org ++ = get_user ((const unsigned long *)buf);
  30921. +        buf += 4;
  30922. +        count -= 4;
  30923. +    }
  30924. +
  30925. +    if (count > 0) {
  30926. +        unsigned long d;
  30927. +
  30928. +        d = (*org >> (count * 8)) << (count * 8);
  30929. +        d |= get_user (buf ++);
  30930. +
  30931. +        if (count > 1)
  30932. +        d |= get_user (buf ++) << 8;
  30933. +
  30934. +        if (count > 2)
  30935. +        d |= get_user (buf ++) << 16;
  30936. +        *org = d;
  30937. +    }
  30938. +    }
  30939. +    written = buf - buf0;
  30940. +    update_scrmem (vt, file->f_pos >> 2, (written + 3) >> 2);
  30941. +    file->f_pos += written;
  30942. +    return written;
  30943. +}
  30944. +
  30945. +static int vcs_open (struct inode *inode, struct file *filp)
  30946. +{
  30947. +    unsigned int cons = (MINOR(inode->i_rdev) & 127);
  30948. +
  30949. +    if (cons && !vt_allocated (vt_con_data + cons - 1))
  30950. +    return -ENXIO;
  30951. +    return 0;
  30952. +}
  30953. +
  30954. +static struct file_operations vcs_fops = {
  30955. +    vcs_lseek,    /* lseek */
  30956. +    vcs_read,    /* read */
  30957. +    vcs_write,    /* write */
  30958. +    NULL,        /* readdir */
  30959. +    NULL,        /* select */
  30960. +    NULL,        /* ioctl */
  30961. +    NULL,        /* mmap */
  30962. +    vcs_open,    /* open */
  30963. +    NULL,        /* release */
  30964. +    NULL        /* fsync */
  30965. +};
  30966. +
  30967. +int vcs_init(void)
  30968. +{
  30969. +    int error;
  30970. +
  30971. +    error = register_chrdev(VCS_MAJOR, "vcs", &vcs_fops);
  30972. +    if (error)
  30973. +    printk("unable to get major %d for vcs device", VCS_MAJOR);
  30974. +    return error;
  30975. +}
  30976. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/vt.c linux/arch/arm/drivers/char/vt.c
  30977. --- linux.orig/arch/arm/drivers/char/vt.c    Thu Jan  1 01:00:00 1970
  30978. +++ linux/arch/arm/drivers/char/vt.c    Sat Sep  7 13:41:49 1996
  30979. @@ -0,0 +1,1029 @@
  30980. +/*
  30981. + * linux/arch/arm/drivers/char/vt.c
  30982. + *
  30983. + * VT routines
  30984. + *
  30985. + * Changelog:
  30986. + *  05-Sep-1996    RMK    Fixed race condition between VT switch & initialisation
  30987. + */
  30988. +
  30989. +#include <linux/config.h>
  30990. +#include <linux/sched.h>
  30991. +#include <linux/tty.h>
  30992. +#include <linux/kd.h>
  30993. +#include <linux/errno.h>
  30994. +#include <linux/malloc.h>
  30995. +#include <linux/mm.h>
  30996. +#include <linux/tty.h>
  30997. +#include <linux/major.h>
  30998. +
  30999. +#include <asm/segment.h>
  31000. +
  31001. +#include "kbd_kern.h"
  31002. +#include "vt_kern.h"
  31003. +
  31004. +#define CON_XMIT_SIZE    2048
  31005. +
  31006. +#ifndef MIN
  31007. +#define MIN(a,b)        ((a) < (b) ? (a) : (b))
  31008. +#endif
  31009. +
  31010. +/*
  31011. + * VCD functions
  31012. + */
  31013. +extern void        vcd_blankscreen (int nopowersave);
  31014. +extern void        vcd_disallocate (struct vt *);
  31015. +extern int        vcd_init (struct vt *, int kmallocok, unsigned long *kmem);
  31016. +extern int        vcd_ioctl (struct vt *, int cmd, unsigned long arg);
  31017. +extern unsigned long    vcd_pre_init (unsigned long kmem, struct vt *);
  31018. +extern int        vcd_resize (int rows, int columns);
  31019. +extern void        vcd_restorestate (const struct vt *);
  31020. +extern void        vcd_savestate (const struct vt *, int blanked);
  31021. +extern void        vcd_unblankscreen (void);
  31022. +extern int        vcd_write (const struct vt *, int from_user, const unsigned char *buf, int count);
  31023. +extern void        vcd_setup_graphics (const struct vt *);
  31024. +
  31025. +extern void con_reset_palette (const struct vt *vt);
  31026. +extern void con_set_palette (const struct vt *vt);
  31027. +extern int con_init (void);
  31028. +
  31029. +static int vt_refcount;
  31030. +static struct tty_driver vt_driver;
  31031. +static struct tty_struct *vt_table[MAX_NR_CONSOLES];
  31032. +static struct termios *vt_termios[MAX_NR_CONSOLES];
  31033. +static struct termios *vt_termios_locked[MAX_NR_CONSOLES];
  31034. +
  31035. +extern void vt_do_blankscreen (int nopowersave);
  31036. +extern void vt_do_unblankscreen (void);
  31037. +
  31038. +struct vt_data vtdata;
  31039. +struct vt vt_con_data[MAX_NR_CONSOLES];
  31040. +
  31041. +/*
  31042. + * last_console is the last used console
  31043. + */
  31044. +struct vt *last_console;
  31045. +
  31046. +/*
  31047. + * Sometimes we want to wait until a particular VT has been activated. We
  31048. + * do it in a very simple manner. Everybody waits on a single queue and
  31049. + * get woken up at once. Those that are satisfied go on with their business,
  31050. + * while those not ready go back to sleep. Seems overkill to add a wait
  31051. + * to each vt just for this - usually this does nothing!
  31052. + */
  31053. +static struct wait_queue *vt_activate_queue = NULL;
  31054. +
  31055. +/*
  31056. + * Sleeps until a vt is activated, or the task is interrupted. Returns
  31057. + * 0 if activation, -1 if interrupted.
  31058. + */
  31059. +static int vt_waitonactivate (void)
  31060. +{
  31061. +    interruptible_sleep_on (&vt_activate_queue);
  31062. +    return (current->signal & ~current->blocked) ? -1 : 0;
  31063. +}
  31064. +
  31065. +#define vt_wake_waitactive() wake_up(&vt_activate_queue)
  31066. +
  31067. +void vt_reset (const struct vt *vt)
  31068. +{
  31069. +    vt->kbd->kbdmode        = VC_XLATE;
  31070. +    vt->vtd->vc_mode        = KD_TEXT;
  31071. +    vt->vtd->vt_mode.mode    = VT_AUTO;
  31072. +    vt->vtd->vt_mode.waitv    = 0;
  31073. +    vt->vtd->vt_mode.relsig    = 0;
  31074. +    vt->vtd->vt_mode.acqsig    = 0;
  31075. +    vt->vtd->vt_mode.frsig    = 0;
  31076. +    vt->vtd->vt_pid        = -1;
  31077. +    vt->vtd->vt_newvt        = NULL;
  31078. +    con_reset_palette (vt);
  31079. +}
  31080. +
  31081. +static int vt_allocate (struct vt *vt)
  31082. +{
  31083. +    if (!vt_allocated(vt)) {
  31084. +    void *data, *p;
  31085. +    int r;
  31086. +
  31087. +    data = kmalloc (sizeof (*vt->vcd) +
  31088. +            sizeof (*vt->kbd) +
  31089. +            sizeof (*vt->vtd) + CON_XMIT_SIZE, GFP_KERNEL);
  31090. +    if (!data)
  31091. +        return -ENOMEM;
  31092. +
  31093. +    vt->vcd = data;  p = ((struct con_struct *)data + 1);
  31094. +    vt->kbd = p;     p = ((struct kbd_struct *)p + 1);
  31095. +    vt->vtd = p;     p = ((struct vt_struct *)p + 1);
  31096. +    vt->vtd->xmit_buf = p;
  31097. +
  31098. +    if ((r = kbd_struct_init (vt, 1)) < 0) {
  31099. +        vt->vcd = NULL;
  31100. +        vt->kbd = NULL;
  31101. +        vt->vtd = NULL;
  31102. +        kfree (data);
  31103. +        return r;
  31104. +    }
  31105. +
  31106. +    if ((r = vcd_init (vt, 1, NULL)) < 0) {
  31107. +        vt->vcd = NULL;
  31108. +        vt->kbd = NULL;
  31109. +        vt->vtd = NULL;
  31110. +        kfree (data);
  31111. +        return r;
  31112. +    }
  31113. +    vt_reset (vt);
  31114. +    vt->vtd->xmitting = vt->vtd->xmit_cnt =
  31115. +    vt->vtd->xmit_out = vt->vtd->xmit_in = 0;
  31116. +    vt->allocinit = 1;
  31117. +    }
  31118. +    return 0;
  31119. +}
  31120. +
  31121. +static int vt_disallocate (struct vt *vt)
  31122. +{
  31123. +    if (vt_allocated (vt)) {
  31124. +    void *data = vt->vcd;
  31125. +
  31126. +    vt->allocinit = 0;
  31127. +    vcd_disallocate (vt);
  31128. +    vt->vcd = NULL;
  31129. +    vt->kbd = NULL;
  31130. +    vt->vtd = NULL;
  31131. +
  31132. +    kfree (data);
  31133. +    }
  31134. +    return 0;
  31135. +}
  31136. +
  31137. +static void vt_updatescreen (const struct vt *newvt)
  31138. +{
  31139. +    static int lock = 0;
  31140. +
  31141. +    if (newvt == vtdata.fgconsole || lock)
  31142. +    return;
  31143. +
  31144. +    if (!vt_allocated (newvt)) {
  31145. +    printk ("updatescreen: tty %d not allocated ??\n", newvt->num);
  31146. +    return;
  31147. +    }
  31148. +
  31149. +    lock = 1;
  31150. +
  31151. +    vcd_savestate (vtdata.fgconsole, vtdata.blanked != NULL);
  31152. +
  31153. +    vtdata.fgconsole = (struct vt *)newvt;
  31154. +
  31155. +    vcd_restorestate (vtdata.fgconsole);
  31156. +    compute_shiftstate ();
  31157. +
  31158. +    lock = 0;
  31159. +}
  31160. +
  31161. +/*
  31162. + * Performs the back end of a vt switch
  31163. + */
  31164. +void vt_completechangeconsole (const struct vt *new_console)
  31165. +{
  31166. +    unsigned char old_vt_mode;
  31167. +    struct vt *old_vt = vtdata.fgconsole;
  31168. +
  31169. +    if (new_console == old_vt)
  31170. +    return;
  31171. +    if (!vt_allocated (new_console))
  31172. +    return;
  31173. +    last_console = old_vt;
  31174. +
  31175. +    /*
  31176. +     * If we're switching, we could be going from KD_GRAPHICS to
  31177. +     * KD_TEXT mode or vice versa, which means we need to blank or
  31178. +     * unblank the screen later.
  31179. +     */
  31180. +    old_vt_mode = old_vt->vtd->vc_mode;
  31181. +    vt_updatescreen (new_console);
  31182. +
  31183. +    /*
  31184. +     * If this new console is under process control, send it a signal
  31185. +     * telling it that it has acquired. Also check if it has died and
  31186. +     * clean up (similar to logic employed in vt_changeconsole())
  31187. +     */
  31188. +    if (new_console->vtd->vt_mode.mode == VT_PROCESS) {
  31189. +    /*
  31190. +     * Send the signal as privileged - kill_proc() will
  31191. +     * tell us if the process has gone or something else
  31192. +     * is awry
  31193. +     */
  31194. +    if (kill_proc(new_console->vtd->vt_pid,
  31195. +                  new_console->vtd->vt_mode.acqsig,
  31196. +                  1) != 0) {
  31197. +        /*
  31198. +         * The controlling process has died, so we revert back to
  31199. +         * normal operation. In this case, we'll also change back
  31200. +         * to KD_TEXT mode. I'm not sure if this is strictly correct
  31201. +         * but it saves the agony when the X server dies and the screen
  31202. +         * remains blanked due to KD_GRAPHICS! It would be nice to do
  31203. +         * this outside of VT_PROCESS but there is no single process
  31204. +         * to account for and tracking tty count may be undesirable.
  31205. +         */
  31206. +        vt_reset (new_console);
  31207. +    }
  31208. +    }
  31209. +
  31210. +    /*
  31211. +     * We do this here because the controlling process above may have
  31212. +     * gone, and so there is now a new vc_mode
  31213. +     */
  31214. +    if (old_vt_mode != new_console->vtd->vc_mode) {
  31215. +    if (new_console->vtd->vc_mode == KD_TEXT)
  31216. +        vt_do_unblankscreen ();
  31217. +    else {
  31218. +        vt_do_blankscreen (1);
  31219. +        vcd_setup_graphics (new_console);
  31220. +    }
  31221. +    }
  31222. +
  31223. +    /* Set the colour palette for this VT */
  31224. +    if (new_console->vtd->vc_mode == KD_TEXT)
  31225. +    con_set_palette (new_console);
  31226. +    
  31227. +    /*
  31228. +     * Wake anyone waiting for their VT to activate
  31229. +     */
  31230. +    vt_wake_waitactive();
  31231. +    return;
  31232. +}
  31233. +
  31234. +/*
  31235. + * Performs the front-end of a vt switch
  31236. + */
  31237. +void vt_changeconsole (struct vt *new_console)
  31238. +{
  31239. +    struct vt *old_vt = vtdata.fgconsole;
  31240. +
  31241. +    if (new_console == old_vt)
  31242. +    return;
  31243. +    if (!vt_allocated (new_console))
  31244. +    return;
  31245. +
  31246. +    /*
  31247. +     * If this vt is in process mode, then we need to handshake with
  31248. +     * that process before switching. Essentially, we store where that
  31249. +     * vt wants to switch to and wait for it to tell us when it's done
  31250. +     * (via VT_RELDISP ioctl).
  31251. +     *
  31252. +     * We also check to see if the controlling process still exists.
  31253. +     * If it doesn't, we reset this vt to auto mode and continue.
  31254. +     * This is a cheap way to track process control. The worst thing
  31255. +     * that can happen is: we send a signal to a process, it dies, and
  31256. +     * the switch gets "lost" waiting for a response; hopefully, the
  31257. +     * user will try again, we'll detect the process is gone (unless
  31258. +     * the user waits just the right amount of time :-) and revert the
  31259. +     * vt to auto control.
  31260. +     */
  31261. +    if (old_vt->vtd->vt_mode.mode == VT_PROCESS) {
  31262. +    /*
  31263. +     * Send the signal as privileged - kill_proc() will
  31264. +     * tell us if the process has gone or something else
  31265. +     * is awry
  31266. +     */
  31267. +    if (kill_proc(old_vt->vtd->vt_pid, old_vt->vtd->vt_mode.relsig, 1) == 0) {
  31268. +        /*
  31269. +         * It worked. Mark the vt to switch to and
  31270. +         * return. The process needs to send us a
  31271. +         * VT_RELDISP ioctl to complete the switch.
  31272. +         */
  31273. +        old_vt->vtd->vt_newvt = new_console;
  31274. +        return;
  31275. +    }
  31276. +
  31277. +    /*
  31278. +     * The controlling process has died, so we revert back to
  31279. +     * normal operation. In this case, we'll also change back
  31280. +     * to KD_TEXT mode. I'm not sure if this is strictly correct
  31281. +     * but it saves the agony when the X server dies and the screen
  31282. +     * remains blanked due to KD_GRAPHICS! It would be nice to do
  31283. +     * this outside of VT_PROCESS but there is no single process
  31284. +     * to account for and tracking tty count may be undesirable.
  31285. +     */
  31286. +    vt_reset (old_vt);
  31287. +
  31288. +    /*
  31289. +     * Fall through to normal (VT_AUTO) handling of the switch...
  31290. +     */
  31291. +    }
  31292. +
  31293. +    /*
  31294. +     * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
  31295. +     */
  31296. +    if (old_vt->vtd->vc_mode == KD_GRAPHICS)
  31297. +    return;
  31298. +
  31299. +    vt_completechangeconsole (new_console);
  31300. +}
  31301. +
  31302. +/*
  31303. + * If a vt is under process control, the kernel will not switch to it
  31304. + * immediately, but postpone the operation until the process calls this
  31305. + * ioctl, allowing the switch to complete.
  31306. + *
  31307. + * According to the X sources this is the behavior:
  31308. + *      0:      pending switch-from not OK
  31309. + *      1:      pending switch-from OK
  31310. + *      2:      completed switch-to OK
  31311. + */
  31312. +static inline int vt_reldisp (const struct vt *old_vt, int arg)
  31313. +{
  31314. +    int i;
  31315. +
  31316. +    if (old_vt->vtd->vt_mode.mode != VT_PROCESS)
  31317. +    return -EINVAL;
  31318. +
  31319. +    if (old_vt->vtd->vt_newvt) {
  31320. +    /*
  31321. +     * Switching-from response
  31322. +     */
  31323. +    if (arg == 0)
  31324. +        /*
  31325. +         * Switch disallowed, so forget we were trying
  31326. +         * to do it.
  31327. +         */
  31328. +        old_vt->vtd->vt_newvt = NULL;
  31329. +    else {
  31330. +        /*
  31331. +         * The current vt has been released, so complete the
  31332. +         * switch.
  31333. +         */
  31334. +        struct vt *new_vt = old_vt->vtd->vt_newvt;
  31335. +        old_vt->vtd->vt_newvt = NULL;
  31336. +        i = vt_allocate (new_vt);
  31337. +        if (i)
  31338. +        return i;
  31339. +        vt_completechangeconsole (new_vt);
  31340. +    }
  31341. +    } else {
  31342. +    /*
  31343. +     * Switched-to response
  31344. +     */
  31345. +    if (arg != VT_ACKACQ)
  31346. +        return -EINVAL;
  31347. +    }
  31348. +    return 0;
  31349. +}
  31350. +
  31351. +/*
  31352. + * Set the mode of a VT.
  31353. + */
  31354. +static inline int vt_kdsetmode (const struct vt *vt, int mode)
  31355. +{
  31356. +    /*
  31357. +     * Currently, setting the mode from KD_TEXT to KD_GRAPHICS
  31358. +     * doesn't do a whole lot. I'm not sure if it should do any
  31359. +     * restoration of modes or what...
  31360. +     */
  31361. +    switch (mode) {
  31362. +    case KD_TEXT0:
  31363. +    case KD_TEXT1:
  31364. +    mode = KD_TEXT;
  31365. +    case KD_GRAPHICS:
  31366. +    case KD_TEXT:
  31367. +    break;
  31368. +    default:
  31369. +    return -EINVAL;
  31370. +    }
  31371. +
  31372. +    if (vt->vtd->vc_mode == mode)
  31373. +    return 0;
  31374. +
  31375. +    vt->vtd->vc_mode = mode;
  31376. +    if (vt != vtdata.fgconsole)
  31377. +    return 0;
  31378. +
  31379. +    /*
  31380. +     * explicitly blank/unblank the screen if switching modes
  31381. +     */
  31382. +    if (mode == KD_TEXT) {
  31383. +    vt_do_unblankscreen ();
  31384. +        vcd_restorestate (vt);
  31385. +    } else {
  31386. +    vt_do_blankscreen (1);
  31387. +    vcd_setup_graphics (vt);
  31388. +    }
  31389. +    return 0;
  31390. +}
  31391. +
  31392. +static inline int vt_setmode (const struct vt *vt, struct vt_mode *vtmode)
  31393. +{
  31394. +    if (vtmode->mode != VT_AUTO && vtmode->mode != VT_PROCESS)
  31395. +    return -EINVAL;
  31396. +
  31397. +    vt->vtd->vt_mode = *vtmode;
  31398. +    vt->vtd->vt_mode.frsig = 0;
  31399. +    vt->vtd->vt_pid = current->pid;
  31400. +    vt->vtd->vt_newvt = NULL;
  31401. +    return 0;
  31402. +}
  31403. +
  31404. +void vt_mksound (unsigned int count, unsigned int vol, unsigned int ticks)
  31405. +{
  31406. +    extern void mk_beep (unsigned int, unsigned int, unsigned int);
  31407. +#ifdef CONFIG_SOUND
  31408. +    mk_beep (count, vol, ticks);
  31409. +#endif
  31410. +}
  31411. +
  31412. +/*
  31413. + * Deallocate memory associated to VT (but leave VT1)
  31414. + */
  31415. +int vt_deallocate (int arg)
  31416. +{
  31417. +    int i;
  31418. +
  31419. +    if (arg == 0) {
  31420. +    /*
  31421. +     * deallocate all unused consoles, but leave 0
  31422. +     */
  31423. +    for (i = 1; i < MAX_NR_CONSOLES; i++)
  31424. +        if (!VT_BUSY (i))
  31425. +        vt_disallocate (vt_con_data + i);
  31426. +    } else {
  31427. +    arg -= 1;
  31428. +    if (VT_BUSY (arg))
  31429. +        return -EBUSY;
  31430. +    if (arg)
  31431. +        vt_disallocate (vt_con_data + arg);
  31432. +    }
  31433. +    return 0;
  31434. +}
  31435. +
  31436. +int vt_resize (int columns, int rows)
  31437. +{
  31438. +    return vcd_resize (rows, columns);
  31439. +}
  31440. +
  31441. +void vt_pokeblankedconsole (void)
  31442. +{
  31443. +    timer_active &= ~(1 << BLANK_TIMER);
  31444. +    if (vtdata.fgconsole->vtd->vc_mode == KD_GRAPHICS)
  31445. +    return;
  31446. +    if (vtdata.blanked) {
  31447. +    timer_table[BLANK_TIMER].expires = 0;
  31448. +    timer_active |= 1 << BLANK_TIMER;
  31449. +    } else
  31450. +    if (vtdata.screen.blankinterval) {
  31451. +    timer_table[BLANK_TIMER].expires = jiffies + vtdata.screen.blankinterval;
  31452. +    timer_active |= 1 << BLANK_TIMER;
  31453. +    }
  31454. +}
  31455. +
  31456. +static void vt_blankscreen (void);
  31457. +
  31458. +void vt_do_unblankscreen (void)
  31459. +{
  31460. +    if (!vtdata.blanked)
  31461. +    return;
  31462. +
  31463. +    if (!vt_allocated (vtdata.fgconsole)) {
  31464. +    /* impossible... */
  31465. +    printk ("unblank_screen: tty %d not allocated ??\n", vtdata.fgconsole->num);
  31466. +    return;
  31467. +    }
  31468. +
  31469. +    timer_table[BLANK_TIMER].fn = vt_blankscreen;
  31470. +
  31471. +    if (vtdata.screen.blankinterval) {
  31472. +    timer_table[BLANK_TIMER].expires = jiffies + vtdata.screen.blankinterval;
  31473. +    timer_active |= 1 << BLANK_TIMER;
  31474. +    }
  31475. +
  31476. +    vtdata.blanked = NULL;
  31477. +
  31478. +    vcd_unblankscreen ();
  31479. +}
  31480. +
  31481. +/*
  31482. + * for panic.c
  31483. + */
  31484. +void do_unblank_screen (void)
  31485. +{
  31486. +    vt_do_unblankscreen ();
  31487. +}
  31488. +
  31489. +void vt_do_blankscreen (int nopowersave)
  31490. +{
  31491. +    if (vtdata.blanked)
  31492. +    return;
  31493. +
  31494. +    timer_active &= ~(1 << BLANK_TIMER);
  31495. +    timer_table[BLANK_TIMER].fn = do_unblank_screen;
  31496. +
  31497. +    vtdata.blanked = vtdata.fgconsole;
  31498. +
  31499. +    vcd_blankscreen (nopowersave);
  31500. +}
  31501. +
  31502. +static void vt_blankscreen (void)
  31503. +{
  31504. +    vt_do_blankscreen (0);
  31505. +}
  31506. +
  31507. +static int vt_open (struct tty_struct *tty, struct file *filp)
  31508. +{
  31509. +    struct vt *vt;
  31510. +    unsigned int idx;
  31511. +    int i;
  31512. +
  31513. +    idx = MINOR(tty->device) - tty->driver.minor_start;
  31514. +
  31515. +    vt = vt_con_data + idx;
  31516. +
  31517. +    if ((i = vt_allocate (vt)) < 0)
  31518. +    return i;
  31519. +
  31520. +    tty->driver_data = vt;
  31521. +
  31522. +    if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
  31523. +    tty->winsize.ws_row = vtdata.numrows;
  31524. +    tty->winsize.ws_col = vtdata.numcolumns;
  31525. +    }
  31526. +    return 0;
  31527. +}
  31528. +
  31529. +static void vt_vtd_flush_chars (const struct vt *vt, struct vt_struct *vtd)
  31530. +{
  31531. +    unsigned long flags;
  31532. +
  31533. +    save_flags (flags);
  31534. +    if (vtd->xmitting)
  31535. +    return;
  31536. +
  31537. +    vtd->xmitting = 1;
  31538. +
  31539. +    while (1) {
  31540. +    int c;
  31541. +
  31542. +    cli ();
  31543. +    c = MIN(vtd->xmit_cnt, CON_XMIT_SIZE - vtd->xmit_out);
  31544. +
  31545. +    if (c <= 0)
  31546. +        break;
  31547. +
  31548. +    restore_flags (flags);
  31549. +
  31550. +    c = vcd_write (vt, 0, vtd->xmit_buf + vtd->xmit_out, c);
  31551. +
  31552. +    cli ();
  31553. +
  31554. +    if (c <= 0)
  31555. +        break;
  31556. +    vtd->xmit_out = (vtd->xmit_out + c) & (CON_XMIT_SIZE - 1);
  31557. +    vtd->xmit_cnt -= c;
  31558. +    }
  31559. +
  31560. +    vtd->xmitting = 0;
  31561. +    restore_flags (flags);
  31562. +    if (*vt->tty)
  31563. +    wake_up_interruptible (&(*vt->tty)->write_wait);
  31564. +}
  31565. +
  31566. +static int vt_write (struct tty_struct *tty, int from_user,
  31567. +            const unsigned char *buf, int count)
  31568. +{
  31569. +    static unsigned long last_error = 0;
  31570. +    const struct vt *vt = (struct vt *)tty->driver_data;
  31571. +
  31572. +    if (vt_allocated (vt)) {
  31573. +    if (vt->vtd->xmit_cnt)
  31574. +        vt_vtd_flush_chars (vt, vt->vtd);
  31575. +    return vcd_write (vt, from_user, buf, count);
  31576. +    }
  31577. +
  31578. +    if (jiffies > last_error + 10*HZ) {
  31579. +    printk ("vt_write: tty %d not allocated\n", vt->num);
  31580. +    last_error = jiffies;
  31581. +    }
  31582. +    return 0;
  31583. +}
  31584. +
  31585. +static void vt_put_char (struct tty_struct *tty, unsigned char ch)
  31586. +{
  31587. +    const struct vt *vt = (struct vt *)tty->driver_data;
  31588. +    unsigned long flags;
  31589. +
  31590. +    if (!vt_allocated (vt))
  31591. +    return;
  31592. +
  31593. +    save_flags_cli (flags);
  31594. +    if (vt->vtd->xmit_cnt < CON_XMIT_SIZE - 1) {
  31595. +    vt->vtd->xmit_buf[vt->vtd->xmit_in++] = ch;
  31596. +    vt->vtd->xmit_in &= CON_XMIT_SIZE - 1;
  31597. +    vt->vtd->xmit_cnt ++;
  31598. +    }
  31599. +    restore_flags (flags);
  31600. +}
  31601. +
  31602. +static void vt_flush_chars (struct tty_struct *tty)
  31603. +{
  31604. +    const struct vt *vt = (struct vt *)tty->driver_data;
  31605. +
  31606. +    if (!vt_allocated (vt) || !vt->vtd->xmit_cnt || tty->stopped)
  31607. +    return;
  31608. +
  31609. +    vt_vtd_flush_chars (vt, vt->vtd);
  31610. +}
  31611. +
  31612. +static int vt_write_room (struct tty_struct *tty)
  31613. +{
  31614. +    const struct vt *vt = (struct vt *)tty->driver_data;
  31615. +    int r;
  31616. +
  31617. +    if (!vt_allocated (vt))
  31618. +    return 0;
  31619. +
  31620. +    r = CON_XMIT_SIZE - vt->vtd->xmit_cnt - 8; /* allow 8 char overflow */
  31621. +    if (r < 0)
  31622. +    return 0;
  31623. +    else
  31624. +    return r;
  31625. +}
  31626. +
  31627. +static int vt_chars_in_buffer (struct tty_struct *tty)
  31628. +{
  31629. +    const struct vt *vt = (struct vt *)tty->driver_data;
  31630. +
  31631. +    if (!vt_allocated (vt))
  31632. +    return CON_XMIT_SIZE;
  31633. +    return vt->vtd->xmit_cnt;
  31634. +}
  31635. +#if 0
  31636. +static void vt_flush_buffer (struct tty_struct *tty)
  31637. +{
  31638. +    const struct vt *vt = (struct vt *)tty->driver_data;
  31639. +
  31640. +    if (!vt_allocated (vt))
  31641. +    return;
  31642. +
  31643. +    cli ();
  31644. +    vt->vtd->xmit_cnt = vt->vtd->xmit_out = vt->vtd->xmit_in = 0;
  31645. +    sti ();
  31646. +}
  31647. +#endif
  31648. +static int vt_ioctl (struct tty_struct *tty, struct file *filp,
  31649. +            unsigned int cmd, unsigned long arg)
  31650. +{
  31651. +    struct vt *vt = tty->driver_data;
  31652. +    int perm, i;
  31653. +
  31654. +    if (!vt_allocated (vt))    /* impossible ? */
  31655. +    return -ENOIOCTLCMD;
  31656. +    /*
  31657. +     * To have permissions to do most of the vt ioctls, we either
  31658. +     * have to be the owner of the tty, or super-user.
  31659. +     */
  31660. +    perm = 0;
  31661. +    if (current->tty == tty || suser ())
  31662. +    perm = 1;
  31663. +
  31664. +    switch (cmd) {
  31665. +    case KDGETMODE:
  31666. +    i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned long));
  31667. +    if (!i)
  31668. +        put_user (vt->vtd->vc_mode, (unsigned long *)arg);
  31669. +    return i;
  31670. +
  31671. +    case VT_GETMODE:
  31672. +    i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (struct vt_mode));
  31673. +    if (i)
  31674. +        return i;
  31675. +    memcpy_tofs ((void *)arg, &vt->vtd->vt_mode, sizeof (struct vt_mode));
  31676. +    return 0;
  31677. +
  31678. +    case VT_GETSTATE: {
  31679. +    /*
  31680. +     * Returns global VT state.  Note that VT 0 is always open, since
  31681. +     * it's an alias for the current VT, and people can't use it here.
  31682. +     * We cannot return state for more than 16 VTs, since v_state is short.
  31683. +     */
  31684. +    struct vt_stat *vtstat = (struct vt_stat *)arg;
  31685. +    unsigned short state = 1, mask = 2;
  31686. +
  31687. +    i = verify_area (VERIFY_WRITE, vtstat, sizeof (struct vt_stat));
  31688. +    if (i)
  31689. +        return i;
  31690. +
  31691. +    for (i = 0; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
  31692. +        if (VT_IS_IN_USE(i))
  31693. +        state |= mask;
  31694. +
  31695. +    put_user (vtdata.fgconsole->num, &vtstat->v_active);
  31696. +    put_user (state, &vtstat->v_state);
  31697. +    return 0;
  31698. +    }
  31699. +
  31700. +    case VT_OPENQRY:
  31701. +    /*
  31702. +     * Returns the first available (non-open) console
  31703. +     */
  31704. +    i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned long));
  31705. +    if (i)
  31706. +        return i;
  31707. +
  31708. +    for (i = 0; i < MAX_NR_CONSOLES; i++)
  31709. +        if (!VT_IS_IN_USE(i))
  31710. +        break;
  31711. +    if (i < MAX_NR_CONSOLES)
  31712. +        put_user (i + 1, (unsigned long *)arg);
  31713. +    else
  31714. +        put_user (-1, (unsigned long *)arg);
  31715. +    return 0;
  31716. +
  31717. +    case VT_DISALLOCATE:
  31718. +    if (arg > MAX_NR_CONSOLES)
  31719. +        return -ENXIO;
  31720. +    return vt_deallocate (arg);
  31721. +
  31722. +    case VT_GETSCRINFO:
  31723. +    /*
  31724. +     * Get screen dimentions
  31725. +     */
  31726. +    i = verify_area (VERIFY_WRITE, (void *)arg, 5 * sizeof (unsigned long));
  31727. +    if (!i) {
  31728. +        put_user (0, (unsigned long *)arg);
  31729. +        put_user (vtdata.numcolumns * 8, (unsigned long *)(arg + 4));
  31730. +        put_user (vtdata.numrows * 8, (unsigned long *)(arg + 8));
  31731. +        put_user (vtdata.screen.bitsperpix, (unsigned long *)(arg + 12)); /* bpp */
  31732. +        put_user (4, (unsigned long *)(arg + 16)); /* depth */
  31733. +    }
  31734. +    return i;
  31735. +
  31736. +    case KDGKBTYPE:
  31737. +    case KDADDIO:
  31738. +    case KDDELIO:
  31739. +    case KDENABIO:
  31740. +    case KDDISABIO:
  31741. +    case KDGKBMODE:
  31742. +    case KDGKBMETA:
  31743. +    case KDGETKEYCODE:
  31744. +    case KDGKBENT:
  31745. +    case KDGKBSENT:
  31746. +    case KDGKBDIACR:
  31747. +    case KDGKBLED:
  31748. +    case KDGETLED:
  31749. +    return kbd_ioctl (vt, cmd, arg);
  31750. +
  31751. +    case VT_GETPALETTE:
  31752. +    case GIO_FONT:
  31753. +    case GIO_SCRNMAP:
  31754. +    case GIO_UNISCRNMAP:
  31755. +    case GIO_UNIMAP:
  31756. +    return vcd_ioctl (vt, cmd, arg);
  31757. +    }
  31758. +
  31759. +    if (!perm)
  31760. +    return -EPERM;
  31761. +
  31762. +    switch (cmd) {
  31763. +    case KDSETMODE:
  31764. +    return vt_kdsetmode (vt, arg);
  31765. +
  31766. +    case VT_SETMODE: {
  31767. +    struct vt_mode vtmode;
  31768. +
  31769. +    if (!perm)
  31770. +        return -EPERM;
  31771. +    i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct vt_mode));
  31772. +    if (i)
  31773. +        return i;
  31774. +    memcpy_fromfs (&vtmode, (void *)arg, sizeof (struct vt_mode));
  31775. +    return vt_setmode (vt, &vtmode);
  31776. +    }
  31777. +
  31778. +    case VT_ACTIVATE:
  31779. +    /*
  31780. +     * VT activate will cause us to switch to vt #num with num >= 1
  31781. +     * (switches to vt0, our console, are not allowed, just to preserve
  31782. +     * sanity)
  31783. +     */
  31784. +    if (arg == 0 || arg > MAX_NR_CONSOLES)
  31785. +        return -ENXIO;
  31786. +    vt = vt_con_data + (arg - 1);
  31787. +    i = vt_allocate (vt);
  31788. +    if (i)
  31789. +        return i;
  31790. +
  31791. +    vt_changeconsole (vt);
  31792. +    return 0;
  31793. +
  31794. +    case VT_WAITACTIVE:
  31795. +    /*
  31796. +     * wait until the specified VT has been activated
  31797. +     */
  31798. +    if (arg == 0 || arg > MAX_NR_CONSOLES)
  31799. +        return -ENXIO;
  31800. +    vt = vt_con_data + (arg - 1);
  31801. +    while (vt != vtdata.fgconsole) {
  31802. +        if (vt_waitonactivate () < 0)
  31803. +        return -EINTR;
  31804. +        }
  31805. +    return 0;
  31806. +
  31807. +    case VT_RELDISP:
  31808. +    return vt_reldisp (vt, arg);
  31809. +
  31810. +    case VT_RESIZE: {
  31811. +    struct vt_sizes *vtsizes = (struct vt_sizes *)arg;
  31812. +    ushort ll, cc;
  31813. +    i = verify_area (VERIFY_READ, (void *)vtsizes, sizeof (struct vt_sizes));
  31814. +    if (i)
  31815. +        return i;
  31816. +    ll = get_user (&vtsizes->v_rows);
  31817. +    cc = get_user (&vtsizes->v_cols);
  31818. +    return vt_resize (cc, ll);
  31819. +    }
  31820. +
  31821. +    case KIOCSOUND:
  31822. +    vt_mksound (arg, 72, 5);
  31823. +    return 0;
  31824. +
  31825. +    case KDMKTONE: {
  31826. +    unsigned int freq  = get_user ((unsigned long *)arg);
  31827. +    unsigned int vol   = get_user ((unsigned long *)(arg + 4));
  31828. +    unsigned int ticks = get_user ((unsigned long *)(arg + 8));
  31829. +
  31830. +    /*
  31831. +     * Generate the tone for the apropriate number of ticks.
  31832. +     * If time is zero, turn off sound ourselves.
  31833. +     */
  31834. +    vt_mksound (freq, vol, ticks);
  31835. +    return 0;
  31836. +    }
  31837. +
  31838. +    case KDMAPDISP:
  31839. +    case KDUNMAPDISP:
  31840. +    case KDSKBMODE:
  31841. +    case KDSKBMETA:
  31842. +    case KDSETKEYCODE:
  31843. +    case KDSKBENT:
  31844. +    case KDSKBSENT:
  31845. +    case KDSKBDIACR:
  31846. +    case KDSKBLED:
  31847. +    case KDSETLED:
  31848. +    case KDSIGACCEPT:
  31849. +    return kbd_ioctl (vt, cmd, arg);
  31850. +
  31851. +    case VT_SETPALETTE:
  31852. +    case PIO_FONT:
  31853. +    case PIO_SCRNMAP:
  31854. +    case PIO_UNISCRNMAP:
  31855. +    case PIO_UNIMAPCLR:
  31856. +    case PIO_UNIMAP:
  31857. +    return vcd_ioctl (vt, cmd, arg);
  31858. +    }
  31859. +    return -ENOIOCTLCMD;
  31860. +}
  31861. +/*
  31862. + * Turn the Scroll-Lock LED on when the tty is stopped
  31863. + */
  31864. +static void vt_stop (struct tty_struct *tty)
  31865. +{
  31866. +    if (tty) {
  31867. +    const struct vt *vt = (struct vt *)tty->driver_data;
  31868. +    if (vt_allocated (vt)) {
  31869. +        set_vc_kbd_led (vt->kbd, VC_SCROLLOCK);
  31870. +        set_leds ();
  31871. +    }
  31872. +    }
  31873. +}
  31874. +
  31875. +/*
  31876. + * Turn the Scroll-Lock LED off when the tty is started
  31877. + */
  31878. +static void vt_start (struct tty_struct *tty)
  31879. +{
  31880. +    if (tty) {
  31881. +    const struct vt *vt = (struct vt *)tty->driver_data;
  31882. +    if (vt_allocated (vt)) {
  31883. +        clr_vc_kbd_led (vt->kbd, VC_SCROLLOCK);
  31884. +        set_leds ();
  31885. +    }
  31886. +    if (vt->vtd->xmit_cnt)
  31887. +        vt_vtd_flush_chars (vt, vt->vtd);
  31888. +    }
  31889. +}
  31890. +
  31891. +/*
  31892. + * vt_throttle and vt_unthrottle are only used for
  31893. + * paste_selection(), which has to stuff in a large number
  31894. + * of characters...
  31895. + */
  31896. +static void vt_throttle (struct tty_struct *tty)
  31897. +{
  31898. +}
  31899. +
  31900. +static void vt_unthrottle (struct tty_struct *tty)
  31901. +{
  31902. +    const struct vt *vt = (struct vt *)tty->driver_data;
  31903. +
  31904. +    if (vt_allocated (vt))
  31905. +    wake_up_interruptible (&vt->vtd->paste_wait);
  31906. +}
  31907. +
  31908. +/*
  31909. + * We don't have kmalloc setup yet.  We just want to get enough up so that printk
  31910. + * can work.
  31911. + *
  31912. + * Basically, we setup the VT structures for tty1.
  31913. + */
  31914. +unsigned long vt_pre_init (unsigned long kmem)
  31915. +{
  31916. +    struct vt *vt = vt_con_data;
  31917. +
  31918. +    memset (vt_con_data, 0, sizeof (vt_con_data));
  31919. +
  31920. +    vtdata.numcolumns    = ORIG_VIDEO_COLS;
  31921. +    vtdata.numrows    = ORIG_VIDEO_LINES;
  31922. +    vtdata.blanked    = NULL;
  31923. +    vtdata.fgconsole    = vt_con_data;
  31924. +    vtdata.screen.blankinterval = 10*60*HZ;
  31925. +    vtdata.select.vt    = NULL;
  31926. +    vtdata.select.start = -1;
  31927. +    vtdata.select.end    = 0;
  31928. +    vtdata.select.buffer= NULL;
  31929. +
  31930. +    vt->vcd = (struct con_struct *)kmem;    kmem += sizeof (struct con_struct);
  31931. +    vt->kbd = (struct kbd_struct *)kmem;    kmem += sizeof (struct kbd_struct);
  31932. +    vt->vtd = (struct vt_struct *)kmem;        kmem += sizeof (struct vt_struct);
  31933. +    vt->vtd->xmit_buf = (unsigned char *)kmem;    kmem += CON_XMIT_SIZE;
  31934. +    vt->vtd->xmitting = vt->vtd->xmit_cnt =
  31935. +    vt->vtd->xmit_out = vt->vtd->xmit_in = 0;
  31936. +    vt->tty = &vt_table[0];
  31937. +    vt->num = 1;
  31938. +
  31939. +    /*
  31940. +     * vcd_init is called inside vcd_pre_init
  31941. +     */
  31942. +    kbd_struct_init (vt, 0);
  31943. +    vt_reset (vt);
  31944. +    vt->allocinit = 1;
  31945. +
  31946. +    kmem = vcd_pre_init (kmem, vt);
  31947. +
  31948. +    return kmem;
  31949. +}
  31950. +
  31951. +/*
  31952. + * This is the post initialisation.  We have kmalloc setup so we can use it...
  31953. + */
  31954. +void vt_post_init (void)
  31955. +{
  31956. +    int i;
  31957. +
  31958. +    memset (&vt_driver, 0, sizeof (struct tty_driver));
  31959. +    vt_driver.magic        = TTY_DRIVER_MAGIC;
  31960. +    vt_driver.name        = "tty";
  31961. +    vt_driver.name_base        = 1;
  31962. +    vt_driver.major        = TTY_MAJOR;
  31963. +    vt_driver.minor_start    = 1;
  31964. +    vt_driver.num        = MAX_NR_CONSOLES;
  31965. +    vt_driver.type        = TTY_DRIVER_TYPE_CONSOLE;
  31966. +    vt_driver.init_termios    = tty_std_termios;
  31967. +    vt_driver.flags        = TTY_DRIVER_REAL_RAW;
  31968. +    vt_driver.refcount        = &vt_refcount;
  31969. +    vt_driver.table        = vt_table;
  31970. +    vt_driver.termios        = vt_termios;
  31971. +    vt_driver.termios_locked    = vt_termios_locked;
  31972. +    vt_driver.open        = vt_open;
  31973. +    vt_driver.write        = vt_write;
  31974. +    vt_driver.put_char        = vt_put_char;
  31975. +    vt_driver.flush_chars    = vt_flush_chars;
  31976. +    vt_driver.write_room    = vt_write_room;
  31977. +    vt_driver.chars_in_buffer    = vt_chars_in_buffer;
  31978. +#if 0
  31979. +    vt_driver.flush_buffer    = vt_flush_buffer;
  31980. +#endif
  31981. +    vt_driver.ioctl        = vt_ioctl;
  31982. +    vt_driver.stop        = vt_stop;
  31983. +    vt_driver.start        = vt_start;
  31984. +    vt_driver.throttle        = vt_throttle;
  31985. +    vt_driver.unthrottle    = vt_unthrottle;
  31986. +
  31987. +    for (i = 1; i < MAX_NR_CONSOLES; i++) {
  31988. +    struct vt *vt = vt_con_data + i;
  31989. +    vt->tty = &vt_table[i];
  31990. +    vt->num = i + 1;
  31991. +    vt->allocinit = 0;
  31992. +    if (i < MIN_NR_CONSOLES)
  31993. +        vt_allocate (vt);
  31994. +    }
  31995. +
  31996. +    if (tty_register_driver (&vt_driver))
  31997. +    panic ("Couldn't register console driver");
  31998. +
  31999. +    timer_table[BLANK_TIMER].fn    = vt_blankscreen;
  32000. +    if (vtdata.screen.blankinterval) {
  32001. +    timer_table[BLANK_TIMER].expires = jiffies + vtdata.screen.blankinterval;
  32002. +    timer_active |= 1 << BLANK_TIMER;
  32003. +    } else
  32004. +    timer_table[BLANK_TIMER].expires = 0;
  32005. +
  32006. +    kbd_init ();
  32007. +    vcs_init ();
  32008. +}
  32009. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/char/vt_kern.h linux/arch/arm/drivers/char/vt_kern.h
  32010. --- linux.orig/arch/arm/drivers/char/vt_kern.h    Thu Jan  1 01:00:00 1970
  32011. +++ linux/arch/arm/drivers/char/vt_kern.h    Fri Sep  6 22:23:13 1996
  32012. @@ -0,0 +1,201 @@
  32013. +/*
  32014. + * linux/arch/arm/drivers/char/vt.h
  32015. + *
  32016. + * Virtual Terminal bits...
  32017. + */
  32018. +
  32019. +#ifndef _VT_KERN_H
  32020. +#define _VT_KERN_H
  32021. +
  32022. +#include <linux/vt.h>
  32023. +#define NPAR 16
  32024. +#define SEL_BUFFER_SIZE 4096
  32025. +
  32026. +struct vc_state {
  32027. +    unsigned char    forecol;        /* foreground            */
  32028. +    unsigned char    backcol;        /* background            */
  32029. +    unsigned char    x;            /* x position            */
  32030. +    unsigned char    y;            /* y position            */
  32031. +#define FLG_BOLD    0x01
  32032. +#define FLG_ITALIC    0x02
  32033. +#define FLG_UNDERLINE    0x04
  32034. +#define FLG_FLASH    0x08
  32035. +#define FLG_INVERSE    0x10
  32036. +#define FLG_CHRSET    0x20
  32037. +    unsigned char    flags;            /* special flags        */
  32038. +    unsigned char    G0_charset;        /* G0 character set        */
  32039. +    unsigned char    G1_charset;        /* G1 character set        */
  32040. +    unsigned char    __unused;        /* unused            */
  32041. +};
  32042. +
  32043. +struct con_struct {
  32044. +    struct {
  32045. +    unsigned int    origin;            /* address of top-left        */
  32046. +    unsigned int    pos;            /* current position into screen    */
  32047. +    unsigned long    *palette_entries;    /* Current palette        */
  32048. +    unsigned int    cursoron;        /* Cursor on count        */
  32049. +    } screen;
  32050. +
  32051. +    struct {
  32052. +    unsigned long    *buffer;        /* pointer to actual buffer    */
  32053. +    unsigned int    size;            /* size of buffer        */
  32054. +    unsigned int    pos;            /* current position into buffer */
  32055. +    unsigned char    kmalloced    : 1;    /* buffer kmalloced        */
  32056. +    } buffer;
  32057. +
  32058. +    /*
  32059. +     * State
  32060. +     */
  32061. +    struct vc_state    curstate;        /* current state        */
  32062. +    struct vc_state    savedstate;        /* saved state            */
  32063. +    unsigned long    combined_state;        /* combined state        */
  32064. +    unsigned long    cached_backcolwrd;    /* cached background colour    */
  32065. +    unsigned long    tab_stop[5];        /* tab stops            */
  32066. +    unsigned short    *translate;        /* translation table        */
  32067. +
  32068. +    unsigned char    top;            /* top of scrollable region    */
  32069. +    unsigned char    bottom;            /* bottom of scrollable region    */
  32070. +    unsigned char    def_forecol;        /* default foreground        */
  32071. +    unsigned char    def_backcol;        /* default background        */
  32072. +
  32073. +     unsigned char    cursor_count;        /* on/off cursor count (int)    */
  32074. +
  32075. +      unsigned char    disp_ctrl    : 1;    /* display control characters    */
  32076. +      unsigned char    toggle_meta    : 1;    /* toggle high bit        */
  32077. +      unsigned char    decscnm        : 1;    /* screen mode            */
  32078. +      unsigned char    decom        : 1;    /* origin mode            */
  32079. +      unsigned char    decawm        : 1;    /* autowrap mode        */
  32080. +      unsigned char    deccm        : 1;    /* cursor visible        */
  32081. +      unsigned char    decim        : 1;    /* insert mode            */
  32082. +      unsigned char    deccolm        : 1;    /* 80/132 col mode        */
  32083. +
  32084. +      unsigned char    report_mouse    : 2;    /* mouse reporting?        */
  32085. +      unsigned char    need_wrap    : 1;    /* need to wrap            */
  32086. +      unsigned char    ques        : 1;
  32087. +    /*
  32088. +     * UTF
  32089. +     */
  32090. +      unsigned char    utf        : 1;    /* Unicode UTF-8 encoding    */
  32091. +
  32092. +     unsigned char    utf_count;        /* UTF character count        */
  32093. +    unsigned long    utf_char;        /* UTF character built        */
  32094. +    unsigned long    npar;            /* number of params        */
  32095. +    unsigned long    par[NPAR];        /* params            */
  32096. +    unsigned char    state;            /* Current escape state        */
  32097. +
  32098. +};
  32099. +
  32100. +struct vt_data {
  32101. +    unsigned char    numcolumns;        /* number of columns        */
  32102. +    unsigned char    numrows;        /* number of rows        */
  32103. +    unsigned char    __unused[2];
  32104. +    struct vt        *fgconsole;        /* displayed VC            */
  32105. +    struct vt        *blanked;        /* blanked VC            */
  32106. +    struct {
  32107. +        unsigned char    bitsperpix;        /* bits per pixel        */
  32108. +    unsigned char    bytespercharh;        /* horiz. bytes a char takes    */
  32109. +    unsigned char    bytespercharv;        /* vert. bytes a char takes    */
  32110. +    unsigned char    __unused[1];
  32111. +    unsigned long    sizerow;        /* size of a row of chars    */
  32112. +    unsigned long    totsize;        /* total size            */
  32113. +    unsigned long    memstart;        /* video mem start        */
  32114. +    unsigned long    memmask;        /* video mem mask        */
  32115. +    unsigned long    memend;            /* video mem end        */
  32116. +    unsigned long    blankinterval;        /* blank interval        */
  32117. +    } screen;
  32118. +    struct {
  32119. +    unsigned long    totsize;        /* total buffer size        */
  32120. +    unsigned long    sizerow;        /* size of a row of chars    */
  32121. +    } buffer;
  32122. +    struct {
  32123. +    struct vt    *vt;            /* selected VC            */
  32124. +    int        start;            /* start offset            */
  32125. +    int        end;            /* end offset            */
  32126. +    int        length;            /* buffer length        */
  32127. +    char        *buffer;        /* buffer            */
  32128. +    } select;
  32129. +};
  32130. +
  32131. +extern struct vt_data vtdata;
  32132. +extern struct tty_driver console_driver;
  32133. +
  32134. +struct vt_struct {
  32135. +    unsigned char    vc_mode;        /* hmm...            */
  32136. +    unsigned char    vc_kbdraw;
  32137. +    unsigned char    vc_kbde0;
  32138. +    unsigned char    vc_kbdleds;
  32139. +    struct vt_mode    vt_mode;
  32140. +    pid_t        vt_pid;
  32141. +    struct vt        *vt_newvt;        /* VT to switch to..        */
  32142. +    struct wait_queue    *paste_wait;
  32143. +    unsigned char *    xmit_buf;
  32144. +    unsigned int    xmit_cnt;
  32145. +    unsigned int    xmit_out;
  32146. +    unsigned int    xmit_in;
  32147. +    unsigned int    xmitting;
  32148. +};
  32149. +
  32150. +struct vt {
  32151. +    /*
  32152. +     * Per-console data
  32153. +     */
  32154. +    struct con_struct *vcd;
  32155. +    /*
  32156. +     * Keyboard stuff
  32157. +     */
  32158. +    struct kbd_struct *kbd;
  32159. +    /*
  32160. +     * VT stuff
  32161. +     */
  32162. +    struct vt_struct *vtd;
  32163. +    /*
  32164. +     * tty that this VT is connected to
  32165. +     */
  32166. +    struct tty_struct **tty;
  32167. +    /*
  32168. +     * tty number of this vt struct
  32169. +     */
  32170. +    unsigned char num;
  32171. +    /*
  32172. +     * is this vt allocated and initialised?
  32173. +     */
  32174. +    unsigned char allocinit;
  32175. +    /*
  32176. +     * might add  scrmem at some time, to have everything
  32177. +     * in one place - the disadvantage would be that
  32178. +     * vc_cons etc can no longer be static
  32179. +     */
  32180. +};
  32181. +
  32182. +extern struct vt vt_con_data[];
  32183. +
  32184. +#define VT_IS_IN_USE(i) (vt_driver.table[i] && vt_driver.table[i]->count)
  32185. +#define VT_BUSY(i) (VT_IS_IN_USE(i) || vt_con_data + i == vtdata.fgconsole || vt_con_data + i == vtdata.select.vt)
  32186. +
  32187. +extern inline int vt_allocated (const struct vt * const vt)
  32188. +{
  32189. +    return vt->allocinit != 0;
  32190. +}
  32191. +
  32192. +extern void        vt_reset (const struct vt *vt);
  32193. +extern void        vt_completechangeconsole (const struct vt *vt);
  32194. +extern void        vt_changeconsole (struct vt *newvt);
  32195. +extern void        vt_mksound (unsigned int count, unsigned int vol, unsigned int ticks);
  32196. +extern int         vt_deallocate (int arg);
  32197. +extern int        vt_resize (int cols, int rows);
  32198. +
  32199. +/*
  32200. + * Blanking ...
  32201. + */
  32202. +extern void        vt_pokeblankedconsole (void);
  32203. +extern void        vt_do_unblankscreen (void);
  32204. +extern void        vt_do_blankscreen (int nopowersave);
  32205. +
  32206. +/*
  32207. + * Initialisation ...
  32208. + */
  32209. +extern unsigned long    vt_pre_init (unsigned long kmem);
  32210. +extern void        vt_post_init (void);
  32211. +
  32212. +#endif /* _VT_KERN_H */
  32213. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/net/Config.in linux/arch/arm/drivers/net/Config.in
  32214. --- linux.orig/arch/arm/drivers/net/Config.in    Thu Jan  1 01:00:00 1970
  32215. +++ linux/arch/arm/drivers/net/Config.in    Thu Jun 27 20:09:55 1996
  32216. @@ -0,0 +1,21 @@
  32217. +#
  32218. +# Network device configuration
  32219. +#
  32220. +tristate 'Dummy net driver support' CONFIG_DUMMY
  32221. +tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
  32222. +tristate 'PPP (point-to-point) support' CONFIG_PPP
  32223. +if [ ! "$CONFIG_PPP" = "n" ]; then
  32224. +  comment 'CCP compressors for PPP are only built as modules.'
  32225. +fi
  32226. +tristate 'SLIP (serial line) support' CONFIG_SLIP
  32227. +if [ "$CONFIG_SLIP" != "n" ]; then
  32228. +  bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
  32229. +  bool ' Keepalive and linefill' CONFIG_SLIP_SMART
  32230. +  bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
  32231. +fi
  32232. +#tristate 'PLIP (parallel port) support' CONFIG_PLIP
  32233. +#
  32234. +#    Ethernet
  32235. +#
  32236. +tristate 'Ether1 (82586) support' CONFIG_ETHER1
  32237. +tristate 'Ether3 (NQ8005) support' CONFIG_ETHER3
  32238. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/net/Makefile linux/arch/arm/drivers/net/Makefile
  32239. --- linux.orig/arch/arm/drivers/net/Makefile    Thu Jan  1 01:00:00 1970
  32240. +++ linux/arch/arm/drivers/net/Makefile    Sun Aug 25 15:39:47 1996
  32241. @@ -0,0 +1,129 @@
  32242. +# File: drivers/net/Makefile
  32243. +#
  32244. +# Makefile for the Linux network (ethercard) device drivers.
  32245. +#
  32246. +
  32247. +all: links first_rule
  32248. +
  32249. +LK    = README.eql README.multicast README.tunnel README1.PLIP README2.PLIP \
  32250. +      bsd_comp.c dummy.c eql.c loopback.c net_init.c slhc.c slip.c slip.h
  32251. +
  32252. +L_TARGET := net.a
  32253. +L_OBJS   := Space.o auto_irq.o net_init.o loopback.o
  32254. +M_OBJS   :=
  32255. +MOD_LIST_NAME := NET_MODULES
  32256. +
  32257. +# Need these to keep track of whether the SLHC module should
  32258. +# really go in the kernel or a module
  32259. +CONFIG_SLHC_BUILTIN :=
  32260. +CONFIG_SLHC_MODULE  :=
  32261. +
  32262. +ifeq ($(CONFIG_ETHER1),y)
  32263. +L_OBJS += ether1.o
  32264. +else
  32265. +  ifeq ($(CONFIG_ETHER1),m)
  32266. +  M_OBJS += ether1.o
  32267. +  endif
  32268. +endif
  32269. +
  32270. +ifeq ($(CONFIG_ETHER3),y)
  32271. +L_OBJS += ether3.o
  32272. +else
  32273. +  ifeq ($(CONFIG_ETHER3),m)
  32274. +  M_OBJS += ether3.o
  32275. +  endif
  32276. +endif
  32277. +
  32278. +ifeq ($(CONFIG_IPIP),y)
  32279. +L_OBJS += tunnel.o
  32280. +else
  32281. +  ifeq ($(CONFIG_IPIP),m)
  32282. +  M_OBJS += tunnel.o
  32283. +  endif
  32284. +endif
  32285. +
  32286. +ifeq ($(CONFIG_PLIP),y)
  32287. +L_OBJS += plip.o
  32288. +else
  32289. +  ifeq ($(CONFIG_PLIP),m)
  32290. +  M_OBJS += plip.o
  32291. +  endif
  32292. +endif
  32293. +
  32294. +ifeq ($(CONFIG_PPP),y)
  32295. +LX_OBJS += ppp.o
  32296. +CONFIG_SLHC_BUILTIN = y
  32297. +else
  32298. +  ifeq ($(CONFIG_PPP),m)
  32299. +  MX_OBJS += ppp.o
  32300. +  CONFIG_SLHC_MODULE = y
  32301. +  endif
  32302. +endif
  32303. +
  32304. +ifneq ($(CONFIG_PPP),n)
  32305. +  M_OBJS += bsd_comp.o
  32306. +endif
  32307. +
  32308. +ifeq ($(CONFIG_SLIP),y)
  32309. +L_OBJS += slip.o
  32310. +CONFIG_SLHC_BUILTIN = y
  32311. +else
  32312. +  ifeq ($(CONFIG_SLIP),m)
  32313. +  M_OBJS += slip.o
  32314. +  CONFIG_SLHC_MODULE = y
  32315. +  endif
  32316. +endif
  32317. +
  32318. +ifeq ($(CONFIG_DUMMY),y)
  32319. +L_OBJS += dummy.o
  32320. +else
  32321. +  ifeq ($(CONFIG_DUMMY),m)
  32322. +  L_OBJS += dummy.o
  32323. +  endif
  32324. +endif
  32325. +
  32326. +# If anything built-in uses slhc, then build it into the kernel also.
  32327. +# If not, but a module uses it, build as a module.
  32328. +ifdef CONFIG_SLHC_BUILTIN
  32329. +L_OBJS += slhc.o
  32330. +else
  32331. +  ifdef CONFIG_SLHC_MODULE
  32332. +  M_OBJS += slhc.o
  32333. +  endif
  32334. +endif
  32335. +
  32336. +ifeq ($(CONFIG_EQUALIZER),y)
  32337. +L_OBJS += eql.o
  32338. +else
  32339. +  ifeq ($(CONFIG_EQUALIZER),m)
  32340. +  M_OBJS += eql.o
  32341. +  endif
  32342. +endif
  32343. +
  32344. +fastdep: links
  32345. +
  32346. +include $(TOPDIR)/Rules.make
  32347. +
  32348. +clean:
  32349. +    rm -f core *.o *.a *.s
  32350. +
  32351. +net_init.o: ../../../../include/linux/autoconf.h
  32352. +
  32353. +.PHONY: links
  32354. +links:
  32355. +    -@for f in $(LK); do \
  32356. +        if [ ! -e $$f ]; then \
  32357. +            echo "ln -s ../../../../drivers/net/$$f .";\
  32358. +            ln -s ../../../../drivers/net/$$f .; \
  32359. +        fi \
  32360. +    done
  32361. +
  32362. +mrproper:
  32363. +    -@for f in $(LK); do \
  32364. +        if [ -L $$f ]; then \
  32365. +            echo $(RM) $$f; \
  32366. +            $(RM) $$f; \
  32367. +        fi; \
  32368. +    done
  32369. +    $(RM) ppp.ver
  32370. +
  32371. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/net/Space.c linux/arch/arm/drivers/net/Space.c
  32372. --- linux.orig/arch/arm/drivers/net/Space.c    Thu Jan  1 01:00:00 1970
  32373. +++ linux/arch/arm/drivers/net/Space.c    Sun Jul  7 13:12:08 1996
  32374. @@ -0,0 +1,173 @@
  32375. +/*
  32376. + * INET        An implementation of the TCP/IP protocol suite for the LINUX
  32377. + *        operating system.  INET is implemented using the  BSD Socket
  32378. + *        interface as the means of communication with the user level.
  32379. + *
  32380. + *        Holds initial configuration information for devices.
  32381. + *
  32382. + * NOTE:    This file is a nice idea, but its current format does not work
  32383. + *        well for drivers that support multiple units, like the SLIP
  32384. + *        driver.  We should actually have only one pointer to a driver
  32385. + *        here, with the driver knowing how many units it supports.
  32386. + *        Currently, the SLIP driver abuses the "base_addr" integer
  32387. + *        field of the 'device' structure to store the unit number...
  32388. + *        -FvK
  32389. + *
  32390. + * Version:    @(#)Space.c    1.0.7    08/12/93
  32391. + *
  32392. + * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  32393. + *        Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  32394. + *        Donald J. Becker, <becker@super.org>
  32395. + *
  32396. + *    FIXME:
  32397. + *        Sort the device chain fastest first.
  32398. + *
  32399. + *        This program is free software; you can redistribute it and/or
  32400. + *        modify it under the terms of the GNU General Public License
  32401. + *        as published by the Free Software Foundation; either version
  32402. + *        2 of the License, or (at your option) any later version.
  32403. + */
  32404. +#include <linux/config.h>
  32405. +#include <linux/netdevice.h>
  32406. +#include <linux/errno.h>
  32407. +
  32408. +#define    NEXT_DEV    NULL
  32409. +
  32410. +
  32411. +/* A unified ethernet device probe.  This is the easiest way to have every
  32412. +   ethernet adaptor have the name "eth[0123...]".
  32413. +   */
  32414. +extern int ether1_probe (struct device *dev);
  32415. +extern int ether3_probe (struct device *dev);
  32416. +
  32417. +static int
  32418. +ethif_probe(struct device *dev)
  32419. +{
  32420. +    u_long base_addr = dev->base_addr;
  32421. +
  32422. +    if ((base_addr == 0xffe0)  ||  (base_addr == 1))
  32423. +    return 1;        /* ENXIO */
  32424. +
  32425. +    if (1
  32426. +#ifdef CONFIG_ETHER3
  32427. +        && ether3_probe (dev)
  32428. +#endif
  32429. +#ifdef CONFIG_ETHER1
  32430. +    && ether1_probe (dev)
  32431. +#endif
  32432. +    && 1 ) {
  32433. +    return 1;    /* -ENODEV or -EAGAIN would be more accurate. */
  32434. +    }
  32435. +    return 0;
  32436. +}
  32437. +
  32438. +/* The first device defaults to I/O base '0', which means autoprobe. */
  32439. +#ifndef ETH0_ADDR
  32440. +# define ETH0_ADDR 0
  32441. +#endif
  32442. +#ifndef ETH0_IRQ
  32443. +# define ETH0_IRQ 0
  32444. +#endif
  32445. +/* The first device defaults to I/O base '0', which means autoprobe. */
  32446. +#ifndef ETH1_ADDR
  32447. +# define ETH1_ADDR 0
  32448. +#endif
  32449. +#ifndef ETH1_IRQ
  32450. +# define ETH1_IRQ 0
  32451. +#endif
  32452. +/* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20),
  32453. +   which means "don't probe".  These entries exist to only to provide empty
  32454. +   slots which may be enabled at boot-time. */
  32455. +
  32456. +static struct device eth3_dev = {
  32457. +"eth3"        , 0x0, 0x0, 0x0, 0x0, 0xffe0   , 0       , 0, 0, 0, NEXT_DEV  , ethif_probe };
  32458. +
  32459. +static struct device eth2_dev = {
  32460. +"eth2"        , 0x0, 0x0, 0x0, 0x0, 0xffe0   , 0       , 0, 0, 0, ð3_dev , ethif_probe };
  32461. +    
  32462. +static struct device eth1_dev = {
  32463. +"eth1"        , 0x0, 0x0, 0x0, 0x0, ETH1_ADDR, ETH1_IRQ, 0, 0, 0, ð2_dev , ethif_probe };
  32464. +
  32465. +static struct device eth0_dev = {
  32466. +"eth0"        , 0x0, 0x0, 0x0, 0x0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, ð1_dev , ethif_probe };
  32467. +
  32468. +#undef  NEXT_DEV
  32469. +#define NEXT_DEV (ð0_dev)
  32470. +
  32471. +#if defined(PLIP) || defined(CONFIG_PLIP)
  32472. +extern int plip_init(struct device *);
  32473. +static struct device plip2_dev = {
  32474. +"plip2"        , 0x0, 0x0, 0x0, 0x0, 0x278    , 2       , 0, 0, 0, NEXT_DEV  , plip_init };
  32475. +
  32476. +static struct device plip1_dev = {
  32477. +"plip1"        , 0x0, 0x0, 0x0, 0x0, 0x378    , 7       , 0, 0, 0, &plip2_dev, plip_init };
  32478. +
  32479. +static struct device plip0_dev = {
  32480. +"plip0"        , 0x0, 0x0, 0x0, 0x0, 0x3BC    , 5       , 0, 0, 0, &plip1_dev, plip_init };
  32481. +
  32482. +#undef  NEXT_DEV
  32483. +#define NEXT_DEV (&plip0_dev)
  32484. +#endif  /* PLIP */
  32485. +
  32486. +#if defined(SLIP) || defined(CONFIG_SLIP)
  32487. +    /* To be exact, this node just hooks the initialization
  32488. +       routines to the device structures.            */
  32489. +extern int slip_init_ctrl_dev(struct device *);
  32490. +
  32491. +static struct device slip_bootstrap = {
  32492. +"slip_proto"    , 0x0, 0x0, 0x0, 0x0, 0        , 0       , 0, 0, 0, NEXT_DEV  , slip_init_ctrl_dev };
  32493. +
  32494. +#undef  NEXT_DEV
  32495. +#define NEXT_DEV (&slip_bootstrap)
  32496. +#endif /* SLIP */
  32497. +  
  32498. +#if defined(CONFIG_PPP)
  32499. +extern int ppp_init(struct device *);
  32500. +
  32501. +static struct device ppp_bootstrap = {
  32502. +"ppp_proto"    , 0x0, 0x0, 0x0, 0x0, 0        , 0       , 0, 0, 0, NEXT_DEV  , ppp_init };
  32503. +
  32504. +#undef  NEXT_DEV
  32505. +#define NEXT_DEV (&ppp_bootstrap)
  32506. +#endif   /* PPP */
  32507. +
  32508. +#ifdef CONFIG_DUMMY
  32509. +extern int dummy_init(struct device *dev);
  32510. +
  32511. +static struct device dummy_dev = {
  32512. +"dummy"        , 0x0, 0x0, 0x0, 0x0, 0        , 0       , 0, 0, 0, NEXT_DEV  , dummy_init };
  32513. +    
  32514. +#undef    NEXT_DEV
  32515. +#define    NEXT_DEV    (&dummy_dev)
  32516. +#endif
  32517. +
  32518. +#ifdef CONFIG_EQUALIZER
  32519. +extern int eql_init(struct device *dev);
  32520. +
  32521. +static struct device eql_dev = {
  32522. +"eql"        , 0x0, 0x0, 0x0, 0x0, 0        , 0       , 0, 0, 0, NEXT_DEV  , eql_init };
  32523. +
  32524. +#undef  NEXT_DEV
  32525. +#define NEXT_DEV (&eql_dev)
  32526. +#endif
  32527. +
  32528. +#ifdef CONFIG_NET_IPIP
  32529. +#ifdef CONFIG_IP_FORWARD
  32530. +extern int tunnel_init (struct device *dev);
  32531. +
  32532. +static struct device tunnel_dev1 = {
  32533. +"tunl1"        , 0x0, 0x0, 0x0, 0x0, 0        , 0       , 0, 0, 0, NEXT_DEV  , tunnel_init };
  32534. +
  32535. +static struct device tunnel_dev0 = {
  32536. +"tunl0"        , 0x0, 0x0, 0x0, 0x0, 0        , 0       , 0, 0, 0, &tunnel_dev1, tunnel_init };
  32537. +
  32538. +#undef  NEXT_DEV
  32539. +#define NEXT_DEV (&tunnel_dev0)
  32540. +#endif
  32541. +#endif
  32542. +
  32543. +extern int loopback_init(struct device *dev);
  32544. +struct device loopback_dev = {
  32545. +"lo"        , 0x0, 0x0, 0x0, 0x0, 0        , 0       , 0, 0, 0, NEXT_DEV  ,    loopback_init };
  32546. +
  32547. +struct device *dev_base = &loopback_dev;
  32548. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/net/auto_irq.c linux/arch/arm/drivers/net/auto_irq.c
  32549. --- linux.orig/arch/arm/drivers/net/auto_irq.c    Thu Jan  1 01:00:00 1970
  32550. +++ linux/arch/arm/drivers/net/auto_irq.c    Fri Jun 28 21:23:06 1996
  32551. @@ -0,0 +1,122 @@
  32552. +/* auto_irq.c: Auto-configure IRQ lines for linux. */
  32553. +/*
  32554. +    Written 1994 by Donald Becker.
  32555. +
  32556. +    The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
  32557. +    Center of Excellence in Space Data and Information Sciences
  32558. +      Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
  32559. +
  32560. +    This code is a general-purpose IRQ line detector for devices with
  32561. +    jumpered IRQ lines.  If you can make the device raise an IRQ (and
  32562. +    that IRQ line isn't already being used), these routines will tell
  32563. +    you what IRQ line it's using -- perfect for those oh-so-cool boot-time
  32564. +    device probes!
  32565. +
  32566. +    To use this, first call autoirq_setup(timeout). TIMEOUT is how many
  32567. +    'jiffies' (1/100 sec.) to detect other devices that have active IRQ lines,
  32568. +    and can usually be zero at boot.  'autoirq_setup()' returns the bit
  32569. +    vector of nominally-available IRQ lines (lines may be physically in-use,
  32570. +    but not yet registered to a device).
  32571. +    Next, set up your device to trigger an interrupt.
  32572. +    Finally call autoirq_report(TIMEOUT) to find out which IRQ line was
  32573. +    most recently active.  The TIMEOUT should usually be zero, but may
  32574. +    be set to the number of jiffies to wait for a slow device to raise an IRQ.
  32575. +
  32576. +    The idea of using the setup timeout to filter out bogus IRQs came from
  32577. +    the serial driver.
  32578. +*/
  32579. +
  32580. +
  32581. +#ifdef version
  32582. +static const char *version=
  32583. +"auto_irq.c:v1.11 Donald Becker (becker@cesdis.gsfc.nasa.gov)";
  32584. +#endif
  32585. +
  32586. +#include <linux/sched.h>
  32587. +#include <linux/delay.h>
  32588. +#include <asm/bitops.h>
  32589. +#include <asm/io.h>
  32590. +#include <asm/irq.h>
  32591. +#include <linux/netdevice.h>
  32592. +
  32593. +struct device *irq2dev_map[32];
  32594. +
  32595. +unsigned long irqs_busy = 0x2147;        /* The set of fixed IRQs (keyboard, timer, etc) */
  32596. +unsigned long irqs_used = 0x0001;        /* The set of fixed IRQs sometimes enabled. */
  32597. +unsigned long irqs_reserved;            /* An advisory "reserved" table. */
  32598. +unsigned long irqs_shared;            /* IRQ lines "shared" among conforming cards.*/
  32599. +
  32600. +static volatile unsigned long irq_bitmap;    /* The irqs we actually found. */
  32601. +static unsigned long irq_handled;        /* The irq lines we have a handler on. */
  32602. +static volatile int irq_number;            /* The latest irq number we actually found. */
  32603. +
  32604. +static void autoirq_probe(int irq, void *dev_id, struct pt_regs * regs)
  32605. +{
  32606. +    irq_number = irq;
  32607. +    set_bit(irq, (void *)&irq_bitmap);    /* irq_bitmap |= 1 << irq; */
  32608. +    disable_irq(irq);
  32609. +    return;
  32610. +}
  32611. +
  32612. +int autoirq_setup(int waittime)
  32613. +{
  32614. +    int i, mask;
  32615. +    int timeout = jiffies + waittime;
  32616. +    int boguscount = (waittime*loops_per_sec) / 100;
  32617. +
  32618. +    irq_handled = 0;
  32619. +    for (i = 0; i < 16; i++) {
  32620. +        if (test_bit(i, &irqs_busy) == 0
  32621. +            && request_irq(i, autoirq_probe, SA_INTERRUPT, "irq probe", NULL) == 0)
  32622. +            set_bit(i, (void *)&irq_handled);    /* irq_handled |= 1 << i;*/
  32623. +    }
  32624. +    /* Update our USED lists. */
  32625. +    irqs_used |= ~irq_handled;
  32626. +    irq_number = 0;
  32627. +    irq_bitmap = 0;
  32628. +
  32629. +    /* Hang out at least <waittime> jiffies waiting for bogus IRQ hits. */
  32630. +    while (timeout > jiffies  &&  --boguscount > 0)
  32631. +        ;
  32632. +
  32633. +    for (i = 0, mask = 0x01; i < 16; i++, mask <<= 1) {
  32634. +        if (irq_bitmap & irq_handled & mask) {
  32635. +            irq_handled &= ~mask;
  32636. +#ifdef notdef
  32637. +            printk(" Spurious interrupt on IRQ %d\n", i);
  32638. +#endif
  32639. +            free_irq(i, NULL);
  32640. +        }
  32641. +    }
  32642. +    return irq_handled;
  32643. +}
  32644. +
  32645. +int autoirq_report(int waittime)
  32646. +{
  32647. +    int i;
  32648. +    int timeout = jiffies+waittime;
  32649. +    int boguscount = (waittime*loops_per_sec) / 100;
  32650. +
  32651. +    /* Hang out at least <waittime> jiffies waiting for the IRQ. */
  32652. +
  32653. +    while (timeout > jiffies  &&  --boguscount > 0)
  32654. +        if (irq_number)
  32655. +            break;
  32656. +
  32657. +    /* Retract the irq handlers that we installed. */
  32658. +    for (i = 0; i < 16; i++) {
  32659. +        if (test_bit(i, (void *)&irq_handled))
  32660. +            free_irq(i, NULL);
  32661. +    }
  32662. +    return irq_number;
  32663. +}
  32664. +
  32665. +/*
  32666. + * Local variables:
  32667. + *  compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c auto_irq.c"
  32668. + *  version-control: t
  32669. + *  kept-new-versions: 5
  32670. + *  c-indent-level: 4
  32671. + *  tab-width: 4
  32672. + * End:
  32673. + */
  32674. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/net/ether1.c linux/arch/arm/drivers/net/ether1.c
  32675. --- linux.orig/arch/arm/drivers/net/ether1.c    Thu Jan  1 01:00:00 1970
  32676. +++ linux/arch/arm/drivers/net/ether1.c    Mon Jul 29 20:27:07 1996
  32677. @@ -0,0 +1,1132 @@
  32678. +/*
  32679. + * linux/arch/arm/drivers/net/ether1.c
  32680. + *
  32681. + * Acorn ether1 driver (82586 chip)
  32682. + *
  32683. + * (c) 1996 Russell King
  32684. + */
  32685. +
  32686. +/*
  32687. + * We basically keep two queues in the cards memory - one for transmit
  32688. + * and one for receive.  Each has a head and a tail.  The head is where
  32689. + * we/the chip adds packets to be transmitted/received, and the tail
  32690. + * is where the transmitter has got to/where the receiver will stop.
  32691. + * Both of these queues are circular, and since the chip is running
  32692. + * all the time, we have to be careful when we modify the pointers etc
  32693. + * so that the buffer memory is valid all the time.
  32694. + */
  32695. +
  32696. +/*
  32697. + * Change log:
  32698. + * 1.00    RMK            Released
  32699. + * 1.01    RMK       19/03/96    Transfers the last odd byte onto/off of the card now.
  32700. + */
  32701. +
  32702. +#include <linux/module.h>
  32703. +#include <linux/kernel.h>
  32704. +#include <linux/sched.h>
  32705. +#include <linux/types.h>
  32706. +#include <linux/fcntl.h>
  32707. +#include <linux/interrupt.h>
  32708. +#include <linux/ptrace.h>
  32709. +#include <linux/ioport.h>
  32710. +#include <linux/in.h>
  32711. +#include <linux/malloc.h>
  32712. +#include <linux/string.h>
  32713. +#include <asm/system.h>
  32714. +#include <asm/bitops.h>
  32715. +#include <asm/io.h>
  32716. +#include <asm/dma.h>
  32717. +#include <linux/errno.h>
  32718. +
  32719. +#include <linux/netdevice.h>
  32720. +#include <linux/etherdevice.h>
  32721. +#include <linux/skbuff.h>
  32722. +
  32723. +#include <asm/ecard.h>
  32724. +
  32725. +#define __ETHER1_C
  32726. +#include "ether1.h"
  32727. +
  32728. +static unsigned int net_debug = NET_DEBUG;
  32729. +
  32730. +#define FUNC_PROLOGUE \
  32731. +    struct ether1_priv *priv = (struct ether1_priv *)dev->priv
  32732. +
  32733. +#define BUFFER_SIZE    0x10000
  32734. +#define TX_AREA_START    0x00100
  32735. +#define TX_AREA_END    0x05000
  32736. +#define RX_AREA_START    0x05000
  32737. +#define RX_AREA_END    0x0fc00
  32738. +
  32739. +#define tx_done(dev) 0
  32740. +/* ------------------------------------------------------------------------- */
  32741. +static char *version = "ether1 ethernet driver (c) 1995 Russell King v1.01\n";
  32742. +
  32743. +#define BUS_16 16
  32744. +#define BUS_8  8
  32745. +
  32746. +static const int ether1_prods[] = { 0x0003 };
  32747. +static const int ether1_manus[] = { 0x0000 };
  32748. +
  32749. +/* ------------------------------------------------------------------------- */
  32750. +
  32751. +#define DISABLEIRQS 1
  32752. +#define NORMALIRQS  0
  32753. +
  32754. +#define ether1_inw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
  32755. +#define ether1_outw(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
  32756. +
  32757. +static inline unsigned short
  32758. +ether1_inw_p (struct device *dev, int addr, int svflgs)
  32759. +{
  32760. +    unsigned long flags;
  32761. +    unsigned short ret;
  32762. +
  32763. +    if (svflgs) {
  32764. +    save_flags_cli (flags);
  32765. +    }
  32766. +    outb (addr >> 12, REG_PAGE);
  32767. +    ret = inw (ETHER1_RAM + ((addr & 4095) >> 1));
  32768. +    if (svflgs)
  32769. +    restore_flags (flags);
  32770. +    return ret;
  32771. +}
  32772. +
  32773. +static inline void
  32774. +ether1_outw_p (struct device *dev, unsigned short val, int addr, int svflgs)
  32775. +{
  32776. +    unsigned long flags;
  32777. +
  32778. +    if (svflgs) {
  32779. +    save_flags_cli (flags);
  32780. +    }
  32781. +    outb (addr >> 12, REG_PAGE);
  32782. +    outw (val, ETHER1_RAM + ((addr & 4095) >> 1));
  32783. +    if (svflgs)
  32784. +    restore_flags (flags);
  32785. +}
  32786. +
  32787. +static inline void *
  32788. +ether1_inswb (int addr, void *data, unsigned int len)
  32789. +{
  32790. +    int used;
  32791. +
  32792. +    __asm__ __volatile__(
  32793. +    "    subs    %3, %3, #2\n"
  32794. +    "    bmi    2f\n"
  32795. +    "1:    ldr    %0, [%1], #4\n"
  32796. +    "    strb    %0, [%2], #1\n"
  32797. +    "    mov    %0, %0, lsr #8\n"
  32798. +    "    strb    %0, [%2], #1\n"
  32799. +    "    subs    %3, %3, #2\n"
  32800. +    "    bmi    2f\n"
  32801. +    "    ldr    %0, [%1], #4\n"
  32802. +    "    strb    %0, [%2], #1\n"
  32803. +    "    mov    %0, %0, lsr #8\n"
  32804. +    "    strb    %0, [%2], #1\n"
  32805. +    "    subs    %3, %3, #2\n"
  32806. +    "    bmi    2f\n"
  32807. +    "    ldr    %0, [%1], #4\n"
  32808. +    "    strb    %0, [%2], #1\n"
  32809. +    "    mov    %0, %0, lsr #8\n"
  32810. +    "    strb    %0, [%2], #1\n"
  32811. +    "    subs    %3, %3, #2\n"
  32812. +    "    bmi    2f\n"
  32813. +    "    ldr    %0, [%1], #4\n"
  32814. +    "    strb    %0, [%2], #1\n"
  32815. +    "    mov    %0, %0, lsr #8\n"
  32816. +    "    strb    %0, [%2], #1\n"
  32817. +    "    subs    %3, %3, #2\n"
  32818. +    "    bpl    1b\n"
  32819. +    "2:    adds    %3, %3, #1\n"
  32820. +    "    ldreqb    %0, [%1]\n"
  32821. +    "    streqb    %0, [%2]\n"
  32822. +    : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len)
  32823. +    : "1" (addr << 2), "2" (data), "3" (len));
  32824. +
  32825. +    return data;
  32826. +}
  32827. +
  32828. +static inline void *
  32829. +ether1_outswb (int addr, void *data, unsigned int len)
  32830. +{
  32831. +    int used;
  32832. +
  32833. +    __asm__ __volatile__(
  32834. +    "    subs    %3, %3, #2\n"
  32835. +    "    bmi    2f\n"
  32836. +    "1:    ldr    %0, [%2], #2\n"
  32837. +    "    mov    %0, %0, lsl #16\n"
  32838. +    "    orr    %0, %0, %0, lsr #16\n"
  32839. +    "    str    %0, [%1], #4\n"
  32840. +    "    subs    %3, %3, #2\n"
  32841. +    "    bmi    2f\n"
  32842. +    "    ldr    %0, [%2], #2\n"
  32843. +    "    mov    %0, %0, lsl #16\n"
  32844. +    "    orr    %0, %0, %0, lsr #16\n"
  32845. +    "    str    %0, [%1], #4\n"
  32846. +    "    subs    %3, %3, #2\n"
  32847. +    "    bmi    2f\n"
  32848. +    "    ldr    %0, [%2], #2\n"
  32849. +    "    mov    %0, %0, lsl #16\n"
  32850. +    "    orr    %0, %0, %0, lsr #16\n"
  32851. +    "    str    %0, [%1], #4\n"
  32852. +    "    subs    %3, %3, #2\n"
  32853. +    "    bmi    2f\n"
  32854. +    "    ldr    %0, [%2], #2\n"
  32855. +    "    mov    %0, %0, lsl #16\n"
  32856. +    "    orr    %0, %0, %0, lsr #16\n"
  32857. +    "    str    %0, [%1], #4\n"
  32858. +    "    subs    %3, %3, #2\n"
  32859. +    "    bpl    1b\n"
  32860. +    "2:    adds    %3, %3, #1\n"
  32861. +    "    ldreqb    %0, [%2]\n"
  32862. +    "    streqb    %0, [%1]\n"
  32863. +    : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len)
  32864. +    : "1" (addr << 2), "2" (data), "3" (len));
  32865. +
  32866. +    return data;
  32867. +}
  32868. +
  32869. +
  32870. +static void
  32871. +ether1_writebuffer (struct device *dev, void *data, unsigned int start, unsigned int length)
  32872. +{
  32873. +    unsigned int page, thislen, offset;
  32874. +
  32875. +    offset = start & 4095;
  32876. +
  32877. +    for (page = start >> 12; length; page++) {
  32878. +    outb (page, REG_PAGE);
  32879. +    if (offset + length > 4096) {
  32880. +        length -= 4096 - offset;
  32881. +        thislen = 4096 - offset;
  32882. +    } else {
  32883. +        thislen = length;
  32884. +        length = 0;
  32885. +    }
  32886. +
  32887. +    data = ether1_outswb (ETHER1_RAM + (offset >> 1), data, thislen);
  32888. +    offset = 0;
  32889. +    }
  32890. +}
  32891. +
  32892. +static void
  32893. +ether1_readbuffer (struct device *dev, void *data, unsigned int start, unsigned int length)
  32894. +{
  32895. +    unsigned int page, thislen, offset;
  32896. +
  32897. +    offset = start & 4095;
  32898. +
  32899. +    for (page = start >> 12; length; page++) {
  32900. +    outb (page, REG_PAGE);
  32901. +    if (offset + length > 4096) {
  32902. +        length -= 4096 - offset;
  32903. +        thislen = 4096 - offset;
  32904. +    } else {
  32905. +        thislen = length;
  32906. +        length = 0;
  32907. +    }
  32908. +
  32909. +    data = ether1_inswb (ETHER1_RAM + (offset >> 1), data, thislen);
  32910. +    offset = 0;
  32911. +    }
  32912. +}
  32913. +
  32914. +static int
  32915. +ether1_ramtest (struct device *dev, unsigned char byte)
  32916. +{
  32917. +    unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
  32918. +    int i, ret = BUFFER_SIZE;
  32919. +    int max_errors = 15;
  32920. +    int bad = -1;
  32921. +    int bad_start = 0;
  32922. +
  32923. +    if (!buffer)
  32924. +    return 1;
  32925. +
  32926. +    memset (buffer, byte, BUFFER_SIZE);
  32927. +    ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE);
  32928. +    memset (buffer, byte ^ 0xff, BUFFER_SIZE);
  32929. +    ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE);
  32930. +
  32931. +    for (i = 0; i < BUFFER_SIZE; i++) {
  32932. +    if (buffer[i] != byte) {
  32933. +        if (max_errors >= 0 && bad != buffer[i]) {
  32934. +        if (bad != -1)
  32935. +            printk ("\n");
  32936. +        printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X",
  32937. +            dev->name, buffer[i], byte, i);
  32938. +        ret = -ENODEV;
  32939. +        max_errors --;
  32940. +        bad = buffer[i];
  32941. +        bad_start = i;
  32942. +        }
  32943. +    } else {
  32944. +        if (bad != -1) {
  32945. +            if (bad_start == i - 1)
  32946. +            printk ("\n");
  32947. +        else
  32948. +            printk (" - 0x%04X\n", i - 1);
  32949. +        bad = -1;
  32950. +        }
  32951. +    }
  32952. +    }
  32953. +
  32954. +    if (bad != -1)
  32955. +    printk (" - 0x%04X\n", BUFFER_SIZE);
  32956. +    kfree (buffer);
  32957. +
  32958. +    return ret;
  32959. +}
  32960. +
  32961. +static int
  32962. +ether1_reset (struct device *dev)
  32963. +{
  32964. +    outb (CTRL_RST|CTRL_ACK, REG_CONTROL);
  32965. +    return BUS_16;
  32966. +}
  32967. +
  32968. +static int
  32969. +ether1_init_2 (struct device *dev)
  32970. +{
  32971. +    int i;
  32972. +    dev->mem_start = 0;
  32973. +    
  32974. +    i = ether1_ramtest (dev, 0x5a);
  32975. +
  32976. +    if (i > 0)
  32977. +    i = ether1_ramtest (dev, 0x1e);
  32978. +
  32979. +    if (i <= 0)
  32980. +        return -ENODEV;
  32981. +
  32982. +    dev->mem_end = i;
  32983. +    
  32984. +    return 0;
  32985. +}
  32986. +
  32987. +/*
  32988. + * These are the structures that are loaded into the ether RAM card to
  32989. + * initialise the 82586
  32990. + */
  32991. +
  32992. +/* at 0x0100 */
  32993. +#define NOP_ADDR    (TX_AREA_START)
  32994. +#define NOP_SIZE    (0x06)
  32995. +static nop_t  init_nop  = {
  32996. +    0,
  32997. +    CMD_NOP,
  32998. +    NOP_ADDR
  32999. +};
  33000. +
  33001. +/* at 0x003a */
  33002. +#define TDR_ADDR    (0x003a)
  33003. +#define TDR_SIZE    (0x08)
  33004. +static tdr_t  init_tdr    = {
  33005. +    0,
  33006. +    CMD_TDR | CMD_INTR,
  33007. +    NOP_ADDR,
  33008. +    0
  33009. +};
  33010. +
  33011. +/* at 0x002e */
  33012. +#define MC_ADDR        (0x002e)
  33013. +#define MC_SIZE        (0x0c)
  33014. +static mc_t   init_mc   = {
  33015. +    0,
  33016. +    CMD_SETMULTICAST,
  33017. +    TDR_ADDR,
  33018. +    0,
  33019. +    { { 0, } }
  33020. +};
  33021. +
  33022. +/* at 0x0022 */
  33023. +#define SA_ADDR        (0x0022)
  33024. +#define SA_SIZE        (0x0c)
  33025. +static sa_t   init_sa   = {
  33026. +    0,
  33027. +    CMD_SETADDRESS,
  33028. +    MC_ADDR,
  33029. +    { 0, }
  33030. +};
  33031. +
  33032. +/* at 0x0010 */
  33033. +#define CFG_ADDR    (0x0010)
  33034. +#define CFG_SIZE    (0x12)
  33035. +static cfg_t  init_cfg  = {
  33036. +    0,
  33037. +    CMD_CONFIG,
  33038. +    SA_ADDR,
  33039. +    4,
  33040. +    8,
  33041. +    CFG8_SRDY,
  33042. +    CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6),
  33043. +    0,
  33044. +};
  33045. +
  33046. +/* at 0x0000 */
  33047. +#define SCB_ADDR    (0x0000)
  33048. +#define SCB_SIZE    (0x10)
  33049. +static scb_t  init_scb  = {
  33050. +    0,
  33051. +    0,
  33052. +    CFG_ADDR,
  33053. +    RX_AREA_START,
  33054. +    0,
  33055. +    0,
  33056. +    0,
  33057. +    0
  33058. +};
  33059. +
  33060. +/* at 0xffee */
  33061. +#define ISCP_ADDR    (0xffee)
  33062. +#define ISCP_SIZE    (0x08)
  33063. +static iscp_t init_iscp = {
  33064. +    1,
  33065. +    SCB_ADDR,
  33066. +    0x0000,
  33067. +    0x0000
  33068. +};
  33069. +
  33070. +/* at 0xfff6 */
  33071. +#define SCP_ADDR    (0xfff6)
  33072. +#define SCP_SIZE    (0x0a)
  33073. +static scp_t  init_scp  = {
  33074. +    SCP_SY_16BBUS,
  33075. +    { 0, 0 },
  33076. +    ISCP_ADDR,
  33077. +    0
  33078. +};
  33079. +
  33080. +#define RFD_SIZE    (0x16)
  33081. +static rfd_t  init_rfd    = {
  33082. +    0,
  33083. +    0,
  33084. +    0,
  33085. +    0,
  33086. +    { 0, },
  33087. +    { 0, },
  33088. +    0
  33089. +};
  33090. +
  33091. +#define RBD_SIZE    (0x0a)
  33092. +static rbd_t  init_rbd    = {
  33093. +    0,
  33094. +    0,
  33095. +    0,
  33096. +    0,
  33097. +    ETH_FRAME_LEN + 8
  33098. +};
  33099. +
  33100. +#define TX_SIZE        (0x08)
  33101. +#define TBD_SIZE    (0x08)
  33102. +
  33103. +static int
  33104. +ether1_init_for_open (struct device *dev)
  33105. +{
  33106. +    FUNC_PROLOGUE;
  33107. +    int i, status, addr, next, next2;
  33108. +
  33109. +    outb (CTRL_RST|CTRL_ACK, REG_CONTROL);
  33110. +
  33111. +    for (i = 0; i < 6; i++)
  33112. +    init_sa.sa_addr[i] = dev->dev_addr[i];
  33113. +
  33114. +    /* load data structures into ether1 RAM */
  33115. +    ether1_writebuffer (dev, &init_scp,  SCP_ADDR,  SCP_SIZE);
  33116. +    ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE);
  33117. +    ether1_writebuffer (dev, &init_scb,  SCB_ADDR,  SCB_SIZE);
  33118. +    ether1_writebuffer (dev, &init_cfg,  CFG_ADDR,  CFG_SIZE);
  33119. +    ether1_writebuffer (dev, &init_sa,   SA_ADDR,   SA_SIZE);
  33120. +    ether1_writebuffer (dev, &init_mc,   MC_ADDR,   MC_SIZE);
  33121. +    ether1_writebuffer (dev, &init_tdr,  TDR_ADDR,  TDR_SIZE);
  33122. +    ether1_writebuffer (dev, &init_nop,  NOP_ADDR,  NOP_SIZE);
  33123. +
  33124. +    /*
  33125. +     * setup circularly linked list of { rfd, rbd, buffer }, with
  33126. +     * all rfds circularly linked, rbds circularly linked.
  33127. +     * First rfd is linked to scp, first rbd is linked to first
  33128. +     * rfd.  Last rbd has a suspend command.
  33129. +     */
  33130. +    addr = RX_AREA_START;
  33131. +    do {
  33132. +    next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
  33133. +    next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
  33134. +
  33135. +    if (next2 >= RX_AREA_END) {
  33136. +        next = RX_AREA_START;
  33137. +        init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
  33138. +        priv->rx_tail = addr;
  33139. +    } else
  33140. +        init_rfd.rfd_command = 0;
  33141. +    if (addr == RX_AREA_START)
  33142. +        init_rfd.rfd_rbdoffset = addr + RFD_SIZE;
  33143. +    else
  33144. +        init_rfd.rfd_rbdoffset = 0;
  33145. +    init_rfd.rfd_link = next;
  33146. +    init_rbd.rbd_link = next + RFD_SIZE;
  33147. +    init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE;
  33148. +
  33149. +    ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE);
  33150. +    ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE);
  33151. +    addr = next;
  33152. +    } while (next2 < RX_AREA_END);
  33153. +
  33154. +    priv->tx_link = NOP_ADDR;
  33155. +    priv->tx_head = NOP_ADDR + NOP_SIZE;
  33156. +    priv->tx_tail = TDR_ADDR;
  33157. +    priv->rx_head = RX_AREA_START;
  33158. +
  33159. +    /* release reset & give 586 a prod */
  33160. +    priv->resetting = 1;
  33161. +    priv->initialising = 1;
  33162. +    outb (CTRL_RST, REG_CONTROL);
  33163. +    outb (0, REG_CONTROL);
  33164. +    outb (CTRL_CA, REG_CONTROL);
  33165. +
  33166. +    /* 586 should now unset iscp.busy */
  33167. +    i = jiffies + HZ/2;
  33168. +    while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
  33169. +    if (jiffies > i) {
  33170. +        printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
  33171. +        return 1;
  33172. +    }
  33173. +    }
  33174. +
  33175. +    /* check status of commands that we issued */
  33176. +    i += HZ/10;
  33177. +    while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
  33178. +        & STAT_COMPLETE) == 0) {
  33179. +    if (jiffies > i)
  33180. +        break;
  33181. +    }
  33182. +
  33183. +    if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
  33184. +    printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status);
  33185. +    ether1_reset (dev);
  33186. +    return 1;
  33187. +    }
  33188. +
  33189. +    i += HZ/10;
  33190. +    while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
  33191. +        & STAT_COMPLETE) == 0) {
  33192. +    if (jiffies > i)
  33193. +        break;
  33194. +    }
  33195. +
  33196. +    if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
  33197. +    printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status);
  33198. +    ether1_reset (dev);
  33199. +    return 1;
  33200. +    }
  33201. +
  33202. +    i += HZ/10;
  33203. +    while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
  33204. +        & STAT_COMPLETE) == 0) {
  33205. +    if (jiffies > i)
  33206. +        break;
  33207. +    }
  33208. +
  33209. +    if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
  33210. +    printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
  33211. +    ether1_reset (dev);
  33212. +    return 1;
  33213. +    }
  33214. +
  33215. +    i += HZ;
  33216. +    while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
  33217. +        & STAT_COMPLETE) == 0) {
  33218. +    if (jiffies > i)
  33219. +        break;
  33220. +    }
  33221. +
  33222. +    if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
  33223. +    printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);
  33224. +    return 0;
  33225. +    }
  33226. +
  33227. +    status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
  33228. +    if (status & TDR_XCVRPROB)
  33229. +    printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);
  33230. +    else
  33231. +    if (status & (TDR_SHORT|TDR_OPEN)) {
  33232. +#ifdef FANCY
  33233. +    printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,
  33234. +        status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,
  33235. +        (status & TDR_TIME) % 10);
  33236. +#else
  33237. +    printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,
  33238. +        status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));
  33239. +#endif
  33240. +    }
  33241. +
  33242. +    return 0;
  33243. +}
  33244. +
  33245. +static int
  33246. +ether1_probe1 (struct device *dev)
  33247. +{
  33248. +    static unsigned int version_printed = 0;
  33249. +    struct ether1_priv *priv;
  33250. +    int i;
  33251. +
  33252. +    if (!dev->priv)
  33253. +    dev->priv = kmalloc (sizeof (struct ether1_priv), GFP_KERNEL);
  33254. +
  33255. +    if (!dev->priv)
  33256. +        return 1;
  33257. +
  33258. +    priv = (struct ether1_priv *)dev->priv;
  33259. +    memset (priv, 0, sizeof (struct ether1_priv));
  33260. +
  33261. +    if ((priv->bus_type = ether1_reset (dev)) == 0) {
  33262. +    kfree (dev->priv);
  33263. +    return 1;
  33264. +    }
  33265. +
  33266. +    if (net_debug && version_printed++ == 0)
  33267. +    printk (KERN_INFO "%s", version);
  33268. +
  33269. +    printk (KERN_INFO "%s: ether1 found [%d, %04lx, %d]", dev->name, priv->bus_type,
  33270. +        dev->base_addr, dev->irq);
  33271. +
  33272. +    request_region (dev->base_addr, 16, "ether1");
  33273. +    request_region (dev->base_addr + 0x800, 4096, "ether1(ram)");
  33274. +
  33275. +    for (i = 0; i < 6; i++)
  33276. +    printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]);
  33277. +
  33278. +    if (ether1_init_2 (dev)) {
  33279. +    kfree (dev->priv);
  33280. +    return 1;
  33281. +    }
  33282. +
  33283. +    dev->open            = ether1_open;
  33284. +    dev->stop            = ether1_close;
  33285. +    dev->hard_start_xmit    = ether1_sendpacket;
  33286. +    dev->get_stats        = ether1_getstats;
  33287. +    dev->set_multicast_list = ether1_setmulticastlist;
  33288. +
  33289. +    /* Fill in the fields of the device structure with ethernet values */
  33290. +    ether_setup (dev);
  33291. +
  33292. +#ifndef CLAIM_IRQ_AT_OPEN
  33293. +    if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) {
  33294. +    kfree (dev->priv);
  33295. +    return -EAGAIN;
  33296. +    }
  33297. +#endif
  33298. +    return 0;
  33299. +}    
  33300. +    
  33301. +/* ------------------------------------------------------------------------- */
  33302. +
  33303. +static void
  33304. +ether1_addr (struct device *dev)
  33305. +{
  33306. +    int i;
  33307. +    
  33308. +    for (i = 0; i < 6; i++)
  33309. +    dev->dev_addr[i] = inb (IDPROM_ADDRESS + i);
  33310. +}
  33311. +
  33312. +int
  33313. +ether1_probe (struct device *dev)
  33314. +{
  33315. +#ifndef MODULE
  33316. +    struct expansion_card *ec;
  33317. +
  33318. +    if (!dev)
  33319. +    return ENODEV;
  33320. +
  33321. +    if ((ec = ecard_find (0, sizeof (ether1_prods) / sizeof (int), ether1_prods, ether1_manus)) == NULL)
  33322. +    return ENODEV;
  33323. +
  33324. +    dev->base_addr = ((unsigned long)ecard_address (ec->slot_no, ECARD_IOC, ECARD_FAST)) >> 2;
  33325. +    dev->irq       = ec->irq;
  33326. +
  33327. +    ecard_claim (ec);
  33328. +
  33329. +#endif
  33330. +    ether1_addr (dev);
  33331. +
  33332. +    if (ether1_probe1 (dev) == 0)
  33333. +    return 0;
  33334. +    return ENODEV;
  33335. +}
  33336. +
  33337. +/* ------------------------------------------------------------------------- */
  33338. +
  33339. +static int
  33340. +ether1_txalloc (struct device *dev, int size)
  33341. +{
  33342. +    FUNC_PROLOGUE;
  33343. +    int start, tail;
  33344. +
  33345. +    size = (size + 1) & ~1;
  33346. +    tail = priv->tx_tail;
  33347. +
  33348. +    if (priv->tx_head + size > TX_AREA_END) {
  33349. +    if (tail > priv->tx_head)
  33350. +        return -1;
  33351. +    start = TX_AREA_START;
  33352. +    if (start + size > tail)
  33353. +        return -1;
  33354. +    priv->tx_head = start + size;
  33355. +    } else {
  33356. +    if (priv->tx_head < tail && (priv->tx_head + size) > tail)
  33357. +        return -1;
  33358. +    start = priv->tx_head;
  33359. +    priv->tx_head += size;
  33360. +    }
  33361. +
  33362. +    return start;
  33363. +}
  33364. +
  33365. +static void
  33366. +ether1_restart (struct device *dev, char *reason)
  33367. +{
  33368. +    FUNC_PROLOGUE;
  33369. +    priv->stats.tx_errors ++;
  33370. +
  33371. +    if (reason)
  33372. +    printk (KERN_WARNING "%s: %s - resetting device\n", dev->name, reason);
  33373. +    else
  33374. +    printk (" - resetting device\n");
  33375. +
  33376. +    ether1_reset (dev);
  33377. +
  33378. +    dev->start = 0;
  33379. +    dev->tbusy = 0;
  33380. +
  33381. +    if (ether1_init_for_open (dev))
  33382. +    printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
  33383. +
  33384. +    dev->start = 1;
  33385. +}
  33386. +
  33387. +static int
  33388. +ether1_open (struct device *dev)
  33389. +{
  33390. +    FUNC_PROLOGUE;
  33391. +#ifdef CLAIM_IRQ_AT_OPEN
  33392. +    if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev))
  33393. +    return -EAGAIN;
  33394. +#endif
  33395. +    MOD_INC_USE_COUNT;
  33396. +
  33397. +    memset (&priv->stats, 0, sizeof (struct enet_statistics));
  33398. +
  33399. +    if (ether1_init_for_open (dev)) {
  33400. +#ifdef CLAIM_IRQ_AT_OPEN
  33401. +    free_irq (dev->irq, dev);
  33402. +#endif
  33403. +    MOD_DEC_USE_COUNT;
  33404. +    return -EAGAIN;
  33405. +    }
  33406. +
  33407. +    dev->tbusy = 0;
  33408. +    dev->interrupt = 0;
  33409. +    dev->start = 1;
  33410. +
  33411. +    return 0;
  33412. +}
  33413. +
  33414. +static int
  33415. +ether1_sendpacket (struct sk_buff *skb, struct device *dev)
  33416. +{
  33417. +    FUNC_PROLOGUE;
  33418. +
  33419. +    if (dev->tbusy) {
  33420. +    /*
  33421. +     * If we get here, some higher level has decided that we are broken.
  33422. +     * There should really be a "kick me" function call instead.
  33423. +     */
  33424. +    int tickssofar = jiffies - dev->trans_start;
  33425. +
  33426. +    if (tickssofar < 5)
  33427. +        return 1;
  33428. +
  33429. +    /* Try to restart the adapter. */
  33430. +    ether1_restart (dev, "transmit timeout, network cable problem?");
  33431. +    dev->trans_start = jiffies;
  33432. +    }
  33433. +
  33434. +    /*
  33435. +     * If some higher layer thinks we've missed a tx-done interrupt
  33436. +     * we are passed NULL.  Caution: dev_tint() handles the cli()/sti()
  33437. +     * itself.
  33438. +     */
  33439. +    if (skb == NULL) {
  33440. +    dev_tint (dev);
  33441. +    return 0;
  33442. +    }
  33443. +
  33444. +    /*
  33445. +     * Block a timer-based transmit from overlapping.  This could better be
  33446. +     * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
  33447. +     */
  33448. +    if (set_bit (0, (void *)&dev->tbusy) != 0)
  33449. +    printk (KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
  33450. +    else {
  33451. +    int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
  33452. +    int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
  33453. +    unsigned long flags;
  33454. +    tx_t tx;
  33455. +    tbd_t tbd;
  33456. +    nop_t nop;
  33457. +    /*
  33458. +     * insert packet followed by a nop
  33459. +     */
  33460. +    txaddr = ether1_txalloc (dev, TX_SIZE);
  33461. +    tbdaddr = ether1_txalloc (dev, TBD_SIZE);
  33462. +    dataddr = ether1_txalloc (dev, len);
  33463. +    nopaddr = ether1_txalloc (dev, NOP_SIZE);
  33464. +
  33465. +    tx.tx_status = 0;
  33466. +    tx.tx_command = CMD_TX | CMD_INTR;
  33467. +    tx.tx_link = nopaddr;
  33468. +    tx.tx_tbdoffset = tbdaddr;
  33469. +    tbd.tbd_opts = TBD_EOL | len;
  33470. +    tbd.tbd_link = I82586_NULL;
  33471. +    tbd.tbd_bufl = dataddr;
  33472. +    tbd.tbd_bufh = 0;
  33473. +    nop.nop_status = 0;
  33474. +    nop.nop_command = CMD_NOP;
  33475. +    nop.nop_link = nopaddr;
  33476. +
  33477. +    save_flags_cli (flags);
  33478. +    ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
  33479. +    ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
  33480. +    ether1_writebuffer (dev, skb->data, dataddr, len);
  33481. +    ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
  33482. +    tmp = priv->tx_link;
  33483. +    priv->tx_link = nopaddr;
  33484. +
  33485. +    /* now reset the previous nop pointer */
  33486. +    ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
  33487. +
  33488. +    restore_flags (flags);
  33489. +
  33490. +    /* handle transmit */
  33491. +    dev->trans_start = jiffies;
  33492. +
  33493. +    /* check to see if we have room for a full sized ether frame */
  33494. +    tmp = priv->tx_head;
  33495. +    tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
  33496. +    priv->tx_head = tmp;
  33497. +    if (tst != -1)
  33498. +        dev->tbusy = 0;
  33499. +    }
  33500. +    dev_kfree_skb (skb, FREE_WRITE);
  33501. +
  33502. +    return 0;
  33503. +}
  33504. +
  33505. +static void
  33506. +ether1_xmit_done (struct device *dev)
  33507. +{
  33508. +    FUNC_PROLOGUE;
  33509. +    nop_t nop;
  33510. +    int caddr, tst;
  33511. +
  33512. +    caddr = priv->tx_tail;
  33513. +
  33514. +again:
  33515. +    ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
  33516. +
  33517. +    switch (nop.nop_command & CMD_MASK) {
  33518. +    case CMD_TDR:
  33519. +    /* special case */
  33520. +    if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
  33521. +                != (unsigned short)I82586_NULL) {
  33522. +        ether1_outw (dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
  33523. +        scb_command, NORMALIRQS);
  33524. +        outb (CTRL_CA, REG_CONTROL);
  33525. +    }
  33526. +    priv->tx_tail = NOP_ADDR;
  33527. +    return;
  33528. +
  33529. +    case CMD_NOP:
  33530. +    if (nop.nop_link == caddr) {
  33531. +        if (priv->initialising == 0)
  33532. +        printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
  33533. +        else
  33534. +            priv->initialising = 0;
  33535. +        return;
  33536. +    }
  33537. +    caddr = nop.nop_link;
  33538. +    goto again;
  33539. +
  33540. +    case CMD_TX:
  33541. +    if (nop.nop_status & STAT_COMPLETE)
  33542. +        break;
  33543. +    ether1_restart (dev, "strange command complete without completed command!");
  33544. +    return;
  33545. +
  33546. +    default:
  33547. +    printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
  33548. +        nop.nop_command & CMD_MASK, caddr);
  33549. +    ether1_restart (dev, NULL);
  33550. +    return;
  33551. +    }
  33552. +
  33553. +    while (nop.nop_status & STAT_COMPLETE) {
  33554. +    if (nop.nop_status & STAT_OK) {
  33555. +        priv->stats.tx_packets ++;
  33556. +        priv->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
  33557. +    } else {
  33558. +        priv->stats.tx_errors ++;
  33559. +
  33560. +        if (nop.nop_status & STAT_COLLAFTERTX)
  33561. +        priv->stats.collisions ++;
  33562. +        if (nop.nop_status & STAT_NOCARRIER)
  33563. +        priv->stats.tx_carrier_errors ++;
  33564. +        if (nop.nop_status & STAT_TXLOSTCTS)
  33565. +        printk (KERN_WARNING "%s: cts lost\n", dev->name);
  33566. +        if (nop.nop_status & STAT_TXSLOWDMA)
  33567. +        priv->stats.tx_fifo_errors ++;
  33568. +        if (nop.nop_status & STAT_COLLEXCESSIVE)
  33569. +        priv->stats.collisions += 16;
  33570. +    }
  33571. +
  33572. +    if (nop.nop_link == caddr) {
  33573. +        printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);
  33574. +        break;
  33575. +    }
  33576. +
  33577. +    caddr = nop.nop_link;
  33578. +    ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
  33579. +    if ((nop.nop_command & CMD_MASK) != CMD_NOP) {
  33580. +        printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);
  33581. +        break;
  33582. +    }
  33583. +
  33584. +    if (caddr == nop.nop_link)
  33585. +        break;
  33586. +
  33587. +    caddr = nop.nop_link;
  33588. +    ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
  33589. +    if ((nop.nop_command & CMD_MASK) != CMD_TX) {
  33590. +        printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);
  33591. +        break;
  33592. +    }
  33593. +    }
  33594. +    priv->tx_tail = caddr;
  33595. +
  33596. +    caddr = priv->tx_head;
  33597. +    tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
  33598. +    priv->tx_head = caddr;
  33599. +    if (tst != -1)
  33600. +    dev->tbusy = 0;
  33601. +    
  33602. +    mark_bh (NET_BH);
  33603. +}
  33604. +
  33605. +static void
  33606. +ether1_recv_done (struct device *dev)
  33607. +{
  33608. +    FUNC_PROLOGUE;
  33609. +    int status;
  33610. +    int nexttail, rbdaddr;
  33611. +    rbd_t rbd;
  33612. +
  33613. +    do {
  33614. +    status = ether1_inw (dev, priv->rx_head, rfd_t, rfd_status, NORMALIRQS);
  33615. +    if ((status & RFD_COMPLETE) == 0)
  33616. +        break;
  33617. +
  33618. +    rbdaddr = ether1_inw (dev, priv->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
  33619. +    ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
  33620. +
  33621. +    if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
  33622. +        int length = rbd.rbd_status & RBD_ACNT;
  33623. +        struct sk_buff *skb;
  33624. +
  33625. +        length = (length + 1) & ~1;
  33626. +        skb = dev_alloc_skb (length + 2);
  33627. +
  33628. +        if (skb) {
  33629. +        skb->dev = dev;
  33630. +        skb_reserve (skb, 2);
  33631. +
  33632. +        ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);
  33633. +
  33634. +        skb->protocol = eth_type_trans (skb, dev);
  33635. +        netif_rx (skb);
  33636. +        priv->stats.rx_packets ++;
  33637. +        } else
  33638. +        priv->stats.rx_dropped ++;
  33639. +    } else {
  33640. +        printk (KERN_WARNING "%s: %s\n", dev->name,
  33641. +            (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
  33642. +        priv->stats.rx_dropped ++;
  33643. +    }
  33644. +
  33645. +    nexttail = ether1_inw (dev, priv->rx_tail, rfd_t, rfd_link, NORMALIRQS);
  33646. +    /* nexttail should be rx_head */
  33647. +    if (nexttail != priv->rx_head)
  33648. +        printk (KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
  33649. +            dev->name, nexttail, priv->rx_head);
  33650. +    ether1_outw (dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
  33651. +    ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_command, NORMALIRQS);
  33652. +    ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_status, NORMALIRQS);
  33653. +    ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);
  33654. +    
  33655. +    priv->rx_tail = nexttail;
  33656. +    priv->rx_head = ether1_inw (dev, priv->rx_head, rfd_t, rfd_link, NORMALIRQS);
  33657. +    } while (1);
  33658. +}
  33659. +
  33660. +static void
  33661. +ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
  33662. +{
  33663. +    struct device *dev = (struct device *)dev_id;
  33664. +    FUNC_PROLOGUE;
  33665. +    int status;
  33666. +
  33667. +    dev->interrupt = 1;
  33668. +
  33669. +    status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
  33670. +    if (status ) {
  33671. +    ether1_outw (dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
  33672. +            SCB_ADDR, scb_t, scb_command, NORMALIRQS);
  33673. +    outb (CTRL_CA | CTRL_ACK, REG_CONTROL);
  33674. +    if (status & SCB_STCX) {
  33675. +        ether1_xmit_done (dev);
  33676. +    }
  33677. +    if (status & SCB_STCNA) {
  33678. +        if (priv->resetting == 0)
  33679. +        printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);
  33680. +        if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
  33681. +                != (unsigned short)I82586_NULL) {
  33682. +        ether1_outw (dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
  33683. +        outb (CTRL_CA, REG_CONTROL);
  33684. +        }
  33685. +        if (priv->resetting == 2)
  33686. +        priv->resetting = 0;
  33687. +    }
  33688. +    if (status & SCB_STFR) {
  33689. +        ether1_recv_done (dev);
  33690. +    }
  33691. +    if (status & SCB_STRNR) {
  33692. +        printk (KERN_WARNING "%s: RU went not ready\n", dev->name);
  33693. +        printk (KERN_WARNING "RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset,
  33694. +                    NORMALIRQS));
  33695. +    }
  33696. +    } else
  33697. +        outb (CTRL_ACK, REG_CONTROL);
  33698. +
  33699. +    dev->interrupt = 0;
  33700. +}
  33701. +
  33702. +static int
  33703. +ether1_close (struct device *dev)
  33704. +{
  33705. +#ifdef CLAIM_IRQ_AT_OPEN
  33706. +    free_irq (dev->irq, dev);
  33707. +#endif
  33708. +
  33709. +    ether1_reset (dev);
  33710. +
  33711. +    dev->start = 0;
  33712. +    dev->tbusy = 0;
  33713. +
  33714. +    MOD_DEC_USE_COUNT;
  33715. +
  33716. +    return 0;
  33717. +}
  33718. +
  33719. +static struct enet_statistics *
  33720. +ether1_getstats (struct device *dev)
  33721. +{
  33722. +    FUNC_PROLOGUE;
  33723. +    return &priv->stats;
  33724. +}
  33725. +
  33726. +/*
  33727. + * Set or clear the multicast filter for this adaptor.
  33728. + * num_addrs == -1    Promiscuous mode, receive all packets.
  33729. + * num_addrs == 0    Normal mode, clear multicast list.
  33730. + * num_addrs > 0    Multicast mode, receive normal and MC packets, and do
  33731. + *            best-effort filtering.
  33732. + */
  33733. +static void
  33734. +ether1_setmulticastlist (struct device *dev)
  33735. +{
  33736. +}
  33737. +
  33738. +/* ------------------------------------------------------------------------- */
  33739. +
  33740. +#ifdef MODULE
  33741. +
  33742. +static char ethernames[MAX_ECARDS][9];
  33743. +static struct device *my_ethers[MAX_ECARDS];
  33744. +static struct expansion_card *ec[MAX_ECARDS];
  33745. +
  33746. +int
  33747. +init_module (void)
  33748. +{
  33749. +    int i;
  33750. +
  33751. +    for (i = 0; i < MAX_ECARDS; i++) {
  33752. +    my_ethers[i] = NULL;
  33753. +    ec[i] = NULL;
  33754. +    strcpy (ethernames[i], "        ");
  33755. +    }
  33756. +
  33757. +    i = 0;
  33758. +
  33759. +    do {
  33760. +    if ((ec[i] = ecard_find(0, sizeof(ether1_prods) / sizeof(int), ether1_prods, ether1_manus))
  33761. +        == NULL)
  33762. +        break;
  33763. +
  33764. +    my_ethers[i] = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL);
  33765. +    memset (my_ethers[i], 0, sizeof (struct device));
  33766. +
  33767. +    my_ethers[i]->irq = ec[i]->irq;
  33768. +    my_ethers[i]->base_addr = ((unsigned long)ecard_address (ec[i]->slot_no, ECARD_IOC, ECARD_FAST)) >> 2;
  33769. +    my_ethers[i]->init = ether1_probe;
  33770. +    my_ethers[i]->name = ethernames[i];
  33771. +
  33772. +    ecard_claim (ec[i]);
  33773. +
  33774. +    if (register_netdev (my_ethers[i]) != 0) {
  33775. +        for (i = 0; i < 4; i++) {
  33776. +        if (my_ethers[i]) {
  33777. +            kfree (my_ethers[i]);
  33778. +            my_ethers[i] = NULL;
  33779. +        }
  33780. +        if (ec[i]) {
  33781. +            ecard_release (ec[i]);
  33782. +            ec[i] = NULL;
  33783. +        }
  33784. +        }
  33785. +        return -EIO;
  33786. +    }
  33787. +    i++;
  33788. +    } while (i < MAX_ECARDS);
  33789. +
  33790. +    return i != 0 ? 0 : -ENODEV;
  33791. +}
  33792. +
  33793. +void
  33794. +cleanup_module (void)
  33795. +{
  33796. +    int i;
  33797. +
  33798. +    for (i = 0; i < MAX_ECARDS; i++) {
  33799. +    if (my_ethers[i]) {
  33800. +        unregister_netdev (my_ethers[i]);
  33801. +        my_ethers[i] = NULL;
  33802. +    }
  33803. +    if (ec[i]) {
  33804. +        ecard_release (ec[i]);
  33805. +        ec[i] = NULL;
  33806. +    }
  33807. +    }
  33808. +}
  33809. +#endif /* MODULE */
  33810. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/net/ether1.h linux/arch/arm/drivers/net/ether1.h
  33811. --- linux.orig/arch/arm/drivers/net/ether1.h    Thu Jan  1 01:00:00 1970
  33812. +++ linux/arch/arm/drivers/net/ether1.h    Fri Jul 19 20:44:22 1996
  33813. @@ -0,0 +1,281 @@
  33814. +/*
  33815. + * linux/arch/arm/drivers/net/ether1.h
  33816. + *
  33817. + * network driver for Acorn Ether1 cards.
  33818. + *
  33819. + * (c) 1996 Russell King
  33820. + */
  33821. +
  33822. +#ifndef _LINUX_ether1_H
  33823. +#define _LINUX_ether1_H
  33824. +
  33825. +#ifdef __ETHER1_C
  33826. +/* use 0 for production, 1 for verification, >2 for debug */
  33827. +#ifndef NET_DEBUG
  33828. +#define NET_DEBUG 0
  33829. +#endif
  33830. +
  33831. +/* Page register */
  33832. +#define REG_PAGE    (dev->base_addr + 0x00)
  33833. +
  33834. +/* Control register */
  33835. +#define REG_CONTROL    (dev->base_addr + 0x01)
  33836. +#define CTRL_RST    0x01
  33837. +#define CTRL_LOOPBACK    0x02
  33838. +#define CTRL_CA        0x04
  33839. +#define CTRL_ACK    0x08
  33840. +
  33841. +#define ETHER1_RAM    (dev->base_addr + 0x800)
  33842. +
  33843. +/* HW address */
  33844. +#define IDPROM_ADDRESS    (dev->base_addr + 0x09)
  33845. +
  33846. +struct ether1_priv {
  33847. +    struct enet_statistics stats;
  33848. +    int tx_link;
  33849. +    int tx_head;
  33850. +    volatile int tx_tail;
  33851. +    volatile int rx_head;
  33852. +    volatile int rx_tail;
  33853. +    char bus_type;
  33854. +    char resetting;
  33855. +    char initialising;
  33856. +};
  33857. +
  33858. +static int ether1_open (struct device *dev);
  33859. +static int ether1_sendpacket (struct sk_buff *skb, struct device *dev);
  33860. +static void ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs);
  33861. +static int ether1_close (struct device *dev);
  33862. +static struct enet_statistics *ether1_getstats (struct device *dev);
  33863. +static void ether1_setmulticastlist (struct device *dev);
  33864. +
  33865. +#define I82586_NULL (-1)
  33866. +
  33867. +typedef struct { /* tdr */
  33868. +    unsigned short tdr_status;
  33869. +    unsigned short tdr_command;
  33870. +    unsigned short tdr_link;
  33871. +    unsigned short tdr_result;
  33872. +#define TDR_TIME    (0x7ff)
  33873. +#define TDR_SHORT    (1 << 12)
  33874. +#define TDR_OPEN    (1 << 13)
  33875. +#define TDR_XCVRPROB    (1 << 14)
  33876. +#define TDR_LNKOK    (1 << 15)
  33877. +} tdr_t;
  33878. +
  33879. +typedef struct { /* transmit */
  33880. +    unsigned short tx_status;
  33881. +    unsigned short tx_command;
  33882. +    unsigned short tx_link;
  33883. +    unsigned short tx_tbdoffset;
  33884. +} tx_t;
  33885. +
  33886. +typedef struct { /* tbd */
  33887. +    unsigned short tbd_opts;
  33888. +#define TBD_CNT        (0x3fff)
  33889. +#define TBD_EOL        (1 << 15)
  33890. +    unsigned short tbd_link;
  33891. +    unsigned short tbd_bufl;
  33892. +    unsigned short tbd_bufh;
  33893. +} tbd_t;
  33894. +
  33895. +typedef struct { /* rfd */
  33896. +    unsigned short rfd_status;
  33897. +#define RFD_NOEOF    (1 << 6)
  33898. +#define RFD_FRAMESHORT    (1 << 7)
  33899. +#define RFD_DMAOVRN    (1 << 8)
  33900. +#define RFD_NORESOURCES    (1 << 9)
  33901. +#define RFD_ALIGNERROR    (1 << 10)
  33902. +#define RFD_CRCERROR    (1 << 11)
  33903. +#define RFD_OK        (1 << 13)
  33904. +#define RFD_FDCONSUMED    (1 << 14)
  33905. +#define RFD_COMPLETE    (1 << 15)
  33906. +    unsigned short rfd_command;
  33907. +#define RFD_CMDSUSPEND    (1 << 14)
  33908. +#define RFD_CMDEL    (1 << 15)
  33909. +    unsigned short rfd_link;
  33910. +    unsigned short rfd_rbdoffset;
  33911. +    unsigned char  rfd_dest[6];
  33912. +    unsigned char  rfd_src[6];
  33913. +    unsigned short rfd_len;
  33914. +} rfd_t;
  33915. +
  33916. +typedef struct { /* rbd */
  33917. +    unsigned short rbd_status;
  33918. +#define RBD_ACNT    (0x3fff)
  33919. +#define RBD_ACNTVALID    (1 << 14)
  33920. +#define RBD_EOF        (1 << 15)
  33921. +    unsigned short rbd_link;
  33922. +    unsigned short rbd_bufl;
  33923. +    unsigned short rbd_bufh;
  33924. +    unsigned short rbd_len;
  33925. +} rbd_t;
  33926. +
  33927. +typedef struct { /* nop */
  33928. +    unsigned short nop_status;
  33929. +    unsigned short nop_command;
  33930. +    unsigned short nop_link;
  33931. +} nop_t;
  33932. +
  33933. +typedef struct { /* set multicast */
  33934. +    unsigned short mc_status;
  33935. +    unsigned short mc_command;
  33936. +    unsigned short mc_link;
  33937. +    unsigned short mc_cnt;
  33938. +    unsigned char  mc_addrs[1][6];
  33939. +} mc_t;
  33940. +
  33941. +typedef struct { /* set address */
  33942. +    unsigned short sa_status;
  33943. +    unsigned short sa_command;
  33944. +    unsigned short sa_link;
  33945. +    unsigned char  sa_addr[6];
  33946. +} sa_t;
  33947. +
  33948. +typedef struct { /* config command */
  33949. +    unsigned short cfg_status;
  33950. +    unsigned short cfg_command;
  33951. +    unsigned short cfg_link;
  33952. +    unsigned char  cfg_bytecnt;    /* size foll data: 4 - 12         */
  33953. +    unsigned char  cfg_fifolim;    /* FIFO threshold             */
  33954. +    unsigned char  cfg_byte8;
  33955. +#define CFG8_SRDY    (1 << 6)
  33956. +#define CFG8_SAVEBADF    (1 << 7)
  33957. +    unsigned char  cfg_byte9;
  33958. +#define CFG9_ADDRLEN(x)    (x)
  33959. +#define CFG9_ADDRLENBUF    (1 << 3)
  33960. +#define CFG9_PREAMB2    (0 << 4)
  33961. +#define CFG9_PREAMB4    (1 << 4)
  33962. +#define CFG9_PREAMB8    (2 << 4)
  33963. +#define CFG9_PREAMB16    (3 << 4)
  33964. +#define CFG9_ILOOPBACK    (1 << 6)
  33965. +#define CFG9_ELOOPBACK    (1 << 7)
  33966. +    unsigned char  cfg_byte10;
  33967. +#define CFG10_LINPRI(x)    (x)
  33968. +#define CFG10_ACR(x)    (x << 4)
  33969. +#define CFG10_BOFMET    (1 << 7)
  33970. +    unsigned char  cfg_ifs;
  33971. +    unsigned char  cfg_slotl;
  33972. +    unsigned char  cfg_byte13;
  33973. +#define CFG13_SLOTH(x)    (x)
  33974. +#define CFG13_RETRY(x)    (x << 4)
  33975. +    unsigned char  cfg_byte14;
  33976. +#define CFG14_PROMISC    (1 << 0)
  33977. +#define CFG14_DISBRD    (1 << 1)
  33978. +#define CFG14_MANCH    (1 << 2)
  33979. +#define CFG14_TNCRS    (1 << 3)
  33980. +#define CFG14_NOCRC    (1 << 4)
  33981. +#define CFG14_CRC16    (1 << 5)
  33982. +#define CFG14_BTSTF    (1 << 6)
  33983. +#define CFG14_FLGPAD    (1 << 7)
  33984. +    unsigned char  cfg_byte15;
  33985. +#define CFG15_CSTF(x)    (x)
  33986. +#define CFG15_ICSS    (1 << 3)
  33987. +#define CFG15_CDTF(x)    (x << 4)
  33988. +#define CFG15_ICDS    (1 << 7)
  33989. +    unsigned short cfg_minfrmlen;
  33990. +} cfg_t;
  33991. +
  33992. +typedef struct { /* scb */
  33993. +    unsigned short scb_status;    /* status of 82586             */
  33994. +#define SCB_STRXMASK        (7 << 4)
  33995. +#define SCB_STRXIDLE        (0 << 4)
  33996. +#define SCB_STRXSUSP        (1 << 4)
  33997. +#define SCB_STRXNRES        (2 << 4)
  33998. +#define SCB_STRXRDY        (4 << 4)
  33999. +#define SCB_STCUMASK        (7 << 8)
  34000. +#define SCB_STCUIDLE        (0 << 8)
  34001. +#define SCB_STCUSUSP        (1 << 8)
  34002. +#define SCB_STCUACTV        (2 << 8)
  34003. +#define SCB_STRNR        (1 << 12)
  34004. +#define SCB_STCNA        (1 << 13)
  34005. +#define SCB_STFR        (1 << 14)
  34006. +#define SCB_STCX        (1 << 15)
  34007. +    unsigned short scb_command;    /* Next command                 */
  34008. +#define SCB_CMDRXSTART        (1 << 4)
  34009. +#define SCB_CMDRXRESUME        (2 << 4)
  34010. +#define SCB_CMDRXSUSPEND    (3 << 4)
  34011. +#define SCB_CMDRXABORT        (4 << 4)
  34012. +#define SCB_CMDCUCSTART        (1 << 8)
  34013. +#define SCB_CMDCUCRESUME    (2 << 8)
  34014. +#define SCB_CMDCUCSUSPEND    (3 << 8)
  34015. +#define SCB_CMDCUCABORT        (4 << 8)
  34016. +#define SCB_CMDACKRNR        (1 << 12)
  34017. +#define SCB_CMDACKCNA        (1 << 13)
  34018. +#define SCB_CMDACKFR        (1 << 14)
  34019. +#define SCB_CMDACKCX        (1 << 15)
  34020. +    unsigned short scb_cbl_offset;    /* Offset of first command unit         */
  34021. +    unsigned short scb_rfa_offset;    /* Offset of first receive frame area     */
  34022. +    unsigned short scb_crc_errors;    /* Properly aligned frame with CRC error */
  34023. +    unsigned short scb_aln_errors;    /* Misaligned frames             */
  34024. +    unsigned short scb_rsc_errors;    /* Frames lost due to no space         */
  34025. +    unsigned short scb_ovn_errors;    /* Frames lost due to slow bus         */
  34026. +} scb_t;
  34027. +
  34028. +typedef struct { /* iscp */
  34029. +    unsigned short iscp_busy;    /* set by CPU before CA             */
  34030. +    unsigned short iscp_offset;    /* offset of SCB             */
  34031. +    unsigned short iscp_basel;    /* base of SCB                 */
  34032. +    unsigned short iscp_baseh;
  34033. +} iscp_t;
  34034. +
  34035. +    /* this address must be 0xfff6 */
  34036. +typedef struct { /* scp */
  34037. +    unsigned short scp_sysbus;    /* bus size */
  34038. +#define SCP_SY_16BBUS    0x00
  34039. +#define SCP_SY_8BBUS    0x01
  34040. +    unsigned short scp_junk[2];    /* junk */
  34041. +    unsigned short scp_iscpl;    /* lower 16 bits of iscp */
  34042. +    unsigned short scp_iscph;    /* upper 16 bits of iscp */
  34043. +} scp_t;
  34044. +
  34045. +/* commands */
  34046. +#define CMD_NOP            0
  34047. +#define CMD_SETADDRESS        1
  34048. +#define CMD_CONFIG        2
  34049. +#define CMD_SETMULTICAST    3
  34050. +#define CMD_TX            4
  34051. +#define CMD_TDR            5
  34052. +#define CMD_DUMP        6
  34053. +#define CMD_DIAGNOSE        7
  34054. +
  34055. +#define CMD_MASK        7
  34056. +
  34057. +#define CMD_INTR        (1 << 13)
  34058. +#define CMD_SUSP        (1 << 14)
  34059. +#define CMD_EOL            (1 << 15)
  34060. +
  34061. +#define STAT_COLLISIONS        (15)
  34062. +#define STAT_COLLEXCESSIVE    (1 << 5)
  34063. +#define STAT_COLLAFTERTX    (1 << 6)
  34064. +#define STAT_TXDEFERRED        (1 << 7)
  34065. +#define STAT_TXSLOWDMA        (1 << 8)
  34066. +#define STAT_TXLOSTCTS        (1 << 9)
  34067. +#define STAT_NOCARRIER        (1 << 10)
  34068. +#define STAT_FAIL        (1 << 11)
  34069. +#define STAT_ABORTED        (1 << 12)
  34070. +#define STAT_OK            (1 << 13)
  34071. +#define STAT_BUSY        (1 << 14)
  34072. +#define STAT_COMPLETE        (1 << 15)
  34073. +#endif
  34074. +#endif
  34075. +
  34076. +/*
  34077. + * Ether1 card definitions:
  34078. + *
  34079. + * FAST accesses:
  34080. + *    +0    Page register
  34081. + *             16 pages
  34082. + *    +4    Control
  34083. + *            '1' = reset
  34084. + *            '2' = loopback
  34085. + *            '4' = CA
  34086. + *            '8' = int ack
  34087. + *
  34088. + * RAM at address + 0x2000
  34089. + * Pod. Prod id = 3
  34090. + * Words after ID block [base + 8 words]
  34091. + *    +0 pcb issue (0x0c and 0xf3 invalid)
  34092. + *    +1 - +6 eth hw address
  34093. + */
  34094. +
  34095. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/net/ether3.c linux/arch/arm/drivers/net/ether3.c
  34096. --- linux.orig/arch/arm/drivers/net/ether3.c    Thu Jan  1 01:00:00 1970
  34097. +++ linux/arch/arm/drivers/net/ether3.c    Mon Jul 29 20:46:34 1996
  34098. @@ -0,0 +1,892 @@
  34099. +/*
  34100. + * linux/drivers/net/ether3.c
  34101. + *
  34102. + * SEEQ nq8005 ethernet driver
  34103. + *
  34104. + * By Russell King, with some suggestions from borris@ant.co.uk
  34105. + *
  34106. + * Changelog:
  34107. + *  29/02/96:    RMK    Won't pass packets that are from our ethernet address
  34108. + *            up to the higher levels - they're silently ignored.
  34109. + *            I/F can now be put into multicast mode.  Receiver
  34110. + *            routine optimised.
  34111. + *
  34112. + *  30/02/96:    RMK    Now claims interrupt at open when part of the kernel
  34113. + *            rather than when a module.
  34114. + *
  34115. + *  02/03/96:    RMK    Various code cleanups
  34116. + *
  34117. + * TODO:
  34118. + *  When we detect a fatal error on the interface, we should restart it.
  34119. + */
  34120. +
  34121. +#include <linux/module.h>
  34122. +#include <linux/kernel.h>
  34123. +#include <linux/sched.h>
  34124. +#include <linux/types.h>
  34125. +#include <linux/fcntl.h>
  34126. +#include <linux/interrupt.h>
  34127. +#include <linux/ptrace.h>
  34128. +#include <linux/ioport.h>
  34129. +#include <linux/in.h>
  34130. +#include <linux/malloc.h>
  34131. +#include <linux/string.h>
  34132. +#include <linux/errno.h>
  34133. +#include <linux/netdevice.h>
  34134. +#include <linux/etherdevice.h>
  34135. +#include <linux/skbuff.h>
  34136. +
  34137. +#include <asm/system.h>
  34138. +#include <asm/bitops.h>
  34139. +#include <asm/io.h>
  34140. +#include <asm/dma.h>
  34141. +#include <asm/ecard.h>
  34142. +
  34143. +#include "ether3.h"
  34144. +
  34145. +static unsigned int net_debug = NET_DEBUG;
  34146. +static const int ether3_prods[] = { 0x00A4 };
  34147. +static const int ether3_manus[] = { 0x0011 };
  34148. +
  34149. +static void
  34150. +ether3_setmulticastlist (struct device *dev);
  34151. +
  34152. +static char *version = "ether3 ethernet driver (c) 1995 R.M.King v1.10\n";
  34153. +
  34154. +extern int inswb(int reg, void *buffer, int len);
  34155. +extern int outswb(int reg, void *buffer, int len);
  34156. +
  34157. +#define FUNC_PROLOGUE \
  34158. +    struct dev_priv *priv = (struct dev_priv *)dev->priv
  34159. +
  34160. +#define BUS_16 16
  34161. +#define BUS_8  8
  34162. +
  34163. +/*
  34164. + * I'm not sure what address we should default to if the internal one
  34165. + * is corrupted...
  34166. + */
  34167. +unsigned char def_eth_addr[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
  34168. +
  34169. +/* --------------------------------------------------------------------------- */
  34170. +
  34171. +/*
  34172. + * write data to the buffer memory
  34173. + */
  34174. +static void
  34175. +ether3_writebuffer(struct device *dev, void *data, int start, int length)
  34176. +{
  34177. +    FUNC_PROLOGUE;
  34178. +    int timeout = 1000000;
  34179. +
  34180. +    if (start != -1) {
  34181. +    outw (priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  34182. +    outw (priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  34183. +    while ((inw (REG_STATUS) & STAT_FIFOEMPTY) == 0)
  34184. +        if (!timeout--) {
  34185. +        printk (KERN_CRIT "%s: writebuf broken\n", dev->name);
  34186. +        priv->broken = 1;
  34187. +        return;
  34188. +        }
  34189. +    outw (priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  34190. +    outw (start, REG_DMAADDR);
  34191. +    }
  34192. +    if(length != 0)
  34193. +    outswb (REG_BUFWIN, data, length);
  34194. +}
  34195. +
  34196. +/*
  34197. + * read data from the buffer memory
  34198. + */
  34199. +static void
  34200. +ether3_readbuffer(struct device *dev, void *data, int start, int length)
  34201. +{
  34202. +    FUNC_PROLOGUE;
  34203. +    int timeout = 1000000;
  34204. +
  34205. +    if (start != -1) {
  34206. +    outw (priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  34207. +    outw (priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  34208. +    while ((inw( REG_STATUS) & STAT_FIFOEMPTY) == 0)
  34209. +        if (!timeout--) {
  34210. +        printk (KERN_CRIT "%s: readbuf broken\n", dev->name);
  34211. +        priv->broken = 1;
  34212. +        return;
  34213. +        }
  34214. +    outw (start, REG_DMAADDR);
  34215. +    outw (priv->regs.command | CMD_FIFOREAD, REG_COMMAND);
  34216. +    }
  34217. +    if(length != 0)
  34218. +    inswb (REG_BUFWIN, data, length);
  34219. +}
  34220. +
  34221. +/*
  34222. + * Increment the use count, and switch LED on if necessary
  34223. + */
  34224. +static inline void
  34225. +ether3_ledincrementuse (struct device *dev)
  34226. +{
  34227. +    FUNC_PROLOGUE;
  34228. +
  34229. +    if (++ priv->use == 1) {
  34230. +    priv->regs.config2 &= ~CFG2_CTRLO;
  34231. +    outw (priv->regs.config2 , REG_CONFIG2);
  34232. +    }
  34233. +}
  34234. +
  34235. +/*
  34236. + * Decrement the use count and switch LED off if necessary
  34237. + */
  34238. +static inline void
  34239. +ether3_leddecrementuse (struct device *dev)
  34240. +{
  34241. +    FUNC_PROLOGUE;
  34242. +
  34243. +    if (priv->use && -- priv->use == 0) {
  34244. +    priv->regs.config2 |= CFG2_CTRLO;
  34245. +    outw (priv->regs.config2, REG_CONFIG2);
  34246. +    }
  34247. +}
  34248. +
  34249. +/*
  34250. + * Read the ethernet address string from the on board rom.
  34251. + * This is an ascii string!!!
  34252. + */
  34253. +static void
  34254. +ether3_addr (char *addr, struct expansion_card *ec)
  34255. +{
  34256. +    struct chunk_dir cd;
  34257. +    char *s;
  34258. +    
  34259. +    if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) {
  34260. +    int i;
  34261. +    for (i = 0; i<6; i++) {
  34262. +        addr[i] = simple_strtoul(s + 1, &s, 0x10);
  34263. +        if (*s != (i==5?')' : ':' ))
  34264. +        break;
  34265. +    }
  34266. +    if (i == 6)
  34267. +        return;
  34268. +    }
  34269. +    memcpy (addr, def_eth_addr, 6);
  34270. +}
  34271. +
  34272. +/* --------------------------------------------------------------------------- */
  34273. +
  34274. +static int
  34275. +ether3_ramtest(struct device *dev, unsigned char byte)
  34276. +{
  34277. +    unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL);
  34278. +    int i,ret=0;
  34279. +    int max_errors = 4;
  34280. +    int bad=-1;
  34281. +
  34282. +    if (!buffer)
  34283. +    return 1;
  34284. +
  34285. +    memset (buffer, byte, RX_END);
  34286. +    ether3_writebuffer (dev, buffer, 0, TX_END);
  34287. +    ether3_writebuffer (dev, buffer+RX_START, RX_START, RX_LEN);
  34288. +
  34289. +    memset (buffer, byte ^ 0xff, RX_END);
  34290. +    ether3_readbuffer (dev, buffer, 0, TX_END);
  34291. +    ether3_readbuffer (dev, buffer+RX_START, RX_START, RX_LEN);
  34292. +
  34293. +    for (i=0; i<RX_END; i++) {
  34294. +    if (buffer[i] != byte) {
  34295. +        if (max_errors>=0 && bad!=buffer[i]) {
  34296. +        printk (KERN_ERR "%s: RAM failed with (%02X instead of %02X) at 0x%04X",
  34297. +            dev->name, buffer[i], byte, i);
  34298. +        ret = 2;
  34299. +        max_errors--;
  34300. +        bad = buffer[i];
  34301. +        }
  34302. +    } else {
  34303. +        if (bad != -1) {
  34304. +        printk(" - 0x%04X\n", i);
  34305. +        bad = -1;
  34306. +        }
  34307. +    }
  34308. +    }
  34309. +    if (bad != -1)
  34310. +    printk (" - 0x10000\n");
  34311. +    kfree (buffer);
  34312. +
  34313. +    return ret;
  34314. +}
  34315. +
  34316. +/* ------------------------------------------------------------------------------- */
  34317. +
  34318. +static int
  34319. +ether3_init_2(struct device *dev)
  34320. +{
  34321. +    FUNC_PROLOGUE;
  34322. +    int i;
  34323. +    unsigned long txhdr = 0;
  34324. +
  34325. +    priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8;
  34326. +    priv->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC;
  34327. +    priv->regs.command = 0;
  34328. +    /*
  34329. +     * Set up our hardware address
  34330. +     */
  34331. +    outw (priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
  34332. +    for (i = 0; i < 6; i++)
  34333. +    outb (dev->dev_addr[i], REG_BUFWIN);
  34334. +
  34335. +    if (dev->flags & IFF_PROMISC)
  34336. +    priv->regs.config1 |= CFG1_RECVPROMISC;
  34337. +    else
  34338. +    if (dev->flags & IFF_MULTICAST)
  34339. +    priv->regs.config1 |= CFG1_RECVSPECBRMULTI;
  34340. +    else
  34341. +    priv->regs.config1 |= CFG1_RECVSPECBROAD;
  34342. +
  34343. +    /*
  34344. +     * There is a problem with the NQ8005 in that it occasionally losses the
  34345. +     * last two bytes.  To get round this problem, we receive the CRC as well.
  34346. +     * That way, if we do loose the last two, then it doesn't matter
  34347. +     */
  34348. +    outw (priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
  34349. +    outw ((TX_END>>8) - 1, REG_BUFWIN);
  34350. +    outw (priv->regs.recvptr, REG_RECVPTR);
  34351. +    outw (priv->regs.transmitptr, REG_TRANSMITPTR);
  34352. +    outw (priv->regs.recvptr >> 8, REG_RECVEND);
  34353. +    outw (priv->regs.config2, REG_CONFIG2);
  34354. +    outw (priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  34355. +
  34356. +    ether3_writebuffer (dev, &txhdr, priv->regs.transmitptr, 4);
  34357. +
  34358. +    outw (priv->regs.command, REG_COMMAND);
  34359. +
  34360. +    i = ether3_ramtest (dev, 0x5A);
  34361. +    if(i)
  34362. +    return i;
  34363. +    return ether3_ramtest (dev, 0x1E);
  34364. +}
  34365. +
  34366. +static void
  34367. +ether3_init_for_open(struct device *dev)
  34368. +{
  34369. +    FUNC_PROLOGUE;
  34370. +    unsigned long txhdr = 0;
  34371. +    int i;
  34372. +
  34373. +    memset (&priv->stats, 0, sizeof (struct enet_statistics));
  34374. +
  34375. +    priv->regs.command = 0;
  34376. +    priv->txbuffered = 0;
  34377. +    outw (CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
  34378. +    while (inw (REG_STATUS) & (STAT_RXON|STAT_TXON));
  34379. +
  34380. +    outw (priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
  34381. +    for (i = 0; i < 6; i++)
  34382. +    outb (dev->dev_addr[i], REG_BUFWIN);
  34383. +
  34384. +    priv->regs.transmitptr = 0;    /* address that transmitter has processed to */
  34385. +    priv->txinsert = 0;        /* address of next available packet for tx */
  34386. +    priv->txed = 0;            /* transmitted length index */
  34387. +    priv->txto = 0;            /* to transmit length index */
  34388. +    priv->tx_ends[0] = 0;
  34389. +    priv->use = 0;
  34390. +
  34391. +    priv->regs.config2 |= CFG2_CTRLO;
  34392. +
  34393. +    outw (priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
  34394. +    outw ((TX_END>>8) - 1, REG_BUFWIN);
  34395. +
  34396. +    priv->regs.recvptr    = RX_START;
  34397. +    outw (priv->regs.recvptr, REG_RECVPTR);
  34398. +    outw (priv->regs.recvptr >> 8, REG_RECVEND);
  34399. +
  34400. +    outw (0, REG_TRANSMITPTR);
  34401. +    outw (priv->regs.config2, REG_CONFIG2);
  34402. +    outw (priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  34403. +
  34404. +    ether3_writebuffer (dev, &txhdr, priv->regs.transmitptr, 4);
  34405. +
  34406. +    priv->regs.command = CMD_ENINTRX|CMD_ENINTTX;
  34407. +    outw (priv->regs.command | CMD_RXON, REG_COMMAND);
  34408. +}
  34409. +
  34410. +/*
  34411. + * This is the real probe routine.
  34412. + */
  34413. +static int
  34414. +ether3_probe1(struct device *dev)
  34415. +{
  34416. +    static unsigned version_printed = 0;
  34417. +    struct dev_priv *priv;
  34418. +    int i;
  34419. +
  34420. +    if (!dev->priv)
  34421. +    dev->priv = kmalloc (sizeof (struct dev_priv), GFP_KERNEL);
  34422. +
  34423. +    if (!dev->priv)
  34424. +    return -ENOMEM;
  34425. +
  34426. +    priv = (struct dev_priv *) dev->priv;
  34427. +    memset (priv, 0, sizeof(struct dev_priv));
  34428. +    priv->broken = 0;
  34429. +
  34430. +    outb (0x80, REG_CONFIG2 + 1);
  34431. +    outb (0, REG_COMMAND);
  34432. +
  34433. +    /*
  34434. +     * test to see if we have an 8 or 16-bit IO bus
  34435. +     */
  34436. +    outb (1, REG_CONFIG1);
  34437. +    if (inb (REG_CONFIG1 + 1) == 1 && inb (REG_CONFIG1) == 0)
  34438. +        priv->bus_type = BUS_8;
  34439. +    else
  34440. +    if (inw (REG_CONFIG1) == 0x0101)
  34441. +        priv->bus_type = BUS_16;
  34442. +    else {
  34443. +    kfree(dev->priv);
  34444. +    dev->priv = NULL;
  34445. +    return -ENODEV;
  34446. +    }
  34447. +
  34448. +    if (net_debug  &&  version_printed++ == 0)
  34449. +    printk (KERN_INFO "%s", version);
  34450. +
  34451. +    printk(KERN_INFO "%s: ether3 found [%d, %04lx, %d] ", dev->name, priv->bus_type,
  34452. +    dev->base_addr, dev->irq);
  34453. +
  34454. +    request_region (dev->base_addr, 128, "ether3");
  34455. +
  34456. +    if (priv->bus_type == BUS_8) {
  34457. +    printk (KERN_CRIT "*** 8-bit not supported (yet) ***\n");
  34458. +    kfree (dev->priv);
  34459. +    dev->priv = NULL;
  34460. +    return -ENODEV;
  34461. +    }
  34462. +
  34463. +    /* Retrive and print the ethernet address. */
  34464. +    for (i = 0; i < 6; i++)
  34465. +    printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
  34466. +
  34467. +    if (ether3_init_2(dev)) {
  34468. +    kfree (dev->priv);
  34469. +    dev->priv = NULL;
  34470. +    return -ENODEV;
  34471. +    }
  34472. +
  34473. +    dev->open = ether3_open;
  34474. +    dev->stop = ether3_close;
  34475. +    dev->hard_start_xmit = ether3_sendpacket;
  34476. +    dev->get_stats = ether3_getstats;
  34477. +    dev->set_multicast_list = ether3_setmulticastlist;
  34478. +
  34479. +    /* Fill in the fields of the device structure with ethernet values. */
  34480. +    ether_setup(dev);
  34481. +#ifndef CLAIM_IRQ_AT_OPEN
  34482. +    if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) {
  34483. +    kfree (dev->priv);
  34484. +    dev->priv = NULL;
  34485. +    return -EAGAIN;
  34486. +    }
  34487. +#endif
  34488. +    return 0;
  34489. +}
  34490. +
  34491. +#ifndef MODULE
  34492. +int
  34493. +ether3_probe(struct device *dev)
  34494. +{
  34495. +    struct expansion_card *ec;
  34496. +
  34497. +    if (!dev)
  34498. +    return ENODEV;
  34499. +
  34500. +    if ((ec = ecard_find (0, sizeof(ether3_prods), ether3_prods, ether3_manus)) == NULL)
  34501. +    return ENODEV;
  34502. +
  34503. +    dev->base_addr = ((unsigned long)ecard_address (ec->slot_no, ECARD_MEMC, 0)) >> 2;
  34504. +    dev->irq = ec->irq;
  34505. +
  34506. +    ecard_claim (ec);
  34507. +
  34508. +    ether3_addr (dev->dev_addr, ec);
  34509. +    return ether3_probe1(dev);
  34510. +}
  34511. +#endif
  34512. +
  34513. +/*
  34514. + * Open/initialize the board.  This is called (in the current kernel)
  34515. + * sometime after booting when the 'ifconfig' program is run.
  34516. + *
  34517. + * This routine should set everything up anew at each open, even
  34518. + * registers that "should" only need to be set once at boot, so that
  34519. + * there is non-reboot way to recover if something goes wrong.
  34520. + */
  34521. +static int
  34522. +ether3_open(struct device *dev)
  34523. +{
  34524. +    ether3_init_for_open(dev);
  34525. +
  34526. +#ifdef CLAIM_IRQ_AT_OPEN
  34527. +    if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev))
  34528. +    return -EAGAIN;
  34529. +#endif
  34530. +
  34531. +    MOD_INC_USE_COUNT;
  34532. +
  34533. +    dev->tbusy = 0;
  34534. +    dev->interrupt = 0;
  34535. +    dev->start = 1;
  34536. +    return 0;
  34537. +}
  34538. +
  34539. +/*
  34540. + * The inverse routine to ether3_open().
  34541. + */
  34542. +static int
  34543. +ether3_close(struct device *dev)
  34544. +{
  34545. +    FUNC_PROLOGUE;
  34546. +    unsigned long flags;
  34547. +
  34548. +    dev->tbusy = 1;
  34549. +    dev->start = 0;
  34550. +
  34551. +    save_flags_cli (flags);
  34552. +
  34553. +    outw (CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
  34554. +    priv->regs.command = 0;
  34555. +    while (inw (REG_STATUS) & (STAT_RXON|STAT_TXON));
  34556. +    outb (0x80, REG_CONFIG2 + 1);
  34557. +    outw (0, REG_COMMAND);
  34558. +
  34559. +    restore_flags (flags);
  34560. +#ifdef CLAIM_IRQ_AT_OPEN
  34561. +    free_irq (dev->irq, dev);
  34562. +#endif
  34563. +
  34564. +    MOD_DEC_USE_COUNT;
  34565. +    return 0;
  34566. +}
  34567. +
  34568. +/*
  34569. + * Get the current statistics.    This may be called with the card open or
  34570. + * closed.
  34571. + */
  34572. +static struct enet_statistics *ether3_getstats (struct device *dev)
  34573. +{
  34574. +    FUNC_PROLOGUE;
  34575. +    return &priv->stats;
  34576. +}
  34577. +
  34578. +/*
  34579. + * Set or clear promiscuous/multicast mode filter for this adaptor.
  34580. + *
  34581. + * We don't attempt any packet filtering.  The card may have a SEEQ 8004
  34582. + * in which does not have the other ethernet address registers present...
  34583. + */
  34584. +static void ether3_setmulticastlist (struct device *dev)
  34585. +{
  34586. +    FUNC_PROLOGUE;
  34587. +
  34588. +    priv->regs.config1 &= ~CFG1_RECVPROMISC;
  34589. +
  34590. +    if (dev->flags & IFF_PROMISC) {
  34591. +    /* promiscuous mode */
  34592. +    priv->regs.config1 |= CFG1_RECVPROMISC;
  34593. +    } else
  34594. +    if (dev->flags & IFF_ALLMULTI) {
  34595. +    priv->regs.config1 |= CFG1_RECVSPECBRMULTI;
  34596. +    } else
  34597. +    priv->regs.config1 |= CFG1_RECVSPECBROAD;
  34598. +
  34599. +    outw (priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  34600. +}
  34601. +
  34602. +/*
  34603. + * Transmit a packet
  34604. + */
  34605. +static int
  34606. +ether3_sendpacket(struct sk_buff *skb, struct device *dev)
  34607. +{
  34608. +    FUNC_PROLOGUE;
  34609. +
  34610. +    if (dev->tbusy) {
  34611. +    /* If we get here, some higher level has decided we are broken.
  34612. +       There should really be a "kick me" function call instead. */
  34613. +    int tickssofar = jiffies - dev->trans_start;
  34614. +    if (tickssofar < 5)
  34615. +        return 1;
  34616. +    printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name);
  34617. +    /* Try to restart the adaptor. */
  34618. +    dev->tbusy = 0;
  34619. +    priv->use = 0;
  34620. +    priv->regs.config2 |= CFG2_CTRLO;
  34621. +    outw (priv->regs.config2 , REG_CONFIG2);
  34622. +    dev->trans_start = jiffies;
  34623. +    }
  34624. +
  34625. +    /* If some higher layer thinks we've missed an tx-done interrupt
  34626. +       we are passed NULL. Caution: dev_tint() handles the cli()/sti()
  34627. +       itself. */
  34628. +    if (skb == NULL) {
  34629. +    dev_tint(dev);
  34630. +    return 0;
  34631. +    }
  34632. +
  34633. +    /* Block a timer-based transmit from overlapping.  This could better be
  34634. +       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
  34635. +    if (set_bit(0, (void*)&dev->tbusy) != 0)
  34636. +    printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
  34637. +    else {
  34638. +    unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
  34639. +    unsigned int thisdata, thisstart, nextpacket;
  34640. +    unsigned long flags;
  34641. +    unsigned long thishdr = TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS
  34642. +                |TXHDR_ENSUCCESS;
  34643. +    unsigned long nexthdr = 0;
  34644. +
  34645. +    if (priv->broken) {
  34646. +        dev_kfree_skb(skb, FREE_WRITE);
  34647. +        priv->stats.tx_dropped ++;
  34648. +        dev->tbusy = 0;
  34649. +        return 0;
  34650. +    }
  34651. +
  34652. +    thisstart = priv->txinsert;
  34653. +    thisdata  = thisstart + 4;
  34654. +    if (thisdata >= TX_END)
  34655. +        thisdata -= TX_END;
  34656. +
  34657. +    nextpacket = thisdata + length;
  34658. +    if (nextpacket >= TX_END)
  34659. +        nextpacket -= TX_END;
  34660. +
  34661. +    priv->txinsert = nextpacket;
  34662. +    priv->tx_ends[priv->txto++] = nextpacket;
  34663. +
  34664. +    if (priv->txto >= MAX_TXED)
  34665. +        priv->txto = 0;
  34666. +
  34667. +    thishdr |= htons (nextpacket);
  34668. +
  34669. +    save_flags_cli (flags);
  34670. +    ether3_writebuffer(dev, skb->data, thisdata, (length & 1) ? (length + 1) : length);
  34671. +    ether3_writebuffer(dev, &nexthdr, -1, 4);
  34672. +    ether3_ledincrementuse (dev);
  34673. +    ether3_writebuffer(dev, &thishdr, thisstart, 4);
  34674. +
  34675. +    if ((inw (REG_STATUS) & STAT_TXON) == 0) {
  34676. +        outw (thisstart, REG_TRANSMITPTR);
  34677. +        outw (priv->regs.command | CMD_TXON, REG_COMMAND);
  34678. +    }
  34679. +    restore_flags(flags);
  34680. +
  34681. +    dev->trans_start = jiffies;
  34682. +    if (priv->txbuffered ++ < MAX_TX_BUFFERED)
  34683. +        dev->tbusy = 0;
  34684. +    }
  34685. +    dev_kfree_skb (skb, FREE_WRITE);
  34686. +
  34687. +    return 0;
  34688. +}
  34689. +
  34690. +static void
  34691. +ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  34692. +{
  34693. +    struct device *dev = (struct device *)dev_id;
  34694. +    struct dev_priv *priv;
  34695. +    int boguscount = 20, done;
  34696. +
  34697. +#if NET_DEBUG > 1
  34698. +    if(net_debug & DEBUG_INT)
  34699. +    printk(KERN_DEBUG "eth3irq: %d ", irq);
  34700. +#endif
  34701. +
  34702. +    priv = (struct dev_priv *)dev->priv;
  34703. +
  34704. +    dev->interrupt = 1;
  34705. +
  34706. +    do {
  34707. +        unsigned int status;
  34708. +
  34709. +        done = 0;
  34710. +    status = inw(REG_STATUS);
  34711. +
  34712. +    if (status & STAT_INTRX) { /* Got a packet(s). */
  34713. +        outw (CMD_ACKINTRX | priv->regs.command, REG_COMMAND);
  34714. +        ether3_rx (dev, priv);
  34715. +        done = 1;
  34716. +    }
  34717. +    if (status & STAT_INTTX) { /* Packets transmitted */
  34718. +        outw (CMD_ACKINTTX | priv->regs.command, REG_COMMAND);
  34719. +        ether3_tx (dev, priv);
  34720. +        done = 1;
  34721. +    }
  34722. +    if (status & STAT_INTBUFWIN) { /* buffer window interrupt */
  34723. +        outw (CMD_ACKINTBUFWIN | priv->regs.command, REG_COMMAND);
  34724. +    }
  34725. +    } while (-- boguscount && !done) ;
  34726. +
  34727. +    dev->interrupt = 0;
  34728. +
  34729. +#if NET_DEBUG > 1
  34730. +    if(net_debug & DEBUG_INT)
  34731. +    printk("done\n");
  34732. +#endif
  34733. +}
  34734. +
  34735. +/*
  34736. + * If we have a good packet(s), get it/them out of the buffers.
  34737. + */
  34738. +static void
  34739. +ether3_rx(struct device *dev, struct dev_priv *priv)
  34740. +{
  34741. +    unsigned int current_recv_ptr;
  34742. +    unsigned int maxcnt = 10;
  34743. +
  34744. +    ether3_ledincrementuse (dev);
  34745. +
  34746. +    current_recv_ptr = priv->regs.recvptr;
  34747. +
  34748. +    do {
  34749. +        struct t {
  34750. +            unsigned long rxhdr;
  34751. +            unsigned char dst_addr[6];
  34752. +            unsigned char src_addr[6];
  34753. +        } p;
  34754. +    unsigned int prev_recv_ptr;
  34755. +
  34756. +    /*
  34757. +     * read the first 16 bytes from the buffer.
  34758. +     * This contains the status bytes etc and ethernet addresses,
  34759. +     * and we also check the source ethernet address to see if
  34760. +     * it origionated from us.
  34761. +     */
  34762. +    prev_recv_ptr = current_recv_ptr;
  34763. +    ether3_readbuffer (dev, &p, current_recv_ptr, 16);
  34764. +
  34765. +    if ((p.rxhdr & RX_NEXT) == 0 || (p.rxhdr & RXSTAT_DONE) == 0)
  34766. +        break;
  34767. +    current_recv_ptr = ntohs (p.rxhdr & RX_NEXT);
  34768. +
  34769. +    /*
  34770. +      * ignore our own packets...
  34771. +      */
  34772. +    if (memcmp (dev->dev_addr, &p.src_addr, 6) == 0) {
  34773. +        outw (current_recv_ptr >> 8, REG_RECVEND);
  34774. +        if (p.rxhdr & RXHDR_CHAINCONTINUE)
  34775. +        continue;
  34776. +        else
  34777. +        break;
  34778. +    }
  34779. +
  34780. +    if (!(p.rxhdr & (RXSTAT_OVERSIZE|RXSTAT_CRCERROR|RXSTAT_DRIBBLEERROR|RXSTAT_SHORTPACKET))) {
  34781. +        unsigned char *buf;
  34782. +        unsigned int length;
  34783. +        struct sk_buff *skb;
  34784. +
  34785. +        if (current_recv_ptr > prev_recv_ptr)
  34786. +        length = current_recv_ptr - prev_recv_ptr - 4;
  34787. +        else
  34788. +        length = (current_recv_ptr - RX_START) + (RX_END - prev_recv_ptr) - 4;
  34789. +
  34790. +        skb = dev_alloc_skb(length + 2);
  34791. +        if (skb == NULL) {
  34792. +        printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
  34793. +        priv->stats.rx_dropped ++;
  34794. +        break;
  34795. +        }
  34796. +
  34797. +        skb->dev = dev;
  34798. +        skb_reserve (skb, 2);
  34799. +        buf = skb_put (skb, length);
  34800. +        /*
  34801. +         * buf isn't word aligned, and it is probably faster to
  34802. +         * copy the address this way
  34803. +         */
  34804. +        *(unsigned short *)&buf[0] = *(unsigned short *)&p.dst_addr[0];
  34805. +        *(unsigned short *)&buf[2] = *(unsigned short *)&p.dst_addr[2];
  34806. +        *(unsigned short *)&buf[4] = *(unsigned short *)&p.dst_addr[4];
  34807. +        *(unsigned short *)&buf[6] = *(unsigned short *)&p.src_addr[0];
  34808. +        *(unsigned short *)&buf[8] = *(unsigned short *)&p.src_addr[2];
  34809. +        *(unsigned short *)&buf[10] = *(unsigned short *)&p.src_addr[4];
  34810. +    
  34811. +        ether3_readbuffer (dev, buf + 12, -1, length - 12);
  34812. +
  34813. +        outw (current_recv_ptr >> 8, REG_RECVEND);
  34814. +
  34815. +        skb->protocol = eth_type_trans(skb, dev);
  34816. +        netif_rx (skb);
  34817. +        priv->stats.rx_packets++;
  34818. +    } else {
  34819. +        priv->stats.rx_errors++;
  34820. +        if(p.rxhdr & RXSTAT_OVERSIZE) priv->stats.rx_length_errors ++;
  34821. +        if(p.rxhdr & RXSTAT_CRCERROR) priv->stats.rx_crc_errors ++;
  34822. +        if(p.rxhdr & RXSTAT_DRIBBLEERROR) priv->stats.rx_fifo_errors ++;
  34823. +        if(p.rxhdr & RXSTAT_SHORTPACKET) priv->stats.rx_length_errors ++;
  34824. +        outw (current_recv_ptr >> 8, REG_RECVEND);
  34825. +    }
  34826. +    if (!(p.rxhdr & RXHDR_CHAINCONTINUE))
  34827. +        break;
  34828. +    }
  34829. +    while (-- maxcnt);
  34830. +
  34831. +    priv->regs.recvptr = current_recv_ptr;
  34832. +    if (!(inw (REG_STATUS) & STAT_RXON)) {
  34833. +        outw (priv->regs.recvptr, REG_RECVPTR);
  34834. +    outw (priv->regs.command | CMD_RXON, REG_COMMAND);
  34835. +    }
  34836. +
  34837. +    /* If any worth-while packets have been received, dev_rint()
  34838. +       has done a mark_bh(NET_BH) for us and will work on them
  34839. +       when we get to the bottom-half routine. */
  34840. +    ether3_leddecrementuse (dev);
  34841. +}
  34842. +
  34843. +/*
  34844. + * Update stats for the transmitted packet
  34845. + */
  34846. +static void
  34847. +ether3_tx(struct device *dev, struct dev_priv *priv)
  34848. +{
  34849. +    unsigned long txhdr;
  34850. +    unsigned char *buffer = (unsigned char *)&txhdr;
  34851. +    unsigned int txptr;
  34852. +
  34853. +    txptr = priv->regs.transmitptr;
  34854. +
  34855. +    do {
  34856. +        /*
  34857. +         * Read the packet header
  34858. +         */
  34859. +    if (txptr + 4 > TX_END) {
  34860. +        int len = TX_END - txptr;
  34861. +        if (len)
  34862. +        ether3_readbuffer (dev, buffer, txptr, len);
  34863. +        ether3_readbuffer (dev, buffer + len, 0, 4 - len);
  34864. +    } else
  34865. +        ether3_readbuffer (dev, buffer, txptr, 4);
  34866. +
  34867. +    /*
  34868. +     * Check to see if this packet has been transmitted
  34869. +     */
  34870. +    if (!(txhdr & TXSTAT_DONE) || !(txhdr & TXHDR_TRANSMIT)) {
  34871. +        priv->regs.transmitptr = txptr;
  34872. +        return;
  34873. +    }
  34874. +
  34875. +    /*
  34876. +     * Update collision count (undocumented in datasheet)
  34877. +     */
  34878. +    if (txhdr & TXSTAT_COLLISION)
  34879. +        priv->stats.collisions += (txhdr >> (3+24)) & 15;
  34880. +
  34881. +    /*
  34882. +     * Update errors
  34883. +     */
  34884. +    if (txhdr & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS)) {
  34885. +        priv->stats.tx_errors ++;
  34886. +        if (txhdr & TXSTAT_16COLLISIONS) priv->stats.collisions += 16;
  34887. +        if (txhdr & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++;
  34888. +    } else
  34889. +        priv->stats.tx_packets++;
  34890. +
  34891. +    /*
  34892. +     * Get next packet address
  34893. +     */
  34894. +    txptr = priv->tx_ends[priv->txed++]; /* next packet address */
  34895. +
  34896. +    if (priv->txed >= MAX_TXED)
  34897. +        priv->txed = 0;
  34898. +
  34899. +    if (txptr != ntohs (txhdr & TX_NEXT)) {
  34900. +        printk (KERN_WARNING "%s: TX: bad next pointer - %04X instead of %04X\n",
  34901. +        dev->name, ntohs (txhdr & TX_NEXT), txptr);
  34902. +        priv->regs.transmitptr = txptr;
  34903. +        return;
  34904. +    }
  34905. +
  34906. +    if (priv->regs.transmitptr >= TX_END)
  34907. +        priv->regs.transmitptr -= TX_END;
  34908. +
  34909. +    if (priv->txbuffered)
  34910. +        priv->txbuffered -= 1;
  34911. +
  34912. +    dev->tbusy = 0;
  34913. +
  34914. +    ether3_leddecrementuse (dev);
  34915. +    mark_bh (NET_BH);    /* Inform upper layers. */
  34916. +    } while (1);
  34917. +}
  34918. +
  34919. +#ifdef MODULE
  34920. +
  34921. +char ethernames[MAX_ECARDS][9];
  34922. +
  34923. +static struct device *my_ethers[MAX_ECARDS];
  34924. +static struct expansion_card *ec[MAX_ECARDS];
  34925. +
  34926. +int
  34927. +init_module(void)
  34928. +{
  34929. +    int i;
  34930. +
  34931. +    for(i = 0; i < MAX_ECARDS; i++) {
  34932. +    my_ethers[i] = NULL;
  34933. +    ec[i] = NULL;
  34934. +    strcpy (ethernames[i], "        ");
  34935. +    }
  34936. +
  34937. +    i = 0;
  34938. +
  34939. +    do {
  34940. +    if ((ec[i] = ecard_find(0, sizeof(ether3_prods), ether3_prods, ether3_manus)) == NULL)
  34941. +        break;
  34942. +
  34943. +    my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL);
  34944. +    memset(my_ethers[i], 0, sizeof(struct device));
  34945. +
  34946. +    my_ethers[i]->irq = ec[i]->irq;
  34947. +    my_ethers[i]->base_addr= ((unsigned long)ecard_address (ec[i]->slot_no, ECARD_MEMC, 0))>>2;
  34948. +    my_ethers[i]->init = ether3_probe1;
  34949. +    my_ethers[i]->name = ethernames[i];
  34950. +
  34951. +    ether3_addr(my_ethers[i]->dev_addr, ec[i]);
  34952. +
  34953. +    ecard_claim(ec[i]);
  34954. +
  34955. +    if(register_netdev(my_ethers[i]) != 0) {
  34956. +        for (i = 0; i < 4; i++) {
  34957. +        if(my_ethers[i]) {
  34958. +            kfree(my_ethers[i]);
  34959. +            my_ethers[i] = NULL;
  34960. +        }
  34961. +        if(ec[i]) {
  34962. +            ecard_release(ec[i]);
  34963. +            ec[i] = NULL;
  34964. +        }
  34965. +        }
  34966. +        return -EIO;
  34967. +    }
  34968. +    i++;
  34969. +    }
  34970. +    while(i < MAX_ECARDS);
  34971. +
  34972. +    return i != 0 ? 0 : -ENODEV;
  34973. +}
  34974. +
  34975. +void
  34976. +cleanup_module(void)
  34977. +{
  34978. +    int i;
  34979. +    for (i = 0; i < MAX_ECARDS; i++) {
  34980. +    if (my_ethers[i]) {
  34981. +        unregister_netdev(my_ethers[i]);
  34982. +        my_ethers[i] = NULL;
  34983. +    }
  34984. +    if (ec[i]) {
  34985. +        ecard_release(ec[i]);
  34986. +        ec[i] = NULL;
  34987. +    }
  34988. +    }
  34989. +}
  34990. +#endif /* MODULE */
  34991. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/net/ether3.h linux/arch/arm/drivers/net/ether3.h
  34992. --- linux.orig/arch/arm/drivers/net/ether3.h    Thu Jan  1 01:00:00 1970
  34993. +++ linux/arch/arm/drivers/net/ether3.h    Fri Jul 19 20:44:42 1996
  34994. @@ -0,0 +1,174 @@
  34995. +/*
  34996. + * linux/drivers/net/ether3.h
  34997. + *
  34998. + * network driver for Acorn Ether3 cards
  34999. + */
  35000. +
  35001. +#ifndef _LINUX_ether3_H
  35002. +#define _LINUX_ether3_H
  35003. +
  35004. +/* use 0 for production, 1 for verification, >2 for debug. debug flags: */
  35005. +#define DEBUG_TX     2
  35006. +#define DEBUG_RX     4
  35007. +#define DEBUG_INT     8
  35008. +#define DEBUG_IC    16
  35009. +#ifndef NET_DEBUG
  35010. +#define NET_DEBUG     0
  35011. +#endif
  35012. +
  35013. +/* Command register definitions & bits */
  35014. +#define REG_COMMAND        (dev->base_addr + 0x00)
  35015. +#define CMD_ENINTDMA        0x0001
  35016. +#define CMD_ENINTRX        0x0002
  35017. +#define CMD_ENINTTX        0x0004
  35018. +#define CMD_ENINTBUFWIN        0x0008
  35019. +#define CMD_ACKINTDMA        0x0010
  35020. +#define CMD_ACKINTRX        0x0020
  35021. +#define CMD_ACKINTTX        0x0040
  35022. +#define CMD_ACKINTBUFWIN    0x0080
  35023. +#define CMD_DMAON        0x0100
  35024. +#define CMD_RXON        0x0200
  35025. +#define CMD_TXON        0x0400
  35026. +#define CMD_DMAOFF        0x0800
  35027. +#define CMD_RXOFF        0x1000
  35028. +#define CMD_TXOFF        0x2000
  35029. +#define CMD_FIFOREAD        0x4000
  35030. +#define CMD_FIFOWRITE        0x8000
  35031. +
  35032. +/* status register */
  35033. +#define REG_STATUS        (dev->base_addr + 0x00)
  35034. +#define STAT_ENINTSTAT        0x0001
  35035. +#define STAT_ENINTRX        0x0002
  35036. +#define STAT_ENINTTX        0x0004
  35037. +#define STAT_ENINTBUFWIN    0x0008
  35038. +#define STAT_INTDMA        0x0010
  35039. +#define STAT_INTRX        0x0020
  35040. +#define STAT_INTTX        0x0040
  35041. +#define STAT_INTBUFWIN        0x0080
  35042. +#define STAT_DMAON        0x0100
  35043. +#define STAT_RXON        0x0200
  35044. +#define STAT_TXON        0x0400
  35045. +#define STAT_FIFOFULL        0x2000
  35046. +#define STAT_FIFOEMPTY        0x4000
  35047. +#define STAT_FIFODIR        0x8000
  35048. +
  35049. +/* configuration register 1 */
  35050. +#define REG_CONFIG1        (dev->base_addr + 0x10)
  35051. +#define CFG1_BUFSELSTAT0    0x0000
  35052. +#define CFG1_BUFSELSTAT1    0x0001
  35053. +#define CFG1_BUFSELSTAT2    0x0002
  35054. +#define CFG1_BUFSELSTAT3    0x0003
  35055. +#define CFG1_BUFSELSTAT4    0x0004
  35056. +#define CFG1_BUFSELSTAT5    0x0005
  35057. +#define CFG1_ADDRPROM        0x0006
  35058. +#define CFG1_TRANSEND        0x0007
  35059. +#define CFG1_LOCBUFMEM        0x0008
  35060. +#define CFG1_INTVECTOR        0x0009
  35061. +#define CFG1_DMABURSTCONT    0x0000
  35062. +#define CFG1_DMABURST800NS    0x0010
  35063. +#define CFG1_DMABURST1600NS    0x0020
  35064. +#define CFG1_DMABURST3200NS    0x0030
  35065. +#define CFG1_DMABURST1        0x0000
  35066. +#define CFG1_DMABURST4        0x0040
  35067. +#define CFG1_DMABURST8        0x0080
  35068. +#define CFG1_DMABURST16        0x00C0
  35069. +#define CFG1_RECVCOMPSTAT0    0x0100
  35070. +#define CFG1_RECVCOMPSTAT1    0x0200
  35071. +#define CFG1_RECVCOMPSTAT2    0x0400
  35072. +#define CFG1_RECVCOMPSTAT3    0x0800
  35073. +#define CFG1_RECVCOMPSTAT4    0x1000
  35074. +#define CFG1_RECVCOMPSTAT5    0x2000
  35075. +#define CFG1_RECVSPECONLY    0x0000
  35076. +#define CFG1_RECVSPECBROAD    0x4000
  35077. +#define CFG1_RECVSPECBRMULTI    0x8000
  35078. +#define CFG1_RECVPROMISC    0xC000
  35079. +
  35080. +/* configuration register 2 */
  35081. +#define REG_CONFIG2        (dev->base_addr + 0x20)
  35082. +#define CFG2_BYTESWAP        0x0001
  35083. +#define CFG2_ERRENCRC        0x0008
  35084. +#define CFG2_ERRENDRIBBLE    0x0010
  35085. +#define CFG2_ERRSHORTFRAME    0x0020
  35086. +#define CFG2_SLOTSELECT        0x0040
  35087. +#define CFG2_PREAMSELECT    0x0080
  35088. +#define CFG2_ADDRLENGTH        0x0100
  35089. +#define CFG2_RECVCRC        0x0200
  35090. +#define CFG2_XMITNOCRC        0x0400
  35091. +#define CFG2_LOOPBACK        0x0800
  35092. +#define CFG2_CTRLO        0x1000
  35093. +#define CFG2_RESET        0x8000
  35094. +
  35095. +#define REG_RECVEND        (dev->base_addr + 0x30)
  35096. +
  35097. +#define REG_BUFWIN        (dev->base_addr + 0x40)
  35098. +
  35099. +#define REG_RECVPTR        (dev->base_addr + 0x50)
  35100. +
  35101. +#define REG_TRANSMITPTR        (dev->base_addr + 0x60)
  35102. +
  35103. +#define REG_DMAADDR        (dev->base_addr + 0x70)
  35104. +
  35105. +/*
  35106. + * Cards transmit/receive headers
  35107. + */
  35108. +#define TX_NEXT            (0xffff)
  35109. +#define TXHDR_ENBABBLEINT    (1 << 16)
  35110. +#define TXHDR_ENCOLLISIONINT    (1 << 17)
  35111. +#define TXHDR_EN16COLLISION    (1 << 18)
  35112. +#define TXHDR_ENSUCCESS        (1 << 19)
  35113. +#define TXHDR_DATAFOLLOWS    (1 << 21)
  35114. +#define TXHDR_CHAINCONTINUE    (1 << 22)
  35115. +#define TXHDR_TRANSMIT        (1 << 23)
  35116. +#define TXSTAT_BABBLED        (1 << 24)
  35117. +#define TXSTAT_COLLISION    (1 << 25)
  35118. +#define TXSTAT_16COLLISIONS    (1 << 26)
  35119. +#define TXSTAT_DONE        (1 << 31)
  35120. +
  35121. +#define RX_NEXT            (0xffff)
  35122. +#define RXHDR_CHAINCONTINUE    (1 << 22)
  35123. +#define RXHDR_RECEIVE        (1 << 23)
  35124. +#define RXSTAT_OVERSIZE        (1 << 24)
  35125. +#define RXSTAT_CRCERROR        (1 << 25)
  35126. +#define RXSTAT_DRIBBLEERROR    (1 << 26)
  35127. +#define RXSTAT_SHORTPACKET    (1 << 27)
  35128. +#define RXSTAT_DONE        (1 << 31)
  35129. +
  35130. +
  35131. +#define TX_END          0x6000
  35132. +#define RX_START        0x6000
  35133. +#define RX_LEN          0xA000
  35134. +#define RX_END          0x10000
  35135. +#define MAX_TXED    360
  35136. +#define MAX_TX_BUFFERED    10
  35137. +
  35138. +struct dev_priv {
  35139. +    int bus_type;            /* type of bus (not currently used)     */
  35140. +    struct {
  35141. +    unsigned int command;
  35142. +    unsigned int config1;
  35143. +    unsigned int config2;
  35144. +    unsigned int transmitptr;
  35145. +    unsigned int recvptr;
  35146. +    } regs;
  35147. +    struct enet_statistics stats;
  35148. +    unsigned int txinsert;        /* address to insert next packet     */
  35149. +    unsigned int txed;            /* transmitted index in tx_ends         */
  35150. +    unsigned int txto;            /* to transmit index in tx_ends         */
  35151. +    unsigned int txbuffered;        /* number of packets currently buffered     */
  35152. +    unsigned int tx_ends[MAX_TXED];    /* addresses of transmit packets     */
  35153. +    unsigned int use;            /* 0 = card not in use, >0 packet transferring */
  35154. +    int broken;                /* 0 = ok, 1 = something went wrong     */
  35155. +};
  35156. +
  35157. +extern int    ether3_probe (struct device *dev);
  35158. +static int    ether3_probe1 (struct device *dev);
  35159. +static int    ether3_open (struct device *dev);
  35160. +static int    ether3_sendpacket (struct sk_buff *skb, struct device *dev);
  35161. +static void    ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
  35162. +static void    ether3_rx (struct device *dev, struct dev_priv *priv);
  35163. +static void    ether3_tx (struct device *dev, struct dev_priv *priv);
  35164. +static int    ether3_close (struct device *dev);
  35165. +static struct enet_statistics *ether3_getstats (struct device *dev);
  35166. +static void    ether3_setmulticastlist (struct device *dev);
  35167. +
  35168. +#endif
  35169. diff -u -X rej --recursive --new-file linux.orig/arch/arm/drivers/net/ppp.c linux/arch/arm/drivers/net/ppp.c
  35170. --- linux.orig/arch/arm/drivers/net/ppp.c    Thu Jan  1 01:00:00 1970
  35171. +++ linux/arch/arm/drivers/net/ppp.c    Thu Jul 25 23:07:09 1996
  35172. @@ -0,0 +1,3516 @@
  35173. +/*  PPP for Linux
  35174. + *
  35175. + *  Michael Callahan <callahan@maths.ox.ac.uk>
  35176. + *  Al Longyear <longyear@netcom.com>
  35177. + *
  35178. + *  Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
  35179. + *  ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
  35180. + *
  35181. + *  ==FILEVERSION 960528==
  35182. + *
  35183. + *  NOTE TO MAINTAINERS:
  35184. + *     If you modify this file at all, please set the number above to the
  35185. + *     date of the modification as YYMMDD (year month day).
  35186. + *     ppp.c is shipped with a PPP distribution as well as with the kernel;
  35187. + *     if everyone increases the FILEVERSION number above, then scripts
  35188. + *     can do the right thing when deciding whether to install a new ppp.c
  35189. + *     file.  Don't change the format of that line otherwise, so the
  35190. + *     installation script can recognize it.
  35191. + */
  35192. +
  35193. +/*
  35194. +   Sources:
  35195. +
  35196. +   slip.c
  35197. +
  35198. +   RFC1331: The Point-to-Point Protocol (PPP) for the Transmission of
  35199. +   Multi-protocol Datagrams over Point-to-Point Links
  35200. +
  35201. +   RFC1332: IPCP
  35202. +
  35203. +   ppp-2.0
  35204. +
  35205. +   Flags for this module (any combination is acceptable for testing.):
  35206. +
  35207. +   OPTIMIZE_FLAG_TIME - Number of jiffies to force sending of leading flag
  35208. +            character. This is normally set to ((HZ * 3) / 2).
  35209. +            This is 1.5 seconds. If zero then the leading
  35210. +            flag is always sent.
  35211. +
  35212. +   CHECK_CHARACTERS   - Enable the checking on all received characters for
  35213. +            8 data bits, no parity. This adds a small amount of
  35214. +            processing for each received character.
  35215. +*/
  35216. +
  35217. +#define OPTIMIZE_FLAG_TIME    ((HZ * 3)/2)
  35218. +
  35219. +#define CHECK_CHARACTERS    1
  35220. +#define PPP_COMPRESS        1
  35221. +
  35222. +#ifndef PPP_MAX_DEV
  35223. +#define PPP_MAX_DEV    256
  35224. +#endif
  35225. +
  35226. +/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp $
  35227. + * Added dynamic allocation of channels to eliminate
  35228. + *   compiled-in limits on the number of channels.
  35229. + *
  35230. + * Dynamic channel allocation code Copyright 1995 Caldera, Inc.,
  35231. + *   released under the GNU General Public License Version 2.
  35232. + */
  35233. +
  35234. +#include <linux/autoconf.h>
  35235. +#include <linux/module.h>
  35236. +#include <linux/kernel.h>
  35237. +#include <linux/sched.h>
  35238. +#include <linux/types.h>
  35239. +#include <linux/fcntl.h>
  35240. +#include <linux/interrupt.h>
  35241. +#include <linux/ptrace.h>
  35242. +#include <linux/ioport.h>
  35243. +#include <linux/in.h>
  35244. +#include <linux/malloc.h>
  35245. +#include <linux/tty.h>
  35246. +#include <linux/errno.h>
  35247. +#include <linux/sched.h>    /* to get the struct task_struct */
  35248. +#include <linux/string.h>    /* used in new tty drivers */
  35249. +#include <linux/signal.h>    /* used in new tty drivers */
  35250. +#include <asm/system.h>
  35251. +#include <asm/bitops.h>
  35252. +#include <asm/segment.h>
  35253. +#include <linux/if.h>
  35254. +#include <linux/if_ether.h>
  35255. +#include <linux/netdevice.h>
  35256. +#include <linux/skbuff.h>
  35257. +#include <linux/inet.h>
  35258. +#include <linux/ioctl.h>
  35259. +
  35260. +typedef struct sk_buff         sk_buff;
  35261. +#define skb_data(skb)         ((__u8 *) (skb)->data)
  35262. +
  35263. +#include <linux/ip.h>
  35264. +#include <linux/tcp.h>
  35265. +#include <linux/if_arp.h>
  35266. +#include <net/slhc_vj.h>
  35267. +
  35268. +#define fcstab ppp_crc16_table        /* Name of the table in the kernel */
  35269. +#include <linux/ppp_defs.h>
  35270. +
  35271. +#include <linux/socket.h>
  35272. +#include <linux/if_ppp.h>
  35273. +#include <linux/if_pppvar.h>
  35274. +
  35275. +#undef     PACKETPTR
  35276. +#define     PACKETPTR 1
  35277. +#include <linux/ppp-comp.h>
  35278. +#undef     PACKETPTR
  35279. +
  35280. +#define bsd_decompress    (*ppp->sc_rcomp->decompress)
  35281. +#define bsd_compress    (*ppp->sc_xcomp->compress)
  35282. +
  35283. +#ifndef PPP_IPX
  35284. +#define PPP_IPX 0x2b  /* IPX protocol over PPP */
  35285. +#endif
  35286. +
  35287. +#ifndef PPP_LQR
  35288. +#define PPP_LQR 0xc025    /* Link Quality Reporting Protocol */
  35289. +#endif
  35290. +
  35291. +static int ppp_register_compressor (struct compressor *cp);
  35292. +static void ppp_unregister_compressor (struct compressor *cp);
  35293. +
  35294. +/*
  35295. + * Local functions
  35296. + */
  35297. +
  35298. +static struct compressor *find_compressor (int type);
  35299. +static void ppp_init_ctrl_blk (register struct ppp *);
  35300. +static void ppp_kick_tty (struct ppp *, struct ppp_buffer *bfr);
  35301. +static int ppp_doframe (struct ppp *);
  35302. +static struct ppp *ppp_alloc (void);
  35303. +static struct ppp *ppp_find (int pid_value);
  35304. +static void ppp_print_buffer (const __u8 *, const __u8 *, int);
  35305. +extern inline void ppp_stuff_char (struct ppp *ppp,
  35306. +                   register struct ppp_buffer *buf,
  35307. +                   register __u8 chr);
  35308. +extern inline int lock_buffer (register struct ppp_buffer *buf);
  35309. +
  35310. +static int rcv_proto_ip         (struct ppp *, __u16, __u8 *, int);
  35311. +static int rcv_proto_ipx        (struct ppp *, __u16, __u8 *, int);
  35312. +static int rcv_proto_vjc_comp   (struct ppp *, __u16, __u8 *, int);
  35313. +static int rcv_proto_vjc_uncomp (struct ppp *, __u16, __u8 *, int);
  35314. +static int rcv_proto_unknown    (struct ppp *, __u16, __u8 *, int);
  35315. +static int rcv_proto_lqr        (struct ppp *, __u16, __u8 *, int);
  35316. +static void ppp_doframe_lower   (struct ppp *, __u8 *, int);
  35317. +static int ppp_doframe          (struct ppp *);
  35318. +
  35319. +extern int  ppp_bsd_compressor_init(void);
  35320. +static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd);
  35321. +static int  rcv_proto_ccp (struct ppp *, __u16, __u8 *, int);
  35322. +
  35323. +#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (__u8)(c))
  35324. +
  35325. +#ifndef OPTIMIZE_FLAG_TIME
  35326. +#define OPTIMIZE_FLAG_TIME    0
  35327. +#endif
  35328. +
  35329. +#ifndef PPP_MAX_DEV
  35330. +#define PPP_MAX_DEV 256
  35331. +#endif
  35332. +
  35333. +/*
  35334. + * Parameters which may be changed via insmod.
  35335. + */
  35336. +
  35337. +static int  flag_time = OPTIMIZE_FLAG_TIME;
  35338. +static int  max_dev   = PPP_MAX_DEV;
  35339. +
  35340. +/*
  35341. + * The "main" procedure to the ppp device
  35342. + */
  35343. +
  35344. +int ppp_init (struct device *);
  35345. +
  35346. +/*
  35347. + * Network device driver callback routines
  35348. + */
  35349. +
  35350. +static int ppp_dev_open (struct device *);
  35351. +static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd);
  35352. +static int ppp_dev_close (struct device *);
  35353. +static int ppp_dev_xmit (sk_buff *, struct device *);
  35354. +static struct enet_statistics *ppp_dev_stats (struct device *);
  35355. +static int ppp_dev_header (sk_buff *, struct device *, __u16,
  35356. +               void *, void *, unsigned int);
  35357. +static int ppp_dev_rebuild (void *eth, struct device *dev,
  35358. +                 unsigned long raddr, struct sk_buff *skb);
  35359. +/*
  35360. + * TTY callbacks
  35361. + */
  35362. +
  35363. +static int ppp_tty_read (struct tty_struct *, struct file *, __u8 *,
  35364. +             unsigned int);
  35365. +static int ppp_tty_write (struct tty_struct *, struct file *, const __u8 *,
  35366. +              unsigned int);
  35367. +static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
  35368. +              unsigned long);
  35369. +static int ppp_tty_select (struct tty_struct *tty, struct inode *inode,
  35370. +              struct file *filp, int sel_type, select_table * wait);
  35371. +static int ppp_tty_open (struct tty_struct *);
  35372. +static void ppp_tty_close (struct tty_struct *);
  35373. +static int ppp_tty_room (struct tty_struct *tty);
  35374. +static void ppp_tty_receive (struct tty_struct *tty, const __u8 * cp,
  35375. +                 char *fp, int count);
  35376. +static void ppp_tty_wakeup (struct tty_struct *tty);
  35377. +
  35378. +#define CHECK_PPP(a)  if (!ppp->inuse) { printk (ppp_warning, __LINE__); return a;}
  35379. +#define CHECK_PPP_VOID()  if (!ppp->inuse) { printk (ppp_warning, __LINE__); return;}
  35380. +
  35381. +#define in_xmap(ppp,c)    (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
  35382. +#define in_rmap(ppp,c)    ((((unsigned int) (__u8) (c)) < 0x20) && \
  35383. +            ppp->recv_async_map & (1 << (c)))
  35384. +
  35385. +#define bset(p,b)    ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
  35386. +
  35387. +#define tty2ppp(tty)    ((struct ppp *) (tty->disc_data))
  35388. +#define dev2ppp(dev)    ((struct ppp *) (dev->priv))
  35389. +#define ppp2tty(ppp)    ((struct tty_struct *) ppp->tty)
  35390. +#define ppp2dev(ppp)    ((struct device *) ppp->dev)
  35391. +
  35392. +struct ppp_hdr {
  35393. +    __u8 address;
  35394. +    __u8 control;
  35395. +    __u8 protocol[2];
  35396. +};
  35397. +
  35398. +#define PPP_HARD_HDR_LEN    (sizeof (struct ppp_hdr))
  35399. +
  35400. +typedef struct  ppp_ctrl {
  35401. +    struct ppp_ctrl *next;        /* Next structure in the list    */
  35402. +    char            name [8];    /* Name of the device        */
  35403. +    struct ppp      ppp;        /* PPP control table        */
  35404. +    struct device   dev;        /* Device information table    */
  35405. +} ppp_ctrl_t;
  35406. +
  35407. +static ppp_ctrl_t *ppp_list = NULL;
  35408. +
  35409. +#define ctl2ppp(ctl) (struct ppp *)    &ctl->ppp
  35410. +#define ctl2dev(ctl) (struct device *) &ctl->dev
  35411. +#undef  PPP_NRUNIT
  35412. +
  35413. +/* Buffer types */
  35414. +#define BUFFER_TYPE_DEV_RD    0  /* ppp read buffer       */
  35415. +#define BUFFER_TYPE_TTY_WR    1  /* tty write buffer      */
  35416. +#define BUFFER_TYPE_DEV_WR    2  /* ppp write buffer      */
  35417. +#define BUFFER_TYPE_TTY_RD    3  /* tty read buffer       */
  35418. +#define BUFFER_TYPE_VJ        4  /* vj compression buffer */
  35419. +
  35420. +/* Define this string only once for all macro invocations */
  35421. +static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
  35422. +
  35423. +static char szVersion[]         = PPP_VERSION;
  35424. +/*
  35425. + * Information for the protocol decoder
  35426. + */
  35427. +
  35428. +typedef int (*pfn_proto)  (struct ppp *, __u16, __u8 *, int);
  35429. +
  35430. +typedef struct ppp_proto_struct {
  35431. +    int        proto;
  35432. +    pfn_proto    func;
  35433. +} ppp_proto_type;
  35434. +
  35435. +static
  35436. +ppp_proto_type proto_list[] = {
  35437. +    { PPP_IP,         rcv_proto_ip         },
  35438. +    { PPP_IPX,        rcv_proto_ipx        },
  35439. +    { PPP_VJC_COMP,   rcv_proto_vjc_comp   },
  35440. +    { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp },
  35441. +    { PPP_LQR,        rcv_proto_lqr        },
  35442. +    { PPP_CCP,        rcv_proto_ccp        },
  35443. +    { 0,              rcv_proto_unknown    }  /* !!! MUST BE LAST !!! */
  35444. +};
  35445. +
  35446. +__u16 ppp_crc16_table[256] =
  35447. +{
  35448. +    0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
  35449. +    0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
  35450. +    0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
  35451. +    0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
  35452. +    0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
  35453. +    0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
  35454. +    0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
  35455. +    0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
  35456. +    0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
  35457. +    0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
  35458. +    0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
  35459. +    0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
  35460. +    0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
  35461. +    0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
  35462. +    0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
  35463. +    0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
  35464. +    0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
  35465. +    0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
  35466. +    0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
  35467. +    0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
  35468. +    0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
  35469. +    0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
  35470. +    0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
  35471. +    0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
  35472. +    0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
  35473. +    0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
  35474. +    0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
  35475. +    0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
  35476. +    0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
  35477. +    0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
  35478. +    0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
  35479. +    0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
  35480. +};
  35481. +
  35482. +#ifdef CHECK_CHARACTERS
  35483. +static __u32 paritytab[8] =
  35484. +{
  35485. +    0x96696996, 0x69969669, 0x69969669, 0x96696996,
  35486. +    0x69969669, 0x96696996, 0x96696996, 0x69969669
  35487. +};
  35488. +#endif
  35489. +
  35490. +/* local function to store a value into the LQR frame */
  35491. +extern inline __u8 * store_long (register __u8 *p, register int value) {
  35492. +    *p++ = (__u8) (value >> 24);
  35493. +    *p++ = (__u8) (value >> 16);
  35494. +    *p++ = (__u8) (value >>  8);
  35495. +    *p++ = (__u8) value;
  35496. +    return p;
  35497. +}
  35498. +
  35499. +/*************************************************************
  35500. + * INITIALIZATION
  35501. + *************************************************************/
  35502. +
  35503. +/* This procedure is called once and once only to define who we are to
  35504. + * the operating system and the various procedures that it may use in
  35505. + * accessing the ppp protocol.
  35506. + */
  35507. +
  35508. +static int
  35509. +ppp_first_time (void)
  35510. +{
  35511. +    static struct tty_ldisc    ppp_ldisc;
  35512. +    int    status;
  35513. +
  35514. +    printk (KERN_INFO
  35515. +        "PPP: version %s (dynamic channel allocation)"
  35516. +        "\n", szVersion);
  35517. +
  35518. +#ifndef MODULE /* slhc module logic has its own copyright announcement */
  35519. +    printk (KERN_INFO
  35520. +        "TCP compression code copyright 1989 Regents of the "
  35521. +        "University of California\n");
  35522. +#endif
  35523. +    
  35524. +    printk (KERN_INFO
  35525. +        "PPP Dynamic channel allocation code copyright 1995 "
  35526. +        "Caldera, Inc.\n");
  35527. +/*
  35528. + * Register the tty discipline
  35529. + */    
  35530. +    (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
  35531. +    ppp_ldisc.magic        = TTY_LDISC_MAGIC;
  35532. +    ppp_ldisc.open        = ppp_tty_open;
  35533. +    ppp_ldisc.close        = ppp_tty_close;
  35534. +    ppp_ldisc.read        = ppp_tty_read;
  35535. +    ppp_ldisc.write        = ppp_tty_write;
  35536. +    ppp_ldisc.ioctl        = ppp_tty_ioctl;
  35537. +    ppp_ldisc.select    = ppp_tty_select;
  35538. +    ppp_ldisc.receive_room    = ppp_tty_room;
  35539. +    ppp_ldisc.receive_buf    = ppp_tty_receive;
  35540. +    ppp_ldisc.write_wakeup    = ppp_tty_wakeup;
  35541. +    
  35542. +    status = tty_register_ldisc (N_PPP, &ppp_ldisc);
  35543. +    if (status == 0)
  35544. +        printk (KERN_INFO "PPP line discipline registered.\n");
  35545. +    else
  35546. +        printk (KERN_ERR "error registering line discipline: %d\n",
  35547. +            status);
  35548. +    return status;
  35549. +}
  35550. +
  35551. +/*************************************************************
  35552. + * INITIALIZATION
  35553. + *************************************************************/
  35554. +
  35555. +/* called when the device is actually created */
  35556. +
  35557. +static int
  35558. +ppp_init_dev (struct device *dev)
  35559. +{
  35560. +    int    indx;
  35561. +
  35562. +    dev->hard_header      = ppp_dev_header;
  35563. +    dev->rebuild_header   = ppp_dev_rebuild;
  35564. +    dev->hard_header_len  = PPP_HARD_HDR_LEN;
  35565. +
  35566. +    /* device INFO */
  35567. +    dev->mtu              = PPP_MTU;
  35568. +    dev->hard_start_xmit  = ppp_dev_xmit;
  35569. +    dev->open             = ppp_dev_open;
  35570. +    dev->stop             = ppp_dev_close;
  35571. +    dev->get_stats        = ppp_dev_stats;
  35572. +    dev->do_ioctl         = ppp_dev_ioctl;
  35573. +    dev->addr_len         = 0;
  35574. +    dev->tx_queue_len     = 10;
  35575. +    dev->type             = ARPHRD_PPP;
  35576. +
  35577. +    for (indx = 0; indx < DEV_NUMBUFFS; indx++)
  35578. +        skb_queue_head_init (&dev->buffs[indx]);
  35579. +
  35580. +    /* New-style flags */
  35581. +    dev->flags      = IFF_POINTOPOINT;
  35582. +    dev->family     = AF_INET;
  35583. +    dev->pa_addr    = 0;
  35584. +    dev->pa_brdaddr = 0;
  35585. +    dev->pa_mask    = 0;
  35586. +    dev->pa_alen    = 4; /* sizeof (__u32) */
  35587. +
  35588. +    return 0;
  35589. +}
  35590. +
  35591. +/*
  35592. + * Local procedure to initialize the ppp structure
  35593. + */
  35594. +
  35595. +static void
  35596. +ppp_init_ctrl_blk (register struct ppp *ppp)
  35597. +{
  35598. +    ppp->magic  = PPP_MAGIC;
  35599. +    ppp->toss   = 0xE0;
  35600. +    ppp->escape = 0;
  35601. +
  35602. +    ppp->flags  = 0;
  35603. +    ppp->mtu    = PPP_MTU;
  35604. +    ppp->mru    = PPP_MRU;
  35605. +
  35606. +    memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map));
  35607. +    ppp->xmit_async_map[0] = 0xffffffff;
  35608. +    ppp->xmit_async_map[3] = 0x60000000;
  35609. +    ppp->recv_async_map    = 0x00000000;
  35610. +
  35611. +    ppp->rbuf       = NULL;
  35612. +    ppp->wbuf       = NULL;
  35613. +    ppp->ubuf       = NULL;
  35614. +    ppp->cbuf       = NULL;
  35615. +    ppp->slcomp     = NULL;
  35616. +    ppp->read_wait  = NULL;
  35617. +    ppp->write_wait = NULL;
  35618. +    ppp->last_xmit  = jiffies - flag_time;
  35619. +
  35620. +    /* clear statistics */
  35621. +    memset (&ppp->stats, '\0', sizeof (struct pppstat));
  35622. +
  35623. +    /* Reset the demand dial information */
  35624. +    ppp->ddinfo.xmit_idle=         /* time since last NP packet sent */
  35625. +    ppp->ddinfo.recv_idle=jiffies; /* time since last NP packet received */
  35626. +
  35627. +    /* PPP compression data */
  35628. +    ppp->sc_xc_state =
  35629. +    ppp->sc_rc_state = NULL;
  35630. +}
  35631. +
  35632. +static struct symbol_table ppp_syms = {
  35633. +#include <linux/symtab_begin.h>
  35634. +    X(ppp_register_compressor),
  35635. +    X(ppp_unregister_compressor),
  35636. +    X(ppp_crc16_table),
  35637. +#include <linux/symtab_end.h>
  35638. +};
  35639. +
  35640. +/* called at boot/load time for each ppp device defined in the kernel */
  35641. +
  35642. +#ifndef MODULE
  35643. +int
  35644. +ppp_init (struct device *dev)
  35645. +{
  35646. +    static int first_time = 1;
  35647. +    int    answer = 0;
  35648. +
  35649. +    if (first_time) {
  35650. +        first_time = 0;
  35651. +        answer     = ppp_first_time();
  35652. +        if (answer == 0)
  35653. +            (void) register_symtab (&ppp_syms);
  35654. +    }
  35655. +    if (answer == 0)
  35656. +        answer = -ENODEV;
  35657. +    return answer;
  35658. +}
  35659. +#endif
  35660. +
  35661. +/*
  35662. + * Routine to allocate a buffer for later use by the driver.
  35663. + */
  35664. +
  35665. +static struct ppp_buffer *
  35666. +ppp_alloc_buf (int size, int type)
  35667. +{
  35668. +    struct ppp_buffer *buf;
  35669. +
  35670. +    buf = (struct ppp_buffer *) kmalloc (size + sizeof (struct ppp_buffer),
  35671. +                         GFP_ATOMIC);
  35672. +
  35673. +    if (buf != NULL) {
  35674. +        buf->size   = size - 1;    /* Mask for the buffer size */
  35675. +        buf->type   = type;
  35676. +        buf->locked = 0;
  35677. +        buf->count  = 0;
  35678. +        buf->head   = 0;
  35679. +        buf->tail   = 0;
  35680. +        buf->fcs    = PPP_INITFCS;
  35681. +
  35682. +    }
  35683. +    return (buf);
  35684. +}
  35685. +
  35686. +/*
  35687. + * Routine to release the allocated buffer.
  35688. + */
  35689. +
  35690. +static void
  35691. +ppp_free_buf (struct ppp_buffer *ptr)
  35692. +{
  35693. +    if (ptr != NULL)
  35694. +        kfree (ptr);
  35695. +}
  35696. +
  35697. +/*
  35698. + * Lock the indicated transmit buffer
  35699. + */
  35700. +
  35701. +extern inline int
  35702. +lock_buffer (register struct ppp_buffer *buf)
  35703. +{
  35704. +    register int state;
  35705. +    int flags;
  35706. +/*
  35707. + * Save the current state and if free then set it to the "busy" state
  35708. + */
  35709. +    save_flags (flags);
  35710. +    cli ();
  35711. +    state = buf->locked;
  35712. +    if (state == 0)
  35713. +        buf->locked = 2;
  35714. +
  35715. +    restore_flags (flags);
  35716. +    return (state);
  35717. +}
  35718. +
  35719. +/*
  35720. + * MTU has been changed by the IP layer. Unfortunately we are not told
  35721. + * about this, but we spot it ourselves and fix things up. We could be
  35722. + * in an upcall from the tty driver, or in an ip packet queue.
  35723. + */
  35724. +
  35725. +static int
  35726. +ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
  35727. +{
  35728. +    struct device *dev;
  35729. +
  35730. +    struct ppp_buffer *new_rbuf;
  35731. +    struct ppp_buffer *new_wbuf;
  35732. +    struct ppp_buffer *new_cbuf;
  35733. +    struct ppp_buffer *new_tbuf;
  35734. +
  35735. +    struct ppp_buffer *old_rbuf;
  35736. +    struct ppp_buffer *old_wbuf;
  35737. +    struct ppp_buffer *old_cbuf;
  35738. +    struct ppp_buffer *old_tbuf;
  35739. +
  35740. +    int mtu, mru;
  35741. +/*
  35742. + *  Allocate the buffer from the kernel for the data
  35743. + */
  35744. +    dev = ppp2dev (ppp);
  35745. +    mru = new_mru;
  35746. +    /* allow for possible escaping of every character */
  35747. +    mtu = (new_mtu * 2) + 20;
  35748. +
  35749. +    /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
  35750. +    if (mru < PPP_MRU)
  35751. +        mru = PPP_MRU;
  35752. +
  35753. +    mru += 10;
  35754. +    
  35755. +    if (ppp->flags & SC_DEBUG)
  35756. +        printk (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
  35757. +            dev->name, new_mtu, new_mru);
  35758. +
  35759. +    new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN,    BUFFER_TYPE_DEV_WR);
  35760. +    new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24,    BUFFER_TYPE_TTY_WR);
  35761. +    new_rbuf = ppp_alloc_buf (mru + 84,        BUFFER_TYPE_DEV_RD);
  35762. +    new_cbuf = ppp_alloc_buf (mru+PPP_HARD_HDR_LEN,    BUFFER_TYPE_VJ);
  35763. +/*
  35764. + *  If the buffers failed to allocate then complain and release the partial
  35765. + *  allocations.
  35766. + */
  35767. +    if (new_wbuf == NULL || new_tbuf == NULL ||
  35768. +        new_rbuf == NULL || new_cbuf == NULL) {
  35769. +        if (ppp->flags & SC_DEBUG)
  35770. +            printk (KERN_ERR
  35771. +                "ppp: failed to allocate new buffers\n");
  35772. +
  35773. +        ppp_free_buf (new_wbuf);
  35774. +        ppp_free_buf (new_tbuf);
  35775. +        ppp_free_buf (new_rbuf);
  35776. +        ppp_free_buf (new_cbuf);
  35777. +        return 0;
  35778. +    }
  35779. +/*
  35780. + *  Update the pointers to the new buffer structures.
  35781. + */
  35782. +    cli ();
  35783. +    old_wbuf = ppp->wbuf;
  35784. +    old_rbuf = ppp->rbuf;
  35785. +    old_cbuf = ppp->cbuf;
  35786. +    old_tbuf = ppp->tbuf;
  35787. +
  35788. +    ppp->wbuf = new_wbuf;
  35789. +    ppp->rbuf = new_rbuf;
  35790. +    ppp->cbuf = new_cbuf;
  35791. +    ppp->tbuf = new_tbuf;
  35792. +
  35793. +    ppp->rbuf->size -= 80;  /* reserve space for vj header expansion */
  35794. +
  35795. +    dev->mem_start  = (unsigned long) buf_base (new_wbuf);
  35796. +    dev->mem_end    = (unsigned long) (dev->mem_start + mtu);
  35797. +    dev->rmem_start = (unsigned long) buf_base (new_rbuf);
  35798. +    dev->rmem_end   = (unsigned long) (dev->rmem_start + mru);
  35799. +/*
  35800. + *  Update the parameters for the new buffer sizes
  35801. + */
  35802. +    ppp->toss   = 0xE0;    /* To ignore characters until new FLAG */
  35803. +    ppp->escape = 0;    /* No pending escape character */
  35804. +
  35805. +    dev->mtu    =
  35806. +    ppp->mtu    = new_mtu;
  35807. +    ppp->mru    = new_mru;
  35808. +
  35809. +    ppp->s1buf  = NULL;
  35810. +    ppp->s2buf  = NULL;
  35811. +    ppp->xbuf   = NULL;
  35812. +
  35813. +    ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
  35814. +    ppp->flags      &= ~SC_XMIT_BUSY;
  35815. +
  35816. +    sti ();
  35817. +/*
  35818. + *  Release old buffer pointers
  35819. + */
  35820. +    ppp_free_buf (old_rbuf);
  35821. +    ppp_free_buf (old_wbuf);
  35822. +    ppp_free_buf (old_cbuf);
  35823. +    ppp_free_buf (old_tbuf);
  35824. +    return 1;
  35825. +}
  35826. +
  35827. +/*
  35828. + * CCP is down; free (de)compressor state if necessary.
  35829. + */
  35830. +
  35831. +static void
  35832. +ppp_ccp_closed (struct ppp *ppp)
  35833. +{
  35834. +    if (ppp->sc_xc_state) {
  35835. +        (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);
  35836. +        ppp->sc_xc_state = NULL;
  35837. +    }
  35838. +
  35839. +    if (ppp->sc_rc_state) {
  35840. +        (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);
  35841. +        ppp->sc_rc_state = NULL;
  35842. +    }
  35843. +}
  35844. +
  35845. +/*
  35846. + * Called to release all of the information in the current PPP structure.
  35847. + *
  35848. + * It is called when the ppp device goes down or if it is unable to go
  35849. + * up.
  35850. + */
  35851. +
  35852. +static void
  35853. +ppp_release (struct ppp *ppp)
  35854. +{
  35855. +    struct tty_struct *tty;
  35856. +    struct device *dev;
  35857. +
  35858. +    tty = ppp2tty (ppp);
  35859. +    dev = ppp2dev (ppp);
  35860. +
  35861. +    ppp_ccp_closed (ppp);
  35862. +
  35863. +    /* Ensure that the pppd process is not hanging on select() */
  35864. +    wake_up_interruptible (&ppp->read_wait);
  35865. +    wake_up_interruptible (&ppp->write_wait);
  35866. +    
  35867. +    if (tty != NULL && tty->disc_data == ppp)
  35868. +        tty->disc_data = NULL;    /* Break the tty->ppp link */
  35869. +
  35870. +    if (dev && dev->flags & IFF_UP) {
  35871. +        dev_close (dev); /* close the device properly */
  35872. +        dev->flags = 0;  /* prevent recursion */
  35873. +    }
  35874. +
  35875. +    ppp_free_buf (ppp->rbuf);
  35876. +    ppp_free_buf (ppp->wbuf);
  35877. +    ppp_free_buf (ppp->cbuf);
  35878. +    ppp_free_buf (ppp->ubuf);
  35879. +    ppp_free_buf (ppp->tbuf);
  35880. +
  35881. +    ppp->rbuf  =
  35882. +    ppp->wbuf  =
  35883. +    ppp->cbuf  =
  35884. +    ppp->tbuf  =
  35885. +    ppp->xbuf  =
  35886. +    ppp->s1buf =
  35887. +    ppp->s2buf =
  35888. +    ppp->ubuf  = NULL;
  35889. +
  35890. +    if (ppp->slcomp) {
  35891. +        slhc_free (ppp->slcomp);
  35892. +        ppp->slcomp = NULL;
  35893. +    }
  35894. +
  35895. +    ppp->inuse = 0;
  35896. +    ppp->tty   = NULL;
  35897. +}
  35898. +
  35899. +/*
  35900. + * Device callback.
  35901. + *
  35902. + * Called when the PPP device goes down in response to an ifconfig request.
  35903. + */
  35904. +
  35905. +static void
  35906. +ppp_tty_close_local (struct tty_struct *tty, int sc_xfer)
  35907. +{
  35908. +    struct ppp *ppp = tty2ppp (tty);
  35909. +
  35910. +    if (ppp != NULL) {
  35911. +        if (ppp->magic != PPP_MAGIC) {
  35912. +            if (ppp->flags & SC_DEBUG)
  35913. +                printk (KERN_WARNING
  35914. +                       "ppp: trying to close unopened tty!\n");
  35915. +        } else {
  35916. +            CHECK_PPP_VOID();
  35917. +            ppp->sc_xfer = sc_xfer;
  35918. +            if (ppp->flags & SC_DEBUG)
  35919. +                printk (KERN_INFO "ppp: channel %s closing.\n",
  35920. +                    ppp2dev(ppp) -> name);
  35921. +            ppp_release (ppp);
  35922. +            MOD_DEC_USE_COUNT;
  35923. +        }
  35924. +    }
  35925. +}
  35926. +
  35927. +static void
  35928. +ppp_tty_close (struct tty_struct *tty)
  35929. +{
  35930. +    ppp_tty_close_local (tty, 0);
  35931. +}
  35932. +
  35933. +/*
  35934. + * TTY callback.
  35935. + *
  35936. + * Called when the tty discipline is switched to PPP.
  35937. + */
  35938. +
  35939. +static int
  35940. +ppp_tty_open (struct tty_struct *tty)
  35941. +{
  35942. +    struct ppp *ppp = tty2ppp (tty);
  35943. +    int indx;
  35944. +/*
  35945. + * There should not be an existing table for this slot.
  35946. + */
  35947. +    if (ppp) {
  35948. +        if (ppp->flags & SC_DEBUG)
  35949. +            printk (KERN_ERR
  35950. +            "ppp_tty_open: gack! tty already associated to %s!\n",
  35951. +            ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name
  35952. +                        : "unknown");
  35953. +        return -EEXIST;
  35954. +    }
  35955. +/*
  35956. + * Allocate the structure from the system
  35957. + */
  35958. +     ppp = ppp_find(current->pid);
  35959. +     if (ppp == NULL) {
  35960. +         ppp = ppp_find(0);
  35961. +         if (ppp == NULL)
  35962. +             ppp = ppp_alloc();
  35963. +     }
  35964. +    if (ppp == NULL) {
  35965. +        if (ppp->flags & SC_DEBUG)
  35966. +            printk (KERN_ERR
  35967. +            "ppp_tty_open: couldn't allocate ppp channel\n");
  35968. +        return -ENFILE;
  35969. +    }
  35970. +/*
  35971. + * Initialize the control block
  35972. + */
  35973. +    ppp_init_ctrl_blk (ppp);
  35974. +    ppp->tty       = tty;
  35975. +    tty->disc_data = ppp;
  35976. +/*
  35977. + * Flush any pending characters in the driver and discipline.
  35978. + */
  35979. +    if (tty->ldisc.flush_buffer)
  35980. +        tty->ldisc.flush_buffer (tty);
  35981. +
  35982. +    if (tty->driver.flush_buffer)
  35983. +        tty->driver.flush_buffer (tty);
  35984. +/*
  35985. + * Allocate space for the default VJ header compression slots
  35986. + */
  35987. +    ppp->slcomp = slhc_init (16, 16);
  35988. +    if (ppp->slcomp == NULL) {
  35989. +        if (ppp->flags & SC_DEBUG)
  35990. +            printk (KERN_ERR
  35991. +            "ppp_tty_open: no space for compression buffers!\n");
  35992. +        ppp_release (ppp);
  35993. +        return -ENOMEM;
  35994. +    }
  35995. +/*
  35996. + * Allocate space for the MTU and MRU buffers
  35997. + */
  35998. +    if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
  35999. +        ppp_release (ppp);
  36000. +        return -ENOMEM;
  36001. +    }
  36002. +/*
  36003. + * Allocate space for a user level buffer
  36004. + */
  36005. +    ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
  36006. +    if (ppp->ubuf == NULL) {
  36007. +        if (ppp->flags & SC_DEBUG)
  36008. +            printk (KERN_ERR
  36009. +               "ppp_tty_open: no space for user receive buffer\n");
  36010. +        ppp_release (ppp);
  36011. +        return -ENOMEM;
  36012. +    }
  36013. +
  36014. +    if (ppp->flags & SC_DEBUG)
  36015. +        printk (KERN_INFO "ppp: channel %s open\n",
  36016. +            ppp2dev(ppp)->name);
  36017. +
  36018. +    for (indx = 0; indx < NUM_NP; ++indx)
  36019. +        ppp->sc_npmode[indx] = NPMODE_PASS;
  36020. +
  36021. +    MOD_INC_USE_COUNT;
  36022. +    return (ppp->line);
  36023. +}
  36024. +
  36025. +/*
  36026. + * Local function to send the next portion of the buffer.
  36027. + *
  36028. + * Called by the tty driver's tty_wakeup function should it be entered
  36029. + * because the partial buffer was transmitted.
  36030. + *
  36031. + * Called by kick_tty to send the initial portion of the buffer.
  36032. + *
  36033. + * Completion processing of the buffer transmission is handled here.
  36034. + */
  36035. +
  36036. +static void
  36037. +ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
  36038. +             struct ppp_buffer *xbuf)
  36039. +{
  36040. +    register int count, actual;
  36041. +/*
  36042. + * Prevent re-entrancy by ensuring that this routine is called only once.
  36043. + */
  36044. +    cli ();
  36045. +    if (ppp->flags & SC_XMIT_BUSY) {
  36046. +        sti ();
  36047. +        return;
  36048. +    }
  36049. +    ppp->flags |= SC_XMIT_BUSY;
  36050. +    sti ();
  36051. +/*
  36052. + * Send the next block of data to the modem
  36053. + */
  36054. +    count = xbuf->count - xbuf->tail;
  36055. +    actual = tty->driver.write (tty, 0,
  36056. +                    buf_base (xbuf) + xbuf->tail, count);
  36057. +/*
  36058. + * Terminate transmission of any block which may have an error.
  36059. + * This could occur should the carrier drop.
  36060. + */
  36061. +    if (actual < 0) {
  36062. +            ppp->stats.ppp_oerrors++;
  36063. +        actual = count;
  36064. +    } else
  36065. +        ppp->bytes_sent += actual;
  36066. +/*
  36067. + * If the buffer has been transmitted then clear the indicators.
  36068. + */
  36069. +    xbuf->tail += actual;
  36070. +    if (actual == count) {
  36071. +        xbuf = NULL;
  36072. +        ppp->flags &= ~SC_XMIT_BUSY;
  36073. +/*
  36074. + * Complete the transmission on the current buffer.
  36075. + */
  36076. +        xbuf = ppp->xbuf;
  36077. +        if (xbuf != NULL) {
  36078. +            tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
  36079. +            xbuf->locked = 0;
  36080. +            ppp->xbuf    = NULL;
  36081. +/*
  36082. + * If the completed buffer came from the device write, then complete the
  36083. + * transmission block.
  36084. + */
  36085. +            if (ppp2dev (ppp) -> flags & IFF_UP) {
  36086. +                if (xbuf->type == BUFFER_TYPE_DEV_WR)
  36087. +                        ppp2dev (ppp)->tbusy = 0;
  36088. +                mark_bh (NET_BH);
  36089. +            }
  36090. +/*
  36091. + * Wake up the transmission queue for all completion events.
  36092. + */
  36093. +            wake_up_interruptible (&ppp->write_wait);
  36094. +/*
  36095. + * Look at the priorities. Choose a daemon write over the device driver.
  36096. + */
  36097. +            cli();
  36098. +            xbuf = ppp->s1buf;
  36099. +            ppp->s1buf = NULL;
  36100. +            if (xbuf == NULL) {
  36101. +                xbuf = ppp->s2buf;
  36102. +                ppp->s2buf = NULL;
  36103. +            }
  36104. +            sti();
  36105. +/*
  36106. + * If there is a pending buffer then transmit it now.
  36107. + */
  36108. +            if (xbuf != NULL) {
  36109. +                ppp->flags &= ~SC_XMIT_BUSY;
  36110. +                ppp_kick_tty (ppp, xbuf);
  36111. +                return;
  36112. +            }
  36113. +        }
  36114. +    }
  36115. +/*
  36116. + * Clear the re-entry flag
  36117. + */
  36118. +    ppp->flags &= ~SC_XMIT_BUSY;
  36119. +}
  36120. +
  36121. +/*
  36122. + * This function is called by the tty driver when the transmit buffer has
  36123. + * additional space. It is used by the ppp code to continue to transmit
  36124. + * the current buffer should the buffer have been partially sent.
  36125. + *
  36126. + * In addition, it is used to send the first part of the buffer since the
  36127. + * logic and the inter-locking would be identical.
  36128. + */
  36129. +
  36130. +static void
  36131. +ppp_tty_wakeup (struct tty_struct *tty)
  36132. +{
  36133. +    struct ppp_buffer *xbuf;
  36134. +    struct ppp *ppp = tty2ppp (tty);
  36135. +
  36136. +    if (!ppp)
  36137. +        return;
  36138. +
  36139. +    if (ppp->magic != PPP_MAGIC)
  36140. +        return;
  36141. +/*
  36142. + * Ensure that there is a transmission pending. Clear the re-entry flag if
  36143. + * there is no pending buffer. Otherwise, send the buffer.
  36144. + */
  36145. +    xbuf = ppp->xbuf;
  36146. +    if (xbuf == NULL)
  36147. +        tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
  36148. +    else
  36149. +        ppp_tty_wakeup_code (ppp, tty, xbuf);
  36150. +}
  36151. +
  36152. +/*
  36153. + * This function is called to transmit a buffer to the remote. The buffer
  36154. + * is placed on the pending queue if there is presently a buffer being
  36155. + * sent or it is transmitted with the aid of ppp_tty_wakeup.
  36156. + */
  36157. +
  36158. +static void
  36159. +ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
  36160. +{
  36161. +    register int flags;
  36162. +/*
  36163. + * Hold interrupts.
  36164. + */
  36165. +    save_flags (flags);
  36166. +    cli ();
  36167. +/*
  36168. + * Control the flags which are best performed with the interrupts masked.
  36169. + */
  36170. +    xbuf->locked     = 1;
  36171. +    xbuf->tail       = 0;
  36172. +/*
  36173. + * If the transmitter is busy then place the buffer on the appropriate
  36174. + * priority queue.
  36175. + */
  36176. +    if (ppp->xbuf != NULL) {
  36177. +        if (xbuf->type == BUFFER_TYPE_TTY_WR)
  36178. +            ppp->s1buf = xbuf;
  36179. +        else
  36180. +            ppp->s2buf = xbuf;
  36181. +        restore_flags (flags);
  36182. +        return;
  36183. +    }
  36184. +/*
  36185. + * If the transmitter is not busy then this is the highest priority frame
  36186. + */
  36187. +    ppp->flags      &= ~SC_XMIT_BUSY;
  36188. +    ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
  36189. +    ppp->xbuf        = xbuf;
  36190. +    restore_flags (flags);
  36191. +/*
  36192. + * Do the "tty wakeup_code" to actually send this buffer.
  36193. + */
  36194. +    ppp_tty_wakeup_code (ppp, ppp2tty (ppp), xbuf);
  36195. +}
  36196. +
  36197. +/*************************************************************
  36198. + * TTY INPUT
  36199. + *    The following functions handle input that arrives from
  36200. + *    the TTY.    It recognizes PPP frames and either hands them
  36201. + *    to the network layer or queues them for delivery to a
  36202. + *    user process reading this TTY.
  36203. + *************************************************************/
  36204. +
  36205. +/*
  36206. + * Callback function from tty driver. Return the amount of space left
  36207. + * in the receiver's buffer to decide if remote transmitter is to be
  36208. + * throttled.
  36209. + */
  36210. +
  36211. +static int
  36212. +ppp_tty_room (struct tty_struct *tty)
  36213. +{
  36214. +    return 65536;        /* We can handle an infinite amount of data. :-) */
  36215. +}
  36216. +
  36217. +/*
  36218. + * Callback function when data is available at the tty driver.
  36219. + */
  36220. +
  36221. +static void
  36222. +ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
  36223. +         char *flags, int count)
  36224. +{
  36225. +    register struct ppp *ppp = tty2ppp (tty);
  36226. +    register struct ppp_buffer *buf = NULL;
  36227. +    __u8 chr;
  36228. +/*
  36229. + * Fetch the pointer to the buffer. Be careful about race conditions.
  36230. + */
  36231. +    if (ppp != NULL)
  36232. +        buf = ppp->rbuf;
  36233. +
  36234. +    if (buf == NULL)
  36235. +        return;
  36236. +/*
  36237. + * Verify the table pointer and ensure that the line is
  36238. + * still in PPP discipline.
  36239. + */
  36240. +    if (ppp->magic != PPP_MAGIC) {
  36241. +        if (ppp->flags & SC_DEBUG)
  36242. +            printk (KERN_DEBUG
  36243. +                "PPP: handler called but couldn't find "
  36244. +                "PPP struct.\n");
  36245. +        return;
  36246. +    }
  36247. +    CHECK_PPP_VOID ();
  36248. +/*
  36249. + * Print the buffer if desired
  36250. + */
  36251. +    if (ppp->flags & SC_LOG_RAWIN)
  36252. +        ppp_print_buffer ("receive buffer", data, count);
  36253. +/*
  36254. + * Collect the character and error condition for the character. Set the toss
  36255. + * flag for the first character error.
  36256. + */
  36257. +    while (count-- > 0) {
  36258. +        ppp->bytes_rcvd++;
  36259. +        chr = *data++;
  36260. +        if (flags) {
  36261. +            if (*flags && ppp->toss == 0)
  36262. +                ppp->toss = *flags;
  36263. +            ++flags;
  36264. +        }
  36265. +/*
  36266. + * Set the flags for 8 data bits and no parity.
  36267. + *
  36268. + * Actually, it sets the flags for d7 being 0/1 and parity being even/odd
  36269. + * so that the normal processing would have all flags set at the end of the
  36270. + * session. A missing flag bit would denote an error condition.
  36271. + */
  36272. +
  36273. +#ifdef CHECK_CHARACTERS
  36274. +        if (chr & 0x80)
  36275. +            ppp->flags |= SC_RCV_B7_1;
  36276. +        else
  36277. +            ppp->flags |= SC_RCV_B7_0;
  36278. +
  36279. +        if (paritytab[chr >> 5] & (1 << (chr & 0x1F)))
  36280. +            ppp->flags |= SC_RCV_ODDP;
  36281. +        else
  36282. +            ppp->flags |= SC_RCV_EVNP;
  36283. +#endif
  36284. +/*
  36285. + * Branch on the character. Process the escape character. The sequence ESC ESC
  36286. + * is defined to be ESC.
  36287. + */
  36288. +        switch (chr) {
  36289. +        case PPP_ESCAPE: /* PPP_ESCAPE: invert bit in next character */
  36290. +            ppp->escape = PPP_TRANS;
  36291. +            break;
  36292. +/*
  36293. + * FLAG. This is the end of the block. If the block terminated by ESC FLAG,
  36294. + * then the block is to be ignored. In addition, characters before the very
  36295. + * first FLAG are also tossed by this procedure.
  36296. + */
  36297. +        case PPP_FLAG:    /* PPP_FLAG: end of frame */
  36298. +            ppp->stats.ppp_ibytes += ppp->rbuf->count;
  36299. +            if (ppp->escape)
  36300. +                ppp->toss |= 0x80;
  36301. +/*
  36302. + * Process frames which are not to be ignored. If the processing failed,
  36303. + * then clean up the VJ tables.
  36304. + */
  36305. +            if ((ppp->toss & 0x80) != 0 ||
  36306. +                ppp_doframe (ppp) == 0) {
  36307. +                slhc_toss (ppp->slcomp);
  36308. +            }
  36309. +/*
  36310. + * Reset all indicators for the new frame to follow.
  36311. + */
  36312. +            buf->count  = 0;
  36313. +            buf->fcs    = PPP_INITFCS;
  36314. +            ppp->escape = 0;
  36315. +            ppp->toss   = 0;
  36316. +            break;
  36317. +/*
  36318. + * All other characters in the data come here. If the character is in the
  36319. + * receive mask then ignore the character.
  36320. + */
  36321. +        default:
  36322. +            if (in_rmap (ppp, chr))
  36323. +                break;
  36324. +/*
  36325. + * Adjust the character and if the frame is to be discarded then simply
  36326. + * ignore the character until the ending FLAG is received.
  36327. + */
  36328. +            chr ^= ppp->escape;
  36329. +            ppp->escape = 0;
  36330. +
  36331. +            if (ppp->toss != 0)
  36332. +                break;
  36333. +/*
  36334. + * If the count sent is within reason then store the character, bump the
  36335. + * count, and update the FCS for the character.
  36336. + */
  36337. +            if (buf->count < buf->size) {
  36338. +                buf_base (buf)[buf->count++] = chr;
  36339. +                buf->fcs = PPP_FCS (buf->fcs, chr);
  36340. +                break;
  36341. +            }
  36342. +/*
  36343. + * The peer sent too much data. Set the flags to discard the current frame
  36344. + * and wait for the re-synchronization FLAG to be sent.
  36345. + */
  36346. +            ppp->stats.ppp_ierrors++;
  36347. +            ppp->toss |= 0xC0;
  36348. +            break;
  36349. +        }
  36350. +    }
  36351. +}
  36352. +
  36353. +/*
  36354. + * Put the input frame into the networking system for the indicated protocol
  36355. + */
  36356. +
  36357. +static int
  36358. +ppp_rcv_rx (struct ppp *ppp, __u16 proto, __u8 * data, int count)
  36359. +{
  36360. +    sk_buff *skb = dev_alloc_skb (count);
  36361. +/*
  36362. + * Generate a skb buffer for the new frame.
  36363. + */
  36364. +    if (skb == NULL) {
  36365. +        if (ppp->flags & SC_DEBUG)
  36366. +            printk (KERN_ERR
  36367. +             "ppp_do_ip: packet dropped on %s (no memory)!\n",
  36368. +             ppp2dev (ppp)->name);
  36369. +        return 0;
  36370. +    }
  36371. +/*
  36372. + * Move the received data from the input buffer to the skb buffer.
  36373. + */
  36374. +    skb->dev      = ppp2dev (ppp);    /* We are the device */
  36375. +    skb->protocol = proto;
  36376. +    skb->mac.raw  = skb_data(skb);
  36377. +    memcpy (skb_put(skb,count), data, count);    /* move data */
  36378. +/*
  36379. + * Tag the frame and kick it to the proper receive routine
  36380. + */
  36381. +    skb->free = 1;
  36382. +    ppp->ddinfo.recv_idle = jiffies;
  36383. +    netif_rx (skb);
  36384. +    return 1;
  36385. +}
  36386. +
  36387. +/*
  36388. + * Process the receipt of an IP frame
  36389. + */
  36390. +
  36391. +static int
  36392. +rcv_proto_ip (struct ppp *ppp, __u16 proto, __u8 * data, int count)
  36393. +{
  36394. +    if ((ppp2dev (ppp)->flags & IFF_UP) && (count > 0))
  36395. +        if (ppp->sc_npmode[NP_IP] == NPMODE_PASS)
  36396. +            return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count);
  36397. +    return 0;
  36398. +}
  36399. +
  36400. +/*
  36401. + * Process the receipt of an IPX frame
  36402. + */
  36403. +
  36404. +static int
  36405. +rcv_proto_ipx (struct ppp *ppp, __u16 proto, __u8 * data, int count)
  36406. +{
  36407. +    if (((ppp2dev (ppp)->flags & IFF_UP) != 0) && (count > 0))
  36408. +        return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
  36409. +    return 0;
  36410. +}
  36411. +
  36412. +/*
  36413. + * Process the receipt of an VJ Compressed frame
  36414. + */
  36415. +
  36416. +static int
  36417. +rcv_proto_vjc_comp (struct ppp *ppp, __u16 proto,
  36418. +            __u8 *data, int count)
  36419. +{
  36420. +    if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
  36421. +        int new_count = slhc_uncompress (ppp->slcomp, data, count);
  36422. +        if (new_count >= 0) {
  36423. +            return rcv_proto_ip (ppp, PPP_IP, data, new_count);
  36424. +        }
  36425. +        if (ppp->flags & SC_DEBUG)
  36426. +            printk (KERN_NOTICE
  36427. +                "ppp: error in VJ decompression\n");
  36428. +    }
  36429. +    return 0;
  36430. +}
  36431. +
  36432. +/*
  36433. + * Process the receipt of an VJ Un-compressed frame
  36434. + */
  36435. +
  36436. +static int
  36437. +rcv_proto_vjc_uncomp (struct ppp *ppp, __u16 proto,
  36438. +              __u8 *data, int count)
  36439. +{
  36440. +    if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
  36441. +        if (slhc_remember (ppp->slcomp, data, count) > 0) {
  36442. +            return rcv_proto_ip (ppp, PPP_IP, data, count);
  36443. +        }
  36444. +        if (ppp->flags & SC_DEBUG)
  36445. +            printk (KERN_NOTICE
  36446. +                "ppp: error in VJ memorizing\n");
  36447. +    }
  36448. +    return 0;
  36449. +}
  36450. +
  36451. +/*
  36452. + * Receive all unclassified protocols.
  36453. + */
  36454. +
  36455. +static int
  36456. +rcv_proto_unknown (struct ppp *ppp, __u16 proto,
  36457. +           __u8 *data, int len)
  36458. +{
  36459. +    int totlen;
  36460. +    register int current_idx;
  36461. +
  36462. +#define PUTC(c)                         \
  36463. +{                             \
  36464. +    buf_base (ppp->ubuf) [current_idx++] = (__u8) (c); \
  36465. +    current_idx &= ppp->ubuf->size;             \
  36466. +    if (current_idx == ppp->ubuf->tail)             \
  36467. +        goto failure;                 \
  36468. +}
  36469. +
  36470. +/*
  36471. + * The total length includes the protocol data.
  36472. + * Lock the user information buffer.
  36473. + */
  36474. +    if (set_bit (0, &ppp->ubuf->locked)) {
  36475. +        if (ppp->flags & SC_DEBUG)
  36476. +            printk (KERN_DEBUG
  36477. +                "ppp_us_queue: can't get lock\n");
  36478. +    } else {
  36479. +        current_idx = ppp->ubuf->head;
  36480. +/*
  36481. + * Insert the buffer length (not counted), the protocol, and the data
  36482. + */
  36483. +        totlen = len + 2;
  36484. +        PUTC (totlen >> 8);
  36485. +        PUTC (totlen);
  36486. +
  36487. +        PUTC (proto >> 8);
  36488. +        PUTC (proto);
  36489. +
  36490. +        totlen -= 2;
  36491. +        while (totlen-- > 0) {
  36492. +            PUTC (*data++);
  36493. +        }
  36494. +#undef PUTC
  36495. +/*
  36496. + * The frame is complete. Update the head pointer and wakeup the pppd
  36497. + * process.
  36498. + */
  36499. +        ppp->ubuf->head = current_idx;
  36500. +
  36501. +        clear_bit (0, &ppp->ubuf->locked);
  36502. +        wake_up_interruptible (&ppp->read_wait);
  36503. +        if (ppp->tty->fasync != NULL)
  36504. +            kill_fasync (ppp->tty->fasync, SIGIO);
  36505. +
  36506. +        if (ppp->flags & SC_DEBUG)
  36507. +            printk (KERN_INFO
  36508. +                "ppp: successfully queued %d bytes, flags = %x\n",
  36509. +                len + 2, ppp->flags);
  36510. +
  36511. +        return 1;
  36512. +/*
  36513. + * The buffer is full. Unlock the header
  36514. + */
  36515. +failure:
  36516. +        clear_bit (0, &ppp->ubuf->locked);
  36517. +        if (ppp->flags & SC_DEBUG)
  36518. +            printk (KERN_INFO
  36519. +                "ppp_us_queue: ran out of buffer space.\n");
  36520. +    }
  36521. +/*
  36522. + * Discard the frame. There are no takers for this protocol.
  36523. + */
  36524. +    if (ppp->flags & SC_DEBUG)
  36525. +        printk (KERN_WARNING
  36526. +            "ppp: dropping packet on the floor.\n");
  36527. +    slhc_toss (ppp->slcomp);
  36528. +    return 0;
  36529. +}
  36530. +
  36531. +/*
  36532. + * Handle a CCP packet.
  36533. + *
  36534. + * The CCP packet is passed along to the pppd process just like any
  36535. + * other PPP frame. The difference is that some processing needs to be
  36536. + * immediate or the compressors will become confused on the peer.
  36537. + */
  36538. +
  36539. +static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
  36540. +{
  36541. +    int slen    = CCP_LENGTH(dp);
  36542. +    __u8 *opt = dp   + CCP_HDRLEN;
  36543. +    int opt_len = slen - CCP_HDRLEN;
  36544. +
  36545. +    if (slen > len)
  36546. +        return;
  36547. +
  36548. +    switch (CCP_CODE(dp)) {
  36549. +    case CCP_CONFREQ:
  36550. +    case CCP_TERMREQ:
  36551. +    case CCP_TERMACK:
  36552. +/*
  36553. + * CCP must be going down - disable compression
  36554. + */
  36555. +        if (ppp->flags & SC_CCP_UP) {
  36556. +            ppp->flags &= ~(SC_CCP_UP   |
  36557. +                    SC_COMP_RUN |
  36558. +                    SC_DECOMP_RUN);
  36559. +        }
  36560. +        break;
  36561. +
  36562. +    case CCP_CONFACK:
  36563. +        if ((ppp->flags & SC_CCP_OPEN) == 0)
  36564. +            break;
  36565. +        if (ppp->flags & SC_CCP_UP)
  36566. +            break;
  36567. +        if (slen < (CCP_HDRLEN + CCP_OPT_MINLEN))
  36568. +            break;
  36569. +        if (slen < (CCP_OPT_LENGTH (opt) + CCP_HDRLEN))
  36570. +            break;
  36571. +/*
  36572. + * we're agreeing to send compressed packets.
  36573. + */
  36574. +        if (!rcvd) {
  36575. +            if (ppp->sc_xc_state == NULL)
  36576. +                break;
  36577. +
  36578. +            if ((*ppp->sc_xcomp->comp_init)
  36579. +                (ppp->sc_xc_state,
  36580. +                 opt,
  36581. +                 opt_len,
  36582. +                 ppp2dev (ppp)->base_addr,
  36583. +                 0,
  36584. +                 ppp->flags))
  36585. +                ppp->flags |= SC_COMP_RUN;
  36586. +            break;
  36587. +        }
  36588. +/*
  36589. + * peer is agreeing to send compressed packets.
  36590. + */
  36591. +        if (ppp->sc_rc_state == NULL)
  36592. +            break;
  36593. +
  36594. +        if ((*ppp->sc_rcomp->decomp_init)
  36595. +            (ppp->sc_rc_state,
  36596. +             opt,
  36597. +             opt_len,
  36598. +             ppp2dev (ppp)->base_addr,
  36599. +             0,
  36600. +             ppp->mru,
  36601. +             ppp->flags)) {
  36602. +            ppp->flags |= SC_DECOMP_RUN;
  36603. +            ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
  36604. +        }
  36605. +        break;
  36606. +/*
  36607. + * The protocol sequence is complete at this end
  36608. + */
  36609. +    case CCP_RESETACK:
  36610. +        if ((ppp->flags & SC_CCP_UP) == 0)
  36611. +            break;
  36612. +
  36613. +        if (!rcvd) {
  36614. +            if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN))
  36615. +                (*ppp->sc_xcomp->comp_reset)(ppp->sc_xc_state);
  36616. +        } else {
  36617. +            if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) {
  36618. +                  (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state);
  36619. +                ppp->flags &= ~SC_DC_ERROR;
  36620. +            }
  36621. +        }
  36622. +        break;
  36623. +    }
  36624. +}
  36625. +
  36626. +static int
  36627. +rcv_proto_ccp (struct ppp *ppp, __u16 proto, __u8 *dp, int len)
  36628. +{
  36629. +    ppp_proto_ccp (ppp, dp, len, 1);
  36630. +    return rcv_proto_unknown (ppp, proto, dp, len);
  36631. +}
  36632. +
  36633. +/*
  36634. + * Handle a LQR packet.
  36635. + */
  36636. +
  36637. +static int
  36638. +rcv_proto_lqr (struct ppp *ppp, __u16 proto, __u8 * data, int len)
  36639. +{
  36640. +    return rcv_proto_unknown (ppp, proto, data, len);
  36641. +}
  36642. +
  36643. +/* on entry, a received frame is in ppp->rbuf.bufr
  36644. +   check it and dispose as appropriate */
  36645. +
  36646. +static void ppp_doframe_lower (struct ppp *ppp, __u8 *data, int count)
  36647. +{
  36648. +    __u16        proto = PPP_PROTOCOL (data);
  36649. +    ppp_proto_type  *proto_ptr;
  36650. +/*
  36651. + * Ignore empty frames
  36652. + */
  36653. +    if (count <= 4)
  36654. +        return;
  36655. +/*
  36656. + * Count the frame and print it
  36657. + */
  36658. +    ++ppp->stats.ppp_ipackets;
  36659. +    if (ppp->flags & SC_LOG_INPKT)
  36660. +        ppp_print_buffer ("receive frame", data, count);
  36661. +/*
  36662. + * Find the procedure to handle this protocol. The last one is marked
  36663. + * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon.
  36664. + */
  36665. +    proto_ptr = proto_list;
  36666. +    while (proto_ptr->proto != 0 && proto_ptr->proto != proto)
  36667. +        ++proto_ptr;
  36668. +/*
  36669. + * Update the appropriate statistic counter.
  36670. + */
  36671. +    if ((*proto_ptr->func) (ppp, proto,
  36672. +                &data[PPP_HARD_HDR_LEN],
  36673. +                count - PPP_HARD_HDR_LEN))
  36674. +        ppp->stats.ppp_ioctects += count;
  36675. +    else
  36676. +        ++ppp->stats.ppp_discards;
  36677. +}
  36678. +
  36679. +/* on entry, a received frame is in ppp->rbuf.bufr
  36680. +   check it and dispose as appropriate */
  36681. +
  36682. +static int
  36683. +ppp_doframe (struct ppp *ppp)
  36684. +{
  36685. +    __u8    *data = buf_base (ppp->rbuf);
  36686. +    int    count = ppp->rbuf->count;
  36687. +    int    addr, ctrl, proto;
  36688. +    int    new_count;
  36689. +    __u8 *new_data;
  36690. +#ifndef NO_RMK_TEMP_FIX
  36691. +    int    malloced_data;
  36692. +#endif
  36693. +/*
  36694. + * If there is a pending error from the receiver then log it and discard
  36695. + * the damaged frame.
  36696. + */
  36697. +    if (ppp->toss) {
  36698. +        if (ppp->flags & SC_DEBUG)
  36699. +            printk (KERN_WARNING
  36700. +                "ppp_toss: tossing frame, reason = %d\n",
  36701. +                ppp->toss);
  36702. +        ppp->stats.ppp_ierrors++;
  36703. +        return 0;
  36704. +    }
  36705. +/*
  36706. + * An empty frame is ignored. This occurs if the FLAG sequence precedes and
  36707. + * follows each frame.
  36708. + */
  36709. +    if (count == 0)
  36710. +        return 1;
  36711. +/*
  36712. + * Generate an error if the frame is too small.
  36713. + */
  36714. +    if (count < PPP_HARD_HDR_LEN) {
  36715. +        if (ppp->flags & SC_DEBUG)
  36716. +            printk (KERN_WARNING
  36717. +                "ppp: got runt ppp frame, %d chars\n", count);
  36718. +        slhc_toss (ppp->slcomp);
  36719. +        ppp->stats.ppp_ierrors++;
  36720. +        return 1;
  36721. +    }
  36722. +/*
  36723. + * Verify the CRC of the frame and discard the CRC characters from the
  36724. + * end of the buffer.
  36725. + */
  36726. +    if (ppp->rbuf->fcs != PPP_GOODFCS) {
  36727. +        if (ppp->flags & SC_DEBUG)
  36728. +            printk (KERN_WARNING
  36729. +                "ppp: frame with bad fcs, excess = %x\n",
  36730. +                ppp->rbuf->fcs ^ PPP_GOODFCS);
  36731. +        ppp->stats.ppp_ierrors++;
  36732. +        return 0;
  36733. +    }
  36734. +    count -= 2;        /* ignore the fcs characters */
  36735. +/*
  36736. + * Ignore the leading ADDRESS and CONTROL fields in the frame.
  36737. + */
  36738. +    addr   = PPP_ALLSTATIONS;
  36739. +    ctrl   = PPP_UI;
  36740. +
  36741. +    if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
  36742. +        data  += 2;
  36743. +        count -= 2;
  36744. +    }
  36745. +/*
  36746. + * Obtain the protocol from the frame
  36747. + */
  36748. +    proto = (__u16) *data++;
  36749. +    if ((proto & 1) == 0) {
  36750. +        proto = (proto << 8) | (__u16) *data++;
  36751. +        --count;
  36752. +    }
  36753. +/*
  36754. + * Rewrite the header with the full information. This may encroach upon
  36755. + * the 'filler' area in the buffer header. This is the purpose for the
  36756. + * filler.
  36757. + */
  36758. +    *(--data) = proto;
  36759. +    *(--data) = proto >> 8;
  36760. +    *(--data) = ctrl;
  36761. +    *(--data) = addr;
  36762. +    count    += 3;
  36763. +#ifndef NO_RMK_TEMP_FIX
  36764. +    /*
  36765. +     * rmk: should make sure that the packet received is on a word boundary.
  36766. +     * this is a temporary fix!!!
  36767. +     */
  36768. +    if ((int)data & 3) {
  36769. +        new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC); /* would like to have 'count' here */
  36770. +        memcpy (new_data, data, count);
  36771. +        data = new_data;
  36772. +        malloced_data = 1;
  36773. +    } else
  36774. +        malloced_data = 0;
  36775. +#endif
  36776. +/*
  36777. + * Process the active decompressor.
  36778. + */
  36779. +    if ((ppp->sc_rc_state != (void *) 0) &&
  36780. +        (ppp->flags & SC_DECOMP_RUN)     &&
  36781. +        ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {
  36782. +        if (proto == PPP_COMP) {
  36783. +/*
  36784. + * If the frame is compressed then decompress it.
  36785. + */
  36786. +            new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC);
  36787. +            if (new_data == NULL) {
  36788. +                if (ppp->flags & SC_DEBUG)
  36789. +                    printk (KERN_ERR
  36790. +                        "ppp_doframe: no memory\n");
  36791. +                slhc_toss (ppp->slcomp);
  36792. +                (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
  36793. +                              data,
  36794. +                              count);
  36795. +#ifndef NO_RMK_TEMP_FIX
  36796. +                if (malloced_data) kfree (data);
  36797. +#endif                              
  36798. +                return 1;
  36799. +            }
  36800. +/*
  36801. + * Decompress the frame
  36802. + */
  36803. +            new_count = bsd_decompress (ppp->sc_rc_state,
  36804. +                            data,
  36805. +                            count,
  36806. +                            new_data,
  36807. +                            ppp->mru + 4);
  36808. +            switch (new_count) {
  36809. +            default:
  36810. +                ppp_doframe_lower (ppp, new_data, new_count);
  36811. +                kfree (new_data);
  36812. +#ifndef NO_RMK_TEMP_FIX
  36813. +                if (malloced_data) kfree (data);
  36814. +#endif
  36815. +                return 1;
  36816. +
  36817. +            case DECOMP_OK:
  36818. +                break;
  36819. +
  36820. +            case DECOMP_ERROR:
  36821. +                ppp->flags |= SC_DC_ERROR;
  36822. +                break;
  36823. +
  36824. +            case DECOMP_FATALERROR:
  36825. +                ppp->flags |= SC_DC_FERROR;
  36826. +                break;
  36827. +            }
  36828. +/*
  36829. + * Log the error condition and discard the frame.
  36830. + */
  36831. +            if (ppp->flags & SC_DEBUG)
  36832. +                printk (KERN_ERR
  36833. +                    "ppp_proto_comp: "
  36834. +                    "decompress err %d\n", new_count);
  36835. +            kfree (new_data);
  36836. +            slhc_toss (ppp->slcomp);
  36837. +#ifndef NO_RMK_TEMP_FIX
  36838. +            if (malloced_data) kfree (data);
  36839. +#endif                              
  36840. +            return 1;
  36841. +        }
  36842. +/*
  36843. + * The frame is not special. Pass it through the compressor without
  36844. + * actually compressing the data
  36845. + */
  36846. +        (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
  36847. +                      data,
  36848. +                      count);
  36849. +    }
  36850. +/*
  36851. + * Process the uncompressed frame.
  36852. + */
  36853. +    ppp_doframe_lower (ppp, data, count);
  36854. +#ifndef NO_RMK_TEMP_FIX
  36855. +    if (malloced_data) kfree (data);
  36856. +#endif                              
  36857. +    return 1;
  36858. +}
  36859. +
  36860. +/*************************************************************
  36861. + * LINE DISCIPLINE SUPPORT
  36862. + *    The following functions form support user programs
  36863. + *    which read and write data on a TTY with the PPP line
  36864. + *    discipline.  Reading is done from a circular queue,
  36865. + *    filled by the lower TTY levels.
  36866. + *************************************************************/
  36867. +
  36868. +/* read a PPP frame from the us_rbuff circular buffer,
  36869. +   waiting if necessary
  36870. +*/
  36871. +
  36872. +static int
  36873. +ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
  36874. +          unsigned int nr)
  36875. +{
  36876. +    struct ppp *ppp = tty2ppp (tty);
  36877. +    __u8 c;
  36878. +    int len, indx;
  36879. +
  36880. +#define GETC(c)                        \
  36881. +{                            \
  36882. +    c = buf_base (ppp->ubuf) [ppp->ubuf->tail++];    \
  36883. +    ppp->ubuf->tail &= ppp->ubuf->size;        \
  36884. +}
  36885. +
  36886. +/*
  36887. + * Validate the pointers
  36888. + */
  36889. +    if (!ppp)
  36890. +        return -EIO;
  36891. +
  36892. +    if (ppp->magic != PPP_MAGIC)
  36893. +        return -EIO;
  36894. +
  36895. +    CHECK_PPP (-ENXIO);
  36896. +
  36897. +    if (ppp->flags & SC_DEBUG)
  36898. +        printk (KERN_DEBUG
  36899. +            "ppp_tty_read: called buf=%p nr=%u\n",
  36900. +            buf, nr);
  36901. +/*
  36902. + * Acquire the read lock.
  36903. + */
  36904. +    for (;;) {
  36905. +        ppp = tty2ppp (tty);
  36906. +        if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
  36907. +            return 0;
  36908. +
  36909. +        if (set_bit (0, &ppp->ubuf->locked) != 0) {
  36910. +            if (ppp->flags & SC_DEBUG)
  36911. +                printk (KERN_DEBUG
  36912. +                     "ppp_tty_read: sleeping(ubuf)\n");
  36913. +
  36914. +            current->timeout = 0;
  36915. +            current->state   = TASK_INTERRUPTIBLE;
  36916. +            schedule ();
  36917. +
  36918. +            if (current->signal & ~current->blocked)
  36919. +                return -EINTR;
  36920. +            continue;
  36921. +        }
  36922. +/*
  36923. + * Before we attempt to write the frame to the user, ensure that the
  36924. + * user has access to the pages for the total buffer length.
  36925. + */
  36926. +        indx = verify_area (VERIFY_WRITE, buf, nr);
  36927. +        if (indx != 0)
  36928. +            return (indx);
  36929. +/*
  36930. + * Fetch the length of the buffer from the first two bytes.
  36931. + */
  36932. +        if (ppp->ubuf->head == ppp->ubuf->tail)
  36933. +            len = 0;
  36934. +        else {
  36935. +            GETC (c);
  36936. +            len = c << 8;
  36937. +            GETC (c);
  36938. +            len += c;
  36939. +        }
  36940. +/*
  36941. + * If there is no length then wait for the data to arrive.
  36942. + */
  36943. +        if (len == 0) {
  36944. +            /* no data */
  36945. +            clear_bit (0, &ppp->ubuf->locked);
  36946. +            if (file->f_flags & O_NONBLOCK) {
  36947. +                if (ppp->flags & SC_DEBUG)
  36948. +                    printk (KERN_DEBUG
  36949. +                        "ppp_tty_read: no data "
  36950. +                        "(EAGAIN)\n");
  36951. +                return -EAGAIN;
  36952. +            }
  36953. +            current->timeout = 0;
  36954. +
  36955. +            if (ppp->flags & SC_DEBUG)
  36956. +                printk (KERN_DEBUG
  36957. +                    "ppp_tty_read: sleeping(read_wait)\n");
  36958. +
  36959. +            interruptible_sleep_on (&ppp->read_wait);
  36960. +            if (current->signal & ~current->blocked)
  36961. +                return -EINTR;
  36962. +            continue;
  36963. +        }
  36964. +/*
  36965. + * Reset the time of the last read operation.
  36966. + */
  36967. +        if (ppp->flags & SC_DEBUG)
  36968. +            printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len);
  36969. +/*
  36970. + * Ensure that the frame will fit within the caller's buffer. If not, then
  36971. + * discard the frame from the input buffer.
  36972. + */
  36973. +        if (len + 2 > nr) {
  36974. +            /* Can't copy it, update us_rbuff_head */
  36975. +
  36976. +            if (ppp->flags & SC_DEBUG)
  36977. +                printk (KERN_DEBUG
  36978. +                "ppp: read of %u bytes too small for %d "
  36979. +                "frame\n", nr, len + 2);
  36980. +            ppp->ubuf->tail += len;
  36981. +            ppp->ubuf->tail &= ppp->ubuf->size;
  36982. +            clear_bit (0, &ppp->ubuf->locked);
  36983. +            ppp->stats.ppp_ierrors++;
  36984. +            return -EOVERFLOW;
  36985. +        }
  36986. +/*
  36987. + * Before we attempt to write the frame to the user, ensure that the
  36988. + * page tables are proper.
  36989. + */
  36990. +        indx = verify_area (VERIFY_WRITE, buf, len + 2);
  36991. +        if (indx != 0) {
  36992. +            ppp->ubuf->tail += len;
  36993. +            ppp->ubuf->tail &= ppp->ubuf->size;
  36994. +            clear_bit (0, &ppp->ubuf->locked);
  36995. +            return (indx);
  36996. +        }
  36997. +/*
  36998. + * Fake the insertion of the ADDRESS and CONTROL information because these
  36999. + * were not saved in the buffer.
  37000. + */
  37001. +        put_user (PPP_ALLSTATIONS, buf++);
  37002. +        put_user (PPP_UI,          buf++);
  37003. +
  37004. +        indx = len;
  37005. +/*
  37006. + * Copy the received data from the buffer to the caller's area.
  37007. + */
  37008. +        while (indx-- > 0) {
  37009. +            GETC (c);
  37010. +            put_user (c, buf);
  37011. +            ++buf;
  37012. +        }
  37013. +
  37014. +        clear_bit (0, &ppp->ubuf->locked);
  37015. +        len += 2; /* Account for ADDRESS and CONTROL bytes */
  37016. +        if (ppp->flags & SC_DEBUG)
  37017. +            printk (KERN_DEBUG
  37018. +                "ppp_tty_read: passing %d bytes up\n", len);
  37019. +        return len;
  37020. +    }
  37021. +#undef GETC
  37022. +}
  37023. +
  37024. +/* stuff a character into the transmit buffer, using PPP's way of escaping
  37025. +   special characters.
  37026. +   also, update fcs to take account of new character */
  37027. +
  37028. +extern inline void
  37029. +ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
  37030. +        register __u8 chr)
  37031. +{
  37032. +/*
  37033. + * The buffer should not be full.
  37034. + */
  37035. +    if (ppp->flags & SC_DEBUG) {
  37036. +        if ((buf->count < 0) || (buf->count > 3000))
  37037. +            printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
  37038. +                (unsigned int) buf->count,
  37039. +                (unsigned int) chr);
  37040. +    }
  37041. +/*
  37042. + * Update the FCS and if the character needs to be escaped, do it.
  37043. + */
  37044. +    buf->fcs = PPP_FCS (buf->fcs, chr);
  37045. +    if (in_xmap (ppp, chr)) {
  37046. +        chr ^= PPP_TRANS;
  37047. +        ins_char (buf, PPP_ESCAPE);
  37048. +    }
  37049. +/*
  37050. + * Add the character to the buffer.
  37051. + */
  37052. +    ins_char (buf, chr);
  37053. +}
  37054. +
  37055. +/*
  37056. + * Procedure to encode the data with the proper escaping and send the
  37057. + * data to the remote system.
  37058. + */
  37059. +
  37060. +static void
  37061. +ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
  37062. +            __u8 *data, int count, int non_ip)
  37063. +{
  37064. +    __u16 write_fcs;
  37065. +    int     address, control;
  37066. +    int    proto;
  37067. +/*
  37068. + * Insert the leading FLAG character
  37069. + */
  37070. +    buf->count = 0;
  37071. +
  37072. +    if (non_ip || flag_time == 0)
  37073. +        ins_char (buf, PPP_FLAG);
  37074. +    else {
  37075. +        if (jiffies - ppp->last_xmit > flag_time)
  37076. +            ins_char (buf, PPP_FLAG);
  37077. +    }
  37078. +    ppp->last_xmit = jiffies;
  37079. +    buf->fcs       = PPP_INITFCS;
  37080. +/*
  37081. + * Emit the address/control information if needed
  37082. + */
  37083. +    address = PPP_ADDRESS  (data);
  37084. +    control = PPP_CONTROL  (data);
  37085. +    proto   = PPP_PROTOCOL (data);
  37086. +
  37087. +    if (address != PPP_ALLSTATIONS ||
  37088. +        control != PPP_UI ||
  37089. +        (ppp->flags & SC_COMP_AC) == 0) {
  37090. +        ppp_stuff_char (ppp, buf, address);
  37091. +        ppp_stuff_char (ppp, buf, control);
  37092. +    }
  37093. +/*
  37094. + * Emit the protocol (compressed if possible)
  37095. + */
  37096. +    if ((ppp->flags & SC_COMP_PROT) == 0 || (proto & 0xFF00))
  37097. +        ppp_stuff_char (ppp, buf, proto >> 8);
  37098. +
  37099. +    ppp_stuff_char (ppp, buf, proto);
  37100. +/*
  37101. + * Insert the data
  37102. + */
  37103. +    data  += 4;
  37104. +    count -= 4;
  37105. +
  37106. +    while (count-- > 0)
  37107. +        ppp_stuff_char (ppp, buf, *data++);
  37108. +/*
  37109. + * Add the trailing CRC and the final flag character
  37110. + */
  37111. +    write_fcs = buf->fcs ^ 0xFFFF;
  37112. +    ppp_stuff_char (ppp, buf, write_fcs);
  37113. +    ppp_stuff_char (ppp, buf, write_fcs >> 8);
  37114. +
  37115. +    if (ppp->flags & SC_DEBUG)
  37116. +        printk (KERN_DEBUG "ppp_dev_xmit_lower: fcs is %hx\n",
  37117. +            write_fcs);
  37118. +/*
  37119. + * Add the trailing flag character
  37120. + */
  37121. +    ins_char (buf, PPP_FLAG);
  37122. +/*
  37123. + * Print the buffer
  37124. + */
  37125. +    if (ppp->flags & SC_LOG_FLUSH)
  37126. +        ppp_print_buffer ("ppp flush", buf_base (buf),
  37127. +                  buf->count);
  37128. +    else {
  37129. +        if (ppp->flags & SC_DEBUG)
  37130. +            printk (KERN_DEBUG
  37131. +                "ppp_dev_xmit: writing %d chars\n",
  37132. +                buf->count);
  37133. +    }
  37134. +/*
  37135. + * Send the block to the tty driver.
  37136. + */
  37137. +    ppp->stats.ppp_obytes += buf->count;
  37138. +    ppp_kick_tty (ppp, buf);
  37139. +}
  37140. +
  37141. +/*
  37142. + * Send an frame to the remote with the proper bsd compression.
  37143. + *
  37144. + * Return 0 if frame was queued for transmission.
  37145. + *        1 if frame must be re-queued for later driver support.
  37146. + */
  37147. +
  37148. +static int
  37149. +ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
  37150. +            __u8 *data, int count)
  37151. +{
  37152. +    int    proto;
  37153. +    int     address, control;
  37154. +    __u8 *new_data;
  37155. +    int     new_count;
  37156. +/*
  37157. + * Print the buffer
  37158. + */
  37159. +    if (ppp->flags & SC_LOG_OUTPKT)
  37160. +        ppp_print_buffer ("write frame", data, count);
  37161. +/*
  37162. + * Determine if the frame may be compressed. Attempt to compress the
  37163. + * frame if possible.
  37164. + */
  37165. +    proto   = PPP_PROTOCOL (data);
  37166. +    address = PPP_ADDRESS  (data);
  37167. +    control = PPP_CONTROL  (data);
  37168. +
  37169. +    if (((ppp->flags & SC_COMP_RUN) != 0)    &&
  37170. +        (ppp->sc_xc_state != (void *) 0)    &&
  37171. +        (address == PPP_ALLSTATIONS)    &&
  37172. +        (control == PPP_UI)            &&
  37173. +        (proto != PPP_LCP)            &&
  37174. +        (proto != PPP_CCP)) {
  37175. +        new_data = kmalloc (count, GFP_ATOMIC);
  37176. +        if (new_data == NULL) {
  37177. +            if (ppp->flags & SC_DEBUG)
  37178. +                printk (KERN_ERR
  37179. +                    "ppp_dev_xmit_frame: no memory\n");
  37180. +            return 1;
  37181. +        }
  37182. +
  37183. +        new_count = bsd_compress (ppp->sc_xc_state,
  37184. +                      data,
  37185. +                      new_data,
  37186. +                      count,
  37187. +                      count);
  37188. +
  37189. +        if (new_count > 0) {
  37190. +            ++ppp->stats.ppp_opackets;
  37191. +            ppp->stats.ppp_ooctects += new_count;
  37192. +
  37193. +            ppp_dev_xmit_lower (ppp, buf, new_data,
  37194. +                        new_count, 0);
  37195. +            kfree (new_data);
  37196. +            return 0;
  37197. +        }
  37198. +/*
  37199. + * The frame could not be compressed.
  37200. + */
  37201. +        kfree (new_data);
  37202. +    }
  37203. +/*
  37204. + * The frame may not be compressed. Update the statistics before the
  37205. + * count field is destroyed. The frame will be transmitted.
  37206. + */
  37207. +    ++ppp->stats.ppp_opackets;
  37208. +    ppp->stats.ppp_ooctects += count;
  37209. +/*
  37210. + * Go to the escape encoding
  37211. + */
  37212. +    ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00));
  37213. +    return 0;
  37214. +}
  37215. +
  37216. +/*
  37217. + * Revise the tty frame for specific protocols.
  37218. + */
  37219. +
  37220. +static int
  37221. +send_revise_frame (register struct ppp *ppp, __u8 *data, int len)
  37222. +{
  37223. +    __u8 *p;
  37224. +
  37225. +    switch (PPP_PROTOCOL (data)) {
  37226. +/*
  37227. + * Update the LQR frame with the current MIB information. This saves having
  37228. + * the daemon read old MIB data from the driver.
  37229. + */
  37230. +    case PPP_LQR:
  37231. +        len = 48;            /* total size of this frame */
  37232. +        p   = (__u8 *) &data [40];    /* Point to last two items. */
  37233. +        p   = store_long (p, ppp->stats.ppp_opackets + 1);
  37234. +        p   = store_long (p, ppp->stats.ppp_ooctects + len);
  37235. +        break;
  37236. +/*
  37237. + * Outbound compression frames
  37238. + */
  37239. +    case PPP_CCP:
  37240. +        ppp_proto_ccp (ppp,
  37241. +                   data + PPP_HARD_HDR_LEN,
  37242. +                   len  - PPP_HARD_HDR_LEN,
  37243. +                   0);
  37244. +        break;
  37245. +
  37246. +    default:
  37247. +        break;
  37248. +    }
  37249. +
  37250. +    return len;
  37251. +}
  37252. +
  37253. +/*
  37254. + * write a frame with NR chars from BUF to TTY
  37255. + * we have to put the FCS field on ourselves
  37256. + */
  37257. +
  37258. +static int
  37259. +ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
  37260. +           unsigned int count)
  37261. +{
  37262. +    struct ppp *ppp = tty2ppp (tty);
  37263. +    __u8 *new_data;
  37264. +    int status;
  37265. +/*
  37266. + * Verify the pointers.
  37267. + */
  37268. +    if (!ppp)
  37269. +        return -EIO;
  37270. +
  37271. +    if (ppp->magic != PPP_MAGIC)
  37272. +        return -EIO;
  37273. +
  37274. +    CHECK_PPP (-ENXIO);
  37275. +/*
  37276. + * Ensure that the caller does not wish to send too much.
  37277. + */
  37278. +    if (count > PPP_MTU) {
  37279. +        if (ppp->flags & SC_DEBUG)
  37280. +            printk (KERN_WARNING
  37281. +                "ppp_tty_write: truncating user packet "
  37282. +                "from %u to mtu %d\n", count, PPP_MTU);
  37283. +        count = PPP_MTU;
  37284. +    }
  37285. +/*
  37286. + * Allocate a buffer for the data and fetch it from the user space.
  37287. + */
  37288. +    new_data = kmalloc (count, GFP_KERNEL);
  37289. +    if (new_data == NULL) {
  37290. +        if (ppp->flags & SC_DEBUG)
  37291. +            printk (KERN_ERR
  37292. +                "ppp_tty_write: no memory\n");
  37293. +        return 0;
  37294. +    }
  37295. +/*
  37296. + * lock this PPP unit so we will be the only writer;
  37297. + * sleep if necessary
  37298. + */
  37299. +    while (lock_buffer (ppp->tbuf) != 0) {
  37300. +        current->timeout = 0;
  37301. +        if (ppp->flags & SC_DEBUG)
  37302. +            printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
  37303. +        interruptible_sleep_on (&ppp->write_wait);
  37304. +
  37305. +        ppp = tty2ppp (tty);
  37306. +        if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) {
  37307. +            kfree (new_data);
  37308. +            return 0;
  37309. +        }
  37310. +
  37311. +        if (current->signal & ~current->blocked) {
  37312. +            kfree (new_data);
  37313. +            return -EINTR;
  37314. +        }
  37315. +    }
  37316. +/*
  37317. + * Ensure that the caller's buffer is valid.
  37318. + */
  37319. +    status = verify_area (VERIFY_READ, data, count);
  37320. +    if (status != 0) {
  37321. +        kfree (new_data);
  37322. +        ppp->tbuf->locked = 0;
  37323. +        return status;
  37324. +    }
  37325. +
  37326. +    memcpy_fromfs (new_data, data, count);
  37327. +/*
  37328. + * Change the LQR frame
  37329. + */
  37330. +    count = send_revise_frame (ppp, new_data, count);
  37331. +/*
  37332. + * Send the data
  37333. + */
  37334. +    ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count);
  37335. +    kfree (new_data);
  37336. +    return (int) count;
  37337. +}
  37338. +
  37339. +/*
  37340. + * Process the BSD compression IOCTL event for the tty device.
  37341. + */
  37342. +
  37343. +static int
  37344. +ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
  37345. +{
  37346. +    struct compressor *cp;
  37347. +    struct ppp_option_data data;
  37348. +    int error;
  37349. +    int nb;
  37350. +    __u8 *ptr;
  37351. +    __u8 ccp_option[CCP_MAX_OPTION_LENGTH];
  37352. +/*
  37353. + * Fetch the compression parameters
  37354. + */
  37355. +    error = verify_area (VERIFY_READ, odp, sizeof (data));
  37356. +    if (error == 0) {
  37357. +        memcpy_fromfs (&data, odp, sizeof (data));
  37358. +        nb  = data.length;
  37359. +        ptr = data.ptr;
  37360. +        if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH)
  37361. +            nb = CCP_MAX_OPTION_LENGTH;
  37362. +    
  37363. +        error = verify_area (VERIFY_READ, ptr, nb);
  37364. +    }
  37365. +
  37366. +    if (error != 0)
  37367. +        return error;
  37368. +
  37369. +    memcpy_fromfs (ccp_option, ptr, nb);
  37370. +
  37371. +    if (ccp_option[1] < 2)    /* preliminary check on the length byte */
  37372. +        return (-EINVAL);
  37373. +
  37374. +    cp = find_compressor ((int) (unsigned int) (__u8) ccp_option[0]);
  37375. +    if (cp != (struct compressor *) 0) {
  37376. +        /*
  37377. +         * Found a handler for the protocol - try to allocate
  37378. +         * a compressor or decompressor.
  37379. +         */
  37380. +        error = 0;
  37381. +        if (data.transmit) {
  37382. +            if (ppp->sc_xc_state != NULL)
  37383. +                (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
  37384. +
  37385. +            ppp->sc_xcomp    = cp;
  37386. +            ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
  37387. +
  37388. +            if (ppp->sc_xc_state == NULL) {
  37389. +                if (ppp->flags & SC_DEBUG)
  37390. +                    printk("ppp%ld: comp_alloc failed\n",
  37391. +                           ppp2dev (ppp)->base_addr);
  37392. +                error = -ENOBUFS;
  37393. +            }
  37394. +            ppp->flags &= ~SC_COMP_RUN;
  37395. +        } else {
  37396. +            if (ppp->sc_rc_state != NULL)
  37397. +                (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
  37398. +            ppp->sc_rcomp    = cp;
  37399. +            ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
  37400. +            if (ppp->sc_rc_state == NULL) {
  37401. +                if (ppp->flags & SC_DEBUG)
  37402. +                    printk("ppp%ld: decomp_alloc failed\n",
  37403. +                           ppp2dev (ppp)->base_addr);
  37404. +                error = ENOBUFS;
  37405. +            }
  37406. +            ppp->flags &= ~SC_DECOMP_RUN;
  37407. +        }
  37408. +        return (error);
  37409. +    }
  37410. +
  37411. +    if (ppp->flags & SC_DEBUG)
  37412. +        printk(KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n",
  37413. +               ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1],
  37414. +               ccp_option[2], nb);
  37415. +    return (-EINVAL);    /* no handler found */
  37416. +}
  37417. +
  37418. +/*
  37419. + * Process the IOCTL event for the tty device.
  37420. + */
  37421. +
  37422. +static int
  37423. +ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  37424. +           unsigned int param2, unsigned long param3)
  37425. +{
  37426. +    struct ppp *ppp = tty2ppp (tty);
  37427. +    register int temp_i = 0;
  37428. +    int error = 0;
  37429. +/*
  37430. + * Verify the status of the PPP device.
  37431. + */
  37432. +    if (!ppp)
  37433. +        return -EBADF;
  37434. +
  37435. +    if (ppp->magic != PPP_MAGIC)
  37436. +        return -EBADF;
  37437. +
  37438. +    CHECK_PPP (-ENXIO);
  37439. +/*
  37440. + * The user must have an euid of root to do these requests.
  37441. + */
  37442. +    if (!suser ())
  37443. +        return -EPERM;
  37444. +/*
  37445. + * Set the MRU value
  37446. + */
  37447. +    switch (param2) {
  37448. +    case PPPIOCSMRU:
  37449. +        error = verify_area (VERIFY_READ, (void *) param3,
  37450. +                     sizeof (temp_i));
  37451. +        if (error == 0) {
  37452. +            temp_i = get_user ((int *) param3);
  37453. +            if (ppp->flags & SC_DEBUG)
  37454. +                printk (KERN_INFO
  37455. +                 "ppp_tty_ioctl: set mru to %x\n", temp_i);
  37456. +
  37457. +            if (ppp->mru != temp_i)
  37458. +                ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i);
  37459. +        }
  37460. +        break;
  37461. +/*
  37462. + * Fetch the flags
  37463. + */
  37464. +    case PPPIOCGFLAGS:
  37465. +        error = verify_area (VERIFY_WRITE, (void *) param3,
  37466. +                     sizeof (temp_i));
  37467. +        if (error == 0) {
  37468. +            temp_i = (ppp->flags & SC_MASK);
  37469. +#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
  37470. +            temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
  37471. +                  SC_RCV_ODDP | SC_RCV_EVNP;
  37472. +#endif
  37473. +            put_user (temp_i, (int *) param3);
  37474. +            if (ppp->flags & SC_DEBUG)
  37475. +                printk (KERN_DEBUG
  37476. +                "ppp_tty_ioctl: get flags: addr %lx flags "
  37477. +                "%x\n", param3, temp_i);
  37478. +        }
  37479. +        break;
  37480. +/*
  37481. + * Set the flags for the various options
  37482. + */
  37483. +    case PPPIOCSFLAGS:
  37484. +        error = verify_area (VERIFY_READ, (void *) param3,
  37485. +                     sizeof (temp_i));
  37486. +        if (error == 0) {
  37487. +            temp_i  = get_user ((int *) param3) & SC_MASK;
  37488. +            temp_i |= (ppp->flags & ~SC_MASK);
  37489. +
  37490. +            if ((ppp->flags & SC_CCP_OPEN) &&
  37491. +                (temp_i & SC_CCP_OPEN) == 0)
  37492. +                ppp_ccp_closed (ppp);
  37493. +
  37494. +            if ((ppp->flags | temp_i) & SC_DEBUG)
  37495. +                printk (KERN_INFO
  37496. +                   "ppp_tty_ioctl: set flags to %x\n", temp_i);
  37497. +            ppp->flags = temp_i;
  37498. +        }
  37499. +        break;
  37500. +/*
  37501. + * Set the compression mode
  37502. + */
  37503. +    case PPPIOCSCOMPRESS:
  37504. +        error = ppp_set_compression (ppp,
  37505. +                        (struct ppp_option_data *) param3);
  37506. +        break;
  37507. +/*
  37508. + * Retrieve the transmit async map
  37509. + */
  37510. +    case PPPIOCGASYNCMAP:
  37511. +        error = verify_area (VERIFY_WRITE, (void *) param3,
  37512. +                     sizeof (temp_i));
  37513. +        if (error == 0) {
  37514. +            put_user (ppp->xmit_async_map[0], (int *) param3);
  37515. +            if (ppp->flags & SC_DEBUG)
  37516. +                printk (KERN_INFO
  37517. +                     "ppp_tty_ioctl: get asyncmap: addr "
  37518. +                     "%lx asyncmap %x\n",
  37519. +                     param3,
  37520. +                     ppp->xmit_async_map[0]);
  37521. +        }
  37522. +        break;
  37523. +/*
  37524. + * Set the transmit async map
  37525. + */
  37526. +    case PPPIOCSASYNCMAP:
  37527. +        error = verify_area (VERIFY_READ, (void *) param3,
  37528. +                     sizeof (temp_i));
  37529. +        if (error == 0) {
  37530. +            ppp->xmit_async_map[0] = get_user ((int *) param3);
  37531. +            if (ppp->flags & SC_DEBUG)
  37532. +                printk (KERN_INFO
  37533. +                     "ppp_tty_ioctl: set xmit asyncmap %x\n",
  37534. +                     ppp->xmit_async_map[0]);
  37535. +        }
  37536. +        break;
  37537. +/*
  37538. + * Set the receive async map
  37539. + */
  37540. +    case PPPIOCSRASYNCMAP:
  37541. +        error = verify_area (VERIFY_READ, (void *) param3,
  37542. +                     sizeof (temp_i));
  37543. +        if (error == 0) {
  37544. +            ppp->recv_async_map = get_user ((int *) param3);
  37545. +            if (ppp->flags & SC_DEBUG)
  37546. +                printk (KERN_INFO
  37547. +                     "ppp_tty_ioctl: set rcv asyncmap %x\n",
  37548. +                     ppp->recv_async_map);
  37549. +        }
  37550. +        break;
  37551. +/*
  37552. + * Obtain the unit number for this device.
  37553. + */
  37554. +    case PPPIOCGUNIT:
  37555. +        error = verify_area (VERIFY_WRITE, (void *) param3,
  37556. +                     sizeof (temp_i));
  37557. +        if (error == 0) {
  37558. +            put_user (ppp2dev (ppp)->base_addr, (int *) param3);
  37559. +            if (ppp->flags & SC_DEBUG)
  37560. +                printk (KERN_INFO
  37561. +                    "ppp_tty_ioctl: get unit: %ld",
  37562. +                    ppp2dev (ppp)->base_addr);
  37563. +        }
  37564. +        break;
  37565. +/*
  37566. + * Set the debug level
  37567. + */
  37568. +    case PPPIOCSDEBUG:
  37569. +        error = verify_area (VERIFY_READ, (void *) param3,
  37570. +                     sizeof (temp_i));
  37571. +        if (error == 0) {
  37572. +            temp_i  = (get_user ((int *) param3) & 0x1F) << 16;
  37573. +            temp_i |= (ppp->flags & ~0x1F0000);
  37574. +
  37575. +            if ((ppp->flags | temp_i) & SC_DEBUG)
  37576. +                printk (KERN_INFO
  37577. +                   "ppp_tty_ioctl: set flags to %x\n", temp_i);
  37578. +            ppp->flags = temp_i;
  37579. +        }
  37580. +        break;
  37581. +/*
  37582. + * Get the debug level
  37583. + */
  37584. +    case PPPIOCGDEBUG:
  37585. +        error = verify_area (VERIFY_WRITE, (void *) param3,
  37586. +                     sizeof (temp_i));
  37587. +        if (error == 0) {
  37588. +            temp_i = (ppp->flags >> 16) & 0x1F;
  37589. +            put_user (temp_i, (int *) param3);
  37590. +
  37591. +            if (ppp->flags & SC_DEBUG)
  37592. +                printk (KERN_INFO
  37593. +                    "ppp_tty_ioctl: get debug level %d\n",
  37594. +                    temp_i);
  37595. +              }
  37596. +        break;
  37597. +/*
  37598. + * Get the times since the last send/receive frame operation
  37599. + */
  37600. +    case PPPIOCGIDLE:
  37601. +        error = verify_area (VERIFY_WRITE, (void *) param3,
  37602. +                     sizeof (struct ppp_idle));
  37603. +        if (error == 0) {
  37604. +            struct ppp_idle cur_ddinfo;
  37605. +            __u32 cur_jiffies = jiffies;
  37606. +
  37607. +            /* change absolute times to relative times. */
  37608. +            cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ;
  37609. +            cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ;
  37610. +            memcpy_tofs ((void *) param3, &cur_ddinfo,
  37611. +                     sizeof (cur_ddinfo));
  37612. +            if (ppp->flags & SC_DEBUG)
  37613. +                printk (KERN_INFO
  37614. +                "ppp_tty_ioctl: read demand dial info\n");
  37615. +        }
  37616. +        break;
  37617. +/*
  37618. + * Retrieve the extended async map
  37619. + */
  37620. +    case PPPIOCGXASYNCMAP:
  37621. +        error = verify_area (VERIFY_WRITE,
  37622. +                     (void *) param3,
  37623. +                     sizeof (ppp->xmit_async_map));
  37624. +        if (error == 0) {
  37625. +            memcpy_tofs ((void *) param3,
  37626. +                     ppp->xmit_async_map,
  37627. +                     sizeof (ppp->xmit_async_map));
  37628. +
  37629. +            if (ppp->flags & SC_DEBUG)
  37630. +                printk (KERN_INFO
  37631. +                "ppp_tty_ioctl: get xasyncmap: addr %lx\n",
  37632. +                param3);
  37633. +        }
  37634. +        break;
  37635. +/*
  37636. + * Set the async extended map
  37637. + */
  37638. +    case PPPIOCSXASYNCMAP:
  37639. +        error = verify_area (VERIFY_READ, (void *) param3,
  37640. +                     sizeof (ppp->xmit_async_map));
  37641. +        if (error == 0) {
  37642. +            __u32 temp_tbl[8];
  37643. +
  37644. +            memcpy_fromfs (temp_tbl, (void *) param3,
  37645. +                       sizeof (ppp->xmit_async_map));
  37646. +            temp_tbl[1]  =  0x00000000;
  37647. +            temp_tbl[2] &= ~0x40000000;
  37648. +            temp_tbl[3] |=  0x60000000;
  37649. +
  37650. +            if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
  37651. +                (temp_tbl[4] & temp_tbl[5]) != 0 ||
  37652. +                (temp_tbl[6] & temp_tbl[7]) != 0)
  37653. +                error = -EINVAL;
  37654. +            else {
  37655. +                memcpy (ppp->xmit_async_map, temp_tbl,
  37656. +                    sizeof (ppp->xmit_async_map));
  37657. +
  37658. +                if (ppp->flags & SC_DEBUG)
  37659. +                    printk (KERN_INFO
  37660. +                    "ppp_tty_ioctl: set xasyncmap\n");
  37661. +            }
  37662. +        }
  37663. +        break;
  37664. +/*
  37665. + * Set the maximum VJ header compression slot number.
  37666. + */
  37667. +    case PPPIOCSMAXCID:
  37668. +        error = verify_area (VERIFY_READ, (void *) param3,
  37669. +                     sizeof (temp_i));
  37670. +        if (error == 0) {
  37671. +            temp_i = get_user ((int *) param3) + 1;
  37672. +            if (ppp->flags & SC_DEBUG)
  37673. +                printk (KERN_INFO
  37674. +                     "ppp_tty_ioctl: set maxcid to %d\n",
  37675. +                     temp_i);
  37676. +            if (ppp->slcomp != NULL)
  37677. +                slhc_free (ppp->slcomp);
  37678. +            ppp->slcomp = slhc_init (16, temp_i);
  37679. +
  37680. +            if (ppp->slcomp == NULL) {
  37681. +                if (ppp->flags & SC_DEBUG)
  37682. +                    printk (KERN_ERR
  37683. +                    "ppp: no space for compression buffers!\n");
  37684. +                ppp_release (ppp);
  37685. +                error = -ENOMEM;
  37686. +            }
  37687. +        }
  37688. +        break;
  37689. +
  37690. +    case PPPIOCXFERUNIT:
  37691. +        ppp_tty_close_local (tty, current->pid);
  37692. +        break;
  37693. +
  37694. +    case PPPIOCGNPMODE:
  37695. +    case PPPIOCSNPMODE:
  37696. +        error = verify_area (VERIFY_READ, (void *) param3,
  37697. +                    sizeof (struct npioctl));
  37698. +        if (error == 0) {
  37699. +            struct npioctl npi;
  37700. +            memcpy_fromfs (&npi,
  37701. +                       (void *) param3,
  37702. +                       sizeof (npi));
  37703. +
  37704. +            switch (npi.protocol) {
  37705. +            case PPP_IP:
  37706. +                npi.protocol = NP_IP;
  37707. +                break;
  37708. +            default:
  37709. +                error = -EINVAL;
  37710. +            }
  37711. +
  37712. +            if (error != 0)
  37713. +                break;
  37714. +
  37715. +            if (param2 == PPPIOCGNPMODE) {
  37716. +                npi.mode = ppp->sc_npmode[npi.protocol];
  37717. +                error = verify_area (VERIFY_WRITE,
  37718. +                             (void *) param3,
  37719. +                             sizeof (npi));
  37720. +                if (error != 0)
  37721. +                    break;
  37722. +
  37723. +                memcpy_tofs ((void *) param3,
  37724. +                         &npi,
  37725. +                         sizeof (npi));
  37726. +                break;
  37727. +            }
  37728. +
  37729. +            if (npi.mode != ppp->sc_npmode[npi.protocol]) {
  37730. +                ppp->sc_npmode[npi.protocol] = npi.mode;
  37731. +                if (npi.mode != NPMODE_QUEUE) {
  37732. +                    /* ppp_requeue(ppp); maybe needed */
  37733. +                    ppp_tty_wakeup (ppp2tty(ppp));
  37734. +                }
  37735. +            }
  37736. +        }
  37737. +        break;
  37738. +/*
  37739. + * Allow users to read, but not set, the serial port parameters
  37740. + */
  37741. +    case TCGETS:
  37742. +    case TCGETA:
  37743. +        error = n_tty_ioctl (tty, file, param2, param3);
  37744. +        break;
  37745. +
  37746. +    case FIONREAD:
  37747. +        error = verify_area (VERIFY_WRITE,
  37748. +                     (void *) param3,
  37749. +                     sizeof (int));
  37750. +        if (error == 0) {
  37751. +            int count = ppp->ubuf->tail - ppp->ubuf->head;
  37752. +            if (count < 0)
  37753. +                count += (ppp->ubuf->size + 1);
  37754. +
  37755. +            put_user (count, (int *) param3);
  37756. +        }
  37757. +        break;
  37758. +/*
  37759. + *  All other ioctl() events will come here.
  37760. + */
  37761. +    default:
  37762. +        if (ppp->flags & SC_DEBUG)
  37763. +            printk (KERN_ERR
  37764. +                "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n",
  37765. +                param2,
  37766. +                param3);
  37767. +
  37768. +        error = -ENOIOCTLCMD;
  37769. +        break;
  37770. +    }
  37771. +    return error;
  37772. +}
  37773. +
  37774. +/*
  37775. + * TTY callback.
  37776. + *
  37777. + * Process the select() statement for the PPP device.
  37778. + */
  37779. +
  37780. +static int
  37781. +ppp_tty_select (struct tty_struct *tty, struct inode *inode,
  37782. +        struct file *filp, int sel_type, select_table * wait)
  37783. +{
  37784. +    struct ppp *ppp = tty2ppp (tty);
  37785. +    int result = 1;
  37786. +/*
  37787. + * Verify the status of the PPP device.
  37788. + */
  37789. +    if (!ppp)
  37790. +        return -EBADF;
  37791. +
  37792. +    if (ppp->magic != PPP_MAGIC)
  37793. +        return -EBADF;
  37794. +
  37795. +    CHECK_PPP (0);
  37796. +/*
  37797. + * Branch on the type of select mode. A read request must lock the user
  37798. + * buffer area.
  37799. + */
  37800. +    switch (sel_type) {
  37801. +    case SEL_IN:
  37802. +        if (set_bit (0, &ppp->ubuf->locked) == 0) {
  37803. +            /* Test for the presence of data in the queue */
  37804. +            if (ppp->ubuf->head != ppp->ubuf->tail) {
  37805. +                clear_bit (0, &ppp->ubuf->locked);
  37806. +                break;
  37807. +            }
  37808. +            clear_bit (0, &ppp->ubuf->locked);
  37809. +        }        /* fall through */
  37810. +        /*
  37811. + * Exceptions or read errors.
  37812. + */
  37813. +    case SEL_EX:
  37814. +        /* Is this a pty link and the remote disconnected? */
  37815. +        if (tty->flags & (1 << TTY_OTHER_CLOSED))
  37816. +            break;
  37817. +
  37818. +        /* Is this a local link and the modem disconnected? */
  37819. +        if (tty_hung_up_p (filp))
  37820. +            break;
  37821. +
  37822. +        select_wait (&ppp->read_wait, wait);
  37823. +        result = 0;
  37824. +        break;
  37825. +/*
  37826. + * Write mode. A write is allowed if there is no current transmission.
  37827. + */
  37828. +    case SEL_OUT:
  37829. +        if (ppp->tbuf->locked != 0) {
  37830. +            select_wait (&ppp->write_wait, wait);
  37831. +            result = 0;
  37832. +        }
  37833. +        break;
  37834. +    }
  37835. +    return result;
  37836. +}
  37837. +
  37838. +/*************************************************************
  37839. + * NETWORK OUTPUT
  37840. + *    This routine accepts requests from the network layer
  37841. + *    and attempts to deliver the packets.
  37842. + *    It also includes various routines we are compelled to
  37843. + *    have to make the network layer work (arp, etc...).
  37844. + *************************************************************/
  37845. +
  37846. +/*
  37847. + * Callback from the network layer when the device goes up.
  37848. + */
  37849. +
  37850. +static int
  37851. +ppp_dev_open (struct device *dev)
  37852. +{
  37853. +    struct ppp *ppp = dev2ppp (dev);
  37854. +
  37855. +    /* reset POINTOPOINT every time, since dev_close zaps it! */
  37856. +    dev->flags |= IFF_POINTOPOINT;
  37857. +
  37858. +    if (ppp2tty (ppp) == NULL) {
  37859. +        if (ppp->flags & SC_DEBUG)
  37860. +            printk (KERN_ERR
  37861. +            "ppp: %s not connected to a TTY! can't go open!\n",
  37862. +            dev->name);
  37863. +        return -ENXIO;
  37864. +    }
  37865. +
  37866. +    if (ppp->flags & SC_DEBUG)
  37867. +        printk (KERN_INFO
  37868. +            "ppp: channel %s going up for IP packets!\n",
  37869. +            dev->name);
  37870. +
  37871. +    CHECK_PPP (-ENXIO);
  37872. +    return 0;
  37873. +}
  37874. +
  37875. +/*
  37876. + * Callback from the network layer when the ppp device goes down.
  37877. + */
  37878. +
  37879. +static int
  37880. +ppp_dev_close (struct device *dev)
  37881. +{
  37882. +    struct ppp *ppp = dev2ppp (dev);
  37883. +
  37884. +    if (ppp2tty (ppp) == NULL) {
  37885. +        if (ppp->flags & SC_DEBUG)
  37886. +            printk (KERN_ERR
  37887. +            "ppp: %s not connected to a TTY! can't go down!\n",
  37888. +            dev->name);
  37889. +        return -ENXIO;
  37890. +    }
  37891. +/*
  37892. + * We don't do anything about the device going down. It is not important
  37893. + * for us.
  37894. + */
  37895. +    if (ppp->flags & SC_DEBUG)
  37896. +        printk (KERN_INFO
  37897. +            "ppp: channel %s going down for IP packets!\n",
  37898. +            dev->name);
  37899. +    CHECK_PPP (-ENXIO);
  37900. +    return 0;
  37901. +}
  37902. +
  37903. +/*
  37904. + * IOCTL operation to read the version of the driver.
  37905. + */
  37906. +
  37907. +static int
  37908. +ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr)
  37909. +{
  37910. +        int error;
  37911. +    int len;
  37912. +    char *result;
  37913. +/*
  37914. + * Must have write access to the buffer.
  37915. + */
  37916. +    result = (char *) ifr->ifr_ifru.ifru_data;
  37917. +    len    = strlen (szVersion) + 1;
  37918. +    error  = verify_area (VERIFY_WRITE, result, len);
  37919. +/*
  37920. + * Move the version data
  37921. + */
  37922. +    if (error == 0)
  37923. +        memcpy_tofs (result, szVersion, len);
  37924. +
  37925. +    return error;
  37926. +}
  37927. +
  37928. +/*
  37929. + * IOCTL to read the statistics for the pppstats program.
  37930. + */
  37931. +
  37932. +static int
  37933. +ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
  37934. +{
  37935. +    struct ppp_stats *result, temp;
  37936. +    int    error;
  37937. +/*
  37938. + * Must have write access to the buffer.
  37939. + */
  37940. +    result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
  37941. +    error = verify_area (VERIFY_WRITE,
  37942. +                 result,
  37943. +                 sizeof (temp));
  37944. +/*
  37945. + * Supply the information for the caller. First move the version data
  37946. + * then move the ppp stats; and finally the vj stats.
  37947. + */
  37948. +    memset (&temp, 0, sizeof(temp));
  37949. +    if (error == 0 && dev->flags & IFF_UP) {
  37950. +        memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
  37951. +        if (ppp->slcomp != NULL) {
  37952. +            temp.vj.vjs_packets    = ppp->slcomp->sls_o_compressed+
  37953. +                         ppp->slcomp->sls_o_uncompressed;
  37954. +            temp.vj.vjs_compressed = ppp->slcomp->sls_o_compressed;
  37955. +            temp.vj.vjs_searches   = ppp->slcomp->sls_o_searches;
  37956. +            temp.vj.vjs_misses     = ppp->slcomp->sls_o_misses;
  37957. +            temp.vj.vjs_errorin    = ppp->slcomp->sls_i_error;
  37958. +            temp.vj.vjs_tossed     = ppp->slcomp->sls_i_tossed;
  37959. +            temp.vj.vjs_uncompressedin = ppp->slcomp->sls_i_uncompressed;
  37960. +            temp.vj.vjs_compressedin   = ppp->slcomp->sls_i_compressed;
  37961. +        }
  37962. +    }
  37963. +
  37964. +    if (error == 0)
  37965. +        memcpy_tofs (result, &temp, sizeof (temp));
  37966. +    return error;
  37967. +}
  37968. +
  37969. +/*
  37970. + * IOCTL to read the compression statistics for the pppstats program.
  37971. + */
  37972. +
  37973. +static int
  37974. +ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
  37975. +{
  37976. +    struct ppp_comp_stats *result, temp;
  37977. +    int    error;
  37978. +/*
  37979. + * Must have write access to the buffer.
  37980. + */
  37981. +    result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
  37982. +    error = verify_area (VERIFY_WRITE,
  37983. +                 result,
  37984. +                 sizeof (temp));
  37985. +/*
  37986. + * Supply the information for the caller.
  37987. + */
  37988. +    memset (&temp, 0, sizeof(temp));
  37989. +    if (error == 0 && dev->flags & IFF_UP) {
  37990. +        if (ppp->sc_xc_state != NULL)
  37991. +            (*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state,
  37992. +                             &temp.c);
  37993. +
  37994. +        if (ppp->sc_rc_state != NULL)
  37995. +            (*ppp->sc_rcomp->decomp_stat) (ppp->sc_rc_state,
  37996. +                               &temp.d);
  37997. +    }
  37998. +/*
  37999. + * Move the data to the caller's buffer
  38000. + */
  38001. +    if (error == 0)
  38002. +        memcpy_tofs (result, &temp, sizeof (temp));
  38003. +    return error;
  38004. +}
  38005. +
  38006. +/*
  38007. + * Callback from the network layer to process the sockioctl functions.
  38008. + */
  38009. +
  38010. +static int
  38011. +ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
  38012. +{
  38013. +    struct ppp *ppp = dev2ppp (dev);
  38014. +    int error;
  38015. +/*
  38016. + * Process the requests
  38017. + */
  38018. +    switch (cmd) {
  38019. +    case SIOCGPPPSTATS:
  38020. +        error = ppp_dev_ioctl_stats (ppp, ifr, dev);
  38021. +        break;
  38022. +
  38023. +    case SIOCGPPPCSTATS:
  38024. +        error = ppp_dev_ioctl_comp_stats (ppp, ifr, dev);
  38025. +        break;
  38026. +
  38027. +    case SIOCGPPPVER:
  38028. +        error = ppp_dev_ioctl_version (ppp, ifr);
  38029. +        break;
  38030. +
  38031. +    default:
  38032. +        error = -EINVAL;
  38033. +        break;
  38034. +    }
  38035. +    return error;
  38036. +}
  38037. +
  38038. +/*
  38039. + * Send an IP frame to the remote with vj header compression.
  38040. + *
  38041. + * Return 0 if frame was queued for transmission.
  38042. + *        1 if frame must be re-queued for later driver support.
  38043. + */
  38044. +
  38045. +static int
  38046. +ppp_dev_xmit_ip (