home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 4 / DATAFILE_PDCD4.iso / unix / armlinux / cross_comp / LINUXARM_1 / linux.diff
Encoding:
Text File  |  1995-10-27  |  2.2 MB  |  83,914 lines

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. diff -r -u -N linux.orig/.bash_history linux.arm/.bash_history
  2. --- linux.orig/.bash_history    Thu Jan  1 01:00:00 1970
  3. +++ linux.arm/.bash_history    Fri Oct 27 23:16:06 1995
  4. @@ -0,0 +1,271 @@
  5. +dir
  6. +cd mm
  7. +ue swap.c
  8. +cp ~root/.emacsrc ~
  9. +ue swap.c
  10. +ue swap.c
  11. +ue memory.c
  12. +less ../include/asm/pgtable.h 
  13. +ue /etc/shutdown.allow 
  14. +dir
  15. +cd mm
  16. +ue swap.c
  17. +ue memory.c
  18. +ue swap.c
  19. +objdump --disassemble swap.o
  20. +objdump --disassemble swap.o | less
  21. +dir
  22. +ue swap.c
  23. +make
  24. +cd ../
  25. +make
  26. +cd mm
  27. +ue swap.c
  28. +ue Makefile
  29. +ue swap.c
  30. +cd ..
  31. +make
  32. +shutdown -t3 -rf now ; logout
  33. +nohup shutdown -r3 -rf now &; logout
  34. +nohup shutdown -r3 -rf now & ; logout
  35. +shutdown -r3 -rf now ; logout
  36. +cd mm
  37. +objdump --disassemble swap.o | less
  38. +ue swap.c
  39. +mcd ..
  40. +cd ..
  41. +make
  42. +ue mm/swap.c
  43. +make
  44. +/sbin/bootmap /dev/hda1
  45. +sync
  46. +cd /etc
  47. +mv rc rc.old
  48. +cd /sbin
  49. +mv init init.old
  50. +init.old R
  51. +sync
  52. +ue /etc/rc.d/rc.M
  53. +HOME=/root
  54. +cd arch/arm/drivers/scsi
  55. +dir
  56. +diff NCR5380.c ~lin/drivers/scsi/NCR5380.c
  57. +diff --help
  58. +diff NCR5380.c ~lin/drivers/scsi/NCR5380.c -bw
  59. +rm NCR5380.c
  60. +ln -s ../../../../drivers/scsi/NCR5380.c .
  61. +ue ecoscsi.c
  62. +rm NCR5380.h
  63. +ln -s ../../../../drivers/scsi/NCR5380.h .
  64. +rm ecoscsi.o
  65. +ue ecoscsi.c
  66. +make
  67. +make ecoscsi.o
  68. +dir
  69. +ue oak.c
  70. +ue cumana_1.c
  71. +ue oak.c
  72. +ue cumana_1.c
  73. +ue ecoscsi.c
  74. +ue ecoscsi.c
  75. +ue oak.c
  76. +ue cumana_1.c
  77. +ifconfig
  78. +/sbin/ifconfig
  79. +/sbin/ifconfig
  80. +/sbin/ifconfig
  81. +/sbin/ifconfig
  82. +/sbin/ifconfig
  83. +/sbin/ifconfig
  84. +/sbin/ifconfig
  85. +/sbin/ifconfig
  86. +/sbin/ifconfig
  87. +/sbin/ifconfig
  88. +/sbin/ifconfig
  89. +/sbin/ifconfig
  90. +/sbin/ifconfig
  91. +/sbin/ifconfig
  92. +/sbin/ifconfig
  93. +/sbin/ifconfig
  94. +/sbin/ifconfig
  95. +/sbin/ifconfig
  96. +/sbin/ifconfig
  97. +/sbin/ifconfig
  98. +/sbin/ifconfig
  99. +/sbin/ifconfig
  100. +/sbin/ifconfig
  101. +/sbin/ifconfig
  102. +/sbin/ifconfig
  103. +/sbin/ifconfig
  104. +/sbin/ifconfig
  105. +/sbin/ifconfig
  106. +/sbin/ifconfig
  107. +/sbin/ifconfig
  108. +/sbin/ifconfig
  109. +/sbin/ifconfig
  110. +/sbin/ifconfig
  111. +/sbin/ifconfig
  112. +/sbin/ifconfig
  113. +/sbin/ifconfig
  114. +/sbin/ifconfig
  115. +/sbin/ifconfig
  116. +ifconfig eth0 promisc
  117. +/sbin/ifconfig
  118. +/sbin/ifconfig eth0 promisc
  119. +/sbin/ifconfig
  120. +/sbin/ifconfig
  121. +/sbin/ifconfig
  122. +/sbin/ifconfig
  123. +/sbin/ifconfig
  124. +man tcpdump
  125. +/sbin/ifconfig
  126. +/sbin/ifconfig
  127. +/sbin/ifconfig
  128. +man tcpdump
  129. +/sbin/ifconfig
  130. +/sbin/ifconfig
  131. +fdir
  132. +dir
  133. +make -n
  134. +ue cumana_1.c
  135. +less ../podules/scsi.c 
  136. +less ../podules/podlist.c 
  137. +%1
  138. +%2
  139. +%3
  140. +%2
  141. +less ../podules/podlist.c 
  142. +jobs
  143. +%3
  144. +jobs
  145. +ue cumana_1.c
  146. +less ../podules/scsi.c 
  147. +%2
  148. +grep scsi_mem_init *.c
  149. +grep scsi_mem_init ~lin/drivers/scsi/*.c
  150. +diff hosts.c ~lin/drivers/scsi/hosts.c -bw | less
  151. +pwd
  152. +mv hosts.c hosts.c.old
  153. +cp ~lin/drivers/scsi/hosts.c .
  154. +ue hosts.c
  155. +cd ../../../..
  156. +cd arch/arm/drivers/scsi/
  157. +ue hosts.c
  158. +nm hosts.o | grep *UND* | less
  159. +nm hosts.o
  160. +ue hosts.c
  161. +nm hosts.o
  162. +dir
  163. +less hosts.c
  164. +dir
  165. +cd ../..
  166. +ue Makefile 
  167. +cd ../../init
  168. +less init.c
  169. +less main.c
  170. +rm main.o
  171. +cd ..
  172. +cd /
  173. +dir
  174. +dir boot
  175. +dir
  176. +dir etc
  177. +dir
  178. +dir home
  179. +dir home/arm
  180. +dir home/arm/a
  181. +dir home/arm/1
  182. +dir home/arm/1/users/
  183. +dir /root
  184. +rm -f /root/project
  185. +rm -rf /root/project
  186. +df
  187. +dir /root
  188. +rm /root/checklinux 
  189. +df
  190. +dir
  191. +dir sbin
  192. +rm /sbin/connect.cua2
  193. +dir /bin
  194. +cd /bin
  195. +rm sh
  196. +ln -s bash sh
  197. +dir
  198. +chgrp bin bash bashbug csh 
  199. +dir
  200. +cd ..
  201. +df
  202. +cd ../ld.so/
  203. +dir
  204. +less fixups.c
  205. +less ld.so.c
  206. +%1
  207. +less fixups.h
  208. +%1
  209. +jobs
  210. +%1
  211. +%2
  212. +cd arch/arm/drivers/scsi
  213. +HOME=~root
  214. +ue acornscsi.c
  215. +less oak.h
  216. +less acornscsi.h
  217. +%1
  218. +%1
  219. +ue acornscsi.c
  220. +less oak.c
  221. +%1
  222. +ue acornscsi.c
  223. +ps -aux
  224. +%1
  225. +less acornscsi.h
  226. +less scsi.h
  227. +less hosts.c
  228. +less hosts.h
  229. +%1
  230. +less acornscsi.h
  231. +%1
  232. +%2
  233. +less hosts.h
  234. +ue acornscsi.h
  235. +%1
  236. +jobs
  237. +%2
  238. +ue acornscsi.c
  239. +ps -aux
  240. +kill -9 459
  241. + kill -TERM 459
  242. +ps -aux
  243. +kill -KILL 459
  244. +ps -aux
  245. +kill -SEGV 459
  246. +kill -ILL 459
  247. +kill -PWR 459
  248. +kill -l
  249. +kill -BUS 459
  250. +kill -IO 459
  251. +kill -FPE 459
  252. +kill -IOT 459
  253. +ps -aux
  254. +ps -aux
  255. +cat /proc/devices 
  256. +ue acornscsi.c
  257. +mount -w -o remount ~lin
  258. +ue acornscsi.c
  259. +source ~root/.bashrc
  260. +cd arch/arm/drivers/block
  261. +ue blk.h
  262. +cp ~root/.bashrc ./bashrc
  263. +mount -w -o remount .
  264. +cp ~root/.bashrc ./bashrc
  265. +source ~/.bashrc
  266. +pwd
  267. +cp ~root/.bashrc ./.bashrc
  268. +rm bashrc 
  269. +source ~/.bashrc
  270. +cd arch/arm/drivers/block/
  271. +ue mfmhd.c
  272. +../cdplay
  273. +cd arch/arm/drivers/block/
  274. +dir
  275. +ue mfmhd.c
  276. diff -r -u -N linux.orig/.bashrc linux.arm/.bashrc
  277. --- linux.orig/.bashrc    Thu Jan  1 01:00:00 1970
  278. +++ linux.arm/.bashrc    Fri Oct 27 23:16:06 1995
  279. @@ -0,0 +1,4 @@
  280. +PATH=/sbin:/usr/sbin:$PATH
  281. +PS1="\u@\h:[\W]:<\!> "
  282. +alias rm='rm -i'
  283. +
  284. diff -r -u -N linux.orig/.config linux.arm/.config
  285. --- linux.orig/.config    Fri Oct 27 23:09:26 1995
  286. +++ linux.arm/.config    Fri Oct 27 23:16:04 1995
  287. @@ -1,27 +1,26 @@
  288.  #
  289.  # Automatically generated make config: don't edit
  290.  #
  291. +CONFIG_ARM=1
  292. +CONFIG_ARMMOUSE=1
  293.  
  294.  #
  295.  # General setup
  296.  #
  297. -# CONFIG_MATH_EMULATION is not set
  298. +CONFIG_PAGE_32K=y
  299. +CONFIG_MATH_EMULATION=y
  300.  CONFIG_BLK_DEV_FD=y
  301.  CONFIG_ST506=y
  302.  
  303.  #
  304.  # Please see drivers/block/README.ide for help/info on IDE drives
  305.  #
  306. -# CONFIG_BLK_DEV_HD is not set
  307. -CONFIG_BLK_DEV_IDE=y
  308. -# CONFIG_BLK_DEV_IDECD is not set
  309. +CONFIG_BLK_DEV_HD=y
  310. +# CONFIG_BLK_DEV_IDE is not set
  311.  # CONFIG_BLK_DEV_XD is not set
  312.  CONFIG_NET=y
  313.  # CONFIG_MAX_16M is not set
  314. -# CONFIG_PCI is not set
  315.  CONFIG_SYSVIPC=y
  316. -CONFIG_BINFMT_ELF=y
  317. -CONFIG_M486=y
  318.  
  319.  #
  320.  # Loadable module support
  321. @@ -32,8 +31,8 @@
  322.  # Networking options
  323.  #
  324.  CONFIG_INET=y
  325. -# CONFIG_IP_FORWARD is not set
  326. -# CONFIG_IP_MULTICAST is not set
  327. +CONFIG_IP_FORWARD=y
  328. +CONFIG_IP_MULTICAST=y
  329.  # CONFIG_IP_FIREWALL is not set
  330.  # CONFIG_IP_ACCT is not set
  331.  
  332. @@ -49,44 +48,37 @@
  333.  #
  334.  # SCSI support
  335.  #
  336. -# CONFIG_SCSI is not set
  337. +CONFIG_SCSI=y
  338.  
  339.  #
  340. -# Skipping SCSI configuration options...
  341. +# SCSI support type (disk, tape, CDrom)
  342.  #
  343. +CONFIG_BLK_DEV_SD=y
  344. +# CONFIG_CHR_DEV_ST is not set
  345. +CONFIG_BLK_DEV_SR=y
  346. +# CONFIG_CHR_DEV_SG is not set
  347. +
  348. +#
  349. +# SCSI low-level drivers
  350. +#
  351. +CONFIG_SCSI_ACORNSCSI_3=y
  352. +# CONFIG_SCSI_CUMANA_1 is not set
  353. +# CONFIG_SCSI_ECOSCSI is not set
  354. +# CONFIG_SCSI_OAK is not set
  355. +# CONFIG_SCSI_DEBUG is not set
  356.  
  357.  #
  358.  # Network device support
  359.  #
  360.  CONFIG_NETDEVICES=y
  361.  CONFIG_DUMMY=y
  362. -# CONFIG_SLIP is not set
  363. +CONFIG_SLIP=y
  364. +CONFIG_SLIP_COMPRESSED=y
  365. +# SL_SLIP_LOTS is not set
  366. +# SL_DUMP is not set
  367.  # CONFIG_PPP is not set
  368.  # CONFIG_PLIP is not set
  369. -# CONFIG_NET_ALPHA is not set
  370. -# CONFIG_NET_VENDOR_SMC is not set
  371. -# CONFIG_LANCE is not set
  372. -# CONFIG_NET_VENDOR_3COM is not set
  373. -CONFIG_NET_ISA=y
  374. -# CONFIG_E2100 is not set
  375. -# CONFIG_DEPCA is not set
  376. -# CONFIG_EWRK3 is not set
  377. -# CONFIG_HPLAN_PLUS is not set
  378. -# CONFIG_HPLAN is not set
  379. -CONFIG_NE2000=y
  380. -# CONFIG_SK_G16 is not set
  381. -# CONFIG_NET_EISA is not set
  382. -# CONFIG_NET_POCKET is not set
  383. -
  384. -#
  385. -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
  386. -#
  387. -# CONFIG_CDU31A is not set
  388. -# CONFIG_MCD is not set
  389. -CONFIG_SBPCD=y
  390. -# CONFIG_SBPCD2 is not set
  391. -# CONFIG_AZTCD is not set
  392. -# CONFIG_CDU535 is not set
  393. +CONFIG_ETHER3=y
  394.  
  395.  #
  396.  # Filesystems
  397. @@ -100,28 +92,19 @@
  398.  CONFIG_PROC_FS=y
  399.  CONFIG_NFS_FS=y
  400.  CONFIG_ISO9660_FS=y
  401. -# CONFIG_HPFS_FS is not set
  402. -# CONFIG_SYSV_FS is not set
  403.  
  404.  #
  405.  # character devices
  406.  #
  407. -# CONFIG_CYCLADES is not set
  408.  CONFIG_PRINTER=y
  409. -CONFIG_BUSMOUSE=y
  410. -# CONFIG_PSMOUSE is not set
  411. -# CONFIG_MS_BUSMOUSE is not set
  412. -# CONFIG_ATIXL_BUSMOUSE is not set
  413. -# CONFIG_QIC02_TAPE is not set
  414. -CONFIG_FTAPE=y
  415. -NR_FTAPE_BUFFERS=3
  416.  
  417.  #
  418.  # Sound
  419.  #
  420. -# CONFIG_SOUND is not set
  421. +CONFIG_SOUND=y
  422.  
  423.  #
  424.  # Kernel hacking
  425.  #
  426.  # CONFIG_PROFILE is not set
  427. +CONFIG_SCSI_CONSTANTS=y
  428. diff -r -u -N linux.orig/.config.old linux.arm/.config.old
  429. --- linux.orig/.config.old    Fri Oct 27 23:09:26 1995
  430. +++ linux.arm/.config.old    Fri Oct 27 23:16:05 1995
  431. @@ -1,27 +1,27 @@
  432.  #
  433.  # Automatically generated make config: don't edit
  434.  #
  435. +CONFIG_ARM=1
  436. +CONFIG_ARMMOUSE=1
  437.  
  438.  #
  439.  # General setup
  440.  #
  441. -# CONFIG_MATH_EMULATION is not set
  442. +CONFIG_PAGE_32K=y
  443. +CONFIG_MATH_EMULATION=y
  444.  CONFIG_BLK_DEV_FD=y
  445.  CONFIG_ST506=y
  446.  
  447.  #
  448.  # Please see drivers/block/README.ide for help/info on IDE drives
  449.  #
  450. -# CONFIG_BLK_DEV_HD is not set
  451. -CONFIG_BLK_DEV_IDE=y
  452. -# CONFIG_BLK_DEV_IDECD is not set
  453. +CONFIG_BLK_DEV_HD=y
  454. +# CONFIG_BLK_DEV_IDE is not set
  455.  # CONFIG_BLK_DEV_XD is not set
  456.  CONFIG_NET=y
  457.  # CONFIG_MAX_16M is not set
  458. -# CONFIG_PCI is not set
  459.  CONFIG_SYSVIPC=y
  460. -CONFIG_BINFMT_ELF=y
  461. -CONFIG_M486=y
  462. +# CONFIG_BINFMT_ELF is not set
  463.  
  464.  #
  465.  # Loadable module support
  466. @@ -32,8 +32,8 @@
  467.  # Networking options
  468.  #
  469.  CONFIG_INET=y
  470. -# CONFIG_IP_FORWARD is not set
  471. -# CONFIG_IP_MULTICAST is not set
  472. +CONFIG_IP_FORWARD=y
  473. +CONFIG_IP_MULTICAST=y
  474.  # CONFIG_IP_FIREWALL is not set
  475.  # CONFIG_IP_ACCT is not set
  476.  
  477. @@ -49,43 +49,36 @@
  478.  #
  479.  # SCSI support
  480.  #
  481. -# CONFIG_SCSI is not set
  482. +CONFIG_SCSI=y
  483.  
  484.  #
  485. -# Skipping SCSI configuration options...
  486. +# SCSI support type (disk, tape, CDrom)
  487.  #
  488. +CONFIG_BLK_DEV_SD=y
  489. +# CONFIG_CHR_DEV_ST is not set
  490. +CONFIG_BLK_DEV_SR=y
  491. +# CONFIG_CHR_DEV_SG is not set
  492. +
  493. +#
  494. +# SCSI low-level drivers
  495. +#
  496. +# CONFIG_SCSI_CUMANA_1 is not set
  497. +# CONFIG_SCSI_ECOSCSI is not set
  498. +# CONFIG_SCSI_OAK is not set
  499. +# CONFIG_SCSI_DEBUG is not set
  500.  
  501.  #
  502.  # Network device support
  503.  #
  504.  CONFIG_NETDEVICES=y
  505.  CONFIG_DUMMY=y
  506. -# CONFIG_SLIP is not set
  507. +CONFIG_SLIP=y
  508. +CONFIG_SLIP_COMPRESSED=y
  509. +# SL_SLIP_LOTS is not set
  510. +# SL_DUMP is not set
  511.  # CONFIG_PPP is not set
  512.  # CONFIG_PLIP is not set
  513. -# CONFIG_NET_ALPHA is not set
  514. -# CONFIG_NET_VENDOR_SMC is not set
  515. -# CONFIG_LANCE is not set
  516. -# CONFIG_NET_VENDOR_3COM is not set
  517. -CONFIG_NET_ISA=y
  518. -# CONFIG_E2100 is not set
  519. -# CONFIG_DEPCA is not set
  520. -# CONFIG_EWRK3 is not set
  521. -# CONFIG_HPLAN_PLUS is not set
  522. -# CONFIG_HPLAN is not set
  523. -CONFIG_NE2000=y
  524. -# CONFIG_SK_G16 is not set
  525. -# CONFIG_NET_EISA is not set
  526. -# CONFIG_NET_POCKET is not set
  527. -
  528. -#
  529. -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
  530. -#
  531. -# CONFIG_CDU31A is not set
  532. -# CONFIG_MCD is not set
  533. -# CONFIG_SBPCD is not set
  534. -# CONFIG_AZTCD is not set
  535. -# CONFIG_CDU535 is not set
  536. +CONFIG_ETHER3=y
  537.  
  538.  #
  539.  # Filesystems
  540. @@ -99,28 +92,19 @@
  541.  CONFIG_PROC_FS=y
  542.  CONFIG_NFS_FS=y
  543.  CONFIG_ISO9660_FS=y
  544. -# CONFIG_HPFS_FS is not set
  545. -# CONFIG_SYSV_FS is not set
  546.  
  547.  #
  548.  # character devices
  549.  #
  550. -# CONFIG_CYCLADES is not set
  551.  CONFIG_PRINTER=y
  552. -CONFIG_BUSMOUSE=y
  553. -# CONFIG_PSMOUSE is not set
  554. -# CONFIG_MS_BUSMOUSE is not set
  555. -# CONFIG_ATIXL_BUSMOUSE is not set
  556. -# CONFIG_QIC02_TAPE is not set
  557. -CONFIG_FTAPE=y
  558. -NR_FTAPE_BUFFERS=3
  559.  
  560.  #
  561.  # Sound
  562.  #
  563. -# CONFIG_SOUND is not set
  564. +CONFIG_SOUND=y
  565.  
  566.  #
  567.  # Kernel hacking
  568.  #
  569.  # CONFIG_PROFILE is not set
  570. +CONFIG_SCSI_CONSTANTS=y
  571. diff -r -u -N linux.orig/.emacsrc linux.arm/.emacsrc
  572. --- linux.orig/.emacsrc    Thu Jan  1 01:00:00 1970
  573. +++ linux.arm/.emacsrc    Fri Oct 27 23:16:06 1995
  574. @@ -0,0 +1,259 @@
  575. +;    EMACS.RC:    Standard MicroEMACS Startup program
  576. +;            for MicroEMACS 3.12 and above
  577. +;            (C)opyright 1987,92 by Daniel M Lawrence
  578. +;            Last Update: 12/28/92
  579. +
  580. +set $discmd FALSE
  581. +write-message "[Setting up....]"
  582. +
  583. +; If you screen "SNOWS", comment this line
  584. +    set $flicker "FALSE"
  585. +
  586. +; To use an IBM-PC EGA card, uncomment the following line
  587. +;    set $sres "EGA"
  588. +
  589. +;    If you hate clocks or position counters, comment these
  590. +set $timeflag TRUE
  591. +set $posflag TRUE
  592. +
  593. +;    Set Default Global modes
  594. +
  595. +add-global-mode "blue"
  596. +add-global-mode "WHITE"
  597. +;bind-to-key meta-prefix `    ;for annoying keyboards with ` at the top left
  598. +
  599. +;    Toggle function key window display
  600. +
  601. +store-procedure toggle-fkeys
  602. +    !if %rcfkeys
  603. +        !goto rcfoff
  604. +    !endif
  605. +
  606. +;    toggle function key window on
  607. +    save-window
  608. +    1 next-window
  609. +    !if &sequal $cbufname "emacs.hlp"
  610. +        delete-window
  611. +    !endif
  612. +    !if ¬ &sequal $cbufname "Function Keys"
  613. +        1 split-current-window
  614. +        1 select-buffer "Function Keys"
  615. +        add-mode "red"
  616. +        !force 5 resize-window
  617. +        1 goto-line
  618. +    !endif
  619. +    set %rcfkeys TRUE
  620. +    !force restore-window
  621. +    !if &sequal $cbufname "Function Keys"
  622. +        next-window
  623. +    !endif
  624. +    write-message "[Function key window ON]"
  625. +    !return
  626. +
  627. +    ;Toggle the function key window off
  628. +*rcfoff
  629. +    save-window
  630. +    1 next-window
  631. +    !if &sequal "Function Keys" $cbufname
  632. +        delete-window
  633. +    !endif
  634. +    !force restore-window
  635. +    write-message "[Function key window OFF]"
  636. +    set %rcfkeys FALSE
  637. +!endm
  638. +
  639. +;    Bring up Online-help system
  640. +
  641. +store-procedure get-help
  642. +    set $discmd FALSE
  643. +    source ehelp.cmd
  644. +    set $discmd TRUE
  645. +!endm
  646. +
  647. +;    Load a new page
  648. +
  649. +store-procedure get-page-loader
  650. +    !if &seq &find newpage.cmd ""
  651. +        write-message "[Can not find NEWPAGE.CMD]"
  652. +        !return
  653. +    !endif
  654. +    execute-file newpage.cmd
  655. +!endm
  656. +
  657. +;procedure to clean out the current page (which is nothing right now)
  658. +
  659. +store-procedure clean
  660. +    ; nothing by default
  661. +!endm
  662. +
  663. +;    Set up auto CMODE
  664. +
  665. +store-procedure set-default-mode
  666. +    set %rctmp &sin $cfname "."
  667. +    !if &equ %rctmp 0
  668. +        !return
  669. +    !endif
  670. +    set %rctmp &mid $cfname &add %rctmp 1 5
  671. +    !if &or &seq %rctmp "c" &seq %rctmp "h"
  672. +        add-mode "cmode"
  673. +    !endif
  674. +    !if &or &seq %rctmp "cpp" &seq %rctmp "hpp"
  675. +        add-mode "cmode"
  676. +    !endif
  677. +    !if &or &seq %rctmp "mss" &seq %rctmp "txt"
  678. +        add-mode "wrap"
  679. +    !endif
  680. +!endm
  681. +set $readhook set-default-mode
  682. +
  683. +;    This function activates the function key window as
  684. +;    a legitimate place to call up function keys using the mouse
  685. +
  686. +store-procedure mouse-clicks
  687. +
  688. +    ;remember where we started, and do the mouse movement
  689. +    save-window
  690. +    !force mouse-move-down
  691. +
  692. +    ;If not in the function key window... leave
  693. +    !if ¬ &sequal $cbufname "Function Keys"
  694. +        !return
  695. +    !endif
  696. +
  697. +    ;First pos is a screen reposition, let it through
  698. +    !if &and &equ $xpos 0 &equ $ypos 0
  699. +        restore-window
  700. +        !return
  701. +    !endif
  702. +
  703. +    ;Find out what function key were gonna do
  704. +    add-mode magic
  705. +    2 forward-character
  706. +    set %rctmp $search
  707. +    !force search-reverse "[fF][0-9]"
  708. +    !if &seq $status FALSE
  709. +        delete-mode magic
  710. +        set $search %rctmp
  711. +        !return
  712. +    !endif
  713. +
  714. +    ;we are on the "f" or "F".  Get the function key type and number now
  715. +    set $search %rctmp
  716. +    set %fcase lower
  717. +    !if &equ $curchar 70
  718. +        set %fcase upper
  719. +    !endif
  720. +    1 forward-character
  721. +    set %fnum &chr $curchar
  722. +    1 forward-character
  723. +    set %fnum &cat %fnum &chr $curchar
  724. +    set %fnum &add %fnum 0
  725. +    !if &equ %fnum 10
  726. +        set %fnum "0"
  727. +    !endif
  728. +    set %fname &cat "FN" %fnum
  729. +    !if &seq %fcase upper
  730. +        set %fname &cat "S-" %fname
  731. +    !endif
  732. +
  733. +    ;save the function
  734. +    set %rccmd &bind %fname
  735. +    delete-mode MAGIC
  736. +
  737. +    ;swallow the up-button
  738. +    set %rctmp >c
  739. +
  740. +    ;restore the window and exit
  741. +    restore-window
  742. +
  743. +    ;procedures don't need the square brackets
  744. +    !if &seq &left %rccmd 1 "["
  745. +        set %rccmd &mid %rccmd 2 &sub &len %rccmd 2
  746. +        %rccmd
  747. +        !return
  748. +    !endif
  749. +
  750. +    ;and then execute it
  751. +    !force execute-named-command %rccmd
  752. +!endm   
  753. +macro-to-key mouse-clicks MSa
  754. +
  755. +;    ***** Rebind the Function key group
  756. +
  757. +bind-to-key search-forward        FN1
  758. +bind-to-key search-reverse        FN2
  759. +bind-to-key hunt-forward        FN3
  760. +bind-to-key hunt-backward        FN4
  761. +macro-to-key toggle-fkeys        FN5
  762. +macro-to-key get-help            FN6
  763. +bind-to-key next-window         FN7
  764. +macro-to-key get-page-loader        FN8
  765. +bind-to-key save-file            FN9
  766. +bind-to-key exit-emacs            FN0
  767. +
  768. +bind-to-key execute-macro-10        S-FN1
  769. +bind-to-key execute-macro-11        S-FN2
  770. +bind-to-key execute-macro-12        S-FN3
  771. +bind-to-key execute-macro-13        S-FN4
  772. +bind-to-key execute-macro-14        S-FN5
  773. +bind-to-key execute-macro-15        S-FN6
  774. +bind-to-key execute-macro-16        S-FN7
  775. +bind-to-key execute-macro-17        S-FN8
  776. +bind-to-key execute-macro-18        S-FN9
  777. +bind-to-key execute-macro-19        S-FN0
  778. +
  779. +;    bring up the function key window
  780. +
  781. +    1 split-current-window
  782. +    select-buffer "Function Keys"
  783. +    insert-string "f1 search-> f2 <-search Û    MicroEMACS:  Text Editor~n"
  784. +    insert-string "f3 hunt->   f4 <-hunt   Û ~n"
  785. +    insert-string "f5 fkeys    f6 help     Û  Available function key Pages include:~n"
  786. +    insert-string "f7 nxt wind f8 pg[    ] Û    Word  Box  Emacs  Pascal  C  cObol Lisp~n"
  787. +    insert-string "f9 save     f10 exit    Û  [use the f8 key to load Pages]~n"
  788. +    unmark-buffer
  789. +    delete-window
  790. +    set %rcfkeys TRUE
  791. +
  792. +    !if &seq $os "UNIX"
  793. +
  794. +        ;Allow mainframes to simulate function
  795. +        ;keys with ^C<n> and ^C shifted-<n>
  796. +        
  797. +        store-procedure emulate-fkeys
  798. +            !if ¬ $pending
  799. +                write-message "FN-"
  800. +            !endif
  801. +            set %rcchar >key
  802. +            set %rcchar &sindex "1234567890!@#$%^&*()" %rcchar
  803. +            !if &equ %rcchar 0
  804. +                write-message "[Not Bound]"
  805. +                !return
  806. +            !endif
  807. +            clear-message-line
  808. +            set %rctmp "FN"
  809. +            !if &gre %rcchar 10
  810. +                set %rctmp &cat "S-" %rctmp
  811. +            !endif
  812. +            set %rcchar &mid "12345678901234567890" %rcchar 1
  813. +            set %rctmp &bind &cat %rctmp %rcchar
  814. +            !if &seq &lef %rctmp 1 "["
  815. +                set %rctmp &mid %rctmp 2 &sub &len %rctmp 2
  816. +                run %rctmp
  817. +                !return
  818. +            !endif
  819. +            !force execute-named-command %rctmp
  820. +        !endm
  821. +
  822. +        macro-to-key emulate-fkeys ^C
  823. +        
  824. +    !endif
  825. +
  826. +    !if &seq $os "MSWIN"
  827. +        source "mewin.cmd"
  828. +    !else
  829. +        toggle-fkeys
  830. +    !endif
  831. +
  832. +    set $discmd TRUE
  833. +
  834. diff -r -u -N linux.orig/.version linux.arm/.version
  835. --- linux.orig/.version    Fri Oct 27 23:09:26 1995
  836. +++ linux.arm/.version    Fri Oct 27 23:16:05 1995
  837. @@ -1 +1 @@
  838. -4
  839. +0
  840. diff -r -u -N linux.orig/Configure linux.arm/Configure
  841. --- linux.orig/Configure    Fri Oct 27 23:08:06 1995
  842. +++ linux.arm/Configure    Fri Oct 27 23:11:54 1995
  843. @@ -126,8 +126,10 @@
  844.  fi
  845.  . $CONFIG_IN
  846.  
  847. -if [ "$CONFIG_SOUND" = "y" ] ; then
  848. +if [ "$HOSTTYPE" != "arm" ] ; then
  849. +  if [ "$CONFIG_SOUND" = "y" ] ; then
  850.      $MAKE -C drivers/sound config || exit 1
  851. +  fi
  852.  fi
  853.  
  854.  rm -f .config.old
  855. diff -r -u -N linux.orig/Makefile linux.arm/Makefile
  856. --- linux.orig/Makefile    Fri Oct 27 23:08:06 1995
  857. +++ linux.arm/Makefile    Fri Oct 27 23:09:17 1995
  858. @@ -2,7 +2,7 @@
  859.  PATCHLEVEL = 2
  860.  SUBLEVEL = 8
  861.  
  862. -ARCH = i386
  863. +ARCH = arm
  864.  
  865.  .EXPORT_ALL_VARIABLES:
  866.  
  867. @@ -86,11 +86,13 @@
  868.  
  869.  ARCHIVES    =kernel/kernel.o mm/mm.o fs/fs.o net/net.o ipc/ipc.o
  870.  FILESYSTEMS    =fs/filesystems.a
  871. -DRIVERS        =drivers/block/block.a \
  872. -         drivers/char/char.a \
  873. -         drivers/net/net.a
  874. +DRIVERS        =
  875.  LIBS        =$(TOPDIR)/lib/lib.a
  876. -SUBDIRS        =kernel drivers mm fs net ipc lib
  877. +SUBDIRS        =kernel mm fs net ipc lib
  878. +
  879. +DRIVERS := drivers/block/block.a \
  880. +       drivers/char/char.a \
  881. +       drivers/net/net.a
  882.  
  883.  ifdef CONFIG_SCSI
  884.  DRIVERS := $(DRIVERS) drivers/scsi/scsi.a
  885. @@ -125,7 +127,8 @@
  886.          $(FILESYSTEMS) \
  887.          $(DRIVERS) \
  888.          $(LIBS) -o vmlinux
  889. -    $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | sort > System.map
  890. +#    $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | sort > System.map
  891. +    $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)\|\( A \)\|\( t L\)' | sort > System.map
  892.  
  893.  symlinks:
  894.      rm -f include/asm
  895. @@ -198,7 +201,7 @@
  896.  MODV = -DCONFIG_MODVERSIONS
  897.  endif
  898.  
  899. -modules: include/linux/version.h
  900. +modules: include/linux/version.h dummy
  901.      @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i CFLAGS="$(CFLAGS) -DMODULE $(MODV)" modules; done
  902.      
  903.  modules_install:
  904. diff -r -u -N linux.orig/arch/alpha/Makefile linux.arm/arch/alpha/Makefile
  905. --- linux.orig/arch/alpha/Makefile    Fri Oct 27 23:08:07 1995
  906. +++ linux.arm/arch/alpha/Makefile    Fri Oct 27 23:13:50 1995
  907. @@ -15,7 +15,7 @@
  908.  
  909.  HEAD := arch/alpha/kernel/head.o
  910.  
  911. -SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm arch/alpha/lib
  912. +SUBDIRS := drivers $(SUBDIRS) arch/alpha/kernel arch/alpha/mm arch/alpha/lib
  913.  ARCHIVES := arch/alpha/kernel/kernel.o arch/alpha/mm/mm.o $(ARCHIVES)
  914.  LIBS := $(TOPDIR)/arch/alpha/lib/lib.a $(LIBS) $(TOPDIR)/arch/alpha/lib/lib.a
  915.  
  916. diff -r -u -N linux.orig/arch/arm/Makefile linux.arm/arch/arm/Makefile
  917. --- linux.orig/arch/arm/Makefile    Thu Jan  1 01:00:00 1970
  918. +++ linux.arm/arch/arm/Makefile    Fri Oct 27 23:14:02 1995
  919. @@ -0,0 +1,56 @@
  920. +#
  921. +# arch/arm/Makefile
  922. +#
  923. +# This file is included by the global makefile so that you can add your own
  924. +# architecture-specific flags and dependencies. Remember to do have actions
  925. +# for "archclean" and "archdep" for cleaning up and making dependencies for
  926. +# this architecture
  927. +#
  928. +# This file is subject to the terms and conditions of the GNU General Public
  929. +# License.  See the file "COPYING" in the main directory of this archive
  930. +# for more details.
  931. +#
  932. +# Copyright (C) 1995 by Russell King
  933. +#
  934. +
  935. +#
  936. +# Set these to indicate how to link it..
  937. +# -qmagic (we need to remove the 32 byte header for bootup purposes)
  938. +#
  939. +
  940. +ZLINKFLAGS =-N -Ttext 0x01800000
  941. +LINKFLAGS  =-Ttext 0x01800000
  942. +CFLAGS := $(CFLAGS) -fno-omit-frame-pointer
  943. +HEAD := arch/arm/kernel/head.o
  944. +SUBDIRS    := arch/arm/drivers arch/arm/kernel arch/arm/mm arch/arm/lib $(SUBDIRS)
  945. +ARCHIVES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o arch/arm/lib/lib.o $(ARCHIVES)
  946. +LIBS := $(LIBS) `gcc --print-libgcc-file-name`
  947. +
  948. +DRIVERS := arch/arm/drivers/block/block.a arch/arm/drivers/char/char.a \
  949. +           arch/arm/drivers/net/net.a
  950. +
  951. +ifdef CONFIG_SOUND
  952. +DRIVERS := $(DRIVERS) arch/arm/drivers/sound/sound.a
  953. +endif
  954. +
  955. +ifdef CONFIG_SCSI
  956. +DRIVERS := $(DRIVERS) arch/arm/drivers/scsi/scsi.a
  957. +endif
  958. +
  959. +
  960. +arch/arm/kernel: dummy
  961. +    $(MAKE) linuxsubdirs SUBDIRS=arch/arm/kernel
  962. +
  963. +arch/arm/mm: dummy
  964. +    $(MAKE) linuxsubdirs SUBDIRS=arch/arm/mm
  965. +
  966. +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
  967. +
  968. +install: vmlinux
  969. +    @$(MAKEBOOT) install
  970. +
  971. +archclean:
  972. +    @$(MAKEBOOT) clean
  973. +
  974. +archdep:
  975. +    @$(MAKEBOOT) dep
  976. diff -r -u -N linux.orig/arch/arm/boot/Makefile linux.arm/arch/arm/boot/Makefile
  977. --- linux.orig/arch/arm/boot/Makefile    Thu Jan  1 01:00:00 1970
  978. +++ linux.arm/arch/arm/boot/Makefile    Fri Oct 27 23:15:23 1995
  979. @@ -0,0 +1,68 @@
  980. +#
  981. +# arch/i386/boot/Makefile
  982. +#
  983. +# This file is subject to the terms and conditions of the GNU General Public
  984. +# License.  See the file "COPYING" in the main directory of this archive
  985. +# for more details.
  986. +#
  987. +# Copyright (C) 1994 by Linus Torvalds
  988. +#
  989. +
  990. +Image:    $(CONFIGURE) tools/build $(TOPDIR)/vmlinux
  991. +    tools/build $(TOPDIR)/vmlinux > Image
  992. +    sync
  993. +
  994. +install: $(CONFIGURE) Image
  995. +    sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) Image $(TOPDIR)/System.map "$(INSTALL_PATH)"
  996. +
  997. +
  998. +tools/build: tools/build.c
  999. +    $(HOSTCC) $(CFLAGS) -o $@ $< -I$(TOPDIR)/include -static
  1000. +
  1001. +clean:
  1002. +    rm -f Image
  1003. +
  1004. +#zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
  1005. +#    tools/build bootsect setup compressed/vmlinux $(ROOT_DEV) > zImage
  1006. +#    sync
  1007. +
  1008. +#compressed/vmlinux: $(TOPDIR)/vmlinux
  1009. +#    @$(MAKE) -C compressed vmlinux
  1010. +
  1011. +#zdisk: zImage
  1012. +#    dd bs=8192 if=zImage of=/dev/fd0
  1013. +
  1014. +#zlilo: $(CONFIGURE) zImage
  1015. +#    if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
  1016. +#    if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
  1017. +#    cat zImage > $(INSTALL_PATH)/vmlinuz
  1018. +#    cp $(TOPDIR)/System.map $(INSTALL_PATH)/
  1019. +#    if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
  1020. +
  1021. +#install: $(CONFIGURE) zImage
  1022. +#    sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
  1023. +
  1024. +#setup: setup.o
  1025. +#    $(LD86) -s -o $@ $<
  1026. +
  1027. +#setup.o: setup.s
  1028. +#    $(AS86) -o $@ $<
  1029. +
  1030. +#setup.s: setup.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
  1031. +#    $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
  1032. +
  1033. +#bootsect: bootsect.o
  1034. +#    $(LD86) -s -o $@ $<
  1035. +
  1036. +#bootsect.o: bootsect.s
  1037. +#    $(AS86) -o $@ $<
  1038. +
  1039. +#bootsect.s: bootsect.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
  1040. +#    $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
  1041. +
  1042. +dep:
  1043. +
  1044. +#clean:
  1045. +#    rm -f bootsect setup
  1046. +#    rm -f zImage tools/build
  1047. +#    @$(MAKE) -C compressed clean
  1048. diff -r -u -N linux.orig/arch/arm/boot/install.sh linux.arm/arch/arm/boot/install.sh
  1049. --- linux.orig/arch/arm/boot/install.sh    Thu Jan  1 01:00:00 1970
  1050. +++ linux.arm/arch/arm/boot/install.sh    Fri Oct 27 23:15:25 1995
  1051. @@ -0,0 +1,40 @@
  1052. +#!/bin/sh
  1053. +#
  1054. +# arch/i386/boot/install.sh
  1055. +#
  1056. +# This file is subject to the terms and conditions of the GNU General Public
  1057. +# License.  See the file "COPYING" in the main directory of this archive
  1058. +# for more details.
  1059. +#
  1060. +# Copyright (C) 1995 by Linus Torvalds
  1061. +#
  1062. +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
  1063. +#
  1064. +# "make install" script for i386 architecture
  1065. +#
  1066. +# Arguments:
  1067. +#   $1 - kernel version
  1068. +#   $2 - kernel image file
  1069. +#   $3 - kernel map file
  1070. +#   $4 - default install path (blank if root directory)
  1071. +#
  1072. +
  1073. +# User may have a custom install script
  1074. +
  1075. +if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
  1076. +
  1077. +# Default install - same as make zlilo
  1078. +
  1079. +if [ -f $4/vmlinux ]; then
  1080. +    rm $4/vmlinux.$1
  1081. +#    mv $4/vmlinux $4/vmlinux.old
  1082. +fi
  1083. +
  1084. +#if [ -f $4/System.map ]; then
  1085. +#    mv $4/System.map $4/System.old
  1086. +#fi
  1087. +
  1088. +cat $2 > $4/vmlinux.$1
  1089. +#cp $3 $4/System.map
  1090. +
  1091. +if [ -x /sbin/bootmap ]; then /sbin/bootmap /dev/hda1; else echo "You have to install it yourself"; fi
  1092. diff -r -u -N linux.orig/arch/arm/boot/tools/build.c linux.arm/arch/arm/boot/tools/build.c
  1093. --- linux.orig/arch/arm/boot/tools/build.c    Thu Jan  1 01:00:00 1970
  1094. +++ linux.arm/arch/arm/boot/tools/build.c    Fri Oct 27 23:15:25 1995
  1095. @@ -0,0 +1,62 @@
  1096. +#include <stdio.h>
  1097. +#include <stdlib.h>
  1098. +#include <a.out.h>
  1099. +
  1100. +
  1101. +int main(int argc, char **argv)
  1102. +{
  1103. +    void *data;
  1104. +    struct exec ex;
  1105. +    FILE *f, *fo;
  1106. +    int totlen;
  1107. +
  1108. +    if (argc < 2)
  1109. +    {
  1110. +        fprintf(stderr, "Usage: build kernel-name\n");
  1111. +        exit(1);
  1112. +    }
  1113. +
  1114. +    f = fopen(argv[1], "rb");
  1115. +
  1116. +    fread(&ex, 1, sizeof(ex), f);
  1117. +
  1118. +    if(N_MAGIC(ex) == ZMAGIC)
  1119. +    {
  1120. +        fseek(f, 4096, SEEK_SET);
  1121. +        totlen = ex.a_text + ex.a_data + ex.a_bss;
  1122. +    }
  1123. +    else
  1124. +    if(N_MAGIC(ex) == QMAGIC)
  1125. +    {
  1126. +        unsigned long my_header[8];
  1127. +        
  1128. +        fseek(f, 0x20, SEEK_SET);
  1129. +
  1130. +        memset(my_header, 0, 0x20);
  1131. +
  1132. +        my_header[0] = 0xea000006;
  1133. +        
  1134. +        fwrite(my_header, 4, 8, stdout);
  1135. +        
  1136. +        totlen = ex.a_text + ex.a_data + ex.a_bss - 0x20;
  1137. +    }
  1138. +    else
  1139. +    {
  1140. +        fprintf(stderr, "Unacceptable a.out header on kernel\n");
  1141. +        fclose(f);
  1142. +        exit(1);
  1143. +    }
  1144. +
  1145. +    fprintf(stderr, "Kernel is %dk (%dk text, %dk data, %dk bss)\n",
  1146. +        (ex.a_text + ex.a_data + ex.a_bss)/1024,
  1147. +         ex.a_text/1024, ex.a_data/1024, ex.a_bss/1024);
  1148. +
  1149. +    data = malloc(totlen);
  1150. +    fread(data, 1, totlen, f);
  1151. +    fwrite(data, 1, totlen, stdout);
  1152. +
  1153. +    free(data);
  1154. +    fclose(f);
  1155. +    fflush(stdout);
  1156. +    return 0;
  1157. +}
  1158. diff -r -u -N linux.orig/arch/arm/config.in linux.arm/arch/arm/config.in
  1159. --- linux.orig/arch/arm/config.in    Thu Jan  1 01:00:00 1970
  1160. +++ linux.arm/arch/arm/config.in    Fri Oct 27 23:14:02 1995
  1161. @@ -0,0 +1,199 @@
  1162. +#
  1163. +# For a description of the syntax of this configuration file,
  1164. +# see the Configure script.
  1165. +#
  1166. +
  1167. +echo "#define CONFIG_ARM" >> $CONFIG_H
  1168. +echo "#define CONFIG_ARMMOUSE 1" >> $CONFIG_H
  1169. +echo "CONFIG_ARM=1" >> $CONFIG
  1170. +echo "CONFIG_ARMMOUSE=1" >> $CONFIG
  1171. +
  1172. +comment 'General setup'
  1173. +
  1174. +bool 'Page size as 32K' CONFIG_PAGE_32K y
  1175. +if [ "$CONFIG_PAGE_32K" = "n" ]; then
  1176. +  bool 'Page size as 16K' CONFIG_PAGE_16K y
  1177. +  if [ "$CONFIG_PAGE_16K" = "n" ]; then
  1178. +    echo "Auto detected page size"
  1179. +  fi
  1180. +fi
  1181. +bool 'Kernel math emulation' CONFIG_MATH_EMULATION y
  1182. +bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y
  1183. +bool 'IDE disk/cdrom support' CONFIG_ST506 y
  1184. +if [ "$CONFIG_ST506" = "y" ]; then
  1185. +  comment 'Please see drivers/block/README.ide for help/info on IDE drives'
  1186. +  bool '   Use old disk-only driver for primary i/f' CONFIG_BLK_DEV_HD y
  1187. +  if [ "$CONFIG_BLK_DEV_HD" = "y" ]; then
  1188. +    bool '   Include new IDE driver for secondary i/f support' CONFIG_BLK_DEV_IDE n
  1189. +  else
  1190. +    bool '   Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE y
  1191. +  fi
  1192. +  if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
  1193. +    bool '   Include support for IDE/ATAPI CDROMs' CONFIG_BLK_DEV_IDECD n
  1194. +  fi
  1195. +fi
  1196. +
  1197. +bool 'MFM harddisk support' CONFIG_BLK_DEV_XD n
  1198. +bool 'Networking support' CONFIG_NET y
  1199. +bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
  1200. +bool 'System V IPC' CONFIG_SYSVIPC y
  1201. +#bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF n
  1202. +
  1203. +comment 'Loadable module support'
  1204. +bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS n
  1205. +
  1206. +if [ "$CONFIG_NET" = "y" ]; then
  1207. +comment 'Networking options'
  1208. +bool 'TCP/IP networking' CONFIG_INET y
  1209. +if [ "$CONFIG_INET" = "y" ]; then
  1210. +bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD n
  1211. +bool 'IP multicasting' CONFIG_IP_MULTICAST n
  1212. +bool 'IP firewalling' CONFIG_IP_FIREWALL n
  1213. +bool 'IP accounting' CONFIG_IP_ACCT n
  1214. +comment '(it is safe to leave these untouched)'
  1215. +bool 'PC/TCP compatibility mode' CONFIG_INET_PCTCP n
  1216. +bool 'Reverse ARP' CONFIG_INET_RARP n
  1217. +bool 'Assume subnets are local' CONFIG_INET_SNARL y
  1218. +bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
  1219. +fi
  1220. +bool 'The IPX protocol' CONFIG_IPX n
  1221. +#bool 'Appletalk DDP' CONFIG_ATALK n
  1222. +#bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
  1223. +fi
  1224. +
  1225. +comment 'SCSI support'
  1226. +
  1227. +bool 'SCSI support?' CONFIG_SCSI n
  1228. +
  1229. +if [ "$CONFIG_SCSI" = "n" ]; then
  1230. +
  1231. +comment 'Skipping SCSI configuration options...'
  1232. +
  1233. +else
  1234. +
  1235. +comment 'SCSI support type (disk, tape, CDrom)'
  1236. +
  1237. +bool 'Scsi disk support' CONFIG_BLK_DEV_SD y
  1238. +bool 'Scsi tape support' CONFIG_CHR_DEV_ST n
  1239. +bool 'Scsi CDROM support' CONFIG_BLK_DEV_SR n
  1240. +bool 'Scsi generic support' CONFIG_CHR_DEV_SG n
  1241. +
  1242. +comment 'SCSI low-level drivers'
  1243. +
  1244. +bool 'Acorn SCSI card (aka30) support' CONFIG_SCSI_ACORNSCSI_3 y
  1245. +bool 'Cumana 1 support' CONFIG_SCSI_CUMANA_1 n
  1246. +bool 'EcoScsi support' CONFIG_SCSI_ECOSCSI n
  1247. +bool 'Oak SCSI support' CONFIG_SCSI_OAK n
  1248. +bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
  1249. +fi
  1250. +
  1251. +
  1252. +if [ "$CONFIG_NET" = "y" ]; then
  1253. +
  1254. +comment 'Network device support'
  1255. +
  1256. +bool 'Network device support?' CONFIG_NETDEVICES y
  1257. +if [ "$CONFIG_NETDEVICES" = "n" ]; then
  1258. +
  1259. +comment 'Skipping network driver configuration options...'
  1260. +
  1261. +else
  1262. +bool 'Dummy net driver support' CONFIG_DUMMY y
  1263. +bool 'SLIP (serial line) support' CONFIG_SLIP y
  1264. +if [ "$CONFIG_SLIP" = "y" ]; then
  1265. +  bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
  1266. +  bool ' 16 channels instead of 4' SL_SLIP_LOTS n
  1267. +  bool ' SLIP debugging on' SL_DUMP y
  1268. +fi
  1269. +bool 'PPP (point-to-point) support' CONFIG_PPP y
  1270. +bool 'PLIP (parallel port) support' CONFIG_PLIP y
  1271. +bool 'Ether3 (NQ8005) support' CONFIG_ETHER3 n
  1272. +fi
  1273. +fi
  1274. +
  1275. +#comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
  1276. +
  1277. +#bool 'Sony CDU31A/CDU33A CDROM driver support' CONFIG_CDU31A n
  1278. +#bool 'Mitsumi (not IDE/ATAPI) CDROM driver support' CONFIG_MCD n
  1279. +#bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n
  1280. +#if [ "$CONFIG_SBPCD" = "y" ]; then
  1281. +#  bool 'Matsushita/Panasonic second CDROM controller support' CONFIG_SBPCD2 n
  1282. +#  if [ "$CONFIG_SBPCD2" = "y" ]; then
  1283. +#    bool 'Matsushita/Panasonic third CDROM controller support' CONFIG_SBPCD3 n
  1284. +#    if [ "$CONFIG_SBPCD3" = "y" ]; then
  1285. +#      bool 'Matsushita/Panasonic fourth CDROM controller support' CONFIG_SBPCD4 n
  1286. +#    fi
  1287. +#  fi
  1288. +#fi
  1289. +#bool 'Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support' CONFIG_AZTCD n
  1290. +#bool 'Sony CDU535 CDROM driver support' CONFIG_CDU535 n
  1291. +
  1292. +comment 'Filesystems'
  1293. +
  1294. +bool 'Standard (minix) fs support' CONFIG_MINIX_FS n
  1295. +bool 'Extended fs support' CONFIG_EXT_FS n
  1296. +bool 'Second extended fs support' CONFIG_EXT2_FS y
  1297. +bool 'xiafs filesystem support' CONFIG_XIA_FS n
  1298. +bool 'msdos fs support' CONFIG_MSDOS_FS y
  1299. +if [ "$CONFIG_MSDOS_FS" = "y" ]; then
  1300. +bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
  1301. +fi
  1302. +bool '/proc filesystem support' CONFIG_PROC_FS y
  1303. +if [ "$CONFIG_INET" = "y" ]; then
  1304. +bool 'NFS filesystem support' CONFIG_NFS_FS y
  1305. +fi
  1306. +if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_AZTCD" = "y" -o "$CONFIG_CDU535" = "y" ]; then
  1307. +    bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
  1308. +else
  1309. +    bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
  1310. +fi
  1311. +#bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
  1312. +#bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
  1313. +
  1314. +comment 'character devices'
  1315. +
  1316. +#bool 'Cyclades async mux support' CONFIG_CYCLADES n
  1317. +bool 'Parallel printer support' CONFIG_PRINTER y
  1318. +#bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
  1319. +#bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
  1320. +#if [ "$CONFIG_PSMOUSE" = "y" ]; then
  1321. +#bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
  1322. +#fi
  1323. +#bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
  1324. +#bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
  1325. +
  1326. +
  1327. +#bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
  1328. +#if [ "$CONFIG_QIC02_TAPE" = "y" ]; then
  1329. +#bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF y
  1330. +#if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then
  1331. +
  1332. +#comment '>>> Edit configuration parameters in ./include/linux/tpqic02.h!'
  1333. +
  1334. +#else
  1335. +
  1336. +#comment '>>> Setting runtime QIC-02 configuration is done with qic02conf'
  1337. +#comment '>>> Which is available from ftp://ftp.funet.fi/pub/OS/Linux/BETA/QIC-02/'
  1338. +
  1339. +#fi
  1340. +#fi
  1341. +
  1342. +#bool 'QIC-117 tape support' CONFIG_FTAPE n
  1343. +#if [ "$CONFIG_FTAPE" = "y" ]; then
  1344. +#int ' number of ftape buffers' NR_FTAPE_BUFFERS 3
  1345. +#fi
  1346. +
  1347. +comment 'Sound'
  1348. +
  1349. +bool 'Sound support' CONFIG_SOUND n
  1350. +
  1351. +comment 'Kernel hacking'
  1352. +
  1353. +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
  1354. +bool 'Kernel profiling support' CONFIG_PROFILE n
  1355. +if [ "$CONFIG_PROFILE" = "y" ]; then
  1356. +  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
  1357. +fi
  1358. +if [ "$CONFIG_SCSI" = "y" ]; then
  1359. +bool 'Verbose scsi error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
  1360. +fi
  1361. diff -r -u -N linux.orig/arch/arm/drivers/Makefile linux.arm/arch/arm/drivers/Makefile
  1362. --- linux.orig/arch/arm/drivers/Makefile    Thu Jan  1 01:00:00 1970
  1363. +++ linux.arm/arch/arm/drivers/Makefile    Fri Oct 27 23:14:58 1995
  1364. @@ -0,0 +1,48 @@
  1365. +#
  1366. +# Makefile for the linux kernel device drivers.
  1367. +#
  1368. +# Note! Dependencies are done automagically by 'make dep', which also
  1369. +# removes any old dependencies. DON'T put your own dependencies here
  1370. +# unless it's something special (ie not a .c file).
  1371. +#
  1372. +# Note 2! The CFLAGS definitions are now in the main makefile...
  1373. +
  1374. +.S.s:
  1375. +    $(CPP) -traditional $< -o $*.s
  1376. +.c.s:
  1377. +    $(CC) $(CFLAGS) -S $<
  1378. +.s.o:
  1379. +    $(AS) -c -o $*.o $<
  1380. +.c.o:
  1381. +    $(CC) $(CFLAGS) -c $<
  1382. +
  1383. +SUBDIRS    = block char net #streams
  1384. +
  1385. +ifdef CONFIG_SCSI
  1386. +SUBDIRS := $(SUBDIRS) scsi
  1387. +endif
  1388. +
  1389. +ifdef CONFIG_SOUND
  1390. +SUBDIRS := $(SUBDIRS) sound
  1391. +endif
  1392. +
  1393. +all: driversubdirs
  1394. +
  1395. +driversubdirs: dummy
  1396. +    set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
  1397. +
  1398. +modules: dummy
  1399. +    set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i modules; done
  1400. +
  1401. +dep:
  1402. +    set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
  1403. +
  1404. +dummy:
  1405. +
  1406. +#
  1407. +# include a dependency file if one exists
  1408. +#
  1409. +ifeq (.depend,$(wildcard .depend))
  1410. +include .depend
  1411. +endif
  1412. +
  1413. diff -r -u -N linux.orig/arch/arm/drivers/block/Makefile linux.arm/arch/arm/drivers/block/Makefile
  1414. --- linux.orig/arch/arm/drivers/block/Makefile    Thu Jan  1 01:00:00 1970
  1415. +++ linux.arm/arch/arm/drivers/block/Makefile    Fri Oct 27 23:14:45 1995
  1416. @@ -0,0 +1,75 @@
  1417. +#
  1418. +# Makefile for the kernel block device drivers.
  1419. +#
  1420. +# Note! Dependencies are done automagically by 'make dep', which also
  1421. +# removes any old dependencies. DON'T put your own dependencies here
  1422. +# unless it's something special (ie not a .c file).
  1423. +#
  1424. +# Note 2! The CFLAGS definition is now inherited from the
  1425. +# parent makefile.
  1426. +#
  1427. +
  1428. +.c.s:
  1429. +    $(CC) $(CFLAGS) -S $<
  1430. +.s.o:
  1431. +    $(AS) -c -o $*.o $<
  1432. +.c.o:
  1433. +    $(CC) $(CFLAGS) -c $<
  1434. +
  1435. +#
  1436. +# Note : at this point, these files are compiled on all systems. 
  1437. +# In the future, some of these should be built conditionally.
  1438. +#
  1439. +
  1440. +all: block.a
  1441. +
  1442. +OBJS := ll_rw_blk.o ramdisk.o genhd.o hdsrch.o
  1443. +SRCS := ll_rw_blk.c ramdisk.c genhd.c hdsrch.c
  1444. +BLOCK_MODULE_OBJS =
  1445. +
  1446. +ifdef CONFIG_BLK_DEV_FD
  1447. +OBJS := $(OBJS) floppy.o
  1448. +SRCS := $(SRCS) floppy.c
  1449. +endif
  1450. +
  1451. +ifdef CONFIG_BLK_DEV_HD
  1452. +OBJS := $(OBJS) hd.o
  1453. +SRCS := $(SRCS) hd.c
  1454. +endif
  1455. +
  1456. +ifdef CONFIG_BLK_DEV_IDE
  1457. +OBJS := ide.o $(OBJS)
  1458. +SRCS := ide.c $(SRCS)
  1459. +endif
  1460. +
  1461. +ifdef CONFIG_BLK_DEV_MFM
  1462. +OBJS := mfmhd.o $(OBJS)
  1463. +SRCS := mfmhd.c $(OBJS)
  1464. +else
  1465. +BLOCK_MODULE_OBJS := mfm-hd.o
  1466. +
  1467. +mfm-hd.o: mfmhd.o
  1468. +    ld -r -o mfm-hd.o mfmhd.o `gcc --print-libgcc-file-name`
  1469. +
  1470. +endif
  1471. +
  1472. +block.a: $(OBJS)
  1473. +    rm -f block.a
  1474. +    $(AR) rcs block.a $(OBJS)
  1475. +    sync
  1476. +
  1477. +dep:
  1478. +    $(CPP) -M $(SRCS) > .depend
  1479. +
  1480. +modules: $(BLOCK_MODULE_OBJS)
  1481. +    echo $(BLOCK_MODULE_OBJS) > ../../../../modules/BLOCK_MODULES
  1482. +    (cd ../../../../modules;for i in $(BLOCK_MODULE_OBJS); do ln -sf ../arch/arm/drivers/block/$$i .; done)
  1483. +
  1484. +dummy:
  1485. +
  1486. +#
  1487. +# include a dependency file if one exists
  1488. +#
  1489. +ifeq (.depend,$(wildcard .depend))
  1490. +include .depend
  1491. +endif
  1492. diff -r -u -N linux.orig/arch/arm/drivers/block/blk.h linux.arm/arch/arm/drivers/block/blk.h
  1493. --- linux.orig/arch/arm/drivers/block/blk.h    Thu Jan  1 01:00:00 1970
  1494. +++ linux.arm/arch/arm/drivers/block/blk.h    Fri Oct 27 23:14:45 1995
  1495. @@ -0,0 +1,295 @@
  1496. +#ifndef _BLK_H
  1497. +#define _BLK_H
  1498. +
  1499. +#include <linux/blkdev.h>
  1500. +#include <linux/locks.h>
  1501. +#include <linux/config.h>
  1502. +
  1503. +/*
  1504. + * NR_REQUEST is the number of entries in the request-queue.
  1505. + * NOTE that writes may use only the low 2/3 of these: reads
  1506. + * take precedence.
  1507. + *
  1508. + * 32 seems to be a reasonable number: enough to get some benefit
  1509. + * from the elevator-mechanism, but not so much as to lock a lot of
  1510. + * buffers when they are in the queue. 64 seems to be too many (easily
  1511. + * long pauses in reading when heavy writing/syncing is going on)
  1512. + */
  1513. +#define NR_REQUEST    64
  1514. +
  1515. +/*
  1516. + * This is used in the elevator algorithm: Note that
  1517. + * reads always go before writes. This is natural: reads
  1518. + * are much more time-critical than writes.
  1519. + */
  1520. +#define IN_ORDER(s1,s2) \
  1521. +((s1)->cmd < (s2)->cmd || ((s1)->cmd == (s2)->cmd && \
  1522. +((s1)->dev < (s2)->dev || (((s1)->dev == (s2)->dev && \
  1523. +(s1)->sector < (s2)->sector)))))
  1524. +
  1525. +/*
  1526. + * These will have to be changed to be aware of different buffer
  1527. + * sizes etc.. It actually needs a major cleanup.
  1528. + */
  1529. +#define SECTOR_MASK (blksize_size[MAJOR_NR] &&     \
  1530. +    blksize_size[MAJOR_NR][MINOR(CURRENT->dev)] ? \
  1531. +    ((blksize_size[MAJOR_NR][MINOR(CURRENT->dev)] >> 9) - 1) :  \
  1532. +    ((BLOCK_SIZE >> 9)  -  1))
  1533. +
  1534. +#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
  1535. +
  1536. +extern unsigned long hd_init(unsigned long mem_start, unsigned long mem_end);
  1537. +extern unsigned long cdu31a_init(unsigned long mem_start, unsigned long mem_end);
  1538. +extern unsigned long mcd_init(unsigned long mem_start, unsigned long mem_end);
  1539. +#ifdef CONFIG_SBPCD
  1540. +extern unsigned long sbpcd_init(unsigned long, unsigned long);
  1541. +#endif /* CONFIG_SBPCD */
  1542. +extern void set_device_ro(int dev,int flag);
  1543. +
  1544. +extern void rd_load(void);
  1545. +extern long rd_init(long mem_start, int length);
  1546. +extern int ramdisk_size;
  1547. +
  1548. +extern unsigned long xd_init(unsigned long mem_start, unsigned long mem_end);
  1549. +
  1550. +#define RO_IOCTLS(dev,where) \
  1551. +  case BLKROSET: if (!suser()) return -EACCES; \
  1552. +         set_device_ro((dev),get_fs_long((long *) (where))); return 0; \
  1553. +  case BLKROGET: { int __err = verify_area(VERIFY_WRITE, (void *) (where), sizeof(long)); \
  1554. +           if (!__err) put_fs_long(0!=is_read_only(dev),(long *) (where)); return __err; }
  1555. +
  1556. +#ifdef MAJOR_NR
  1557. +
  1558. +/*
  1559. + * Add entries as needed. Currently the only block devices
  1560. + * supported are hard-disks and floppies.
  1561. + */
  1562. +
  1563. +#if (MAJOR_NR == MEM_MAJOR)
  1564. +
  1565. +/* ram disk */
  1566. +#define DEVICE_NAME "ramdisk"
  1567. +#define DEVICE_REQUEST do_rd_request
  1568. +#define DEVICE_NR(device) ((device) & 7)
  1569. +#define DEVICE_ON(device)
  1570. +#define DEVICE_OFF(device)
  1571. +
  1572. +#elif (MAJOR_NR == FLOPPY_MAJOR)
  1573. +
  1574. +static void floppy_off(unsigned int nr);
  1575. +
  1576. +#define DEVICE_NAME "floppy"
  1577. +#define DEVICE_INTR do_floppy
  1578. +#define DEVICE_REQUEST do_fd_request
  1579. +#define DEVICE_NR(device) ( ((device) & 3) | (((device) & 0x80 ) >> 5 ))
  1580. +#define DEVICE_ON(device)
  1581. +#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
  1582. +
  1583. +#elif (MAJOR_NR == HD_MAJOR)
  1584. +
  1585. +/* harddisk: timeout is 6 seconds.. */
  1586. +#define DEVICE_NAME "harddisk"
  1587. +#define DEVICE_INTR do_hd
  1588. +#define DEVICE_TIMEOUT HD_TIMER
  1589. +#define TIMEOUT_VALUE 600
  1590. +#define DEVICE_REQUEST do_hd_request
  1591. +#define DEVICE_NR(device) (MINOR(device)>>6)
  1592. +#define DEVICE_ON(device)
  1593. +#define DEVICE_OFF(device)
  1594. +
  1595. +#elif (MAJOR_NR == SCSI_DISK_MAJOR)
  1596. +
  1597. +#define DEVICE_NAME "scsidisk"
  1598. +#define DEVICE_INTR do_sd
  1599. +#define TIMEOUT_VALUE 200
  1600. +#define DEVICE_REQUEST do_sd_request
  1601. +#define DEVICE_NR(device) (MINOR(device) >> 4)
  1602. +#define DEVICE_ON(device)
  1603. +#define DEVICE_OFF(device)
  1604. +
  1605. +#elif (MAJOR_NR == SCSI_TAPE_MAJOR)
  1606. +
  1607. +#define DEVICE_NAME "scsitape"
  1608. +#define DEVICE_INTR do_st
  1609. +#define DEVICE_NR(device) (MINOR(device))
  1610. +#define DEVICE_ON(device)
  1611. +#define DEVICE_OFF(device)
  1612. +
  1613. +#elif (MAJOR_NR == SCSI_CDROM_MAJOR)
  1614. +
  1615. +#define DEVICE_NAME "CD-ROM"
  1616. +#define DEVICE_INTR do_sr
  1617. +#define DEVICE_REQUEST do_sr_request
  1618. +#define DEVICE_NR(device) (MINOR(device))
  1619. +#define DEVICE_ON(device)
  1620. +#define DEVICE_OFF(device)
  1621. +
  1622. +#elif (MAJOR_NR == XT_DISK_MAJOR)
  1623. +
  1624. +#define DEVICE_NAME "xt disk"
  1625. +#define DEVICE_REQUEST do_xd_request
  1626. +#define DEVICE_NR(device) (MINOR(device) >> 6)
  1627. +#define DEVICE_ON(device)
  1628. +#define DEVICE_OFF(device)
  1629. +
  1630. +#elif defined(MFM_DISK_MAJOR) && (MAJOR_NR == MFM_DISK_MAJOR)
  1631. +
  1632. +#define DEVICE_NAME "mfm disk"
  1633. +#define DEVICE_INTR do_mfm
  1634. +#define DEVICE_REQUEST do_mfm_request
  1635. +#define DEVICE_NR(device) (MINOR(device) >> 6)
  1636. +#define DEVICE_ON(device)
  1637. +#define DEVICE_OFF(device)
  1638. +
  1639. +#elif (MAJOR_NR == CDU31A_CDROM_MAJOR)
  1640. +
  1641. +#define DEVICE_NAME "CDU31A"
  1642. +#define DEVICE_REQUEST do_cdu31a_request
  1643. +#define DEVICE_NR(device) (MINOR(device))
  1644. +#define DEVICE_ON(device)
  1645. +#define DEVICE_OFF(device)
  1646. +
  1647. +#elif (MAJOR_NR == MITSUMI_CDROM_MAJOR)
  1648. +
  1649. +#define DEVICE_NAME "Mitsumi CD-ROM"
  1650. +/* #define DEVICE_INTR do_mcd */
  1651. +#define DEVICE_REQUEST do_mcd_request
  1652. +#define DEVICE_NR(device) (MINOR(device))
  1653. +#define DEVICE_ON(device)
  1654. +#define DEVICE_OFF(device)
  1655. +
  1656. +#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
  1657. +
  1658. +#define DEVICE_NAME "Matsushita CD-ROM controller #1"
  1659. +#define DEVICE_REQUEST do_sbpcd_request
  1660. +#define DEVICE_NR(device) (MINOR(device))
  1661. +#define DEVICE_ON(device)
  1662. +#define DEVICE_OFF(device)
  1663. +
  1664. +#elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR)
  1665. +
  1666. +#define DEVICE_NAME "Matsushita CD-ROM controller #2"
  1667. +#define DEVICE_REQUEST do_sbpcd2_request
  1668. +#define DEVICE_NR(device) (MINOR(device))
  1669. +#define DEVICE_ON(device)
  1670. +#define DEVICE_OFF(device)
  1671. +
  1672. +#elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR)
  1673. +
  1674. +#define DEVICE_NAME "Matsushita CD-ROM controller #3"
  1675. +#define DEVICE_REQUEST do_sbpcd3_request
  1676. +#define DEVICE_NR(device) (MINOR(device))
  1677. +#define DEVICE_ON(device)
  1678. +#define DEVICE_OFF(device)
  1679. +
  1680. +#elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR)
  1681. +
  1682. +#define DEVICE_NAME "Matsushita CD-ROM controller #4"
  1683. +#define DEVICE_REQUEST do_sbpcd4_request
  1684. +#define DEVICE_NR(device) (MINOR(device))
  1685. +#define DEVICE_ON(device)
  1686. +#define DEVICE_OFF(device)
  1687. +
  1688. +#endif
  1689. +
  1690. +#if (MAJOR_NR != SCSI_TAPE_MAJOR)
  1691. +
  1692. +#ifndef CURRENT
  1693. +#define CURRENT (blk_dev[MAJOR_NR].current_request)
  1694. +#endif
  1695. +
  1696. +#define CURRENT_DEV DEVICE_NR(CURRENT->dev)
  1697. +
  1698. +#ifdef DEVICE_INTR
  1699. +void (*DEVICE_INTR)(void) = NULL;
  1700. +#endif
  1701. +#ifdef DEVICE_TIMEOUT
  1702. +
  1703. +#define SET_TIMER \
  1704. +((timer_table[DEVICE_TIMEOUT].expires = jiffies + TIMEOUT_VALUE), \
  1705. +(timer_active |= 1<<DEVICE_TIMEOUT))
  1706. +
  1707. +#define CLEAR_TIMER \
  1708. +timer_active &= ~(1<<DEVICE_TIMEOUT)
  1709. +
  1710. +#define SET_INTR(x) \
  1711. +if ((DEVICE_INTR = (x)) != NULL) \
  1712. +    SET_TIMER; \
  1713. +else \
  1714. +    CLEAR_TIMER;
  1715. +
  1716. +#else
  1717. +
  1718. +#define SET_INTR(x) (DEVICE_INTR = (x))
  1719. +
  1720. +#endif
  1721. +static void (DEVICE_REQUEST)(void);
  1722. +
  1723. +/* end_request() - SCSI devices have their own version */
  1724. +
  1725. +#if ! SCSI_MAJOR(MAJOR_NR)
  1726. +
  1727. +static void end_request(int uptodate)
  1728. +{
  1729. +    struct request * req;
  1730. +    struct buffer_head * bh;
  1731. +
  1732. +    req = CURRENT;
  1733. +    req->errors = 0;
  1734. +    if (!uptodate) {
  1735. +        printk(DEVICE_NAME " I/O error\n");
  1736. +        printk("dev %04lX, sector %lu\n",
  1737. +               (unsigned long)req->dev, req->sector);
  1738. +        req->nr_sectors--;
  1739. +        req->nr_sectors &= ~SECTOR_MASK;
  1740. +        req->sector += (BLOCK_SIZE / 512);
  1741. +        req->sector &= ~SECTOR_MASK;
  1742. +    }
  1743. +
  1744. +    if ((bh = req->bh) != NULL) {
  1745. +        req->bh = bh->b_reqnext;
  1746. +        bh->b_reqnext = NULL;
  1747. +        bh->b_uptodate = uptodate;
  1748. +        if (!uptodate) bh->b_req = 0; /* So no "Weird" errors */
  1749. +        unlock_buffer(bh);
  1750. +        if ((bh = req->bh) != NULL) {
  1751. +            req->current_nr_sectors = bh->b_size >> 9;
  1752. +            if (req->nr_sectors < req->current_nr_sectors) {
  1753. +                req->nr_sectors = req->current_nr_sectors;
  1754. +                printk("end_request: buffer-list destroyed\n");
  1755. +            }
  1756. +            req->buffer = bh->b_data;
  1757. +            return;
  1758. +        }
  1759. +    }
  1760. +    DEVICE_OFF(req->dev);
  1761. +    CURRENT = req->next;
  1762. +    if (req->sem != NULL)
  1763. +        up(req->sem);
  1764. +    req->dev = -1;
  1765. +    wake_up(&wait_for_request);
  1766. +}
  1767. +#endif
  1768. +
  1769. +#ifdef DEVICE_INTR
  1770. +#define CLEAR_INTR SET_INTR(NULL)
  1771. +#else
  1772. +#define CLEAR_INTR
  1773. +#endif
  1774. +
  1775. +#define INIT_REQUEST \
  1776. +    if (!CURRENT) {\
  1777. +        CLEAR_INTR; \
  1778. +        return; \
  1779. +    } \
  1780. +    if (MAJOR(CURRENT->dev) != MAJOR_NR) \
  1781. +        panic(DEVICE_NAME ": request list destroyed"); \
  1782. +    if (CURRENT->bh) { \
  1783. +        if (!CURRENT->bh->b_lock) \
  1784. +            panic(DEVICE_NAME ": block not locked"); \
  1785. +    }
  1786. +
  1787. +#endif
  1788. +
  1789. +#endif
  1790. +#endif
  1791. diff -r -u -N linux.orig/arch/arm/drivers/block/floppy.c linux.arm/arch/arm/drivers/block/floppy.c
  1792. --- linux.orig/arch/arm/drivers/block/floppy.c    Thu Jan  1 01:00:00 1970
  1793. +++ linux.arm/arch/arm/drivers/block/floppy.c    Fri Oct 27 23:14:43 1995
  1794. @@ -0,0 +1,3227 @@
  1795. +/*
  1796. + *  linux/kernel/floppy.c
  1797. + *
  1798. + *  Copyright (C) 1991, 1992  Linus Torvalds
  1799. + *  Copyright (C) 1993, 1994  Alain Knaff
  1800. + */
  1801. +
  1802. +/* Configuration */
  1803. +/* The following does some extra sanity checks */
  1804. +#define SANITY
  1805. +
  1806. +/* the following is the mask of allowed drives. By default units 2 and
  1807. + * 3 of both floppy controllers are disabled, because switching on the
  1808. + * motor of these drives causes system hangs on some PCI computers. drive
  1809. + * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
  1810. + * a drive is allowed. */
  1811. +#define ALLOWED_DRIVE_MASK 0x0F
  1812. +
  1813. +/* Undefine the following if you have to floppy disk controllers:
  1814. + * This works at least for me; if you get two controllers working, with
  1815. + * drives attached to both, please mail me: Alain.Knaff@imag.fr */
  1816. +/* #define HAVE_2_CONTROLLERS */
  1817. +
  1818. +
  1819. +/* Define the following if you don't like that your drives seek audibly
  1820. + * after a disk change (but it may not work correctly for everybody)
  1821. + */
  1822. +#define SILENT_DC_CLEAR
  1823. +
  1824. +
  1825. +/* End of configuration */
  1826. +
  1827. +/*
  1828. + * 02.12.91 - Changed to static variables to indicate need for reset
  1829. + * and recalibrate. This makes some things easier (output_byte reset
  1830. + * checking etc), and means less interrupt jumping in case of errors,
  1831. + * so the code is hopefully easier to understand.
  1832. + */
  1833. +
  1834. +/*
  1835. + * This file is certainly a mess. I've tried my best to get it working,
  1836. + * but I don't like programming floppies, and I have only one anyway.
  1837. + * Urgel. I should check for more errors, and do more graceful error
  1838. + * recovery. Seems there are problems with several drives. I've tried to
  1839. + * correct them. No promises.
  1840. + */
  1841. +
  1842. +/*
  1843. + * As with hd.c, all routines within this file can (and will) be called
  1844. + * by interrupts, so extreme caution is needed. A hardware interrupt
  1845. + * handler may not sleep, or a kernel panic will happen. Thus I cannot
  1846. + * call "floppy-on" directly, but have to set a special timer interrupt
  1847. + * etc.
  1848. + */
  1849. +
  1850. +/*
  1851. + * 28.02.92 - made track-buffering routines, based on the routines written
  1852. + * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
  1853. + */
  1854. +
  1855. +/*
  1856. + * Automatic floppy-detection and formatting written by Werner Almesberger
  1857. + * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
  1858. + * the floppy-change signal detection.
  1859. + */
  1860. +
  1861. +/*
  1862. + * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
  1863. + * FDC data overrun bug, added some preliminary stuff for vertical
  1864. + * recording support.
  1865. + *
  1866. + * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
  1867. + *
  1868. + * TODO: Errors are still not counted properly.
  1869. + */
  1870. +
  1871. +/* 1992/9/20
  1872. + * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
  1873. + * modelled after the freeware MS/DOS program fdformat/88 V1.8 by
  1874. + * Christoph H. Hochst\"atter.
  1875. + * I have fixed the shift values to the ones I always use. Maybe a new
  1876. + * ioctl() should be created to be able to modify them.
  1877. + * There is a bug in the driver that makes it impossible to format a
  1878. + * floppy as the first thing after bootup.
  1879. + */
  1880. +
  1881. +/*
  1882. + * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
  1883. + * this helped the floppy driver as well. Much cleaner, and still seems to
  1884. + * work.
  1885. + */
  1886. +
  1887. +/* 1994/6/24 --bbroad-- added the floppy table entries and made
  1888. + * minor modifications to allow 2.88 floppies to be run.
  1889. + */
  1890. +
  1891. +/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
  1892. + * disk types.
  1893. + */
  1894. +
  1895. +/*
  1896. + * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
  1897. + * format bug fixes, but unfortunately some new bugs too...
  1898. + */
  1899. +
  1900. +/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
  1901. + * errors to allow safe writing by specialized programs.
  1902. + */
  1903. +int no_floppies;
  1904. +#define FLOPPY_IRQ 12
  1905. +#define FLOPPY_DMA 2
  1906. +#define DEBUGT 2
  1907. +
  1908. +#include <linux/config.h>
  1909. +#include <linux/sched.h>
  1910. +#include <linux/fs.h>
  1911. +#include <linux/kernel.h>
  1912. +#include <linux/timer.h>
  1913. +#include <linux/tqueue.h>
  1914. +#define FDPATCHES
  1915. +#include <linux/fdreg.h>
  1916. +#include <linux/fd.h>
  1917. +#include <linux/errno.h>
  1918. +#include <linux/malloc.h>
  1919. +#include <linux/string.h>
  1920. +#include <linux/fcntl.h>
  1921. +#include <linux/delay.h>
  1922. +
  1923. +#include <asm/dma.h>
  1924. +#include <asm/irq.h>
  1925. +#include <asm/system.h>
  1926. +#include <asm/io.h>
  1927. +#include <asm/segment.h>
  1928. +
  1929. +#define MAJOR_NR FLOPPY_MAJOR
  1930. +#include "blk.h"
  1931. +
  1932. +static unsigned int changed_floppies = 0xff, fake_change = 0;
  1933. +static int initialising=1;
  1934. +
  1935. +#ifdef HAVE_2_CONTROLLERS
  1936. +#define N_FDC 2
  1937. +#define N_DRIVE 8
  1938. +#else
  1939. +#define N_FDC 1
  1940. +#define N_DRIVE 4
  1941. +#endif
  1942. +
  1943. +#define TYPE(x) ( ((x)>>2) & 0x1f )
  1944. +#define DRIVE(x) ( ((x)&0x03) | (((x)&0x80 ) >> 5))
  1945. +#define UNIT(x) ( (x) & 0x03 )        /* drive on fdc */
  1946. +#define FDC(x) ( ((x) & 0x04) >> 2 )  /* fdc of drive */
  1947. +#define REVDRIVE(fdc, unit) ( (unit) + ((fdc) << 2 ))
  1948. +                /* reverse mapping from unit and fdc to drive */
  1949. +#define DP (&drive_params[current_drive])
  1950. +#define DRS (&drive_state[current_drive])
  1951. +#define DRWE (&write_errors[current_drive])
  1952. +#define FDCS (&fdc_state[fdc])
  1953. +
  1954. +#define UDP (&drive_params[drive])
  1955. +#define UDRS (&drive_state[drive])
  1956. +#define UDRWE (&write_errors[drive])
  1957. +#define UFDCS (&fdc_state[FDC(drive)])
  1958. +
  1959. +#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive);
  1960. +
  1961. +#define DPRINT1(x,x1) \
  1962. +printk(DEVICE_NAME "%d: " x,current_drive,(x1));
  1963. +
  1964. +#define DPRINT2(x,x1,x2) \
  1965. +printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2));
  1966. +
  1967. +#define DPRINT3(x,x1,x2,x3) \
  1968. +printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3));
  1969. +
  1970. +/* read/write */
  1971. +#define COMMAND raw_cmd.cmd[0]
  1972. +#define DR_SELECT raw_cmd.cmd[1]
  1973. +#define TRACK raw_cmd.cmd[2]
  1974. +#define HEAD raw_cmd.cmd[3]
  1975. +#define SECTOR raw_cmd.cmd[4]
  1976. +#define SIZECODE raw_cmd.cmd[5]
  1977. +#define SECT_PER_TRACK raw_cmd.cmd[6]
  1978. +#define GAP raw_cmd.cmd[7]
  1979. +#define SIZECODE2 raw_cmd.cmd[8]
  1980. +#define NR_RW 9
  1981. +
  1982. +/* format */
  1983. +#define F_SIZECODE raw_cmd.cmd[2]
  1984. +#define F_SECT_PER_TRACK raw_cmd.cmd[3]
  1985. +#define F_GAP raw_cmd.cmd[4]
  1986. +#define F_FILL raw_cmd.cmd[5]
  1987. +#define NR_F 6
  1988. +
  1989. +/*
  1990. + * Maximum disk size (in kilobytes). This default is used whenever the
  1991. + * current disk size is unknown.
  1992. + */
  1993. +#define MAX_DISK_SIZE 3984
  1994. +
  1995. +
  1996. +
  1997. +/*
  1998. + * The DMA channel used by the floppy controller cannot access data at
  1999. + * addresses >= 16MB
  2000. + *
  2001. + * Went back to the 1MB limit, as some people had problems with the floppy
  2002. + * driver otherwise. It doesn't matter much for performance anyway, as most
  2003. + * floppy accesses go through the track buffer.
  2004. + */
  2005. +#if 0
  2006. +#define LAST_DMA_ADDR    (0x1000000)
  2007. +#else
  2008. +/* Everything has to go via dma buffer */
  2009. +#define LAST_DMA_ADDR    (0x1)
  2010. +#endif
  2011. +#define K_64 (0x10000) /* 64 k */
  2012. +/*
  2013. + * globals used by 'result()'
  2014. + */
  2015. +#define MAX_REPLIES 10
  2016. +static unsigned char reply_buffer[MAX_REPLIES];
  2017. +static int inr; /* size of reply buffer, when called from interrupt */
  2018. +#define ST0 (reply_buffer[0])
  2019. +#define ST1 (reply_buffer[1])
  2020. +#define ST2 (reply_buffer[2])
  2021. +#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
  2022. +#define R_TRACK (reply_buffer[3])
  2023. +#define R_HEAD (reply_buffer[4])
  2024. +#define R_SECTOR (reply_buffer[5])
  2025. +#define R_SIZECODE (reply_buffer[6])
  2026. +
  2027. +/*
  2028. + * this struct defines the different floppy drive types.
  2029. + */
  2030. +static struct {
  2031. +    struct floppy_drive_params params;
  2032. +    char *name; /* name printed while booting */
  2033. +} default_drive_params[]= {
  2034. +/* NOTE: the time values in jiffies should be in msec!
  2035. + CMOS drive type
  2036. +  |     Maximum data rate supported by drive type
  2037. +  |     |   Head load time, msec
  2038. +  |     |   |   Head unload time, msec (not used)
  2039. +  |     |   |   |     Step rate interval, usec
  2040. +  |     |   |   |     |    Time needed for spinup time (jiffies)
  2041. +  |     |   |   |     |    |    Timeout for spinning down (jiffies)
  2042. +  |     |   |   |     |    |    |   Spindown offset (where disk stops)
  2043. +  |     |   |   |     |    |    |   |  Select delay
  2044. +  |     |   |   |     |    |    |   |  |  RPS
  2045. +  |     |   |   |     |    |    |   |  |  |    Max number of tracks
  2046. +  |     |   |   |     |    |    |   |  |  |    |     Interrupt timeout
  2047. +  |     |   |   |     |    |    |   |  |  |    |     |   Max nonintlv. sectors
  2048. +  |     |   |   |     |    |    |   |  |  |    |     |   | -Max Errors- flags */
  2049. +{{0,  500, 16, 16, 8000, 100, 300,  0, 2, 5,  80, 3*HZ, 20, {3,1,2,0,2}, 0,
  2050. +      0, { 7, 4, 8, 2, 1, 5, 3,10}, 150, 0 }, "unknown" },
  2051. +
  2052. +{{1,  300, 16, 16, 8000, 100, 300,  0, 2, 5,  40, 3*HZ, 17, {3,1,2,0,2}, 0,
  2053. +      0, { 1, 0, 0, 0, 0, 0, 0, 0}, 150, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
  2054. +
  2055. +{{2,  500, 16, 16, 6000,  40, 300, 14, 2, 6,  83, 3*HZ, 17, {3,1,2,0,2}, 0,
  2056. +      0, { 2, 5, 6,23,10,20,11, 0}, 150, 2 }, "1.2M" }, /*5 1/4 HD AT*/
  2057. +
  2058. +{{3,  250, 16, 16, 3000, 100, 300,  0, 2, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
  2059. +      0, { 4,22,21,30, 3, 0, 0, 0}, 150, 4 }, "720k" }, /*3 1/2 DD*/
  2060. +
  2061. +#if 0
  2062. +{{4,  500, 16, 16, 4000,  40, 300, 10, 2, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
  2063. +      0, { 7, 4,25,22,31,21,29,11}, 150, 7 }, "1.44M" }, /*3 1/2 HD*/
  2064. +#else
  2065. +{{4,  500, 16, 16, 3000,  40, 300, 10, 2, 5,  83, 3*HZ, 20, {3,1,2,0,0}, FTD_MSG,
  2066. +      0, { 7, 4,25,22,31,21,29,11}, 150, 7 }, "1.44M" }, /*3 1/2 HD*/
  2067. +#endif
  2068. +
  2069. +{{5, 1000, 15,  8, 3000,  40, 300, 10, 2, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
  2070. +      0, { 7, 8, 4,25,28,22,31,21}, 150, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
  2071. +
  2072. +{{6, 1000, 15,  8, 3000,  40, 300, 10, 2, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
  2073. +      0, { 7, 8, 4,25,28,22,31,21}, 150, 8 }, "2.88M" } /*3 1/2 ED*/
  2074. +/*    |  ---autodetected formats--   |   |      |
  2075. +      read_track                     |   |    Name printed when booting
  2076. +                                     |  Native format
  2077. +                                   Frequency of disk change checks */
  2078. +};
  2079. +
  2080. +static struct floppy_drive_params drive_params[N_DRIVE];
  2081. +static struct floppy_drive_struct volatile drive_state[N_DRIVE];
  2082. +static struct floppy_write_errors volatile write_errors[N_DRIVE];
  2083. +static struct floppy_raw_cmd raw_cmd;
  2084. +
  2085. +/*
  2086. + * This struct defines the different floppy types.
  2087. + *
  2088. + * The 'stretch' tells if the tracks need to be doubled for some
  2089. + * types (ie 360kB diskette in 1.2MB drive etc). Others should
  2090. + * be self-explanatory.
  2091. + */
  2092. +/*
  2093. +             Size
  2094. +             |  Sectors per track
  2095. +             |  | Head
  2096. +             |  | |  Tracks
  2097. +             |  | |  | Stretch
  2098. +             |  | |  | |  Gap 1 size
  2099. +             |  | |  | |    |  Data rate, | 0x40 for perp
  2100. +         |  | |  | |    |    |  Spec1 (stepping rate, head unload
  2101. +             |  | |  | |    |    |    |    /fmt gap (gap2) */
  2102. +static struct floppy_struct floppy_type[32] = {
  2103. +    {    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL    },    /*  0 no testing    */
  2104. +    {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360"  }, /*  1 360KB PC      */
  2105. +    { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" },    /*  2 1.2MB AT      */
  2106. +    {  720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360"  },    /*  3 360KB SS 3.5" */
  2107. +    { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720"  },    /*  4 720KB 3.5"    */
  2108. +    {  720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360"  },    /*  5 360KB AT      */
  2109. +    { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720"  },    /*  6 720KB AT      */
  2110. +    { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" },    /*  7 1.44MB 3.5"   */
  2111. +    { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" },    /*  8 2.88MB 3.5"   */
  2112. +    { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"CompaQ"},    /*  9 2.88MB 3.5"   */
  2113. +
  2114. +    { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25"  */
  2115. +    { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5"   */
  2116. +    {  820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410"  },    /* 12 410KB 5.25"   */
  2117. +    { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820"  },    /* 13 820KB 3.5"    */
  2118. +    { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" },    /* 14 1.48MB 5.25"  */
  2119. +    { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" },    /* 15 1.72MB 3.5"   */
  2120. +    {  840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420"  },    /* 16 420KB 5.25"   */
  2121. +    { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830"  },    /* 17 830KB 3.5"    */
  2122. +    { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" },    /* 18 1.49MB 5.25"  */
  2123. +    { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5"  */
  2124. +
  2125. +    { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880"  }, /* 20 880KB 5.25"   */
  2126. +    { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5"   */
  2127. +    { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5"   */
  2128. +    { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25"   */
  2129. +    { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5"   */
  2130. +    { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5"   */
  2131. +    { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5"   */
  2132. +    { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5"   */
  2133. +    { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5"   */
  2134. +
  2135. +    { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5"   */
  2136. +    { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800"  },    /* 30 800KB 3.5"    */
  2137. +    { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5"    */
  2138. +};
  2139. +
  2140. +#define    NUMBER(x)    (sizeof(x) / sizeof(*(x)))
  2141. +#define SECTSIZE ( _FD_SECTSIZE(*floppy))
  2142. +
  2143. +/* Auto-detection: Disk type used until the next media change occurs. */
  2144. +struct floppy_struct *current_type[N_DRIVE] = {
  2145. +    NULL, NULL, NULL, NULL
  2146. +#ifdef HAVE_2_CONTROLLERS
  2147. +    ,
  2148. +    NULL, NULL, NULL, NULL
  2149. +#endif
  2150. +};
  2151. +
  2152. +/*
  2153. + * User-provided type information. current_type points to
  2154. + * the respective entry of this array.
  2155. + */
  2156. +struct floppy_struct user_params[N_DRIVE];
  2157. +
  2158. +static int floppy_sizes[256];
  2159. +
  2160. +/*
  2161. + * The driver is trying to determine the correct media format
  2162. + * while probing is set. rw_interrupt() clears it after a
  2163. + * successful access.
  2164. + */
  2165. +static int probing = 0;
  2166. +
  2167. +/* Synchronization of FDC access. */
  2168. +#define FD_COMMAND_DETECT -2
  2169. +#define FD_COMMAND_NONE -1
  2170. +#define FD_COMMAND_ERROR 2
  2171. +#define FD_COMMAND_OKAY 3
  2172. +
  2173. +static volatile int command_status = FD_COMMAND_NONE, fdc_busy = 0;
  2174. +static struct wait_queue *fdc_wait = NULL, *command_done = NULL;
  2175. +#define NO_SIGNAL (!(current->signal & ~current->blocked) || !interruptible)
  2176. +#define CALL(x) if( (x) == -EINTR) return -EINTR;
  2177. +
  2178. +/* Errors during formatting are counted here. */
  2179. +static int format_errors;
  2180. +
  2181. +/* Format request descriptor. */
  2182. +static struct format_descr format_req;
  2183. +
  2184. +/*
  2185. + * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
  2186. + * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
  2187. + * H is head unload time (1=16ms, 2=32ms, etc)
  2188. + */
  2189. +
  2190. +/*
  2191. + * Track buffer
  2192. + * Because these are written to by the DMA controller, they must
  2193. + * not contain a 64k byte boundary crossing, or data will be
  2194. + * corrupted/lost. Alignment of these is enforced in boot/head.S.
  2195. + * Note that you must not change the sizes below without updating head.S.
  2196. + */
  2197. +#if 0
  2198. +extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
  2199. +#else
  2200. +char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
  2201. +#endif
  2202. +#define max_buffer_sectors MAX_BUFFER_SECTORS
  2203. +
  2204. +int *errors;
  2205. +typedef void (*done_f)(int);
  2206. +struct cont_t {
  2207. +void (*interrupt)(void); /* this is called after the interrupt of the
  2208. +              * main command */
  2209. +void (*redo)(void); /* this is called to retry the operation */
  2210. +void (*error)(void); /* this is called to tally an error */
  2211. +done_f done; /* this is called to say if the operation has succeeded/failed */
  2212. +} *cont;
  2213. +
  2214. +static void floppy_start(void);
  2215. +static void redo_fd_request(void);
  2216. +static void recalibrate_floppy(void);
  2217. +static void seek_floppy(void);
  2218. +static void floppy_shutdown(void);
  2219. +
  2220. +static int floppy_grab_irq_and_dma(void);
  2221. +static void floppy_release_irq_and_dma(void);
  2222. +
  2223. +/*
  2224. + * The "reset" variable should be tested whenever an interrupt is scheduled,
  2225. + * after the commands have been sent. This is to ensure that the driver doesn't
  2226. + * get wedged when the interrupt doesn't come because of a failed command.
  2227. + * reset doesn't need to be tested before sending commands, because
  2228. + * output_byte is automatically disabled when reset is set.
  2229. + */
  2230. +#define CHECK_RESET { if ( FDCS->reset ){ reset_fdc(); return ; } }
  2231. +static void reset_fdc(void);
  2232. +
  2233. +/*
  2234. + * These are global variables, as that's the easiest way to give
  2235. + * information to interrupts. They are the data used for the current
  2236. + * request.
  2237. + */
  2238. +#define NO_TRACK -1
  2239. +#define NEED_1_RECAL -2
  2240. +#define NEED_2_RECAL -3
  2241. +#define PROVEN_ABSENT -4
  2242. +
  2243. +/* buffer related variables */
  2244. +static int buffer_track = -1;
  2245. +static int buffer_drive = -1;
  2246. +static int buffer_min = -1;
  2247. +static int buffer_max = -1;
  2248. +
  2249. +/* fdc related variables, should end up in a struct */
  2250. +static struct floppy_fdc_state fdc_state[N_FDC];
  2251. +int fdc; /* current fdc */
  2252. +
  2253. +static struct floppy_struct * floppy = floppy_type;
  2254. +static unsigned char current_drive = 255;
  2255. +static long current_count_sectors = 0;
  2256. +static char *current_addr = 0;
  2257. +static unsigned char sector_t; /* sector in track */
  2258. +
  2259. +#ifdef DEBUGT
  2260. +long unsigned debugtimer;
  2261. +#endif
  2262. +
  2263. +/*
  2264. + * Floppy_selects1 is the list of DOR's to select a drive n
  2265. + * Floppy_selects2 is the list of DOR's to select drive fd
  2266. + * On initialisation, the floppy list is scanned, and the drives allocated
  2267. + * in the order that they are found.  This is done by seeking the drive
  2268. + * to a non-zero track, and then restoring it to track 0.  If an error occurs,
  2269. + * then there is no floppy drive present.
  2270. + */
  2271. +
  2272. +unsigned char floppy_selects1[]={ 0x10, 0x21, 0x23, 0x33 };
  2273. +unsigned char floppy_selects2[]={ 0   , 0   , 0   , 0    };
  2274. +
  2275. +int fd_sectsizes[256];
  2276. +
  2277. +/*
  2278. + * Debugging
  2279. + * =========
  2280. + */
  2281. +static inline void set_debugt(void)
  2282. +{
  2283. +#ifdef DEBUGT
  2284. +    debugtimer = jiffies;
  2285. +#endif
  2286. +}
  2287. +
  2288. +static inline void debugt(char *message)
  2289. +{
  2290. +#ifdef DEBUGT
  2291. +  if ( DP->flags & DEBUGT )
  2292. +    printk("%s dtime=%lu\n", message, jiffies-debugtimer );
  2293. +#endif
  2294. +}
  2295. +
  2296. +/*
  2297. + * Bottom half floppy driver.
  2298. + * ==========================
  2299. + *
  2300. + * This part of the file contains the code talking directly to the hardware,
  2301. + * and also the main service loop (seek-configure-spinup-command)
  2302. + */
  2303. +
  2304. +/*
  2305. + * disk change.
  2306. + * This routine is responsible for maintaining the changed_floppies flag,
  2307. + * and the last_checked date.
  2308. + *
  2309. + * last_checked is the date of the last check which showed 'no disk change'
  2310. + * changed_floppies is set under two conditions:
  2311. + * 1. The floppy has been changed after some i/o to that floppy already
  2312. + *    took place.
  2313. + * 2. No floppy disk is in the drive.
  2314. + *
  2315. + * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
  2316. + * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
  2317. + *  each seek. If a disk is present, the disk change line should also be
  2318. + *  cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
  2319. + *  change line is set, this means either that no disk is in the drive, or
  2320. + *  that it has been removed since the last seek.
  2321. + *
  2322. + * This means that we really have a third possibility too:
  2323. + *  The floppy has been changed after the last seek.
  2324. + */
  2325. +
  2326. +static int disk_change(int drive)
  2327. +{
  2328. +    if(jiffies < DP->select_delay + DRS->select_date)
  2329. +        udelay(20000);
  2330. +
  2331. +    if(inb_p(FD_DIR) & 0x80){
  2332. +        UDRS->flags |= FD_VERIFY; /* verify write protection */
  2333. +
  2334. +        if(UDRS->maxblock || /* disk change check */
  2335. +           !(UDRS->flags & FD_DISK_NEWCHANGE)){/* disk presence check */
  2336. +            /* mark it changed or absent */
  2337. +            set_bit(drive,&changed_floppies);
  2338. +
  2339. +            /* invalidate its geometry */
  2340. +            if (UDRS->keep_data >= 0) {
  2341. +                if ((DP->flags & FTD_MSG) &&
  2342. +                    current_type[drive] != NULL)
  2343. +                    DPRINT("Disk type is undefined after "
  2344. +                           "disk change\n");
  2345. +                current_type[drive] = NULL;
  2346. +                floppy_sizes[drive] = MAX_DISK_SIZE;
  2347. +            }
  2348. +        }
  2349. +        UDRS->flags |= FD_DISK_NEWCHANGE;
  2350. +        return 1;
  2351. +    } else {
  2352. +        UDRS->last_checked=jiffies;
  2353. +        UDRS->flags &= ~FD_DISK_NEWCHANGE;
  2354. +        return 0;
  2355. +    }
  2356. +}
  2357. +
  2358. +static void arm_set_dor(int dor)
  2359. +{
  2360. +    if(dor & 0xf0)
  2361. +        outb_p((dor & 0x0c) | floppy_selects1[dor & 3], FD_DOR);
  2362. +    else
  2363. +        outb_p((dor & 0x0c), FD_DOR);
  2364. +}
  2365. +
  2366. +static int locked=0;
  2367. +static int set_dor(int fdc, char mask, char data)
  2368. +{
  2369. +    register unsigned char drive, unit, newdor,olddor;
  2370. +
  2371. +    locked=1;
  2372. +    olddor = FDCS->dor;
  2373. +    newdor =  (olddor & mask) | data;
  2374. +    if ( newdor != olddor ){
  2375. +        unit = olddor & 0x3;
  2376. +        drive = REVDRIVE(fdc,unit);
  2377. +        if ( olddor & ( 0x10 << unit ))
  2378. +            disk_change(drive);
  2379. +        FDCS->dor = newdor;
  2380. +        arm_set_dor(newdor);
  2381. +    }
  2382. +    locked=0;
  2383. +    return olddor;
  2384. +}
  2385. +
  2386. +static void twaddle(void)
  2387. +{
  2388. +    cli();
  2389. +#if 0
  2390. +    outb_p(FDCS->dor & ~(0x10<<UNIT(current_drive)),FD_DOR);
  2391. +    outb_p(FDCS->dor, FD_DOR);
  2392. +#else
  2393. +    arm_set_dor(FDCS->dor);
  2394. +#endif
  2395. +    sti();
  2396. +}
  2397. +
  2398. +/* reset all driver information about the current fdc. This is needed after
  2399. + * a reset, and after a raw command. */
  2400. +static void reset_fdc_info(int mode)
  2401. +{
  2402. +    int drive;
  2403. +
  2404. +    FDCS->spec1 = FDCS->spec2 = -1;
  2405. +    FDCS->need_configure = 1;
  2406. +    FDCS->perp_mode = 1;
  2407. +    FDCS->rawcmd = 0;
  2408. +    for ( drive = 0; drive < N_DRIVE; drive++)
  2409. +        if (FDC(drive) == fdc &&
  2410. +            UDRS->track != PROVEN_ABSENT &&
  2411. +            ( mode || UDRS->track != NEED_1_RECAL))
  2412. +            UDRS->track = NEED_2_RECAL;
  2413. +}
  2414. +
  2415. +/* selects the fdc and drive, and enables the fdc's input/dma. */
  2416. +static void set_fdc(int drive)
  2417. +{
  2418. +    if ( drive >= 0 ){
  2419. +        fdc = FDC(drive);
  2420. +        current_drive = drive;
  2421. +    }
  2422. +    set_dor(fdc,~0,8);
  2423. +#ifdef HAVE_2_CONTROLLERS
  2424. +    set_dor(1-fdc, ~8, 0);
  2425. +#endif
  2426. +    if ( FDCS->rawcmd == 2 )
  2427. +        reset_fdc_info(1);
  2428. +    if( inb_p(FD_STATUS) != STATUS_READY )
  2429. +        FDCS->reset = 1;
  2430. +}
  2431. +
  2432. +static int usage_count = 0;
  2433. +/* locks the driver */
  2434. +static int lock_fdc(int drive, int interruptible)
  2435. +{
  2436. +
  2437. +    if(!usage_count){
  2438. +        printk("trying to lock fdc while usage count=0\n");
  2439. +        return -1;
  2440. +    }
  2441. +    floppy_grab_irq_and_dma();
  2442. +    cli();
  2443. +    while (fdc_busy && NO_SIGNAL)
  2444. +        interruptible_sleep_on(&fdc_wait);
  2445. +    if(fdc_busy){
  2446. +        sti();
  2447. +        return -EINTR;
  2448. +    }
  2449. +    fdc_busy = 1;
  2450. +    sti();
  2451. +    command_status = FD_COMMAND_NONE;
  2452. +    set_fdc(drive);
  2453. +    return 0;
  2454. +}
  2455. +
  2456. +#define LOCK_FDC(drive,interruptible) \
  2457. +if(lock_fdc(drive,interruptible)) return -EINTR;
  2458. +
  2459. +/* unlocks the driver */
  2460. +static inline void unlock_fdc(void)
  2461. +{
  2462. +    if (!fdc_busy)
  2463. +        DPRINT("FDC access conflict!\n");
  2464. +
  2465. +    if ( DEVICE_INTR )
  2466. +        DPRINT1("device interrupt still active at FDC release: %p!\n",
  2467. +            DEVICE_INTR);
  2468. +    command_status = FD_COMMAND_NONE;
  2469. +    timer_active &= ~(1 << FLOPPY_TIMER);
  2470. +    fdc_busy = 0;
  2471. +    floppy_release_irq_and_dma();
  2472. +    wake_up(&fdc_wait);
  2473. +}
  2474. +
  2475. +/* switches the motor off after a given timeout */
  2476. +static void motor_off_callback(unsigned long nr)
  2477. +{
  2478. +    unsigned char mask = ~(0x10 << UNIT(nr));
  2479. +
  2480. +    if(locked)
  2481. +        floppy_off(nr);
  2482. +    else
  2483. +        set_dor( FDC(nr), mask, 0 );
  2484. +}
  2485. +
  2486. +static struct timer_list motor_off_timer[N_DRIVE] = {
  2487. +    { NULL, NULL, 0, 0, motor_off_callback },
  2488. +    { NULL, NULL, 0, 1, motor_off_callback },
  2489. +    { NULL, NULL, 0, 2, motor_off_callback },
  2490. +    { NULL, NULL, 0, 3, motor_off_callback }
  2491. +#ifdef HAVE_2_CONTROLLERS
  2492. +    ,
  2493. +    { NULL, NULL, 0, 4, motor_off_callback },
  2494. +    { NULL, NULL, 0, 5, motor_off_callback },
  2495. +    { NULL, NULL, 0, 6, motor_off_callback },
  2496. +    { NULL, NULL, 0, 7, motor_off_callback }
  2497. +#endif
  2498. +};
  2499. +
  2500. +/* schedules motor off */
  2501. +static void floppy_off(unsigned int nr)
  2502. +{
  2503. +    unsigned long volatile delta;
  2504. +    register int fdc=FDC(nr);
  2505. +
  2506. +    if( !(FDCS->dor & ( 0x10 << UNIT(nr))))
  2507. +        return;
  2508. +
  2509. +    del_timer(motor_off_timer+nr);
  2510. +
  2511. +    /* make spindle stop in a position which minimizes spinup time
  2512. +     * next time */
  2513. +    if ( drive_params[nr].rps ){
  2514. +        delta = jiffies - drive_state[nr].first_read_date + HZ -
  2515. +            drive_params[nr].spindown_offset;
  2516. +        delta = (( delta * drive_params[nr].rps) % HZ ) /
  2517. +            drive_params[nr].rps;
  2518. +        motor_off_timer[nr].expires = drive_params[nr].spindown - delta;
  2519. +    }
  2520. +    add_timer(motor_off_timer+nr);
  2521. +}
  2522. +
  2523. +/*
  2524. + * cycle through all N_DRIVE floppy drives, for disk change testing.
  2525. + * stopping at current drive. This is done before any long operation, to
  2526. + * be sure to have up to date disk change information.
  2527. + */
  2528. +static void scandrives(void)
  2529. +{
  2530. +    int i, drive, saved_drive;
  2531. +
  2532. +    saved_drive = current_drive % N_DRIVE;
  2533. +    for(i=0; i< N_DRIVE; i++){
  2534. +        drive = (saved_drive + i + 1 ) % N_DRIVE;
  2535. +        if ( UDRS->fd_ref == 0 )
  2536. +            continue; /* skip closed drives */
  2537. +        set_fdc(drive);
  2538. +        if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
  2539. +            ((FDCS->dor & 0x3) != UNIT(drive)))
  2540. +            UDRS->select_date = jiffies;
  2541. +        if(! (set_dor( fdc, ~3, UNIT(drive) | ( 0x10 << UNIT(drive))) &
  2542. +              (0x10 << UNIT(drive))))
  2543. +            /* switch the motor off again, if it was off to
  2544. +             * begin with */
  2545. +            set_dor( fdc, ~( 0x10 << UNIT(drive) ), 0 );
  2546. +    }
  2547. +    current_drive = saved_drive;
  2548. +}
  2549. +
  2550. +typedef void (*timeout_fn)(unsigned long);
  2551. +static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 };
  2552. +
  2553. +/* this function makes sure that the disk stays in the drive during the
  2554. + * transfer */
  2555. +static void fd_watchdog(void)
  2556. +{
  2557. +    if ( disk_change(current_drive) ){
  2558. +        DPRINT("disk removed during i/o\n");
  2559. +        floppy_shutdown();
  2560. +    } else {
  2561. +        del_timer(&fd_timer);
  2562. +        fd_timer.function = (timeout_fn) fd_watchdog;
  2563. +        fd_timer.expires = 10;
  2564. +        add_timer(&fd_timer);
  2565. +    }
  2566. +}
  2567. +
  2568. +static void main_command_interrupt(void)
  2569. +{
  2570. +    del_timer(&fd_timer);
  2571. +    cont->interrupt();
  2572. +}
  2573. +
  2574. +/* waits for a delay (spinup or select) to pass */
  2575. +static int wait_for_completion(int nr, int delay, timeout_fn function)
  2576. +{
  2577. +    if ( FDCS->reset ){
  2578. +        reset_fdc(); /* do the reset during sleep to win time
  2579. +                  * if we don't need to sleep, it's a good
  2580. +                  * occasion anyways */
  2581. +        return 1;
  2582. +    }
  2583. +
  2584. +    if ( jiffies < delay ){
  2585. +        del_timer(&fd_timer);
  2586. +        fd_timer.function = function;
  2587. +        fd_timer.expires = delay  - jiffies;
  2588. +        add_timer(&fd_timer);
  2589. +        return 1;
  2590. +    }
  2591. +    return 0;
  2592. +}
  2593. +
  2594. +static void setup_DMA(void)
  2595. +{
  2596. +#ifdef SANITY
  2597. +    if ((!CURRENT ||
  2598. +         CURRENT->buffer != current_addr ||
  2599. +         raw_cmd.length > 512 * CURRENT->nr_sectors) &&
  2600. +        (current_addr < floppy_track_buffer ||
  2601. +         current_addr + raw_cmd.length >
  2602. +         floppy_track_buffer + 1024 * max_buffer_sectors)){
  2603. +        printk("bad address. start=%p lg=%lx tb=%p\n",
  2604. +               current_addr, raw_cmd.length, floppy_track_buffer);
  2605. +        if ( CURRENT ){
  2606. +            printk("buffer=%p nr=%lx cnr=%lx\n",
  2607. +                   CURRENT->buffer, CURRENT->nr_sectors,
  2608. +                   CURRENT->current_nr_sectors);
  2609. +        }
  2610. +        cont->done(0);
  2611. +        FDCS->reset=1;
  2612. +        return;
  2613. +    }
  2614. +#if 0
  2615. +    if ((long) current_addr % 512 ){
  2616. +        printk("non aligned address: %p\n", current_addr );
  2617. +        cont->done(0);
  2618. +        FDCS->reset=1;
  2619. +        return;
  2620. +    }
  2621. +    if ( ( (long)current_addr & ~(64*1024-1) ) !=
  2622. +        ((long)(current_addr + raw_cmd.length-1)  & ~(64*1024-1))){
  2623. +        printk("DMA crossing 64-K boundary %p-%p\n",
  2624. +               current_addr, current_addr + raw_cmd.length);
  2625. +        cont->done(0);
  2626. +        FDCS->reset=1;
  2627. +        return;
  2628. +    }
  2629. +#endif
  2630. +#endif
  2631. +    cli();
  2632. +    disable_dma(FLOPPY_DMA);
  2633. +    clear_dma_ff(FLOPPY_DMA);
  2634. +    set_dma_mode(FLOPPY_DMA,
  2635. +             (raw_cmd.flags & FD_RAW_READ)?
  2636. +             DMA_MODE_READ : DMA_MODE_WRITE);
  2637. +    set_dma_addr(FLOPPY_DMA, (long) current_addr);
  2638. +    set_dma_count(FLOPPY_DMA, raw_cmd.length);
  2639. +    enable_dma(FLOPPY_DMA);
  2640. +    sti();
  2641. +}
  2642. +
  2643. +/* sends a command byte to the fdc */
  2644. +static int output_byte(char byte)
  2645. +{
  2646. +    int counter;
  2647. +    unsigned char status;
  2648. +
  2649. +    if (FDCS->reset)
  2650. +        return -1;
  2651. +    for(counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
  2652. +        status = inb_p(FD_STATUS) &(STATUS_READY|STATUS_DIR|STATUS_DMA);
  2653. +        if (status == STATUS_READY){
  2654. +            outb_p(byte,FD_DATA);
  2655. +            return 0;
  2656. +        }
  2657. +        if (!(status & STATUS_READY))
  2658. +            continue;
  2659. +        break;
  2660. +    }
  2661. +    FDCS->reset = 1;
  2662. +    if ( !initialising )
  2663. +        DPRINT2("Unable to send byte %x to FDC. Status=%x\n",
  2664. +            byte, status);
  2665. +    return -1;
  2666. +}
  2667. +#define LAST_OUT(x) if(output_byte(x)){ reset_fdc();return;}
  2668. +
  2669. +/* gets the response from the fdc */
  2670. +static int result(void)
  2671. +{
  2672. +    int i = 0, counter, status;
  2673. +
  2674. +    if (FDCS->reset)
  2675. +        return -1;
  2676. +    for (counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
  2677. +        status = inb_p(FD_STATUS)&
  2678. +            (STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA);
  2679. +        if (!(status & STATUS_READY))
  2680. +            continue;
  2681. +        if (status == STATUS_READY)
  2682. +            return i;
  2683. +        if (status & STATUS_DMA )
  2684. +            break;
  2685. +        if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
  2686. +            if (i >= MAX_REPLIES) {
  2687. +                DPRINT("floppy_stat reply overrun\n");
  2688. +                break;
  2689. +            }
  2690. +            reply_buffer[i++] = inb_p(FD_DATA);
  2691. +        }
  2692. +    }
  2693. +    FDCS->reset = 1;
  2694. +    if ( !initialising )
  2695. +        DPRINT3("Getstatus times out (%x) on fdc %d [%d]\n",
  2696. +            status, fdc, i);
  2697. +    return -1;
  2698. +}
  2699. +
  2700. +/* Set perpendicular mode as required, based on data rate, if supported.
  2701. + * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
  2702. + */
  2703. +static inline void perpendicular_mode(void)
  2704. +{
  2705. +    unsigned char perp_mode;
  2706. +
  2707. +    if (!floppy)
  2708. +        return;
  2709. +    if (floppy->rate & 0x40){
  2710. +        switch(raw_cmd.rate){
  2711. +        case 0:
  2712. +            perp_mode=2;
  2713. +            break;
  2714. +        case 3:
  2715. +            perp_mode=3;
  2716. +            break;
  2717. +        default:
  2718. +            DPRINT("Invalid data rate for perpendicular mode!\n");
  2719. +            cont->done(0);
  2720. +            FDCS->reset = 1; /* convenient way to return to
  2721. +                      * redo without to much hassle (deep
  2722. +                      * stack et al. */
  2723. +            return;
  2724. +        }
  2725. +    } else
  2726. +        perp_mode = 0;
  2727. +
  2728. +    if ( FDCS->perp_mode == perp_mode )
  2729. +        return;
  2730. +    if (FDCS->version >= FDC_82077_ORIG && FDCS->has_fifo) {
  2731. +        output_byte(FD_PERPENDICULAR);
  2732. +        output_byte(perp_mode);
  2733. +        FDCS->perp_mode = perp_mode;
  2734. +    } else if (perp_mode) {
  2735. +        DPRINT("perpendicular mode not supported by this FDC.\n");
  2736. +    }
  2737. +} /* perpendicular_mode */
  2738. +
  2739. +#define NOMINAL_DTR 500
  2740. +
  2741. +/* Issue a "SPECIFY" command to set the step rate time, head unload time,
  2742. + * head load time, and DMA disable flag to values needed by floppy.
  2743. + *
  2744. + * The value "dtr" is the data transfer rate in Kbps.  It is needed
  2745. + * to account for the data rate-based scaling done by the 82072 and 82077
  2746. + * FDC types.  This parameter is ignored for other types of FDCs (i.e.
  2747. + * 8272a).
  2748. + *
  2749. + * Note that changing the data transfer rate has a (probably deleterious)
  2750. + * effect on the parameters subject to scaling for 82072/82077 FDCs, so
  2751. + * fdc_specify is called again after each data transfer rate
  2752. + * change.
  2753. + *
  2754. + * srt: 1000 to 16000 in microseconds
  2755. + * hut: 16 to 240 milliseconds
  2756. + * hlt: 2 to 254 milliseconds
  2757. + *
  2758. + * These values are rounded up to the next highest available delay time.
  2759. + */
  2760. +static void fdc_specify(void)
  2761. +{
  2762. +    unsigned char spec1, spec2;
  2763. +    int srt, hlt, hut;
  2764. +    unsigned long dtr = NOMINAL_DTR;
  2765. +    unsigned long scale_dtr = NOMINAL_DTR;
  2766. +    int hlt_max_code = 0x7f;
  2767. +    int hut_max_code = 0xf;
  2768. +
  2769. +    if (FDCS->need_configure && FDCS->has_fifo) {
  2770. +        if ( FDCS->reset )
  2771. +            return;
  2772. +        /* Turn on FIFO for 82077-class FDC (improves performance) */
  2773. +        /* TODO: lock this in via LOCK during initialization */
  2774. +        output_byte(FD_CONFIGURE);
  2775. +        output_byte(0);
  2776. +        output_byte(0x1A);    /* FIFO on, polling off, 10 byte threshold */
  2777. +        output_byte(0);        /* precompensation from track 0 upwards */
  2778. +        if ( FDCS->reset ){
  2779. +            FDCS->has_fifo=0;
  2780. +            return;
  2781. +        }
  2782. +        FDCS->need_configure = 0;
  2783. +        /*DPRINT("FIFO enabled\n");*/
  2784. +    }
  2785. +
  2786. +    switch (raw_cmd.rate & 0x03) {
  2787. +    case 3:
  2788. +        dtr = 1000;
  2789. +        break;
  2790. +    case 1:
  2791. +        dtr = 300;
  2792. +        break;
  2793. +    case 2:
  2794. +        dtr = 250;
  2795. +        break;
  2796. +    }
  2797. +
  2798. +    if (FDCS->version >= FDC_82072) {
  2799. +        scale_dtr = dtr;
  2800. +        hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
  2801. +        hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
  2802. +    }
  2803. +
  2804. +    /* Convert step rate from microseconds to milliseconds and 4 bits */
  2805. +    srt = 16 - (DP->srt*scale_dtr/1000 + NOMINAL_DTR - 1)/NOMINAL_DTR;
  2806. +    if (srt > 0xf)
  2807. +        srt = 0xf;
  2808. +    else if (srt < 0)
  2809. +        srt = 0;
  2810. +
  2811. +    hlt = (DP->hlt*scale_dtr/2 + NOMINAL_DTR - 1)/NOMINAL_DTR;
  2812. +    if (hlt < 0x01)
  2813. +        hlt = 0x01;
  2814. +    else if (hlt > 0x7f)
  2815. +        hlt = hlt_max_code;
  2816. +
  2817. +    hut = (DP->hut*scale_dtr/16 + NOMINAL_DTR - 1)/NOMINAL_DTR;
  2818. +    if (hut < 0x1)
  2819. +        hut = 0x1;
  2820. +    else if (hut > 0xf)
  2821. +        hut = hut_max_code;
  2822. +
  2823. +    spec1 = (srt << 4) | hut;
  2824. +    spec2 = (hlt << 1);
  2825. +
  2826. +    /* If these parameters did not change, just return with success */
  2827. +    if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
  2828. +        /* Go ahead and set spec1 and spec2 */
  2829. +        output_byte(FD_SPECIFY);
  2830. +        output_byte(FDCS->spec1 = spec1);
  2831. +        output_byte(FDCS->spec2 = spec2);
  2832. +    }
  2833. +} /* fdc_specify */
  2834. +
  2835. +/* Set the FDC's data transfer rate on behalf of the specified drive.
  2836. + * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
  2837. + * of the specify command (i.e. using the fdc_specify function).
  2838. + */
  2839. +static void fdc_dtr(void)
  2840. +{
  2841. +    /* If data rate not already set to desired value, set it. */
  2842. +    if ( raw_cmd.rate == FDCS->dtr)
  2843. +        return;
  2844. +
  2845. +    /* Set dtr */
  2846. +    outb_p(raw_cmd.rate, FD_DCR);
  2847. +
  2848. +    /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
  2849. +     * need a stabilization period of several milliseconds to be
  2850. +     * enforced after data rate changes before R/W operations.
  2851. +     * Pause 5 msec to avoid trouble.
  2852. +     */
  2853. +    udelay(5000);
  2854. +    FDCS->dtr = raw_cmd.rate;
  2855. +} /* fdc_dtr */
  2856. +
  2857. +static void tell_sector(void)
  2858. +{
  2859. +    printk(": track %d, head %d, sector %d, size %d",
  2860. +           R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
  2861. +} /* tell_sector */
  2862. +
  2863. +
  2864. +/*
  2865. + * Ok, this error interpreting routine is called after a
  2866. + * DMA read/write has succeeded
  2867. + * or failed, so we check the results, and copy any buffers.
  2868. + * hhb: Added better error reporting.
  2869. + * ak: Made this into a separate routine.
  2870. + */
  2871. +static int interpret_errors(void)
  2872. +{
  2873. +    char bad;
  2874. +int res = get_dma_residue(FLOPPY_DMA);
  2875. +if(res) {printk("\n-- DMA residue (%d)",res); tell_sector(); printk("\n");}
  2876. +    if (inr!=7) {
  2877. +        DPRINT("-- FDC reply error");
  2878. +        FDCS->reset = 1;
  2879. +        return 1;
  2880. +    }
  2881. +
  2882. +    /* check IC to find cause of interrupt */
  2883. +    switch ((ST0 & ST0_INTR)>>6) {
  2884. +        case 1:    /* error occured during command execution */
  2885. +            bad = 1;
  2886. +            if (ST1 & ST1_WP) {
  2887. +                DPRINT("Drive is write protected\n");
  2888. +                DRS->flags &= ~FD_DISK_WRITABLE;
  2889. +                cont->done(0);
  2890. +                bad = 2;
  2891. +            } else if (ST1 & ST1_ND) {
  2892. +                DRS->flags |= FD_NEED_TWADDLE;
  2893. +            } else if (ST1 & ST1_OR) {
  2894. +                if (DP->flags & FTD_MSG )
  2895. +                    DPRINT("Over/Underrun - retrying\n");
  2896. +                bad = 0;
  2897. +            }else if(*errors >= DP->max_errors.reporting){
  2898. +                DPRINT("");
  2899. +                if (ST0 & ST0_ECE) {
  2900. +                    printk("Recalibrate failed!");
  2901. +                } else if (ST2 & ST2_CRC) {
  2902. +                    printk("data CRC error");
  2903. +                    tell_sector();
  2904. +                } else if (ST1 & ST1_CRC) {
  2905. +                    printk("CRC error");
  2906. +                    tell_sector();
  2907. +                } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) {
  2908. +                    if (!probing) {
  2909. +                        printk("sector not found");
  2910. +                        tell_sector();
  2911. +                    } else
  2912. +                        printk("probe failed...");
  2913. +                } else if (ST2 & ST2_WC) {    /* seek error */
  2914. +                    printk("wrong cylinder");
  2915. +                } else if (ST2 & ST2_BC) {    /* cylinder marked as bad */
  2916. +                    printk("bad cylinder");
  2917. +                } else {
  2918. +                    printk("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x", ST0, ST1, ST2);
  2919. +                    tell_sector();
  2920. +                }
  2921. +                printk("\n");
  2922. +
  2923. +            }
  2924. +            if ( ST2 & ST2_WC || ST2 & ST2_BC)
  2925. +{
  2926. +printk("Wrong cylinder!\n");
  2927. +                /* wrong cylinder => recal */
  2928. +                DRS->track = NEED_2_RECAL;
  2929. +}
  2930. +            return bad;
  2931. +        case 2: /* invalid command given */
  2932. +            DPRINT("Invalid FDC command given!\n");
  2933. +            cont->done(0);
  2934. +            return 2;
  2935. +        case 3:
  2936. +            DPRINT("Abnormal termination caused by polling\n");
  2937. +            cont->error();
  2938. +            return 2;
  2939. +        default: /* (0) Normal command termination */
  2940. +            return 0;
  2941. +    }
  2942. +}
  2943. +
  2944. +/*
  2945. + * This routine is called when everything should be correctly set up
  2946. + * for the transfer (ie floppy motor is on, the correct floppy is
  2947. + * selected, and the head is sitting on the right track).
  2948. + */
  2949. +static void setup_rw_floppy(void)
  2950. +{
  2951. +    int i,ready_date,r, flags,dflags;
  2952. +    timeout_fn function;
  2953. +
  2954. +    flags = raw_cmd.flags;
  2955. +    if ( flags & ( FD_RAW_READ | FD_RAW_WRITE))
  2956. +        flags |= FD_RAW_INTR;
  2957. +
  2958. +    if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)){
  2959. +        ready_date = DRS->spinup_date + DP->spinup;
  2960. +        /* If spinup will take a long time, rerun scandrives
  2961. +         * again just before spinup completion. Beware that
  2962. +         * after scandrives, we must again wait for selection.
  2963. +         */
  2964. +        if ( ready_date > jiffies + DP->select_delay){
  2965. +            ready_date -= DP->select_delay;
  2966. +            function = (timeout_fn) floppy_start;
  2967. +        } else
  2968. +            function = (timeout_fn) setup_rw_floppy;
  2969. +
  2970. +        /* wait until the floppy is spinning fast enough */
  2971. +        if (wait_for_completion(current_drive,ready_date,function))
  2972. +            return;
  2973. +    }
  2974. +    dflags = DRS->flags;
  2975. +
  2976. +    if ( (flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
  2977. +        setup_DMA();
  2978. +
  2979. +    if ( flags & FD_RAW_INTR )
  2980. +        SET_INTR(main_command_interrupt);
  2981. +
  2982. +    r=0;
  2983. +    for(i=0; i< raw_cmd.cmd_count; i++)
  2984. +        r|=output_byte( raw_cmd.cmd[i] );
  2985. +
  2986. +#ifdef DEBUGT
  2987. +    debugt("rw_command: ");
  2988. +#endif
  2989. +    if ( r ){
  2990. +        reset_fdc();
  2991. +        return;
  2992. +    }
  2993. +
  2994. +    if ( ! ( flags & FD_RAW_INTR )){
  2995. +        inr = result();
  2996. +        cont->interrupt();
  2997. +    } else if ( flags & FD_RAW_NEED_DISK )
  2998. +        fd_watchdog();
  2999. +}
  3000. +
  3001. +#ifdef SILENT_DC_CLEAR
  3002. +static int blind_seek;
  3003. +#endif
  3004. +
  3005. +/*
  3006. + * This is the routine called after every seek (or recalibrate) interrupt
  3007. + * from the floppy controller.
  3008. + */
  3009. +static void seek_interrupt(void)
  3010. +{
  3011. +#ifdef DEBUGT
  3012. +    debugt("seek interrupt:");
  3013. +#endif
  3014. +#ifdef SILENT_DC_CLEAR
  3015. +    set_dor(fdc, ~0,  (0x10 << UNIT(current_drive)));
  3016. +#endif
  3017. +    if (inr != 2 || (ST0 & 0xF8) != 0x20 ) {
  3018. +        DPRINT("seek failed\n");
  3019. +        DRS->track = NEED_2_RECAL;
  3020. +        cont->error();
  3021. +        cont->redo();
  3022. +        return;
  3023. +    }
  3024. +    if (DRS->track >= 0 && DRS->track != ST1
  3025. +#ifdef SILENT_DC_CLEAR
  3026. +        && !blind_seek
  3027. +#endif
  3028. +        )
  3029. +        DRS->flags &= ~FD_DISK_NEWCHANGE; /* effective seek */
  3030. +    DRS->track = ST1;
  3031. +    DRS->select_date = jiffies;
  3032. +    seek_floppy();
  3033. +}
  3034. +
  3035. +static void check_wp(void)
  3036. +{
  3037. +    if (DRS->flags & FD_VERIFY) {
  3038. +        /* check write protection */
  3039. +        output_byte( FD_GETSTATUS );
  3040. +        output_byte( UNIT(current_drive) );
  3041. +        if ( result() != 1 ){
  3042. +            FDCS->reset = 1;
  3043. +            return;
  3044. +        }
  3045. +        DRS->flags &= ~(FD_VERIFY | FD_DISK_WRITABLE | FD_NEED_TWADDLE);
  3046. +
  3047. +        if (!( ST3  & 0x40))
  3048. +            DRS->flags |= FD_DISK_WRITABLE;
  3049. +    }
  3050. +}
  3051. +
  3052. +static void seek_floppy(void)
  3053. +{
  3054. +    int track;
  3055. +
  3056. +#ifdef SILENT_DC_CLEAR
  3057. +    blind_seek=0;
  3058. +#endif
  3059. +    disk_change(current_drive);
  3060. +    if ((raw_cmd.flags & FD_RAW_NEED_DISK) &&
  3061. +        test_bit(current_drive,&changed_floppies)){
  3062. +        /* the media changed flag should be cleared after the seek.
  3063. +         * If it isn't, this means that there is really no disk in
  3064. +         * the drive.
  3065. +         */
  3066. +        cont->done(0);
  3067. +        cont->redo();
  3068. +        return;
  3069. +    }
  3070. +    if ( DRS->track <= NEED_1_RECAL ){
  3071. +        recalibrate_floppy();
  3072. +        return;
  3073. +    } else if ((DRS->flags & FD_DISK_NEWCHANGE) &&
  3074. +           (raw_cmd.flags & FD_RAW_NEED_DISK) &&
  3075. +           (DRS->track <= NO_TRACK || DRS->track == raw_cmd.track)) {
  3076. +        /* we seek to clear the media-changed condition. Does anybody
  3077. +         * know a more elegant way, which works on all drives? */
  3078. +        if ( raw_cmd.track )
  3079. +            track = raw_cmd.track - 1;
  3080. +        else {
  3081. +#ifdef SILENT_DC_CLEAR
  3082. +            set_dor(fdc, ~ (0x10 << UNIT(current_drive)), 0);
  3083. +            blind_seek = 1;
  3084. +#endif
  3085. +            track = 1;
  3086. +        }
  3087. +    } else {
  3088. +        check_wp();
  3089. +        if (raw_cmd.track != DRS->track)
  3090. +            track = raw_cmd.track;
  3091. +        else {
  3092. +            setup_rw_floppy();
  3093. +            return;
  3094. +        }
  3095. +    }
  3096. +
  3097. +#ifndef SILENT_DC_CLEAR
  3098. +    if ( !track && DRS->track >= 0 && DRS->track < 80 ){
  3099. +        DRS->flags &= ~FD_DISK_NEWCHANGE;
  3100. +        /* if we go to track 0 anyways, we can just as well use
  3101. +         * recalibrate */
  3102. +        recalibrate_floppy();
  3103. +    } else
  3104. +#endif
  3105. +    {
  3106. +        SET_INTR(seek_interrupt);
  3107. +        output_byte(FD_SEEK);
  3108. +        output_byte(UNIT(current_drive));
  3109. +        LAST_OUT(track);
  3110. +#ifdef DEBUGT
  3111. +        debugt("seek command:");
  3112. +#endif
  3113. +    }
  3114. +}
  3115. +
  3116. +static void recal_interrupt(void)
  3117. +{
  3118. +#ifdef DEBUGT
  3119. +    debugt("recal interrupt:");
  3120. +#endif
  3121. +    if (inr !=2 )
  3122. +        FDCS->reset = 1;
  3123. +    else if (ST0 & ST0_ECE) {
  3124. +               switch(DRS->track){
  3125. +        case PROVEN_ABSENT:
  3126. +#ifdef DEBUGT
  3127. +            debugt("recal interrupt proven absent:");
  3128. +#endif
  3129. +            /* fall through */
  3130. +               case NEED_1_RECAL:
  3131. +#ifdef DEBUGT
  3132. +            debugt("recal interrupt need 1 recal:");
  3133. +#endif
  3134. +            /* after a second recalibrate, we still haven't
  3135. +             * reached track 0. Probably no drive. Raise an
  3136. +             * error, as failing immediately might upset
  3137. +             * computers possessed by the Devil :-) */
  3138. +            cont->error();
  3139. +            cont->redo();
  3140. +            return;
  3141. +        case NEED_2_RECAL:
  3142. +#ifdef DEBUGT
  3143. +            debugt("recal interrupt need 2 recal:");
  3144. +#endif
  3145. +            /* If we already did a recalibrate, and we are not at
  3146. +             * track 0, this means we have moved. (The only way
  3147. +             * not to move at recalibration is to be already at
  3148. +             * track 0.) Clear the new change flag
  3149. +             */
  3150. +            DRS->flags &= ~FD_DISK_NEWCHANGE;
  3151. +            /* fall through */
  3152. +        default:
  3153. +#ifdef DEBUGT
  3154. +            debugt("recal interrupt default:");
  3155. +#endif
  3156. +            /* Recalibrate moves the head by at most 80 steps. If
  3157. +             * after one recalibrate we don't have reached track
  3158. +             * 0, this might mean that we started beyond track 80.
  3159. +             * Try again.
  3160. +             */
  3161. +            DRS->track = NEED_1_RECAL;
  3162. +            break;
  3163. +        }
  3164. +    } else
  3165. +        DRS->track = ST1;
  3166. +    seek_floppy();
  3167. +}
  3168. +
  3169. +/*
  3170. + * Unexpected interrupt - Print as much debugging info as we can...
  3171. + * All bets are off...
  3172. + */
  3173. +static void unexpected_floppy_interrupt(void)
  3174. +{
  3175. +    int i;
  3176. +    if ( initialising )
  3177. +        return;
  3178. +    cli();
  3179. +    DPRINT("unexpected interrupt\n");
  3180. +    if ( inr >= 0 )
  3181. +        for(i=0; i<inr; i++)
  3182. +            printk("%d %x\n", i, reply_buffer[i] );
  3183. +    while(1){
  3184. +        output_byte(FD_SENSEI);
  3185. +        inr=result();
  3186. +        if ( inr != 2 )
  3187. +            break;
  3188. +        printk("sensei\n");
  3189. +        for(i=0; i<inr; i++)
  3190. +            printk("%d %x\n", i, reply_buffer[i] );
  3191. +    }
  3192. +    FDCS->reset = 1;
  3193. +}
  3194. +
  3195. +struct tq_struct floppy_tq =
  3196. +{ 0, 0, (void (*) (void *)) unexpected_floppy_interrupt, 0 };
  3197. +
  3198. +/* interrupt handler */
  3199. +static void floppy_interrupt(int unused, struct pt_regs *regs)
  3200. +{
  3201. +    void (*handler)(void) = DEVICE_INTR;
  3202. +
  3203. +    CLEAR_INTR;
  3204. +    if ( fdc >= N_FDC ){ /* we don't even know which FDC is the culprit */
  3205. +        printk("floppy interrupt on bizarre fdc\n");
  3206. +        return;
  3207. +    }
  3208. +    inr = result();
  3209. +    if (!handler){
  3210. +        unexpected_floppy_interrupt();
  3211. +        return;
  3212. +    }
  3213. +    if ( inr == 0 ){
  3214. +        do {
  3215. +            output_byte(FD_SENSEI);
  3216. +            inr = result();
  3217. +        } while ( (ST0 & 0x83) != UNIT(current_drive) && inr == 2);
  3218. +    }
  3219. +    floppy_tq.routine = (void (*)(void *)) handler;
  3220. +    queue_task_irq(&floppy_tq, &tq_timer);
  3221. +}
  3222. +
  3223. +static void recalibrate_floppy(void)
  3224. +{
  3225. +#ifdef DEBUGT
  3226. +    debugt("recalibrate floppy:");
  3227. +#endif
  3228. +    SET_INTR(recal_interrupt);
  3229. +    output_byte(FD_RECALIBRATE);
  3230. +    LAST_OUT(UNIT(current_drive));
  3231. +}
  3232. +
  3233. +/*
  3234. + * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
  3235. + */
  3236. +static void reset_interrupt(void)
  3237. +{
  3238. +#ifdef DEBUGT
  3239. +    debugt("reset interrupt:");
  3240. +#endif
  3241. +    fdc_specify();        /* reprogram fdc */
  3242. +    result();        /* get the status ready for set_fdc */
  3243. +    if ( FDCS->reset )
  3244. +        cont->error(); /* a reset just after a reset. BAD! */
  3245. +    cont->redo();
  3246. +}
  3247. +
  3248. +/*
  3249. + * reset is done by pulling bit 2 of DOR low for a while (old FDC's),
  3250. + * or by setting the self clearing bit 7 of STATUS (newer FDC's)
  3251. + */
  3252. +static void reset_fdc(void)
  3253. +{
  3254. +    SET_INTR(reset_interrupt);
  3255. +    FDCS->reset = 0;
  3256. +    reset_fdc_info(0);
  3257. +    if ( FDCS->version >= FDC_82077 )
  3258. +        outb_p(0x80 | ( FDCS->dtr &3), FD_STATUS);
  3259. +    else {
  3260. +        arm_set_dor(FDCS->dor & ~0x04);
  3261. +        udelay(FD_RESET_DELAY);
  3262. +        arm_set_dor(FDCS->dor);
  3263. +    }
  3264. +}
  3265. +
  3266. +static void empty(void)
  3267. +{
  3268. +}
  3269. +
  3270. +void show_floppy(void)
  3271. +{
  3272. +    int i;
  3273. +
  3274. +    printk("\n");
  3275. +    printk("floppy driver state\n");
  3276. +    printk("-------------------\n");
  3277. +    for(i=0; i<N_FDC; i++){
  3278. +        printk("dor %d = %x\n", i, fdc_state[i].dor );
  3279. +        outb_p(fdc_state[i].address+2, fdc_state[i].dor);
  3280. +        udelay(1000); /* maybe we'll catch an interrupt... */
  3281. +    }
  3282. +    printk("status=%x\n", inb_p(FD_STATUS));
  3283. +    printk("fdc_busy=%d\n", fdc_busy);
  3284. +    if( DEVICE_INTR)
  3285. +        printk("DEVICE_INTR=%p\n", DEVICE_INTR);
  3286. +    if(floppy_tq.sync)
  3287. +        printk("floppy_tq.routine=%p\n", floppy_tq.routine);
  3288. +    if(fd_timer.prev)
  3289. +        printk("fd_timer.function=%p\n", fd_timer.function);
  3290. +    if( timer_active & (1 << FLOPPY_TIMER)){
  3291. +        printk("timer_table=%p\n",timer_table[FLOPPY_TIMER].fn);
  3292. +        printk("expires=%ld\n",timer_table[FLOPPY_TIMER].expires);
  3293. +        printk("now=%ld\n",jiffies);
  3294. +    }
  3295. +    printk("cont=%p\n", cont);
  3296. +    printk("CURRENT=%p\n", CURRENT);
  3297. +    printk("command_status=%d\n", command_status);
  3298. +    printk("\n");
  3299. +}
  3300. +
  3301. +static void floppy_shutdown(void)
  3302. +{
  3303. +    CLEAR_INTR;
  3304. +    floppy_tq.routine = (void (*)(void *)) empty;
  3305. +    del_timer( &fd_timer);
  3306. +    disable_dma(FLOPPY_DMA);
  3307. +    /* avoid dma going to a random drive after shutdown */
  3308. +    if(!initialising)
  3309. +        DPRINT("floppy timeout\n");
  3310. +    FDCS->reset = 1;
  3311. +    cont->done(0);
  3312. +    cont->redo(); /* this will recall reset when needed */
  3313. +}
  3314. +
  3315. +/* start motor, check media-changed condition and write protection */
  3316. +static void start_motor(void)
  3317. +{
  3318. +    int mask, data;
  3319. +
  3320. +    mask = 0xfc;
  3321. +    data = UNIT(current_drive);
  3322. +
  3323. +    if ( (FDCS->dor & 0x03) != UNIT(current_drive) ||
  3324. +        !(FDCS->dor & ( 0x10 << UNIT(current_drive) ) ))
  3325. +        /* notes select time if floppy is not yet selected */
  3326. +        DRS->select_date = jiffies;
  3327. +
  3328. +    if (!(raw_cmd.flags & FD_RAW_NO_MOTOR)){
  3329. +        if(!(FDCS->dor & ( 0x10 << UNIT(current_drive) ) )){
  3330. +            set_debugt();
  3331. +            /* no read since this drive is running */
  3332. +            DRS->first_read_date = 0;
  3333. +            /* note motor start time if motor is not yet running */
  3334. +            DRS->spinup_date = jiffies;
  3335. +            data |= (0x10 << UNIT(current_drive));
  3336. +        }
  3337. +    } else
  3338. +        if (FDCS->dor & ( 0x10 << UNIT(current_drive) ) )
  3339. +            mask &= ~(0x10 << UNIT(current_drive));
  3340. +
  3341. +    /* starts motor and selects floppy */
  3342. +    del_timer(motor_off_timer + current_drive);
  3343. +    set_dor( fdc, mask, data);
  3344. +    if( raw_cmd.flags & FD_RAW_NO_MOTOR)
  3345. +        return;
  3346. +
  3347. +    disk_change(current_drive);
  3348. +
  3349. +    return;
  3350. +}
  3351. +
  3352. +static void floppy_ready(void)
  3353. +{
  3354. +    CHECK_RESET;
  3355. +    start_motor();
  3356. +
  3357. +    /* wait_for_completion also schedules reset if needed. */
  3358. +    if(wait_for_completion(current_drive,
  3359. +                   DRS->select_date+DP->select_delay,
  3360. +                   (timeout_fn) floppy_ready))
  3361. +        return;
  3362. +    fdc_dtr();
  3363. +    if ( raw_cmd.flags & FD_RAW_NEED_SEEK ){
  3364. +        perpendicular_mode();
  3365. +        fdc_specify(); /* must be done here because of hut, hlt ... */
  3366. +        seek_floppy();
  3367. +    } else
  3368. +        setup_rw_floppy();
  3369. +}
  3370. +
  3371. +static void floppy_start(void)
  3372. +{
  3373. +    timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout;
  3374. +    timer_active |= 1 << FLOPPY_TIMER;
  3375. +    scandrives();
  3376. +    floppy_ready();
  3377. +}
  3378. +
  3379. +/*
  3380. + * ========================================================================
  3381. + * here ends the bottom half. Exported routines are:
  3382. +  * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
  3383. + * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
  3384. + * Initialisation also uses output_byte, result, set_dor, floppy_interrupt
  3385. + * and set_dor.
  3386. + * ========================================================================
  3387. + */
  3388. +/*
  3389. + * General purpose continuations.
  3390. + * ==============================
  3391. + */
  3392. +
  3393. +static void do_wakeup(void)
  3394. +{
  3395. +    timer_active &= ~(1 << FLOPPY_TIMER);
  3396. +    cont = 0;
  3397. +    command_status += 2;
  3398. +    wake_up(&command_done);
  3399. +}
  3400. +
  3401. +static struct cont_t wakeup_cont={
  3402. +    empty,
  3403. +    do_wakeup,
  3404. +    empty,
  3405. +    (done_f)empty
  3406. +};
  3407. +
  3408. +static int wait_til_done( void (*handler)(void ), int interruptible )
  3409. +{
  3410. +    int ret;
  3411. +
  3412. +    floppy_tq.routine = (void (*)(void *)) handler;
  3413. +    queue_task(&floppy_tq, &tq_timer);
  3414. +
  3415. +    cli();
  3416. +    while(command_status < 2 && NO_SIGNAL)
  3417. +        if (current->pid)
  3418. +            interruptible_sleep_on(&command_done);
  3419. +        else {
  3420. +            sti();
  3421. +            run_task_queue(&tq_timer);
  3422. +            cli();
  3423. +        }
  3424. +    if(command_status < 2){
  3425. +        sti();
  3426. +        floppy_shutdown();
  3427. +        redo_fd_request();
  3428. +        return -EINTR;
  3429. +    }
  3430. +    sti();
  3431. +
  3432. +    if ( FDCS->reset )
  3433. +        command_status = FD_COMMAND_ERROR;
  3434. +    if ( command_status == FD_COMMAND_OKAY )
  3435. +        ret=0;
  3436. +    else
  3437. +        ret=-EIO;
  3438. +    command_status = FD_COMMAND_NONE;
  3439. +    return ret;
  3440. +}
  3441. +
  3442. +static void generic_done(int result)
  3443. +{
  3444. +    command_status = result;
  3445. +    cont = &wakeup_cont;
  3446. +}
  3447. +
  3448. +static void generic_success(void)
  3449. +{
  3450. +    generic_done(1);
  3451. +}
  3452. +
  3453. +static void generic_failure(void)
  3454. +{
  3455. +    generic_done(0);
  3456. +}
  3457. +
  3458. +static void success_and_wakeup(void)
  3459. +{
  3460. +    generic_success();
  3461. +    do_wakeup();
  3462. +}
  3463. +
  3464. +static void failure_and_wakeup(void)
  3465. +{
  3466. +    generic_failure();
  3467. +    do_wakeup();
  3468. +}
  3469. +
  3470. +/*
  3471. + * formatting and rw support.
  3472. + * ==========================
  3473. + */
  3474. +
  3475. +static int next_valid_format(void)
  3476. +{
  3477. +    int probed_format;
  3478. +    while(1){
  3479. +        probed_format = DRS->probed_format;
  3480. +        if ( probed_format > 8 ||
  3481. +            ! DP->autodetect[probed_format] ){
  3482. +            DRS->probed_format = 0;
  3483. +            return 1;
  3484. +        }
  3485. +        if ( floppy_type[DP->autodetect[probed_format]].sect ){
  3486. +            DRS->probed_format = probed_format;
  3487. +            return 0;
  3488. +        }
  3489. +        probed_format++;
  3490. +    }
  3491. +}
  3492. +
  3493. +static void bad_flp_intr(void)
  3494. +{
  3495. +    if ( probing ){
  3496. +        DRS->probed_format++;
  3497. +        if ( !next_valid_format())
  3498. +            return;
  3499. +    }
  3500. +    (*errors)++;
  3501. +    if (*errors > DRWE->badness)
  3502. +            DRWE->badness = *errors;
  3503. +    if (*errors > DP->max_errors.abort)
  3504. +        cont->done(0);
  3505. +    if (*errors > DP->max_errors.reset)
  3506. +        FDCS->reset = 1;
  3507. +    else if (*errors > DP->max_errors.recal)
  3508. +        DRS->track = NEED_2_RECAL;
  3509. +}
  3510. +
  3511. +static void set_floppy(int device)
  3512. +{
  3513. +    if (TYPE(device))
  3514. +        floppy = TYPE(device) + floppy_type;
  3515. +    else
  3516. +        floppy = current_type[ DRIVE(device) ];
  3517. +}
  3518. +
  3519. +/*
  3520. + * formatting and support.
  3521. + * =======================
  3522. + */
  3523. +static void format_interrupt(void)
  3524. +{
  3525. +    switch (interpret_errors()){
  3526. +    case 1:
  3527. +        cont->error();
  3528. +    case 2:
  3529. +        break;
  3530. +    case 0:
  3531. +        cont->done(1);
  3532. +    }
  3533. +    cont->redo();
  3534. +}
  3535. +#define CODE2SIZE (ssize = ( ( 1 << SIZECODE ) + 3 ) >> 2)
  3536. +#define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80 ) >>1))
  3537. +#define CT(x) ( (x) | 0x40 )
  3538. +static void setup_format_params(void)
  3539. +{
  3540. +    struct fparm {
  3541. +        unsigned char track,head,sect,size;
  3542. +    } *here = (struct fparm *)floppy_track_buffer;
  3543. +    int il,n;
  3544. +    int count,head_shift,track_shift;
  3545. +
  3546. +    raw_cmd.flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
  3547. +        /*FD_RAW_NEED_DISK |*/ FD_RAW_NEED_SEEK;
  3548. +    raw_cmd.rate = floppy->rate & 0x3;
  3549. +    raw_cmd.cmd_count = NR_F;
  3550. +    COMMAND = FM_MODE(floppy,FD_FORMAT);
  3551. +    DR_SELECT = UNIT(current_drive) + ( format_req.head << 2 );
  3552. +    F_SIZECODE = FD_SIZECODE(floppy);
  3553. +    F_SECT_PER_TRACK = floppy->sect << 2 >> F_SIZECODE;
  3554. +    F_GAP = floppy->fmt_gap;
  3555. +    F_FILL = FD_FILL_BYTE;
  3556. +
  3557. +    current_addr = floppy_track_buffer;
  3558. +    raw_cmd.length = 4 * F_SECT_PER_TRACK;
  3559. +
  3560. +    /* allow for about 30ms for data transport per track */
  3561. +    head_shift  = (F_SECT_PER_TRACK + 5) / 6;
  3562. +
  3563. +    /* a ``cylinder'' is two tracks plus a little stepping time */
  3564. +    track_shift = 2 * head_shift + 1;
  3565. +
  3566. +    /* position of logical sector 1 on this track */
  3567. +    n = (track_shift * format_req.track + head_shift * format_req.head )
  3568. +        % F_SECT_PER_TRACK;
  3569. +
  3570. +    /* determine interleave */
  3571. +    il = 1;
  3572. +    if (floppy->sect > DP->interleave_sect && F_SIZECODE == 2)
  3573. +        il++;
  3574. +
  3575. +    /* initialize field */
  3576. +    for (count = 0; count < F_SECT_PER_TRACK; ++count) {
  3577. +        here[count].track = format_req.track;
  3578. +        here[count].head = format_req.head;
  3579. +        here[count].sect = 0;
  3580. +        here[count].size = F_SIZECODE;
  3581. +    }
  3582. +    /* place logical sectors */
  3583. +    for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
  3584. +        here[n].sect = count;
  3585. +        n = (n+il) % F_SECT_PER_TRACK;
  3586. +        if (here[n].sect) { /* sector busy, find next free sector */
  3587. +            ++n;
  3588. +            if (n>= F_SECT_PER_TRACK) {
  3589. +                n-=F_SECT_PER_TRACK;
  3590. +                while (here[n].sect) ++n;
  3591. +            }
  3592. +        }
  3593. +    }
  3594. +}
  3595. +
  3596. +static void redo_format(void)
  3597. +{
  3598. +    raw_cmd.track = format_req.track << floppy->stretch;
  3599. +    buffer_track = -1;
  3600. +    setup_format_params();
  3601. +    clear_bit(current_drive, &changed_floppies);
  3602. +    floppy_start();
  3603. +#ifdef DEBUGT
  3604. +    debugt("queue format request");
  3605. +#endif
  3606. +}
  3607. +
  3608. +static struct cont_t format_cont={
  3609. +    format_interrupt,
  3610. +    redo_format,
  3611. +    bad_flp_intr,
  3612. +    generic_done };
  3613. +
  3614. +static int do_format(int device, struct format_descr *tmp_format_req)
  3615. +{
  3616. +    int okay;
  3617. +
  3618. +    LOCK_FDC(DRIVE(device),1);
  3619. +    set_floppy(device);
  3620. +    if (!floppy ||
  3621. +        tmp_format_req->track >= floppy->track ||
  3622. +        tmp_format_req->head >= floppy->head){
  3623. +        redo_fd_request();
  3624. +        return -EINVAL;
  3625. +    }
  3626. +    format_req = *tmp_format_req;
  3627. +    format_errors = 0;
  3628. +    cont = &format_cont;
  3629. +    errors = &format_errors;
  3630. +    CALL(okay=wait_til_done(redo_format,1));
  3631. +    redo_fd_request();
  3632. +    return okay;
  3633. +}
  3634. +
  3635. +/*
  3636. + * Buffer read/write and support
  3637. + * =============================
  3638. + */
  3639. +
  3640. +/* new request_done. Can handle physical sectors which are smaller than a
  3641. + * logical buffer */
  3642. +static void request_done(int uptodate)
  3643. +{
  3644. +    int block;
  3645. +
  3646. +    probing = 0;
  3647. +    timer_active &= ~(1 << FLOPPY_TIMER);
  3648. +
  3649. +    if (!CURRENT){
  3650. +        DPRINT("request list destroyed in floppy request done\n");
  3651. +        return;
  3652. +    }
  3653. +    if (uptodate){
  3654. +        /* maintain values for invalidation on geometry
  3655. +           change */
  3656. +        block = current_count_sectors + CURRENT->sector;
  3657. +        if (block > DRS->maxblock)
  3658. +            DRS->maxblock=block;
  3659. +        if ( block > floppy->sect)
  3660. +            DRS->maxtrack = 1;
  3661. +
  3662. +        /* unlock chained buffers */
  3663. +        while (current_count_sectors && CURRENT &&
  3664. +               current_count_sectors >= CURRENT->current_nr_sectors ){
  3665. +            current_count_sectors -= CURRENT->current_nr_sectors;
  3666. +            CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
  3667. +            CURRENT->sector += CURRENT->current_nr_sectors;
  3668. +            end_request(1);
  3669. +        }
  3670. +        if ( current_count_sectors && CURRENT){
  3671. +            /* "unlock" last subsector */
  3672. +            CURRENT->buffer += current_count_sectors <<9;
  3673. +            CURRENT->current_nr_sectors -= current_count_sectors;
  3674. +            CURRENT->nr_sectors -= current_count_sectors;
  3675. +            CURRENT->sector += current_count_sectors;
  3676. +            return;
  3677. +        }
  3678. +
  3679. +        if ( current_count_sectors && ! CURRENT )
  3680. +            DPRINT("request list destroyed in floppy request done\n");
  3681. +
  3682. +    } else {
  3683. +        if(CURRENT->cmd == WRITE) {
  3684. +            /* record write error information */
  3685. +            DRWE->write_errors++;
  3686. +            if(DRWE->write_errors == 1) {
  3687. +                DRWE->first_error_sector = CURRENT->sector;
  3688. +                DRWE->first_error_generation = DRS->generation;
  3689. +            }
  3690. +            DRWE->last_error_sector = CURRENT->sector;
  3691. +            DRWE->last_error_generation = DRS->generation;
  3692. +        }
  3693. +        end_request(0);
  3694. +    }
  3695. +}
  3696. +
  3697. +/* Interrupt handler evaluating the result of the r/w operation */
  3698. +static void rw_interrupt(void)
  3699. +{
  3700. +    int nr_sectors, ssize;
  3701. +
  3702. +    if ( ! DRS->first_read_date )
  3703. +        DRS->first_read_date = jiffies;
  3704. +
  3705. +    nr_sectors = 0;
  3706. +    CODE2SIZE;
  3707. +    nr_sectors = ((R_TRACK-TRACK)*floppy->head+R_HEAD-HEAD) *
  3708. +        floppy->sect + ((R_SECTOR-SECTOR) <<  SIZECODE >> 2) -
  3709. +            (sector_t % floppy->sect) % ssize;
  3710. +
  3711. +#ifdef SANITY
  3712. +    if ( nr_sectors > current_count_sectors + ssize -
  3713. +        (current_count_sectors + sector_t) % ssize +
  3714. +        sector_t % ssize){
  3715. +        DPRINT2("long rw: %x instead of %lx\n",
  3716. +            nr_sectors, current_count_sectors);
  3717. +        printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
  3718. +        printk("rh=%d h=%d\n", R_HEAD, HEAD);
  3719. +        printk("rt=%d t=%d\n", R_TRACK, TRACK);
  3720. +        printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,
  3721. +               sector_t, ssize);
  3722. +    }
  3723. +#endif
  3724. +    if ( nr_sectors < 0 )
  3725. +        nr_sectors = 0;
  3726. +    if ( nr_sectors < current_count_sectors )
  3727. +        current_count_sectors = nr_sectors;
  3728. +
  3729. +    switch (interpret_errors()){
  3730. +    case 2:
  3731. +        cont->redo();
  3732. +        return;
  3733. +    case 1:
  3734. +        if (  !current_count_sectors){
  3735. +            cont->error();
  3736. +            cont->redo();
  3737. +            return;
  3738. +        }
  3739. +        break;
  3740. +    case 0:
  3741. +        if (  !current_count_sectors){
  3742. +            cont->redo();
  3743. +            return;
  3744. +        }
  3745. +        current_type[current_drive] = floppy;
  3746. +        floppy_sizes[DRIVE(current_drive) + (FDC(current_drive) << 7)] =
  3747. +            floppy->size >> 1;
  3748. +        break;
  3749. +    }
  3750. +
  3751. +    if (probing) {
  3752. +        if (DP->flags & FTD_MSG)
  3753. +            DPRINT2("Auto-detected floppy type %s in fd%d\n",
  3754. +                floppy->name,current_drive);
  3755. +        current_type[current_drive] = floppy;
  3756. +        floppy_sizes[DRIVE(current_drive) + (FDC(current_drive) << 7)] =
  3757. +            floppy->size >> 1;
  3758. +        probing = 0;
  3759. +    }
  3760. +
  3761. +    if ( CT(COMMAND) != FD_READ || current_addr == CURRENT->buffer ){
  3762. +        /* transfer directly from buffer */
  3763. +        cont->done(1);
  3764. +    } else if ( CT(COMMAND) == FD_READ){
  3765. +        buffer_track = raw_cmd.track;
  3766. +        buffer_drive = current_drive;
  3767. +        if ( nr_sectors + sector_t > buffer_max )
  3768. +            buffer_max = nr_sectors + sector_t;
  3769. +    }
  3770. +    cont->redo();
  3771. +}
  3772. +
  3773. +/* Compute maximal contiguous buffer size. */
  3774. +static int buffer_chain_size(void)
  3775. +{
  3776. +    struct buffer_head *bh;
  3777. +    int size;
  3778. +    char *base;
  3779. +
  3780. +    base = CURRENT->buffer;
  3781. +    size = CURRENT->current_nr_sectors << 9;
  3782. +    bh = CURRENT->bh;
  3783. +
  3784. +    if(bh){
  3785. +        bh = bh->b_reqnext;
  3786. +        while ( bh && bh->b_data == base + size ){
  3787. +            size += bh->b_size;
  3788. +            bh = bh->b_reqnext;
  3789. +        }
  3790. +    }
  3791. +    return size >> 9;
  3792. +}
  3793. +
  3794. +/* Compute the maximal transfer size */
  3795. +static int transfer_size(int ssize, int max_sector, int max_size)
  3796. +{
  3797. +    if ( max_sector > sector_t + max_size)
  3798. +        max_sector = sector_t + max_size;
  3799. +
  3800. +    /* alignment */
  3801. +    max_sector -= (max_sector % floppy->sect ) % ssize;
  3802. +
  3803. +    /* transfer size, beginning not aligned */
  3804. +    current_count_sectors = max_sector - sector_t ;
  3805. +
  3806. +    return max_sector;
  3807. +}
  3808. +
  3809. +/*
  3810. + * Move data from/to the track buffer to/from the buffer cache.
  3811. + */
  3812. +static void copy_buffer(int ssize, int max_sector, int max_sector_2)
  3813. +{
  3814. +    int remaining; /* number of transferred 512-byte sectors */
  3815. +    struct buffer_head *bh;
  3816. +    char *buffer, *dma_buffer;
  3817. +    int size;
  3818. +
  3819. +    if ( max_sector > max_sector_2 )
  3820. +        max_sector = max_sector_2;
  3821. +
  3822. +    max_sector = transfer_size(ssize, max_sector, CURRENT->nr_sectors);
  3823. +
  3824. +    if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
  3825. +        buffer_max > sector_t + CURRENT->nr_sectors){
  3826. +        current_count_sectors = buffer_max - sector_t;
  3827. +        if ( current_count_sectors > CURRENT->nr_sectors )
  3828. +            current_count_sectors = CURRENT->nr_sectors;
  3829. +    }
  3830. +    remaining = current_count_sectors << 9;
  3831. +#ifdef SANITY
  3832. +    if ((remaining >> 9) > CURRENT->nr_sectors  &&
  3833. +        CT(COMMAND) == FD_WRITE ){
  3834. +        DPRINT("in copy buffer\n");
  3835. +        printk("current_count_sectors=%ld\n", current_count_sectors);
  3836. +        printk("remaining=%d\n", remaining >> 9);
  3837. +        printk("CURRENT->nr_sectors=%ld\n",CURRENT->nr_sectors);
  3838. +        printk("CURRENT->current_nr_sectors=%ld\n",
  3839. +               CURRENT->current_nr_sectors);
  3840. +        printk("max_sector=%d\n", max_sector);
  3841. +        printk("ssize=%d\n", ssize);
  3842. +    }
  3843. +#endif
  3844. +
  3845. +    if ( max_sector > buffer_max )
  3846. +        buffer_max = max_sector;
  3847. +
  3848. +    dma_buffer = floppy_track_buffer + ((sector_t - buffer_min) << 9);
  3849. +
  3850. +    bh = CURRENT->bh;
  3851. +    size = CURRENT->current_nr_sectors << 9;
  3852. +    buffer = CURRENT->buffer;
  3853. +
  3854. +    while ( remaining > 0){
  3855. +        if ( size > remaining )
  3856. +            size = remaining;
  3857. +#ifdef SANITY
  3858. +        if (dma_buffer + size >
  3859. +            floppy_track_buffer + (max_buffer_sectors << 10) ||
  3860. +            dma_buffer < floppy_track_buffer ){
  3861. +            DPRINT1("buffer overrun in copy buffer %d\n",
  3862. +                (floppy_track_buffer - dma_buffer) >>9);
  3863. +            printk("sector_t=%d buffer_min=%d\n",
  3864. +                   sector_t, buffer_min);
  3865. +            printk("current_count_sectors=%ld\n",
  3866. +                   current_count_sectors);
  3867. +            if ( CT(COMMAND) == FD_READ )
  3868. +                printk("read\n");
  3869. +            if ( CT(COMMAND) == FD_READ )
  3870. +                printk("write\n");
  3871. +            break;
  3872. +        }
  3873. +        if ( ((int)buffer) % 512 )
  3874. +            DPRINT1("%p buffer not aligned\n", buffer);
  3875. +#endif
  3876. +        if ( CT(COMMAND) == FD_READ )
  3877. +            memcpy( buffer, dma_buffer, size);
  3878. +        else
  3879. +            memcpy( dma_buffer, buffer, size);
  3880. +        remaining -= size;
  3881. +        if ( !remaining)
  3882. +            break;
  3883. +
  3884. +        dma_buffer += size;
  3885. +        bh = bh->b_reqnext;
  3886. +#ifdef SANITY
  3887. +        if ( !bh){
  3888. +            DPRINT("bh=null in copy buffer after copy\n");
  3889. +            break;
  3890. +        }
  3891. +#endif
  3892. +        size = bh->b_size;
  3893. +        buffer = bh->b_data;
  3894. +    }
  3895. +#ifdef SANITY
  3896. +    if ( remaining ){
  3897. +        if ( remaining > 0 )
  3898. +            max_sector -= remaining >> 9;
  3899. +        DPRINT1("weirdness: remaining %d\n", remaining>>9);
  3900. +    }
  3901. +#endif
  3902. +}
  3903. +
  3904. +/*
  3905. + * Formulate a read/write request.
  3906. + * this routine decides where to load the data (directly to buffer, or to
  3907. + * tmp floppy area), how much data to load (the size of the buffer, the whole
  3908. + * track, or a single sector)
  3909. + * All floppy_track_buffer handling goes in here. If we ever add track buffer
  3910. + * allocation on the fly, it should be done here. No other part should need
  3911. + * modification.
  3912. + */
  3913. +
  3914. +static int make_raw_rw_request(void)
  3915. +{
  3916. +    int aligned_sector_t;
  3917. +    int max_sector, max_size, tracksize, ssize;
  3918. +
  3919. +    current_drive = DRIVE(CURRENT->dev);
  3920. +
  3921. +    raw_cmd.flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
  3922. +        FD_RAW_NEED_SEEK;
  3923. +    raw_cmd.cmd_count = NR_RW;
  3924. +    if (CURRENT->cmd == READ){
  3925. +        raw_cmd.flags |= FD_RAW_READ;
  3926. +        COMMAND = FM_MODE(floppy,FD_READ);
  3927. +    } else if (CURRENT->cmd == WRITE){
  3928. +        raw_cmd.flags |= FD_RAW_WRITE;
  3929. +        COMMAND = FM_MODE(floppy,FD_WRITE);
  3930. +    } else {
  3931. +        DPRINT("make_raw_rw_request: unknown command\n");
  3932. +        return 0;
  3933. +    }
  3934. +
  3935. +    max_sector = floppy->sect * floppy->head;
  3936. +    TRACK = CURRENT->sector / max_sector;
  3937. +    sector_t = CURRENT->sector % max_sector;
  3938. +    if ( floppy->track && TRACK >= floppy->track )
  3939. +        return 0;
  3940. +    HEAD = sector_t / floppy->sect;
  3941. +
  3942. +    if ( (DRS->flags & FD_NEED_TWADDLE) && sector_t < floppy->sect )
  3943. +        max_sector = floppy->sect;
  3944. +
  3945. +    /* 2M disks have phantom sectors on the first track */
  3946. +    if ( (floppy->rate & FD_2M ) && (!TRACK) && (!HEAD)){
  3947. +        max_sector = 2 * floppy->sect / 3;
  3948. +        if (sector_t >= max_sector){
  3949. +            current_count_sectors =  (floppy->sect - sector_t);
  3950. +            if ( current_count_sectors > CURRENT->nr_sectors )
  3951. +                current_count_sectors = CURRENT->nr_sectors;
  3952. +            return 1;
  3953. +        }
  3954. +        SIZECODE = 2;
  3955. +    } else
  3956. +        SIZECODE = FD_SIZECODE(floppy);
  3957. +    raw_cmd.rate = floppy->rate & 3;
  3958. +    if ((floppy->rate & FD_2M) &&
  3959. +        (TRACK || HEAD ) &&
  3960. +        raw_cmd.rate == 2)
  3961. +        raw_cmd.rate = 1;
  3962. +
  3963. +    if ( SIZECODE )
  3964. +        SIZECODE2 = 0xff;
  3965. +    else
  3966. +        SIZECODE2 = 0x80;
  3967. +    raw_cmd.track = TRACK << floppy->stretch;
  3968. +    DR_SELECT = UNIT(current_drive) + ( HEAD << 2 );
  3969. +    GAP = floppy->gap;
  3970. +    CODE2SIZE;
  3971. +    SECT_PER_TRACK = floppy->sect << 2 >> SIZECODE;
  3972. +    SECTOR = ((sector_t % floppy->sect) << 2 >> SIZECODE) + 1;
  3973. +    tracksize = floppy->sect - floppy->sect % ssize;
  3974. +    if ( tracksize < floppy->sect ){
  3975. +        SECT_PER_TRACK ++;
  3976. +        if (  tracksize <= sector_t % floppy->sect)
  3977. +            SECTOR--;
  3978. +        while ( tracksize <= sector_t % floppy->sect){
  3979. +            while( tracksize + ssize > floppy->sect ){
  3980. +                SIZECODE--;
  3981. +                ssize >>= 1;
  3982. +            }
  3983. +            SECTOR++; SECT_PER_TRACK ++;
  3984. +            tracksize += ssize;
  3985. +        }
  3986. +        max_sector = HEAD * floppy->sect + tracksize;
  3987. +    } else if ( !TRACK && !HEAD && !( floppy->rate & FD_2M ) && probing)
  3988. +        max_sector = floppy->sect;
  3989. +
  3990. +    aligned_sector_t = sector_t - ( sector_t % floppy->sect ) % ssize;
  3991. +    max_size = CURRENT->nr_sectors;
  3992. +    if ((raw_cmd.track == buffer_track) && (current_drive == buffer_drive) &&
  3993. +        (sector_t >= buffer_min) && (sector_t < buffer_max)) {
  3994. +        /* data already in track buffer */
  3995. +        if (CT(COMMAND) == FD_READ) {
  3996. +            copy_buffer(1, max_sector, buffer_max);
  3997. +            return 1;
  3998. +        }
  3999. +    } else if (aligned_sector_t != sector_t || CURRENT->nr_sectors < ssize){
  4000. +        if (CT(COMMAND) == FD_WRITE){
  4001. +            if(sector_t + CURRENT->nr_sectors > ssize &&
  4002. +               sector_t + CURRENT->nr_sectors < ssize + ssize)
  4003. +                max_size = ssize + ssize;
  4004. +            else
  4005. +                max_size = ssize;
  4006. +        }
  4007. +        raw_cmd.flags &= ~FD_RAW_WRITE;
  4008. +        raw_cmd.flags |= FD_RAW_READ;
  4009. +        COMMAND = FM_MODE(floppy,FD_READ);
  4010. +    }
  4011. +    else if ((long)CURRENT->buffer <= LAST_DMA_ADDR ) {
  4012. +        int direct, indirect;
  4013. +
  4014. +        indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) -
  4015. +            sector_t;
  4016. +
  4017. +        max_size = buffer_chain_size();
  4018. +#if 0
  4019. +        if ( max_size > ( LAST_DMA_ADDR - ((long) CURRENT->buffer))>>9)
  4020. +            max_size=(LAST_DMA_ADDR - ((long)CURRENT->buffer))>>9;
  4021. +        /* 64 kb boundaries */
  4022. +        if ( ((max_size << 9) + ((long) CURRENT->buffer)) / K_64 !=
  4023. +             ((long) CURRENT->buffer ) / K_64 )
  4024. +            max_size = ( K_64 - ((long) CURRENT->buffer) % K_64)>>9;
  4025. +#endif
  4026. +        direct = transfer_size(ssize,max_sector,max_size) - sector_t;
  4027. +        /*
  4028. +         * We try to read tracks, but if we get too many errors, we
  4029. +         * go back to reading just one sector at a time.
  4030. +         *
  4031. +         * This means we should be able to read a sector even if there
  4032. +         * are other bad sectors on this track.
  4033. +         */
  4034. +        if ((indirect - sector_t) * 2 > (direct - sector_t) * 3 &&
  4035. +            *errors < DP->max_errors.read_track &&
  4036. +            /*!(DRS->flags & FD_NEED_TWADDLE) &&*/
  4037. +            ( ( !probing || (DP->read_track &
  4038. +               (1 <<DRS->probed_format))))){
  4039. +            max_size = CURRENT->nr_sectors;
  4040. +        } else {
  4041. +            current_addr = CURRENT->buffer;
  4042. +            raw_cmd.length = current_count_sectors << 9;
  4043. +            return 2;
  4044. +        }
  4045. +    }
  4046. +
  4047. +    if ( CT(COMMAND) == FD_READ )
  4048. +        max_size = max_sector; /* unbounded */
  4049. +
  4050. +    /* claim buffer track if needed */
  4051. +    if (buffer_track != raw_cmd.track ||  /* bad track */
  4052. +        buffer_drive !=current_drive || /* bad drive */
  4053. +        sector_t < buffer_min ||
  4054. +        ((CT(COMMAND) == FD_READ ||
  4055. +          (aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize ))&&
  4056. +         max_sector > 2 * max_buffer_sectors + buffer_min &&
  4057. +         max_size + sector_t > 2 * max_buffer_sectors + buffer_min)
  4058. +        /* not enough space */ ){
  4059. +        buffer_track = -1;
  4060. +        buffer_drive = current_drive;
  4061. +        buffer_max = buffer_min = aligned_sector_t;
  4062. +    }
  4063. +    current_addr = floppy_track_buffer +((aligned_sector_t-buffer_min )<<9);
  4064. +
  4065. +    if ( CT(COMMAND) == FD_WRITE ){
  4066. +        /* copy write buffer to track buffer.
  4067. +         * if we get here, we know that the write
  4068. +         * is either aligned or the data already in the buffer
  4069. +         * (buffer will be overwritten) */
  4070. +#ifdef SANITY
  4071. +        if (sector_t != aligned_sector_t && buffer_track == -1 )
  4072. +            DPRINT("internal error offset !=0 on write\n");
  4073. +#endif
  4074. +        buffer_track = raw_cmd.track;
  4075. +        buffer_drive = current_drive;
  4076. +        copy_buffer(ssize, max_sector, 2*max_buffer_sectors+buffer_min);
  4077. +    } else
  4078. +        transfer_size(ssize, max_sector,
  4079. +                  2*max_buffer_sectors+buffer_min-aligned_sector_t);
  4080. +
  4081. +    /* round up current_count_sectors to get dma xfer size */
  4082. +    raw_cmd.length = sector_t+current_count_sectors-aligned_sector_t;
  4083. +    raw_cmd.length = ((raw_cmd.length -1)|(ssize-1))+1;
  4084. +    raw_cmd.length <<= 9;
  4085. +
  4086. +#ifdef SANITY
  4087. +    if ((raw_cmd.length < current_count_sectors << 9) ||
  4088. +        (current_addr != CURRENT->buffer &&
  4089. +         CT(COMMAND) == FD_WRITE &&
  4090. +         (aligned_sector_t + (raw_cmd.length >> 9) > buffer_max ||
  4091. +          aligned_sector_t < buffer_min )) ||
  4092. +        raw_cmd.length % ( 128 << SIZECODE ) ||
  4093. +        raw_cmd.length <= 0 || current_count_sectors <= 0){
  4094. +        DPRINT2("fractionary current count b=%lx s=%lx\n",
  4095. +            raw_cmd.length, current_count_sectors);
  4096. +        if ( current_addr != CURRENT->buffer )
  4097. +            printk("addr=%d, length=%ld\n",
  4098. +                   (current_addr - floppy_track_buffer ) >> 9,
  4099. +                   current_count_sectors);
  4100. +        printk("st=%d ast=%d mse=%d msi=%d\n",
  4101. +               sector_t, aligned_sector_t, max_sector, max_size);
  4102. +        printk("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
  4103. +        printk("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
  4104. +               COMMAND, SECTOR, HEAD, TRACK);
  4105. +        printk("buffer drive=%d\n", buffer_drive);
  4106. +        printk("buffer track=%d\n", buffer_track);
  4107. +        printk("buffer_min=%d\n", buffer_min );
  4108. +        printk("buffer_max=%d\n", buffer_max );
  4109. +        return 0;
  4110. +    }
  4111. +
  4112. +    if (current_addr != CURRENT->buffer ){
  4113. +        if (current_addr < floppy_track_buffer ||
  4114. +            current_count_sectors < 0 ||
  4115. +            raw_cmd.length < 0 ||
  4116. +            current_addr + raw_cmd.length >
  4117. +            floppy_track_buffer + (max_buffer_sectors  << 10)){
  4118. +            DPRINT("buffer overrun in schedule dma\n");
  4119. +            printk("sector_t=%d buffer_min=%d current_count=%ld\n",
  4120. +                   sector_t, buffer_min,
  4121. +                   raw_cmd.length >> 9 );
  4122. +            printk("current_count_sectors=%ld\n",
  4123. +                   current_count_sectors);
  4124. +            if ( CT(COMMAND) == FD_READ )
  4125. +                printk("read\n");
  4126. +            if ( CT(COMMAND) == FD_READ )
  4127. +                printk("write\n");
  4128. +            return 0;
  4129. +        }
  4130. +    } else if (raw_cmd.length > CURRENT->nr_sectors << 9 ||
  4131. +           current_count_sectors > CURRENT->nr_sectors){
  4132. +        DPRINT("buffer overrun in direct transfer\n");
  4133. +        return 0;
  4134. +    } else if ( raw_cmd.length < current_count_sectors << 9 ){
  4135. +        DPRINT("more sectors than bytes\n");
  4136. +        printk("bytes=%ld\n", raw_cmd.length >> 9 );
  4137. +        printk("sectors=%ld\n", current_count_sectors);
  4138. +    }
  4139. +#endif
  4140. +    return 2;
  4141. +}
  4142. +
  4143. +static struct cont_t rw_cont={
  4144. +    rw_interrupt,
  4145. +    redo_fd_request,
  4146. +    bad_flp_intr,
  4147. +    request_done };
  4148. +
  4149. +static void redo_fd_request(void)
  4150. +{
  4151. +#define REPEAT {request_done(0); continue; }
  4152. +    int device;
  4153. +    int tmp;
  4154. +
  4155. +    if (current_drive < N_DRIVE)
  4156. +        floppy_off(current_drive);
  4157. +
  4158. +    if (CURRENT && CURRENT->dev < 0) return;
  4159. +
  4160. +    cont = &rw_cont;
  4161. +    while(1){
  4162. +        if (!CURRENT) {
  4163. +            CLEAR_INTR;
  4164. +            unlock_fdc();
  4165. +            return;
  4166. +        }
  4167. +        if (MAJOR(CURRENT->dev) != MAJOR_NR)
  4168. +            panic(DEVICE_NAME ": request list destroyed");
  4169. +        if (CURRENT->bh && !CURRENT->bh->b_lock)
  4170. +            panic(DEVICE_NAME ": block not locked");
  4171. +
  4172. +        device = CURRENT->dev;
  4173. +        set_fdc( DRIVE(device));
  4174. +
  4175. +        timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout;
  4176. +        timer_active |= 1 << FLOPPY_TIMER;
  4177. +        raw_cmd.flags=0;
  4178. +        start_motor();
  4179. +        if(test_bit( DRIVE(device), &fake_change) ||
  4180. +           test_bit( DRIVE(device), &changed_floppies)){
  4181. +            DPRINT("disk absent or changed during operation\n");
  4182. +            REPEAT;
  4183. +        }
  4184. +        set_floppy(device);
  4185. +        if (!floppy) { /* Autodetection */
  4186. +            if (!probing){
  4187. +                DRS->probed_format = 0;
  4188. +                if ( next_valid_format() ){
  4189. +                    DPRINT("no autodetectable formats\n");
  4190. +                    floppy = NULL;
  4191. +                    REPEAT;
  4192. +                }
  4193. +            }
  4194. +            probing = 1;
  4195. +            floppy = floppy_type+DP->autodetect[DRS->probed_format];
  4196. +        } else
  4197. +            probing = 0;
  4198. +        errors = & (CURRENT->errors);
  4199. +        tmp = make_raw_rw_request();
  4200. +        if ( tmp < 2 ){
  4201. +            request_done(tmp);
  4202. +            continue;
  4203. +        }
  4204. +
  4205. +        floppy_tq.routine = (void (*)(void *)) floppy_start;
  4206. +        queue_task(&floppy_tq, &tq_timer);
  4207. +#ifdef DEBUGT
  4208. +        debugt("queue fd request");
  4209. +#endif
  4210. +        return;
  4211. +    }
  4212. +#undef REPEAT
  4213. +}
  4214. +
  4215. +void do_fd_request(void)
  4216. +{
  4217. +    if (fdc_busy)
  4218. +        /* fdc busy, this new request will be treated when the
  4219. +           current one is done */
  4220. +        return;
  4221. +    /* fdc_busy cannot be set by an interrupt or a bh */
  4222. +    floppy_grab_irq_and_dma();
  4223. +    fdc_busy=1;
  4224. +    redo_fd_request();
  4225. +}
  4226. +
  4227. +/*
  4228. + * User triggered reset
  4229. + * ====================
  4230. + */
  4231. +
  4232. +static void reset_intr(void)
  4233. +{
  4234. +    printk("weird, reset interrupt called\n");
  4235. +}
  4236. +
  4237. +static struct cont_t reset_cont={
  4238. +    reset_intr,
  4239. +    success_and_wakeup,
  4240. +    generic_failure,
  4241. +    generic_done };
  4242. +
  4243. +static int user_reset_fdc(int drive, int arg, int interruptible)
  4244. +{
  4245. +    int result;
  4246. +
  4247. +    result=0;
  4248. +    LOCK_FDC(drive,interruptible);
  4249. +    switch(arg){
  4250. +    case FD_RESET_ALWAYS:
  4251. +        FDCS->reset=1;
  4252. +        break;
  4253. +    case FD_RESET_IF_RAWCMD:
  4254. +        if(FDCS->rawcmd == 2 )
  4255. +            reset_fdc_info(1);
  4256. +        break;
  4257. +    }
  4258. +    if ( FDCS->reset ){
  4259. +        cont = &reset_cont;
  4260. +        timer_table[FLOPPY_TIMER].expires = jiffies + 5;
  4261. +        timer_active |= 1 << FLOPPY_TIMER;
  4262. +        CALL(result=wait_til_done(reset_fdc,interruptible));
  4263. +    }
  4264. +    if ( UDRS->track == PROVEN_ABSENT )
  4265. +        UDRS->track = NEED_2_RECAL;
  4266. +    redo_fd_request();
  4267. +    return result;
  4268. +}
  4269. +
  4270. +/*
  4271. + * Misc Ioctl's and support
  4272. + * ========================
  4273. + */
  4274. +static int fd_copyout(void *param, volatile void *address, int size)
  4275. +{
  4276. +    int i;
  4277. +
  4278. +    i = verify_area(VERIFY_WRITE,param,size);
  4279. +    if (i)
  4280. +        return i;
  4281. +    memcpy_tofs(param,(void *) address, size);
  4282. +    return 0;
  4283. +}
  4284. +
  4285. +#define COPYOUT(x) (fd_copyout( (void *)param, &(x), sizeof(x)))
  4286. +#define COPYIN(x) (memcpy_fromfs( &(x), (void *) param, sizeof(x)),0)
  4287. +
  4288. +static char *drive_name(int type, int drive )
  4289. +{
  4290. +    struct floppy_struct *floppy;
  4291. +
  4292. +    if ( type )
  4293. +        floppy = floppy_type + type;
  4294. +    else {
  4295. +        if ( UDP->native_format )
  4296. +            floppy = floppy_type + UDP->native_format;
  4297. +        else
  4298. +            return "(null)";
  4299. +    }
  4300. +    if ( floppy->name )
  4301. +        return floppy->name;
  4302. +    else
  4303. +        return "(null)";
  4304. +}
  4305. +
  4306. +/* raw commands */
  4307. +static struct cont_t raw_cmd_cont={
  4308. +    success_and_wakeup,
  4309. +    failure_and_wakeup,
  4310. +    generic_failure,
  4311. +    generic_done };
  4312. +
  4313. +static int raw_cmd_ioctl(int drive, void *param)
  4314. +{
  4315. +    int i, count, ret;
  4316. +
  4317. +    if ( FDCS->rawcmd <= 1 )
  4318. +        FDCS->rawcmd = 1;
  4319. +    for ( i= 0; i < N_DRIVE; i++){
  4320. +        if ( FDC(i) != fdc)
  4321. +            continue;
  4322. +        if ( i == drive ){
  4323. +            if ( drive_state[i].fd_ref > 1 ){
  4324. +                FDCS->rawcmd = 2;
  4325. +                break;
  4326. +            }
  4327. +        } else if ( drive_state[i].fd_ref ){
  4328. +            FDCS->rawcmd = 2;
  4329. +            break;
  4330. +        }
  4331. +    }
  4332. +
  4333. +    if(FDCS->reset)
  4334. +        return -EIO;
  4335. +
  4336. +    COPYIN(raw_cmd);
  4337. +    raw_cmd.rate &= 0x03;
  4338. +    count = raw_cmd.length;
  4339. +    if (raw_cmd.flags & (FD_RAW_WRITE | FD_RAW_READ)){
  4340. +        if(count > max_buffer_sectors * 1024 )
  4341. +            return -ENOMEM;
  4342. +        buffer_track = -1;
  4343. +    }
  4344. +    if ( raw_cmd.flags & FD_RAW_WRITE ){
  4345. +        i = verify_area(VERIFY_READ, raw_cmd.data, count );
  4346. +        if (i)
  4347. +            return i;
  4348. +        memcpy_fromfs(floppy_track_buffer, raw_cmd.data, count);
  4349. +    }
  4350. +
  4351. +    current_addr = floppy_track_buffer;
  4352. +    cont = &raw_cmd_cont;
  4353. +    CALL(ret=wait_til_done(floppy_start,1));
  4354. +    if( disk_change(current_drive) )
  4355. +        raw_cmd.flags |= FD_RAW_DISK_CHANGE;
  4356. +    else
  4357. +        raw_cmd.flags &= ~FD_RAW_DISK_CHANGE;
  4358. +    if(raw_cmd.flags & FD_RAW_NO_MOTOR_AFTER)
  4359. +        motor_off_callback(drive);
  4360. +
  4361. +    if ( !ret && !FDCS->reset ){
  4362. +        raw_cmd.reply_count = inr;
  4363. +        for( i=0; i< raw_cmd.reply_count; i++)
  4364. +            raw_cmd.reply[i] = reply_buffer[i];
  4365. +        if ( raw_cmd.flags & ( FD_RAW_READ | FD_RAW_WRITE ))
  4366. +            raw_cmd.length = get_dma_residue(FLOPPY_DMA);
  4367. +    } else
  4368. +        ret = -EIO;
  4369. +
  4370. +    DRS->track = NO_TRACK;
  4371. +    if ( ret )
  4372. +        return ret;
  4373. +
  4374. +    if ( raw_cmd.flags & FD_RAW_READ ){
  4375. +        i=fd_copyout( raw_cmd.data, floppy_track_buffer, count);
  4376. +        if (i)
  4377. +            return i;
  4378. +    }
  4379. +
  4380. +    return COPYOUT(raw_cmd);
  4381. +}
  4382. +
  4383. +static int invalidate_drive(int rdev)
  4384. +{
  4385. +    /* invalidate the buffer track to force a reread */
  4386. +    set_bit( DRIVE(rdev), &fake_change);
  4387. +    redo_fd_request();
  4388. +    check_disk_change(rdev);
  4389. +    return 0;
  4390. +}
  4391. +
  4392. +static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
  4393. +    unsigned long param)
  4394. +{
  4395. +#define IOCTL_MODE_BIT 8
  4396. +#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
  4397. +
  4398. +    struct floppy_struct newparams;
  4399. +    struct format_descr tmp_format_req;
  4400. +    int i,device,drive,type,cnt;
  4401. +    struct floppy_struct *this_floppy;
  4402. +    char *name;
  4403. +
  4404. +    device = inode->i_rdev;
  4405. +    switch (cmd) {
  4406. +        RO_IOCTLS(device,param);
  4407. +    }
  4408. +    type = TYPE(device);
  4409. +    drive = DRIVE(device);
  4410. +    switch (cmd) {
  4411. +    case FDGETDRVTYP:
  4412. +        i=verify_area(VERIFY_WRITE,(void *) param,16);
  4413. +        if (i)
  4414. +            return i;
  4415. +        name = drive_name(type,drive);
  4416. +        for ( cnt=0; cnt<16; cnt++){
  4417. +            put_fs_byte(name[cnt],
  4418. +                    ((char*)param)+cnt);
  4419. +            if ( ! *name )
  4420. +                break;
  4421. +        }
  4422. +        return 0;
  4423. +    case FDGETMAXERRS:
  4424. +        return COPYOUT(UDP->max_errors);
  4425. +    case FDGETPRM:
  4426. +        if (type)
  4427. +            this_floppy = &floppy_type[type];
  4428. +        else if ((this_floppy = current_type[drive]) ==
  4429. +             NULL)
  4430. +            return -ENODEV;
  4431. +        return COPYOUT(this_floppy[0]);
  4432. +    case FDPOLLDRVSTAT:
  4433. +        check_disk_change(device);
  4434. +        /* fall through */
  4435. +    case FDGETDRVSTAT:
  4436. +        return COPYOUT(*UDRS);
  4437. +    case FDGETFDCSTAT:
  4438. +        return COPYOUT(*UFDCS);
  4439. +    case FDGETDRVPRM:
  4440. +        return COPYOUT(*UDP);
  4441. +    case FDWERRORGET:
  4442. +        return COPYOUT(*UDRWE);
  4443. +    }
  4444. +
  4445. +    if (!IOCTL_ALLOWED)
  4446. +        return -EPERM;
  4447. +
  4448. +    switch (cmd) {
  4449. +    case FDWERRORCLR:
  4450. +                UDRWE->write_errors = 0;
  4451. +                UDRWE->first_error_sector = 0;
  4452. +                UDRWE->first_error_generation = 0;
  4453. +                UDRWE->last_error_sector = 0;
  4454. +                UDRWE->last_error_generation = 0;
  4455. +                UDRWE->badness = 0;
  4456. +                return 0;
  4457. +    case FDRAWCMD:
  4458. +        if (type)
  4459. +            return -EINVAL;
  4460. +        LOCK_FDC(drive,1);
  4461. +        set_floppy(device);
  4462. +        CALL(i = raw_cmd_ioctl(drive, (void *) param));
  4463. +        redo_fd_request();
  4464. +        return i;
  4465. +    case FDFMTTRK:
  4466. +        if (UDRS->fd_ref != 1)
  4467. +            return -EBUSY;
  4468. +        if (UDRS->track == PROVEN_ABSENT)
  4469. +            return -ENXIO;
  4470. +        COPYIN(tmp_format_req);
  4471. +        return do_format(device, &tmp_format_req);
  4472. +    case FDSETMAXERRS:
  4473. +        return COPYIN(UDP->max_errors);
  4474. +    case FDFMTBEG:
  4475. +        return 0;
  4476. +    case FDCLRPRM:
  4477. +        LOCK_FDC(drive,1);
  4478. +        current_type[drive] = NULL;
  4479. +        floppy_sizes[drive] = 2;
  4480. +        UDRS->keep_data = 0;
  4481. +        return invalidate_drive(device);
  4482. +    case FDFMTEND:
  4483. +    case FDFLUSH:
  4484. +        LOCK_FDC(drive,1);
  4485. +        return invalidate_drive(device);
  4486. +    case FDSETPRM:
  4487. +    case FDDEFPRM:
  4488. +        COPYIN(newparams);
  4489. +        /* sanity checking for parameters.*/
  4490. +        if(newparams.sect <= 0 ||
  4491. +           newparams.head <= 0 ||
  4492. +           newparams.track <= 0 ||
  4493. +           newparams.track >
  4494. +           UDP->tracks>>newparams.stretch)
  4495. +            return -EINVAL;
  4496. +        if ( type){
  4497. +            if ( !suser() )
  4498. +                return -EPERM;
  4499. +            LOCK_FDC(-1,1);
  4500. +            for ( cnt = 0; cnt < N_DRIVE; cnt++){
  4501. +                if (TYPE(drive_state[cnt].fd_device) == type &&
  4502. +                    drive_state[cnt].fd_ref)
  4503. +                    set_bit(drive, &fake_change);
  4504. +            }
  4505. +            floppy_type[type] = newparams;
  4506. +            floppy_type[type].name="user format";
  4507. +            for (cnt = type << 2 ;
  4508. +                 cnt < (type << 2 ) + 4 ;
  4509. +                 cnt++)
  4510. +                floppy_sizes[cnt]=
  4511. +#ifdef HAVE_2_CONTROLLERS
  4512. +                    floppy_sizes[cnt+0x80]=
  4513. +#endif
  4514. +                        floppy_type[type].size>>1;
  4515. +            redo_fd_request();
  4516. +            for ( cnt = 0; cnt < N_DRIVE; cnt++){
  4517. +                if (TYPE(drive_state[cnt].fd_device) == type &&
  4518. +                    drive_state[cnt].fd_ref)
  4519. +                    check_disk_change(drive_state[cnt].
  4520. +                              fd_device);
  4521. +            }
  4522. +            return 0;
  4523. +        }
  4524. +
  4525. +        LOCK_FDC(drive,1);
  4526. +        if ( cmd != FDDEFPRM ){
  4527. +            /* notice a disk change immediately, else
  4528. +             * we loose our settings immediately*/
  4529. +            raw_cmd.flags = 0;
  4530. +            start_motor();
  4531. +        }
  4532. +        user_params[drive] = newparams;
  4533. +        if (buffer_drive == drive &&
  4534. +            buffer_max > user_params[drive].sect)
  4535. +            buffer_max=user_params[drive].sect;
  4536. +        current_type[drive] = &user_params[drive];
  4537. +        floppy_sizes[drive] = user_params[drive].size >> 1;
  4538. +        if (cmd == FDDEFPRM)
  4539. +            DRS->keep_data = -1;
  4540. +        else
  4541. +            DRS->keep_data = 1;
  4542. +        /* invalidation. Invalidate only when needed, i.e.
  4543. +         * when there are already sectors in the buffer cache
  4544. +         * whose number will change. This is useful, because
  4545. +         * mtools often changes the geometry of the disk after
  4546. +         * looking at the boot block */
  4547. +        if (DRS->maxblock >
  4548. +            user_params[drive].sect ||
  4549. +            DRS->maxtrack )
  4550. +            invalidate_drive(device);
  4551. +        else
  4552. +            redo_fd_request();
  4553. +        return 0;
  4554. +    case FDRESET:
  4555. +        return user_reset_fdc( drive, (int)param, 1);
  4556. +    case FDMSGON:
  4557. +        UDP->flags |= FTD_MSG;
  4558. +        return 0;
  4559. +    case FDMSGOFF:
  4560. +        UDP->flags &= ~FTD_MSG;
  4561. +        return 0;
  4562. +    case FDSETEMSGTRESH:
  4563. +        UDP->max_errors.reporting =
  4564. +            (unsigned short) (param & 0x0f);
  4565. +        return 0;
  4566. +    case FDTWADDLE:
  4567. +        LOCK_FDC(drive,1);
  4568. +        twaddle();
  4569. +        redo_fd_request();
  4570. +    }
  4571. +    if ( ! suser() )
  4572. +        return -EPERM;
  4573. +    switch(cmd){
  4574. +    case FDSETDRVPRM:
  4575. +        return COPYIN(*UDP);
  4576. +    default:
  4577. +        return -EINVAL;
  4578. +    }
  4579. +    return 0;
  4580. +#undef IOCTL_ALLOWED
  4581. +}
  4582. +
  4583. +static void set_base_type(int drive, int code)
  4584. +{
  4585. +    if(code>0 && code <= NUMBER(default_drive_params)+1) {
  4586. +        memcpy((char *)UDP,
  4587. +            (char *)(&default_drive_params[code-1].params),
  4588. +            sizeof(struct floppy_drive_params));
  4589. +        printk("fd%d is %s", drive, default_drive_params[code-1].name);
  4590. +        return;
  4591. +    }
  4592. +    else if (!code)
  4593. +        printk("fd%d is not installed", drive);
  4594. +    else
  4595. +        printk("fd%d is unknown type %d", drive, code);
  4596. +}
  4597. +
  4598. +static void config_types(void)
  4599. +{
  4600. +    int drive;
  4601. +
  4602. +    for (drive=0; drive<N_DRIVE ; drive++){
  4603. +          /* default type for unidentifiable drives */
  4604. +          memcpy((char *) UDP, (char *) (&default_drive_params->params),
  4605. +              sizeof( struct floppy_drive_params ));
  4606. +    }
  4607. +    printk("Floppy drive(s): ");
  4608. +    for(drive=0; drive<no_floppies; drive++)
  4609. +    {
  4610. +      set_base_type(drive, 1+4);
  4611. +      if(drive < no_floppies-1)
  4612. +        printk(", ");
  4613. +    }
  4614. +    printk("\n");
  4615. +}
  4616. +
  4617. +int floppy_is_wp( int minor)
  4618. +{
  4619. +    check_disk_change(minor + (MAJOR_NR << 8));
  4620. +    return ! ( drive_state[ DRIVE(minor) ].flags & FD_DISK_WRITABLE );
  4621. +}
  4622. +
  4623. +
  4624. +#define WRAPPER(op) \
  4625. +static int floppy_##op(struct inode * inode, struct file * filp, \
  4626. +             char * buf, int count) \
  4627. +{ \
  4628. +    check_disk_change(inode->i_rdev); \
  4629. +    if ( drive_state[DRIVE(inode->i_rdev)].track == PROVEN_ABSENT ) \
  4630. +         return -ENXIO; \
  4631. +    if ( test_bit(DRIVE(inode->i_rdev),&changed_floppies)) \
  4632. +        return -ENXIO; \
  4633. +    return block_##op(inode, filp, buf, count); \
  4634. +}
  4635. +
  4636. +WRAPPER(read)
  4637. +WRAPPER(write)
  4638. +
  4639. +static void floppy_release(struct inode * inode, struct file * filp)
  4640. +{
  4641. +    int drive;
  4642. +
  4643. +    drive = DRIVE(inode->i_rdev);
  4644. +
  4645. +    fsync_dev(inode->i_rdev);
  4646. +
  4647. +    if (UDRS->fd_ref < 0)
  4648. +        UDRS->fd_ref=0;
  4649. +    else if (!UDRS->fd_ref--) {
  4650. +        DPRINT("floppy_release with fd_ref == 0");
  4651. +        UDRS->fd_ref = 0;
  4652. +    }
  4653. +    floppy_release_irq_and_dma();
  4654. +}
  4655. +
  4656. +/*
  4657. + * floppy_open check for aliasing (/dev/fd0 can be the same as
  4658. + * /dev/PS0 etc), and disallows simultaneous access to the same
  4659. + * drive with different device numbers.
  4660. + */
  4661. +#define RETERR(x) \
  4662. +    do{floppy_release(inode,filp); \
  4663. +       return -(x);}while(0)
  4664. +
  4665. +static int floppy_open(struct inode * inode, struct file * filp)
  4666. +{
  4667. +    int drive;
  4668. +    int old_dev;
  4669. +
  4670. +    if (!filp) {
  4671. +        DPRINT("Weird, open called with filp=0\n");
  4672. +        return -EIO;
  4673. +    }
  4674. +
  4675. +    drive = DRIVE(inode->i_rdev);
  4676. +    if ( drive >= N_DRIVE || !( ALLOWED_DRIVE_MASK & ( 1 << drive)) )
  4677. +        return -ENXIO;
  4678. +
  4679. +    if (TYPE(inode->i_rdev) >= NUMBER(floppy_type))
  4680. +        return -ENXIO;
  4681. +
  4682. +    if ((filp->f_mode & 3)  &&
  4683. +        UDRS->track == PROVEN_ABSENT )
  4684. +        return -ENXIO;
  4685. +
  4686. +    old_dev = UDRS->fd_device;
  4687. +    if (UDRS->fd_ref && old_dev != inode->i_rdev)
  4688. +        return -EBUSY;
  4689. +
  4690. +    if(UDRS->fd_ref == -1 ||
  4691. +       (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
  4692. +        return -EBUSY;
  4693. +
  4694. +    if (floppy_grab_irq_and_dma())
  4695. +        return -EBUSY;
  4696. +
  4697. +    if(filp->f_flags & O_EXCL)
  4698. +        UDRS->fd_ref = -1;
  4699. +    else
  4700. +        UDRS->fd_ref++;
  4701. +
  4702. +    UDRS->fd_device = inode->i_rdev;
  4703. +
  4704. +    if (old_dev && old_dev != inode->i_rdev) {
  4705. +        if (buffer_drive == drive)
  4706. +            buffer_track = -1;
  4707. +        invalidate_buffers(old_dev);
  4708. +    }
  4709. +
  4710. +    /* Allow ioctls if we have write-permissions even if read-only open */
  4711. +    if ((filp->f_mode & 2) || (permission(inode,2) == 0))
  4712. +        filp->f_mode |= IOCTL_MODE_BIT;
  4713. +
  4714. +    if (UFDCS->rawcmd == 1)
  4715. +           UFDCS->rawcmd = 2;
  4716. +
  4717. +    if (filp->f_flags & O_NDELAY)
  4718. +        return 0;
  4719. +
  4720. +    if (filp->f_mode && UDRS->track == PROVEN_ABSENT )
  4721. +        RETERR(ENXIO);
  4722. +
  4723. +    if (user_reset_fdc(drive, FD_RESET_IF_NEEDED,0))
  4724. +        RETERR(EIO);
  4725. +
  4726. +    if (filp->f_mode & 3) {
  4727. +        UDRS->last_checked = 0;
  4728. +        check_disk_change(inode->i_rdev);
  4729. +        if (test_bit(drive,&changed_floppies))
  4730. +            RETERR(ENXIO);
  4731. +    }
  4732. +
  4733. +    if (filp->f_mode && UDRS->track == PROVEN_ABSENT )
  4734. +        RETERR(ENXIO);
  4735. +
  4736. +    if ((filp->f_mode & 2) && !(UDRS->flags & FD_DISK_WRITABLE))
  4737. +        RETERR(EROFS);
  4738. +    return 0;
  4739. +#undef RETERR
  4740. +}
  4741. +
  4742. +/*
  4743. + * Check if the disk has been changed or if a change has been faked.
  4744. + */
  4745. +static int check_floppy_change(dev_t dev)
  4746. +{
  4747. +    int drive = DRIVE( dev );
  4748. +
  4749. +    if (MAJOR(dev) != MAJOR_NR) {
  4750. +        DPRINT("floppy_changed: not a floppy\n");
  4751. +        return 0;
  4752. +    }
  4753. +
  4754. +    if(test_bit(drive, &changed_floppies))
  4755. +        return 1;
  4756. +
  4757. +    if(UDRS->last_checked + UDP->checkfreq < jiffies){
  4758. +        lock_fdc(drive,0);
  4759. +        start_motor();
  4760. +        redo_fd_request();
  4761. +    }
  4762. +
  4763. +    if(test_bit(drive, &changed_floppies))
  4764. +        return 1;
  4765. +    if(test_bit(drive, &fake_change))
  4766. +        return 1;
  4767. +    return 0;
  4768. +}
  4769. +
  4770. +static struct cont_t poll_cont={
  4771. +    success_and_wakeup,
  4772. +    floppy_ready,
  4773. +    generic_failure,
  4774. +    generic_done };
  4775. +
  4776. +
  4777. +/* revalidate the floppy disk, i.e. trigger format autodetection by reading
  4778. + * the bootblock (block 0). "Autodetection" is also needed to check wether
  4779. + * there is a disk in the drive at all... Thus we also do it for fixed
  4780. + * geometry formats */
  4781. +static int floppy_revalidate(dev_t dev)
  4782. +{
  4783. +    struct buffer_head * bh;
  4784. +    int drive=DRIVE(dev);
  4785. +    int cf;
  4786. +
  4787. +    cf = test_bit(drive, &changed_floppies);
  4788. +    if(cf || test_bit(drive, &fake_change)){
  4789. +        lock_fdc(drive,0);
  4790. +        cf = test_bit(drive, &changed_floppies);
  4791. +        if(! (cf || test_bit(drive, &fake_change))){
  4792. +            redo_fd_request(); /* already done by another thread */
  4793. +            return 0;
  4794. +        }
  4795. +        UDRS->maxblock = 0;
  4796. +        UDRS->maxtrack = 0;
  4797. +        if ( buffer_drive == drive)
  4798. +            buffer_track = -1;
  4799. +        clear_bit(drive, &fake_change);
  4800. +        clear_bit(drive, &changed_floppies);
  4801. +        if(cf){
  4802. +            UDRS->generation++;
  4803. +            if(!current_type[drive] && !TYPE(dev)){
  4804. +                /* auto-sensing */
  4805. +                if (!(bh = getblk(dev,0,1024))){
  4806. +                    redo_fd_request();
  4807. +                    return 1;
  4808. +                }
  4809. +                if ( bh && ! bh->b_uptodate)
  4810. +                    ll_rw_block(READ, 1, &bh);
  4811. +                redo_fd_request();
  4812. +                wait_on_buffer(bh);
  4813. +                brelse(bh);
  4814. +                return 0;
  4815. +            } else {
  4816. +                /* no auto-sense, just clear dcl */
  4817. +                raw_cmd.flags=FD_RAW_NEED_SEEK|FD_RAW_NEED_DISK;
  4818. +                raw_cmd.track=0;
  4819. +                raw_cmd.cmd_count=0;
  4820. +                cont = &poll_cont;
  4821. +                wait_til_done(floppy_ready,0);
  4822. +            }
  4823. +        }
  4824. +        redo_fd_request();
  4825. +    }
  4826. +    return 0;
  4827. +}
  4828. +
  4829. +static struct file_operations floppy_fops = {
  4830. +    NULL,            /* lseek - default */
  4831. +    floppy_read,        /* read - general block-dev read */
  4832. +    floppy_write,        /* write - general block-dev write */
  4833. +    NULL,                   /* readdir - bad */
  4834. +    NULL,            /* select */
  4835. +    fd_ioctl,        /* ioctl */
  4836. +    NULL,            /* mmap */
  4837. +    floppy_open,        /* open */
  4838. +    floppy_release,        /* release */
  4839. +    block_fsync,        /* fsync */
  4840. +    NULL,            /* fasync */
  4841. +    check_floppy_change,    /* media_change */
  4842. +    floppy_revalidate,    /* revalidate */
  4843. +};
  4844. +
  4845. +/*
  4846. + * Floppy Driver initialisation
  4847. + * =============================
  4848. + */
  4849. +
  4850. +/* Determine the floppy disk controller type */
  4851. +/* This routine was written by David C. Niemi */
  4852. +static char get_fdc_version(void)
  4853. +{
  4854. +    int r;
  4855. +
  4856. +    output_byte(FD_DUMPREGS);    /* 82072 and better know DUMPREGS */
  4857. +    if ( FDCS->reset )
  4858. +        return FDC_NONE;
  4859. +    if ( (r = result()) <= 0x00)
  4860. +        return FDC_NONE;    /* No FDC present ??? */
  4861. +    if ((r==1) && (reply_buffer[0] == 0x80)){
  4862. +        printk("FDC %d is a 8272A\n",fdc);
  4863. +        return FDC_8272A;        /* 8272a/765 don't know DUMPREGS */
  4864. +    }
  4865. +    if (r != 10) {
  4866. +        printk("FDC init: DUMPREGS: unexpected return of %d bytes.\n", r);
  4867. +        return FDC_UNKNOWN;
  4868. +    }
  4869. +    output_byte(FD_VERSION);
  4870. +    r = result();
  4871. +    if ((r == 1) && (reply_buffer[0] == 0x80)){
  4872. +        printk("FDC %d is a 82072\n",fdc);
  4873. +        return FDC_82072;        /* 82072 doesn't know VERSION */
  4874. +    }
  4875. +    if ((r != 1) || (reply_buffer[0] != 0x90)) {
  4876. +        printk("FDC init: VERSION: unexpected return of %d bytes.\n", r);
  4877. +        return FDC_UNKNOWN;
  4878. +    }
  4879. +    output_byte(FD_UNLOCK);
  4880. +    r = result();
  4881. +    if ((r == 1) && (reply_buffer[0] == 0x80)){
  4882. +        printk("FDC %d is a pre-1991 82077\n", fdc);
  4883. +        return FDC_82077_ORIG;    /* Pre-1991 82077 doesn't know LOCK/UNLOCK */
  4884. +    }
  4885. +    if ((r != 1) || (reply_buffer[0] != 0x00)) {
  4886. +        printk("FDC init: UNLOCK: unexpected return of %d bytes.\n", r);
  4887. +        return FDC_UNKNOWN;
  4888. +    }
  4889. +    printk("FDC %d is a post-1991 82077\n",fdc);
  4890. +    return FDC_82077;    /* Revised 82077AA passes all the tests */
  4891. +} /* fdc_init */
  4892. +
  4893. +void floppy_init(void)
  4894. +{
  4895. +    int i;
  4896. +
  4897. +    sti();
  4898. +
  4899. +    if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
  4900. +        printk("Unable to get major %d for floppy\n",MAJOR_NR);
  4901. +        return;
  4902. +    }
  4903. +
  4904. +    for(i=0; i<256; i++)
  4905. +        if ( TYPE(i))
  4906. +            floppy_sizes[i] = floppy_type[TYPE(i)].size >> 1;
  4907. +        else
  4908. +            floppy_sizes[i] = MAX_DISK_SIZE;
  4909. +
  4910. +    blk_size[MAJOR_NR] = floppy_sizes;
  4911. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  4912. +    hardsect_size[MAJOR_NR] = fd_sectsizes;
  4913. +    timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
  4914. +    timer_active &= ~(1 << FLOPPY_TIMER);
  4915. +    config_types();
  4916. +
  4917. +    for(i = 0; i<256; i++)
  4918. +        fd_sectsizes[i] = 1024;            /* patch for msdos driver */
  4919. +
  4920. +    fdc_state[0].address = 0x3f0;
  4921. +#if N_FDC > 1
  4922. +    fdc_state[1].address = 0x370;
  4923. +#endif
  4924. +    for (i = 0 ; i < N_FDC ; i++) {
  4925. +        fdc = i;
  4926. +        FDCS->dtr = -1;
  4927. +        FDCS->dor = 0;
  4928. +        FDCS->reset = 0;
  4929. +        FDCS->version = FDC_NONE;
  4930. +        set_dor(fdc, ~0, 0xc );
  4931. +    }
  4932. +
  4933. +    /* initialise drive state */
  4934. +    for (i = 0; i < N_DRIVE ; i++) {
  4935. +        current_drive = i;
  4936. +        DRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE;
  4937. +        DRS->generation = 0;
  4938. +        DRS->keep_data = 0;
  4939. +        DRS->fd_ref = 0;
  4940. +        DRS->fd_device = 0;
  4941. +        DRWE->write_errors = 0;
  4942. +        DRWE->first_error_sector = 0;
  4943. +        DRWE->first_error_generation = 0;
  4944. +        DRWE->last_error_sector = 0;
  4945. +        DRWE->last_error_generation = 0;
  4946. +        DRWE->badness = 0;
  4947. +    }
  4948. +
  4949. +    floppy_grab_irq_and_dma();
  4950. +    for (i = 0 ; i < N_FDC ; i++) {
  4951. +        fdc = i;
  4952. +        FDCS->rawcmd = 2;
  4953. +        if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0))
  4954. +            continue;
  4955. +        /* Try to determine the floppy controller type */
  4956. +        FDCS->version = get_fdc_version();
  4957. +        if (FDCS->version == FDC_NONE)
  4958. +            continue;
  4959. +
  4960. +        /* Not all FDCs seem to be able to handle the version command
  4961. +         * properly, so force a reset for the standard FDC clones,
  4962. +         * to avoid interrupt garbage.
  4963. +         */
  4964. +        FDCS->has_fifo = FDCS->version >= FDC_82077_ORIG;
  4965. +        user_reset_fdc(-1,FD_RESET_ALWAYS,0);
  4966. +    }
  4967. +    fdc=0;
  4968. +    current_drive = 0;
  4969. +    floppy_release_irq_and_dma();
  4970. +    initialising=0;
  4971. +}
  4972. +
  4973. +static int floppy_grab_irq_and_dma(void)
  4974. +{
  4975. +    int i;
  4976. +    cli();
  4977. +    if (usage_count++){
  4978. +        sti();
  4979. +        return 0;
  4980. +    }
  4981. +    sti();
  4982. +
  4983. +    for(i=0; i< N_FDC; i++){
  4984. +        fdc = i;
  4985. +        reset_fdc_info(1);
  4986. +        arm_set_dor(FDCS->dor);
  4987. +    }
  4988. +    set_dor(0, ~0, 8); /* avoid immediate interrupt */
  4989. +
  4990. +    if (request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT, "floppy")) {
  4991. +        DPRINT1("Unable to grab IRQ%d for the floppy driver\n",
  4992. +            FLOPPY_IRQ);
  4993. +        return -1;
  4994. +    }
  4995. +    if (request_dma(FLOPPY_DMA,"floppy")) {
  4996. +        DPRINT1("Unable to grab DMA%d for the floppy driver\n",
  4997. +            FLOPPY_DMA);
  4998. +        free_irq(FLOPPY_IRQ);
  4999. +        return -1;
  5000. +    }
  5001. +    enable_irq(FLOPPY_IRQ);
  5002. +    return 0;
  5003. +}
  5004. +
  5005. +static void floppy_release_irq_and_dma(void)
  5006. +{
  5007. +    int i;
  5008. +    cli();
  5009. +    if (--usage_count){
  5010. +        sti();
  5011. +        return;
  5012. +    }
  5013. +    sti();
  5014. +    disable_dma(FLOPPY_DMA);
  5015. +    free_dma(FLOPPY_DMA);
  5016. +    disable_irq(FLOPPY_IRQ);
  5017. +    free_irq(FLOPPY_IRQ);
  5018. +    /* switch off dma gates */
  5019. +    for(i=0; i< N_FDC; i++)
  5020. +        set_dor(i, ~8, 0);
  5021. +}
  5022. diff -r -u -N linux.orig/arch/arm/drivers/block/genhd.c linux.arm/arch/arm/drivers/block/genhd.c
  5023. --- linux.orig/arch/arm/drivers/block/genhd.c    Thu Jan  1 01:00:00 1970
  5024. +++ linux.arm/arch/arm/drivers/block/genhd.c    Fri Oct 27 23:14:43 1995
  5025. @@ -0,0 +1,295 @@
  5026. +/*
  5027. + *  Code extracted from
  5028. + *  linux/kernel/hd.c
  5029. + *
  5030. + *  Copyright (C) 1991, 1992  Linus Torvalds
  5031. + */
  5032. +
  5033. +/*
  5034. + *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  5035. + *  in the early extended-partition checks and added DM partitions
  5036. + */
  5037. +
  5038. +#include <linux/config.h>
  5039. +#include <linux/fs.h>
  5040. +#include <linux/genhd.h>
  5041. +#include <linux/kernel.h>
  5042. +
  5043. +#ifndef __ARM__
  5044. +#define __ARM__
  5045. +#endif
  5046. +
  5047. +#ifndef __ARM__
  5048. +struct gendisk *gendisk_head = NULL;
  5049. +#else
  5050. +struct gendisk *gendisk_head;
  5051. +#endif
  5052. +
  5053. +static int current_minor;
  5054. +extern int *blk_size[];
  5055. +extern void rd_load(void);
  5056. +extern int ramdisk_size;
  5057. +
  5058. +#ifndef __ARM__
  5059. +/*
  5060. + * Create devices for each logical partition in an extended partition.
  5061. + * The logical partitions form a linked list, with each entry being
  5062. + * a partition table with two entries.  The first entry
  5063. + * is the real data partition (with a start relative to the partition
  5064. + * table start).  The second is a pointer to the next logical partition
  5065. + * (with a start relative to the entire extended partition).
  5066. + * We do not create a Linux partition for the partition tables, but
  5067. + * only for the actual data partitions.
  5068. + */
  5069. +
  5070. +static void extended_partition(struct gendisk *hd, int dev)
  5071. +{
  5072. +    struct buffer_head *bh;
  5073. +    struct partition *p;
  5074. +    unsigned long first_sector, this_sector;
  5075. +    int mask = (1 << hd->minor_shift) - 1;
  5076. +
  5077. +    first_sector = hd->part[MINOR(dev)].start_sect;
  5078. +    this_sector = first_sector;
  5079. +
  5080. +    while (1) {
  5081. +        if ((current_minor & mask) >= (4 + hd->max_p))
  5082. +            return;
  5083. +        if (!(bh = bread(dev,0,1024)))
  5084. +            return;
  5085. +      /*
  5086. +       * This block is from a device that we're about to stomp on.
  5087. +       * So make sure nobody thinks this block is usable.
  5088. +       */
  5089. +        bh->b_dirt = 0;
  5090. +        bh->b_uptodate = 0;
  5091. +        bh->b_req = 0;
  5092. +        if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
  5093. +            p = (struct partition *) (0x1BE + bh->b_data);
  5094. +        /*
  5095. +         * Process the first entry, which should be the real
  5096. +         * data partition.
  5097. +         */
  5098. +            if (p->sys_ind == EXTENDED_PARTITION ||
  5099. +                !(hd->part[current_minor].nr_sects = p->nr_sects))
  5100. +                goto done;  /* shouldn't happen */
  5101. +            hd->part[current_minor].start_sect = this_sector + p->start_sect;
  5102. +            printk(" %s%c%d", hd->major_name,
  5103. +                'a'+(current_minor >> hd->minor_shift),
  5104. +                mask & current_minor);
  5105. +            current_minor++;
  5106. +            p++;
  5107. +        /*
  5108. +         * Process the second entry, which should be a link
  5109. +         * to the next logical partition.  Create a minor
  5110. +         * for this just long enough to get the next partition
  5111. +         * table.  The minor will be reused for the real
  5112. +         * data partition.
  5113. +         */
  5114. +            if (p->sys_ind != EXTENDED_PARTITION ||
  5115. +                !(hd->part[current_minor].nr_sects = p->nr_sects))
  5116. +                goto done;  /* no more logicals in this partition */
  5117. +            hd->part[current_minor].start_sect = first_sector + p->start_sect;
  5118. +            this_sector = first_sector + p->start_sect;
  5119. +            dev = ((hd->major) << 8) | current_minor;
  5120. +            brelse(bh);
  5121. +        } else
  5122. +            goto done;
  5123. +    }
  5124. +done:
  5125. +    brelse(bh);
  5126. +}
  5127. +
  5128. +static void check_partition(struct gendisk *hd, unsigned int dev)
  5129. +{
  5130. +    static int first_time = 1;
  5131. +    int i, minor = current_minor;
  5132. +    struct buffer_head *bh;
  5133. +    struct partition *p;
  5134. +    unsigned long first_sector;
  5135. +    int mask = (1 << hd->minor_shift) - 1;
  5136. +
  5137. +    if (first_time)
  5138. +        printk("Partition check:\n");
  5139. +    first_time = 0;
  5140. +    first_sector = hd->part[MINOR(dev)].start_sect;
  5141. +    if (!(bh = bread(dev,0,1024))) {
  5142. +        printk("  unable to read partition table of device %04x\n",dev);
  5143. +        return;
  5144. +    }
  5145. +    printk("  %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift));
  5146. +    current_minor += 4;  /* first "extra" minor */
  5147. +    if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
  5148. +        p = (struct partition *) (0x1BE + bh->b_data);
  5149. +        for (i=1 ; i<=4 ; minor++,i++,p++) {
  5150. +            if (!(hd->part[minor].nr_sects = p->nr_sects))
  5151. +                continue;
  5152. +            hd->part[minor].start_sect = first_sector + p->start_sect;
  5153. +            printk(" %s%c%d", hd->major_name,'a'+(minor >> hd->minor_shift), i);
  5154. +            if ((current_minor & 0x3f) >= 60)
  5155. +                continue;
  5156. +            if (p->sys_ind == EXTENDED_PARTITION) {
  5157. +                printk(" <");
  5158. +                extended_partition(hd, (hd->major << 8) | minor);
  5159. +                printk(" >");
  5160. +            }
  5161. +        }
  5162. +        /*
  5163. +         * check for Disk Manager partition table
  5164. +         */
  5165. +        if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
  5166. +            p = (struct partition *) (0x1BE + bh->b_data);
  5167. +            for (i = 4 ; i < 16 ; i++, current_minor++) {
  5168. +                p--;
  5169. +                if ((current_minor & mask) >= mask-2)
  5170. +                    break;
  5171. +                if (!(p->start_sect && p->nr_sects))
  5172. +                    continue;
  5173. +                hd->part[current_minor].start_sect = p->start_sect;
  5174. +                hd->part[current_minor].nr_sects = p->nr_sects;
  5175. +                printk(" %s%c%d", hd->major_name,
  5176. +                    'a'+(current_minor >> hd->minor_shift),
  5177. +                    current_minor & mask);
  5178. +            }
  5179. +        }
  5180. +    } else
  5181. +        printk(" bad partition table");
  5182. +    printk("\n");
  5183. +    brelse(bh);
  5184. +}
  5185. +#else
  5186. +/* 'ARC hard drives' minor allocation:
  5187. + *   physical hd    = minor >> hd->minor_shift
  5188. + *   image file        = (minor-1) & 3
  5189. + *   extra file        = image file + n<<2
  5190. + */
  5191. +
  5192. +static void pc_check_hd(struct gendisk *hd, int minor)
  5193. +{ /* minor is the whole device minor */
  5194. +    int dev = (hd->major << 8)+minor;
  5195. +    int i;
  5196. +    struct buffer_head *bh;
  5197. +    struct partition *p;
  5198. +    
  5199. +    minor+=4;
  5200. +#define GET_WORD(n) (((unsigned char *)&n)[0] + (((unsigned char *)&n)[1] << 8) + \
  5201. +            (((unsigned char *)&n)[2] << 16) + (((unsigned char *)&n)[3] << 24))
  5202. +
  5203. +    if (!(bh = bread(dev,0,1024))) {
  5204. +        printk("  unable to read partition table of device %04x\n",dev);
  5205. +        return;
  5206. +    }
  5207. +    if (*(unsigned short *) (bh->b_data + 510) == 0xAA55) {
  5208. +        printk(" <");
  5209. +        p = (struct partition *) (0x1BE + bh->b_data);
  5210. +        for (i=1 ; i<=4 ; minor+=4,i++,p++) {
  5211. +            if (!(hd->part[minor].nr_sects = GET_WORD(p->nr_sects)))
  5212. +                continue;
  5213. +            hd->part[minor].start_sect = GET_WORD(p->start_sect);
  5214. +            printk(" %s%c%d", hd->major_name,'a'+(minor >> hd->minor_shift), minor);
  5215. +        }
  5216. +        printk(" >");
  5217. +    }
  5218. +#undef GET_WORD
  5219. +}
  5220. +
  5221. +extern int image_allocate_list(int dev,int minor,struct hd_struct *);
  5222. +extern void image_release_dev(int dev);
  5223. +
  5224. +void check_imagefiles(struct gendisk *hd, int real_dev)
  5225. +{
  5226. +    static int first_time = 1;
  5227. +    int minor = current_minor;
  5228. +    int i,p = 0;
  5229. +
  5230. +    if(first_time)
  5231. +        printk("Image file check:\n");
  5232. +    first_time = 0;
  5233. +
  5234. +    current_minor += 4;  /* first "extra" minor */
  5235. +
  5236. +    for (i=1 ; i<=4 ; minor++,i++) {
  5237. +        int len;
  5238. +        len = image_allocate_list(real_dev, minor, &hd->part[minor]);
  5239. +        if(len && !p)
  5240. +        {
  5241. +            printk("  %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift));
  5242. +            p = 1;
  5243. +        }
  5244. +        if(len)
  5245. +        {
  5246. +            printk(" %s%c%d", hd->major_name,'a'+(minor >> hd->minor_shift), i);
  5247. +/* Now scan it for pc partitions */
  5248. +            pc_check_hd(hd, minor);
  5249. +        }
  5250. +    }
  5251. +    image_release_dev(real_dev);
  5252. +    printk("\n");
  5253. +}
  5254. +#endif
  5255. +/* This function is used to re-read partition tables for removable disks.
  5256. +   Much of the cleanup from the old partition tables should have already been
  5257. +   done */
  5258. +
  5259. +/* This function will re-read the partition tables for a given device,
  5260. +and set things back up again.  There are some important caveats,
  5261. +however.  You must ensure that no one is using the device, and no one
  5262. +can start using the device while this function is being executed. */
  5263. +
  5264. +void resetup_one_dev(struct gendisk *dev, int drive)
  5265. +{
  5266. +    int i;
  5267. +    int start = drive<<dev->minor_shift;
  5268. +    int j = start + dev->max_p;
  5269. +    int major = dev->major << 8;
  5270. +
  5271. +    current_minor = 1+(drive<<dev->minor_shift);
  5272. +#ifndef __ARM__
  5273. +    check_partition(dev, major+(drive<<dev->minor_shift));
  5274. +#else
  5275. +    check_imagefiles(dev, major+(drive<<dev->minor_shift));
  5276. +#endif
  5277. +
  5278. +    for (i=start ; i < j ; i++)
  5279. +        dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
  5280. +}
  5281. +
  5282. +static void setup_dev(struct gendisk *dev)
  5283. +{
  5284. +    int i;
  5285. +    int j = dev->max_nr * dev->max_p;
  5286. +    int major = dev->major << 8;
  5287. +    int drive;
  5288. +
  5289. +
  5290. +    for (i = 0 ; i < j; i++)  {
  5291. +        dev->part[i].start_sect = 0;
  5292. +        dev->part[i].nr_sects = 0;
  5293. +    }
  5294. +    dev->init();
  5295. +    for (drive=0 ; drive<dev->nr_real ; drive++) {
  5296. +        current_minor = 1+(drive<<dev->minor_shift);
  5297. +#ifndef __ARM__
  5298. +        check_partition(dev, major+(drive<<dev->minor_shift));
  5299. +#else
  5300. +        check_imagefiles(dev, major+(drive<<dev->minor_shift));
  5301. +#endif
  5302. +    }
  5303. +    for (i=0 ; i < j ; i++)
  5304. +        dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
  5305. +    blk_size[dev->major] = dev->sizes;
  5306. +}
  5307. +
  5308. +void device_setup(void)
  5309. +{
  5310. +    struct gendisk *p;
  5311. +    int nr=0;
  5312. +
  5313. +    for (p = gendisk_head ; p ; p=p->next) {
  5314. +        setup_dev(p);
  5315. +        nr += p->nr_real;
  5316. +    }
  5317. +
  5318. +    if (ramdisk_size)
  5319. +        rd_load();
  5320. +}
  5321. diff -r -u -N linux.orig/arch/arm/drivers/block/hd.c linux.arm/arch/arm/drivers/block/hd.c
  5322. --- linux.orig/arch/arm/drivers/block/hd.c    Thu Jan  1 01:00:00 1970
  5323. +++ linux.arm/arch/arm/drivers/block/hd.c    Fri Oct 27 23:14:44 1995
  5324. @@ -0,0 +1,1231 @@
  5325. +/*
  5326. + *  linux/arch/arm/drivers/block/hd.c
  5327. + *
  5328. + *  Copyright (C) 1991, 1992  Linus Torvalds
  5329. + *  Modified 1995  Russell King for ARM.
  5330. + */
  5331. +
  5332. +/*
  5333. + * This is the low-level hd interrupt support. It traverses the
  5334. + * request-list, using interrupts to jump between functions. As
  5335. + * all the functions are called within interrupts, we may not
  5336. + * sleep. Special care is recommended.
  5337. + * 
  5338. + *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
  5339. + *
  5340. + *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  5341. + *  in the early extended-partition checks and added DM partitions
  5342. + *
  5343. + *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
  5344. + *  and general streamlining by mlord@bnr.ca (Mark Lord).
  5345. + */
  5346. +
  5347. +/* This is the maximum number of fragments accessed in one go */
  5348. +int no_hds;
  5349. +#define MAX_FRAGS    16
  5350. +static unsigned long frag_start[MAX_FRAGS];    /* Start of fragments */
  5351. +static unsigned long frag_len[MAX_FRAGS];    /* Fragment length */
  5352. +static int frag_count;                /* Number of fragments to go */
  5353. +static int frag_pos;                /* Position in fragment arrays */
  5354. +static unsigned int frag_sectors;
  5355. +
  5356. +#define DEFAULT_MULT_COUNT  0    /* set to 0 to disable multiple mode at boot */
  5357. +#define DEFAULT_UNMASK_INTR 0    /* set to 0 to *NOT* unmask irq's more often */
  5358. +
  5359. +#include <asm/irq.h>
  5360. +#include <linux/errno.h>
  5361. +#include <linux/signal.h>
  5362. +#include <linux/sched.h>
  5363. +#include <linux/timer.h>
  5364. +#include <linux/fs.h>
  5365. +#include <linux/kernel.h>
  5366. +#include <linux/hdreg.h>
  5367. +#include <linux/genhd.h>
  5368. +#include <linux/config.h>
  5369. +#include <linux/malloc.h>
  5370. +#include <linux/string.h>
  5371. +
  5372. +#define REALLY_SLOW_IO
  5373. +#include <asm/system.h>
  5374. +#include <asm/io.h>
  5375. +#include <asm/segment.h>
  5376. +
  5377. +#define MAJOR_NR HD_MAJOR
  5378. +#include "blk.h"
  5379. +
  5380. +void reissue_request(struct request *current);
  5381. +int issue_request(int dev, unsigned int block, unsigned int nsect, struct request *current);
  5382. +#define HD_IRQ 11
  5383. +
  5384. +static int revalidate_hddisk(int, int);
  5385. +
  5386. +#define    HD_DELAY    0
  5387. +
  5388. +#define MAX_ERRORS     16    /* Max read/write errors/sector */
  5389. +#define RESET_FREQ      8    /* Reset controller every 8th retry */
  5390. +#define RECAL_FREQ      4    /* Recalibrate every 4th retry */
  5391. +#define MAX_HD        2
  5392. +
  5393. +#define STAT_OK        (READY_STAT|SEEK_STAT)
  5394. +#define OK_STATUS(s)    (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
  5395. +
  5396. +static void recal_intr(void);
  5397. +static void bad_rw_intr(void);
  5398. +
  5399. +static char recalibrate[MAX_HD] = { 0, };
  5400. +static char special_op[MAX_HD] = { 0, };
  5401. +static int access_count[MAX_HD] = {0, };
  5402. +static char busy[MAX_HD] = {0, };
  5403. +static struct wait_queue * busy_wait = NULL;
  5404. +
  5405. +static int reset = 0;
  5406. +static int hd_error = 0;
  5407. +
  5408. +/*
  5409. + *  This struct defines the HD's and their types.
  5410. + */
  5411. +struct hd_i_struct {
  5412. +    unsigned int head,sect,cyl,wpcom,lzone,ctl;
  5413. +    };
  5414. +static struct hd_driveid *hd_ident_info[MAX_HD] = {0, };
  5415. +    
  5416. +#ifdef HD_TYPE
  5417. +static struct hd_i_struct hd_info[] = { HD_TYPE };
  5418. +struct hd_i_struct bios_info[] = { HD_TYPE };
  5419. +static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
  5420. +#else
  5421. +static struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
  5422. +struct hd_i_struct bios_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
  5423. +static int NR_HD = 0;
  5424. +#endif
  5425. +
  5426. +static struct hd_struct hd[MAX_HD<<6]={{0,0},};
  5427. +static int hd_sizes[MAX_HD<<6] = {0, };
  5428. +static int hd_blocksizes[MAX_HD<<6] = {0, };
  5429. +
  5430. +#if (HD_DELAY > 0)
  5431. +unsigned long last_req;
  5432. +
  5433. +unsigned long read_timer(void)
  5434. +{
  5435. +    unsigned long t, flags;
  5436. +    int i;
  5437. +
  5438. +    save_flags(flags);
  5439. +    cli();
  5440. +    t = jiffies * 11932;
  5441. +        outb_p(0, 0x43);
  5442. +    i = inb_p(0x40);
  5443. +    i |= inb(0x40) << 8;
  5444. +    restore_flags(flags);
  5445. +    return(t - i);
  5446. +}
  5447. +#endif
  5448. +
  5449. +void hd_setup(char *str, int *ints)
  5450. +{
  5451. +    int hdind = 0;
  5452. +
  5453. +    if (ints[0] != 3)
  5454. +        return;
  5455. +    if (bios_info[0].head != 0)
  5456. +        hdind=1;
  5457. +    bios_info[hdind].head  = hd_info[hdind].head = ints[2];
  5458. +    bios_info[hdind].sect  = hd_info[hdind].sect = ints[3];
  5459. +    bios_info[hdind].cyl   = hd_info[hdind].cyl = ints[1];
  5460. +    bios_info[hdind].wpcom = hd_info[hdind].wpcom = 0;
  5461. +    bios_info[hdind].lzone = hd_info[hdind].lzone = ints[1];
  5462. +    bios_info[hdind].ctl   = hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
  5463. +    NR_HD = hdind+1;
  5464. +}
  5465. +
  5466. +static void dump_status (char *msg, unsigned int stat)
  5467. +{
  5468. +    unsigned long flags;
  5469. +    char devc;
  5470. +
  5471. +    devc = CURRENT ? 'a' + DEVICE_NR(CURRENT->dev) : '?';
  5472. +    save_flags (flags);
  5473. +    sti();
  5474. +    printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
  5475. +    if (stat & BUSY_STAT)    printk("Busy ");
  5476. +    if (stat & READY_STAT)    printk("DriveReady ");
  5477. +    if (stat & WRERR_STAT)    printk("WriteFault ");
  5478. +    if (stat & SEEK_STAT)    printk("SeekComplete ");
  5479. +    if (stat & DRQ_STAT)    printk("DataRequest ");
  5480. +    if (stat & ECC_STAT)    printk("CorrectedError ");
  5481. +    if (stat & INDEX_STAT)    printk("Index ");
  5482. +    if (stat & ERR_STAT)    printk("Error ");
  5483. +    printk("}\n");
  5484. +    if ((stat & ERR_STAT) == 0) {
  5485. +        hd_error = 0;
  5486. +    } else {
  5487. +        hd_error = inb(HD_ERROR);
  5488. +        printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
  5489. +        if (hd_error & BBD_ERR)        printk("BadSector ");
  5490. +        if (hd_error & ECC_ERR)        printk("UncorrectableError ");
  5491. +        if (hd_error & ID_ERR)        printk("SectorIdNotFound ");
  5492. +        if (hd_error & ABRT_ERR)    printk("DriveStatusError ");
  5493. +        if (hd_error & TRK0_ERR)    printk("TrackZeroNotFound ");
  5494. +        if (hd_error & MARK_ERR)    printk("AddrMarkNotFound ");
  5495. +        printk("}");
  5496. +        if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
  5497. +            printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
  5498. +                inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
  5499. +            if (CURRENT)
  5500. +                printk(", sector=%ld", CURRENT->sector);
  5501. +        }
  5502. +        printk("\n");
  5503. +    }
  5504. +    restore_flags (flags);
  5505. +}
  5506. +
  5507. +void check_status(void)
  5508. +{
  5509. +    int i = inb_p(HD_STATUS);
  5510. +
  5511. +    if (!OK_STATUS(i)) {
  5512. +        dump_status("check_status", i);
  5513. +        bad_rw_intr();
  5514. +    }
  5515. +}
  5516. +
  5517. +static int controller_busy(void)
  5518. +{
  5519. +    int retries = 100000;
  5520. +    unsigned char status;
  5521. +
  5522. +    do {
  5523. +        status = inb_p(HD_STATUS);
  5524. +    } while ((status & BUSY_STAT) && --retries);
  5525. +    return status;
  5526. +}
  5527. +
  5528. +static int status_ok(void)
  5529. +{
  5530. +    unsigned char status = inb_p(HD_STATUS);
  5531. +
  5532. +    if (status & BUSY_STAT)
  5533. +        return 1;    /* Ancient, but does it make sense??? */
  5534. +    if (status & WRERR_STAT)
  5535. +        return 0;
  5536. +    if (!(status & READY_STAT))
  5537. +        return 0;
  5538. +    if (!(status & SEEK_STAT))
  5539. +        return 0;
  5540. +    return 1;
  5541. +}
  5542. +
  5543. +static int controller_ready(unsigned int drive, unsigned int head)
  5544. +{
  5545. +    int retry = 100;
  5546. +
  5547. +    do {
  5548. +        if (controller_busy() & BUSY_STAT)
  5549. +            return 0;
  5550. +        outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
  5551. +        if (status_ok())
  5552. +            return 1;
  5553. +    } while (--retry);
  5554. +    return 0;
  5555. +}
  5556. +
  5557. +static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
  5558. +        unsigned int head,unsigned int cyl,unsigned int cmd,
  5559. +        void (*intr_addr)(void))
  5560. +{
  5561. +    unsigned short port;
  5562. +
  5563. +#if (HD_DELAY > 0)
  5564. +    while (read_timer() - last_req < HD_DELAY)
  5565. +        /* nothing */;
  5566. +#endif
  5567. +    if (reset)
  5568. +        return;
  5569. +    if (!controller_ready(drive, head)) {
  5570. +        reset = 1;
  5571. +        return;
  5572. +    }
  5573. +    SET_INTR(intr_addr);
  5574. +    outb_p(hd_info[drive].ctl,HD_CMD);
  5575. +    port=HD_DATA;
  5576. +    outb_p(hd_info[drive].wpcom>>2,++port);
  5577. +    outb_p(nsect,++port);
  5578. +    outb_p(sect,++port);
  5579. +    outb_p(cyl,++port);
  5580. +    outb_p(cyl>>8,++port);
  5581. +    outb_p(0xA0|(drive<<4)|head,++port);
  5582. +    outb_p(cmd,++port);
  5583. +}
  5584. +
  5585. +static void hd_request (void);
  5586. +static unsigned int identified  [MAX_HD] = {0,}; /* 1 = drive ID already displayed   */
  5587. +static unsigned int unmask_intr [MAX_HD] = {0,}; /* 1 = unmask IRQs during I/O       */
  5588. +static unsigned int max_mult    [MAX_HD] = {0,}; /* max sectors for MultMode         */
  5589. +static unsigned int mult_req    [MAX_HD] = {0,}; /* requested MultMode count         */
  5590. +static unsigned int mult_count  [MAX_HD] = {0,}; /* currently enabled MultMode count */
  5591. +static struct request WCURRENT;
  5592. +
  5593. +static void fixstring (unsigned char *s, int bytecount)
  5594. +{
  5595. +    unsigned char *p, *end = &s[bytecount &= ~1];    /* bytecount must be even */
  5596. +
  5597. +    /* convert from big-endian to little-endian */
  5598. +    for (p = end ; p != s;) {
  5599. +        unsigned short *pp = (unsigned short *) (p -= 2);
  5600. +        *pp = (*pp >> 8) | (*pp << 8);
  5601. +    }
  5602. +
  5603. +    /* strip leading blanks */
  5604. +    while (s != end && *s == ' ')
  5605. +        ++s;
  5606. +
  5607. +    /* compress internal blanks and strip trailing blanks */
  5608. +    while (s != end && *s) {
  5609. +        if (*s++ != ' ' || (s != end && *s && *s != ' '))
  5610. +            *p++ = *(s-1);
  5611. +    }
  5612. +
  5613. +    /* wipe out trailing garbage */
  5614. +    while (p != end)
  5615. +        *p++ = '\0';
  5616. +}
  5617. +
  5618. +static void identify_intr(void)
  5619. +{
  5620. +    unsigned int dev = DEVICE_NR(CURRENT->dev);
  5621. +    unsigned short stat = inb_p(HD_STATUS);
  5622. +    struct hd_driveid *id = hd_ident_info[dev];
  5623. +
  5624. +    if (unmask_intr[dev])
  5625. +        sti();
  5626. +    if (stat & (BUSY_STAT|ERR_STAT)) {
  5627. +        printk ("  hd%c: non-IDE device, %dMB, CHS=%d/%d/%d\n", dev+'a',
  5628. +            hd_info[dev].cyl*hd_info[dev].head*hd_info[dev].sect / 2048,
  5629. +            hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect);
  5630. +        if (id != NULL) {
  5631. +            hd_ident_info[dev] = NULL;
  5632. +            kfree_s (id, 512);
  5633. +        }
  5634. +    } else {
  5635. +        insw(HD_DATA, id, 256); /* get ID info */
  5636. +        max_mult[dev] = id->max_multsect;
  5637. +        if ((id->field_valid&1) && id->cur_cyls && id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
  5638. +            /*
  5639. +             * Extract the physical drive geometry for our use.
  5640. +             * Note that we purposely do *not* update the bios_info.
  5641. +             * This way, programs that use it (like fdisk) will 
  5642. +             * still have the same logical view as the BIOS does,
  5643. +             * which keeps the partition table from being screwed.
  5644. +             */
  5645. +            hd_info[dev].cyl  = id->cur_cyls;
  5646. +            hd_info[dev].head = id->cur_heads;
  5647. +            hd_info[dev].sect = id->cur_sectors; 
  5648. +        }
  5649. +        fixstring (id->serial_no, sizeof(id->serial_no));
  5650. +        fixstring (id->fw_rev, sizeof(id->fw_rev));
  5651. +        fixstring (id->model, sizeof(id->model));
  5652. +        printk ("  hd%c: %.40s, %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n",
  5653. +            dev+'a', id->model, id->cyls*id->heads*id->sectors/2048,
  5654. +            id->buf_size/2, hd_info[dev].cyl, hd_info[dev].head,
  5655. +            hd_info[dev].sect, id->max_multsect);
  5656. +        /*
  5657. +         * Early model Quantum drives go weird at this point,
  5658. +         *   but doing a recalibrate seems to "fix" them.
  5659. +         * (Doing a full reset confuses some other model Quantums)
  5660. +         */
  5661. +        if (!strncmp(id->model, "QUANTUM", 7))
  5662. +            special_op[dev] = recalibrate[dev] = 1;
  5663. +    }
  5664. +#if (HD_DELAY > 0)
  5665. +    last_req = read_timer();
  5666. +#endif
  5667. +    hd_request();
  5668. +    return;
  5669. +}
  5670. +
  5671. +static void set_multmode_intr(void)
  5672. +{
  5673. +    unsigned int dev = DEVICE_NR(CURRENT->dev), stat = inb_p(HD_STATUS);
  5674. +
  5675. +    if (unmask_intr[dev])
  5676. +        sti();
  5677. +    if (stat & (BUSY_STAT|ERR_STAT)) {
  5678. +        mult_req[dev] = mult_count[dev] = 0;
  5679. +        dump_status("set multmode failed", stat);
  5680. +    } else {
  5681. +        if ((mult_count[dev] = mult_req[dev]))
  5682. +            printk ("  hd%c: enabled %d-sector multiple mode\n",
  5683. +                dev+'a', mult_count[dev]);
  5684. +        else
  5685. +            printk ("  hd%c: disabled multiple mode\n", dev+'a');
  5686. +    }
  5687. +#if (HD_DELAY > 0)
  5688. +    last_req = read_timer();
  5689. +#endif
  5690. +    hd_request();
  5691. +    return;
  5692. +}
  5693. +
  5694. +static int drive_busy(void)
  5695. +{
  5696. +    unsigned int i;
  5697. +    unsigned char c;
  5698. +
  5699. +    for (i = 0; i < 500000 ; i++) {
  5700. +        c = inb_p(HD_STATUS);
  5701. +        if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
  5702. +            return 0;
  5703. +    }
  5704. +    dump_status("reset timed out", c);
  5705. +    return 1;
  5706. +}
  5707. +
  5708. +static void reset_controller(void)
  5709. +{
  5710. +    int    i;
  5711. +
  5712. +    outb_p(4,HD_CMD);
  5713. +    for(i = 0; i < 1000; i++) nop();
  5714. +    outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
  5715. +    for(i = 0; i < 1000; i++) nop();
  5716. +    if (drive_busy())
  5717. +        printk("hd: controller still busy\n");
  5718. +    else if ((hd_error = inb(HD_ERROR)) != 1)
  5719. +        printk("hd: controller reset failed: %02x\n",hd_error);
  5720. +}
  5721. +
  5722. +static void reset_hd(void)
  5723. +{
  5724. +    static int i;
  5725. +
  5726. +repeat:
  5727. +    if (reset) {
  5728. +        reset = 0;
  5729. +        i = -1;
  5730. +        reset_controller();
  5731. +    } else {
  5732. +        check_status();
  5733. +        if (reset)
  5734. +            goto repeat;
  5735. +    }
  5736. +    if (++i < NR_HD) {
  5737. +        special_op[i] = recalibrate[i] = 1;
  5738. +        if (unmask_intr[i]) {
  5739. +            unmask_intr[i] = DEFAULT_UNMASK_INTR;
  5740. +            printk("hd%c: reset irq-unmasking to %d\n",i+'a',
  5741. +                DEFAULT_UNMASK_INTR);
  5742. +        }
  5743. +        if (mult_req[i] || mult_count[i]) {
  5744. +            mult_count[i] = 0;
  5745. +            mult_req[i] = DEFAULT_MULT_COUNT;
  5746. +            printk("hd%c: reset multiple mode to %d\n",i+'a',
  5747. +                DEFAULT_MULT_COUNT);
  5748. +        }
  5749. +        hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
  5750. +            hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
  5751. +        if (reset)
  5752. +            goto repeat;
  5753. +    } else
  5754. +        hd_request();
  5755. +}
  5756. +
  5757. +/*
  5758. + * Ok, don't know what to do with the unexpected interrupts: on some machines
  5759. + * doing a reset and a retry seems to result in an eternal loop. Right now I
  5760. + * ignore it, and just set the timeout.
  5761. + *
  5762. + * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
  5763. + * drive enters "idle", "standby", or "sleep" mode, so if the status looks
  5764. + * "good", we just ignore the interrupt completely.
  5765. + */
  5766. +void unexpected_hd_interrupt(void)
  5767. +{
  5768. +    unsigned int stat = inb_p(HD_STATUS);
  5769. +
  5770. +    if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
  5771. +        dump_status ("unexpected interrupt", stat);
  5772. +        SET_TIMER;
  5773. +    }
  5774. +}
  5775. +
  5776. +/*
  5777. + * bad_rw_intr() now tries to be a bit smarter and does things
  5778. + * according to the error returned by the controller.
  5779. + * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
  5780. + */
  5781. +static void bad_rw_intr(void)
  5782. +{
  5783. +    int dev;
  5784. +
  5785. +    if (!CURRENT)
  5786. +        return;
  5787. +    dev = DEVICE_NR(CURRENT->dev);
  5788. +    if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
  5789. +        end_request(0);
  5790. +        special_op[dev] = recalibrate[dev] = 1;
  5791. +    } else if (CURRENT->errors % RESET_FREQ == 0)
  5792. +        reset = 1;
  5793. +    else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
  5794. +        special_op[dev] = recalibrate[dev] = 1;
  5795. +    /* Otherwise just retry */
  5796. +}
  5797. +
  5798. +static inline int wait_DRQ(void)
  5799. +{
  5800. +    int retries = 100000, stat;
  5801. +
  5802. +    while (--retries > 0)
  5803. +        if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
  5804. +            return 0;
  5805. +    dump_status("wait_DRQ", stat);
  5806. +    return -1;
  5807. +}
  5808. +
  5809. +static void read_intr(void)
  5810. +{
  5811. +    unsigned int dev = DEVICE_NR(CURRENT->dev);
  5812. +    int i, retries = 100000, msect = mult_count[dev], nsect;
  5813. +
  5814. +    if (unmask_intr[dev])
  5815. +        sti();            /* permit other IRQs during xfer */
  5816. +    do {
  5817. +        i = (unsigned) inb_p(HD_STATUS);
  5818. +        if (i & BUSY_STAT)
  5819. +            continue;
  5820. +        if (!OK_STATUS(i))
  5821. +            break;
  5822. +        if (i & DRQ_STAT)
  5823. +            goto ok_to_read;
  5824. +    } while (--retries > 0);
  5825. +    dump_status("read_intr", i);
  5826. +    bad_rw_intr();
  5827. +    hd_request();
  5828. +    return;
  5829. +ok_to_read:
  5830. +    if (msect) {
  5831. +        if ((nsect = CURRENT->current_nr_sectors) > msect)
  5832. +            nsect = msect;
  5833. +        msect -= nsect;
  5834. +    } else
  5835. +        nsect = 1;
  5836. +    insw(HD_DATA,CURRENT->buffer,nsect<<8);
  5837. +    CURRENT->sector += nsect;
  5838. +    CURRENT->buffer += nsect<<9;
  5839. +    CURRENT->errors = 0;
  5840. +    i = (CURRENT->nr_sectors -= nsect);
  5841. +
  5842. +#ifdef DEBUG
  5843. +    printk("hd%c: read: sectors(%ld-%ld), remaining=%ld, buffer=0x%08lx\n",
  5844. +        dev+'a', CURRENT->sector, CURRENT->sector+nsect,
  5845. +        CURRENT->nr_sectors, (unsigned long) CURRENT->buffer+(nsect<<9));
  5846. +#endif
  5847. +    if ((CURRENT->current_nr_sectors -= nsect) <= 0)
  5848. +        end_request(1);
  5849. +    if (i > 0) {
  5850. +        if (msect)
  5851. +            goto ok_to_read;
  5852. +        if(!(--frag_sectors))
  5853. +         /* Next fragment req.d */
  5854. +            reissue_request(CURRENT);
  5855. +        else
  5856. +        {
  5857. +            SET_INTR(&read_intr);
  5858. +        }
  5859. +        return;
  5860. +    }
  5861. +    (void) inb_p(HD_STATUS);
  5862. +#if (HD_DELAY > 0)
  5863. +    last_req = read_timer();
  5864. +#endif
  5865. +    if (CURRENT)
  5866. +        hd_request();
  5867. +    return;
  5868. +}
  5869. +
  5870. +static inline void multwrite (unsigned int dev)
  5871. +{
  5872. +    unsigned int mcount = mult_count[dev];
  5873. +
  5874. +    while (mcount--) {
  5875. +        outsw(HD_DATA,WCURRENT.buffer,256);
  5876. +        if (!--WCURRENT.nr_sectors)
  5877. +            return;
  5878. +        WCURRENT.buffer += 512;
  5879. +        if (!--WCURRENT.current_nr_sectors) {
  5880. +            WCURRENT.bh = WCURRENT.bh->b_reqnext;
  5881. +            if (WCURRENT.bh == NULL)
  5882. +                panic("buffer list corrupted\n");
  5883. +            WCURRENT.current_nr_sectors = WCURRENT.bh->b_size>>9;
  5884. +            WCURRENT.buffer             = WCURRENT.bh->b_data;
  5885. +        }
  5886. +    }
  5887. +}
  5888. +
  5889. +static void multwrite_intr(void)
  5890. +{
  5891. +    int i;
  5892. +    unsigned int dev = DEVICE_NR(WCURRENT.dev);
  5893. +
  5894. +    if (unmask_intr[dev])
  5895. +        sti();
  5896. +    if (OK_STATUS(i=inb_p(HD_STATUS))) {
  5897. +        if (i & DRQ_STAT) {
  5898. +            if (WCURRENT.nr_sectors) {
  5899. +                multwrite(dev);
  5900. +                SET_INTR(&multwrite_intr);
  5901. +                return;
  5902. +            }
  5903. +        } else {
  5904. +            if (!WCURRENT.nr_sectors) {    /* all done? */
  5905. +                for (i = CURRENT->nr_sectors; i > 0;){
  5906. +                    i -= CURRENT->current_nr_sectors;
  5907. +                    end_request(1);
  5908. +                }
  5909. +#if (HD_DELAY > 0)
  5910. +                last_req = read_timer();
  5911. +#endif
  5912. +                if (CURRENT)
  5913. +                    hd_request();
  5914. +                return;
  5915. +            }
  5916. +        }
  5917. +    }
  5918. +    dump_status("multwrite_intr", i);
  5919. +    bad_rw_intr();
  5920. +    hd_request();
  5921. +}
  5922. +
  5923. +static void write_intr(void)
  5924. +{
  5925. +    int i;
  5926. +    int retries = 100000;
  5927. +
  5928. +    if (unmask_intr[DEVICE_NR(WCURRENT.dev)])
  5929. +        sti();
  5930. +    do {
  5931. +        i = (unsigned) inb_p(HD_STATUS);
  5932. +        if (i & BUSY_STAT)
  5933. +            continue;
  5934. +        if (!OK_STATUS(i))
  5935. +            break;
  5936. +        if ((CURRENT->nr_sectors <= 1) || (frag_sectors <= 1) || (i & DRQ_STAT))
  5937. +            goto ok_to_write;
  5938. +    } while (--retries > 0);
  5939. +    dump_status("write_intr", i);
  5940. +    bad_rw_intr();
  5941. +    hd_request();
  5942. +    return;
  5943. +ok_to_write:
  5944. +    CURRENT->sector++;
  5945. +    i = --CURRENT->nr_sectors;
  5946. +    --CURRENT->current_nr_sectors;
  5947. +    CURRENT->buffer += 512;
  5948. +    if (!i || (CURRENT->bh && !SUBSECTOR(i)))
  5949. +        end_request(1);
  5950. +    if (i > 0) {
  5951. +        if(!(--frag_sectors))
  5952. +         /* Next fragment req.d */
  5953. +            reissue_request(CURRENT);
  5954. +        else
  5955. +        {
  5956. +            SET_INTR(&write_intr);
  5957. +            outsw(HD_DATA,CURRENT->buffer,256);
  5958. +            sti();
  5959. +        }
  5960. +    } else {
  5961. +#if (HD_DELAY > 0)
  5962. +        last_req = read_timer();
  5963. +#endif
  5964. +        hd_request();
  5965. +    }
  5966. +    return;
  5967. +}
  5968. +
  5969. +static void recal_intr(void)
  5970. +{
  5971. +    check_status();
  5972. +#if (HD_DELAY > 0)
  5973. +    last_req = read_timer();
  5974. +#endif
  5975. +    hd_request();
  5976. +}
  5977. +
  5978. +/*
  5979. + * This is another of the error-routines I don't know what to do with. The
  5980. + * best idea seems to just set reset, and start all over again.
  5981. + */
  5982. +static void hd_times_out(void)
  5983. +{
  5984. +    unsigned int dev;
  5985. +
  5986. +    DEVICE_INTR = NULL;
  5987. +    if (!CURRENT)
  5988. +        return;
  5989. +    disable_irq(HD_IRQ);
  5990. +    sti();
  5991. +    reset = 1;
  5992. +    dev = DEVICE_NR(CURRENT->dev);
  5993. +    printk("hd%c: timeout\n", dev+'a');
  5994. +    if (++CURRENT->errors >= MAX_ERRORS) {
  5995. +#ifdef DEBUG
  5996. +        printk("hd%c: too many errors\n", dev+'a');
  5997. +#endif
  5998. +        end_request(0);
  5999. +    }
  6000. +    cli();
  6001. +    hd_request();
  6002. +    enable_irq(HD_IRQ);
  6003. +}
  6004. +
  6005. +int do_special_op (unsigned int dev)
  6006. +{
  6007. +    if (recalibrate[dev]) {
  6008. +        recalibrate[dev] = 0;
  6009. +        hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
  6010. +        return reset;
  6011. +    }
  6012. +    if (!identified[dev]) {
  6013. +        identified[dev]  = 1;
  6014. +        unmask_intr[dev] = DEFAULT_UNMASK_INTR;
  6015. +        mult_req[dev]    = DEFAULT_MULT_COUNT;
  6016. +        hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
  6017. +        return reset;
  6018. +    }
  6019. +    if (mult_req[dev] != mult_count[dev]) {
  6020. +        hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
  6021. +        return reset;
  6022. +    }
  6023. +    if (hd_info[dev].head > 16) {
  6024. +        printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
  6025. +        end_request(0);
  6026. +    }
  6027. +    special_op[dev] = 0;
  6028. +    return 1;
  6029. +}
  6030. +
  6031. +/*
  6032. + * The driver enables interrupts as much as possible.  In order to do this,
  6033. + * (a) the device-interrupt is disabled before entering hd_request(),
  6034. + * and (b) the timeout-interrupt is disabled before the sti().
  6035. + *
  6036. + * Interrupts are still masked (by default) whenever we are exchanging
  6037. + * data/cmds with a drive, because some drives seem to have very poor
  6038. + * tolerance for latency during I/O.  For devices which don't suffer from
  6039. + * that problem (most don't), the unmask_intr[] flag can be set to unmask
  6040. + * other interrupts during data/cmd transfers (by defining DEFAULT_UNMASK_INTR
  6041. + * to 1, or by using "hdparm -u1 /dev/hd?" from the shell).
  6042. + */
  6043. +static void hd_request(void)
  6044. +{
  6045. +    unsigned int dev, block, nsect;
  6046. +
  6047. +    if (CURRENT && CURRENT->dev < 0) return;
  6048. +    if (DEVICE_INTR)
  6049. +        return;
  6050. +repeat:
  6051. +    timer_active &= ~(1<<HD_TIMER);
  6052. +    sti();
  6053. +    INIT_REQUEST;
  6054. +    if (reset) {
  6055. +        cli();
  6056. +        reset_hd();
  6057. +        return;
  6058. +    }
  6059. +    dev = MINOR(CURRENT->dev);
  6060. +    block = CURRENT->sector;
  6061. +    nsect = CURRENT->nr_sectors;
  6062. +    if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
  6063. +#ifdef DEBUG
  6064. +        if (dev >= (NR_HD<<6))
  6065. +            printk("hd: bad minor number: device=0x%04x\n", CURRENT->dev);
  6066. +        else
  6067. +            printk("hd%c: bad access: block=%d, count=%d\n",
  6068. +                (dev>>6)+'a', block, nsect);
  6069. +#endif
  6070. +        end_request(0);
  6071. +        goto repeat;
  6072. +    }
  6073. +    block += hd[dev].start_sect;
  6074. +    if(dev & 0x3f)
  6075. +    { /* map sectors block to block+nsect to frags, 
  6076. +       */
  6077. +        if(!image_file_check(CURRENT->dev,CURRENT->cmd))
  6078. +            goto repeat;
  6079. +        frag_count = image_file_map(CURRENT->dev, block, nsect, MAX_FRAGS, 
  6080. +                        frag_start, frag_len);
  6081. +        if(!frag_count)
  6082. +        {
  6083. +            goto repeat;
  6084. +        }
  6085. +        
  6086. +        block = frag_start[0];
  6087. +        frag_sectors = nsect = frag_len[0];
  6088. +        frag_pos = 0;
  6089. +    }
  6090. +    else
  6091. +    {
  6092. +        frag_pos = 0;
  6093. +        frag_count = 1;
  6094. +        frag_sectors = nsect;
  6095. +        if(CURRENT->cmd == WRITE)
  6096. +        { /* Protect normal HD from writes */
  6097. +            printk("hd%d : attempted write on protected drive\n",dev);
  6098. +            end_request(0);
  6099. +            goto repeat;
  6100. +        }
  6101. +    }
  6102. +    if(issue_request(dev,block,nsect, CURRENT))
  6103. +        goto repeat;
  6104. +}
  6105. +
  6106. +void reissue_request(struct request *current)
  6107. +{
  6108. +    unsigned int dev, block, nsect;
  6109. +
  6110. +    dev = MINOR(current->dev);
  6111. +    frag_pos++;
  6112. +    if(frag_pos >= MAX_FRAGS)
  6113. +    {
  6114. +        block = current->sector;
  6115. +        block += hd[dev].start_sect;
  6116. +        nsect = current->nr_sectors;
  6117. +        if(!image_file_check(current->dev,current->cmd))
  6118. +        {
  6119. +            end_request(0);
  6120. +            hd_request();
  6121. +            return;
  6122. +        }
  6123. +        frag_count = image_file_map(current->dev, block, nsect, MAX_FRAGS, 
  6124. +                        frag_start, frag_len);
  6125. +        if(!frag_count)
  6126. +        {
  6127. +            end_request(0);
  6128. +            hd_request();
  6129. +            return;
  6130. +        }
  6131. +        
  6132. +        frag_pos = 0;
  6133. +        }        
  6134. +    frag_sectors = frag_len[frag_pos];
  6135. +repeat:
  6136. +    if(issue_request(dev, frag_start[frag_pos], frag_len[frag_pos], current))
  6137. +    {
  6138. +        printk("EEEEK - going round the loop\n");
  6139. +        goto repeat;
  6140. +    }
  6141. +}
  6142. +
  6143. +/* 
  6144. + * This routine actually issues a request to the hard disk itself
  6145. + */
  6146. +int issue_request(int dev, unsigned int block, unsigned int nsect, struct request *current)
  6147. +{
  6148. +    unsigned int sec, track, head, cyl;
  6149. +int d = dev;
  6150. +    dev >>= 6;
  6151. +    if (special_op[dev]) {
  6152. +        if (do_special_op(dev))
  6153. +            return 1;
  6154. +        return 0;
  6155. +    }
  6156. +    sec   = block % hd_info[dev].sect + 1;
  6157. +    track = block / hd_info[dev].sect;
  6158. +    head  = track % hd_info[dev].head;
  6159. +    cyl   = track / hd_info[dev].head;
  6160. +#ifdef DEBUG
  6161. +    printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
  6162. +        dev+'a', (current->cmd == READ)?"read":"writ",
  6163. +        cyl, head, sec, nsect, (unsigned long) current->buffer,current);
  6164. +#endif
  6165. +    frag_sectors = nsect;
  6166. +    if (!unmask_intr[dev])
  6167. +        cli();
  6168. +    if (current->cmd == READ) {
  6169. +        unsigned int cmd = mult_count[dev] > 1 ? WIN_MULTREAD : WIN_READ;
  6170. +        hd_out(dev,nsect,sec,head,cyl,cmd,&read_intr);
  6171. +        if (reset)
  6172. +            return 1;
  6173. +        return 0;
  6174. +    }
  6175. +    if (current->cmd == WRITE) {
  6176. +#if 1
  6177. +#if 0
  6178. +        if (mult_count[dev])
  6179. +            hd_out(dev,nsect,sec,head,cyl,WIN_MULTWRITE,&multwrite_intr);
  6180. +        else
  6181. +#endif
  6182. +            hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
  6183. +        if (reset)
  6184. +            return 1;
  6185. +        if (wait_DRQ()) {
  6186. +            bad_rw_intr();
  6187. +            return 1;
  6188. +        }
  6189. +#if 0
  6190. +        if (mult_count[dev]) {
  6191. +            WCURRENT = *current;
  6192. +            multwrite(dev);
  6193. +        } else
  6194. +#endif
  6195. +            outsw(HD_DATA,current->buffer,256);
  6196. +if(d == 1 && block < 10) while(1);
  6197. +#else
  6198. +if(d == 1)
  6199. +        printk("write: buffer = %p (%08lX)\n", current->buffer, *(unsigned long *)current->buffer);
  6200. +{int i; for(i=0; i<0x003fffff; i++); }
  6201. +        end_request(0);
  6202. +        return 1;
  6203. +#endif
  6204. +        return 0;
  6205. +    }
  6206. +    panic("unknown hd-command");
  6207. +    return 0;
  6208. +}
  6209. +
  6210. +static void do_hd_request (void)
  6211. +{
  6212. +    disable_irq(HD_IRQ);
  6213. +    hd_request();
  6214. +    enable_irq(HD_IRQ);
  6215. +}
  6216. +
  6217. +static int hd_ioctl(struct inode * inode, struct file * file,
  6218. +    unsigned int cmd, unsigned long arg)
  6219. +{
  6220. +    struct hd_geometry *loc = (struct hd_geometry *) arg;
  6221. +    int dev, err;
  6222. +    unsigned long flags;
  6223. +
  6224. +    if ((!inode) || (!inode->i_rdev))
  6225. +        return -EINVAL;
  6226. +    dev = DEVICE_NR(inode->i_rdev);
  6227. +    if (dev >= NR_HD)
  6228. +        return -EINVAL;
  6229. +    switch (cmd) {
  6230. +        case HDIO_GETGEO:
  6231. +            if (!loc)  return -EINVAL;
  6232. +            err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
  6233. +            if (err)
  6234. +                return err;
  6235. +            put_fs_byte(bios_info[dev].head,
  6236. +                (char *) &loc->heads);
  6237. +            put_fs_byte(bios_info[dev].sect,
  6238. +                (char *) &loc->sectors);
  6239. +            put_fs_word(bios_info[dev].cyl,
  6240. +                (short *) &loc->cylinders);
  6241. +            put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
  6242. +                (long *) &loc->start);
  6243. +            return 0;
  6244. +        case BLKRASET:
  6245. +            if(!suser())  return -EACCES;
  6246. +            if(arg > 0xff) return -EINVAL;
  6247. +            read_ahead[MAJOR(inode->i_rdev)] = arg;
  6248. +            return 0;
  6249. +        case BLKRAGET:
  6250. +            if (!arg)  return -EINVAL;
  6251. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  6252. +            if (err)
  6253. +                return err;
  6254. +            put_fs_long(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
  6255. +            return 0;
  6256. +             case BLKGETSIZE:   /* Return device size */
  6257. +            if (!arg)  return -EINVAL;
  6258. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  6259. +            if (err)
  6260. +                return err;
  6261. +            put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
  6262. +            return 0;
  6263. +        case BLKFLSBUF:
  6264. +            if(!suser())  return -EACCES;
  6265. +            fsync_dev(inode->i_rdev);
  6266. +            invalidate_buffers(inode->i_rdev);
  6267. +            return 0;
  6268. +
  6269. +        case BLKRRPART: /* Re-read partition tables */
  6270. +            return revalidate_hddisk(inode->i_rdev, 1);
  6271. +
  6272. +        case HDIO_SET_UNMASKINTR:
  6273. +            if (!suser()) return -EACCES;
  6274. +            if ((arg > 1) || (MINOR(inode->i_rdev) & 0x3F))
  6275. +                return -EINVAL;
  6276. +            unmask_intr[dev] = arg;
  6277. +            return 0;
  6278. +
  6279. +                case HDIO_GET_UNMASKINTR:
  6280. +            if (!arg)  return -EINVAL;
  6281. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  6282. +            if (err)
  6283. +                return err;
  6284. +            put_fs_long(unmask_intr[dev], (long *) arg);
  6285. +            return 0;
  6286. +
  6287. +                case HDIO_GET_MULTCOUNT:
  6288. +            if (!arg)  return -EINVAL;
  6289. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  6290. +            if (err)
  6291. +                return err;
  6292. +            put_fs_long(mult_count[dev], (long *) arg);
  6293. +            return 0;
  6294. +
  6295. +        case HDIO_SET_MULTCOUNT:
  6296. +            if (!suser()) return -EACCES;
  6297. +            if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
  6298. +            save_flags(flags);
  6299. +            cli();    /* a prior request might still be in progress */
  6300. +            if (arg > max_mult[dev])
  6301. +                err = -EINVAL;    /* out of range for device */
  6302. +            else if (mult_req[dev] != mult_count[dev]) {
  6303. +                special_op[dev] = 1;
  6304. +                err = -EBUSY;    /* busy, try again */
  6305. +            } else {
  6306. +                mult_req[dev] = arg;
  6307. +                special_op[dev] = 1;
  6308. +                err = 0;
  6309. +            }
  6310. +            restore_flags(flags);
  6311. +            return err;
  6312. +
  6313. +        case HDIO_GET_IDENTITY:
  6314. +            if (!arg)  return -EINVAL;
  6315. +            if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
  6316. +            if (hd_ident_info[dev] == NULL)  return -ENOMSG;
  6317. +            err = verify_area(VERIFY_WRITE, (char *) arg, sizeof(struct hd_driveid));
  6318. +            if (err)
  6319. +                return err;
  6320. +            memcpy_tofs((char *)arg, (char *) hd_ident_info[dev], sizeof(struct hd_driveid));
  6321. +            return 0;
  6322. +
  6323. +        RO_IOCTLS(inode->i_rdev,arg);
  6324. +        default:
  6325. +            return -EINVAL;
  6326. +    }
  6327. +}
  6328. +
  6329. +static int hd_open(struct inode * inode, struct file * filp)
  6330. +{
  6331. +    int target;
  6332. +    target =  DEVICE_NR(inode->i_rdev);
  6333. +
  6334. +    if (target >= NR_HD)
  6335. +        return -ENODEV;
  6336. +
  6337. +    while (busy[target])
  6338. +        sleep_on(&busy_wait);
  6339. +    access_count[target]++;
  6340. +    return 0;
  6341. +}
  6342. +
  6343. +/*
  6344. + * Releasing a block device means we sync() it, so that it can safely
  6345. + * be forgotten about...
  6346. + */
  6347. +static void hd_release(struct inode * inode, struct file * file)
  6348. +{
  6349. +        int target;
  6350. +    sync_dev(inode->i_rdev);
  6351. +
  6352. +    target =  DEVICE_NR(inode->i_rdev);
  6353. +    access_count[target]--;
  6354. +
  6355. +}
  6356. +
  6357. +static void hd_geninit(void);
  6358. +
  6359. +static struct gendisk hd_gendisk = {
  6360. +    MAJOR_NR,    /* Major number */    
  6361. +    "hd",        /* Major name */
  6362. +    6,        /* Bits to shift to get real from partition */
  6363. +    1 << 6,        /* Number of partitions per real */
  6364. +    MAX_HD,        /* maximum number of real */
  6365. +    hd_geninit,    /* init function */
  6366. +    hd,        /* hd struct */
  6367. +    hd_sizes,    /* block sizes */
  6368. +    0,        /* number */
  6369. +    (void *) bios_info,    /* internal */
  6370. +    NULL        /* next */
  6371. +};
  6372. +    
  6373. +static void hd_interrupt(int irq, struct pt_regs *regs)
  6374. +{
  6375. +    void (*handler)(void) = DEVICE_INTR;
  6376. +
  6377. +    DEVICE_INTR = NULL;
  6378. +    timer_active &= ~(1<<HD_TIMER);
  6379. +    if (!handler)
  6380. +        handler = unexpected_hd_interrupt;
  6381. +    handler();
  6382. +    sti();
  6383. +}
  6384. +
  6385. +
  6386. +void set_hdinfo(int dev,unsigned char secsptrack,unsigned char heads,
  6387. +                    unsigned long discsize,unsigned int secsize)
  6388. +{
  6389. +  dev=MINOR(dev);
  6390. +  if(hd_info[dev>>6].cyl==1)
  6391. +  {
  6392. +    hd_info[dev>>6].cyl=discsize/(secsptrack*heads*secsize);
  6393. +    hd_info[dev>>6].head=heads;
  6394. +    hd_info[dev>>6].wpcom=-1;
  6395. +    hd_info[dev>>6].ctl=8;
  6396. +    hd_info[dev>>6].lzone=hd_info[dev>>6].cyl-1;
  6397. +    hd_info[dev>>6].sect=secsptrack;
  6398. +  }
  6399. +  hd[dev].start_sect=0;
  6400. +  hd[dev].nr_sects=discsize/secsize;
  6401. +#if 0
  6402. +  printk("hd%c: %d cylinders, %d heads, %d sectors (%d total)\n",'a'+(dev>>6),
  6403. +    hd_info[dev>>6].cyl, heads, secsptrack, discsize);
  6404. +#endif
  6405. +}
  6406. +
  6407. +/*
  6408. + * This is the harddisk IRQ description. The SA_INTERRUPT in sa_flags
  6409. + * means we run the IRQ-handler with interrupts disabled: this is bad for
  6410. + * interrupt latency, but anything else has led to problems on some
  6411. + * machines...
  6412. + *
  6413. + * We enable interrupts in some of the routines after making sure it's
  6414. + * safe.
  6415. + */
  6416. +int no_hds;
  6417. +static void hd_geninit(void)
  6418. +{
  6419. +    int drive, i;
  6420. +
  6421. +NR_HD = 0;
  6422. +    if (!NR_HD) {
  6423. +    /* Default settings */
  6424. +        for (drive=0 ; drive<2 ; drive++) {
  6425. +            bios_info[drive].cyl    = hd_info[drive].cyl    = 1;
  6426. +            bios_info[drive].head    = hd_info[drive].head    = 1;
  6427. +            bios_info[drive].wpcom    = hd_info[drive].wpcom    = -1;
  6428. +            bios_info[drive].ctl    = hd_info[drive].ctl    = 8;
  6429. +            bios_info[drive].lzone    = hd_info[drive].lzone    = 1;
  6430. +            bios_info[drive].sect    = hd_info[drive].sect    = 17;
  6431. +            if(hd_info[drive].cyl && NR_HD == drive)
  6432. +                NR_HD++;
  6433. +        }
  6434. +        }
  6435. +
  6436. +    NR_HD = no_hds;
  6437. +
  6438. +    i = NR_HD;
  6439. +    while (i-- > 0) {
  6440. +        /*
  6441. +         * The newer E-IDE BIOSs handle drives larger than 1024
  6442. +         * cylinders by increasing the number of logical heads
  6443. +         * to keep the number of logical cylinders below the
  6444. +         * sacred INT13 limit of 1024 (10 bits).  If that is
  6445. +         * what's happening here, we'll find out and correct
  6446. +         * it later when "identifying" the drive.
  6447. +         */
  6448. +        hd[i<<6].nr_sects = bios_info[i].head *
  6449. +                bios_info[i].sect * bios_info[i].cyl;
  6450. +        hd_ident_info[i] = (struct hd_driveid *) kmalloc(512,GFP_KERNEL);
  6451. +        special_op[i] = 1;
  6452. +    }
  6453. +    if (NR_HD) {
  6454. +        if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd")) {
  6455. +            printk("hd: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
  6456. +            NR_HD = 0;
  6457. +        } else {
  6458. +            request_region(HD_DATA, 8, "hd");
  6459. +            request_region(HD_CMD, 1, "hd(cmd)");
  6460. +        }
  6461. +    }
  6462. +    hd_gendisk.nr_real = NR_HD;
  6463. +
  6464. +    for(i=0;i<(MAX_HD << 6);i++) hd_blocksizes[i] = 1024;
  6465. +    blksize_size[MAJOR_NR] = hd_blocksizes;
  6466. +}
  6467. +
  6468. +static struct file_operations hd_fops = {
  6469. +    NULL,            /* lseek - default */
  6470. +    block_read,        /* read - general block-dev read */
  6471. +    block_write,        /* write - general block-dev write */
  6472. +    NULL,            /* readdir - bad */
  6473. +    NULL,            /* select */
  6474. +    hd_ioctl,        /* ioctl */
  6475. +    NULL,            /* mmap */
  6476. +    hd_open,        /* open */
  6477. +    hd_release,        /* release */
  6478. +    block_fsync        /* fsync */
  6479. +};
  6480. +
  6481. +unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
  6482. +{
  6483. +    if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
  6484. +        printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);
  6485. +        return mem_start;
  6486. +    }
  6487. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  6488. +    read_ahead[MAJOR_NR] = 8;        /* 8 sector (4kB) read-ahead */
  6489. +    hd_gendisk.next = gendisk_head;
  6490. +    gendisk_head = &hd_gendisk;
  6491. +    timer_table[HD_TIMER].fn = hd_times_out;
  6492. +    return mem_start;
  6493. +}
  6494. +
  6495. +#define DEVICE_BUSY busy[target]
  6496. +#define USAGE access_count[target]
  6497. +#define CAPACITY (bios_info[target].head*bios_info[target].sect*bios_info[target].cyl)
  6498. +/* We assume that the the bios parameters do not change, so the disk capacity
  6499. +   will not change */
  6500. +#undef MAYBE_REINIT
  6501. +#define GENDISK_STRUCT hd_gendisk
  6502. +
  6503. +/*
  6504. + * This routine is called to flush all partitions and partition tables
  6505. + * for a changed scsi disk, and then re-read the new partition table.
  6506. + * If we are revalidating a disk because of a media change, then we
  6507. + * enter with usage == 0.  If we are using an ioctl, we automatically have
  6508. + * usage == 1 (we need an open channel to use an ioctl :-), so this
  6509. + * is our limit.
  6510. + */
  6511. +static int revalidate_hddisk(int dev, int maxusage)
  6512. +{
  6513. +    int target, major;
  6514. +    struct gendisk * gdev;
  6515. +    int max_p;
  6516. +    int start;
  6517. +    int i;
  6518. +    unsigned long flags;
  6519. +
  6520. +    target =  DEVICE_NR(dev);
  6521. +    gdev = &GENDISK_STRUCT;
  6522. +
  6523. +    save_flags(flags);
  6524. +    cli();
  6525. +    if (DEVICE_BUSY || USAGE > maxusage) {
  6526. +        restore_flags(flags);
  6527. +        return -EBUSY;
  6528. +    };
  6529. +    DEVICE_BUSY = 1;
  6530. +    restore_flags(flags);
  6531. +
  6532. +    max_p = gdev->max_p;
  6533. +    start = target << gdev->minor_shift;
  6534. +    major = MAJOR_NR << 8;
  6535. +
  6536. +    for (i=max_p - 1; i >=0 ; i--) {
  6537. +        sync_dev(major | start | i);
  6538. +        invalidate_inodes(major | start | i);
  6539. +        invalidate_buffers(major | start | i);
  6540. +        gdev->part[start+i].start_sect = 0;
  6541. +        gdev->part[start+i].nr_sects = 0;
  6542. +    };
  6543. +
  6544. +#ifdef MAYBE_REINIT
  6545. +    MAYBE_REINIT;
  6546. +#endif
  6547. +
  6548. +    gdev->part[start].nr_sects = CAPACITY;
  6549. +    resetup_one_dev(gdev, target);
  6550. +
  6551. +    DEVICE_BUSY = 0;
  6552. +    wake_up(&busy_wait);
  6553. +    return 0;
  6554. +}
  6555. +
  6556. diff -r -u -N linux.orig/arch/arm/drivers/block/hd.diff linux.arm/arch/arm/drivers/block/hd.diff
  6557. --- linux.orig/arch/arm/drivers/block/hd.diff    Thu Jan  1 01:00:00 1970
  6558. +++ linux.arm/arch/arm/drivers/block/hd.diff    Fri Oct 27 23:14:52 1995
  6559. @@ -0,0 +1,2672 @@
  6560. +--- /usr/src/linux/arch/arm/drivers/block/floppy.c    Thu Aug 31 22:19:59 1995
  6561. ++++ /usr/src/linux/drivers/block/floppy.c    Sun Sep 24 10:23:30 1995
  6562. +@@ -4,32 +4,6 @@
  6563. +  *  Copyright (C) 1991, 1992  Linus Torvalds
  6564. +  *  Copyright (C) 1993, 1994  Alain Knaff
  6565. +  */
  6566. +-
  6567. +-/* Configuration */
  6568. +-/* The following does some extra sanity checks */
  6569. +-#define SANITY
  6570. +-
  6571. +-/* the following is the mask of allowed drives. By default units 2 and
  6572. +- * 3 of both floppy controllers are disabled, because switching on the
  6573. +- * motor of these drives causes system hangs on some PCI computers. drive
  6574. +- * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
  6575. +- * a drive is allowed. */
  6576. +-#define ALLOWED_DRIVE_MASK 0x0F
  6577. +-
  6578. +-/* Undefine the following if you have to floppy disk controllers:
  6579. +- * This works at least for me; if you get two controllers working, with
  6580. +- * drives attached to both, please mail me: Alain.Knaff@imag.fr */
  6581. +-/* #define HAVE_2_CONTROLLERS */
  6582. +-
  6583. +-
  6584. +-/* Define the following if you don't like that your drives seek audibly
  6585. +- * after a disk change (but it may not work correctly for everybody)
  6586. +- */
  6587. +-#define SILENT_DC_CLEAR
  6588. +-
  6589. +-
  6590. +-/* End of configuration */
  6591. +-
  6592. + /*
  6593. +  * 02.12.91 - Changed to static variables to indicate need for reset
  6594. +  * and recalibrate. This makes some things easier (output_byte reset
  6595. +@@ -103,15 +77,39 @@
  6596. +  * format bug fixes, but unfortunately some new bugs too...
  6597. +  */
  6598. +-/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
  6599. ++/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write 
  6600. +  * errors to allow safe writing by specialized programs.
  6601. +  */
  6602. +-int no_floppies;
  6603. +-#define FLOPPY_IRQ 12
  6604. +-#define FLOPPY_DMA 2
  6605. ++
  6606. ++#define CONFIG_FLOPPY_SANITY
  6607. ++#undef  CONFIG_FLOPPY_SILENT_DCL_CLEAR
  6608. ++
  6609. ++#define REALLY_SLOW_IO
  6610. ++
  6611. + #define DEBUGT 2
  6612. ++#define DCL_DEBUG /* debug disk change line */
  6613. + #include <linux/config.h>
  6614. ++
  6615. ++/* do print messages for unexpected interrupts */
  6616. ++static int print_unex=1;
  6617. ++
  6618. ++#ifndef FD_MODULE
  6619. ++/* the following is the mask of allowed drives. By default units 2 and
  6620. ++ * 3 of both floppy controllers are disabled, because switching on the
  6621. ++ * motor of these drives causes system hangs on some PCI computers. drive
  6622. ++ * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
  6623. ++ * a drive is allowed. */
  6624. ++static int ALLOWED_DRIVE_MASK=0x33;
  6625. ++
  6626. ++#define FLOPPY_IRQ 6
  6627. ++#define FLOPPY_DMA 2
  6628. ++#define FDC1 0x3f0
  6629. ++static int FDC2=-1;
  6630. ++#endif
  6631. ++
  6632. ++#define MODULE_AWARE_DRIVER
  6633. ++
  6634. + #include <linux/sched.h>
  6635. + #include <linux/fs.h>
  6636. + #include <linux/kernel.h>
  6637. +@@ -125,6 +123,7 @@
  6638. + #include <linux/string.h>
  6639. + #include <linux/fcntl.h>
  6640. + #include <linux/delay.h>
  6641. ++#include <linux/mc146818rtc.h> /* CMOS defines */
  6642. + #include <asm/dma.h>
  6643. + #include <asm/irq.h>
  6644. +@@ -135,16 +134,24 @@
  6645. + #define MAJOR_NR FLOPPY_MAJOR
  6646. + #include "blk.h"
  6647. +-static unsigned int changed_floppies = 0xff, fake_change = 0;
  6648. ++static unsigned int fake_change = 0;
  6649. + static int initialising=1;
  6650. +-#ifdef HAVE_2_CONTROLLERS
  6651. ++#define FLOPPY0_TYPE    ((CMOS_READ(0x10) >> 4) & 15)
  6652. ++#define FLOPPY1_TYPE    (CMOS_READ(0x10) & 15)
  6653. ++
  6654. ++/*
  6655. ++ * Again, the CMOS information doesn't work on the alpha..
  6656. ++ */
  6657. ++#ifdef __alpha__
  6658. ++#undef FLOPPY0_TYPE
  6659. ++#undef FLOPPY1_TYPE
  6660. ++#define FLOPPY0_TYPE 6
  6661. ++#define FLOPPY1_TYPE 0
  6662. ++#endif
  6663. ++
  6664. + #define N_FDC 2
  6665. + #define N_DRIVE 8
  6666. +-#else
  6667. +-#define N_FDC 1
  6668. +-#define N_DRIVE 4
  6669. +-#endif
  6670. + #define TYPE(x) ( ((x)>>2) & 0x1f )
  6671. + #define DRIVE(x) ( ((x)&0x03) | (((x)&0x80 ) >> 5))
  6672. +@@ -156,22 +163,28 @@
  6673. + #define DRS (&drive_state[current_drive])
  6674. + #define DRWE (&write_errors[current_drive])
  6675. + #define FDCS (&fdc_state[fdc])
  6676. ++#define CLEARF(x) (clear_bit(x##_BIT, &DRS->flags))
  6677. ++#define SETF(x) (set_bit(x##_BIT, &DRS->flags))
  6678. ++#define TESTF(x) (test_bit(x##_BIT, &DRS->flags))
  6679. + #define UDP (&drive_params[drive])
  6680. + #define UDRS (&drive_state[drive])
  6681. + #define UDRWE (&write_errors[drive])
  6682. + #define UFDCS (&fdc_state[FDC(drive)])
  6683. ++#define UCLEARF(x) (clear_bit(x##_BIT, &UDRS->flags))
  6684. ++#define USETF(x) (set_bit(x##_BIT, &UDRS->flags))
  6685. ++#define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags))
  6686. +-#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive);
  6687. ++#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive)
  6688. + #define DPRINT1(x,x1) \
  6689. +-printk(DEVICE_NAME "%d: " x,current_drive,(x1));
  6690. ++printk(DEVICE_NAME "%d: " x,current_drive,(x1))
  6691. + #define DPRINT2(x,x1,x2) \
  6692. +-printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2));
  6693. ++printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2))
  6694. + #define DPRINT3(x,x1,x2,x3) \
  6695. +-printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3));
  6696. ++printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
  6697. + /* read/write */
  6698. + #define COMMAND raw_cmd.cmd[0]
  6699. +@@ -195,8 +208,9 @@
  6700. + /*
  6701. +  * Maximum disk size (in kilobytes). This default is used whenever the
  6702. +  * current disk size is unknown.
  6703. ++ * [Now it is rather a minimum]
  6704. +  */
  6705. +-#define MAX_DISK_SIZE 3984
  6706. ++#define MAX_DISK_SIZE 2 /* 3984*/
  6707. +@@ -208,13 +222,9 @@
  6708. +  * driver otherwise. It doesn't matter much for performance anyway, as most
  6709. +  * floppy accesses go through the track buffer.
  6710. +  */
  6711. +-#if 0
  6712. + #define LAST_DMA_ADDR    (0x1000000)
  6713. +-#else
  6714. +-/* Everything has to go via dma buffer */
  6715. +-#define LAST_DMA_ADDR    (0x1)
  6716. +-#endif
  6717. + #define K_64 (0x10000) /* 64 k */
  6718. ++
  6719. + /*
  6720. +  * globals used by 'result()'
  6721. +  */
  6722. +@@ -230,6 +240,9 @@
  6723. + #define R_SECTOR (reply_buffer[5])
  6724. + #define R_SIZECODE (reply_buffer[6])
  6725. ++#define SEL_DLY (2*HZ/100)
  6726. ++
  6727. ++#define ARRAY_SIZE(x) (sizeof(x) / sizeof( (x)[0] ))
  6728. + /*
  6729. +  * this struct defines the different floppy drive types.
  6730. +  */
  6731. +@@ -243,49 +256,44 @@
  6732. +   |     |   Head load time, msec
  6733. +   |     |   |   Head unload time, msec (not used)
  6734. +   |     |   |   |     Step rate interval, usec
  6735. +-  |     |   |   |     |    Time needed for spinup time (jiffies)
  6736. +-  |     |   |   |     |    |    Timeout for spinning down (jiffies)
  6737. +-  |     |   |   |     |    |    |   Spindown offset (where disk stops)
  6738. +-  |     |   |   |     |    |    |   |  Select delay
  6739. +-  |     |   |   |     |    |    |   |  |  RPS
  6740. +-  |     |   |   |     |    |    |   |  |  |    Max number of tracks
  6741. +-  |     |   |   |     |    |    |   |  |  |    |     Interrupt timeout
  6742. +-  |     |   |   |     |    |    |   |  |  |    |     |   Max nonintlv. sectors
  6743. +-  |     |   |   |     |    |    |   |  |  |    |     |   | -Max Errors- flags */
  6744. +-{{0,  500, 16, 16, 8000, 100, 300,  0, 2, 5,  80, 3*HZ, 20, {3,1,2,0,2}, 0,
  6745. +-      0, { 7, 4, 8, 2, 1, 5, 3,10}, 150, 0 }, "unknown" },
  6746. +-
  6747. +-{{1,  300, 16, 16, 8000, 100, 300,  0, 2, 5,  40, 3*HZ, 17, {3,1,2,0,2}, 0,
  6748. +-      0, { 1, 0, 0, 0, 0, 0, 0, 0}, 150, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
  6749. +-
  6750. +-{{2,  500, 16, 16, 6000,  40, 300, 14, 2, 6,  83, 3*HZ, 17, {3,1,2,0,2}, 0,
  6751. +-      0, { 2, 5, 6,23,10,20,11, 0}, 150, 2 }, "1.2M" }, /*5 1/4 HD AT*/
  6752. +-
  6753. +-{{3,  250, 16, 16, 3000, 100, 300,  0, 2, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
  6754. +-      0, { 4,22,21,30, 3, 0, 0, 0}, 150, 4 }, "720k" }, /*3 1/2 DD*/
  6755. +-
  6756. +-#if 0
  6757. +-{{4,  500, 16, 16, 4000,  40, 300, 10, 2, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
  6758. +-      0, { 7, 4,25,22,31,21,29,11}, 150, 7 }, "1.44M" }, /*3 1/2 HD*/
  6759. +-#else
  6760. +-{{4,  500, 16, 16, 3000,  40, 300, 10, 2, 5,  83, 3*HZ, 20, {3,1,2,0,0}, FTD_MSG,
  6761. +-      0, { 7, 4,25,22,31,21,29,11}, 150, 7 }, "1.44M" }, /*3 1/2 HD*/
  6762. +-#endif
  6763. +-
  6764. +-{{5, 1000, 15,  8, 3000,  40, 300, 10, 2, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
  6765. +-      0, { 7, 8, 4,25,28,22,31,21}, 150, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
  6766. +-
  6767. +-{{6, 1000, 15,  8, 3000,  40, 300, 10, 2, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
  6768. +-      0, { 7, 8, 4,25,28,22,31,21}, 150, 8 }, "2.88M" } /*3 1/2 ED*/
  6769. +-/*    |  ---autodetected formats--   |   |      |
  6770. +-      read_track                     |   |    Name printed when booting
  6771. +-                                     |  Native format
  6772. ++  |     |   |   |     |       Time needed for spinup time (jiffies)
  6773. ++  |     |   |   |     |       |      Timeout for spinning down (jiffies)
  6774. ++  |     |   |   |     |       |      |   Spindown offset (where disk stops)
  6775. ++  |     |   |   |     |       |      |   |     Select delay
  6776. ++  |     |   |   |     |       |      |   |     |     RPS
  6777. ++  |     |   |   |     |       |      |   |     |     |    Max number of tracks
  6778. ++  |     |   |   |     |       |      |   |     |     |    |     Interrupt timeout
  6779. ++  |     |   |   |     |       |      |   |     |     |    |     |   Max nonintlv. sectors
  6780. ++  |     |   |   |     |       |      |   |     |     |    |     |   | -Max Errors- flags */
  6781. ++{{0,  500, 16, 16, 8000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  80, 3*HZ, 20, {3,1,2,0,2}, 0,
  6782. ++      0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
  6783. ++
  6784. ++{{1,  300, 16, 16, 8000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  40, 3*HZ, 17, {3,1,2,0,2}, 0,
  6785. ++      0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
  6786. ++
  6787. ++{{2,  500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6,  83, 3*HZ, 17, {3,1,2,0,2}, 0,
  6788. ++      0, { 2, 5, 6,23,10,20,11, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
  6789. ++
  6790. ++{{3,  250, 16, 16, 3000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
  6791. ++      0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
  6792. ++
  6793. ++{{4,  500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
  6794. ++      0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
  6795. ++
  6796. ++{{5, 1000, 15,  8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
  6797. ++      0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
  6798. ++
  6799. ++{{6, 1000, 15,  8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
  6800. ++      0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
  6801. ++/*    |  ---autodetected formats--   |      |      |
  6802. ++      read_track                     |      |    Name printed when booting
  6803. ++                                     |     Native format
  6804. +                                    Frequency of disk change checks */
  6805. + };
  6806. + static struct floppy_drive_params drive_params[N_DRIVE];
  6807. +-static struct floppy_drive_struct volatile drive_state[N_DRIVE];
  6808. +-static struct floppy_write_errors volatile write_errors[N_DRIVE];
  6809. ++static struct floppy_drive_struct drive_state[N_DRIVE];
  6810. ++static struct floppy_write_errors write_errors[N_DRIVE];
  6811. + static struct floppy_raw_cmd raw_cmd;
  6812. + /*
  6813. +@@ -295,16 +303,6 @@
  6814. +  * types (ie 360kB diskette in 1.2MB drive etc). Others should
  6815. +  * be self-explanatory.
  6816. +  */
  6817. +-/*
  6818. +-             Size
  6819. +-             |  Sectors per track
  6820. +-             |  | Head
  6821. +-             |  | |  Tracks
  6822. +-             |  | |  | Stretch
  6823. +-             |  | |  | |  Gap 1 size
  6824. +-             |  | |  | |    |  Data rate, | 0x40 for perp
  6825. +-         |  | |  | |    |    |  Spec1 (stepping rate, head unload
  6826. +-             |  | |  | |    |    |    |    /fmt gap (gap2) */
  6827. + static struct floppy_struct floppy_type[32] = {
  6828. +     {    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL    },    /*  0 no testing    */
  6829. +     {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360"  }, /*  1 360KB PC      */
  6830. +@@ -348,11 +346,8 @@
  6831. + /* Auto-detection: Disk type used until the next media change occurs. */
  6832. + struct floppy_struct *current_type[N_DRIVE] = {
  6833. ++    NULL, NULL, NULL, NULL,
  6834. +     NULL, NULL, NULL, NULL
  6835. +-#ifdef HAVE_2_CONTROLLERS
  6836. +-    ,
  6837. +-    NULL, NULL, NULL, NULL
  6838. +-#endif
  6839. + };
  6840. + /*
  6841. +@@ -362,6 +357,7 @@
  6842. + struct floppy_struct user_params[N_DRIVE];
  6843. + static int floppy_sizes[256];
  6844. ++static int floppy_blocksizes[256] = { 0, };
  6845. + /*
  6846. +  * The driver is trying to determine the correct media format
  6847. +@@ -380,6 +376,9 @@
  6848. + static struct wait_queue *fdc_wait = NULL, *command_done = NULL;
  6849. + #define NO_SIGNAL (!(current->signal & ~current->blocked) || !interruptible)
  6850. + #define CALL(x) if( (x) == -EINTR) return -EINTR;
  6851. ++#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
  6852. ++#define WAIT(x) _WAIT((x),interruptible)
  6853. ++#define IWAIT(x) _WAIT((x),1)
  6854. + /* Errors during formatting are counted here. */
  6855. + static int format_errors;
  6856. +@@ -400,11 +399,7 @@
  6857. +  * corrupted/lost. Alignment of these is enforced in boot/head.S.
  6858. +  * Note that you must not change the sizes below without updating head.S.
  6859. +  */
  6860. +-#if 0
  6861. + extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
  6862. +-#else
  6863. +-char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
  6864. +-#endif
  6865. + #define max_buffer_sectors MAX_BUFFER_SECTORS
  6866. + int *errors;
  6867. +@@ -417,10 +412,10 @@
  6868. + done_f done; /* this is called to say if the operation has succeeded/failed */
  6869. + } *cont;
  6870. ++static void floppy_ready(void);
  6871. + static void floppy_start(void);
  6872. +-static void redo_fd_request(void);
  6873. ++static void process_fd_request(void);
  6874. + static void recalibrate_floppy(void);
  6875. +-static void seek_floppy(void);
  6876. + static void floppy_shutdown(void);
  6877. + static int floppy_grab_irq_and_dma(void);
  6878. +@@ -444,7 +439,10 @@
  6879. + #define NO_TRACK -1
  6880. + #define NEED_1_RECAL -2
  6881. + #define NEED_2_RECAL -3
  6882. +-#define PROVEN_ABSENT -4
  6883. ++
  6884. ++/* */
  6885. ++static int usage_count = 0;
  6886. ++
  6887. + /* buffer related variables */
  6888. + static int buffer_track = -1;
  6889. +@@ -454,10 +452,10 @@
  6890. + /* fdc related variables, should end up in a struct */
  6891. + static struct floppy_fdc_state fdc_state[N_FDC];
  6892. +-int fdc; /* current fdc */
  6893. ++static int fdc; /* current fdc */
  6894. + static struct floppy_struct * floppy = floppy_type;
  6895. +-static unsigned char current_drive = 255;
  6896. ++static unsigned char current_drive = 0;
  6897. + static long current_count_sectors = 0;
  6898. + static char *current_addr = 0;
  6899. + static unsigned char sector_t; /* sector in track */
  6900. +@@ -467,20 +465,6 @@
  6901. + #endif
  6902. + /*
  6903. +- * Floppy_selects1 is the list of DOR's to select a drive n
  6904. +- * Floppy_selects2 is the list of DOR's to select drive fd
  6905. +- * On initialisation, the floppy list is scanned, and the drives allocated
  6906. +- * in the order that they are found.  This is done by seeking the drive
  6907. +- * to a non-zero track, and then restoring it to track 0.  If an error occurs,
  6908. +- * then there is no floppy drive present.
  6909. +- */
  6910. +-
  6911. +-unsigned char floppy_selects1[]={ 0x10, 0x21, 0x23, 0x33 };
  6912. +-unsigned char floppy_selects2[]={ 0   , 0   , 0   , 0    };
  6913. +-
  6914. +-int fd_sectsizes[256];
  6915. +-
  6916. +-/*
  6917. +  * Debugging
  6918. +  * =========
  6919. +  */
  6920. +@@ -509,14 +493,17 @@
  6921. + /*
  6922. +  * disk change.
  6923. +- * This routine is responsible for maintaining the changed_floppies flag,
  6924. ++ * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
  6925. +  * and the last_checked date.
  6926. +  *
  6927. +  * last_checked is the date of the last check which showed 'no disk change'
  6928. +- * changed_floppies is set under two conditions:
  6929. ++ * FD_DISK_CHANGE is set under two conditions:
  6930. +  * 1. The floppy has been changed after some i/o to that floppy already
  6931. +  *    took place.
  6932. +- * 2. No floppy disk is in the drive.
  6933. ++ * 2. No floppy disk is in the drive. This is done in order to ensure that
  6934. ++ *    requests are quickly flushed in case there is no disk in the drive. It
  6935. ++ *    follows that FD_DISK_CHANGE can only be cleared if there is a disk in
  6936. ++ *    the drive.
  6937. +  *
  6938. +  * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
  6939. +  * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
  6940. +@@ -531,74 +518,102 @@
  6941. + static int disk_change(int drive)
  6942. + {
  6943. +-    if(jiffies < DP->select_delay + DRS->select_date)
  6944. +-        udelay(20000);
  6945. +-
  6946. +-    if(inb_p(FD_DIR) & 0x80){
  6947. +-        UDRS->flags |= FD_VERIFY; /* verify write protection */
  6948. ++    int fdc=FDC(drive);
  6949. ++#ifdef CONFIG_FLOPPY_SANITY
  6950. ++    if(jiffies < UDP->select_delay + UDRS->select_date)
  6951. ++        DPRINT("WARNING disk change called early\n");
  6952. ++    if(! (FDCS->dor & (0x10 << UNIT(drive))) ||
  6953. ++       (FDCS->dor & 3) != UNIT(drive) ||
  6954. ++       fdc != FDC(drive)){
  6955. ++        DPRINT("probing disk change on unselected drive\n");
  6956. ++        DPRINT3("drive=%d fdc=%d dor=%x\n",drive, FDC(drive),
  6957. ++            FDCS->dor);
  6958. ++    }
  6959. ++#endif
  6960. +-        if(UDRS->maxblock || /* disk change check */
  6961. +-           !(UDRS->flags & FD_DISK_NEWCHANGE)){/* disk presence check */
  6962. +-            /* mark it changed or absent */
  6963. +-            set_bit(drive,&changed_floppies);
  6964. ++#ifdef DCL_DEBUG
  6965. ++    if (UDP->flags & FD_DEBUG){
  6966. ++        DPRINT1("checking disk change line for drive %d\n",drive);
  6967. ++        DPRINT1("jiffies=%ld\n", jiffies);
  6968. ++        DPRINT1("disk change line=%x\n",inb_p(FD_DIR)&0x80);
  6969. ++        DPRINT1("flags=%x\n",UDRS->flags);
  6970. ++    }
  6971. ++#endif
  6972. ++    if (UDP->flags & FD_BROKEN_DCL)
  6973. ++        return UTESTF(FD_DISK_CHANGED);
  6974. ++    if( (inb_p(FD_DIR) ^ UDP->flags) & 0x80){
  6975. ++        USETF(FD_VERIFY); /* verify write protection */        
  6976. ++        if(UDRS->maxblock){
  6977. ++            /* mark it changed */
  6978. ++            USETF(FD_DISK_CHANGED);
  6979. +             /* invalidate its geometry */
  6980. +             if (UDRS->keep_data >= 0) {
  6981. +-                if ((DP->flags & FTD_MSG) &&
  6982. ++                if ((UDP->flags & FTD_MSG) &&
  6983. +                     current_type[drive] != NULL)
  6984. +                     DPRINT("Disk type is undefined after "
  6985. +                            "disk change\n");
  6986. +                 current_type[drive] = NULL;
  6987. +-                floppy_sizes[drive] = MAX_DISK_SIZE;
  6988. ++                floppy_sizes[DRIVE(current_drive) + (FDC(current_drive) << 7)] = MAX_DISK_SIZE;
  6989. +             }
  6990. +         }
  6991. +-        UDRS->flags |= FD_DISK_NEWCHANGE;
  6992. ++        /*USETF(FD_DISK_NEWCHANGE);*/
  6993. +         return 1;
  6994. +     } else {
  6995. +         UDRS->last_checked=jiffies;
  6996. +-        UDRS->flags &= ~FD_DISK_NEWCHANGE;
  6997. +-        return 0;
  6998. ++        UCLEARF(FD_DISK_NEWCHANGE);
  6999. +     }
  7000. ++    return 0;
  7001. + }
  7002. +-static void arm_set_dor(int dor)
  7003. ++static inline int is_selected(int dor, int unit)
  7004. + {
  7005. +-    if(dor & 0xf0)
  7006. +-        outb_p((dor & 0x0c) | floppy_selects1[dor & 3], FD_DOR);
  7007. +-    else
  7008. +-        outb_p((dor & 0x0c), FD_DOR);
  7009. ++    return ( (dor  & (0x10 << unit)) && (dor &3) == unit);
  7010. + }
  7011. +-static int locked=0;
  7012. + static int set_dor(int fdc, char mask, char data)
  7013. + {
  7014. +     register unsigned char drive, unit, newdor,olddor;
  7015. +-    locked=1;
  7016. ++    if(FDCS->address == -1)
  7017. ++        return -1;
  7018. ++
  7019. +     olddor = FDCS->dor;
  7020. +     newdor =  (olddor & mask) | data;
  7021. +     if ( newdor != olddor ){
  7022. +         unit = olddor & 0x3;
  7023. +-        drive = REVDRIVE(fdc,unit);
  7024. +-        if ( olddor & ( 0x10 << unit ))
  7025. ++        if(is_selected(olddor, unit) && !is_selected(newdor,unit)){
  7026. ++            drive = REVDRIVE(fdc,unit);
  7027. ++#ifdef DCL_DEBUG
  7028. ++    if (UDP->flags & FD_DEBUG){
  7029. ++        DPRINT("calling disk change from set_dor\n");
  7030. ++    }
  7031. ++#endif
  7032. +             disk_change(drive);
  7033. ++        }
  7034. +         FDCS->dor = newdor;
  7035. +-        arm_set_dor(newdor);
  7036. ++        outb_p(newdor, FD_DOR);
  7037. ++
  7038. ++        unit = newdor & 0x3;
  7039. ++        if(!is_selected(olddor, unit) && is_selected(newdor,unit)){
  7040. ++            drive = REVDRIVE(fdc,unit);
  7041. ++            UDRS->select_date = jiffies;
  7042. ++        }
  7043. +     }
  7044. +-    locked=0;
  7045. ++    if ( newdor & 0xf0 )
  7046. ++        floppy_grab_irq_and_dma();
  7047. ++    if( olddor & 0xf0 )
  7048. ++        floppy_release_irq_and_dma();
  7049. +     return olddor;
  7050. + }
  7051. + static void twaddle(void)
  7052. + {
  7053. +-    cli();
  7054. +-#if 0
  7055. ++    if (DP->select_delay)
  7056. ++        return;
  7057. +     outb_p(FDCS->dor & ~(0x10<<UNIT(current_drive)),FD_DOR);
  7058. +     outb_p(FDCS->dor, FD_DOR);
  7059. +-#else
  7060. +-    arm_set_dor(FDCS->dor);
  7061. +-#endif
  7062. +-    sti();
  7063. ++    DRS->select_date = jiffies;
  7064. + }
  7065. + /* reset all driver information about the current fdc. This is needed after
  7066. +@@ -613,7 +628,6 @@
  7067. +     FDCS->rawcmd = 0;
  7068. +     for ( drive = 0; drive < N_DRIVE; drive++)
  7069. +         if (FDC(drive) == fdc &&
  7070. +-            UDRS->track != PROVEN_ABSENT &&
  7071. +             ( mode || UDRS->track != NEED_1_RECAL))
  7072. +             UDRS->track = NEED_2_RECAL;
  7073. + }
  7074. +@@ -621,30 +635,28 @@
  7075. + /* selects the fdc and drive, and enables the fdc's input/dma. */
  7076. + static void set_fdc(int drive)
  7077. + {
  7078. +-    if ( drive >= 0 ){
  7079. ++    if (drive >= 0 && drive < N_DRIVE){
  7080. +         fdc = FDC(drive);
  7081. +         current_drive = drive;
  7082. +     }
  7083. +     set_dor(fdc,~0,8);
  7084. +-#ifdef HAVE_2_CONTROLLERS
  7085. +     set_dor(1-fdc, ~8, 0);
  7086. +-#endif
  7087. +     if ( FDCS->rawcmd == 2 )
  7088. +         reset_fdc_info(1);
  7089. +     if( inb_p(FD_STATUS) != STATUS_READY )
  7090. +         FDCS->reset = 1;
  7091. + }
  7092. +-static int usage_count = 0;
  7093. + /* locks the driver */
  7094. + static int lock_fdc(int drive, int interruptible)
  7095. + {
  7096. +-
  7097. +     if(!usage_count){
  7098. +         printk("trying to lock fdc while usage count=0\n");
  7099. +         return -1;
  7100. +     }
  7101. +     floppy_grab_irq_and_dma();
  7102. ++    if (!current->pid)
  7103. ++        run_task_queue(&tq_timer);
  7104. +     cli();
  7105. +     while (fdc_busy && NO_SIGNAL)
  7106. +         interruptible_sleep_on(&fdc_wait);
  7107. +@@ -662,6 +674,10 @@
  7108. + #define LOCK_FDC(drive,interruptible) \
  7109. + if(lock_fdc(drive,interruptible)) return -EINTR;
  7110. ++typedef void (*timeout_fn)(unsigned long);
  7111. ++static struct timer_list fd_timeout ={ NULL, NULL, 0, 0, 
  7112. ++                           (timeout_fn) floppy_shutdown };
  7113. ++
  7114. + /* unlocks the driver */
  7115. + static inline void unlock_fdc(void)
  7116. + {
  7117. +@@ -672,7 +688,7 @@
  7118. +         DPRINT1("device interrupt still active at FDC release: %p!\n",
  7119. +             DEVICE_INTR);
  7120. +     command_status = FD_COMMAND_NONE;
  7121. +-    timer_active &= ~(1 << FLOPPY_TIMER);
  7122. ++    del_timer(&fd_timeout);
  7123. +     fdc_busy = 0;
  7124. +     floppy_release_irq_and_dma();
  7125. +     wake_up(&fdc_wait);
  7126. +@@ -683,47 +699,40 @@
  7127. + {
  7128. +     unsigned char mask = ~(0x10 << UNIT(nr));
  7129. +-    if(locked)
  7130. +-        floppy_off(nr);
  7131. +-    else
  7132. +-        set_dor( FDC(nr), mask, 0 );
  7133. ++    set_dor( FDC(nr), mask, 0 );
  7134. + }
  7135. + static struct timer_list motor_off_timer[N_DRIVE] = {
  7136. +     { NULL, NULL, 0, 0, motor_off_callback },
  7137. +     { NULL, NULL, 0, 1, motor_off_callback },
  7138. +     { NULL, NULL, 0, 2, motor_off_callback },
  7139. +-    { NULL, NULL, 0, 3, motor_off_callback }
  7140. +-#ifdef HAVE_2_CONTROLLERS
  7141. +-    ,
  7142. ++    { NULL, NULL, 0, 3, motor_off_callback },
  7143. +     { NULL, NULL, 0, 4, motor_off_callback },
  7144. +     { NULL, NULL, 0, 5, motor_off_callback },
  7145. +     { NULL, NULL, 0, 6, motor_off_callback },
  7146. +     { NULL, NULL, 0, 7, motor_off_callback }
  7147. +-#endif
  7148. + };
  7149. + /* schedules motor off */
  7150. +-static void floppy_off(unsigned int nr)
  7151. ++static void floppy_off(unsigned int drive)
  7152. + {
  7153. +     unsigned long volatile delta;
  7154. +-    register int fdc=FDC(nr);
  7155. ++    register int fdc=FDC(drive);
  7156. +-    if( !(FDCS->dor & ( 0x10 << UNIT(nr))))
  7157. ++    if( !(FDCS->dor & ( 0x10 << UNIT(drive))))
  7158. +         return;
  7159. +-    del_timer(motor_off_timer+nr);
  7160. ++    del_timer(motor_off_timer+drive);
  7161. +     /* make spindle stop in a position which minimizes spinup time
  7162. +      * next time */
  7163. +-    if ( drive_params[nr].rps ){
  7164. +-        delta = jiffies - drive_state[nr].first_read_date + HZ -
  7165. +-            drive_params[nr].spindown_offset;
  7166. +-        delta = (( delta * drive_params[nr].rps) % HZ ) /
  7167. +-            drive_params[nr].rps;
  7168. +-        motor_off_timer[nr].expires = drive_params[nr].spindown - delta;
  7169. ++    if (UDP->rps ){
  7170. ++        delta = jiffies - UDRS->first_read_date + HZ -
  7171. ++            UDP->spindown_offset;
  7172. ++        delta = (( delta * UDP->rps) % HZ ) / UDP->rps;
  7173. ++        motor_off_timer[drive].expires = UDP->spindown - delta;
  7174. +     }
  7175. +-    add_timer(motor_off_timer+nr);
  7176. ++    add_timer(motor_off_timer+drive);
  7177. + }
  7178. + /*
  7179. +@@ -734,36 +743,41 @@
  7180. + static void scandrives(void)
  7181. + {
  7182. +     int i, drive, saved_drive;
  7183. ++    
  7184. ++    if (DP->select_delay)
  7185. ++        return;
  7186. +-    saved_drive = current_drive % N_DRIVE;
  7187. ++    saved_drive = current_drive;
  7188. +     for(i=0; i< N_DRIVE; i++){
  7189. +         drive = (saved_drive + i + 1 ) % N_DRIVE;
  7190. +-        if ( UDRS->fd_ref == 0 )
  7191. ++        if ( UDRS->fd_ref == 0 || UDP->select_delay != 0)
  7192. +             continue; /* skip closed drives */
  7193. +         set_fdc(drive);
  7194. +-        if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
  7195. +-            ((FDCS->dor & 0x3) != UNIT(drive)))
  7196. +-            UDRS->select_date = jiffies;
  7197. +         if(! (set_dor( fdc, ~3, UNIT(drive) | ( 0x10 << UNIT(drive))) &
  7198. +               (0x10 << UNIT(drive))))
  7199. +             /* switch the motor off again, if it was off to
  7200. +              * begin with */
  7201. +             set_dor( fdc, ~( 0x10 << UNIT(drive) ), 0 );
  7202. +     }
  7203. +-    current_drive = saved_drive;
  7204. ++    set_fdc(saved_drive);
  7205. + }
  7206. +-typedef void (*timeout_fn)(unsigned long);
  7207. + static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 };
  7208. + /* this function makes sure that the disk stays in the drive during the
  7209. +  * transfer */
  7210. + static void fd_watchdog(void)
  7211. + {
  7212. ++#ifdef DCL_DEBUG
  7213. ++    if (DP->flags & FD_DEBUG){
  7214. ++        DPRINT("calling disk change from watchdog\n");
  7215. ++    }
  7216. ++#endif
  7217. ++
  7218. +     if ( disk_change(current_drive) ){
  7219. +         DPRINT("disk removed during i/o\n");
  7220. +         floppy_shutdown();
  7221. +-    } else {
  7222. ++    } else {        
  7223. +         del_timer(&fd_timer);
  7224. +         fd_timer.function = (timeout_fn) fd_watchdog;
  7225. +         fd_timer.expires = 10;
  7226. +@@ -778,7 +792,7 @@
  7227. + }
  7228. + /* waits for a delay (spinup or select) to pass */
  7229. +-static int wait_for_completion(int nr, int delay, timeout_fn function)
  7230. ++static int wait_for_completion(int delay, timeout_fn function)
  7231. + {
  7232. +     if ( FDCS->reset ){
  7233. +         reset_fdc(); /* do the reset during sleep to win time
  7234. +@@ -797,9 +811,50 @@
  7235. +     return 0;
  7236. + }
  7237. ++static int hlt_disabled=0;
  7238. ++static void floppy_disable_hlt(void)
  7239. ++{
  7240. ++    unsigned long flags;
  7241. ++    save_flags(flags);
  7242. ++    cli();
  7243. ++    if(!hlt_disabled){
  7244. ++        hlt_disabled=1;
  7245. ++#ifdef HAVE_DISABLE_HLT
  7246. ++        disable_hlt();
  7247. ++#endif
  7248. ++    }
  7249. ++    restore_flags(flags);
  7250. ++}
  7251. ++
  7252. ++static void floppy_enable_hlt(void)
  7253. ++{
  7254. ++    unsigned long flags;
  7255. ++    save_flags(flags);
  7256. ++    cli();
  7257. ++    if(hlt_disabled){
  7258. ++        hlt_disabled=0;
  7259. ++#ifdef HAVE_DISABLE_HLT
  7260. ++        enable_hlt();
  7261. ++#endif
  7262. ++    }
  7263. ++    restore_flags(flags);
  7264. ++}
  7265. ++        
  7266. ++
  7267. + static void setup_DMA(void)
  7268. + {
  7269. +-#ifdef SANITY
  7270. ++#ifdef CONFIG_FLOPPY_SANITY
  7271. ++    if (raw_cmd.length == 0){
  7272. ++        int i;
  7273. ++
  7274. ++        printk("zero dma transfer size:");
  7275. ++        for(i=0; i< raw_cmd.cmd_count; i++)
  7276. ++            printk("%x,", raw_cmd.cmd[i]);
  7277. ++        printk("\n");
  7278. ++        cont->done(0);
  7279. ++        FDCS->reset = 1;
  7280. ++        return;
  7281. ++    }
  7282. +     if ((!CURRENT ||
  7283. +          CURRENT->buffer != current_addr ||
  7284. +          raw_cmd.length > 512 * CURRENT->nr_sectors) &&
  7285. +@@ -817,7 +872,6 @@
  7286. +         FDCS->reset=1;
  7287. +         return;
  7288. +     }
  7289. +-#if 0
  7290. +     if ((long) current_addr % 512 ){
  7291. +         printk("non aligned address: %p\n", current_addr );
  7292. +         cont->done(0);
  7293. +@@ -832,7 +886,7 @@
  7294. +         FDCS->reset=1;
  7295. +         return;
  7296. +     }
  7297. +-#endif
  7298. ++
  7299. + #endif
  7300. +     cli();
  7301. +     disable_dma(FLOPPY_DMA);
  7302. +@@ -844,6 +898,7 @@
  7303. +     set_dma_count(FLOPPY_DMA, raw_cmd.length);
  7304. +     enable_dma(FLOPPY_DMA);
  7305. +     sti();
  7306. ++    floppy_disable_hlt();
  7307. + }
  7308. + /* sends a command byte to the fdc */
  7309. +@@ -856,13 +911,13 @@
  7310. +         return -1;
  7311. +     for(counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
  7312. +         status = inb_p(FD_STATUS) &(STATUS_READY|STATUS_DIR|STATUS_DMA);
  7313. ++        if (!(status & STATUS_READY))
  7314. ++            continue;
  7315. +         if (status == STATUS_READY){
  7316. +             outb_p(byte,FD_DATA);
  7317. +             return 0;
  7318. +-        }
  7319. +-        if (!(status & STATUS_READY))
  7320. +-            continue;
  7321. +-        break;
  7322. ++        } else
  7323. ++            break;
  7324. +     }
  7325. +     FDCS->reset = 1;
  7326. +     if ( !initialising )
  7327. +@@ -930,7 +985,7 @@
  7328. +         }
  7329. +     } else
  7330. +         perp_mode = 0;
  7331. +-
  7332. ++            
  7333. +     if ( FDCS->perp_mode == perp_mode )
  7334. +         return;
  7335. +     if (FDCS->version >= FDC_82077_ORIG && FDCS->has_fifo) {
  7336. +@@ -979,7 +1034,7 @@
  7337. +         /* TODO: lock this in via LOCK during initialization */
  7338. +         output_byte(FD_CONFIGURE);
  7339. +         output_byte(0);
  7340. +-        output_byte(0x1A);    /* FIFO on, polling off, 10 byte threshold */
  7341. ++        output_byte(0x2A);    /* FIFO on, polling off, 10 byte threshold */
  7342. +         output_byte(0);        /* precompensation from track 0 upwards */
  7343. +         if ( FDCS->reset ){
  7344. +             FDCS->has_fifo=0;
  7345. +@@ -1042,22 +1097,23 @@
  7346. +  * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
  7347. +  * of the specify command (i.e. using the fdc_specify function).
  7348. +  */
  7349. +-static void fdc_dtr(void)
  7350. ++static int fdc_dtr(void)
  7351. + {
  7352. +     /* If data rate not already set to desired value, set it. */
  7353. +     if ( raw_cmd.rate == FDCS->dtr)
  7354. +-        return;
  7355. +-
  7356. ++        return 0;
  7357. ++    
  7358. +     /* Set dtr */
  7359. +     outb_p(raw_cmd.rate, FD_DCR);
  7360. +-
  7361. ++    
  7362. +     /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
  7363. +      * need a stabilization period of several milliseconds to be
  7364. +      * enforced after data rate changes before R/W operations.
  7365. +-     * Pause 5 msec to avoid trouble.
  7366. ++     * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
  7367. +      */
  7368. +-    udelay(5000);
  7369. +     FDCS->dtr = raw_cmd.rate;
  7370. ++    return(wait_for_completion(jiffies+2,
  7371. ++                   (timeout_fn) floppy_ready));
  7372. + } /* fdc_dtr */
  7373. + static void tell_sector(void)
  7374. +@@ -1077,8 +1133,7 @@
  7375. + static int interpret_errors(void)
  7376. + {
  7377. +     char bad;
  7378. +-int res = get_dma_residue(FLOPPY_DMA);
  7379. +-if(res) {printk("\n-- DMA residue (%d)",res); tell_sector(); printk("\n");}
  7380. ++
  7381. +     if (inr!=7) {
  7382. +         DPRINT("-- FDC reply error");
  7383. +         FDCS->reset = 1;
  7384. +@@ -1087,15 +1142,15 @@
  7385. +     /* check IC to find cause of interrupt */
  7386. +     switch ((ST0 & ST0_INTR)>>6) {
  7387. +-        case 1:    /* error occured during command execution */
  7388. ++        case 1:    /* error occurred during command execution */
  7389. +             bad = 1;
  7390. +             if (ST1 & ST1_WP) {
  7391. +                 DPRINT("Drive is write protected\n");
  7392. +-                DRS->flags &= ~FD_DISK_WRITABLE;
  7393. ++                CLEARF(FD_DISK_WRITABLE);
  7394. +                 cont->done(0);
  7395. +                 bad = 2;
  7396. +             } else if (ST1 & ST1_ND) {
  7397. +-                DRS->flags |= FD_NEED_TWADDLE;
  7398. ++                SETF(FD_NEED_TWADDLE);
  7399. +             } else if (ST1 & ST1_OR) {
  7400. +                 if (DP->flags & FTD_MSG )
  7401. +                     DPRINT("Over/Underrun - retrying\n");
  7402. +@@ -1128,11 +1183,8 @@
  7403. +             }
  7404. +             if ( ST2 & ST2_WC || ST2 & ST2_BC)
  7405. +-{
  7406. +-printk("Wrong cylinder!\n");
  7407. +                 /* wrong cylinder => recal */
  7408. +                 DRS->track = NEED_2_RECAL;
  7409. +-}
  7410. +             return bad;
  7411. +         case 2: /* invalid command given */
  7412. +             DPRINT("Invalid FDC command given!\n");
  7413. +@@ -1162,7 +1214,7 @@
  7414. +         flags |= FD_RAW_INTR;
  7415. +     if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)){
  7416. +-        ready_date = DRS->spinup_date + DP->spinup;
  7417. ++        ready_date = DRS->spinup_date + DP->spinup;        
  7418. +         /* If spinup will take a long time, rerun scandrives
  7419. +          * again just before spinup completion. Beware that
  7420. +          * after scandrives, we must again wait for selection.
  7421. +@@ -1174,14 +1226,14 @@
  7422. +             function = (timeout_fn) setup_rw_floppy;
  7423. +         /* wait until the floppy is spinning fast enough */
  7424. +-        if (wait_for_completion(current_drive,ready_date,function))
  7425. ++        if (wait_for_completion(ready_date,function))
  7426. +             return;
  7427. +     }
  7428. +     dflags = DRS->flags;
  7429. +     if ( (flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
  7430. +         setup_DMA();
  7431. +-
  7432. ++    
  7433. +     if ( flags & FD_RAW_INTR )
  7434. +         SET_INTR(main_command_interrupt);
  7435. +@@ -1204,9 +1256,7 @@
  7436. +         fd_watchdog();
  7437. + }
  7438. +-#ifdef SILENT_DC_CLEAR
  7439. + static int blind_seek;
  7440. +-#endif
  7441. + /*
  7442. +  * This is the routine called after every seek (or recalibrate) interrupt
  7443. +@@ -1217,9 +1267,6 @@
  7444. + #ifdef DEBUGT
  7445. +     debugt("seek interrupt:");
  7446. + #endif
  7447. +-#ifdef SILENT_DC_CLEAR
  7448. +-    set_dor(fdc, ~0,  (0x10 << UNIT(current_drive)));
  7449. +-#endif
  7450. +     if (inr != 2 || (ST0 & 0xF8) != 0x20 ) {
  7451. +         DPRINT("seek failed\n");
  7452. +         DRS->track = NEED_2_RECAL;
  7453. +@@ -1227,20 +1274,23 @@
  7454. +         cont->redo();
  7455. +         return;
  7456. +     }
  7457. +-    if (DRS->track >= 0 && DRS->track != ST1
  7458. +-#ifdef SILENT_DC_CLEAR
  7459. +-        && !blind_seek
  7460. ++    if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek){
  7461. ++#ifdef DCL_DEBUG
  7462. ++        if (DP->flags & FD_DEBUG){
  7463. ++            DPRINT("clearing NEWCHANGE flag because of effective seek\n");
  7464. ++            DPRINT1("jiffies=%ld\n", jiffies);
  7465. ++        }
  7466. + #endif
  7467. +-        )
  7468. +-        DRS->flags &= ~FD_DISK_NEWCHANGE; /* effective seek */
  7469. ++        CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
  7470. ++        DRS->select_date = jiffies;
  7471. ++    }
  7472. +     DRS->track = ST1;
  7473. +-    DRS->select_date = jiffies;
  7474. +-    seek_floppy();
  7475. ++    floppy_ready();
  7476. + }
  7477. + static void check_wp(void)
  7478. + {
  7479. +-    if (DRS->flags & FD_VERIFY) {
  7480. ++    if (TESTF(FD_VERIFY)) {
  7481. +         /* check write protection */
  7482. +         output_byte( FD_GETSTATUS );
  7483. +         output_byte( UNIT(current_drive) );
  7484. +@@ -1248,10 +1298,18 @@
  7485. +             FDCS->reset = 1;
  7486. +             return;
  7487. +         }
  7488. +-        DRS->flags &= ~(FD_VERIFY | FD_DISK_WRITABLE | FD_NEED_TWADDLE);
  7489. +-
  7490. ++        CLEARF(FD_VERIFY);
  7491. ++        CLEARF(FD_NEED_TWADDLE);
  7492. ++#ifdef DCL_DEBUG
  7493. ++        if (DP->flags & FD_DEBUG){
  7494. ++            DPRINT("checking whether disk is write protected\n");
  7495. ++            DPRINT1("wp=%x\n",ST3 & 0x40);
  7496. ++        }
  7497. ++#endif
  7498. +         if (!( ST3  & 0x40))
  7499. +-            DRS->flags |= FD_DISK_WRITABLE;
  7500. ++            SETF(FD_DISK_WRITABLE);
  7501. ++        else
  7502. ++            CLEARF(FD_DISK_WRITABLE);
  7503. +     }
  7504. + }
  7505. +@@ -1259,16 +1317,22 @@
  7506. + {
  7507. +     int track;
  7508. +-#ifdef SILENT_DC_CLEAR
  7509. +     blind_seek=0;
  7510. ++
  7511. ++#ifdef DCL_DEBUG
  7512. ++    if (DP->flags & FD_DEBUG){
  7513. ++        DPRINT("calling disk change from seek\n");
  7514. ++    }
  7515. + #endif
  7516. +-    disk_change(current_drive);
  7517. +-    if ((raw_cmd.flags & FD_RAW_NEED_DISK) &&
  7518. +-        test_bit(current_drive,&changed_floppies)){
  7519. ++
  7520. ++    if (!TESTF(FD_DISK_NEWCHANGE) &&
  7521. ++        disk_change(current_drive) &&
  7522. ++        (raw_cmd.flags & FD_RAW_NEED_DISK)){
  7523. +         /* the media changed flag should be cleared after the seek.
  7524. +          * If it isn't, this means that there is really no disk in
  7525. +          * the drive.
  7526. +          */
  7527. ++        SETF(FD_DISK_CHANGED);
  7528. +         cont->done(0);
  7529. +         cont->redo();
  7530. +         return;
  7531. +@@ -1276,7 +1340,7 @@
  7532. +     if ( DRS->track <= NEED_1_RECAL ){
  7533. +         recalibrate_floppy();
  7534. +         return;
  7535. +-    } else if ((DRS->flags & FD_DISK_NEWCHANGE) &&
  7536. ++    } else if (TESTF(FD_DISK_NEWCHANGE) &&
  7537. +            (raw_cmd.flags & FD_RAW_NEED_DISK) &&
  7538. +            (DRS->track <= NO_TRACK || DRS->track == raw_cmd.track)) {
  7539. +         /* we seek to clear the media-changed condition. Does anybody
  7540. +@@ -1284,15 +1348,17 @@
  7541. +         if ( raw_cmd.track )
  7542. +             track = raw_cmd.track - 1;
  7543. +         else {
  7544. +-#ifdef SILENT_DC_CLEAR
  7545. +-            set_dor(fdc, ~ (0x10 << UNIT(current_drive)), 0);
  7546. +-            blind_seek = 1;
  7547. +-#endif
  7548. ++            if(DP->flags & FD_SILENT_DCL_CLEAR){
  7549. ++                set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
  7550. ++                blind_seek = 1;
  7551. ++                raw_cmd.flags |= FD_RAW_NEED_SEEK;
  7552. ++            }
  7553. +             track = 1;
  7554. +         }
  7555. +     } else {
  7556. +         check_wp();
  7557. +-        if (raw_cmd.track != DRS->track)
  7558. ++        if (raw_cmd.track != DRS->track &&
  7559. ++            (raw_cmd.flags & FD_RAW_NEED_SEEK))
  7560. +             track = raw_cmd.track;
  7561. +         else {
  7562. +             setup_rw_floppy();
  7563. +@@ -1300,23 +1366,13 @@
  7564. +         }
  7565. +     }
  7566. +-#ifndef SILENT_DC_CLEAR
  7567. +-    if ( !track && DRS->track >= 0 && DRS->track < 80 ){
  7568. +-        DRS->flags &= ~FD_DISK_NEWCHANGE;
  7569. +-        /* if we go to track 0 anyways, we can just as well use
  7570. +-         * recalibrate */
  7571. +-        recalibrate_floppy();
  7572. +-    } else
  7573. +-#endif
  7574. +-    {
  7575. +-        SET_INTR(seek_interrupt);
  7576. +-        output_byte(FD_SEEK);
  7577. +-        output_byte(UNIT(current_drive));
  7578. +-        LAST_OUT(track);
  7579. ++    SET_INTR(seek_interrupt);
  7580. ++    output_byte(FD_SEEK);
  7581. ++    output_byte(UNIT(current_drive));
  7582. ++    LAST_OUT(track);
  7583. + #ifdef DEBUGT
  7584. +-        debugt("seek command:");
  7585. ++    debugt("seek command:");
  7586. + #endif
  7587. +-    }
  7588. + }
  7589. + static void recal_interrupt(void)
  7590. +@@ -1328,18 +1384,13 @@
  7591. +         FDCS->reset = 1;
  7592. +     else if (ST0 & ST0_ECE) {
  7593. +                switch(DRS->track){
  7594. +-        case PROVEN_ABSENT:
  7595. +-#ifdef DEBUGT
  7596. +-            debugt("recal interrupt proven absent:");
  7597. +-#endif
  7598. +-            /* fall through */
  7599. +                case NEED_1_RECAL:
  7600. + #ifdef DEBUGT
  7601. +             debugt("recal interrupt need 1 recal:");
  7602. + #endif
  7603. +             /* after a second recalibrate, we still haven't
  7604. +              * reached track 0. Probably no drive. Raise an
  7605. +-             * error, as failing immediately might upset
  7606. ++             * error, as failing immediately might upset 
  7607. +              * computers possessed by the Devil :-) */
  7608. +             cont->error();
  7609. +             cont->redo();
  7610. +@@ -1353,7 +1404,14 @@
  7611. +              * not to move at recalibration is to be already at
  7612. +              * track 0.) Clear the new change flag
  7613. +              */
  7614. +-            DRS->flags &= ~FD_DISK_NEWCHANGE;
  7615. ++#ifdef DCL_DEBUG
  7616. ++            if (DP->flags & FD_DEBUG){
  7617. ++                DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
  7618. ++            }
  7619. ++#endif
  7620. ++
  7621. ++            CLEARF(FD_DISK_NEWCHANGE);
  7622. ++            DRS->select_date = jiffies;
  7623. +             /* fall through */
  7624. +         default:
  7625. + #ifdef DEBUGT
  7626. +@@ -1369,7 +1427,7 @@
  7627. +         }
  7628. +     } else
  7629. +         DRS->track = ST1;
  7630. +-    seek_floppy();
  7631. ++    floppy_ready();
  7632. + }
  7633. + /*
  7634. +@@ -1381,34 +1439,41 @@
  7635. +     int i;
  7636. +     if ( initialising )
  7637. +         return;
  7638. +-    cli();
  7639. +-    DPRINT("unexpected interrupt\n");
  7640. +-    if ( inr >= 0 )
  7641. +-        for(i=0; i<inr; i++)
  7642. +-            printk("%d %x\n", i, reply_buffer[i] );
  7643. ++    if(print_unex){
  7644. ++        DPRINT("unexpected interrupt\n");
  7645. ++        if ( inr >= 0 )
  7646. ++            for(i=0; i<inr; i++)
  7647. ++                printk("%d %x\n", i, reply_buffer[i] );
  7648. ++    }
  7649. +     while(1){
  7650. +         output_byte(FD_SENSEI);
  7651. +         inr=result();
  7652. +         if ( inr != 2 )
  7653. +             break;
  7654. +-        printk("sensei\n");
  7655. +-        for(i=0; i<inr; i++)
  7656. +-            printk("%d %x\n", i, reply_buffer[i] );
  7657. ++        if(print_unex){
  7658. ++            printk("sensei\n");
  7659. ++            for(i=0; i<inr; i++)
  7660. ++                printk("%d %x\n", i, reply_buffer[i] );
  7661. ++        }
  7662. +     }
  7663. +     FDCS->reset = 1;
  7664. + }
  7665. +-struct tq_struct floppy_tq =
  7666. +-{ 0, 0, (void (*) (void *)) unexpected_floppy_interrupt, 0 };
  7667. ++struct tq_struct floppy_tq = 
  7668. ++{ 0, 0, (void *) (void *) unexpected_floppy_interrupt, 0 };
  7669. + /* interrupt handler */
  7670. +-static void floppy_interrupt(int unused, struct pt_regs *regs)
  7671. ++static void floppy_interrupt(int irq, struct pt_regs * regs)
  7672. + {
  7673. +     void (*handler)(void) = DEVICE_INTR;
  7674. ++    floppy_enable_hlt();
  7675. +     CLEAR_INTR;
  7676. +-    if ( fdc >= N_FDC ){ /* we don't even know which FDC is the culprit */
  7677. +-        printk("floppy interrupt on bizarre fdc\n");
  7678. ++    if ( fdc >= N_FDC || FDCS->address == -1){
  7679. ++        /* we don't even know which FDC is the culprit */
  7680. ++        printk("DOR0=%x\n", fdc_state[0].dor);
  7681. ++        printk("floppy interrupt on bizarre fdc %d\n",fdc);
  7682. ++        printk("handler=%p\n", handler);
  7683. +         return;
  7684. +     }
  7685. +     inr = result();
  7686. +@@ -1422,7 +1487,7 @@
  7687. +             inr = result();
  7688. +         } while ( (ST0 & 0x83) != UNIT(current_drive) && inr == 2);
  7689. +     }
  7690. +-    floppy_tq.routine = (void (*)(void *)) handler;
  7691. ++    floppy_tq.routine = (void *)(void *) handler;
  7692. +     queue_task_irq(&floppy_tq, &tq_timer);
  7693. + }
  7694. +@@ -1463,9 +1528,9 @@
  7695. +     if ( FDCS->version >= FDC_82077 )
  7696. +         outb_p(0x80 | ( FDCS->dtr &3), FD_STATUS);
  7697. +     else {
  7698. +-        arm_set_dor(FDCS->dor & ~0x04);
  7699. ++        outb_p(FDCS->dor & ~0x04, FD_DOR);
  7700. +         udelay(FD_RESET_DELAY);
  7701. +-        arm_set_dor(FDCS->dor);
  7702. ++        outb(FDCS->dor, FD_DOR);
  7703. +     }
  7704. + }
  7705. +@@ -1481,9 +1546,11 @@
  7706. +     printk("floppy driver state\n");
  7707. +     printk("-------------------\n");
  7708. +     for(i=0; i<N_FDC; i++){
  7709. +-        printk("dor %d = %x\n", i, fdc_state[i].dor );
  7710. +-        outb_p(fdc_state[i].address+2, fdc_state[i].dor);
  7711. +-        udelay(1000); /* maybe we'll catch an interrupt... */
  7712. ++        if(FDCS->address != -1){
  7713. ++            printk("dor %d = %x\n", i, fdc_state[i].dor );
  7714. ++            outb_p(fdc_state[i].address+2, fdc_state[i].dor);
  7715. ++            udelay(1000); /* maybe we'll catch an interrupt... */
  7716. ++        }
  7717. +     }
  7718. +     printk("status=%x\n", inb_p(FD_STATUS));
  7719. +     printk("fdc_busy=%d\n", fdc_busy);
  7720. +@@ -1493,9 +1560,9 @@
  7721. +         printk("floppy_tq.routine=%p\n", floppy_tq.routine);
  7722. +     if(fd_timer.prev)
  7723. +         printk("fd_timer.function=%p\n", fd_timer.function);
  7724. +-    if( timer_active & (1 << FLOPPY_TIMER)){
  7725. +-        printk("timer_table=%p\n",timer_table[FLOPPY_TIMER].fn);
  7726. +-        printk("expires=%ld\n",timer_table[FLOPPY_TIMER].expires);
  7727. ++    if(fd_timeout.prev){
  7728. ++        printk("timer_table=%p\n",fd_timeout.function);
  7729. ++        printk("expires=%ld\n",fd_timeout.expires);
  7730. +         printk("now=%ld\n",jiffies);
  7731. +     }
  7732. +     printk("cont=%p\n", cont);
  7733. +@@ -1507,30 +1574,28 @@
  7734. + static void floppy_shutdown(void)
  7735. + {
  7736. +     CLEAR_INTR;
  7737. +-    floppy_tq.routine = (void (*)(void *)) empty;
  7738. ++    floppy_tq.routine = (void *)(void *) empty;
  7739. +     del_timer( &fd_timer);
  7740. ++
  7741. ++    floppy_enable_hlt();
  7742. +     disable_dma(FLOPPY_DMA);
  7743. +     /* avoid dma going to a random drive after shutdown */
  7744. ++
  7745. +     if(!initialising)
  7746. +         DPRINT("floppy timeout\n");
  7747. +     FDCS->reset = 1;
  7748. +     cont->done(0);
  7749. +     cont->redo(); /* this will recall reset when needed */
  7750. + }
  7751. ++/*typedef void (*timeout_fn)(unsigned long);*/
  7752. + /* start motor, check media-changed condition and write protection */
  7753. +-static void start_motor(void)
  7754. ++static int start_motor( void (*function)(void)  )
  7755. + {
  7756. +     int mask, data;
  7757. +     mask = 0xfc;
  7758. +     data = UNIT(current_drive);
  7759. +-
  7760. +-    if ( (FDCS->dor & 0x03) != UNIT(current_drive) ||
  7761. +-        !(FDCS->dor & ( 0x10 << UNIT(current_drive) ) ))
  7762. +-        /* notes select time if floppy is not yet selected */
  7763. +-        DRS->select_date = jiffies;
  7764. +-
  7765. +     if (!(raw_cmd.flags & FD_RAW_NO_MOTOR)){
  7766. +         if(!(FDCS->dor & ( 0x10 << UNIT(current_drive) ) )){
  7767. +             set_debugt();
  7768. +@@ -1547,26 +1612,31 @@
  7769. +     /* starts motor and selects floppy */
  7770. +     del_timer(motor_off_timer + current_drive);
  7771. +     set_dor( fdc, mask, data);
  7772. +-    if( raw_cmd.flags & FD_RAW_NO_MOTOR)
  7773. +-        return;
  7774. +-    disk_change(current_drive);
  7775. +-
  7776. +-    return;
  7777. ++    /* wait_for_completion also schedules reset if needed. */
  7778. ++    return(wait_for_completion(DRS->select_date+DP->select_delay,
  7779. ++                   (timeout_fn) function));
  7780. + }
  7781. + static void floppy_ready(void)
  7782. + {
  7783. +     CHECK_RESET;
  7784. +-    start_motor();
  7785. ++    if(start_motor(floppy_ready)) return;
  7786. ++    if(fdc_dtr()) return;
  7787. +-    /* wait_for_completion also schedules reset if needed. */
  7788. +-    if(wait_for_completion(current_drive,
  7789. +-                   DRS->select_date+DP->select_delay,
  7790. +-                   (timeout_fn) floppy_ready))
  7791. +-        return;
  7792. +-    fdc_dtr();
  7793. +-    if ( raw_cmd.flags & FD_RAW_NEED_SEEK ){
  7794. ++#ifdef DCL_DEBUG
  7795. ++    if (DP->flags & FD_DEBUG){
  7796. ++        DPRINT("calling disk change from floppy_ready\n");
  7797. ++    }
  7798. ++#endif
  7799. ++
  7800. ++    if(!(raw_cmd.flags & FD_RAW_NO_MOTOR) &&
  7801. ++       disk_change(current_drive) &&
  7802. ++       !DP->select_delay)
  7803. ++        twaddle(); /* this clears the dcl on certain drive/controller
  7804. ++                * combinations */
  7805. ++
  7806. ++    if ( raw_cmd.flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){
  7807. +         perpendicular_mode();
  7808. +         fdc_specify(); /* must be done here because of hut, hlt ... */
  7809. +         seek_floppy();
  7810. +@@ -1576,9 +1646,17 @@
  7811. + static void floppy_start(void)
  7812. + {
  7813. +-    timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout;
  7814. +-    timer_active |= 1 << FLOPPY_TIMER;
  7815. ++    del_timer(&fd_timeout);
  7816. ++    fd_timeout.expires = DP->timeout;
  7817. ++    add_timer(&fd_timeout);
  7818. ++
  7819. +     scandrives();
  7820. ++#ifdef DCL_DEBUG
  7821. ++        if (DP->flags & FD_DEBUG){
  7822. ++            DPRINT("setting NEWCHANGE in floppy_start\n");
  7823. ++        }
  7824. ++#endif
  7825. ++    SETF(FD_DISK_NEWCHANGE);
  7826. +     floppy_ready();
  7827. + }
  7828. +@@ -1598,7 +1676,7 @@
  7829. + static void do_wakeup(void)
  7830. + {
  7831. +-    timer_active &= ~(1 << FLOPPY_TIMER);
  7832. ++    del_timer(&fd_timeout);
  7833. +     cont = 0;
  7834. +     command_status += 2;
  7835. +     wake_up(&command_done);
  7836. +@@ -1615,7 +1693,7 @@
  7837. + {
  7838. +     int ret;
  7839. +-    floppy_tq.routine = (void (*)(void *)) handler;
  7840. ++    floppy_tq.routine = (void *)(void *) handler;
  7841. +     queue_task(&floppy_tq, &tq_timer);
  7842. +     cli();
  7843. +@@ -1630,7 +1708,7 @@
  7844. +     if(command_status < 2){
  7845. +         sti();
  7846. +         floppy_shutdown();
  7847. +-        redo_fd_request();
  7848. ++        process_fd_request();
  7849. +         return -EINTR;
  7850. +     }
  7851. +     sti();
  7852. +@@ -1681,9 +1759,10 @@
  7853. + static int next_valid_format(void)
  7854. + {
  7855. +     int probed_format;
  7856. ++
  7857. ++    probed_format = DRS->probed_format;
  7858. +     while(1){
  7859. +-        probed_format = DRS->probed_format;
  7860. +-        if ( probed_format > 8 ||
  7861. ++        if ( probed_format >= 8 ||
  7862. +             ! DP->autodetect[probed_format] ){
  7863. +             DRS->probed_format = 0;
  7864. +             return 1;
  7865. +@@ -1738,6 +1817,7 @@
  7866. +     }
  7867. +     cont->redo();
  7868. + }
  7869. ++
  7870. + #define CODE2SIZE (ssize = ( ( 1 << SIZECODE ) + 3 ) >> 2)
  7871. + #define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80 ) >>1))
  7872. + #define CT(x) ( (x) | 0x40 )
  7873. +@@ -1804,7 +1884,6 @@
  7874. +     raw_cmd.track = format_req.track << floppy->stretch;
  7875. +     buffer_track = -1;
  7876. +     setup_format_params();
  7877. +-    clear_bit(current_drive, &changed_floppies);
  7878. +     floppy_start();
  7879. + #ifdef DEBUGT
  7880. +     debugt("queue format request");
  7881. +@@ -1819,23 +1898,27 @@
  7882. + static int do_format(int device, struct format_descr *tmp_format_req)
  7883. + {
  7884. +-    int okay;
  7885. ++    int ret;
  7886. ++    int drive=DRIVE(device);
  7887. +-    LOCK_FDC(DRIVE(device),1);
  7888. ++    LOCK_FDC(drive,1);
  7889. +     set_floppy(device);
  7890. +     if (!floppy ||
  7891. ++        floppy->track > DP->tracks ||
  7892. +         tmp_format_req->track >= floppy->track ||
  7893. +-        tmp_format_req->head >= floppy->head){
  7894. +-        redo_fd_request();
  7895. ++        tmp_format_req->head >= floppy->head ||
  7896. ++        (floppy->sect << 2) % (1 <<  FD_SIZECODE(floppy)) ||
  7897. ++        !floppy->fmt_gap) {
  7898. ++        process_fd_request();
  7899. +         return -EINVAL;
  7900. +     }
  7901. +     format_req = *tmp_format_req;
  7902. +     format_errors = 0;
  7903. +     cont = &format_cont;
  7904. +     errors = &format_errors;
  7905. +-    CALL(okay=wait_til_done(redo_format,1));
  7906. +-    redo_fd_request();
  7907. +-    return okay;
  7908. ++    IWAIT(redo_format);
  7909. ++    process_fd_request();
  7910. ++    return ret;
  7911. + }
  7912. + /*
  7913. +@@ -1850,7 +1933,7 @@
  7914. +     int block;
  7915. +     probing = 0;
  7916. +-    timer_active &= ~(1 << FLOPPY_TIMER);
  7917. ++    del_timer(&fd_timeout);
  7918. +     if (!CURRENT){
  7919. +         DPRINT("request list destroyed in floppy request done\n");
  7920. +@@ -1914,7 +1997,7 @@
  7921. +         floppy->sect + ((R_SECTOR-SECTOR) <<  SIZECODE >> 2) -
  7922. +             (sector_t % floppy->sect) % ssize;
  7923. +-#ifdef SANITY
  7924. ++#ifdef CONFIG_FLOPPY_SANITY
  7925. +     if ( nr_sectors > current_count_sectors + ssize -
  7926. +         (current_count_sectors + sector_t) % ssize +
  7927. +         sector_t % ssize){
  7928. +@@ -1987,7 +2070,7 @@
  7929. +     size = CURRENT->current_nr_sectors << 9;
  7930. +     bh = CURRENT->bh;
  7931. +-    if(bh){
  7932. ++    if (bh){
  7933. +         bh = bh->b_reqnext;
  7934. +         while ( bh && bh->b_data == base + size ){
  7935. +             size += bh->b_size;
  7936. +@@ -2034,8 +2117,8 @@
  7937. +             current_count_sectors = CURRENT->nr_sectors;
  7938. +     }
  7939. +     remaining = current_count_sectors << 9;
  7940. +-#ifdef SANITY
  7941. +-    if ((remaining >> 9) > CURRENT->nr_sectors  &&
  7942. ++#ifdef CONFIG_FLOPPY_SANITY
  7943. ++    if ((remaining >> 9) > CURRENT->nr_sectors  && 
  7944. +         CT(COMMAND) == FD_WRITE ){
  7945. +         DPRINT("in copy buffer\n");
  7946. +         printk("current_count_sectors=%ld\n", current_count_sectors);
  7947. +@@ -2060,12 +2143,12 @@
  7948. +     while ( remaining > 0){
  7949. +         if ( size > remaining )
  7950. +             size = remaining;
  7951. +-#ifdef SANITY
  7952. ++#ifdef CONFIG_FLOPPY_SANITY
  7953. +         if (dma_buffer + size >
  7954. +             floppy_track_buffer + (max_buffer_sectors << 10) ||
  7955. +             dma_buffer < floppy_track_buffer ){
  7956. +             DPRINT1("buffer overrun in copy buffer %d\n",
  7957. +-                (floppy_track_buffer - dma_buffer) >>9);
  7958. ++                (int) ((floppy_track_buffer - dma_buffer) >>9));
  7959. +             printk("sector_t=%d buffer_min=%d\n",
  7960. +                    sector_t, buffer_min);
  7961. +             printk("current_count_sectors=%ld\n",
  7962. +@@ -2076,7 +2159,7 @@
  7963. +                 printk("write\n");
  7964. +             break;
  7965. +         }
  7966. +-        if ( ((int)buffer) % 512 )
  7967. ++        if ( ((unsigned long)buffer) % 512 )
  7968. +             DPRINT1("%p buffer not aligned\n", buffer);
  7969. + #endif
  7970. +         if ( CT(COMMAND) == FD_READ )
  7971. +@@ -2089,7 +2172,7 @@
  7972. +         dma_buffer += size;
  7973. +         bh = bh->b_reqnext;
  7974. +-#ifdef SANITY
  7975. ++#ifdef CONFIG_FLOPPY_SANITY
  7976. +         if ( !bh){
  7977. +             DPRINT("bh=null in copy buffer after copy\n");
  7978. +             break;
  7979. +@@ -2098,7 +2181,7 @@
  7980. +         size = bh->b_size;
  7981. +         buffer = bh->b_data;
  7982. +     }
  7983. +-#ifdef SANITY
  7984. ++#ifdef CONFIG_FLOPPY_SANITY
  7985. +     if ( remaining ){
  7986. +         if ( remaining > 0 )
  7987. +             max_sector -= remaining >> 9;
  7988. +@@ -2122,7 +2205,7 @@
  7989. +     int aligned_sector_t;
  7990. +     int max_sector, max_size, tracksize, ssize;
  7991. +-    current_drive = DRIVE(CURRENT->dev);
  7992. ++    set_fdc(DRIVE(CURRENT->dev));
  7993. +     raw_cmd.flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
  7994. +         FD_RAW_NEED_SEEK;
  7995. +@@ -2145,7 +2228,7 @@
  7996. +         return 0;
  7997. +     HEAD = sector_t / floppy->sect;
  7998. +-    if ( (DRS->flags & FD_NEED_TWADDLE) && sector_t < floppy->sect )
  7999. ++    if ( TESTF( FD_NEED_TWADDLE) && sector_t < floppy->sect )
  8000. +         max_sector = floppy->sect;
  8001. +     /* 2M disks have phantom sectors on the first track */
  8002. +@@ -2213,22 +2296,19 @@
  8003. +         raw_cmd.flags &= ~FD_RAW_WRITE;
  8004. +         raw_cmd.flags |= FD_RAW_READ;
  8005. +         COMMAND = FM_MODE(floppy,FD_READ);
  8006. +-    }
  8007. +-    else if ((long)CURRENT->buffer <= LAST_DMA_ADDR ) {
  8008. ++    } else if ((long)CURRENT->buffer <= LAST_DMA_ADDR ) {
  8009. +         int direct, indirect;
  8010. +         indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) -
  8011. +             sector_t;
  8012. +         max_size = buffer_chain_size();
  8013. +-#if 0
  8014. +         if ( max_size > ( LAST_DMA_ADDR - ((long) CURRENT->buffer))>>9)
  8015. +             max_size=(LAST_DMA_ADDR - ((long)CURRENT->buffer))>>9;
  8016. +         /* 64 kb boundaries */
  8017. +         if ( ((max_size << 9) + ((long) CURRENT->buffer)) / K_64 !=
  8018. +              ((long) CURRENT->buffer ) / K_64 )
  8019. +             max_size = ( K_64 - ((long) CURRENT->buffer) % K_64)>>9;
  8020. +-#endif
  8021. +         direct = transfer_size(ssize,max_sector,max_size) - sector_t;
  8022. +         /*
  8023. +          * We try to read tracks, but if we get too many errors, we
  8024. +@@ -2237,15 +2317,21 @@
  8025. +          * This means we should be able to read a sector even if there
  8026. +          * are other bad sectors on this track.
  8027. +          */
  8028. +-        if ((indirect - sector_t) * 2 > (direct - sector_t) * 3 &&
  8029. +-            *errors < DP->max_errors.read_track &&
  8030. +-            /*!(DRS->flags & FD_NEED_TWADDLE) &&*/
  8031. +-            ( ( !probing || (DP->read_track &
  8032. +-               (1 <<DRS->probed_format))))){
  8033. ++        if (!direct ||
  8034. ++            (indirect * 2 > direct * 3 &&
  8035. ++             *errors < DP->max_errors.read_track &&
  8036. ++             /*!TESTF( FD_NEED_TWADDLE) &&*/
  8037. ++             ((!probing || (DP->read_track&(1<<DRS->probed_format)))))){
  8038. +             max_size = CURRENT->nr_sectors;
  8039. +         } else {
  8040. +             current_addr = CURRENT->buffer;
  8041. +             raw_cmd.length = current_count_sectors << 9;
  8042. ++            if (raw_cmd.length == 0){
  8043. ++                DPRINT("zero dma transfer attempted from make_raw_request\n");
  8044. ++                DPRINT3("indirect=%d direct=%d sector_t=%d",
  8045. ++                    indirect, direct, sector_t);
  8046. ++                return 0;
  8047. ++            }
  8048. +             return 2;
  8049. +         }
  8050. +     }
  8051. +@@ -2256,6 +2342,7 @@
  8052. +     /* claim buffer track if needed */
  8053. +     if (buffer_track != raw_cmd.track ||  /* bad track */
  8054. +         buffer_drive !=current_drive || /* bad drive */
  8055. ++        sector_t > buffer_max ||
  8056. +         sector_t < buffer_min ||
  8057. +         ((CT(COMMAND) == FD_READ ||
  8058. +           (aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize ))&&
  8059. +@@ -2273,7 +2360,7 @@
  8060. +          * if we get here, we know that the write
  8061. +          * is either aligned or the data already in the buffer
  8062. +          * (buffer will be overwritten) */
  8063. +-#ifdef SANITY
  8064. ++#ifdef CONFIG_FLOPPY_SANITY
  8065. +         if (sector_t != aligned_sector_t && buffer_track == -1 )
  8066. +             DPRINT("internal error offset !=0 on write\n");
  8067. + #endif
  8068. +@@ -2288,8 +2375,7 @@
  8069. +     raw_cmd.length = sector_t+current_count_sectors-aligned_sector_t;
  8070. +     raw_cmd.length = ((raw_cmd.length -1)|(ssize-1))+1;
  8071. +     raw_cmd.length <<= 9;
  8072. +-
  8073. +-#ifdef SANITY
  8074. ++#ifdef CONFIG_FLOPPY_SANITY
  8075. +     if ((raw_cmd.length < current_count_sectors << 9) ||
  8076. +         (current_addr != CURRENT->buffer &&
  8077. +          CT(COMMAND) == FD_WRITE &&
  8078. +@@ -2301,7 +2387,7 @@
  8079. +             raw_cmd.length, current_count_sectors);
  8080. +         if ( current_addr != CURRENT->buffer )
  8081. +             printk("addr=%d, length=%ld\n",
  8082. +-                   (current_addr - floppy_track_buffer ) >> 9,
  8083. ++                   (int) ((current_addr - floppy_track_buffer ) >> 9),
  8084. +                    current_count_sectors);
  8085. +         printk("st=%d ast=%d mse=%d msi=%d\n",
  8086. +                sector_t, aligned_sector_t, max_sector, max_size);
  8087. +@@ -2342,28 +2428,27 @@
  8088. +         printk("bytes=%ld\n", raw_cmd.length >> 9 );
  8089. +         printk("sectors=%ld\n", current_count_sectors);
  8090. +     }
  8091. ++    if (raw_cmd.length == 0){
  8092. ++        DPRINT("zero dma transfer attempted from make_raw_request\n");
  8093. ++        return 0;
  8094. ++    }
  8095. + #endif
  8096. +     return 2;
  8097. + }
  8098. +-static struct cont_t rw_cont={
  8099. +-    rw_interrupt,
  8100. +-    redo_fd_request,
  8101. +-    bad_flp_intr,
  8102. +-    request_done };
  8103. +-
  8104. + static void redo_fd_request(void)
  8105. + {
  8106. + #define REPEAT {request_done(0); continue; }
  8107. +     int device;
  8108. +     int tmp;
  8109. ++    int error;
  8110. ++    error = -1;
  8111. +     if (current_drive < N_DRIVE)
  8112. +         floppy_off(current_drive);
  8113. +     if (CURRENT && CURRENT->dev < 0) return;
  8114. +-    cont = &rw_cont;
  8115. +     while(1){
  8116. +         if (!CURRENT) {
  8117. +             CLEAR_INTR;
  8118. +@@ -2374,20 +2459,29 @@
  8119. +             panic(DEVICE_NAME ": request list destroyed");
  8120. +         if (CURRENT->bh && !CURRENT->bh->b_lock)
  8121. +             panic(DEVICE_NAME ": block not locked");
  8122. +-
  8123. ++#if 0
  8124. ++        if (!CURRENT->bh->b_count && 
  8125. ++            (CURRENT->errors || error == CURRENT->dev)){
  8126. ++            error=CURRENT->dev;
  8127. ++            DPRINT("skipping read ahead buffer\n");
  8128. ++            REPEAT;
  8129. ++        }
  8130. ++#endif
  8131. ++        error=-1;
  8132. +         device = CURRENT->dev;
  8133. +         set_fdc( DRIVE(device));
  8134. +-        timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout;
  8135. +-        timer_active |= 1 << FLOPPY_TIMER;
  8136. +-        raw_cmd.flags=0;
  8137. +-        start_motor();
  8138. +-        if(test_bit( DRIVE(device), &fake_change) ||
  8139. +-           test_bit( DRIVE(device), &changed_floppies)){
  8140. ++        del_timer(&fd_timeout);
  8141. ++        fd_timeout.expires = DP->timeout;
  8142. ++        add_timer(&fd_timeout);
  8143. ++
  8144. ++        set_floppy(device);
  8145. ++        if(start_motor(redo_fd_request)) return;
  8146. ++        if(test_bit(current_drive, &fake_change) ||
  8147. ++           TESTF(FD_DISK_CHANGED)){
  8148. +             DPRINT("disk absent or changed during operation\n");
  8149. +             REPEAT;
  8150. +         }
  8151. +-        set_floppy(device);
  8152. +         if (!floppy) { /* Autodetection */
  8153. +             if (!probing){
  8154. +                 DRS->probed_format = 0;
  8155. +@@ -2408,7 +2502,9 @@
  8156. +             continue;
  8157. +         }
  8158. +-        floppy_tq.routine = (void (*)(void *)) floppy_start;
  8159. ++        if (TESTF(FD_NEED_TWADDLE))
  8160. ++            twaddle();
  8161. ++        floppy_tq.routine = (void *)(void *) floppy_start;
  8162. +         queue_task(&floppy_tq, &tq_timer);
  8163. + #ifdef DEBUGT
  8164. +         debugt("queue fd request");
  8165. +@@ -2418,7 +2514,22 @@
  8166. + #undef REPEAT
  8167. + }
  8168. +-void do_fd_request(void)
  8169. ++static struct cont_t rw_cont={
  8170. ++    rw_interrupt,
  8171. ++    redo_fd_request,
  8172. ++    bad_flp_intr,
  8173. ++    request_done };
  8174. ++
  8175. ++struct tq_struct request_tq = 
  8176. ++{ 0, 0, (void *) (void *) redo_fd_request, 0 };
  8177. ++
  8178. ++static void process_fd_request(void)
  8179. ++{
  8180. ++    cont = &rw_cont;
  8181. ++    queue_task(&request_tq, &tq_timer);
  8182. ++}
  8183. ++
  8184. ++static void do_fd_request(void)
  8185. + {
  8186. +     if (fdc_busy)
  8187. +         /* fdc busy, this new request will be treated when the
  8188. +@@ -2427,7 +2538,30 @@
  8189. +     /* fdc_busy cannot be set by an interrupt or a bh */
  8190. +     floppy_grab_irq_and_dma();
  8191. +     fdc_busy=1;
  8192. +-    redo_fd_request();
  8193. ++    process_fd_request();
  8194. ++}
  8195. ++
  8196. ++static struct cont_t poll_cont={
  8197. ++    success_and_wakeup,
  8198. ++    floppy_ready,
  8199. ++    generic_failure,
  8200. ++    generic_done };
  8201. ++
  8202. ++static int poll_drive(int interruptible, int flag){
  8203. ++    int ret;
  8204. ++    /* no auto-sense, just clear dcl */
  8205. ++    raw_cmd.flags= flag;
  8206. ++    raw_cmd.track=0;
  8207. ++    raw_cmd.cmd_count=0;
  8208. ++    cont = &poll_cont;
  8209. ++#ifdef DCL_DEBUG
  8210. ++        if (DP->flags & FD_DEBUG){
  8211. ++            DPRINT("setting NEWCHANGE in poll_drive\n");
  8212. ++        }
  8213. ++#endif
  8214. ++    SETF(FD_DISK_NEWCHANGE);
  8215. ++    WAIT(floppy_ready);
  8216. ++    return ret;
  8217. + }
  8218. + /*
  8219. +@@ -2448,29 +2582,23 @@
  8220. + static int user_reset_fdc(int drive, int arg, int interruptible)
  8221. + {
  8222. +-    int result;
  8223. ++    int ret;
  8224. +-    result=0;
  8225. ++    ret=0;
  8226. ++    if(arg == FD_RESET_IF_NEEDED && !FDCS->reset)
  8227. ++        return 0;
  8228. +     LOCK_FDC(drive,interruptible);
  8229. +-    switch(arg){
  8230. +-    case FD_RESET_ALWAYS:
  8231. ++    if(arg == FD_RESET_ALWAYS)
  8232. +         FDCS->reset=1;
  8233. +-        break;
  8234. +-    case FD_RESET_IF_RAWCMD:
  8235. +-        if(FDCS->rawcmd == 2 )
  8236. +-            reset_fdc_info(1);
  8237. +-        break;
  8238. +-    }
  8239. +     if ( FDCS->reset ){
  8240. +         cont = &reset_cont;
  8241. +-        timer_table[FLOPPY_TIMER].expires = jiffies + 5;
  8242. +-        timer_active |= 1 << FLOPPY_TIMER;
  8243. +-        CALL(result=wait_til_done(reset_fdc,interruptible));
  8244. +-    }
  8245. +-    if ( UDRS->track == PROVEN_ABSENT )
  8246. +-        UDRS->track = NEED_2_RECAL;
  8247. +-    redo_fd_request();
  8248. +-    return result;
  8249. ++        del_timer(&fd_timeout);
  8250. ++        fd_timeout.expires = DP->timeout;
  8251. ++        add_timer(&fd_timeout);
  8252. ++        WAIT(reset_fdc);
  8253. ++    }
  8254. ++    process_fd_request();
  8255. ++    return ret;
  8256. + }
  8257. + /*
  8258. +@@ -2493,7 +2621,7 @@
  8259. + static char *drive_name(int type, int drive )
  8260. + {
  8261. +-    struct floppy_struct *floppy;
  8262. ++    struct floppy_struct *floppy;    
  8263. +     if ( type )
  8264. +         floppy = floppy_type + type;
  8265. +@@ -2516,21 +2644,21 @@
  8266. +     generic_failure,
  8267. +     generic_done };
  8268. +-static int raw_cmd_ioctl(int drive, void *param)
  8269. ++static int raw_cmd_ioctl(void *param)
  8270. + {
  8271. +-    int i, count, ret;
  8272. ++    int i, drive, count, ret;
  8273. +     if ( FDCS->rawcmd <= 1 )
  8274. +         FDCS->rawcmd = 1;
  8275. +-    for ( i= 0; i < N_DRIVE; i++){
  8276. +-        if ( FDC(i) != fdc)
  8277. ++    for ( drive= 0; drive < N_DRIVE; drive++){
  8278. ++        if ( FDC(drive) != fdc)
  8279. +             continue;
  8280. +-        if ( i == drive ){
  8281. +-            if ( drive_state[i].fd_ref > 1 ){
  8282. ++        if ( drive == current_drive ){
  8283. ++            if ( UDRS->fd_ref > 1 ){
  8284. +                 FDCS->rawcmd = 2;
  8285. +                 break;
  8286. +             }
  8287. +-        } else if ( drive_state[i].fd_ref ){
  8288. ++        } else if ( UDRS->fd_ref ){
  8289. +             FDCS->rawcmd = 2;
  8290. +             break;
  8291. +         }
  8292. +@@ -2540,11 +2668,15 @@
  8293. +         return -EIO;
  8294. +     COPYIN(raw_cmd);
  8295. +-    raw_cmd.rate &= 0x03;
  8296. ++    raw_cmd.rate &= 0x03;    
  8297. +     count = raw_cmd.length;
  8298. +     if (raw_cmd.flags & (FD_RAW_WRITE | FD_RAW_READ)){
  8299. +         if(count > max_buffer_sectors * 1024 )
  8300. +             return -ENOMEM;
  8301. ++        if(count == 0){
  8302. ++            printk("attempt to do a 0 byte dma transfer\n");
  8303. ++            return -EINVAL;
  8304. ++        }
  8305. +         buffer_track = -1;
  8306. +     }
  8307. +     if ( raw_cmd.flags & FD_RAW_WRITE ){
  8308. +@@ -2556,13 +2688,18 @@
  8309. +     current_addr = floppy_track_buffer;
  8310. +     cont = &raw_cmd_cont;
  8311. +-    CALL(ret=wait_til_done(floppy_start,1));
  8312. ++    IWAIT(floppy_start);
  8313. ++#ifdef DCL_DEBUG
  8314. ++    if (DP->flags & FD_DEBUG){
  8315. ++        DPRINT("calling disk change from raw_cmd ioctl\n");
  8316. ++    }
  8317. ++#endif
  8318. +     if( disk_change(current_drive) )
  8319. +         raw_cmd.flags |= FD_RAW_DISK_CHANGE;
  8320. +     else
  8321. +         raw_cmd.flags &= ~FD_RAW_DISK_CHANGE;
  8322. +     if(raw_cmd.flags & FD_RAW_NO_MOTOR_AFTER)
  8323. +-        motor_off_callback(drive);
  8324. ++        motor_off_callback(current_drive);    
  8325. +     if ( !ret && !FDCS->reset ){
  8326. +         raw_cmd.reply_count = inr;
  8327. +@@ -2572,7 +2709,6 @@
  8328. +             raw_cmd.length = get_dma_residue(FLOPPY_DMA);
  8329. +     } else
  8330. +         ret = -EIO;
  8331. +-
  8332. +     DRS->track = NO_TRACK;
  8333. +     if ( ret )
  8334. +         return ret;
  8335. +@@ -2582,7 +2718,7 @@
  8336. +         if (i)
  8337. +             return i;
  8338. +     }
  8339. +-
  8340. ++       
  8341. +     return COPYOUT(raw_cmd);
  8342. + }
  8343. +@@ -2590,7 +2726,7 @@
  8344. + {
  8345. +     /* invalidate the buffer track to force a reread */
  8346. +     set_bit( DRIVE(rdev), &fake_change);
  8347. +-    redo_fd_request();
  8348. ++    process_fd_request();
  8349. +     check_disk_change(rdev);
  8350. +     return 0;
  8351. + }
  8352. +@@ -2599,6 +2735,7 @@
  8353. +     unsigned long param)
  8354. + {
  8355. + #define IOCTL_MODE_BIT 8
  8356. ++#define OPEN_WRITE_BIT 16
  8357. + #define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
  8358. +     struct floppy_struct newparams;
  8359. +@@ -2636,7 +2773,9 @@
  8360. +             return -ENODEV;
  8361. +         return COPYOUT(this_floppy[0]);
  8362. +     case FDPOLLDRVSTAT:
  8363. +-        check_disk_change(device);
  8364. ++        LOCK_FDC(drive,1);
  8365. ++        CALL(poll_drive(1, FD_RAW_NEED_DISK));
  8366. ++        process_fd_request();
  8367. +         /* fall through */
  8368. +     case FDGETDRVSTAT:
  8369. +         return COPYOUT(*UDRS);
  8370. +@@ -2647,10 +2786,8 @@
  8371. +     case FDWERRORGET:
  8372. +         return COPYOUT(*UDRWE);
  8373. +     }
  8374. +-
  8375. +     if (!IOCTL_ALLOWED)
  8376. +         return -EPERM;
  8377. +-
  8378. +     switch (cmd) {
  8379. +     case FDWERRORCLR:
  8380. +                 UDRWE->write_errors = 0;
  8381. +@@ -2665,14 +2802,12 @@
  8382. +             return -EINVAL;
  8383. +         LOCK_FDC(drive,1);
  8384. +         set_floppy(device);
  8385. +-        CALL(i = raw_cmd_ioctl(drive, (void *) param));
  8386. +-        redo_fd_request();
  8387. ++        CALL(i = raw_cmd_ioctl((void *) param));
  8388. ++        process_fd_request();
  8389. +         return i;
  8390. +     case FDFMTTRK:
  8391. +         if (UDRS->fd_ref != 1)
  8392. +             return -EBUSY;
  8393. +-        if (UDRS->track == PROVEN_ABSENT)
  8394. +-            return -ENXIO;
  8395. +         COPYIN(tmp_format_req);
  8396. +         return do_format(device, &tmp_format_req);
  8397. +     case FDSETMAXERRS:
  8398. +@@ -2682,7 +2817,7 @@
  8399. +     case FDCLRPRM:
  8400. +         LOCK_FDC(drive,1);
  8401. +         current_type[drive] = NULL;
  8402. +-        floppy_sizes[drive] = 2;
  8403. ++        floppy_sizes[drive] = MAX_DISK_SIZE;
  8404. +         UDRS->keep_data = 0;
  8405. +         return invalidate_drive(device);
  8406. +     case FDFMTEND:
  8407. +@@ -2702,7 +2837,7 @@
  8408. +         if ( type){
  8409. +             if ( !suser() )
  8410. +                 return -EPERM;
  8411. +-            LOCK_FDC(-1,1);
  8412. ++            LOCK_FDC(drive,1);
  8413. +             for ( cnt = 0; cnt < N_DRIVE; cnt++){
  8414. +                 if (TYPE(drive_state[cnt].fd_device) == type &&
  8415. +                     drive_state[cnt].fd_ref)
  8416. +@@ -2714,11 +2849,9 @@
  8417. +                  cnt < (type << 2 ) + 4 ;
  8418. +                  cnt++)
  8419. +                 floppy_sizes[cnt]=
  8420. +-#ifdef HAVE_2_CONTROLLERS
  8421. +                     floppy_sizes[cnt+0x80]=
  8422. +-#endif
  8423. +                         floppy_type[type].size>>1;
  8424. +-            redo_fd_request();
  8425. ++            process_fd_request();
  8426. +             for ( cnt = 0; cnt < N_DRIVE; cnt++){
  8427. +                 if (TYPE(drive_state[cnt].fd_device) == type &&
  8428. +                     drive_state[cnt].fd_ref)
  8429. +@@ -2729,12 +2862,10 @@
  8430. +         }
  8431. +         LOCK_FDC(drive,1);
  8432. +-        if ( cmd != FDDEFPRM ){
  8433. ++        if ( cmd != FDDEFPRM )
  8434. +             /* notice a disk change immediately, else
  8435. +              * we loose our settings immediately*/
  8436. +-            raw_cmd.flags = 0;
  8437. +-            start_motor();
  8438. +-        }
  8439. ++            CALL(poll_drive(1,0));
  8440. +         user_params[drive] = newparams;
  8441. +         if (buffer_drive == drive &&
  8442. +             buffer_max > user_params[drive].sect)
  8443. +@@ -2755,7 +2886,7 @@
  8444. +             DRS->maxtrack )
  8445. +             invalidate_drive(device);
  8446. +         else
  8447. +-            redo_fd_request();
  8448. ++            process_fd_request();
  8449. +         return 0;
  8450. +     case FDRESET:
  8451. +         return user_reset_fdc( drive, (int)param, 1);
  8452. +@@ -2772,7 +2903,7 @@
  8453. +     case FDTWADDLE:
  8454. +         LOCK_FDC(drive,1);
  8455. +         twaddle();
  8456. +-        redo_fd_request();
  8457. ++        process_fd_request();
  8458. +     }
  8459. +     if ( ! suser() )
  8460. +         return -EPERM;
  8461. +@@ -2786,70 +2917,89 @@
  8462. + #undef IOCTL_ALLOWED
  8463. + }
  8464. +-static void set_base_type(int drive, int code)
  8465. +-{
  8466. +-    if(code>0 && code <= NUMBER(default_drive_params)+1) {
  8467. +-        memcpy((char *)UDP,
  8468. +-            (char *)(&default_drive_params[code-1].params),
  8469. +-            sizeof(struct floppy_drive_params));
  8470. +-        printk("fd%d is %s", drive, default_drive_params[code-1].name);
  8471. +-        return;
  8472. +-    }
  8473. +-    else if (!code)
  8474. +-        printk("fd%d is not installed", drive);
  8475. +-    else
  8476. +-        printk("fd%d is unknown type %d", drive, code);
  8477. +-}
  8478. +-
  8479. + static void config_types(void)
  8480. + {
  8481. ++    int first=1;
  8482. +     int drive;
  8483. +-    for (drive=0; drive<N_DRIVE ; drive++){
  8484. +-          /* default type for unidentifiable drives */
  8485. +-          memcpy((char *) UDP, (char *) (&default_drive_params->params),
  8486. +-              sizeof( struct floppy_drive_params ));
  8487. +-    }
  8488. +-    printk("Floppy drive(s): ");
  8489. +-    for(drive=0; drive<no_floppies; drive++)
  8490. +-    {
  8491. +-      set_base_type(drive, 1+4);
  8492. +-      if(drive < no_floppies-1)
  8493. +-        printk(", ");
  8494. ++    /* read drive info out of physical cmos */
  8495. ++    drive=0;
  8496. ++    if (!UDP->cmos )
  8497. ++        UDP->cmos= FLOPPY0_TYPE;
  8498. ++    drive=1;
  8499. ++    if (!UDP->cmos && FLOPPY1_TYPE)
  8500. ++        UDP->cmos = FLOPPY1_TYPE;
  8501. ++
  8502. ++    /* XXX */
  8503. ++    /* additional physical CMOS drive detection should go here */
  8504. ++
  8505. ++    for (drive=0; drive < N_DRIVE; drive++){
  8506. ++        if (UDP->cmos >= 0 && UDP->cmos <= NUMBER(default_drive_params))
  8507. ++            memcpy((char *) UDP,
  8508. ++                   (char *) (&default_drive_params[(int)UDP->cmos].params),
  8509. ++                   sizeof(struct floppy_drive_params));
  8510. ++        if (UDP->cmos){
  8511. ++            if (first)
  8512. ++                printk("Floppy drive(s): ");
  8513. ++            else
  8514. ++                printk(", ");
  8515. ++            first=0;
  8516. ++            if (UDP->cmos > 0 ){
  8517. ++                ALLOWED_DRIVE_MASK |= 1 << drive;
  8518. ++                printk("fd%d is %s", drive,
  8519. ++                       default_drive_params[(int)UDP->cmos].name);
  8520. ++            } else
  8521. ++                printk("fd%d is unknown type %d",drive,
  8522. ++                       UDP->cmos);
  8523. ++        }
  8524. +     }
  8525. +-    printk("\n");
  8526. ++    if(!first)
  8527. ++        printk("\n");
  8528. + }
  8529. +-int floppy_is_wp( int minor)
  8530. ++static int floppy_read(struct inode * inode, struct file * filp,
  8531. ++               char * buf, int count)
  8532. + {
  8533. +-    check_disk_change(minor + (MAJOR_NR << 8));
  8534. +-    return ! ( drive_state[ DRIVE(minor) ].flags & FD_DISK_WRITABLE );
  8535. ++    int drive = DRIVE(inode->i_rdev);
  8536. ++
  8537. ++    check_disk_change(inode->i_rdev);
  8538. ++    if (UTESTF(FD_DISK_CHANGED))
  8539. ++        return -ENXIO;
  8540. ++    return block_read(inode, filp, buf, count);
  8541. + }
  8542. ++static int floppy_write(struct inode * inode, struct file * filp,
  8543. ++            char * buf, int count)
  8544. ++{
  8545. ++    int block;
  8546. ++    int ret;
  8547. ++    int drive = DRIVE(inode->i_rdev);
  8548. +-#define WRAPPER(op) \
  8549. +-static int floppy_##op(struct inode * inode, struct file * filp, \
  8550. +-             char * buf, int count) \
  8551. +-{ \
  8552. +-    check_disk_change(inode->i_rdev); \
  8553. +-    if ( drive_state[DRIVE(inode->i_rdev)].track == PROVEN_ABSENT ) \
  8554. +-         return -ENXIO; \
  8555. +-    if ( test_bit(DRIVE(inode->i_rdev),&changed_floppies)) \
  8556. +-        return -ENXIO; \
  8557. +-    return block_##op(inode, filp, buf, count); \
  8558. ++    if(!UDRS->maxblock)
  8559. ++        UDRS->maxblock=1;/* make change detectable */
  8560. ++    check_disk_change(inode->i_rdev);
  8561. ++    if (UTESTF(FD_DISK_CHANGED)) 
  8562. ++        return -ENXIO;
  8563. ++    if(!UTESTF(FD_DISK_WRITABLE))
  8564. ++        return -EROFS;
  8565. ++    block = (filp->f_pos + count) >> 9;
  8566. ++    if(block > UDRS->maxblock)
  8567. ++        UDRS->maxblock = block;
  8568. ++    ret= block_write(inode, filp, buf, count);
  8569. ++    return ret;
  8570. + }
  8571. +-WRAPPER(read)
  8572. +-WRAPPER(write)
  8573. +-
  8574. + static void floppy_release(struct inode * inode, struct file * filp)
  8575. + {
  8576. +     int drive;
  8577. +-
  8578. ++    
  8579. +     drive = DRIVE(inode->i_rdev);
  8580. +-    fsync_dev(inode->i_rdev);
  8581. +-
  8582. ++    if( !filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
  8583. ++        /* if the file is mounted OR (writable now AND writable at
  8584. ++         * open time) Linus: Does this cover all cases? */
  8585. ++        block_fsync(inode,filp);
  8586. ++            
  8587. +     if (UDRS->fd_ref < 0)
  8588. +         UDRS->fd_ref=0;
  8589. +     else if (!UDRS->fd_ref--) {
  8590. +@@ -2879,20 +3029,22 @@
  8591. +     }
  8592. +     drive = DRIVE(inode->i_rdev);
  8593. +-    if ( drive >= N_DRIVE || !( ALLOWED_DRIVE_MASK & ( 1 << drive)) )
  8594. ++    if (drive >= N_DRIVE || 
  8595. ++        !( ALLOWED_DRIVE_MASK & ( 1 << drive)) ||
  8596. ++        fdc_state[FDC(drive)].version == FDC_NONE)
  8597. +         return -ENXIO;
  8598. +     if (TYPE(inode->i_rdev) >= NUMBER(floppy_type))
  8599. +         return -ENXIO;
  8600. +-
  8601. +-    if ((filp->f_mode & 3)  &&
  8602. +-        UDRS->track == PROVEN_ABSENT )
  8603. +-        return -ENXIO;
  8604. +-
  8605. +     old_dev = UDRS->fd_device;
  8606. +     if (UDRS->fd_ref && old_dev != inode->i_rdev)
  8607. +         return -EBUSY;
  8608. ++    if(!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){
  8609. ++        USETF(FD_DISK_CHANGED);
  8610. ++        USETF(FD_VERIFY);
  8611. ++    }
  8612. ++
  8613. +     if(UDRS->fd_ref == -1 ||
  8614. +        (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
  8615. +         return -EBUSY;
  8616. +@@ -2900,7 +3052,7 @@
  8617. +     if (floppy_grab_irq_and_dma())
  8618. +         return -EBUSY;
  8619. +-    if(filp->f_flags & O_EXCL)
  8620. ++    if (filp->f_flags & O_EXCL)
  8621. +         UDRS->fd_ref = -1;
  8622. +     else
  8623. +         UDRS->fd_ref++;
  8624. +@@ -2916,30 +3068,21 @@
  8625. +     /* Allow ioctls if we have write-permissions even if read-only open */
  8626. +     if ((filp->f_mode & 2) || (permission(inode,2) == 0))
  8627. +         filp->f_mode |= IOCTL_MODE_BIT;
  8628. ++    if (filp->f_mode & 2)
  8629. ++        filp->f_mode |= OPEN_WRITE_BIT;
  8630. +     if (UFDCS->rawcmd == 1)
  8631. +            UFDCS->rawcmd = 2;
  8632. +     if (filp->f_flags & O_NDELAY)
  8633. +         return 0;
  8634. +-
  8635. +-    if (filp->f_mode && UDRS->track == PROVEN_ABSENT )
  8636. +-        RETERR(ENXIO);
  8637. +-
  8638. +-    if (user_reset_fdc(drive, FD_RESET_IF_NEEDED,0))
  8639. +-        RETERR(EIO);
  8640. +-
  8641. +     if (filp->f_mode & 3) {
  8642. +         UDRS->last_checked = 0;
  8643. +         check_disk_change(inode->i_rdev);
  8644. +-        if (test_bit(drive,&changed_floppies))
  8645. ++        if (UTESTF(FD_DISK_CHANGED))
  8646. +             RETERR(ENXIO);
  8647. +     }
  8648. +-
  8649. +-    if (filp->f_mode && UDRS->track == PROVEN_ABSENT )
  8650. +-        RETERR(ENXIO);
  8651. +-
  8652. +-    if ((filp->f_mode & 2) && !(UDRS->flags & FD_DISK_WRITABLE))
  8653. ++    if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE)))
  8654. +         RETERR(EROFS);
  8655. +     return 0;
  8656. + #undef RETERR
  8657. +@@ -2957,45 +3100,38 @@
  8658. +         return 0;
  8659. +     }
  8660. +-    if(test_bit(drive, &changed_floppies))
  8661. ++    if (UTESTF(FD_DISK_CHANGED))
  8662. +         return 1;
  8663. +     if(UDRS->last_checked + UDP->checkfreq < jiffies){
  8664. +         lock_fdc(drive,0);
  8665. +-        start_motor();
  8666. +-        redo_fd_request();
  8667. ++        poll_drive(0,0);
  8668. ++        process_fd_request();
  8669. +     }
  8670. +-
  8671. +-    if(test_bit(drive, &changed_floppies))
  8672. +-        return 1;
  8673. +-    if(test_bit(drive, &fake_change))
  8674. ++        
  8675. ++    if(UTESTF(FD_DISK_CHANGED) ||
  8676. ++       test_bit(drive, &fake_change) ||
  8677. ++       (!TYPE(dev) && !current_type[drive]))
  8678. +         return 1;
  8679. +     return 0;
  8680. + }
  8681. +-static struct cont_t poll_cont={
  8682. +-    success_and_wakeup,
  8683. +-    floppy_ready,
  8684. +-    generic_failure,
  8685. +-    generic_done };
  8686. +-
  8687. +-
  8688. + /* revalidate the floppy disk, i.e. trigger format autodetection by reading
  8689. +- * the bootblock (block 0). "Autodetection" is also needed to check wether
  8690. ++ * the bootblock (block 0). "Autodetection" is also needed to check whether
  8691. +  * there is a disk in the drive at all... Thus we also do it for fixed
  8692. +  * geometry formats */
  8693. + static int floppy_revalidate(dev_t dev)
  8694. + {
  8695. ++#define NO_GEOM (!current_type[drive] && !TYPE(dev))
  8696. +     struct buffer_head * bh;
  8697. +     int drive=DRIVE(dev);
  8698. +     int cf;
  8699. +-    cf = test_bit(drive, &changed_floppies);
  8700. +-    if(cf || test_bit(drive, &fake_change)){
  8701. ++    if(UTESTF(FD_DISK_CHANGED) || test_bit(drive, &fake_change) || NO_GEOM){
  8702. +         lock_fdc(drive,0);
  8703. +-        cf = test_bit(drive, &changed_floppies);
  8704. +-        if(! (cf || test_bit(drive, &fake_change))){
  8705. +-            redo_fd_request(); /* already done by another thread */
  8706. ++        cf = UTESTF(FD_DISK_CHANGED);
  8707. ++        if(! (cf || test_bit(drive, &fake_change) || NO_GEOM)){
  8708. ++            process_fd_request(); /*already done by another thread*/
  8709. +             return 0;
  8710. +         }
  8711. +         UDRS->maxblock = 0;
  8712. +@@ -3003,31 +3139,28 @@
  8713. +         if ( buffer_drive == drive)
  8714. +             buffer_track = -1;
  8715. +         clear_bit(drive, &fake_change);
  8716. +-        clear_bit(drive, &changed_floppies);
  8717. +-        if(cf){
  8718. ++        UCLEARF(FD_DISK_CHANGED);
  8719. ++        if(cf)
  8720. +             UDRS->generation++;
  8721. +-            if(!current_type[drive] && !TYPE(dev)){
  8722. +-                /* auto-sensing */
  8723. +-                if (!(bh = getblk(dev,0,1024))){
  8724. +-                    redo_fd_request();
  8725. +-                    return 1;
  8726. +-                }
  8727. +-                if ( bh && ! bh->b_uptodate)
  8728. +-                    ll_rw_block(READ, 1, &bh);
  8729. +-                redo_fd_request();
  8730. +-                wait_on_buffer(bh);
  8731. +-                brelse(bh);
  8732. +-                return 0;
  8733. +-            } else {
  8734. +-                /* no auto-sense, just clear dcl */
  8735. +-                raw_cmd.flags=FD_RAW_NEED_SEEK|FD_RAW_NEED_DISK;
  8736. +-                raw_cmd.track=0;
  8737. +-                raw_cmd.cmd_count=0;
  8738. +-                cont = &poll_cont;
  8739. +-                wait_til_done(floppy_ready,0);
  8740. ++        if(NO_GEOM){
  8741. ++            /* auto-sensing */
  8742. ++            int size = floppy_blocksizes[MINOR(dev)];
  8743. ++            if (!size)
  8744. ++                size = 1024;
  8745. ++            if (!(bh = getblk(dev,0,size))){
  8746. ++                process_fd_request();
  8747. ++                return 1;
  8748. +             }
  8749. +-        }
  8750. +-        redo_fd_request();
  8751. ++            if ( bh && ! bh->b_uptodate)
  8752. ++                ll_rw_block(READ, 1, &bh);
  8753. ++            process_fd_request();
  8754. ++            wait_on_buffer(bh);
  8755. ++            brelse(bh);
  8756. ++            return 0;
  8757. ++        } 
  8758. ++        if(cf)
  8759. ++                poll_drive(0, FD_RAW_NEED_DISK);
  8760. ++        process_fd_request();
  8761. +     }
  8762. +     return 0;
  8763. + }
  8764. +@@ -3094,17 +3227,145 @@
  8765. +     }
  8766. +     printk("FDC %d is a post-1991 82077\n",fdc);
  8767. +     return FDC_82077;    /* Revised 82077AA passes all the tests */
  8768. +-} /* fdc_init */
  8769. ++} /* get_fdc_version */
  8770. +-void floppy_init(void)
  8771. ++/* lilo configuration */
  8772. ++
  8773. ++/* we make the invert_dcl function global. One day, somebody might
  8774. ++want to centralize all thinkpad related options into one lilo option,
  8775. ++there are just so many thinkpad related quirks! */
  8776. ++void floppy_invert_dcl(int *ints,int param)
  8777. ++{
  8778. ++    int i;
  8779. ++    
  8780. ++    for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
  8781. ++        if (param)
  8782. ++            default_drive_params[i].params.flags |= 0x80;
  8783. ++        else
  8784. ++            default_drive_params[i].params.flags &= ~0x80;
  8785. ++    }
  8786. ++    DPRINT("Configuring drives for inverted dcl\n");
  8787. ++}
  8788. ++
  8789. ++static void daring(int *ints,int param)
  8790. + {
  8791. +     int i;
  8792. ++    for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
  8793. ++        if (param){
  8794. ++            default_drive_params[i].params.select_delay = 0;
  8795. ++            default_drive_params[i].params.flags |= FD_SILENT_DCL_CLEAR;
  8796. ++        } else {
  8797. ++            default_drive_params[i].params.select_delay = 2*HZ/100;
  8798. ++            default_drive_params[i].params.flags &= ~FD_SILENT_DCL_CLEAR;
  8799. ++        }
  8800. ++    }
  8801. ++    DPRINT1("Assuming %s floppy hardware\n", param ? "standard" : "broken");
  8802. ++}
  8803. ++
  8804. ++static void allow_drives(int *ints, int param)
  8805. ++{
  8806. ++    ALLOWED_DRIVE_MASK=param;
  8807. ++    DPRINT1("setting allowed_drive_mask to 0x%x\n", param);
  8808. ++}
  8809. ++
  8810. ++static void fdc2_adr(int *ints, int param)
  8811. ++{
  8812. ++    FDC2 = param;
  8813. ++    if(param)
  8814. ++        DPRINT1("enabling second fdc at address 0x%3x\n", FDC2);
  8815. ++    else
  8816. ++        DPRINT("disabling second fdc\n");
  8817. ++}
  8818. ++
  8819. ++static void unex(int *ints,int param)
  8820. ++{
  8821. ++    print_unex = param;
  8822. ++    DPRINT1("%sprinting messages for unexpected interrupts\n",
  8823. ++        param ? "" : "not ");
  8824. ++}
  8825. ++
  8826. ++static void set_cmos(int *ints, int dummy)
  8827. ++{
  8828. ++    int current_drive=0;
  8829. ++
  8830. ++    if ( ints[0] != 2 ){
  8831. ++        DPRINT("wrong number of parameter for cmos\n");
  8832. ++        return;
  8833. ++    }
  8834. ++    current_drive = ints[1];
  8835. ++    if (current_drive < 0 || current_drive >= 8 ){
  8836. ++        DPRINT("bad drive for set_cmos\n");
  8837. ++        return;
  8838. ++    }
  8839. ++    if(ints[2] <= 0 || ints[2] >= NUMBER(default_drive_params)){
  8840. ++        DPRINT1("bad cmos code %d\n", ints[2]);
  8841. ++        return;
  8842. ++    }
  8843. ++    DP->cmos = ints[2];
  8844. ++    DPRINT1("setting cmos code to %d\n", ints[2]);
  8845. ++}
  8846. ++        
  8847. ++static struct param_table {
  8848. ++    char *name;
  8849. ++    void (*fn)(int *ints, int param);
  8850. ++    int def_param;
  8851. ++} config_params[]={
  8852. ++{ "allowed_drive_mask", allow_drives, 0xff },
  8853. ++{ "all_drives", allow_drives, 0xff },
  8854. ++{ "asus_pci", allow_drives, 0x33 },
  8855. ++
  8856. ++{ "daring", daring, 1},
  8857. ++
  8858. ++{ "two_fdc", fdc2_adr, 0x370 },
  8859. ++{ "one_fdc", fdc2_adr, 0 },
  8860. ++
  8861. ++{ "thinkpad", floppy_invert_dcl, 1 },
  8862. ++
  8863. ++{ "cmos", set_cmos, 0 },
  8864. ++
  8865. ++{ "unexpected_interrupts", unex, 1 },
  8866. ++{ "no_unexpected_interrupts", unex, 0 },
  8867. ++{ "L40SX", unex, 0 } };
  8868. ++
  8869. ++#define FLOPPY_SETUP
  8870. ++void floppy_setup(char *str, int *ints)
  8871. ++{
  8872. ++    int i;
  8873. ++    int param;
  8874. ++    if(!str)
  8875. ++        return;
  8876. ++    for(i=0; i< ARRAY_SIZE(config_params); i++){
  8877. ++        if (strcmp(str,config_params[i].name) == 0 ){
  8878. ++            if (ints[0] )
  8879. ++                param = ints[1];
  8880. ++            else
  8881. ++                param = config_params[i].def_param;
  8882. ++            config_params[i].fn(ints,param);
  8883. ++            return;
  8884. ++        }
  8885. ++    }
  8886. ++    DPRINT1("unknown floppy option %s\n", str);
  8887. ++    DPRINT("allowed options are:");
  8888. ++    for(i=0; i< ARRAY_SIZE(config_params); i++)
  8889. ++        printk(" %s",config_params[i].name);
  8890. ++    printk("\n");
  8891. ++    DPRINT("Read linux/drivers/block/README.fd\n");
  8892. ++}
  8893. ++
  8894. ++#ifdef FD_MODULE
  8895. ++static
  8896. ++#endif
  8897. ++int new_floppy_init(void)
  8898. ++{
  8899. ++    int i,drive;
  8900. ++    int have_no_fdc=0;
  8901. ++
  8902. +     sti();
  8903. +     if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
  8904. +         printk("Unable to get major %d for floppy\n",MAJOR_NR);
  8905. +-        return;
  8906. ++        return -EBUSY;
  8907. +     }
  8908. +     for(i=0; i<256; i++)
  8909. +@@ -3114,55 +3375,63 @@
  8910. +             floppy_sizes[i] = MAX_DISK_SIZE;
  8911. +     blk_size[MAJOR_NR] = floppy_sizes;
  8912. ++    blksize_size[MAJOR_NR] = floppy_blocksizes;
  8913. +     blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  8914. +-    hardsect_size[MAJOR_NR] = fd_sectsizes;
  8915. +-    timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
  8916. +-    timer_active &= ~(1 << FLOPPY_TIMER);
  8917. ++    del_timer(&fd_timeout);
  8918. +     config_types();
  8919. +-    for(i = 0; i<256; i++)
  8920. +-        fd_sectsizes[i] = 1024;            /* patch for msdos driver */
  8921. +-
  8922. +-    fdc_state[0].address = 0x3f0;
  8923. ++    fdc_state[0].address = FDC1;
  8924. ++    fdc_state[0].dor = 0;
  8925. + #if N_FDC > 1
  8926. +-    fdc_state[1].address = 0x370;
  8927. ++    fdc_state[1].address = FDC2;
  8928. ++    fdc_state[1].dor = 0;
  8929. + #endif
  8930. ++
  8931. +     for (i = 0 ; i < N_FDC ; i++) {
  8932. +         fdc = i;
  8933. +         FDCS->dtr = -1;
  8934. +-        FDCS->dor = 0;
  8935. ++        FDCS->dor = 0x4;
  8936. +         FDCS->reset = 0;
  8937. +         FDCS->version = FDC_NONE;
  8938. +-        set_dor(fdc, ~0, 0xc );
  8939. ++    }
  8940. ++
  8941. ++    if(floppy_grab_irq_and_dma()){
  8942. ++        unregister_blkdev(MAJOR_NR,"fd");
  8943. ++        return -EBUSY;
  8944. +     }
  8945. +     /* initialise drive state */
  8946. +-    for (i = 0; i < N_DRIVE ; i++) {
  8947. +-        current_drive = i;
  8948. +-        DRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE;
  8949. +-        DRS->generation = 0;
  8950. +-        DRS->keep_data = 0;
  8951. +-        DRS->fd_ref = 0;
  8952. +-        DRS->fd_device = 0;
  8953. +-        DRWE->write_errors = 0;
  8954. +-        DRWE->first_error_sector = 0;
  8955. +-        DRWE->first_error_generation = 0;
  8956. +-        DRWE->last_error_sector = 0;
  8957. +-        DRWE->last_error_generation = 0;
  8958. +-        DRWE->badness = 0;
  8959. ++    for (drive = 0; drive < N_DRIVE ; drive++) {
  8960. ++        UDRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE | FD_DISK_CHANGED;
  8961. ++        UDRS->generation = 0;
  8962. ++        UDRS->keep_data = 0;
  8963. ++        UDRS->fd_ref = 0;
  8964. ++        UDRS->fd_device = 0;
  8965. ++        UDRWE->write_errors = 0;
  8966. ++        UDRWE->first_error_sector = 0;
  8967. ++        UDRWE->first_error_generation = 0;
  8968. ++        UDRWE->last_error_sector = 0;
  8969. ++        UDRWE->last_error_generation = 0;
  8970. ++        UDRWE->badness = 0;
  8971. +     }
  8972. +-    floppy_grab_irq_and_dma();
  8973. +     for (i = 0 ; i < N_FDC ; i++) {
  8974. +         fdc = i;
  8975. ++        if (FDCS->address == -1 )
  8976. ++            continue;
  8977. +         FDCS->rawcmd = 2;
  8978. +-        if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0))
  8979. ++        if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0)){
  8980. ++            FDCS->address = -1;
  8981. +             continue;
  8982. ++        }
  8983. +         /* Try to determine the floppy controller type */
  8984. +         FDCS->version = get_fdc_version();
  8985. +-        if (FDCS->version == FDC_NONE)
  8986. ++        if (FDCS->version == FDC_NONE){
  8987. ++            FDCS->address = -1;
  8988. +             continue;
  8989. ++        }
  8990. ++        have_no_fdc = 0;
  8991. +         /* Not all FDCs seem to be able to handle the version command
  8992. +          * properly, so force a reset for the standard FDC clones,
  8993. +          * to avoid interrupt garbage.
  8994. +@@ -3174,6 +3443,15 @@
  8995. +     current_drive = 0;
  8996. +     floppy_release_irq_and_dma();
  8997. +     initialising=0;
  8998. ++    if(have_no_fdc)
  8999. ++        unregister_blkdev(MAJOR_NR,"fd");
  9000. ++    return have_no_fdc;
  9001. ++}
  9002. ++
  9003. ++/* stupid compatibility hack... */
  9004. ++void floppy_init(void)
  9005. ++{
  9006. ++    new_floppy_init();
  9007. + }
  9008. + static int floppy_grab_irq_and_dma(void)
  9009. +@@ -3185,13 +3463,17 @@
  9010. +         return 0;
  9011. +     }
  9012. +     sti();
  9013. +-
  9014. ++#ifdef FD_MODULE
  9015. ++    MOD_INC_USE_COUNT;
  9016. ++#endif
  9017. +     for(i=0; i< N_FDC; i++){
  9018. +-        fdc = i;
  9019. +-        reset_fdc_info(1);
  9020. +-        arm_set_dor(FDCS->dor);
  9021. ++        if(FDCS->address != -1){    
  9022. ++            fdc = i;
  9023. ++            reset_fdc_info(1);
  9024. ++            outb_p(FDCS->dor, FD_DOR);
  9025. ++        }
  9026. +     }
  9027. +-    set_dor(0, ~0, 8); /* avoid immediate interrupt */
  9028. ++    set_dor(0, ~0, 8);  /* avoid immediate interrupt */
  9029. +     if (request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT, "floppy")) {
  9030. +         DPRINT1("Unable to grab IRQ%d for the floppy driver\n",
  9031. +@@ -3204,24 +3486,49 @@
  9032. +         free_irq(FLOPPY_IRQ);
  9033. +         return -1;
  9034. +     }
  9035. ++    for(fdc = 0; fdc < N_FDC ; fdc++)
  9036. ++        if(FDCS->address != -1)
  9037. ++            outb_p(FDCS->dor, FD_DOR);
  9038. ++    fdc = 0;
  9039. +     enable_irq(FLOPPY_IRQ);
  9040. +     return 0;
  9041. + }
  9042. + static void floppy_release_irq_and_dma(void)
  9043. + {
  9044. +-    int i;
  9045. ++#ifdef CONFIG_FLOPPY_SANITY
  9046. ++    int drive;
  9047. ++#endif
  9048. +     cli();
  9049. +     if (--usage_count){
  9050. +         sti();
  9051. +         return;
  9052. +     }
  9053. +     sti();
  9054. ++#ifdef FD_MODULE
  9055. ++    MOD_DEC_USE_COUNT;
  9056. ++#endif
  9057. +     disable_dma(FLOPPY_DMA);
  9058. +     free_dma(FLOPPY_DMA);
  9059. +     disable_irq(FLOPPY_IRQ);
  9060. +     free_irq(FLOPPY_IRQ);
  9061. +-    /* switch off dma gates */
  9062. +-    for(i=0; i< N_FDC; i++)
  9063. +-        set_dor(i, ~8, 0);
  9064. ++
  9065. ++    set_dor(0, ~0, 8);
  9066. ++#if N_FDC > 1
  9067. ++    set_dor(1, ~8, 0);
  9068. ++#endif
  9069. ++    floppy_enable_hlt();
  9070. ++#ifdef CONFIG_FLOPPY_SANITY
  9071. ++    for(drive=0; drive < N_FDC * 4; drive++)
  9072. ++        if( motor_off_timer[drive].next )
  9073. ++            printk("motor off timer %d still active\n", drive);
  9074. ++    
  9075. ++    if(fd_timeout.next)
  9076. ++        printk("floppy timer still active\n");
  9077. ++    if (fd_timer.next)
  9078. ++        printk("auxiliary floppy timer still active\n");
  9079. ++    if(floppy_tq.sync)
  9080. ++        printk("task queue still active\n");
  9081. ++#endif
  9082. + }
  9083. ++
  9084. diff -r -u -N linux.orig/arch/arm/drivers/block/hdsrch.c linux.arm/arch/arm/drivers/block/hdsrch.c
  9085. --- linux.orig/arch/arm/drivers/block/hdsrch.c    Thu Jan  1 01:00:00 1970
  9086. +++ linux.arm/arch/arm/drivers/block/hdsrch.c    Fri Oct 27 23:14:44 1995
  9087. @@ -0,0 +1,654 @@
  9088. +#include <linux/config.h>
  9089. +#include <linux/ctype.h>
  9090. +#include <linux/kernel.h>
  9091. +#include <linux/mm.h>
  9092. +#include <linux/malloc.h>
  9093. +#include <linux/string.h>
  9094. +#include <linux/genhd.h>
  9095. +
  9096. +#pragma no_check_stack
  9097. +
  9098. +#define RECSIZE 60
  9099. +
  9100. +#define MAX_BLK_FRAGS 64
  9101. +
  9102. +struct boot_block
  9103. +{
  9104. +  unsigned char  log2secsize;
  9105. +  unsigned char  secspertrack;
  9106. +  unsigned char  heads;
  9107. +  unsigned char  density;
  9108. +  unsigned char  idlen;
  9109. +  unsigned char  log2bpmb;
  9110. +  unsigned char  shew;
  9111. +  unsigned char  bootoption;
  9112. +  unsigned char  lowsector;
  9113. +  unsigned char  nzones;
  9114. +  unsigned short zone_spare;
  9115. +  unsigned long  root;
  9116. +  unsigned long  disc_size;
  9117. +  unsigned short disc_id;
  9118. +  unsigned char  disc_name[32-22];
  9119. +  unsigned long  disctype;
  9120. +};
  9121. +
  9122. +static struct boot_block *boot=NULL;
  9123. +static unsigned int zonesize;
  9124. +static unsigned int idsperzone;
  9125. +static long rootaddr;
  9126. +static long mapaddr;
  9127. +static long maplen;
  9128. +static void *map=NULL;
  9129. +#if 0
  9130. +static long *pages=NULL;
  9131. +#endif
  9132. +static char ignoring;
  9133. +
  9134. +static int read_sectors(int dev,void *ptr,long address,int size)
  9135. +{
  9136. +  struct buffer_head *bh;
  9137. +  char *p=ptr;
  9138. +  while(size>0)
  9139. +  {
  9140. +    if((bh=bread(dev,address/1024,1024)))
  9141. +    {
  9142. +      memcpy(p,bh->b_data+((address & 0x200)?512:0),(address & 0x200 || size<1024)?512:1024);
  9143. +      if(address & 0x200)
  9144. +        address-=0x200;
  9145. +    }
  9146. +    else
  9147. +    {
  9148. +      printk("hda%c: bread failed\n",'a'+((dev & 0xc0)>>6));
  9149. +      return 0;
  9150. +    }
  9151. +    brelse(bh);
  9152. +    p+=1024;
  9153. +    address+=1024;
  9154. +    size-=1024;
  9155. +  }
  9156. +  return 1;
  9157. +}
  9158. +
  9159. +/* + Read boot block at disc address &C00 (sector 6)
  9160. + * + Calculate map address & length
  9161. + */
  9162. +
  9163. +static int getdiskinfo(int dev)
  9164. +{
  9165. +  char *ptr;
  9166. +  extern void set_hdinfo(int,unsigned char,unsigned char,unsigned long,unsigned int);
  9167. +
  9168. +  if(boot)
  9169. +      return 1;
  9170. +
  9171. +  boot=(struct boot_block *)kmalloc(sizeof(struct boot_block),GFP_KERNEL);
  9172. +  if(!boot)
  9173. +  {
  9174. +    printk("hda%c: out of memory for bootblock\n",(dev>>6)+'a');
  9175. +    return 0;
  9176. +  }
  9177. +
  9178. +  ptr=(char *)kmalloc(1024,GFP_KERNEL);
  9179. +  if(!ptr)
  9180. +  {
  9181. +    printk("hda%c: out of memory for bootblock\n",(dev>>6)+'a');
  9182. +    return 0;
  9183. +  }
  9184. +
  9185. +  if(!read_sectors(dev,ptr,0xC00,1024))
  9186. +  {
  9187. +    kfree_s(ptr,1024);
  9188. +    return 0;
  9189. +  }
  9190. +  memcpy(boot,(ptr+0x1C0),sizeof(struct boot_block));
  9191. +  kfree_s(ptr,1024);
  9192. +
  9193. +  set_hdinfo(dev,boot->secspertrack,boot->heads,boot->disc_size,1<<boot->log2secsize);
  9194. +
  9195. +  zonesize=(8<<boot->log2secsize)-boot->zone_spare;
  9196. +  idsperzone=zonesize/(boot->idlen+1);
  9197. +  mapaddr=((boot->nzones>>1)*zonesize-((boot->nzones>1)?RECSIZE*8:0))<<boot->log2bpmb;
  9198. +  maplen=boot->nzones<<boot->log2secsize;
  9199. +  return 1;
  9200. +}
  9201. +
  9202. +static unsigned char map_cross_valid_byte(void)
  9203. +{
  9204. +  unsigned char const *const map_base=map;
  9205. +  unsigned int check=0;
  9206. +  unsigned int i;
  9207. +
  9208. +  for(i=0;i<boot->nzones;i++)
  9209. +    check^=map_base[(i<<boot->log2secsize)+3];
  9210. +
  9211. +  return check;
  9212. +}
  9213. +
  9214. +static int get_map(int dev)
  9215. +{
  9216. +  if(!getdiskinfo(dev))
  9217. +    return 0;
  9218. +
  9219. +  if(map)
  9220. +    return 1;
  9221. +
  9222. +  map = (unsigned long *)vmalloc(maplen);
  9223. +  if(!map)
  9224. +    return 0;
  9225. +
  9226. +  if(!read_sectors(dev,map,mapaddr,maplen))
  9227. +    return 0;
  9228. +  if(map_cross_valid_byte()!=0xFF)
  9229. +  {
  9230. +    printk("Map 1 has invalid cross check - trying second map\n");
  9231. +    if(!read_sectors(dev,map,mapaddr+maplen,maplen))
  9232. +      return 0;
  9233. +    if(map_cross_valid_byte()!=0xFF)
  9234. +    {
  9235. +      printk("Map 2 has invalid cross check - ignoring drive\n");
  9236. +      ignoring=dev;
  9237. +      return 0;
  9238. +    }
  9239. +  }
  9240. +
  9241. +  memcpy(boot,(char*)map+4,sizeof(struct boot_block));
  9242. +
  9243. +  rootaddr=mapaddr+2*maplen;
  9244. +  return 1;
  9245. +}
  9246. +
  9247. +static int readmap(int sin,int *fzone,int *fstart,int *fend,int max_frags)
  9248. +{
  9249. +    static int startzone;    /* Start zone             */
  9250. +    static int fragment;    /* Fragment id to look for     */
  9251. +    static int curzone;    /* Current zone             */
  9252. +    static int curmapp;    /* Current map bit position     */
  9253. +  
  9254. +    register unsigned int t,z,frag,czone,cmap;
  9255. +    register unsigned char const *mapaddr;
  9256. +    register int *fz,*fs,*fe;
  9257. +    register unsigned char n;
  9258. +    
  9259. +  
  9260. +    if(sin)
  9261. +    {/* If we have new address, start from new position */
  9262. +        fragment = sin >> 8;
  9263. +        curzone = startzone = fragment / idsperzone;
  9264. +        curmapp=0;
  9265. +    }
  9266. +    if(curzone == -1)
  9267. +        return 0;
  9268. +    frag = fragment;
  9269. +    czone = curzone;
  9270. +    cmap = curmapp;
  9271. +    fz = fzone;
  9272. +    fs = fstart;
  9273. +    fe = fend;
  9274. +
  9275. +/*   printk("readmap: internal_address: %p, fragment: %p, zone: %p\n",sin,frag, */
  9276. +/*     czone); */
  9277. +
  9278. +    while(1)
  9279. +    {
  9280. +        mapaddr=(unsigned char const *)map+
  9281. +                (czone<<boot->log2secsize)+4+((czone==0)?RECSIZE:0);
  9282. +        while(cmap<zonesize-((czone==0)?RECSIZE*8:0))/* ? */
  9283. +        {
  9284. +            *fs=cmap;
  9285. +            z=cmap>>3;
  9286. +            t=((mapaddr[z]|(mapaddr[z+1]<<8)|(mapaddr[z+2]<<16))>>(cmap & 7)) &
  9287. +                ((1<<boot->idlen)-1);
  9288. +            cmap+=boot->idlen;
  9289. +            
  9290. +            while((cmap & 7)!=0 && (mapaddr[cmap>>3] & (1<<(cmap & 7)))==0)
  9291. +                cmap+=1;
  9292. +
  9293. +            while((n=mapaddr[cmap>>3]) == 0)
  9294. +                cmap+=8;
  9295. +
  9296. +            while((n & (1<<(cmap & 7)))==0)
  9297. +                cmap+=1;
  9298. +            cmap+=1;
  9299. +            if(t==frag)
  9300. +            {
  9301. +                *fz++=czone;
  9302. +                *fe++=cmap;
  9303. +                fs++;
  9304. +                if(!--max_frags)
  9305. +                {
  9306. +/*                     printf("Breaking out\n"); */
  9307. +                    curmapp = cmap;
  9308. +                    curzone = czone;
  9309. +                    return fs - fstart;
  9310. +                }
  9311. +            }
  9312. +        }
  9313. +        czone+=1;
  9314. +        if(czone==boot->nzones)
  9315. +            czone=0;
  9316. +        if(czone==startzone)
  9317. +            break;
  9318. +        cmap=0;
  9319. +    }
  9320. +    curzone = -1;
  9321. +    return fs - fstart;
  9322. +}
  9323. +
  9324. +static unsigned long calcaddr(int zone,int offset)
  9325. +{
  9326. +  if(zone)
  9327. +    return (zone*zonesize-RECSIZE*8+offset)<<boot->log2bpmb;
  9328. +  else
  9329. +    return offset<<boot->log2bpmb;
  9330. +}
  9331. +
  9332. +static void scan_name(char *name,int len)
  9333. +{
  9334. +  int i;
  9335. +  for(i=0;i<len+1;i++)
  9336. +  {
  9337. +    if(name[i]<32 || name[i]=='.' || i==len)
  9338. +    {
  9339. +      name[i]=0;
  9340. +      break;
  9341. +    }
  9342. +    if(islower(name[i]))
  9343. +      name[i]=toupper(name[i]);
  9344. +  }
  9345. +}
  9346. +
  9347. +static unsigned long scandir(int dev,unsigned long diraddress,char *file,int *type,
  9348. +       unsigned long *length)
  9349. +{
  9350. +  unsigned char *dir;
  9351. +  unsigned char *dd;
  9352. +  unsigned long addr;
  9353. +
  9354. +  scan_name(file,10);
  9355. +
  9356. +  dir=(unsigned char *)kmalloc(2048,GFP_KERNEL);
  9357. +
  9358. +  read_sectors(dev,dir,diraddress,2048);
  9359. +
  9360. +  if(strncmp((char*)dir+1,"Nick",4)!=0 && strncmp((char*)dir+1,"Hugo",4)!=0)
  9361. +  {
  9362. +    printk("Broken directory - skipping\n");
  9363. +    return 0;
  9364. +  }
  9365. +
  9366. +  dd=dir+5-26;
  9367. +  do
  9368. +  {
  9369. +    dd+=26;
  9370. +    scan_name((char*)dd,10);
  9371. +    if(strcmp(file,(char*)dd)==0)
  9372. +      break;
  9373. +  }
  9374. +  while(*dd!=0);
  9375. +  if(*dd==0)
  9376. +    return 0;
  9377. +  else
  9378. +  if(dd[25] & 8)
  9379. +    *type=0;
  9380. +  *length=(unsigned long)dd[18]|(dd[19]<<8)|(dd[20]<<16)|(dd[21]<<24);
  9381. +  addr=(unsigned long)dd[22]|(dd[23]<<8)|(dd[24]<<16);
  9382. +
  9383. +  kfree_s(dir,2048);
  9384. +
  9385. +  return addr;
  9386. +}
  9387. +
  9388. +static int search_path(int dev,char *path,unsigned long *start,unsigned long *length, int maxbits)
  9389. +{
  9390. +  unsigned long dir,iad,len;
  9391. +  int type,i,n,fzones[MAX_BLK_FRAGS],fstart[MAX_BLK_FRAGS],fend[MAX_BLK_FRAGS];
  9392. +  char *p;
  9393. +
  9394. +/*   p=strchr(path,':'); */
  9395. +/*   if(p!=NULL) */
  9396. +/*   { */
  9397. +/*     drive=p[1]-'0'; */
  9398. +/*     if(drive<4 || drive>5) */
  9399. +/*       return 0; */
  9400. +/*     p=strchr(p,'.'); */
  9401. +/*     if(p==NULL) */
  9402. +/*       return 0; */
  9403. +/*     path=p+1; */
  9404. +/*   } */
  9405. +  if(!get_map(dev))
  9406. +    return 0;
  9407. +
  9408. +  dir=rootaddr;
  9409. +  while(path)
  9410. +  {
  9411. +    type=1;
  9412. +    p=strchr(path,'.');
  9413. +    if(p!=NULL)
  9414. +    {
  9415. +      p[0]=0;
  9416. +    }
  9417. +    if(path[0]!='\0')
  9418. +    {
  9419. +      iad=scandir(dev,dir,path,&type,&len);
  9420. +      if(iad==0)
  9421. +      {
  9422. +        printk("%s '%s' not found - skipping\n",p==NULL?"File":"Directory",path);
  9423. +        return 0;
  9424. +      }
  9425. +      if(type==0)
  9426. +      {
  9427. +        n=readmap(iad,fzones,fstart,fend,1);
  9428. +        dir=calcaddr(fzones[0],fstart[0]);
  9429. +      }
  9430. +      else
  9431. +      if(p!=NULL)
  9432. +      {
  9433. +        printk("'%s' is a directory - skipping\n",path);
  9434. +        return 0;
  9435. +      }
  9436. +      else
  9437. +      {
  9438. +        int j=0;
  9439. +        unsigned int secoff;
  9440. +        secoff=(iad & 0xFF)?(unsigned int)((iad & 0xFF)-1)<<boot->log2secsize:0;
  9441. +        len=((len-1)|((1<<boot->log2secsize)-1))+1;
  9442. +        n=readmap(iad,fzones,fstart,fend,MAX_BLK_FRAGS); /* Handle 64 entries at a time */
  9443. +        do
  9444. +        {
  9445. +          for(i=0;i<n;i++)
  9446. +          {
  9447. +            start[j]=calcaddr(fzones[i],fstart[i]);
  9448. +            length[j]=calcaddr(fzones[i],fend[i])-start[j];
  9449. +            if(secoff!=0)
  9450. +            {
  9451. +              if(length[j]>secoff)
  9452. +              {
  9453. +                start[j]+=secoff;
  9454. +                length[j]-=secoff;
  9455. +                secoff=0;
  9456. +              }
  9457. +              else
  9458. +              {
  9459. +                secoff-=length[j];
  9460. +                continue;
  9461. +              }
  9462. +            }
  9463. +        
  9464. +            if(j > 0 && start[j]==(start[j-1]+length[j-1]))
  9465. +            {/* Combine parts */
  9466. +              len += length[j-1];
  9467. +              length[j-1]+=length[j];
  9468. +              j--;
  9469. +            }
  9470. +        
  9471. +            if(length[j]>len)
  9472. +            {
  9473. +              length[j]=len;
  9474. +              j++;
  9475. +              break;
  9476. +            }
  9477. +            else
  9478. +              len-=length[j];
  9479. +            j++;
  9480. +            if(j >= maxbits)
  9481. +            {
  9482. +#ifdef NOT_YET_TESTED
  9483. +        unsigned long **sn,**ln;
  9484. +        sn=(unsigned long*)kmalloc(maxbits+BLK_INCREMENT,GFP_KERNEL);
  9485. +        ln=(unsigned long*)kmalloc(maxbits+BLK_INCREMENT,GFP_KERNEL);
  9486. +        if(maxbits && start && length)
  9487. +        {
  9488. +          memcpy(sn,start,maxbits);
  9489. +          memcpy(ln,length,maxbits);
  9490. +          kfree_s((void *)start, maxbits);
  9491. +          kfree_s((void *)length, maxbits);
  9492. +        }
  9493. +        maxbits+=BLK_INCREMENT;
  9494. +#else
  9495. +                printk("**** EEEK!!!! - Image file is in too many chunks!\n");
  9496. +                return 0;
  9497. +#endif
  9498. +            }
  9499. +          }
  9500. +        }
  9501. +        while((n=readmap(0,fzones,fstart,fend,MAX_BLK_FRAGS))>0);
  9502. +        return j;
  9503. +      }
  9504. +    }
  9505. +    if(p)
  9506. +    {
  9507. +      path=p+1;
  9508. +      p[0]='.';
  9509. +    }
  9510. +    else
  9511. +      path=0;
  9512. +  }
  9513. +  printk("Pathname invalid?!?\n");
  9514. +  return 0;
  9515. +}
  9516. +
  9517. +#define MAX_HD_IMAGES    8
  9518. +#define TWO_HDS
  9519. +#define MAX_HD_BITS    128
  9520. +
  9521. +static int initialised[MAX_HD_IMAGES];
  9522. +static int maxblock[MAX_HD_IMAGES];
  9523. +static unsigned long startchk[MAX_HD_IMAGES],lengthchk[MAX_HD_IMAGES];
  9524. +#ifndef NOT_YET_TESTED
  9525. +static unsigned long startaddr[MAX_HD_IMAGES][MAX_HD_BITS],
  9526. +            lengthaddr[MAX_HD_IMAGES][MAX_HD_BITS];
  9527. +#else
  9528. +static unsigned long *startaddr[MAX_HD_IMAGES],
  9529. +                    *lengthaddr[MAX_HD_IMAGES];
  9530. +#endif
  9531. +
  9532. +/* --------------------------------------------------------------------------------- */
  9533. +/*  Externally visible functions/variables
  9534. + * --------------------------------------------------------------------------------- */
  9535. +
  9536. +char arc_hd_files[MAX_HD_IMAGES][128]=
  9537. +{
  9538. +  {0,},
  9539. +  {0,},
  9540. +  {0,},
  9541. +  {0,}
  9542. +};
  9543. +
  9544. +/*
  9545. + * Get the sectors used by device 'dev'
  9546. + */
  9547. +int image_allocate_list(int dev,int devno,struct hd_struct *part)
  9548. +{
  9549. +    unsigned long chk1=0,chk2=0;
  9550. +    int i,sects=0;
  9551. +
  9552. +#ifndef TWO_HDS
  9553. +    if(dev!=0x300)
  9554. +    {
  9555. +        printk("Can't cope with >1 hd!\n");
  9556. +        return 0;
  9557. +    }
  9558. +#else
  9559. +    if(dev!=0x300 && dev!=0x340)
  9560. +    {
  9561. +        printk("Can't cope with >2 hds! (device %02X:%02X)\n",dev>>8,dev & 255);
  9562. +        return 0;
  9563. +    }
  9564. +    if(dev == 0x340)
  9565. +      devno=(devno & 0x3f) + 4;
  9566. +#endif
  9567. +
  9568. +    if(ignoring==dev)
  9569. +        return 0;
  9570. +
  9571. +    devno--;
  9572. +
  9573. +    if(devno > MAX_HD_IMAGES)
  9574. +        return 0;
  9575. +
  9576. +    if(!arc_hd_files[devno][0])
  9577. +        return 0;
  9578. +
  9579. +#ifndef NOT_YET_TESTED
  9580. +    maxblock[devno]=search_path(dev,arc_hd_files[devno],startaddr[devno],lengthaddr[devno],MAX_HD_BITS);
  9581. +#else
  9582. +    maxblock[devno]=search_path(dev,arc_hd_files[devno],startaddr[devno],lengthaddr[devno],0);
  9583. +#endif
  9584. +    if(maxblock[devno]>MAX_HD_BITS)
  9585. +        panic("image allocator: image file is too fragmented\n");
  9586. +    if(!maxblock[devno])
  9587. +        return 0;
  9588. +
  9589. +    for(i=0; i<maxblock[devno]; i++)
  9590. +    {
  9591. +        /* convert to blocks & calculate checksums */
  9592. +#define ADDR2BLOCK(x) ((x)>>9)
  9593. +        startaddr[devno][i]=ADDR2BLOCK(startaddr[devno][i]);
  9594. +        lengthaddr[devno][i]=ADDR2BLOCK(lengthaddr[devno][i]);
  9595. +        chk1^=startaddr[devno][i];
  9596. +        chk2^=lengthaddr[devno][i];
  9597. +        sects+=lengthaddr[devno][i];
  9598. +    }
  9599. +    startchk[devno]=chk1;
  9600. +    lengthchk[devno]=chk2;
  9601. +    initialised[devno]=1;
  9602. +    part->start_sect=0;
  9603. +    part->nr_sects=sects;
  9604. +
  9605. +#ifdef DEBUG
  9606. +    for(i=0;i<n;i++)
  9607. +        printk("%10X : %10X\n",start[devno][i],length[devno][i]);
  9608. +#endif
  9609. +    return 1;
  9610. +}
  9611. +
  9612. +/*
  9613. + * This is called to release all the memory with this device
  9614. + *
  9615. + * This must be called before accessing a new device
  9616. + */
  9617. +
  9618. +void image_release_dev(int dev)
  9619. +{
  9620. +  if(boot)
  9621. +  {
  9622. +    kfree_s(boot,sizeof(struct boot_block));
  9623. +    boot=NULL;
  9624. +  }
  9625. +
  9626. +  if(map)
  9627. +  {
  9628. +    vfree(map);
  9629. +    map = NULL;
  9630. +  }
  9631. +
  9632. +  ignoring=0;
  9633. +}
  9634. +
  9635. +/* 
  9636. + * This macro maps a device major/minor to the internal image file number
  9637. + */
  9638. +#ifndef TWO_HDS
  9639. +#define GET_DEV(dev) \
  9640. +    if((dev)<0x301 || (dev)>0x314) \
  9641. +    { \
  9642. +        printk("Bad device %X passed to image_file_check\n",(dev)); \
  9643. +        return 0; \
  9644. +    } \
  9645. +    (dev)=((dev)-1) & 3;
  9646. +#else
  9647. +#define GET_DEV(dev) \
  9648. +    if(((dev) & 0x33F)<0x301 || ((dev) & 0x33F)>0x314) \
  9649. +    { \
  9650. +        printk("Bad device %X passed to image_file_check\n",(dev)); \
  9651. +        return 0; \
  9652. +    } \
  9653. +    switch((dev) & 0xC0) \
  9654. +    { \
  9655. +        case 0x00: (dev)=((dev) -1) & 3;     break;\
  9656. +        case 0x40: (dev)=(((dev) -1) & 3)+4; break;\
  9657. +    }
  9658. +#endif
  9659. +
  9660. +/* 
  9661. + * This function is called to perform checks on the image file.
  9662. + *  Checks made: Image file has been initialised, and
  9663. + *     for writes, the checksums on the start/length data are correct.
  9664. + */
  9665. +int image_file_check(int dev,int cmd)
  9666. +{
  9667. +    long chk1=0,chk2=0;
  9668. +    int i;
  9669. +
  9670. +    GET_DEV(dev);
  9671. +
  9672. +    if(!initialised[dev])
  9673. +    {
  9674. +        printk("hd%c%d: %s of uninitialised image file.\n",(dev>>6)+'a',dev & 0x3f,
  9675. +          cmd==WRITE?"write":"read");
  9676. +        return 0;
  9677. +    }
  9678. +
  9679. +    if(cmd==WRITE)
  9680. +    {
  9681. +/* Check the table! Just in case. We don't want to write to a part of the HD that
  9682. + * is not allocated to us! It might be the map or something!
  9683. + */
  9684. +        for(i=0; i<maxblock[dev]; i++)
  9685. +        {
  9686. +              chk1^=startaddr[dev][i];
  9687. +              chk2^=lengthaddr[dev][i];
  9688. +        }
  9689. +        if(chk1!=startchk[dev] || chk2!=lengthchk[dev])
  9690. +        {
  9691. +            printk("hda%c%d: mapping tables corrupted on write.",
  9692. +                (dev>>6)+'a',dev & 0x3f);
  9693. +            return 0;
  9694. +        }
  9695. +    }
  9696. +    return 1;
  9697. +}
  9698. +
  9699. +/*
  9700. + * Map an image file block to a physical device returns 0 on error,
  9701. + * or the number of entries.  This is called quite often when accessing
  9702. + * image files.
  9703. + */
  9704. +int image_file_map(int dev,unsigned long reqblock,unsigned long reqlength,
  9705. +            unsigned long max_reqs,
  9706. +                    unsigned long *block,unsigned long *length)
  9707. +{
  9708. +    int i,num=0;
  9709. +    unsigned long blk=reqblock,totlen=0;
  9710. +
  9711. +    GET_DEV(dev);
  9712. +
  9713. +    for(i=0; i<maxblock[dev]; i++)
  9714. +    {
  9715. +        long remainder;
  9716. +        totlen+=lengthaddr[dev][i];
  9717. +        if(reqblock >= lengthaddr[dev][i])
  9718. +        {
  9719. +            reqblock-=lengthaddr[dev][i];
  9720. +            continue;
  9721. +        }
  9722. +        block[num]=reqblock+startaddr[dev][i];
  9723. +        remainder=reqblock+reqlength-lengthaddr[dev][i];
  9724. +        if(remainder<=0)
  9725. +        {
  9726. +            length[num]=reqlength;
  9727. +            return num+1;
  9728. +        }
  9729. +        length[num]=lengthaddr[dev][i]-reqblock;
  9730. +        if(num+1 >= max_reqs)
  9731. +            return num+1;
  9732. +        reqblock=0;
  9733. +        reqlength=remainder;
  9734. +        num++;
  9735. +    }
  9736. +
  9737. +    printk("hd%c%d: attempted read for sector %ld past end if image file at %ld.\n",
  9738. +        (dev>>6)+'a',dev & 0x3f,blk,totlen);
  9739. +        /* Should never happen! */
  9740. +    return 0;
  9741. +}
  9742. diff -r -u -N linux.orig/arch/arm/drivers/block/ll_rw_blk.c linux.arm/arch/arm/drivers/block/ll_rw_blk.c
  9743. --- linux.orig/arch/arm/drivers/block/ll_rw_blk.c    Thu Jan  1 01:00:00 1970
  9744. +++ linux.arm/arch/arm/drivers/block/ll_rw_blk.c    Fri Oct 27 23:14:45 1995
  9745. @@ -0,0 +1,568 @@
  9746. +/*
  9747. + *  linux/drivers/block/ll_rw_blk.c
  9748. + *
  9749. + * Copyright (C) 1991, 1992 Linus Torvalds
  9750. + * Copyright (C) 1994,      Karl Keyte: Added support for disk statistics
  9751. + */
  9752. +
  9753. +/*
  9754. + * This handles all read/write requests to block devices
  9755. + */
  9756. +#include <linux/sched.h>
  9757. +#include <linux/kernel.h>
  9758. +#include <linux/kernel_stat.h>
  9759. +#include <linux/errno.h>
  9760. +#include <linux/string.h>
  9761. +#include <linux/config.h>
  9762. +#include <linux/locks.h>
  9763. +#include <linux/mm.h>
  9764. +
  9765. +#include <asm/system.h>
  9766. +#include <asm/io.h>
  9767. +#include "blk.h"
  9768. +
  9769. +/*
  9770. + * The request-struct contains all necessary data
  9771. + * to load a nr of sectors into memory
  9772. + */
  9773. +static struct request all_requests[NR_REQUEST];
  9774. +
  9775. +/*
  9776. + * used to wait on when there are no free requests
  9777. + */
  9778. +struct wait_queue * wait_for_request = NULL;
  9779. +
  9780. +/* This specifies how many sectors to read ahead on the disk.  */
  9781. +
  9782. +int read_ahead[MAX_BLKDEV] = {0, };
  9783. +
  9784. +/* blk_dev_struct is:
  9785. + *    do_request-address
  9786. + *    next-request
  9787. + */
  9788. +struct blk_dev_struct blk_dev[MAX_BLKDEV] = {
  9789. +    { NULL, NULL },        /* 0 no_dev */
  9790. +    { NULL, NULL },        /* 1 dev mem */
  9791. +    { NULL, NULL },        /* 2 dev fd */
  9792. +    { NULL, NULL },        /* 3 dev ide0 or hd */
  9793. +    { NULL, NULL },        /* 4 dev ttyx */
  9794. +    { NULL, NULL },        /* 5 dev tty */
  9795. +    { NULL, NULL },        /* 6 dev lp */
  9796. +    { NULL, NULL },        /* 7 dev pipes */
  9797. +    { NULL, NULL },        /* 8 dev sd */
  9798. +    { NULL, NULL },        /* 9 dev st */
  9799. +    { NULL, NULL },        /* 10 */
  9800. +    { NULL, NULL },        /* 11 */
  9801. +    { NULL, NULL },        /* 12 */
  9802. +    { NULL, NULL },        /* 13 */
  9803. +    { NULL, NULL },        /* 14 */
  9804. +    { NULL, NULL },        /* 15 */
  9805. +    { NULL, NULL },        /* 16 */
  9806. +    { NULL, NULL },        /* 17 */
  9807. +    { NULL, NULL },        /* 18 */
  9808. +    { NULL, NULL },        /* 19 */
  9809. +    { NULL, NULL },        /* 20 */
  9810. +    { NULL, NULL },        /* 21 */
  9811. +    { NULL, NULL }        /* 22 dev ide1 */
  9812. +};
  9813. +
  9814. +/*
  9815. + * blk_size contains the size of all block-devices in units of 1024 byte
  9816. + * sectors:
  9817. + *
  9818. + * blk_size[MAJOR][MINOR]
  9819. + *
  9820. + * if (!blk_size[MAJOR]) then no minor size checking is done.
  9821. + */
  9822. +int * blk_size[MAX_BLKDEV] = { NULL, NULL, };
  9823. +
  9824. +/*
  9825. + * blksize_size contains the size of all block-devices:
  9826. + *
  9827. + * blksize_size[MAJOR][MINOR]
  9828. + *
  9829. + * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
  9830. + */
  9831. +int * blksize_size[MAX_BLKDEV] = { NULL, NULL, };
  9832. +
  9833. +/*
  9834. + * hardsect_size contains the size of the hardware sector of a device.
  9835. + *
  9836. + * hardsect_size[MAJOR][MINOR]
  9837. + *
  9838. + * if (!hardsect_size[MAJOR])
  9839. + *        then 512 bytes is assumed.
  9840. + * else
  9841. + *        sector_size is hardsect_size[MAJOR][MINOR]
  9842. + * This is currently set by some scsi device and read by the msdos fs driver
  9843. + * This might be a some uses later.
  9844. + */
  9845. +int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
  9846. +
  9847. +/*
  9848. + * look for a free request in the first N entries.
  9849. + * NOTE: interrupts must be disabled on the way in, and will still
  9850. + *       be disabled on the way out.
  9851. + */
  9852. +static inline struct request * get_request(int n, int dev)
  9853. +{
  9854. +    static struct request *prev_found = NULL, *prev_limit = NULL;
  9855. +    register struct request *req, *limit;
  9856. +
  9857. +    if (n <= 0)
  9858. +        panic("get_request(%d): impossible!\n", n);
  9859. +
  9860. +    limit = all_requests + n;
  9861. +    if (limit != prev_limit) {
  9862. +        prev_limit = limit;
  9863. +        prev_found = all_requests;
  9864. +    }
  9865. +    req = prev_found;
  9866. +    for (;;) {
  9867. +        req = ((req > all_requests) ? req : limit) - 1;
  9868. +        if (req->dev < 0)
  9869. +            break;
  9870. +        if (req == prev_found)
  9871. +            return NULL;
  9872. +    }
  9873. +    prev_found = req;
  9874. +    req->dev = dev;
  9875. +    return req;
  9876. +}
  9877. +
  9878. +/*
  9879. + * wait until a free request in the first N entries is available.
  9880. + * NOTE: interrupts must be disabled on the way in, and will still
  9881. + *       be disabled on the way out.
  9882. + */
  9883. +static inline struct request * get_request_wait(int n, int dev)
  9884. +{
  9885. +    register struct request *req;
  9886. +
  9887. +    while ((req = get_request(n, dev)) == NULL)
  9888. +        sleep_on(&wait_for_request);
  9889. +    return req;
  9890. +}
  9891. +
  9892. +/* RO fail safe mechanism */
  9893. +
  9894. +static long ro_bits[MAX_BLKDEV][8];
  9895. +
  9896. +int is_read_only(int dev)
  9897. +{
  9898. +    int minor,major;
  9899. +
  9900. +    major = MAJOR(dev);
  9901. +    minor = MINOR(dev);
  9902. +    if (major < 0 || major >= MAX_BLKDEV) return 0;
  9903. +    return ro_bits[major][minor >> 5] & (1 << (minor & 31));
  9904. +}
  9905. +
  9906. +void set_device_ro(int dev,int flag)
  9907. +{
  9908. +    int minor,major;
  9909. +
  9910. +    major = MAJOR(dev);
  9911. +    minor = MINOR(dev);
  9912. +    if (major < 0 || major >= MAX_BLKDEV) return;
  9913. +    if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
  9914. +    else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
  9915. +}
  9916. +
  9917. +/*
  9918. + * add-request adds a request to the linked list.
  9919. + * It disables interrupts so that it can muck with the
  9920. + * request-lists in peace.
  9921. + */
  9922. +static void add_request(struct blk_dev_struct * dev, struct request * req)
  9923. +{
  9924. +    struct request * tmp;
  9925. +    short         disk_index;
  9926. +
  9927. +    switch (MAJOR(req->dev)) {
  9928. +        case SCSI_DISK_MAJOR:    disk_index = (MINOR(req->dev) & 0x0070) >> 4;
  9929. +                    if (disk_index < 4)
  9930. +                        kstat.dk_drive[disk_index]++;
  9931. +                    break;
  9932. +        case HD_MAJOR:
  9933. +        case XT_DISK_MAJOR:    disk_index = (MINOR(req->dev) & 0x0040) >> 6;
  9934. +                    kstat.dk_drive[disk_index]++;
  9935. +                    break;
  9936. +        case IDE1_MAJOR:    disk_index = ((MINOR(req->dev) & 0x0040) >> 6) + 2;
  9937. +                    kstat.dk_drive[disk_index]++;
  9938. +        default:        break;
  9939. +    }
  9940. +
  9941. +    req->next = NULL;
  9942. +    cli();
  9943. +    if (req->bh)
  9944. +        mark_buffer_clean(req->bh);
  9945. +    if (!(tmp = dev->current_request)) {
  9946. +        dev->current_request = req;
  9947. +        (dev->request_fn)();
  9948. +        sti();
  9949. +        return;
  9950. +    }
  9951. +    for ( ; tmp->next ; tmp = tmp->next) {
  9952. +        if ((IN_ORDER(tmp,req) ||
  9953. +            !IN_ORDER(tmp,tmp->next)) &&
  9954. +            IN_ORDER(req,tmp->next))
  9955. +            break;
  9956. +    }
  9957. +    req->next = tmp->next;
  9958. +    tmp->next = req;
  9959. +
  9960. +/* for SCSI devices, call request_fn unconditionally */
  9961. +    if (scsi_major(MAJOR(req->dev)))
  9962. +        (dev->request_fn)();
  9963. +
  9964. +    sti();
  9965. +}
  9966. +
  9967. +static void make_request(int major,int rw, struct buffer_head * bh)
  9968. +{
  9969. +    unsigned int sector, count;
  9970. +    struct request * req;
  9971. +    int rw_ahead, max_req;
  9972. +
  9973. +/* WRITEA/READA is special case - it is not really needed, so if the */
  9974. +/* buffer is locked, we just forget about it, else it's a normal read */
  9975. +    rw_ahead = (rw == READA || rw == WRITEA);
  9976. +    if (rw_ahead) {
  9977. +        if (bh->b_lock)
  9978. +            return;
  9979. +        if (rw == READA)
  9980. +            rw = READ;
  9981. +        else
  9982. +            rw = WRITE;
  9983. +    }
  9984. +    if (rw!=READ && rw!=WRITE) {
  9985. +        printk("Bad block dev command, must be R/W/RA/WA\n");
  9986. +        return;
  9987. +    }
  9988. +    count = bh->b_size >> 9;
  9989. +    sector = bh->b_blocknr * count;
  9990. +    if (blk_size[major])
  9991. +        if (blk_size[major][MINOR(bh->b_dev)] < (sector + count)>>1) {
  9992. +            bh->b_dirt = bh->b_uptodate = 0;
  9993. +            bh->b_req = 0;
  9994. +            return;
  9995. +        }
  9996. +    /* Uhhuh.. Nasty dead-lock possible here.. */
  9997. +    if (bh->b_lock)
  9998. +        return;
  9999. +    /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */
  10000. +    lock_buffer(bh);
  10001. +    if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {
  10002. +        unlock_buffer(bh);
  10003. +        return;
  10004. +    }
  10005. +
  10006. +/* we don't allow the write-requests to fill up the queue completely:
  10007. + * we want some room for reads: they take precedence. The last third
  10008. + * of the requests are only for reads.
  10009. + */
  10010. +    max_req = (rw == READ) ? NR_REQUEST : ((NR_REQUEST*2)/3);
  10011. +
  10012. +/* big loop: look for a free request. */
  10013. +
  10014. +repeat:
  10015. +    cli();
  10016. +
  10017. +/* The scsi disk drivers and the IDE driver completely remove the request
  10018. + * from the queue when they start processing an entry.  For this reason
  10019. + * it is safe to continue to add links to the top entry for those devices.
  10020. + */
  10021. +    if ((   major == IDE0_MAJOR    /* same as HD_MAJOR */
  10022. +         || major == IDE1_MAJOR
  10023. +         || major == FLOPPY_MAJOR
  10024. +         || major == SCSI_DISK_MAJOR
  10025. +         || major == SCSI_CDROM_MAJOR)
  10026. +        && (req = blk_dev[major].current_request))
  10027. +    {
  10028. +#ifdef CONFIG_BLK_DEV_HD
  10029. +            if (major == HD_MAJOR || major == FLOPPY_MAJOR)
  10030. +#else
  10031. +        if (major == FLOPPY_MAJOR)
  10032. +#endif CONFIG_BLK_DEV_HD
  10033. +            req = req->next;
  10034. +        while (req) {
  10035. +            if (req->dev == bh->b_dev &&
  10036. +                !req->sem &&
  10037. +                req->cmd == rw &&
  10038. +                req->sector + req->nr_sectors == sector &&
  10039. +                req->nr_sectors < 244)
  10040. +            {
  10041. +                req->bhtail->b_reqnext = bh;
  10042. +                req->bhtail = bh;
  10043. +                req->nr_sectors += count;
  10044. +                mark_buffer_clean(bh);
  10045. +                sti();
  10046. +                return;
  10047. +            }
  10048. +
  10049. +            if (req->dev == bh->b_dev &&
  10050. +                !req->sem &&
  10051. +                req->cmd == rw &&
  10052. +                req->sector - count == sector &&
  10053. +                req->nr_sectors < 244)
  10054. +            {
  10055. +                    req->nr_sectors += count;
  10056. +                    bh->b_reqnext = req->bh;
  10057. +                    req->buffer = bh->b_data;
  10058. +                    req->current_nr_sectors = count;
  10059. +                    req->sector = sector;
  10060. +                mark_buffer_clean(bh);
  10061. +                    req->bh = bh;
  10062. +                    sti();
  10063. +                    return;
  10064. +            }    
  10065. +
  10066. +            req = req->next;
  10067. +        }
  10068. +    }
  10069. +
  10070. +/* find an unused request. */
  10071. +    req = get_request(max_req, bh->b_dev);
  10072. +
  10073. +/* if no request available: if rw_ahead, forget it; otherwise try again. */
  10074. +    if (! req) {
  10075. +        if (rw_ahead) {
  10076. +            sti();
  10077. +            unlock_buffer(bh);
  10078. +            return;
  10079. +        }
  10080. +        sleep_on(&wait_for_request);
  10081. +        sti();
  10082. +        goto repeat;
  10083. +    }
  10084. +
  10085. +/* we found a request. */
  10086. +    sti();
  10087. +
  10088. +/* fill up the request-info, and add it to the queue */
  10089. +    req->cmd = rw;
  10090. +    req->errors = 0;
  10091. +    req->sector = sector;
  10092. +    req->nr_sectors = count;
  10093. +    req->current_nr_sectors = count;
  10094. +    req->buffer = bh->b_data;
  10095. +    req->sem = NULL;
  10096. +    req->bh = bh;
  10097. +    req->bhtail = bh;
  10098. +    req->next = NULL;
  10099. +    add_request(major+blk_dev,req);
  10100. +}
  10101. +
  10102. +void ll_rw_page(int rw, int dev, int page, char * buffer)
  10103. +{
  10104. +    struct request * req;
  10105. +    unsigned int major = MAJOR(dev);
  10106. +    struct semaphore sem = MUTEX_LOCKED;
  10107. +
  10108. +    if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
  10109. +        printk("Trying to read nonexistent block-device %04x (%d)\n",dev,page*8);
  10110. +        return;
  10111. +    }
  10112. +    if (rw!=READ && rw!=WRITE)
  10113. +        panic("Bad block dev command, must be R/W");
  10114. +    if (rw == WRITE && is_read_only(dev)) {
  10115. +        printk("Can't page to read-only device 0x%X\n",dev);
  10116. +        return;
  10117. +    }
  10118. +    cli();
  10119. +    req = get_request_wait(NR_REQUEST, dev);
  10120. +    sti();
  10121. +/* fill up the request-info, and add it to the queue */
  10122. +    req->cmd = rw;
  10123. +    req->errors = 0;
  10124. +    req->sector = page << (PAGE_SHIFT-9);
  10125. +    req->nr_sectors = 1 << (PAGE_SHIFT-9);
  10126. +    req->current_nr_sectors = 1 << (PAGE_SHIFT-9);
  10127. +    req->buffer = buffer;
  10128. +    req->sem = &sem;
  10129. +    req->bh = NULL;
  10130. +    req->next = NULL;
  10131. +    add_request(major+blk_dev,req);
  10132. +    down(&sem);
  10133. +}
  10134. +
  10135. +/* This function can be used to request a number of buffers from a block
  10136. +   device. Currently the only restriction is that all buffers must belong to
  10137. +   the same device */
  10138. +
  10139. +void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
  10140. +{
  10141. +    unsigned int major;
  10142. +    struct request plug;
  10143. +    int plugged;
  10144. +    int correct_size;
  10145. +    struct blk_dev_struct * dev;
  10146. +    int i;
  10147. +
  10148. +    /* Make sure that the first block contains something reasonable */
  10149. +    while (!*bh) {
  10150. +        bh++;
  10151. +        if (--nr <= 0)
  10152. +            return;
  10153. +    };
  10154. +
  10155. +    dev = NULL;
  10156. +    if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV)
  10157. +        dev = blk_dev + major;
  10158. +    if (!dev || !dev->request_fn) {
  10159. +        printk(
  10160. +    "ll_rw_block: Trying to read nonexistent block-device %04lX (%ld)\n",
  10161. +               (unsigned long) bh[0]->b_dev, bh[0]->b_blocknr);
  10162. +        goto sorry;
  10163. +    }
  10164. +
  10165. +    /* Determine correct block size for this device.  */
  10166. +    correct_size = BLOCK_SIZE;
  10167. +    if (blksize_size[major]) {
  10168. +        i = blksize_size[major][MINOR(bh[0]->b_dev)];
  10169. +        if (i)
  10170. +            correct_size = i;
  10171. +    }
  10172. +
  10173. +    /* Verify requested block sizes.  */
  10174. +    for (i = 0; i < nr; i++) {
  10175. +        if (bh[i] && bh[i]->b_size != correct_size) {
  10176. +            printk(
  10177. +            "ll_rw_block: only %d-char blocks implemented (%lu)\n",
  10178. +                   correct_size, bh[i]->b_size);
  10179. +            goto sorry;
  10180. +        }
  10181. +    }
  10182. +
  10183. +    if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) {
  10184. +        printk("Can't write to read-only device 0x%X\n",bh[0]->b_dev);
  10185. +        goto sorry;
  10186. +    }
  10187. +
  10188. +    /* If there are no pending requests for this device, then we insert
  10189. +       a dummy request for that device.  This will prevent the request
  10190. +       from starting until we have shoved all of the blocks into the
  10191. +       queue, and then we let it rip.  */
  10192. +
  10193. +    plugged = 0;
  10194. +    cli();
  10195. +    if (!dev->current_request && nr > 1) {
  10196. +        dev->current_request = &plug;
  10197. +        plug.dev = -1;
  10198. +        plug.next = NULL;
  10199. +        plugged = 1;
  10200. +    }
  10201. +    sti();
  10202. +    for (i = 0; i < nr; i++) {
  10203. +        if (bh[i]) {
  10204. +            bh[i]->b_req = 1;
  10205. +            make_request(major, rw, bh[i]);
  10206. +            if (rw == READ || rw == READA)
  10207. +                kstat.pgpgin++;
  10208. +            else
  10209. +                kstat.pgpgout++;
  10210. +        }
  10211. +    }
  10212. +    if (plugged) {
  10213. +        cli();
  10214. +        dev->current_request = plug.next;
  10215. +        (dev->request_fn)();
  10216. +        sti();
  10217. +    }
  10218. +    return;
  10219. +
  10220. +      sorry:
  10221. +    for (i = 0; i < nr; i++) {
  10222. +        if (bh[i])
  10223. +            bh[i]->b_dirt = bh[i]->b_uptodate = 0;
  10224. +    }
  10225. +    return;
  10226. +}
  10227. +
  10228. +void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
  10229. +{
  10230. +    int i;
  10231. +    int buffersize;
  10232. +    struct request * req;
  10233. +    unsigned int major = MAJOR(dev);
  10234. +    struct semaphore sem = MUTEX_LOCKED;
  10235. +
  10236. +    if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
  10237. +        printk("ll_rw_swap_file: trying to swap nonexistent block-device\n");
  10238. +        return;
  10239. +    }
  10240. +
  10241. +    if (rw!=READ && rw!=WRITE) {
  10242. +        printk("ll_rw_swap: bad block dev command, must be R/W");
  10243. +        return;
  10244. +    }
  10245. +    if (rw == WRITE && is_read_only(dev)) {
  10246. +        printk("Can't swap to read-only device 0x%X\n",dev);
  10247. +        return;
  10248. +    }
  10249. +    printk("ll_rw_swap: cannot swap to a swapfile!\n");
  10250. +
  10251. +    return;
  10252. +    buffersize = PAGE_SIZE / nb;
  10253. +
  10254. +    for (i=0; i<nb; i++, buf += buffersize)
  10255. +    {
  10256. +        cli();
  10257. +        req = get_request_wait(NR_REQUEST, dev);
  10258. +        sti();
  10259. +        req->cmd = rw;
  10260. +        req->errors = 0;
  10261. +        req->sector = (b[i] * buffersize) >> 9;
  10262. +        req->nr_sectors = buffersize >> 9;
  10263. +        req->current_nr_sectors = buffersize >> 9;
  10264. +        req->buffer = buf;
  10265. +        req->sem = &sem;
  10266. +        req->bh = NULL;
  10267. +        req->next = NULL;
  10268. +        add_request(major+blk_dev,req);
  10269. +        down(&sem);
  10270. +    }
  10271. +}
  10272. +
  10273. +long blk_dev_init(long mem_start, long mem_end)
  10274. +{
  10275. +    struct request * req;
  10276. +
  10277. +    req = all_requests + NR_REQUEST;
  10278. +    while (--req >= all_requests) {
  10279. +        req->dev = -1;
  10280. +        req->next = NULL;
  10281. +    }
  10282. +    memset(ro_bits,0,sizeof(ro_bits));
  10283. +#ifdef CONFIG_BLK_DEV_HD
  10284. +    mem_start = hd_init(mem_start,mem_end);
  10285. +#endif
  10286. +#ifdef CONFIG_BLK_DEV_IDE
  10287. +    mem_start = ide_init(mem_start,mem_end);
  10288. +#endif
  10289. +#ifdef CONFIG_BLK_DEV_XD
  10290. +    mem_start = xd_init(mem_start,mem_end);
  10291. +#endif
  10292. +#ifdef CONFIG_CDU31A
  10293. +    mem_start = cdu31a_init(mem_start,mem_end);
  10294. +#endif
  10295. +#ifdef CONFIG_CDU535
  10296. +    mem_start = sony535_init(mem_start,mem_end);
  10297. +#endif
  10298. +#ifdef CONFIG_MCD
  10299. +    mem_start = mcd_init(mem_start,mem_end);
  10300. +#endif
  10301. +#ifdef CONFIG_AZTCD
  10302. +        mem_start = aztcd_init(mem_start,mem_end);
  10303. +#endif
  10304. +#ifdef CONFIG_BLK_DEV_FD
  10305. +    floppy_init();
  10306. +#endif
  10307. +#ifdef CONFIG_SBPCD
  10308. +    mem_start = sbpcd_init(mem_start, mem_end);
  10309. +#endif CONFIG_SBPCD
  10310. +    if (ramdisk_size)
  10311. +        mem_start += rd_init(mem_start, ramdisk_size*1024);
  10312. +    return mem_start;
  10313. +}
  10314. diff -r -u -N linux.orig/arch/arm/drivers/block/ll_rw_blk.c.old linux.arm/arch/arm/drivers/block/ll_rw_blk.c.old
  10315. --- linux.orig/arch/arm/drivers/block/ll_rw_blk.c.old    Thu Jan  1 01:00:00 1970
  10316. +++ linux.arm/arch/arm/drivers/block/ll_rw_blk.c.old    Fri Oct 27 23:14:50 1995
  10317. @@ -0,0 +1,519 @@
  10318. +/*
  10319. + *  linux/drivers/block/ll_rw_blk.c
  10320. + *
  10321. + * Copyright (C) 1991, 1992 Linus Torvalds
  10322. + * Copyright (C) 1994,      Karl Keyte: Added support for disk statistics
  10323. + */
  10324. +
  10325. +/*
  10326. + * This handles all read/write requests to block devices
  10327. + */
  10328. +#include <linux/sched.h>
  10329. +#include <linux/kernel.h>
  10330. +#include <linux/kernel_stat.h>
  10331. +#include <linux/errno.h>
  10332. +#include <linux/string.h>
  10333. +#include <linux/config.h>
  10334. +#include <linux/locks.h>
  10335. +
  10336. +#include <asm/system.h>
  10337. +#include <asm/io.h>
  10338. +#include <asm/pgtable.h>
  10339. +#include "blk.h"
  10340. +
  10341. +/*
  10342. + * The request-struct contains all necessary data
  10343. + * to load a nr of sectors into memory
  10344. + */
  10345. +static struct request all_requests[NR_REQUEST];
  10346. +
  10347. +/*
  10348. + * used to wait on when there are no free requests
  10349. + */
  10350. +struct wait_queue * wait_for_request = NULL;
  10351. +
  10352. +/* This specifies how many sectors to read ahead on the disk.  */
  10353. +
  10354. +int read_ahead[MAX_BLKDEV] = {0, };
  10355. +
  10356. +/* blk_dev_struct is:
  10357. + *    do_request-address
  10358. + *    next-request
  10359. + */
  10360. +struct blk_dev_struct blk_dev[MAX_BLKDEV] = {
  10361. +    { NULL, NULL },        /* no_dev */
  10362. +    { NULL, NULL },        /* dev mem */
  10363. +    { NULL, NULL },        /* dev fd */
  10364. +    { NULL, NULL },        /* dev hd */
  10365. +    { NULL, NULL },        /* dev ttyx */
  10366. +    { NULL, NULL },        /* dev tty */
  10367. +    { NULL, NULL },        /* dev lp */
  10368. +    { NULL, NULL },        /* dev pipes */
  10369. +    { NULL, NULL },        /* dev sd */
  10370. +    { NULL, NULL }        /* dev st */
  10371. +};
  10372. +
  10373. +/*
  10374. + * blk_size contains the size of all block-devices in units of 1024 byte
  10375. + * sectors:
  10376. + *
  10377. + * blk_size[MAJOR][MINOR]
  10378. + *
  10379. + * if (!blk_size[MAJOR]) then no minor size checking is done.
  10380. + */
  10381. +int * blk_size[MAX_BLKDEV] = { NULL, NULL, };
  10382. +
  10383. +/*
  10384. + * blksize_size contains the size of all block-devices:
  10385. + *
  10386. + * blksize_size[MAJOR][MINOR]
  10387. + *
  10388. + * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
  10389. + */
  10390. +int * blksize_size[MAX_BLKDEV] = { NULL, NULL, };
  10391. +
  10392. +/*
  10393. + * look for a free request in the first N entries.
  10394. + * NOTE: interrupts must be disabled on the way in, and will still
  10395. + *       be disabled on the way out.
  10396. + */
  10397. +static inline struct request * get_request(int n, int dev)
  10398. +{
  10399. +    static struct request *prev_found = NULL, *prev_limit = NULL;
  10400. +    register struct request *req, *limit;
  10401. +
  10402. +    if (n <= 0)
  10403. +        panic("get_request(%d): impossible!\n", n);
  10404. +
  10405. +    limit = all_requests + n;
  10406. +    if (limit != prev_limit) {
  10407. +        prev_limit = limit;
  10408. +        prev_found = all_requests;
  10409. +    }
  10410. +    req = prev_found;
  10411. +    for (;;) {
  10412. +        req = ((req > all_requests) ? req : limit) - 1;
  10413. +        if (req->dev < 0)
  10414. +            break;
  10415. +        if (req == prev_found)
  10416. +            return NULL;
  10417. +    }
  10418. +    prev_found = req;
  10419. +    req->dev = dev;
  10420. +    return req;
  10421. +}
  10422. +
  10423. +/*
  10424. + * wait until a free request in the first N entries is available.
  10425. + * NOTE: interrupts must be disabled on the way in, and will still
  10426. + *       be disabled on the way out.
  10427. + */
  10428. +static inline struct request * get_request_wait(int n, int dev)
  10429. +{
  10430. +    register struct request *req;
  10431. +
  10432. +    while ((req = get_request(n, dev)) == NULL)
  10433. +        sleep_on(&wait_for_request);
  10434. +    return req;
  10435. +}
  10436. +
  10437. +/* RO fail safe mechanism */
  10438. +
  10439. +static long ro_bits[MAX_BLKDEV][8];
  10440. +
  10441. +int is_read_only(int dev)
  10442. +{
  10443. +    int minor,major;
  10444. +
  10445. +    major = MAJOR(dev);
  10446. +    minor = MINOR(dev);
  10447. +    if (major < 0 || major >= MAX_BLKDEV) return 0;
  10448. +    return ro_bits[major][minor >> 5] & (1 << (minor & 31));
  10449. +}
  10450. +
  10451. +void set_device_ro(int dev,int flag)
  10452. +{
  10453. +    int minor,major;
  10454. +
  10455. +    major = MAJOR(dev);
  10456. +    minor = MINOR(dev);
  10457. +    if (major < 0 || major >= MAX_BLKDEV) return;
  10458. +    if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
  10459. +    else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
  10460. +}
  10461. +
  10462. +/*
  10463. + * add-request adds a request to the linked list.
  10464. + * It disables interrupts so that it can muck with the
  10465. + * request-lists in peace.
  10466. + */
  10467. +static void add_request(struct blk_dev_struct * dev, struct request * req)
  10468. +{
  10469. +    struct request * tmp;
  10470. +    short         disk_index;
  10471. +
  10472. +    switch (MAJOR(req->dev)) {
  10473. +        case SCSI_DISK_MAJOR:    disk_index = (MINOR(req->dev) & 0x0070) >> 4;
  10474. +                    if (disk_index < 4)
  10475. +                        kstat.dk_drive[disk_index]++;
  10476. +                    break;
  10477. +        case HD_MAJOR:
  10478. +        case XT_DISK_MAJOR:    disk_index = (MINOR(req->dev) & 0x00C0) >> 6;
  10479. +                    if (disk_index < 4)
  10480. +                        kstat.dk_drive[disk_index]++;
  10481. +                    break;
  10482. +        default:        break;
  10483. +    }
  10484. +
  10485. +    req->next = NULL;
  10486. +    cli();
  10487. +    if (req->bh)
  10488. +        mark_buffer_clean(req->bh);
  10489. +    if (!(tmp = dev->current_request)) {
  10490. +        dev->current_request = req;
  10491. +        (dev->request_fn)();
  10492. +        sti();
  10493. +        return;
  10494. +    }
  10495. +    for ( ; tmp->next ; tmp = tmp->next) {
  10496. +        if ((IN_ORDER(tmp,req) ||
  10497. +            !IN_ORDER(tmp,tmp->next)) &&
  10498. +            IN_ORDER(req,tmp->next))
  10499. +            break;
  10500. +    }
  10501. +    req->next = tmp->next;
  10502. +    tmp->next = req;
  10503. +
  10504. +/* for SCSI devices, call request_fn unconditionally */
  10505. +    if (scsi_major(MAJOR(req->dev)))
  10506. +        (dev->request_fn)();
  10507. +
  10508. +    sti();
  10509. +}
  10510. +
  10511. +static void make_request(int major,int rw, struct buffer_head * bh)
  10512. +{
  10513. +    unsigned int sector, count;
  10514. +    struct request * req;
  10515. +    int rw_ahead, max_req;
  10516. +
  10517. +/* WRITEA/READA is special case - it is not really needed, so if the */
  10518. +/* buffer is locked, we just forget about it, else it's a normal read */
  10519. +    rw_ahead = (rw == READA || rw == WRITEA);
  10520. +    if (rw_ahead) {
  10521. +        if (bh->b_lock)
  10522. +            return;
  10523. +        if (rw == READA)
  10524. +            rw = READ;
  10525. +        else
  10526. +            rw = WRITE;
  10527. +    }
  10528. +    if (rw!=READ && rw!=WRITE) {
  10529. +        printk("Bad block dev command, must be R/W/RA/WA\n");
  10530. +        return;
  10531. +    }
  10532. +    count = bh->b_size >> 9;
  10533. +    sector = bh->b_blocknr * count;
  10534. +    if (blk_size[major])
  10535. +        if (blk_size[major][MINOR(bh->b_dev)] < (sector + count)>>1) {
  10536. +            bh->b_dirt = bh->b_uptodate = 0;
  10537. +            bh->b_req = 0;
  10538. +            return;
  10539. +        }
  10540. +    lock_buffer(bh);
  10541. +    if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {
  10542. +        unlock_buffer(bh);
  10543. +        return;
  10544. +    }
  10545. +
  10546. +/* we don't allow the write-requests to fill up the queue completely:
  10547. + * we want some room for reads: they take precedence. The last third
  10548. + * of the requests are only for reads.
  10549. + */
  10550. +    max_req = (rw == READ) ? NR_REQUEST : ((NR_REQUEST*2)/3);
  10551. +
  10552. +/* big loop: look for a free request. */
  10553. +
  10554. +repeat:
  10555. +    cli();
  10556. +
  10557. +/* The scsi disk drivers completely remove the request from the queue when
  10558. + * they start processing an entry.  For this reason it is safe to continue
  10559. + * to add links to the top entry for scsi devices.
  10560. + */
  10561. +    if ((major == HD_MAJOR
  10562. +         || major == FLOPPY_MAJOR
  10563. +         || major == SCSI_DISK_MAJOR
  10564. +         || major == SCSI_CDROM_MAJOR)
  10565. +        && (req = blk_dev[major].current_request))
  10566. +    {
  10567. +            if (major == HD_MAJOR || major == FLOPPY_MAJOR)
  10568. +            req = req->next;
  10569. +        while (req) {
  10570. +            if (req->dev == bh->b_dev &&
  10571. +                !req->sem &&
  10572. +                req->cmd == rw &&
  10573. +                req->sector + req->nr_sectors == sector &&
  10574. +                req->nr_sectors < 244)
  10575. +            {
  10576. +                req->bhtail->b_reqnext = bh;
  10577. +                req->bhtail = bh;
  10578. +                req->nr_sectors += count;
  10579. +                mark_buffer_clean(bh);
  10580. +                sti();
  10581. +                return;
  10582. +            }
  10583. +
  10584. +            if (req->dev == bh->b_dev &&
  10585. +                !req->sem &&
  10586. +                req->cmd == rw &&
  10587. +                req->sector - count == sector &&
  10588. +                req->nr_sectors < 244)
  10589. +            {
  10590. +                    req->nr_sectors += count;
  10591. +                    bh->b_reqnext = req->bh;
  10592. +                    req->buffer = bh->b_data;
  10593. +                    req->current_nr_sectors = count;
  10594. +                    req->sector = sector;
  10595. +                mark_buffer_clean(bh);
  10596. +                    req->bh = bh;
  10597. +                    sti();
  10598. +                    return;
  10599. +            }
  10600. +
  10601. +            req = req->next;
  10602. +        }
  10603. +    }
  10604. +
  10605. +/* find an unused request. */
  10606. +    req = get_request(max_req, bh->b_dev);
  10607. +
  10608. +/* if no request available: if rw_ahead, forget it; otherwise try again. */
  10609. +    if (! req) {
  10610. +        if (rw_ahead) {
  10611. +            sti();
  10612. +            unlock_buffer(bh);
  10613. +            return;
  10614. +        }
  10615. +        sleep_on(&wait_for_request);
  10616. +        sti();
  10617. +        goto repeat;
  10618. +    }
  10619. +
  10620. +/* we found a request. */
  10621. +    sti();
  10622. +
  10623. +/* fill up the request-info, and add it to the queue */
  10624. +    req->cmd = rw;
  10625. +    req->errors = 0;
  10626. +    req->sector = sector;
  10627. +    req->nr_sectors = count;
  10628. +    req->current_nr_sectors = count;
  10629. +    req->buffer = bh->b_data;
  10630. +    req->sem = NULL;
  10631. +    req->bh = bh;
  10632. +    req->bhtail = bh;
  10633. +    req->next = NULL;
  10634. +    add_request(major+blk_dev,req);
  10635. +}
  10636. +
  10637. +void ll_rw_page(int rw, int dev, int page, char * buffer)
  10638. +{
  10639. +    struct request * req;
  10640. +    unsigned int major = MAJOR(dev);
  10641. +    struct semaphore sem = MUTEX_LOCKED;
  10642. +
  10643. +    if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
  10644. +        printk("Trying to read nonexistent block-device %04x (%d)\n",dev,page*8);
  10645. +        return;
  10646. +    }
  10647. +    if (rw!=READ && rw!=WRITE)
  10648. +        panic("Bad block dev command, must be R/W");
  10649. +    if (rw == WRITE && is_read_only(dev)) {
  10650. +        printk("Can't page to read-only device 0x%X\n",dev);
  10651. +        return;
  10652. +    }
  10653. +    cli();
  10654. +    req = get_request_wait(NR_REQUEST, dev);
  10655. +    sti();
  10656. +/* fill up the request-info, and add it to the queue */
  10657. +    req->cmd = rw;
  10658. +    req->errors = 0;
  10659. +    req->sector = page << (PAGE_SHIFT-9);
  10660. +    req->nr_sectors = 1 << (PAGE_SHIFT-9);
  10661. +    req->current_nr_sectors = 1 << (PAGE_SHIFT-9);
  10662. +    req->buffer = buffer;
  10663. +    req->sem = &sem;
  10664. +    req->bh = NULL;
  10665. +    req->next = NULL;
  10666. +    add_request(major+blk_dev,req);
  10667. +    down(&sem);
  10668. +}
  10669. +
  10670. +/* This function can be used to request a number of buffers from a block
  10671. +   device. Currently the only restriction is that all buffers must belong to
  10672. +   the same device */
  10673. +
  10674. +void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
  10675. +{
  10676. +    unsigned int major;
  10677. +    struct request plug;
  10678. +    int plugged;
  10679. +    int correct_size;
  10680. +    struct blk_dev_struct * dev;
  10681. +    int i;
  10682. +
  10683. +    /* Make sure that the first block contains something reasonable */
  10684. +    while (!*bh) {
  10685. +        bh++;
  10686. +        if (--nr <= 0)
  10687. +            return;
  10688. +    };
  10689. +
  10690. +    dev = NULL;
  10691. +    if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV)
  10692. +        dev = blk_dev + major;
  10693. +    if (!dev || !dev->request_fn) {
  10694. +        printk(
  10695. +    "ll_rw_block: Trying to read nonexistent block-device %04lX (%ld)\n",
  10696. +               (unsigned long) bh[0]->b_dev, bh[0]->b_blocknr);
  10697. +        goto sorry;
  10698. +    }
  10699. +
  10700. +    /* Determine correct block size for this device.  */
  10701. +    correct_size = BLOCK_SIZE;
  10702. +    if (blksize_size[major]) {
  10703. +        i = blksize_size[major][MINOR(bh[0]->b_dev)];
  10704. +        if (i)
  10705. +            correct_size = i;
  10706. +    }
  10707. +
  10708. +    /* Verify requested block sizes.  */
  10709. +    for (i = 0; i < nr; i++) {
  10710. +        if (bh[i] && bh[i]->b_size != correct_size) {
  10711. +            printk(
  10712. +            "ll_rw_block: only %d-char blocks implemented (%lu)\n",
  10713. +                   correct_size, bh[i]->b_size);
  10714. +            goto sorry;
  10715. +        }
  10716. +    }
  10717. +
  10718. +    if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) {
  10719. +        printk("Can't write to read-only device 0x%X\n",bh[0]->b_dev);
  10720. +        goto sorry;
  10721. +    }
  10722. +
  10723. +    /* If there are no pending requests for this device, then we insert
  10724. +       a dummy request for that device.  This will prevent the request
  10725. +       from starting until we have shoved all of the blocks into the
  10726. +       queue, and then we let it rip.  */
  10727. +
  10728. +    plugged = 0;
  10729. +    cli();
  10730. +    if (!dev->current_request && nr > 1) {
  10731. +        dev->current_request = &plug;
  10732. +        plug.dev = -1;
  10733. +        plug.next = NULL;
  10734. +        plugged = 1;
  10735. +    }
  10736. +    sti();
  10737. +    for (i = 0; i < nr; i++) {
  10738. +        if (bh[i]) {
  10739. +            bh[i]->b_req = 1;
  10740. +            make_request(major, rw, bh[i]);
  10741. +            if (rw == READ || rw == READA)
  10742. +                kstat.pgpgin++;
  10743. +            else
  10744. +                kstat.pgpgout++;
  10745. +        }
  10746. +    }
  10747. +    if (plugged) {
  10748. +        cli();
  10749. +        dev->current_request = plug.next;
  10750. +        (dev->request_fn)();
  10751. +        sti();
  10752. +    }
  10753. +    return;
  10754. +
  10755. +      sorry:
  10756. +    for (i = 0; i < nr; i++) {
  10757. +        if (bh[i])
  10758. +            bh[i]->b_dirt = bh[i]->b_uptodate = 0;
  10759. +    }
  10760. +    return;
  10761. +}
  10762. +
  10763. +void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
  10764. +{
  10765. +    int i;
  10766. +    int buffersize;
  10767. +    struct request * req;
  10768. +    unsigned int major = MAJOR(dev);
  10769. +    struct semaphore sem = MUTEX_LOCKED;
  10770. +
  10771. +    if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
  10772. +        printk("ll_rw_swap_file: trying to swap nonexistent block-device\n");
  10773. +        return;
  10774. +    }
  10775. +
  10776. +    if (rw!=READ && rw!=WRITE) {
  10777. +        printk("ll_rw_swap: bad block dev command, must be R/W");
  10778. +        return;
  10779. +    }
  10780. +    if (rw == WRITE && is_read_only(dev)) {
  10781. +        printk("Can't swap to read-only device 0x%X\n",dev);
  10782. +        return;
  10783. +    }
  10784. +    printk("ll_rw_swap: cannot swap to a swapfile!\n");
  10785. +    return;
  10786. +
  10787. +    buffersize = PAGE_SIZE / nb;
  10788. +
  10789. +    for (i=0; i<nb; i++, buf += buffersize)
  10790. +    {
  10791. +        cli();
  10792. +        req = get_request_wait(NR_REQUEST, dev);
  10793. +        sti();
  10794. +        req->cmd = rw;
  10795. +        req->errors = 0;
  10796. +        req->sector = (b[i] * buffersize) >> 9;
  10797. +        req->nr_sectors = buffersize >> 9;
  10798. +        req->current_nr_sectors = buffersize >> 9;
  10799. +        req->buffer = buf;
  10800. +        req->sem = &sem;
  10801. +        req->bh = NULL;
  10802. +        req->next = NULL;
  10803. +        add_request(major+blk_dev,req);
  10804. +        down(&sem);
  10805. +    }
  10806. +}
  10807. +
  10808. +long blk_dev_init(long mem_start, long mem_end)
  10809. +{
  10810. +    struct request * req;
  10811. +
  10812. +    req = all_requests + NR_REQUEST;
  10813. +    while (--req >= all_requests) {
  10814. +        req->dev = -1;
  10815. +        req->next = NULL;
  10816. +    }
  10817. +    memset(ro_bits,0,sizeof(ro_bits));
  10818. +#ifdef CONFIG_BLK_DEV_HD
  10819. +    mem_start = hd_init(mem_start,mem_end);
  10820. +#endif
  10821. +#ifdef CONFIG_BLK_DEV_XD
  10822. +    mem_start = xd_init(mem_start,mem_end);
  10823. +#endif
  10824. +#ifdef CONFIG_CDU31A
  10825. +    mem_start = cdu31a_init(mem_start,mem_end);
  10826. +#endif
  10827. +#ifdef CONFIG_MCD
  10828. +    mem_start = mcd_init(mem_start,mem_end);
  10829. +#endif
  10830. +#ifdef CONFIG_SBPCD
  10831. +    mem_start = sbpcd_init(mem_start, mem_end);
  10832. +#endif CONFIG_SBPCD
  10833. +    if (ramdisk_size)
  10834. +        mem_start += rd_init(mem_start, ramdisk_size*1024);
  10835. +    return mem_start;
  10836. +}
  10837. diff -r -u -N linux.orig/arch/arm/drivers/block/mfmhd.c linux.arm/arch/arm/drivers/block/mfmhd.c
  10838. --- linux.orig/arch/arm/drivers/block/mfmhd.c    Thu Jan  1 01:00:00 1970
  10839. +++ linux.arm/arch/arm/drivers/block/mfmhd.c    Fri Oct 27 23:14:51 1995
  10840. @@ -0,0 +1,770 @@
  10841. +#ifdef MODULE
  10842. +#include <linux/module.h>
  10843. +#include <linux/version.h>
  10844. +#endif
  10845. +
  10846. +#include <linux/config.h>
  10847. +#include <linux/sched.h>
  10848. +#include <linux/fs.h>
  10849. +#include <linux/kernel.h>
  10850. +#include <linux/timer.h>
  10851. +#include <linux/tqueue.h>
  10852. +#include <linux/mm.h>
  10853. +
  10854. +#include <linux/xd.h>
  10855. +#include <linux/errno.h>
  10856. +#include <linux/genhd.h>
  10857. +#include <linux/major.h>
  10858. +
  10859. +#include <asm/system.h>
  10860. +#include <asm/io.h>
  10861. +#include <asm/segment.h>
  10862. +#include <asm/dma.h>
  10863. +
  10864. +#include <asm/ecard.h>
  10865. +
  10866. +#define MFM_DISK_MAJOR    13
  10867. +#undef  XT_DISK_MAJOR
  10868. +#define XT_DISK_MAJOR    -1
  10869. +#define MAJOR_NR    MFM_DISK_MAJOR
  10870. +#include "blk.h"
  10871. +
  10872. +XD_INFO mfm_info[XD_MAXDRIVES];
  10873. +
  10874. +#define DEBUG
  10875. +
  10876. +#define MFM_COMMAND (mfm_addr + 0)
  10877. +#define MFM_DATAOUT (mfm_addr + 1)
  10878. +#define MFM_STATUS  (mfm_addr + 8)
  10879. +#define MFM_DATAIN  (mfm_addr + 9)
  10880. +
  10881. +static void mfm_geninit (void);
  10882. +static int  mfm_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg);
  10883. +static int  mfm_open (struct inode *inode,struct file *file);
  10884. +static void mfm_release (struct inode *inode, struct file *file);
  10885. +static void mfm_interrupt_handler (int, struct pt_regs *);
  10886. +static void mfm_seek (void);
  10887. +static void mfm_unexpected_interrupt (void);
  10888. +static void mfm_request (void);
  10889. +static int  mfm_reread_partitions (int dev);
  10890. +static void mfm_request (void);
  10891. +
  10892. +#define mfm_init xd_init
  10893. +
  10894. +static struct hd_struct mfm[XD_MAXDRIVES << 6];
  10895. +static int mfm_sizes[XD_MAXDRIVES << 6], mfm_access[XD_MAXDRIVES] = { 0, 0 };
  10896. +static int mfm_blocksizes[XD_MAXDRIVES << 6];
  10897. +static unsigned char mfm_valid[XD_MAXDRIVES] = { -1, };
  10898. +static struct wait_queue *mfm_wait_open = NULL;
  10899. +
  10900. +static int mfm_irq;        /* Interrupt number */
  10901. +static int mfm_addr;        /* Controller address */
  10902. +static int mfm_drives = 0;    /* drives available */
  10903. +static int mfm_status = 0;    /* interrupt status */
  10904. +static char mfm_busy = 0;    /* mfm busy */
  10905. +static int *errors;
  10906. +
  10907. +static struct rawcmd
  10908. +{
  10909. +  unsigned int flags;
  10910. +  unsigned int dev;
  10911. +  unsigned int cylinder;
  10912. +  unsigned int head;
  10913. +  unsigned int sector;
  10914. +  unsigned int cmdtype;
  10915. +  unsigned int cmdcode;
  10916. +  unsigned char cmddata[16];
  10917. +  unsigned int cmdlen;
  10918. +} raw_cmd;
  10919. +
  10920. +#define NEED_SEEK 1
  10921. +unsigned char result[16];
  10922. +unsigned char resultlen;
  10923. +
  10924. +static struct cont
  10925. +{
  10926. +    void (*interrupt)(void);/* interrupt handler */
  10927. +    void (*error)(void);    /* error handler */
  10928. +    void (*redo)(void);    /* redo handler */
  10929. +    void (*done)(int st);    /* done handler */
  10930. +} *cont = NULL;
  10931. +
  10932. +static struct drvparam
  10933. +{
  10934. +    int cylinder;
  10935. +    unsigned int nocylinders;
  10936. +    unsigned int lowcurrentcylinder;
  10937. +    unsigned int precompcylinder;
  10938. +    unsigned char noheads;
  10939. +    unsigned char nosectors;
  10940. +    struct
  10941. +    {
  10942. +        char recal;
  10943. +        char report;
  10944. +        char abort;
  10945. +    } errors;
  10946. +} mfm_drive_param[8] =
  10947. +{
  10948. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  10949. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  10950. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  10951. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  10952. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  10953. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  10954. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  10955. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } }
  10956. +};
  10957. +
  10958. +#define MFM_DRV_PARAM mfm_drive_param[raw_cmd.dev]
  10959. +
  10960. +struct tq_struct mfm_tq =
  10961. +{ 0, 0, (void (*) (void *)) mfm_unexpected_interrupt, 0 };
  10962. +
  10963. +#define NO_TRACK -1
  10964. +#define NEED_1_RECAL -2
  10965. +#define NEED_2_RECAL -3
  10966. +
  10967. +
  10968. +/* ------------------------------------------------------------------------------------------ */
  10969. +/*
  10970. + * From the HD63463 data sheet from Hitachi Ltd.
  10971. + */
  10972. +
  10973. +#define CMD_ABT        0xF0        /* Abort */
  10974. +#define CMD_SPC        0xE8        /* Specify */
  10975. +#define CMD_TST        0xE0        /* Test */
  10976. +#define CMD_RCLB    0xC8        /* Recalibrate */
  10977. +#define CMD_SEK        0xC0        /* Seek */
  10978. +#define CMD_WFS        0xAB        /* Write Format Skew */
  10979. +#define CMD_WFM        0xA3        /* Write Format */
  10980. +#define CMD_MTB        0x90        /* Memory to buffer */
  10981. +#define CMD_CMPD    0x88        /* Compare data */
  10982. +#define CMD_WD        0x87        /* Write data */
  10983. +#define CMD_RED        0x70        /* Read erroneous data */
  10984. +#define CMD_RIS        0x68        /* Read ID skew */
  10985. +#define CMD_FID        0x61        /* Find ID */
  10986. +#define CMD_RID        0x60        /* Read ID */
  10987. +#define CMD_BTM        0x50        /* Buffer to memory */
  10988. +#define CMD_CKD        0x48        /* Check data */
  10989. +#define CMD_RD        0x40        /* Read data */
  10990. +#define CMD_OPBW    0x38        /* Open buffer write */
  10991. +#define CMD_OPBR    0x30        /* Open buffer read */
  10992. +#define CMD_CKV        0x28        /* Check drive */
  10993. +#define CMD_CKE        0x20        /* Check ECC */
  10994. +#define CMD_POD        0x18        /* Polling disable */
  10995. +#define CMD_POL        0x10        /* Polling enable */
  10996. +#define CMD_RCAL    0x08        /* Recall */
  10997. +
  10998. +#define STAT_BSY    0x8000        /* Busy */
  10999. +#define STAT_CPR    0x4000        /* Command Parameter Rejection */
  11000. +#define STAT_CED    0x2000        /* Command end */
  11001. +#define STAT_SED    0x1000        /* Seek end */
  11002. +#define STAT_DER    0x0800        /* Drive error */
  11003. +#define STAT_ABN    0x0400        /* Abnormal end */
  11004. +#define STAT_POL    0x0200        /* Polling */
  11005. +
  11006. +/* ------------------------------------------------------------------------------------------ */
  11007. +
  11008. +static struct gendisk mfm_gendisk = {
  11009. +    MAJOR_NR,    /* Major number */
  11010. +    "mfm",        /* Major name */
  11011. +    6,        /* Bits to shift to get real from partition */
  11012. +    1 << 6,        /* Number of partitions per real */
  11013. +    XD_MAXDRIVES,    /* maximum number of real */
  11014. +    mfm_geninit,    /* init function */
  11015. +    mfm,        /* hd struct */
  11016. +    mfm_sizes,    /* block sizes */
  11017. +    0,        /* number */
  11018. +    (void *)mfm_info,/* internal */
  11019. +    NULL        /* next */
  11020. +};
  11021. +
  11022. +static struct file_operations mfm_fops = {
  11023. +    NULL,            /* lseek - default */
  11024. +    block_read,        /* read - general block-dev read */
  11025. +    block_write,        /* write - general block-dev write */
  11026. +    NULL,            /* readdir - bad */
  11027. +    NULL,            /* select */
  11028. +    mfm_ioctl,        /* ioctl */
  11029. +    NULL,            /* mmap */
  11030. +    mfm_open,        /* open */
  11031. +    mfm_release,        /* release */
  11032. +    block_fsync        /* fsync */
  11033. +};
  11034. +
  11035. +static struct expansion_card *ecs;
  11036. +static int mfm_prods[] = { 0x000b };
  11037. +static int mfm_manus[] = { 0x0000 };
  11038. +
  11039. +unsigned long mfm_init (unsigned long mem_start, unsigned long mem_end)
  11040. +{
  11041. +    ecs = ecard_find(0, sizeof(mfm_prods), mfm_prods, mfm_manus);
  11042. +    if(!ecs)
  11043. +        return mem_start;
  11044. +
  11045. +    mfm_irq = ecs->irq;
  11046. +    mfm_addr= ((((int)ecs->r_podaddr) & 0x03eff000) + 0x2000)>>2;
  11047. +
  11048. +    ecard_claim(ecs);
  11049. +
  11050. +    printk("mfm: controller found at address %X, interrupt %d\n", mfm_addr, mfm_irq);
  11051. +
  11052. +    if(register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) {
  11053. +        printk("mfm_init: unable to get major number %d\n", MAJOR_NR);
  11054. +        return mem_start;
  11055. +    }
  11056. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  11057. +    read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahread */
  11058. +#ifndef MODULE
  11059. +    mfm_gendisk.next = gendisk_head;
  11060. +    gendisk_head = & mfm_gendisk;
  11061. +#endif
  11062. +
  11063. +    return mem_start;
  11064. +}
  11065. +
  11066. +static int mfm_initdrives (void)
  11067. +{
  11068. +    mfm_info[0].heads = 4;
  11069. +    mfm_info[0].cylinders = 615;
  11070. +    mfm_info[0].sectors = 32;
  11071. +    mfm_info[0].control = 0;
  11072. +    return 1;
  11073. +}
  11074. +
  11075. +static void mfm_geninit (void)
  11076. +{
  11077. +    int i;
  11078. +
  11079. +    mfm_drives = mfm_initdrives();
  11080. +    printk("mfm: detected %d hard drive%s\n", mfm_drives, mfm_drives == 1?"":"s");
  11081. +    for(i = 0; i < mfm_drives; i++)
  11082. +        printk("mfm%d: heads = %d, cylinders = %d, sectors = %d\n", i,
  11083. +             mfm_info[i].heads, mfm_info[i].cylinders, mfm_info[i].sectors);
  11084. +
  11085. +    if(request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk"))
  11086. +        printk("mfm: unable to get IRQ%d\n", mfm_irq);
  11087. +
  11088. +    outw(0x80, mfm_addr + (0x1000 >> 2));
  11089. +
  11090. +    for(i = 0; i < mfm_drives; i++) {
  11091. +        mfm[i << 6].nr_sects = mfm_info[i].heads * mfm_info[i].cylinders *
  11092. +                mfm_info[i].sectors;
  11093. +        mfm[i << 6].start_sect = 0;
  11094. +        mfm_valid[i] = 1;
  11095. +    }
  11096. +    mfm_gendisk.nr_real = mfm_drives;
  11097. +
  11098. +    for(i=0; i<(XD_MAXDRIVES << 6); i++)
  11099. +        mfm_blocksizes[i] = 1024;
  11100. +    blksize_size[MAJOR_NR] = mfm_blocksizes;
  11101. +}
  11102. +
  11103. +static int mfm_open (struct inode *inode,struct file *file)
  11104. +{
  11105. +    int dev = DEVICE_NR(MINOR(inode->i_rdev));
  11106. +
  11107. +    if (dev < mfm_drives) {
  11108. +        while (!mfm_valid[dev])
  11109. +            sleep_on(&mfm_wait_open);
  11110. +
  11111. +        mfm_access[dev]++;
  11112. +
  11113. +        return (0);
  11114. +    }
  11115. +    else
  11116. +        return (-ENODEV);
  11117. +}
  11118. +
  11119. +static int mfm_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
  11120. +{
  11121. +    XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg;
  11122. +    int dev = DEVICE_NR(MINOR(inode->i_rdev)),err;
  11123. +
  11124. +    if (inode && (dev < mfm_drives))
  11125. +        switch (cmd) {
  11126. +            case HDIO_GETGEO:
  11127. +                if (arg) {
  11128. +                    if ((err = verify_area(VERIFY_WRITE, geometry, sizeof(*geometry))))
  11129. +                        return (err);
  11130. +                    put_fs_byte(mfm_info[dev].heads,(char *) &geometry->heads);
  11131. +                    put_fs_byte(mfm_info[dev].sectors,(char *) &geometry->sectors);
  11132. +                    put_fs_word(mfm_info[dev].cylinders,(short *) &geometry->cylinders);
  11133. +                    put_fs_long(mfm[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start);
  11134. +
  11135. +                    return (0);
  11136. +                }
  11137. +                break;
  11138. +            case BLKRASET:
  11139. +              if(!suser())  return -EACCES;
  11140. +              if(!inode->i_rdev) return -EINVAL;
  11141. +              if(arg > 0xff) return -EINVAL;
  11142. +              read_ahead[MAJOR(inode->i_rdev)] = arg;
  11143. +              return 0;
  11144. +            case BLKGETSIZE:
  11145. +                if (arg) {
  11146. +                    if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
  11147. +                        return (err);
  11148. +                    put_fs_long(mfm[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
  11149. +
  11150. +                    return (0);
  11151. +                }
  11152. +                break;
  11153. +            case BLKFLSBUF:
  11154. +                if(!suser())  return -EACCES;
  11155. +                if(!inode->i_rdev) return -EINVAL;
  11156. +                fsync_dev(inode->i_rdev);
  11157. +                invalidate_buffers(inode->i_rdev);
  11158. +                return 0;
  11159. +
  11160. +            case BLKRRPART:
  11161. +                return (mfm_reread_partitions(inode->i_rdev));
  11162. +            RO_IOCTLS(inode->i_rdev,arg);
  11163. +        }
  11164. +    return (-EINVAL);
  11165. +}
  11166. +
  11167. +static void mfm_release (struct inode *inode, struct file *file)
  11168. +{
  11169. +    int dev = DEVICE_NR(MINOR(inode->i_rdev));
  11170. +
  11171. +    if (dev < mfm_drives) {
  11172. +        sync_dev(dev);
  11173. +        mfm_access[dev]--;
  11174. +    }
  11175. +}
  11176. +
  11177. +static int mfm_reread_partitions (int dev)
  11178. +{
  11179. +    int target = DEVICE_NR(MINOR(dev)),start = target << mfm_gendisk.minor_shift,partition;
  11180. +
  11181. +    cli();
  11182. +
  11183. +    mfm_valid[target] = (mfm_access[target] != 1);
  11184. +
  11185. +    sti();
  11186. +
  11187. +    if (mfm_valid[target])
  11188. +        return -EBUSY;
  11189. +
  11190. +    for (partition = mfm_gendisk.max_p - 1; partition >= 0; partition--) {
  11191. +        sync_dev(MAJOR_NR << 8 | start | partition);
  11192. +        invalidate_inodes(MAJOR_NR << 8 | start | partition);
  11193. +        invalidate_buffers(MAJOR_NR << 8 | start | partition);
  11194. +        mfm_gendisk.part[start + partition].start_sect = 0;
  11195. +        mfm_gendisk.part[start + partition].nr_sects = 0;
  11196. +    };
  11197. +
  11198. +    mfm_gendisk.part[start].nr_sects = mfm_info[target].heads *
  11199. +        mfm_info[target].cylinders * mfm_info[target].sectors;
  11200. +    resetup_one_dev(&mfm_gendisk,target);
  11201. +
  11202. +    mfm_valid[target] = 1;
  11203. +    wake_up(&mfm_wait_open);
  11204. +
  11205. +    return 0;
  11206. +}
  11207. +
  11208. +static void print_status (void)
  11209. +{
  11210. +    char *error;
  11211. +    static char *errors[] =
  11212. +    { "no error",
  11213. +      "command aborted",
  11214. +      "invalid command",
  11215. +      "parameter error",
  11216. +      "not initialised",
  11217. +      "rejected TEST",
  11218. +      "no useld",
  11219. +      "write fault",
  11220. +      "not ready",
  11221. +      "no scp",
  11222. +      "in seek",
  11223. +      "invalid NCA",
  11224. +      "invalid step rate",
  11225. +      "seek error",
  11226. +      "over run",
  11227. +      "invalid PHA",
  11228. +      "data field EEC error",
  11229. +      "data field CRC error",
  11230. +      "error corrected",
  11231. +      "data field fatal error",
  11232. +      "no data am",
  11233. +      "not hit",
  11234. +      "ID field CRC error",
  11235. +      "time over",
  11236. +      "no ID am",
  11237. +      "not writable"
  11238. +    };
  11239. +    if(result[1] < 0x65)
  11240. +        error = errors[result[1] >> 2];
  11241. +    else
  11242. +        error = "unknown";
  11243. +    printk("(");
  11244. +    if(mfm_status & STAT_BSY)
  11245. +        printk("BSY ");
  11246. +    if(mfm_status & STAT_CPR)
  11247. +        printk("CPR ");
  11248. +    if(mfm_status & STAT_CED)
  11249. +        printk("CED ");
  11250. +    if(mfm_status & STAT_SED)
  11251. +        printk("SED ");
  11252. +    if(mfm_status & STAT_DER)
  11253. +        printk("DER ");
  11254. +    if(mfm_status & STAT_ABN)
  11255. +        printk("ABN ");
  11256. +    if(mfm_status & STAT_POL)
  11257. +        printk("POL ");
  11258. +    printk(") SSB = %X (%s)\n", result[1], error);
  11259. +
  11260. +}
  11261. +
  11262. +/* ------------------------------------------------------------------------------------- */
  11263. +
  11264. +static void issue_command (int command, unsigned char *cmdb, int len)
  11265. +{
  11266. +    int status;
  11267. +#ifdef DEBUG
  11268. +    int i;
  11269. +    printk("issue_command: %02X: ",command);
  11270. +    for(i=0; i<len; i++)
  11271. +      printk("%02X ", cmdb[i]);
  11272. +    printk("\n");
  11273. +#endif
  11274. +
  11275. +    do {
  11276. +        status = inw(MFM_STATUS);
  11277. +    } while(status & (STAT_BSY|STAT_POL));
  11278. +    if(status & STAT_CPR)
  11279. +    {
  11280. +        outw(CMD_RCAL, MFM_COMMAND);
  11281. +        while(inw(MFM_STATUS) & STAT_BSY);
  11282. +    }
  11283. +
  11284. +    while(len > 0)
  11285. +    {
  11286. +        outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT);
  11287. +        len -= 2;
  11288. +        cmdb += 2;
  11289. +    }
  11290. +    outw(command, MFM_COMMAND);
  11291. +}
  11292. +
  11293. +static void wait_for_completion (void)
  11294. +{
  11295. +    while((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
  11296. +}
  11297. +
  11298. +/* ------------------------------------------------------------------------------------- */
  11299. +
  11300. +static void mfm_rw_intr (void)
  11301. +{
  11302. +    printk("mfm_rw_intr...\n");
  11303. +    if (cont)
  11304. +    {
  11305. +        cont->done(1);
  11306. +    }
  11307. +    mfm_request();
  11308. +}
  11309. +
  11310. +static void mfm_setup_rw (void)
  11311. +{
  11312. +    printk("setting up for rw...\n");
  11313. +#if 1
  11314. +    SET_INTR(mfm_rw_intr);
  11315. +    issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);
  11316. +#else
  11317. +    if(cont)
  11318. +    {
  11319. +        cont->done(0);
  11320. +        cont->redo();
  11321. +    }
  11322. +#endif
  11323. +}
  11324. +
  11325. +static void mfm_recal_intr (void)
  11326. +{
  11327. +    printk("recal intr - status = ");
  11328. +    print_status();
  11329. +    if(mfm_status & (STAT_DER|STAT_ABN)) {
  11330. +        printk("recal failed\n");
  11331. +        MFM_DRV_PARAM.cylinder = NEED_2_RECAL;
  11332. +        if(cont)
  11333. +        {
  11334. +            cont->error();
  11335. +            cont->redo();
  11336. +        }
  11337. +        return;
  11338. +    }
  11339. +    if(mfm_status & STAT_SED) {
  11340. +        issue_command(CMD_POD, NULL, 0);
  11341. +        MFM_DRV_PARAM.cylinder = 0;
  11342. +        mfm_seek();
  11343. +        return;
  11344. +    }
  11345. +    if(mfm_status & STAT_CED) {
  11346. +        SET_INTR(mfm_recal_intr);
  11347. +        issue_command(CMD_POL, NULL, 0);
  11348. +        return;
  11349. +    }
  11350. +    printk("recal: unknown status\n");
  11351. +}
  11352. +
  11353. +static void mfm_seek_intr (void)
  11354. +{
  11355. +    printk("seek intr - status = ");
  11356. +    print_status();
  11357. +    if(mfm_status & (STAT_DER|STAT_ABN)) {
  11358. +        printk("seek failed\n");
  11359. +        MFM_DRV_PARAM.cylinder = NEED_2_RECAL;
  11360. +        if(cont)
  11361. +        {
  11362. +            cont->error();
  11363. +            cont->redo();
  11364. +        }
  11365. +        return;
  11366. +    }
  11367. +    if(mfm_status & STAT_SED) {
  11368. +        issue_command(CMD_POD, NULL, 0);
  11369. +        MFM_DRV_PARAM.cylinder = raw_cmd.cylinder;
  11370. +        mfm_seek();
  11371. +        return;
  11372. +    }
  11373. +    if(mfm_status & STAT_CED) {
  11374. +        SET_INTR(mfm_seek_intr);
  11375. +        issue_command(CMD_POL, NULL, 0);
  11376. +        return;
  11377. +    }
  11378. +    printk("seek: unknown status\n");
  11379. +}
  11380. +
  11381. +static void mfm_specify (void)
  11382. +{
  11383. +    unsigned char cmdb[16];
  11384. +    printk("specify...\n");
  11385. +    cmdb[0] = 0x1F;
  11386. +    cmdb[1] = 0xC3;
  11387. +    cmdb[2] = 0x16;
  11388. +    cmdb[3] = 0x02;
  11389. +    cmdb[4] = 0xFC | ((MFM_DRV_PARAM.nocylinders - 1) >> 8);
  11390. +    cmdb[5] = MFM_DRV_PARAM.nocylinders - 1;
  11391. +    cmdb[6] = MFM_DRV_PARAM.noheads - 1;
  11392. +    cmdb[7] = MFM_DRV_PARAM.nosectors - 1;
  11393. +    cmdb[8] = 0xA9;
  11394. +    cmdb[9] = 0x0A;
  11395. +    cmdb[10]= 0x0D;
  11396. +    cmdb[11]= 0x0C;
  11397. +    cmdb[12]= (MFM_DRV_PARAM.precompcylinder - 1) >> 8;
  11398. +    cmdb[13]= MFM_DRV_PARAM.precompcylinder - 1;
  11399. +    cmdb[14]= (MFM_DRV_PARAM.lowcurrentcylinder - 1) >> 8;
  11400. +    cmdb[15]= MFM_DRV_PARAM.lowcurrentcylinder - 1;
  11401. +
  11402. +    issue_command(CMD_SPC, cmdb, 16);
  11403. +    wait_for_completion();
  11404. +}
  11405. +
  11406. +static void mfm_seek (void)
  11407. +{
  11408. +    unsigned char cmdb[4];
  11409. +    printk("seeking...\n");
  11410. +    if(MFM_DRV_PARAM.cylinder < 0) {
  11411. +        cmdb[0] = raw_cmd.dev + 1;
  11412. +        cmdb[1] = raw_cmd.head;
  11413. +
  11414. +        SET_INTR(mfm_recal_intr);
  11415. +        issue_command(CMD_RCLB, cmdb, 2);
  11416. +        return;
  11417. +    }
  11418. +    mfm_specify();
  11419. +    if(MFM_DRV_PARAM.cylinder != raw_cmd.cylinder)
  11420. +    {
  11421. +        cmdb[0] = raw_cmd.dev + 1;
  11422. +        cmdb[1] = raw_cmd.head;
  11423. +        cmdb[2] = raw_cmd.cylinder >> 8;
  11424. +        cmdb[3] = raw_cmd.cylinder;
  11425. +
  11426. +        SET_INTR(mfm_seek_intr);
  11427. +        issue_command(CMD_SEK, cmdb, 4);
  11428. +    }
  11429. +    else
  11430. +        mfm_setup_rw();
  11431. +}
  11432. +
  11433. +static void mfm_initialise (void)
  11434. +{
  11435. +    printk("init...\n");
  11436. +    if(raw_cmd.flags & NEED_SEEK)
  11437. +        mfm_seek();
  11438. +    else
  11439. +        mfm_setup_rw();
  11440. +}
  11441. +
  11442. +/* ------------------------------------------------------------------------------------- */
  11443. +
  11444. +static void request_done(int uptodate)
  11445. +{
  11446. +    if(!CURRENT) {
  11447. +        printk("mfm: request list destroyed\n");
  11448. +        return;
  11449. +    }
  11450. +    if(uptodate) {
  11451. +        end_request (1);
  11452. +    }
  11453. +    else {
  11454. +        end_request (0);
  11455. +    }
  11456. +}
  11457. +
  11458. +static void error_handler (void)
  11459. +{
  11460. +    int i;
  11461. +    printk("error detected... status = ");
  11462. +    print_status();
  11463. +    (*errors) ++;
  11464. +    if(*errors > MFM_DRV_PARAM.errors.abort)
  11465. +        cont->done(0);
  11466. +    if(*errors > MFM_DRV_PARAM.errors.recal)
  11467. +        MFM_DRV_PARAM.cylinder = NEED_2_RECAL;
  11468. +}
  11469. +
  11470. +static void rw_interrupt(void)
  11471. +{
  11472. +}
  11473. +
  11474. +static struct cont rw_cont ={
  11475. +    rw_interrupt,
  11476. +    error_handler,
  11477. +    mfm_request,
  11478. +    request_done
  11479. +};
  11480. +
  11481. +static void mfm_request (void)
  11482. +{
  11483. +    unsigned int dev, block, nsect, track;
  11484. +
  11485. +    if(CURRENT && CURRENT->dev < 0)
  11486. +        return;
  11487. +
  11488. +    while(1){
  11489. +        sti();
  11490. +
  11491. +        INIT_REQUEST;
  11492. +        dev = MINOR(CURRENT->dev);
  11493. +        block = CURRENT->sector;
  11494. +        nsect = CURRENT->nr_sectors;
  11495. +
  11496. +        if(dev >= (mfm_drives << 6) ||
  11497. +            block >= mfm[dev].nr_sects || ((block+nsect) > mfm[dev].nr_sects)) {
  11498. +#ifdef DEBUG
  11499. +            if(dev >= (mfm_drives << 6))
  11500. +                printk("mfm: bad minor number: device=0x%04x\n", CURRENT->dev);
  11501. +            else
  11502. +                printk("mfm%c: bad access: block=%d, count=%d\n", (dev>>6)+'a',
  11503. +                    block, nsect);
  11504. +#endif
  11505. +            end_request(0);
  11506. +            continue;
  11507. +        }
  11508. +        block += mfm[dev].start_sect;
  11509. +
  11510. +        if(CURRENT->cmd != READ && CURRENT->cmd != WRITE)
  11511. +        {
  11512. +            printk("unknown mfm-command %d\n", CURRENT->cmd);
  11513. +            end_request(0);
  11514. +            continue;
  11515. +        }
  11516. +
  11517. +        dev >>= 6;
  11518. +
  11519. +        track = block / mfm_info[dev].sectors;
  11520. +        raw_cmd.flags        = NEED_SEEK;
  11521. +        raw_cmd.dev        = dev;
  11522. +        raw_cmd.sector        = block % mfm_info[dev].sectors;
  11523. +        raw_cmd.head        = track % mfm_info[dev].heads;
  11524. +        raw_cmd.cylinder    = track / mfm_info[dev].heads;
  11525. +        raw_cmd.cmdtype     = CURRENT->cmd;
  11526. +        raw_cmd.cmdcode     = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD;
  11527. +        raw_cmd.cmddata[0]    = dev;
  11528. +        raw_cmd.cmddata[1]    = raw_cmd.head;
  11529. +        raw_cmd.cmddata[2]    = raw_cmd.cylinder >> 8;
  11530. +        raw_cmd.cmddata[3]    = raw_cmd.cylinder;
  11531. +        raw_cmd.cmddata[4]    = raw_cmd.head;
  11532. +        raw_cmd.cmddata[5]    = raw_cmd.sector;
  11533. +        raw_cmd.cmddata[6]    = nsect >> 8;
  11534. +        raw_cmd.cmddata[7]    = nsect;
  11535. +        raw_cmd.cmdlen        = 8;
  11536. +
  11537. +#ifdef DEBUG
  11538. +        printk("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
  11539. +            raw_cmd.dev+'a', (CURRENT->cmd == READ)?"read":"writ",
  11540. +            raw_cmd.cylinder,
  11541. +            raw_cmd.head,
  11542. +            raw_cmd.sector, nsect, (unsigned long)CURRENT->buffer, CURRENT);
  11543. +#endif
  11544. +        cont = &rw_cont;
  11545. +        errors = &(CURRENT->errors);
  11546. +        mfm_tq.routine = (void (*)(void *))mfm_initialise;
  11547. +        queue_task(&mfm_tq, &tq_timer);
  11548. +        break;
  11549. +    }
  11550. +}
  11551. +
  11552. +static void do_mfm_request (void)
  11553. +{
  11554. +    mfm_request();
  11555. +}
  11556. +
  11557. +static void mfm_unexpected_interrupt (void)
  11558. +{
  11559. +    printk("mfm: unexpected interrupt - status = ");
  11560. +    print_status();
  11561. +}
  11562. +
  11563. +static void mfm_interrupt_handler (int unused, struct pt_regs *regs)
  11564. +{
  11565. +    int i;
  11566. +    void (*handler)(void) = DEVICE_INTR;
  11567. +
  11568. +    CLEAR_INTR;
  11569. +    mfm_status = inw(MFM_STATUS);
  11570. +
  11571. +    if((mfm_status & (STAT_CPR|STAT_BSY)) == STAT_CPR)
  11572. +    {
  11573. +        int len = 0;
  11574. +        while(len <16)
  11575. +        {
  11576. +            int in;
  11577. +            in = inw(MFM_DATAIN);
  11578. +            result[len++] = in>>8;
  11579. +            result[len++] = in;
  11580. +        }
  11581. +    }
  11582. +
  11583. +    outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
  11584. +
  11585. +    if(!handler) {
  11586. +        mfm_unexpected_interrupt();
  11587. +        return;
  11588. +    }
  11589. +    mfm_tq.routine = (void (*)(void *))handler;
  11590. +    queue_task_irq(&mfm_tq, &tq_timer);
  11591. +}
  11592. +
  11593. +#ifdef MODULE
  11594. +
  11595. +char kernel_version[] = UTS_RELEASE;
  11596. +
  11597. +int init_module (void)
  11598. +{
  11599. +    mfm_init(0, 0);
  11600. +    mfm_geninit();
  11601. +    return 0;
  11602. +}
  11603. +
  11604. +void cleanup_module (void)
  11605. +{
  11606. +    if (ecs)
  11607. +        ecard_release(ecs);
  11608. +}
  11609. +    
  11610. +#endif
  11611. diff -r -u -N linux.orig/arch/arm/drivers/block/ramdisk.c linux.arm/arch/arm/drivers/block/ramdisk.c
  11612. --- linux.orig/arch/arm/drivers/block/ramdisk.c    Thu Jan  1 01:00:00 1970
  11613. +++ linux.arm/arch/arm/drivers/block/ramdisk.c    Fri Oct 27 23:14:45 1995
  11614. @@ -0,0 +1,234 @@
  11615. +/*
  11616. + *  linux/kernel/blk_drv/ramdisk.c
  11617. + *
  11618. + *  Written by Theodore Ts'o, 12/2/91
  11619. + *
  11620. + * Modifications by Fred N. van Kempen to allow for bootable root
  11621. + * disks (which are used in LINUX/Pro).  Also some cleanups.  03/03/93
  11622. + */
  11623. +
  11624. +
  11625. +#include <linux/sched.h>
  11626. +#include <linux/minix_fs.h>
  11627. +#include <linux/ext2_fs.h>
  11628. +#include <linux/fs.h>
  11629. +#include <linux/kernel.h>
  11630. +#include <linux/string.h>
  11631. +#include <linux/mm.h>
  11632. +
  11633. +#include <asm/system.h>
  11634. +#include <asm/segment.h>
  11635. +
  11636. +#define MAJOR_NR  MEM_MAJOR
  11637. +#include "blk.h"
  11638. +
  11639. +#define RAMDISK_MINOR    1
  11640. +
  11641. +extern void wait_for_keypress(void);
  11642. +
  11643. +char    *rd_start;
  11644. +int    rd_length = 0;
  11645. +static int rd_blocksizes[2] = {0, 0};
  11646. +
  11647. +static void do_rd_request(void)
  11648. +{
  11649. +    int    len;
  11650. +    char    *addr;
  11651. +
  11652. +repeat:
  11653. +    INIT_REQUEST;
  11654. +    addr = rd_start + (CURRENT->sector << 9);
  11655. +    len = CURRENT->current_nr_sectors << 9;
  11656. +
  11657. +    if ((MINOR(CURRENT->dev) != RAMDISK_MINOR) ||
  11658. +        (addr+len > rd_start+rd_length)) {
  11659. +        end_request(0);
  11660. +        goto repeat;
  11661. +    }
  11662. +    if (CURRENT-> cmd == WRITE) {
  11663. +        (void ) memcpy(addr,
  11664. +                  CURRENT->buffer,
  11665. +                  len);
  11666. +    } else if (CURRENT->cmd == READ) {
  11667. +        (void) memcpy(CURRENT->buffer, 
  11668. +                  addr,
  11669. +                  len);
  11670. +    } else
  11671. +        panic("RAMDISK: unknown RAM disk command !\n");
  11672. +    end_request(1);
  11673. +    goto repeat;
  11674. +}
  11675. +
  11676. +static struct file_operations rd_fops = {
  11677. +    NULL,            /* lseek - default */
  11678. +    block_read,        /* read - general block-dev read */
  11679. +    block_write,        /* write - general block-dev write */
  11680. +    NULL,            /* readdir - bad */
  11681. +    NULL,            /* select */
  11682. +    NULL,            /* ioctl */
  11683. +    NULL,            /* mmap */
  11684. +    NULL,            /* no special open code */
  11685. +    NULL,            /* no special release code */
  11686. +    block_fsync        /* fsync */
  11687. +};
  11688. +
  11689. +/*
  11690. + * Returns amount of memory which needs to be reserved.
  11691. + */
  11692. +long rd_init(long mem_start, int length)
  11693. +{
  11694. +    int    i;
  11695. +    char    *cp;
  11696. +
  11697. +    if (register_blkdev(MEM_MAJOR,"rd",&rd_fops)) {
  11698. +        printk("RAMDISK: Unable to get major %d.\n", MEM_MAJOR);
  11699. +        return 0;
  11700. +    }
  11701. +    blk_dev[MEM_MAJOR].request_fn = DEVICE_REQUEST;
  11702. +    rd_start = (char *) mem_start;
  11703. +    rd_length = length;
  11704. +    cp = rd_start;
  11705. +    for (i=0; i < length; i++)
  11706. +        *cp++ = '\0';
  11707. +
  11708. +    for(i=0;i<2;i++) rd_blocksizes[i] = 1024;
  11709. +    blksize_size[MAJOR_NR] = rd_blocksizes;
  11710. +
  11711. +    return(length);
  11712. +}
  11713. +
  11714. +static void do_load(void)
  11715. +{
  11716. +    struct buffer_head *bh;
  11717. +    struct super_block {
  11718. +      union
  11719. +      {
  11720. +        char minix [sizeof (struct minix_super_block)];
  11721. +        char ext2 [sizeof (struct ext2_super_block)];
  11722. +      } record;
  11723. +    } sb;
  11724. +    struct minix_super_block *minixsb =
  11725. +        (struct minix_super_block *)&sb;
  11726. +    struct ext2_super_block *ext2sb =
  11727. +        (struct ext2_super_block *)&sb;
  11728. +    int        block, tries;
  11729. +    int        i = 1;
  11730. +    int        nblocks;
  11731. +    char        *cp;
  11732. +    
  11733. +    /*
  11734. +     * Check for a super block on the diskette.
  11735. +     * The old-style boot/root diskettes had their RAM image
  11736. +     * starting at block 512 of the boot diskette.  LINUX/Pro
  11737. +     * uses the entire diskette as a file system, so in that
  11738. +     * case, we have to look at block 0.  Be intelligent about
  11739. +     * this, and check both... - FvK
  11740. +     */
  11741. +    for (tries = 0; tries < 1000; tries += 512) {
  11742. +        block = tries;
  11743. +        bh = breada(ROOT_DEV,block+1,BLOCK_SIZE, 0,  PAGE_SIZE);
  11744. +        if (!bh) {
  11745. +            printk("RAMDISK: I/O error while looking for super block!\n");
  11746. +            return;
  11747. +        }
  11748. +
  11749. +        /* This is silly- why do we require it to be a MINIX FS? */
  11750. +        *((struct super_block *) &sb) =
  11751. +            *((struct super_block *) bh->b_data);
  11752. +        brelse(bh);
  11753. +
  11754. +
  11755. +        /* Try Minix */
  11756. +        nblocks = -1;
  11757. +        if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
  11758. +            minixsb->s_magic == MINIX_SUPER_MAGIC2) {
  11759. +            printk("RAMDISK: Minix filesystem found at block %d\n",
  11760. +                block);
  11761. +            nblocks = minixsb->s_nzones << minixsb->s_log_zone_size;
  11762. +        }
  11763. +
  11764. +        /* Try ext2 */
  11765. +        if (nblocks == -1 && (ext2sb->s_magic ==
  11766. +            EXT2_PRE_02B_MAGIC ||
  11767. +            ext2sb->s_magic == EXT2_SUPER_MAGIC))
  11768. +            {
  11769. +            printk("RAMDISK: Ext2 filesystem found at block %d\n",
  11770. +                block);
  11771. +            nblocks = ext2sb->s_blocks_count;
  11772. +        }
  11773. +
  11774. +        if (nblocks == -1)
  11775. +        {
  11776. +            printk("RAMDISK: trying old-style RAM image.\n");
  11777. +            continue;
  11778. +        }
  11779. +
  11780. +        if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) {
  11781. +            printk("RAMDISK: image too big! (%d/%d blocks)\n",
  11782. +                    nblocks, rd_length >> BLOCK_SIZE_BITS);
  11783. +            return;
  11784. +        }
  11785. +        printk("RAMDISK: Loading %d blocks into RAM disk", nblocks);
  11786. +
  11787. +        /* We found an image file system.  Load it into core! */
  11788. +        cp = rd_start;
  11789. +        while (nblocks) {
  11790. +            if (nblocks > 2) 
  11791. +                    bh = breada(ROOT_DEV, block, BLOCK_SIZE, 0,  PAGE_SIZE);
  11792. +            else
  11793. +                bh = bread(ROOT_DEV, block, BLOCK_SIZE);
  11794. +            if (!bh) {
  11795. +                printk("RAMDISK: I/O error on block %d, aborting!\n", 
  11796. +                block);
  11797. +                return;
  11798. +            }
  11799. +            (void) memcpy(cp, bh->b_data, BLOCK_SIZE);
  11800. +            brelse(bh);
  11801. +            if (!(nblocks-- & 15)) printk(".");
  11802. +            cp += BLOCK_SIZE;
  11803. +            block++;
  11804. +            i++;
  11805. +        }
  11806. +        printk("\ndone\n");
  11807. +
  11808. +        /* We loaded the file system image.  Prepare for mounting it. */
  11809. +        ROOT_DEV = ((MEM_MAJOR << 8) | RAMDISK_MINOR);
  11810. +        return;
  11811. +    }
  11812. +}
  11813. +
  11814. +/*
  11815. + * If the root device is the RAM disk, try to load it.
  11816. + * In order to do this, the root device is originally set to the
  11817. + * floppy, and we later change it to be RAM disk.
  11818. + */
  11819. +void rd_load(void)
  11820. +{
  11821. +    struct inode inode;
  11822. +    struct file filp;
  11823. +
  11824. +    /* If no RAM disk specified, give up early. */
  11825. +    if (!rd_length)
  11826. +        return;
  11827. +    printk("RAMDISK: %d bytes, starting at 0x%x\n",
  11828. +            rd_length, (int) rd_start);
  11829. +
  11830. +    /* If we are doing a diskette boot, we might have to pre-load it. */
  11831. +    if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR)
  11832. +        return;
  11833. +
  11834. +    /* for Slackware install disks */
  11835. +    printk(KERN_NOTICE "VFS: Insert ramdisk floppy and press ENTER\n");
  11836. +    wait_for_keypress();
  11837. +
  11838. +    memset(&filp, 0, sizeof(filp));
  11839. +    memset(&inode, 0, sizeof(inode));
  11840. +    inode.i_rdev = ROOT_DEV;
  11841. +    filp.f_mode = 1; /* read only */
  11842. +    filp.f_inode = &inode;
  11843. +    if(blkdev_open(&inode, &filp) == 0 ){
  11844. +        do_load();
  11845. +        if(filp.f_op && filp.f_op->release)
  11846. +            filp.f_op->release(&inode,&filp);
  11847. +    }
  11848. +}
  11849. diff -r -u -N linux.orig/arch/arm/drivers/char/Makefile linux.arm/arch/arm/drivers/char/Makefile
  11850. --- linux.orig/arch/arm/drivers/char/Makefile    Thu Jan  1 01:00:00 1970
  11851. +++ linux.arm/arch/arm/drivers/char/Makefile    Fri Oct 27 23:14:21 1995
  11852. @@ -0,0 +1,81 @@
  11853. +#
  11854. +# Makefile for the kernel character device drivers.
  11855. +#
  11856. +# Note! Dependencies are done automagically by 'make dep', which also
  11857. +# removes any old dependencies. DON'T put your own dependencies here
  11858. +# unless it's something special (ie not a .c file).
  11859. +#
  11860. +# Note 2! The CFLAGS definitions are now inherited from the
  11861. +# parent makes..
  11862. +#
  11863. +
  11864. +.c.s:
  11865. +    $(CC) $(CFLAGS) -S $<
  11866. +.s.o:
  11867. +    $(AS) -c -o $*.o $<
  11868. +.c.o:
  11869. +    $(CC) $(CFLAGS) -c $<
  11870. +
  11871. +OBJS  = tty_io.o n_tty.o console.o keyboard.o serial.o \
  11872. +    tty_ioctl.o pty.o vt.o mem.o \
  11873. +    defkeymap.o consolemap.o arcmouse.o ptr.o iic.o \
  11874. +    vc_screen.o
  11875. +# vesa_blank.o selection.o
  11876. +
  11877. +SRCS  = tty_io.c n_tty.c console.c keyboard.c serial.c \
  11878. +    tty_ioctl.c pty.c vt.c mem.c \
  11879. +    defkeymap.c consolemap.c arcmouse.c ptr.c iic.c \
  11880. +    vc_screen.c
  11881. +#vc_screen.c \
  11882. +#    defkeymap.c vesa_blank.c selection.c
  11883. +
  11884. +
  11885. +ifdef CONFIG_PRINTER
  11886. +OBJS := $(OBJS) lp.o
  11887. +SRCS := $(SRCS) lp.c
  11888. +else
  11889. +MODULES := $(MODULES) lp.o
  11890. +endif
  11891. +
  11892. +ifdef CONFIG_ARMMOUSE
  11893. +OBJS := $(OBJS) arcmouse.o
  11894. +SRCS := $(SRCS) arcmouse.c
  11895. +M = 1
  11896. +endif
  11897. +
  11898. +ifdef M
  11899. +OBJS := $(OBJS) mouse.o
  11900. +SRCS := $(SRCS) mouse.c
  11901. +endif
  11902. +
  11903. +all: char.a
  11904. +
  11905. +char.a: $(OBJS)
  11906. +    $(AR) rcs char.a $(OBJS)
  11907. +    sync    
  11908. +
  11909. +ifdef MODULES
  11910. +
  11911. +modules: $(MODULES)
  11912. +    (cd ../../modules;for i in $(MODULES); do ln -sf ../drivers/char/$$i .; done)
  11913. +
  11914. +else
  11915. +
  11916. +modules:
  11917. +
  11918. +endif
  11919. +
  11920. +dep:
  11921. +    $(CPP) -M $(SRCS) > .depend
  11922. +ifdef MODULES
  11923. +    $(CPP) -M -DMODULE $(MODULES:.o=.c) >> .depend
  11924. +endif
  11925. +
  11926. +dummy:
  11927. +
  11928. +#
  11929. +# include a dependency file if one exists
  11930. +#
  11931. +ifeq (.depend,$(wildcard .depend))
  11932. +include .depend
  11933. +endif
  11934. diff -r -u -N linux.orig/arch/arm/drivers/char/arcmouse.c linux.arm/arch/arm/drivers/char/arcmouse.c
  11935. --- linux.orig/arch/arm/drivers/char/arcmouse.c    Thu Jan  1 01:00:00 1970
  11936. +++ linux.arm/arch/arm/drivers/char/arcmouse.c    Fri Oct 27 23:14:22 1995
  11937. @@ -0,0 +1,140 @@
  11938. +#include <linux/config.h>
  11939. +#include <linux/kernel.h>
  11940. +#include <linux/sched.h>
  11941. +#include <linux/errno.h>
  11942. +
  11943. +#include <asm/system.h>
  11944. +#include <asm/segment.h>
  11945. +
  11946. +#pragma no_check_stack
  11947. +
  11948. +char   mouse_buttons;
  11949. +int    mouse_dxpos;
  11950. +int    mouse_dypos;
  11951. +int    mouse_present;
  11952. +char   mouse_ready;
  11953. +char   mouse_active;
  11954. +struct wait_queue *mouse_wait;
  11955. +
  11956. +void arch_mouse_close(struct inode *inode,struct file *file)
  11957. +{
  11958. +  mouse_active=0;
  11959. +  mouse_ready =0;
  11960. +  return;
  11961. +}
  11962. +
  11963. +int arch_mouse_open(struct inode *inode,struct file *file)
  11964. +{
  11965. +  unsigned long flags;
  11966. +
  11967. +  if(!mouse_present)
  11968. +    return -EINVAL;
  11969. +
  11970. +  if(mouse_active)
  11971. +    return -EBUSY;
  11972. +
  11973. +  save_flags(flags);
  11974. +  cli();
  11975. +
  11976. +  mouse_active =1;
  11977. +  mouse_ready  =0;
  11978. +  mouse_dxpos  =0;
  11979. +  mouse_dypos  =0;
  11980. +  mouse_buttons=0;
  11981. +
  11982. +  restore_flags(flags);
  11983. +
  11984. +  return 0;
  11985. +}
  11986. +
  11987. +int arch_mouse_read(struct inode *inode,struct file *file,char *buffer,int count)
  11988. +{
  11989. +  unsigned long flags;
  11990. +  int dxpos,dypos,i,buttons;
  11991. +
  11992. +  if(count<3)
  11993. +    return -EINVAL;
  11994. +
  11995. +  if(!mouse_ready)
  11996. +    return -EAGAIN;
  11997. +
  11998. +  save_flags(flags);
  11999. +  cli();
  12000. +
  12001. +  dxpos=mouse_dxpos;
  12002. +  dypos=mouse_dypos;
  12003. +  buttons=mouse_buttons^7;
  12004. +
  12005. +  if(dxpos<-127)
  12006. +    dxpos=-127;
  12007. +  if(dxpos>127)
  12008. +    dxpos=127;
  12009. +  if(dypos<-127)
  12010. +    dypos=-127;
  12011. +  if(dypos>127)
  12012. +    dypos=127;
  12013. +
  12014. +  mouse_dxpos-=dxpos;
  12015. +  mouse_dypos-=dypos;
  12016. +  mouse_ready=0;
  12017. +
  12018. +  restore_flags(flags);
  12019. +
  12020. +  put_fs_byte((char)buttons|0x80,buffer);
  12021. +  put_fs_byte((char)dxpos,buffer+1);
  12022. +  put_fs_byte((char)dypos,buffer+2);
  12023. +  for(i=3;i<count;i++)
  12024. +    put_fs_byte(0x00,buffer+i);
  12025. +
  12026. +  return i;
  12027. +}
  12028. +
  12029. +int arch_mouse_write(struct inode *inode,struct file *file,char *buffer,int count)
  12030. +{
  12031. +  return -EINVAL;
  12032. +}
  12033. +
  12034. +int arch_mouse_select(struct inode *inode,struct file *file,int sel_type,select_table *wait)
  12035. +{
  12036. +  if(sel_type!=SEL_IN)
  12037. +    return 0;
  12038. +
  12039. +  if(mouse_ready)
  12040. +    return 1;
  12041. +
  12042. +  select_wait(&mouse_wait,wait);
  12043. +
  12044. +  return 0;
  12045. +}
  12046. +
  12047. +struct file_operations arch_mouse_fops=
  12048. +{
  12049. +  NULL,            /* mouse_seek */
  12050. +  arch_mouse_read,
  12051. +  arch_mouse_write,
  12052. +  NULL,            /* mouse_readdir */
  12053. +  arch_mouse_select,
  12054. +  NULL,            /* mouse_ioctl */
  12055. +  NULL,            /* mouse_mmap */
  12056. +  arch_mouse_open,
  12057. +  arch_mouse_close
  12058. +};
  12059. +
  12060. +unsigned long arch_mouse_init(unsigned long kmem_start)
  12061. +{
  12062. +  unsigned long flags;
  12063. +
  12064. +  save_flags(flags);
  12065. +  cli();
  12066. +
  12067. +  mouse_buttons=0;
  12068. +  mouse_dxpos  =0;
  12069. +  mouse_dypos  =0;
  12070. +  mouse_present=1;
  12071. +  mouse_ready  =0;
  12072. +  mouse_active =0;
  12073. +  mouse_wait   =NULL;
  12074. +
  12075. +  restore_flags(flags);
  12076. +  return kmem_start;
  12077. +}
  12078. diff -r -u -N linux.orig/arch/arm/drivers/char/console.c linux.arm/arch/arm/drivers/char/console.c
  12079. --- linux.orig/arch/arm/drivers/char/console.c    Thu Jan  1 01:00:00 1970
  12080. +++ linux.arm/arch/arm/drivers/char/console.c    Fri Oct 27 23:14:30 1995
  12081. @@ -0,0 +1,2663 @@
  12082. +/*
  12083. + * linux/arch/arm/drivers/char/console.c
  12084. + */
  12085. +
  12086. +/*
  12087. + *  arcscr.c
  12088. + *
  12089. + * This module exports the console io functions:
  12090. + *
  12091. + *    'int vc_allocate(unsigned int console)'
  12092. + *    'int vc_cons_allocated(unsigned int console)'
  12093. + *    'int vc_resize(unsigned long lines,unsigned long cols)'
  12094. + *    'void vc_disallocate(unsigned int currcons)'
  12095. + *
  12096. + *    'long con_init(long)'
  12097. + * S    'int con_open(struct tty_struct *tty,struct file *filp)'
  12098. + * S    'void con_write(struct tty_struct *tty)'
  12099. + * S    'void console_print(const char *b)'
  12100. + *    'void update_screen(int new_console)'
  12101. + *
  12102. + *    'void blank_screen(void)'
  12103. + *    'void unblank_screen(void)'
  12104. + *    'void poke_blanked_console(void)'
  12105. + *    'void scrollback(int lines)'            *
  12106. + *    'void scrollfront(int lines)'            *
  12107. + *    'int do_screendump(int arg)'
  12108. + *
  12109. + *    'int con_get_font(char *)'
  12110. + *    'int con_set_font(char *)'
  12111. + *    'int con_get_trans(char *)'
  12112. + *    'int con_set_trans(char *)'
  12113. + *
  12114. + *    'int set_selection(const int arg)'        *
  12115. + *    'int paste_selection(struct tty_struct *tty)'    *
  12116. + *    'int sel_loadlut(const int arg)'        *
  12117. + *    'int mouse_reporting(void)'            *
  12118. + *
  12119. + */
  12120. +
  12121. +#define BLANK 0x0020
  12122. +
  12123. +/* A bitmap for codes <32. A bit of 1 indicates that the code
  12124. + * corresponding to that bit number invokes a special action
  12125. + * (such as cursor movement) and should not be displayed as a
  12126. + * glyph unless the disp_ctrl mode is explicitly enabled.
  12127. + */
  12128. +#define CTRL_ACTION 0xd00ff80
  12129. +#include <linux/config.h>
  12130. +#include <linux/sched.h>
  12131. +#include <linux/timer.h>
  12132. +#include <linux/interrupt.h>
  12133. +#include <linux/tty.h>
  12134. +#include <linux/tty_flip.h>
  12135. +#include <linux/kernel.h>
  12136. +#include <linux/errno.h>
  12137. +#include <linux/kd.h>
  12138. +#include <linux/major.h>
  12139. +#include <linux/mm.h>
  12140. +#include <linux/malloc.h>
  12141. +
  12142. +#include <asm/segment.h>
  12143. +#include <asm/irq-no.h>
  12144. +
  12145. +#include "kbd_kern.h"
  12146. +#include "vt_kern.h"
  12147. +#include "consolemap.h"
  12148. +
  12149. +/* ARM Extensions */
  12150. +extern void memc_write (int reg, int val);
  12151. +extern void vidc_write (int reg, int val);
  12152. +extern void ll_char_write(unsigned long ps, int ch, unsigned char forec,
  12153. +             unsigned char backc, unsigned char flgs);
  12154. +extern void memfastset (void *ptr, unsigned long word, int length);
  12155. +extern void prints (const char *, ...);
  12156. +extern void map_screen_mem (unsigned long vid_base, int remap);
  12157. +static void ll_erase(int currcons,unsigned char sx,unsigned char sy,
  12158. +            unsigned char cx,unsigned char cy);
  12159. +static void vsync_irq(int irq, struct pt_regs *regs);
  12160. +static void put_cursor(char on_off,unsigned long cpp);
  12161. +unsigned char bytes_per_char_h;
  12162. +unsigned char bytes_per_char_v;
  12163. +unsigned long video_addr_mask;
  12164. +/* MUST get rid of these */
  12165. +#define BOLD        0x01
  12166. +#define ITALIC        0x02
  12167. +#define UNDERLINE    0x04
  12168. +#define FLASH        0x08
  12169. +#define INVERSE        0x10
  12170. +#define FLAGS ((underline?UNDERLINE:0)|(reverse?INVERSE:0)|(blink?FLASH:0)|intensity)
  12171. +
  12172. +#include <linux/ctype.h>
  12173. +
  12174. +/* Routines for selection control. */
  12175. +int set_selection(const int arg, struct tty_struct *tty);
  12176. +int paste_selection(struct tty_struct *tty);
  12177. +static void clear_selection(void);
  12178. +static void highlight_pointer(const int currcons,const int where);
  12179. +
  12180. +#define SEL_BUFFER_SIZE 4096
  12181. +int sel_cons = 0;
  12182. +static int sel_start = -1;
  12183. +static int sel_end;
  12184. +static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' };
  12185. +
  12186. +
  12187. +
  12188. +#ifndef MIN
  12189. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  12190. +#endif
  12191. +
  12192. +struct tty_driver console_driver;
  12193. +static int console_refcount;
  12194. +static struct tty_struct *console_table[MAX_NR_CONSOLES];
  12195. +static struct termios *console_termios[MAX_NR_CONSOLES];
  12196. +static struct termios *console_termios_locked[MAX_NR_CONSOLES];
  12197. +
  12198. +#define NPAR 16
  12199. +
  12200. +static void con_setsize(unsigned long rows, unsigned long cols);
  12201. +static void vc_init(unsigned int console, unsigned long rows, unsigned long cols,
  12202. +            int do_clear);
  12203. +static void get_scrmem(int currcons);
  12204. +static void set_scrmem(int currcons, long offset);
  12205. +static void set_origin(int currcons);
  12206. +static void blank_screen(void);
  12207. +static void unblank_screen(void);
  12208. +void poke_blanked_console(void);
  12209. +static void gotoxy(int currcons, int new_x, int new_y);
  12210. +static void save_cur(int currcons);
  12211. +static inline void set_cursor(int currcons);
  12212. +static void reset_terminal(int currcons, int do_clear);
  12213. +extern void reset_vc(unsigned int new_console);
  12214. +extern void vt_init(void);
  12215. +extern void register_console(void (*proc)(const char *));
  12216. +extern void compute_shiftstate(void);
  12217. +extern int conv_uni_to_pc(unsigned long ucs);
  12218. +
  12219. +/* Description of the hardware situation */
  12220. +static unsigned long    video_mem_base;        /* Base of video memory        */
  12221. +static unsigned long    video_mem_term;        /* End of video memory        */
  12222. +       unsigned long    video_num_columns;    /* Number of text columns    */
  12223. +static unsigned long    video_num_lines;    /* Number of text lines        */
  12224. +static unsigned long    video_size_row;
  12225. +static unsigned long    video_screen_size;
  12226. +static unsigned long    video_buf_size;
  12227. +static int can_do_color = 1;
  12228. +static int printable = 0;            /* Is console ready for printing? */
  12229. +
  12230. +static unsigned char *vc_scrbuf[MAX_NR_CONSOLES];
  12231. +
  12232. +static int console_blanked = 0;
  12233. +static int blankinterval = 10*60*HZ;
  12234. +
  12235. +struct vc_data {
  12236. +    unsigned long    vc_screenbuf_size;
  12237. +    unsigned short    vc_video_erase_char;    /* Background erase character */
  12238. +    unsigned char    vc_attr;        /* Current attributes */
  12239. +    unsigned char    vc_def_forecol;
  12240. +    unsigned char    vc_def_backcol;
  12241. +    unsigned char    vc_forecol;
  12242. +    unsigned char    vc_backcol;
  12243. +    unsigned char    vc_s_forecol;
  12244. +    unsigned char    vc_s_backcol;
  12245. +    unsigned char    vc_cursoron;        /* Cursor on/off */
  12246. +    unsigned char    vc_ulcolor;        /* Colour for underline mode */
  12247. +    unsigned char    vc_halfcolor;        /* Colour for half intensity mode */
  12248. +    unsigned long    vc_origin;        /* Used for EGA/VGA fast scroll    */
  12249. +    unsigned long    vc_scr_end;        /* Used for EGA/VGA fast scroll    */
  12250. +    unsigned long    vc_pos;
  12251. +    unsigned long    vc_x,vc_y;
  12252. +    unsigned long    vc_top,vc_bottom;
  12253. +    unsigned long    vc_cstate;
  12254. +    unsigned long    vc_npar,vc_par[NPAR];
  12255. +    unsigned long    vc_video_mem_start;    /* Start of video RAM        */
  12256. +    unsigned long    vc_video_mem_end;    /* End of video RAM (sort of)    */
  12257. +    unsigned long    vc_saved_x;
  12258. +    unsigned long    vc_saved_y;
  12259. +    /* mode flags */
  12260. +    unsigned long    vc_charset    : 1;    /* Character set G0 / G1 */
  12261. +    unsigned long    vc_s_charset    : 1;    /* Saved character set */
  12262. +    unsigned long    vc_disp_ctrl    : 1;    /* Display chars < 32? */
  12263. +    unsigned long    vc_toggle_meta    : 1;    /* Toggle high bit? */
  12264. +    unsigned long    vc_decscnm    : 1;    /* Screen Mode */
  12265. +    unsigned long    vc_decom    : 1;    /* Origin Mode */
  12266. +    unsigned long    vc_decawm    : 1;    /* Autowrap Mode */
  12267. +    unsigned long    vc_deccm    : 1;    /* Cursor Visible */
  12268. +    unsigned long    vc_decim    : 1;    /* Insert Mode */
  12269. +    unsigned long    vc_deccolm    : 1;    /* 80/132 Column Mode */
  12270. +    /* attribute flags */
  12271. +    unsigned long    vc_intensity    : 2;    /* 0=half-bright, 1=normal, 2=bold */
  12272. +    unsigned long    vc_underline    : 1;
  12273. +    unsigned long    vc_blink    : 1;
  12274. +    unsigned long    vc_reverse    : 1;
  12275. +    unsigned long    vc_s_intensity    : 2;    /* saved rendition */
  12276. +    unsigned long    vc_s_underline    : 1;
  12277. +    unsigned long    vc_s_blink    : 1;
  12278. +    unsigned long    vc_s_reverse    : 1;
  12279. +    /* misc */
  12280. +    unsigned long    vc_ques        : 1;
  12281. +    unsigned long    vc_need_wrap    : 1;
  12282. +    unsigned long    vc_has_scrolled : 1;    /* Info for unblank_screen */
  12283. +    unsigned long    vc_kmalloced    : 1;    /* kfree_s() needed */
  12284. +    unsigned long    vc_report_mouse : 2;
  12285. +    unsigned char    vc_utf        : 1;    /* Unicode UTF-8 encoding */
  12286. +    unsigned char    vc_utf_count;
  12287. +    unsigned long    vc_utf_char;
  12288. +    unsigned long    vc_tab_stop[5];        /* Tab stops. 160 columns. */
  12289. +    unsigned char * vc_translate;
  12290. +    unsigned char     vc_G0_charset;
  12291. +    unsigned char     vc_G1_charset;
  12292. +    unsigned char     vc_saved_G0;
  12293. +    unsigned char     vc_saved_G1;
  12294. +    unsigned long * vc_paletteentries;
  12295. +    /* additional information is in vt_kern.h */
  12296. +};
  12297. +
  12298. +static struct vc {
  12299. +    struct vc_data *d;
  12300. +
  12301. +    /* might add  scrmem, vt_struct, kbd  at some time,
  12302. +       to have everything in one place - the disadvantage
  12303. +       would be that vc_cons etc can no longer be static */
  12304. +} vc_cons [MAX_NR_CONSOLES];
  12305. +
  12306. +#define screenbuf_size    (vc_cons[currcons].d->vc_screenbuf_size)
  12307. +#define origin        (vc_cons[currcons].d->vc_origin)
  12308. +#define scr_end        (vc_cons[currcons].d->vc_scr_end)
  12309. +#define pos        (vc_cons[currcons].d->vc_pos)
  12310. +#define top        (vc_cons[currcons].d->vc_top)
  12311. +#define bottom        (vc_cons[currcons].d->vc_bottom)
  12312. +#define x        (vc_cons[currcons].d->vc_x)
  12313. +#define y        (vc_cons[currcons].d->vc_y)
  12314. +#define vc_state    (vc_cons[currcons].d->vc_cstate)
  12315. +#define npar        (vc_cons[currcons].d->vc_npar)
  12316. +#define par        (vc_cons[currcons].d->vc_par)
  12317. +#define ques        (vc_cons[currcons].d->vc_ques)
  12318. +#define attr        (vc_cons[currcons].d->vc_attr)
  12319. +#define saved_x        (vc_cons[currcons].d->vc_saved_x)
  12320. +#define saved_y        (vc_cons[currcons].d->vc_saved_y)
  12321. +#define translate    (vc_cons[currcons].d->vc_translate)
  12322. +#define G0_charset    (vc_cons[currcons].d->vc_G0_charset)
  12323. +#define G1_charset    (vc_cons[currcons].d->vc_G1_charset)
  12324. +#define saved_G0    (vc_cons[currcons].d->vc_saved_G0)
  12325. +#define saved_G1    (vc_cons[currcons].d->vc_saved_G1)
  12326. +#define utf        (vc_cons[currcons].d->vc_utf)
  12327. +#define utf_count    (vc_cons[currcons].d->vc_utf_count)
  12328. +#define utf_char    (vc_cons[currcons].d->vc_utf_char)
  12329. +#define video_mem_start    (vc_cons[currcons].d->vc_video_mem_start)
  12330. +#define video_mem_end    (vc_cons[currcons].d->vc_video_mem_end)
  12331. +#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)
  12332. +#define disp_ctrl    (vc_cons[currcons].d->vc_disp_ctrl)
  12333. +#define toggle_meta    (vc_cons[currcons].d->vc_toggle_meta)
  12334. +#define decscnm        (vc_cons[currcons].d->vc_decscnm)
  12335. +#define decom        (vc_cons[currcons].d->vc_decom)
  12336. +#define decawm        (vc_cons[currcons].d->vc_decawm)
  12337. +#define deccm        (vc_cons[currcons].d->vc_deccm)
  12338. +#define decim        (vc_cons[currcons].d->vc_decim)
  12339. +#define deccolm         (vc_cons[currcons].d->vc_deccolm)
  12340. +#define need_wrap    (vc_cons[currcons].d->vc_need_wrap)
  12341. +#define has_scrolled    (vc_cons[currcons].d->vc_has_scrolled)
  12342. +#define kmalloced    (vc_cons[currcons].d->vc_kmalloced)
  12343. +#define report_mouse    (vc_cons[currcons].d->vc_report_mouse)
  12344. +#define forecol        (vc_cons[currcons].d->vc_forecol)
  12345. +#define backcol        (vc_cons[currcons].d->vc_backcol)
  12346. +#define s_forecol    (vc_cons[currcons].d->vc_s_forecol)
  12347. +#define s_backcol    (vc_cons[currcons].d->vc_s_backcol)
  12348. +#define def_forecol    (vc_cons[currcons].d->vc_def_forecol)
  12349. +#define def_backcol    (vc_cons[currcons].d->vc_def_backcol)
  12350. +#define cursoron    (vc_cons[currcons].d->vc_cursoron)
  12351. +#define charset        (vc_cons[currcons].d->vc_charset)
  12352. +#define s_charset    (vc_cons[currcons].d->vc_s_charset)
  12353. +#define    intensity    (vc_cons[currcons].d->vc_intensity)
  12354. +#define    underline    (vc_cons[currcons].d->vc_underline)
  12355. +#define    blink        (vc_cons[currcons].d->vc_blink)
  12356. +#define    reverse        (vc_cons[currcons].d->vc_reverse)
  12357. +#define    s_intensity    (vc_cons[currcons].d->vc_s_intensity)
  12358. +#define    s_underline    (vc_cons[currcons].d->vc_s_underline)
  12359. +#define    s_blink        (vc_cons[currcons].d->vc_s_blink)
  12360. +#define    s_reverse    (vc_cons[currcons].d->vc_s_reverse)
  12361. +#define tab_stop    (vc_cons[currcons].d->vc_tab_stop)
  12362. +#define paletteentries    (vc_cons[currcons].d->vc_paletteentries)
  12363. +
  12364. +#define vcmode        (vt_cons[currcons]->vc_mode)
  12365. +#define structsize    (sizeof(struct vc_data) + sizeof(struct vt_struct))
  12366. +
  12367. +/* ARC Extention */
  12368. +char cmap_80[][8]=
  12369. +{
  12370. + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /*   */
  12371. + {0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x00}, /* ! */
  12372. + {0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, /* " */
  12373. + {0x36,0x36,0x7F,0x36,0x7F,0x36,0x36,0x00}, /* # */
  12374. + {0x0C,0x3F,0x68,0x3E,0x0B,0x7E,0x18,0x00}, /* $ */
  12375. + {0x60,0x66,0x0C,0x18,0x30,0x66,0x06,0x00}, /* % */
  12376. + {0x38,0x6C,0x6C,0x38,0x6D,0x66,0x3B,0x00}, /* & */
  12377. + {0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, /* ' */
  12378. + {0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, /* ( */
  12379. + {0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, /* ) */
  12380. + {0x00,0x18,0x7E,0x3C,0x7E,0x18,0x00,0x00}, /* * */
  12381. + {0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00}, /* + */
  12382. + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, /* , */
  12383. + {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, /* - */
  12384. + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, /* . */
  12385. + {0x00,0x06,0x0C,0x18,0x30,0x60,0x00,0x00}, /* / */
  12386. + {0x3C,0x66,0x6E,0x7E,0x76,0x66,0x3C,0x00}, /* 0 */
  12387. + {0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00}, /* 1 */
  12388. + {0x3C,0x66,0x06,0x0C,0x18,0x30,0x7E,0x00}, /* 2 */
  12389. + {0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, /* 3 */
  12390. + {0x0C,0x1C,0x3C,0x6C,0x7E,0x0C,0x0C,0x00}, /* 4 */
  12391. + {0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, /* 5 */
  12392. + {0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, /* 6 */
  12393. + {0x7E,0x06,0x0C,0x18,0x30,0x30,0x30,0x00}, /* 7 */
  12394. + {0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, /* 8 */
  12395. + {0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, /* 9 */
  12396. + {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x00}, /* : */
  12397. + {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x30}, /* ; */
  12398. + {0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, /* < */
  12399. + {0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00}, /* = */
  12400. + {0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, /* > */
  12401. + {0x3C,0x66,0x0C,0x18,0x18,0x00,0x18,0x00}, /* ? */
  12402. + {0x3C,0x66,0x6E,0x6A,0x6E,0x60,0x3C,0x00}, /* @ */
  12403. + {0x3C,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, /* A */
  12404. + {0x7C,0x66,0x66,0x7C,0x66,0x66,0x7C,0x00}, /* B */
  12405. + {0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x00}, /* C */
  12406. + {0x78,0x6C,0x66,0x66,0x66,0x6C,0x78,0x00}, /* D */
  12407. + {0x7E,0x60,0x60,0x7C,0x60,0x60,0x7E,0x00}, /* E */
  12408. + {0x7E,0x60,0x60,0x7C,0x60,0x60,0x60,0x00}, /* F */
  12409. + {0x3C,0x66,0x60,0x6E,0x66,0x66,0x3C,0x00}, /* G */
  12410. + {0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, /* H */
  12411. + {0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00}, /* I */
  12412. + {0x3E,0x0C,0x0C,0x0C,0x0C,0x6C,0x38,0x00}, /* J */
  12413. + {0x66,0x6C,0x78,0x70,0x78,0x6C,0x66,0x00}, /* K */
  12414. + {0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00}, /* L */
  12415. + {0x63,0x77,0x7F,0x6B,0x6B,0x63,0x63,0x00}, /* M */
  12416. + {0x66,0x66,0x76,0x7E,0x6E,0x66,0x66,0x00}, /* N */
  12417. + {0x3C,0x66,0x66,0x66,0x66,0x66,0x3C,0x00}, /* O */
  12418. + {0x7C,0x66,0x66,0x7C,0x60,0x60,0x60,0x00}, /* P */
  12419. + {0x3C,0x66,0x66,0x66,0x6A,0x6C,0x36,0x00}, /* Q */
  12420. + {0x7C,0x66,0x66,0x7C,0x6C,0x66,0x66,0x00}, /* R */
  12421. + {0x3C,0x66,0x60,0x3C,0x06,0x66,0x3C,0x00}, /* S */
  12422. + {0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, /* T */
  12423. + {0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00}, /* U */
  12424. + {0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, /* V */
  12425. + {0x63,0x63,0x6B,0x6B,0x7F,0x77,0x63,0x00}, /* W */
  12426. + {0x66,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00}, /* X */
  12427. + {0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00}, /* Y */
  12428. + {0x7E,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00}, /* Z */
  12429. + {0x7C,0x60,0x60,0x60,0x60,0x60,0x7C,0x00}, /* [ */
  12430. + {0x00,0x60,0x30,0x18,0x0C,0x06,0x00,0x00}, /* \ */
  12431. + {0x3E,0x06,0x06,0x06,0x06,0x06,0x3E,0x00}, /* ] */
  12432. + {0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00}, /* ^ */
  12433. + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, /* _ */
  12434. + {0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00}, /* ` */
  12435. + {0x00,0x00,0x3C,0x06,0x3E,0x66,0x3E,0x00}, /* a */
  12436. + {0x60,0x60,0x7C,0x66,0x66,0x66,0x7C,0x00}, /* b */
  12437. + {0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, /* c */
  12438. + {0x06,0x06,0x3E,0x66,0x66,0x66,0x3E,0x00}, /* d */
  12439. + {0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, /* e */
  12440. + {0x1C,0x30,0x30,0x7C,0x30,0x30,0x30,0x00}, /* f */
  12441. + {0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x3C}, /* g */
  12442. + {0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x00}, /* h */
  12443. + {0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, /* i */
  12444. + {0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x70}, /* j */
  12445. + {0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00}, /* k */
  12446. + {0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, /* l */
  12447. + {0x00,0x00,0x36,0x7F,0x6B,0x6B,0x63,0x00}, /* m */
  12448. + {0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, /* n */
  12449. + {0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, /* o */
  12450. + {0x00,0x00,0x7C,0x66,0x66,0x7C,0x60,0x60}, /* p */
  12451. + {0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x07}, /* q */
  12452. + {0x00,0x00,0x6C,0x76,0x60,0x60,0x60,0x00}, /* r */
  12453. + {0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, /* s */
  12454. + {0x30,0x30,0x7C,0x30,0x30,0x30,0x1C,0x00}, /* t */
  12455. + {0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x00}, /* u */
  12456. + {0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, /* v */
  12457. + {0x00,0x00,0x63,0x6B,0x6B,0x7F,0x36,0x00}, /* w */
  12458. + {0x00,0x00,0x66,0x3C,0x18,0x3C,0x66,0x00}, /* x */
  12459. + {0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x3C}, /* y */
  12460. + {0x00,0x00,0x7E,0x0C,0x18,0x30,0x7E,0x00}, /* z */
  12461. + {0x0C,0x18,0x18,0x70,0x18,0x18,0x0C,0x00}, /* { */
  12462. + {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, /* | */
  12463. + {0x30,0x18,0x18,0x0E,0x18,0x18,0x30,0x00}, /* } */
  12464. + {0x31,0x6B,0x46,0x00,0x00,0x00,0x00,0x00}, /* ~ */
  12465. + {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}  /*  */
  12466. +};
  12467. +
  12468. +static unsigned long palette_4[]=
  12469. +{
  12470. +    0x1000,       /* Black */
  12471. +    0x100D,       /* Red */
  12472. +    0x10D0,       /* Green */
  12473. +    0x10DD,       /* Yellow */
  12474. +    0x1D00,       /* Blue */
  12475. +    0x1D0D,       /* Magenta */
  12476. +    0x1DD0,       /* Cyan */
  12477. +    0x1DDD,       /* White */
  12478. +    0x1000,
  12479. +    0x100F,
  12480. +    0x10F0,
  12481. +    0x10FF,
  12482. +    0x1F00,
  12483. +    0x1F0F,
  12484. +    0x1FF0,
  12485. +    0x1FFF,
  12486. +    0x1000
  12487. +};
  12488. +
  12489. +static unsigned long palette_8[]=
  12490. +{
  12491. +    0x1000,
  12492. +    0x1111,
  12493. +    0x1222,
  12494. +    0x1333,
  12495. +    0x1400,
  12496. +    0x1511,
  12497. +    0x1622,
  12498. +    0x1733,
  12499. +    0x1004,
  12500. +    0x1115,
  12501. +    0x1226,
  12502. +    0x1337,
  12503. +    0x1404,
  12504. +    0x1515,
  12505. +    0x1626,
  12506. +    0x1737,
  12507. +    0x1000
  12508. +};
  12509. +
  12510. +static unsigned long *default_palette_entries = palette_4;
  12511. +
  12512. +/* -------------------------------------------------------------------------------
  12513. + * Low level char write
  12514. + * ------------------------------------------------------------------------------- */
  12515. +
  12516. +static inline void charwrite(int currcons,unsigned long ps,int ch)
  12517. +{
  12518. +  unsigned long *buffer = (unsigned long *)vc_scrbuf[currcons];
  12519. +  unsigned int index;
  12520. +  unsigned char flgs;
  12521. +
  12522. +  flgs=FLAGS;
  12523. +
  12524. +  if(currcons == fg_console)
  12525. +    ll_char_write(ps, ch, forecol, backcol, flgs);
  12526. +
  12527. +  index = (x + y * video_num_columns);
  12528. +
  12529. +  buffer[index] = (flgs<<24)|(backcol<<16)|(forecol<<8)|ch;
  12530. +}
  12531. +
  12532. +static char cursor_on=0;
  12533. +unsigned long cp;
  12534. +
  12535. +static inline void remove_cursors(int currcons)
  12536. +{
  12537. +  unsigned long flags;
  12538. +
  12539. +  save_flags(flags);
  12540. +  cli();
  12541. +  if(--cursoron==0 && currcons == fg_console)
  12542. +    put_cursor(0, cp);
  12543. +  restore_flags(flags);
  12544. +}
  12545. +
  12546. +static inline void restore_cursors(int currcons)
  12547. +{
  12548. +  unsigned long flags;
  12549. +
  12550. +  save_flags(flags);
  12551. +  cli();
  12552. +  if(++cursoron==1 && cursor_on && currcons == fg_console)
  12553. +    put_cursor(1,cp);
  12554. +  restore_flags(flags);
  12555. +}
  12556. +
  12557. +/* -----------------------------------------------------------------------------------------
  12558. + * VC stuff
  12559. + * ----------------------------------------------------------------------------------------- */
  12560. +
  12561. +int vc_cons_allocated(unsigned int i)
  12562. +{
  12563. +      return (i < MAX_NR_CONSOLES && vc_cons[i].d);
  12564. +}
  12565. +
  12566. +int vc_allocate(unsigned int i)
  12567. +{
  12568. +    if (i >= MAX_NR_CONSOLES)
  12569. +      return -ENODEV;
  12570. +    if (!vc_cons[i].d) {
  12571. +        long p, q;
  12572. +
  12573. +        /* prevent users from taking too much memory */
  12574. +        if (i >= MAX_NR_USER_CONSOLES && !suser())
  12575. +          return -EPERM;
  12576. +
  12577. +        /* due to the granularity of kmalloc, we waste some memory here */
  12578. +        /* the alloc is done in two steps, to optimize the common situation
  12579. +           of a 25x80 console (structsize=216, video_screen_size=4000) */
  12580. +        q = (long) kmalloc(video_buf_size, GFP_KERNEL);
  12581. +        if (!q)
  12582. +          return -ENOMEM;
  12583. +        p = (long) kmalloc(structsize, GFP_KERNEL);
  12584. +        if (!p) {
  12585. +        kfree_s((char *) q, video_buf_size);
  12586. +        return -ENOMEM;
  12587. +        }
  12588. +
  12589. +        memset((void *)q, 0, video_buf_size);
  12590. +
  12591. +        vc_cons[i].d = (struct vc_data *) p;
  12592. +        p += sizeof(struct vc_data);
  12593. +        vt_cons[i] = (struct vt_struct *) p;
  12594. +        vc_scrbuf[i] = (unsigned char *) q;
  12595. +        vc_cons[i].d->vc_kmalloced = 1;
  12596. +        vc_cons[i].d->vc_screenbuf_size = video_buf_size;
  12597. +        vc_init (i, video_num_lines, video_num_columns, 1);
  12598. +    }
  12599. +    return 0;
  12600. +}
  12601. +
  12602. +int vc_resize(unsigned long lines, unsigned long cols)
  12603. +{/* TODO */
  12604. +    return -ENOMEM;
  12605. +}
  12606. +
  12607. +void vc_disallocate(unsigned int currcons)
  12608. +{
  12609. +    if(vc_cons_allocated(currcons))
  12610. +    {
  12611. +      if(kmalloced)
  12612. +        kfree_s(vc_scrbuf[currcons], screenbuf_size);
  12613. +      if(currcons >= MIN_NR_CONSOLES)
  12614. +        kfree_s(vc_cons[currcons].d, structsize);
  12615. +      vc_cons[currcons].d = 0;
  12616. +    }
  12617. +}
  12618. +
  12619. +#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
  12620. +#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
  12621. +#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
  12622. +
  12623. +#define decarm        VC_REPEAT
  12624. +#define decckm        VC_CKMODE
  12625. +#define kbdapplic    VC_APPLIC
  12626. +#define lnm        VC_CRLF
  12627. +
  12628. +/*
  12629. + * this is what the terminal answers to a ESC-Z or csi0c query.
  12630. + */
  12631. +#define VT100ID "\033[?1;2c"
  12632. +#define VT102ID "\033[?6c"
  12633. +
  12634. +static unsigned char color_4[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 };
  12635. +static unsigned char color_8[] = {0x00, 0x1B, 0x63, 0x7B, 0x87, 0x9F, 0xE7, 0xFF,
  12636. +                                  0x00, 0x1B, 0x63, 0x7B, 0x87, 0x9F, 0xE7, 0xFF};
  12637. +static unsigned char *color_table = color_4;
  12638. +
  12639. +/*
  12640. + * gotoxy() must verify all boundaries, because the arguments
  12641. + * might also be negative. If a given position is out of
  12642. + * bounds, the cursor is placed at the nearest margin.
  12643. + */
  12644. +static void gotoxy(int currcons,int new_x,int new_y)
  12645. +{
  12646. +  int max_y;
  12647. +
  12648. +  if(new_x<0)
  12649. +    x = 0;
  12650. +  else
  12651. +  if(new_x>=video_num_columns)
  12652. +    x = video_num_columns-1;
  12653. +  else
  12654. +    x = new_x;
  12655. +
  12656. +  if(decom)
  12657. +  {
  12658. +    new_y += top;
  12659. +    max_y = bottom;
  12660. +  }
  12661. +  else
  12662. +    max_y=video_num_lines;
  12663. +
  12664. +  if(new_y < 0)
  12665. +    y = 0;
  12666. +  else
  12667. +  if(new_y >= max_y)
  12668. +    y = max_y-1;
  12669. +  else
  12670. +    y = new_y;
  12671. +
  12672. +  pos = origin + (y*video_num_columns*bytes_per_char_v+x)*bytes_per_char_h;
  12673. +  need_wrap=0;
  12674. +}
  12675. +
  12676. +static unsigned long __real_origin;
  12677. +static unsigned long __origin;        /* Offset of currently displayed screen */
  12678. +
  12679. +static void __set_origin(unsigned long offset)
  12680. +{
  12681. +  unsigned long flags;
  12682. +  clear_selection();
  12683. +  save_flags(flags); cli();
  12684. +  __origin = offset;
  12685. +
  12686. +  memc_write(0,offset>>2);
  12687. +  memc_write(1,0);
  12688. +  memc_write(2,video_addr_mask>>2);
  12689. +  restore_flags(flags);
  12690. +}
  12691. +
  12692. +/*
  12693. +void scrollback(int lines)
  12694. +{
  12695. +}
  12696. +
  12697. +void scrollfront(int lines)
  12698. +{
  12699. +}
  12700. + */
  12701. +
  12702. +static void set_origin(int currcons)
  12703. +{
  12704. +    if(currcons != fg_console || vcmode == KD_GRAPHICS)
  12705. +        return;
  12706. +    __real_origin = origin - video_mem_start;
  12707. +    if(__real_origin >= video_addr_mask)
  12708. +        __real_origin -= video_addr_mask;
  12709. +    __set_origin(__real_origin);
  12710. +}
  12711. +
  12712. +static void hide_cursor(void)
  12713. +{
  12714. +    put_cursor(0,-1);
  12715. +}
  12716. +
  12717. +static void set_cursor(int currcons)
  12718. +{
  12719. +    unsigned long flags;
  12720. +
  12721. +    if(currcons != fg_console || vcmode == KD_GRAPHICS)
  12722. +        return;
  12723. +
  12724. +    if(__real_origin != __origin)
  12725. +        __set_origin(__real_origin);
  12726. +    save_flags(flags);
  12727. +    cli();
  12728. +
  12729. +    if(deccm)
  12730. +        cp = pos + video_num_columns * bytes_per_char_h * (bytes_per_char_v - 1);
  12731. +    else
  12732. +        hide_cursor();
  12733. +    restore_flags(flags);
  12734. +}
  12735. +
  12736. +/* --------------------------------------------------------------------------------
  12737. + * Screen scrolling
  12738. + * -------------------------------------------------------------------------------- */
  12739. +
  12740. +static void scrup(int currcons,unsigned int t, unsigned int b,unsigned char l)
  12741. +{
  12742. +    unsigned char flgs;
  12743. +
  12744. +    if(b > video_num_columns || t >= b)
  12745. +        return;
  12746. +
  12747. +    if(currcons == fg_console)
  12748. +    {
  12749. +        if(t || b != video_num_lines)
  12750. +        {
  12751. +            if(l<t-b)
  12752. +                memmove((void*)(origin+t*video_size_row),
  12753. +                        (void*)(origin+(t+l)*video_size_row),
  12754. +                        (b-t-l)*video_size_row);
  12755. +            else
  12756. +            if(l>b-t)
  12757. +                l=b-t;
  12758. +
  12759. +            memfastset((void*)(origin+(b-l)*video_size_row),
  12760. +                    0x11111111*backcol,l*video_size_row);
  12761. +        }
  12762. +        else
  12763. +        {
  12764. +            memfastset((void*)(origin+l*video_size_row*video_num_lines),
  12765. +                0x11111111L*backcol,l*video_size_row);
  12766. +            pos-=origin;
  12767. +            origin+=l*video_size_row;
  12768. +            if(origin>=video_mem_term)
  12769. +                origin=origin-video_mem_term+video_mem_base;
  12770. +            pos+=origin;
  12771. +            set_origin(currcons);
  12772. +        }
  12773. +    }
  12774. +    else
  12775. +    {
  12776. +        if(!t && b == video_num_lines)
  12777. +        {
  12778. +            pos-=origin;
  12779. +            origin+=l*video_size_row;
  12780. +            if(origin>=video_mem_term)
  12781. +                origin=origin-video_mem_term+video_mem_base;
  12782. +            pos+=origin;
  12783. +        }
  12784. +        }
  12785. +    if(l < t-b)
  12786. +        memmove((void*)(vc_scrbuf[currcons]+t*video_num_columns*4),
  12787. +            (void*)(vc_scrbuf[currcons]+(t+l)*video_num_columns*4),
  12788. +            (b-t-l)*video_num_columns*4);
  12789. +    else
  12790. +    if(l > b-t)
  12791. +        l=b-t;
  12792. +
  12793. +    flgs=FLAGS;
  12794. +
  12795. +    memfastset((void*)(vc_scrbuf[currcons]+(b-l)*video_num_columns*4),
  12796. +        (flgs << 24)|(backcol << 16)|(forecol << 8)|32,
  12797. +        l*video_num_columns*4);
  12798. +}
  12799. +
  12800. +static void scrdown(int currcons,unsigned int t,unsigned int b,unsigned char l)
  12801. +{
  12802. +    unsigned char flgs;
  12803. +
  12804. +    if(b>video_num_columns || t >= b)
  12805. +        return;
  12806. +
  12807. +    if(currcons == fg_console)
  12808. +    {
  12809. +        if(t || b != video_num_lines)
  12810. +        {
  12811. +            if(l<t-b)
  12812. +                memmove((void*)(origin+(t+l)*video_size_row),
  12813. +                        (void*)(origin+t*video_size_row),
  12814. +                        (b-t-l)*video_size_row);
  12815. +            else
  12816. +            if(l>b-t)
  12817. +                l=b-t;
  12818. +
  12819. +            memfastset((void*)(origin+t*video_size_row),
  12820. +                    0x11111111*backcol,l*video_size_row);
  12821. +        }
  12822. +        else
  12823. +        {
  12824. +            pos-=origin;
  12825. +            origin-=l*video_size_row;
  12826. +            if(origin<video_mem_base)
  12827. +                origin=origin-video_mem_base+video_mem_term;
  12828. +            pos+=origin;
  12829. +            memfastset((void*)origin,0x11111111L*backcol,l*video_size_row);
  12830. +            set_origin(currcons);
  12831. +        }
  12832. +    }
  12833. +    else
  12834. +    {
  12835. +        if(!t && b == video_num_lines)
  12836. +        {
  12837. +            pos-=origin;
  12838. +            origin-=l*video_size_row;
  12839. +            if(origin<video_mem_base)
  12840. +                origin=origin-video_mem_base+video_mem_term;
  12841. +            pos+=origin;
  12842. +        }
  12843. +    }
  12844. +    if(l < t-b)
  12845. +        memmove((void*)(vc_scrbuf[currcons]+(t+l)*video_num_columns*4),
  12846. +            (void*)(vc_scrbuf[currcons]+t*video_num_columns*4),
  12847. +            (b-t-l)*video_num_columns*4);
  12848. +    else
  12849. +    if(l > b-t)
  12850. +        l = b-t;
  12851. +
  12852. +    flgs=FLAGS;
  12853. +    memfastset((void*)(vc_scrbuf[currcons]+t*video_num_columns*4),
  12854. +        (flgs << 24)|(backcol << 16)|(forecol << 8)|32,
  12855. +        l*video_num_columns*4);
  12856. +}
  12857. +
  12858. +static void lf(int currcons)
  12859. +{
  12860. +    if (y + 1 < bottom) {
  12861. +        y++;
  12862. +        pos += video_size_row;
  12863. +        return;
  12864. +    }
  12865. +    scrup(currcons,top,bottom,1);
  12866. +    need_wrap=0;
  12867. +}
  12868. +
  12869. +static void ri(int currcons)
  12870. +{
  12871. +    if (y > top) {
  12872. +        y--;
  12873. +        pos -= video_size_row;
  12874. +        return;
  12875. +    }
  12876. +    scrdown(currcons,top,bottom,1);
  12877. +    need_wrap=0;
  12878. +}
  12879. +
  12880. +static inline void cr(int currcons)
  12881. +{
  12882. +    pos -= x*bytes_per_char_h;
  12883. +    need_wrap = x = 0;
  12884. +}
  12885. +
  12886. +static inline void bs(int currcons)
  12887. +{
  12888. +    if (x) {
  12889. +        if (!need_wrap) {
  12890. +            pos -= bytes_per_char_h;
  12891. +            x--;
  12892. +        }
  12893. +        need_wrap = 0;
  12894. +    }
  12895. +}
  12896. +
  12897. +static inline void del(int currcons)
  12898. +{
  12899. +  /* ignored */
  12900. +}
  12901. +
  12902. +static void csi_J(int currcons, int vpar)
  12903. +{
  12904. +    unsigned char countx,county;
  12905. +    unsigned char startx,starty;
  12906. +
  12907. +    switch(vpar) {
  12908. +        case 0: /* erase from cursor to bottom of screen */
  12909. +            startx=x;
  12910. +            starty=y;
  12911. +            countx=video_num_columns-x;
  12912. +            county=video_num_lines-y-1;
  12913. +            break;
  12914. +        case 1: /* erase from top of screen to cursor */
  12915. +            startx=0;
  12916. +            starty=0;
  12917. +            countx=x;
  12918. +            county=y;
  12919. +            break;
  12920. +        case 2: /* erase entire screen */
  12921. +            startx=0;
  12922. +            starty=0;
  12923. +            countx=video_num_columns;
  12924. +            county=video_num_lines-1;
  12925. +            origin=video_mem_base;
  12926. +            set_origin(currcons);
  12927. +            gotoxy(currcons,x,y);
  12928. +            break;
  12929. +        default:
  12930. +            return;
  12931. +    }
  12932. +    ll_erase(currcons,startx,starty,countx,county);
  12933. +    need_wrap = 0;
  12934. +}
  12935. +
  12936. +static void csi_K(int currcons, int vpar)
  12937. +{
  12938. +    unsigned char countx;
  12939. +    unsigned char startx;
  12940. +
  12941. +    switch(vpar) {
  12942. +        case 0: /* erase from cursor to end of line */
  12943. +            startx = x;
  12944. +            countx = video_num_columns - x;
  12945. +            break;
  12946. +        case 1: /* erase from beginning of line to cursor */
  12947. +            startx = 0;
  12948. +            countx = x;
  12949. +            break;
  12950. +        case 2: /* erase entire line */
  12951. +            startx=0;
  12952. +            countx=video_num_columns;
  12953. +            break;
  12954. +        default:
  12955. +            return;
  12956. +    }
  12957. +    ll_erase(currcons,startx,y,countx,0);
  12958. +    need_wrap = 0;
  12959. +}
  12960. +
  12961. +static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
  12962. +{                      /* not vt100? */
  12963. +    unsigned char countx,county;
  12964. +    unsigned char startx,starty;
  12965. +
  12966. +    if (!vpar)
  12967. +        vpar++;
  12968. +
  12969. +    startx = x;
  12970. +    starty = y;
  12971. +    countx = 0;
  12972. +    county = 0;
  12973. +#if 0 /* TODO */
  12974. +    ll_erase(currcons,startx,starty,countx,county);
  12975. +#endif
  12976. +    need_wrap = 0;
  12977. +}
  12978. +
  12979. +
  12980. +/*
  12981. +static void update_addr(int currcons)
  12982. +{
  12983. +
  12984. +}
  12985. + */
  12986. +static void default_attr(int currcons)
  12987. +{
  12988. +    underline = 0;
  12989. +    reverse = 0;
  12990. +    blink = 0;
  12991. +    intensity = 0;
  12992. +
  12993. +    forecol = def_forecol;
  12994. +    backcol = def_backcol;
  12995. +}
  12996. +
  12997. +static void csi_m(int currcons)
  12998. +{
  12999. +  int i;
  13000. +
  13001. +  for(i=0;i<=npar;i++)
  13002. +  {
  13003. +    switch(par[i])
  13004. +    {
  13005. +      case 0:    default_attr(currcons); break;
  13006. +      case 1:    intensity|=BOLD;    break;    /* Bold */
  13007. +      case 2:    intensity&=~BOLD;    break;    /* Feint */
  13008. +      case 3:    intensity|=ITALIC;    break;    /* Italic */
  13009. +      case 4:    underline = 1;        break;    /* Underline */
  13010. +      case 5:
  13011. +      case 6:    blink = 1;        break;    /* Flash */
  13012. +      case 7:    reverse = 1;        break;    /* Inverse chars */
  13013. +
  13014. +            case 10: /* ANSI X3.64-1979 (SCO-ish?)
  13015. +                  * Select primary font, don't display
  13016. +                  * control chars if defined, don't set
  13017. +                  * bit 8 on output.
  13018. +                  */
  13019. +                translate = set_translate(charset == 0
  13020. +                        ? G0_charset
  13021. +                        : G1_charset);
  13022. +                disp_ctrl = 0;
  13023. +                toggle_meta = 0;
  13024. +                break;
  13025. +            case 11: /* ANSI X3.64-1979 (SCO-ish?)
  13026. +                  * Select first alternate font, let's
  13027. +                  * chars < 32 be displayed as ROM chars.
  13028. +                  */
  13029. +                translate = set_translate(NULL_MAP);
  13030. +                disp_ctrl = 1;
  13031. +                toggle_meta = 0;
  13032. +                break;
  13033. +            case 12: /* ANSI X3.64-1979 (SCO-ish?)
  13034. +                  * Select second alternate font, toggle
  13035. +                  * high bit before displaying as ROM char.
  13036. +                  */
  13037. +                translate = set_translate(NULL_MAP);
  13038. +                disp_ctrl = 1;
  13039. +                toggle_meta = 1;
  13040. +                break;
  13041. +
  13042. +      case 21:
  13043. +      case 22:  intensity = 0;    break;
  13044. +      case 24:  underline = 0;    break;
  13045. +      case 25:  blink = 0;    break;
  13046. +      case 27:    reverse = 0;    break;
  13047. +      case 30:
  13048. +      case 31:
  13049. +      case 32:
  13050. +      case 33:
  13051. +      case 34:
  13052. +      case 35:
  13053. +      case 36:
  13054. +      case 37:  forecol=color_table[par[i]-30];        break;    /* Foreground colour */
  13055. +      case 38:  forecol=def_forecol; underline = 1;    break;
  13056. +      case 39:  forecol=def_forecol; underline = 0;    break;    /* Default foreground colour */
  13057. +      case 40:
  13058. +      case 41:
  13059. +      case 42:
  13060. +      case 43:
  13061. +      case 44:
  13062. +      case 45:
  13063. +      case 46:
  13064. +      case 47:  backcol=color_table[par[i]-40];    break;    /* Background colour */
  13065. +      case 49:  backcol=def_backcol;        break;    /* Default background colour */
  13066. +    }
  13067. +  }
  13068. +}
  13069. +
  13070. +static void respond_string(char *p,struct tty_struct *tty)
  13071. +{
  13072. +    while(*p)
  13073. +        tty_insert_flip_char(tty, *p++, 0);
  13074. +    tty_schedule_flip(tty);
  13075. +}
  13076. +
  13077. +static void cursor_report(int currcons,struct tty_struct *tty)
  13078. +{
  13079. +    char buf[40];
  13080. +
  13081. +    sprintf(buf, "\033[%ld;%ldR",y + (decom ? top+1 : 1),
  13082. +                     x + 1);
  13083. +    respond_string(buf, tty);
  13084. +}
  13085. +
  13086. +static void status_report(struct tty_struct *tty)
  13087. +{
  13088. +    respond_string("\033[0n",tty);
  13089. +}
  13090. +
  13091. +static void respond_ID(struct tty_struct *tty)
  13092. +{
  13093. +    respond_string(VT102ID,tty);
  13094. +}
  13095. +
  13096. +static void mouse_report(int currcons, struct tty_struct *tty, int butt, int mrx, int mry)
  13097. +{
  13098. +    char buf[8];
  13099. +
  13100. +    sprintf(buf,"\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
  13101. +        (char)('!'+mry));
  13102. +    respond_string(buf,tty);
  13103. +}
  13104. +
  13105. +/* invoked by ioctl(TIOCLINUX) */
  13106. +int mouse_reporting(void)
  13107. +{
  13108. +    int currcons = fg_console;
  13109. +
  13110. +    return report_mouse;
  13111. +}
  13112. +
  13113. +static void invert_screen(void)
  13114. +{
  13115. +  /* Todo */
  13116. +}
  13117. +
  13118. +unsigned long *screen_pos(int currcons, int screen_offset)
  13119. +{
  13120. +    return (unsigned long *)(vc_scrbuf[currcons] + screen_offset * 4);
  13121. +}
  13122. +
  13123. +void getconsxy(int currcons, char *p)
  13124. +{
  13125. +    p[0] = x;
  13126. +    p[1] = y;
  13127. +}
  13128. +
  13129. +void putconsxy(int currcons, char *p)
  13130. +{
  13131. +    gotoxy(currcons, p[0], p[1]);
  13132. +    set_cursor(currcons);
  13133. +}
  13134. +
  13135. +static void set_mode(int currcons, int on_off)
  13136. +{
  13137. +    int i;
  13138. +
  13139. +    for(i=0;i<=npar;i++)
  13140. +        if(ques) switch(par[i]) {    /* DEC private modes set/reset */
  13141. +            case 1:            /* Cursor keys send ^[Ox/^[[x */
  13142. +                if (on_off)
  13143. +                    set_kbd(decckm);
  13144. +                else
  13145. +                    clr_kbd(decckm);
  13146. +                break;
  13147. +            case 3:         /* 80/132 mode switch unimplemented */
  13148. +                deccolm = on_off;
  13149. +#if 0
  13150. +                csi_J(currcons,2);
  13151. +                gotoxy(currcons,0,0);
  13152. +#endif
  13153. +                break;
  13154. +            case 5:            /* Inverted screen on/off */
  13155. +                if (decscnm != on_off) {
  13156. +                    decscnm = on_off;
  13157. +                    invert_screen();
  13158. +/*                     update_attr(); */
  13159. +                }
  13160. +                break;
  13161. +            case 6:            /* Origin relative/absolute */
  13162. +                decom = on_off;
  13163. +                gotoxy(currcons,0,0);
  13164. +                break;
  13165. +            case 7:            /* Autowrap on/off */
  13166. +                decawm = on_off;
  13167. +                break;
  13168. +            case 8:            /* Autorepeat on/off */
  13169. +                if (on_off)
  13170. +                    set_kbd(decarm);
  13171. +                else
  13172. +                    clr_kbd(decarm);
  13173. +                break;
  13174. +            case 9:
  13175. +                report_mouse = on_off ? 1 : 0;
  13176. +                break;
  13177. +            case 25:        /* Cursor on/off */
  13178. +                deccm = on_off;
  13179. +                set_cursor(currcons);
  13180. +                break;
  13181. +            case 1000:
  13182. +                report_mouse = on_off ? 2 : 0;
  13183. +                break;
  13184. +        } else switch(par[i]) {        /* ANSI modes set/reset */
  13185. +            case 3:            /* Monitor (display ctrls) */
  13186. +                disp_ctrl = on_off;
  13187. +                break;
  13188. +            case 4:            /* Insert mode on/off */
  13189. +                decim = on_off;
  13190. +                break;
  13191. +            case 20:        /* Lf, Enter = CrLf/Lf */
  13192. +                if (on_off)
  13193. +                    set_kbd(lnm);
  13194. +                else
  13195. +                    clr_kbd(lnm);
  13196. +                break;
  13197. +        }
  13198. +}
  13199. +
  13200. +static void setterm_command(int currcons)
  13201. +{
  13202. +    switch(par[0]) {
  13203. +        case 1: /* Set colour for underline mode (implemented as an underline) */
  13204. +            break;
  13205. +        case 2: /* set colour for half intensity mode (implemented as half) */
  13206. +            break;
  13207. +        case 8:
  13208. +            def_forecol = forecol;
  13209. +            def_backcol = backcol;
  13210. +            break;
  13211. +        case 9:
  13212. +            blankinterval=((par[1]<60)?par[1]:60)*60*HZ;
  13213. +            break;
  13214. +    }
  13215. +}
  13216. +
  13217. +static void insert_char(int currcons)
  13218. +{
  13219. +    register unsigned char *c,*cc;
  13220. +    register unsigned char row;
  13221. +    register int col;
  13222. +
  13223. +    c = (unsigned char*)pos;
  13224. +    cc = (unsigned char*)pos + bytes_per_char_h;
  13225. +
  13226. +    for (row = 0; row < bytes_per_char_v; row++) {
  13227. +        for(col = (video_num_columns - x - 1) * bytes_per_char_h - 1; col >= 0; col--)
  13228. +            cc[col] = c[col];
  13229. +        *c = 0x11*backcol;
  13230. +        c += video_num_columns * bytes_per_char_h;
  13231. +        cc += video_num_columns * bytes_per_char_h;
  13232. +    }
  13233. +}
  13234. +
  13235. +static void insert_line(int currcons,int n)
  13236. +{
  13237. +    scrdown(currcons,y,bottom,n);
  13238. +    need_wrap = 0;
  13239. +}
  13240. +
  13241. +static void delete_char(int currcons)
  13242. +{
  13243. +    register unsigned char *c, *cc;
  13244. +    register unsigned char row;
  13245. +    register unsigned int  col;
  13246. +
  13247. +    c = (unsigned char*)pos;
  13248. +    cc = (unsigned char*)pos + bytes_per_char_h;
  13249. +
  13250. +    for (row=0; row < bytes_per_char_v; row++) {
  13251. +        for (col=0; col < bytes_per_char_h * (video_num_columns - x - 1); col++) {
  13252. +            c[col] = cc[col];
  13253. +            cc[col] = 0x11*backcol;
  13254. +        }
  13255. +        c += video_num_columns * bytes_per_char_h;
  13256. +        cc += video_num_columns * bytes_per_char_h;
  13257. +    }
  13258. +}
  13259. +
  13260. +static void delete_line(int currcons,int n)
  13261. +{
  13262. +    scrup(currcons,y,bottom,n);
  13263. +    need_wrap = 0;
  13264. +}
  13265. +
  13266. +static void csi_at(int currcons,int nr)
  13267. +{
  13268. +    if (nr > video_num_columns - x)
  13269. +        nr = video_num_columns-x;
  13270. +    else if (!nr)
  13271. +        nr = 1;
  13272. +    while(nr--)
  13273. +        insert_char(currcons);
  13274. +}
  13275. +
  13276. +static void csi_L(int currcons,int nr)
  13277. +{
  13278. +    if (nr > video_num_lines - y)
  13279. +        nr = video_num_lines - y;
  13280. +    else if (!nr)
  13281. +        nr = 1;
  13282. +    insert_line(currcons,nr);
  13283. +}
  13284. +
  13285. +static void csi_P(int currcons,int nr)
  13286. +{
  13287. +    if (nr > video_num_columns)
  13288. +        nr = video_num_columns;
  13289. +    else if (!nr)
  13290. +        nr = 1;
  13291. +    while(nr--)
  13292. +        delete_char(currcons);
  13293. +}
  13294. +
  13295. +static void csi_M(int currcons,int nr)
  13296. +{
  13297. +    if (nr > video_num_lines)
  13298. +        nr = video_num_lines;
  13299. +    else if (!nr)
  13300. +        nr = 1;
  13301. +    delete_line(currcons,nr);
  13302. +}
  13303. +
  13304. +static void save_cur(int currcons)
  13305. +{
  13306. +    saved_x        = x;
  13307. +    saved_y        = y;
  13308. +    saved_G0    = G0_charset;
  13309. +    saved_G1    = G1_charset;
  13310. +    s_intensity    = intensity;
  13311. +    s_blink        = blink;
  13312. +    s_underline    = underline;
  13313. +    s_reverse    = reverse;
  13314. +    s_forecol    = forecol;
  13315. +    s_backcol    = backcol;
  13316. +}
  13317. +
  13318. +static void restore_cur(int currcons)
  13319. +{
  13320. +    gotoxy(currcons,saved_x,saved_y);
  13321. +    G0_charset    = saved_G0;
  13322. +    G1_charset    = saved_G1;
  13323. +    intensity    = s_intensity;
  13324. +    blink        = s_blink;
  13325. +    underline    = s_underline;
  13326. +    reverse        = s_reverse;
  13327. +    forecol        = s_forecol;
  13328. +    backcol        = s_backcol;
  13329. +    need_wrap    = 0;
  13330. +}
  13331. +
  13332. +enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
  13333. +    EShash, ESsetG0, ESsetG1, ESpercent, ESignore };
  13334. +
  13335. +static void reset_terminal(int currcons,int do_clear)
  13336. +{
  13337. +    top        = 0;
  13338. +    bottom        = video_num_lines;
  13339. +    vc_state    = ESnormal;
  13340. +    ques        = 0;
  13341. +    translate    = set_translate(NORM_MAP);
  13342. +    G0_charset    = NORM_MAP;
  13343. +    G1_charset    = GRAF_MAP;
  13344. +    charset        = 0;
  13345. +    need_wrap    = 0;
  13346. +    report_mouse    = 0;
  13347. +    utf        = 0; /* ? *** */
  13348. +    utf_count    = 0;
  13349. +
  13350. +    paletteentries    = 0;
  13351. +    disp_ctrl    = 0;
  13352. +    toggle_meta    = 0;
  13353. +
  13354. +    def_forecol    = color_table[7];
  13355. +    def_backcol    = color_table[0];
  13356. +    forecol    = color_table[7];
  13357. +    backcol    = color_table[0];
  13358. +
  13359. +    decscnm        = 0;
  13360. +    decom        = 0;
  13361. +    decawm        = 1;
  13362. +    deccm        = 1;
  13363. +    decim        = 0;
  13364. +
  13365. +    set_kbd(decarm);
  13366. +    clr_kbd(decckm);
  13367. +    clr_kbd(kbdapplic);
  13368. +    clr_kbd(lnm);
  13369. +    kbd_table[currcons].lockstate = 0;
  13370. +    kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
  13371. +    kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
  13372. +    set_leds();
  13373. +
  13374. +    default_attr(currcons);
  13375. +
  13376. +    tab_stop[0]    = 0x01010100;
  13377. +    tab_stop[1]    =
  13378. +    tab_stop[2]    =
  13379. +    tab_stop[3]    =
  13380. +    tab_stop[4]    = 0x01010101;
  13381. +
  13382. +    gotoxy(currcons,0,0);
  13383. +    save_cur(currcons);
  13384. +    if (do_clear)
  13385. +        csi_J(currcons,2);
  13386. +}
  13387. +
  13388. +/*
  13389. + * Turn the Scroll-Lock LED on when the tty is stopped
  13390. + */
  13391. +static void con_stop(struct tty_struct *tty)
  13392. +{
  13393. +    int console_num;
  13394. +    if (!tty)
  13395. +        return;
  13396. +    console_num = MINOR(tty->device) - (tty->driver.minor_start);
  13397. +    if (!vc_cons_allocated(console_num))
  13398. +        return;
  13399. +    set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
  13400. +    set_leds();
  13401. +}
  13402. +
  13403. +/*
  13404. + * Turn the Scroll-Lock LED off when the console is started
  13405. + */
  13406. +static void con_start(struct tty_struct *tty)
  13407. +{
  13408. +    int console_num;
  13409. +    if(!tty)
  13410. +        return;
  13411. +    console_num = MINOR(tty->device) - (tty->driver.minor_start);
  13412. +    if (!vc_cons_allocated(console_num))
  13413. +        return;
  13414. +    clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
  13415. +    set_leds();
  13416. +}
  13417. +
  13418. +static int con_write(struct tty_struct * tty, int from_user,
  13419. +             unsigned char *buf, int count)
  13420. +{
  13421. +    int c, tc, ok, n = 0, r = 0;
  13422. +    unsigned int currcons;
  13423. +    struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
  13424. +    unsigned char buffer[32], *p = buffer;
  13425. +
  13426. +    currcons = vt->vc_num;
  13427. +    if (!vc_cons_allocated(currcons)) {
  13428. +        /* could this happen? */
  13429. +        static int error = 0;
  13430. +        if(!error) {
  13431. +        error = 1;
  13432. +        printk("con_write: tty %d not allocated\n", currcons+1);
  13433. +        }
  13434. +        return 0;
  13435. +    }
  13436. +
  13437. +    remove_cursors(currcons);
  13438. +    if(currcons == sel_cons)
  13439. +        clear_selection();
  13440. +
  13441. +    disable_bh(KEYBOARD_BH);
  13442. +    while(!tty->stopped && count) {
  13443. +        if(from_user && r == 0)
  13444. +        {
  13445. +            r = count;
  13446. +            if(r > 32) r = 32;
  13447. +            memcpy_fromfs(buffer, buf, r);
  13448. +            p = buffer;
  13449. +            }
  13450. +        c = from_user ? *p++ : *buf;
  13451. +        buf++; n++; count--;
  13452. +        if(from_user) r--;
  13453. +
  13454. +        if (utf) {
  13455. +            /* Combine UTF-8 into Unicode */
  13456. +            /* Incomplete characters silently ignored */
  13457. +            if(c > 0x7f) {
  13458. +            if (utf_count > 0 && (c & 0xc0) == 0x80) {
  13459. +                utf_char = (utf_char << 6) | (c & 0x3f);
  13460. +                utf_count--;
  13461. +                if (utf_count == 0)
  13462. +                    c = utf_char;
  13463. +                else continue;
  13464. +            } else {
  13465. +                if ((c & 0xe0) == 0xc0) {
  13466. +                    utf_count = 1;
  13467. +                    utf_char = (c & 0x1f);
  13468. +                } else if ((c & 0xf0) == 0xe0) {
  13469. +                    utf_count = 2;
  13470. +                    utf_char = (c & 0x0f);
  13471. +                } else
  13472. +                    utf_count = 0;
  13473. +                continue;
  13474. +            }
  13475. +            } else
  13476. +              utf_count = 0;
  13477. +
  13478. +            tc = conv_uni_to_pc(c);
  13479. +            if (tc == -1 || tc == -2)
  13480. +              continue;
  13481. +            if (tc == -3 || tc == -4) { /* hashtable not valid */
  13482. +                            /* or symbol not found */
  13483. +                tc = (c <= 0xff) ? translate[c] : 040;
  13484. +                ok = 0;
  13485. +            } else
  13486. +                ok = 1;
  13487. +        } else {    /* no utf */
  13488. +            tc = translate[toggle_meta ? (c|0x80) : c];
  13489. +            ok = 0;
  13490. +        }
  13491. +
  13492. +        /* If the origional code was < 32 we only allow a
  13493. +         * glyph to be displayed if the code is not normally
  13494. +         * used (such as for cursor movement) or if the
  13495. +         * disp_ctrl mode has been explicitly enabled.
  13496. +         * Note: ESC is *never* allowed to be displayed as
  13497. +         * that would disable all escape sequences!
  13498. +         */
  13499. +        if (!ok && tc && (c >= 32 || (disp_ctrl && c !=0x1b)
  13500. +        || !((CTRL_ACTION >> c) & 1)))
  13501. +            ok = 1;
  13502. +
  13503. +        if (vc_state == ESnormal && ok) {
  13504. +            if (need_wrap) {
  13505. +                cr(currcons);
  13506. +                lf(currcons);
  13507. +                  }
  13508. +            if(decim)
  13509. +                insert_char(currcons);
  13510. +            charwrite(currcons, pos, translate[c]);
  13511. +            if (x == video_num_columns - 1)
  13512. +                need_wrap = decawm;
  13513. +            else {
  13514. +                x++;
  13515. +                pos+=bytes_per_char_h;
  13516. +            }
  13517. +            continue;
  13518. +        }
  13519. +
  13520. +        /*
  13521. +         *  Control characters can be used in the _middle_
  13522. +         *  of an escape sequence.
  13523. +         */
  13524. +        switch(c) {
  13525. +            case 7:
  13526. +                kd_mksound(0x637, HZ/8);
  13527. +                continue;
  13528. +            case 8:
  13529. +                bs(currcons);
  13530. +                continue;
  13531. +            case 9:
  13532. +                pos -= x * bytes_per_char_h;
  13533. +                while (x < video_num_columns - 1) {
  13534. +                    x++;
  13535. +                    if (tab_stop[x >> 5] & (1 << (x & 31)))
  13536. +                        break;
  13537. +                }
  13538. +                pos += x * bytes_per_char_h;
  13539. +                continue;
  13540. +            case 10: case 11: case 12:
  13541. +                lf(currcons);
  13542. +                if(!is_kbd(lnm))
  13543. +                    continue;
  13544. +            case 13:
  13545. +                cr(currcons);
  13546. +                continue;
  13547. +            case 14:
  13548. +                charset = 1;
  13549. +                translate = set_translate(G1_charset);
  13550. +                disp_ctrl = 1;
  13551. +                continue;
  13552. +            case 15:
  13553. +                charset = 0;
  13554. +                translate = set_translate(G0_charset);
  13555. +                disp_ctrl = 0;
  13556. +                continue;
  13557. +            case 24: case 26:
  13558. +                vc_state = ESnormal;
  13559. +                continue;
  13560. +            case 27:
  13561. +                vc_state = ESesc;
  13562. +                continue;
  13563. +            case 127:
  13564. +                del(currcons);
  13565. +                continue;
  13566. +            case 128+27:
  13567. +                vc_state = ESsquare;
  13568. +                continue;
  13569. +            }
  13570. +        switch(vc_state) {
  13571. +            case ESesc:
  13572. +                vc_state = ESnormal;
  13573. +                switch (c) {
  13574. +                    case '[':
  13575. +                        vc_state = ESsquare;
  13576. +                        continue;
  13577. +                    case '%':
  13578. +                        vc_state = ESpercent;
  13579. +                        continue;
  13580. +                    case 'E':
  13581. +                        cr(currcons);
  13582. +                        lf(currcons);
  13583. +                        continue;
  13584. +                    case 'M':
  13585. +                        ri(currcons);
  13586. +                        continue;
  13587. +                    case 'D':
  13588. +                        lf(currcons);
  13589. +                        continue;
  13590. +                    case 'H':
  13591. +                        tab_stop[x >> 5] |= (1 << (x & 31));
  13592. +                        continue;
  13593. +                    case 'Z':
  13594. +                        respond_ID(tty);
  13595. +                        continue;
  13596. +                    case '7':
  13597. +                        save_cur(currcons);
  13598. +                        continue;
  13599. +                    case '8':
  13600. +                        restore_cur(currcons);
  13601. +                        continue;
  13602. +                    case '(':
  13603. +                        vc_state = ESsetG0;
  13604. +                        continue;
  13605. +                    case ')':
  13606. +                        vc_state = ESsetG1;
  13607. +                        continue;
  13608. +                    case '#':
  13609. +                        vc_state = EShash;
  13610. +                        continue;
  13611. +                    case 'c':
  13612. +                        reset_terminal(currcons,1);
  13613. +                        continue;
  13614. +                    case '>': /* Numeric keypad */
  13615. +                        clr_kbd(kbdapplic);
  13616. +                        continue;
  13617. +                    case '=': /* Appl. keypad */
  13618. +                        set_kbd(kbdapplic);
  13619. +                        continue;
  13620. +                }
  13621. +                continue;
  13622. +            case ESsquare:
  13623. +                for(npar = 0; npar < NPAR ; npar++)
  13624. +                    par[npar] = 0;
  13625. +                npar = 0;
  13626. +                vc_state = ESgetpars;
  13627. +                if (c == '[') { /* Function key */
  13628. +                    vc_state=ESfunckey;
  13629. +                    continue;
  13630. +                }
  13631. +                ques = (c == '?');
  13632. +                if (ques)
  13633. +                    continue;
  13634. +            case ESgetpars:
  13635. +                if(c==';' && npar<NPAR-1) {
  13636. +                    npar++;
  13637. +                    continue;
  13638. +                } else if (c>='0' && c<='9') {
  13639. +                    par[npar] = par[npar] * 10 + c - '0';
  13640. +                    continue;
  13641. +                } else vc_state=ESgotpars;
  13642. +            case ESgotpars:
  13643. +                vc_state=ESnormal;
  13644. +                switch (c) {
  13645. +                    case 'h':
  13646. +                        set_mode(currcons,1);
  13647. +                        continue;
  13648. +                    case 'l':
  13649. +                        set_mode(currcons,0);
  13650. +                        continue;
  13651. +                    case 'n':
  13652. +                        if (!ques) {
  13653. +                            if (par[0] == 5)
  13654. +                                status_report(tty);
  13655. +                            else if (par[0] == 6)
  13656. +                                cursor_report(currcons,tty);
  13657. +                        }
  13658. +                        continue;
  13659. +                }
  13660. +                if (ques) {
  13661. +                    ques = 0;
  13662. +                    continue;
  13663. +                }
  13664. +                switch(c) {
  13665. +                    case 'G': case '`':
  13666. +                        if (par[0]) par[0]--;
  13667. +                        gotoxy(currcons,par[0],y);
  13668. +                        continue;
  13669. +                    case 'A':
  13670. +                        if (!par[0]) par[0]++;
  13671. +                        gotoxy(currcons,x,y-par[0]);
  13672. +                        continue;
  13673. +                    case 'B': case 'e':
  13674. +                        if (!par[0]) par[0]++;
  13675. +                        gotoxy(currcons,x,y+par[0]);
  13676. +                        continue;
  13677. +                    case 'C': case 'a':
  13678. +                        if (!par[0]) par[0]++;
  13679. +                        gotoxy(currcons,x+par[0],y);
  13680. +                        continue;
  13681. +                    case 'D':
  13682. +                        if (!par[0]) par[0]++;
  13683. +                        gotoxy(currcons,x-par[0],y);
  13684. +                        continue;
  13685. +                    case 'E':
  13686. +                        if (!par[0]) par[0]++;
  13687. +                        gotoxy(currcons,0,y+par[0]);
  13688. +                        continue;
  13689. +                    case 'F':
  13690. +                        if (!par[0]) par[0]++;
  13691. +                        gotoxy(currcons,0,y-par[0]);
  13692. +                        continue;
  13693. +                    case 'd':
  13694. +                        if (par[0]) par[0]--;
  13695. +                        gotoxy(currcons,x,par[0]);
  13696. +                        continue;
  13697. +                    case 'H': case 'f':
  13698. +                        if (par[0]) par[0]--;
  13699. +                        if (par[1]) par[1]--;
  13700. +                        gotoxy(currcons,par[1],par[0]);
  13701. +                        continue;
  13702. +                    case 'J':
  13703. +                        csi_J(currcons,par[0]);
  13704. +                        continue;
  13705. +                    case 'K':
  13706. +                        csi_K(currcons,par[0]);
  13707. +                        continue;
  13708. +                    case 'L':
  13709. +                        csi_L(currcons,par[0]);
  13710. +                        continue;
  13711. +                    case 'M':
  13712. +                        csi_M(currcons,par[0]);
  13713. +                        continue;
  13714. +                    case 'P':
  13715. +                        csi_P(currcons,par[0]);
  13716. +                        continue;
  13717. +                    case 'c':
  13718. +                        if (!par[0])
  13719. +                            respond_ID(tty);
  13720. +                        continue;
  13721. +                    case 'g':
  13722. +                        if (!par[0])
  13723. +                            tab_stop[x >> 5] &= ~(1 << (x & 31));
  13724. +                        else if (par[0] == 3) {
  13725. +                            tab_stop[0] =
  13726. +                            tab_stop[1] =
  13727. +                            tab_stop[2] =
  13728. +                            tab_stop[3] =
  13729. +                            tab_stop[4] = 0;
  13730. +                        }
  13731. +                        continue;
  13732. +                    case 'm':
  13733. +                        csi_m(currcons);
  13734. +                        continue;
  13735. +                    case 'q': /* DECLL - but only 3 leds */
  13736. +                        /* map 0,1,2,3 to 0,1,2,4 */
  13737. +                        if (par[0] < 4)
  13738. +                          setledstate(kbd_table + currcons,
  13739. +                                    (par[0] < 3 ? par[0] : 4));
  13740. +                        continue;
  13741. +                    case 'r':
  13742. +                        if (!par[0])
  13743. +                            par[0]++;
  13744. +                        if (!par[1])
  13745. +                            par[1] = video_num_lines;
  13746. +                        if (par[0] < par[1] &&
  13747. +                            par[1] <= video_num_lines) {
  13748. +                            top=par[0]-1;
  13749. +                            bottom=par[1];
  13750. +                            gotoxy(currcons,0,0);
  13751. +                        }
  13752. +                        continue;
  13753. +                    case 's':
  13754. +                        save_cur(currcons);
  13755. +                        continue;
  13756. +                    case 'u':
  13757. +                        restore_cur(currcons);
  13758. +                        continue;
  13759. +                    case 'X':
  13760. +                        csi_X(currcons, par[0]);
  13761. +                        continue;
  13762. +                    case '@':
  13763. +                        csi_at(currcons,par[0]);
  13764. +                        continue;
  13765. +                    case ']': /* setterm functions */
  13766. +                        setterm_command(currcons);
  13767. +                        continue;
  13768. +                }
  13769. +                continue;
  13770. +            case ESpercent:
  13771. +                vc_state = ESnormal;
  13772. +                switch (c) {
  13773. +                    case '@': /* defined in ISO 2022 */
  13774. +                        utf = 0;
  13775. +                        continue;
  13776. +                    case 'G': /* prelim official escape code */
  13777. +                    case '8': /* retained for compatibility */
  13778. +                        utf = 1;
  13779. +                        continue;
  13780. +                }
  13781. +                continue;
  13782. +            case ESfunckey:
  13783. +                vc_state = ESnormal;
  13784. +                continue;
  13785. +            case EShash:
  13786. +                vc_state = ESnormal;
  13787. +                if (c == '8') {
  13788. +                    /* DEC screen alignment test. kludge :-) */
  13789. +                }
  13790. +                continue;
  13791. +            case ESsetG0:
  13792. +                if (c == '0')
  13793. +                    G0_charset = GRAF_MAP;
  13794. +                else if (c == 'B')
  13795. +                    G0_charset = NORM_MAP;
  13796. +                else if (c == 'U')
  13797. +                    G0_charset = NULL_MAP;
  13798. +                else if (c == 'K')
  13799. +                    G0_charset = USER_MAP;
  13800. +                if (charset == 0)
  13801. +                    translate = set_translate(G0_charset);
  13802. +                vc_state = ESnormal;
  13803. +                continue;
  13804. +            case ESsetG1:
  13805. +                if (c == '0')
  13806. +                    G1_charset = GRAF_MAP;
  13807. +                else if (c == 'B')
  13808. +                    G1_charset = NORM_MAP;
  13809. +                else if (c == 'U')
  13810. +                    G1_charset = NULL_MAP;
  13811. +                else if (c == 'K')
  13812. +                    G1_charset = USER_MAP;
  13813. +                if (charset == 1)
  13814. +                    translate = set_translate(G1_charset);
  13815. +                vc_state = ESnormal;
  13816. +                continue;
  13817. +            default:
  13818. +                vc_state = ESnormal;
  13819. +        }
  13820. +    }
  13821. +    if (vcmode != KD_GRAPHICS)
  13822. +        set_cursor(currcons);
  13823. +    enable_bh(KEYBOARD_BH);
  13824. +    restore_cursors(currcons);
  13825. +    return n;
  13826. +}
  13827. +
  13828. +static int con_write_room(struct tty_struct *tty)
  13829. +{
  13830. +    if (tty->stopped)
  13831. +        return 0;
  13832. +    return 4096;        /* No limit, really; we're not buffering */
  13833. +}
  13834. +
  13835. +static int con_chars_in_buffer(struct tty_struct *tty)
  13836. +{
  13837. +    return 0;        /* we're not buffering */
  13838. +}
  13839. +
  13840. +void poke_blanked_console(void)
  13841. +{
  13842. +    timer_active&=~(1<<BLANK_TIMER);
  13843. +    if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
  13844. +        return;
  13845. +    if (console_blanked) {
  13846. +        timer_table[BLANK_TIMER].expires = 0;
  13847. +        timer_active |= 1<<BLANK_TIMER;
  13848. +    } else if(blankinterval) {
  13849. +        timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
  13850. +        timer_active |= 1<<BLANK_TIMER;
  13851. +    }
  13852. +}
  13853. +
  13854. +static void console_print(const char *b)
  13855. +{
  13856. +    int currcons = fg_console;
  13857. +    unsigned char c;
  13858. +    static int printing = 0;
  13859. +
  13860. +  if(vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
  13861. +  {
  13862. +    prints(b);
  13863. +    return;
  13864. +  }
  13865. +
  13866. +    if (!printable || printing)
  13867. +        return;  /* console not yet initialized */
  13868. +    printing = 1;
  13869. +
  13870. +    if(!vc_cons_allocated(currcons)) {
  13871. +        /* impossible */
  13872. +          printk("console_print: tty %d not allocated ??\n",currcons+1);
  13873. +          return;
  13874. +    }
  13875. +
  13876. +    remove_cursors(currcons);
  13877. +
  13878. +    while ((c = *b++) != 0) {
  13879. +        if (c == 10 || c == 13 || need_wrap) {
  13880. +            if (c != 13)
  13881. +                lf(currcons);
  13882. +            cr(currcons);
  13883. +            if(c==10 || c==13)
  13884. +                continue;
  13885. +        }
  13886. +        charwrite(currcons,pos,c);
  13887. +        if (x == video_num_columns - 1) {
  13888. +            need_wrap=1;
  13889. +            continue;
  13890. +        }
  13891. +        x++;
  13892. +        pos += bytes_per_char_h;
  13893. +    }
  13894. +    set_cursor(currcons);
  13895. +
  13896. +    restore_cursors(currcons);
  13897. +
  13898. +    poke_blanked_console();
  13899. +    printing = 0;
  13900. +}
  13901. +
  13902. +/*
  13903. + * con_throttle and con_unthrottle are only used for
  13904. + * paste_selection(), which has to stuff in a large number of
  13905. + * characters...
  13906. + */
  13907. +static void con_throttle(struct tty_struct *tty)
  13908. +{
  13909. +}
  13910. +
  13911. +static void con_unthrottle(struct tty_struct *tty)
  13912. +{
  13913. +      struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
  13914. +
  13915. +      wake_up_interruptible(&vt->paste_wait);
  13916. +}
  13917. +
  13918. +static void vc_init(unsigned int currcons, unsigned long rows, unsigned long cols, int do_clear)
  13919. +{
  13920. +    long base = (long) vc_scrbuf[currcons];
  13921. +
  13922. +    video_num_columns = cols;
  13923. +    video_num_lines   = rows;
  13924. +    video_size_row    = video_num_columns*bytes_per_char_h*bytes_per_char_v;
  13925. +    video_screen_size = video_num_lines * video_size_row;
  13926. +    video_buf_size    = video_num_lines * video_num_columns * 4;
  13927. +    video_mem_start   = video_mem_base;
  13928. +    video_mem_end      = video_mem_term;
  13929. +
  13930. +    pos = origin      = video_mem_start;
  13931. +    scr_end          = video_mem_start + video_num_lines * video_size_row;
  13932. +    video_mem_end     = base + video_screen_size;
  13933. +    reset_vc(currcons);
  13934. +    def_forecol      = color_table[7];
  13935. +    def_backcol      = color_table[0];
  13936. +    vt_cons[currcons]->paste_wait = 0;
  13937. +    cursoron      = 0;
  13938. +
  13939. +    reset_terminal(currcons,do_clear);
  13940. +}
  13941. +
  13942. +static void con_setsize(unsigned long rows,unsigned long cols)
  13943. +{
  13944. +    video_num_lines   = rows;
  13945. +    video_num_columns = cols;
  13946. +    video_size_row    = video_num_columns*bytes_per_char_h*bytes_per_char_v;
  13947. +    video_screen_size = video_num_lines * video_size_row;
  13948. +    video_buf_size    = video_num_lines * video_num_columns * 4;
  13949. +}
  13950. +
  13951. +static int con_ioctl(struct tty_struct *tty, struct file * file,
  13952. +         unsigned int cmd, unsigned long arg)
  13953. +{
  13954. +    return vt_ioctl(tty, file, cmd, arg);
  13955. +}
  13956. +
  13957. +/*
  13958. + *  long con_init(long);
  13959. + *
  13960. + * This routine initialises console interrupts, and does nothing
  13961. + * else. If you want the screen to clear, call tty_write with
  13962. + * the apropriate escape-sequence.
  13963. + *
  13964. + */
  13965. +long con_init(long kmem_start)
  13966. +{
  13967. +    int currcons = 0, i;
  13968. +
  13969. +    memset(&console_driver, 0, sizeof(struct tty_driver));
  13970. +    console_driver.magic = TTY_DRIVER_MAGIC;
  13971. +    console_driver.name = "tty";
  13972. +    console_driver.name_base = 1;
  13973. +    console_driver.major = TTY_MAJOR;
  13974. +    console_driver.minor_start = 1;
  13975. +    console_driver.num = MAX_NR_CONSOLES;
  13976. +    console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
  13977. +    console_driver.init_termios = tty_std_termios;
  13978. +    console_driver.flags = TTY_DRIVER_REAL_RAW;
  13979. +    console_driver.refcount = &console_refcount;
  13980. +    console_driver.table = console_table;
  13981. +    console_driver.termios = console_termios;
  13982. +    console_driver.termios_locked = console_termios_locked;
  13983. +
  13984. +    console_driver.open = con_open;
  13985. +    console_driver.write = con_write;
  13986. +    console_driver.write_room = con_write_room;
  13987. +    console_driver.chars_in_buffer = con_chars_in_buffer;
  13988. +    console_driver.ioctl = con_ioctl;
  13989. +    console_driver.stop = con_stop;
  13990. +    console_driver.start = con_start;
  13991. +    console_driver.throttle = con_throttle;
  13992. +    console_driver.unthrottle = con_unthrottle;
  13993. +
  13994. +    if(tty_register_driver(&console_driver))
  13995. +          panic("Couldn't register console driver\n");
  13996. +
  13997. +    con_setsize(ORIG_VIDEO_LINES,ORIG_VIDEO_COLS);
  13998. +
  13999. +    timer_table[BLANK_TIMER].fn=blank_screen;
  14000. +    timer_table[BLANK_TIMER].expires=0;
  14001. +    if(blankinterval) {
  14002. +          timer_table[BLANK_TIMER].expires=jiffies+blankinterval;
  14003. +        timer_active|=1<<BLANK_TIMER;
  14004. +    }
  14005. +
  14006. +    for(i=0; i<17; i++)
  14007. +        vidc_write(i<<2, default_palette_entries[i]);
  14008. +
  14009. +    /* Use ORIG_VIDEO_MODE */
  14010. +    video_addr_mask= (video_num_lines * video_num_columns * bytes_per_char_h *
  14011. +                 bytes_per_char_v - 1) | (PAGE_SIZE-1);
  14012. +    video_mem_term = 0x02000000;
  14013. +    video_mem_base = video_mem_term - video_addr_mask - 1;
  14014. +
  14015. +    map_screen_mem (video_mem_base, 1);
  14016. +
  14017. +    can_do_color=1;
  14018. +    if(bytes_per_char_h == 8)
  14019. +    {
  14020. +        default_palette_entries = palette_8;
  14021. +        color_table = color_8;
  14022. +    }
  14023. +
  14024. +    for(currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
  14025. +        vc_cons[currcons].d = (struct vc_data *) kmem_start;
  14026. +        kmem_start += sizeof(struct vc_data);
  14027. +        vt_cons[currcons] = (struct vt_struct *) kmem_start;
  14028. +        kmem_start += sizeof(struct vt_struct);
  14029. +        vc_scrbuf[currcons] = (unsigned char *) kmem_start;
  14030. +        memfastset(vc_scrbuf[currcons],    0x00000720, video_buf_size);
  14031. +        kmem_start += video_buf_size;
  14032. +        kmalloced = 0;
  14033. +        screenbuf_size = video_buf_size;
  14034. +        vc_init(currcons, video_num_lines, video_num_columns,currcons);
  14035. +    }
  14036. +
  14037. +    currcons = fg_console = 0;
  14038. +
  14039. +    video_mem_start = video_mem_base;
  14040. +    video_mem_end    = video_mem_term;
  14041. +    pos=origin=cp    = video_mem_start;
  14042. +    scr_end        = video_mem_start + video_num_lines * video_size_row;
  14043. +    cursoron    = 1;
  14044. +
  14045. +    gotoxy (currcons,ORIG_X,ORIG_Y);
  14046. +    csi_J (currcons, 0);
  14047. +    printable=1;
  14048. +    printk ("Console: %s %s %ldx%ldx%d, %d virtual console%s (max %d)\n","colour", "A5000",
  14049. +          video_num_columns,
  14050. +          video_num_lines,
  14051. +          bytes_per_char_h == 8 ? 256:16,
  14052. +          MIN_NR_CONSOLES,
  14053. +          (MIN_NR_CONSOLES == 1) ? "":"s",
  14054. +          MAX_NR_CONSOLES);
  14055. +    register_console (console_print);
  14056. +    if(request_irq (IRQ_VSYNCPULSE, vsync_irq, 0, "console"))
  14057. +        panic ("Unable to get VSYNC irq for console\n");
  14058. +    return kmem_start;
  14059. +}
  14060. +
  14061. +static void get_scrmem(int currcons)
  14062. +{
  14063. +}
  14064. +
  14065. +void update_scrmem(int currcons, int start, int length)
  14066. +{
  14067. +    unsigned long p, pp, sx, sy, ex, ey;
  14068. +    unsigned long *buffer;
  14069. +
  14070. +    sy = start / video_num_columns;
  14071. +    sx = start % video_num_columns;
  14072. +    length += start;
  14073. +    ey = length / video_num_columns;
  14074. +    ex = length % video_num_columns;
  14075. +
  14076. +    if (ey > video_num_lines)
  14077. +        ey = video_num_lines;
  14078. +
  14079. +    p = origin + sy * video_size_row;
  14080. +    buffer = ((unsigned long *)vc_scrbuf[currcons]) + start;
  14081. +
  14082. +    if (ey > sy)
  14083. +    {
  14084. +        for (; sy < ey; sy++)
  14085. +        {
  14086. +            pp = p + sx * bytes_per_char_h;
  14087. +            for (; sx < video_num_columns; sx++)
  14088. +            {
  14089. +                ll_char_write (pp, buffer[0] & 0xff, (buffer[0] >> 8) & 0xff,
  14090. +                    (buffer[0] >> 16) & 0xff, (buffer[0] >> 24) & 0xff);
  14091. +                pp += bytes_per_char_h;
  14092. +                buffer ++;
  14093. +            }
  14094. +            p += video_size_row;
  14095. +            sx = 0;
  14096. +        }
  14097. +    }
  14098. +    if (ey == sy && ex)
  14099. +    {
  14100. +        for (; sx < ex; sx++)
  14101. +        {
  14102. +            ll_char_write (p, buffer[0] & 0xff, (buffer[0] >> 8) & 0xff,
  14103. +                (buffer[0] >> 16) & 0xff, (buffer[0] >> 24) & 0xff);
  14104. +            p += bytes_per_char_h;
  14105. +            buffer ++;
  14106. +        }
  14107. +    }
  14108. +}
  14109. +
  14110. +void set_scrmem(int currcons,long offset)
  14111. +{
  14112. +    unsigned long p,pp,mx,my;
  14113. +    unsigned long *buffer;
  14114. +    int i;
  14115. +
  14116. +    p = origin;
  14117. +    buffer = (unsigned long *)vc_scrbuf[currcons];
  14118. +
  14119. +    for(my = 0; my < video_num_lines ; my++)
  14120. +    {
  14121. +        pp = p;
  14122. +        for(mx = 0; mx < video_num_columns; mx++)
  14123. +        {
  14124. +            ll_char_write(pp,buffer[0] & 0xff,(buffer[0] >> 8) & 0xff,
  14125. +                     (buffer[0] >> 16) & 0xff,(buffer[0] >> 24) & 0xff);
  14126. +            pp+=bytes_per_char_h;
  14127. +            buffer+=1;
  14128. +        }
  14129. +        p+=video_size_row;
  14130. +    }
  14131. +    pp = origin + ((video_screen_size + 0x7FFF) & PAGE_MASK);
  14132. +    while(p<pp)
  14133. +    {
  14134. +        *(unsigned long *)p=0;
  14135. +        p+=4;
  14136. +    }
  14137. +    if(!paletteentries || vcmode != KD_GRAPHICS)
  14138. +        for(i=0; i<17; i++)
  14139. +            vidc_write(i<<2, default_palette_entries[i]);
  14140. +    else
  14141. +        for(i=0; i<17; i++)
  14142. +            vidc_write(i<<2, paletteentries[i] & 0x1fff);
  14143. +}
  14144. +
  14145. +/* ------------------------------------------------------------------------------------- *
  14146. + * Screen blanking routines
  14147. + * ------------------------------------------------------------------------------------- */
  14148. +
  14149. +void do_blank_screen(int nopowersave)
  14150. +{
  14151. +    int i;
  14152. +
  14153. +    if (console_blanked)
  14154. +        return;
  14155. +
  14156. +    timer_active &= ~(1<<BLANK_TIMER);
  14157. +    timer_table[BLANK_TIMER].fn = unblank_screen;
  14158. +
  14159. +    /* DISABLE VIDEO */
  14160. +    for (i = 0; i < 17; i++)
  14161. +        vidc_write(i<<2, 0);
  14162. +
  14163. +    console_blanked = fg_console + 1;
  14164. +}
  14165. +
  14166. +void do_unblank_screen(void)
  14167. +{
  14168. +    int i;
  14169. +    int currcons;
  14170. +
  14171. +    if (!console_blanked)
  14172. +        return;
  14173. +    if (!vc_cons_allocated(fg_console)) {
  14174. +        /* impossible */
  14175. +        printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
  14176. +        return;
  14177. +    }
  14178. +    timer_table[BLANK_TIMER].fn = blank_screen;
  14179. +    if (blankinterval)
  14180. +    {
  14181. +        timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
  14182. +        timer_active |= 1<<BLANK_TIMER;
  14183. +    }
  14184. +
  14185. +    currcons = fg_console;
  14186. +    console_blanked = 0;
  14187. +
  14188. +    if(!paletteentries || vcmode != KD_GRAPHICS)
  14189. +        for(i=0; i<17; i++)
  14190. +            vidc_write(i<<2, default_palette_entries[i]);
  14191. +    else
  14192. +        for(i=0; i<17; i++)
  14193. +            vidc_write(i<<2, paletteentries[i] & 0x1fff);
  14194. +}
  14195. +
  14196. +/*
  14197. + * If a blank_screen is due to a timer, then a power save is allowed.
  14198. + * If it is related to console_switching, then avoid power save.
  14199. + */
  14200. +static void blank_screen(void)
  14201. +{
  14202. +    do_blank_screen(0);
  14203. +}
  14204. +
  14205. +static void unblank_screen(void)
  14206. +{
  14207. +    do_unblank_screen();
  14208. +}
  14209. +
  14210. +void update_screen(int new_console)
  14211. +{
  14212. +    static int lock = 0;
  14213. +
  14214. +    if(new_console == fg_console || lock)
  14215. +        return;
  14216. +    if(!vc_cons_allocated(new_console)) {
  14217. +        /* strange ... */
  14218. +        printk("update_screen: tty %d not allocated ??\n",new_console);
  14219. +        return;
  14220. +    }
  14221. +    lock = 1;
  14222. +    
  14223. +    highlight_pointer(fg_console,-1);
  14224. +    
  14225. +    remove_cursors(fg_console);
  14226. +    
  14227. +    if(!console_blanked)
  14228. +        get_scrmem(fg_console);
  14229. +    else
  14230. +        console_blanked = -1;        /* no longer of the form console+1 */
  14231. +    fg_console = new_console;    /* this is the only (nonzero) assignment to fg_console */
  14232. +                    /* consequently, fg_console will always be allocated */
  14233. +    set_scrmem(fg_console, 0);
  14234. +    set_origin(fg_console);
  14235. +    set_cursor(fg_console);
  14236. +    restore_cursors(fg_console);
  14237. +    set_leds();
  14238. +    compute_shiftstate();
  14239. +    lock = 0;
  14240. +}
  14241. +
  14242. +/*
  14243. + * Allocate the console screen memory
  14244. + */
  14245. +int con_open(struct tty_struct *tty,struct file *filp)
  14246. +{
  14247. +    unsigned int idx;
  14248. +    int i;
  14249. +    
  14250. +    idx = MINOR(tty->device) - tty->driver.minor_start;
  14251. +
  14252. +    i = vc_allocate(idx);
  14253. +    if(i)
  14254. +        return i;
  14255. +
  14256. +    vt_cons[idx]->vc_num = idx;
  14257. +    tty->driver_data = vt_cons[idx];
  14258. +
  14259. +    if(!tty->winsize.ws_row && !tty->winsize.ws_col) {
  14260. +        tty->winsize.ws_row = video_num_lines;
  14261. +        tty->winsize.ws_col = video_num_columns;
  14262. +    }
  14263. +    return 0;
  14264. +}
  14265. +
  14266. +/*
  14267. + * PIO_FONT support
  14268. + */
  14269. +int con_set_font (char *arg)
  14270. +{
  14271. +    return -EINVAL;
  14272. +}
  14273. +
  14274. +int con_get_font (char *arg)
  14275. +{
  14276. +    return -EINVAL;
  14277. +}
  14278. +
  14279. +/* == arm specific console code ============================================================== */
  14280. +
  14281. +int palette_getentries(int currcons, int offset, int size, unsigned long *entries)
  14282. +{
  14283. +  int i;
  14284. +
  14285. +  if(offset>18 || offset<0 || size<1)
  14286. +    return -EINVAL;
  14287. +
  14288. +  if(size>19)
  14289. +    size=19;
  14290. +
  14291. +  verify_area(VERIFY_WRITE,entries,size);
  14292. +
  14293. +  if(!paletteentries)
  14294. +    for(i=offset; i<offset+size; i++)
  14295. +      *entries++=default_palette_entries[i];
  14296. +  else
  14297. +    for(i=offset; i<offset+size; i++)
  14298. +      *entries++=(paletteentries[i] & 0x1FFF);
  14299. +
  14300. +  return size;
  14301. +}
  14302. +
  14303. +int palette_setentries(int currcons, int offset, int size, unsigned long *entries)
  14304. +{
  14305. +  int i;
  14306. +
  14307. +  if(offset>18 || offset<0 || size<1)
  14308. +    return -EINVAL;
  14309. +
  14310. +  if(size>19)
  14311. +    size=19;
  14312. +
  14313. +  verify_area(VERIFY_READ, entries, size);
  14314. +
  14315. +  if(!paletteentries)
  14316. +  {
  14317. +    paletteentries = (unsigned long *)kmalloc(sizeof(unsigned long)*19,GFP_KERNEL);
  14318. +    if(!paletteentries)
  14319. +      return -ENOMEM;
  14320. +
  14321. +    for(i=0; i<19; i++)
  14322. +      paletteentries[i]=default_palette_entries[i];
  14323. +  }
  14324. +
  14325. +  for(i=offset; i<offset+size; i++)
  14326. +    paletteentries[i]=(*entries++);
  14327. +
  14328. +  if(vcmode == KD_GRAPHICS && currcons == fg_console)
  14329. +    for(i=0; i<17; i++)
  14330. +      vidc_write(i<<2, paletteentries[i] & 0x1fff);
  14331. +
  14332. +  return size;
  14333. +}
  14334. +
  14335. +void palette_update(int currcons)
  14336. +{
  14337. +  int i;
  14338. +  if(vcmode == KD_GRAPHICS && paletteentries)
  14339. +    for(i=0; i<17; i++)
  14340. +      vidc_write(i<<2, paletteentries[i] & 0x1fff);
  14341. +  else
  14342. +    for(i=0; i<17; i++)
  14343. +      vidc_write(i<<2, default_palette_entries[i]);
  14344. +}
  14345. +
  14346. +int console_getparams(int con, unsigned long *data)
  14347. +{
  14348. +    data[0] = 0;                    /* version      */
  14349. +    data[1] = video_num_columns * 8;        /* horiz pixels */
  14350. +    data[2] = video_num_lines * 8;            /* vert. pixels */
  14351. +    data[3] = bytes_per_char_h == 4 ? 4 : 8;    /* bits per pix */
  14352. +    data[4] = 4;                    /* depth        */
  14353. +    return 0;
  14354. +}
  14355. +
  14356. +static void put_cursor(char on_off,unsigned long newcp)
  14357. +{
  14358. +  static char con=0;
  14359. +  unsigned long cp_p=cp;
  14360. +  int c = bytes_per_char_h == 8 ? color_table[15] : 0x11 * color_table[15];
  14361. +  int i;
  14362. +
  14363. +  if(vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
  14364. +    return;
  14365. +
  14366. +  cp=newcp;
  14367. +
  14368. +  if(con!=on_off)
  14369. +  {
  14370. +    if(cp_p!=-1)
  14371. +      for(i=0;i<bytes_per_char_h;i++)
  14372. +        ((unsigned char*)cp_p)[i]^=c;
  14373. +    con=on_off;
  14374. +  }
  14375. +}
  14376. +
  14377. +static void vsync_irq(int irq, struct pt_regs *regs)
  14378. +{
  14379. +  static char cursor_flash=0;
  14380. +  int currcons = fg_console;
  14381. +
  14382. +  if(++cursor_flash==16)
  14383. +  {
  14384. +    cursor_flash=0;
  14385. +    cursor_on=cursor_on?0:1;
  14386. +    if(cursoron>0)
  14387. +      put_cursor(cursor_on,cp);
  14388. +  }
  14389. +}
  14390. +
  14391. +int do_screendump(int arg)
  14392. +{
  14393. +  char *buf=(char *)arg;
  14394. +  int l;
  14395. +  if(!suser())
  14396. +    return -EPERM;
  14397. +  l=verify_area(VERIFY_WRITE,buf,2);
  14398. +  if(l)
  14399. +    return l;
  14400. +  return -ENOSYS;
  14401. +}
  14402. +
  14403. +/* This routine reverses the highlight on s-e position */
  14404. +
  14405. +static void highlight(const int currcons, int s, int e)
  14406. +{
  14407. +    int i;
  14408. +    unsigned char *buffer = (unsigned char *)vc_scrbuf[currcons];
  14409. +
  14410. +    for(i = s; i <= e; i++)
  14411. +        buffer[4*i+3] ^= INVERSE;
  14412. +
  14413. +
  14414. +    if(currcons == fg_console)
  14415. +    {
  14416. +        unsigned long p,pp;
  14417. +        int hx,hy,hex,hey,mx,my;
  14418. +
  14419. +        buffer += (s*4);
  14420. +
  14421. +        hx = s % video_num_columns;
  14422. +        hy = s / video_num_columns;
  14423. +        hex = e % video_num_columns;
  14424. +        hey = e / video_num_columns;
  14425. +
  14426. +        p = origin + (hy * video_size_row);
  14427. +        for(my = hy; my <= hey ; my++)
  14428. +        {
  14429. +            pp = p + (hx * bytes_per_char_h);
  14430. +            for(mx = hx; mx < ((my == hey)?hex+1:video_num_columns); mx++)
  14431. +            {
  14432. +                ll_char_write(pp,buffer[0],buffer[1],buffer[2],buffer[3]);
  14433. +                pp+=bytes_per_char_h;
  14434. +                buffer+=4;
  14435. +                hx = 0;
  14436. +            }
  14437. +            p+=video_size_row;
  14438. +        }
  14439. +    }
  14440. +}
  14441. +
  14442. +static void highlight_pointer(const int currcons,const int where)
  14443. +{
  14444. +}
  14445. +
  14446. +static unsigned long inwordLut[4]={
  14447. +  0x00000000, /* control char      */
  14448. +  0x03FF0000, /* digits            */
  14449. +  0x87FFFFFE, /* uppercase and '_' */
  14450. +  0x07FFFFFE  /* lowercase         */
  14451. +};
  14452. +
  14453. +static inline int inword(const char c)
  14454. +{
  14455. +  return ( inwordLut[(c>>5)&3] >> (c&0x1F) ) & 1;
  14456. +}
  14457. +
  14458. +int sel_loadlut(const int arg)
  14459. +{
  14460. +    memcpy_fromfs(inwordLut, (unsigned long *)(arg+4), 16);
  14461. +    return 0;
  14462. +}
  14463. +
  14464. +static inline int atedge(const int p)
  14465. +{
  14466. +    return (!(p % video_num_columns) || !((p + 1) % video_num_columns));
  14467. +}
  14468. +
  14469. +/* constrain v such that l <= v <= u */
  14470. +static inline short limit(const int v, const int l, const int u)
  14471. +{
  14472. +    return (v < l) ? l : ((v > u) ? u : v);
  14473. +}
  14474. +
  14475. +int set_selection(const int arg, struct tty_struct *tty)
  14476. +{
  14477. +    unsigned short *args, xs, ys, xe, ye;
  14478. +    int sel_mode, new_sel_start, new_sel_end;
  14479. +    int ps, pe, i;
  14480. +    int currcons = fg_console;
  14481. +    char spc, *obp, *bp, *spos;
  14482. +
  14483. +    char *off = (char *)vc_scrbuf[currcons];
  14484. +
  14485. +    unblank_screen();
  14486. +    args = (unsigned short *)(arg + 1);
  14487. +    xs = limit(get_fs_word(args++) - 1, 0, video_num_columns - 1);
  14488. +    ys = limit(get_fs_word(args++) - 1, 0, video_num_lines - 1);
  14489. +    xe = limit(get_fs_word(args++) - 1, 0, video_num_columns - 1);
  14490. +    ye = limit(get_fs_word(args++) - 1, 0, video_num_lines - 1);
  14491. +    sel_mode = get_fs_word(args);
  14492. +
  14493. +    ps = ys * video_num_columns + xs;
  14494. +    pe = ye * video_num_columns + xe;
  14495. +
  14496. +    if (report_mouse && (sel_mode & 16))
  14497. +    {
  14498. +        mouse_report(currcons, tty, sel_mode & 15, xs, ys);
  14499. +        return 0;
  14500. +    }
  14501. +
  14502. +    if ( ps > pe )
  14503. +    {
  14504. +        ps ^= pe;
  14505. +        pe ^= ps;
  14506. +        ps ^= pe;
  14507. +    }
  14508. +
  14509. +    switch (sel_mode)
  14510. +    {
  14511. +        case 0: /* character-by-character selection */
  14512. +            new_sel_start = ps;
  14513. +            new_sel_end = pe;
  14514. +            break;
  14515. +        case 1:    /* word-by-word selection */
  14516. +            spc = isspace(*off + (ps << 2));
  14517. +            for (new_sel_start = ps; ; ps -= 1)
  14518. +            {
  14519. +                if ((spc && !isspace(*(off + (ps << 2)))) ||
  14520. +                    (!spc && !inword(*(off + (ps << 2)))))
  14521. +                    break;
  14522. +                new_sel_start = ps;
  14523. +                if (!(ps % video_num_columns))
  14524. +                    break;
  14525. +            }
  14526. +            spc = isspace(*(off + (pe << 2)));
  14527. +            for (new_sel_end = pe; ; pe += 1)
  14528. +            {
  14529. +                if ((spc && !isspace(*(off + (pe << 2)))) ||
  14530. +                    (!spc && !inword(*(off + (pe << 2)))))
  14531. +                    break;
  14532. +                new_sel_end = pe;
  14533. +                if (!((pe + 1) % video_num_columns))
  14534. +                    break;
  14535. +            }
  14536. +            break;
  14537. +        case 2: /* line-by-line selection */
  14538. +            new_sel_start = ps - ps % video_num_columns;
  14539. +            new_sel_end   = pe + video_num_columns - pe % video_num_columns - 1;
  14540. +            break;
  14541. +        case 3:    /* pointer highlight */
  14542. +            if (sel_cons != currcons)
  14543. +            {
  14544. +                highlight_pointer(sel_cons, -1);
  14545. +                clear_selection();
  14546. +                sel_cons = currcons;
  14547. +            }
  14548. +            highlight_pointer(sel_cons, pe);
  14549. +            return 0;
  14550. +        default:
  14551. +            return -EINVAL;
  14552. +    }
  14553. +    if(new_sel_end > new_sel_start && !atedge(new_sel_end) &&
  14554. +            isspace(*(off + (new_sel_end << 2))))
  14555. +    {
  14556. +        for (pe = new_sel_end + 1; ; pe += 1)
  14557. +        {
  14558. +            if (!isspace(*(off + (pe << 2))) || atedge(pe))
  14559. +                break;
  14560. +        }
  14561. +        if (isspace(*(off + (pe << 2))))
  14562. +            new_sel_end = pe;
  14563. +    }
  14564. +    if (sel_cons != currcons)
  14565. +    {
  14566. +        clear_selection();
  14567. +        sel_cons = currcons;
  14568. +    }
  14569. +    if(sel_start == -1)
  14570. +        highlight(sel_cons, new_sel_start, new_sel_end);
  14571. +    else if (new_sel_start == sel_start)
  14572. +    {
  14573. +        if (new_sel_end == sel_end)    /* no action required */
  14574. +            return 0;
  14575. +        else if (new_sel_end > sel_end)    /* extend to right/down */
  14576. +            highlight(sel_cons, sel_end + 1, new_sel_end);
  14577. +        else                /* contract from right/up */
  14578. +            highlight(sel_cons, new_sel_end + 1, sel_end);
  14579. +    }
  14580. +    else if (new_sel_end == sel_end)
  14581. +    {
  14582. +        if (new_sel_start < sel_start)    /* extend to left */
  14583. +            highlight(sel_cons, new_sel_start, sel_start - 1);
  14584. +        else
  14585. +            highlight(sel_cons, sel_start, new_sel_start - 1);
  14586. +    }
  14587. +    else
  14588. +    {
  14589. +        clear_selection();
  14590. +        highlight(sel_cons, new_sel_start, new_sel_end);
  14591. +    }
  14592. +    sel_start = new_sel_start;
  14593. +    sel_end = new_sel_end;
  14594. +
  14595. +    obp = bp = sel_buffer;
  14596. +
  14597. +    for (i = sel_start; i <= sel_end; i+=1)
  14598. +    {
  14599. +        spos = (char *)off + (i << 2);
  14600. +        *bp++ = *spos;
  14601. +        if (!isspace(*spos))
  14602. +            obp = bp;
  14603. +        if (! ((i+1) % video_num_columns))
  14604. +        {
  14605. +             /* strip trailing spaces from line and add newline,
  14606. +                unless non-space at end of line. */
  14607. +             if (obp != bp)
  14608. +             {
  14609. +                 bp = obp;
  14610. +                 *bp++ = '\r';
  14611. +             }
  14612. +             obp = bp;
  14613. +        }
  14614. +        /* check for space, leaving room for next character, possible
  14615. +           newline, and null at end. */
  14616. +        if (bp - sel_buffer > SEL_BUFFER_SIZE - 3)
  14617. +            break;
  14618. +    }
  14619. +    *bp = '\0';
  14620. +    return 0;
  14621. +}
  14622. +
  14623. +int paste_selection(struct tty_struct *tty)
  14624. +{
  14625. +    struct wait_queue wait;
  14626. +    char *bp = sel_buffer;
  14627. +    int c,l;
  14628. +    struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
  14629. +
  14630. +    if(!sel_buffer[0])
  14631. +        return 0;
  14632. +    unblank_screen();
  14633. +    c = strlen(sel_buffer);
  14634. +    current->state = TASK_INTERRUPTIBLE;
  14635. +    add_wait_queue(&vt->paste_wait, &wait);
  14636. +    while (c) {
  14637. +        if (test_bit(TTY_THROTTLED, &tty->flags)) {
  14638. +            schedule();
  14639. +            continue;
  14640. +        }
  14641. +        l = MIN(c, tty->ldisc.receive_room(tty));
  14642. +        tty->ldisc.receive_buf(tty,(unsigned char *) bp, 0, l);
  14643. +        c -= l;
  14644. +        bp += l;
  14645. +    }
  14646. +    current->state = TASK_RUNNING;
  14647. +    return 0;
  14648. +}
  14649. +
  14650. +static void clear_selection()
  14651. +{
  14652. +    highlight_pointer(sel_cons, -1); /* hide the pointer */
  14653. +    if (sel_start != -1)
  14654. +    {
  14655. +        highlight(sel_cons, sel_start, sel_end);
  14656. +        sel_start = -1;
  14657. +    }
  14658. +}
  14659. +
  14660. +/* -------------------------------------------------------------------------------
  14661. + * erasing
  14662. + * ------------------------------------------------------------------------------- */
  14663. +
  14664. +static void ll_erasebuf(int currcons,unsigned char sx,unsigned char sy,
  14665. +            unsigned char cx,unsigned char cy)
  14666. +{
  14667. +    unsigned char *buffer = vc_scrbuf[currcons];
  14668. +    if(sx!=0) /* Erase to end of line */
  14669. +    {
  14670. +        register unsigned char c;
  14671. +        if(cy!=0)
  14672. +            c=video_num_columns-sx;
  14673. +        else
  14674. +            c=video_num_columns-sx<cx?video_num_columns-sx:cx;
  14675. +        memfastset((void*)(buffer+4*(sx+sy*video_num_columns)),
  14676. +            (backcol<<16) | (forecol<<8) | 32, 4*c);
  14677. +        cx-=c;
  14678. +        sy++;
  14679. +        if(cy>0)
  14680. +            cy--;
  14681. +        sx=0;
  14682. +    }
  14683. +    if(cy!=0)
  14684. +    {
  14685. +        memfastset((void*)(buffer+sy*video_num_columns*4),
  14686. +            (backcol<<16) | (forecol<<8) | 32,cy*video_num_columns*4);
  14687. +    }
  14688. +    if(cx!=0)
  14689. +    {
  14690. +        memfastset((void*)(buffer+(sy+cy)*video_num_columns*4),
  14691. +            (backcol<<16) | (forecol<<8) | 32,cx*4);
  14692. +    }
  14693. +}
  14694. +
  14695. +static void ll_erase(int currcons,unsigned char sx,unsigned char sy,
  14696. +                      unsigned char cx,unsigned char cy)
  14697. +{
  14698. +    register unsigned char *p,cc;
  14699. +    register unsigned int i1,i2;
  14700. +
  14701. +    ll_erasebuf(currcons,sx,sy,cx,cy);
  14702. +
  14703. +    if(currcons==fg_console)
  14704. +    {
  14705. +        cc=0x11*backcol;
  14706. +
  14707. +        if(sx!=0) /* Erase to end of line */
  14708. +        {
  14709. +            register unsigned char c;
  14710. +            if(cy!=0)
  14711. +                c=video_num_columns-sx;
  14712. +            else
  14713. +                c=video_num_columns-sx<cx?video_num_columns-sx:cx;
  14714. +            p=(unsigned char*)(origin+sy*video_num_columns*
  14715. +                        bytes_per_char_h*bytes_per_char_v+
  14716. +                                sx*bytes_per_char_h);
  14717. +            for(i1=0;i1<c*bytes_per_char_h;i1++)
  14718. +                for(i2=0;i2<bytes_per_char_v;i2++)
  14719. +                    p[i1+i2*video_num_columns*bytes_per_char_h]=cc;
  14720. +            cx-=c;
  14721. +            if(cy>0)
  14722. +                cy--;
  14723. +            sy++;
  14724. +            sx=0;
  14725. +        }
  14726. +        if(cy!=0)
  14727. +        {
  14728. +            memfastset((void*)(origin+sy*video_num_columns*
  14729. +                        bytes_per_char_h*bytes_per_char_v),
  14730. +                0x11111111L*backcol,
  14731. +                cy*bytes_per_char_h*bytes_per_char_v*video_num_columns);
  14732. +        }
  14733. +        if(cx!=0)
  14734. +        {
  14735. +            p=(unsigned char*)(origin+(sy+cy)*video_num_columns*
  14736. +                        bytes_per_char_h*bytes_per_char_v);
  14737. +            for(i1=0;i1<cx*bytes_per_char_h;i1++)
  14738. +                for(i2=0;i2<bytes_per_char_v;i2++)
  14739. +                    p[i1+i2*video_num_columns*bytes_per_char_h]=cc;
  14740. +        }
  14741. +    }
  14742. +}
  14743. +
  14744. diff -r -u -N linux.orig/arch/arm/drivers/char/consolemap.c linux.arm/arch/arm/drivers/char/consolemap.c
  14745. --- linux.orig/arch/arm/drivers/char/consolemap.c    Thu Jan  1 01:00:00 1970
  14746. +++ linux.arm/arch/arm/drivers/char/consolemap.c    Fri Oct 27 23:14:30 1995
  14747. @@ -0,0 +1,286 @@
  14748. +/*
  14749. + * consolemap.c
  14750. + *
  14751. + * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
  14752. + * to font positions.
  14753. + *
  14754. + * aeb, 950210
  14755. + */
  14756. +
  14757. +#include <linux/kd.h>
  14758. +#include <linux/errno.h>
  14759. +#include <linux/mm.h>
  14760. +#include <linux/malloc.h>
  14761. +#include <asm/segment.h>
  14762. +#include "consolemap.h"
  14763. +
  14764. +static unsigned char * translations[] = {
  14765. +/* 8-bit Latin-1 mapped to the PC character set: '\0' means non-printable */
  14766. +(unsigned char *)
  14767. +    "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  14768. +    "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
  14769. +    " !\"#$%&'()*+,-./0123456789:;<=>?"
  14770. +    "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
  14771. +    "`abcdefghijklmnopqrstuvwxyz{|}~\0"
  14772. +    "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  14773. +    "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  14774. +    "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
  14775. +    "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
  14776. +    "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
  14777. +    "\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341"
  14778. +    "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
  14779. +    "\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230",
  14780. +/* vt100 graphics */
  14781. +(unsigned char *)
  14782. +    "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  14783. +    "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
  14784. +    " !\"#$%&'()*+,-./0123456789:;<=>?"
  14785. +    "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
  14786. +    "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304"
  14787. +    "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0"
  14788. +    "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  14789. +    "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  14790. +    "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
  14791. +    "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
  14792. +    "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
  14793. +    "\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
  14794. +    "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
  14795. +    "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
  14796. +/* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */
  14797. +(unsigned char *)
  14798. +    "\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000"
  14799. +    "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
  14800. +    "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
  14801. +    "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
  14802. +    "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
  14803. +    "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
  14804. +    "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
  14805. +    "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
  14806. +    "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
  14807. +    "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
  14808. +    "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
  14809. +    "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
  14810. +    "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
  14811. +    "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
  14812. +    "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
  14813. +    "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",
  14814. + /* USER: customizable mappings, initialized as the previous one (IBM) */
  14815. +(unsigned char *)
  14816. +    "\000\001\002\003\004\005\006\007\010\011\000\013\000\000\016\017"
  14817. +    "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
  14818. +    "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
  14819. +    "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
  14820. +    "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
  14821. +    "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
  14822. +    "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
  14823. +    "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
  14824. +    "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
  14825. +    "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
  14826. +    "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
  14827. +    "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
  14828. +    "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
  14829. +    "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
  14830. +    "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
  14831. +    "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
  14832. +};
  14833. +
  14834. +/* the above mappings are not invertible - this is just a best effort */
  14835. +static unsigned char * inv_translate = NULL;
  14836. +static unsigned char inv_norm_transl[E_TABSZ];
  14837. +static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL };
  14838. +
  14839. +static void set_inverse_transl(int i)
  14840. +{
  14841. +    int j;
  14842. +    unsigned char *p = translations[i];
  14843. +    unsigned char *q = inverse_translations[i];
  14844. +
  14845. +    if (!q) {
  14846. +        /* slightly messy to avoid calling kmalloc too early */
  14847. +        q = inverse_translations[i] = ((i == NORM_MAP)
  14848. +            ? inv_norm_transl
  14849. +            : (unsigned char *) kmalloc(E_TABSZ, GFP_KERNEL));
  14850. +        if (!q)
  14851. +            return;
  14852. +    }
  14853. +    for (j=0; j<E_TABSZ; j++)
  14854. +        q[j] = 0;
  14855. +    for (j=0; j<E_TABSZ; j++)
  14856. +        if (q[p[j]] < 32)    /* prefer '-' above SHY etc. */
  14857. +            q[p[j]] = j;
  14858. +}
  14859. +
  14860. +unsigned char *set_translate(int m)
  14861. +{
  14862. +    if (!inverse_translations[m])
  14863. +        set_inverse_transl(m);
  14864. +    inv_translate = inverse_translations[m];
  14865. +    return translations[m];
  14866. +}
  14867. +
  14868. +/*
  14869. + * Inverse translation is impossible for several reasons:
  14870. + * 1. The translation maps are not 1-1
  14871. + * 2. The text may have been written while a different translation map
  14872. + *    was active
  14873. + * Still, it is now possible to a certain extent to cut and paste non-ASCII.
  14874. + */
  14875. +unsigned char inverse_translate(unsigned char c) {
  14876. +    return ((inv_translate && inv_translate[c]) ? inv_translate[c] : c);
  14877. +}
  14878. +
  14879. +/*
  14880. + * Load customizable translation table
  14881. + * arg points to a 256 byte translation table.
  14882. + */
  14883. +int con_set_trans(char * arg)
  14884. +{
  14885. +    int i;
  14886. +    unsigned char *p = translations[USER_MAP];
  14887. +
  14888. +    i = verify_area(VERIFY_READ, (void *)arg, E_TABSZ);
  14889. +    if (i)
  14890. +        return i;
  14891. +
  14892. +    for (i=0; i<E_TABSZ ; i++)
  14893. +        p[i] = get_fs_byte(arg+i);
  14894. +    p[012] = p[014] = p[015] = p[033] = 0;
  14895. +    set_inverse_transl(USER_MAP);
  14896. +    return 0;
  14897. +}
  14898. +
  14899. +int con_get_trans(char * arg)
  14900. +{
  14901. +    int i;
  14902. +    unsigned char *p = translations[USER_MAP];
  14903. +
  14904. +    i = verify_area(VERIFY_WRITE, (void *)arg, E_TABSZ);
  14905. +    if (i)
  14906. +        return i;
  14907. +
  14908. +    for (i=0; i<E_TABSZ ; i++) put_fs_byte(p[i],arg+i);
  14909. +    return 0;
  14910. +}
  14911. +
  14912. +/*
  14913. + * Unicode -> current font conversion 
  14914. + *
  14915. + * A font has at most 512 chars, usually 256.
  14916. + * But one font position may represent several Unicode chars
  14917. + * (and moreover, hashtables work best when they are not too full),
  14918. + * so pick HASHSIZE somewhat larger than 512.
  14919. + * Since there are likely to be long consecutive stretches
  14920. + * (like U+0000 to U+00FF), HASHSTEP should not be too small.
  14921. + * Searches longer than MAXHASHLEVEL steps are refused, unless
  14922. + * requested explicitly.
  14923. + *
  14924. + * Note: no conversion tables are compiled in, so the user
  14925. + * must supply an explicit mapping herself. See kbd-0.90 (or an
  14926. + * earlier kernel version) for the default Unicode-to-PC mapping.
  14927. + * Usually, the mapping will be loaded simultaneously with the font.
  14928. + */
  14929. +
  14930. +#define HASHSIZE   641
  14931. +#define HASHSTEP   189        /* yields hashlevel = 3 initially */
  14932. +#define MAXHASHLEVEL 6
  14933. +static struct unipair hashtable[HASHSIZE];
  14934. +
  14935. +int hashtable_contents_valid = 0;     /* cleared by setfont */
  14936. +
  14937. +static unsigned int hashsize;
  14938. +static unsigned int hashstep;
  14939. +static unsigned int hashlevel;
  14940. +static unsigned int maxhashlevel;
  14941. +
  14942. +void
  14943. +con_clear_unimap(struct unimapinit *ui) {
  14944. +    int i;
  14945. +
  14946. +    /* read advisory values for hash algorithm */
  14947. +    hashsize = ui->advised_hashsize;
  14948. +    if (hashsize < 256 || hashsize > HASHSIZE)
  14949. +      hashsize = HASHSIZE;
  14950. +    hashstep = (ui->advised_hashstep % hashsize);
  14951. +    if (hashstep < 64)
  14952. +      hashstep = HASHSTEP;
  14953. +    maxhashlevel = ui->advised_hashlevel;
  14954. +    if (!maxhashlevel)
  14955. +      maxhashlevel = MAXHASHLEVEL;
  14956. +    if (maxhashlevel > hashsize)
  14957. +      maxhashlevel = hashsize;
  14958. +
  14959. +    /* initialize */
  14960. +    hashlevel = 0;
  14961. +    for (i=0; i<hashsize; i++)
  14962. +      hashtable[i].unicode = 0xffff;
  14963. +    hashtable_contents_valid = 1;
  14964. +}
  14965. +
  14966. +int
  14967. +con_set_unimap(ushort ct, struct unipair *list){
  14968. +    int i, lct;
  14969. +    ushort u, hu;
  14970. +    struct unimapinit hashdefaults = { 0, 0, 0 };
  14971. +
  14972. +    if (!hashtable_contents_valid)
  14973. +      con_clear_unimap(&hashdefaults);
  14974. +    while(ct) {
  14975. +        u = get_fs_word(&list->unicode);
  14976. +        i = u % hashsize;
  14977. +        lct = 1;
  14978. +        while ((hu = hashtable[i].unicode) != 0xffff && hu != u) {
  14979. +        if (lct++ >=  maxhashlevel)
  14980. +          return -ENOMEM;
  14981. +        i += hashstep;
  14982. +        if (i >= hashsize)
  14983. +          i -= hashsize;
  14984. +        }
  14985. +        if (lct > hashlevel)
  14986. +          hashlevel = lct;
  14987. +        hashtable[i].unicode = u;
  14988. +        hashtable[i].fontpos = get_fs_word(&list->fontpos);
  14989. +        list++;
  14990. +        ct--;
  14991. +    }
  14992. +    return 0;
  14993. +}
  14994. +
  14995. +int
  14996. +con_get_unimap(ushort ct, ushort *uct, struct unipair *list){
  14997. +    int i, ect;
  14998. +
  14999. +    ect = 0;
  15000. +    if (hashtable_contents_valid)
  15001. +      for (i = 0; i<hashsize; i++)
  15002. +        if (hashtable[i].unicode != 0xffff) {
  15003. +        if (ect++ < ct) {
  15004. +            put_fs_word(hashtable[i].unicode, &list->unicode);
  15005. +            put_fs_word(hashtable[i].fontpos, &list->fontpos);
  15006. +            list++;
  15007. +        }
  15008. +        }
  15009. +    put_fs_word(ect, uct);
  15010. +    return ((ect <= ct) ? 0 : -ENOMEM);
  15011. +}
  15012. +
  15013. +int
  15014. +conv_uni_to_pc(unsigned long ucs) {
  15015. +      int i, h;
  15016. +
  15017. +      if (!hashtable_contents_valid || ucs < 0x20)
  15018. +    return -3;
  15019. +      if (ucs == 0xffff || ucs == 0xfffe)
  15020. +    return -1;
  15021. +      if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
  15022. +    return -2;
  15023. +      
  15024. +      h = ucs % hashsize;
  15025. +      for (i = 0; i < hashlevel; i++) {
  15026. +      if (hashtable[h].unicode == ucs)
  15027. +        return hashtable[h].fontpos;
  15028. +      if ((h += hashstep) >= hashsize)
  15029. +        h -= hashsize;
  15030. +      }
  15031. +
  15032. +      return -4;        /* not found */
  15033. +}
  15034. diff -r -u -N linux.orig/arch/arm/drivers/char/consolemap.h linux.arm/arch/arm/drivers/char/consolemap.h
  15035. --- linux.orig/arch/arm/drivers/char/consolemap.h    Thu Jan  1 01:00:00 1970
  15036. +++ linux.arm/arch/arm/drivers/char/consolemap.h    Fri Oct 27 23:14:39 1995
  15037. @@ -0,0 +1,13 @@
  15038. +/*
  15039. + * consolemap.h
  15040. + *
  15041. + * Interface between console.c, selection.c  and consolemap.c
  15042. + */
  15043. +#define NORM_MAP 0
  15044. +#define GRAF_MAP 1
  15045. +#define NULL_MAP 2
  15046. +#define USER_MAP 3
  15047. +
  15048. +extern int hashtable_contents_valid;
  15049. +extern unsigned char inverse_translate(unsigned char c);
  15050. +extern unsigned char *set_translate(int m);
  15051. diff -r -u -N linux.orig/arch/arm/drivers/char/defkeymap.c linux.arm/arch/arm/drivers/char/defkeymap.c
  15052. --- linux.orig/arch/arm/drivers/char/defkeymap.c    Thu Jan  1 01:00:00 1970
  15053. +++ linux.arm/arch/arm/drivers/char/defkeymap.c    Fri Oct 27 23:14:20 1995
  15054. @@ -0,0 +1,331 @@
  15055. +#include <linux/types.h>
  15056. +#include <linux/keyboard.h>
  15057. +#include <linux/kd.h>
  15058. +
  15059. +/* Normal (maps 1:1 with no processing) */
  15060. +#define KTn    0xF0
  15061. +/* Function keys */
  15062. +#define KTf    0xF1
  15063. +/* Special (Performs special house-keeping funcs) */
  15064. +#define KTs    0xF2
  15065. +#define KIGNORE        K(KTs, 0)    /* Ignore */
  15066. +#define KENTER        K(KTs, 1)    /* Enter */
  15067. +#define KREGS        K(KTs, 2)    /* Regs */
  15068. +#define KMEM        K(KTs, 3)    /* Mem */
  15069. +#define KSTAT        K(KTs, 4)    /* State */
  15070. +#define KINTR        K(KTs, 5)    /* Intr */
  15071. +#define Ksl    6    /* Last console */
  15072. +#define KCAPSLK        K(KTs, 7)    /* Caps lock */
  15073. +#define KNUMLK        K(KTs, 8)    /* Num-lock */
  15074. +#define KSCRLLK        K(KTs, 9)    /* Scroll-lock */
  15075. +#define KSCRLFOR    K(KTs,10)    /* Scroll forward */
  15076. +#define KSCRLBAK    K(KTs,11)    /* Scroll back */
  15077. +#define KREBOOT        K(KTs,12)    /* Reboot */
  15078. +#define KCAPSON        K(KTs,13)    /* Caps on */
  15079. +#define KCOMPOSE    K(KTs,14)    /* Compose */
  15080. +#define KSAK        K(KTs,15)    /* SAK */
  15081. +#define CONS_DEC    K(KTs,16)    /* Dec console */
  15082. +#define CONS_INC    K(KTs,17)    /* Incr console */
  15083. +#define KFLOPPY        K(KTs,18)    /* Floppy */
  15084. +/* Key pad (0-9 = digits, 10=+, 11=-, 12=*, 13=/, 14=enter, 16=., 17=# */
  15085. +#define KTp    0xF3
  15086. +#define KPAD_0        K(KTp, 0 )
  15087. +#define KPAD_1      K(KTp, 1 )
  15088. +#define KPAD_2        K(KTp, 2 )
  15089. +#define KPAD_3        K(KTp, 3 )
  15090. +#define KPAD_4        K(KTp, 4 )
  15091. +#define KPAD_5        K(KTp, 5 )
  15092. +#define KPAD_6        K(KTp, 6 )
  15093. +#define KPAD_7        K(KTp, 7 )
  15094. +#define KPAD_8        K(KTp, 8 )
  15095. +#define KPAD_9        K(KTp, 9 )
  15096. +#define KPAD_PL        K(KTp,10 )
  15097. +#define KPAD_MI        K(KTp,11 )
  15098. +#define KPAD_ML        K(KTp,12 )
  15099. +#define KPAD_DV        K(KTp,13 )
  15100. +#define KPAD_EN        K(KTp,14 )
  15101. +#define KPAD_DT        K(KTp,16 )
  15102. +#define KPAD_HS        K(KTp,18 )
  15103. +/* Console switching */
  15104. +#define KCn    0xF5
  15105. +/* Cursor */
  15106. +#define KTc    0xF6
  15107. +#define Kcd    0    /* Cursor down */
  15108. +#define Kcl    1    /* Cursor left */
  15109. +#define Kcr    2    /* Cursor right */
  15110. +#define Kcu    3    /* Cursor up */
  15111. +/* Shift/alt modifiers etc */
  15112. +#define KMd    0xF7
  15113. +#define KSHIFT        K(KMd, 0 )
  15114. +#define KALTGR        K(KMd, 1 )
  15115. +#define KCTRL        K(KMd, 2 )
  15116. +#define KALT        K(KMd, 3 )
  15117. +/* Meta */
  15118. +#define KMt    0xF8
  15119. +#define KAs    0xF9
  15120. +#define KPADA_0        K(KAs, 0 )
  15121. +#define KPADA_1        K(KAs, 1 )
  15122. +#define KPADA_2        K(KAs, 2 )
  15123. +#define KPADA_3        K(KAs, 3 )
  15124. +#define KPADA_4        K(KAs, 4 )
  15125. +#define KPADA_5        K(KAs, 5 )
  15126. +#define KPADA_6        K(KAs, 6 )
  15127. +#define KPADA_7        K(KAs, 7 )
  15128. +#define KPADA_8        K(KAs, 8 )
  15129. +#define KPADA_9        K(KAs, 9 )
  15130. +#define KPADB_0        K(KAs,10 )
  15131. +#define KPADB_1        K(KAs,11 )
  15132. +#define KPADB_2        K(KAs,12 )
  15133. +#define KPADB_3        K(KAs,13 )
  15134. +#define KPADB_4        K(KAs,14 )
  15135. +#define KPADB_5        K(KAs,15 )
  15136. +#define KPADB_6        K(KAs,16 )
  15137. +#define KPADB_7        K(KAs,17 )
  15138. +#define KPADB_8        K(KAs,18 )
  15139. +#define KPADB_9        K(KAs,19 )
  15140. +/* Locking keys */
  15141. +#define KLk    0xFA
  15142. +/* Letters */
  15143. +#define KTl    0xFB
  15144. +
  15145. +u_short plain_map[]=
  15146. +{
  15147. +  K(KTn, 27),K(KTf,  0),K(KTf,  1),K(KTf,  2 ),K(KTf,  3),K(KTf,  4),K(KTf,  5 ),K(KTf,  6),
  15148. +  K(KTf,  7),K(KTf,  8),K(KTf,  9),K(KTf, 10 ),K(KTf, 11),KIGNORE   ,KSCRLLK    ,KINTR     ,
  15149. +  K(KTn,'`'),K(KTn,'1'),K(KTn,'2'),K(KTn,'3' ),K(KTn,'4'),K(KTn,'5'),K(KTn,'6' ),K(KTn,'7'),
  15150. +  K(KTn,'8'),K(KTn,'9'),K(KTn,'0'),K(KTn,'-' ),K(KTn,'='),K(KTn,'£'),K(KTn,127 ),K(KTf,21 ),
  15151. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,K(KTn,  9 ),K(KTl,'q'),
  15152. +  K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
  15153. +  K(KTl,'p'),K(KTn,'['),K(KTn,']'),K(KTn,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  15154. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTl,'a'),K(KTl,'s'),K(KTl,'d' ),K(KTl,'f'),
  15155. +  K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),K(KTn,';'),K(KTn,'\''),KENTER    ,
  15156. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTl,'z' ),K(KTl,'x'),
  15157. +  K(KTl,'c'),K(KTl,'v'),K(KTl,'b'),K(KTl,'n' ),K(KTl,'m'),K(KTn,','),K(KTn,'.' ),K(KTn,'/'),
  15158. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn,' '),
  15159. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  15160. +};
  15161. +
  15162. +u_short shift_map[]=
  15163. +{
  15164. +  K(KTn, 27),K(KTf, 10),K(KTf, 11),K(KTf, 12 ),K(KTf, 13),K(KTf, 14),K(KTf, 15 ),K(KTf, 16),
  15165. +  K(KTf, 17),K(KTf, 18),K(KTf, 19),K(KTf, 20 ),K(KTf, 21),KIGNORE   ,KMEM       ,KINTR     ,
  15166. +  K(KTn,'~'),K(KTn,'!'),K(KTn,'@'),K(KTn,'#' ),K(KTn,'$'),K(KTn,'%'),K(KTn,'^' ),K(KTn,'&'),
  15167. +  K(KTn,'*'),K(KTn,'('),K(KTn,')'),K(KTn,'_' ),K(KTn,'+'),K(KTn,'¤'),K(KTn,127 ),K(KTf,21 ),
  15168. +  K(KTf,20 ),KSCRLBAK  ,KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,K(KTn,  9 ),K(KTl,'Q'),
  15169. +  K(KTl,'W'),K(KTl,'E'),K(KTl,'R'),K(KTl,'T' ),K(KTl,'Y'),K(KTl,'U'),K(KTl,'I' ),K(KTl,'O'),
  15170. +  K(KTl,'P'),K(KTn,'{'),K(KTn,'}'),K(KTn,'|' ),K(KTf,22 ),K(KTf,23 ),KSCRLFOR   ,KPAD_7    ,
  15171. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTl,'A'),K(KTl,'S'),K(KTl,'D' ),K(KTl,'F'),
  15172. +  K(KTl,'G'),K(KTl,'H'),K(KTl,'J'),K(KTl,'K' ),K(KTl,'L'),K(KTn,':'),K(KTn,'"' ),KENTER    ,
  15173. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTl,'Z' ),K(KTl,'X'),
  15174. +  K(KTl,'C'),K(KTl,'V'),K(KTl,'B'),K(KTl,'N' ),K(KTl,'M'),K(KTn,'<'),K(KTn,'>' ),K(KTn,'?'),
  15175. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn,' '),
  15176. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  15177. +};
  15178. +
  15179. +u_short altgr_map[]=
  15180. +{
  15181. +  KIGNORE   ,K(KCn,12 ),K(KCn,13 ),K(KCn,14  ),K(KCn,15 ),K(KCn,16 ),K(KCn,17  ),K(KCn, 18),
  15182. +  K(KCn, 19),K(KCn,20 ),K(KCn,21 ),K(KCn,22  ),K(KCn,23 ),KIGNORE   ,KREGS      ,KINTR     ,
  15183. +  KIGNORE   ,KIGNORE   ,K(KTn,'@'),KIGNORE    ,K(KTn,'$'),KIGNORE   ,KIGNORE    ,K(KTn,'{'),
  15184. +  K(KTn,'['),K(KTn,']'),K(KTn,'}'),K(KTn,'\\'),KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,21 ),
  15185. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KTl,'q'),
  15186. +  K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
  15187. +  K(KTl,'p'),KIGNORE   ,K(KTn,'~'),KIGNORE    ,K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPADB_7   ,
  15188. +  KPADB_8   ,KPADB_9   ,KPAD_MI   ,KCTRL      ,K(KAs,20 ),K(KTl,'s'),K(KAs,23  ),K(KAs,25 ),
  15189. +  K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),KIGNORE   ,KIGNORE    ,KENTER    ,
  15190. +  KPADB_4   ,KPADB_5   ,KPADB_6   ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTl,'z' ),K(KTl,'x'),
  15191. +  K(KAs,22 ),K(KTl,'v'),K(KTl,21 ),K(KTl,'n' ),K(KTl,'m'),KIGNORE   ,KIGNORE    ,KIGNORE   ,
  15192. +  KSHIFT    ,K(KTc,Kcu),KPADB_1   ,KPADB_2    ,KPADB_3   ,KCAPSLK   ,KALT       ,KIGNORE   ,
  15193. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPADB_0   ,KPAD_DT    ,KPAD_EN
  15194. +};
  15195. +
  15196. +u_short ctrl_map[]=
  15197. +{
  15198. +  KIGNORE   ,K(KTf,  0),K(KTf,  1),K(KTf,  2 ),K(KTf,  3),K(KTf,  4),K(KTf, 5  ),K(KTf,  6),
  15199. +  K(KTf,  7),K(KTf,  8),K(KTf,  9),K(KTf, 10 ),K(KTf, 11),KIGNORE   ,KSTAT      ,KINTR     ,
  15200. +  KIGNORE   ,K(KTn, 1 ),K(KTn, 2 ),K(KTn, 3  ),K(KTn, 4 ),K(KTn, 5 ),K(KTn, 6  ),K(KTn, 7 ),
  15201. +  K(KTn, 8 ),K(KTn, 9 ),K(KTn, 0 ),K(KTn,31  ),KIGNORE   ,KIGNORE   ,K(KTn, 8  ),K(KTf,21 ),
  15202. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KTn,17 ),
  15203. +  K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20  ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9  ),K(KTn,15 ),
  15204. +  K(KTn,16 ),K(KTn,27 ),K(KTn,29 ),K(KTn,28  ),K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  15205. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4  ),K(KTn, 6 ),
  15206. +  K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11  ),K(KTn,12 ),KIGNORE   ,K(KTn, 7  ),KENTER    ,
  15207. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTn,26  ),K(KTn,24 ),
  15208. +  K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14  ),K(KTn,13 ),KIGNORE   ,KCOMPOSE   ,K(KTn,127),
  15209. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn, 0 ),
  15210. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  15211. +};
  15212. +
  15213. +u_short shift_ctrl_map[]=
  15214. +{
  15215. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,
  15216. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KFLOPPY    ,KINTR     ,
  15217. +  KIGNORE   ,KIGNORE   ,K(KTn, 0 ),KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,
  15218. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,K(KTn,31  ),KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,21 ),
  15219. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KTn,17 ),
  15220. +  K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20  ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9  ),K(KTn,15 ),
  15221. +  K(KTn,16 ),KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  15222. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4  ),K(KTn, 6 ),
  15223. +  K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11  ),K(KTn,12 ),KIGNORE   ,K(KTn, 7  ),KENTER    ,
  15224. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTn,26  ),K(KTn,24 ),
  15225. +  K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14  ),K(KTn,13 ),KIGNORE   ,KIGNORE    ,KIGNORE   ,
  15226. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn, 0 ),
  15227. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  15228. +};
  15229. +
  15230. +u_short alt_map[]=
  15231. +{
  15232. +  K(KMt,27 ),K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2  ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5  ),K(KCn, 6 ),
  15233. +  K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10  ),K(KCn,11 ),KIGNORE   ,KSCRLLK    ,KINTR     ,
  15234. +  K(KMt,'`'),K(KMt,'1'),K(KMt,'2'),K(KMt,'3' ),K(KMt,'4'),K(KMt,'5'),K(KMt,'6' ),K(KMt,'7'),
  15235. +  K(KMt,'8'),K(KMt,'9'),K(KMt,'0'),K(KMt,'-' ),K(KMt,'='),K(KMt,'£'),K(KMt,127 ),K(KTf,21 ),
  15236. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,K(KMt, 9  ),K(KMt,'q'),
  15237. +  K(KMt,'w'),K(KMt,'e'),K(KMt,'r'),K(KMt,'t' ),K(KMt,'y'),K(KMt,'u'),K(KMt,'i' ),K(KMt,'o'),
  15238. +  K(KMt,'p'),K(KMt,'['),K(KMt,']'),K(KMt,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPADA_7   ,
  15239. +  KPADA_8   ,KPADA_9   ,KPAD_MI   ,KCTRL      ,K(KMt,'a'),K(KMt,'s'),K(KMt,'d' ),K(KMt,'f'),
  15240. +  K(KMt,'g'),K(KMt,'h'),K(KMt,'j'),K(KMt,'k' ),K(KMt,'l'),K(KMt,';'),K(KMt,'\''),K(KMt,13 ),
  15241. +  KPADA_4   ,KPADA_5   ,KPADA_6   ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KMt,'z' ),K(KMt,'x'),
  15242. +  K(KMt,'c'),K(KMt,'v'),K(KMt,'b'),K(KMt,'n' ),K(KMt,'m'),K(KMt,','),K(KMt,'.' ),KIGNORE   ,
  15243. +  KSHIFT    ,K(KTc,Kcu),KPADA_1   ,KPADA_2    ,KPADA_3   ,KCAPSLK   ,KALT       ,K(KMt,' '),
  15244. +  KALTGR    ,KCTRL     ,CONS_DEC  ,K(KTc,Kcd ),CONS_INC  ,KPADA_0   ,KPAD_DT    ,KPAD_EN
  15245. +};
  15246. +
  15247. +u_short ctrl_alt_map[]=
  15248. +{
  15249. +  KIGNORE   ,K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2  ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5  ),K(KCn, 6 ),
  15250. +  K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10  ),K(KCn,11 ),KIGNORE   ,KIGNORE    ,KINTR     ,
  15251. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,
  15252. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,21 ),
  15253. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KMt,17 ),
  15254. +  K(KMt,23 ),K(KMt, 5 ),K(KMt,18 ),K(KMt,20  ),K(KMt,25 ),K(KMt,21 ),K(KMt, 9  ),K(KMt,15 ),
  15255. +  K(KMt,16 ),KIGNORE   ,KIGNORE   ,KIGNORE    ,KREBOOT   ,K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  15256. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KMt, 1 ),K(KMt,19 ),K(KMt, 4  ),K(KMt, 6 ),
  15257. +  K(KMt, 7 ),K(KMt, 8 ),K(KMt,10 ),K(KMt,11  ),K(KMt,12 ),KIGNORE   ,KIGNORE    ,KENTER    ,
  15258. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KMt,26  ),K(KMt,24 ),
  15259. +  K(KMt, 3 ),K(KMt,22 ),K(KMt, 2 ),K(KMt,14  ),K(KMt,13 ),KIGNORE   ,KIGNORE    ,KIGNORE   ,
  15260. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,KIGNORE   ,
  15261. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KREBOOT    ,KPAD_EN
  15262. +};
  15263. +
  15264. +ushort *key_maps[MAX_NR_KEYMAPS] = {
  15265. +    plain_map, shift_map, altgr_map, 0,
  15266. +    ctrl_map, shift_ctrl_map, 0, 0,
  15267. +    alt_map, 0, 0, 0,
  15268. +    ctrl_alt_map,    0
  15269. +};
  15270. +
  15271. +unsigned int keymap_count = 7;
  15272. +
  15273. +/*
  15274. + * Philosophy: most people do not define more strings, but they who do
  15275. + * often want quite a lot of string space. So, we statically allocate
  15276. + * the default and allocate dynamically in chunks of 512 bytes.
  15277. + */
  15278. +
  15279. +char func_buf[] = {
  15280. +    '\033', '[', '[', 'A', 0,
  15281. +    '\033', '[', '[', 'B', 0,
  15282. +    '\033', '[', '[', 'C', 0,
  15283. +    '\033', '[', '[', 'D', 0,
  15284. +    '\033', '[', '[', 'E', 0,
  15285. +    '\033', '[', '1', '7', '~', 0,
  15286. +    '\033', '[', '1', '8', '~', 0,
  15287. +    '\033', '[', '1', '9', '~', 0,
  15288. +    '\033', '[', '2', '0', '~', 0,
  15289. +    '\033', '[', '2', '1', '~', 0,
  15290. +    '\033', '[', '2', '3', '~', 0,
  15291. +    '\033', '[', '2', '4', '~', 0,
  15292. +    '\033', '[', '2', '5', '~', 0,
  15293. +    '\033', '[', '2', '6', '~', 0,
  15294. +    '\033', '[', '2', '8', '~', 0,
  15295. +    '\033', '[', '2', '9', '~', 0,
  15296. +    '\033', '[', '3', '1', '~', 0,
  15297. +    '\033', '[', '3', '2', '~', 0,
  15298. +    '\033', '[', '3', '3', '~', 0,
  15299. +    '\033', '[', '3', '4', '~', 0,
  15300. +    '\033', '[', '1', '~', 0,
  15301. +    '\033', '[', '2', '~', 0,
  15302. +    '\033', '[', '3', '~', 0,
  15303. +    '\033', '[', '4', '~', 0,
  15304. +    '\033', '[', '5', '~', 0,
  15305. +    '\033', '[', '6', '~', 0,
  15306. +    '\033', '[', 'M', 0,
  15307. +    '\033', '[', 'P', 0,
  15308. +};
  15309. +
  15310. +char *funcbufptr = func_buf;
  15311. +int funcbufsize = sizeof(func_buf);
  15312. +int funcbufleft = 0;          /* space left */
  15313. +
  15314. +char *func_table[MAX_NR_FUNC] = {
  15315. +    func_buf + 0,
  15316. +    func_buf + 5,
  15317. +    func_buf + 10,
  15318. +    func_buf + 15,
  15319. +    func_buf + 20,
  15320. +    func_buf + 25,
  15321. +    func_buf + 31,
  15322. +    func_buf + 37,
  15323. +    func_buf + 43,
  15324. +    func_buf + 49,
  15325. +    func_buf + 55,
  15326. +    func_buf + 61,
  15327. +    func_buf + 67,
  15328. +    func_buf + 73,
  15329. +    func_buf + 79,
  15330. +    func_buf + 85,
  15331. +    func_buf + 91,
  15332. +    func_buf + 97,
  15333. +    func_buf + 103,
  15334. +    func_buf + 109,
  15335. +    func_buf + 115,
  15336. +    func_buf + 120,
  15337. +    func_buf + 125,
  15338. +    func_buf + 130,
  15339. +    func_buf + 135,
  15340. +    func_buf + 140,
  15341. +    func_buf + 145,
  15342. +    0,
  15343. +    0,
  15344. +    func_buf + 149,
  15345. +    0,
  15346. +};
  15347. +
  15348. +struct kbdiacr accent_table[MAX_DIACR] = {
  15349. +    {'`', 'A', '\300'},    {'`', 'a', '\340'},
  15350. +    {'\'', 'A', '\301'},    {'\'', 'a', '\341'},
  15351. +    {'^', 'A', '\302'},    {'^', 'a', '\342'},
  15352. +    {'~', 'A', '\303'},    {'~', 'a', '\343'},
  15353. +    {'"', 'A', '\304'},    {'"', 'a', '\344'},
  15354. +    {'O', 'A', '\305'},    {'o', 'a', '\345'},
  15355. +    {'0', 'A', '\305'},    {'0', 'a', '\345'},
  15356. +    {'A', 'A', '\305'},    {'a', 'a', '\345'},
  15357. +    {'A', 'E', '\306'},    {'a', 'e', '\346'},
  15358. +    {',', 'C', '\307'},    {',', 'c', '\347'},
  15359. +    {'`', 'E', '\310'},    {'`', 'e', '\350'},
  15360. +    {'\'', 'E', '\311'},    {'\'', 'e', '\351'},
  15361. +    {'^', 'E', '\312'},    {'^', 'e', '\352'},
  15362. +    {'"', 'E', '\313'},    {'"', 'e', '\353'},
  15363. +    {'`', 'I', '\314'},    {'`', 'i', '\354'},
  15364. +    {'\'', 'I', '\315'},    {'\'', 'i', '\355'},
  15365. +    {'^', 'I', '\316'},    {'^', 'i', '\356'},
  15366. +    {'"', 'I', '\317'},    {'"', 'i', '\357'},
  15367. +    {'-', 'D', '\320'},    {'-', 'd', '\360'},
  15368. +    {'~', 'N', '\321'},    {'~', 'n', '\361'},
  15369. +    {'`', 'O', '\322'},    {'`', 'o', '\362'},
  15370. +    {'\'', 'O', '\323'},    {'\'', 'o', '\363'},
  15371. +    {'^', 'O', '\324'},    {'^', 'o', '\364'},
  15372. +    {'~', 'O', '\325'},    {'~', 'o', '\365'},
  15373. +    {'"', 'O', '\326'},    {'"', 'o', '\366'},
  15374. +    {'/', 'O', '\330'},    {'/', 'o', '\370'},
  15375. +    {'`', 'U', '\331'},    {'`', 'u', '\371'},
  15376. +    {'\'', 'U', '\332'},    {'\'', 'u', '\372'},
  15377. +    {'^', 'U', '\333'},    {'^', 'u', '\373'},
  15378. +    {'"', 'U', '\334'},    {'"', 'u', '\374'},
  15379. +    {'\'', 'Y', '\335'},    {'\'', 'y', '\375'},
  15380. +    {'T', 'H', '\336'},    {'t', 'h', '\376'},
  15381. +    {'s', 's', '\337'},    {'"', 'y', '\377'},
  15382. +    {'s', 'z', '\337'},    {'i', 'j', '\377'},
  15383. +};
  15384. +
  15385. +unsigned int accent_table_size = 68;
  15386. diff -r -u -N linux.orig/arch/arm/drivers/char/diacr.h linux.arm/arch/arm/drivers/char/diacr.h
  15387. --- linux.orig/arch/arm/drivers/char/diacr.h    Thu Jan  1 01:00:00 1970
  15388. +++ linux.arm/arch/arm/drivers/char/diacr.h    Fri Oct 27 23:14:20 1995
  15389. @@ -0,0 +1,8 @@
  15390. +#ifndef _DIACR_H
  15391. +#define _DIACR_H
  15392. +#include <linux/kd.h>
  15393. +
  15394. +extern struct kbdiacr accent_table[];
  15395. +extern unsigned int accent_table_size;
  15396. +
  15397. +#endif /* _DIACR_H */
  15398. diff -r -u -N linux.orig/arch/arm/drivers/char/iic.c linux.arm/arch/arm/drivers/char/iic.c
  15399. --- linux.orig/arch/arm/drivers/char/iic.c    Thu Jan  1 01:00:00 1970
  15400. +++ linux.arm/arch/arm/drivers/char/iic.c    Fri Oct 27 23:14:20 1995
  15401. @@ -0,0 +1,102 @@
  15402. +#pragma no_check_stack
  15403. +#include <asm/system.h>
  15404. +
  15405. +#define DELAY udelay(10)
  15406. +
  15407. +/* extern volatile char *const ioc; */
  15408. +#define ioc ((volatile char *)0x03200000)
  15409. +
  15410. +static void iic_start(void)
  15411. +{
  15412. +  char out;
  15413. +
  15414. +  out=(ioc[0] & 0xFC) | 0xC0;
  15415. +
  15416. +  ioc[0]=out|3;  DELAY;
  15417. +  ioc[0]=out|2;  DELAY;
  15418. +}
  15419. +
  15420. +static void iic_stop(void)
  15421. +{
  15422. +  char out;
  15423. +
  15424. +  out=(ioc[0] & 0xFC) | 0xC0;
  15425. +
  15426. +  DELAY;  ioc[0]=out|2;
  15427. +  DELAY;  ioc[0]=out|3;
  15428. +}
  15429. +
  15430. +static int iic_sendbyte(char b)
  15431. +{
  15432. +  char out,in;
  15433. +  int i;
  15434. +
  15435. +  out=(ioc[0] & 0xFC) | 0xC0;
  15436. +
  15437. +  ioc[0]=out;
  15438. +  for(i=7;i>=0;i--)
  15439. +  {
  15440. +    ioc[0]=out|((b&(1<<i))?1:0);    DELAY;
  15441. +    ioc[0]=out|((b&(1<<i))?1:0)|2;  DELAY;
  15442. +    ioc[0]=out|((b&(1<<i))?1:0);
  15443. +  }
  15444. +  ioc[0]=out|1;  DELAY;
  15445. +  ioc[0]=out|3;  DELAY;
  15446. +  in=ioc[0]&1;
  15447. +  ioc[0]=out|1;  DELAY;
  15448. +  ioc[0]=out;    DELAY;
  15449. +  if(in)
  15450. +  {
  15451. +    printk("No acknowledge from RTC\n");
  15452. +    return 1;
  15453. +  }
  15454. +  else
  15455. +    return 0;
  15456. +}
  15457. +
  15458. +static char iic_recvbyte(void)
  15459. +{
  15460. +  char out,in;
  15461. +  int i;
  15462. +
  15463. +  out=(ioc[0] & 0xFC) | 0xC0;
  15464. +
  15465. +  ioc[0]=out;
  15466. +  for(i=7;i>=0;i--)
  15467. +  {
  15468. +    ioc[0]=out|1;  DELAY;
  15469. +    ioc[0]=out|3;  DELAY;
  15470. +    in=(in<<1)|(ioc[0]&1);
  15471. +    ioc[0]=out|1;  DELAY;
  15472. +  }
  15473. +  ioc[0]=out;      DELAY;
  15474. +  ioc[0]=out|2;    DELAY;
  15475. +  return in;
  15476. +}
  15477. +
  15478. +void iic_control(int addr,int loc,char *buf,int len)
  15479. +{
  15480. +  iic_start();
  15481. +  if(iic_sendbyte(addr & 0xFE))
  15482. +    goto error;
  15483. +  if(iic_sendbyte(loc))
  15484. +    goto error;
  15485. +  if(addr & 1)
  15486. +  {
  15487. +    int i;
  15488. +    for(i=0;i<len;i++)
  15489. +      if(iic_sendbyte(buf[i]))
  15490. +        goto error;
  15491. +  }
  15492. +  else
  15493. +  {
  15494. +    int i;
  15495. +    iic_stop();
  15496. +    iic_start();
  15497. +    iic_sendbyte(addr|1);
  15498. +    for(i=0;i<len;i++)
  15499. +      buf[i]=iic_recvbyte();
  15500. +  }
  15501. +  error:
  15502. +  iic_stop();
  15503. +}
  15504. diff -r -u -N linux.orig/arch/arm/drivers/char/kbd_kern.h linux.arm/arch/arm/drivers/char/kbd_kern.h
  15505. --- linux.orig/arch/arm/drivers/char/kbd_kern.h    Thu Jan  1 01:00:00 1970
  15506. +++ linux.arm/arch/arm/drivers/char/kbd_kern.h    Fri Oct 27 23:14:23 1995
  15507. @@ -0,0 +1,127 @@
  15508. +#ifndef _KBD_KERN_H
  15509. +#define _KBD_KERN_H
  15510. +
  15511. +#include <linux/interrupt.h>
  15512. +#define set_leds() mark_bh(KEYBOARD_BH)
  15513. +
  15514. +#include <linux/keyboard.h>
  15515. +
  15516. +extern char *func_table[MAX_NR_FUNC];
  15517. +extern char func_buf[];
  15518. +extern char *funcbufptr;
  15519. +extern int funcbufsize, funcbufleft;
  15520. +
  15521. +/*
  15522. + * kbd->xxx contains the VC-local things (flag settings etc..)
  15523. + *
  15524. + * Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h
  15525. + *       The code in KDGETLED / KDSETLED depends on the internal and
  15526. + *       external order being the same.
  15527. + *
  15528. + * Note: lockstate is used as index in the array key_map.
  15529. + */
  15530. +struct kbd_struct {
  15531. +
  15532. +    unsigned char lockstate;
  15533. +/* 8 modifiers - the names do not have any meaning at all;
  15534. +   they can be associated to arbitrarily chosen keys */
  15535. +#define VC_SHIFTLOCK    KG_SHIFT    /* shift lock mode */
  15536. +#define VC_ALTGRLOCK    KG_ALTGR    /* altgr lock mode */
  15537. +#define VC_CTRLLOCK    KG_CTRL     /* control lock mode */
  15538. +#define VC_ALTLOCK    KG_ALT      /* alt lock mode */
  15539. +#define VC_SHIFTLLOCK    KG_SHIFTL    /* shiftl lock mode */
  15540. +#define VC_SHIFTRLOCK    KG_SHIFTR    /* shiftr lock mode */
  15541. +#define VC_CTRLLLOCK    KG_CTRLL     /* ctrll lock mode */
  15542. +#define VC_CTRLRLOCK    KG_CTRLR     /* ctrlr lock mode */
  15543. +
  15544. +    unsigned char ledmode:2;     /* one 2-bit value */
  15545. +#define LED_SHOW_FLAGS 0        /* traditional state */
  15546. +#define LED_SHOW_IOCTL 1        /* only change leds upon ioctl */
  15547. +#define LED_SHOW_MEM 2          /* `heartbeat': peek into memory */
  15548. +
  15549. +    unsigned char ledflagstate:3;    /* flags, not lights */
  15550. +    unsigned char default_ledflagstate:3;
  15551. +#define VC_SCROLLOCK    0    /* scroll-lock mode */
  15552. +#define VC_NUMLOCK    1    /* numeric lock mode */
  15553. +#define VC_CAPSLOCK    2    /* capslock mode */
  15554. +
  15555. +    unsigned char kbdmode:2;    /* one 2-bit value */
  15556. +#define VC_XLATE    0    /* translate keycodes using keymap */
  15557. +#define VC_MEDIUMRAW    1    /* medium raw (keycode) mode */
  15558. +#define VC_RAW        2    /* raw (scancode) mode */
  15559. +#define VC_UNICODE    3    /* Unicode mode */
  15560. +
  15561. +    unsigned char modeflags:5;
  15562. +#define VC_APPLIC    0    /* application key mode */
  15563. +#define VC_CKMODE    1    /* cursor key mode */
  15564. +#define VC_REPEAT    2    /* keyboard repeat */
  15565. +#define VC_CRLF        3    /* 0 - enter sends CR, 1 - enter sends CRLF */
  15566. +#define VC_META        4    /* 0 - meta, 1 - meta=prefix with ESC */
  15567. +};
  15568. +
  15569. +extern struct kbd_struct kbd_table[];
  15570. +
  15571. +extern unsigned long kbd_init(unsigned long);
  15572. +
  15573. +extern unsigned char getledstate(void);
  15574. +extern void setledstate(struct kbd_struct *kbd, unsigned int led);
  15575. +#ifndef __ARM__
  15576. +extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
  15577. +{
  15578. +    return ((kbd->modeflags >> flag) & 1);
  15579. +}
  15580. +
  15581. +extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
  15582. +{
  15583. +    return ((kbd->ledflagstate >> flag) & 1);
  15584. +}
  15585. +
  15586. +extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
  15587. +{
  15588. +    kbd->modeflags |= 1 << flag;
  15589. +}
  15590. +
  15591. +extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
  15592. +{
  15593. +    kbd->ledflagstate |= 1 << flag;
  15594. +}
  15595. +
  15596. +extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
  15597. +{
  15598. +    kbd->modeflags &= ~(1 << flag);
  15599. +}
  15600. +
  15601. +extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
  15602. +{
  15603. +    kbd->ledflagstate &= ~(1 << flag);
  15604. +}
  15605. +
  15606. +extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
  15607. +{
  15608. +    kbd->lockstate ^= 1 << flag;
  15609. +}
  15610. +
  15611. +extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
  15612. +{
  15613. +    kbd->modeflags ^= 1 << flag;
  15614. +}
  15615. +
  15616. +extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
  15617. +{
  15618. +    kbd->ledflagstate ^= 1 << flag;
  15619. +}
  15620. +#else
  15621. +#define vc_kbd_mode(kbd,flag)        (((kbd)->modeflags >> flag) & 1)
  15622. +#define vc_kbd_led(kbd,flag)        (((kbd)->ledflagstate >> flag) & 1)
  15623. +#define set_vc_kbd_mode(kbd,flag)    ((kbd)->modeflags |= 1 << flag)
  15624. +#define set_vc_kbd_led(kbd,flag)    ((kbd)->ledflagstate |= 1 << flag)
  15625. +#define clr_vc_kbd_mode(kbd,flag)    ((kbd)->modeflags &= ~(1 << flag))
  15626. +#define clr_vc_kbd_led(kbd,flag)    ((kbd)->ledflagstate &= ~(1 << flag))
  15627. +#define chg_vc_kbd_lock(kbd,flag)    ((kbd)->lockstate ^= 1 << flag)
  15628. +#define chg_vc_kbd_mode(kbd,flag)    ((kbd)->modeflags ^= 1 << flag)
  15629. +#define chg_vc_kbd_led(kbd,flag)    ((kbd)->ledflagstate ^= 1 << flag)
  15630. +#endif
  15631. +
  15632. +#define U(x) ((x) ^ 0xf000)
  15633. +
  15634. +#endif
  15635. diff -r -u -N linux.orig/arch/arm/drivers/char/keyboard.c linux.arm/arch/arm/drivers/char/keyboard.c
  15636. --- linux.orig/arch/arm/drivers/char/keyboard.c    Thu Jan  1 01:00:00 1970
  15637. +++ linux.arm/arch/arm/drivers/char/keyboard.c    Fri Oct 27 23:14:24 1995
  15638. @@ -0,0 +1,1062 @@
  15639. +#define IRQ_KEYBOARDRX 15
  15640. +#define IRQ_KEYBOARDTX 14
  15641. +
  15642. +#define VERSION 002
  15643. +
  15644. +#include <linux/config.h>
  15645. +#include <linux/sched.h>
  15646. +#include <linux/interrupt.h>
  15647. +#include <linux/tty.h>
  15648. +#include <linux/tty_flip.h>
  15649. +#include <linux/ctype.h>
  15650. +#include <linux/mm.h>
  15651. +#include <linux/timer.h>
  15652. +#include <linux/ptrace.h>
  15653. +
  15654. +#include <asm/irq.h>
  15655. +
  15656. +#include "kbd_kern.h"
  15657. +#include "diacr.h"
  15658. +#include "vt_kern.h"
  15659. +
  15660. +#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
  15661. +
  15662. +/* Mouse stuff */
  15663. +
  15664. +extern struct wait_queue *mouse_wait;
  15665. +extern char        mouse_buttons;
  15666. +extern int        mouse_dxpos;
  15667. +extern int        mouse_dypos;
  15668. +extern char        mouse_ready;
  15669. +
  15670. +#define KBD_IRQ_RPT    1
  15671. +#define KBD_IRQ_KEY    2
  15672. +
  15673. +#ifndef KBD_DEFMODE
  15674. +#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
  15675. +#endif
  15676. +
  15677. +#ifndef KBD_DEFLEDS
  15678. +#define KBD_DEFLEDS 0 /* VC_NUMLOCK */
  15679. +#endif
  15680. +
  15681. +#ifndef KBD_DEFLOCK
  15682. +#define KBD_DEFLOCK 0
  15683. +#endif
  15684. +
  15685. +#define KBD_SHIFT     0x11
  15686. +#define KBD_CTRL      0x22
  15687. +#define KBD_ALT       0x44
  15688. +
  15689. +#define KBD_LSHIFT    0x01
  15690. +#define KBD_LCTRL    0x02
  15691. +#define KBD_LALT    0x04
  15692. +#define KBD_RSHIFT    0x10
  15693. +#define KBD_RCTRL    0x20
  15694. +#define KBD_RALT    0x40
  15695. +
  15696. +#define HRST 0xFF
  15697. +#define RAK1 0xFE
  15698. +#define RAK2 0xFD
  15699. +#define SMAK 0x33
  15700. +
  15701. +extern void poke_blanked_console (void);
  15702. +extern void ctrl_alt_del (void);
  15703. +extern void change_console (unsigned int console);
  15704. +static void process_key(int keycode, char up_flag, int repeattimeout);
  15705. +static unsigned char getleds(void);
  15706. +
  15707. +static unsigned char k_down[NR_SHIFT] = {0, };
  15708. +
  15709. +static int want_console    = -1;
  15710. +static int last_console    = 0;         /* last used VC */
  15711. +static int dead_key_next   = 0;
  15712. +
  15713. +int shift_state     = 0;
  15714. +static int npadch          = -1;        /* -1 or number assembled on pad */
  15715. +static unsigned char diacr = 0;
  15716. +static char rep            = 0;            /* Flag telling character repeat */
  15717. +struct kbd_struct kbd_table[MAX_NR_CONSOLES];
  15718. +static struct tty_struct **ttytab;
  15719. +static struct kbd_struct * kbd = kbd_table;
  15720. +static struct tty_struct * tty;
  15721. +
  15722. +static int kbd_rollover[3] = {-1,-1,-1};
  15723. +
  15724. +extern unsigned char    *ioc;
  15725. +static unsigned char    kbd_sendvala[4];
  15726. +static unsigned char    kbd_sendptri;
  15727. +static unsigned char    kbd_sendptro;
  15728. +static unsigned char    ledstate = 0xff;
  15729. +static unsigned char    kbd_repeatkey=-1;
  15730. +
  15731. +typedef void (*k_hand)(unsigned char value, char up_flag);
  15732. +typedef void (k_handfn)(unsigned char value, char up_flag);
  15733. +
  15734. +static k_handfn
  15735. +    do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
  15736. +    do_meta, do_ascii, do_lock, do_lowercase, do_ignore;
  15737. +
  15738. +static k_hand key_handler[16] = {
  15739. +    do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
  15740. +    do_meta, do_ascii, do_lock, do_lowercase,
  15741. +    do_ignore, do_ignore, do_ignore, do_ignore
  15742. +};
  15743. +
  15744. +typedef void (*void_fnp)(void);
  15745. +typedef void (void_fn)(void);
  15746. +
  15747. +static void_fn enter, show_ptregs, send_intr, lastcons, caps_toggle,
  15748. +    num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
  15749. +    SAK, decr_console, incr_console, show_stack/*, show_floppy*/;
  15750. +
  15751. +static void_fnp spec_fn_table[] = {
  15752. +    NULL,        enter,        show_ptregs,    show_mem,
  15753. +    show_state,    send_intr,    lastcons,    caps_toggle,
  15754. +    num,        hold,        scroll_forw,    scroll_back,
  15755. +    boot_it,    caps_on,    compose,    SAK,
  15756. +    decr_console,    incr_console,    show_stack/*,    show_floppy*/
  15757. +};
  15758. +
  15759. +/* maximum values each key_handler can handle */
  15760. +const int max_vals[] = {
  15761. +    255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
  15762. +    NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
  15763. +    255, NR_ASCII - 1, NR_LOCK - 1, 255
  15764. +};
  15765. +
  15766. +const int NR_TYPES = SIZE(max_vals);
  15767. +
  15768. +static void put_queue(int);
  15769. +static unsigned char handle_diacr(unsigned char);
  15770. +
  15771. +/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
  15772. +static struct pt_regs * pt_regs;
  15773. +
  15774. +void to_utf8(ushort c) {
  15775. +    if (c < 0x80)
  15776. +    put_queue(c);            /*  0*******  */
  15777. +    else if (c < 0x800) {
  15778. +    put_queue(0xc0 | (c >> 6));     /*  110***** 10******  */
  15779. +    put_queue(0x80 | (c & 0x3f));
  15780. +    } else {
  15781. +    put_queue(0xe0 | (c >> 12));     /*  1110**** 10****** 10******  */
  15782. +    put_queue(0x80 | ((c >> 6) & 0x3f));
  15783. +    put_queue(0x80 | (c & 0x3f));
  15784. +    }
  15785. +     /* uft-8 is defined for words of up to 36 bits,
  15786. +       but we need only 16 bits here */
  15787. +}
  15788. +
  15789. +int setkeycode(unsigned int scancode, unsigned int keycode)
  15790. +{
  15791. +#if 0
  15792. +    if (scancode < SC_LIM || scancode > 255 || keycode > 127)
  15793. +        return -EINVAL;
  15794. +    if (scancode < 128)
  15795. +        high_keys[scancode - SC_LIM] = keycode;
  15796. +    else
  15797. +        e0_keys[scancode - 128] = keycode;
  15798. +    return 0;
  15799. +#else
  15800. +    return -EINVAL;
  15801. +#endif
  15802. +}
  15803. +
  15804. +int getkeycode(unsigned int scancode)
  15805. +{
  15806. +#if 0
  15807. +    return
  15808. +        (scancode < SC_LIM || scancode > 255) ? -EINVAL :
  15809. +        (scancode < 128) ? high_keys[scancode - SC_LIM] :
  15810. +        e0_keys[scancode - 128];
  15811. +#else
  15812. +    return -EINVAL;
  15813. +#endif
  15814. +}
  15815. +
  15816. +
  15817. +/* ----------------------------------------------------------------------------------------- */
  15818. +
  15819. +static void key_callback(unsigned long nr)
  15820. +{
  15821. +  rep = 1;
  15822. +  mark_bh(KEYBOARD_BH);
  15823. +}
  15824. +
  15825. +static struct timer_list key_timer=
  15826. +{
  15827. +  NULL,NULL,0,0,key_callback
  15828. +};
  15829. +
  15830. +static void kbd_key(int keycode, char up_flag)
  15831. +{
  15832. +  char process=0;
  15833. +  if(keycode >= 0x70 && keycode <= 0x72)
  15834. +  {
  15835. +    switch(keycode)
  15836. +    {
  15837. +      case 0x70:/* Left mouse button */
  15838. +        if(up_flag)
  15839. +          mouse_buttons&=~4;
  15840. +        else
  15841. +          mouse_buttons|=4;
  15842. +        break;
  15843. +
  15844. +      case 0x71:/* Middle mouse button */
  15845. +        if(up_flag)
  15846. +          mouse_buttons&=~2;
  15847. +        else
  15848. +          mouse_buttons|=2;
  15849. +        break;
  15850. +
  15851. +      case 0x72:/* Right mouse button */
  15852. +        if(up_flag)
  15853. +          mouse_buttons&=~1;
  15854. +        else
  15855. +          mouse_buttons|=1;
  15856. +        break;
  15857. +    }
  15858. +    mouse_ready=1;
  15859. +    wake_up_interruptible(&mouse_wait);
  15860. +    mark_bh(KEYBOARD_BH);
  15861. +    return;
  15862. +  }
  15863. +
  15864. +  tty = ttytab[fg_console];
  15865. +  kbd = kbd_table + fg_console;
  15866. +
  15867. +  if(!up_flag)
  15868. +  {
  15869. +    if(kbd_rollover[0] != -1)
  15870. +    {
  15871. +      if(kbd_rollover[1] != -1)
  15872. +      {
  15873. +        if(kbd_rollover[2] != -1)
  15874. +          return;
  15875. +        kbd_rollover[2] = kbd_rollover[1];
  15876. +      }
  15877. +      kbd_rollover[1] = kbd_rollover[0];
  15878. +    }
  15879. +    kbd_rollover[0] = keycode;
  15880. +    process=1;
  15881. +  }
  15882. +  else
  15883. +  {
  15884. +    if(kbd_rollover[0] == keycode)
  15885. +      kbd_rollover[0] = -1;
  15886. +    if(kbd_rollover[1] == keycode)
  15887. +      kbd_rollover[1] = -1;
  15888. +    if(kbd_rollover[2] == keycode)
  15889. +      kbd_rollover[2] = -1;
  15890. +    process=1;
  15891. +  }
  15892. +
  15893. +  del_timer(&key_timer);
  15894. +  rep = 0;
  15895. +
  15896. +  if(kbd->kbdmode == VC_RAW)
  15897. +    put_queue(keycode|(up_flag?0x80:0));
  15898. +  else
  15899. +  {
  15900. +    if(process)
  15901. +      process_key(keycode, up_flag, HZ*300/1000);
  15902. +    mark_bh(KEYBOARD_BH);
  15903. +  }
  15904. +}
  15905. +
  15906. +static void kbd_sendval(unsigned char val)
  15907. +{
  15908. +  kbd_sendvala[kbd_sendptri]=val;
  15909. +  kbd_sendptri=(kbd_sendptri+1)&3;
  15910. +  disable_irq(15);
  15911. +  enable_irq(14);
  15912. +}
  15913. +
  15914. +static void kbd_reset(void)
  15915. +{
  15916. +  int i;
  15917. +  for(i = 0; i<NR_SHIFT; i++)
  15918. +    k_down[i] = 0;
  15919. +  shift_state = 0;
  15920. +}
  15921. +
  15922. +/*
  15923. + * Keyboard states:
  15924. + *  0 initial reset condition, sent HRST, wait for HRST
  15925. + *  1 Sent RAK1, wait for RAK1
  15926. + *  2 Sent RAK2, wait for RAK2
  15927. + *  3 Sent SMAK, wait for *
  15928. + *  4 Wait for second keyboard nibble for key pressed
  15929. + *  5 Wait for second keyboard nibble for key released
  15930. + *  6 Wait for second part of mouse data
  15931. + */
  15932. +
  15933. +static void kbd_rx(int irq, struct pt_regs *regs)
  15934. +{
  15935. +  int keyval;
  15936. +  static char kbd_mousedx=0;
  15937. +  static unsigned char kbd_state=0;
  15938. +  static unsigned char kbd_keyhigh=0;
  15939. +
  15940. +  keyval=ioc[4];
  15941. +
  15942. +  switch(kbd_state)
  15943. +  {
  15944. +    case 0:/* initial reset condition */
  15945. +      if(keyval == HRST)
  15946. +      {
  15947. +        kbd_reset();
  15948. +        kbd_sendval(RAK1);
  15949. +        kbd_state = 1;
  15950. +      }
  15951. +      else
  15952. +      {
  15953. +        kbd_sendval(HRST);
  15954. +        kbd_state = 0;
  15955. +      }
  15956. +      break;
  15957. +
  15958. +    case 1:/* Sent RAK1 */
  15959. +      if(keyval == RAK1)
  15960. +      {
  15961. +        kbd_sendval(RAK2);
  15962. +        kbd_state = 2;
  15963. +      }
  15964. +      else
  15965. +      {
  15966. +        kbd_sendval(HRST);
  15967. +        kbd_state = 0;
  15968. +      }
  15969. +      break;
  15970. +
  15971. +    case 2:/* Sent RAK2 */
  15972. +      if(keyval == RAK2)
  15973. +      {
  15974. +        kbd_sendval(SMAK);
  15975. +        kbd_state = 3;
  15976. +        ledstate  = 0xff;
  15977. +        mark_bh(KEYBOARD_BH);
  15978. +      }
  15979. +      else
  15980. +      {
  15981. +        kbd_sendval(HRST);
  15982. +        kbd_state = 0;
  15983. +      }
  15984. +      break;
  15985. +
  15986. +    case 3:/* Send SMAK, ready for any reply */
  15987. +      if(keyval == HRST)
  15988. +      {
  15989. +        kbd_sendval(HRST);
  15990. +        kbd_state = 0;
  15991. +      }
  15992. +      else
  15993. +      if(keyval&0x80)
  15994. +      {
  15995. +        switch(keyval&0xF0)
  15996. +        {
  15997. +          case 0xC0:
  15998. +            kbd_keyhigh=keyval;
  15999. +            kbd_state = 4;
  16000. +            kbd_sendval(0x3F);
  16001. +            break;
  16002. +
  16003. +          case 0xD0:
  16004. +            kbd_keyhigh=keyval;
  16005. +            kbd_state = 5;
  16006. +            kbd_sendval(0x3F);
  16007. +            break;
  16008. +
  16009. +          default:
  16010. +            kbd_state = 0;
  16011. +            kbd_sendval(HRST);
  16012. +        }
  16013. +      }
  16014. +      else
  16015. +      {
  16016. +        kbd_mousedx=keyval&0x40?keyval|0x80:keyval;
  16017. +        kbd_state = 6;
  16018. +        kbd_sendval(0x3F);
  16019. +      }
  16020. +      break;
  16021. +
  16022. +    case 4:
  16023. +      if((keyval & 0xF0)!=0xC0)
  16024. +      {
  16025. +        kbd_state = 0;
  16026. +        kbd_sendval(HRST);
  16027. +      }
  16028. +      else
  16029. +      {
  16030. +        kbd_state = 3;
  16031. +        kbd_sendval(SMAK);
  16032. +        if(((kbd_keyhigh^keyval)&0xF0)==0)
  16033. +          kbd_key((keyval&0x0F)|((kbd_keyhigh<<4)&0xF0),0);
  16034. +      }
  16035. +      break;
  16036. +
  16037. +    case 5:
  16038. +      if((keyval & 0xF0)!=0xD0)
  16039. +      {
  16040. +        kbd_state = 0;
  16041. +        kbd_sendval(HRST);
  16042. +      }
  16043. +      else
  16044. +      {
  16045. +        kbd_state = 3;
  16046. +        kbd_sendval(SMAK);
  16047. +        if(((kbd_keyhigh^keyval)&0xF0)==0)
  16048. +          kbd_key((keyval&0x0F)|((kbd_keyhigh<<4)&0xF0),1);
  16049. +      }
  16050. +      break;
  16051. +
  16052. +    case 6:
  16053. +      if(keyval & 0x80)
  16054. +      {
  16055. +        kbd_state = 0;
  16056. +        kbd_sendval(HRST);
  16057. +      }
  16058. +      else
  16059. +      {
  16060. +        kbd_state = 3;
  16061. +        kbd_sendval(SMAK);
  16062. +        mouse_dypos+=(int)((char)(keyval&0x40?keyval|0x80:keyval));
  16063. +        mouse_dxpos+=(int)kbd_mousedx;
  16064. +        mouse_ready=1;
  16065. +        wake_up_interruptible(&mouse_wait);
  16066. +        mark_bh(KEYBOARD_BH);
  16067. +      }
  16068. +      break;
  16069. +  }
  16070. +}
  16071. +
  16072. +static void kbd_tx(int irq, struct pt_regs *regs)
  16073. +{
  16074. +  if(kbd_sendptri!=kbd_sendptro)
  16075. +  {
  16076. +    ioc[0x04]=kbd_sendvala[kbd_sendptro];
  16077. +    kbd_sendptro=(kbd_sendptro+1)&3;
  16078. +  }
  16079. +  if(kbd_sendptri==kbd_sendptro)
  16080. +  {
  16081. +    disable_irq(14);
  16082. +    enable_irq(15);
  16083. +  }
  16084. +}
  16085. +
  16086. +static void process_key(int keycode, char up_flag, int repeattimeout)
  16087. +{
  16088. +  del_timer(&key_timer);
  16089. +
  16090. +  if(!up_flag)
  16091. +  {
  16092. +    kbd_repeatkey = keycode;
  16093. +    if(vc_kbd_mode(kbd, VC_REPEAT))
  16094. +    {
  16095. +      key_timer.expires = repeattimeout;
  16096. +      add_timer(&key_timer);
  16097. +    }
  16098. +  }
  16099. +  else
  16100. +    del_timer(&key_timer);
  16101. +
  16102. +  if(!rep || (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
  16103. +               (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0))))
  16104. +  {
  16105. +    u_short keysym;
  16106. +    u_char  type;
  16107. +    int     shift_final = shift_state ^ kbd->lockstate;
  16108. +    u_short *key_map = key_maps[shift_final];
  16109. +
  16110. +    if(key_map != NULL)
  16111. +    {
  16112. +      keysym = key_map[keycode];
  16113. +      type   = KTYP(keysym);
  16114. +
  16115. +      if((type & 15) == KT_SHIFT)
  16116. +        kbd_rollover[0] = -1;
  16117. +
  16118. +      if(type >= 0xf0)
  16119. +      {
  16120. +        type -= 0xf0;
  16121. +        if(type == KT_LETTER)
  16122. +        {
  16123. +          type = KT_LATIN;
  16124. +          if(vc_kbd_led(kbd, VC_CAPSLOCK))
  16125. +          {
  16126. +            key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
  16127. +            if (key_map)
  16128. +              keysym = key_map[keycode];
  16129. +          }
  16130. +        }
  16131. +        (*key_handler[type])(keysym & 0xff, up_flag);
  16132. +      }
  16133. +      else
  16134. +      {
  16135. +        if(!up_flag)
  16136. +          to_utf8(keysym);
  16137. +      }
  16138. +    }
  16139. +    else
  16140. +    {
  16141. +      keysym = U(plain_map[keycode]);
  16142. +      type   = KTYP(keysym);
  16143. +      if(type == KT_SHIFT)
  16144. +        (*key_handler[type])(keysym & 0xff, up_flag);
  16145. +    }
  16146. +  }
  16147. +}
  16148. +
  16149. +static void kbd_bh(void *unused)
  16150. +{
  16151. +  unsigned char leds;
  16152. +
  16153. +  tty = ttytab[fg_console];
  16154. +  kbd = kbd_table + fg_console;
  16155. +
  16156. +  if(rep)
  16157. +    process_key(kbd_repeatkey, 0, HZ*30/1000);
  16158. +  rep = 0;
  16159. +
  16160. +  if(want_console >= 0)
  16161. +  {
  16162. +    if(want_console != fg_console)
  16163. +    {
  16164. +      last_console = fg_console;
  16165. +      change_console(want_console);
  16166. +    }
  16167. +    want_console = -1;
  16168. +  }
  16169. +
  16170. +  leds = getleds();
  16171. +  if(leds != ledstate)
  16172. +  {
  16173. +    unsigned long flags;
  16174. +    ledstate = leds;
  16175. +#define LED_LKCAPS        1
  16176. +#define LED_LKNUM        2
  16177. +#define LED_LKSCRL        4
  16178. +    leds = ((leds & (1<<VC_SCROLLOCK))?LED_LKSCRL:0) | ((leds & (1<<VC_NUMLOCK))?LED_LKNUM:0) |
  16179. +            ((leds & (1<<VC_CAPSLOCK))?LED_LKCAPS:0);
  16180. +    save_flags(flags); cli(); intr_count -= 1;
  16181. +    kbd_sendval(leds);
  16182. +    intr_count += 1; restore_flags(flags);
  16183. +  }
  16184. +  poke_blanked_console();
  16185. +}
  16186. +
  16187. +/* ----------------------------------------------------------------------------------------- */
  16188. +
  16189. +static void put_queue(int ch)
  16190. +{
  16191. +     wake_up(&keypress_wait);
  16192. +    if (tty) {
  16193. +        tty_insert_flip_char(tty, ch, 0);
  16194. +        tty_schedule_flip(tty);
  16195. +    }
  16196. +}
  16197. +
  16198. +static void puts_queue(char *cp)
  16199. +{
  16200. +    wake_up(&keypress_wait);
  16201. +    if (!tty)
  16202. +        return;
  16203. +
  16204. +    while(*cp)
  16205. +        tty_insert_flip_char(tty, *cp++, 0);
  16206. +    tty_schedule_flip(tty);
  16207. +}
  16208. +
  16209. +static void applkey(int key, char mode)
  16210. +{
  16211. +  static char buf[] = { 0x1b, 'O', 0x00, 0x00};
  16212. +
  16213. +  buf[1] = (mode ? 'O' : '[');
  16214. +  buf[2] = key;
  16215. +  puts_queue(buf);
  16216. +}
  16217. +
  16218. +static void enter(void)
  16219. +{
  16220. +  put_queue(13);
  16221. +  if(vc_kbd_mode(kbd, VC_CRLF))
  16222. +    put_queue(10);
  16223. +}
  16224. +
  16225. +static void caps_toggle(void)
  16226. +{
  16227. +  if(rep)
  16228. +    return;
  16229. +  chg_vc_kbd_led(kbd, VC_CAPSLOCK);
  16230. +}
  16231. +
  16232. +static void caps_on(void)
  16233. +{
  16234. +  if(rep)
  16235. +    return;
  16236. +
  16237. +  set_vc_kbd_led(kbd, VC_CAPSLOCK);
  16238. +}
  16239. +int debug_flag=0;
  16240. +static void show_ptregs(void)
  16241. +{ debug_flag ^= 1;
  16242. +  if(!pt_regs)
  16243. +    return;
  16244. +  printk("\n");
  16245. +}
  16246. +
  16247. +static void show_stack(void)
  16248. +{
  16249. +    unsigned long *p;
  16250. +    unsigned long *q = (unsigned long *)((int)current->kernel_stack_page + 4096);
  16251. +    int i;
  16252. +    __asm__("mov %0, sp\n\t": "=r" (p));
  16253. +
  16254. +    for(i=0; p < q; p++, i++)
  16255. +    {
  16256. +        if(i && !(i & 7))
  16257. +            printk("\n");
  16258. +        printk("%08lX ", *p);
  16259. +    }
  16260. +}
  16261. +
  16262. +static void hold(void)
  16263. +{
  16264. +  if(rep || !tty)
  16265. +    return;
  16266. +
  16267. +  if(tty->stopped)
  16268. +    start_tty(tty);
  16269. +  else
  16270. +    stop_tty(tty);
  16271. +}
  16272. +
  16273. +static void num(void)
  16274. +{
  16275. +  if(vc_kbd_mode(kbd,VC_APPLIC))
  16276. +  {
  16277. +    applkey('P', 1);
  16278. +    return;
  16279. +  }
  16280. +  if(!rep)
  16281. +    chg_vc_kbd_led(kbd, VC_NUMLOCK);
  16282. +}
  16283. +
  16284. +static void lastcons(void)
  16285. +{
  16286. +  want_console = last_console;
  16287. +}
  16288. +
  16289. +static void decr_console(void)
  16290. +{
  16291. +  int i;
  16292. +
  16293. +  for(i=fg_console - 1; i != fg_console; i--)
  16294. +  {
  16295. +    if(i == -1)
  16296. +      i = MAX_NR_CONSOLES - 1;
  16297. +    if(vc_cons_allocated(i))
  16298. +      break;
  16299. +  }
  16300. +  want_console = i;
  16301. +}
  16302. +
  16303. +static void incr_console(void)
  16304. +{
  16305. +  int i;
  16306. +
  16307. +  for(i=fg_console + 1; i != fg_console; i++)
  16308. +  {
  16309. +    if(i == MAX_NR_CONSOLES)
  16310. +      i = 0;
  16311. +    if(vc_cons_allocated(i))
  16312. +      break;
  16313. +  }
  16314. +  want_console = i;
  16315. +}
  16316. +
  16317. +static void send_intr(void)
  16318. +{
  16319. +  if(!tty || (tty->termios && I_IGNBRK(tty)))
  16320. +    return;
  16321. +  tty_insert_flip_char(tty, 0, TTY_BREAK);
  16322. +}
  16323. +
  16324. +static void scroll_forw(void)
  16325. +{
  16326. +}
  16327. +
  16328. +static void scroll_back(void)
  16329. +{
  16330. +}
  16331. +
  16332. +static void boot_it(void)
  16333. +{
  16334. +  ctrl_alt_del();
  16335. +}
  16336. +
  16337. +static void compose(void)
  16338. +{
  16339. +  dead_key_next = 1;
  16340. +}
  16341. +
  16342. +int spawnpid, spawnsig;
  16343. +
  16344. +static void spawn_console(void)
  16345. +{
  16346. +    if (spawnpid)
  16347. +      if (kill_proc(spawnpid, spawnsig, 1))
  16348. +        spawnpid = 0;
  16349. +}
  16350. +
  16351. +static void SAK(void)
  16352. +{
  16353. +  do_SAK(tty);
  16354. +}
  16355. +
  16356. +static void do_ignore(unsigned char value, char up_flag)
  16357. +{
  16358. +}
  16359. +
  16360. +static void do_spec(unsigned char value,char up_flag)
  16361. +{
  16362. +  if(up_flag)
  16363. +    return;
  16364. +  if(value >= SIZE(spec_fn_table))
  16365. +    return;
  16366. +  if(!spec_fn_table[value])
  16367. +    return;
  16368. +  spec_fn_table[value]();
  16369. +}
  16370. +
  16371. +static void do_lowercase(unsigned char value, char up_flag)
  16372. +{
  16373. +  printk("keyboard.c: do_lowercase was called - impossible\n");
  16374. +}
  16375. +
  16376. +static void do_self(unsigned char value, char up_flag)
  16377. +{
  16378. +  if(up_flag)
  16379. +    return;
  16380. +
  16381. +  if(diacr)
  16382. +    value = handle_diacr(value);
  16383. +
  16384. +  if(dead_key_next)
  16385. +  {
  16386. +    dead_key_next = 0;
  16387. +    diacr = value;
  16388. +    return;
  16389. +  }
  16390. +if (debug_flag) printk("inserting into put_queue\n");
  16391. +  put_queue(value);
  16392. +}
  16393. +
  16394. +#define A_GRAVE '`'
  16395. +#define A_ACUTE '\''
  16396. +#define A_CFLEX '^'
  16397. +#define A_TILDE '~'
  16398. +#define A_DIAER '"'
  16399. +static unsigned char ret_diacr[] = {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
  16400. +
  16401. +static void do_dead(unsigned char value, char up_flag)
  16402. +{
  16403. +  if(up_flag)
  16404. +    return;
  16405. +
  16406. +  value = ret_diacr[value];
  16407. +  if(diacr == value)
  16408. +  {
  16409. +    diacr = 0;
  16410. +    put_queue(value);
  16411. +    return;
  16412. +  }
  16413. +  diacr = value;
  16414. +}
  16415. +
  16416. +static unsigned char handle_diacr(unsigned char ch)
  16417. +{
  16418. +  int d = diacr;
  16419. +  int i;
  16420. +
  16421. +  diacr = 0;
  16422. +  if(ch == ' ')
  16423. +    return d;
  16424. +
  16425. +  for(i = 0; i<accent_table_size; i++)
  16426. +  {
  16427. +    if(accent_table[i].diacr == d && accent_table[i].base == ch)
  16428. +      return accent_table[i].result;
  16429. +  }
  16430. +  put_queue(d);
  16431. +  return ch;
  16432. +}
  16433. +
  16434. +static void do_cons(unsigned char value, char up_flag)
  16435. +{
  16436. +  if(up_flag)
  16437. +    return;
  16438. +  want_console = value;
  16439. +}
  16440. +
  16441. +static void do_fn(unsigned char value, char up_flag)
  16442. +{
  16443. +  if(up_flag)
  16444. +    return;
  16445. +
  16446. +  if(value<sizeof(func_table) && func_table[value]!=NULL)
  16447. +    puts_queue(func_table[value]);
  16448. +  else
  16449. +    printk("do_fn called with value=%d\n",value);
  16450. +}
  16451. +
  16452. +static void do_pad(unsigned char value, char up_flag)
  16453. +{
  16454. +  static char *pad_chars = "0123456789+-*/\015,.?#";
  16455. +  static char *app_map = "pqrstuvwxylSRQMnn?#";
  16456. +
  16457. +  if(up_flag)
  16458. +    return;
  16459. +
  16460. +  if(vc_kbd_mode(kbd, VC_APPLIC) && !k_down[KG_SHIFT])
  16461. +  {
  16462. +    applkey(app_map[value], 1);
  16463. +    return;
  16464. +  }
  16465. +
  16466. +  if(!vc_kbd_led(kbd,VC_NUMLOCK))
  16467. +    switch(value)
  16468. +    {
  16469. +      case 15:
  16470. +      case 16: do_fn (22, 0); return;
  16471. +      case 7:  do_fn (20, 0); return;
  16472. +      case 8:  do_cur( 3, 0); return;
  16473. +      case 9:  do_fn (24, 0); return;
  16474. +      case 4:  do_cur( 1, 0); return;
  16475. +      case 6:  do_cur( 2, 0); return;
  16476. +      case 1:  do_fn (23, 0); return;
  16477. +      case 2:  do_cur( 0, 0); return;
  16478. +      case 3:  do_fn (25, 0); return;
  16479. +      case 5:  applkey('G',vc_kbd_mode(kbd, VC_APPLIC)); return;
  16480. +    }
  16481. +
  16482. +  put_queue(pad_chars[value]);
  16483. +  if(value == 14 && vc_kbd_mode(kbd, VC_CRLF))
  16484. +    put_queue(10);
  16485. +}
  16486. +
  16487. +static void do_cur(unsigned char value, char up_flag)
  16488. +{
  16489. +  static char *cur_chars = "BDCA";
  16490. +
  16491. +  if(up_flag)
  16492. +    return;
  16493. +
  16494. +  applkey(cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
  16495. +}
  16496. +
  16497. +void compute_shiftstate(void)
  16498. +{
  16499. +}
  16500. +
  16501. +static void do_shift(unsigned char value, char up_flag)
  16502. +{
  16503. +  int old_state = shift_state;
  16504. +
  16505. +  if (rep)
  16506. +    return;
  16507. +
  16508. +  /* Mimic typewriter: a CapsShift key acts like Shift but undoes CapsLock */
  16509. +  if (value == KVAL(K_CAPSSHIFT))
  16510. +  {
  16511. +    value = KVAL(K_SHIFT);
  16512. +    if(!up_flag)
  16513. +      clr_vc_kbd_led(kbd, VC_CAPSLOCK);
  16514. +  }
  16515. +
  16516. +  if(up_flag)
  16517. +  {
  16518. +    /* handle the case that two shift or control
  16519. +           keys are depressed simultaneously */
  16520. +    if(k_down[value])
  16521. +      k_down[value]--;
  16522. +  }
  16523. +  else
  16524. +    k_down[value]++;
  16525. +
  16526. +  if(k_down[value])
  16527. +    shift_state |= (1 << value);
  16528. +  else
  16529. +    shift_state &= ~ (1 << value);
  16530. +
  16531. +  /* kludge */
  16532. +  if(up_flag && shift_state != old_state && npadch != -1)
  16533. +  {
  16534. +    if(kbd->kbdmode == VC_UNICODE)
  16535. +      to_utf8(npadch & 0xffff);
  16536. +    else
  16537. +      put_queue(npadch & 0xff);
  16538. +    npadch = -1;
  16539. +  }
  16540. +}
  16541. +
  16542. +static void do_meta(unsigned char value, char up_flag)
  16543. +{
  16544. +  if(up_flag)
  16545. +    return;
  16546. +
  16547. +  if(vc_kbd_mode(kbd, VC_META))
  16548. +  {
  16549. +    put_queue('\033');
  16550. +    put_queue(value);
  16551. +  }
  16552. +  else
  16553. +    put_queue(value | 0x80);
  16554. +}
  16555. +
  16556. +static void do_ascii(unsigned char value, char up_flag)
  16557. +{
  16558. +  int base;
  16559. +
  16560. +  if(up_flag)
  16561. +    return;
  16562. +
  16563. +  if(value < 10)
  16564. +    base = 10;
  16565. +  else
  16566. +  {
  16567. +    value -= 10;
  16568. +    base = 16;
  16569. +  }
  16570. +
  16571. +  if(npadch == -1)
  16572. +    npadch = value;
  16573. +  else
  16574. +    npadch = npadch * base + value;
  16575. +}
  16576. +
  16577. +static void do_lock(unsigned char value, char up_flag)
  16578. +{
  16579. +  if(up_flag || rep)
  16580. +    return;
  16581. +  chg_vc_kbd_lock(kbd, value);
  16582. +}
  16583. +
  16584. +/* --------------------------------------------------------------------------------------- *
  16585. + * Led driver                                           *
  16586. + * --------------------------------------------------------------------------------------- */
  16587. +
  16588. +static unsigned char ledioctl;
  16589. +
  16590. +unsigned char getledstate(void)
  16591. +{
  16592. +  return ledstate;
  16593. +}
  16594. +
  16595. +void setledstate(struct kbd_struct *kbd, unsigned int led)
  16596. +{
  16597. +  if(!(led & ~7))
  16598. +  {
  16599. +    ledioctl = led;
  16600. +    kbd->ledmode = LED_SHOW_IOCTL;
  16601. +  }
  16602. +  else
  16603. +    kbd->ledmode = LED_SHOW_FLAGS;
  16604. +  set_leds();
  16605. +}
  16606. +
  16607. +static struct ledptr
  16608. +{
  16609. +  unsigned int *addr;
  16610. +  unsigned int mask;
  16611. +  unsigned char valid:1;
  16612. +} ledptrs[3];
  16613. +
  16614. +void register_leds(int console,unsigned int led,unsigned int *addr,unsigned int mask)
  16615. +{
  16616. +  struct kbd_struct *kbd = kbd_table + console;
  16617. +
  16618. +  if(led < 3)
  16619. +  {
  16620. +    ledptrs[led].addr = addr;
  16621. +    ledptrs[led].mask = mask;
  16622. +    ledptrs[led].valid= 1;
  16623. +    kbd->ledmode = LED_SHOW_MEM;
  16624. +  }
  16625. +  else
  16626. +    kbd->ledmode = LED_SHOW_FLAGS;
  16627. +}
  16628. +
  16629. +static unsigned char getleds(void)
  16630. +{
  16631. +  struct kbd_struct *kbd = kbd_table + fg_console;
  16632. +  unsigned char leds;
  16633. +
  16634. +  if(kbd->ledmode == LED_SHOW_IOCTL)
  16635. +    return ledioctl;
  16636. +  leds = kbd->ledflagstate;
  16637. +  if(kbd->ledmode == LED_SHOW_MEM)
  16638. +  {
  16639. +    if(ledptrs[0].valid)
  16640. +    {
  16641. +      if(*ledptrs[0].addr & ledptrs[0].mask)
  16642. +        leds|=1;
  16643. +      else
  16644. +        leds&=~1;
  16645. +    }
  16646. +    if(ledptrs[1].valid)
  16647. +    {
  16648. +      if(*ledptrs[1].addr & ledptrs[1].mask)
  16649. +        leds|=2;
  16650. +      else
  16651. +        leds&=~2;
  16652. +    }
  16653. +    if(ledptrs[2].valid)
  16654. +    {
  16655. +      if(*ledptrs[2].addr & ledptrs[2].mask)
  16656. +        leds|=4;
  16657. +      else
  16658. +        leds&=~4;
  16659. +    }
  16660. +  }
  16661. +  return leds;
  16662. +}
  16663. +
  16664. +/* --------------------------------------------------------------------------------------- *
  16665. + *                                   Keyboard initialisation                               *
  16666. + *    kbd_rx must be allocated first, then kbd_tx                                          *
  16667. + * --------------------------------------------------------------------------------------- */
  16668. +
  16669. +unsigned long kbd_init(unsigned long kmem_start)
  16670. +{
  16671. +    int i;
  16672. +    struct kbd_struct kbd0;
  16673. +    extern struct tty_driver console_driver;
  16674. +    unsigned long flags;
  16675. +
  16676. +    kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
  16677. +    kbd0.ledmode      = LED_SHOW_FLAGS;
  16678. +    kbd0.lockstate    = KBD_DEFLOCK;
  16679. +    kbd0.modeflags    = KBD_DEFMODE;
  16680. +    kbd0.kbdmode      = VC_XLATE;
  16681. +
  16682. +    for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
  16683. +        kbd_table[i] = kbd0;
  16684. +
  16685. +    ttytab = console_driver.table;
  16686. +
  16687. +    bh_base[KEYBOARD_BH].routine=kbd_bh;
  16688. +    save_flags(flags);
  16689. +    cli();
  16690. +    if(request_irq(IRQ_KEYBOARDRX, kbd_rx, 0, "keyboard")!=0)
  16691. +        panic("Could not allocate keyboard receive IRQ!");
  16692. +    if(request_irq(IRQ_KEYBOARDTX, kbd_tx, 0, "Keyboard")!=0)
  16693. +        panic("Could not allocate keyboard transmit IRQ!");
  16694. +    disable_irq(IRQ_KEYBOARDTX);
  16695. +    restore_flags(flags);
  16696. +    kbd_sendval(HRST);
  16697. +    printk("%s keyboard driver installed (%s) v%d.%02d.\n", "A5000", "English", VERSION/100, VERSION%100);
  16698. +    return kmem_start;
  16699. +}
  16700. +
  16701. diff -r -u -N linux.orig/arch/arm/drivers/char/lp.c linux.arm/arch/arm/drivers/char/lp.c
  16702. --- linux.orig/arch/arm/drivers/char/lp.c    Thu Jan  1 01:00:00 1970
  16703. +++ linux.arm/arch/arm/drivers/char/lp.c    Fri Oct 27 23:14:24 1995
  16704. @@ -0,0 +1,618 @@
  16705. +/*
  16706. + * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
  16707. + * Copyright (C) 1992,1993 by Michael K. Johnson
  16708. + * - Thanks much to Gunter Windau for pointing out to me where the error
  16709. + *   checking ought to be.
  16710. + * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
  16711. + * Copyright (C) 1994 by Alan Cox (Modularised it)
  16712. + * LPCAREFUL, LPABORT, LPGETSTATUS added by Chris Metcalf, metcalf@lcs.mit.edu
  16713. + */
  16714. +
  16715. +#ifdef MODULE
  16716. +#include <linux/module.h>
  16717. +#include <linux/version.h>
  16718. +#else
  16719. +#define MOD_INC_USE_COUNT
  16720. +#define MOD_DEC_USE_COUNT
  16721. +#endif
  16722. +
  16723. +#include <linux/errno.h>
  16724. +#include <linux/kernel.h>
  16725. +#include <linux/major.h>
  16726. +#include <linux/sched.h>
  16727. +#include <linux/lp.h>
  16728. +#include <linux/malloc.h>
  16729. +#include <linux/ioport.h>
  16730. +#include <linux/fcntl.h>
  16731. +
  16732. +#include <asm/io.h>
  16733. +#include <asm/segment.h>
  16734. +#include <asm/system.h>
  16735. +
  16736. +/* the BIOS manuals say there can be up to 4 lpt devices
  16737. + * but I have not seen a board where the 4th address is listed
  16738. + * if you have different hardware change the table below 
  16739. + * please let me know if you have different equipment
  16740. + * if you have more than 3 printers, remember to increase LP_NO
  16741. + */
  16742. +struct lp_struct lp_table[] = {
  16743. +    { 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
  16744. +    { 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
  16745. +    { 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
  16746. +}; 
  16747. +#define LP_NO 3
  16748. +
  16749. +/* Test if printer is ready (and optionally has no error conditions) */
  16750. +#define LP_READY(minor, status) \
  16751. +  ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : (status & LP_PBUSY))
  16752. +#define LP_CAREFUL_READY(minor, status) \
  16753. +  ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : 1)
  16754. +#define _LP_CAREFUL_READY(status) \
  16755. +   (status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
  16756. +      (LP_PBUSY|LP_PSELECD|LP_PERRORP) 
  16757. +
  16758. +/* Allow old versions of tunelp to continue to work */
  16759. +#define OLD_LPCHAR   0x0001
  16760. +#define OLD_LPTIME   0x0002
  16761. +#define OLD_LPABORT  0x0004
  16762. +#define OLD_LPSETIRQ 0x0005
  16763. +#define OLD_LPGETIRQ 0x0006
  16764. +#define OLD_LPWAIT   0x0008
  16765. +#define OLD_IOCTL_MAX 8
  16766. +
  16767. +/* 
  16768. + * All my debugging code assumes that you debug with only one printer at
  16769. + * a time. RWWH
  16770. + */
  16771. +
  16772. +#undef LP_DEBUG
  16773. +
  16774. +static int lp_reset(int minor)
  16775. +{
  16776. +    int testvalue;
  16777. +    unsigned char command;
  16778. +
  16779. +    command = LP_PSELECP | LP_PINITP;
  16780. +
  16781. +    /* reset value */
  16782. +    outb_p(0, LP_C(minor));
  16783. +    for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
  16784. +        ;
  16785. +    outb_p(command, LP_C(minor));
  16786. +    return LP_S(minor);
  16787. +}
  16788. +
  16789. +#ifdef LP_DEBUG
  16790. +static int lp_max_count = 1;
  16791. +#endif
  16792. +
  16793. +static int lp_char_polled(char lpchar, int minor)
  16794. +{
  16795. +    int status = 0, wait = 0;
  16796. +    unsigned long count  = 0; 
  16797. +
  16798. +    do {
  16799. +        status = LP_S(minor);
  16800. +        count ++;
  16801. +        if(need_resched)
  16802. +            schedule();
  16803. +    } while(!LP_READY(minor,status) && count < LP_CHAR(minor));
  16804. +
  16805. +    if (count == LP_CHAR(minor)) {
  16806. +        return 0;
  16807. +        /* we timed out, and the character was /not/ printed */
  16808. +    }
  16809. +#ifdef LP_DEBUG
  16810. +    if (count > lp_max_count) {
  16811. +        printk("lp success after %d counts.\n",count);
  16812. +        lp_max_count=count;
  16813. +    }
  16814. +#endif
  16815. +    outb_p(lpchar, LP_B(minor));
  16816. +    /* must wait before taking strobe high, and after taking strobe
  16817. +       low, according spec.  Some printers need it, others don't. */
  16818. +    while(wait != LP_WAIT(minor)) wait++;
  16819. +        /* control port takes strobe high */
  16820. +    outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
  16821. +    while(wait) wait--;
  16822. +        /* take strobe low */
  16823. +    outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
  16824. +
  16825. +    return 1;
  16826. +}
  16827. +
  16828. +static int lp_char_interrupt(char lpchar, int minor)
  16829. +{
  16830. +    int wait = 0;
  16831. +    unsigned char status;
  16832. +
  16833. +
  16834. +    if (!((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
  16835. +    || !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
  16836. +    || !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)) {
  16837. +
  16838. +        if (!LP_CAREFUL_READY(minor, status))
  16839. +            return 0;
  16840. +        outb_p(lpchar, LP_B(minor));
  16841. +        /* must wait before taking strobe high, and after taking strobe
  16842. +           low, according spec.  Some printers need it, others don't. */
  16843. +        while(wait != LP_WAIT(minor)) wait++;
  16844. +        /* control port takes strobe high */
  16845. +        outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
  16846. +        while(wait) wait--;
  16847. +        /* take strobe low */
  16848. +        outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
  16849. +        return 1;
  16850. +    }
  16851. +
  16852. +    return 0;
  16853. +}
  16854. +
  16855. +#ifdef LP_DEBUG
  16856. +    unsigned int lp_total_chars = 0;
  16857. +    unsigned int lp_last_call = 0;
  16858. +#endif
  16859. +
  16860. +static void lp_interrupt(int irq, struct pt_regs *regs)
  16861. +{
  16862. +    struct lp_struct *lp = &lp_table[0];
  16863. +    struct lp_struct *lp_end = &lp_table[LP_NO];
  16864. +
  16865. +    while (irq != lp->irq) {
  16866. +        if (++lp >= lp_end)
  16867. +            return;
  16868. +    }
  16869. +
  16870. +    wake_up(&lp->lp_wait_q);
  16871. +}
  16872. +
  16873. +static int lp_write_interrupt(struct inode * inode, struct file * file, char * buf, int count)
  16874. +{
  16875. +    unsigned int minor = MINOR(inode->i_rdev);
  16876. +    unsigned long copy_size;
  16877. +    unsigned long total_bytes_written = 0;
  16878. +    unsigned long bytes_written;
  16879. +    struct lp_struct *lp = &lp_table[minor];
  16880. +    unsigned char status;
  16881. +
  16882. +    do {
  16883. +        bytes_written = 0;
  16884. +        copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
  16885. +        memcpy_fromfs(lp->lp_buffer, buf, copy_size);
  16886. +
  16887. +        while (copy_size) {
  16888. +            if (lp_char_interrupt(lp->lp_buffer[bytes_written], minor)) {
  16889. +                --copy_size;
  16890. +                ++bytes_written;
  16891. +            } else {
  16892. +                int rc = total_bytes_written + bytes_written;
  16893. +                status = LP_S(minor);
  16894. +                if ((status & LP_POUTPA)) {
  16895. +                    printk(KERN_INFO "lp%d out of paper\n", minor);
  16896. +                    if (LP_F(minor) & LP_ABORT)
  16897. +                        return rc?rc:-ENOSPC;
  16898. +                } else if (!(status & LP_PSELECD)) {
  16899. +                    printk(KERN_INFO "lp%d off-line\n", minor);
  16900. +                    if (LP_F(minor) & LP_ABORT)
  16901. +                        return rc?rc:-EIO;
  16902. +                } else if (!(status & LP_PERRORP)) {
  16903. +                    printk(KERN_ERR "lp%d printer error\n", minor);
  16904. +                    if (LP_F(minor) & LP_ABORT)
  16905. +                        return rc?rc:-EIO;
  16906. +                }
  16907. +                cli();
  16908. +                outb_p((LP_PSELECP|LP_PINITP|LP_PINTEN), (LP_C(minor)));
  16909. +                status = LP_S(minor);
  16910. +                if ((!(status & LP_PACK) || (status & LP_PBUSY))
  16911. +                  && LP_CAREFUL_READY(minor, status)) {
  16912. +                    outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
  16913. +                    sti();
  16914. +                    continue;
  16915. +                }
  16916. +                current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
  16917. +                interruptible_sleep_on(&lp->lp_wait_q);
  16918. +                outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
  16919. +                sti();
  16920. +                if (current->signal & ~current->blocked) {
  16921. +                    if (total_bytes_written + bytes_written)
  16922. +                        return total_bytes_written + bytes_written;
  16923. +                    else
  16924. +                        return -EINTR;
  16925. +                }
  16926. +            }
  16927. +        }
  16928. +
  16929. +        total_bytes_written += bytes_written;
  16930. +        buf += bytes_written;
  16931. +        count -= bytes_written;
  16932. +
  16933. +    } while (count > 0);
  16934. +
  16935. +    return total_bytes_written;
  16936. +}
  16937. +
  16938. +static int lp_write_polled(struct inode * inode, struct file * file,
  16939. +               char * buf, int count)
  16940. +{
  16941. +    int  retval;
  16942. +    unsigned int minor = MINOR(inode->i_rdev);
  16943. +    char c, *temp = buf;
  16944. +
  16945. +#ifdef LP_DEBUG
  16946. +    if (jiffies-lp_last_call > LP_TIME(minor)) {
  16947. +        lp_total_chars = 0;
  16948. +        lp_max_count = 1;
  16949. +    }
  16950. +    lp_last_call = jiffies;
  16951. +#endif
  16952. +
  16953. +    temp = buf;
  16954. +    while (count > 0) {
  16955. +        c = get_fs_byte(temp);
  16956. +        retval = lp_char_polled(c, minor);
  16957. +        /* only update counting vars if character was printed */
  16958. +        if (retval) { count--; temp++;
  16959. +#ifdef LP_DEBUG
  16960. +            lp_total_chars++;
  16961. +#endif
  16962. +        }
  16963. +        if (!retval) { /* if printer timed out */
  16964. +            int status = LP_S(minor);
  16965. +
  16966. +            if (status & LP_POUTPA) {
  16967. +                printk(KERN_INFO "lp%d out of paper\n", minor);
  16968. +                if(LP_F(minor) & LP_ABORT)
  16969. +                    return temp-buf?temp-buf:-ENOSPC;
  16970. +                current->state = TASK_INTERRUPTIBLE;
  16971. +                current->timeout = jiffies + LP_TIMEOUT_POLLED;
  16972. +                schedule();
  16973. +            } else
  16974. +            if (!(status & LP_PSELECD)) {
  16975. +                printk(KERN_INFO "lp%d off-line\n", minor);
  16976. +                if(LP_F(minor) & LP_ABORT)
  16977. +                    return temp-buf?temp-buf:-EIO;
  16978. +                current->state = TASK_INTERRUPTIBLE;
  16979. +                current->timeout = jiffies + LP_TIMEOUT_POLLED;
  16980. +                schedule();
  16981. +            } else
  16982. +                    /* not offline or out of paper. on fire? */
  16983. +            if (!(status & LP_PERRORP)) {
  16984. +                printk(KERN_ERR "lp%d reported invalid error status (on fire, eh?)\n", minor);
  16985. +                if(LP_F(minor) & LP_ABORT)
  16986. +                    return temp-buf?temp-buf:-EIO;
  16987. +                current->state = TASK_INTERRUPTIBLE;
  16988. +                current->timeout = jiffies + LP_TIMEOUT_POLLED;
  16989. +                schedule();
  16990. +            }
  16991. +
  16992. +            /* check for signals before going to sleep */
  16993. +            if (current->signal & ~current->blocked) {
  16994. +                if (temp != buf)
  16995. +                    return temp-buf;
  16996. +                else
  16997. +                    return -EINTR;
  16998. +            }
  16999. +#ifdef LP_DEBUG
  17000. +            printk("lp sleeping at %d characters for %d jiffies\n",
  17001. +                lp_total_chars, LP_TIME(minor));
  17002. +            lp_total_chars=0;
  17003. +#endif
  17004. +            current->state = TASK_INTERRUPTIBLE;
  17005. +            current->timeout = jiffies + LP_TIME(minor);
  17006. +            schedule();
  17007. +        }
  17008. +    }
  17009. +    return temp-buf;
  17010. +}
  17011. +
  17012. +static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
  17013. +{
  17014. +    if (LP_IRQ(MINOR(inode->i_rdev)))
  17015. +        return lp_write_interrupt(inode, file, buf, count);
  17016. +    else
  17017. +        return lp_write_polled(inode, file, buf, count);
  17018. +}
  17019. +
  17020. +static int lp_lseek(struct inode * inode, struct file * file,
  17021. +            off_t offset, int origin)
  17022. +{
  17023. +    return -ESPIPE;
  17024. +}
  17025. +
  17026. +static int lp_open(struct inode * inode, struct file * file)
  17027. +{
  17028. +    unsigned int minor = MINOR(inode->i_rdev);
  17029. +    int ret;
  17030. +    unsigned int irq;
  17031. +
  17032. +    if (minor >= LP_NO)
  17033. +        return -ENODEV;
  17034. +    if ((LP_F(minor) & LP_EXIST) == 0)
  17035. +        return -ENODEV;
  17036. +    if (LP_F(minor) & LP_BUSY)
  17037. +        return -EBUSY;
  17038. +
  17039. +    MOD_INC_USE_COUNT;
  17040. +
  17041. +    /* If ABORTOPEN is set and the printer is offline or out of paper,
  17042. +       we may still want to open it to perform ioctl()s.  Therefore we
  17043. +       have commandeered O_NONBLOCK, even though it is being used in
  17044. +       a non-standard manner.  This is strictly a Linux hack, and
  17045. +       should most likely only ever be used by the tunelp application. */
  17046. +        if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) {
  17047. +        int status = LP_S(minor);
  17048. +        if (status & LP_POUTPA) {
  17049. +            printk(KERN_INFO "lp%d out of paper\n", minor);
  17050. +            MOD_DEC_USE_COUNT;
  17051. +            return -ENOSPC;
  17052. +        } else if (!(status & LP_PSELECD)) {
  17053. +            printk(KERN_INFO "lp%d off-line\n", minor);
  17054. +            MOD_DEC_USE_COUNT;
  17055. +            return -EIO;
  17056. +        } else if (!(status & LP_PERRORP)) {
  17057. +            printk(KERN_ERR "lp%d printer error\n", minor);
  17058. +            MOD_DEC_USE_COUNT;
  17059. +            return -EIO;
  17060. +        }
  17061. +    }
  17062. +
  17063. +    if ((irq = LP_IRQ(minor))) {
  17064. +        lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
  17065. +        if (!lp_table[minor].lp_buffer) {
  17066. +            MOD_DEC_USE_COUNT;
  17067. +            return -ENOMEM;
  17068. +        }
  17069. +
  17070. +        ret = request_irq(irq, lp_interrupt, SA_INTERRUPT, "printer");
  17071. +        if (ret) {
  17072. +            kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
  17073. +            lp_table[minor].lp_buffer = NULL;
  17074. +            printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret);
  17075. +            MOD_DEC_USE_COUNT;
  17076. +            return ret;
  17077. +        }
  17078. +    }
  17079. +
  17080. +    LP_F(minor) |= LP_BUSY;
  17081. +    return 0;
  17082. +}
  17083. +
  17084. +static void lp_release(struct inode * inode, struct file * file)
  17085. +{
  17086. +    unsigned int minor = MINOR(inode->i_rdev);
  17087. +    unsigned int irq;
  17088. +
  17089. +    if ((irq = LP_IRQ(minor))) {
  17090. +        free_irq(irq);
  17091. +        kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
  17092. +        lp_table[minor].lp_buffer = NULL;
  17093. +    }
  17094. +
  17095. +    LP_F(minor) &= ~LP_BUSY;
  17096. +    MOD_DEC_USE_COUNT;
  17097. +}
  17098. +
  17099. +
  17100. +static int lp_ioctl(struct inode *inode, struct file *file,
  17101. +            unsigned int cmd, unsigned long arg)
  17102. +{
  17103. +    unsigned int minor = MINOR(inode->i_rdev);
  17104. +    int retval = 0;
  17105. +
  17106. +#ifdef LP_DEBUG
  17107. +    printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
  17108. +#endif
  17109. +    if (minor >= LP_NO)
  17110. +        return -ENODEV;
  17111. +    if ((LP_F(minor) & LP_EXIST) == 0)
  17112. +        return -ENODEV;
  17113. +    if (cmd <= OLD_IOCTL_MAX)
  17114. +        printk(KERN_NOTICE "lp%d: warning: obsolete ioctl %#x (perhaps you need a new tunelp)\n",
  17115. +            minor, cmd);
  17116. +    switch ( cmd ) {
  17117. +        case OLD_LPTIME:
  17118. +        case LPTIME:
  17119. +            LP_TIME(minor) = arg;
  17120. +            break;
  17121. +        case OLD_LPCHAR:
  17122. +        case LPCHAR:
  17123. +            LP_CHAR(minor) = arg;
  17124. +            break;
  17125. +        case OLD_LPABORT:
  17126. +        case LPABORT:
  17127. +            if (arg)
  17128. +                LP_F(minor) |= LP_ABORT;
  17129. +            else
  17130. +                LP_F(minor) &= ~LP_ABORT;
  17131. +            break;
  17132. +        case LPABORTOPEN:
  17133. +            if (arg)
  17134. +                LP_F(minor) |= LP_ABORTOPEN;
  17135. +            else
  17136. +                LP_F(minor) &= ~LP_ABORTOPEN;
  17137. +            break;
  17138. +        case LPCAREFUL:
  17139. +            if (arg)
  17140. +                LP_F(minor) |= LP_CAREFUL;
  17141. +            else
  17142. +                LP_F(minor) &= ~LP_CAREFUL;
  17143. +            break;
  17144. +        case OLD_LPWAIT:
  17145. +        case LPWAIT:
  17146. +            LP_WAIT(minor) = arg;
  17147. +            break;
  17148. +        case OLD_LPSETIRQ:
  17149. +        case LPSETIRQ: {
  17150. +            int oldirq;
  17151. +            int newirq = arg;
  17152. +            struct lp_struct *lp = &lp_table[minor];
  17153. +
  17154. +            if (!suser())
  17155. +                return -EPERM;
  17156. +
  17157. +            oldirq = LP_IRQ(minor);
  17158. +
  17159. +            /* Allocate buffer now if we are going to need it */
  17160. +            if (!oldirq && newirq) {
  17161. +                lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
  17162. +                if (!lp->lp_buffer)
  17163. +                    return -ENOMEM;
  17164. +            }
  17165. +
  17166. +            if (oldirq) {
  17167. +                free_irq(oldirq);
  17168. +            }
  17169. +            if (newirq) {
  17170. +                /* Install new irq */
  17171. +                if ((retval = request_irq(newirq, lp_interrupt, SA_INTERRUPT, "printer"))) {
  17172. +                    if (oldirq) {
  17173. +                        /* restore old irq */
  17174. +                        request_irq(oldirq, lp_interrupt, SA_INTERRUPT, "printer");
  17175. +                    } else {
  17176. +                        /* We don't need the buffer */
  17177. +                        kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
  17178. +                        lp->lp_buffer = NULL;
  17179. +                    }
  17180. +                    return retval;
  17181. +                }
  17182. +            }
  17183. +            if (oldirq && !newirq) {
  17184. +                /* We don't need the buffer */
  17185. +                kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
  17186. +                lp->lp_buffer = NULL;
  17187. +            }
  17188. +            LP_IRQ(minor) = newirq;
  17189. +            lp_reset(minor);
  17190. +            break;
  17191. +        }
  17192. +        case OLD_LPGETIRQ:
  17193. +            retval = LP_IRQ(minor);
  17194. +            break;
  17195. +        case LPGETIRQ:
  17196. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  17197. +                sizeof(int));
  17198. +                if (retval)
  17199. +                    return retval;
  17200. +            memcpy_tofs((int *) arg, &LP_IRQ(minor), sizeof(int));
  17201. +            break;
  17202. +        case LPGETSTATUS:
  17203. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  17204. +                sizeof(int));
  17205. +                if (retval)
  17206. +                    return retval;
  17207. +            else {
  17208. +                int status = LP_S(minor);
  17209. +                memcpy_tofs((int *) arg, &status, sizeof(int));
  17210. +            }
  17211. +            break;
  17212. +        case LPRESET:
  17213. +            lp_reset(minor);
  17214. +            break;
  17215. +        default:
  17216. +            retval = -EINVAL;
  17217. +    }
  17218. +    return retval;
  17219. +}
  17220. +
  17221. +
  17222. +static struct file_operations lp_fops = {
  17223. +    lp_lseek,
  17224. +    NULL,        /* lp_read */
  17225. +    lp_write,
  17226. +    NULL,        /* lp_readdir */
  17227. +    NULL,        /* lp_select */
  17228. +    lp_ioctl,
  17229. +    NULL,        /* lp_mmap */
  17230. +    lp_open,
  17231. +    lp_release
  17232. +};
  17233. +
  17234. +#ifndef MODULE
  17235. +
  17236. +long lp_init(long kmem_start)
  17237. +{
  17238. +    int offset = 0;
  17239. +    unsigned int testvalue = 0;
  17240. +    int count = 0;
  17241. +
  17242. +    if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
  17243. +        printk("unable to get major %d for line printer\n", LP_MAJOR);
  17244. +        return kmem_start;
  17245. +    }
  17246. +    /* take on all known port values */
  17247. +    for (offset = 0; offset < LP_NO; offset++) {
  17248. +        if (check_region(LP_B(offset), 3))
  17249. +            continue;
  17250. +        /* write to port & read back to check */
  17251. +        outb_p( LP_DUMMY, LP_B(offset));
  17252. +        for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
  17253. +            ;
  17254. +        testvalue = inb_p(LP_B(offset));
  17255. +        if (testvalue == LP_DUMMY) {
  17256. +            LP_F(offset) |= LP_EXIST;
  17257. +            lp_reset(offset);
  17258. +            printk("lp%d at 0x%04x, ", offset,LP_B(offset));
  17259. +            request_region(LP_B(offset), 3, "lp");
  17260. +            if (LP_IRQ(offset))
  17261. +                printk("using IRQ%d\n", LP_IRQ(offset));
  17262. +            else
  17263. +                printk("using polling driver\n");
  17264. +            count++;
  17265. +        }
  17266. +    }
  17267. +    if (count == 0)
  17268. +        printk("lp_init: no lp devices found\n");
  17269. +    return kmem_start;
  17270. +}
  17271. +
  17272. +#else
  17273. +
  17274. +char kernel_version[]= UTS_RELEASE;
  17275. +
  17276. +int init_module(void)
  17277. +{
  17278. +    int offset = 0;
  17279. +    unsigned int testvalue = 0;
  17280. +    int count = 0;
  17281. +
  17282. +    if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
  17283. +        printk("unable to get major %d for line printer\n", LP_MAJOR);
  17284. +        return -EIO;
  17285. +    }
  17286. +    /* take on all known port values */
  17287. +    for (offset = 0; offset < LP_NO; offset++) {
  17288. +        /* write to port & read back to check */
  17289. +        outb_p( LP_DUMMY, LP_B(offset));
  17290. +        for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
  17291. +            ;
  17292. +        testvalue = inb_p(LP_B(offset));
  17293. +        if (testvalue == LP_DUMMY) {
  17294. +            LP_F(offset) |= LP_EXIST;
  17295. +            lp_reset(offset);
  17296. +            printk("lp%d at 0x%04x, ", offset,LP_B(offset));
  17297. +            request_region(LP_B(offset),3,"lp");
  17298. +            if (LP_IRQ(offset))
  17299. +                printk("using IRQ%d\n", LP_IRQ(offset));
  17300. +            else
  17301. +                printk("using polling driver\n");
  17302. +            count++;
  17303. +        }
  17304. +    }
  17305. +    if (count == 0)
  17306. +        printk("lp_init: no lp devices found\n");
  17307. +    return 0;
  17308. +}
  17309. +
  17310. +void cleanup_module(void)
  17311. +{
  17312. +        int offset;
  17313. +    if(MOD_IN_USE)
  17314. +               printk("lp: busy - remove delayed\n");
  17315. +        else
  17316. +               unregister_chrdev(LP_MAJOR,"lp");
  17317. +           for (offset = 0; offset < LP_NO; offset++) 
  17318. +            if(LP_F(offset) && LP_EXIST) 
  17319. +                 release_region(LP_B(offset),3);
  17320. +}
  17321. +
  17322. +#endif
  17323. diff -r -u -N linux.orig/arch/arm/drivers/char/lp.c.orig linux.arm/arch/arm/drivers/char/lp.c.orig
  17324. --- linux.orig/arch/arm/drivers/char/lp.c.orig    Thu Jan  1 01:00:00 1970
  17325. +++ linux.arm/arch/arm/drivers/char/lp.c.orig    Fri Oct 27 23:14:38 1995
  17326. @@ -0,0 +1,526 @@
  17327. +/*
  17328. + * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
  17329. + * Copyright (C) 1992,1993 by Michael K. Johnson
  17330. + * - Thanks much to Gunter Windau for pointing out to me where the error
  17331. + *   checking ought to be.
  17332. + * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
  17333. + * Copyright (C) 1994 by Alan Cox (Modularised it)
  17334. + */
  17335. +
  17336. +#include <linux/config.h>
  17337. +#include <linux/errno.h>
  17338. +#include <linux/kernel.h>
  17339. +#include <linux/major.h>
  17340. +#include <linux/sched.h>
  17341. +#include <linux/lp.h>
  17342. +#include <linux/malloc.h>
  17343. +
  17344. +#include <asm/io.h>
  17345. +#include <asm/segment.h>
  17346. +#include <asm/system.h>
  17347. +
  17348. +/* the BIOS manuals say there can be up to 4 lpt devices
  17349. + * but I have not seen a board where the 4th address is listed
  17350. + * if you have different hardware change the table below
  17351. + * please let me know if you have different equipment
  17352. + * if you have more than 3 printers, remember to increase LP_NO
  17353. + */
  17354. +struct lp_struct lp_table[] = {
  17355. +    { 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
  17356. +    { 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
  17357. +    { 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
  17358. +};
  17359. +#define LP_NO 3
  17360. +
  17361. +#ifdef MODULE
  17362. +#include <linux/module.h>
  17363. +#include "../../tools/version.h"
  17364. +#endif
  17365. +
  17366. +/*
  17367. + * All my debugging code assumes that you debug with only one printer at
  17368. + * a time. RWWH
  17369. + */
  17370. +
  17371. +#undef LP_DEBUG
  17372. +
  17373. +static int lp_reset(int minor)
  17374. +{
  17375. +    int testvalue;
  17376. +    unsigned char command;
  17377. +
  17378. +    command = LP_PSELECP | LP_PINITP;
  17379. +
  17380. +    /* reset value */
  17381. +    outb_p(0, LP_C(minor));
  17382. +    for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
  17383. +        ;
  17384. +    outb_p(command, LP_C(minor));
  17385. +    return LP_S(minor);
  17386. +}
  17387. +
  17388. +#ifdef LP_DEBUG
  17389. +static int lp_max_count = 1;
  17390. +#endif
  17391. +
  17392. +static int lp_char_polled(char lpchar, int minor)
  17393. +{
  17394. +    int status = 0, wait = 0;
  17395. +    unsigned long count  = 0;
  17396. +
  17397. +    do {
  17398. +        status = LP_S(minor);
  17399. +        count ++;
  17400. +        if(need_resched)
  17401. +            schedule();
  17402. +    } while(!(status & LP_PBUSY) && count < LP_CHAR(minor));
  17403. +
  17404. +    if (count == LP_CHAR(minor)) {
  17405. +        return 0;
  17406. +        /* we timed out, and the character was /not/ printed */
  17407. +    }
  17408. +#ifdef LP_DEBUG
  17409. +    if (count > lp_max_count) {
  17410. +        printk("lp success after %d counts.\n",count);
  17411. +        lp_max_count=count;
  17412. +    }
  17413. +#endif
  17414. +    outb_p(lpchar, LP_B(minor));
  17415. +    /* must wait before taking strobe high, and after taking strobe
  17416. +       low, according spec.  Some printers need it, others don't. */
  17417. +    while(wait != LP_WAIT(minor)) wait++;
  17418. +        /* control port takes strobe high */
  17419. +    outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
  17420. +    while(wait) wait--;
  17421. +        /* take strobe low */
  17422. +    outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
  17423. +
  17424. +    return 1;
  17425. +}
  17426. +
  17427. +static int lp_char_interrupt(char lpchar, int minor)
  17428. +{
  17429. +    int wait = 0;
  17430. +    unsigned char status;
  17431. +
  17432. +
  17433. +    if (!((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
  17434. +    || !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
  17435. +    || !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)) {
  17436. +
  17437. +        outb_p(lpchar, LP_B(minor));
  17438. +        /* must wait before taking strobe high, and after taking strobe
  17439. +           low, according spec.  Some printers need it, others don't. */
  17440. +        while(wait != LP_WAIT(minor)) wait++;
  17441. +        /* control port takes strobe high */
  17442. +        outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
  17443. +        while(wait) wait--;
  17444. +        /* take strobe low */
  17445. +        outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
  17446. +        return 1;
  17447. +    }
  17448. +
  17449. +    return 0;
  17450. +}
  17451. +
  17452. +#ifdef LP_DEBUG
  17453. +    unsigned int lp_total_chars = 0;
  17454. +    unsigned int lp_last_call = 0;
  17455. +#endif
  17456. +
  17457. +static void lp_interrupt(int irq)
  17458. +{
  17459. +    struct lp_struct *lp = &lp_table[0];
  17460. +    struct lp_struct *lp_end = &lp_table[LP_NO];
  17461. +
  17462. +    while (irq != lp->irq) {
  17463. +        if (++lp >= lp_end)
  17464. +            return;
  17465. +    }
  17466. +
  17467. +    wake_up(&lp->lp_wait_q);
  17468. +}
  17469. +
  17470. +static int lp_write_interrupt(struct inode * inode, struct file * file, char * buf, int count)
  17471. +{
  17472. +    unsigned int minor = MINOR(inode->i_rdev);
  17473. +    unsigned long copy_size;
  17474. +    unsigned long total_bytes_written = 0;
  17475. +    unsigned long bytes_written;
  17476. +    struct lp_struct *lp = &lp_table[minor];
  17477. +    unsigned char status;
  17478. +
  17479. +    do {
  17480. +        bytes_written = 0;
  17481. +        copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
  17482. +        memcpy_fromfs(lp->lp_buffer, buf, copy_size);
  17483. +
  17484. +        while (copy_size) {
  17485. +            if (lp_char_interrupt(lp->lp_buffer[bytes_written], minor)) {
  17486. +                --copy_size;
  17487. +                ++bytes_written;
  17488. +            } else {
  17489. +                if (!((status = LP_S(minor)) & LP_PERRORP)) {
  17490. +                    int rc = total_bytes_written + bytes_written;
  17491. +
  17492. +                    if ((status & LP_POUTPA)) {
  17493. +                        printk("lp%d out of paper\n", minor);
  17494. +                        if (!rc)
  17495. +                            rc = -ENOSPC;
  17496. +                    } else if (!(status & LP_PSELECD)) {
  17497. +                        printk("lp%d off-line\n", minor);
  17498. +                        if (!rc)
  17499. +                            rc = -EIO;
  17500. +                    } else {
  17501. +                        printk("lp%d printer error\n", minor);
  17502. +                        if (!rc)
  17503. +                            rc = -EIO;
  17504. +                    }
  17505. +                    if(LP_F(minor) & LP_ABORT)
  17506. +                        return rc;
  17507. +                }
  17508. +                cli();
  17509. +                outb_p((LP_PSELECP|LP_PINITP|LP_PINTEN), (LP_C(minor)));
  17510. +                status = LP_S(minor);
  17511. +                if (!(status & LP_PACK) || (status & LP_PBUSY)) {
  17512. +                    outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
  17513. +                    sti();
  17514. +                    continue;
  17515. +                }
  17516. +                current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
  17517. +                interruptible_sleep_on(&lp->lp_wait_q);
  17518. +                outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
  17519. +                sti();
  17520. +                if (current->signal & ~current->blocked) {
  17521. +                    if (total_bytes_written + bytes_written)
  17522. +                        return total_bytes_written + bytes_written;
  17523. +                    else
  17524. +                        return -EINTR;
  17525. +                }
  17526. +            }
  17527. +        }
  17528. +
  17529. +        total_bytes_written += bytes_written;
  17530. +        buf += bytes_written;
  17531. +        count -= bytes_written;
  17532. +
  17533. +    } while (count > 0);
  17534. +
  17535. +    return total_bytes_written;
  17536. +}
  17537. +
  17538. +static int lp_write_polled(struct inode * inode, struct file * file,
  17539. +               char * buf, int count)
  17540. +{
  17541. +    int  retval;
  17542. +    unsigned int minor = MINOR(inode->i_rdev);
  17543. +    char c, *temp = buf;
  17544. +
  17545. +#ifdef LP_DEBUG
  17546. +    if (jiffies-lp_last_call > LP_TIME(minor)) {
  17547. +        lp_total_chars = 0;
  17548. +        lp_max_count = 1;
  17549. +    }
  17550. +    lp_last_call = jiffies;
  17551. +#endif
  17552. +
  17553. +    temp = buf;
  17554. +    while (count > 0) {
  17555. +        c = get_fs_byte(temp);
  17556. +        retval = lp_char_polled(c, minor);
  17557. +        /* only update counting vars if character was printed */
  17558. +        if (retval) { count--; temp++;
  17559. +#ifdef LP_DEBUG
  17560. +            lp_total_chars++;
  17561. +#endif
  17562. +        }
  17563. +        if (!retval) { /* if printer timed out */
  17564. +            int status = LP_S(minor);
  17565. +
  17566. +            if (status & LP_POUTPA) {
  17567. +                printk("lp%d out of paper\n", minor);
  17568. +                if(LP_F(minor) & LP_ABORT)
  17569. +                    return temp-buf?temp-buf:-ENOSPC;
  17570. +                current->state = TASK_INTERRUPTIBLE;
  17571. +                current->timeout = jiffies + LP_TIMEOUT_POLLED;
  17572. +                schedule();
  17573. +            } else
  17574. +            if (!(status & LP_PSELECD)) {
  17575. +                printk("lp%d off-line\n", minor);
  17576. +                if(LP_F(minor) & LP_ABORT)
  17577. +                    return temp-buf?temp-buf:-EIO;
  17578. +                current->state = TASK_INTERRUPTIBLE;
  17579. +                current->timeout = jiffies + LP_TIMEOUT_POLLED;
  17580. +                schedule();
  17581. +            } else
  17582. +                    /* not offline or out of paper. on fire? */
  17583. +            if (!(status & LP_PERRORP)) {
  17584. +                printk("lp%d reported invalid error status (on fire, eh?)\n", minor);
  17585. +                if(LP_F(minor) & LP_ABORT)
  17586. +                    return temp-buf?temp-buf:-EFAULT;
  17587. +                current->state = TASK_INTERRUPTIBLE;
  17588. +                current->timeout = jiffies + LP_TIMEOUT_POLLED;
  17589. +                schedule();
  17590. +            }
  17591. +
  17592. +            /* check for signals before going to sleep */
  17593. +            if (current->signal & ~current->blocked) {
  17594. +                if (temp != buf)
  17595. +                    return temp-buf;
  17596. +                else
  17597. +                    return -EINTR;
  17598. +            }
  17599. +#ifdef LP_DEBUG
  17600. +            printk("lp sleeping at %d characters for %d jiffies\n",
  17601. +                lp_total_chars, LP_TIME(minor));
  17602. +            lp_total_chars=0;
  17603. +#endif
  17604. +            current->state = TASK_INTERRUPTIBLE;
  17605. +            current->timeout = jiffies + LP_TIME(minor);
  17606. +            schedule();
  17607. +        }
  17608. +    }
  17609. +    return temp-buf;
  17610. +}
  17611. +
  17612. +static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
  17613. +{
  17614. +    if (LP_IRQ(MINOR(inode->i_rdev)))
  17615. +        return lp_write_interrupt(inode, file, buf, count);
  17616. +    else
  17617. +        return lp_write_polled(inode, file, buf, count);
  17618. +}
  17619. +
  17620. +static int lp_lseek(struct inode * inode, struct file * file,
  17621. +            off_t offset, int origin)
  17622. +{
  17623. +    return -ESPIPE;
  17624. +}
  17625. +
  17626. +static int lp_open(struct inode * inode, struct file * file)
  17627. +{
  17628. +    unsigned int minor = MINOR(inode->i_rdev);
  17629. +    int ret;
  17630. +    unsigned int irq;
  17631. +
  17632. +    if (minor >= LP_NO)
  17633. +        return -ENODEV;
  17634. +    if ((LP_F(minor) & LP_EXIST) == 0)
  17635. +        return -ENODEV;
  17636. +    if (LP_F(minor) & LP_BUSY)
  17637. +        return -EBUSY;
  17638. +
  17639. +    if ((irq = LP_IRQ(minor))) {
  17640. +        lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
  17641. +        if (!lp_table[minor].lp_buffer)
  17642. +            return -ENOMEM;
  17643. +
  17644. +        ret = request_irq(irq, lp_interrupt, SA_INTERRUPT, "printer");
  17645. +        if (ret) {
  17646. +            kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
  17647. +            lp_table[minor].lp_buffer = NULL;
  17648. +            printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret);
  17649. +            return ret;
  17650. +        }
  17651. +    }
  17652. +
  17653. +    LP_F(minor) |= LP_BUSY;
  17654. +#ifdef MODULE
  17655. +    MOD_INC_USE_COUNT;
  17656. +#endif
  17657. +    return 0;
  17658. +}
  17659. +
  17660. +static void lp_release(struct inode * inode, struct file * file)
  17661. +{
  17662. +    unsigned int minor = MINOR(inode->i_rdev);
  17663. +    unsigned int irq;
  17664. +
  17665. +    if ((irq = LP_IRQ(minor))) {
  17666. +        free_irq(irq);
  17667. +        kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
  17668. +        lp_table[minor].lp_buffer = NULL;
  17669. +    }
  17670. +
  17671. +    LP_F(minor) &= ~LP_BUSY;
  17672. +#ifdef MODULE
  17673. +    MOD_DEC_USE_COUNT;
  17674. +#endif
  17675. +}
  17676. +
  17677. +
  17678. +static int lp_ioctl(struct inode *inode, struct file *file,
  17679. +            unsigned int cmd, unsigned long arg)
  17680. +{
  17681. +    unsigned int minor = MINOR(inode->i_rdev);
  17682. +    int retval = 0;
  17683. +
  17684. +#ifdef LP_DEBUG
  17685. +    printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
  17686. +#endif
  17687. +    if (minor >= LP_NO)
  17688. +        return -ENODEV;
  17689. +    if ((LP_F(minor) & LP_EXIST) == 0)
  17690. +        return -ENODEV;
  17691. +    switch ( cmd ) {
  17692. +        case LPTIME:
  17693. +            LP_TIME(minor) = arg;
  17694. +            break;
  17695. +        case LPCHAR:
  17696. +            LP_CHAR(minor) = arg;
  17697. +            break;
  17698. +        case LPABORT:
  17699. +            if (arg)
  17700. +                LP_F(minor) |= LP_ABORT;
  17701. +            else
  17702. +                LP_F(minor) &= ~LP_ABORT;
  17703. +            break;
  17704. +        case LPWAIT:
  17705. +            LP_WAIT(minor) = arg;
  17706. +            break;
  17707. +        case LPSETIRQ: {
  17708. +            int oldirq;
  17709. +            int newirq = arg;
  17710. +            struct lp_struct *lp = &lp_table[minor];
  17711. +
  17712. +            if (!suser())
  17713. +                return -EPERM;
  17714. +
  17715. +            oldirq = LP_IRQ(minor);
  17716. +
  17717. +            /* Allocate buffer now if we are going to need it */
  17718. +            if (!oldirq && newirq) {
  17719. +                lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
  17720. +                if (!lp->lp_buffer)
  17721. +                    return -ENOMEM;
  17722. +            }
  17723. +
  17724. +            if (oldirq) {
  17725. +                free_irq(oldirq);
  17726. +            }
  17727. +            if (newirq) {
  17728. +                /* Install new irq */
  17729. +                if ((retval = request_irq(newirq, lp_interrupt, SA_INTERRUPT, "printer"))) {
  17730. +                    if (oldirq) {
  17731. +                        /* restore old irq */
  17732. +                        request_irq(oldirq, lp_interrupt, SA_INTERRUPT, "printer");
  17733. +                    } else {
  17734. +                        /* We don't need the buffer */
  17735. +                        kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
  17736. +                        lp->lp_buffer = NULL;
  17737. +                    }
  17738. +                    return retval;
  17739. +                }
  17740. +            }
  17741. +            if (oldirq && !newirq) {
  17742. +                /* We don't need the buffer */
  17743. +                kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
  17744. +                lp->lp_buffer = NULL;
  17745. +            }
  17746. +            LP_IRQ(minor) = newirq;
  17747. +            lp_reset(minor);
  17748. +            break;
  17749. +        }
  17750. +        case LPGETIRQ:
  17751. +            retval = LP_IRQ(minor);
  17752. +            break;
  17753. +        default:
  17754. +            retval = -EINVAL;
  17755. +    }
  17756. +    return retval;
  17757. +}
  17758. +
  17759. +
  17760. +static struct file_operations lp_fops = {
  17761. +    lp_lseek,
  17762. +    NULL,        /* lp_read */
  17763. +    lp_write,
  17764. +    NULL,        /* lp_readdir */
  17765. +    NULL,        /* lp_select */
  17766. +    lp_ioctl,
  17767. +    NULL,        /* lp_mmap */
  17768. +    lp_open,
  17769. +    lp_release
  17770. +};
  17771. +
  17772. +#ifndef MODULE
  17773. +
  17774. +long lp_init(long kmem_start)
  17775. +{
  17776. +    int offset = 0;
  17777. +    unsigned int testvalue = 0;
  17778. +    int count = 0;
  17779. +
  17780. +    if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
  17781. +        printk("unable to get major %d for line printer\n", LP_MAJOR);
  17782. +        return kmem_start;
  17783. +    }
  17784. +    /* take on all known port values */
  17785. +    for (offset = 0; offset < LP_NO; offset++) {
  17786. +        /* write to port & read back to check */
  17787. +        outb_p( LP_DUMMY, LP_B(offset));
  17788. +        for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
  17789. +            ;
  17790. +        testvalue = inb_p(LP_B(offset));
  17791. +        if (testvalue == LP_DUMMY) {
  17792. +            LP_F(offset) |= LP_EXIST;
  17793. +            lp_reset(offset);
  17794. +            printk("lp_init: lp%d exists, ", offset);
  17795. +            if (LP_IRQ(offset))
  17796. +                printk("using IRQ%d\n", LP_IRQ(offset));
  17797. +            else
  17798. +                printk("using polling driver\n");
  17799. +            count++;
  17800. +        }
  17801. +    }
  17802. +    if (count == 0)
  17803. +        printk("lp_init: no lp devices found\n");
  17804. +    return kmem_start;
  17805. +}
  17806. +
  17807. +#else
  17808. +
  17809. +char kernel_version[]= UTS_RELEASE;
  17810. +
  17811. +int init_module(void)
  17812. +{
  17813. +    int offset = 0;
  17814. +    unsigned int testvalue = 0;
  17815. +    int count = 0;
  17816. +
  17817. +    if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
  17818. +        printk("unable to get major %d for line printer\n", LP_MAJOR);
  17819. +        return -EIO;
  17820. +    }
  17821. +    /* take on all known port values */
  17822. +    for (offset = 0; offset < LP_NO; offset++) {
  17823. +        /* write to port & read back to check */
  17824. +        outb_p( LP_DUMMY, LP_B(offset));
  17825. +        for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
  17826. +            ;
  17827. +        testvalue = inb_p(LP_B(offset));
  17828. +        if (testvalue == LP_DUMMY) {
  17829. +            LP_F(offset) |= LP_EXIST;
  17830. +            lp_reset(offset);
  17831. +            printk("lp_init: lp%d exists, ", offset);
  17832. +            if (LP_IRQ(offset))
  17833. +                printk("using IRQ%d\n", LP_IRQ(offset));
  17834. +            else
  17835. +                printk("using polling driver\n");
  17836. +            count++;
  17837. +        }
  17838. +    }
  17839. +    if (count == 0)
  17840. +        printk("lp_init: no lp devices found\n");
  17841. +    return 0;
  17842. +}
  17843. +
  17844. +void cleanup_module(void)
  17845. +{
  17846. +       if(MOD_IN_USE)
  17847. +               printk("lp: busy - remove delayed\n");
  17848. +       else
  17849. +               unregister_chrdev(LP_MAJOR,"lp");
  17850. +}
  17851. +
  17852. +#endif
  17853. diff -r -u -N linux.orig/arch/arm/drivers/char/mem.c linux.arm/arch/arm/drivers/char/mem.c
  17854. --- linux.orig/arch/arm/drivers/char/mem.c    Thu Jan  1 01:00:00 1970
  17855. +++ linux.arm/arch/arm/drivers/char/mem.c    Fri Oct 27 23:14:24 1995
  17856. @@ -0,0 +1,388 @@
  17857. +/*
  17858. + *  linux/drivers/char/mem.c
  17859. + *
  17860. + *  Copyright (C) 1991, 1992  Linus Torvalds
  17861. + */
  17862. +
  17863. +#include <linux/config.h>
  17864. +#include <linux/types.h>
  17865. +#include <linux/errno.h>
  17866. +#include <linux/sched.h>
  17867. +#include <linux/kernel.h>
  17868. +#include <linux/major.h>
  17869. +#include <linux/tty.h>
  17870. +#include <linux/mouse.h>
  17871. +#include <linux/tpqic02.h>
  17872. +#include <linux/malloc.h>
  17873. +#include <linux/mman.h>
  17874. +
  17875. +#include <asm/segment.h>
  17876. +#include <asm/io.h>
  17877. +
  17878. +#ifdef CONFIG_SOUND
  17879. +extern long soundcard_init(long mem_start);
  17880. +#endif
  17881. +
  17882. +static int read_ram(struct inode * inode, struct file * file,char * buf, int count)
  17883. +{
  17884. +    return -EIO;
  17885. +}
  17886. +
  17887. +static int write_ram(struct inode * inode, struct file * file,char * buf, int count)
  17888. +{
  17889. +    return -EIO;
  17890. +}
  17891. +
  17892. +static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
  17893. +{
  17894. +    unsigned long p = file->f_pos;
  17895. +    int read;
  17896. +
  17897. +    if (count < 0)
  17898. +        return -EINVAL;
  17899. +    if (p >= high_memory)
  17900. +        return 0;
  17901. +    if (count > high_memory - p)
  17902. +        count = high_memory - p;
  17903. +    read = 0;
  17904. +    while (p < PAGE_SIZE && count > 0) {
  17905. +        put_fs_byte(0,buf);
  17906. +        buf++;
  17907. +        p++;
  17908. +        count--;
  17909. +        read++;
  17910. +    }
  17911. +    memcpy_tofs(buf,(void *) p,count);
  17912. +    read += count;
  17913. +    file->f_pos += read;
  17914. +    return read;
  17915. +}
  17916. +
  17917. +static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
  17918. +{
  17919. +    unsigned long p = file->f_pos;
  17920. +    int written;
  17921. +
  17922. +    if (count < 0)
  17923. +        return -EINVAL;
  17924. +    if (p >= high_memory)
  17925. +        return 0;
  17926. +    if (count > high_memory - p)
  17927. +        count = high_memory - p;
  17928. +    written = 0;
  17929. +    while (p < PAGE_SIZE && count > 0) {
  17930. +        /* Hmm. Do something? */
  17931. +        buf++;
  17932. +        p++;
  17933. +        count--;
  17934. +        written++;
  17935. +    }
  17936. +    memcpy_fromfs((void *) p,buf,count);
  17937. +    written += count;
  17938. +    file->f_pos += written;
  17939. +    return count;
  17940. +}
  17941. +
  17942. +static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_struct * vma)
  17943. +{
  17944. +    if (vma->vm_offset & ~PAGE_MASK)
  17945. +        return -ENXIO;
  17946. +#ifndef __arm__
  17947. +    if (x86 > 3 && vma->vm_offset >= high_memory)
  17948. +        vma->vm_page_prot |= PAGE_PCD;
  17949. +#endif
  17950. +    if (remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
  17951. +        return -EAGAIN;
  17952. +    vma->vm_inode = inode;
  17953. +    inode->i_count++;
  17954. +    return 0;
  17955. +}
  17956. +
  17957. +static int read_kmem(struct inode *inode, struct file *file, char *buf, int count)
  17958. +{
  17959. +    int read1, read2;
  17960. +
  17961. +    read1 = read_mem(inode, file, buf, count);
  17962. +    if (read1 < 0)
  17963. +        return read1;
  17964. +    read2 = vread(buf + read1, (char *) ((unsigned long) file->f_pos), count - read1);
  17965. +    if (read2 < 0)
  17966. +        return read2;
  17967. +    file->f_pos += read2;
  17968. +    return read1 + read2;
  17969. +}
  17970. +
  17971. +static int read_port(struct inode * inode,struct file * file,char * buf, int count)
  17972. +{
  17973. +    unsigned int i = file->f_pos;
  17974. +    char * tmp = buf;
  17975. +
  17976. +    while (count-- > 0 && i < 65536) {
  17977. +        put_fs_byte(inb(i),tmp);
  17978. +        i++;
  17979. +        tmp++;
  17980. +    }
  17981. +    file->f_pos = i;
  17982. +    return tmp-buf;
  17983. +}
  17984. +
  17985. +static int write_port(struct inode * inode,struct file * file,char * buf, int count)
  17986. +{
  17987. +    unsigned int i = file->f_pos;
  17988. +    char * tmp = buf;
  17989. +
  17990. +    while (count-- > 0 && i < 65536) {
  17991. +        outb(get_fs_byte(tmp),i);
  17992. +        i++;
  17993. +        tmp++;
  17994. +    }
  17995. +    file->f_pos = i;
  17996. +    return tmp-buf;
  17997. +}
  17998. +
  17999. +static int read_null(struct inode * node,struct file * file,char * buf,int count)
  18000. +{
  18001. +    return 0;
  18002. +}
  18003. +
  18004. +static int write_null(struct inode * inode,struct file * file,char * buf, int count)
  18005. +{
  18006. +    return count;
  18007. +}
  18008. +
  18009. +static int read_zero(struct inode * node,struct file * file,char * buf,int count)
  18010. +{
  18011. +    int left;
  18012. +
  18013. +    for (left = count; left > 0; left--) {
  18014. +        put_fs_byte(0,buf);
  18015. +        buf++;
  18016. +    }
  18017. +    return count;
  18018. +}
  18019. +
  18020. +static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_struct * vma)
  18021. +{
  18022. +    if (vma->vm_flags & VM_SHARED)
  18023. +        return -EINVAL;
  18024. +    if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
  18025. +        return -EAGAIN;
  18026. +    return 0;
  18027. +}
  18028. +
  18029. +static int read_full(struct inode * node,struct file * file,char * buf,int count)
  18030. +{
  18031. +    return count;
  18032. +}
  18033. +
  18034. +static int write_full(struct inode * inode,struct file * file,char * buf, int count)
  18035. +{
  18036. +    return -ENOSPC;
  18037. +}
  18038. +
  18039. +/*
  18040. + * Special lseek() function for /dev/null and /dev/zero.  Most notably, you can fopen()
  18041. + * both devices with "a" now.  This was previously impossible.  SRB.
  18042. + */
  18043. +
  18044. +static int null_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  18045. +{
  18046. +    return file->f_pos=0;
  18047. +}
  18048. +/*
  18049. + * The memory devices use the full 32 bits of the offset, and so we cannot
  18050. + * check against negative addresses: they are ok. The return value is weird,
  18051. + * though, in that case (0).
  18052. + *
  18053. + * also note that seeking relative to the "end of file" isn't supported:
  18054. + * it has no meaning, so it returns -EINVAL.
  18055. + */
  18056. +static int memory_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  18057. +{
  18058. +    switch (orig) {
  18059. +        case 0:
  18060. +            file->f_pos = offset;
  18061. +            return file->f_pos;
  18062. +        case 1:
  18063. +            file->f_pos += offset;
  18064. +            return file->f_pos;
  18065. +        default:
  18066. +            return -EINVAL;
  18067. +    }
  18068. +    if (file->f_pos < 0)
  18069. +        return 0;
  18070. +    return file->f_pos;
  18071. +}
  18072. +
  18073. +#define write_kmem    write_mem
  18074. +#define mmap_kmem    mmap_mem
  18075. +#define zero_lseek    null_lseek
  18076. +#define write_zero    write_null
  18077. +
  18078. +static struct file_operations ram_fops = {
  18079. +    memory_lseek,
  18080. +    read_ram,
  18081. +    write_ram,
  18082. +    NULL,        /* ram_readdir */
  18083. +    NULL,        /* ram_select */
  18084. +    NULL,        /* ram_ioctl */
  18085. +    NULL,        /* ram_mmap */
  18086. +    NULL,        /* no special open code */
  18087. +    NULL,        /* no special release code */
  18088. +    NULL        /* fsync */
  18089. +};
  18090. +
  18091. +static struct file_operations mem_fops = {
  18092. +    memory_lseek,
  18093. +    read_mem,
  18094. +    write_mem,
  18095. +    NULL,        /* mem_readdir */
  18096. +    NULL,        /* mem_select */
  18097. +    NULL,        /* mem_ioctl */
  18098. +    mmap_mem,
  18099. +    NULL,        /* no special open code */
  18100. +    NULL,        /* no special release code */
  18101. +    NULL        /* fsync */
  18102. +};
  18103. +
  18104. +static struct file_operations kmem_fops = {
  18105. +    memory_lseek,
  18106. +    read_kmem,
  18107. +    write_kmem,
  18108. +    NULL,        /* kmem_readdir */
  18109. +    NULL,        /* kmem_select */
  18110. +    NULL,        /* kmem_ioctl */
  18111. +    mmap_kmem,
  18112. +    NULL,        /* no special open code */
  18113. +    NULL,        /* no special release code */
  18114. +    NULL        /* fsync */
  18115. +};
  18116. +
  18117. +static struct file_operations null_fops = {
  18118. +    null_lseek,
  18119. +    read_null,
  18120. +    write_null,
  18121. +    NULL,        /* null_readdir */
  18122. +    NULL,        /* null_select */
  18123. +    NULL,        /* null_ioctl */
  18124. +    NULL,        /* null_mmap */
  18125. +    NULL,        /* no special open code */
  18126. +    NULL,        /* no special release code */
  18127. +    NULL        /* fsync */
  18128. +};
  18129. +
  18130. +static struct file_operations port_fops = {
  18131. +    memory_lseek,
  18132. +    read_port,
  18133. +    write_port,
  18134. +    NULL,        /* port_readdir */
  18135. +    NULL,        /* port_select */
  18136. +    NULL,        /* port_ioctl */
  18137. +    NULL,        /* port_mmap */
  18138. +    NULL,        /* no special open code */
  18139. +    NULL,        /* no special release code */
  18140. +    NULL        /* fsync */
  18141. +};
  18142. +
  18143. +static struct file_operations zero_fops = {
  18144. +    zero_lseek,
  18145. +    read_zero,
  18146. +    write_zero,
  18147. +    NULL,        /* zero_readdir */
  18148. +    NULL,        /* zero_select */
  18149. +    NULL,        /* zero_ioctl */
  18150. +    mmap_zero,
  18151. +    NULL,        /* no special open code */
  18152. +    NULL        /* no special release code */
  18153. +};
  18154. +
  18155. +static struct file_operations full_fops = {
  18156. +    memory_lseek,
  18157. +    read_full,
  18158. +    write_full,
  18159. +    NULL,        /* full_readdir */
  18160. +    NULL,        /* full_select */
  18161. +    NULL,        /* full_ioctl */
  18162. +    NULL,        /* full_mmap */
  18163. +    NULL,        /* no special open code */
  18164. +    NULL        /* no special release code */
  18165. +};
  18166. +
  18167. +static int memory_open(struct inode * inode, struct file * filp)
  18168. +{
  18169. +    switch (MINOR(inode->i_rdev)) {
  18170. +        case 0:
  18171. +            filp->f_op = &ram_fops;
  18172. +            break;
  18173. +        case 1:
  18174. +            filp->f_op = &mem_fops;
  18175. +            break;
  18176. +        case 2:
  18177. +            filp->f_op = &kmem_fops;
  18178. +            break;
  18179. +        case 3:
  18180. +            filp->f_op = &null_fops;
  18181. +            break;
  18182. +        case 4:
  18183. +            filp->f_op = &port_fops;
  18184. +            break;
  18185. +        case 5:
  18186. +            filp->f_op = &zero_fops;
  18187. +            break;
  18188. +        case 7:
  18189. +            filp->f_op = &full_fops;
  18190. +            break;
  18191. +        default:
  18192. +            return -ENODEV;
  18193. +    }
  18194. +    if (filp->f_op && filp->f_op->open)
  18195. +        return filp->f_op->open(inode,filp);
  18196. +    return 0;
  18197. +}
  18198. +
  18199. +static struct file_operations memory_fops = {
  18200. +    NULL,        /* lseek */
  18201. +    NULL,        /* read */
  18202. +    NULL,        /* write */
  18203. +    NULL,        /* readdir */
  18204. +    NULL,        /* select */
  18205. +    NULL,        /* ioctl */
  18206. +    NULL,        /* mmap */
  18207. +    memory_open,    /* just a selector for the real open */
  18208. +    NULL,        /* release */
  18209. +    NULL        /* fsync */
  18210. +};
  18211. +
  18212. +#ifdef CONFIG_FTAPE
  18213. +char* ftape_big_buffer;
  18214. +#endif
  18215. +
  18216. +long chr_dev_init(long mem_start, long mem_end)
  18217. +{
  18218. +    if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
  18219. +        printk("unable to get major %d for memory devs\n", MEM_MAJOR);
  18220. +    mem_start = tty_init(mem_start);
  18221. +#ifdef CONFIG_PRINTER
  18222. +    mem_start = lp_init(mem_start);
  18223. +#endif
  18224. +#ifdef CONFIG_ARMMOUSE
  18225. +    mem_start = mouse_init(mem_start);
  18226. +#endif
  18227. +/*#ifdef CONFIG_SOUND
  18228. +    mem_start = soundcard_init(mem_start);
  18229. +#endif*/
  18230. +#ifdef CONFIG_QIC02_TAPE
  18231. +    mem_start = qic02_tape_init(mem_start);
  18232. +#endif
  18233. +/*
  18234. + *      Rude way to allocate kernel memory buffer for tape device
  18235. + */
  18236. +#ifdef CONFIG_FTAPE
  18237. +        /* allocate NR_FTAPE_BUFFERS 32Kb buffers at aligned address */
  18238. +        ftape_big_buffer= (char*) ((mem_start + 0x7fff) & ~0x7fff);
  18239. +        printk( "ftape: allocated %d buffers aligned at: %p\n",
  18240. +               NR_FTAPE_BUFFERS, ftape_big_buffer);
  18241. +        mem_start = (long) ftape_big_buffer + NR_FTAPE_BUFFERS * 0x8000;
  18242. +#endif
  18243. +    return mem_start;
  18244. +}
  18245. diff -r -u -N linux.orig/arch/arm/drivers/char/mouse.c linux.arm/arch/arm/drivers/char/mouse.c
  18246. --- linux.orig/arch/arm/drivers/char/mouse.c    Thu Jan  1 01:00:00 1970
  18247. +++ linux.arm/arch/arm/drivers/char/mouse.c    Fri Oct 27 23:14:24 1995
  18248. @@ -0,0 +1,68 @@
  18249. +/*
  18250. + * linux/drivers/char/mouse.c
  18251. + *
  18252. + * Generic mouse open routine by Johan Myreen
  18253. + *
  18254. + * Based on code from Linus
  18255. + *
  18256. + * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
  18257. + *   changes incorporated into 0.97pl4
  18258. + *   by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
  18259. + *   See busmouse.c for particulars.
  18260. + *
  18261. + * Made things a lot mode modular - easy to compile in just one or two
  18262. + * of the mouse drivers, as they are now completely independent. Linus.
  18263. + */
  18264. +
  18265. +#include <linux/fs.h>
  18266. +#include <linux/errno.h>
  18267. +#include <linux/mouse.h>
  18268. +#include <linux/config.h>
  18269. +#include <linux/kernel.h>
  18270. +#include <linux/major.h>
  18271. +
  18272. +/*
  18273. + * note that you can remove any or all of the drivers by undefining
  18274. + * the minor values in <linux/mouse.h>
  18275. + */
  18276. +extern struct file_operations arch_mouse_fops;
  18277. +extern unsigned long arch_mouse_init(unsigned long);
  18278. +
  18279. +static int mouse_open(struct inode * inode, struct file * file)
  18280. +{
  18281. +    int minor = MINOR(inode->i_rdev);
  18282. +
  18283. +    switch (minor) {
  18284. +#ifdef CONFIG_ARMMOUSE
  18285. +        case 4:
  18286. +            file->f_op = &arch_mouse_fops;
  18287. +            break;
  18288. +#endif
  18289. +        default:
  18290. +            return -ENODEV;
  18291. +    }
  18292. +        return file->f_op->open(inode,file);
  18293. +}
  18294. +
  18295. +static struct file_operations mouse_fops = {
  18296. +        NULL,        /* seek */
  18297. +    NULL,        /* read */
  18298. +    NULL,        /* write */
  18299. +    NULL,        /* readdir */
  18300. +    NULL,        /* select */
  18301. +    NULL,        /* ioctl */
  18302. +    NULL,        /* mmap */
  18303. +        mouse_open,
  18304. +        NULL        /* release */
  18305. +};
  18306. +
  18307. +unsigned long mouse_init(unsigned long kmem_start)
  18308. +{
  18309. +#ifdef CONFIG_ARMMOUSE
  18310. +    kmem_start = arch_mouse_init(kmem_start);
  18311. +#endif
  18312. +    if (register_chrdev(MOUSE_MAJOR, "mouse", &mouse_fops))
  18313. +        printk("unable to get major %d for mouse devices\n",
  18314. +               MOUSE_MAJOR);
  18315. +    return kmem_start;
  18316. +}
  18317. diff -r -u -N linux.orig/arch/arm/drivers/char/n_tty.c linux.arm/arch/arm/drivers/char/n_tty.c
  18318. --- linux.orig/arch/arm/drivers/char/n_tty.c    Thu Jan  1 01:00:00 1970
  18319. +++ linux.arm/arch/arm/drivers/char/n_tty.c    Fri Oct 27 23:14:25 1995
  18320. @@ -0,0 +1,1021 @@
  18321. +/*
  18322. + * n_tty.c --- implements the N_TTY line discipline.
  18323. + * 
  18324. + * This code used to be in tty_io.c, but things are getting hairy
  18325. + * enough that it made sense to split things off.  (The N_TTY
  18326. + * processing has changed so much that it's hardly recognizable,
  18327. + * anyway...)
  18328. + *
  18329. + * Note that the open routine for N_TTY is guaranteed never to return
  18330. + * an error.  This is because Linux will fall back to setting a line
  18331. + * to N_TTY if it can not switch to any other line discipline.  
  18332. + *
  18333. + * Written by Theodore Ts'o, Copyright 1994.
  18334. + * 
  18335. + * This file also contains code originally written by Linus Torvalds,
  18336. + * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
  18337. + * 
  18338. + * This file may be redistributed under the terms of the GNU Public
  18339. + * License.
  18340. + */
  18341. +
  18342. +#include <linux/types.h>
  18343. +#include <linux/major.h>
  18344. +#include <linux/errno.h>
  18345. +#include <linux/signal.h>
  18346. +#include <linux/fcntl.h>
  18347. +#include <linux/sched.h>
  18348. +#include <linux/interrupt.h>
  18349. +#include <linux/tty.h>
  18350. +#include <linux/timer.h>
  18351. +#include <linux/ctype.h>
  18352. +#include <linux/kd.h>
  18353. +#include <linux/mm.h>
  18354. +#include <linux/string.h>
  18355. +#include <linux/malloc.h>
  18356. +
  18357. +#include <asm/segment.h>
  18358. +#include <asm/system.h>
  18359. +#include <asm/bitops.h>
  18360. +
  18361. +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
  18362. +
  18363. +#ifndef MIN
  18364. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  18365. +#endif
  18366. +
  18367. +/* number of characters left in xmit buffer before select has we have room */
  18368. +#define WAKEUP_CHARS 256
  18369. +
  18370. +/*
  18371. + * This defines the low- and high-watermarks for throttling and
  18372. + * unthrottling the TTY driver.  These watermarks are used for
  18373. + * controlling the space in the read buffer.
  18374. + */
  18375. +#define TTY_THRESHOLD_THROTTLE        (N_TTY_BUF_SIZE - 128)
  18376. +#define TTY_THRESHOLD_UNTHROTTLE     128
  18377. +
  18378. +static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
  18379. +{
  18380. +    if (tty->read_cnt < N_TTY_BUF_SIZE) {
  18381. +        tty->read_buf[tty->read_head] = c;
  18382. +        tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
  18383. +        tty->read_cnt++;
  18384. +    }
  18385. +}
  18386. +
  18387. +/*
  18388. + * Flush the input buffer
  18389. + */
  18390. +void n_tty_flush_buffer(struct tty_struct * tty)
  18391. +{
  18392. +    tty->read_head = tty->read_tail = tty->read_cnt = 0;
  18393. +    tty->canon_head = tty->canon_data = tty->erasing = 0;
  18394. +    memset(&tty->read_flags, 0, sizeof tty->read_flags);
  18395. +    
  18396. +    if (!tty->link)
  18397. +        return;
  18398. +
  18399. +    if (tty->driver.unthrottle)
  18400. +        (tty->driver.unthrottle)(tty);
  18401. +    if (tty->link->packet) {
  18402. +        tty->ctrl_status |= TIOCPKT_FLUSHREAD;
  18403. +        wake_up_interruptible(&tty->link->read_wait);
  18404. +    }
  18405. +}
  18406. +
  18407. +/*
  18408. + * Return number of characters buffered to be delivered to user
  18409. + */
  18410. +int n_tty_chars_in_buffer(struct tty_struct *tty)
  18411. +{
  18412. +    return tty->read_cnt;
  18413. +}
  18414. +
  18415. +/*
  18416. + * Perform OPOST processing.  Returns -1 when the output device is
  18417. + * full and the character must be retried.
  18418. + */
  18419. +static int opost(unsigned char c, struct tty_struct *tty)
  18420. +{
  18421. +    int    space, spaces;
  18422. +
  18423. +    space = tty->driver.write_room(tty);
  18424. +    if (!space)
  18425. +        return -1;
  18426. +
  18427. +    if (O_OPOST(tty)) {
  18428. +        switch (c) {
  18429. +        case '\n':
  18430. +            if (O_ONLRET(tty))
  18431. +                tty->column = 0;
  18432. +            if (O_ONLCR(tty)) {
  18433. +                if (space < 2)
  18434. +                    return -1;
  18435. +                tty->driver.put_char(tty, '\r');
  18436. +                tty->column = 0;
  18437. +            }
  18438. +            tty->canon_column = tty->column;
  18439. +            break;
  18440. +        case '\r':
  18441. +            if (O_ONOCR(tty) && tty->column == 0)
  18442. +                return 0;
  18443. +            if (O_OCRNL(tty)) {
  18444. +                c = '\n';
  18445. +                if (O_ONLRET(tty))
  18446. +                    tty->canon_column = tty->column = 0;
  18447. +                break;
  18448. +            }
  18449. +            tty->canon_column = tty->column = 0;
  18450. +            break;
  18451. +        case '\t':
  18452. +            spaces = 8 - (tty->column & 7);
  18453. +            if (O_TABDLY(tty) == XTABS) {
  18454. +                if (space < spaces)
  18455. +                    return -1;
  18456. +                tty->column += spaces;
  18457. +                tty->driver.write(tty, 0, "        ", spaces);
  18458. +                return 0;
  18459. +            }
  18460. +            tty->column += spaces;
  18461. +            break;
  18462. +        case '\b':
  18463. +            if (tty->column > 0)
  18464. +                tty->column--;
  18465. +            break;
  18466. +        default:
  18467. +            if (O_OLCUC(tty))
  18468. +                c = toupper(c);
  18469. +            if (!iscntrl(c))
  18470. +                tty->column++;
  18471. +            break;
  18472. +        }
  18473. +    }
  18474. +    tty->driver.put_char(tty, c);
  18475. +    return 0;
  18476. +}
  18477. +
  18478. +static inline void put_char(unsigned char c, struct tty_struct *tty)
  18479. +{
  18480. +    tty->driver.put_char(tty, c);
  18481. +}
  18482. +
  18483. +/* Must be called only when L_ECHO(tty) is true. */
  18484. +
  18485. +static void echo_char(unsigned char c, struct tty_struct *tty)
  18486. +{
  18487. +    if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
  18488. +        put_char('^', tty);
  18489. +        put_char(c ^ 0100, tty);
  18490. +        tty->column += 2;
  18491. +    } else
  18492. +        opost(c, tty);
  18493. +}
  18494. +
  18495. +static inline void finish_erasing(struct tty_struct *tty)
  18496. +{
  18497. +    if (tty->erasing) {
  18498. +        put_char('/', tty);
  18499. +        tty->column += 2;
  18500. +        tty->erasing = 0;
  18501. +    }
  18502. +}
  18503. +
  18504. +static void eraser(unsigned char c, struct tty_struct *tty)
  18505. +{
  18506. +    enum { ERASE, WERASE, KILL } kill_type;
  18507. +    int head, seen_alnums;
  18508. +
  18509. +    if (tty->read_head == tty->canon_head) {
  18510. +        /* opost('\a', tty); */        /* what do you think? */
  18511. +        return;
  18512. +    }
  18513. +    if (c == ERASE_CHAR(tty))
  18514. +        kill_type = ERASE;
  18515. +    else if (c == WERASE_CHAR(tty))
  18516. +        kill_type = WERASE;
  18517. +    else {
  18518. +        if (!L_ECHO(tty)) {
  18519. +            tty->read_cnt -= ((tty->read_head - tty->canon_head) &
  18520. +                      (N_TTY_BUF_SIZE - 1));
  18521. +            tty->read_head = tty->canon_head;
  18522. +            return;
  18523. +        }
  18524. +        if (!L_ECHOK(tty) || !L_ECHOKE(tty)) {
  18525. +            tty->read_cnt -= ((tty->read_head - tty->canon_head) &
  18526. +                      (N_TTY_BUF_SIZE - 1));
  18527. +            tty->read_head = tty->canon_head;
  18528. +            finish_erasing(tty);
  18529. +            echo_char(KILL_CHAR(tty), tty);
  18530. +            /* Add a newline if ECHOK is on and ECHOKE is off. */
  18531. +            if (L_ECHOK(tty))
  18532. +                opost('\n', tty);
  18533. +            return;
  18534. +        }
  18535. +        kill_type = KILL;
  18536. +    }
  18537. +
  18538. +    seen_alnums = 0;
  18539. +    while (tty->read_head != tty->canon_head) {
  18540. +        head = (tty->read_head - 1) & (N_TTY_BUF_SIZE-1);
  18541. +        c = tty->read_buf[head];
  18542. +        if (kill_type == WERASE) {
  18543. +            /* Equivalent to BSD's ALTWERASE. */
  18544. +            if (isalnum(c) || c == '_')
  18545. +                seen_alnums++;
  18546. +            else if (seen_alnums)
  18547. +                break;
  18548. +        }
  18549. +        tty->read_head = head;
  18550. +        tty->read_cnt--;
  18551. +        if (L_ECHO(tty)) {
  18552. +            if (L_ECHOPRT(tty)) {
  18553. +                if (!tty->erasing) {
  18554. +                    put_char('\\', tty);
  18555. +                    tty->column++;
  18556. +                    tty->erasing = 1;
  18557. +                }
  18558. +                echo_char(c, tty);
  18559. +            } else if (!L_ECHOE(tty)) {
  18560. +                echo_char(ERASE_CHAR(tty), tty);
  18561. +            } else if (c == '\t') {
  18562. +                unsigned int col = tty->canon_column;
  18563. +                unsigned long tail = tty->canon_head;
  18564. +
  18565. +                /* Find the column of the last char. */
  18566. +                while (tail != tty->read_head) {
  18567. +                    c = tty->read_buf[tail];
  18568. +                    if (c == '\t')
  18569. +                        col = (col | 7) + 1;
  18570. +                    else if (iscntrl(c)) {
  18571. +                        if (L_ECHOCTL(tty))
  18572. +                            col += 2;
  18573. +                    } else
  18574. +                        col++;
  18575. +                    tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  18576. +                }
  18577. +
  18578. +                /* Now backup to that column. */
  18579. +                while (tty->column > col) {
  18580. +                    /* Can't use opost here. */
  18581. +                    put_char('\b', tty);
  18582. +                    tty->column--;
  18583. +                }
  18584. +            } else {
  18585. +                if (iscntrl(c) && L_ECHOCTL(tty)) {
  18586. +                    put_char('\b', tty);
  18587. +                    put_char(' ', tty);
  18588. +                    put_char('\b', tty);
  18589. +                    tty->column--;
  18590. +                }
  18591. +                if (!iscntrl(c) || L_ECHOCTL(tty)) {
  18592. +                    put_char('\b', tty);
  18593. +                    put_char(' ', tty);
  18594. +                    put_char('\b', tty);
  18595. +                    tty->column--;
  18596. +                }
  18597. +            }
  18598. +        }
  18599. +        if (kill_type == ERASE)
  18600. +            break;
  18601. +    }
  18602. +    if (tty->read_head == tty->canon_head)
  18603. +        finish_erasing(tty);
  18604. +}
  18605. +
  18606. +static void isig(int sig, struct tty_struct *tty)
  18607. +{
  18608. +    if (tty->pgrp > 0)
  18609. +        kill_pg(tty->pgrp, sig, 1);
  18610. +    if (!L_NOFLSH(tty)) {
  18611. +        n_tty_flush_buffer(tty);
  18612. +        if (tty->driver.flush_buffer)
  18613. +            tty->driver.flush_buffer(tty);
  18614. +    }
  18615. +}
  18616. +
  18617. +static inline void n_tty_receive_break(struct tty_struct *tty)
  18618. +{
  18619. +    if (I_IGNBRK(tty))
  18620. +        return;
  18621. +    if (I_BRKINT(tty)) {
  18622. +        isig(SIGINT, tty);
  18623. +        return;
  18624. +    }
  18625. +    if (I_PARMRK(tty)) {
  18626. +        put_tty_queue('\377', tty);
  18627. +        put_tty_queue('\0', tty);
  18628. +    }
  18629. +    put_tty_queue('\0', tty);
  18630. +    wake_up_interruptible(&tty->read_wait);
  18631. +}
  18632. +
  18633. +static inline void n_tty_receive_overrun(struct tty_struct *tty)
  18634. +{
  18635. +    char buf[64];
  18636. +
  18637. +    tty->num_overrun++;
  18638. +    if (tty->overrun_time < (jiffies - HZ)) {
  18639. +        printk("%s: %d input overrun(s)\n", _tty_name(tty, buf),
  18640. +               tty->num_overrun);
  18641. +        tty->overrun_time = jiffies;
  18642. +        tty->num_overrun = 0;
  18643. +    }
  18644. +}
  18645. +
  18646. +static inline void n_tty_receive_parity_error(struct tty_struct *tty,
  18647. +                          unsigned char c)
  18648. +{
  18649. +    if (I_IGNPAR(tty)) {
  18650. +        return;
  18651. +    }
  18652. +    if (I_PARMRK(tty)) {
  18653. +        put_tty_queue('\377', tty);
  18654. +        put_tty_queue('\0', tty);
  18655. +        put_tty_queue(c, tty);
  18656. +    } else
  18657. +        put_tty_queue('\0', tty);
  18658. +    wake_up_interruptible(&tty->read_wait);
  18659. +}
  18660. +extern int debug_flag;
  18661. +static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
  18662. +{if (debug_flag) printk("received from queue: n_tty_receive_char");
  18663. +    if (tty->raw) {
  18664. +        put_tty_queue(c, tty);
  18665. +        return;
  18666. +    }
  18667. +    
  18668. +    if (tty->stopped && I_IXON(tty) && I_IXANY(tty)) {
  18669. +        start_tty(tty);
  18670. +        return;
  18671. +    }
  18672. +    
  18673. +    if (I_ISTRIP(tty))
  18674. +        c &= 0x7f;
  18675. +    if (I_IUCLC(tty) && L_IEXTEN(tty))
  18676. +        c=tolower(c);
  18677. +
  18678. +    if (tty->closing) {
  18679. +        if (I_IXON(tty)) {
  18680. +            if (c == START_CHAR(tty))
  18681. +                start_tty(tty);
  18682. +            else if (c == STOP_CHAR(tty))
  18683. +                stop_tty(tty);
  18684. +        }
  18685. +        return;
  18686. +    }
  18687. +if (debug_flag) printk("trace 1\n");
  18688. +    /*
  18689. +     * If the previous character was LNEXT, or we know that this
  18690. +     * character is not one of the characters that we'll have to
  18691. +     * handle specially, do shortcut processing to speed things
  18692. +     * up.
  18693. +     */
  18694. +    if (!test_bit(c, &tty->process_char_map) || tty->lnext) {
  18695. +        finish_erasing(tty);
  18696. +        tty->lnext = 0;
  18697. +        if (L_ECHO(tty)) {
  18698. +            if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  18699. +                put_char('\a', tty); /* beep if no space */
  18700. +                return;
  18701. +            }
  18702. +            /* Record the column of first canon char. */
  18703. +            if (tty->canon_head == tty->read_head)
  18704. +                tty->canon_column = tty->column;
  18705. +            echo_char(c, tty);
  18706. +        }
  18707. +        if (I_PARMRK(tty) && c == (unsigned char) '\377')
  18708. +            put_tty_queue(c, tty);
  18709. +        put_tty_queue(c, tty);
  18710. +        return;
  18711. +    }
  18712. +if (debug_flag) printk("trace 2\n");
  18713. +    if (c == '\r') {
  18714. +        if (I_IGNCR(tty))
  18715. +            return;
  18716. +        if (I_ICRNL(tty))
  18717. +            c = '\n';
  18718. +    } else if (c == '\n' && I_INLCR(tty))
  18719. +        c = '\r';
  18720. +    if (I_IXON(tty)) {
  18721. +        if (c == START_CHAR(tty)) {
  18722. +            start_tty(tty);
  18723. +            return;
  18724. +        }
  18725. +        if (c == STOP_CHAR(tty)) {
  18726. +            stop_tty(tty);
  18727. +            return;
  18728. +        }
  18729. +    }
  18730. +    if (L_ISIG(tty)) {
  18731. +        if (c == INTR_CHAR(tty)) {
  18732. +            isig(SIGINT, tty);
  18733. +            return;
  18734. +        }
  18735. +        if (c == QUIT_CHAR(tty)) {
  18736. +            isig(SIGQUIT, tty);
  18737. +            return;
  18738. +        }
  18739. +        if (c == SUSP_CHAR(tty)) {
  18740. +            if (!is_orphaned_pgrp(tty->pgrp))
  18741. +                isig(SIGTSTP, tty);
  18742. +            return;
  18743. +        }
  18744. +    }
  18745. +if (debug_flag) printk("trace 3\n");
  18746. +    if (L_ICANON(tty)) {
  18747. +        if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
  18748. +            (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
  18749. +            eraser(c, tty);
  18750. +            return;
  18751. +        }
  18752. +        if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
  18753. +            tty->lnext = 1;
  18754. +            if (L_ECHO(tty)) {
  18755. +                finish_erasing(tty);
  18756. +                if (L_ECHOCTL(tty)) {
  18757. +                    put_char('^', tty);
  18758. +                    put_char('\b', tty);
  18759. +                }
  18760. +            }
  18761. +            return;
  18762. +        }
  18763. +        if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
  18764. +            L_IEXTEN(tty)) {
  18765. +            unsigned long tail = tty->canon_head;
  18766. +
  18767. +            finish_erasing(tty);
  18768. +            echo_char(c, tty);
  18769. +            opost('\n', tty);
  18770. +            while (tail != tty->read_head) {
  18771. +                echo_char(tty->read_buf[tail], tty);
  18772. +                tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  18773. +            }
  18774. +            return;
  18775. +        }
  18776. +        if (c == '\n') {
  18777. +            if (L_ECHO(tty) || L_ECHONL(tty)) {
  18778. +                if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  18779. +                    put_char('\a', tty);
  18780. +                    return;
  18781. +                }
  18782. +                opost('\n', tty);
  18783. +            }
  18784. +            goto handle_newline;
  18785. +        }
  18786. +        if (c == EOF_CHAR(tty)) {
  18787. +                if (tty->canon_head != tty->read_head)
  18788. +                    set_bit(TTY_PUSH, &tty->flags);
  18789. +            c = __DISABLED_CHAR;
  18790. +            goto handle_newline;
  18791. +        }
  18792. +        if ((c == EOL_CHAR(tty)) ||
  18793. +            (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
  18794. +            /*
  18795. +             * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
  18796. +             */
  18797. +            if (L_ECHO(tty)) {
  18798. +                if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  18799. +                    put_char('\a', tty);
  18800. +                    return;
  18801. +                }
  18802. +                /* Record the column of first canon char. */
  18803. +                if (tty->canon_head == tty->read_head)
  18804. +                    tty->canon_column = tty->column;
  18805. +                echo_char(c, tty);
  18806. +            }
  18807. +            /*
  18808. +             * XXX does PARMRK doubling happen for
  18809. +             * EOL_CHAR and EOL2_CHAR?
  18810. +             */
  18811. +            if (I_PARMRK(tty) && c == (unsigned char) '\377')
  18812. +                put_tty_queue(c, tty);
  18813. +
  18814. +        handle_newline:
  18815. +            set_bit(tty->read_head, &tty->read_flags);
  18816. +            put_tty_queue(c, tty);
  18817. +            tty->canon_head = tty->read_head;
  18818. +            tty->canon_data++;
  18819. +            if (tty->fasync)
  18820. +                kill_fasync(tty->fasync, SIGIO);
  18821. +            if (tty->read_wait)
  18822. +                wake_up_interruptible(&tty->read_wait);
  18823. +            return;
  18824. +        }
  18825. +    }
  18826. +    
  18827. +    finish_erasing(tty);
  18828. +    if (L_ECHO(tty)) {
  18829. +        if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  18830. +            put_char('\a', tty); /* beep if no space */
  18831. +            return;
  18832. +        }
  18833. +        if (c == '\n')
  18834. +            opost('\n', tty);
  18835. +        else {
  18836. +            /* Record the column of first canon char. */
  18837. +            if (tty->canon_head == tty->read_head)
  18838. +                tty->canon_column = tty->column;
  18839. +            echo_char(c, tty);
  18840. +        }
  18841. +    }
  18842. +
  18843. +    if (I_PARMRK(tty) && c == (unsigned char) '\377')
  18844. +        put_tty_queue(c, tty);
  18845. +
  18846. +    put_tty_queue(c, tty);
  18847. +}    
  18848. +
  18849. +static void n_tty_receive_buf(struct tty_struct *tty, unsigned char *cp,
  18850. +                  char *fp, int count)
  18851. +{
  18852. +    unsigned char *p;
  18853. +    char *f, flags = 0;
  18854. +    int    i;
  18855. +if (debug_flag) printk("n_tty_receive_buf\n");
  18856. +    if (!tty->read_buf)
  18857. +        return;
  18858. +if (debug_flag) printk("trace a\n");
  18859. +    if (tty->real_raw) {
  18860. +if (debug_flag) printk("trace b\n");
  18861. +        i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,
  18862. +                   N_TTY_BUF_SIZE - tty->read_head));
  18863. +        memcpy(tty->read_buf + tty->read_head, cp, i);
  18864. +        tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
  18865. +        tty->read_cnt += i;
  18866. +        cp += i;
  18867. +        count -= i;
  18868. +
  18869. +        i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,
  18870. +                   N_TTY_BUF_SIZE - tty->read_head));
  18871. +        memcpy(tty->read_buf + tty->read_head, cp, i);
  18872. +        tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
  18873. +        tty->read_cnt += i;
  18874. +    } else {
  18875. +if (debug_flag) printk("trace c\n");
  18876. +        for (i=count, p = cp, f = fp; i; i--, p++) {
  18877. +            if (f)
  18878. +                flags = *f++;
  18879. +            switch (flags) {
  18880. +            case TTY_NORMAL:
  18881. +                n_tty_receive_char(tty, *p);
  18882. +                break;
  18883. +            case TTY_BREAK:
  18884. +                n_tty_receive_break(tty);
  18885. +                break;
  18886. +            case TTY_PARITY:
  18887. +            case TTY_FRAME:
  18888. +                n_tty_receive_parity_error(tty, *p);
  18889. +                break;
  18890. +            case TTY_OVERRUN:
  18891. +                n_tty_receive_overrun(tty);
  18892. +                break;
  18893. +            default:
  18894. +                printk("%s: unknown flag %d\n", tty_name(tty),
  18895. +                       flags);
  18896. +                break;
  18897. +            }
  18898. +        }
  18899. +        if (tty->driver.flush_chars)
  18900. +            tty->driver.flush_chars(tty);
  18901. +    }
  18902. +if (debug_flag) printk("trace d\n");
  18903. +    if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {
  18904. +if (debug_flag) printk("trace e: %p %p\n", tty->fasync, tty->read_wait);
  18905. +        if (tty->fasync)
  18906. +            kill_fasync(tty->fasync, SIGIO);
  18907. +        if (tty->read_wait)
  18908. +            wake_up_interruptible(&tty->read_wait);
  18909. +    }
  18910. +
  18911. +    if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) &&
  18912. +        tty->driver.throttle &&
  18913. +        !set_bit(TTY_THROTTLED, &tty->flags))
  18914. +        tty->driver.throttle(tty);
  18915. +}
  18916. +
  18917. +static int n_tty_receive_room(struct tty_struct *tty)
  18918. +{
  18919. +    int    left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
  18920. +
  18921. +    /*
  18922. +     * If we are doing input canonicalization, and there are no
  18923. +     * pending newlines, let characters through without limit, so
  18924. +     * that erase characters will be handled.  Other excess
  18925. +     * characters will be beeped.
  18926. +     */
  18927. +    if (tty->icanon && !tty->canon_data)
  18928. +        return N_TTY_BUF_SIZE;
  18929. +
  18930. +    if (left > 0)
  18931. +        return left;
  18932. +    return 0;
  18933. +}
  18934. +
  18935. +int is_ignored(int sig)
  18936. +{
  18937. +    return ((current->blocked & (1<<(sig-1))) ||
  18938. +            (current->sigaction[sig-1].sa_handler == SIG_IGN));
  18939. +}
  18940. +
  18941. +static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
  18942. +{
  18943. +    if (!tty)
  18944. +        return;
  18945. +    
  18946. +    tty->icanon = (L_ICANON(tty) != 0);
  18947. +    if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
  18948. +        I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
  18949. +        I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
  18950. +        I_PARMRK(tty)) {
  18951. +        cli();
  18952. +        memset(tty->process_char_map, 0, 256/32);
  18953. +
  18954. +        if (I_IGNCR(tty) || I_ICRNL(tty))
  18955. +            set_bit('\r', &tty->process_char_map);
  18956. +        if (I_INLCR(tty))
  18957. +            set_bit('\n', &tty->process_char_map);
  18958. +
  18959. +        if (L_ICANON(tty)) {
  18960. +            set_bit(ERASE_CHAR(tty), &tty->process_char_map);
  18961. +            set_bit(KILL_CHAR(tty), &tty->process_char_map);
  18962. +            set_bit(EOF_CHAR(tty), &tty->process_char_map);
  18963. +            set_bit('\n', &tty->process_char_map);
  18964. +            set_bit(EOL_CHAR(tty), &tty->process_char_map);
  18965. +            if (L_IEXTEN(tty)) {
  18966. +                set_bit(WERASE_CHAR(tty),
  18967. +                    &tty->process_char_map);
  18968. +                set_bit(LNEXT_CHAR(tty),
  18969. +                    &tty->process_char_map);
  18970. +                set_bit(EOL2_CHAR(tty),
  18971. +                    &tty->process_char_map);
  18972. +                if (L_ECHO(tty))
  18973. +                    set_bit(REPRINT_CHAR(tty),
  18974. +                        &tty->process_char_map);
  18975. +            }
  18976. +        }
  18977. +        if (I_IXON(tty)) {
  18978. +            set_bit(START_CHAR(tty), &tty->process_char_map);
  18979. +            set_bit(STOP_CHAR(tty), &tty->process_char_map);
  18980. +        }
  18981. +        if (L_ISIG(tty)) {
  18982. +            set_bit(INTR_CHAR(tty), &tty->process_char_map);
  18983. +            set_bit(QUIT_CHAR(tty), &tty->process_char_map);
  18984. +            set_bit(SUSP_CHAR(tty), &tty->process_char_map);
  18985. +        }
  18986. +        clear_bit(__DISABLED_CHAR, &tty->process_char_map);
  18987. +        sti();
  18988. +        tty->raw = 0;
  18989. +        tty->real_raw = 0;
  18990. +    } else {
  18991. +        tty->raw = 1;
  18992. +        if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
  18993. +            (I_IGNPAR(tty) || !I_INPCK(tty)) &&
  18994. +            (tty->driver.flags & TTY_DRIVER_REAL_RAW))
  18995. +            tty->real_raw = 1;
  18996. +        else
  18997. +            tty->real_raw = 0;
  18998. +    }
  18999. +}
  19000. +
  19001. +static void n_tty_close(struct tty_struct *tty)
  19002. +{
  19003. +    n_tty_flush_buffer(tty);
  19004. +    if (tty->read_buf) {
  19005. +        kfree_s((unsigned char *) tty->read_buf, N_TTY_BUF_SIZE);
  19006. +        tty->read_buf = 0;
  19007. +    }
  19008. +}
  19009. +
  19010. +static int n_tty_open(struct tty_struct *tty)
  19011. +{
  19012. +    if (!tty)
  19013. +        return -EINVAL;
  19014. +
  19015. +    if (!tty->read_buf) {
  19016. +        tty->read_buf = (unsigned char *)
  19017. +            kmalloc(N_TTY_BUF_SIZE, intr_count ? GFP_ATOMIC : GFP_KERNEL);
  19018. +        if (!tty->read_buf)
  19019. +            return -ENOMEM;
  19020. +    }
  19021. +    memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
  19022. +    tty->read_head = tty->read_tail = tty->read_cnt = 0;
  19023. +    memset(tty->read_flags, 0, sizeof(tty->read_flags));
  19024. +    n_tty_set_termios(tty, 0);
  19025. +    tty->minimum_to_wake = 1;
  19026. +    tty->closing = 0;
  19027. +    return 0;
  19028. +}
  19029. +
  19030. +static inline int input_available_p(struct tty_struct *tty, int amt)
  19031. +{
  19032. +    if (L_ICANON(tty)) {
  19033. +        if (tty->canon_data)
  19034. +            return 1;
  19035. +    } else if (tty->read_cnt >= (amt ? amt : 1))
  19036. +        return 1;
  19037. +
  19038. +    return 0;
  19039. +}
  19040. +
  19041. +/*
  19042. + * Helper function to speed up read_chan.  It is only called when
  19043. + * ICANON is off; it copies characters straight from the tty queue to
  19044. + * user space directly.  It can be profitably called twice; once to
  19045. + * drain the space from the tail pointer to the (physical) end of the
  19046. + * buffer, and once to drain the space from the (physical) beginning of
  19047. + * the buffer to head pointer.
  19048. + */
  19049. +static inline void copy_from_read_buf(struct tty_struct *tty,
  19050. +                      unsigned char **b,
  19051. +                      unsigned int *nr)
  19052. +
  19053. +{
  19054. +    int    n;
  19055. +
  19056. +    n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));
  19057. +    if (!n)
  19058. +        return;
  19059. +    memcpy_tofs(*b, &tty->read_buf[tty->read_tail], n);
  19060. +    tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
  19061. +    tty->read_cnt -= n;
  19062. +    *b += n;
  19063. +    *nr -= n;
  19064. +}
  19065. +
  19066. +static int read_chan(struct tty_struct *tty, struct file *file,
  19067. +             unsigned char *buf, unsigned int nr)
  19068. +{
  19069. +    struct wait_queue wait = { current, NULL };
  19070. +    int c;
  19071. +    unsigned char *b = buf;
  19072. +    int minimum, time;
  19073. +    int retval = 0;
  19074. +    int size;
  19075. +
  19076. +do_it_again:
  19077. +
  19078. +    if (!tty->read_buf) {
  19079. +        printk("n_tty_read_chan: called with read_buf == NULL?!?\n");
  19080. +        return -EIO;
  19081. +    }
  19082. +
  19083. +    /* Job control check -- must be done at start and after
  19084. +       every sleep (POSIX.1 7.1.1.4). */
  19085. +    /* NOTE: not yet done after every sleep pending a thorough
  19086. +       check of the logic of this change. -- jlc */
  19087. +    /* don't stop on /dev/console */
  19088. +    if (file->f_inode->i_rdev != CONSOLE_DEV &&
  19089. +        current->tty == tty) {
  19090. +        if (tty->pgrp <= 0)
  19091. +            printk("read_chan: tty->pgrp <= 0!\n");
  19092. +        else if (current->pgrp != tty->pgrp) {
  19093. +            if (is_ignored(SIGTTIN) ||
  19094. +                is_orphaned_pgrp(current->pgrp))
  19095. +                return -EIO;
  19096. +            kill_pg(current->pgrp, SIGTTIN, 1);
  19097. +            return -ERESTARTSYS;
  19098. +        }
  19099. +    }
  19100. +
  19101. +    if (L_ICANON(tty)) {
  19102. +        minimum = time = 0;
  19103. +        current->timeout = (unsigned long) -1;
  19104. +    } else {
  19105. +        time = (HZ / 10) * TIME_CHAR(tty);
  19106. +        minimum = MIN_CHAR(tty);
  19107. +        if (minimum) {
  19108. +              current->timeout = (unsigned long) -1;
  19109. +            if (time)
  19110. +                tty->minimum_to_wake = 1;
  19111. +            else if (!tty->read_wait ||
  19112. +                 (tty->minimum_to_wake > minimum))
  19113. +                tty->minimum_to_wake = minimum;
  19114. +        } else {
  19115. +            if (time) {
  19116. +                current->timeout = time + jiffies;
  19117. +                time = 0;
  19118. +            } else
  19119. +                current->timeout = 0;
  19120. +            tty->minimum_to_wake = minimum = 1;
  19121. +        }
  19122. +    }
  19123. +
  19124. +    add_wait_queue(&tty->read_wait, &wait);
  19125. +    while (1) {
  19126. +        /* First test for status change. */
  19127. +        if (tty->packet && tty->link->ctrl_status) {
  19128. +            if (b != buf)
  19129. +                break;
  19130. +            put_fs_byte(tty->link->ctrl_status, b++);
  19131. +            tty->link->ctrl_status = 0;
  19132. +            break;
  19133. +        }
  19134. +        /* This statement must be first before checking for input
  19135. +           so that any interrupt will set the state back to
  19136. +           TASK_RUNNING. */
  19137. +        current->state = TASK_INTERRUPTIBLE;
  19138. +        
  19139. +        if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
  19140. +            ((minimum - (b - buf)) >= 1))
  19141. +            tty->minimum_to_wake = (minimum - (b - buf));
  19142. +        
  19143. +        if (!input_available_p(tty, 0)) {
  19144. +            if (tty->flags & (1 << TTY_SLAVE_CLOSED)) {
  19145. +                retval = -EIO;
  19146. +                break;
  19147. +            }
  19148. +            if (tty_hung_up_p(file))
  19149. +                break;
  19150. +            if (!current->timeout)
  19151. +                break;
  19152. +            if (file->f_flags & O_NONBLOCK) {
  19153. +                retval = -EAGAIN;
  19154. +                break;
  19155. +            }
  19156. +            if (current->signal & ~current->blocked) {
  19157. +                retval = -ERESTARTSYS;
  19158. +                break;
  19159. +            }
  19160. +            schedule();
  19161. +            continue;
  19162. +        }
  19163. +        current->state = TASK_RUNNING;
  19164. +
  19165. +        /* Deal with packet mode. */
  19166. +        if (tty->packet && b == buf) {
  19167. +            put_fs_byte(TIOCPKT_DATA, b++);
  19168. +            nr--;
  19169. +        }
  19170. +
  19171. +        if (L_ICANON(tty)) {
  19172. +            while (1) {
  19173. +                int eol;
  19174. +
  19175. +                disable_bh(TQUEUE_BH);
  19176. +                if (!tty->read_cnt) {
  19177. +                    enable_bh(TQUEUE_BH);
  19178. +                    break;
  19179. +                }
  19180. +                eol = clear_bit(tty->read_tail,
  19181. +                        &tty->read_flags);
  19182. +                c = tty->read_buf[tty->read_tail];
  19183. +                tty->read_tail = ((tty->read_tail+1) &
  19184. +                          (N_TTY_BUF_SIZE-1));
  19185. +                tty->read_cnt--;
  19186. +                enable_bh(TQUEUE_BH);
  19187. +                if (!eol) {
  19188. +                    put_fs_byte(c, b++);
  19189. +                    if (--nr)
  19190. +                        continue;
  19191. +                    break;
  19192. +                }
  19193. +                if (--tty->canon_data < 0) {
  19194. +                    tty->canon_data = 0;
  19195. +                }
  19196. +                if (c != __DISABLED_CHAR) {
  19197. +                    put_fs_byte(c, b++);
  19198. +                    nr--;
  19199. +                }
  19200. +                break;
  19201. +            }
  19202. +        } else {
  19203. +            disable_bh(TQUEUE_BH);
  19204. +            copy_from_read_buf(tty, &b, &nr);
  19205. +            copy_from_read_buf(tty, &b, &nr);
  19206. +            enable_bh(TQUEUE_BH);
  19207. +        }
  19208. +
  19209. +        /* If there is enough space in the read buffer now, let the
  19210. +           low-level driver know. */
  19211. +        if (tty->driver.unthrottle &&
  19212. +            (tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE)
  19213. +            && clear_bit(TTY_THROTTLED, &tty->flags))
  19214. +            tty->driver.unthrottle(tty);
  19215. +
  19216. +        if (b - buf >= minimum || !nr)
  19217. +            break;
  19218. +        if (time)
  19219. +            current->timeout = time + jiffies;
  19220. +    }
  19221. +    remove_wait_queue(&tty->read_wait, &wait);
  19222. +
  19223. +    if (!tty->read_wait)
  19224. +        tty->minimum_to_wake = minimum;
  19225. +
  19226. +    current->state = TASK_RUNNING;
  19227. +    current->timeout = 0;
  19228. +    size = b - buf;
  19229. +    if (size && nr)
  19230. +            clear_bit(TTY_PUSH, &tty->flags);
  19231. +        if (!size && clear_bit(TTY_PUSH, &tty->flags))
  19232. +                goto do_it_again;
  19233. +    if (!size && !retval)
  19234. +            clear_bit(TTY_PUSH, &tty->flags);
  19235. +        return (size ? size : retval);
  19236. +}
  19237. +
  19238. +static int write_chan(struct tty_struct * tty, struct file * file,
  19239. +              unsigned char * buf, unsigned int nr)
  19240. +{
  19241. +    struct wait_queue wait = { current, NULL };
  19242. +    int c;
  19243. +    unsigned char *b = buf;
  19244. +    int retval = 0;
  19245. +
  19246. +    /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
  19247. +    if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) {
  19248. +        retval = tty_check_change(tty);
  19249. +        if (retval)
  19250. +            return retval;
  19251. +    }
  19252. +
  19253. +    add_wait_queue(&tty->write_wait, &wait);
  19254. +    while (1) {
  19255. +        current->state = TASK_INTERRUPTIBLE;
  19256. +        if (current->signal & ~current->blocked) {
  19257. +            retval = -ERESTARTSYS;
  19258. +            break;
  19259. +        }
  19260. +        if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
  19261. +            retval = -EIO;
  19262. +            break;
  19263. +        }
  19264. +        if (O_OPOST(tty)) {
  19265. +            while (nr > 0) {
  19266. +                c = get_fs_byte(b);
  19267. +                if (opost(c, tty) < 0)
  19268. +                    break;
  19269. +                b++; nr--;
  19270. +            }
  19271. +            if (tty->driver.flush_chars)
  19272. +                tty->driver.flush_chars(tty);
  19273. +        } else {
  19274. +            c = tty->driver.write(tty, 1, b, nr);
  19275. +            b += c;
  19276. +            nr -= c;
  19277. +        }
  19278. +        if (!nr)
  19279. +            break;
  19280. +        if (file->f_flags & O_NONBLOCK) {
  19281. +            retval = -EAGAIN;
  19282. +            break;
  19283. +        }
  19284. +        schedule();
  19285. +    }
  19286. +    current->state = TASK_RUNNING;
  19287. +    remove_wait_queue(&tty->write_wait, &wait);
  19288. +    return (b - buf) ? b - buf : retval;
  19289. +}
  19290. +
  19291. +static int normal_select(struct tty_struct * tty, struct inode * inode,
  19292. +             struct file * file, int sel_type, select_table *wait)
  19293. +{
  19294. +    switch (sel_type) {
  19295. +        case SEL_IN:
  19296. +            if (input_available_p(tty, TIME_CHAR(tty) ? 0 :
  19297. +                          MIN_CHAR(tty)))
  19298. +                return 1;
  19299. +            /* fall through */
  19300. +        case SEL_EX:
  19301. +            if (tty->packet && tty->link->ctrl_status)
  19302. +                return 1;
  19303. +            if (tty->flags & (1 << TTY_SLAVE_CLOSED))
  19304. +                return 1;
  19305. +            if (tty_hung_up_p(file))
  19306. +                return 1;
  19307. +            if (!tty->read_wait) {
  19308. +                if (MIN_CHAR(tty) && !TIME_CHAR(tty))
  19309. +                    tty->minimum_to_wake = MIN_CHAR(tty);
  19310. +                else
  19311. +                    tty->minimum_to_wake = 1;
  19312. +            }
  19313. +            select_wait(&tty->read_wait, wait);
  19314. +            return 0;
  19315. +        case SEL_OUT:
  19316. +            if (tty->driver.chars_in_buffer(tty) < WAKEUP_CHARS)
  19317. +                return 1;
  19318. +            select_wait(&tty->write_wait, wait);
  19319. +            return 0;
  19320. +    }
  19321. +    return 0;
  19322. +}
  19323. +
  19324. +struct tty_ldisc tty_ldisc_N_TTY = {
  19325. +    TTY_LDISC_MAGIC,    /* magic */
  19326. +    0,            /* num */
  19327. +    0,            /* flags */
  19328. +    n_tty_open,        /* open */
  19329. +    n_tty_close,        /* close */
  19330. +    n_tty_flush_buffer,    /* flush_buffer */
  19331. +    n_tty_chars_in_buffer,    /* chars_in_buffer */
  19332. +    read_chan,        /* read */
  19333. +    write_chan,        /* write */
  19334. +    n_tty_ioctl,        /* ioctl */
  19335. +    n_tty_set_termios,    /* set_termios */
  19336. +    normal_select,        /* select */
  19337. +    n_tty_receive_buf,    /* receive_buf */
  19338. +    n_tty_receive_room,    /* receive_room */
  19339. +    0            /* write_wakeup */
  19340. +};
  19341. +
  19342. diff -r -u -N linux.orig/arch/arm/drivers/char/n_tty.c.orig linux.arm/arch/arm/drivers/char/n_tty.c.orig
  19343. --- linux.orig/arch/arm/drivers/char/n_tty.c.orig    Thu Jan  1 01:00:00 1970
  19344. +++ linux.arm/arch/arm/drivers/char/n_tty.c.orig    Fri Oct 27 23:14:38 1995
  19345. @@ -0,0 +1,1007 @@
  19346. +/*
  19347. + * n_tty.c --- implements the N_TTY line discipline.
  19348. + *
  19349. + * This code used to be in tty_io.c, but things are getting hairy
  19350. + * enough that it made sense to split things off.  (The N_TTY
  19351. + * processing has changed so much that it's hardly recognizable,
  19352. + * anyway...)
  19353. + *
  19354. + * Note that the open routine for N_TTY is guaranteed never to return
  19355. + * an error.  This is because Linux will fall back to setting a line
  19356. + * to N_TTY if it can not switch to any other line discipline.
  19357. + *
  19358. + * Written by Theodore Ts'o, Copyright 1994.
  19359. + *
  19360. + * This file also contains code originally written by Linus Torvalds,
  19361. + * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
  19362. + *
  19363. + * This file may be redistributed under the terms of the GNU Public
  19364. + * License.
  19365. + */
  19366. +
  19367. +#include <linux/types.h>
  19368. +#include <linux/major.h>
  19369. +#include <linux/errno.h>
  19370. +#include <linux/signal.h>
  19371. +#include <linux/fcntl.h>
  19372. +#include <linux/sched.h>
  19373. +#include <linux/interrupt.h>
  19374. +#include <linux/tty.h>
  19375. +#include <linux/timer.h>
  19376. +#include <linux/ctype.h>
  19377. +#include <linux/kd.h>
  19378. +#include <linux/mm.h>
  19379. +#include <linux/string.h>
  19380. +#include <linux/malloc.h>
  19381. +
  19382. +#include <asm/segment.h>
  19383. +#include <asm/system.h>
  19384. +#include <asm/bitops.h>
  19385. +
  19386. +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
  19387. +
  19388. +#ifndef MIN
  19389. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  19390. +#endif
  19391. +
  19392. +/* number of characters left in xmit buffer before select has we have room */
  19393. +#define WAKEUP_CHARS 256
  19394. +
  19395. +/*
  19396. + * This defines the low- and high-watermarks for throttling and
  19397. + * unthrottling the TTY driver.  These watermarks are used for
  19398. + * controlling the space in the read buffer.
  19399. + */
  19400. +#define TTY_THRESHOLD_THROTTLE        (N_TTY_BUF_SIZE - 128)
  19401. +#define TTY_THRESHOLD_UNTHROTTLE     128
  19402. +
  19403. +static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
  19404. +{
  19405. +    if (tty->read_cnt < N_TTY_BUF_SIZE) {
  19406. +        tty->read_buf[tty->read_head] = c;
  19407. +        tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
  19408. +        tty->read_cnt++;
  19409. +    }
  19410. +}
  19411. +
  19412. +/*
  19413. + * Flush the input buffer
  19414. + */
  19415. +void n_tty_flush_buffer(struct tty_struct * tty)
  19416. +{
  19417. +    tty->read_head = tty->read_tail = tty->read_cnt = 0;
  19418. +    tty->canon_head = tty->canon_data = tty->erasing = 0;
  19419. +    memset(&tty->read_flags, 0, sizeof tty->read_flags);
  19420. +
  19421. +    if (!tty->link)
  19422. +        return;
  19423. +
  19424. +    if (tty->driver.unthrottle)
  19425. +        (tty->driver.unthrottle)(tty);
  19426. +    if (tty->link->packet) {
  19427. +        tty->ctrl_status |= TIOCPKT_FLUSHREAD;
  19428. +        wake_up_interruptible(&tty->link->read_wait);
  19429. +    }
  19430. +}
  19431. +
  19432. +/*
  19433. + * Return number of characters buffered to be delivered to user
  19434. + */
  19435. +int n_tty_chars_in_buffer(struct tty_struct *tty)
  19436. +{
  19437. +    return tty->read_cnt;
  19438. +}
  19439. +
  19440. +/*
  19441. + * Perform OPOST processing.  Returns -1 when the output device is
  19442. + * full and the character must be retried.
  19443. + */
  19444. +static int opost(unsigned char c, struct tty_struct *tty)
  19445. +{
  19446. +    int    space, spaces;
  19447. +
  19448. +    space = tty->driver.write_room(tty);
  19449. +    if (!space)
  19450. +        return -1;
  19451. +
  19452. +    if (O_OPOST(tty)) {
  19453. +        switch (c) {
  19454. +        case '\n':
  19455. +            if (O_ONLRET(tty))
  19456. +                tty->column = 0;
  19457. +            if (O_ONLCR(tty)) {
  19458. +                if (space < 2)
  19459. +                    return -1;
  19460. +                tty->driver.put_char(tty, '\r');
  19461. +                tty->column = 0;
  19462. +            }
  19463. +            tty->canon_column = tty->column;
  19464. +            break;
  19465. +        case '\r':
  19466. +            if (O_ONOCR(tty) && tty->column == 0)
  19467. +                return 0;
  19468. +            if (O_OCRNL(tty)) {
  19469. +                c = '\n';
  19470. +                if (O_ONLRET(tty))
  19471. +                    tty->canon_column = tty->column = 0;
  19472. +                break;
  19473. +            }
  19474. +            tty->canon_column = tty->column = 0;
  19475. +            break;
  19476. +        case '\t':
  19477. +            spaces = 8 - (tty->column & 7);
  19478. +            if (O_TABDLY(tty) == XTABS) {
  19479. +                if (space < spaces)
  19480. +                    return -1;
  19481. +                tty->column += spaces;
  19482. +                tty->driver.write(tty, 0, "        ", spaces);
  19483. +                return 0;
  19484. +            }
  19485. +            tty->column += spaces;
  19486. +            break;
  19487. +        case '\b':
  19488. +            if (tty->column > 0)
  19489. +                tty->column--;
  19490. +            break;
  19491. +        default:
  19492. +            if (O_OLCUC(tty))
  19493. +                c = toupper(c);
  19494. +            if (!iscntrl(c))
  19495. +                tty->column++;
  19496. +            break;
  19497. +        }
  19498. +    }
  19499. +    tty->driver.put_char(tty, c);
  19500. +    return 0;
  19501. +}
  19502. +
  19503. +static inline void put_char(unsigned char c, struct tty_struct *tty)
  19504. +{
  19505. +    tty->driver.put_char(tty, c);
  19506. +}
  19507. +
  19508. +/* Must be called only when L_ECHO(tty) is true. */
  19509. +
  19510. +static void echo_char(unsigned char c, struct tty_struct *tty)
  19511. +{
  19512. +    if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
  19513. +        put_char('^', tty);
  19514. +        put_char(c ^ 0100, tty);
  19515. +        tty->column += 2;
  19516. +    } else
  19517. +        opost(c, tty);
  19518. +}
  19519. +
  19520. +static inline void finish_erasing(struct tty_struct *tty)
  19521. +{
  19522. +    if (tty->erasing) {
  19523. +        put_char('/', tty);
  19524. +        tty->column += 2;
  19525. +        tty->erasing = 0;
  19526. +    }
  19527. +}
  19528. +
  19529. +static void eraser(unsigned char c, struct tty_struct *tty)
  19530. +{
  19531. +    enum { ERASE, WERASE, KILL } kill_type;
  19532. +    int head, seen_alnums;
  19533. +
  19534. +    if (tty->read_head == tty->canon_head) {
  19535. +        /* opost('\a', tty); */        /* what do you think? */
  19536. +        return;
  19537. +    }
  19538. +    if (c == ERASE_CHAR(tty))
  19539. +        kill_type = ERASE;
  19540. +    else if (c == WERASE_CHAR(tty))
  19541. +        kill_type = WERASE;
  19542. +    else {
  19543. +        if (!L_ECHO(tty)) {
  19544. +            tty->read_cnt -= ((tty->read_head - tty->canon_head) &
  19545. +                      (N_TTY_BUF_SIZE - 1));
  19546. +            tty->read_head = tty->canon_head;
  19547. +            return;
  19548. +        }
  19549. +        if (!L_ECHOK(tty) || !L_ECHOKE(tty)) {
  19550. +            tty->read_cnt -= ((tty->read_head - tty->canon_head) &
  19551. +                      (N_TTY_BUF_SIZE - 1));
  19552. +            tty->read_head = tty->canon_head;
  19553. +            finish_erasing(tty);
  19554. +            echo_char(KILL_CHAR(tty), tty);
  19555. +            /* Add a newline if ECHOK is on and ECHOKE is off. */
  19556. +            if (L_ECHOK(tty))
  19557. +                opost('\n', tty);
  19558. +            return;
  19559. +        }
  19560. +        kill_type = KILL;
  19561. +    }
  19562. +
  19563. +    seen_alnums = 0;
  19564. +    while (tty->read_head != tty->canon_head) {
  19565. +        head = (tty->read_head - 1) & (N_TTY_BUF_SIZE-1);
  19566. +        c = tty->read_buf[head];
  19567. +        if (kill_type == WERASE) {
  19568. +            /* Equivalent to BSD's ALTWERASE. */
  19569. +            if (isalnum(c) || c == '_')
  19570. +                seen_alnums++;
  19571. +            else if (seen_alnums)
  19572. +                break;
  19573. +        }
  19574. +        tty->read_head = head;
  19575. +        tty->read_cnt--;
  19576. +        if (L_ECHO(tty)) {
  19577. +            if (L_ECHOPRT(tty)) {
  19578. +                if (!tty->erasing) {
  19579. +                    put_char('\\', tty);
  19580. +                    tty->column++;
  19581. +                    tty->erasing = 1;
  19582. +                }
  19583. +                echo_char(c, tty);
  19584. +            } else if (!L_ECHOE(tty)) {
  19585. +                echo_char(ERASE_CHAR(tty), tty);
  19586. +            } else if (c == '\t') {
  19587. +                unsigned int col = tty->canon_column;
  19588. +                unsigned long tail = tty->canon_head;
  19589. +
  19590. +                /* Find the column of the last char. */
  19591. +                while (tail != tty->read_head) {
  19592. +                    c = tty->read_buf[tail];
  19593. +                    if (c == '\t')
  19594. +                        col = (col | 7) + 1;
  19595. +                    else if (iscntrl(c)) {
  19596. +                        if (L_ECHOCTL(tty))
  19597. +                            col += 2;
  19598. +                    } else
  19599. +                        col++;
  19600. +                    tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  19601. +                }
  19602. +
  19603. +                /* Now backup to that column. */
  19604. +                while (tty->column > col) {
  19605. +                    /* Can't use opost here. */
  19606. +                    put_char('\b', tty);
  19607. +                    tty->column--;
  19608. +                }
  19609. +            } else {
  19610. +                if (iscntrl(c) && L_ECHOCTL(tty)) {
  19611. +                    put_char('\b', tty);
  19612. +                    put_char(' ', tty);
  19613. +                    put_char('\b', tty);
  19614. +                    tty->column--;
  19615. +                }
  19616. +                if (!iscntrl(c) || L_ECHOCTL(tty)) {
  19617. +                    put_char('\b', tty);
  19618. +                    put_char(' ', tty);
  19619. +                    put_char('\b', tty);
  19620. +                    tty->column--;
  19621. +                }
  19622. +            }
  19623. +        }
  19624. +        if (kill_type == ERASE)
  19625. +            break;
  19626. +    }
  19627. +    if (tty->read_head == tty->canon_head)
  19628. +        finish_erasing(tty);
  19629. +}
  19630. +
  19631. +static void isig(int sig, struct tty_struct *tty)
  19632. +{
  19633. +    if (tty->pgrp > 0)
  19634. +        kill_pg(tty->pgrp, sig, 1);
  19635. +    if (!L_NOFLSH(tty)) {
  19636. +        n_tty_flush_buffer(tty);
  19637. +        if (tty->driver.flush_buffer)
  19638. +            tty->driver.flush_buffer(tty);
  19639. +    }
  19640. +}
  19641. +
  19642. +static inline void n_tty_receive_break(struct tty_struct *tty)
  19643. +{
  19644. +    if (I_IGNBRK(tty))
  19645. +        return;
  19646. +    if (I_BRKINT(tty)) {
  19647. +        isig(SIGINT, tty);
  19648. +        return;
  19649. +    }
  19650. +    if (I_PARMRK(tty)) {
  19651. +        put_tty_queue('\377', tty);
  19652. +        put_tty_queue('\0', tty);
  19653. +    }
  19654. +    put_tty_queue('\0', tty);
  19655. +    wake_up_interruptible(&tty->read_wait);
  19656. +}
  19657. +
  19658. +static inline void n_tty_receive_overrun(struct tty_struct *tty)
  19659. +{
  19660. +    char buf[64];
  19661. +
  19662. +    tty->num_overrun++;
  19663. +    if (tty->overrun_time < (jiffies - HZ)) {
  19664. +        printk("%s: %d input overrun(s)\n", _tty_name(tty, buf),
  19665. +               tty->num_overrun);
  19666. +        tty->overrun_time = jiffies;
  19667. +        tty->num_overrun = 0;
  19668. +    }
  19669. +}
  19670. +
  19671. +static inline void n_tty_receive_parity_error(struct tty_struct *tty,
  19672. +                          unsigned char c)
  19673. +{
  19674. +    if (I_IGNPAR(tty)) {
  19675. +        return;
  19676. +    }
  19677. +    if (I_PARMRK(tty)) {
  19678. +        put_tty_queue('\377', tty);
  19679. +        put_tty_queue('\0', tty);
  19680. +        put_tty_queue(c, tty);
  19681. +    } else
  19682. +        put_tty_queue('\0', tty);
  19683. +    wake_up_interruptible(&tty->read_wait);
  19684. +}
  19685. +
  19686. +static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
  19687. +{
  19688. +    if (tty->raw) {
  19689. +        put_tty_queue(c, tty);
  19690. +        return;
  19691. +    }
  19692. +
  19693. +    if (tty->stopped && I_IXON(tty) && I_IXANY(tty) && L_IEXTEN(tty)) {
  19694. +        start_tty(tty);
  19695. +        return;
  19696. +    }
  19697. +
  19698. +    if (I_ISTRIP(tty))
  19699. +        c &= 0x7f;
  19700. +    if (I_IUCLC(tty) && L_IEXTEN(tty))
  19701. +        c=tolower(c);
  19702. +
  19703. +    /*
  19704. +     * If the previous character was LNEXT, or we know that this
  19705. +     * character is not one of the characters that we'll have to
  19706. +     * handle specially, do shortcut processing to speed things
  19707. +     * up.
  19708. +     */
  19709. +    if (!test_bit(c, &tty->process_char_map) || tty->lnext) {
  19710. +        finish_erasing(tty);
  19711. +        tty->lnext = 0;
  19712. +        if (L_ECHO(tty)) {
  19713. +            if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  19714. +                put_char('\a', tty); /* beep if no space */
  19715. +                return;
  19716. +            }
  19717. +            /* Record the column of first canon char. */
  19718. +            if (tty->canon_head == tty->read_head)
  19719. +                tty->canon_column = tty->column;
  19720. +            echo_char(c, tty);
  19721. +        }
  19722. +        if (I_PARMRK(tty) && c == (unsigned char) '\377')
  19723. +            put_tty_queue(c, tty);
  19724. +        put_tty_queue(c, tty);
  19725. +        return;
  19726. +    }
  19727. +
  19728. +    if (c == '\r') {
  19729. +        if (I_IGNCR(tty))
  19730. +            return;
  19731. +        if (I_ICRNL(tty))
  19732. +            c = '\n';
  19733. +    } else if (c == '\n' && I_INLCR(tty))
  19734. +        c = '\r';
  19735. +    if (I_IXON(tty)) {
  19736. +        if (c == START_CHAR(tty)) {
  19737. +            start_tty(tty);
  19738. +            return;
  19739. +        }
  19740. +        if (c == STOP_CHAR(tty)) {
  19741. +            stop_tty(tty);
  19742. +            return;
  19743. +        }
  19744. +    }
  19745. +    if (L_ISIG(tty)) {
  19746. +        if (c == INTR_CHAR(tty)) {
  19747. +            isig(SIGINT, tty);
  19748. +            return;
  19749. +        }
  19750. +        if (c == QUIT_CHAR(tty)) {
  19751. +            isig(SIGQUIT, tty);
  19752. +            return;
  19753. +        }
  19754. +        if (c == SUSP_CHAR(tty)) {
  19755. +            if (!is_orphaned_pgrp(tty->pgrp))
  19756. +                isig(SIGTSTP, tty);
  19757. +            return;
  19758. +        }
  19759. +    }
  19760. +    if (L_ICANON(tty)) {
  19761. +        if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
  19762. +            (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
  19763. +            eraser(c, tty);
  19764. +            return;
  19765. +        }
  19766. +        if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
  19767. +            tty->lnext = 1;
  19768. +            if (L_ECHO(tty)) {
  19769. +                finish_erasing(tty);
  19770. +                if (L_ECHOCTL(tty)) {
  19771. +                    put_char('^', tty);
  19772. +                    put_char('\b', tty);
  19773. +                }
  19774. +            }
  19775. +            return;
  19776. +        }
  19777. +        if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
  19778. +            L_IEXTEN(tty)) {
  19779. +            unsigned long tail = tty->canon_head;
  19780. +
  19781. +            finish_erasing(tty);
  19782. +            echo_char(c, tty);
  19783. +            opost('\n', tty);
  19784. +            while (tail != tty->read_head) {
  19785. +                echo_char(tty->read_buf[tail], tty);
  19786. +                tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  19787. +            }
  19788. +            return;
  19789. +        }
  19790. +        if (c == '\n') {
  19791. +            if (L_ECHO(tty) || L_ECHONL(tty)) {
  19792. +                if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  19793. +                    put_char('\a', tty);
  19794. +                    return;
  19795. +                }
  19796. +                opost('\n', tty);
  19797. +            }
  19798. +            goto handle_newline;
  19799. +        }
  19800. +        if (c == EOF_CHAR(tty)) {
  19801. +                if (tty->canon_head != tty->read_head)
  19802. +                    set_bit(TTY_PUSH, &tty->flags);
  19803. +            c = __DISABLED_CHAR;
  19804. +            goto handle_newline;
  19805. +        }
  19806. +        if ((c == EOL_CHAR(tty)) ||
  19807. +            (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
  19808. +            /*
  19809. +             * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
  19810. +             */
  19811. +            if (L_ECHO(tty)) {
  19812. +                if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  19813. +                    put_char('\a', tty);
  19814. +                    return;
  19815. +                }
  19816. +                /* Record the column of first canon char. */
  19817. +                if (tty->canon_head == tty->read_head)
  19818. +                    tty->canon_column = tty->column;
  19819. +                echo_char(c, tty);
  19820. +            }
  19821. +            /*
  19822. +             * XXX does PARMRK doubling happen for
  19823. +             * EOL_CHAR and EOL2_CHAR?
  19824. +             */
  19825. +            if (I_PARMRK(tty) && c == (unsigned char) '\377')
  19826. +                put_tty_queue(c, tty);
  19827. +
  19828. +        handle_newline:
  19829. +            set_bit(tty->read_head, &tty->read_flags);
  19830. +            put_tty_queue(c, tty);
  19831. +            tty->canon_head = tty->read_head;
  19832. +            tty->canon_data++;
  19833. +            if (tty->fasync)
  19834. +                kill_fasync(tty->fasync, SIGIO);
  19835. +            if (tty->read_wait)
  19836. +                wake_up_interruptible(&tty->read_wait);
  19837. +            return;
  19838. +        }
  19839. +    }
  19840. +
  19841. +    finish_erasing(tty);
  19842. +    if (L_ECHO(tty)) {
  19843. +        if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  19844. +            put_char('\a', tty); /* beep if no space */
  19845. +            return;
  19846. +        }
  19847. +        if (c == '\n')
  19848. +            opost('\n', tty);
  19849. +        else {
  19850. +            /* Record the column of first canon char. */
  19851. +            if (tty->canon_head == tty->read_head)
  19852. +                tty->canon_column = tty->column;
  19853. +            echo_char(c, tty);
  19854. +        }
  19855. +    }
  19856. +
  19857. +    if (I_PARMRK(tty) && c == (unsigned char) '\377')
  19858. +        put_tty_queue(c, tty);
  19859. +
  19860. +    put_tty_queue(c, tty);
  19861. +}
  19862. +
  19863. +static void n_tty_receive_buf(struct tty_struct *tty, unsigned char *cp,
  19864. +                  char *fp, int count)
  19865. +{
  19866. +    unsigned char *p;
  19867. +    char *f, flags = 0;
  19868. +    int    i;
  19869. +
  19870. +    if (!tty->read_buf)
  19871. +        return;
  19872. +
  19873. +    if (tty->real_raw) {
  19874. +        i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,
  19875. +                   N_TTY_BUF_SIZE - tty->read_head));
  19876. +        memcpy(tty->read_buf + tty->read_head, cp, i);
  19877. +        tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
  19878. +        tty->read_cnt += i;
  19879. +        cp += i;
  19880. +        count -= i;
  19881. +
  19882. +        i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,
  19883. +                   N_TTY_BUF_SIZE - tty->read_head));
  19884. +        memcpy(tty->read_buf + tty->read_head, cp, i);
  19885. +        tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
  19886. +        tty->read_cnt += i;
  19887. +    } else {
  19888. +        for (i=count, p = cp, f = fp; i; i--, p++) {
  19889. +            if (f)
  19890. +                flags = *f++;
  19891. +            switch (flags) {
  19892. +            case TTY_NORMAL:
  19893. +                n_tty_receive_char(tty, *p);
  19894. +                break;
  19895. +            case TTY_BREAK:
  19896. +                n_tty_receive_break(tty);
  19897. +                break;
  19898. +            case TTY_PARITY:
  19899. +            case TTY_FRAME:
  19900. +                n_tty_receive_parity_error(tty, *p);
  19901. +                break;
  19902. +            case TTY_OVERRUN:
  19903. +                n_tty_receive_overrun(tty);
  19904. +                break;
  19905. +            default:
  19906. +                printk("%s: unknown flag %d\n", tty_name(tty),
  19907. +                       flags);
  19908. +                break;
  19909. +            }
  19910. +        }
  19911. +        if (tty->driver.flush_chars)
  19912. +            tty->driver.flush_chars(tty);
  19913. +    }
  19914. +
  19915. +    if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {
  19916. +        if (tty->fasync)
  19917. +            kill_fasync(tty->fasync, SIGIO);
  19918. +        if (tty->read_wait)
  19919. +            wake_up_interruptible(&tty->read_wait);
  19920. +    }
  19921. +
  19922. +    if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) &&
  19923. +        tty->driver.throttle &&
  19924. +        !set_bit(TTY_THROTTLED, &tty->flags))
  19925. +        tty->driver.throttle(tty);
  19926. +}
  19927. +
  19928. +static int n_tty_receive_room(struct tty_struct *tty)
  19929. +{
  19930. +    int    left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
  19931. +
  19932. +    /*
  19933. +     * If we are doing input canonicalization, let as many
  19934. +     * characters through as possible, so that the excess
  19935. +     * characters can be "beeped".
  19936. +     */
  19937. +    if (L_ICANON(tty))
  19938. +        return N_TTY_BUF_SIZE;
  19939. +
  19940. +    if (left > 0)
  19941. +        return left;
  19942. +    return 0;
  19943. +}
  19944. +
  19945. +int is_ignored(int sig)
  19946. +{
  19947. +    return ((current->blocked & (1<<(sig-1))) ||
  19948. +            (current->sigaction[sig-1].sa_handler == SIG_IGN));
  19949. +}
  19950. +
  19951. +static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
  19952. +{
  19953. +    if (!tty)
  19954. +        return;
  19955. +
  19956. +    tty->icanon = (L_ICANON(tty) != 0);
  19957. +    if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
  19958. +        I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
  19959. +        I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
  19960. +        I_PARMRK(tty)) {
  19961. +        cli();
  19962. +        memset(tty->process_char_map, 0, 256/32);
  19963. +
  19964. +        if (I_IGNCR(tty) || I_ICRNL(tty))
  19965. +            set_bit('\r', &tty->process_char_map);
  19966. +        if (I_INLCR(tty))
  19967. +            set_bit('\n', &tty->process_char_map);
  19968. +
  19969. +        if (L_ICANON(tty)) {
  19970. +            set_bit(ERASE_CHAR(tty), &tty->process_char_map);
  19971. +            set_bit(KILL_CHAR(tty), &tty->process_char_map);
  19972. +            set_bit(EOF_CHAR(tty), &tty->process_char_map);
  19973. +            set_bit('\n', &tty->process_char_map);
  19974. +            set_bit(EOL_CHAR(tty), &tty->process_char_map);
  19975. +            if (L_IEXTEN(tty)) {
  19976. +                set_bit(WERASE_CHAR(tty),
  19977. +                    &tty->process_char_map);
  19978. +                set_bit(LNEXT_CHAR(tty),
  19979. +                    &tty->process_char_map);
  19980. +                set_bit(EOL2_CHAR(tty),
  19981. +                    &tty->process_char_map);
  19982. +                if (L_ECHO(tty))
  19983. +                    set_bit(REPRINT_CHAR(tty),
  19984. +                        &tty->process_char_map);
  19985. +            }
  19986. +        }
  19987. +        if (I_IXON(tty)) {
  19988. +            set_bit(START_CHAR(tty), &tty->process_char_map);
  19989. +            set_bit(STOP_CHAR(tty), &tty->process_char_map);
  19990. +        }
  19991. +        if (L_ISIG(tty)) {
  19992. +            set_bit(INTR_CHAR(tty), &tty->process_char_map);
  19993. +            set_bit(QUIT_CHAR(tty), &tty->process_char_map);
  19994. +            set_bit(SUSP_CHAR(tty), &tty->process_char_map);
  19995. +        }
  19996. +        clear_bit(__DISABLED_CHAR, &tty->process_char_map);
  19997. +        sti();
  19998. +        tty->raw = 0;
  19999. +        tty->real_raw = 0;
  20000. +    } else {
  20001. +        tty->raw = 1;
  20002. +        if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
  20003. +            (I_IGNPAR(tty) || !I_INPCK(tty)) &&
  20004. +            (tty->driver.flags & TTY_DRIVER_REAL_RAW))
  20005. +            tty->real_raw = 1;
  20006. +        else
  20007. +            tty->real_raw = 0;
  20008. +    }
  20009. +}
  20010. +
  20011. +static void n_tty_close(struct tty_struct *tty)
  20012. +{
  20013. +    tty_wait_until_sent(tty, 0);
  20014. +    n_tty_flush_buffer(tty);
  20015. +    if (tty->read_buf) {
  20016. +        kfree_s(tty->read_buf,N_TTY_BUF_SIZE);
  20017. +        tty->read_buf = 0;
  20018. +    }
  20019. +}
  20020. +
  20021. +static int n_tty_open(struct tty_struct *tty)
  20022. +{
  20023. +    if (!tty)
  20024. +        return -EINVAL;
  20025. +
  20026. +    if (!tty->read_buf) {
  20027. +        tty->read_buf = (unsigned char *)
  20028. +            kmalloc(N_TTY_BUF_SIZE, intr_count ? GFP_ATOMIC : GFP_KERNEL);
  20029. +        if (!tty->read_buf)
  20030. +            return -ENOMEM;
  20031. +    }
  20032. +    memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
  20033. +    tty->read_head = tty->read_tail = tty->read_cnt = 0;
  20034. +    memset(tty->read_flags, 0, sizeof(tty->read_flags));
  20035. +    n_tty_set_termios(tty, 0);
  20036. +    tty->minimum_to_wake = 1;
  20037. +    return 0;
  20038. +}
  20039. +
  20040. +static inline int input_available_p(struct tty_struct *tty, int amt)
  20041. +{
  20042. +    if (L_ICANON(tty)) {
  20043. +        if (tty->canon_data)
  20044. +            return 1;
  20045. +    } else if (tty->read_cnt >= (amt ? amt : 1))
  20046. +        return 1;
  20047. +
  20048. +    return 0;
  20049. +}
  20050. +
  20051. +/*
  20052. + * Helper function to speed up read_chan.  It is only called when
  20053. + * ICANON is off; it copies characters straight from the tty queue to
  20054. + * user space directly.  It can be profitably called twice; once to
  20055. + * drain the space from the tail pointer to the (physical) end of the
  20056. + * buffer, and once to drain the space from the (physical) beginning of
  20057. + * the buffer to head pointer.
  20058. + */
  20059. +static inline void copy_from_read_buf(struct tty_struct *tty,
  20060. +                      unsigned char **b,
  20061. +                      unsigned int *nr)
  20062. +
  20063. +{
  20064. +    int    n;
  20065. +
  20066. +    n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));
  20067. +    if (!n)
  20068. +        return;
  20069. +    memcpy_tofs(*b, &tty->read_buf[tty->read_tail], n);
  20070. +    tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
  20071. +    tty->read_cnt -= n;
  20072. +    *b += n;
  20073. +    *nr -= n;
  20074. +}
  20075. +
  20076. +static int read_chan(struct tty_struct *tty, struct file *file,
  20077. +             unsigned char *buf, unsigned int nr)
  20078. +{
  20079. +    int c;
  20080. +    unsigned char *b = buf;
  20081. +    int minimum, time;
  20082. +    int retval = 0;
  20083. +    int size;
  20084. +    struct wait_queue wait = { current, NULL };
  20085. +
  20086. +do_it_again:
  20087. +
  20088. +    if (!tty->read_buf) {
  20089. +        printk("n_tty_read_chan: called with read_buf == NULL?!?\n");
  20090. +        return -EIO;
  20091. +    }
  20092. +
  20093. +    /* Job control check -- must be done at start and after
  20094. +       every sleep (POSIX.1 7.1.1.4). */
  20095. +    /* NOTE: not yet done after every sleep pending a thorough
  20096. +       check of the logic of this change. -- jlc */
  20097. +    /* don't stop on /dev/console */
  20098. +    if (file->f_inode->i_rdev != CONSOLE_DEV &&
  20099. +        current->tty == tty) {
  20100. +        if (tty->pgrp <= 0)
  20101. +            printk("read_chan: tty->pgrp <= 0!\n");
  20102. +        else if (current->pgrp != tty->pgrp) {
  20103. +            if (is_ignored(SIGTTIN) ||
  20104. +                is_orphaned_pgrp(current->pgrp))
  20105. +                return -EIO;
  20106. +printk("read_chan: suspending: tpgrp = %p, ttypgrp = %p\n",current->pgrp, tty->pgrp);
  20107. +            kill_pg(current->pgrp, SIGTTIN, 1);
  20108. +            return -ERESTARTSYS;
  20109. +        }
  20110. +    }
  20111. +
  20112. +    if (L_ICANON(tty)) {
  20113. +        minimum = time = 0;
  20114. +        current->timeout = (unsigned long) -1;
  20115. +    } else {
  20116. +        time = (HZ / 10) * TIME_CHAR(tty);
  20117. +        minimum = MIN_CHAR(tty);
  20118. +        if (minimum) {
  20119. +              current->timeout = (unsigned long) -1;
  20120. +            if (time)
  20121. +                tty->minimum_to_wake = 1;
  20122. +            else if (!tty->read_wait ||
  20123. +                 (tty->minimum_to_wake > minimum))
  20124. +                tty->minimum_to_wake = minimum;
  20125. +        } else {
  20126. +            if (time) {
  20127. +                current->timeout = time + jiffies;
  20128. +                time = 0;
  20129. +            } else
  20130. +                current->timeout = 0;
  20131. +            tty->minimum_to_wake = minimum = 1;
  20132. +        }
  20133. +    }
  20134. +
  20135. +    add_wait_queue(&tty->read_wait, &wait);
  20136. +    while (1) {
  20137. +        /* First test for status change. */
  20138. +        if (tty->packet && tty->link->ctrl_status) {
  20139. +            if (b != buf)
  20140. +                break;
  20141. +            put_fs_byte(tty->link->ctrl_status, b++);
  20142. +            tty->link->ctrl_status = 0;
  20143. +            break;
  20144. +        }
  20145. +        /* This statement must be first before checking for input
  20146. +           so that any interrupt will set the state back to
  20147. +           TASK_RUNNING. */
  20148. +        current->state = TASK_INTERRUPTIBLE;
  20149. +
  20150. +        if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
  20151. +            ((minimum - (b - buf)) >= 1))
  20152. +            tty->minimum_to_wake = (minimum - (b - buf));
  20153. +
  20154. +        if (!input_available_p(tty, 0)) {
  20155. +            if (tty->flags & (1 << TTY_SLAVE_CLOSED)) {
  20156. +                retval = -EIO;
  20157. +                break;
  20158. +            }
  20159. +            if (tty_hung_up_p(file))
  20160. +                break;
  20161. +            if (!current->timeout)
  20162. +                break;
  20163. +            if (file->f_flags & O_NONBLOCK) {
  20164. +                retval = -EAGAIN;
  20165. +                break;
  20166. +            }
  20167. +            if (current->signal & ~current->blocked) {
  20168. +                retval = -ERESTARTSYS;
  20169. +                break;
  20170. +            }
  20171. +            schedule();
  20172. +            continue;
  20173. +        }
  20174. +        current->state = TASK_RUNNING;
  20175. +
  20176. +        /* Deal with packet mode. */
  20177. +        if (tty->packet && b == buf) {
  20178. +            put_fs_byte(TIOCPKT_DATA, b++);
  20179. +            nr--;
  20180. +        }
  20181. +
  20182. +        if (L_ICANON(tty)) {
  20183. +            while (1) {
  20184. +                int eol;
  20185. +
  20186. +                disable_bh(TQUEUE_BH);
  20187. +                if (!tty->read_cnt) {
  20188. +                    enable_bh(TQUEUE_BH);
  20189. +                    break;
  20190. +                }
  20191. +                eol = clear_bit(tty->read_tail,
  20192. +                        &tty->read_flags);
  20193. +                c = tty->read_buf[tty->read_tail];
  20194. +                tty->read_tail = ((tty->read_tail+1) &
  20195. +                          (N_TTY_BUF_SIZE-1));
  20196. +                tty->read_cnt--;
  20197. +                enable_bh(TQUEUE_BH);
  20198. +                if (!eol) {
  20199. +                    put_fs_byte(c, b++);
  20200. +                    if (--nr)
  20201. +                        continue;
  20202. +                    break;
  20203. +                }
  20204. +                if (--tty->canon_data < 0) {
  20205. +                    tty->canon_data = 0;
  20206. +                }
  20207. +                if (c != __DISABLED_CHAR) {
  20208. +                    put_fs_byte(c, b++);
  20209. +                    nr--;
  20210. +                }
  20211. +                break;
  20212. +            }
  20213. +        } else {
  20214. +            disable_bh(TQUEUE_BH);
  20215. +            copy_from_read_buf(tty, &b, &nr);
  20216. +            copy_from_read_buf(tty, &b, &nr);
  20217. +            enable_bh(TQUEUE_BH);
  20218. +        }
  20219. +
  20220. +        /* If there is enough space in the read buffer now, let the
  20221. +           low-level driver know. */
  20222. +        if (tty->driver.unthrottle &&
  20223. +            (tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE)
  20224. +            && clear_bit(TTY_THROTTLED, &tty->flags))
  20225. +            tty->driver.unthrottle(tty);
  20226. +
  20227. +        if (b - buf >= minimum || !nr)
  20228. +            break;
  20229. +        if (time)
  20230. +            current->timeout = time + jiffies;
  20231. +    }
  20232. +    remove_wait_queue(&tty->read_wait, &wait);
  20233. +
  20234. +    if (!tty->read_wait)
  20235. +        tty->minimum_to_wake = minimum;
  20236. +
  20237. +    current->state = TASK_RUNNING;
  20238. +    current->timeout = 0;
  20239. +    size = b - buf;
  20240. +    if (size && nr)
  20241. +            clear_bit(TTY_PUSH, &tty->flags);
  20242. +        if (!size && clear_bit(TTY_PUSH, &tty->flags))
  20243. +                goto do_it_again;
  20244. +    if (!size && !retval)
  20245. +            clear_bit(TTY_PUSH, &tty->flags);
  20246. +        return (size ? size : retval);
  20247. +}
  20248. +
  20249. +static int write_chan(struct tty_struct * tty, struct file * file,
  20250. +              unsigned char * buf, unsigned int nr)
  20251. +{
  20252. +    int c;
  20253. +    unsigned char *b = buf;
  20254. +    int retval = 0;
  20255. +    struct wait_queue wait = { current, NULL };
  20256. +
  20257. +    /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
  20258. +    if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) {
  20259. +        retval = tty_check_change(tty);
  20260. +        if (retval)
  20261. +            return retval;
  20262. +    }
  20263. +
  20264. +    add_wait_queue(&tty->write_wait, &wait);
  20265. +    while (1) {
  20266. +        current->state = TASK_INTERRUPTIBLE;
  20267. +        if (current->signal & ~current->blocked) {
  20268. +            retval = -ERESTARTSYS;
  20269. +            break;
  20270. +        }
  20271. +        if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
  20272. +            retval = -EIO;
  20273. +            break;
  20274. +        }
  20275. +        if (O_OPOST(tty)) {
  20276. +            while (nr > 0) {
  20277. +                c = get_fs_byte(b);
  20278. +                if (opost(c, tty) < 0)
  20279. +                    break;
  20280. +                b++; nr--;
  20281. +            }
  20282. +            if (tty->driver.flush_chars)
  20283. +                tty->driver.flush_chars(tty);
  20284. +        } else {
  20285. +            c = tty->driver.write(tty, 1, b, nr);
  20286. +            b += c;
  20287. +            nr -= c;
  20288. +        }
  20289. +        if (!nr)
  20290. +            break;
  20291. +        if (file->f_flags & O_NONBLOCK) {
  20292. +            retval = -EAGAIN;
  20293. +            break;
  20294. +        }
  20295. +        schedule();
  20296. +    }
  20297. +    current->state = TASK_RUNNING;
  20298. +    remove_wait_queue(&tty->write_wait, &wait);
  20299. +    return (b - buf) ? b - buf : retval;
  20300. +}
  20301. +
  20302. +static int normal_select(struct tty_struct * tty, struct inode * inode,
  20303. +             struct file * file, int sel_type, select_table *wait)
  20304. +{
  20305. +    switch (sel_type) {
  20306. +        case SEL_IN:
  20307. +            if (input_available_p(tty, TIME_CHAR(tty) ? 0 :
  20308. +                          MIN_CHAR(tty)))
  20309. +                return 1;
  20310. +            /* fall through */
  20311. +        case SEL_EX:
  20312. +            if (tty->packet && tty->link->ctrl_status)
  20313. +                return 1;
  20314. +            if (tty->flags & (1 << TTY_SLAVE_CLOSED))
  20315. +                return 1;
  20316. +            if (tty_hung_up_p(file))
  20317. +                return 1;
  20318. +            if (!tty->read_wait) {
  20319. +                if (MIN_CHAR(tty) && !TIME_CHAR(tty))
  20320. +                    tty->minimum_to_wake = MIN_CHAR(tty);
  20321. +                else
  20322. +                    tty->minimum_to_wake = 1;
  20323. +            }
  20324. +            select_wait(&tty->read_wait, wait);
  20325. +            return 0;
  20326. +        case SEL_OUT:
  20327. +            if (tty->driver.chars_in_buffer(tty) < WAKEUP_CHARS)
  20328. +                return 1;
  20329. +            select_wait(&tty->write_wait, wait);
  20330. +            return 0;
  20331. +    }
  20332. +    return 0;
  20333. +}
  20334. +
  20335. +struct tty_ldisc tty_ldisc_N_TTY = {
  20336. +    TTY_LDISC_MAGIC,    /* magic */
  20337. +    0,            /* num */
  20338. +    0,            /* flags */
  20339. +    n_tty_open,        /* open */
  20340. +    n_tty_close,        /* close */
  20341. +    n_tty_flush_buffer,    /* flush_buffer */
  20342. +    n_tty_chars_in_buffer,    /* chars_in_buffer */
  20343. +    read_chan,        /* read */
  20344. +    write_chan,        /* write */
  20345. +    n_tty_ioctl,        /* ioctl */
  20346. +    n_tty_set_termios,    /* set_termios */
  20347. +    normal_select,        /* select */
  20348. +    n_tty_receive_buf,    /* receive_buf */
  20349. +    n_tty_receive_room,    /* receive_room */
  20350. +    0            /* write_wakeup */
  20351. +};
  20352. +
  20353. diff -r -u -N linux.orig/arch/arm/drivers/char/ptr.c linux.arm/arch/arm/drivers/char/ptr.c
  20354. --- linux.orig/arch/arm/drivers/char/ptr.c    Thu Jan  1 01:00:00 1970
  20355. +++ linux.arm/arch/arm/drivers/char/ptr.c    Fri Oct 27 23:14:20 1995
  20356. @@ -0,0 +1,210 @@
  20357. +/*
  20358. + * ptr.c
  20359. + *
  20360. + * Archimedes pointer driver
  20361. + *
  20362. + * By R.M.King
  20363. + *
  20364. + * This pointer driver provides a total of 5 possible pointers.
  20365. + *
  20366. + */
  20367. +#include <linux/errno.h>
  20368. +#include <linux/mm.h>
  20369. +
  20370. +#include <asm/segment.h>
  20371. +
  20372. +extern void vidc_write(int reg, int val);
  20373. +extern void memc_write(int reg, int val);
  20374. +
  20375. +/* Have to go into a separate file */
  20376. +#define N_PTRS 5
  20377. +
  20378. +#define ARC_MOUSE_ON        0x7A01
  20379. +#define ARC_MOUSE_OFF        0x7A02
  20380. +#define ARC_MOUSE_SETPOS    0x7A03
  20381. +#define ARC_MOUSE_SHAPE        0x7A04
  20382. +#define ARC_MOUSE_SELECT    0x7A05
  20383. +
  20384. +#define MAX_X 799
  20385. +#define MAX_Y 599
  20386. +
  20387. +struct pointer_define
  20388. +{
  20389. +  unsigned char no;
  20390. +  unsigned char x;    /* X size */
  20391. +  unsigned char y;    /* Y size */
  20392. +  unsigned char x_hot;    /* Hot spot X offset */
  20393. +  unsigned char y_hot;    /* Hot spot Y offset */
  20394. +  char ndata[1];
  20395. +};
  20396. +
  20397. +static unsigned char current_ptr=0;
  20398. +static unsigned long ptr_y=0;
  20399. +static unsigned long ptr_x=0;
  20400. +static int ptr_toupdate=0;
  20401. +static int ptr_displayed=0;
  20402. +
  20403. +static struct ptr_data
  20404. +{
  20405. +    unsigned char x_size;
  20406. +    unsigned char y_size;
  20407. +    unsigned char x_hot;
  20408. +    unsigned char y_hot;
  20409. +} data[N_PTRS];
  20410. +
  20411. +void ptr_update(void)
  20412. +{
  20413. +    long y;
  20414. +    y = ptr_y - (int)data[current_ptr].y_hot;
  20415. +    if(ptr_toupdate & 3)
  20416. +    {
  20417. +         long x,ry,ey;
  20418. +        x  = 195 + ptr_x - (int)data[current_ptr].x_hot;
  20419. +        ry = 23 + (y < 0 ? 0 : y);
  20420. +        ey = 23 + y + (int)data[current_ptr].y_size;
  20421. +
  20422. +        if(ey < 7)
  20423. +            ey=7;
  20424. +
  20425. +        vidc_write(0x98, (x  << 13));
  20426. +        vidc_write(0xB8, (ry << 14));
  20427. +        vidc_write(0xBC, (ey << 14));
  20428. +    }
  20429. +    if(ptr_toupdate & 3)
  20430. +    {
  20431. +        if(y < 0)
  20432. +            memc_write(3, (0x40100+0x300*current_ptr+8*(-y))>>2);
  20433. +        else
  20434. +            memc_write(3, (0x40100+0x300*current_ptr)>>2);
  20435. +    }
  20436. +
  20437. +    if(ptr_toupdate & 4)
  20438. +    {
  20439. +        vidc_write(0x98, 0);
  20440. +        vidc_write(0xB8, 0);
  20441. +        vidc_write(0xBC, 0x4000);
  20442. +    }
  20443. +    ptr_toupdate = 0;
  20444. +}
  20445. +
  20446. +int ptr_ioctl(struct tty_struct *tty, struct file * file,
  20447. +    unsigned int cmd, unsigned long arg)
  20448. +{
  20449. +    int i;
  20450. +    /* Check to make sure that this tty is local */
  20451. +
  20452. +    switch(cmd)
  20453. +    {
  20454. +        case ARC_MOUSE_ON:
  20455. +            ptr_displayed = 1;
  20456. +            ptr_toupdate |= 3;
  20457. +            return 0;
  20458. +
  20459. +        case ARC_MOUSE_OFF:
  20460. +            ptr_displayed = 0;
  20461. +            ptr_toupdate |= 4;
  20462. +            return 0;
  20463. +
  20464. +        case ARC_MOUSE_SETPOS:
  20465. +            i = verify_area(VERIFY_READ, (void *)arg, 8);
  20466. +            if(i)
  20467. +                return i;
  20468. +            ptr_x = get_fs_long((unsigned long *)arg);
  20469. +            ptr_y = get_fs_long(((unsigned long *)arg)+1);
  20470. +            if(ptr_x > MAX_X)
  20471. +              ptr_x = MAX_X;
  20472. +            if(ptr_y > MAX_Y)
  20473. +              ptr_y = MAX_Y;
  20474. +
  20475. +            ptr_toupdate |= ptr_displayed?3:0;
  20476. +            return 0;
  20477. +
  20478. +        case ARC_MOUSE_SHAPE:
  20479. +        {
  20480. +            struct pointer_define ptrdef;
  20481. +            int total_bytes,ptrbuf,y;
  20482. +            unsigned char ptr;
  20483. +
  20484. +            i = verify_area(VERIFY_READ, (void *)arg,
  20485. +                    sizeof(struct pointer_define)-1);
  20486. +            if (i)
  20487. +                return i;
  20488. +
  20489. +            memcpy_fromfs((void *)&ptrdef, (void *)arg,
  20490. +                sizeof(struct pointer_define)-1);
  20491. +
  20492. +            total_bytes = ptrdef.x * ptrdef.y / 4;
  20493. +            ptr = ptrdef.no;
  20494. +
  20495. +            if(total_bytes > 0x300 || ptr > 4)
  20496. +                return -EINVAL;
  20497. +            i = verify_area(VERIFY_READ,
  20498. +                (void *)(arg + sizeof(struct pointer_define)-1), total_bytes);
  20499. +            if (i)
  20500. +                return i;
  20501. +
  20502. +            /* Hmm. Or shall I switch it off, update & switch on? */
  20503. +            if(ptr == current_ptr && ptr_displayed)
  20504. +                return -EBUSY;
  20505. +
  20506. +            data[ptr].x_size = ptrdef.x;
  20507. +            data[ptr].y_size = ptrdef.y;
  20508. +            data[ptr].x_hot  = ptrdef.x_hot;
  20509. +            data[ptr].y_hot  = ptrdef.y_hot;
  20510. +
  20511. +            ptrbuf = 0x100 + 0x300 * ptr;
  20512. +            memset((void *)ptrbuf, 0, 0x300);
  20513. +
  20514. +            for(y=0; y < ptrdef.y; y++)
  20515. +            {
  20516. +                memcpy_fromfs((void *)(ptrbuf + 8 * y),
  20517. +                    (void *)(arg + 5 + y*ptrdef.x/4),
  20518. +                    ptrdef.x / 4);
  20519. +            }
  20520. +            return 0;
  20521. +                }
  20522. +        case ARC_MOUSE_SELECT:
  20523. +            if(arg > 4)
  20524. +                return -EINVAL;
  20525. +
  20526. +            current_ptr = arg;
  20527. +            ptr_toupdate |= ptr_displayed?3:0;
  20528. +            return 0;
  20529. +    }
  20530. +    return -EINVAL;
  20531. +}
  20532. +
  20533. +void ptr_concontrol(int on_off, unsigned int pos)
  20534. +{
  20535. +  if(on_off)
  20536. +  {
  20537. +    if(!ptr_displayed)
  20538. +    {
  20539. +      int i;
  20540. +      current_ptr = 0;
  20541. +      ptr_displayed = 1;
  20542. +      data[0].x_size = 4;
  20543. +      data[0].y_size = 8;
  20544. +      data[0].x_hot  = 0;
  20545. +      data[0].y_hot  = 0;
  20546. +      for(i = 0x100; i < 0x300; i++)
  20547. +        *(unsigned char *)i=0x55 << (i & 1);
  20548. +    }
  20549. +
  20550. +    ptr_x = pos % (MAX_X+1);
  20551. +    ptr_y = pos / (MAX_X+1);
  20552. +
  20553. +    if(ptr_y > MAX_Y)
  20554. +      ptr_y = MAX_Y;
  20555. +
  20556. +    ptr_toupdate |= 3;
  20557. +  }
  20558. +  else
  20559. +  {
  20560. +    if(ptr_displayed)
  20561. +    {
  20562. +      ptr_displayed = 0;
  20563. +      ptr_toupdate |= 4;
  20564. +    }
  20565. +  }
  20566. +}
  20567. diff -r -u -N linux.orig/arch/arm/drivers/char/pty.c linux.arm/arch/arm/drivers/char/pty.c
  20568. --- linux.orig/arch/arm/drivers/char/pty.c    Thu Jan  1 01:00:00 1970
  20569. +++ linux.arm/arch/arm/drivers/char/pty.c    Fri Oct 27 23:14:25 1995
  20570. @@ -0,0 +1,262 @@
  20571. +/*
  20572. + *  linux/drivers/char/pty.c
  20573. + *
  20574. + *  Copyright (C) 1991, 1992  Linus Torvalds
  20575. + */
  20576. +
  20577. +/*
  20578. + *    pty.c
  20579. + *
  20580. + * This module exports the following pty function:
  20581. + *
  20582. + *     int  pty_open(struct tty_struct * tty, struct file * filp);
  20583. + */
  20584. +
  20585. +#include <linux/errno.h>
  20586. +#include <linux/sched.h>
  20587. +#include <linux/interrupt.h>
  20588. +#include <linux/tty.h>
  20589. +#include <linux/tty_flip.h>
  20590. +#include <linux/fcntl.h>
  20591. +#include <linux/string.h>
  20592. +#include <linux/major.h>
  20593. +#include <linux/mm.h>
  20594. +
  20595. +#include <asm/segment.h>
  20596. +#include <asm/system.h>
  20597. +#include <asm/bitops.h>
  20598. +
  20599. +struct pty_struct {
  20600. +    int    magic;
  20601. +    struct wait_queue * open_wait;
  20602. +};
  20603. +
  20604. +#define PTY_MAGIC 0x5001
  20605. +#define PTY_BUF_SIZE 4096/2
  20606. +/*
  20607. + * tmp_buf is used as a temporary buffer by pty_write.  We need to
  20608. + * lock it in case the memcpy_fromfs blocks while swapping in a page,
  20609. + * and some other program tries to do a pty write at the same time.
  20610. + * Since the lock will only come under contention when the system is
  20611. + * swapping and available memory is low, it makes sense to share one
  20612. + * buffer across all the PTY's, since it significantly saves memory if
  20613. + * large numbers of PTY's are open.
  20614. + */
  20615. +static unsigned char *tmp_buf;
  20616. +static struct semaphore tmp_buf_sem = MUTEX;
  20617. +
  20618. +struct tty_driver pty_driver, pty_slave_driver;
  20619. +static int pty_refcount;
  20620. +
  20621. +static struct tty_struct *pty_table[NR_PTYS];
  20622. +static struct termios *pty_termios[NR_PTYS];
  20623. +static struct termios *pty_termios_locked[NR_PTYS];
  20624. +static struct tty_struct *ttyp_table[NR_PTYS];
  20625. +static struct termios *ttyp_termios[NR_PTYS];
  20626. +static struct termios *ttyp_termios_locked[NR_PTYS];
  20627. +static struct pty_struct pty_state[NR_PTYS];
  20628. +
  20629. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  20630. +
  20631. +static void pty_close(struct tty_struct * tty, struct file * filp)
  20632. +{
  20633. +    if (!tty)
  20634. +        return;
  20635. +    if (tty->driver.subtype == PTY_TYPE_MASTER) {
  20636. +        if (tty->count > 1)
  20637. +            printk("master pty_close: count = %d!!\n", tty->count);
  20638. +    } else {
  20639. +        if (tty->count > 2)
  20640. +            return;
  20641. +    }
  20642. +    wake_up_interruptible(&tty->read_wait);
  20643. +    wake_up_interruptible(&tty->write_wait);
  20644. +    if (!tty->link)
  20645. +        return;
  20646. +    wake_up_interruptible(&tty->link->read_wait);
  20647. +    wake_up_interruptible(&tty->link->write_wait);
  20648. +    if (tty->driver.subtype == PTY_TYPE_MASTER)
  20649. +        tty_hangup(tty->link);
  20650. +    else {
  20651. +        start_tty(tty);
  20652. +        set_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
  20653. +    }
  20654. +}
  20655. +
  20656. +/*
  20657. + * The unthrottle routine is called by the line discipline to signal
  20658. + * that it can receive more characters.  For PTY's, the TTY_THROTTLED
  20659. + * flag is always set, to force the line discipline to always call the
  20660. + * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
  20661. + * characters in the queue.  This is necessary since each time this
  20662. + * happens, we need to wake up any sleeping processes that could be
  20663. + * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
  20664. + * for the pty buffer to be drained.
  20665. + */
  20666. +static void pty_unthrottle(struct tty_struct * tty)
  20667. +{
  20668. +    struct tty_struct *o_tty = tty->link;
  20669. +
  20670. +    if (!o_tty)
  20671. +        return;
  20672. +
  20673. +    if ((o_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  20674. +        o_tty->ldisc.write_wakeup)
  20675. +        (o_tty->ldisc.write_wakeup)(o_tty);
  20676. +    wake_up_interruptible(&o_tty->write_wait);
  20677. +    set_bit(TTY_THROTTLED, &tty->flags);
  20678. +}
  20679. +
  20680. +static int pty_write(struct tty_struct * tty, int from_user,
  20681. +               unsigned char *buf, int count)
  20682. +{
  20683. +    struct tty_struct *to = tty->link;
  20684. +    int    c=0, n, r;
  20685. +    char    *temp_buffer;
  20686. +
  20687. +    if (!to || tty->stopped)
  20688. +        return 0;
  20689. +
  20690. +    if (from_user) {
  20691. +        down(&tmp_buf_sem);
  20692. +        temp_buffer = tmp_buf +
  20693. +            ((tty->driver.subtype-1) * PTY_BUF_SIZE);
  20694. +        while (count > 0) {
  20695. +            n = MIN(count, PTY_BUF_SIZE);
  20696. +            memcpy_fromfs(temp_buffer, buf, n);
  20697. +            r = to->ldisc.receive_room(to);
  20698. +            if (r <= 0)
  20699. +                break;
  20700. +            n = MIN(n, r);
  20701. +            to->ldisc.receive_buf(to, temp_buffer, 0, n);
  20702. +            buf += n;  c+= n;
  20703. +            count -= n;
  20704. +        }
  20705. +        up(&tmp_buf_sem);
  20706. +    } else {
  20707. +        c = MIN(count, to->ldisc.receive_room(to));
  20708. +        to->ldisc.receive_buf(to, buf, 0, c);
  20709. +    }
  20710. +
  20711. +    return c;
  20712. +}
  20713. +
  20714. +static int pty_write_room(struct tty_struct *tty)
  20715. +{
  20716. +    struct tty_struct *to = tty->link;
  20717. +
  20718. +    if (!to || tty->stopped)
  20719. +        return 0;
  20720. +
  20721. +    return to->ldisc.receive_room(to);
  20722. +}
  20723. +
  20724. +static int pty_chars_in_buffer(struct tty_struct *tty)
  20725. +{
  20726. +    struct tty_struct *to = tty->link;
  20727. +
  20728. +    if (!to || !to->ldisc.chars_in_buffer)
  20729. +        return 0;
  20730. +
  20731. +    return to->ldisc.chars_in_buffer(to);
  20732. +}
  20733. +
  20734. +static void pty_flush_buffer(struct tty_struct *tty)
  20735. +{
  20736. +    struct tty_struct *to = tty->link;
  20737. +
  20738. +    if (!to)
  20739. +        return;
  20740. +
  20741. +    if (to->ldisc.flush_buffer)
  20742. +        to->ldisc.flush_buffer(to);
  20743. +
  20744. +    if (to->packet) {
  20745. +        tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
  20746. +        wake_up_interruptible(&to->read_wait);
  20747. +    }
  20748. +}
  20749. +
  20750. +int pty_open(struct tty_struct *tty, struct file * filp)
  20751. +{
  20752. +    int    line;
  20753. +    struct    pty_struct *pty;
  20754. +
  20755. +    if (!tty || !tty->link)
  20756. +        return -ENODEV;
  20757. +    line = MINOR(tty->device) - tty->driver.minor_start;
  20758. +    if ((line < 0) || (line >= NR_PTYS))
  20759. +        return -ENODEV;
  20760. +    pty = pty_state + line;
  20761. +    tty->driver_data = pty;
  20762. +
  20763. +    if (!tmp_buf) {
  20764. +        tmp_buf = (unsigned char *) kmalloc(PTY_BUF_SIZE*2,GFP_KERNEL);
  20765. +        if (!tmp_buf)
  20766. +            return -ENOMEM;
  20767. +    }
  20768. +
  20769. +    if (tty->driver.subtype == PTY_TYPE_SLAVE)
  20770. +        clear_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
  20771. +    wake_up_interruptible(&pty->open_wait);
  20772. +    set_bit(TTY_THROTTLED, &tty->flags);
  20773. +    if (filp->f_flags & O_NDELAY)
  20774. +        return 0;
  20775. +    while (!tty->link->count && !(current->signal & ~current->blocked))
  20776. +        interruptible_sleep_on(&pty->open_wait);
  20777. +    if (!tty->link->count)
  20778. +        return -ERESTARTSYS;
  20779. +    return 0;
  20780. +}
  20781. +
  20782. +long pty_init(long kmem_start)
  20783. +{
  20784. +    memset(&pty_state, 0, sizeof(pty_state));
  20785. +    memset(&pty_driver, 0, sizeof(struct tty_driver));
  20786. +    pty_driver.magic = TTY_DRIVER_MAGIC;
  20787. +    pty_driver.name = "pty";
  20788. +    pty_driver.major = TTY_MAJOR;
  20789. +    pty_driver.minor_start = 128;
  20790. +    pty_driver.num = NR_PTYS;
  20791. +    pty_driver.type = TTY_DRIVER_TYPE_PTY;
  20792. +    pty_driver.subtype = PTY_TYPE_MASTER;
  20793. +    pty_driver.init_termios = tty_std_termios;
  20794. +    pty_driver.init_termios.c_iflag = 0;
  20795. +    pty_driver.init_termios.c_oflag = 0;
  20796. +    pty_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
  20797. +    pty_driver.init_termios.c_lflag = 0;
  20798. +    pty_driver.flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
  20799. +    pty_driver.refcount = &pty_refcount;
  20800. +    pty_driver.table = pty_table;
  20801. +    pty_driver.termios = pty_termios;
  20802. +    pty_driver.termios_locked = pty_termios_locked;
  20803. +    pty_driver.other = &pty_slave_driver;
  20804. +
  20805. +    pty_driver.open = pty_open;
  20806. +    pty_driver.close = pty_close;
  20807. +    pty_driver.write = pty_write;
  20808. +    pty_driver.write_room = pty_write_room;
  20809. +    pty_driver.flush_buffer = pty_flush_buffer;
  20810. +    pty_driver.chars_in_buffer = pty_chars_in_buffer;
  20811. +    pty_driver.unthrottle = pty_unthrottle;
  20812. +
  20813. +    pty_slave_driver = pty_driver;
  20814. +    pty_slave_driver.name = "ttyp";
  20815. +    pty_slave_driver.subtype = PTY_TYPE_SLAVE;
  20816. +    pty_slave_driver.minor_start = 192;
  20817. +    pty_slave_driver.init_termios = tty_std_termios;
  20818. +    pty_slave_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
  20819. +    pty_slave_driver.table = ttyp_table;
  20820. +    pty_slave_driver.termios = ttyp_termios;
  20821. +    pty_slave_driver.termios_locked = ttyp_termios_locked;
  20822. +    pty_slave_driver.other = &pty_driver;
  20823. +
  20824. +    tmp_buf = 0;
  20825. +
  20826. +    if (tty_register_driver(&pty_driver))
  20827. +        panic("Couldn't register pty driver");
  20828. +    if (tty_register_driver(&pty_slave_driver))
  20829. +        panic("Couldn't register pty slave driver");
  20830. +
  20831. +    return kmem_start;
  20832. +}
  20833. diff -r -u -N linux.orig/arch/arm/drivers/char/serial.c linux.arm/arch/arm/drivers/char/serial.c
  20834. --- linux.orig/arch/arm/drivers/char/serial.c    Thu Jan  1 01:00:00 1970
  20835. +++ linux.arm/arch/arm/drivers/char/serial.c    Fri Oct 27 23:14:26 1995
  20836. @@ -0,0 +1,2691 @@
  20837. +/*
  20838. + *  linux/arch/arm/drivers/char/serial.c
  20839. + *
  20840. + *  Copyright (C) 1991, 1992  Linus Torvalds
  20841. + *
  20842. + *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
  20843. + *  much more extensible to support other serial cards based on the
  20844. + *  16450/16550A UART's.  Added support for the AST FourPort and the
  20845. + *  Accent Async board.  
  20846. + *
  20847. + *  set_serial_info fixed to set the flags, custom divisor, and uart
  20848. + *     type fields.  Fix suggested by Michael K. Johnson 12/12/92.
  20849. + *
  20850. + * This module exports the following rs232 io functions:
  20851. + *
  20852. + *    long rs_init(long);
  20853. + *     int  rs_open(struct tty_struct * tty, struct file * filp)
  20854. + *
  20855. + *  Slight modifications for ARM
  20856. + */
  20857. +
  20858. +#include <linux/errno.h>
  20859. +#include <linux/signal.h>
  20860. +#include <linux/sched.h>
  20861. +#include <linux/timer.h>
  20862. +#include <linux/interrupt.h>
  20863. +#include <linux/tty.h>
  20864. +#include <linux/tty_flip.h>
  20865. +#include <linux/serial.h>
  20866. +#include <linux/serial_reg.h>
  20867. +#include <linux/config.h>
  20868. +#include <linux/major.h>
  20869. +#include <linux/string.h>
  20870. +#include <linux/fcntl.h>
  20871. +#include <linux/ptrace.h>
  20872. +#include <linux/major.h>
  20873. +#include <linux/ioport.h>
  20874. +#include <linux/mm.h>
  20875. +
  20876. +#include <asm/system.h>
  20877. +#include <asm/io.h>
  20878. +#include <asm/segment.h>
  20879. +#include <asm/bitops.h>
  20880. +
  20881. +DECLARE_TASK_QUEUE(tq_serial);
  20882. +
  20883. +struct tty_driver serial_driver, callout_driver;
  20884. +static int serial_refcount;
  20885. +
  20886. +/* serial subtype definitions */
  20887. +#define SERIAL_TYPE_NORMAL    1
  20888. +#define SERIAL_TYPE_CALLOUT    2
  20889. +
  20890. +/* number of characters left in xmit buffer before we ask for more */
  20891. +#define WAKEUP_CHARS 256
  20892. +
  20893. +/*
  20894. + * Serial driver configuration section.  Here are the various options:
  20895. + *
  20896. + * CONFIG_HUB6
  20897. + *        Enables support for the venerable Bell Technologies
  20898. + *        HUB6 card.
  20899. + *
  20900. + * SERIAL_PARANOIA_CHECK
  20901. + *         Check the magic number for the async_structure where
  20902. + *         ever possible.
  20903. + */
  20904. +
  20905. +#define SERIAL_PARANOIA_CHECK
  20906. +#define CONFIG_SERIAL_NOPAUSE_IO
  20907. +#define SERIAL_DO_RESTART
  20908. +
  20909. +#undef SERIAL_DEBUG_INTR
  20910. +#undef SERIAL_DEBUG_OPEN
  20911. +#undef SERIAL_DEBUG_FLOW
  20912. +
  20913. +#define RS_STROBE_TIME 10
  20914. +#define RS_ISR_PASS_LIMIT 256
  20915. +
  20916. +#define _INLINE_ inline
  20917. +  
  20918. +/*
  20919. + * IRQ_timeout        - How long the timeout should be for each IRQ
  20920. + *                 should be after the IRQ has been active.
  20921. + */
  20922. +
  20923. +static struct async_struct *IRQ_ports[16];
  20924. +static struct rs_multiport_struct rs_multiport[16];
  20925. +static int IRQ_timeout[16];
  20926. +static volatile int rs_irq_triggered;
  20927. +static volatile int rs_triggered;
  20928. +static int rs_wild_int_mask;
  20929. +
  20930. +static void autoconfig(struct async_struct * info);
  20931. +static void change_speed(struct async_struct *info);
  20932. +    
  20933. +/*
  20934. + * This assumes you have a 1.8432 MHz clock for your UART.
  20935. + *
  20936. + * It'd be nice if someone built a serial card with a 24.576 MHz
  20937. + * clock, since the 16550A is capable of handling a top speed of 1.5
  20938. + * megabits/second; but this requires the faster clock.
  20939. + */
  20940. +#define BASE_BAUD ( 1843200 / 16 )
  20941. +
  20942. +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST )
  20943. +
  20944. +struct async_struct rs_table[] = {
  20945. +    /* UART CLK   PORT IRQ     FLAGS        */
  20946. +    { 0, BASE_BAUD, 0x3F8,10, STD_COM_FLAGS },    /* ttyS0 */
  20947. +    { 0, BASE_BAUD, 0x2F8,10, STD_COM_FLAGS },    /* ttyS1 */
  20948. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS2 */
  20949. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS3 */
  20950. +
  20951. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },     /* ttyS4 */
  20952. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS5 */
  20953. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS6 */
  20954. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS7 */
  20955. +
  20956. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS8 */
  20957. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS9 */
  20958. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS10 */
  20959. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS11 */
  20960. +    
  20961. +};
  20962. +
  20963. +#define NR_PORTS    (sizeof(rs_table)/sizeof(struct async_struct))
  20964. +
  20965. +static struct tty_struct *serial_table[NR_PORTS];
  20966. +static struct termios *serial_termios[NR_PORTS];
  20967. +static struct termios *serial_termios_locked[NR_PORTS];
  20968. +
  20969. +#ifndef MIN
  20970. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  20971. +#endif
  20972. +
  20973. +/*
  20974. + * tmp_buf is used as a temporary buffer by serial_write.  We need to
  20975. + * lock it in case the memcpy_fromfs blocks while swapping in a page,
  20976. + * and some other program tries to do a serial write at the same time.
  20977. + * Since the lock will only come under contention when the system is
  20978. + * swapping and available memory is low, it makes sense to share one
  20979. + * buffer across all the serial ports, since it significantly saves
  20980. + * memory if large numbers of serial ports are open.
  20981. + */
  20982. +static unsigned char *tmp_buf = 0;
  20983. +static struct semaphore tmp_buf_sem = MUTEX;
  20984. +
  20985. +static inline int serial_paranoia_check(struct async_struct *info,
  20986. +                    dev_t device, const char *routine)
  20987. +{
  20988. +#ifdef SERIAL_PARANOIA_CHECK
  20989. +    static const char *badmagic =
  20990. +        "Warning: bad magic number for serial struct (%d, %d) in %s\n";
  20991. +    static const char *badinfo =
  20992. +        "Warning: null async_struct for (%d, %d) in %s\n";
  20993. +
  20994. +    if (!info) {
  20995. +        printk(badinfo, MAJOR(device), MINOR(device), routine);
  20996. +        return 1;
  20997. +    }
  20998. +    if (info->magic != SERIAL_MAGIC) {
  20999. +        printk(badmagic, MAJOR(device), MINOR(device), routine);
  21000. +        return 1;
  21001. +    }
  21002. +#endif
  21003. +    return 0;
  21004. +}
  21005. +
  21006. +/*
  21007. + * This is used to figure out the divisor speeds and the timeouts
  21008. + */
  21009. +static int baud_table[] = {
  21010. +    0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
  21011. +    9600, 19200, 38400, 57600, 115200, 0 };
  21012. +
  21013. +static inline unsigned int serial_in(struct async_struct *info, int offset)
  21014. +{
  21015. +#ifdef CONFIG_HUB6
  21016. +    if (info->hub6) {
  21017. +    outb(info->hub6 - 1 + offset, info->port);
  21018. +    return inb(info->port+1);
  21019. +    } else
  21020. +#endif
  21021. +    return inb(info->port + offset);
  21022. +}
  21023. +
  21024. +static inline unsigned int serial_inp(struct async_struct *info, int offset)
  21025. +{
  21026. +#ifdef CONFIG_HUB6
  21027. +    if (info->hub6) {
  21028. +    outb(info->hub6 - 1 + offset, info->port);
  21029. +    return inb_p(info->port+1);
  21030. +    } else
  21031. +#endif
  21032. +#ifdef CONFIG_SERIAL_NOPAUSE_IO
  21033. +    return inb(info->port + offset);
  21034. +#else
  21035. +    return inb_p(info->port + offset);
  21036. +#endif
  21037. +}
  21038. +
  21039. +static inline void serial_out(struct async_struct *info, int offset, int value)
  21040. +{
  21041. +#ifdef CONFIG_HUB6
  21042. +    if (info->hub6) {
  21043. +    outb(info->hub6 - 1 + offset, info->port);
  21044. +    outb(value, info->port+1);
  21045. +    } else
  21046. +#endif
  21047. +    outb(value, info->port+offset);
  21048. +}
  21049. +
  21050. +static inline void serial_outp(struct async_struct *info, int offset,
  21051. +                   int value)
  21052. +{
  21053. +#ifdef CONFIG_HUB6
  21054. +    if (info->hub6) {
  21055. +    outb(info->hub6 - 1 + offset, info->port);
  21056. +    outb_p(value, info->port+1);
  21057. +    } else
  21058. +#endif
  21059. +#ifdef CONFIG_SERIAL_NOPAUSE_IO
  21060. +    outb(value, info->port+offset);
  21061. +#else
  21062. +        outb_p(value, info->port+offset);
  21063. +#endif
  21064. +}
  21065. +
  21066. +/*
  21067. + * ------------------------------------------------------------
  21068. + * rs_stop() and rs_start()
  21069. + *
  21070. + * This routines are called before setting or resetting tty->stopped.
  21071. + * They enable or disable transmitter interrupts, as necessary.
  21072. + * ------------------------------------------------------------
  21073. + */
  21074. +static void rs_stop(struct tty_struct *tty)
  21075. +{
  21076. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  21077. +    unsigned long flags;
  21078. +
  21079. +    if (serial_paranoia_check(info, tty->device, "rs_stop"))
  21080. +        return;
  21081. +    
  21082. +    save_flags(flags); cli();
  21083. +    if (info->IER & UART_IER_THRI) {
  21084. +        info->IER &= ~UART_IER_THRI;
  21085. +        serial_out(info, UART_IER, info->IER);
  21086. +    }
  21087. +    restore_flags(flags);
  21088. +}
  21089. +
  21090. +static void rs_start(struct tty_struct *tty)
  21091. +{
  21092. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  21093. +    unsigned long flags;
  21094. +    
  21095. +    if (serial_paranoia_check(info, tty->device, "rs_start"))
  21096. +        return;
  21097. +    
  21098. +    save_flags(flags); cli();
  21099. +    if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
  21100. +        info->IER |= UART_IER_THRI;
  21101. +        serial_out(info, UART_IER, info->IER);
  21102. +    }
  21103. +    restore_flags(flags);
  21104. +}
  21105. +
  21106. +/*
  21107. + * ----------------------------------------------------------------------
  21108. + *
  21109. + * Here starts the interrupt handling routines.  All of the following
  21110. + * subroutines are declared as inline and are folded into
  21111. + * rs_interrupt().  They were separated out for readability's sake.
  21112. + *
  21113. + * Note: rs_interrupt() is a "fast" interrupt, which means that it
  21114. + * runs with interrupts turned off.  People who may want to modify
  21115. + * rs_interrupt() should try to keep the interrupt handler as fast as
  21116. + * possible.  After you are done making modifications, it is not a bad
  21117. + * idea to do:
  21118. + * 
  21119. + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
  21120. + *
  21121. + * and look at the resulting assemble code in serial.s.
  21122. + *
  21123. + *                 - Ted Ts'o (tytso@mit.edu), 7-Mar-93
  21124. + * -----------------------------------------------------------------------
  21125. + */
  21126. +
  21127. +/*
  21128. + * This is the serial driver's interrupt routine while we are probing
  21129. + * for submarines.
  21130. + */
  21131. +static void rs_probe(int irq, struct pt_regs * regs)
  21132. +{
  21133. +    rs_irq_triggered = irq;
  21134. +    rs_triggered |= 1 << irq;
  21135. +    return;
  21136. +}
  21137. +
  21138. +/*
  21139. + * This routine is used by the interrupt handler to schedule
  21140. + * processing in the software interrupt portion of the driver.
  21141. + */
  21142. +static _INLINE_ void rs_sched_event(struct async_struct *info,
  21143. +                  int event)
  21144. +{
  21145. +    info->event |= 1 << event;
  21146. +    queue_task_irq_off(&info->tqueue, &tq_serial);
  21147. +    mark_bh(SERIAL_BH);
  21148. +}
  21149. +
  21150. +static _INLINE_ void receive_chars(struct async_struct *info,
  21151. +                 int *status)
  21152. +{
  21153. +    struct tty_struct *tty = info->tty;
  21154. +    unsigned char ch;
  21155. +    int ignored = 0;
  21156. +
  21157. +    do {
  21158. +        ch = serial_inp(info, UART_RX);
  21159. +        if (*status & info->ignore_status_mask) {
  21160. +            if (++ignored > 100)
  21161. +                break;
  21162. +            goto ignore_char;
  21163. +        }
  21164. +        if (tty->flip.count >= TTY_FLIPBUF_SIZE)
  21165. +            break;
  21166. +        tty->flip.count++;
  21167. +        if (*status & (UART_LSR_BI)) {
  21168. +            printk("handling break....");
  21169. +            *tty->flip.flag_buf_ptr++ = TTY_BREAK;
  21170. +            if (info->flags & ASYNC_SAK)
  21171. +                do_SAK(tty);
  21172. +        } else if (*status & UART_LSR_PE)
  21173. +            *tty->flip.flag_buf_ptr++ = TTY_PARITY;
  21174. +        else if (*status & UART_LSR_FE)
  21175. +            *tty->flip.flag_buf_ptr++ = TTY_FRAME;
  21176. +        else if (*status & UART_LSR_OE) 
  21177. +            *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
  21178. +        else
  21179. +            *tty->flip.flag_buf_ptr++ = 0;
  21180. +        *tty->flip.char_buf_ptr++ = ch;
  21181. +    ignore_char:
  21182. +        *status = serial_inp(info, UART_LSR) & info->read_status_mask;
  21183. +    } while (*status & UART_LSR_DR);
  21184. +    queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
  21185. +#ifdef SERIAL_DEBUG_INTR
  21186. +    printk("DR...");
  21187. +#endif
  21188. +}
  21189. +
  21190. +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
  21191. +{
  21192. +    int count;
  21193. +    
  21194. +    if (info->x_char) {
  21195. +        serial_outp(info, UART_TX, info->x_char);
  21196. +        info->x_char = 0;
  21197. +        if (intr_done)
  21198. +            *intr_done = 0;
  21199. +        return;
  21200. +    }
  21201. +    if ((info->xmit_cnt <= 0) || info->tty->stopped ||
  21202. +        info->tty->hw_stopped) {
  21203. +        info->IER &= ~UART_IER_THRI;
  21204. +        serial_out(info, UART_IER, info->IER);
  21205. +        return;
  21206. +    }
  21207. +    
  21208. +    count = info->xmit_fifo_size;
  21209. +    do {
  21210. +        serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
  21211. +        info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
  21212. +        if (--info->xmit_cnt <= 0)
  21213. +            break;
  21214. +    } while (--count > 0);
  21215. +    
  21216. +    if (info->xmit_cnt < WAKEUP_CHARS)
  21217. +        rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
  21218. +
  21219. +#ifdef SERIAL_DEBUG_INTR
  21220. +    printk("THRE...");
  21221. +#endif
  21222. +    if (intr_done)
  21223. +        *intr_done = 0;
  21224. +
  21225. +    if (info->xmit_cnt <= 0) {
  21226. +        info->IER &= ~UART_IER_THRI;
  21227. +        serial_out(info, UART_IER, info->IER);
  21228. +    }
  21229. +}
  21230. +
  21231. +static _INLINE_ void check_modem_status(struct async_struct *info)
  21232. +{
  21233. +    int    status;
  21234. +    
  21235. +    status = serial_in(info, UART_MSR);
  21236. +
  21237. +    if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
  21238. +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
  21239. +        printk("ttys%d CD now %s...", info->line,
  21240. +               (status & UART_MSR_DCD) ? "on" : "off");
  21241. +#endif        
  21242. +        if (status & UART_MSR_DCD)
  21243. +            wake_up_interruptible(&info->open_wait);
  21244. +        else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  21245. +               (info->flags & ASYNC_CALLOUT_NOHUP))) {
  21246. +#ifdef SERIAL_DEBUG_OPEN
  21247. +            printk("scheduling hangup...");
  21248. +#endif
  21249. +            queue_task_irq_off(&info->tqueue_hangup,
  21250. +                       &tq_scheduler);
  21251. +        }
  21252. +    }
  21253. +    if (info->flags & ASYNC_CTS_FLOW) {
  21254. +        if (info->tty->hw_stopped) {
  21255. +            if (status & UART_MSR_CTS) {
  21256. +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
  21257. +                printk("CTS tx start...");
  21258. +#endif
  21259. +                info->tty->hw_stopped = 0;
  21260. +                info->IER |= UART_IER_THRI;
  21261. +                serial_out(info, UART_IER, info->IER);
  21262. +                rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
  21263. +                return;
  21264. +            }
  21265. +        } else {
  21266. +            if (!(status & UART_MSR_CTS)) {
  21267. +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
  21268. +                printk("CTS tx stop...");
  21269. +#endif
  21270. +                info->tty->hw_stopped = 1;
  21271. +                info->IER &= ~UART_IER_THRI;
  21272. +                serial_out(info, UART_IER, info->IER);
  21273. +            }
  21274. +        }
  21275. +    }
  21276. +}
  21277. +
  21278. +/*
  21279. + * This is the serial driver's generic interrupt routine
  21280. + */
  21281. +static void rs_interrupt(int irq, struct pt_regs * regs)
  21282. +{
  21283. +    int status;
  21284. +    struct async_struct * info;
  21285. +    int pass_counter = 0;
  21286. +    struct async_struct *end_mark = 0;
  21287. +    int first_multi = 0;
  21288. +    struct rs_multiport_struct *multi;
  21289. +
  21290. +#ifdef SERIAL_DEBUG_INTR
  21291. +    printk("rs_interrupt(%d)...", irq);
  21292. +#endif
  21293. +    
  21294. +    info = IRQ_ports[irq];
  21295. +    if (!info)
  21296. +        return;
  21297. +    
  21298. +    multi = &rs_multiport[irq];
  21299. +    if (multi->port_monitor)
  21300. +        first_multi = inb(multi->port_monitor);
  21301. +
  21302. +    do {
  21303. +        if (!info->tty ||
  21304. +            (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
  21305. +            if (!end_mark)
  21306. +                end_mark = info;
  21307. +            goto next;
  21308. +        }
  21309. +        end_mark = 0;
  21310. +
  21311. +        info->last_active = jiffies;
  21312. +
  21313. +        status = serial_inp(info, UART_LSR) & info->read_status_mask;
  21314. +#ifdef SERIAL_DEBUG_INTR
  21315. +        printk("status = %x...", status);
  21316. +#endif
  21317. +        if (status & UART_LSR_DR)
  21318. +            receive_chars(info, &status);
  21319. +        check_modem_status(info);
  21320. +        if (status & UART_LSR_THRE)
  21321. +            transmit_chars(info, 0);
  21322. +
  21323. +    next:
  21324. +        info = info->next_port;
  21325. +        if (!info) {
  21326. +            info = IRQ_ports[irq];
  21327. +            if (pass_counter++ > RS_ISR_PASS_LIMIT) {
  21328. +#if 0
  21329. +                printk("rs loop break\n");
  21330. +#endif
  21331. +                break;     /* Prevent infinite loops */
  21332. +            }
  21333. +            continue;
  21334. +        }
  21335. +    } while (end_mark != info);
  21336. +    if (multi->port_monitor)
  21337. +        printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
  21338. +               info->irq, first_multi, inb(multi->port_monitor));
  21339. +#ifdef SERIAL_DEBUG_INTR
  21340. +    printk("end.\n");
  21341. +#endif
  21342. +}
  21343. +
  21344. +/*
  21345. + * This is the serial driver's interrupt routine for a single port
  21346. + */
  21347. +static void rs_interrupt_single(int irq, struct pt_regs * regs)
  21348. +{
  21349. +    int status;
  21350. +    int pass_counter = 0;
  21351. +    int first_multi = 0;
  21352. +    struct async_struct * info;
  21353. +    struct rs_multiport_struct *multi;
  21354. +    
  21355. +#ifdef SERIAL_DEBUG_INTR
  21356. +    printk("rs_interrupt_single(%d)...", irq);
  21357. +#endif
  21358. +    
  21359. +    info = IRQ_ports[irq];
  21360. +    if (!info || !info->tty)
  21361. +        return;
  21362. +
  21363. +    multi = &rs_multiport[irq];
  21364. +    if (multi->port_monitor)
  21365. +        first_multi = inb(multi->port_monitor);
  21366. +
  21367. +    do {
  21368. +        status = serial_inp(info, UART_LSR) & info->read_status_mask;
  21369. +#ifdef SERIAL_DEBUG_INTR
  21370. +        printk("status = %x...", status);
  21371. +#endif
  21372. +        if (status & UART_LSR_DR)
  21373. +            receive_chars(info, &status);
  21374. +        check_modem_status(info);
  21375. +        if (status & UART_LSR_THRE)
  21376. +            transmit_chars(info, 0);
  21377. +        if (pass_counter++ > RS_ISR_PASS_LIMIT) {
  21378. +#if 0
  21379. +            printk("rs_single loop break.\n");
  21380. +#endif
  21381. +            break;
  21382. +        }
  21383. +    } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
  21384. +    info->last_active = jiffies;
  21385. +    if (multi->port_monitor)
  21386. +        printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
  21387. +               info->irq, first_multi, inb(multi->port_monitor));
  21388. +#ifdef SERIAL_DEBUG_INTR
  21389. +    printk("end.\n");
  21390. +#endif
  21391. +}
  21392. +
  21393. +/*
  21394. + * This is the serial driver's for multiport boards
  21395. + */
  21396. +static void rs_interrupt_multi(int irq, struct pt_regs * regs)
  21397. +{
  21398. +    int status;
  21399. +    struct async_struct * info;
  21400. +    int pass_counter = 0;
  21401. +    int first_multi= 0;
  21402. +    struct rs_multiport_struct *multi;
  21403. +
  21404. +#ifdef SERIAL_DEBUG_INTR
  21405. +    printk("rs_interrupt_multi(%d)...", irq);
  21406. +#endif
  21407. +    
  21408. +    info = IRQ_ports[irq];
  21409. +    if (!info)
  21410. +        return;
  21411. +    multi = &rs_multiport[irq];
  21412. +    if (!multi->port1) {
  21413. +        /* Should never happen */
  21414. +        printk("rs_interrupt_multi: NULL port1!\n");
  21415. +        return;
  21416. +    }
  21417. +    if (multi->port_monitor)
  21418. +        first_multi = inb(multi->port_monitor);
  21419. +    
  21420. +    while (1) {
  21421. +        if (!info->tty ||
  21422. +            (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
  21423. +            goto next;
  21424. +
  21425. +        info->last_active = jiffies;
  21426. +
  21427. +        status = serial_inp(info, UART_LSR) & info->read_status_mask;
  21428. +#ifdef SERIAL_DEBUG_INTR
  21429. +        printk("status = %x...", status);
  21430. +#endif
  21431. +        if (status & UART_LSR_DR)
  21432. +            receive_chars(info, &status);
  21433. +        check_modem_status(info);
  21434. +        if (status & UART_LSR_THRE)
  21435. +            transmit_chars(info, 0);
  21436. +
  21437. +    next:
  21438. +        info = info->next_port;
  21439. +        if (info)
  21440. +            continue;
  21441. +
  21442. +        info = IRQ_ports[irq];
  21443. +        if (pass_counter++ > RS_ISR_PASS_LIMIT) {
  21444. +#if 1
  21445. +            printk("rs_multi loop break\n");
  21446. +#endif
  21447. +            break;     /* Prevent infinite loops */
  21448. +        }
  21449. +        if (multi->port_monitor)
  21450. +            printk("rs port monitor irq %d: 0x%x, 0x%x\n",
  21451. +                   info->irq, first_multi,
  21452. +                   inb(multi->port_monitor));
  21453. +        if ((inb(multi->port1) & multi->mask1) != multi->match1)
  21454. +            continue;
  21455. +        if (!multi->port2)
  21456. +            break;
  21457. +        if ((inb(multi->port2) & multi->mask2) != multi->match2)
  21458. +            continue;
  21459. +        if (!multi->port3)
  21460. +            break;
  21461. +        if ((inb(multi->port3) & multi->mask3) != multi->match3)
  21462. +            continue;
  21463. +        if (!multi->port4)
  21464. +            break;
  21465. +        if ((inb(multi->port4) & multi->mask4) == multi->match4)
  21466. +            continue;
  21467. +        break;
  21468. +    } 
  21469. +#ifdef SERIAL_DEBUG_INTR
  21470. +    printk("end.\n");
  21471. +#endif
  21472. +}
  21473. +
  21474. +
  21475. +/*
  21476. + * -------------------------------------------------------------------
  21477. + * Here ends the serial interrupt routines.
  21478. + * -------------------------------------------------------------------
  21479. + */
  21480. +
  21481. +/*
  21482. + * This routine is used to handle the "bottom half" processing for the
  21483. + * serial driver, known also the "software interrupt" processing.
  21484. + * This processing is done at the kernel interrupt level, after the
  21485. + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
  21486. + * is where time-consuming activities which can not be done in the
  21487. + * interrupt driver proper are done; the interrupt driver schedules
  21488. + * them using rs_sched_event(), and they get done here.
  21489. + */
  21490. +static void do_serial_bh(void *unused)
  21491. +{
  21492. +    run_task_queue(&tq_serial);
  21493. +}
  21494. +
  21495. +static void do_softint(void *private_)
  21496. +{
  21497. +    struct async_struct    *info = (struct async_struct *) private_;
  21498. +    struct tty_struct    *tty;
  21499. +    
  21500. +    tty = info->tty;
  21501. +    if (!tty)
  21502. +        return;
  21503. +
  21504. +    if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
  21505. +        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  21506. +            tty->ldisc.write_wakeup)
  21507. +            (tty->ldisc.write_wakeup)(tty);
  21508. +        wake_up_interruptible(&tty->write_wait);
  21509. +    }
  21510. +}
  21511. +
  21512. +/*
  21513. + * This routine is called from the scheduler tqueue when the interrupt
  21514. + * routine has signalled that a hangup has occurred.  The path of
  21515. + * hangup processing is:
  21516. + *
  21517. + *     serial interrupt routine -> (scheduler tqueue) ->
  21518. + *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
  21519. + * 
  21520. + */
  21521. +static void do_serial_hangup(void *private_)
  21522. +{
  21523. +    struct async_struct    *info = (struct async_struct *) private_;
  21524. +    struct tty_struct    *tty;
  21525. +    
  21526. +    tty = info->tty;
  21527. +    if (!tty)
  21528. +        return;
  21529. +
  21530. +    tty_hangup(tty);
  21531. +}
  21532. +
  21533. +
  21534. +/*
  21535. + * This subroutine is called when the RS_TIMER goes off.  It is used
  21536. + * by the serial driver to handle ports that do not have an interrupt
  21537. + * (irq=0).  This doesn't work very well for 16450's, but gives barely
  21538. + * passable results for a 16550A.  (Although at the expense of much
  21539. + * CPU overhead).
  21540. + */
  21541. +static void rs_timer(void)
  21542. +{
  21543. +    static unsigned long last_strobe = 0;
  21544. +    struct async_struct *info;
  21545. +    unsigned int    i;
  21546. +
  21547. +    if ((jiffies - last_strobe) >= RS_STROBE_TIME*HZ) {
  21548. +        for (i=1; i < 16; i++) {
  21549. +            info = IRQ_ports[i];
  21550. +            if (!info)
  21551. +                continue;
  21552. +            cli();
  21553. +            if (info->next_port) {
  21554. +                do {
  21555. +                    serial_out(info, UART_IER, 0);
  21556. +                    info->IER |= UART_IER_THRI;
  21557. +                    serial_out(info, UART_IER, info->IER);
  21558. +                    info = info->next_port;
  21559. +                } while (info);
  21560. +                if (rs_multiport[i].port1)
  21561. +                    rs_interrupt_multi(i, NULL);
  21562. +                else
  21563. +                    rs_interrupt(i, NULL);
  21564. +            } else
  21565. +                rs_interrupt_single(i, NULL);
  21566. +            sti();
  21567. +        }
  21568. +    }
  21569. +    last_strobe = jiffies;
  21570. +    timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME * HZ;
  21571. +    timer_active |= 1 << RS_TIMER;
  21572. +
  21573. +    if (IRQ_ports[0]) {
  21574. +        cli();
  21575. +        rs_interrupt(0, NULL);
  21576. +        sti();
  21577. +
  21578. +        timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
  21579. +    }
  21580. +}
  21581. +
  21582. +/*
  21583. + * ---------------------------------------------------------------
  21584. + * Low level utility subroutines for the serial driver:  routines to
  21585. + * figure out the appropriate timeout for an interrupt chain, routines
  21586. + * to initialize and startup a serial port, and routines to shutdown a
  21587. + * serial port.  Useful stuff like that.
  21588. + * ---------------------------------------------------------------
  21589. + */
  21590. +
  21591. +/*
  21592. + * Grab all interrupts in preparation for doing an automatic irq
  21593. + * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a
  21594. + * mask of irq's which were grabbed and should therefore be freed
  21595. + * using free_all_interrupts().
  21596. + */
  21597. +static int grab_all_interrupts(int dontgrab)
  21598. +{
  21599. +    int             irq_lines = 0;
  21600. +    int            i, mask;
  21601. +    
  21602. +    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
  21603. +        if (!(mask & dontgrab) && !request_irq(i, rs_probe, SA_INTERRUPT, "serial probe")) {
  21604. +            irq_lines |= mask;
  21605. +        }
  21606. +    }
  21607. +    return irq_lines;
  21608. +}
  21609. +
  21610. +/*
  21611. + * Release all interrupts grabbed by grab_all_interrupts
  21612. + */
  21613. +static void free_all_interrupts(int irq_lines)
  21614. +{
  21615. +    int    i;
  21616. +    
  21617. +    for (i = 0; i < 16; i++) {
  21618. +        if (irq_lines & (1 << i))
  21619. +            free_irq(i);
  21620. +    }
  21621. +}
  21622. +
  21623. +/*
  21624. + * This routine figures out the correct timeout for a particular IRQ.
  21625. + * It uses the smallest timeout of all of the serial ports in a
  21626. + * particular interrupt chain.  Now only used for IRQ 0....
  21627. + */
  21628. +static void figure_IRQ_timeout(int irq)
  21629. +{
  21630. +    struct    async_struct    *info;
  21631. +    int    timeout = 6000;    /* 60 seconds === a long time :-) */
  21632. +
  21633. +    info = IRQ_ports[irq];
  21634. +    if (!info) {
  21635. +        IRQ_timeout[irq] = 6000;
  21636. +        return;
  21637. +    }
  21638. +    while (info) {
  21639. +        if (info->timeout < timeout)
  21640. +            timeout = info->timeout;
  21641. +        info = info->next_port;
  21642. +    }
  21643. +    if (!irq)
  21644. +        timeout = timeout / 2;
  21645. +    IRQ_timeout[irq] = timeout ? timeout : 1;
  21646. +}
  21647. +
  21648. +static int startup(struct async_struct * info)
  21649. +{
  21650. +    unsigned short ICP;
  21651. +    unsigned long flags;
  21652. +    int    retval;
  21653. +    void (*handler)(int, struct pt_regs *);
  21654. +
  21655. +    if (info->flags & ASYNC_INITIALIZED)
  21656. +        return 0;
  21657. +
  21658. +    if (!info->port || !info->type) {
  21659. +        if (info->tty)
  21660. +            set_bit(TTY_IO_ERROR, &info->tty->flags);
  21661. +        return 0;
  21662. +    }
  21663. +
  21664. +    if (!info->xmit_buf) {
  21665. +        info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
  21666. +        if (!info->xmit_buf)
  21667. +            return -ENOMEM;
  21668. +    }
  21669. +
  21670. +    save_flags(flags); cli();
  21671. +
  21672. +#ifdef SERIAL_DEBUG_OPEN
  21673. +    printk("starting up ttys%d (irq %d)...", info->line, info->irq);
  21674. +#endif
  21675. +
  21676. +    /*
  21677. +     * Clear the FIFO buffers and disable them
  21678. +     * (they will be reenabled in change_speed())
  21679. +     */
  21680. +    if (info->type == PORT_16650) {
  21681. +        serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  21682. +                         UART_FCR_CLEAR_XMIT));
  21683. +        info->xmit_fifo_size = 1; /* disabled for now */
  21684. +    } else if (info->type == PORT_16550A) {
  21685. +        serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  21686. +                         UART_FCR_CLEAR_XMIT));
  21687. +        info->xmit_fifo_size = 16;
  21688. +    } else
  21689. +        info->xmit_fifo_size = 1;
  21690. +
  21691. +    /*
  21692. +     * At this point there's no way the LSR could still be 0xFF;
  21693. +     * if it is, then bail out, because there's likely no UART
  21694. +     * here.
  21695. +     */
  21696. +    if (serial_inp(info, UART_LSR) == 0xff) {
  21697. +        restore_flags(flags);
  21698. +        if (suser()) {
  21699. +            if (info->tty)
  21700. +                set_bit(TTY_IO_ERROR, &info->tty->flags);
  21701. +            return 0;
  21702. +        } else
  21703. +            return -ENODEV;
  21704. +    }
  21705. +    
  21706. +    /*
  21707. +     * Allocate the IRQ if necessary
  21708. +     */
  21709. +    if (info->irq && (!IRQ_ports[info->irq] ||
  21710. +              !IRQ_ports[info->irq]->next_port)) {
  21711. +        if (IRQ_ports[info->irq]) {
  21712. +            free_irq(info->irq);
  21713. +            if (rs_multiport[info->irq].port1)
  21714. +                handler = rs_interrupt_multi;
  21715. +            else
  21716. +                handler = rs_interrupt;
  21717. +        } else 
  21718. +            handler = rs_interrupt_single;
  21719. +
  21720. +        retval = request_irq(info->irq, handler, SA_INTERRUPT, "serial");
  21721. +        if (retval) {
  21722. +            restore_flags(flags);
  21723. +            if (suser()) {
  21724. +                if (info->tty)
  21725. +                    set_bit(TTY_IO_ERROR,
  21726. +                        &info->tty->flags);
  21727. +                return 0;
  21728. +            } else
  21729. +                return retval;
  21730. +        }
  21731. +    }
  21732. +
  21733. +    /*
  21734. +     * Clear the interrupt registers.
  21735. +     */
  21736. +     /* (void) serial_inp(info, UART_LSR); */   /* (see above) */
  21737. +    (void) serial_inp(info, UART_RX);
  21738. +    (void) serial_inp(info, UART_IIR);
  21739. +    (void) serial_inp(info, UART_MSR);
  21740. +
  21741. +    /*
  21742. +     * Now, initialize the UART 
  21743. +     */
  21744. +    serial_outp(info, UART_LCR, UART_LCR_WLEN8);    /* reset DLAB */
  21745. +    if (info->flags & ASYNC_FOURPORT) {
  21746. +        info->MCR = UART_MCR_DTR | UART_MCR_RTS;
  21747. +        info->MCR_noint = UART_MCR_DTR | UART_MCR_OUT1;
  21748. +    } else {
  21749. +        info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
  21750. +        info->MCR_noint = UART_MCR_DTR | UART_MCR_RTS;
  21751. +    }
  21752. +#ifdef __alpha__
  21753. +    info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
  21754. +    info->MCR_noint |= UART_MCR_OUT1 | UART_MCR_OUT2;
  21755. +#endif
  21756. +    if (info->irq == 0)
  21757. +        info->MCR = info->MCR_noint;
  21758. +    serial_outp(info, UART_MCR, info->MCR);
  21759. +    
  21760. +    /*
  21761. +     * Finally, enable interrupts
  21762. +     */
  21763. +    info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
  21764. +    serial_outp(info, UART_IER, info->IER);    /* enable interrupts */
  21765. +    
  21766. +    if (info->flags & ASYNC_FOURPORT) {
  21767. +        /* Enable interrupts on the AST Fourport board */
  21768. +        ICP = (info->port & 0xFE0) | 0x01F;
  21769. +        outb_p(0x80, ICP);
  21770. +        (void) inb_p(ICP);
  21771. +    }
  21772. +
  21773. +    /*
  21774. +     * And clear the interrupt registers again for luck.
  21775. +     */
  21776. +    (void)serial_inp(info, UART_LSR);
  21777. +    (void)serial_inp(info, UART_RX);
  21778. +    (void)serial_inp(info, UART_IIR);
  21779. +    (void)serial_inp(info, UART_MSR);
  21780. +
  21781. +    if (info->tty)
  21782. +        clear_bit(TTY_IO_ERROR, &info->tty->flags);
  21783. +    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
  21784. +
  21785. +    /*
  21786. +     * Insert serial port into IRQ chain.
  21787. +     */
  21788. +    info->prev_port = 0;
  21789. +    info->next_port = IRQ_ports[info->irq];
  21790. +    if (info->next_port)
  21791. +        info->next_port->prev_port = info;
  21792. +    IRQ_ports[info->irq] = info;
  21793. +    figure_IRQ_timeout(info->irq);
  21794. +
  21795. +    /*
  21796. +     * Set up serial timers...
  21797. +     */
  21798. +    timer_table[RS_TIMER].expires = jiffies + 2;
  21799. +    timer_active |= 1 << RS_TIMER;
  21800. +
  21801. +    /*
  21802. +     * and set the speed of the serial port
  21803. +     */
  21804. +    change_speed(info);
  21805. +
  21806. +    info->flags |= ASYNC_INITIALIZED;
  21807. +    restore_flags(flags);
  21808. +    return 0;
  21809. +}
  21810. +
  21811. +/*
  21812. + * This routine will shutdown a serial port; interrupts are disabled, and
  21813. + * DTR is dropped if the hangup on close termio flag is on.
  21814. + */
  21815. +static void shutdown(struct async_struct * info)
  21816. +{
  21817. +    unsigned long    flags;
  21818. +    int        retval;
  21819. +
  21820. +    if (!(info->flags & ASYNC_INITIALIZED))
  21821. +        return;
  21822. +
  21823. +#ifdef SERIAL_DEBUG_OPEN
  21824. +    printk("Shutting down serial port %d (irq %d)....", info->line,
  21825. +           info->irq);
  21826. +#endif
  21827. +    
  21828. +    save_flags(flags); cli(); /* Disable interrupts */
  21829. +    
  21830. +    /*
  21831. +     * First unlink the serial port from the IRQ chain...
  21832. +     */
  21833. +    if (info->next_port)
  21834. +        info->next_port->prev_port = info->prev_port;
  21835. +    if (info->prev_port)
  21836. +        info->prev_port->next_port = info->next_port;
  21837. +    else
  21838. +        IRQ_ports[info->irq] = info->next_port;
  21839. +    figure_IRQ_timeout(info->irq);
  21840. +    
  21841. +    /*
  21842. +     * Free the IRQ, if necessary
  21843. +     */
  21844. +    if (info->irq && (!IRQ_ports[info->irq] ||
  21845. +              !IRQ_ports[info->irq]->next_port)) {
  21846. +        if (IRQ_ports[info->irq]) {
  21847. +            free_irq(info->irq);
  21848. +            retval = request_irq(info->irq, rs_interrupt_single, SA_INTERRUPT, "serial");
  21849. +            
  21850. +            if (retval)
  21851. +                printk("serial shutdown: request_irq: error %d"
  21852. +                       "  Couldn't reacquire IRQ.\n", retval);
  21853. +        } else
  21854. +            free_irq(info->irq);
  21855. +    }
  21856. +
  21857. +    if (info->xmit_buf) {
  21858. +        free_page((unsigned long) info->xmit_buf);
  21859. +        info->xmit_buf = 0;
  21860. +    }
  21861. +
  21862. +    info->IER = 0;
  21863. +    serial_outp(info, UART_IER, 0x00);    /* disable all intrs */
  21864. +    if (info->flags & ASYNC_FOURPORT) {
  21865. +        /* reset interrupts on the AST Fourport board */
  21866. +        (void) inb((info->port & 0xFE0) | 0x01F);
  21867. +    }
  21868. +    
  21869. +    if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
  21870. +        info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
  21871. +        info->MCR_noint &= ~(UART_MCR_DTR|UART_MCR_RTS);
  21872. +    }
  21873. +    serial_outp(info, UART_MCR, info->MCR_noint);
  21874. +
  21875. +    /* disable FIFO's */    
  21876. +    serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  21877. +                     UART_FCR_CLEAR_XMIT));
  21878. +    (void)serial_in(info, UART_RX);    /* read data port to reset things */
  21879. +    
  21880. +    if (info->tty)
  21881. +        set_bit(TTY_IO_ERROR, &info->tty->flags);
  21882. +    
  21883. +    info->flags &= ~ASYNC_INITIALIZED;
  21884. +    restore_flags(flags);
  21885. +}
  21886. +
  21887. +/*
  21888. + * This routine is called to set the UART divisor registers to match
  21889. + * the specified baud rate for a serial port.
  21890. + */
  21891. +static void change_speed(struct async_struct *info)
  21892. +{
  21893. +    unsigned short port;
  21894. +    int    quot = 0;
  21895. +    unsigned cflag,cval,fcr;
  21896. +    int    i;
  21897. +
  21898. +    if (!info->tty || !info->tty->termios)
  21899. +        return;
  21900. +    cflag = info->tty->termios->c_cflag;
  21901. +    if (!(port = info->port))
  21902. +        return;
  21903. +    i = cflag & CBAUD;
  21904. +    if (i & CBAUDEX) {
  21905. +        i &= ~CBAUDEX;
  21906. +        if (i < 1 || i > 2) 
  21907. +            info->tty->termios->c_cflag &= ~CBAUDEX;
  21908. +        else
  21909. +            i += 15;
  21910. +    }
  21911. +    if (i == 15) {
  21912. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
  21913. +            i += 1;
  21914. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
  21915. +            i += 2;
  21916. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
  21917. +            quot = info->custom_divisor;
  21918. +    }
  21919. +    if (quot) {
  21920. +        info->timeout = ((info->xmit_fifo_size*HZ*15*quot) /
  21921. +                 info->baud_base) + 2;
  21922. +    } else if (baud_table[i] == 134) {
  21923. +        quot = (2*info->baud_base / 269);
  21924. +        info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
  21925. +    } else if (baud_table[i]) {
  21926. +        quot = info->baud_base / baud_table[i];
  21927. +        info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
  21928. +    } else {
  21929. +        quot = 0;
  21930. +        info->timeout = 0;
  21931. +    }
  21932. +    if (quot) {
  21933. +        info->MCR |= UART_MCR_DTR;
  21934. +        info->MCR_noint |= UART_MCR_DTR;
  21935. +        cli();
  21936. +        serial_out(info, UART_MCR, info->MCR);
  21937. +        sti();
  21938. +    } else {
  21939. +        info->MCR &= ~UART_MCR_DTR;
  21940. +        info->MCR_noint &= ~UART_MCR_DTR;
  21941. +        cli();
  21942. +        serial_out(info, UART_MCR, info->MCR);
  21943. +        sti();
  21944. +        return;
  21945. +    }
  21946. +    /* byte size and parity */
  21947. +    cval = cflag & (CSIZE | CSTOPB);
  21948. +    cval >>= 4;
  21949. +    if (cflag & PARENB)
  21950. +        cval |= UART_LCR_PARITY;
  21951. +    if (!(cflag & PARODD))
  21952. +        cval |= UART_LCR_EPAR;
  21953. +    if (info->type == PORT_16550A) {
  21954. +        if ((info->baud_base / quot) < 2400)
  21955. +            fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
  21956. +        else
  21957. +            fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
  21958. +    } else if (info->type == PORT_16650) {
  21959. +        /*
  21960. +         * On the 16650, we disable the FIFOs altogether
  21961. +         * because of a design bug in how the implement
  21962. +         * things.  We could support it by completely changing
  21963. +         * how we handle the interrupt driver, but not today....
  21964. +         *
  21965. +         * N.B.  Because there's no way to set a FIFO trigger
  21966. +         * at 1 char, we'd probably disable at speed below
  21967. +         * 2400 baud anyway...
  21968. +         */
  21969. +        fcr = 0;
  21970. +    } else
  21971. +        fcr = 0;
  21972. +    
  21973. +    /* CTS flow control flag and modem status interrupts */
  21974. +    info->IER &= ~UART_IER_MSI;
  21975. +    if (cflag & CRTSCTS) {
  21976. +        info->flags |= ASYNC_CTS_FLOW;
  21977. +        info->IER |= UART_IER_MSI;
  21978. +    } else
  21979. +        info->flags &= ~ASYNC_CTS_FLOW;
  21980. +    if (cflag & CLOCAL)
  21981. +        info->flags &= ~ASYNC_CHECK_CD;
  21982. +    else {
  21983. +        info->flags |= ASYNC_CHECK_CD;
  21984. +        info->IER |= UART_IER_MSI;
  21985. +    }
  21986. +    serial_out(info, UART_IER, info->IER);
  21987. +
  21988. +    /*
  21989. +     * Set up parity check flag
  21990. +     */
  21991. +    info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
  21992. +    if (I_INPCK(info->tty))
  21993. +        info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
  21994. +    if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
  21995. +        info->read_status_mask |= UART_LSR_BI;
  21996. +    
  21997. +    info->ignore_status_mask = 0;
  21998. +    if (I_IGNPAR(info->tty)) {
  21999. +        info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
  22000. +        info->read_status_mask |= UART_LSR_PE | UART_LSR_FE;
  22001. +    }
  22002. +    if (I_IGNBRK(info->tty)) {
  22003. +        info->ignore_status_mask |= UART_LSR_BI;
  22004. +        info->read_status_mask |= UART_LSR_BI;
  22005. +        /*
  22006. +         * If we're ignore parity and break indicators, ignore 
  22007. +         * overruns too.  (For real raw support).
  22008. +         */
  22009. +        if (I_IGNPAR(info->tty)) {
  22010. +            info->ignore_status_mask |= UART_LSR_OE;
  22011. +            info->read_status_mask |= UART_LSR_OE;
  22012. +        }
  22013. +    }
  22014. +    
  22015. +    cli();
  22016. +    serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);    /* set DLAB */
  22017. +    serial_outp(info, UART_DLL, quot & 0xff);    /* LS of divisor */
  22018. +    serial_outp(info, UART_DLM, quot >> 8);        /* MS of divisor */
  22019. +    serial_outp(info, UART_LCR, cval);        /* reset DLAB */
  22020. +    serial_outp(info, UART_FCR, fcr);     /* set fcr */
  22021. +    sti();
  22022. +}
  22023. +
  22024. +static void rs_put_char(struct tty_struct *tty, unsigned char ch)
  22025. +{
  22026. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  22027. +    unsigned long flags;
  22028. +
  22029. +    if (serial_paranoia_check(info, tty->device, "rs_put_char"))
  22030. +        return;
  22031. +
  22032. +    if (!tty || !info->xmit_buf)
  22033. +        return;
  22034. +
  22035. +    save_flags(flags); cli();
  22036. +    if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
  22037. +        restore_flags(flags);
  22038. +        return;
  22039. +    }
  22040. +
  22041. +    info->xmit_buf[info->xmit_head++] = ch;
  22042. +    info->xmit_head &= SERIAL_XMIT_SIZE-1;
  22043. +    info->xmit_cnt++;
  22044. +    restore_flags(flags);
  22045. +}
  22046. +
  22047. +static void rs_flush_chars(struct tty_struct *tty)
  22048. +{
  22049. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  22050. +    unsigned long flags;
  22051. +                
  22052. +    if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
  22053. +        return;
  22054. +
  22055. +    if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
  22056. +        !info->xmit_buf)
  22057. +        return;
  22058. +
  22059. +    save_flags(flags); cli();
  22060. +    info->IER |= UART_IER_THRI;
  22061. +    serial_out(info, UART_IER, info->IER);
  22062. +    restore_flags(flags);
  22063. +}
  22064. +
  22065. +static int rs_write(struct tty_struct * tty, int from_user,
  22066. +            unsigned char *buf, int count)
  22067. +{
  22068. +    int    c, total = 0;
  22069. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  22070. +    unsigned long flags;
  22071. +                
  22072. +    if (serial_paranoia_check(info, tty->device, "rs_write"))
  22073. +        return 0;
  22074. +
  22075. +    if (!tty || !info->xmit_buf || !tmp_buf)
  22076. +        return 0;
  22077. +        
  22078. +    save_flags(flags);
  22079. +    while (1) {
  22080. +        cli();        
  22081. +        c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
  22082. +                   SERIAL_XMIT_SIZE - info->xmit_head));
  22083. +        if (c <= 0)
  22084. +            break;
  22085. +
  22086. +        if (from_user) {
  22087. +            down(&tmp_buf_sem);
  22088. +            memcpy_fromfs(tmp_buf, buf, c);
  22089. +            c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
  22090. +                       SERIAL_XMIT_SIZE - info->xmit_head));
  22091. +            memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
  22092. +            up(&tmp_buf_sem);
  22093. +        } else
  22094. +            memcpy(info->xmit_buf + info->xmit_head, buf, c);
  22095. +        info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
  22096. +        info->xmit_cnt += c;
  22097. +        restore_flags(flags);
  22098. +        buf += c;
  22099. +        count -= c;
  22100. +        total += c;
  22101. +    }
  22102. +    if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
  22103. +        !(info->IER & UART_IER_THRI)) {
  22104. +        info->IER |= UART_IER_THRI;
  22105. +        serial_out(info, UART_IER, info->IER);
  22106. +    }
  22107. +    restore_flags(flags);
  22108. +    return total;
  22109. +}
  22110. +
  22111. +static int rs_write_room(struct tty_struct *tty)
  22112. +{
  22113. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  22114. +    int    ret;
  22115. +                
  22116. +    if (serial_paranoia_check(info, tty->device, "rs_write_room"))
  22117. +        return 0;
  22118. +    ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
  22119. +    if (ret < 0)
  22120. +        ret = 0;
  22121. +    return ret;
  22122. +}
  22123. +
  22124. +static int rs_chars_in_buffer(struct tty_struct *tty)
  22125. +{
  22126. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  22127. +                
  22128. +    if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
  22129. +        return 0;
  22130. +    return info->xmit_cnt;
  22131. +}
  22132. +
  22133. +static void rs_flush_buffer(struct tty_struct *tty)
  22134. +{
  22135. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  22136. +                
  22137. +    if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
  22138. +        return;
  22139. +    cli();
  22140. +    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
  22141. +    sti();
  22142. +    wake_up_interruptible(&tty->write_wait);
  22143. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  22144. +        tty->ldisc.write_wakeup)
  22145. +        (tty->ldisc.write_wakeup)(tty);
  22146. +}
  22147. +
  22148. +/*
  22149. + * ------------------------------------------------------------
  22150. + * rs_throttle()
  22151. + * 
  22152. + * This routine is called by the upper-layer tty layer to signal that
  22153. + * incoming characters should be throttled.
  22154. + * ------------------------------------------------------------
  22155. + */
  22156. +static void rs_throttle(struct tty_struct * tty)
  22157. +{
  22158. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  22159. +#ifdef SERIAL_DEBUG_THROTTLE
  22160. +    char    buf[64];
  22161. +    
  22162. +    printk("throttle %s: %d....\n", _tty_name(tty, buf),
  22163. +           tty->ldisc.chars_in_buffer(tty));
  22164. +#endif
  22165. +
  22166. +    if (serial_paranoia_check(info, tty->device, "rs_throttle"))
  22167. +        return;
  22168. +    
  22169. +    if (I_IXOFF(tty))
  22170. +        info->x_char = STOP_CHAR(tty);
  22171. +
  22172. +    info->MCR &= ~UART_MCR_RTS;
  22173. +    info->MCR_noint &= ~UART_MCR_RTS;
  22174. +    cli();
  22175. +    serial_out(info, UART_MCR, info->MCR);
  22176. +    sti();
  22177. +}
  22178. +
  22179. +static void rs_unthrottle(struct tty_struct * tty)
  22180. +{
  22181. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  22182. +#ifdef SERIAL_DEBUG_THROTTLE
  22183. +    char    buf[64];
  22184. +    
  22185. +    printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
  22186. +           tty->ldisc.chars_in_buffer(tty));
  22187. +#endif
  22188. +
  22189. +    if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
  22190. +        return;
  22191. +    
  22192. +    if (I_IXOFF(tty)) {
  22193. +        if (info->x_char)
  22194. +            info->x_char = 0;
  22195. +        else
  22196. +            info->x_char = START_CHAR(tty);
  22197. +    }
  22198. +    info->MCR |= UART_MCR_RTS;
  22199. +    info->MCR_noint |= UART_MCR_RTS;
  22200. +    cli();
  22201. +    serial_out(info, UART_MCR, info->MCR);
  22202. +    sti();
  22203. +}
  22204. +
  22205. +/*
  22206. + * ------------------------------------------------------------
  22207. + * rs_ioctl() and friends
  22208. + * ------------------------------------------------------------
  22209. + */
  22210. +
  22211. +static int get_serial_info(struct async_struct * info,
  22212. +               struct serial_struct * retinfo)
  22213. +{
  22214. +    struct serial_struct tmp;
  22215. +  
  22216. +    if (!retinfo)
  22217. +        return -EFAULT;
  22218. +    memset(&tmp, 0, sizeof(tmp));
  22219. +    tmp.type = info->type;
  22220. +    tmp.line = info->line;
  22221. +    tmp.port = info->port;
  22222. +    tmp.irq = info->irq;
  22223. +    tmp.flags = info->flags;
  22224. +    tmp.baud_base = info->baud_base;
  22225. +    tmp.close_delay = info->close_delay;
  22226. +    tmp.closing_wait = info->closing_wait;
  22227. +    tmp.custom_divisor = info->custom_divisor;
  22228. +    tmp.hub6 = info->hub6;
  22229. +    memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
  22230. +    return 0;
  22231. +}
  22232. +
  22233. +static int set_serial_info(struct async_struct * info,
  22234. +               struct serial_struct * new_info)
  22235. +{
  22236. +    struct serial_struct new_serial;
  22237. +    struct async_struct old_info;
  22238. +    unsigned int        i,change_irq,change_port;
  22239. +    int             retval = 0;
  22240. +
  22241. +    if (!new_info)
  22242. +        return -EFAULT;
  22243. +    memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
  22244. +    old_info = *info;
  22245. +
  22246. +    change_irq = new_serial.irq != info->irq;
  22247. +    change_port = (new_serial.port != info->port) || (new_serial.hub6 != info->hub6);
  22248. +
  22249. +    if (!suser()) {
  22250. +        if (change_irq || change_port ||
  22251. +            (new_serial.baud_base != info->baud_base) ||
  22252. +            (new_serial.type != info->type) ||
  22253. +            (new_serial.close_delay != info->close_delay) ||
  22254. +            ((new_serial.flags & ~ASYNC_USR_MASK) !=
  22255. +             (info->flags & ~ASYNC_USR_MASK)))
  22256. +            return -EPERM;
  22257. +        info->flags = ((info->flags & ~ASYNC_USR_MASK) |
  22258. +                   (new_serial.flags & ASYNC_USR_MASK));
  22259. +        info->custom_divisor = new_serial.custom_divisor;
  22260. +        goto check_and_exit;
  22261. +    }
  22262. +
  22263. +    if (new_serial.irq == 2)
  22264. +        new_serial.irq = 9;
  22265. +
  22266. +    if ((new_serial.irq > 15) || (new_serial.port > 0xffff) ||
  22267. +        (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
  22268. +        return -EINVAL;
  22269. +    }
  22270. +
  22271. +    /* Make sure address is not already in use */
  22272. +    if (new_serial.type) {
  22273. +        for (i = 0 ; i < NR_PORTS; i++)
  22274. +            if ((info != &rs_table[i]) &&
  22275. +                (rs_table[i].port == new_serial.port) &&
  22276. +                rs_table[i].type)
  22277. +                return -EADDRINUSE;
  22278. +    }
  22279. +
  22280. +    if ((change_port || change_irq) && (info->count > 1))
  22281. +        return -EBUSY;
  22282. +
  22283. +    /*
  22284. +     * OK, past this point, all the error checking has been done.
  22285. +     * At this point, we start making changes.....
  22286. +     */
  22287. +
  22288. +    info->baud_base = new_serial.baud_base;
  22289. +    info->flags = ((info->flags & ~ASYNC_FLAGS) |
  22290. +            (new_serial.flags & ASYNC_FLAGS));
  22291. +    info->custom_divisor = new_serial.custom_divisor;
  22292. +    info->type = new_serial.type;
  22293. +    info->close_delay = new_serial.close_delay;
  22294. +    info->closing_wait = new_serial.closing_wait;
  22295. +
  22296. +    release_region(info->port,8);
  22297. +    if (change_port || change_irq) {
  22298. +        /*
  22299. +         * We need to shutdown the serial port at the old
  22300. +         * port/irq combination.
  22301. +         */
  22302. +        shutdown(info);
  22303. +        info->irq = new_serial.irq;
  22304. +        info->port = new_serial.port;
  22305. +        info->hub6 = new_serial.hub6;
  22306. +    }
  22307. +    if(info->type != PORT_UNKNOWN)
  22308. +        request_region(info->port,8,"serial(set)");
  22309. +
  22310. +    
  22311. +check_and_exit:
  22312. +    if (!info->port || !info->type)
  22313. +        return 0;
  22314. +    if (info->flags & ASYNC_INITIALIZED) {
  22315. +        if (((old_info.flags & ASYNC_SPD_MASK) !=
  22316. +             (info->flags & ASYNC_SPD_MASK)) ||
  22317. +            (old_info.custom_divisor != info->custom_divisor))
  22318. +            change_speed(info);
  22319. +    } else
  22320. +        retval = startup(info);
  22321. +    return retval;
  22322. +}
  22323. +
  22324. +
  22325. +/*
  22326. + * get_lsr_info - get line status register info
  22327. + *
  22328. + * Purpose: Let user call ioctl() to get info when the UART physically
  22329. + *         is emptied.  On bus types like RS485, the transmitter must
  22330. + *         release the bus after transmitting. This must be done when
  22331. + *         the transmit shift register is empty, not be done when the
  22332. + *         transmit holding register is empty.  This functionality
  22333. + *         allows RS485 driver to be written in user space. 
  22334. + */
  22335. +static int get_lsr_info(struct async_struct * info, unsigned int *value)
  22336. +{
  22337. +    unsigned char status;
  22338. +    unsigned int result;
  22339. +
  22340. +    cli();
  22341. +    status = serial_in(info, UART_LSR);
  22342. +    sti();
  22343. +    result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
  22344. +    put_fs_long(result,(unsigned long *) value);
  22345. +    return 0;
  22346. +}
  22347. +
  22348. +
  22349. +static int get_modem_info(struct async_struct * info, unsigned int *value)
  22350. +{
  22351. +    unsigned char control, status;
  22352. +    unsigned int result;
  22353. +
  22354. +    control = info->MCR;
  22355. +    cli();
  22356. +    status = serial_in(info, UART_MSR);
  22357. +    sti();
  22358. +    result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
  22359. +        | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
  22360. +        | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
  22361. +        | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
  22362. +        | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
  22363. +        | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
  22364. +    put_fs_long(result,(unsigned long *) value);
  22365. +    return 0;
  22366. +}
  22367. +
  22368. +static int set_modem_info(struct async_struct * info, unsigned int cmd,
  22369. +              unsigned int *value)
  22370. +{
  22371. +    int error;
  22372. +    unsigned int arg;
  22373. +
  22374. +    error = verify_area(VERIFY_READ, value, sizeof(int));
  22375. +    if (error)
  22376. +        return error;
  22377. +    arg = get_fs_long((unsigned long *) value);
  22378. +    switch (cmd) {
  22379. +    case TIOCMBIS: 
  22380. +        if (arg & TIOCM_RTS) {
  22381. +            info->MCR |= UART_MCR_RTS;
  22382. +            info->MCR_noint |= UART_MCR_RTS;
  22383. +        }
  22384. +        if (arg & TIOCM_DTR) {
  22385. +            info->MCR |= UART_MCR_DTR;
  22386. +            info->MCR_noint |= UART_MCR_DTR;
  22387. +        }
  22388. +        break;
  22389. +    case TIOCMBIC:
  22390. +        if (arg & TIOCM_RTS) {
  22391. +            info->MCR &= ~UART_MCR_RTS;
  22392. +            info->MCR_noint &= ~UART_MCR_RTS;
  22393. +        }
  22394. +        if (arg & TIOCM_DTR) {
  22395. +            info->MCR &= ~UART_MCR_DTR;
  22396. +            info->MCR_noint &= ~UART_MCR_DTR;
  22397. +        }
  22398. +        break;
  22399. +    case TIOCMSET:
  22400. +        info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR))
  22401. +                 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
  22402. +                 | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
  22403. +        info->MCR_noint = ((info->MCR_noint
  22404. +                    & ~(UART_MCR_RTS | UART_MCR_DTR))
  22405. +                   | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
  22406. +                   | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
  22407. +        break;
  22408. +    default:
  22409. +        return -EINVAL;
  22410. +    }
  22411. +    cli();
  22412. +    serial_out(info, UART_MCR, info->MCR);
  22413. +    sti();
  22414. +    return 0;
  22415. +}
  22416. +
  22417. +static int do_autoconfig(struct async_struct * info)
  22418. +{
  22419. +    int            retval;
  22420. +    
  22421. +    if (!suser())
  22422. +        return -EPERM;
  22423. +    
  22424. +    if (info->count > 1)
  22425. +        return -EBUSY;
  22426. +    
  22427. +    shutdown(info);
  22428. +
  22429. +    cli();
  22430. +    autoconfig(info);
  22431. +    sti();
  22432. +
  22433. +    retval = startup(info);
  22434. +    if (retval)
  22435. +        return retval;
  22436. +    return 0;
  22437. +}
  22438. +
  22439. +
  22440. +/*
  22441. + * This routine sends a break character out the serial port.
  22442. + */
  22443. +static void send_break(    struct async_struct * info, int duration)
  22444. +{
  22445. +    if (!info->port)
  22446. +        return;
  22447. +    current->state = TASK_INTERRUPTIBLE;
  22448. +    current->timeout = jiffies + duration;
  22449. +    cli();
  22450. +    serial_out(info, UART_LCR, serial_inp(info, UART_LCR) | UART_LCR_SBC);
  22451. +    schedule();
  22452. +    serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
  22453. +    sti();
  22454. +}
  22455. +
  22456. +/*
  22457. + * This routine returns a bitfield of "wild interrupts".  Basically,
  22458. + * any unclaimed interrupts which is flapping around.
  22459. + */
  22460. +static int check_wild_interrupts(int doprint)
  22461. +{
  22462. +    int    i, mask;
  22463. +    int    wild_interrupts = 0;
  22464. +    int    irq_lines;
  22465. +    unsigned long timeout;
  22466. +    unsigned long flags;
  22467. +    
  22468. +    /* Turn on interrupts (they may be off) */
  22469. +    save_flags(flags); sti();
  22470. +
  22471. +    irq_lines = grab_all_interrupts(0);
  22472. +    
  22473. +    /*
  22474. +     * Delay for 0.1 seconds -- we use a busy loop since this may 
  22475. +     * occur during the bootup sequence
  22476. +     */
  22477. +    timeout = jiffies+10;
  22478. +    while (timeout >= jiffies)
  22479. +        ;
  22480. +    
  22481. +    rs_triggered = 0;    /* Reset after letting things settle */
  22482. +
  22483. +    timeout = jiffies+10;
  22484. +    while (timeout >= jiffies)
  22485. +        ;
  22486. +    
  22487. +    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
  22488. +        if ((rs_triggered & (1 << i)) &&
  22489. +            (irq_lines & (1 << i))) {
  22490. +            wild_interrupts |= mask;
  22491. +            if (doprint)
  22492. +                printk("Wild interrupt?  (IRQ %d)\n", i);
  22493. +        }
  22494. +    }
  22495. +    free_all_interrupts(irq_lines);
  22496. +    restore_flags(flags);
  22497. +    return wild_interrupts;
  22498. +}
  22499. +
  22500. +static int get_multiport_struct(struct async_struct * info,
  22501. +                struct serial_multiport_struct *retinfo)
  22502. +{
  22503. +    struct serial_multiport_struct ret;
  22504. +    struct rs_multiport_struct *multi;
  22505. +    
  22506. +    multi = &rs_multiport[info->irq];
  22507. +
  22508. +    ret.port_monitor = multi->port_monitor;
  22509. +    
  22510. +    ret.port1 = multi->port1;
  22511. +    ret.mask1 = multi->mask1;
  22512. +    ret.match1 = multi->match1;
  22513. +    
  22514. +    ret.port2 = multi->port2;
  22515. +    ret.mask2 = multi->mask2;
  22516. +    ret.match2 = multi->match2;
  22517. +    
  22518. +    ret.port3 = multi->port3;
  22519. +    ret.mask3 = multi->mask3;
  22520. +    ret.match3 = multi->match3;
  22521. +    
  22522. +    ret.port4 = multi->port4;
  22523. +    ret.mask4 = multi->mask4;
  22524. +    ret.match4 = multi->match4;
  22525. +
  22526. +    ret.irq = info->irq;
  22527. +
  22528. +    memcpy_tofs(retinfo,&ret,sizeof(*retinfo));
  22529. +    return 0;
  22530. +    
  22531. +}
  22532. +
  22533. +static int set_multiport_struct(struct async_struct * info,
  22534. +                struct serial_multiport_struct *in_multi)
  22535. +{
  22536. +    struct serial_multiport_struct new_multi;
  22537. +    struct rs_multiport_struct *multi;
  22538. +    int    was_multi, now_multi;
  22539. +    int    retval;
  22540. +    void (*handler)(int, struct pt_regs *);
  22541. +
  22542. +    if (!suser())
  22543. +        return -EPERM;
  22544. +    if (!in_multi)
  22545. +        return -EFAULT;
  22546. +    memcpy_fromfs(&new_multi, in_multi,
  22547. +              sizeof(struct serial_multiport_struct));
  22548. +
  22549. +    if (new_multi.irq != info->irq || info->irq == 0 ||
  22550. +        !IRQ_ports[info->irq])
  22551. +        return -EINVAL;
  22552. +
  22553. +    multi = &rs_multiport[info->irq];
  22554. +    was_multi = (multi->port1 != 0);
  22555. +    
  22556. +    multi->port_monitor = new_multi.port_monitor;
  22557. +    
  22558. +    multi->port1 = new_multi.port1;
  22559. +    multi->mask1 = new_multi.mask1;
  22560. +    multi->match1 = new_multi.match1;
  22561. +
  22562. +    multi->port2 = new_multi.port2;
  22563. +    multi->mask2 = new_multi.mask2;
  22564. +    multi->match2 = new_multi.match2;
  22565. +
  22566. +    multi->port3 = new_multi.port3;
  22567. +    multi->mask3 = new_multi.mask3;
  22568. +    multi->match3 = new_multi.match3;
  22569. +
  22570. +    multi->port4 = new_multi.port4;
  22571. +    multi->mask4 = new_multi.mask4;
  22572. +    multi->match4 = new_multi.match4;
  22573. +
  22574. +    now_multi = (multi->port1 != 0);
  22575. +    
  22576. +    if (IRQ_ports[info->irq]->next_port &&
  22577. +        (was_multi != now_multi)) {
  22578. +        free_irq(info->irq);
  22579. +        if (now_multi)
  22580. +            handler = rs_interrupt_multi;
  22581. +        else
  22582. +            handler = rs_interrupt;
  22583. +
  22584. +        retval = request_irq(info->irq, handler, SA_INTERRUPT,
  22585. +                     "serial");
  22586. +        if (retval) {
  22587. +            printk("Couldn't reallocate serial interrupt "
  22588. +                   "driver!!\n");
  22589. +        }
  22590. +    }
  22591. +
  22592. +    return 0;
  22593. +}
  22594. +
  22595. +static int rs_ioctl(struct tty_struct *tty, struct file * file,
  22596. +            unsigned int cmd, unsigned long arg)
  22597. +{
  22598. +    int error;
  22599. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  22600. +    int retval;
  22601. +
  22602. +    if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
  22603. +        return -ENODEV;
  22604. +
  22605. +    if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
  22606. +        (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
  22607. +        (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
  22608. +        if (tty->flags & (1 << TTY_IO_ERROR))
  22609. +            return -EIO;
  22610. +    }
  22611. +    
  22612. +    switch (cmd) {
  22613. +        case TCSBRK:    /* SVID version: non-zero arg --> no break */
  22614. +            retval = tty_check_change(tty);
  22615. +            if (retval)
  22616. +                return retval;
  22617. +            tty_wait_until_sent(tty, 0);
  22618. +            if (!arg)
  22619. +                send_break(info, HZ/4);    /* 1/4 second */
  22620. +            return 0;
  22621. +        case TCSBRKP:    /* support for POSIX tcsendbreak() */
  22622. +            retval = tty_check_change(tty);
  22623. +            if (retval)
  22624. +                return retval;
  22625. +            tty_wait_until_sent(tty, 0);
  22626. +            send_break(info, arg ? arg*(HZ/10) : HZ/4);
  22627. +            return 0;
  22628. +        case TIOCGSOFTCAR:
  22629. +            error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
  22630. +            if (error)
  22631. +                return error;
  22632. +            put_fs_long(C_CLOCAL(tty) ? 1 : 0,
  22633. +                    (unsigned long *) arg);
  22634. +            return 0;
  22635. +        case TIOCSSOFTCAR:
  22636. +            arg = get_fs_long((unsigned long *) arg);
  22637. +            tty->termios->c_cflag =
  22638. +                ((tty->termios->c_cflag & ~CLOCAL) |
  22639. +                 (arg ? CLOCAL : 0));
  22640. +            return 0;
  22641. +        case TIOCMGET:
  22642. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  22643. +                sizeof(unsigned int));
  22644. +            if (error)
  22645. +                return error;
  22646. +            return get_modem_info(info, (unsigned int *) arg);
  22647. +        case TIOCMBIS:
  22648. +        case TIOCMBIC:
  22649. +        case TIOCMSET:
  22650. +            return set_modem_info(info, cmd, (unsigned int *) arg);
  22651. +        case TIOCGSERIAL:
  22652. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  22653. +                        sizeof(struct serial_struct));
  22654. +            if (error)
  22655. +                return error;
  22656. +            return get_serial_info(info,
  22657. +                           (struct serial_struct *) arg);
  22658. +        case TIOCSSERIAL:
  22659. +            return set_serial_info(info,
  22660. +                           (struct serial_struct *) arg);
  22661. +        case TIOCSERCONFIG:
  22662. +            return do_autoconfig(info);
  22663. +
  22664. +        case TIOCSERGWILD:
  22665. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  22666. +                        sizeof(int));
  22667. +            if (error)
  22668. +                return error;
  22669. +            put_fs_long(rs_wild_int_mask, (unsigned long *) arg);
  22670. +            return 0;
  22671. +
  22672. +        case TIOCSERGETLSR: /* Get line status register */
  22673. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  22674. +                sizeof(unsigned int));
  22675. +            if (error)
  22676. +                return error;
  22677. +            else
  22678. +                return get_lsr_info(info, (unsigned int *) arg);
  22679. +
  22680. +        case TIOCSERSWILD:
  22681. +            if (!suser())
  22682. +                return -EPERM;
  22683. +            rs_wild_int_mask = get_fs_long((unsigned long *) arg);
  22684. +            if (rs_wild_int_mask < 0)
  22685. +                rs_wild_int_mask = check_wild_interrupts(0);
  22686. +            return 0;
  22687. +
  22688. +        case TIOCSERGSTRUCT:
  22689. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  22690. +                        sizeof(struct async_struct));
  22691. +            if (error)
  22692. +                return error;
  22693. +            memcpy_tofs((struct async_struct *) arg,
  22694. +                    info, sizeof(struct async_struct));
  22695. +            return 0;
  22696. +            
  22697. +        case TIOCSERGETMULTI:
  22698. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  22699. +                    sizeof(struct serial_multiport_struct));
  22700. +            if (error)
  22701. +                return error;
  22702. +            return get_multiport_struct(info,
  22703. +                       (struct serial_multiport_struct *) arg);
  22704. +        case TIOCSERSETMULTI:
  22705. +            return set_multiport_struct(info,
  22706. +                       (struct serial_multiport_struct *) arg);
  22707. +        default:
  22708. +            return -ENOIOCTLCMD;
  22709. +        }
  22710. +    return 0;
  22711. +}
  22712. +
  22713. +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
  22714. +{
  22715. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  22716. +
  22717. +    if (tty->termios->c_cflag == old_termios->c_cflag)
  22718. +        return;
  22719. +
  22720. +    change_speed(info);
  22721. +
  22722. +    if ((old_termios->c_cflag & CRTSCTS) &&
  22723. +        !(tty->termios->c_cflag & CRTSCTS)) {
  22724. +        tty->hw_stopped = 0;
  22725. +        rs_start(tty);
  22726. +    }
  22727. +
  22728. +#if 0
  22729. +    /*
  22730. +     * No need to wake up processes in open wait, since they
  22731. +     * sample the CLOCAL flag once, and don't recheck it.
  22732. +     * XXX  It's not clear whether the current behavior is correct
  22733. +     * or not.  Hence, this may change.....
  22734. +     */
  22735. +    if (!(old_termios->c_cflag & CLOCAL) &&
  22736. +        (tty->termios->c_cflag & CLOCAL))
  22737. +        wake_up_interruptible(&info->open_wait);
  22738. +#endif
  22739. +}
  22740. +
  22741. +/*
  22742. + * ------------------------------------------------------------
  22743. + * rs_close()
  22744. + * 
  22745. + * This routine is called when the serial port gets closed.  First, we
  22746. + * wait for the last remaining data to be sent.  Then, we unlink its
  22747. + * async structure from the interrupt chain if necessary, and we free
  22748. + * that IRQ if nothing is left in the chain.
  22749. + * ------------------------------------------------------------
  22750. + */
  22751. +static void rs_close(struct tty_struct *tty, struct file * filp)
  22752. +{
  22753. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  22754. +    unsigned long flags;
  22755. +    unsigned long timeout;
  22756. +
  22757. +    if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
  22758. +        return;
  22759. +    
  22760. +    save_flags(flags); cli();
  22761. +    
  22762. +    if (tty_hung_up_p(filp)) {
  22763. +        restore_flags(flags);
  22764. +        return;
  22765. +    }
  22766. +    
  22767. +#ifdef SERIAL_DEBUG_OPEN
  22768. +    printk("rs_close ttys%d, count = %d\n", info->line, info->count);
  22769. +#endif
  22770. +    if ((tty->count == 1) && (info->count != 1)) {
  22771. +        /*
  22772. +         * Uh, oh.  tty->count is 1, which means that the tty
  22773. +         * structure will be freed.  Info->count should always
  22774. +         * be one in these conditions.  If it's greater than
  22775. +         * one, we've got real problems, since it means the
  22776. +         * serial port won't be shutdown.
  22777. +         */
  22778. +        printk("rs_close: bad serial port count; tty->count is 1, "
  22779. +               "info->count is %d\n", info->count);
  22780. +        info->count = 1;
  22781. +    }
  22782. +    if (--info->count < 0) {
  22783. +        printk("rs_close: bad serial port count for ttys%d: %d\n",
  22784. +               info->line, info->count);
  22785. +        info->count = 0;
  22786. +    }
  22787. +    if (info->count) {
  22788. +        restore_flags(flags);
  22789. +        return;
  22790. +    }
  22791. +    info->flags |= ASYNC_CLOSING;
  22792. +    /*
  22793. +     * Save the termios structure, since this port may have
  22794. +     * separate termios for callout and dialin.
  22795. +     */
  22796. +    if (info->flags & ASYNC_NORMAL_ACTIVE)
  22797. +        info->normal_termios = *tty->termios;
  22798. +    if (info->flags & ASYNC_CALLOUT_ACTIVE)
  22799. +        info->callout_termios = *tty->termios;
  22800. +    /*
  22801. +     * Now we wait for the transmit buffer to clear; and we notify 
  22802. +     * the line discipline to only process XON/XOFF characters.
  22803. +     */
  22804. +    tty->closing = 1;
  22805. +    if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
  22806. +        tty_wait_until_sent(tty, info->closing_wait);
  22807. +    /*
  22808. +     * At this point we stop accepting input.  To do this, we
  22809. +     * disable the receive line status interrupts, and tell the
  22810. +     * interrupt driver to stop checking the data ready bit in the
  22811. +     * line status register.
  22812. +     */
  22813. +    info->IER &= ~UART_IER_RLSI;
  22814. +    info->read_status_mask &= ~UART_LSR_DR;
  22815. +    if (info->flags & ASYNC_INITIALIZED) {
  22816. +        serial_out(info, UART_IER, info->IER);
  22817. +        /*
  22818. +         * Before we drop DTR, make sure the UART transmitter
  22819. +         * has completely drained; this is especially
  22820. +         * important if there is a transmit FIFO!
  22821. +         */
  22822. +        timeout = jiffies+HZ;
  22823. +        while (!(serial_inp(info, UART_LSR) & UART_LSR_TEMT)) {
  22824. +            current->state = TASK_INTERRUPTIBLE;
  22825. +            current->timeout = jiffies + info->timeout;
  22826. +            schedule();
  22827. +            if (jiffies > timeout)
  22828. +                break;
  22829. +        }
  22830. +    }
  22831. +    shutdown(info);
  22832. +    if (tty->driver.flush_buffer)
  22833. +        tty->driver.flush_buffer(tty);
  22834. +    if (tty->ldisc.flush_buffer)
  22835. +        tty->ldisc.flush_buffer(tty);
  22836. +    tty->closing = 0;
  22837. +    info->event = 0;
  22838. +    info->tty = 0;
  22839. +    if (tty->ldisc.num != ldiscs[N_TTY].num) {
  22840. +        if (tty->ldisc.close)
  22841. +            (tty->ldisc.close)(tty);
  22842. +        tty->ldisc = ldiscs[N_TTY];
  22843. +        tty->termios->c_line = N_TTY;
  22844. +        if (tty->ldisc.open)
  22845. +            (tty->ldisc.open)(tty);
  22846. +    }
  22847. +    if (info->blocked_open) {
  22848. +        if (info->close_delay) {
  22849. +            current->state = TASK_INTERRUPTIBLE;
  22850. +            current->timeout = jiffies + info->close_delay;
  22851. +            schedule();
  22852. +        }
  22853. +        wake_up_interruptible(&info->open_wait);
  22854. +    }
  22855. +    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
  22856. +             ASYNC_CLOSING);
  22857. +    wake_up_interruptible(&info->close_wait);
  22858. +    restore_flags(flags);
  22859. +}
  22860. +
  22861. +/*
  22862. + * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
  22863. + */
  22864. +void rs_hangup(struct tty_struct *tty)
  22865. +{
  22866. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  22867. +    
  22868. +    if (serial_paranoia_check(info, tty->device, "rs_hangup"))
  22869. +        return;
  22870. +    
  22871. +    rs_flush_buffer(tty);
  22872. +    shutdown(info);
  22873. +    info->event = 0;
  22874. +    info->count = 0;
  22875. +    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
  22876. +    info->tty = 0;
  22877. +    wake_up_interruptible(&info->open_wait);
  22878. +}
  22879. +
  22880. +/*
  22881. + * ------------------------------------------------------------
  22882. + * rs_open() and friends
  22883. + * ------------------------------------------------------------
  22884. + */
  22885. +static int block_til_ready(struct tty_struct *tty, struct file * filp,
  22886. +               struct async_struct *info)
  22887. +{
  22888. +    struct wait_queue wait = { current, NULL };
  22889. +    int        retval;
  22890. +    int        do_clocal = 0;
  22891. +
  22892. +    /*
  22893. +     * If the device is in the middle of being closed, then block
  22894. +     * until it's done, and then try again.
  22895. +     */
  22896. +    if (info->flags & ASYNC_CLOSING) {
  22897. +        interruptible_sleep_on(&info->close_wait);
  22898. +#ifdef SERIAL_DO_RESTART
  22899. +        if (info->flags & ASYNC_HUP_NOTIFY)
  22900. +            return -EAGAIN;
  22901. +        else
  22902. +            return -ERESTARTSYS;
  22903. +#else
  22904. +        return -EAGAIN;
  22905. +#endif
  22906. +    }
  22907. +
  22908. +    /*
  22909. +     * If this is a callout device, then just make sure the normal
  22910. +     * device isn't being used.
  22911. +     */
  22912. +    if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
  22913. +        if (info->flags & ASYNC_NORMAL_ACTIVE)
  22914. +            return -EBUSY;
  22915. +        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  22916. +            (info->flags & ASYNC_SESSION_LOCKOUT) &&
  22917. +            (info->session != current->session))
  22918. +            return -EBUSY;
  22919. +        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  22920. +            (info->flags & ASYNC_PGRP_LOCKOUT) &&
  22921. +            (info->pgrp != current->pgrp))
  22922. +            return -EBUSY;
  22923. +        info->flags |= ASYNC_CALLOUT_ACTIVE;
  22924. +        return 0;
  22925. +    }
  22926. +    
  22927. +    /*
  22928. +     * If non-blocking mode is set, or the port is not enabled,
  22929. +     * then make the check up front and then exit.
  22930. +     */
  22931. +    if ((filp->f_flags & O_NONBLOCK) ||
  22932. +        (tty->flags & (1 << TTY_IO_ERROR))) {
  22933. +        if (info->flags & ASYNC_CALLOUT_ACTIVE)
  22934. +            return -EBUSY;
  22935. +        info->flags |= ASYNC_NORMAL_ACTIVE;
  22936. +        return 0;
  22937. +    }
  22938. +
  22939. +    if (info->flags & ASYNC_CALLOUT_ACTIVE) {
  22940. +        if (info->normal_termios.c_cflag & CLOCAL)
  22941. +            do_clocal = 1;
  22942. +    } else {
  22943. +        if (tty->termios->c_cflag & CLOCAL)
  22944. +            do_clocal = 1;
  22945. +    }
  22946. +    
  22947. +    /*
  22948. +     * Block waiting for the carrier detect and the line to become
  22949. +     * free (i.e., not in use by the callout).  While we are in
  22950. +     * this loop, info->count is dropped by one, so that
  22951. +     * rs_close() knows when to free things.  We restore it upon
  22952. +     * exit, either normal or abnormal.
  22953. +     */
  22954. +    retval = 0;
  22955. +    add_wait_queue(&info->open_wait, &wait);
  22956. +#ifdef SERIAL_DEBUG_OPEN
  22957. +    printk("block_til_ready before block: ttys%d, count = %d\n",
  22958. +           info->line, info->count);
  22959. +#endif
  22960. +    info->count--;
  22961. +    info->blocked_open++;
  22962. +    while (1) {
  22963. +        cli();
  22964. +        if (!(info->flags & ASYNC_CALLOUT_ACTIVE))
  22965. +            serial_out(info, UART_MCR,
  22966. +                   serial_inp(info, UART_MCR) |
  22967. +                   (UART_MCR_DTR | UART_MCR_RTS));
  22968. +        sti();
  22969. +        current->state = TASK_INTERRUPTIBLE;
  22970. +        if (tty_hung_up_p(filp) ||
  22971. +            !(info->flags & ASYNC_INITIALIZED)) {
  22972. +#ifdef SERIAL_DO_RESTART
  22973. +            if (info->flags & ASYNC_HUP_NOTIFY)
  22974. +                retval = -EAGAIN;
  22975. +            else
  22976. +                retval = -ERESTARTSYS;    
  22977. +#else
  22978. +            retval = -EAGAIN;
  22979. +#endif
  22980. +            break;
  22981. +        }
  22982. +        if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
  22983. +            !(info->flags & ASYNC_CLOSING) &&
  22984. +            (do_clocal || (serial_in(info, UART_MSR) &
  22985. +                   UART_MSR_DCD)))
  22986. +            break;
  22987. +        if (current->signal & ~current->blocked) {
  22988. +            retval = -ERESTARTSYS;
  22989. +            break;
  22990. +        }
  22991. +#ifdef SERIAL_DEBUG_OPEN
  22992. +        printk("block_til_ready blocking: ttys%d, count = %d\n",
  22993. +               info->line, info->count);
  22994. +#endif
  22995. +        schedule();
  22996. +    }
  22997. +    current->state = TASK_RUNNING;
  22998. +    remove_wait_queue(&info->open_wait, &wait);
  22999. +    if (!tty_hung_up_p(filp))
  23000. +        info->count++;
  23001. +    info->blocked_open--;
  23002. +#ifdef SERIAL_DEBUG_OPEN
  23003. +    printk("block_til_ready after blocking: ttys%d, count = %d\n",
  23004. +           info->line, info->count);
  23005. +#endif
  23006. +    if (retval)
  23007. +        return retval;
  23008. +    info->flags |= ASYNC_NORMAL_ACTIVE;
  23009. +    return 0;
  23010. +}    
  23011. +
  23012. +/*
  23013. + * This routine is called whenever a serial port is opened.  It
  23014. + * enables interrupts for a serial port, linking in its async structure into
  23015. + * the IRQ chain.   It also performs the serial-specific
  23016. + * initialization for the tty structure.
  23017. + */
  23018. +int rs_open(struct tty_struct *tty, struct file * filp)
  23019. +{
  23020. +    struct async_struct    *info;
  23021. +    int             retval, line;
  23022. +
  23023. +    line = MINOR(tty->device) - tty->driver.minor_start;
  23024. +    if ((line < 0) || (line >= NR_PORTS))
  23025. +        return -ENODEV;
  23026. +    info = rs_table + line;
  23027. +    if (serial_paranoia_check(info, tty->device, "rs_open"))
  23028. +        return -ENODEV;
  23029. +
  23030. +#ifdef SERIAL_DEBUG_OPEN
  23031. +    printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
  23032. +           info->count);
  23033. +#endif
  23034. +    info->count++;
  23035. +    tty->driver_data = info;
  23036. +    info->tty = tty;
  23037. +
  23038. +    if (!tmp_buf) {
  23039. +        tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
  23040. +        if (!tmp_buf)
  23041. +            return -ENOMEM;
  23042. +    }
  23043. +    
  23044. +    /*
  23045. +     * Start up serial port
  23046. +     */
  23047. +    retval = startup(info);
  23048. +    if (retval)
  23049. +        return retval;
  23050. +
  23051. +    retval = block_til_ready(tty, filp, info);
  23052. +    if (retval) {
  23053. +#ifdef SERIAL_DEBUG_OPEN
  23054. +        printk("rs_open returning after block_til_ready with %d\n",
  23055. +               retval);
  23056. +#endif
  23057. +        return retval;
  23058. +    }
  23059. +
  23060. +    if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
  23061. +        if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
  23062. +            *tty->termios = info->normal_termios;
  23063. +        else 
  23064. +            *tty->termios = info->callout_termios;
  23065. +        change_speed(info);
  23066. +    }
  23067. +
  23068. +    info->session = current->session;
  23069. +    info->pgrp = current->pgrp;
  23070. +
  23071. +#ifdef SERIAL_DEBUG_OPEN
  23072. +    printk("rs_open ttys%d successful...", info->line);
  23073. +#endif
  23074. +    return 0;
  23075. +}
  23076. +
  23077. +/*
  23078. + * ---------------------------------------------------------------------
  23079. + * rs_init() and friends
  23080. + *
  23081. + * rs_init() is called at boot-time to initialize the serial driver.
  23082. + * ---------------------------------------------------------------------
  23083. + */
  23084. +
  23085. +/*
  23086. + * This routine prints out the appropriate serial driver version
  23087. + * number, and identifies which options were configured into this
  23088. + * driver.
  23089. + */
  23090. +static void show_serial_version(void)
  23091. +{
  23092. +    printk("Serial driver version 4.11 with");
  23093. +#ifdef CONFIG_HUB6
  23094. +    printk(" HUB-6");
  23095. +#define SERIAL_OPT
  23096. +#endif
  23097. +#ifdef SERIAL_OPT
  23098. +    printk(" enabled\n");
  23099. +#else
  23100. +    printk(" no serial options enabled\n");
  23101. +#endif
  23102. +#undef SERIAL_OPT
  23103. +}
  23104. +
  23105. +/*
  23106. + * This routine is called by do_auto_irq(); it attempts to determine
  23107. + * which interrupt a serial port is configured to use.  It is not
  23108. + * fool-proof, but it works a large part of the time.
  23109. + */
  23110. +static int get_auto_irq(struct async_struct *info)
  23111. +{
  23112. +    unsigned char save_MCR, save_IER, save_ICP=0;
  23113. +    unsigned short ICP=0, port = info->port;
  23114. +    unsigned long timeout;
  23115. +    
  23116. +    /*
  23117. +     * Enable interrupts and see who answers
  23118. +     */
  23119. +    rs_irq_triggered = 0;
  23120. +    cli();
  23121. +    save_IER = serial_inp(info, UART_IER);
  23122. +    save_MCR = serial_inp(info, UART_MCR);
  23123. +    if (info->flags & ASYNC_FOURPORT)  {
  23124. +        serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
  23125. +        serial_outp(info, UART_IER, 0x0f);    /* enable all intrs */
  23126. +        ICP = (port & 0xFE0) | 0x01F;
  23127. +        save_ICP = inb_p(ICP);
  23128. +        outb_p(0x80, ICP);
  23129. +        (void) inb_p(ICP);
  23130. +    } else {
  23131. +        serial_outp(info, UART_MCR,
  23132. +                UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
  23133. +        serial_outp(info, UART_IER, 0x0f);    /* enable all intrs */
  23134. +    }
  23135. +    sti();
  23136. +    /*
  23137. +     * Next, clear the interrupt registers.
  23138. +     */
  23139. +    (void)serial_inp(info, UART_LSR);
  23140. +    (void)serial_inp(info, UART_RX);
  23141. +    (void)serial_inp(info, UART_IIR);
  23142. +    (void)serial_inp(info, UART_MSR);
  23143. +    
  23144. +    timeout = jiffies+2;
  23145. +    while (timeout >= jiffies) {
  23146. +        if (rs_irq_triggered)
  23147. +            break;
  23148. +    }
  23149. +    /*
  23150. +     * Now check to see if we got any business, and clean up.
  23151. +     */
  23152. +    cli();
  23153. +    serial_outp(info, UART_IER, save_IER);
  23154. +    serial_outp(info, UART_MCR, save_MCR);
  23155. +    if (info->flags & ASYNC_FOURPORT)
  23156. +        outb_p(save_ICP, ICP);
  23157. +    sti();
  23158. +    return(rs_irq_triggered);
  23159. +}
  23160. +
  23161. +/*
  23162. + * Calls get_auto_irq() multiple times, to make sure we don't get
  23163. + * faked out by random interrupts
  23164. + */
  23165. +static int do_auto_irq(struct async_struct * info)
  23166. +{
  23167. +    unsigned         port = info->port;
  23168. +    int             irq_lines = 0;
  23169. +    int            irq_try_1 = 0, irq_try_2 = 0;
  23170. +    int            retries;
  23171. +    unsigned long flags;
  23172. +
  23173. +    if (!port)
  23174. +        return 0;
  23175. +
  23176. +    /* Turn on interrupts (they may be off) */
  23177. +    save_flags(flags); sti();
  23178. +
  23179. +    irq_lines = grab_all_interrupts(rs_wild_int_mask);
  23180. +    
  23181. +    for (retries = 0; retries < 5; retries++) {
  23182. +        if (!irq_try_1)
  23183. +            irq_try_1 = get_auto_irq(info);
  23184. +        if (!irq_try_2)
  23185. +            irq_try_2 = get_auto_irq(info);
  23186. +        if (irq_try_1 && irq_try_2) {
  23187. +            if (irq_try_1 == irq_try_2)
  23188. +                break;
  23189. +            irq_try_1 = irq_try_2 = 0;
  23190. +        }
  23191. +    }
  23192. +    restore_flags(flags);
  23193. +    free_all_interrupts(irq_lines);
  23194. +    return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
  23195. +}
  23196. +
  23197. +/*
  23198. + * This routine is called by rs_init() to initialize a specific serial
  23199. + * port.  It determines what type of UART ship this serial port is
  23200. + * using: 8250, 16450, 16550, 16550A.  The important question is
  23201. + * whether or not this UART is a 16550A or not, since this will
  23202. + * determine whether or not we can use its FIFO features or not.
  23203. + */
  23204. +static void autoconfig(struct async_struct * info)
  23205. +{
  23206. +    unsigned char status1, status2, scratch, scratch2;
  23207. +    unsigned port = info->port;
  23208. +    unsigned long flags;
  23209. +
  23210. +    info->type = PORT_UNKNOWN;
  23211. +    
  23212. +    if (!port)
  23213. +        return;
  23214. +
  23215. +    save_flags(flags); cli();
  23216. +    
  23217. +    /*
  23218. +     * Do a simple existence test first; if we fail this, there's
  23219. +     * no point trying anything else.
  23220. +     *
  23221. +     * 0x80 is used as a nonsense port to prevent against false
  23222. +     * positives due to ISA bus float.  The assumption is that
  23223. +     * 0x80 is a non-existent port; which should be safe since
  23224. +     * include/asm/io.h also makes this assumption.
  23225. +     */
  23226. +    scratch = serial_inp(info, UART_IER);
  23227. +    serial_outp(info, UART_IER, 0);
  23228. +    outb(0xff, 0x080);
  23229. +    scratch2 = serial_inp(info, UART_IER);
  23230. +    serial_outp(info, UART_IER, scratch);
  23231. +    if (scratch2) {
  23232. +        restore_flags(flags);
  23233. +        return;        /* We failed; there's nothing here */
  23234. +    }
  23235. +
  23236. +    /* 
  23237. +     * Check to see if a UART is really there.  Certain broken
  23238. +     * internal modems based on the Rockwell chipset fail this
  23239. +     * test, because they apparently don't implement the loopback
  23240. +     * test mode.  So this test is skipped on the COM 1 through
  23241. +     * COM 4 ports.  This *should* be safe, since no board
  23242. +     * manufacturer would be stupid enough to design a board
  23243. +     * that conflicts with COM 1-4 --- we hope!
  23244. +     */
  23245. +    if (!(info->flags & ASYNC_SKIP_TEST)) {
  23246. +        scratch = serial_inp(info, UART_MCR);
  23247. +        serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
  23248. +        scratch2 = serial_inp(info, UART_MSR);
  23249. +        serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
  23250. +        status1 = serial_inp(info, UART_MSR) & 0xF0;
  23251. +        serial_outp(info, UART_MCR, scratch);
  23252. +        serial_outp(info, UART_MSR, scratch2);
  23253. +        if (status1 != 0x90) {
  23254. +            restore_flags(flags);
  23255. +            return;
  23256. +        }
  23257. +    } 
  23258. +    
  23259. +    /*
  23260. +     * If the AUTO_IRQ flag is set, try to do the automatic IRQ
  23261. +     * detection.
  23262. +     */
  23263. +    if (info->flags & ASYNC_AUTO_IRQ)
  23264. +        info->irq = do_auto_irq(info);
  23265. +        
  23266. +    scratch2 = serial_in(info, UART_LCR);
  23267. +    serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
  23268. +    serial_outp(info, UART_EFR, 0);    /* EFR is the same as FCR */
  23269. +    serial_outp(info, UART_LCR, scratch2);
  23270. +    serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
  23271. +    scratch = serial_in(info, UART_IIR) >> 6;
  23272. +    info->xmit_fifo_size = 1;
  23273. +    switch (scratch) {
  23274. +        case 0:
  23275. +            info->type = PORT_16450;
  23276. +            break;
  23277. +        case 1:
  23278. +            info->type = PORT_UNKNOWN;
  23279. +            break;
  23280. +        case 2:
  23281. +            info->type = PORT_16550;
  23282. +            break;
  23283. +        case 3:
  23284. +            serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
  23285. +            if (serial_in(info, UART_EFR) == 0) {
  23286. +                info->type = PORT_16650;
  23287. +                info->xmit_fifo_size = 32;
  23288. +            } else {
  23289. +                info->type = PORT_16550A;
  23290. +                info->xmit_fifo_size = 16;
  23291. +            }
  23292. +            serial_outp(info, UART_LCR, scratch2);
  23293. +            break;
  23294. +    }
  23295. +    if (info->type == PORT_16450) {
  23296. +        scratch = serial_in(info, UART_SCR);
  23297. +        serial_outp(info, UART_SCR, 0xa5);
  23298. +        status1 = serial_in(info, UART_SCR);
  23299. +        serial_outp(info, UART_SCR, 0x5a);
  23300. +        status2 = serial_in(info, UART_SCR);
  23301. +        serial_outp(info, UART_SCR, scratch);
  23302. +
  23303. +        if ((status1 != 0xa5) || (status2 != 0x5a))
  23304. +            info->type = PORT_8250;
  23305. +    }
  23306. +    request_region(info->port,8,"serial(auto)");
  23307. +
  23308. +    /*
  23309. +     * Reset the UART.
  23310. +     */
  23311. +#ifdef __alpha__
  23312. +    /*
  23313. +     * I wonder what DEC did to the OUT1 and OUT2 lines?
  23314. +     * clearing them results in endless interrupts.
  23315. +     */
  23316. +    serial_outp(info, UART_MCR, 0x0c);
  23317. +#else
  23318. +    serial_outp(info, UART_MCR, 0x00);
  23319. +#endif
  23320. +    serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  23321. +                     UART_FCR_CLEAR_XMIT));
  23322. +    (void)serial_in(info, UART_RX);
  23323. +    
  23324. +    restore_flags(flags);
  23325. +}
  23326. +
  23327. +/*
  23328. + * The serial driver boot-time initialization code!
  23329. + */
  23330. +long rs_init(long kmem_start)
  23331. +{
  23332. +    int i;
  23333. +    struct async_struct * info;
  23334. +    
  23335. +    bh_base[SERIAL_BH].routine = do_serial_bh;
  23336. +    enable_bh(SERIAL_BH);
  23337. +    timer_table[RS_TIMER].fn = rs_timer;
  23338. +    timer_table[RS_TIMER].expires = 0;
  23339. +#ifdef CONFIG_AUTO_IRQ
  23340. +    rs_wild_int_mask = check_wild_interrupts(1);
  23341. +#endif
  23342. +
  23343. +    for (i = 0; i < 16; i++) {
  23344. +        IRQ_ports[i] = 0;
  23345. +        IRQ_timeout[i] = 0;
  23346. +        memset(&rs_multiport[i], 0, sizeof(struct rs_multiport_struct));
  23347. +    }
  23348. +    
  23349. +    show_serial_version();
  23350. +
  23351. +    /* Initialize the tty_driver structure */
  23352. +    
  23353. +    memset(&serial_driver, 0, sizeof(struct tty_driver));
  23354. +    serial_driver.magic = TTY_DRIVER_MAGIC;
  23355. +    serial_driver.name = "ttyS";
  23356. +    serial_driver.major = TTY_MAJOR;
  23357. +    serial_driver.minor_start = 64;
  23358. +    serial_driver.num = NR_PORTS;
  23359. +    serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
  23360. +    serial_driver.subtype = SERIAL_TYPE_NORMAL;
  23361. +    serial_driver.init_termios = tty_std_termios;
  23362. +    serial_driver.init_termios.c_cflag =
  23363. +        B9600 | CS8 | CREAD | HUPCL | CLOCAL;
  23364. +    serial_driver.flags = TTY_DRIVER_REAL_RAW;
  23365. +    serial_driver.refcount = &serial_refcount;
  23366. +    serial_driver.table = serial_table;
  23367. +    serial_driver.termios = serial_termios;
  23368. +    serial_driver.termios_locked = serial_termios_locked;
  23369. +
  23370. +    serial_driver.open = rs_open;
  23371. +    serial_driver.close = rs_close;
  23372. +    serial_driver.write = rs_write;
  23373. +    serial_driver.put_char = rs_put_char;
  23374. +    serial_driver.flush_chars = rs_flush_chars;
  23375. +    serial_driver.write_room = rs_write_room;
  23376. +    serial_driver.chars_in_buffer = rs_chars_in_buffer;
  23377. +    serial_driver.flush_buffer = rs_flush_buffer;
  23378. +    serial_driver.ioctl = rs_ioctl;
  23379. +    serial_driver.throttle = rs_throttle;
  23380. +    serial_driver.unthrottle = rs_unthrottle;
  23381. +    serial_driver.set_termios = rs_set_termios;
  23382. +    serial_driver.stop = rs_stop;
  23383. +    serial_driver.start = rs_start;
  23384. +    serial_driver.hangup = rs_hangup;
  23385. +
  23386. +    /*
  23387. +     * The callout device is just like normal device except for
  23388. +     * major number and the subtype code.
  23389. +     */
  23390. +    callout_driver = serial_driver;
  23391. +    callout_driver.name = "cua";
  23392. +    callout_driver.major = TTYAUX_MAJOR;
  23393. +    callout_driver.subtype = SERIAL_TYPE_CALLOUT;
  23394. +
  23395. +    if (tty_register_driver(&serial_driver))
  23396. +        panic("Couldn't register serial driver\n");
  23397. +    if (tty_register_driver(&callout_driver))
  23398. +        panic("Couldn't register callout driver\n");
  23399. +    
  23400. +    for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
  23401. +        info->magic = SERIAL_MAGIC;
  23402. +        info->line = i;
  23403. +        info->tty = 0;
  23404. +        info->type = PORT_UNKNOWN;
  23405. +        info->custom_divisor = 0;
  23406. +        info->close_delay = 50;
  23407. +        info->closing_wait = 3000;
  23408. +        info->x_char = 0;
  23409. +        info->event = 0;
  23410. +        info->count = 0;
  23411. +        info->blocked_open = 0;
  23412. +        info->tqueue.routine = do_softint;
  23413. +        info->tqueue.data = info;
  23414. +        info->tqueue_hangup.routine = do_serial_hangup;
  23415. +        info->tqueue_hangup.data = info;
  23416. +        info->callout_termios =callout_driver.init_termios;
  23417. +        info->normal_termios = serial_driver.init_termios;
  23418. +        info->open_wait = 0;
  23419. +        info->close_wait = 0;
  23420. +        info->next_port = 0;
  23421. +        info->prev_port = 0;
  23422. +        if (info->irq == 2)
  23423. +            info->irq = 9;
  23424. +        if (!(info->flags & ASYNC_BOOT_AUTOCONF))
  23425. +            continue;
  23426. +        autoconfig(info);
  23427. +        if (info->type == PORT_UNKNOWN)
  23428. +            continue;
  23429. +        printk("tty%02d%s at 0x%04x (irq = %d)", info->line, 
  23430. +               (info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
  23431. +               info->port, info->irq);
  23432. +        switch (info->type) {
  23433. +            case PORT_8250:
  23434. +                printk(" is a 8250\n");
  23435. +                break;
  23436. +            case PORT_16450:
  23437. +                printk(" is a 16450\n");
  23438. +                break;
  23439. +            case PORT_16550:
  23440. +                printk(" is a 16550\n");
  23441. +                break;
  23442. +            case PORT_16550A:
  23443. +                printk(" is a 16550A\n");
  23444. +                break;
  23445. +            case PORT_16650:
  23446. +                printk(" is a 16650\n");
  23447. +                break;
  23448. +            default:
  23449. +                printk("\n");
  23450. +                break;
  23451. +        }
  23452. +    }
  23453. +    return kmem_start;
  23454. +}
  23455. +
  23456. +/*
  23457. + * register_serial and unregister_serial allows for serial ports to be
  23458. + * configured at run-time, to support PCMCIA modems.
  23459. + */
  23460. +int register_serial(struct serial_struct *req)
  23461. +{
  23462. +    int i;
  23463. +    unsigned long flags;
  23464. +    struct async_struct *info;
  23465. +
  23466. +    save_flags(flags);
  23467. +    cli();
  23468. +    for (i = 0; i < NR_PORTS; i++) {
  23469. +        if (rs_table[i].port == req->port)
  23470. +            break;
  23471. +    }
  23472. +    if (i == NR_PORTS) {
  23473. +        for (i = 0; i < NR_PORTS; i++)
  23474. +            if ((rs_table[i].type == PORT_UNKNOWN) &&
  23475. +                (rs_table[i].count == 0))
  23476. +                break;
  23477. +    }
  23478. +    if (i == NR_PORTS) {
  23479. +        restore_flags(flags);
  23480. +        return -1;
  23481. +    }
  23482. +    info = &rs_table[i];
  23483. +    if (rs_table[i].count) {
  23484. +        restore_flags(flags);
  23485. +        printk("Couldn't configure serial #%d (port=%d,irq=%d): "
  23486. +               "device already open\n", i, req->port, req->irq);
  23487. +        return -1;
  23488. +    }
  23489. +    info->irq = req->irq;
  23490. +    info->port = req->port;
  23491. +    autoconfig(info);
  23492. +    if (info->type == PORT_UNKNOWN) {
  23493. +        restore_flags(flags);
  23494. +        printk("register_serial(): autoconfig failed\n");
  23495. +        return -1;
  23496. +    }
  23497. +    printk("tty%02d at 0x%04x (irq = %d)", info->line, 
  23498. +           info->port, info->irq);
  23499. +    switch (info->type) {
  23500. +    case PORT_8250:
  23501. +        printk(" is a 8250\n"); break;
  23502. +    case PORT_16450:
  23503. +        printk(" is a 16450\n"); break;
  23504. +    case PORT_16550:
  23505. +        printk(" is a 16550\n"); break;
  23506. +    case PORT_16550A:
  23507. +        printk(" is a 16550A\n"); break;
  23508. +    default:
  23509. +        printk("\n"); break;
  23510. +    }
  23511. +    restore_flags(flags);
  23512. +    return info->line;
  23513. +}
  23514. +
  23515. +void unregister_serial(int line)
  23516. +{
  23517. +    unsigned long flags;
  23518. +    struct async_struct *info = &rs_table[line];
  23519. +
  23520. +    save_flags(flags);
  23521. +    cli();
  23522. +    if (info->tty)
  23523. +        tty_hangup(info->tty);
  23524. +    info->type = PORT_UNKNOWN;
  23525. +    printk("tty%02d unloaded\n", info->line);
  23526. +    restore_flags(flags);
  23527. +}
  23528. diff -r -u -N linux.orig/arch/arm/drivers/char/serial.c.orig linux.arm/arch/arm/drivers/char/serial.c.orig
  23529. --- linux.orig/arch/arm/drivers/char/serial.c.orig    Thu Jan  1 01:00:00 1970
  23530. +++ linux.arm/arch/arm/drivers/char/serial.c.orig    Fri Oct 27 23:14:39 1995
  23531. @@ -0,0 +1,2478 @@
  23532. +/*
  23533. + *  linux/drivers/char/serial.c
  23534. + *
  23535. + *  Copyright (C) 1991, 1992  Linus Torvalds
  23536. + *
  23537. + *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
  23538. + *  much more extensible to support other serial cards based on the
  23539. + *  16450/16550A UART's.  Added support for the AST FourPort and the
  23540. + *  Accent Async board.
  23541. + *
  23542. + *  set_serial_info fixed to set the flags, custom divisor, and uart
  23543. + *     type fields.  Fix suggested by Michael K. Johnson 12/12/92.
  23544. + *
  23545. + * This module exports the following rs232 io functions:
  23546. + *
  23547. + *    long rs_init(long);
  23548. + *     int  rs_open(struct tty_struct * tty, struct file * filp)
  23549. + */
  23550. +
  23551. +#include <linux/config.h>
  23552. +#include <linux/errno.h>
  23553. +#include <linux/signal.h>
  23554. +#include <linux/sched.h>
  23555. +#include <linux/timer.h>
  23556. +#include <linux/interrupt.h>
  23557. +#include <linux/tty.h>
  23558. +#include <linux/tty_flip.h>
  23559. +#include <linux/serial.h>
  23560. +#include <linux/serial_reg.h>
  23561. +#include <linux/major.h>
  23562. +#include <linux/string.h>
  23563. +#include <linux/fcntl.h>
  23564. +#include <linux/ptrace.h>
  23565. +#include <linux/major.h>
  23566. +#include <linux/mm.h>
  23567. +
  23568. +#include <asm/system.h>
  23569. +#include <asm/io.h>
  23570. +#include <asm/segment.h>
  23571. +#include <asm/bitops.h>
  23572. +
  23573. +DECLARE_TASK_QUEUE(tq_serial);
  23574. +
  23575. +struct tty_driver serial_driver, callout_driver;
  23576. +static int serial_refcount;
  23577. +
  23578. +/* serial subtype definitions */
  23579. +#define SERIAL_TYPE_NORMAL    1
  23580. +#define SERIAL_TYPE_CALLOUT    2
  23581. +
  23582. +/* number of characters left in xmit buffer before we ask for more */
  23583. +#define WAKEUP_CHARS 256
  23584. +
  23585. +/*
  23586. + * Serial driver configuration section.  Here are the various options:
  23587. + *
  23588. + * CONFIG_HUB6
  23589. + *        Enables support for the venerable Bell Technologies
  23590. + *        HUB6 card.
  23591. + *
  23592. + * SERIAL_PARANOIA_CHECK
  23593. + *         Check the magic number for the async_structure where
  23594. + *         ever possible.
  23595. + */
  23596. +int ser_check=0;
  23597. +#define SERIAL_PARANOIA_CHECK
  23598. +#define CONFIG_SERIAL_NOPAUSE_IO
  23599. +#define SERIAL_DO_RESTART
  23600. +#define CONFIG_SERIAL_NEW_ISR
  23601. +
  23602. +#undef SERIAL_DEBUG_INTR
  23603. +#undef SERIAL_DEBUG_OPEN
  23604. +#undef SERIAL_DEBUG_FLOW
  23605. +
  23606. +#define _INLINE_ inline
  23607. +
  23608. +/*
  23609. + * IRQ_timeout        - How long the timeout should be for each IRQ
  23610. + *                 should be after the IRQ has been active.
  23611. + */
  23612. +
  23613. +static struct async_struct *IRQ_ports[16];
  23614. +static int IRQ_timeout[16];
  23615. +static volatile int rs_irq_triggered;
  23616. +static volatile int rs_triggered;
  23617. +static int rs_wild_int_mask;
  23618. +
  23619. +static void autoconfig(struct async_struct * info);
  23620. +static void change_speed(struct async_struct *info);
  23621. +
  23622. +/*
  23623. + * This assumes you have a 1.8432 MHz clock for your UART.
  23624. + *
  23625. + * It'd be nice if someone built a serial card with a 24.576 MHz
  23626. + * clock, since the 16550A is capable of handling a top speed of 1.5
  23627. + * megabits/second; but this requires the faster clock.
  23628. + */
  23629. +#define BASE_BAUD ( 1843200 / 16 )
  23630. +
  23631. +/* Standard COM flags (except for COM4, because of the 8514 problem) */
  23632. +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST )
  23633. +#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
  23634. +
  23635. +#define FOURPORT_FLAGS ASYNC_FOURPORT
  23636. +#define ACCENT_FLAGS 0
  23637. +#define BOCA_FLAGS 0
  23638. +#define HUB6_FLAGS 0
  23639. +
  23640. +/*
  23641. + * The following define the access methods for the HUB6 card. All
  23642. + * access is through two ports for all 24 possible chips. The card is
  23643. + * selected through the high 2 bits, the port on that card with the
  23644. + * "middle" 3 bits, and the register on that port with the bottom
  23645. + * 3 bits.
  23646. + *
  23647. + * While the access port and interrupt is configurable, the default
  23648. + * port locations are 0x302 for the port control register, and 0x303
  23649. + * for the data read/write register. Normally, the interrupt is at irq3
  23650. + * but can be anything from 3 to 7 inclusive. Note that using 3 will
  23651. + * require disabling com2.
  23652. + */
  23653. +
  23654. +#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
  23655. +
  23656. +struct async_struct rs_table[] = {
  23657. +    /* UART CLK   PORT IRQ     FLAGS        */
  23658. +#ifdef __arm__
  23659. +    { 0, BASE_BAUD, 0x3F8,10, STD_COM_FLAGS },
  23660. +    { 0, BASE_BAUD, 0x2F8,10, STD_COM_FLAGS }
  23661. +#define PODULE
  23662. +#ifdef PODULE
  23663. +       ,{ 0, BASE_BAUD,     0, 0, STD_COM_FLAGS },
  23664. +    { 0, BASE_BAUD,     0, 0, STD_COM_FLAGS },
  23665. +    { 0, BASE_BAUD,     0, 0, STD_COM_FLAGS },
  23666. +    { 0, BASE_BAUD,     0, 0, STD_COM_FLAGS },
  23667. +    { 0, BASE_BAUD,     0, 0, STD_COM_FLAGS },
  23668. +    { 0, BASE_BAUD,     0, 0, STD_COM_FLAGS },
  23669. +    { 0, BASE_BAUD,     0, 0, STD_COM_FLAGS },
  23670. +    { 0, BASE_BAUD,     0, 0, STD_COM_FLAGS }
  23671. +#endif
  23672. +#else
  23673. +    { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },    /* ttyS0 */
  23674. +    { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },    /* ttyS1 */
  23675. +    { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },    /* ttyS2 */
  23676. +    { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },    /* ttyS3 */
  23677. +
  23678. +    { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */
  23679. +    { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },    /* ttyS5 */
  23680. +    { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },    /* ttyS6 */
  23681. +    { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },    /* ttyS7 */
  23682. +
  23683. +    { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },    /* ttyS8 */
  23684. +    { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },    /* ttyS9 */
  23685. +    { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },    /* ttyS10 */
  23686. +    { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },    /* ttyS11 */
  23687. +
  23688. +    { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },    /* ttyS12 */
  23689. +    { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },    /* ttyS13 */
  23690. +    { 0, BASE_BAUD, 0x000, 0, 0 },    /* ttyS14 (spare; user configurable) */
  23691. +    { 0, BASE_BAUD, 0x000, 0, 0 },    /* ttyS15 (spare; user configurable) */
  23692. +
  23693. +    { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },    /* ttyS16 */
  23694. +    { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },    /* ttyS17 */
  23695. +    { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },    /* ttyS18 */
  23696. +    { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },    /* ttyS19 */
  23697. +    { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },    /* ttyS20 */
  23698. +    { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },    /* ttyS21 */
  23699. +    { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },    /* ttyS22 */
  23700. +    { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },    /* ttyS23 */
  23701. +    { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },    /* ttyS24 */
  23702. +    { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },    /* ttyS25 */
  23703. +    { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },    /* ttyS26 */
  23704. +    { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },    /* ttyS27 */
  23705. +    { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },    /* ttyS28 */
  23706. +    { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },    /* ttyS29 */
  23707. +    { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },    /* ttyS30 */
  23708. +    { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },    /* ttyS31 */
  23709. +
  23710. +/* You can have up to four HUB6's in the system, but I've only
  23711. + * included two cards here for a total of twelve ports.
  23712. + */
  23713. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },    /* ttyS32 */
  23714. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },    /* ttyS33 */
  23715. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },    /* ttyS34 */
  23716. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },    /* ttyS35 */
  23717. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },    /* ttyS36 */
  23718. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },    /* ttyS37 */
  23719. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },    /* ttyS32 */
  23720. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },    /* ttyS33 */
  23721. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },    /* ttyS34 */
  23722. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },    /* ttyS35 */
  23723. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },    /* ttyS36 */
  23724. +    { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },    /* ttyS37 */
  23725. +#endif
  23726. +};
  23727. +
  23728. +#define NR_PORTS    (sizeof(rs_table)/sizeof(struct async_struct))
  23729. +#ifdef PODULE
  23730. +int dser_sport = 2; /* This is the start of the serial port NULL entries */
  23731. +#endif
  23732. +
  23733. +static struct tty_struct *serial_table[NR_PORTS];
  23734. +static struct termios *serial_termios[NR_PORTS];
  23735. +static struct termios *serial_termios_locked[NR_PORTS];
  23736. +
  23737. +#ifndef MIN
  23738. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  23739. +#endif
  23740. +
  23741. +/*
  23742. + * tmp_buf is used as a temporary buffer by serial_write.  We need to
  23743. + * lock it in case the memcpy_fromfs blocks while swapping in a page,
  23744. + * and some other program tries to do a serial write at the same time.
  23745. + * Since the lock will only come under contention when the system is
  23746. + * swapping and available memory is low, it makes sense to share one
  23747. + * buffer across all the serial ports, since it significantly saves
  23748. + * memory if large numbers of serial ports are open.
  23749. + */
  23750. +static unsigned char *tmp_buf = 0;
  23751. +static struct semaphore tmp_buf_sem = MUTEX;
  23752. +
  23753. +static inline int serial_paranoia_check(struct async_struct *info,
  23754. +                    dev_t device, const char *routine)
  23755. +{
  23756. +#ifdef SERIAL_PARANOIA_CHECK
  23757. +    static const char *badmagic =
  23758. +        "Warning: bad magic number for serial struct (%d, %d) in %s\n";
  23759. +    static const char *badinfo =
  23760. +        "Warning: null async_struct for (%d, %d) in %s\n";
  23761. +
  23762. +    if (!info) {
  23763. +        printk(badinfo, MAJOR(device), MINOR(device), routine);
  23764. +        return 1;
  23765. +    }
  23766. +    if (info->magic != SERIAL_MAGIC) {
  23767. +        printk(badmagic, MAJOR(device), MINOR(device), routine);
  23768. +        return 1;
  23769. +    }
  23770. +#endif
  23771. +    return 0;
  23772. +}
  23773. +
  23774. +/*
  23775. + * This is used to figure out the divisor speeds and the timeouts
  23776. + */
  23777. +static int baud_table[] = {
  23778. +    0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
  23779. +    9600, 19200, 38400, 57600, 115200, 0 };
  23780. +
  23781. +static inline unsigned int serial_in(struct async_struct *info, int offset)
  23782. +{
  23783. +#ifdef CONFIG_HUB6
  23784. +    if (info->hub6) {
  23785. +    outb(info->hub6 - 1 + offset, info->port);
  23786. +    return inb(info->port+1);
  23787. +    } else
  23788. +#endif
  23789. +    return inb(info->port + offset);
  23790. +}
  23791. +
  23792. +static inline unsigned int serial_inp(struct async_struct *info, int offset)
  23793. +{
  23794. +#ifdef CONFIG_HUB6
  23795. +    if (info->hub6) {
  23796. +    outb(info->hub6 - 1 + offset, info->port);
  23797. +    return inb_p(info->port+1);
  23798. +    } else
  23799. +#endif
  23800. +#ifdef CONFIG_SERIAL_NOPAUSE_IO
  23801. +    return inb(info->port + offset);
  23802. +#else
  23803. +    return inb_p(info->port + offset);
  23804. +#endif
  23805. +}
  23806. +
  23807. +static inline void serial_out(struct async_struct *info, int offset, int value)
  23808. +{
  23809. +#ifdef CONFIG_HUB6
  23810. +    if (info->hub6) {
  23811. +    outb(info->hub6 - 1 + offset, info->port);
  23812. +    outb(value, info->port+1);
  23813. +    } else
  23814. +#endif
  23815. +    outb(value, info->port+offset);
  23816. +}
  23817. +
  23818. +static inline void serial_outp(struct async_struct *info, int offset,
  23819. +                   int value)
  23820. +{
  23821. +#ifdef CONFIG_HUB6
  23822. +    if (info->hub6) {
  23823. +    outb(info->hub6 - 1 + offset, info->port);
  23824. +    outb_p(value, info->port+1);
  23825. +    } else
  23826. +#endif
  23827. +#ifdef CONFIG_SERIAL_NOPAUSE_IO
  23828. +    outb(value, info->port+offset);
  23829. +#else
  23830. +        outb_p(value, info->port+offset);
  23831. +#endif
  23832. +}
  23833. +
  23834. +/*
  23835. + * ------------------------------------------------------------
  23836. + * rs_stop() and rs_start()
  23837. + *
  23838. + * This routines are called before setting or resetting tty->stopped.
  23839. + * They enable or disable transmitter interrupts, as necessary.
  23840. + * ------------------------------------------------------------
  23841. + */
  23842. +static void rs_stop(struct tty_struct *tty)
  23843. +{
  23844. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  23845. +    unsigned long flags;
  23846. +
  23847. +    if (serial_paranoia_check(info, tty->device, "rs_stop"))
  23848. +        return;
  23849. +
  23850. +    save_flags(flags); cli();
  23851. +    if (info->IER & UART_IER_THRI) {
  23852. +        info->IER &= ~UART_IER_THRI;
  23853. +        serial_out(info, UART_IER, info->IER);
  23854. +    }
  23855. +    restore_flags(flags);
  23856. +}
  23857. +
  23858. +static void rs_start(struct tty_struct *tty)
  23859. +{
  23860. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  23861. +    unsigned long flags;
  23862. +
  23863. +    if (serial_paranoia_check(info, tty->device, "rs_start"))
  23864. +        return;
  23865. +
  23866. +    save_flags(flags); cli();
  23867. +    if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
  23868. +        info->IER |= UART_IER_THRI;
  23869. +        serial_out(info, UART_IER, info->IER);
  23870. +    }
  23871. +    restore_flags(flags);
  23872. +}
  23873. +
  23874. +/*
  23875. + * ----------------------------------------------------------------------
  23876. + *
  23877. + * Here starts the interrupt handling routines.  All of the following
  23878. + * subroutines are declared as inline and are folded into
  23879. + * rs_interrupt().  They were separated out for readability's sake.
  23880. + *
  23881. + * Note: rs_interrupt() is a "fast" interrupt, which means that it
  23882. + * runs with interrupts turned off.  People who may want to modify
  23883. + * rs_interrupt() should try to keep the interrupt handler as fast as
  23884. + * possible.  After you are done making modifications, it is not a bad
  23885. + * idea to do:
  23886. + *
  23887. + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
  23888. + *
  23889. + * and look at the resulting assemble code in serial.s.
  23890. + *
  23891. + *                 - Ted Ts'o (tytso@mit.edu), 7-Mar-93
  23892. + * -----------------------------------------------------------------------
  23893. + */
  23894. +
  23895. +/*
  23896. + * This is the serial driver's interrupt routine while we are probing
  23897. + * for submarines.
  23898. + */
  23899. +static void rs_probe(int irq)
  23900. +{
  23901. +    rs_irq_triggered = irq;
  23902. +    rs_triggered |= 1 << irq;
  23903. +    return;
  23904. +}
  23905. +
  23906. +/*
  23907. + * This routine is used by the interrupt handler to schedule
  23908. + * processing in the software interrupt portion of the driver.
  23909. + */
  23910. +static _INLINE_ void rs_sched_event(struct async_struct *info,
  23911. +                  int event)
  23912. +{
  23913. +    info->event |= 1 << event;
  23914. +    queue_task_irq_off(&info->tqueue, &tq_serial);
  23915. +    mark_bh(SERIAL_BH);
  23916. +}
  23917. +
  23918. +static _INLINE_ void receive_chars(struct async_struct *info,
  23919. +                 int *status)
  23920. +{
  23921. +    struct tty_struct *tty = info->tty;
  23922. +    unsigned char ch;
  23923. +
  23924. +    do {
  23925. +        ch = serial_inp(info, UART_RX);
  23926. +        if (*status & (info->ignore_status_mask & ~UART_LSR_OE))/* RMK - stupid to ignore errors! */
  23927. +            continue;
  23928. +        if (tty->flip.count >= TTY_FLIPBUF_SIZE)
  23929. +            break;
  23930. +        tty->flip.count++;
  23931. +        if (*status & info->read_status_mask) {
  23932. +            if (*status & (UART_LSR_BI)) {
  23933. +                *tty->flip.flag_buf_ptr++ = TTY_BREAK;
  23934. +                if (info->flags & ASYNC_SAK)
  23935. +                    do_SAK(tty);
  23936. +            } else if (*status & UART_LSR_PE)
  23937. +                *tty->flip.flag_buf_ptr++ = TTY_PARITY;
  23938. +            else if (*status & UART_LSR_FE)
  23939. +                *tty->flip.flag_buf_ptr++ = TTY_FRAME;
  23940. +            else if (*status & UART_LSR_OE)
  23941. +                *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
  23942. +            else
  23943. +                *tty->flip.flag_buf_ptr++ = 0;
  23944. +        } else
  23945. +            *tty->flip.flag_buf_ptr++ = 0;
  23946. +        *tty->flip.char_buf_ptr++ = ch;
  23947. +    } while ((*status = serial_inp(info, UART_LSR)) & UART_LSR_DR);
  23948. +    queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
  23949. +#ifdef SERIAL_DEBUG_INTR
  23950. +    printk("DR...");
  23951. +#endif
  23952. +}
  23953. +
  23954. +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
  23955. +{
  23956. +    int count;
  23957. +
  23958. +    if (info->x_char) {
  23959. +        serial_outp(info, UART_TX, info->x_char);
  23960. +        info->x_char = 0;
  23961. +        if (intr_done)
  23962. +            *intr_done = 0;
  23963. +        return;
  23964. +    }
  23965. +    if ((info->xmit_cnt <= 0) || info->tty->stopped ||
  23966. +        info->tty->hw_stopped) {
  23967. +        info->IER &= ~UART_IER_THRI;
  23968. +#ifdef CONFIG_SERIAL_NEW_ISR
  23969. +        serial_out(info, UART_IER, info->IER);
  23970. +#endif
  23971. +        return;
  23972. +    }
  23973. +
  23974. +    count = info->xmit_fifo_size;
  23975. +    do {
  23976. +        serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
  23977. +        info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
  23978. +        if (--info->xmit_cnt <= 0)
  23979. +            break;
  23980. +    } while (--count > 0);
  23981. +
  23982. +    if (info->xmit_cnt < WAKEUP_CHARS)
  23983. +        rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
  23984. +
  23985. +#ifdef SERIAL_DEBUG_INTR
  23986. +    printk("THRE...");
  23987. +#endif
  23988. +    if (intr_done)
  23989. +        *intr_done = 0;
  23990. +
  23991. +    if (info->xmit_cnt <= 0) {
  23992. +        info->IER &= ~UART_IER_THRI;
  23993. +#ifdef CONFIG_SERIAL_NEW_ISR
  23994. +        serial_out(info, UART_IER, info->IER);
  23995. +#endif
  23996. +    }
  23997. +}
  23998. +
  23999. +static _INLINE_ void check_modem_status(struct async_struct *info)
  24000. +{
  24001. +    int    status;
  24002. +
  24003. +    status = serial_in(info, UART_MSR);
  24004. +
  24005. +    if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
  24006. +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
  24007. +        printk("ttys%d CD now %s...\n", info->line,
  24008. +               (status & UART_MSR_DCD) ? "on" : "off");
  24009. +#endif
  24010. +        if (status & UART_MSR_DCD)
  24011. +            wake_up_interruptible(&info->open_wait);
  24012. +        else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  24013. +               (info->flags & ASYNC_CALLOUT_NOHUP))) {
  24014. +#ifdef SERIAL_DEBUG_OPEN
  24015. +            printk("scheduling hangup...\n");
  24016. +#endif
  24017. +            rs_sched_event(info, RS_EVENT_HANGUP);
  24018. +        }
  24019. +    }
  24020. +    if (info->flags & ASYNC_CTS_FLOW) {
  24021. +        if (info->tty->hw_stopped) {
  24022. +            if (status & UART_MSR_CTS) {
  24023. +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
  24024. +                printk("CTS tx start...");
  24025. +#endif
  24026. +                info->tty->hw_stopped = 0;
  24027. +                info->IER |= UART_IER_THRI;
  24028. +#ifdef CONFIG_SERIAL_NEW_ISR
  24029. +                serial_out(info, UART_IER, info->IER);
  24030. +#endif
  24031. +                rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
  24032. +                return;
  24033. +            }
  24034. +        } else {
  24035. +            if (!(status & UART_MSR_CTS)) {
  24036. +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
  24037. +                printk("CTS tx stop...");
  24038. +#endif
  24039. +                info->tty->hw_stopped = 1;
  24040. +                info->IER &= ~UART_IER_THRI;
  24041. +#ifdef CONFIG_SERIAL_NEW_ISR
  24042. +                serial_out(info, UART_IER, info->IER);
  24043. +#endif
  24044. +            }
  24045. +        }
  24046. +    }
  24047. +}
  24048. +
  24049. +#ifdef CONFIG_SERIAL_NEW_ISR
  24050. +/*
  24051. + * This is the serial driver's generic interrupt routine
  24052. + */
  24053. +static void rs_interrupt(int irq)
  24054. +{
  24055. +    int status;
  24056. +    struct async_struct * info;
  24057. +    int pass_counter = 0;
  24058. +    struct async_struct *end_mark = 0;
  24059. +
  24060. +#ifdef SERIAL_DEBUG_INTR
  24061. +    printk("rs_interrupt(%d)...", irq);
  24062. +#endif
  24063. +
  24064. +    info = IRQ_ports[irq];
  24065. +    if (!info)
  24066. +        return;
  24067. +
  24068. +    do {
  24069. +        if (!info->tty ||
  24070. +            (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
  24071. +            if (!end_mark)
  24072. +                end_mark = info;
  24073. +            goto next;
  24074. +        }
  24075. +        end_mark = 0;
  24076. +
  24077. +        info->last_active = jiffies;
  24078. +
  24079. +        status = serial_inp(info, UART_LSR);
  24080. +        if (status & UART_LSR_DR)
  24081. +            receive_chars(info, &status);
  24082. +        check_modem_status(info);
  24083. +        if (status & UART_LSR_THRE)
  24084. +            transmit_chars(info, 0);
  24085. +
  24086. +    next:
  24087. +        info = info->next_port;
  24088. +        if (!info) {
  24089. +            info = IRQ_ports[irq];
  24090. +            if (pass_counter++ > 64) {
  24091. +#if 0
  24092. +                printk("rs loop break\n");
  24093. +#endif
  24094. +                break;     /* Prevent infinite loops */
  24095. +            }
  24096. +            continue;
  24097. +        }
  24098. +    } while (end_mark != info);
  24099. +}
  24100. +
  24101. +/*
  24102. + * This is the serial driver's interrupt routine for a single port
  24103. + */
  24104. +static void rs_interrupt_single(int irq)
  24105. +{
  24106. +    int status;
  24107. +    int pass_counter = 0;
  24108. +    struct async_struct * info;
  24109. +
  24110. +#ifdef SERIAL_DEBUG_INTR
  24111. +    printk("rs_interrupt_single(%d)...", irq);
  24112. +#endif
  24113. +
  24114. +    info = IRQ_ports[irq];
  24115. +    if (!info || !info->tty)
  24116. +        return;
  24117. +
  24118. +    do {
  24119. +        status = serial_inp(info, UART_LSR);
  24120. +        if (status & UART_LSR_DR)
  24121. +            receive_chars(info, &status);
  24122. +        check_modem_status(info);
  24123. +        if (status & UART_LSR_THRE)
  24124. +            transmit_chars(info, 0);
  24125. +        if (pass_counter++ > 64) {
  24126. +#if 0
  24127. +            printk("rs_single loop break.\n");
  24128. +#endif
  24129. +            break;
  24130. +        }
  24131. +    } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
  24132. +    info->last_active = jiffies;
  24133. +}
  24134. +
  24135. +#else /* CONFIG_SERIAL_NEW_ISR */
  24136. +
  24137. +/*
  24138. + * This is the serial driver's generic interrupt routine
  24139. + */
  24140. +static void rs_interrupt(int irq)
  24141. +{
  24142. +    int status;
  24143. +    struct async_struct * info;
  24144. +    int done = 1, pass_counter = 0;
  24145. +
  24146. +
  24147. +#ifdef SERIAL_DEBUG_INTR
  24148. +    printk("rs_interrupt(%d)...", irq);
  24149. +#endif
  24150. +
  24151. +    info = IRQ_ports[irq];
  24152. +    if (!info)
  24153. +        return;
  24154. +
  24155. +    while (1) {
  24156. +        if (!info->tty)
  24157. +            goto next;
  24158. +
  24159. +        serial_outp(info, UART_IER, 0);
  24160. +        status = serial_inp(info, UART_LSR);
  24161. +        if (status & UART_LSR_DR) {
  24162. +            receive_chars(info, &status);
  24163. +            done = 0;
  24164. +        }
  24165. +        check_modem_status(info);
  24166. +        if (status & UART_LSR_THRE)
  24167. +            transmit_chars(info, &done);
  24168. +
  24169. +    next:
  24170. +        info = info->next_port;
  24171. +        if (!info) {
  24172. +            info = IRQ_ports[irq];
  24173. +            if (done)
  24174. +                break;
  24175. +            done = 1;
  24176. +            if (pass_counter++ > 64) {
  24177. +#if 0
  24178. +                printk("rs loop break\n");
  24179. +#endif
  24180. +                break;     /* Prevent infinite loops */
  24181. +            }
  24182. +        }
  24183. +    }
  24184. +
  24185. +    /*
  24186. +     * Reset the IER registers; info is already set up from the
  24187. +     * above while loop.
  24188. +     */
  24189. +    do
  24190. +        serial_outp(info, UART_IER, info->IER);
  24191. +    while ((info = info->next_port) != NULL);
  24192. +}
  24193. +
  24194. +/*
  24195. + * This is the serial driver's interrupt routine for a single port
  24196. + */
  24197. +static void rs_interrupt_single(int irq)
  24198. +{
  24199. +    int status;
  24200. +    struct async_struct * info;
  24201. +
  24202. +
  24203. +#ifdef SERIAL_DEBUG_INTR
  24204. +    printk("rs_interrupt_single(%d)...", irq);
  24205. +#endif
  24206. +
  24207. +    info = IRQ_ports[irq];
  24208. +    if (!info || !info->tty)
  24209. +        return;
  24210. +
  24211. +    serial_outp(info, UART_IER, 0);
  24212. +    status = serial_inp(info, UART_LSR);
  24213. +    if (status & UART_LSR_DR)
  24214. +        receive_chars(info, &status);
  24215. +    check_modem_status(info);
  24216. +    if (status & UART_LSR_THRE)
  24217. +        transmit_chars(info, 0);
  24218. +
  24219. +    /*
  24220. +     * Reset the IER register
  24221. +     */
  24222. +    serial_outp(info, UART_IER, info->IER);
  24223. +}
  24224. +
  24225. +#endif /* CONFIG_SERIAL_NEW_ISR */
  24226. +
  24227. +/*
  24228. + * -------------------------------------------------------------------
  24229. + * Here ends the serial interrupt routines.
  24230. + * -------------------------------------------------------------------
  24231. + */
  24232. +
  24233. +/*
  24234. + * This routine is used to handle the "bottom half" processing for the
  24235. + * serial driver, known also the "software interrupt" processing.
  24236. + * This processing is done at the kernel interrupt level, after the
  24237. + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
  24238. + * is where time-consuming activities which can not be done in the
  24239. + * interrupt driver proper are done; the interrupt driver schedules
  24240. + * them using rs_sched_event(), and they get done here.
  24241. + */
  24242. +static void do_serial_bh(void *unused)
  24243. +{
  24244. +    run_task_queue(&tq_serial);
  24245. +}
  24246. +
  24247. +static void do_softint(void *private_)
  24248. +{
  24249. +    struct async_struct    *info = (struct async_struct *) private_;
  24250. +    struct tty_struct    *tty;
  24251. +
  24252. +    tty = info->tty;
  24253. +    if (!tty)
  24254. +        return;
  24255. +
  24256. +    if (clear_bit(RS_EVENT_HANGUP, &info->event)) {
  24257. +        tty_hangup(tty);
  24258. +        wake_up_interruptible(&info->open_wait);
  24259. +        info->flags &= ~(ASYNC_NORMAL_ACTIVE|
  24260. +                 ASYNC_CALLOUT_ACTIVE);
  24261. +    }
  24262. +    if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
  24263. +        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  24264. +            tty->ldisc.write_wakeup)
  24265. +            (tty->ldisc.write_wakeup)(tty);
  24266. +        wake_up_interruptible(&tty->write_wait);
  24267. +    }
  24268. +}
  24269. +
  24270. +/*
  24271. + * This subroutine is called when the RS_TIMER goes off.  It is used
  24272. + * by the serial driver to handle ports that do not have an interrupt
  24273. + * (irq=0).  This doesn't work very well for 16450's, but gives barely
  24274. + * passable results for a 16550A.  (Although at the expense of much
  24275. + * CPU overhead).
  24276. + */
  24277. +static void rs_timer(void)
  24278. +{
  24279. +    static unsigned long last_strobe = 0;
  24280. +    struct async_struct *info;
  24281. +    unsigned int    i;
  24282. +
  24283. +    if ((jiffies - last_strobe) >= 60*HZ) {
  24284. +        for (i=1; i < 16; i++) {
  24285. +            info = IRQ_ports[i];
  24286. +            if (!info)
  24287. +                continue;
  24288. +            cli();
  24289. +            if (info->next_port) {
  24290. +                do {
  24291. +                    serial_out(info, UART_IER, 0);
  24292. +                    info->IER |= UART_IER_THRI;
  24293. +                    serial_out(info, UART_IER, info->IER);
  24294. +                    info = info->next_port;
  24295. +                } while (info);
  24296. +                rs_interrupt(i);
  24297. +            } else
  24298. +                rs_interrupt_single(i);
  24299. +            sti();
  24300. +        }
  24301. +    }
  24302. +    last_strobe = jiffies;
  24303. +    timer_table[RS_TIMER].expires = jiffies + 60 * HZ;
  24304. +    timer_active |= 1 << RS_TIMER;
  24305. +
  24306. +    if (IRQ_ports[0]) {
  24307. +        cli();
  24308. +        rs_interrupt(0);
  24309. +        sti();
  24310. +
  24311. +        timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
  24312. +    }
  24313. +}
  24314. +
  24315. +/*
  24316. + * ---------------------------------------------------------------
  24317. + * Low level utility subroutines for the serial driver:  routines to
  24318. + * figure out the appropriate timeout for an interrupt chain, routines
  24319. + * to initialize and startup a serial port, and routines to shutdown a
  24320. + * serial port.  Useful stuff like that.
  24321. + * ---------------------------------------------------------------
  24322. + */
  24323. +
  24324. +/*
  24325. + * Grab all interrupts in preparation for doing an automatic irq
  24326. + * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a
  24327. + * mask of irq's which were grabbed and should therefore be freed
  24328. + * using free_all_interrupts().
  24329. + */
  24330. +static int grab_all_interrupts(int dontgrab)
  24331. +{
  24332. +    int             irq_lines = 0;
  24333. +    int            i, mask;
  24334. +
  24335. +    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
  24336. +        if (!(mask & dontgrab) && !request_irq(i, rs_probe, SA_INTERRUPT, "serial probe")) {
  24337. +            irq_lines |= mask;
  24338. +        }
  24339. +    }
  24340. +    return irq_lines;
  24341. +}
  24342. +
  24343. +/*
  24344. + * Release all interrupts grabbed by grab_all_interrupts
  24345. + */
  24346. +static void free_all_interrupts(int irq_lines)
  24347. +{
  24348. +    int    i;
  24349. +
  24350. +    for (i = 0; i < 16; i++) {
  24351. +        if (irq_lines & (1 << i))
  24352. +            free_irq(i);
  24353. +    }
  24354. +}
  24355. +
  24356. +/*
  24357. + * This routine figures out the correct timeout for a particular IRQ.
  24358. + * It uses the smallest timeout of all of the serial ports in a
  24359. + * particular interrupt chain.  Now only used for IRQ 0....
  24360. + */
  24361. +static void figure_IRQ_timeout(int irq)
  24362. +{
  24363. +    struct    async_struct    *info;
  24364. +    int    timeout = 6000;    /* 60 seconds === a long time :-) */
  24365. +
  24366. +    info = IRQ_ports[irq];
  24367. +    if (!info) {
  24368. +        IRQ_timeout[irq] = 6000;
  24369. +        return;
  24370. +    }
  24371. +    while (info) {
  24372. +        if (info->timeout < timeout)
  24373. +            timeout = info->timeout;
  24374. +        info = info->next_port;
  24375. +    }
  24376. +    if (!irq)
  24377. +        timeout = timeout / 2;
  24378. +    IRQ_timeout[irq] = timeout ? timeout : 1;
  24379. +}
  24380. +
  24381. +static int startup(struct async_struct * info)
  24382. +{
  24383. +    unsigned short ICP;
  24384. +    unsigned long flags;
  24385. +    int    retval;
  24386. +    void (*handler)(int);
  24387. +
  24388. +    if (info->flags & ASYNC_INITIALIZED)
  24389. +        return 0;
  24390. +
  24391. +    if (!info->port || !info->type) {
  24392. +        if (info->tty)
  24393. +            set_bit(TTY_IO_ERROR, &info->tty->flags);
  24394. +        return 0;
  24395. +    }
  24396. +
  24397. +    if (!info->xmit_buf) {
  24398. +        info->xmit_buf = (unsigned char *) kmalloc(SERIAL_XMIT_SIZE,GFP_KERNEL);
  24399. +        if (!info->xmit_buf)
  24400. +            return -ENOMEM;
  24401. +    }
  24402. +
  24403. +    save_flags(flags); cli();
  24404. +
  24405. +#ifdef SERIAL_DEBUG_OPEN
  24406. +    printk("starting up ttys%d (irq %d)...\n", info->line, info->irq);
  24407. +#endif
  24408. +
  24409. +    /*
  24410. +     * Clear the FIFO buffers and disable them
  24411. +     * (they will be reenabled in change_speed())
  24412. +     */
  24413. +    if (info->type == PORT_16550A) {
  24414. +        serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  24415. +                         UART_FCR_CLEAR_XMIT));
  24416. +        info->xmit_fifo_size = 16;
  24417. +    } else
  24418. +        info->xmit_fifo_size = 1;
  24419. +
  24420. +    /*
  24421. +     * At this point there's no way the LSR could still be 0xFF;
  24422. +     * if it is, then bail out, because there's likely no UART
  24423. +     * here.
  24424. +     */
  24425. +    if (serial_inp(info, UART_LSR) == 0xff) {
  24426. +        restore_flags(flags);
  24427. +        if (suser()) {
  24428. +            if (info->tty)
  24429. +                set_bit(TTY_IO_ERROR, &info->tty->flags);
  24430. +            return 0;
  24431. +        } else
  24432. +            return -ENODEV;
  24433. +    }
  24434. +
  24435. +    /*
  24436. +     * Allocate the IRQ if necessary
  24437. +     */
  24438. +    if (info->irq && (!IRQ_ports[info->irq] ||
  24439. +              !IRQ_ports[info->irq]->next_port)) {
  24440. +        if (IRQ_ports[info->irq]) {
  24441. +            free_irq(info->irq);
  24442. +            handler = rs_interrupt;
  24443. +        } else
  24444. +            handler = rs_interrupt_single;
  24445. +
  24446. +        retval = request_irq(info->irq, handler, SA_INTERRUPT, "serial");
  24447. +        if (retval) {
  24448. +            restore_flags(flags);
  24449. +            if (suser()) {
  24450. +                if (info->tty)
  24451. +                    set_bit(TTY_IO_ERROR,
  24452. +                        &info->tty->flags);
  24453. +                return 0;
  24454. +            } else
  24455. +                return retval;
  24456. +        }
  24457. +    }
  24458. +
  24459. +    /*
  24460. +     * Clear the interrupt registers.
  24461. +     */
  24462. +     /* (void) serial_inp(info, UART_LSR); */   /* (see above) */
  24463. +    (void) serial_inp(info, UART_RX);
  24464. +    (void) serial_inp(info, UART_IIR);
  24465. +    (void) serial_inp(info, UART_MSR);
  24466. +
  24467. +    /*
  24468. +     * Now, initialize the UART
  24469. +     */
  24470. +    serial_outp(info, UART_LCR, UART_LCR_WLEN8);    /* reset DLAB */
  24471. +    if (info->flags & ASYNC_FOURPORT) {
  24472. +        info->MCR = UART_MCR_DTR | UART_MCR_RTS;
  24473. +        info->MCR_noint = UART_MCR_DTR | UART_MCR_OUT1;
  24474. +    } else {
  24475. +        info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
  24476. +        info->MCR_noint = UART_MCR_DTR | UART_MCR_RTS;
  24477. +    }
  24478. +    if (info->irq == 0)
  24479. +        info->MCR = info->MCR_noint;
  24480. +    serial_outp(info, UART_MCR, info->MCR);
  24481. +
  24482. +    /*
  24483. +     * Finally, enable interrupts
  24484. +     */
  24485. +    info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
  24486. +    serial_outp(info, UART_IER, info->IER);    /* enable interrupts */
  24487. +
  24488. +    if (info->flags & ASYNC_FOURPORT) {
  24489. +        /* Enable interrupts on the AST Fourport board */
  24490. +        ICP = (info->port & 0xFE0) | 0x01F;
  24491. +        outb_p(0x80, ICP);
  24492. +        (void) inb_p(ICP);
  24493. +    }
  24494. +
  24495. +    /*
  24496. +     * And clear the interrupt registers again for luck.
  24497. +     */
  24498. +    (void)serial_inp(info, UART_LSR);
  24499. +    (void)serial_inp(info, UART_RX);
  24500. +    (void)serial_inp(info, UART_IIR);
  24501. +    (void)serial_inp(info, UART_MSR);
  24502. +
  24503. +    if (info->tty)
  24504. +        clear_bit(TTY_IO_ERROR, &info->tty->flags);
  24505. +    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
  24506. +
  24507. +    /*
  24508. +     * Insert serial port into IRQ chain.
  24509. +     */
  24510. +    info->prev_port = 0;
  24511. +    info->next_port = IRQ_ports[info->irq];
  24512. +    if (info->next_port)
  24513. +        info->next_port->prev_port = info;
  24514. +    IRQ_ports[info->irq] = info;
  24515. +    figure_IRQ_timeout(info->irq);
  24516. +
  24517. +    /*
  24518. +     * Set up serial timers...
  24519. +     */
  24520. +    timer_table[RS_TIMER].expires = jiffies + 2;
  24521. +    timer_active |= 1 << RS_TIMER;
  24522. +
  24523. +    /*
  24524. +     * and set the speed of the serial port
  24525. +     */
  24526. +    change_speed(info);
  24527. +
  24528. +    info->flags |= ASYNC_INITIALIZED;
  24529. +    restore_flags(flags);
  24530. +    return 0;
  24531. +}
  24532. +
  24533. +/*
  24534. + * This routine will shutdown a serial port; interrupts are disabled, and
  24535. + * DTR is dropped if the hangup on close termio flag is on.
  24536. + */
  24537. +static void shutdown(struct async_struct * info)
  24538. +{
  24539. +    unsigned long    flags;
  24540. +    int        retval;
  24541. +
  24542. +    if (!(info->flags & ASYNC_INITIALIZED))
  24543. +        return;
  24544. +#ifdef SERIAL_DEBUG_OPEN
  24545. +    printk("Shutting down serial port %d (irq %d)....\n", info->line,
  24546. +           info->irq);
  24547. +#endif
  24548. +
  24549. +    save_flags(flags); cli(); /* Disable interrupts */
  24550. +
  24551. +    /*
  24552. +     * First unlink the serial port from the IRQ chain...
  24553. +     */
  24554. +    if (info->next_port)
  24555. +        info->next_port->prev_port = info->prev_port;
  24556. +    if (info->prev_port)
  24557. +        info->prev_port->next_port = info->next_port;
  24558. +    else
  24559. +        IRQ_ports[info->irq] = info->next_port;
  24560. +    figure_IRQ_timeout(info->irq);
  24561. +
  24562. +    /*
  24563. +     * Free the IRQ, if necessary
  24564. +     */
  24565. +    if (info->irq && (!IRQ_ports[info->irq] ||
  24566. +              !IRQ_ports[info->irq]->next_port)) {
  24567. +        if (IRQ_ports[info->irq]) {
  24568. +            free_irq(info->irq);
  24569. +            retval = request_irq(info->irq, rs_interrupt_single, SA_INTERRUPT, "serial");
  24570. +
  24571. +            if (retval)
  24572. +                printk("serial shutdown: request_irq: error %d"
  24573. +                       "  Couldn't reacquire IRQ.\n", retval);
  24574. +        } else
  24575. +            free_irq(info->irq);
  24576. +    }
  24577. +    if (info->xmit_buf) {
  24578. +        kfree_s(info->xmit_buf, SERIAL_XMIT_SIZE);
  24579. +        info->xmit_buf = 0;
  24580. +    }
  24581. +
  24582. +    info->IER = 0;
  24583. +    serial_outp(info, UART_IER, 0x00);    /* disable all intrs */
  24584. +    if (info->flags & ASYNC_FOURPORT) {
  24585. +        /* reset interrupts on the AST Fourport board */
  24586. +        (void) inb((info->port & 0xFE0) | 0x01F);
  24587. +    }
  24588. +
  24589. +    if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
  24590. +        info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
  24591. +        info->MCR_noint &= ~(UART_MCR_DTR|UART_MCR_RTS);
  24592. +    }
  24593. +    serial_outp(info, UART_MCR, info->MCR_noint);
  24594. +
  24595. +    /* disable FIFO's */
  24596. +    serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  24597. +                     UART_FCR_CLEAR_XMIT));
  24598. +    (void)serial_in(info, UART_RX);    /* read data port to reset things */
  24599. +
  24600. +    if (info->tty)
  24601. +        set_bit(TTY_IO_ERROR, &info->tty->flags);
  24602. +
  24603. +    info->flags &= ~ASYNC_INITIALIZED;
  24604. +    restore_flags(flags);
  24605. +}
  24606. +
  24607. +/*
  24608. + * This routine is called to set the UART divisor registers to match
  24609. + * the specified baud rate for a serial port.
  24610. + */
  24611. +static void change_speed(struct async_struct *info)
  24612. +{
  24613. +    unsigned short port;
  24614. +    int    quot = 0;
  24615. +    unsigned cflag,cval,fcr;
  24616. +    int    i;
  24617. +
  24618. +    if (!info->tty || !info->tty->termios)
  24619. +        return;
  24620. +    cflag = info->tty->termios->c_cflag;
  24621. +    if (!(port = info->port))
  24622. +        return;
  24623. +    i = cflag & CBAUD;
  24624. +
  24625. +    if (i == 15) {
  24626. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
  24627. +            i += 1;
  24628. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
  24629. +            i += 2;
  24630. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
  24631. +            quot = info->custom_divisor;
  24632. +    }
  24633. +    if (quot) {
  24634. +        info->timeout = ((info->xmit_fifo_size*HZ*15*quot) /
  24635. +                 info->baud_base) + 2;
  24636. +    } else if (baud_table[i] == 134) {
  24637. +        quot = (2*info->baud_base / 269);
  24638. +        info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
  24639. +    } else if (baud_table[i]) {
  24640. +        quot = info->baud_base / baud_table[i];
  24641. +        info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
  24642. +    } else {
  24643. +        quot = 0;
  24644. +        info->timeout = 0;
  24645. +    }
  24646. +    if (quot) {
  24647. +        info->MCR |= UART_MCR_DTR;
  24648. +        info->MCR_noint |= UART_MCR_DTR;
  24649. +        cli();
  24650. +        serial_out(info, UART_MCR, info->MCR);
  24651. +        sti();
  24652. +    } else {
  24653. +        info->MCR &= ~UART_MCR_DTR;
  24654. +        info->MCR_noint &= ~UART_MCR_DTR;
  24655. +        cli();
  24656. +        serial_out(info, UART_MCR, info->MCR);
  24657. +        sti();
  24658. +        return;
  24659. +    }
  24660. +    /* byte size and parity */
  24661. +    cval = cflag & (CSIZE | CSTOPB);
  24662. +    cval >>= 4;
  24663. +    if (cflag & PARENB)
  24664. +        cval |= UART_LCR_PARITY;
  24665. +    if (!(cflag & PARODD))
  24666. +        cval |= UART_LCR_EPAR;
  24667. +    if (info->type == PORT_16550A) {
  24668. +        if ((info->baud_base / quot) < 2400)
  24669. +            fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
  24670. +        else
  24671. +            fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
  24672. +    } else
  24673. +        fcr = 0;
  24674. +
  24675. +    /* CTS flow control flag and modem status interrupts */
  24676. +    info->IER &= ~UART_IER_MSI;
  24677. +    if (cflag & CRTSCTS) {
  24678. +        info->flags |= ASYNC_CTS_FLOW;
  24679. +        info->IER |= UART_IER_MSI;
  24680. +    } else
  24681. +        info->flags &= ~ASYNC_CTS_FLOW;
  24682. +    if (cflag & CLOCAL)
  24683. +        info->flags &= ~ASYNC_CHECK_CD;
  24684. +    else {
  24685. +        info->flags |= ASYNC_CHECK_CD;
  24686. +        info->IER |= UART_IER_MSI;
  24687. +    }
  24688. +    serial_out(info, UART_IER, info->IER);
  24689. +
  24690. +    /*
  24691. +     * Set up parity check flag
  24692. +     */
  24693. +    info->read_status_mask = UART_LSR_OE;
  24694. +    if (I_INPCK(info->tty))
  24695. +        info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
  24696. +    if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
  24697. +        info->read_status_mask |= UART_LSR_BI;
  24698. +
  24699. +    info->ignore_status_mask = 0;
  24700. +    if (I_IGNPAR(info->tty))
  24701. +        info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
  24702. +    if (I_IGNBRK(info->tty)) {
  24703. +        info->ignore_status_mask |= UART_LSR_BI;
  24704. +        /*
  24705. +         * If we're ignore parity and break indicators, ignore
  24706. +         * overruns too.  (For real raw support).
  24707. +         */
  24708. +        if (I_IGNPAR(info->tty))
  24709. +            info->ignore_status_mask |= UART_LSR_OE;
  24710. +    }
  24711. +
  24712. +    cli();
  24713. +    serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);    /* set DLAB */
  24714. +    serial_outp(info, UART_DLL, quot & 0xff);    /* LS of divisor */
  24715. +    serial_outp(info, UART_DLM, quot >> 8);        /* MS of divisor */
  24716. +    serial_outp(info, UART_LCR, cval);        /* reset DLAB */
  24717. +    serial_outp(info, UART_FCR, fcr);     /* set fcr */
  24718. +    sti();
  24719. +}
  24720. +
  24721. +static void rs_put_char(struct tty_struct *tty, unsigned char ch)
  24722. +{
  24723. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  24724. +    unsigned long flags;
  24725. +
  24726. +    if (serial_paranoia_check(info, tty->device, "rs_put_char"))
  24727. +        return;
  24728. +
  24729. +    if (!tty || !info->xmit_buf)
  24730. +        return;
  24731. +
  24732. +    save_flags(flags); cli();
  24733. +    if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
  24734. +        restore_flags(flags);
  24735. +        return;
  24736. +    }
  24737. +
  24738. +    info->xmit_buf[info->xmit_head++] = ch;
  24739. +    info->xmit_head &= SERIAL_XMIT_SIZE-1;
  24740. +    info->xmit_cnt++;
  24741. +    restore_flags(flags);
  24742. +}
  24743. +
  24744. +static void rs_flush_chars(struct tty_struct *tty)
  24745. +{
  24746. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  24747. +    unsigned long flags;
  24748. +
  24749. +    if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
  24750. +        return;
  24751. +
  24752. +    if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
  24753. +        !info->xmit_buf)
  24754. +        return;
  24755. +
  24756. +    save_flags(flags); cli();
  24757. +    info->IER |= UART_IER_THRI;
  24758. +    serial_out(info, UART_IER, info->IER);
  24759. +    restore_flags(flags);
  24760. +}
  24761. +
  24762. +static int rs_write(struct tty_struct * tty, int from_user,
  24763. +            unsigned char *buf, int count)
  24764. +{
  24765. +    int    c, total = 0;
  24766. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  24767. +    unsigned long flags;
  24768. +
  24769. +    if (serial_paranoia_check(info, tty->device, "rs_write"))
  24770. +        return 0;
  24771. +
  24772. +    if (!tty || !info->xmit_buf || !tmp_buf)
  24773. +        return 0;
  24774. +
  24775. +    save_flags(flags);
  24776. +    while (1) {
  24777. +        cli();
  24778. +        c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
  24779. +                   SERIAL_XMIT_SIZE - info->xmit_head));
  24780. +        if (c <= 0)
  24781. +            break;
  24782. +
  24783. +        if (from_user) {
  24784. +            down(&tmp_buf_sem);
  24785. +            memcpy_fromfs(tmp_buf, buf, c);
  24786. +            c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
  24787. +                       SERIAL_XMIT_SIZE - info->xmit_head));
  24788. +            memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
  24789. +            up(&tmp_buf_sem);
  24790. +        } else
  24791. +            memcpy(info->xmit_buf + info->xmit_head, buf, c);
  24792. +        info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
  24793. +        info->xmit_cnt += c;
  24794. +        restore_flags(flags);
  24795. +        buf += c;
  24796. +        count -= c;
  24797. +        total += c;
  24798. +    }
  24799. +    if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
  24800. +        !(info->IER & UART_IER_THRI)) {
  24801. +        info->IER |= UART_IER_THRI;
  24802. +        serial_out(info, UART_IER, info->IER);
  24803. +    }
  24804. +    restore_flags(flags);
  24805. +    return total;
  24806. +}
  24807. +
  24808. +static int rs_write_room(struct tty_struct *tty)
  24809. +{
  24810. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  24811. +    int    ret;
  24812. +
  24813. +    if (serial_paranoia_check(info, tty->device, "rs_write_room"))
  24814. +        return 0;
  24815. +    ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
  24816. +    if (ret < 0)
  24817. +        ret = 0;
  24818. +    return ret;
  24819. +}
  24820. +
  24821. +static int rs_chars_in_buffer(struct tty_struct *tty)
  24822. +{
  24823. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  24824. +
  24825. +    if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
  24826. +        return 0;
  24827. +    return info->xmit_cnt;
  24828. +}
  24829. +
  24830. +static void rs_flush_buffer(struct tty_struct *tty)
  24831. +{
  24832. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  24833. +
  24834. +    if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
  24835. +        return;
  24836. +    cli();
  24837. +    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
  24838. +    sti();
  24839. +    wake_up_interruptible(&tty->write_wait);
  24840. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  24841. +        tty->ldisc.write_wakeup)
  24842. +        (tty->ldisc.write_wakeup)(tty);
  24843. +}
  24844. +
  24845. +/*
  24846. + * ------------------------------------------------------------
  24847. + * rs_throttle()
  24848. + *
  24849. + * This routine is called by the upper-layer tty layer to signal that
  24850. + * incoming characters should be throttled.
  24851. + * ------------------------------------------------------------
  24852. + */
  24853. +static void rs_throttle(struct tty_struct * tty)
  24854. +{
  24855. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  24856. +#ifdef SERIAL_DEBUG_THROTTLE
  24857. +    char    buf[64];
  24858. +
  24859. +    printk("throttle %s: %d....\n", _tty_name(tty, buf),
  24860. +           tty->ldisc.chars_in_buffer(tty));
  24861. +#endif
  24862. +
  24863. +    if (serial_paranoia_check(info, tty->device, "rs_throttle"))
  24864. +        return;
  24865. +
  24866. +    if (I_IXOFF(tty))
  24867. +        info->x_char = STOP_CHAR(tty);
  24868. +
  24869. +    info->MCR &= ~UART_MCR_RTS;
  24870. +    info->MCR_noint &= ~UART_MCR_RTS;
  24871. +    cli();
  24872. +    serial_out(info, UART_MCR, info->MCR);
  24873. +    sti();
  24874. +}
  24875. +
  24876. +static void rs_unthrottle(struct tty_struct * tty)
  24877. +{
  24878. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  24879. +#ifdef SERIAL_DEBUG_THROTTLE
  24880. +    char    buf[64];
  24881. +
  24882. +    printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
  24883. +           tty->ldisc.chars_in_buffer(tty));
  24884. +#endif
  24885. +
  24886. +    if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
  24887. +        return;
  24888. +
  24889. +    if (I_IXOFF(tty)) {
  24890. +        if (info->x_char)
  24891. +            info->x_char = 0;
  24892. +        else
  24893. +            info->x_char = START_CHAR(tty);
  24894. +    }
  24895. +    info->MCR |= UART_MCR_RTS;
  24896. +    info->MCR_noint |= UART_MCR_RTS;
  24897. +    cli();
  24898. +    serial_out(info, UART_MCR, info->MCR);
  24899. +    sti();
  24900. +}
  24901. +
  24902. +/*
  24903. + * ------------------------------------------------------------
  24904. + * rs_ioctl() and friends
  24905. + * ------------------------------------------------------------
  24906. + */
  24907. +
  24908. +static int get_serial_info(struct async_struct * info,
  24909. +               struct serial_struct * retinfo)
  24910. +{
  24911. +    struct serial_struct tmp;
  24912. +
  24913. +    if (!retinfo)
  24914. +        return -EFAULT;
  24915. +    memset(&tmp, 0, sizeof(tmp));
  24916. +    tmp.type = info->type;
  24917. +    tmp.line = info->line;
  24918. +    tmp.port = info->port;
  24919. +    tmp.irq = info->irq;
  24920. +    tmp.flags = info->flags;
  24921. +    tmp.baud_base = info->baud_base;
  24922. +    tmp.close_delay = info->close_delay;
  24923. +    tmp.custom_divisor = info->custom_divisor;
  24924. +    tmp.hub6 = info->hub6;
  24925. +    memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
  24926. +    return 0;
  24927. +}
  24928. +
  24929. +static int set_serial_info(struct async_struct * info,
  24930. +               struct serial_struct * new_info)
  24931. +{
  24932. +    struct serial_struct new_serial;
  24933. +    struct async_struct old_info;
  24934. +    unsigned int        i,change_irq,change_port;
  24935. +    int             retval = 0;
  24936. +
  24937. +    if (!new_info)
  24938. +        return -EFAULT;
  24939. +    memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
  24940. +    old_info = *info;
  24941. +
  24942. +    change_irq = new_serial.irq != info->irq;
  24943. +    change_port = (new_serial.port != info->port) || (new_serial.hub6 != info->hub6);
  24944. +
  24945. +    if (!suser()) {
  24946. +        if (change_irq || change_port ||
  24947. +            (new_serial.baud_base != info->baud_base) ||
  24948. +            (new_serial.type != info->type) ||
  24949. +            (new_serial.close_delay != info->close_delay) ||
  24950. +            ((new_serial.flags & ~ASYNC_USR_MASK) !=
  24951. +             (info->flags & ~ASYNC_USR_MASK)))
  24952. +            return -EPERM;
  24953. +        info->flags = ((info->flags & ~ASYNC_USR_MASK) |
  24954. +                   (new_serial.flags & ASYNC_USR_MASK));
  24955. +        info->custom_divisor = new_serial.custom_divisor;
  24956. +        goto check_and_exit;
  24957. +    }
  24958. +
  24959. +    if (new_serial.irq == 2)
  24960. +        new_serial.irq = 9;
  24961. +    if ((new_serial.irq > 31) || (new_serial.port > 0xffff) ||
  24962. +        (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
  24963. +        return -EINVAL;
  24964. +    }
  24965. +
  24966. +    /* Make sure address is not already in use */
  24967. +    if (new_serial.type) {
  24968. +        for (i = 0 ; i < NR_PORTS; i++)
  24969. +            if ((info != &rs_table[i]) &&
  24970. +                (rs_table[i].port == new_serial.port) &&
  24971. +                rs_table[i].type)
  24972. +                return -EADDRINUSE;
  24973. +    }
  24974. +
  24975. +    if ((change_port || change_irq) && (info->count > 1))
  24976. +        return -EBUSY;
  24977. +
  24978. +    /*
  24979. +     * OK, past this point, all the error checking has been done.
  24980. +     * At this point, we start making changes.....
  24981. +     */
  24982. +
  24983. +    info->baud_base = new_serial.baud_base;
  24984. +    info->flags = ((info->flags & ~ASYNC_FLAGS) |
  24985. +            (new_serial.flags & ASYNC_FLAGS));
  24986. +    info->custom_divisor = new_serial.custom_divisor;
  24987. +    info->type = new_serial.type;
  24988. +    info->close_delay = new_serial.close_delay;
  24989. +
  24990. +    if (change_port || change_irq) {
  24991. +        /*
  24992. +         * We need to shutdown the serial port at the old
  24993. +         * port/irq combination.
  24994. +         */
  24995. +        shutdown(info);
  24996. +        info->irq = new_serial.irq;
  24997. +        info->port = new_serial.port;
  24998. +        info->hub6 = new_serial.hub6;
  24999. +    }
  25000. +
  25001. +check_and_exit:
  25002. +    if (!info->port || !info->type)
  25003. +        return 0;
  25004. +    if (info->flags & ASYNC_INITIALIZED) {
  25005. +        if (((old_info.flags & ASYNC_SPD_MASK) !=
  25006. +             (info->flags & ASYNC_SPD_MASK)) ||
  25007. +            (old_info.custom_divisor != info->custom_divisor))
  25008. +            change_speed(info);
  25009. +    } else
  25010. +        retval = startup(info);
  25011. +    return retval;
  25012. +}
  25013. +
  25014. +static int get_modem_info(struct async_struct * info, unsigned int *value)
  25015. +{
  25016. +    unsigned char control, status;
  25017. +    unsigned int result;
  25018. +
  25019. +    control = info->MCR;
  25020. +    cli();
  25021. +    status = serial_in(info, UART_MSR);
  25022. +    sti();
  25023. +    result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
  25024. +        | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
  25025. +        | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
  25026. +        | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
  25027. +        | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
  25028. +        | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
  25029. +    put_fs_long(result,(unsigned long *) value);
  25030. +    return 0;
  25031. +}
  25032. +
  25033. +static int set_modem_info(struct async_struct * info, unsigned int cmd,
  25034. +              unsigned int *value)
  25035. +{
  25036. +    unsigned int arg = get_fs_long((unsigned long *) value);
  25037. +
  25038. +    switch (cmd) {
  25039. +    case TIOCMBIS:
  25040. +        if (arg & TIOCM_RTS) {
  25041. +            info->MCR |= UART_MCR_RTS;
  25042. +            info->MCR_noint |= UART_MCR_RTS;
  25043. +        }
  25044. +        if (arg & TIOCM_DTR) {
  25045. +            info->MCR |= UART_MCR_DTR;
  25046. +            info->MCR_noint |= UART_MCR_DTR;
  25047. +        }
  25048. +        break;
  25049. +    case TIOCMBIC:
  25050. +        if (arg & TIOCM_RTS) {
  25051. +            info->MCR &= ~UART_MCR_RTS;
  25052. +            info->MCR_noint &= ~UART_MCR_RTS;
  25053. +        }
  25054. +        if (arg & TIOCM_DTR) {
  25055. +            info->MCR &= ~UART_MCR_DTR;
  25056. +            info->MCR_noint &= ~UART_MCR_DTR;
  25057. +        }
  25058. +        break;
  25059. +    case TIOCMSET:
  25060. +        info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR))
  25061. +                 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
  25062. +                 | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
  25063. +        info->MCR_noint = ((info->MCR_noint
  25064. +                    & ~(UART_MCR_RTS | UART_MCR_DTR))
  25065. +                   | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
  25066. +                   | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
  25067. +        break;
  25068. +    default:
  25069. +        return -EINVAL;
  25070. +    }
  25071. +    cli();
  25072. +    serial_out(info, UART_MCR, info->MCR);
  25073. +    sti();
  25074. +    return 0;
  25075. +}
  25076. +
  25077. +static int do_autoconfig(struct async_struct * info)
  25078. +{
  25079. +    int            retval;
  25080. +
  25081. +    if (!suser())
  25082. +        return -EPERM;
  25083. +
  25084. +    if (info->count > 1)
  25085. +        return -EBUSY;
  25086. +
  25087. +    shutdown(info);
  25088. +
  25089. +    cli();
  25090. +    autoconfig(info);
  25091. +    sti();
  25092. +
  25093. +    retval = startup(info);
  25094. +    if (retval)
  25095. +        return retval;
  25096. +    return 0;
  25097. +}
  25098. +
  25099. +
  25100. +/*
  25101. + * This routine sends a break character out the serial port.
  25102. + */
  25103. +static void send_break(    struct async_struct * info, int duration)
  25104. +{
  25105. +    if (!info->port)
  25106. +        return;
  25107. +    current->state = TASK_INTERRUPTIBLE;
  25108. +    current->timeout = jiffies + duration;
  25109. +    cli();
  25110. +    serial_out(info, UART_LCR, serial_inp(info, UART_LCR) | UART_LCR_SBC);
  25111. +    schedule();
  25112. +    serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
  25113. +    sti();
  25114. +}
  25115. +
  25116. +/*
  25117. + * This routine returns a bitfield of "wild interrupts".  Basically,
  25118. + * any unclaimed interrupts which is flapping around.
  25119. + */
  25120. +static int check_wild_interrupts(int doprint)
  25121. +{
  25122. +    int    i, mask;
  25123. +    int    wild_interrupts = 0;
  25124. +    int    irq_lines;
  25125. +    unsigned long timeout;
  25126. +    unsigned long flags;
  25127. +
  25128. +    /* Turn on interrupts (they may be off) */
  25129. +    save_flags(flags); sti();
  25130. +
  25131. +    irq_lines = grab_all_interrupts(0);
  25132. +
  25133. +    /*
  25134. +     * Delay for 0.1 seconds -- we use a busy loop since this may
  25135. +     * occur during the bootup sequence
  25136. +     */
  25137. +    timeout = jiffies+10;
  25138. +    while (timeout >= jiffies)
  25139. +        ;
  25140. +
  25141. +    rs_triggered = 0;    /* Reset after letting things settle */
  25142. +
  25143. +    timeout = jiffies+10;
  25144. +    while (timeout >= jiffies)
  25145. +        ;
  25146. +
  25147. +    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
  25148. +        if ((rs_triggered & (1 << i)) &&
  25149. +            (irq_lines & (1 << i))) {
  25150. +            wild_interrupts |= mask;
  25151. +            if (doprint)
  25152. +                printk("Wild interrupt?  (IRQ %d)\n", i);
  25153. +        }
  25154. +    }
  25155. +    free_all_interrupts(irq_lines);
  25156. +    restore_flags(flags);
  25157. +    return wild_interrupts;
  25158. +}
  25159. +
  25160. +static int rs_ioctl(struct tty_struct *tty, struct file * file,
  25161. +            unsigned int cmd, unsigned long arg)
  25162. +{
  25163. +    int error;
  25164. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  25165. +    int retval;
  25166. +
  25167. +    if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
  25168. +        return -ENODEV;
  25169. +
  25170. +    switch (cmd) {
  25171. +        case TCSBRK:    /* SVID version: non-zero arg --> no break */
  25172. +            retval = tty_check_change(tty);
  25173. +            if (retval)
  25174. +                return retval;
  25175. +            tty_wait_until_sent(tty, 0);
  25176. +            if (!arg)
  25177. +                send_break(info, HZ/4);    /* 1/4 second */
  25178. +            return 0;
  25179. +        case TCSBRKP:    /* support for POSIX tcsendbreak() */
  25180. +            retval = tty_check_change(tty);
  25181. +            if (retval)
  25182. +                return retval;
  25183. +            tty_wait_until_sent(tty, 0);
  25184. +            send_break(info, arg ? arg*(HZ/10) : HZ/4);
  25185. +            return 0;
  25186. +        case TIOCGSOFTCAR:
  25187. +            error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
  25188. +            if (error)
  25189. +                return error;
  25190. +            put_fs_long(C_CLOCAL(tty) ? 1 : 0,
  25191. +                    (unsigned long *) arg);
  25192. +            return 0;
  25193. +        case TIOCSSOFTCAR:
  25194. +            arg = get_fs_long((unsigned long *) arg);
  25195. +            tty->termios->c_cflag =
  25196. +                ((tty->termios->c_cflag & ~CLOCAL) |
  25197. +                 (arg ? CLOCAL : 0));
  25198. +            return 0;
  25199. +        case TIOCMGET:
  25200. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  25201. +                sizeof(unsigned int));
  25202. +            if (error)
  25203. +                return error;
  25204. +            return get_modem_info(info, (unsigned int *) arg);
  25205. +        case TIOCMBIS:
  25206. +        case TIOCMBIC:
  25207. +        case TIOCMSET:
  25208. +            return set_modem_info(info, cmd, (unsigned int *) arg);
  25209. +        case TIOCGSERIAL:
  25210. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  25211. +                        sizeof(struct serial_struct));
  25212. +            if (error)
  25213. +                return error;
  25214. +            return get_serial_info(info,
  25215. +                           (struct serial_struct *) arg);
  25216. +        case TIOCSSERIAL:
  25217. +            return set_serial_info(info,
  25218. +                           (struct serial_struct *) arg);
  25219. +        case TIOCSERCONFIG:
  25220. +            return do_autoconfig(info);
  25221. +
  25222. +        case TIOCSERGWILD:
  25223. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  25224. +                        sizeof(int));
  25225. +            if (error)
  25226. +                return error;
  25227. +            put_fs_long(rs_wild_int_mask, (unsigned long *) arg);
  25228. +            return 0;
  25229. +
  25230. +        case TIOCSERSWILD:
  25231. +            if (!suser())
  25232. +                return -EPERM;
  25233. +            rs_wild_int_mask = get_fs_long((unsigned long *) arg);
  25234. +            if (rs_wild_int_mask < 0)
  25235. +                rs_wild_int_mask = check_wild_interrupts(0);
  25236. +            return 0;
  25237. +
  25238. +        case TIOCSERGSTRUCT:
  25239. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  25240. +                        sizeof(struct async_struct));
  25241. +            if (error)
  25242. +                return error;
  25243. +            memcpy_tofs((struct async_struct *) arg,
  25244. +                    info, sizeof(struct async_struct));
  25245. +            return 0;
  25246. +
  25247. +        default:
  25248. +            return -ENOIOCTLCMD;
  25249. +        }
  25250. +    return 0;
  25251. +}
  25252. +
  25253. +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
  25254. +{
  25255. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  25256. +
  25257. +    if (tty->termios->c_cflag == old_termios->c_cflag)
  25258. +        return;
  25259. +
  25260. +    change_speed(info);
  25261. +
  25262. +    if ((old_termios->c_cflag & CRTSCTS) &&
  25263. +        !(tty->termios->c_cflag & CRTSCTS)) {
  25264. +        tty->hw_stopped = 0;
  25265. +        rs_start(tty);
  25266. +    }
  25267. +
  25268. +    if (!(old_termios->c_cflag & CLOCAL) &&
  25269. +        (tty->termios->c_cflag & CLOCAL))
  25270. +        wake_up_interruptible(&info->open_wait);
  25271. +}
  25272. +
  25273. +/*
  25274. + * ------------------------------------------------------------
  25275. + * rs_close()
  25276. + *
  25277. + * This routine is called when the serial port gets closed.  First, we
  25278. + * wait for the last remaining data to be sent.  Then, we unlink its
  25279. + * async structure from the interrupt chain if necessary, and we free
  25280. + * that IRQ if nothing is left in the chain.
  25281. + * ------------------------------------------------------------
  25282. + */
  25283. +static void rs_close(struct tty_struct *tty, struct file * filp)
  25284. +{
  25285. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  25286. +    unsigned long flags;
  25287. +    unsigned long timeout;
  25288. +
  25289. +    if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
  25290. +        return;
  25291. +
  25292. +    save_flags(flags); cli();
  25293. +
  25294. +    if (tty_hung_up_p(filp)) {
  25295. +        restore_flags(flags);
  25296. +        return;
  25297. +    }
  25298. +
  25299. +#ifdef SERIAL_DEBUG_OPEN
  25300. +    printk("rs_close ttys%d, count = %d\n", info->line, info->count);
  25301. +#endif
  25302. +    if ((tty->count == 1) && (info->count != 1)) {
  25303. +        /*
  25304. +         * Uh, oh.  tty->count is 1, which means that the tty
  25305. +         * structure will be freed.  Info->count should always
  25306. +         * be one in these conditions.  If it's greater than
  25307. +         * one, we've got real problems, since it means the
  25308. +         * serial port won't be shutdown.
  25309. +         */
  25310. +        printk("rs_close: bad serial port count; tty->count is 1, "
  25311. +               "info->count is %d\n", info->count);
  25312. +        info->count = 1;
  25313. +    }
  25314. +    if (--info->count < 0) {
  25315. +        printk("rs_close: bad serial port count for ttys%d: %d\n",
  25316. +               info->line, info->count);
  25317. +        info->count = 0;
  25318. +    }
  25319. +    if (info->count) {
  25320. +        restore_flags(flags);
  25321. +        return;
  25322. +    }
  25323. +    info->flags |= ASYNC_CLOSING;
  25324. +    /*
  25325. +     * Save the termios structure, since this port may have
  25326. +     * separate termios for callout and dialin.
  25327. +     */
  25328. +    if (info->flags & ASYNC_NORMAL_ACTIVE)
  25329. +        info->normal_termios = *tty->termios;
  25330. +    if (info->flags & ASYNC_CALLOUT_ACTIVE)
  25331. +        info->callout_termios = *tty->termios;
  25332. +    if (info->flags & ASYNC_INITIALIZED) {
  25333. +        tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
  25334. +        /*
  25335. +         * Before we drop DTR, make sure the UART transmitter
  25336. +         * has completely drained; this is especially
  25337. +         * important if there is a transmit FIFO!
  25338. +         */
  25339. +        timeout = jiffies+HZ;
  25340. +        while (!(serial_inp(info, UART_LSR) & UART_LSR_TEMT)) {
  25341. +            current->state = TASK_INTERRUPTIBLE;
  25342. +            current->timeout = jiffies + info->timeout;
  25343. +            schedule();
  25344. +            if (jiffies > timeout)
  25345. +                break;
  25346. +        }
  25347. +    }
  25348. +    shutdown(info);
  25349. +    if (tty->driver.flush_buffer)
  25350. +        tty->driver.flush_buffer(tty);
  25351. +    if (tty->ldisc.flush_buffer)
  25352. +        tty->ldisc.flush_buffer(tty);
  25353. +    info->event = 0;
  25354. +    info->tty = 0;
  25355. +    if (tty->ldisc.num != ldiscs[N_TTY].num) {
  25356. +        if (tty->ldisc.close)
  25357. +            (tty->ldisc.close)(tty);
  25358. +        tty->ldisc = ldiscs[N_TTY];
  25359. +        tty->termios->c_line = N_TTY;
  25360. +        if (tty->ldisc.open)
  25361. +            (tty->ldisc.open)(tty);
  25362. +    }
  25363. +    if (info->blocked_open) {
  25364. +        if (info->close_delay) {
  25365. +            current->state = TASK_INTERRUPTIBLE;
  25366. +            current->timeout = jiffies + info->close_delay;
  25367. +            schedule();
  25368. +        }
  25369. +        wake_up_interruptible(&info->open_wait);
  25370. +    }
  25371. +    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
  25372. +             ASYNC_CLOSING);
  25373. +    wake_up_interruptible(&info->close_wait);
  25374. +    restore_flags(flags);
  25375. +}
  25376. +
  25377. +/*
  25378. + * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
  25379. + */
  25380. +void rs_hangup(struct tty_struct *tty)
  25381. +{
  25382. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  25383. +
  25384. +    if (serial_paranoia_check(info, tty->device, "rs_hangup"))
  25385. +        return;
  25386. +
  25387. +    shutdown(info);
  25388. +    info->event = 0;
  25389. +    info->count = 0;
  25390. +    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
  25391. +    info->tty = 0;
  25392. +    wake_up_interruptible(&info->open_wait);
  25393. +}
  25394. +
  25395. +/*
  25396. + * ------------------------------------------------------------
  25397. + * rs_open() and friends
  25398. + * ------------------------------------------------------------
  25399. + */
  25400. +static int block_til_ready(struct tty_struct *tty, struct file * filp,
  25401. +               struct async_struct *info)
  25402. +{
  25403. +    int        retval;
  25404. +    int        do_clocal = 0;
  25405. +    struct wait_queue wait = { current, NULL };
  25406. +
  25407. +    /*
  25408. +     * If the device is in the middle of being closed, then block
  25409. +     * until it's done, and then try again.
  25410. +     */
  25411. +    if (info->flags & ASYNC_CLOSING) {
  25412. +        interruptible_sleep_on(&info->close_wait);
  25413. +#ifdef SERIAL_DO_RESTART
  25414. +        if (info->flags & ASYNC_HUP_NOTIFY)
  25415. +            return -EAGAIN;
  25416. +        else
  25417. +            return -ERESTARTSYS;
  25418. +#else
  25419. +        return -EAGAIN;
  25420. +#endif
  25421. +    }
  25422. +
  25423. +    /*
  25424. +     * If this is a callout device, then just make sure the normal
  25425. +     * device isn't being used.
  25426. +     */
  25427. +    if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
  25428. +        if (info->flags & ASYNC_NORMAL_ACTIVE)
  25429. +            return -EBUSY;
  25430. +        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  25431. +            (info->flags & ASYNC_SESSION_LOCKOUT) &&
  25432. +            (info->session != current->session))
  25433. +            return -EBUSY;
  25434. +        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  25435. +            (info->flags & ASYNC_PGRP_LOCKOUT) &&
  25436. +            (info->pgrp != current->pgrp))
  25437. +            return -EBUSY;
  25438. +        info->flags |= ASYNC_CALLOUT_ACTIVE;
  25439. +        return 0;
  25440. +    }
  25441. +
  25442. +    /*
  25443. +     * If non-blocking mode is set, then make the check up front
  25444. +     * and then exit.
  25445. +     */
  25446. +    if (filp->f_flags & O_NONBLOCK) {
  25447. +        if (info->flags & ASYNC_CALLOUT_ACTIVE)
  25448. +            return -EBUSY;
  25449. +        info->flags |= ASYNC_NORMAL_ACTIVE;
  25450. +        return 0;
  25451. +    }
  25452. +
  25453. +    if (info->normal_termios.c_cflag & CLOCAL)
  25454. +        do_clocal = 1;
  25455. +
  25456. +    /*
  25457. +     * Block waiting for the carrier detect and the line to become
  25458. +     * free (i.e., not in use by the callout).  While we are in
  25459. +     * this loop, info->count is dropped by one, so that
  25460. +     * rs_close() knows when to free things.  We restore it upon
  25461. +     * exit, either normal or abnormal.
  25462. +     */
  25463. +    retval = 0;
  25464. +    add_wait_queue(&info->open_wait, &wait);
  25465. +#ifdef SERIAL_DEBUG_OPEN
  25466. +    printk("block_til_ready before block: ttys%d, count = %d\n",
  25467. +           info->line, info->count);
  25468. +#endif
  25469. +    info->count--;
  25470. +    info->blocked_open++;
  25471. +    while (1) {
  25472. +        cli();
  25473. +        if (!(info->flags & ASYNC_CALLOUT_ACTIVE))
  25474. +            serial_out(info, UART_MCR,
  25475. +                   serial_inp(info, UART_MCR) |
  25476. +                   (UART_MCR_DTR | UART_MCR_RTS));
  25477. +        sti();
  25478. +        current->state = TASK_INTERRUPTIBLE;
  25479. +        if (tty_hung_up_p(filp) ||
  25480. +            !(info->flags & ASYNC_INITIALIZED)) {
  25481. +#ifdef SERIAL_DO_RESTART
  25482. +            if (info->flags & ASYNC_HUP_NOTIFY)
  25483. +                retval = -EAGAIN;
  25484. +            else
  25485. +                retval = -ERESTARTSYS;
  25486. +#else
  25487. +            retval = -EAGAIN;
  25488. +#endif
  25489. +            break;
  25490. +        }
  25491. +        if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
  25492. +            !(info->flags & ASYNC_CLOSING) &&
  25493. +            (do_clocal || (serial_in(info, UART_MSR) &
  25494. +                   UART_MSR_DCD)))
  25495. +            break;
  25496. +        if (current->signal & ~current->blocked) {
  25497. +            retval = -ERESTARTSYS;
  25498. +            break;
  25499. +        }
  25500. +#ifdef SERIAL_DEBUG_OPEN
  25501. +        printk("block_til_ready blocking: ttys%d, count = %d\n",
  25502. +               info->line, info->count);
  25503. +#endif
  25504. +        schedule();
  25505. +    }
  25506. +    current->state = TASK_RUNNING;
  25507. +    remove_wait_queue(&info->open_wait, &wait);
  25508. +    if (!tty_hung_up_p(filp))
  25509. +        info->count++;
  25510. +    info->blocked_open--;
  25511. +#ifdef SERIAL_DEBUG_OPEN
  25512. +    printk("block_til_ready after blocking: ttys%d, count = %d\n",
  25513. +           info->line, info->count);
  25514. +#endif
  25515. +    if (retval)
  25516. +        return retval;
  25517. +    info->flags |= ASYNC_NORMAL_ACTIVE;
  25518. +    return 0;
  25519. +}
  25520. +
  25521. +/*
  25522. + * This routine is called whenever a serial port is opened.  It
  25523. + * enables interrupts for a serial port, linking in its async structure into
  25524. + * the IRQ chain.   It also performs the serial-specific
  25525. + * initialization for the tty structure.
  25526. + */
  25527. +int rs_open(struct tty_struct *tty, struct file * filp)
  25528. +{
  25529. +    struct async_struct    *info;
  25530. +    int             retval, line;
  25531. +
  25532. +    line = MINOR(tty->device) - tty->driver.minor_start;
  25533. +    if ((line < 0) || (line >= NR_PORTS))
  25534. +        return -ENODEV;
  25535. +    info = rs_table + line;
  25536. +    if (serial_paranoia_check(info, tty->device, "rs_open"))
  25537. +        return -ENODEV;
  25538. +
  25539. +#ifdef SERIAL_DEBUG_OPEN
  25540. +    printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
  25541. +           info->count);
  25542. +#endif
  25543. +    info->count++;
  25544. +    tty->driver_data = info;
  25545. +    info->tty = tty;
  25546. +
  25547. +    if (!tmp_buf) {
  25548. +        tmp_buf = (unsigned char *) kmalloc(SERIAL_XMIT_SIZE,GFP_KERNEL);
  25549. +        if (!tmp_buf)
  25550. +            return -ENOMEM;
  25551. +    }
  25552. +
  25553. +    /*
  25554. +     * Start up serial port
  25555. +     */
  25556. +    retval = startup(info);
  25557. +    if (retval)
  25558. +        return retval;
  25559. +
  25560. +    retval = block_til_ready(tty, filp, info);
  25561. +    if (retval) {
  25562. +#ifdef SERIAL_DEBUG_OPEN
  25563. +        printk("rs_open returning after block_til_ready with %d\n",
  25564. +               retval);
  25565. +#endif
  25566. +        return retval;
  25567. +    }
  25568. +
  25569. +    if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
  25570. +        if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
  25571. +            *tty->termios = info->normal_termios;
  25572. +        else
  25573. +            *tty->termios = info->callout_termios;
  25574. +        change_speed(info);
  25575. +    }
  25576. +
  25577. +    info->session = current->session;
  25578. +    info->pgrp = current->pgrp;
  25579. +
  25580. +#ifdef SERIAL_DEBUG_OPEN
  25581. +    printk("rs_open ttys%d successful...\n", info->line);
  25582. +#endif
  25583. +    return 0;
  25584. +}
  25585. +
  25586. +/*
  25587. + * ---------------------------------------------------------------------
  25588. + * rs_init() and friends
  25589. + *
  25590. + * rs_init() is called at boot-time to initialize the serial driver.
  25591. + * ---------------------------------------------------------------------
  25592. + */
  25593. +
  25594. +/*
  25595. + * This routine prints out the appropriate serial driver version
  25596. + * number, and identifies which options were configured into this
  25597. + * driver.
  25598. + */
  25599. +static void show_serial_version(void)
  25600. +{
  25601. +    printk("Serial driver version 4.00 with");
  25602. +#ifdef CONFIG_HUB6
  25603. +    printk(" HUB-6");
  25604. +#define SERIAL_OPT
  25605. +#endif
  25606. +#ifdef SERIAL_OPT
  25607. +    printk(" enabled\n");
  25608. +#else
  25609. +    printk(" no serial options enabled\n");
  25610. +#endif
  25611. +#undef SERIAL_OPT
  25612. +}
  25613. +
  25614. +/*
  25615. + * This routine is called by do_auto_irq(); it attempts to determine
  25616. + * which interrupt a serial port is configured to use.  It is not
  25617. + * fool-proof, but it works a large part of the time.
  25618. + */
  25619. +static int get_auto_irq(struct async_struct *info)
  25620. +{
  25621. +    unsigned char save_MCR, save_IER, save_ICP=0;
  25622. +    unsigned short ICP=0, port = info->port;
  25623. +    unsigned long timeout;
  25624. +
  25625. +    /*
  25626. +     * Enable interrupts and see who answers
  25627. +     */
  25628. +    rs_irq_triggered = 0;
  25629. +    cli();
  25630. +    save_IER = serial_inp(info, UART_IER);
  25631. +    save_MCR = serial_inp(info, UART_MCR);
  25632. +    if (info->flags & ASYNC_FOURPORT)  {
  25633. +        serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
  25634. +        serial_outp(info, UART_IER, 0x0f);    /* enable all intrs */
  25635. +        ICP = (port & 0xFE0) | 0x01F;
  25636. +        save_ICP = inb_p(ICP);
  25637. +        outb_p(0x80, ICP);
  25638. +        (void) inb_p(ICP);
  25639. +    } else {
  25640. +        serial_outp(info, UART_MCR,
  25641. +                UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
  25642. +        serial_outp(info, UART_IER, 0x0f);    /* enable all intrs */
  25643. +    }
  25644. +    sti();
  25645. +    /*
  25646. +     * Next, clear the interrupt registers.
  25647. +     */
  25648. +    (void)serial_inp(info, UART_LSR);
  25649. +    (void)serial_inp(info, UART_RX);
  25650. +    (void)serial_inp(info, UART_IIR);
  25651. +    (void)serial_inp(info, UART_MSR);
  25652. +
  25653. +    timeout = jiffies+2;
  25654. +    while (timeout >= jiffies) {
  25655. +        if (rs_irq_triggered)
  25656. +            break;
  25657. +    }
  25658. +    /*
  25659. +     * Now check to see if we got any business, and clean up.
  25660. +     */
  25661. +    cli();
  25662. +    serial_outp(info, UART_IER, save_IER);
  25663. +    serial_outp(info, UART_MCR, save_MCR);
  25664. +    if (info->flags & ASYNC_FOURPORT)
  25665. +        outb_p(save_ICP, ICP);
  25666. +    sti();
  25667. +    return(rs_irq_triggered);
  25668. +}
  25669. +
  25670. +/*
  25671. + * Calls get_auto_irq() multiple times, to make sure we don't get
  25672. + * faked out by random interrupts
  25673. + */
  25674. +static int do_auto_irq(struct async_struct * info)
  25675. +{
  25676. +    unsigned         port = info->port;
  25677. +    int             irq_lines = 0;
  25678. +    int            irq_try_1 = 0, irq_try_2 = 0;
  25679. +    int            retries;
  25680. +    unsigned long flags;
  25681. +
  25682. +    if (!port)
  25683. +        return 0;
  25684. +
  25685. +    /* Turn on interrupts (they may be off) */
  25686. +    save_flags(flags); sti();
  25687. +
  25688. +    irq_lines = grab_all_interrupts(rs_wild_int_mask);
  25689. +
  25690. +    for (retries = 0; retries < 5; retries++) {
  25691. +        if (!irq_try_1)
  25692. +            irq_try_1 = get_auto_irq(info);
  25693. +        if (!irq_try_2)
  25694. +            irq_try_2 = get_auto_irq(info);
  25695. +        if (irq_try_1 && irq_try_2) {
  25696. +            if (irq_try_1 == irq_try_2)
  25697. +                break;
  25698. +            irq_try_1 = irq_try_2 = 0;
  25699. +        }
  25700. +    }
  25701. +    restore_flags(flags);
  25702. +    free_all_interrupts(irq_lines);
  25703. +    return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
  25704. +}
  25705. +
  25706. +/*
  25707. + * This routine is called by rs_init() to initialize a specific serial
  25708. + * port.  It determines what type of UART ship this serial port is
  25709. + * using: 8250, 16450, 16550, 16550A.  The important question is
  25710. + * whether or not this UART is a 16550A or not, since this will
  25711. + * determine whether or not we can use its FIFO features or not.
  25712. + */
  25713. +static void autoconfig(struct async_struct * info)
  25714. +{
  25715. +    unsigned char status1, status2, scratch, scratch2;
  25716. +    unsigned port = info->port;
  25717. +    unsigned long flags;
  25718. +
  25719. +    info->type = PORT_UNKNOWN;
  25720. +
  25721. +    if (!port)
  25722. +        return;
  25723. +
  25724. +    save_flags(flags); cli();
  25725. +
  25726. +    /*
  25727. +     * Do a simple existence test first; if we fail this, there's
  25728. +     * no point trying anything else.
  25729. +     *
  25730. +     * 0x80 is used as a nonsense port to prevent against false
  25731. +     * positives due to ISA bus float.  The assumption is that
  25732. +     * 0x80 is a non-existent port; which should be safe since
  25733. +     * include/asm/io.h also makes this assumption.
  25734. +     */
  25735. +    scratch = serial_inp(info, UART_IER);
  25736. +    serial_outp(info, UART_IER, 0);
  25737. +    outb(0xff, 0x080);
  25738. +    scratch2 = serial_inp(info, UART_IER);
  25739. +    serial_outp(info, UART_IER, scratch);
  25740. +    if (scratch2) {
  25741. +        restore_flags(flags);
  25742. +        return;        /* We failed; there's nothing here */
  25743. +    }
  25744. +
  25745. +    /*
  25746. +     * Check to see if a UART is really there.  Certain broken
  25747. +     * internal modems based on the Rockwell chipset fail this
  25748. +     * test, because they apparently don't implement the loopback
  25749. +     * test mode.  So this test is skipped on the COM 1 through
  25750. +     * COM 4 ports.  This *should* be safe, since no board
  25751. +     * manufacturer would be stupid enough to design a board
  25752. +     * that conflicts with COM 1-4 --- we hope!
  25753. +     */
  25754. +    if (!(info->flags & ASYNC_SKIP_TEST)) {
  25755. +        scratch = serial_inp(info, UART_MCR);
  25756. +        serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
  25757. +        scratch2 = serial_inp(info, UART_MSR);
  25758. +        serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
  25759. +        status1 = serial_inp(info, UART_MSR) & 0xF0;
  25760. +        serial_outp(info, UART_MCR, scratch);
  25761. +        serial_outp(info, UART_MSR, scratch2);
  25762. +        if (status1 != 0x90) {
  25763. +            restore_flags(flags);
  25764. +            return;
  25765. +        }
  25766. +    }
  25767. +
  25768. +    /*
  25769. +     * If the AUTO_IRQ flag is set, try to do the automatic IRQ
  25770. +     * detection.
  25771. +     */
  25772. +    if (info->flags & ASYNC_AUTO_IRQ)
  25773. +        info->irq = do_auto_irq(info);
  25774. +
  25775. +    serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
  25776. +    scratch = serial_in(info, UART_IIR) >> 6;
  25777. +    info->xmit_fifo_size = 1;
  25778. +    switch (scratch) {
  25779. +        case 0:
  25780. +            info->type = PORT_16450;
  25781. +            break;
  25782. +        case 1:
  25783. +            info->type = PORT_UNKNOWN;
  25784. +            break;
  25785. +        case 2:
  25786. +            info->type = PORT_16550;
  25787. +            break;
  25788. +        case 3:
  25789. +            info->type = PORT_16550A;
  25790. +            info->xmit_fifo_size = 16;
  25791. +            break;
  25792. +    }
  25793. +    if (info->type == PORT_16450) {
  25794. +        scratch = serial_in(info, UART_SCR);
  25795. +        serial_outp(info, UART_SCR, 0xa5);
  25796. +        status1 = serial_in(info, UART_SCR);
  25797. +        serial_outp(info, UART_SCR, 0x5a);
  25798. +        status2 = serial_in(info, UART_SCR);
  25799. +        serial_outp(info, UART_SCR, scratch);
  25800. +
  25801. +        if ((status1 != 0xa5) || (status2 != 0x5a))
  25802. +            info->type = PORT_8250;
  25803. +    }
  25804. +
  25805. +    /*
  25806. +     * Reset the UART.
  25807. +     */
  25808. +    serial_outp(info, UART_MCR, 0x00);
  25809. +    serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  25810. +                     UART_FCR_CLEAR_XMIT));
  25811. +    (void)serial_in(info, UART_RX);
  25812. +
  25813. +    restore_flags(flags);
  25814. +}
  25815. +
  25816. +/*
  25817. + * The serial driver boot-time initialization code!
  25818. + */
  25819. +long rs_init(long kmem_start)
  25820. +{
  25821. +    int i;
  25822. +    struct async_struct * info;
  25823. +
  25824. +    bh_base[SERIAL_BH].routine = do_serial_bh;
  25825. +    enable_bh(SERIAL_BH);
  25826. +    timer_table[RS_TIMER].fn = rs_timer;
  25827. +    timer_table[RS_TIMER].expires = 0;
  25828. +#ifdef CONFIG_AUTO_IRQ
  25829. +    rs_wild_int_mask = check_wild_interrupts(1);
  25830. +#endif
  25831. +
  25832. +    for (i = 0; i < 16; i++) {
  25833. +        IRQ_ports[i] = 0;
  25834. +        IRQ_timeout[i] = 0;
  25835. +    }
  25836. +
  25837. +    show_serial_version();
  25838. +
  25839. +    /* Initialize the tty_driver structure */
  25840. +
  25841. +    memset(&serial_driver, 0, sizeof(struct tty_driver));
  25842. +    serial_driver.magic = TTY_DRIVER_MAGIC;
  25843. +    serial_driver.name = "ttyS";
  25844. +    serial_driver.major = TTY_MAJOR;
  25845. +    serial_driver.minor_start = 64;
  25846. +    serial_driver.num = NR_PORTS;
  25847. +    serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
  25848. +    serial_driver.subtype = SERIAL_TYPE_NORMAL;
  25849. +    serial_driver.init_termios = tty_std_termios;
  25850. +    serial_driver.init_termios.c_cflag =
  25851. +        B9600 | CS8 | CREAD | HUPCL | CLOCAL;
  25852. +    serial_driver.flags = TTY_DRIVER_REAL_RAW;
  25853. +    serial_driver.refcount = &serial_refcount;
  25854. +    serial_driver.table = serial_table;
  25855. +    serial_driver.termios = serial_termios;
  25856. +    serial_driver.termios_locked = serial_termios_locked;
  25857. +
  25858. +    serial_driver.open = rs_open;
  25859. +    serial_driver.close = rs_close;
  25860. +    serial_driver.write = rs_write;
  25861. +    serial_driver.put_char = rs_put_char;
  25862. +    serial_driver.flush_chars = rs_flush_chars;
  25863. +    serial_driver.write_room = rs_write_room;
  25864. +    serial_driver.chars_in_buffer = rs_chars_in_buffer;
  25865. +    serial_driver.flush_buffer = rs_flush_buffer;
  25866. +    serial_driver.ioctl = rs_ioctl;
  25867. +    serial_driver.throttle = rs_throttle;
  25868. +    serial_driver.unthrottle = rs_unthrottle;
  25869. +    serial_driver.set_termios = rs_set_termios;
  25870. +    serial_driver.stop = rs_stop;
  25871. +    serial_driver.start = rs_start;
  25872. +    serial_driver.hangup = rs_hangup;
  25873. +
  25874. +    /*
  25875. +     * The callout device is just like normal device except for
  25876. +     * major number and the subtype code.
  25877. +     */
  25878. +    callout_driver = serial_driver;
  25879. +    callout_driver.name = "cua";
  25880. +    callout_driver.major = TTYAUX_MAJOR;
  25881. +    callout_driver.subtype = SERIAL_TYPE_CALLOUT;
  25882. +
  25883. +    if (tty_register_driver(&serial_driver))
  25884. +        panic("Couldn't register serial driver\n");
  25885. +    if (tty_register_driver(&callout_driver))
  25886. +        panic("Couldn't register callout driver\n");
  25887. +
  25888. +    for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
  25889. +        info->magic = SERIAL_MAGIC;
  25890. +        info->line = i;
  25891. +        info->tty = 0;
  25892. +        info->type = PORT_UNKNOWN;
  25893. +        info->custom_divisor = 0;
  25894. +        info->close_delay = 50;
  25895. +        info->x_char = 0;
  25896. +        info->event = 0;
  25897. +        info->count = 0;
  25898. +        info->blocked_open = 0;
  25899. +        info->tqueue.routine = do_softint;
  25900. +        info->tqueue.data = info;
  25901. +        info->callout_termios =callout_driver.init_termios;
  25902. +        info->normal_termios = serial_driver.init_termios;
  25903. +        info->open_wait = 0;
  25904. +        info->close_wait = 0;
  25905. +        info->next_port = 0;
  25906. +        info->prev_port = 0;
  25907. +        if (info->irq == 2)
  25908. +            info->irq = 9;
  25909. +        if (!(info->flags & ASYNC_BOOT_AUTOCONF))
  25910. +            continue;
  25911. +        autoconfig(info);
  25912. +        if (info->type == PORT_UNKNOWN)
  25913. +            continue;
  25914. +        printk("tty%02d%s at 0x%04x (irq = %d)", info->line,
  25915. +               (info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
  25916. +               info->port, info->irq);
  25917. +        switch (info->type) {
  25918. +            case PORT_8250:
  25919. +                printk(" is a 8250\n");
  25920. +                break;
  25921. +            case PORT_16450:
  25922. +                printk(" is a 16450\n");
  25923. +                break;
  25924. +            case PORT_16550:
  25925. +                printk(" is a 16550\n");
  25926. +                break;
  25927. +            case PORT_16550A:
  25928. +                printk(" is a 16550A\n");
  25929. +                break;
  25930. +            default:
  25931. +                printk("\n");
  25932. +                break;
  25933. +        }
  25934. +    }
  25935. +    return kmem_start;
  25936. +}
  25937. +
  25938. +/*
  25939. + * register_serial and unregister_serial allows for serial ports to be
  25940. + * configured at run-time, to support PCMCIA modems.
  25941. + */
  25942. +int register_serial(struct serial_struct *req)
  25943. +{
  25944. +    int i;
  25945. +    unsigned long flags;
  25946. +    struct async_struct *info;
  25947. +
  25948. +    save_flags(flags);
  25949. +    cli();
  25950. +    for (i = 0; i < NR_PORTS; i++) {
  25951. +        if (rs_table[i].port == req->port)
  25952. +            break;
  25953. +    }
  25954. +    if (i == NR_PORTS) {
  25955. +        for (i = 0; i < NR_PORTS; i++)
  25956. +            if ((rs_table[i].type == PORT_UNKNOWN) &&
  25957. +                (rs_table[i].count == 0))
  25958. +                break;
  25959. +    }
  25960. +    if (i == NR_PORTS) {
  25961. +        restore_flags(flags);
  25962. +        return -1;
  25963. +    }
  25964. +    info = &rs_table[i];
  25965. +    if (rs_table[i].count) {
  25966. +        restore_flags(flags);
  25967. +        printk("Couldn't configure serial #%d (port=%d,irq=%d): "
  25968. +               "device already open\n", i, req->port, req->irq);
  25969. +        return -1;
  25970. +    }
  25971. +    info->irq = req->irq;
  25972. +    info->port = req->port;
  25973. +    autoconfig(info);
  25974. +    if (info->type == PORT_UNKNOWN) {
  25975. +        restore_flags(flags);
  25976. +        printk("register_serial(): autoconfig failed\n");
  25977. +        return -1;
  25978. +    }
  25979. +    printk("tty%02d at 0x%04x (irq = %d)", info->line,
  25980. +           info->port, info->irq);
  25981. +    switch (info->type) {
  25982. +    case PORT_8250:
  25983. +        printk(" is a 8250\n"); break;
  25984. +    case PORT_16450:
  25985. +        printk(" is a 16450\n"); break;
  25986. +    case PORT_16550:
  25987. +        printk(" is a 16550\n"); break;
  25988. +    case PORT_16550A:
  25989. +        printk(" is a 16550A\n"); break;
  25990. +    default:
  25991. +        printk("\n"); break;
  25992. +    }
  25993. +    restore_flags(flags);
  25994. +    return info->line;
  25995. +}
  25996. +
  25997. +void unregister_serial(int line)
  25998. +{
  25999. +    unsigned long flags;
  26000. +    struct async_struct *info = &rs_table[line];
  26001. +
  26002. +    save_flags(flags);
  26003. +    cli();
  26004. +    if (info->tty)
  26005. +        tty_hangup(info->tty);
  26006. +    info->type = PORT_UNKNOWN;
  26007. +    printk("tty%02d unloaded\n", info->line);
  26008. +    restore_flags(flags);
  26009. +}
  26010. diff -r -u -N linux.orig/arch/arm/drivers/char/tty_diff linux.arm/arch/arm/drivers/char/tty_diff
  26011. --- linux.orig/arch/arm/drivers/char/tty_diff    Thu Jan  1 01:00:00 1970
  26012. +++ linux.arm/arch/arm/drivers/char/tty_diff    Fri Oct 27 23:14:40 1995
  26013. @@ -0,0 +1,605 @@
  26014. +--- tty_io.c    Fri Jul 14 00:07:27 1995
  26015. ++++ ../../../../drivers/char/tty_io.c    Sun Sep 24 11:09:57 1995
  26016. +@@ -52,6 +52,7 @@
  26017. + #include <linux/mm.h>
  26018. + #include <linux/string.h>
  26019. + #include <linux/malloc.h>
  26020. ++#include <linux/config.h>
  26021. + #include <asm/segment.h>
  26022. + #include <asm/system.h>
  26023. +@@ -59,18 +60,27 @@
  26024. + #include "kbd_kern.h"
  26025. + #include "vt_kern.h"
  26026. ++/* This to come */
  26027. ++/*#include "selection.h"*/
  26028. + #define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
  26029. + #define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
  26030. + #undef TTY_DEBUG_HANGUP
  26031. ++/* These to go */
  26032. + extern int set_selection(const int arg, struct tty_struct *tty);
  26033. + extern int paste_selection(struct tty_struct *tty);
  26034. + extern int sel_loadlut(const int arg);
  26035. + extern int mouse_reporting(void);
  26036. + extern int shift_state;
  26037. + extern int do_screendump(int arg);
  26038. ++#define TTY_PARANOIA_CHECK
  26039. ++#define CHECK_TTY_COUNT
  26040. ++
  26041. ++extern void do_blank_screen(int nopowersave);
  26042. ++extern void do_unblank_screen(void);
  26043. ++/*extern void set_vesa_blanking(const unsigned long arg);*/
  26044. + struct termios tty_std_termios;        /* for the benefit of tty drivers  */
  26045. + struct tty_driver *tty_drivers = NULL;    /* linked list of tty drivers */
  26046. +@@ -78,10 +80,12 @@
  26047. + /*
  26048. +  * fg_console is the current virtual console,
  26049. ++ * last_console is the last used one
  26050. +  * redirect is the pseudo-tty that console output
  26051. +  * is redirected to if asked by TIOCCONS.
  26052. +  */
  26053. + int fg_console = 0;
  26054. ++int last_console = 0;
  26055. + struct tty_struct * redirect = NULL;
  26056. + struct wait_queue * keypress_wait = NULL;
  26057. +@@ -123,8 +127,6 @@
  26058. +     return(_tty_name(tty, buf));
  26059. + }
  26060. +-#define TTY_PARANOIA_CHECK
  26061. +-
  26062. + inline int tty_paranoia_check(struct tty_struct *tty, dev_t device,
  26063. +                   const char *routine)
  26064. + {
  26065. +@@ -146,18 +148,45 @@
  26066. +     return 0;
  26067. + }
  26068. ++static int check_tty_count(struct tty_struct *tty, const char *routine)
  26069. ++{
  26070. ++#ifdef CHECK_TTY_COUNT
  26071. ++    struct file *f;
  26072. ++    int i, count = 0;
  26073. ++    
  26074. ++    for (f = first_file, i=0; i<nr_files; i++, f = f->f_next) {
  26075. ++        if (!f->f_count)
  26076. ++            continue;
  26077. ++        if (f->private_data == tty) {
  26078. ++            count++;
  26079. ++        }
  26080. ++    }
  26081. ++    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  26082. ++        tty->driver.subtype == PTY_TYPE_SLAVE &&
  26083. ++        tty->link && tty->link->count)
  26084. ++        count++;
  26085. ++    if (tty->count != count) {
  26086. ++        printk("Warning: dev (%d, %d) tty->count(%d) != #fd's(%d) in %s\n",
  26087. ++               MAJOR(tty->device), MINOR(tty->device), tty->count,
  26088. ++               count, routine);
  26089. ++        return count;
  26090. ++       }    
  26091. ++#endif
  26092. ++    return 0;
  26093. ++}
  26094. ++
  26095. + int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
  26096. + {
  26097. +     if (disc < N_TTY || disc >= NR_LDISCS)
  26098. +         return -EINVAL;
  26099. +
  26100. +     if (new_ldisc) {
  26101. +         ldiscs[disc] = *new_ldisc;
  26102. +         ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
  26103. +         ldiscs[disc].num = disc;
  26104. +     } else
  26105. +         memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
  26106. +
  26107. +     return 0;
  26108. + }
  26109. +@@ -175,6 +204,8 @@
  26110. +         return 0;    /* We are already in the desired discipline */
  26111. +     o_ldisc = tty->ldisc;
  26112. ++    tty_wait_until_sent(tty, 0);
  26113. ++    
  26114. +     /* Shutdown the current discipline. */
  26115. +     if (tty->ldisc.close)
  26116. +         (tty->ldisc.close)(tty);
  26117. +@@ -313,6 +344,7 @@
  26118. +     if (!tty)
  26119. +         return;
  26120. ++    check_tty_count(tty, "do_tty_hangup");
  26121. +     for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) {
  26122. +         if (!filp->f_count)
  26123. +             continue;
  26124. +@@ -352,18 +384,22 @@
  26125. +                        -i);
  26126. +         }
  26127. +     }
  26128. +-
  26129. +-    if (tty->session > 0) {
  26130. +-        kill_sl(tty->session,SIGHUP,1);
  26131. +-        kill_sl(tty->session,SIGCONT,1);
  26132. +-    }
  26133. +-    tty->flags = 0;
  26134. +-    tty->session = 0;
  26135. +-    tty->pgrp = -1;
  26136. ++    
  26137. +      for_each_task(p) {
  26138. ++        if ((tty->session > 0) && (p->session == tty->session) &&
  26139. ++            p->leader) {
  26140. ++            send_sig(SIGHUP,p,1);
  26141. ++            send_sig(SIGCONT,p,1);
  26142. ++            if (tty->pgrp > 0)
  26143. ++                p->tty_old_pgrp = tty->pgrp;
  26144. ++        }
  26145. +         if (p->tty == tty)
  26146. +             p->tty = NULL;
  26147. +     }
  26148. ++    tty->flags = 0;
  26149. ++    tty->session = 0;
  26150. ++    tty->pgrp = -1;
  26151. ++    tty->ctrl_status = 0;
  26152. +     if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
  26153. +         *tty->termios = tty->driver.init_termios;
  26154. +     if (tty->driver.hangup)
  26155. +@@ -406,13 +442,19 @@
  26156. +     struct tty_struct *tty = current->tty;
  26157. +     struct task_struct *p;
  26158. +-    if (!tty)
  26159. ++    if (!tty) {
  26160. ++        if (current->tty_old_pgrp) {
  26161. ++            kill_pg(current->tty_old_pgrp, SIGHUP, priv);
  26162. ++            kill_pg(current->tty_old_pgrp, SIGCONT, priv);
  26163. ++        }
  26164. +         return;
  26165. +-
  26166. ++    }
  26167. +     if (tty->pgrp > 0) {
  26168. +         kill_pg(tty->pgrp, SIGHUP, priv);
  26169. +         kill_pg(tty->pgrp, SIGCONT, priv);
  26170. +     }
  26171. ++
  26172. ++    current->tty_old_pgrp = 0;
  26173. +     tty->session = 0;
  26174. +     tty->pgrp = -1;
  26175. +@@ -466,6 +508,7 @@
  26176. +                 return;
  26177. +         if (!vc_cons_allocated(new_console))
  26178. +                 return;
  26179. ++    last_console = fg_console;
  26180. +     /*
  26181. +      * If we're switching, we could be going from KD_GRAPHICS to
  26182. +@@ -511,11 +554,9 @@
  26183. +     if (old_vc_mode != vt_cons[new_console]->vc_mode)
  26184. +     {
  26185. +         if (vt_cons[new_console]->vc_mode == KD_TEXT)
  26186. +-            unblank_screen();
  26187. +-        else {
  26188. +-            timer_active &= ~(1<<BLANK_TIMER);
  26189. +-            blank_screen();
  26190. +-        }
  26191. ++            do_unblank_screen();
  26192. ++        else
  26193. ++            do_blank_screen(1);
  26194. +     }
  26195. +     /*
  26196. +@@ -715,7 +756,7 @@
  26197. +     struct tty_struct *tty, **tty_loc, *o_tty, **o_tty_loc;
  26198. +     struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
  26199. +     struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
  26200. +-    struct tty_driver *driver;
  26201. ++    struct tty_driver *driver;    
  26202. +     int retval;
  26203. +     int idx;
  26204. +@@ -733,6 +774,7 @@
  26205. +     tty_loc = &driver->table[idx];
  26206. +     tp_loc = &driver->termios[idx];
  26207. +     ltp_loc = &driver->termios_locked[idx];
  26208. ++
  26209. + repeat:
  26210. +     retval = -EAGAIN;
  26211. +     if (driver->type == TTY_DRIVER_TYPE_PTY &&
  26212. +@@ -772,9 +813,10 @@
  26213. +         if (!*o_tty_loc && !o_tty) {
  26214. +             dev_t     o_device;
  26215. ++            
  26216. +             o_tty = (struct tty_struct *)
  26217. +                 kmalloc(sizeof(struct tty_struct),
  26218. +                     GFP_KERNEL);
  26219. +             if (!o_tty)
  26220. +                 goto end_init;
  26221. +             o_device = MKDEV(driver->other->major,
  26222. +@@ -800,7 +841,7 @@
  26223. +             memset(o_ltp, 0, sizeof(struct termios));
  26224. +             goto repeat;
  26225. +         }
  26226. +-
  26227. ++        
  26228. +     }
  26229. +     /* Now we have allocated all the structures: update all the pointers.. */
  26230. +     if (!*tp_loc) {
  26231. +@@ -826,8 +867,15 @@
  26232. +             }
  26233. +         }
  26234. +         tty = NULL;
  26235. +-    } else
  26236. ++    } else {
  26237. ++        if ((*tty_loc)->flags & (1 << TTY_CLOSING)) {
  26238. ++            printk("Attempt to open closing tty %s.\n",
  26239. ++                   tty_name(*tty_loc));
  26240. ++            printk("Ack!!!!  This should never happen!!\n");
  26241. ++            return -EINVAL;
  26242. ++        }
  26243. +         (*tty_loc)->count++;
  26244. ++    }
  26245. +     if (driver->type == TTY_DRIVER_TYPE_PTY) {
  26246. +         if (!*o_tp_loc) {
  26247. +             *o_tp_loc = o_tp;
  26248. +@@ -887,12 +935,13 @@
  26249. +     struct termios *tp, *o_tp, *ltp, *o_ltp;
  26250. +     struct task_struct **p;
  26251. +     int    idx;
  26252. +-
  26253. +-
  26254. ++    
  26255. +     tty = (struct tty_struct *)filp->private_data;
  26256. +     if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "release_dev"))
  26257. +         return;
  26258. ++    check_tty_count(tty, "release_dev");
  26259. ++
  26260. +     tty_fasync(filp->f_inode, filp, 0);
  26261. +     tp = tty->termios;
  26262. +@@ -955,7 +1004,7 @@
  26263. +         }
  26264. +     }
  26265. + #endif
  26266. +-
  26267. ++    
  26268. +     if (tty->driver.close)
  26269. +         tty->driver.close(tty, filp);
  26270. +     if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  26271. +@@ -974,6 +1023,9 @@
  26272. +     if (tty->count)
  26273. +         return;
  26274. ++    /*
  26275. ++     * We're committed; at this point, we must not block!
  26276. ++     */
  26277. +     if (o_tty) {
  26278. +         if (o_tty->count)
  26279. +             return;
  26280. +@@ -981,10 +1033,11 @@
  26281. +         tty->driver.other->termios[idx] = NULL;
  26282. +         kfree_s(o_tp, sizeof(struct termios));
  26283. +     }
  26284. +-
  26285. ++    
  26286. + #ifdef TTY_DEBUG_HANGUP
  26287. +     printk("freeing tty structure...");
  26288. + #endif
  26289. ++    tty->flags |= (1 << TTY_CLOSING);
  26290. +     /*
  26291. +      * Make sure there aren't any processes that still think this
  26292. +@@ -1007,7 +1060,12 @@
  26293. +         (tty->ldisc.close)(tty);
  26294. +     tty->ldisc = ldiscs[N_TTY];
  26295. +     tty->termios->c_line = N_TTY;
  26296. +-
  26297. ++    if (o_tty) {
  26298. ++        if (o_tty->ldisc.close)
  26299. ++            (o_tty->ldisc.close)(o_tty);
  26300. ++        o_tty->ldisc = ldiscs[N_TTY];
  26301. ++    }
  26302. ++    
  26303. +     tty->driver.table[idx] = NULL;
  26304. +     if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
  26305. +         tty->driver.termios[idx] = NULL;
  26306. +@@ -1036,11 +1094,12 @@
  26307. +     sti();
  26308. +     tty->magic = 0;
  26309. +     (*tty->driver.refcount)--;
  26310. +     kfree_s(tty,sizeof(struct tty_struct));
  26311. ++    filp->private_data = 0;
  26312. +     if (o_tty) {
  26313. +         o_tty->magic = 0;
  26314. +         (*o_tty->driver.refcount)--;
  26315. +         kfree_s(o_tty,sizeof(struct tty_struct));
  26316. +     }
  26317. + }
  26318. +@@ -1077,11 +1136,12 @@
  26319. +         noctty = 1;
  26320. +     }
  26321. +     minor = MINOR(device);
  26322. +-
  26323. ++    
  26324. +     retval = init_dev(device, &tty);
  26325. +-    filp->private_data = tty;
  26326. +     if (retval)
  26327. +         return retval;
  26328. ++    filp->private_data = tty;
  26329. ++    check_tty_count(tty, "tty_open");
  26330. +     if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  26331. +         tty->driver.subtype == PTY_TYPE_MASTER)
  26332. +         noctty = 1;
  26333. +@@ -1118,6 +1178,7 @@
  26334. +         !current->tty &&
  26335. +         tty->session == 0) {
  26336. +         current->tty = tty;
  26337. ++        current->tty_old_pgrp = 0;
  26338. +         tty->session = current->session;
  26339. +         tty->pgrp = current->pgrp;
  26340. +     }
  26341. +@@ -1190,13 +1251,14 @@
  26342. +         if (!tty->fasync && !tty->read_wait)
  26343. +             tty->minimum_to_wake = N_TTY_BUF_SIZE;
  26344. +     }
  26345. +-    return 0;
  26346. ++    return 0;    
  26347. + }
  26348. ++#if 0
  26349. + /*
  26350. +  * XXX does anyone use this anymore?!?
  26351. +  */
  26352. +-static int do_get_ps_info(int arg)
  26353. ++static int do_get_ps_info(unsigned long arg)
  26354. + {
  26355. +     struct tstruct {
  26356. +         int flag;
  26357. +@@ -1207,7 +1269,7 @@
  26358. +     struct task_struct **p;
  26359. +     char *c, *d;
  26360. +     int i, n = 0;
  26361. +-
  26362. ++    
  26363. +     i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
  26364. +     if (i)
  26365. +         return i;
  26366. +@@ -1220,10 +1282,11 @@
  26367. +                 put_fs_byte(*c++, d++);
  26368. +             put_fs_long(1, (unsigned long *)(ts->present+n));
  26369. +         }
  26370. +-        else
  26371. ++        else    
  26372. +             put_fs_long(0, (unsigned long *)(ts->present+n));
  26373. +-    return(0);
  26374. ++    return(0);            
  26375. + }
  26376. ++#endif
  26377. + static int tty_ioctl(struct inode * inode, struct file * file,
  26378. +              unsigned int cmd, unsigned long arg)
  26379. +@@ -1235,7 +1298,7 @@
  26380. +     pid_t pgrp;
  26381. +     unsigned char    ch;
  26382. +     char    mbz = 0;
  26383. +-
  26384. ++    
  26385. +     tty = (struct tty_struct *)file->private_data;
  26386. +     if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
  26387. +         return -EINVAL;
  26388. +@@ -1268,7 +1331,7 @@
  26389. +             retval = verify_area(VERIFY_READ, (void *) arg,
  26390. +                          sizeof (struct winsize));
  26391. +             if (retval)
  26392. +-                return retval;
  26393. ++                return retval;            
  26394. +             memcpy_fromfs(&tmp_ws, (struct winsize *) arg,
  26395. +                       sizeof (struct winsize));
  26396. +             if (memcmp(&tmp_ws, &tty->winsize,
  26397. +@@ -1344,6 +1407,7 @@
  26398. +                     return -EPERM;
  26399. +             }
  26400. +             current->tty = tty;
  26401. ++            current->tty_old_pgrp = 0;
  26402. +             tty->session = current->session;
  26403. +             tty->pgrp = current->pgrp;
  26404. +             return 0;
  26405. +@@ -1389,39 +1453,61 @@
  26406. +             arg = get_fs_long((unsigned long *) arg);
  26407. +             return tty_set_ldisc(tty, arg);
  26408. +         case TIOCLINUX:
  26409. ++            if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
  26410. ++                return -EINVAL;
  26411. ++            if (current->tty != tty && !suser())
  26412. ++                return -EPERM;
  26413. +             retval = verify_area(VERIFY_READ, (void *) arg, 1);
  26414. +             if (retval)
  26415. +                 return retval;
  26416. +-            switch (get_fs_byte((char *)arg))
  26417. ++            switch (retval = get_fs_byte((char *)arg))
  26418. +             {
  26419. +                 case 0:
  26420. +-                    return do_screendump(arg);
  26421. ++                case 8:
  26422. ++                case 9:
  26423. ++                    printk("TIOCLINUX (0/8/9) ioctl is gone - use /dev/vcs\n");
  26424. ++                    return -EINVAL;
  26425. ++#if 0
  26426. +                 case 1:
  26427. +                     printk("Deprecated TIOCLINUX (1) ioctl\n");
  26428. +                     return do_get_ps_info(arg);
  26429. ++#endif
  26430. +                 case 2:
  26431. +                     return set_selection(arg, tty);
  26432. +                 case 3:
  26433. +                     return paste_selection(tty);
  26434. +                 case 4:
  26435. +-                    unblank_screen();
  26436. ++                    do_unblank_screen();
  26437. +                     return 0;
  26438. +                 case 5:
  26439. +                     return sel_loadlut(arg);
  26440. +                 case 6:
  26441. +-            /* Make it possible to react to Shift+Mousebutton */
  26442. +-            /* Note that shift_state is an undocumented
  26443. +-               kernel-internal variable; programs not closely
  26444. +-               related to the kernel should not use this. */
  26445. +-                    put_fs_byte(0, arg);
  26446. +-/*                     put_fs_byte(shift_state,arg); */
  26447. ++            /*
  26448. ++             * Make it possible to react to Shift+Mousebutton.
  26449. ++             * Note that 'shift_state' is an undocumented
  26450. ++             * kernel-internal variable; programs not closely
  26451. ++             * related to the kernel should not use this.
  26452. ++             */
  26453. ++                    put_fs_byte(shift_state,arg);
  26454. +                     return 0;
  26455. +                 case 7:
  26456. +                     put_fs_byte(mouse_reporting(),arg);
  26457. +                     return 0;
  26458. +-                default:
  26459. ++/*                case 10:
  26460. ++                    set_vesa_blanking(arg);
  26461. ++                    return 0;*/
  26462. ++                default: 
  26463. +                     return -EINVAL;
  26464. +             }
  26465. ++
  26466. ++        case TIOCTTYGSTRUCT:
  26467. ++            retval = verify_area(VERIFY_WRITE, (void *) arg,
  26468. ++                        sizeof(struct tty_struct));
  26469. ++            if (retval)
  26470. ++                return retval;
  26471. ++            memcpy_tofs((struct tty_struct *) arg,
  26472. ++                    tty, sizeof(struct tty_struct));
  26473. ++            return 0;
  26474. +         default:
  26475. +             if (tty->driver.ioctl) {
  26476. +                 retval = (tty->driver.ioctl)(tty, file,
  26477. +@@ -1445,7 +1531,7 @@
  26478. +  * prevent trojan horses by killing all processes associated with this
  26479. +  * tty when the user hits the "Secure Attention Key".  Required for
  26480. +  * super-paranoid applications --- see the Orange Book for more details.
  26481. +- *
  26482. ++ * 
  26483. +  * This code could be nicer; ideally it should send a HUP, wait a few
  26484. +  * seconds, then send a INT, and then a KILL signal.  But you then
  26485. +  * have to coordinate with the init process, since all processes associated
  26486. +@@ -1461,7 +1547,7 @@
  26487. +     int session;
  26488. +     int        i;
  26489. +     struct file    *filp;
  26490. +-
  26491. ++    
  26492. +     if (!tty)
  26493. +         return;
  26494. +     session  = tty->session;
  26495. +@@ -1520,7 +1606,7 @@
  26496. +     count = tty->flip.count;
  26497. +     tty->flip.count = 0;
  26498. +     sti();
  26499. +-
  26500. ++    
  26501. + #if 0
  26502. +     if (count > tty->max_flip_cnt)
  26503. +         tty->max_flip_cnt = count;
  26504. +@@ -1569,10 +1655,10 @@
  26505. +     if (!driver->put_char)
  26506. +         driver->put_char = tty_default_put_char;
  26507. +-
  26508. ++    
  26509. +     driver->prev = 0;
  26510. +     driver->next = tty_drivers;
  26511. +-    tty_drivers->prev = driver;
  26512. ++    if (tty_drivers) tty_drivers->prev = driver;
  26513. +     tty_drivers = driver;
  26514. +     return error;
  26515. + }
  26516. +@@ -1585,31 +1671,32 @@
  26517. +     int    retval;
  26518. +     struct tty_driver *p;
  26519. +     int    found = 0;
  26520. +-    int    major_inuse = 0;
  26521. +-
  26522. +-    if (driver->refcount)
  26523. ++    char *othername = NULL;
  26524. ++    
  26525. ++    if (*driver->refcount)
  26526. +         return -EBUSY;
  26527. +     for (p = tty_drivers; p; p = p->next) {
  26528. +         if (p == driver)
  26529. +             found++;
  26530. +         else if (p->major == driver->major)
  26531. +-            major_inuse++;
  26532. ++            othername = p->name;
  26533. +     }
  26534. +-    if (!major_inuse) {
  26535. ++    if (othername == NULL) {
  26536. +         retval = unregister_chrdev(driver->major, driver->name);
  26537. +         if (retval)
  26538. +             return retval;
  26539. +-    }
  26540. ++    } else
  26541. ++        register_chrdev(driver->major, othername, &tty_fops);
  26542. +     if (driver->prev)
  26543. +         driver->prev->next = driver->next;
  26544. +     else
  26545. +         tty_drivers = driver->next;
  26546. +-
  26547. ++    
  26548. +     if (driver->next)
  26549. +-        driver->next = driver->next->prev;
  26550. ++        driver->next->prev = driver->prev;
  26551. +     return 0;
  26552. + }
  26553. +@@ -1628,20 +1715,19 @@
  26554. +     (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
  26555. +     /*
  26556. +-     * Set up the standard termios.  Individual tty drivers may
  26557. ++     * Set up the standard termios.  Individual tty drivers may 
  26558. +      * deviate from this; this is used as a template.
  26559. +      */
  26560. +-
  26561. +     memset(&tty_std_termios, 0, sizeof(struct termios));
  26562. +     memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
  26563. +-
  26564. +     tty_std_termios.c_iflag = ICRNL | IXON;
  26565. +     tty_std_termios.c_oflag = OPOST | ONLCR;
  26566. +     tty_std_termios.c_cflag = B38400 | CS8 | CREAD;
  26567. +     tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
  26568. +         ECHOCTL | ECHOKE | IEXTEN;
  26569. ++
  26570. +     /*
  26571. +-     * set up the console device so that later boot sequences can
  26572. ++     * set up the console device so that later boot sequences can 
  26573. +      * inform about problems etc..
  26574. +      */
  26575. +     return con_init(kmem_start);
  26576. +@@ -1662,6 +1748,10 @@
  26577. +     kmem_start = kbd_init(kmem_start);
  26578. +     kmem_start = rs_init(kmem_start);
  26579. ++#ifdef CONFIG_CYCLADES
  26580. ++    kmem_start = cy_init(kmem_start);
  26581. ++#endif
  26582. +     kmem_start = pty_init(kmem_start);
  26583. ++    kmem_start = vcs_init(kmem_start);
  26584. +     return kmem_start;
  26585. + }
  26586. diff -r -u -N linux.orig/arch/arm/drivers/char/tty_io.c linux.arm/arch/arm/drivers/char/tty_io.c
  26587. --- linux.orig/arch/arm/drivers/char/tty_io.c    Thu Jan  1 01:00:00 1970
  26588. +++ linux.arm/arch/arm/drivers/char/tty_io.c    Fri Oct 27 23:14:27 1995
  26589. @@ -0,0 +1,1767 @@
  26590. +/*
  26591. + *  linux/drivers/char/tty_io.c
  26592. + *
  26593. + *  Copyright (C) 1991, 1992  Linus Torvalds
  26594. + */
  26595. +
  26596. +/*
  26597. + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
  26598. + * or rs-channels. It also implements echoing, cooked mode etc.
  26599. + *
  26600. + * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
  26601. + *
  26602. + * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
  26603. + * tty_struct and tty_queue structures.  Previously there was a array
  26604. + * of 256 tty_struct's which was statically allocated, and the
  26605. + * tty_queue structures were allocated at boot time.  Both are now
  26606. + * dynamically allocated only when the tty is open.
  26607. + *
  26608. + * Also restructured routines so that there is more of a separation
  26609. + * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
  26610. + * the low-level tty routines (serial.c, pty.c, console.c).  This
  26611. + * makes for cleaner and more compact code.  -TYT, 9/17/92
  26612. + *
  26613. + * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
  26614. + * which can be dynamically activated and de-activated by the line
  26615. + * discipline handling modules (like SLIP).
  26616. + *
  26617. + * NOTE: pay no attention to the line discipline code (yet); its
  26618. + * interface is still subject to change in this version...
  26619. + * -- TYT, 1/31/92
  26620. + *
  26621. + * Added functionality to the OPOST tty handling.  No delays, but all
  26622. + * other bits should be there.
  26623. + *    -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
  26624. + *
  26625. + * Rewrote canonical mode and added more termios flags.
  26626. + *     -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
  26627. + */
  26628. +
  26629. +#include <linux/types.h>
  26630. +#include <linux/major.h>
  26631. +#include <linux/errno.h>
  26632. +#include <linux/signal.h>
  26633. +#include <linux/fcntl.h>
  26634. +#include <linux/sched.h>
  26635. +#include <linux/interrupt.h>
  26636. +#include <linux/tty.h>
  26637. +#include <linux/tty_flip.h>
  26638. +#include <linux/timer.h>
  26639. +#include <linux/ctype.h>
  26640. +#include <linux/kd.h>
  26641. +#include <linux/mm.h>
  26642. +#include <linux/string.h>
  26643. +#include <linux/malloc.h>
  26644. +#include <linux/config.h>
  26645. +
  26646. +#include <asm/segment.h>
  26647. +#include <asm/system.h>
  26648. +#include <asm/bitops.h>
  26649. +
  26650. +#include "kbd_kern.h"
  26651. +#include "vt_kern.h"
  26652. +/* This to come */
  26653. +/*#include "selection.h"*/
  26654. +
  26655. +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
  26656. +#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
  26657. +
  26658. +#undef TTY_DEBUG_HANGUP
  26659. +
  26660. +/* These to go */
  26661. +extern int set_selection(const int arg, struct tty_struct *tty);
  26662. +extern int paste_selection(struct tty_struct *tty);
  26663. +extern int sel_loadlut(const int arg);
  26664. +extern int mouse_reporting(void);
  26665. +extern int shift_state;
  26666. +extern int do_screendump(int arg);
  26667. +#define TTY_PARANOIA_CHECK
  26668. +#define CHECK_TTY_COUNT
  26669. +
  26670. +extern void do_blank_screen(int nopowersave);
  26671. +extern void do_unblank_screen(void);
  26672. +/*extern void set_vesa_blanking(const unsigned long arg);*/
  26673. +
  26674. +struct termios tty_std_termios;        /* for the benefit of tty drivers  */
  26675. +struct tty_driver *tty_drivers = NULL;    /* linked list of tty drivers */
  26676. +struct tty_ldisc ldiscs[NR_LDISCS];    /* line disc dispatch table    */
  26677. +
  26678. +/*
  26679. + * fg_console is the current virtual console,
  26680. + * last_console is the last used one
  26681. + * redirect is the pseudo-tty that console output
  26682. + * is redirected to if asked by TIOCCONS.
  26683. + */
  26684. +int fg_console = 0;
  26685. +int last_console = 0;
  26686. +struct tty_struct * redirect = NULL;
  26687. +struct wait_queue * keypress_wait = NULL;
  26688. +
  26689. +static void initialize_tty_struct(struct tty_struct *tty);
  26690. +
  26691. +static int tty_read(struct inode *, struct file *, char *, int);
  26692. +static int tty_write(struct inode *, struct file *, char *, int);
  26693. +static int tty_select(struct inode *, struct file *, int, select_table *);
  26694. +static int tty_open(struct inode *, struct file *);
  26695. +static void tty_release(struct inode *, struct file *);
  26696. +static int tty_ioctl(struct inode * inode, struct file * file,
  26697. +             unsigned int cmd, unsigned long arg);
  26698. +static int tty_fasync(struct inode * inode, struct file * filp, int on);
  26699. +
  26700. +#ifndef MIN
  26701. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  26702. +#endif
  26703. +
  26704. +/*
  26705. + * These two routines return the name of tty.  tty_name() should NOT
  26706. + * be used in interrupt drivers, since it's not re-entrant.  Use
  26707. + * _tty_name() instead.
  26708. + */
  26709. +char *_tty_name(struct tty_struct *tty, char *buf)
  26710. +{
  26711. +    if (tty)
  26712. +        sprintf(buf, "%s%d", tty->driver.name,
  26713. +            MINOR(tty->device) - tty->driver.minor_start +
  26714. +            tty->driver.name_base);
  26715. +    else
  26716. +        strcpy(buf, "NULL tty");
  26717. +    return buf;
  26718. +}
  26719. +
  26720. +char *tty_name(struct tty_struct *tty)
  26721. +{
  26722. +    static char buf[64];
  26723. +
  26724. +    return(_tty_name(tty, buf));
  26725. +}
  26726. +
  26727. +inline int tty_paranoia_check(struct tty_struct *tty, dev_t device,
  26728. +                  const char *routine)
  26729. +{
  26730. +#ifdef TTY_PARANOIA_CHECK
  26731. +    static const char *badmagic =
  26732. +        "Warning: bad magic number for tty struct (%d, %d) in %s\n";
  26733. +    static const char *badtty =
  26734. +        "Warning: null TTY for (%d, %d) in %s\n";
  26735. +
  26736. +    if (!tty) {
  26737. +        printk(badtty, MAJOR(device), MINOR(device), routine);
  26738. +        return 1;
  26739. +    }
  26740. +    if (tty->magic != TTY_MAGIC) {
  26741. +        printk(badmagic, MAJOR(device), MINOR(device), routine);
  26742. +        return 1;
  26743. +    }
  26744. +#endif
  26745. +    return 0;
  26746. +}
  26747. +
  26748. +static int check_tty_count(struct tty_struct *tty, const char *routine)
  26749. +{
  26750. +#ifdef CHECK_TTY_COUNT
  26751. +    struct file *f;
  26752. +    int i, count = 0;
  26753. +    
  26754. +    for (f = first_file, i=0; i<nr_files; i++, f = f->f_next) {
  26755. +        if (!f->f_count)
  26756. +            continue;
  26757. +        if (f->private_data == tty) {
  26758. +            count++;
  26759. +        }
  26760. +    }
  26761. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  26762. +        tty->driver.subtype == PTY_TYPE_SLAVE &&
  26763. +        tty->link && tty->link->count)
  26764. +        count++;
  26765. +    if (tty->count != count) {
  26766. +        printk("Warning: dev (%d, %d) tty->count(%d) != #fd's(%d) in %s\n",
  26767. +               MAJOR(tty->device), MINOR(tty->device), tty->count,
  26768. +               count, routine);
  26769. +        return count;
  26770. +       }    
  26771. +#endif
  26772. +    return 0;
  26773. +}
  26774. +
  26775. +int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
  26776. +{
  26777. +    if (disc < N_TTY || disc >= NR_LDISCS)
  26778. +        return -EINVAL;
  26779. +
  26780. +    if (new_ldisc) {
  26781. +        ldiscs[disc] = *new_ldisc;
  26782. +        ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
  26783. +        ldiscs[disc].num = disc;
  26784. +    } else
  26785. +        memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
  26786. +
  26787. +    return 0;
  26788. +}
  26789. +
  26790. +/* Set the discipline of a tty line. */
  26791. +static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
  26792. +{
  26793. +    int    retval = 0;
  26794. +    struct    tty_ldisc o_ldisc;
  26795. +
  26796. +    if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
  26797. +        !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
  26798. +        return -EINVAL;
  26799. +
  26800. +    if (tty->ldisc.num == ldisc)
  26801. +        return 0;    /* We are already in the desired discipline */
  26802. +    o_ldisc = tty->ldisc;
  26803. +
  26804. +    tty_wait_until_sent(tty, 0);
  26805. +    
  26806. +    /* Shutdown the current discipline. */
  26807. +    if (tty->ldisc.close)
  26808. +        (tty->ldisc.close)(tty);
  26809. +
  26810. +    /* Now set up the new line discipline. */
  26811. +    tty->ldisc = ldiscs[ldisc];
  26812. +    tty->termios->c_line = ldisc;
  26813. +    if (tty->ldisc.open)
  26814. +        retval = (tty->ldisc.open)(tty);
  26815. +    if (retval < 0) {
  26816. +        tty->ldisc = o_ldisc;
  26817. +        tty->termios->c_line = tty->ldisc.num;
  26818. +        if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
  26819. +            tty->ldisc = ldiscs[N_TTY];
  26820. +            tty->termios->c_line = N_TTY;
  26821. +            if (tty->ldisc.open) {
  26822. +                int r = tty->ldisc.open(tty);
  26823. +
  26824. +                if (r < 0)
  26825. +                    panic("Couldn't open N_TTY ldisc for "
  26826. +                          "%s --- error %d.",
  26827. +                          tty_name(tty), r);
  26828. +            }
  26829. +        }
  26830. +    }
  26831. +    if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc)
  26832. +        tty->driver.set_ldisc(tty);
  26833. +    return retval;
  26834. +}
  26835. +
  26836. +/*
  26837. + * This routine returns a tty driver structure, given a device number
  26838. + */
  26839. +struct tty_driver *get_tty_driver(dev_t device)
  26840. +{
  26841. +    int    major, minor;
  26842. +    struct tty_driver *p;
  26843. +
  26844. +    minor = MINOR(device);
  26845. +    major = MAJOR(device);
  26846. +
  26847. +    for (p = tty_drivers; p; p = p->next) {
  26848. +        if (p->major != major)
  26849. +            continue;
  26850. +        if (minor < p->minor_start)
  26851. +            continue;
  26852. +        if (minor >= p->minor_start + p->num)
  26853. +            continue;
  26854. +        return p;
  26855. +    }
  26856. +    return NULL;
  26857. +}
  26858. +
  26859. +/*
  26860. + * If we try to write to, or set the state of, a terminal and we're
  26861. + * not in the foreground, send a SIGTTOU.  If the signal is blocked or
  26862. + * ignored, go ahead and perform the operation.  (POSIX 7.2)
  26863. + */
  26864. +int tty_check_change(struct tty_struct * tty)
  26865. +{
  26866. +    if (current->tty != tty)
  26867. +        return 0;
  26868. +    if (tty->pgrp <= 0) {
  26869. +        printk("tty_check_change: tty->pgrp <= 0!\n");
  26870. +        return 0;
  26871. +    }
  26872. +    if (current->pgrp == tty->pgrp)
  26873. +        return 0;
  26874. +    if (is_ignored(SIGTTOU))
  26875. +        return 0;
  26876. +    if (is_orphaned_pgrp(current->pgrp))
  26877. +        return -EIO;
  26878. +    (void) kill_pg(current->pgrp,SIGTTOU,1);
  26879. +    return -ERESTARTSYS;
  26880. +}
  26881. +
  26882. +static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count)
  26883. +{
  26884. +    return 0;
  26885. +}
  26886. +
  26887. +static int hung_up_tty_write(struct inode * inode, struct file * file, char * buf, int count)
  26888. +{
  26889. +    return -EIO;
  26890. +}
  26891. +
  26892. +static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
  26893. +{
  26894. +    return 1;
  26895. +}
  26896. +
  26897. +static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
  26898. +                 unsigned int cmd, unsigned long arg)
  26899. +{
  26900. +    return -EIO;
  26901. +}
  26902. +
  26903. +static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  26904. +{
  26905. +    return -ESPIPE;
  26906. +}
  26907. +
  26908. +static struct file_operations tty_fops = {
  26909. +    tty_lseek,
  26910. +    tty_read,
  26911. +    tty_write,
  26912. +    NULL,        /* tty_readdir */
  26913. +    tty_select,
  26914. +    tty_ioctl,
  26915. +    NULL,        /* tty_mmap */
  26916. +    tty_open,
  26917. +    tty_release,
  26918. +    NULL,        /* tty_fsync */
  26919. +    tty_fasync
  26920. +};
  26921. +
  26922. +static struct file_operations hung_up_tty_fops = {
  26923. +    tty_lseek,
  26924. +    hung_up_tty_read,
  26925. +    hung_up_tty_write,
  26926. +    NULL,        /* hung_up_tty_readdir */
  26927. +    hung_up_tty_select,
  26928. +    hung_up_tty_ioctl,
  26929. +    NULL,        /* hung_up_tty_mmap */
  26930. +    NULL,        /* hung_up_tty_open */
  26931. +    tty_release,    /* hung_up_tty_release */
  26932. +    NULL,        /* hung_up_tty_fsync  */
  26933. +    NULL        /* hung_up_tty_fasync */
  26934. +};
  26935. +
  26936. +void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
  26937. +{
  26938. +    int i;
  26939. +    struct file * filp;
  26940. +    struct task_struct *p;
  26941. +
  26942. +    if (!tty)
  26943. +        return;
  26944. +    check_tty_count(tty, "do_tty_hangup");
  26945. +    for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) {
  26946. +        if (!filp->f_count)
  26947. +            continue;
  26948. +        if (filp->private_data != tty)
  26949. +            continue;
  26950. +        if (filp->f_inode && filp->f_inode->i_rdev == CONSOLE_DEV)
  26951. +            continue;
  26952. +        if (filp->f_op != &tty_fops)
  26953. +            continue;
  26954. +        tty_fasync(filp->f_inode, filp, 0);
  26955. +        filp->f_op = fops;
  26956. +    }
  26957. +
  26958. +    if (tty->ldisc.flush_buffer)
  26959. +        tty->ldisc.flush_buffer(tty);
  26960. +    if (tty->driver.flush_buffer)
  26961. +        tty->driver.flush_buffer(tty);
  26962. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  26963. +        tty->ldisc.write_wakeup)
  26964. +        (tty->ldisc.write_wakeup)(tty);
  26965. +    wake_up_interruptible(&tty->write_wait);
  26966. +    wake_up_interruptible(&tty->read_wait);
  26967. +
  26968. +    /*
  26969. +     * Shutdown the current line discipline, and reset it to
  26970. +     * N_TTY.
  26971. +     */
  26972. +    if (tty->ldisc.num != ldiscs[N_TTY].num) {
  26973. +        if (tty->ldisc.close)
  26974. +            (tty->ldisc.close)(tty);
  26975. +        tty->ldisc = ldiscs[N_TTY];
  26976. +        tty->termios->c_line = N_TTY;
  26977. +        if (tty->ldisc.open) {
  26978. +            i = (tty->ldisc.open)(tty);
  26979. +            if (i < 0)
  26980. +                printk("do_tty_hangup: N_TTY open: error %d\n",
  26981. +                       -i);
  26982. +        }
  26983. +    }
  26984. +    
  26985. +     for_each_task(p) {
  26986. +        if ((tty->session > 0) && (p->session == tty->session) &&
  26987. +            p->leader) {
  26988. +            send_sig(SIGHUP,p,1);
  26989. +            send_sig(SIGCONT,p,1);
  26990. +            if (tty->pgrp > 0)
  26991. +                p->tty_old_pgrp = tty->pgrp;
  26992. +        }
  26993. +        if (p->tty == tty)
  26994. +            p->tty = NULL;
  26995. +    }
  26996. +    tty->flags = 0;
  26997. +    tty->session = 0;
  26998. +    tty->pgrp = -1;
  26999. +    tty->ctrl_status = 0;
  27000. +    if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
  27001. +        *tty->termios = tty->driver.init_termios;
  27002. +    if (tty->driver.hangup)
  27003. +        (tty->driver.hangup)(tty);
  27004. +}
  27005. +
  27006. +void tty_hangup(struct tty_struct * tty)
  27007. +{
  27008. +#ifdef TTY_DEBUG_HANGUP
  27009. +    printk("%s hangup...\n", tty_name(tty));
  27010. +#endif
  27011. +    do_tty_hangup(tty, &hung_up_tty_fops);
  27012. +}
  27013. +
  27014. +void tty_vhangup(struct tty_struct * tty)
  27015. +{
  27016. +#ifdef TTY_DEBUG_HANGUP
  27017. +    printk("%s vhangup...\n", tty_name(tty));
  27018. +#endif
  27019. +    do_tty_hangup(tty, &hung_up_tty_fops);
  27020. +}
  27021. +
  27022. +int tty_hung_up_p(struct file * filp)
  27023. +{
  27024. +    return (filp->f_op == &hung_up_tty_fops);
  27025. +}
  27026. +
  27027. +/*
  27028. + * This function is typically called only by the session leader, when
  27029. + * it wants to disassociate itself from its controlling tty.
  27030. + *
  27031. + * It performs the following functions:
  27032. + *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
  27033. + *     (2)  Clears the tty from being controlling the session
  27034. + *     (3)  Clears the controlling tty for all processes in the
  27035. + *         session group.
  27036. + */
  27037. +void disassociate_ctty(int priv)
  27038. +{
  27039. +    struct tty_struct *tty = current->tty;
  27040. +    struct task_struct *p;
  27041. +
  27042. +    if (!tty) {
  27043. +        if (current->tty_old_pgrp) {
  27044. +            kill_pg(current->tty_old_pgrp, SIGHUP, priv);
  27045. +            kill_pg(current->tty_old_pgrp, SIGCONT, priv);
  27046. +        }
  27047. +        return;
  27048. +    }
  27049. +    if (tty->pgrp > 0) {
  27050. +        kill_pg(tty->pgrp, SIGHUP, priv);
  27051. +        kill_pg(tty->pgrp, SIGCONT, priv);
  27052. +    }
  27053. +
  27054. +    current->tty_old_pgrp = 0;
  27055. +    tty->session = 0;
  27056. +    tty->pgrp = -1;
  27057. +
  27058. +    for_each_task(p)
  27059. +          if (p->session == current->session)
  27060. +            p->tty = NULL;
  27061. +}
  27062. +
  27063. +/*
  27064. + * Sometimes we want to wait until a particular VT has been activated. We
  27065. + * do it in a very simple manner. Everybody waits on a single queue and
  27066. + * get woken up at once. Those that are satisfied go on with their business,
  27067. + * while those not ready go back to sleep. Seems overkill to add a wait
  27068. + * to each vt just for this - usually this does nothing!
  27069. + */
  27070. +static struct wait_queue *vt_activate_queue = NULL;
  27071. +
  27072. +/*
  27073. + * Sleeps until a vt is activated, or the task is interrupted. Returns
  27074. + * 0 if activation, -1 if interrupted.
  27075. + */
  27076. +int vt_waitactive(void)
  27077. +{
  27078. +    interruptible_sleep_on(&vt_activate_queue);
  27079. +    return (current->signal & ~current->blocked) ? -1 : 0;
  27080. +}
  27081. +
  27082. +#define vt_wake_waitactive() wake_up(&vt_activate_queue)
  27083. +
  27084. +void reset_vc(unsigned int new_console)
  27085. +{
  27086. +    vt_cons[new_console]->vc_mode = KD_TEXT;
  27087. +    kbd_table[new_console].kbdmode = VC_XLATE;
  27088. +    vt_cons[new_console]->vt_mode.mode = VT_AUTO;
  27089. +    vt_cons[new_console]->vt_mode.waitv = 0;
  27090. +    vt_cons[new_console]->vt_mode.relsig = 0;
  27091. +    vt_cons[new_console]->vt_mode.acqsig = 0;
  27092. +    vt_cons[new_console]->vt_mode.frsig = 0;
  27093. +    vt_cons[new_console]->vt_pid = -1;
  27094. +    vt_cons[new_console]->vt_newvt = -1;
  27095. +}
  27096. +
  27097. +/*
  27098. + * Performs the back end of a vt switch
  27099. + */
  27100. +void complete_change_console(unsigned int new_console)
  27101. +{
  27102. +    unsigned char old_vc_mode;
  27103. +
  27104. +        if (new_console == fg_console)
  27105. +                return;
  27106. +        if (!vc_cons_allocated(new_console))
  27107. +                return;
  27108. +    last_console = fg_console;
  27109. +
  27110. +    /*
  27111. +     * If we're switching, we could be going from KD_GRAPHICS to
  27112. +     * KD_TEXT mode or vice versa, which means we need to blank or
  27113. +     * unblank the screen later.
  27114. +     */
  27115. +    old_vc_mode = vt_cons[fg_console]->vc_mode;
  27116. +    update_screen(new_console);
  27117. +
  27118. +    /*
  27119. +     * If this new console is under process control, send it a signal
  27120. +     * telling it that it has acquired. Also check if it has died and
  27121. +     * clean up (similar to logic employed in change_console())
  27122. +     */
  27123. +    if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS)
  27124. +    {
  27125. +        /*
  27126. +         * Send the signal as privileged - kill_proc() will
  27127. +         * tell us if the process has gone or something else
  27128. +         * is awry
  27129. +         */
  27130. +        if (kill_proc(vt_cons[new_console]->vt_pid,
  27131. +                  vt_cons[new_console]->vt_mode.acqsig,
  27132. +                  1) != 0)
  27133. +        {
  27134. +        /*
  27135. +         * The controlling process has died, so we revert back to
  27136. +         * normal operation. In this case, we'll also change back
  27137. +         * to KD_TEXT mode. I'm not sure if this is strictly correct
  27138. +         * but it saves the agony when the X server dies and the screen
  27139. +         * remains blanked due to KD_GRAPHICS! It would be nice to do
  27140. +         * this outside of VT_PROCESS but there is no single process
  27141. +         * to account for and tracking tty count may be undesirable.
  27142. +         */
  27143. +                reset_vc(new_console);
  27144. +        }
  27145. +    }
  27146. +
  27147. +    /*
  27148. +     * We do this here because the controlling process above may have
  27149. +     * gone, and so there is now a new vc_mode
  27150. +     */
  27151. +    if (old_vc_mode != vt_cons[new_console]->vc_mode)
  27152. +    {
  27153. +        if (vt_cons[new_console]->vc_mode == KD_TEXT)
  27154. +            do_unblank_screen();
  27155. +        else
  27156. +            do_blank_screen(1);
  27157. +    }
  27158. +
  27159. +    /*
  27160. +     * Wake anyone waiting for their VT to activate
  27161. +     */
  27162. +    vt_wake_waitactive();
  27163. +    return;
  27164. +}
  27165. +
  27166. +/*
  27167. + * Performs the front-end of a vt switch
  27168. + */
  27169. +void change_console(unsigned int new_console)
  27170. +{
  27171. +        if (new_console == fg_console)
  27172. +                return;
  27173. +        if (!vc_cons_allocated(new_console))
  27174. +        return;
  27175. +
  27176. +    /*
  27177. +     * If this vt is in process mode, then we need to handshake with
  27178. +     * that process before switching. Essentially, we store where that
  27179. +     * vt wants to switch to and wait for it to tell us when it's done
  27180. +     * (via VT_RELDISP ioctl).
  27181. +     *
  27182. +     * We also check to see if the controlling process still exists.
  27183. +     * If it doesn't, we reset this vt to auto mode and continue.
  27184. +     * This is a cheap way to track process control. The worst thing
  27185. +     * that can happen is: we send a signal to a process, it dies, and
  27186. +     * the switch gets "lost" waiting for a response; hopefully, the
  27187. +     * user will try again, we'll detect the process is gone (unless
  27188. +     * the user waits just the right amount of time :-) and revert the
  27189. +     * vt to auto control.
  27190. +     */
  27191. +    if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS)
  27192. +    {
  27193. +        /*
  27194. +         * Send the signal as privileged - kill_proc() will
  27195. +         * tell us if the process has gone or something else
  27196. +         * is awry
  27197. +         */
  27198. +        if (kill_proc(vt_cons[fg_console]->vt_pid,
  27199. +                  vt_cons[fg_console]->vt_mode.relsig,
  27200. +                  1) == 0)
  27201. +        {
  27202. +            /*
  27203. +             * It worked. Mark the vt to switch to and
  27204. +             * return. The process needs to send us a
  27205. +             * VT_RELDISP ioctl to complete the switch.
  27206. +             */
  27207. +            vt_cons[fg_console]->vt_newvt = new_console;
  27208. +            return;
  27209. +        }
  27210. +
  27211. +        /*
  27212. +         * The controlling process has died, so we revert back to
  27213. +         * normal operation. In this case, we'll also change back
  27214. +         * to KD_TEXT mode. I'm not sure if this is strictly correct
  27215. +         * but it saves the agony when the X server dies and the screen
  27216. +         * remains blanked due to KD_GRAPHICS! It would be nice to do
  27217. +         * this outside of VT_PROCESS but there is no single process
  27218. +         * to account for and tracking tty count may be undesirable.
  27219. +         */
  27220. +        reset_vc(fg_console);
  27221. +
  27222. +        /*
  27223. +         * Fall through to normal (VT_AUTO) handling of the switch...
  27224. +         */
  27225. +    }
  27226. +
  27227. +    /*
  27228. +     * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
  27229. +     */
  27230. +    if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
  27231. +        return;
  27232. +
  27233. +    complete_change_console(new_console);
  27234. +}
  27235. +
  27236. +void wait_for_keypress(void)
  27237. +{
  27238. +    sleep_on(&keypress_wait);
  27239. +}
  27240. +
  27241. +void stop_tty(struct tty_struct *tty)
  27242. +{
  27243. +    if (tty->stopped)
  27244. +        return;
  27245. +    tty->stopped = 1;
  27246. +    if (tty->link && tty->link->packet) {
  27247. +        tty->ctrl_status &= ~TIOCPKT_START;
  27248. +        tty->ctrl_status |= TIOCPKT_STOP;
  27249. +        wake_up_interruptible(&tty->link->read_wait);
  27250. +    }
  27251. +    if (tty->driver.stop)
  27252. +        (tty->driver.stop)(tty);
  27253. +}
  27254. +
  27255. +void start_tty(struct tty_struct *tty)
  27256. +{
  27257. +    if (!tty->stopped)
  27258. +        return;
  27259. +    tty->stopped = 0;
  27260. +    if (tty->link && tty->link->packet) {
  27261. +        tty->ctrl_status &= ~TIOCPKT_STOP;
  27262. +        tty->ctrl_status |= TIOCPKT_START;
  27263. +        wake_up_interruptible(&tty->link->read_wait);
  27264. +    }
  27265. +    if (tty->driver.start)
  27266. +        (tty->driver.start)(tty);
  27267. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  27268. +        tty->ldisc.write_wakeup)
  27269. +        (tty->ldisc.write_wakeup)(tty);
  27270. +    wake_up_interruptible(&tty->write_wait);
  27271. +}
  27272. +
  27273. +static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
  27274. +{
  27275. +    int i;
  27276. +    struct tty_struct * tty;
  27277. +
  27278. +    tty = (struct tty_struct *)file->private_data;
  27279. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_read"))
  27280. +        return -EIO;
  27281. +    if (!tty || (tty->flags & (1 << TTY_IO_ERROR)))
  27282. +        return -EIO;
  27283. +
  27284. +    /* This check not only needs to be done before reading, but also
  27285. +       whenever read_chan() gets woken up after sleeping, so I've
  27286. +       moved it to there.  This should only be done for the N_TTY
  27287. +       line discipline, anyway.  Same goes for write_chan(). -- jlc. */
  27288. +#if 0
  27289. +    if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
  27290. +        (tty->pgrp > 0) &&
  27291. +        (current->tty == tty) &&
  27292. +        (tty->pgrp != current->pgrp))
  27293. +        if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
  27294. +            return -EIO;
  27295. +        else {
  27296. +            (void) kill_pg(current->pgrp, SIGTTIN, 1);
  27297. +            return -ERESTARTSYS;
  27298. +        }
  27299. +#endif
  27300. +    if (tty->ldisc.read)
  27301. +        /* XXX casts are for what kernel-wide prototypes should be. */
  27302. +        i = (tty->ldisc.read)(tty,file,(unsigned char *)buf,(unsigned int)count);
  27303. +    else
  27304. +        i = -EIO;
  27305. +    if (i > 0)
  27306. +        inode->i_atime = CURRENT_TIME;
  27307. +    return i;
  27308. +}
  27309. +
  27310. +static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
  27311. +{
  27312. +    int i, is_console;
  27313. +    struct tty_struct * tty;
  27314. +
  27315. +    is_console = (inode->i_rdev == CONSOLE_DEV);
  27316. +
  27317. +    if (is_console && redirect)
  27318. +        tty = redirect;
  27319. +    else
  27320. +        tty = (struct tty_struct *)file->private_data;
  27321. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_write"))
  27322. +        return -EIO;
  27323. +    if (!tty || !tty->driver.write || (tty->flags & (1 << TTY_IO_ERROR)))
  27324. +        return -EIO;
  27325. +#if 0
  27326. +    if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
  27327. +        (current->tty == tty) && (tty->pgrp != current->pgrp)) {
  27328. +        if (is_orphaned_pgrp(current->pgrp))
  27329. +            return -EIO;
  27330. +        if (!is_ignored(SIGTTOU)) {
  27331. +            (void) kill_pg(current->pgrp, SIGTTOU, 1);
  27332. +            return -ERESTARTSYS;
  27333. +        }
  27334. +    }
  27335. +#endif
  27336. +    if (tty->ldisc.write)
  27337. +        /* XXX casts are for what kernel-wide prototypes should be. */
  27338. +        i = (tty->ldisc.write)(tty,file,(unsigned char *)buf,(unsigned int)count);
  27339. +    else
  27340. +        i = -EIO;
  27341. +    if (i > 0)
  27342. +        inode->i_mtime = CURRENT_TIME;
  27343. +    return i;
  27344. +}
  27345. +
  27346. +/*
  27347. + * This is so ripe with races that you should *really* not touch this
  27348. + * unless you know exactly what you are doing. All the changes have to be
  27349. + * made atomically, or there may be incorrect pointers all over the place.
  27350. + */
  27351. +static int init_dev(dev_t device, struct tty_struct **ret_tty)
  27352. +{
  27353. +    struct tty_struct *tty, **tty_loc, *o_tty, **o_tty_loc;
  27354. +    struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
  27355. +    struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
  27356. +    struct tty_driver *driver;    
  27357. +    int retval;
  27358. +    int idx;
  27359. +
  27360. +    driver = get_tty_driver(device);
  27361. +    if (!driver)
  27362. +        return -ENODEV;
  27363. +
  27364. +    idx = MINOR(device) - driver->minor_start;
  27365. +    tty = o_tty = NULL;
  27366. +    tp = o_tp = NULL;
  27367. +    ltp = o_ltp = NULL;
  27368. +    o_tty_loc = NULL;
  27369. +    o_tp_loc = o_ltp_loc = NULL;
  27370. +
  27371. +    tty_loc = &driver->table[idx];
  27372. +    tp_loc = &driver->termios[idx];
  27373. +    ltp_loc = &driver->termios_locked[idx];
  27374. +
  27375. +repeat:
  27376. +    retval = -EAGAIN;
  27377. +    if (driver->type == TTY_DRIVER_TYPE_PTY &&
  27378. +        driver->subtype == PTY_TYPE_MASTER &&
  27379. +        *tty_loc && (*tty_loc)->count)
  27380. +        goto end_init;
  27381. +    retval = -ENOMEM;
  27382. +    if (!*tty_loc && !tty) {
  27383. +        if (!(tty = (struct tty_struct*) kmalloc(sizeof(struct tty_struct),
  27384. +                            GFP_KERNEL)))
  27385. +            goto end_init;
  27386. +        initialize_tty_struct(tty);
  27387. +        tty->device = device;
  27388. +        tty->driver = *driver;
  27389. +        goto repeat;
  27390. +    }
  27391. +    if (!*tp_loc && !tp) {
  27392. +        tp = (struct termios *) kmalloc(sizeof(struct termios),
  27393. +                        GFP_KERNEL);
  27394. +        if (!tp)
  27395. +            goto end_init;
  27396. +        *tp = driver->init_termios;
  27397. +        goto repeat;
  27398. +    }
  27399. +    if (!*ltp_loc && !ltp) {
  27400. +        ltp = (struct termios *) kmalloc(sizeof(struct termios),
  27401. +                         GFP_KERNEL);
  27402. +        if (!ltp)
  27403. +            goto end_init;
  27404. +        memset(ltp, 0, sizeof(struct termios));
  27405. +        goto repeat;
  27406. +    }
  27407. +    if (driver->type == TTY_DRIVER_TYPE_PTY) {
  27408. +        o_tty_loc = &driver->other->table[idx];
  27409. +        o_tp_loc = &driver->other->termios[idx];
  27410. +        o_ltp_loc = &driver->other->termios_locked[idx];
  27411. +
  27412. +        if (!*o_tty_loc && !o_tty) {
  27413. +            dev_t     o_device;
  27414. +            
  27415. +            o_tty = (struct tty_struct *)
  27416. +                kmalloc(sizeof(struct tty_struct),
  27417. +                    GFP_KERNEL);
  27418. +            if (!o_tty)
  27419. +                goto end_init;
  27420. +            o_device = MKDEV(driver->other->major,
  27421. +                     driver->other->minor_start + idx);
  27422. +            initialize_tty_struct(o_tty);
  27423. +            o_tty->device = o_device;
  27424. +            o_tty->driver = *driver->other;
  27425. +            goto repeat;
  27426. +        }
  27427. +        if (!*o_tp_loc && !o_tp) {
  27428. +            o_tp = (struct termios *)
  27429. +                kmalloc(sizeof(struct termios), GFP_KERNEL);
  27430. +            if (!o_tp)
  27431. +                goto end_init;
  27432. +            *o_tp = driver->other->init_termios;
  27433. +            goto repeat;
  27434. +        }
  27435. +        if (!*o_ltp_loc && !o_ltp) {
  27436. +            o_ltp = (struct termios *)
  27437. +                kmalloc(sizeof(struct termios), GFP_KERNEL);
  27438. +            if (!o_ltp)
  27439. +                goto end_init;
  27440. +            memset(o_ltp, 0, sizeof(struct termios));
  27441. +            goto repeat;
  27442. +        }
  27443. +        
  27444. +    }
  27445. +    /* Now we have allocated all the structures: update all the pointers.. */
  27446. +    if (!*tp_loc) {
  27447. +        *tp_loc = tp;
  27448. +        tp = NULL;
  27449. +    }
  27450. +    if (!*ltp_loc) {
  27451. +        *ltp_loc = ltp;
  27452. +        ltp = NULL;
  27453. +    }
  27454. +    if (!*tty_loc) {
  27455. +        tty->termios = *tp_loc;
  27456. +        tty->termios_locked = *ltp_loc;
  27457. +        *tty_loc = tty;
  27458. +        (*driver->refcount)++;
  27459. +        (*tty_loc)->count++;
  27460. +        if (tty->ldisc.open) {
  27461. +            retval = (tty->ldisc.open)(tty);
  27462. +            if (retval < 0) {
  27463. +                (*tty_loc)->count--;
  27464. +                tty = NULL;
  27465. +                goto end_init;
  27466. +            }
  27467. +        }
  27468. +        tty = NULL;
  27469. +    } else {
  27470. +        if ((*tty_loc)->flags & (1 << TTY_CLOSING)) {
  27471. +            printk("Attempt to open closing tty %s.\n",
  27472. +                   tty_name(*tty_loc));
  27473. +            printk("Ack!!!!  This should never happen!!\n");
  27474. +            return -EINVAL;
  27475. +        }
  27476. +        (*tty_loc)->count++;
  27477. +    }
  27478. +    if (driver->type == TTY_DRIVER_TYPE_PTY) {
  27479. +        if (!*o_tp_loc) {
  27480. +            *o_tp_loc = o_tp;
  27481. +            o_tp = NULL;
  27482. +        }
  27483. +        if (!*o_ltp_loc) {
  27484. +            *o_ltp_loc = o_ltp;
  27485. +            o_ltp = NULL;
  27486. +        }
  27487. +        if (!*o_tty_loc) {
  27488. +            o_tty->termios = *o_tp_loc;
  27489. +            o_tty->termios_locked = *o_ltp_loc;
  27490. +            *o_tty_loc = o_tty;
  27491. +            (*driver->other->refcount)++;
  27492. +            if (o_tty->ldisc.open) {
  27493. +                retval = (o_tty->ldisc.open)(o_tty);
  27494. +                if (retval < 0) {
  27495. +                    (*tty_loc)->count--;
  27496. +                    o_tty = NULL;
  27497. +                    goto end_init;
  27498. +                }
  27499. +            }
  27500. +            o_tty = NULL;
  27501. +        }
  27502. +        (*tty_loc)->link = *o_tty_loc;
  27503. +        (*o_tty_loc)->link = *tty_loc;
  27504. +        if (driver->subtype == PTY_TYPE_MASTER)
  27505. +            (*o_tty_loc)->count++;
  27506. +    }
  27507. +    (*tty_loc)->driver = *driver;
  27508. +    *ret_tty = *tty_loc;
  27509. +    retval = 0;
  27510. +end_init:
  27511. +    if (tty)
  27512. +        kfree_s(tty,sizeof(struct tty_struct));
  27513. +    if (o_tty)
  27514. +        kfree_s(o_tty,sizeof(struct tty_struct));
  27515. +    if (tp)
  27516. +        kfree_s(tp, sizeof(struct termios));
  27517. +    if (o_tp)
  27518. +        kfree_s(o_tp, sizeof(struct termios));
  27519. +    if (ltp)
  27520. +        kfree_s(ltp, sizeof(struct termios));
  27521. +    if (o_ltp)
  27522. +        kfree_s(o_ltp, sizeof(struct termios));
  27523. +    return retval;
  27524. +}
  27525. +
  27526. +/*
  27527. + * Even releasing the tty structures is a tricky business.. We have
  27528. + * to be very careful that the structures are all released at the
  27529. + * same time, as interrupts might otherwise get the wrong pointers.
  27530. + */
  27531. +static void release_dev(struct file * filp)
  27532. +{
  27533. +    struct tty_struct *tty, *o_tty;
  27534. +    struct termios *tp, *o_tp, *ltp, *o_ltp;
  27535. +    struct task_struct **p;
  27536. +    int    idx;
  27537. +    
  27538. +    tty = (struct tty_struct *)filp->private_data;
  27539. +    if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "release_dev"))
  27540. +        return;
  27541. +
  27542. +    check_tty_count(tty, "release_dev");
  27543. +
  27544. +    tty_fasync(filp->f_inode, filp, 0);
  27545. +
  27546. +    tp = tty->termios;
  27547. +    ltp = tty->termios_locked;
  27548. +
  27549. +    idx = MINOR(tty->device) - tty->driver.minor_start;
  27550. +#ifdef TTY_PARANOIA_CHECK
  27551. +    if (idx < 0 || idx >= tty->driver.num) {
  27552. +        printk("release_dev: bad idx when trying to free (%d, %d)\n",
  27553. +               MAJOR(tty->device), MINOR(tty->device));
  27554. +        return;
  27555. +    }
  27556. +    if (tty != tty->driver.table[idx]) {
  27557. +        printk("release_dev: driver.table[%d] not tty for (%d, %d)\n",
  27558. +               idx, MAJOR(tty->device), MINOR(tty->device));
  27559. +        return;
  27560. +    }
  27561. +    if (tp != tty->driver.termios[idx]) {
  27562. +        printk("release_dev: driver.termios[%d] not termios for (%d, %d)\n",
  27563. +               idx, MAJOR(tty->device), MINOR(tty->device));
  27564. +        return;
  27565. +    }
  27566. +    if (ltp != tty->driver.termios_locked[idx]) {
  27567. +        printk("release_dev: driver.termios_locked[%d] not termios_locked for (%d, %d)\n",
  27568. +               idx, MAJOR(tty->device), MINOR(tty->device));
  27569. +        return;
  27570. +    }
  27571. +#endif
  27572. +
  27573. +#ifdef TTY_DEBUG_HANGUP
  27574. +    printk("release_dev of %s (tty count=%d)...", tty_name(tty),
  27575. +           tty->count);
  27576. +#endif
  27577. +
  27578. +    o_tty = tty->link;
  27579. +    o_tp = (o_tty) ? o_tty->termios : NULL;
  27580. +    o_ltp = (o_tty) ? o_tty->termios_locked : NULL;
  27581. +
  27582. +#ifdef TTY_PARANOIA_CHECK
  27583. +    if (tty->driver.other) {
  27584. +        if (o_tty != tty->driver.other->table[idx]) {
  27585. +            printk("release_dev: other->table[%d] not o_tty for (%d, %d)\n",
  27586. +                   idx, MAJOR(tty->device), MINOR(tty->device));
  27587. +            return;
  27588. +        }
  27589. +        if (o_tp != tty->driver.other->termios[idx]) {
  27590. +            printk("release_dev: other->termios[%d] not o_termios for (%d, %d)\n",
  27591. +                   idx, MAJOR(tty->device), MINOR(tty->device));
  27592. +            return;
  27593. +        }
  27594. +        if (o_ltp != tty->driver.other->termios_locked[idx]) {
  27595. +            printk("release_dev: other->termios_locked[%d] not o_termios_locked for (%d, %d)\n",
  27596. +                   idx, MAJOR(tty->device), MINOR(tty->device));
  27597. +            return;
  27598. +        }
  27599. +
  27600. +        if (o_tty->link != tty) {
  27601. +            printk("release_dev: bad pty pointers\n");
  27602. +            return;
  27603. +        }
  27604. +    }
  27605. +#endif
  27606. +    
  27607. +    if (tty->driver.close)
  27608. +        tty->driver.close(tty, filp);
  27609. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  27610. +        tty->driver.subtype == PTY_TYPE_MASTER) {
  27611. +        if (--tty->link->count < 0) {
  27612. +            printk("release_dev: bad pty slave count (%d) for %s\n",
  27613. +                   tty->count, tty_name(tty));
  27614. +            tty->link->count = 0;
  27615. +        }
  27616. +    }
  27617. +    if (--tty->count < 0) {
  27618. +        printk("release_dev: bad tty->count (%d) for %s\n",
  27619. +               tty->count, tty_name(tty));
  27620. +        tty->count = 0;
  27621. +    }
  27622. +    if (tty->count)
  27623. +        return;
  27624. +
  27625. +    /*
  27626. +     * We're committed; at this point, we must not block!
  27627. +     */
  27628. +    if (o_tty) {
  27629. +        if (o_tty->count)
  27630. +            return;
  27631. +        tty->driver.other->table[idx] = NULL;
  27632. +        tty->driver.other->termios[idx] = NULL;
  27633. +        kfree_s(o_tp, sizeof(struct termios));
  27634. +    }
  27635. +    
  27636. +#ifdef TTY_DEBUG_HANGUP
  27637. +    printk("freeing tty structure...");
  27638. +#endif
  27639. +    tty->flags |= (1 << TTY_CLOSING);
  27640. +
  27641. +    /*
  27642. +     * Make sure there aren't any processes that still think this
  27643. +     * tty is their controlling tty.
  27644. +     */
  27645. +    for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  27646. +        if (*p == 0)
  27647. +            continue;
  27648. +        if ((*p)->tty == tty)
  27649. +            (*p)->tty = NULL;
  27650. +        if (o_tty && (*p)->tty == o_tty)
  27651. +            (*p)->tty = NULL;
  27652. +    }
  27653. +
  27654. +    /*
  27655. +     * Shutdown the current line discipline, and reset it to
  27656. +     * N_TTY.
  27657. +     */
  27658. +    if (tty->ldisc.close)
  27659. +        (tty->ldisc.close)(tty);
  27660. +    tty->ldisc = ldiscs[N_TTY];
  27661. +    tty->termios->c_line = N_TTY;
  27662. +    if (o_tty) {
  27663. +        if (o_tty->ldisc.close)
  27664. +            (o_tty->ldisc.close)(o_tty);
  27665. +        o_tty->ldisc = ldiscs[N_TTY];
  27666. +    }
  27667. +    
  27668. +    tty->driver.table[idx] = NULL;
  27669. +    if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
  27670. +        tty->driver.termios[idx] = NULL;
  27671. +        kfree_s(tp, sizeof(struct termios));
  27672. +    }
  27673. +    if (tty == redirect || o_tty == redirect)
  27674. +        redirect = NULL;
  27675. +    /*
  27676. +     * Make sure that the tty's task queue isn't activated.  If it
  27677. +     * is, take it out of the linked list.
  27678. +     */
  27679. +    cli();
  27680. +    if (tty->flip.tqueue.sync) {
  27681. +        struct tq_struct *tq, *prev;
  27682. +
  27683. +        for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {
  27684. +            if (tq == &tty->flip.tqueue) {
  27685. +                if (prev)
  27686. +                    prev->next = tq->next;
  27687. +                else
  27688. +                    tq_timer = tq->next;
  27689. +                break;
  27690. +            }
  27691. +        }
  27692. +    }
  27693. +    sti();
  27694. +    tty->magic = 0;
  27695. +    (*tty->driver.refcount)--;
  27696. +    kfree_s(tty,sizeof(struct tty_struct));
  27697. +    filp->private_data = 0;
  27698. +    if (o_tty) {
  27699. +        o_tty->magic = 0;
  27700. +        (*o_tty->driver.refcount)--;
  27701. +        kfree_s(o_tty,sizeof(struct tty_struct));
  27702. +    }
  27703. +}
  27704. +
  27705. +/*
  27706. + * tty_open and tty_release keep up the tty count that contains the
  27707. + * number of opens done on a tty. We cannot use the inode-count, as
  27708. + * different inodes might point to the same tty.
  27709. + *
  27710. + * Open-counting is needed for pty masters, as well as for keeping
  27711. + * track of serial lines: DTR is dropped when the last close happens.
  27712. + * (This is not done solely through tty->count, now.  - Ted 1/27/92)
  27713. + *
  27714. + * The termios state of a pty is reset on first open so that
  27715. + * settings don't persist across reuse.
  27716. + */
  27717. +static int tty_open(struct inode * inode, struct file * filp)
  27718. +{
  27719. +    struct tty_struct *tty;
  27720. +    int minor;
  27721. +    int noctty, retval;
  27722. +    dev_t device;
  27723. +
  27724. +retry_open:
  27725. +    noctty = filp->f_flags & O_NOCTTY;
  27726. +    device = inode->i_rdev;
  27727. +    if (device == TTY_DEV) {
  27728. +        if (!current->tty)
  27729. +            return -ENXIO;
  27730. +        device = current->tty->device;
  27731. +        /* noctty = 1; */
  27732. +    }
  27733. +    if (device == CONSOLE_DEV) {
  27734. +        device = MKDEV(TTY_MAJOR, fg_console+1);
  27735. +        noctty = 1;
  27736. +    }
  27737. +    minor = MINOR(device);
  27738. +    
  27739. +    retval = init_dev(device, &tty);
  27740. +    if (retval)
  27741. +        return retval;
  27742. +    filp->private_data = tty;
  27743. +    check_tty_count(tty, "tty_open");
  27744. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  27745. +        tty->driver.subtype == PTY_TYPE_MASTER)
  27746. +        noctty = 1;
  27747. +#ifdef TTY_DEBUG_HANGUP
  27748. +    printk("opening %s...", tty_name(tty));
  27749. +#endif
  27750. +    if (tty->driver.open)
  27751. +        retval = tty->driver.open(tty, filp);
  27752. +    else
  27753. +        retval = -ENODEV;
  27754. +
  27755. +    if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())
  27756. +        retval = -EBUSY;
  27757. +
  27758. +    if (retval) {
  27759. +#ifdef TTY_DEBUG_HANGUP
  27760. +        printk("error %d in opening %s...", retval, tty_name(tty));
  27761. +#endif
  27762. +
  27763. +        release_dev(filp);
  27764. +        if (retval != -ERESTARTSYS)
  27765. +            return retval;
  27766. +        if (current->signal & ~current->blocked)
  27767. +            return retval;
  27768. +        schedule();
  27769. +        /*
  27770. +         * Need to reset f_op in case a hangup happened.
  27771. +         */
  27772. +        filp->f_op = &tty_fops;
  27773. +        goto retry_open;
  27774. +    }
  27775. +    if (!noctty &&
  27776. +        current->leader &&
  27777. +        !current->tty &&
  27778. +        tty->session == 0) {
  27779. +        current->tty = tty;
  27780. +        current->tty_old_pgrp = 0;
  27781. +        tty->session = current->session;
  27782. +        tty->pgrp = current->pgrp;
  27783. +    }
  27784. +    return 0;
  27785. +}
  27786. +
  27787. +/*
  27788. + * Note that releasing a pty master also releases the child, so
  27789. + * we have to make the redirection checks after that and on both
  27790. + * sides of a pty.
  27791. + */
  27792. +static void tty_release(struct inode * inode, struct file * filp)
  27793. +{
  27794. +    release_dev(filp);
  27795. +}
  27796. +
  27797. +static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
  27798. +{
  27799. +    struct tty_struct * tty;
  27800. +
  27801. +    tty = (struct tty_struct *)filp->private_data;
  27802. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_select"))
  27803. +        return 0;
  27804. +
  27805. +    if (tty->ldisc.select)
  27806. +        return (tty->ldisc.select)(tty, inode, filp, sel_type, wait);
  27807. +    return 0;
  27808. +}
  27809. +
  27810. +static int tty_fasync(struct inode * inode, struct file * filp, int on)
  27811. +{
  27812. +    struct tty_struct * tty;
  27813. +    struct fasync_struct *fa, *prev;
  27814. +
  27815. +    tty = (struct tty_struct *)filp->private_data;
  27816. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync"))
  27817. +        return 0;
  27818. +
  27819. +    for (fa = tty->fasync, prev = 0; fa; prev= fa, fa = fa->fa_next) {
  27820. +        if (fa->fa_file == filp)
  27821. +            break;
  27822. +    }
  27823. +
  27824. +    if (on) {
  27825. +        if (fa)
  27826. +            return 0;
  27827. +        fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
  27828. +        if (!fa)
  27829. +            return -ENOMEM;
  27830. +        fa->magic = FASYNC_MAGIC;
  27831. +        fa->fa_file = filp;
  27832. +        fa->fa_next = tty->fasync;
  27833. +        tty->fasync = fa;
  27834. +        if (!tty->read_wait)
  27835. +            tty->minimum_to_wake = 1;
  27836. +        if (filp->f_owner == 0) {
  27837. +            if (tty->pgrp)
  27838. +                filp->f_owner = -tty->pgrp;
  27839. +            else
  27840. +                filp->f_owner = current->pid;
  27841. +        }
  27842. +    } else {
  27843. +        if (!fa)
  27844. +            return 0;
  27845. +        if (prev)
  27846. +            prev->fa_next = fa->fa_next;
  27847. +        else
  27848. +            tty->fasync = fa->fa_next;
  27849. +        kfree_s(fa, sizeof(struct fasync_struct));
  27850. +        if (!tty->fasync && !tty->read_wait)
  27851. +            tty->minimum_to_wake = N_TTY_BUF_SIZE;
  27852. +    }
  27853. +    return 0;    
  27854. +}
  27855. +
  27856. +#if 0
  27857. +/*
  27858. + * XXX does anyone use this anymore?!?
  27859. + */
  27860. +static int do_get_ps_info(unsigned long arg)
  27861. +{
  27862. +    struct tstruct {
  27863. +        int flag;
  27864. +        int present[NR_TASKS];
  27865. +        struct task_struct tasks[NR_TASKS];
  27866. +    };
  27867. +    struct tstruct *ts = (struct tstruct *)arg;
  27868. +    struct task_struct **p;
  27869. +    char *c, *d;
  27870. +    int i, n = 0;
  27871. +    
  27872. +    i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
  27873. +    if (i)
  27874. +        return i;
  27875. +    for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
  27876. +        if (*p)
  27877. +        {
  27878. +            c = (char *)(*p);
  27879. +            d = (char *)(ts->tasks+n);
  27880. +            for (i=0 ; i<sizeof(struct task_struct) ; i++)
  27881. +                put_fs_byte(*c++, d++);
  27882. +            put_fs_long(1, (unsigned long *)(ts->present+n));
  27883. +        }
  27884. +        else    
  27885. +            put_fs_long(0, (unsigned long *)(ts->present+n));
  27886. +    return(0);            
  27887. +}
  27888. +#endif
  27889. +
  27890. +static int tty_ioctl(struct inode * inode, struct file * file,
  27891. +             unsigned int cmd, unsigned long arg)
  27892. +{
  27893. +    int    retval;
  27894. +    struct tty_struct * tty;
  27895. +    struct tty_struct * real_tty;
  27896. +    struct winsize tmp_ws;
  27897. +    pid_t pgrp;
  27898. +    unsigned char    ch;
  27899. +    char    mbz = 0;
  27900. +    
  27901. +    tty = (struct tty_struct *)file->private_data;
  27902. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
  27903. +        return -EINVAL;
  27904. +
  27905. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  27906. +        tty->driver.subtype == PTY_TYPE_MASTER)
  27907. +        real_tty = tty->link;
  27908. +    else
  27909. +        real_tty = tty;
  27910. +
  27911. +    switch (cmd) {
  27912. +        case TIOCSTI:
  27913. +            if ((current->tty != tty) && !suser())
  27914. +                return -EPERM;
  27915. +            retval = verify_area(VERIFY_READ, (void *) arg, 1);
  27916. +            if (retval)
  27917. +                return retval;
  27918. +            ch = get_fs_byte((char *) arg);
  27919. +            tty->ldisc.receive_buf(tty, &ch, &mbz, 1);
  27920. +            return 0;
  27921. +        case TIOCGWINSZ:
  27922. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  27923. +                         sizeof (struct winsize));
  27924. +            if (retval)
  27925. +                return retval;
  27926. +            memcpy_tofs((struct winsize *) arg, &tty->winsize,
  27927. +                    sizeof (struct winsize));
  27928. +            return 0;
  27929. +        case TIOCSWINSZ:
  27930. +            retval = verify_area(VERIFY_READ, (void *) arg,
  27931. +                         sizeof (struct winsize));
  27932. +            if (retval)
  27933. +                return retval;            
  27934. +            memcpy_fromfs(&tmp_ws, (struct winsize *) arg,
  27935. +                      sizeof (struct winsize));
  27936. +            if (memcmp(&tmp_ws, &tty->winsize,
  27937. +                   sizeof(struct winsize))) {
  27938. +                if (tty->pgrp > 0)
  27939. +                    kill_pg(tty->pgrp, SIGWINCH, 1);
  27940. +                if ((real_tty->pgrp != tty->pgrp) &&
  27941. +                    (real_tty->pgrp > 0))
  27942. +                    kill_pg(real_tty->pgrp, SIGWINCH, 1);
  27943. +            }
  27944. +            tty->winsize = tmp_ws;
  27945. +            real_tty->winsize = tmp_ws;
  27946. +            return 0;
  27947. +        case TIOCCONS:
  27948. +            if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE) {
  27949. +                if (!suser())
  27950. +                    return -EPERM;
  27951. +                redirect = NULL;
  27952. +                return 0;
  27953. +            }
  27954. +            if (redirect)
  27955. +                return -EBUSY;
  27956. +            redirect = real_tty;
  27957. +            return 0;
  27958. +        case FIONBIO:
  27959. +            retval = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
  27960. +            if (retval)
  27961. +                return retval;
  27962. +            arg = get_fs_long((unsigned long *) arg);
  27963. +            if (arg)
  27964. +                file->f_flags |= O_NONBLOCK;
  27965. +            else
  27966. +                file->f_flags &= ~O_NONBLOCK;
  27967. +            return 0;
  27968. +        case TIOCEXCL:
  27969. +            set_bit(TTY_EXCLUSIVE, &tty->flags);
  27970. +            return 0;
  27971. +        case TIOCNXCL:
  27972. +            clear_bit(TTY_EXCLUSIVE, &tty->flags);
  27973. +            return 0;
  27974. +        case TIOCNOTTY:
  27975. +            if (current->tty != tty)
  27976. +                return -ENOTTY;
  27977. +            if (current->leader)
  27978. +                disassociate_ctty(0);
  27979. +            current->tty = NULL;
  27980. +            return 0;
  27981. +        case TIOCSCTTY:
  27982. +            if (current->leader &&
  27983. +                (current->session == tty->session))
  27984. +                return 0;
  27985. +            /*
  27986. +             * The process must be a session leader and
  27987. +             * not have a controlling tty already.
  27988. +             */
  27989. +            if (!current->leader || current->tty)
  27990. +                return -EPERM;
  27991. +            if (tty->session > 0) {
  27992. +                /*
  27993. +                 * This tty is already the controlling
  27994. +                 * tty for another session group!
  27995. +                 */
  27996. +                if ((arg == 1) && suser()) {
  27997. +                    /*
  27998. +                     * Steal it away
  27999. +                     */
  28000. +                    struct task_struct *p;
  28001. +
  28002. +                    for_each_task(p)
  28003. +                        if (p->tty == tty)
  28004. +                            p->tty = NULL;
  28005. +                } else
  28006. +                    return -EPERM;
  28007. +            }
  28008. +            current->tty = tty;
  28009. +            current->tty_old_pgrp = 0;
  28010. +            tty->session = current->session;
  28011. +            tty->pgrp = current->pgrp;
  28012. +            return 0;
  28013. +        case TIOCGPGRP:
  28014. +            /*
  28015. +             * (tty == real_tty) is a cheap way of
  28016. +             * testing if the tty is NOT a master pty.
  28017. +             */
  28018. +            if (tty == real_tty && current->tty != real_tty)
  28019. +                return -ENOTTY;
  28020. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  28021. +                         sizeof (pid_t));
  28022. +            if (retval)
  28023. +                return retval;
  28024. +            put_fs_long(real_tty->pgrp, (pid_t *) arg);
  28025. +            return 0;
  28026. +        case TIOCSPGRP:
  28027. +            retval = tty_check_change(real_tty);
  28028. +            if (retval)
  28029. +                return retval;
  28030. +            if (!current->tty ||
  28031. +                (current->tty != real_tty) ||
  28032. +                (real_tty->session != current->session))
  28033. +                return -ENOTTY;
  28034. +            pgrp = get_fs_long((pid_t *) arg);
  28035. +            if (pgrp < 0)
  28036. +                return -EINVAL;
  28037. +            if (session_of_pgrp(pgrp) != current->session)
  28038. +                return -EPERM;
  28039. +            real_tty->pgrp = pgrp;
  28040. +            return 0;
  28041. +        case TIOCGETD:
  28042. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  28043. +                         sizeof (unsigned long));
  28044. +            if (retval)
  28045. +                return retval;
  28046. +            put_fs_long(tty->ldisc.num, (unsigned long *) arg);
  28047. +            return 0;
  28048. +        case TIOCSETD:
  28049. +            retval = tty_check_change(tty);
  28050. +            if (retval)
  28051. +                return retval;
  28052. +            arg = get_fs_long((unsigned long *) arg);
  28053. +            return tty_set_ldisc(tty, arg);
  28054. +        case TIOCLINUX:
  28055. +            if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
  28056. +                return -EINVAL;
  28057. +            if (current->tty != tty && !suser())
  28058. +                return -EPERM;
  28059. +            retval = verify_area(VERIFY_READ, (void *) arg, 1);
  28060. +            if (retval)
  28061. +                return retval;
  28062. +            switch (retval = get_fs_byte((char *)arg))
  28063. +            {
  28064. +                case 0:
  28065. +                case 8:
  28066. +                case 9:
  28067. +                    printk("TIOCLINUX (0/8/9) ioctl is gone - use /dev/vcs\n");
  28068. +                    return -EINVAL;
  28069. +#if 0
  28070. +                case 1:
  28071. +                    printk("Deprecated TIOCLINUX (1) ioctl\n");
  28072. +                    return do_get_ps_info(arg);
  28073. +#endif
  28074. +                case 2:
  28075. +                    return set_selection(arg, tty);
  28076. +                case 3:
  28077. +                    return paste_selection(tty);
  28078. +                case 4:
  28079. +                    do_unblank_screen();
  28080. +                    return 0;
  28081. +                case 5:
  28082. +                    return sel_loadlut(arg);
  28083. +                case 6:
  28084. +            /*
  28085. +             * Make it possible to react to Shift+Mousebutton.
  28086. +             * Note that 'shift_state' is an undocumented
  28087. +             * kernel-internal variable; programs not closely
  28088. +             * related to the kernel should not use this.
  28089. +             */
  28090. +                    put_fs_byte(shift_state,arg);
  28091. +                    return 0;
  28092. +                case 7:
  28093. +                    put_fs_byte(mouse_reporting(),arg);
  28094. +                    return 0;
  28095. +/*                case 10:
  28096. +                    set_vesa_blanking(arg);
  28097. +                    return 0;*/
  28098. +                default: 
  28099. +                    return -EINVAL;
  28100. +            }
  28101. +
  28102. +        case TIOCTTYGSTRUCT:
  28103. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  28104. +                        sizeof(struct tty_struct));
  28105. +            if (retval)
  28106. +                return retval;
  28107. +            memcpy_tofs((struct tty_struct *) arg,
  28108. +                    tty, sizeof(struct tty_struct));
  28109. +            return 0;
  28110. +        default:
  28111. +            if (tty->driver.ioctl) {
  28112. +                retval = (tty->driver.ioctl)(tty, file,
  28113. +                                 cmd, arg);
  28114. +                if (retval != -ENOIOCTLCMD)
  28115. +                    return retval;
  28116. +            }
  28117. +            if (tty->ldisc.ioctl) {
  28118. +                retval = (tty->ldisc.ioctl)(tty, file,
  28119. +                                cmd, arg);
  28120. +                if (retval != -ENOIOCTLCMD)
  28121. +                    return retval;
  28122. +            }
  28123. +            return -EINVAL;
  28124. +        }
  28125. +}
  28126. +
  28127. +
  28128. +/*
  28129. + * This implements the "Secure Attention Key" ---  the idea is to
  28130. + * prevent trojan horses by killing all processes associated with this
  28131. + * tty when the user hits the "Secure Attention Key".  Required for
  28132. + * super-paranoid applications --- see the Orange Book for more details.
  28133. + * 
  28134. + * This code could be nicer; ideally it should send a HUP, wait a few
  28135. + * seconds, then send a INT, and then a KILL signal.  But you then
  28136. + * have to coordinate with the init process, since all processes associated
  28137. + * with the current tty must be dead before the new getty is allowed
  28138. + * to spawn.
  28139. + */
  28140. +void do_SAK( struct tty_struct *tty)
  28141. +{
  28142. +#ifdef TTY_SOFT_SAK
  28143. +    tty_hangup(tty);
  28144. +#else
  28145. +    struct task_struct **p;
  28146. +    int session;
  28147. +    int        i;
  28148. +    struct file    *filp;
  28149. +    
  28150. +    if (!tty)
  28151. +        return;
  28152. +    session  = tty->session;
  28153. +    if (tty->ldisc.flush_buffer)
  28154. +        tty->ldisc.flush_buffer(tty);
  28155. +    if (tty->driver.flush_buffer)
  28156. +        tty->driver.flush_buffer(tty);
  28157. +     for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  28158. +        if (!(*p))
  28159. +            continue;
  28160. +        if (((*p)->tty == tty) ||
  28161. +            ((session > 0) && ((*p)->session == session)))
  28162. +            send_sig(SIGKILL, *p, 1);
  28163. +        else {
  28164. +            for (i=0; i < NR_OPEN; i++) {
  28165. +                filp = (*p)->files->fd[i];
  28166. +                if (filp && (filp->f_op == &tty_fops) &&
  28167. +                    (filp->private_data == tty)) {
  28168. +                    send_sig(SIGKILL, *p, 1);
  28169. +                    break;
  28170. +                }
  28171. +            }
  28172. +        }
  28173. +    }
  28174. +#endif
  28175. +}
  28176. +
  28177. +/*
  28178. + * This routine is called out of the software interrupt to flush data
  28179. + * from the flip buffer to the line discipline.
  28180. + */
  28181. +static void flush_to_ldisc(void *private_)
  28182. +{
  28183. +    struct tty_struct *tty = (struct tty_struct *) private_;
  28184. +    unsigned char    *cp;
  28185. +    char        *fp;
  28186. +    int        count;
  28187. +
  28188. +    if (tty->flip.buf_num) {
  28189. +        cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
  28190. +        fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
  28191. +        tty->flip.buf_num = 0;
  28192. +
  28193. +        cli();
  28194. +        tty->flip.char_buf_ptr = tty->flip.char_buf;
  28195. +        tty->flip.flag_buf_ptr = tty->flip.flag_buf;
  28196. +    } else {
  28197. +        cp = tty->flip.char_buf;
  28198. +        fp = tty->flip.flag_buf;
  28199. +        tty->flip.buf_num = 1;
  28200. +
  28201. +        cli();
  28202. +        tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
  28203. +        tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
  28204. +    }
  28205. +    count = tty->flip.count;
  28206. +    tty->flip.count = 0;
  28207. +    sti();
  28208. +    
  28209. +#if 0
  28210. +    if (count > tty->max_flip_cnt)
  28211. +        tty->max_flip_cnt = count;
  28212. +#endif
  28213. +    tty->ldisc.receive_buf(tty, cp, fp, count);
  28214. +}
  28215. +
  28216. +/*
  28217. + * This subroutine initializes a tty structure.
  28218. + */
  28219. +static void initialize_tty_struct(struct tty_struct *tty)
  28220. +{
  28221. +    memset(tty, 0, sizeof(struct tty_struct));
  28222. +    tty->magic = TTY_MAGIC;
  28223. +    tty->ldisc = ldiscs[N_TTY];
  28224. +    tty->pgrp = -1;
  28225. +    tty->flip.char_buf_ptr = tty->flip.char_buf;
  28226. +    tty->flip.flag_buf_ptr = tty->flip.flag_buf;
  28227. +    tty->flip.tqueue.routine = flush_to_ldisc;
  28228. +    tty->flip.tqueue.data = tty;
  28229. +}
  28230. +
  28231. +/*
  28232. + * The default put_char routine if the driver did not define one.
  28233. + */
  28234. +void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
  28235. +{
  28236. +    tty->driver.write(tty, 0, &ch, 1);
  28237. +}
  28238. +
  28239. +/*
  28240. + * Called by a tty driver to register itself.
  28241. + */
  28242. +int tty_register_driver(struct tty_driver *driver)
  28243. +{
  28244. +    int error;
  28245. +
  28246. +    if (driver->flags & TTY_DRIVER_INSTALLED)
  28247. +        return 0;
  28248. +
  28249. +    error = register_chrdev(driver->major, driver->name, &tty_fops);
  28250. +    if (error < 0)
  28251. +        return error;
  28252. +    else if(driver->major == 0)
  28253. +        driver->major = error;
  28254. +
  28255. +    if (!driver->put_char)
  28256. +        driver->put_char = tty_default_put_char;
  28257. +    
  28258. +    driver->prev = 0;
  28259. +    driver->next = tty_drivers;
  28260. +    if (tty_drivers) tty_drivers->prev = driver;
  28261. +    tty_drivers = driver;
  28262. +    return error;
  28263. +}
  28264. +
  28265. +/*
  28266. + * Called by a tty driver to unregister itself.
  28267. + */
  28268. +int tty_unregister_driver(struct tty_driver *driver)
  28269. +{
  28270. +    int    retval;
  28271. +    struct tty_driver *p;
  28272. +    int    found = 0;
  28273. +    char *othername = NULL;
  28274. +    
  28275. +    if (*driver->refcount)
  28276. +        return -EBUSY;
  28277. +
  28278. +    for (p = tty_drivers; p; p = p->next) {
  28279. +        if (p == driver)
  28280. +            found++;
  28281. +        else if (p->major == driver->major)
  28282. +            othername = p->name;
  28283. +    }
  28284. +
  28285. +    if (othername == NULL) {
  28286. +        retval = unregister_chrdev(driver->major, driver->name);
  28287. +        if (retval)
  28288. +            return retval;
  28289. +    } else
  28290. +        register_chrdev(driver->major, othername, &tty_fops);
  28291. +
  28292. +    if (driver->prev)
  28293. +        driver->prev->next = driver->next;
  28294. +    else
  28295. +        tty_drivers = driver->next;
  28296. +    
  28297. +    if (driver->next)
  28298. +        driver->next->prev = driver->prev;
  28299. +
  28300. +    return 0;
  28301. +}
  28302. +
  28303. +
  28304. +/*
  28305. + * Initialize the console device. This is called *early*, so
  28306. + * we can't necessarily depend on lots of kernel help here.
  28307. + * Just do some early initializations, and do the complex setup
  28308. + * later.
  28309. + */
  28310. +long console_init(long kmem_start, long kmem_end)
  28311. +{
  28312. +    /* Setup the default TTY line discipline. */
  28313. +    memset(ldiscs, 0, sizeof(ldiscs));
  28314. +    (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
  28315. +
  28316. +    /*
  28317. +     * Set up the standard termios.  Individual tty drivers may 
  28318. +     * deviate from this; this is used as a template.
  28319. +     */
  28320. +    memset(&tty_std_termios, 0, sizeof(struct termios));
  28321. +    memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
  28322. +    tty_std_termios.c_iflag = ICRNL | IXON;
  28323. +    tty_std_termios.c_oflag = OPOST | ONLCR;
  28324. +    tty_std_termios.c_cflag = B38400 | CS8 | CREAD;
  28325. +    tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
  28326. +        ECHOCTL | ECHOKE | IEXTEN;
  28327. +
  28328. +    /*
  28329. +     * set up the console device so that later boot sequences can 
  28330. +     * inform about problems etc..
  28331. +     */
  28332. +    return con_init(kmem_start);
  28333. +}
  28334. +
  28335. +/*
  28336. + * Ok, now we can initialize the rest of the tty devices and can count
  28337. + * on memory allocations, interrupts etc..
  28338. + */
  28339. +long tty_init(long kmem_start)
  28340. +{
  28341. +    if (sizeof(struct tty_struct) > PAGE_SIZE)
  28342. +        panic("size of tty structure > PAGE_SIZE!");
  28343. +    if (register_chrdev(TTY_MAJOR,"tty",&tty_fops))
  28344. +        panic("unable to get major %d for tty device", TTY_MAJOR);
  28345. +    if (register_chrdev(TTYAUX_MAJOR,"cua",&tty_fops))
  28346. +        panic("unable to get major %d for tty device", TTYAUX_MAJOR);
  28347. +
  28348. +    kmem_start = kbd_init(kmem_start);
  28349. +    kmem_start = rs_init(kmem_start);
  28350. +#ifdef CONFIG_CYCLADES
  28351. +    kmem_start = cy_init(kmem_start);
  28352. +#endif
  28353. +    kmem_start = pty_init(kmem_start);
  28354. +    kmem_start = vcs_init(kmem_start);
  28355. +    return kmem_start;
  28356. +}
  28357. diff -r -u -N linux.orig/arch/arm/drivers/char/tty_io.c.orig linux.arm/arch/arm/drivers/char/tty_io.c.orig
  28358. --- linux.orig/arch/arm/drivers/char/tty_io.c.orig    Thu Jan  1 01:00:00 1970
  28359. +++ linux.arm/arch/arm/drivers/char/tty_io.c.orig    Fri Oct 27 23:14:41 1995
  28360. @@ -0,0 +1,1667 @@
  28361. +/*
  28362. + *  linux/drivers/char/tty_io.c
  28363. + *
  28364. + *  Copyright (C) 1991, 1992  Linus Torvalds
  28365. + */
  28366. +
  28367. +/*
  28368. + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
  28369. + * or rs-channels. It also implements echoing, cooked mode etc.
  28370. + *
  28371. + * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
  28372. + *
  28373. + * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
  28374. + * tty_struct and tty_queue structures.  Previously there was a array
  28375. + * of 256 tty_struct's which was statically allocated, and the
  28376. + * tty_queue structures were allocated at boot time.  Both are now
  28377. + * dynamically allocated only when the tty is open.
  28378. + *
  28379. + * Also restructured routines so that there is more of a separation
  28380. + * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
  28381. + * the low-level tty routines (serial.c, pty.c, console.c).  This
  28382. + * makes for cleaner and more compact code.  -TYT, 9/17/92
  28383. + *
  28384. + * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
  28385. + * which can be dynamically activated and de-activated by the line
  28386. + * discipline handling modules (like SLIP).
  28387. + *
  28388. + * NOTE: pay no attention to the line discipline code (yet); its
  28389. + * interface is still subject to change in this version...
  28390. + * -- TYT, 1/31/92
  28391. + *
  28392. + * Added functionality to the OPOST tty handling.  No delays, but all
  28393. + * other bits should be there.
  28394. + *    -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
  28395. + *
  28396. + * Rewrote canonical mode and added more termios flags.
  28397. + *     -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
  28398. + */
  28399. +
  28400. +#include <linux/types.h>
  28401. +#include <linux/major.h>
  28402. +#include <linux/errno.h>
  28403. +#include <linux/signal.h>
  28404. +#include <linux/fcntl.h>
  28405. +#include <linux/sched.h>
  28406. +#include <linux/interrupt.h>
  28407. +#include <linux/tty.h>
  28408. +#include <linux/tty_flip.h>
  28409. +#include <linux/timer.h>
  28410. +#include <linux/ctype.h>
  28411. +#include <linux/kd.h>
  28412. +#include <linux/mm.h>
  28413. +#include <linux/string.h>
  28414. +#include <linux/malloc.h>
  28415. +
  28416. +#include <asm/segment.h>
  28417. +#include <asm/system.h>
  28418. +#include <asm/bitops.h>
  28419. +
  28420. +#include "kbd_kern.h"
  28421. +#include "vt_kern.h"
  28422. +
  28423. +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
  28424. +#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
  28425. +
  28426. +#undef TTY_DEBUG_HANGUP
  28427. +
  28428. +extern int set_selection(const int arg, struct tty_struct *tty);
  28429. +extern int paste_selection(struct tty_struct *tty);
  28430. +extern int sel_loadlut(const int arg);
  28431. +extern int mouse_reporting(void);
  28432. +extern int shift_state;
  28433. +extern int do_screendump(int arg);
  28434. +
  28435. +struct termios tty_std_termios;        /* for the benefit of tty drivers  */
  28436. +struct tty_driver *tty_drivers = NULL;    /* linked list of tty drivers */
  28437. +struct tty_ldisc ldiscs[NR_LDISCS];    /* line disc dispatch table    */
  28438. +
  28439. +/*
  28440. + * fg_console is the current virtual console,
  28441. + * redirect is the pseudo-tty that console output
  28442. + * is redirected to if asked by TIOCCONS.
  28443. + */
  28444. +int fg_console = 0;
  28445. +struct tty_struct * redirect = NULL;
  28446. +struct wait_queue * keypress_wait = NULL;
  28447. +
  28448. +static void initialize_tty_struct(struct tty_struct *tty);
  28449. +
  28450. +static int tty_read(struct inode *, struct file *, char *, int);
  28451. +static int tty_write(struct inode *, struct file *, char *, int);
  28452. +static int tty_select(struct inode *, struct file *, int, select_table *);
  28453. +static int tty_open(struct inode *, struct file *);
  28454. +static void tty_release(struct inode *, struct file *);
  28455. +static int tty_ioctl(struct inode * inode, struct file * file,
  28456. +             unsigned int cmd, unsigned long arg);
  28457. +static int tty_fasync(struct inode * inode, struct file * filp, int on);
  28458. +
  28459. +#ifndef MIN
  28460. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  28461. +#endif
  28462. +
  28463. +/*
  28464. + * These two routines return the name of tty.  tty_name() should NOT
  28465. + * be used in interrupt drivers, since it's not re-entrant.  Use
  28466. + * _tty_name() instead.
  28467. + */
  28468. +char *_tty_name(struct tty_struct *tty, char *buf)
  28469. +{
  28470. +    if (tty)
  28471. +        sprintf(buf, "%s%d", tty->driver.name,
  28472. +            MINOR(tty->device) - tty->driver.minor_start +
  28473. +            tty->driver.name_base);
  28474. +    else
  28475. +        strcpy(buf, "NULL tty");
  28476. +    return buf;
  28477. +}
  28478. +
  28479. +char *tty_name(struct tty_struct *tty)
  28480. +{
  28481. +    static char buf[64];
  28482. +
  28483. +    return(_tty_name(tty, buf));
  28484. +}
  28485. +
  28486. +#define TTY_PARANOIA_CHECK
  28487. +
  28488. +inline int tty_paranoia_check(struct tty_struct *tty, dev_t device,
  28489. +                  const char *routine)
  28490. +{
  28491. +#ifdef TTY_PARANOIA_CHECK
  28492. +    static const char *badmagic =
  28493. +        "Warning: bad magic number for tty struct (%d, %d) in %s\n";
  28494. +    static const char *badtty =
  28495. +        "Warning: null TTY for (%d, %d) in %s\n";
  28496. +
  28497. +    if (!tty) {
  28498. +        printk(badtty, MAJOR(device), MINOR(device), routine);
  28499. +        return 1;
  28500. +    }
  28501. +    if (tty->magic != TTY_MAGIC) {
  28502. +        printk(badmagic, MAJOR(device), MINOR(device), routine);
  28503. +        return 1;
  28504. +    }
  28505. +#endif
  28506. +    return 0;
  28507. +}
  28508. +
  28509. +int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
  28510. +{
  28511. +    if (disc < N_TTY || disc >= NR_LDISCS)
  28512. +        return -EINVAL;
  28513. +
  28514. +    if (new_ldisc) {
  28515. +        ldiscs[disc] = *new_ldisc;
  28516. +        ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
  28517. +        ldiscs[disc].num = disc;
  28518. +    } else
  28519. +        memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
  28520. +
  28521. +    return 0;
  28522. +}
  28523. +
  28524. +/* Set the discipline of a tty line. */
  28525. +static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
  28526. +{
  28527. +    int    retval = 0;
  28528. +    struct    tty_ldisc o_ldisc;
  28529. +
  28530. +    if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
  28531. +        !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
  28532. +        return -EINVAL;
  28533. +
  28534. +    if (tty->ldisc.num == ldisc)
  28535. +        return 0;    /* We are already in the desired discipline */
  28536. +    o_ldisc = tty->ldisc;
  28537. +
  28538. +    /* Shutdown the current discipline. */
  28539. +    if (tty->ldisc.close)
  28540. +        (tty->ldisc.close)(tty);
  28541. +
  28542. +    /* Now set up the new line discipline. */
  28543. +    tty->ldisc = ldiscs[ldisc];
  28544. +    tty->termios->c_line = ldisc;
  28545. +    if (tty->ldisc.open)
  28546. +        retval = (tty->ldisc.open)(tty);
  28547. +    if (retval < 0) {
  28548. +        tty->ldisc = o_ldisc;
  28549. +        tty->termios->c_line = tty->ldisc.num;
  28550. +        if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
  28551. +            tty->ldisc = ldiscs[N_TTY];
  28552. +            tty->termios->c_line = N_TTY;
  28553. +            if (tty->ldisc.open) {
  28554. +                int r = tty->ldisc.open(tty);
  28555. +
  28556. +                if (r < 0)
  28557. +                    panic("Couldn't open N_TTY ldisc for "
  28558. +                          "%s --- error %d.",
  28559. +                          tty_name(tty), r);
  28560. +            }
  28561. +        }
  28562. +    }
  28563. +    if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc)
  28564. +        tty->driver.set_ldisc(tty);
  28565. +    return retval;
  28566. +}
  28567. +
  28568. +/*
  28569. + * This routine returns a tty driver structure, given a device number
  28570. + */
  28571. +struct tty_driver *get_tty_driver(dev_t device)
  28572. +{
  28573. +    int    major, minor;
  28574. +    struct tty_driver *p;
  28575. +
  28576. +    minor = MINOR(device);
  28577. +    major = MAJOR(device);
  28578. +
  28579. +    for (p = tty_drivers; p; p = p->next) {
  28580. +        if (p->major != major)
  28581. +            continue;
  28582. +        if (minor < p->minor_start)
  28583. +            continue;
  28584. +        if (minor >= p->minor_start + p->num)
  28585. +            continue;
  28586. +        return p;
  28587. +    }
  28588. +    return NULL;
  28589. +}
  28590. +
  28591. +/*
  28592. + * If we try to write to, or set the state of, a terminal and we're
  28593. + * not in the foreground, send a SIGTTOU.  If the signal is blocked or
  28594. + * ignored, go ahead and perform the operation.  (POSIX 7.2)
  28595. + */
  28596. +int tty_check_change(struct tty_struct * tty)
  28597. +{
  28598. +    if (current->tty != tty)
  28599. +        return 0;
  28600. +    if (tty->pgrp <= 0) {
  28601. +        printk("tty_check_change: tty->pgrp <= 0!\n");
  28602. +        return 0;
  28603. +    }
  28604. +    if (current->pgrp == tty->pgrp)
  28605. +        return 0;
  28606. +    if (is_ignored(SIGTTOU))
  28607. +        return 0;
  28608. +    if (is_orphaned_pgrp(current->pgrp))
  28609. +        return -EIO;
  28610. +    (void) kill_pg(current->pgrp,SIGTTOU,1);
  28611. +    return -ERESTARTSYS;
  28612. +}
  28613. +
  28614. +static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count)
  28615. +{
  28616. +    return 0;
  28617. +}
  28618. +
  28619. +static int hung_up_tty_write(struct inode * inode, struct file * file, char * buf, int count)
  28620. +{
  28621. +    return -EIO;
  28622. +}
  28623. +
  28624. +static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
  28625. +{
  28626. +    return 1;
  28627. +}
  28628. +
  28629. +static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
  28630. +                 unsigned int cmd, unsigned long arg)
  28631. +{
  28632. +    return -EIO;
  28633. +}
  28634. +
  28635. +static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  28636. +{
  28637. +    return -ESPIPE;
  28638. +}
  28639. +
  28640. +static struct file_operations tty_fops = {
  28641. +    tty_lseek,
  28642. +    tty_read,
  28643. +    tty_write,
  28644. +    NULL,        /* tty_readdir */
  28645. +    tty_select,
  28646. +    tty_ioctl,
  28647. +    NULL,        /* tty_mmap */
  28648. +    tty_open,
  28649. +    tty_release,
  28650. +    NULL,        /* tty_fsync */
  28651. +    tty_fasync
  28652. +};
  28653. +
  28654. +static struct file_operations hung_up_tty_fops = {
  28655. +    tty_lseek,
  28656. +    hung_up_tty_read,
  28657. +    hung_up_tty_write,
  28658. +    NULL,        /* hung_up_tty_readdir */
  28659. +    hung_up_tty_select,
  28660. +    hung_up_tty_ioctl,
  28661. +    NULL,        /* hung_up_tty_mmap */
  28662. +    NULL,        /* hung_up_tty_open */
  28663. +    tty_release,    /* hung_up_tty_release */
  28664. +    NULL,        /* hung_up_tty_fsync  */
  28665. +    NULL        /* hung_up_tty_fasync */
  28666. +};
  28667. +
  28668. +void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
  28669. +{
  28670. +    int i;
  28671. +    struct file * filp;
  28672. +    struct task_struct *p;
  28673. +
  28674. +    if (!tty)
  28675. +        return;
  28676. +    for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) {
  28677. +        if (!filp->f_count)
  28678. +            continue;
  28679. +        if (filp->private_data != tty)
  28680. +            continue;
  28681. +        if (filp->f_inode && filp->f_inode->i_rdev == CONSOLE_DEV)
  28682. +            continue;
  28683. +        if (filp->f_op != &tty_fops)
  28684. +            continue;
  28685. +        tty_fasync(filp->f_inode, filp, 0);
  28686. +        filp->f_op = fops;
  28687. +    }
  28688. +
  28689. +    if (tty->ldisc.flush_buffer)
  28690. +        tty->ldisc.flush_buffer(tty);
  28691. +    if (tty->driver.flush_buffer)
  28692. +        tty->driver.flush_buffer(tty);
  28693. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  28694. +        tty->ldisc.write_wakeup)
  28695. +        (tty->ldisc.write_wakeup)(tty);
  28696. +    wake_up_interruptible(&tty->write_wait);
  28697. +    wake_up_interruptible(&tty->read_wait);
  28698. +
  28699. +    /*
  28700. +     * Shutdown the current line discipline, and reset it to
  28701. +     * N_TTY.
  28702. +     */
  28703. +    if (tty->ldisc.num != ldiscs[N_TTY].num) {
  28704. +        if (tty->ldisc.close)
  28705. +            (tty->ldisc.close)(tty);
  28706. +        tty->ldisc = ldiscs[N_TTY];
  28707. +        tty->termios->c_line = N_TTY;
  28708. +        if (tty->ldisc.open) {
  28709. +            i = (tty->ldisc.open)(tty);
  28710. +            if (i < 0)
  28711. +                printk("do_tty_hangup: N_TTY open: error %d\n",
  28712. +                       -i);
  28713. +        }
  28714. +    }
  28715. +
  28716. +    if (tty->session > 0) {
  28717. +        kill_sl(tty->session,SIGHUP,1);
  28718. +        kill_sl(tty->session,SIGCONT,1);
  28719. +    }
  28720. +    tty->flags = 0;
  28721. +    tty->session = 0;
  28722. +    tty->pgrp = -1;
  28723. +     for_each_task(p) {
  28724. +        if (p->tty == tty)
  28725. +            p->tty = NULL;
  28726. +    }
  28727. +    if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
  28728. +        *tty->termios = tty->driver.init_termios;
  28729. +    if (tty->driver.hangup)
  28730. +        (tty->driver.hangup)(tty);
  28731. +}
  28732. +
  28733. +void tty_hangup(struct tty_struct * tty)
  28734. +{
  28735. +#ifdef TTY_DEBUG_HANGUP
  28736. +    printk("%s hangup...\n", tty_name(tty));
  28737. +#endif
  28738. +    do_tty_hangup(tty, &hung_up_tty_fops);
  28739. +}
  28740. +
  28741. +void tty_vhangup(struct tty_struct * tty)
  28742. +{
  28743. +#ifdef TTY_DEBUG_HANGUP
  28744. +    printk("%s vhangup...\n", tty_name(tty));
  28745. +#endif
  28746. +    do_tty_hangup(tty, &hung_up_tty_fops);
  28747. +}
  28748. +
  28749. +int tty_hung_up_p(struct file * filp)
  28750. +{
  28751. +    return (filp->f_op == &hung_up_tty_fops);
  28752. +}
  28753. +
  28754. +/*
  28755. + * This function is typically called only by the session leader, when
  28756. + * it wants to disassociate itself from its controlling tty.
  28757. + *
  28758. + * It performs the following functions:
  28759. + *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
  28760. + *     (2)  Clears the tty from being controlling the session
  28761. + *     (3)  Clears the controlling tty for all processes in the
  28762. + *         session group.
  28763. + */
  28764. +void disassociate_ctty(int priv)
  28765. +{
  28766. +    struct tty_struct *tty = current->tty;
  28767. +    struct task_struct *p;
  28768. +
  28769. +    if (!tty)
  28770. +        return;
  28771. +
  28772. +    if (tty->pgrp > 0) {
  28773. +        kill_pg(tty->pgrp, SIGHUP, priv);
  28774. +        kill_pg(tty->pgrp, SIGCONT, priv);
  28775. +    }
  28776. +    tty->session = 0;
  28777. +    tty->pgrp = -1;
  28778. +
  28779. +    for_each_task(p)
  28780. +          if (p->session == current->session)
  28781. +            p->tty = NULL;
  28782. +}
  28783. +
  28784. +/*
  28785. + * Sometimes we want to wait until a particular VT has been activated. We
  28786. + * do it in a very simple manner. Everybody waits on a single queue and
  28787. + * get woken up at once. Those that are satisfied go on with their business,
  28788. + * while those not ready go back to sleep. Seems overkill to add a wait
  28789. + * to each vt just for this - usually this does nothing!
  28790. + */
  28791. +static struct wait_queue *vt_activate_queue = NULL;
  28792. +
  28793. +/*
  28794. + * Sleeps until a vt is activated, or the task is interrupted. Returns
  28795. + * 0 if activation, -1 if interrupted.
  28796. + */
  28797. +int vt_waitactive(void)
  28798. +{
  28799. +    interruptible_sleep_on(&vt_activate_queue);
  28800. +    return (current->signal & ~current->blocked) ? -1 : 0;
  28801. +}
  28802. +
  28803. +#define vt_wake_waitactive() wake_up(&vt_activate_queue)
  28804. +
  28805. +void reset_vc(unsigned int new_console)
  28806. +{
  28807. +    vt_cons[new_console]->vc_mode = KD_TEXT;
  28808. +    kbd_table[new_console].kbdmode = VC_XLATE;
  28809. +    vt_cons[new_console]->vt_mode.mode = VT_AUTO;
  28810. +    vt_cons[new_console]->vt_mode.waitv = 0;
  28811. +    vt_cons[new_console]->vt_mode.relsig = 0;
  28812. +    vt_cons[new_console]->vt_mode.acqsig = 0;
  28813. +    vt_cons[new_console]->vt_mode.frsig = 0;
  28814. +    vt_cons[new_console]->vt_pid = -1;
  28815. +    vt_cons[new_console]->vt_newvt = -1;
  28816. +}
  28817. +
  28818. +/*
  28819. + * Performs the back end of a vt switch
  28820. + */
  28821. +void complete_change_console(unsigned int new_console)
  28822. +{
  28823. +    unsigned char old_vc_mode;
  28824. +
  28825. +        if (new_console == fg_console)
  28826. +                return;
  28827. +        if (!vc_cons_allocated(new_console))
  28828. +                return;
  28829. +
  28830. +    /*
  28831. +     * If we're switching, we could be going from KD_GRAPHICS to
  28832. +     * KD_TEXT mode or vice versa, which means we need to blank or
  28833. +     * unblank the screen later.
  28834. +     */
  28835. +    old_vc_mode = vt_cons[fg_console]->vc_mode;
  28836. +    update_screen(new_console);
  28837. +
  28838. +    /*
  28839. +     * If this new console is under process control, send it a signal
  28840. +     * telling it that it has acquired. Also check if it has died and
  28841. +     * clean up (similar to logic employed in change_console())
  28842. +     */
  28843. +    if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS)
  28844. +    {
  28845. +        /*
  28846. +         * Send the signal as privileged - kill_proc() will
  28847. +         * tell us if the process has gone or something else
  28848. +         * is awry
  28849. +         */
  28850. +        if (kill_proc(vt_cons[new_console]->vt_pid,
  28851. +                  vt_cons[new_console]->vt_mode.acqsig,
  28852. +                  1) != 0)
  28853. +        {
  28854. +        /*
  28855. +         * The controlling process has died, so we revert back to
  28856. +         * normal operation. In this case, we'll also change back
  28857. +         * to KD_TEXT mode. I'm not sure if this is strictly correct
  28858. +         * but it saves the agony when the X server dies and the screen
  28859. +         * remains blanked due to KD_GRAPHICS! It would be nice to do
  28860. +         * this outside of VT_PROCESS but there is no single process
  28861. +         * to account for and tracking tty count may be undesirable.
  28862. +         */
  28863. +                reset_vc(new_console);
  28864. +        }
  28865. +    }
  28866. +
  28867. +    /*
  28868. +     * We do this here because the controlling process above may have
  28869. +     * gone, and so there is now a new vc_mode
  28870. +     */
  28871. +    if (old_vc_mode != vt_cons[new_console]->vc_mode)
  28872. +    {
  28873. +        if (vt_cons[new_console]->vc_mode == KD_TEXT)
  28874. +            unblank_screen();
  28875. +        else {
  28876. +            timer_active &= ~(1<<BLANK_TIMER);
  28877. +            blank_screen();
  28878. +        }
  28879. +    }
  28880. +
  28881. +    /*
  28882. +     * Wake anyone waiting for their VT to activate
  28883. +     */
  28884. +    vt_wake_waitactive();
  28885. +    return;
  28886. +}
  28887. +
  28888. +/*
  28889. + * Performs the front-end of a vt switch
  28890. + */
  28891. +void change_console(unsigned int new_console)
  28892. +{
  28893. +        if (new_console == fg_console)
  28894. +                return;
  28895. +        if (!vc_cons_allocated(new_console))
  28896. +        return;
  28897. +
  28898. +    /*
  28899. +     * If this vt is in process mode, then we need to handshake with
  28900. +     * that process before switching. Essentially, we store where that
  28901. +     * vt wants to switch to and wait for it to tell us when it's done
  28902. +     * (via VT_RELDISP ioctl).
  28903. +     *
  28904. +     * We also check to see if the controlling process still exists.
  28905. +     * If it doesn't, we reset this vt to auto mode and continue.
  28906. +     * This is a cheap way to track process control. The worst thing
  28907. +     * that can happen is: we send a signal to a process, it dies, and
  28908. +     * the switch gets "lost" waiting for a response; hopefully, the
  28909. +     * user will try again, we'll detect the process is gone (unless
  28910. +     * the user waits just the right amount of time :-) and revert the
  28911. +     * vt to auto control.
  28912. +     */
  28913. +    if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS)
  28914. +    {
  28915. +        /*
  28916. +         * Send the signal as privileged - kill_proc() will
  28917. +         * tell us if the process has gone or something else
  28918. +         * is awry
  28919. +         */
  28920. +        if (kill_proc(vt_cons[fg_console]->vt_pid,
  28921. +                  vt_cons[fg_console]->vt_mode.relsig,
  28922. +                  1) == 0)
  28923. +        {
  28924. +            /*
  28925. +             * It worked. Mark the vt to switch to and
  28926. +             * return. The process needs to send us a
  28927. +             * VT_RELDISP ioctl to complete the switch.
  28928. +             */
  28929. +            vt_cons[fg_console]->vt_newvt = new_console;
  28930. +            return;
  28931. +        }
  28932. +
  28933. +        /*
  28934. +         * The controlling process has died, so we revert back to
  28935. +         * normal operation. In this case, we'll also change back
  28936. +         * to KD_TEXT mode. I'm not sure if this is strictly correct
  28937. +         * but it saves the agony when the X server dies and the screen
  28938. +         * remains blanked due to KD_GRAPHICS! It would be nice to do
  28939. +         * this outside of VT_PROCESS but there is no single process
  28940. +         * to account for and tracking tty count may be undesirable.
  28941. +         */
  28942. +        reset_vc(fg_console);
  28943. +
  28944. +        /*
  28945. +         * Fall through to normal (VT_AUTO) handling of the switch...
  28946. +         */
  28947. +    }
  28948. +
  28949. +    /*
  28950. +     * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
  28951. +     */
  28952. +    if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
  28953. +        return;
  28954. +
  28955. +    complete_change_console(new_console);
  28956. +}
  28957. +
  28958. +void wait_for_keypress(void)
  28959. +{
  28960. +    sleep_on(&keypress_wait);
  28961. +}
  28962. +
  28963. +void stop_tty(struct tty_struct *tty)
  28964. +{
  28965. +    if (tty->stopped)
  28966. +        return;
  28967. +    tty->stopped = 1;
  28968. +    if (tty->link && tty->link->packet) {
  28969. +        tty->ctrl_status &= ~TIOCPKT_START;
  28970. +        tty->ctrl_status |= TIOCPKT_STOP;
  28971. +        wake_up_interruptible(&tty->link->read_wait);
  28972. +    }
  28973. +    if (tty->driver.stop)
  28974. +        (tty->driver.stop)(tty);
  28975. +}
  28976. +
  28977. +void start_tty(struct tty_struct *tty)
  28978. +{
  28979. +    if (!tty->stopped)
  28980. +        return;
  28981. +    tty->stopped = 0;
  28982. +    if (tty->link && tty->link->packet) {
  28983. +        tty->ctrl_status &= ~TIOCPKT_STOP;
  28984. +        tty->ctrl_status |= TIOCPKT_START;
  28985. +        wake_up_interruptible(&tty->link->read_wait);
  28986. +    }
  28987. +    if (tty->driver.start)
  28988. +        (tty->driver.start)(tty);
  28989. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  28990. +        tty->ldisc.write_wakeup)
  28991. +        (tty->ldisc.write_wakeup)(tty);
  28992. +    wake_up_interruptible(&tty->write_wait);
  28993. +}
  28994. +
  28995. +static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
  28996. +{
  28997. +    int i;
  28998. +    struct tty_struct * tty;
  28999. +
  29000. +    tty = (struct tty_struct *)file->private_data;
  29001. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_read"))
  29002. +        return -EIO;
  29003. +    if (!tty || (tty->flags & (1 << TTY_IO_ERROR)))
  29004. +        return -EIO;
  29005. +
  29006. +    /* This check not only needs to be done before reading, but also
  29007. +       whenever read_chan() gets woken up after sleeping, so I've
  29008. +       moved it to there.  This should only be done for the N_TTY
  29009. +       line discipline, anyway.  Same goes for write_chan(). -- jlc. */
  29010. +#if 0
  29011. +    if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
  29012. +        (tty->pgrp > 0) &&
  29013. +        (current->tty == tty) &&
  29014. +        (tty->pgrp != current->pgrp))
  29015. +        if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
  29016. +            return -EIO;
  29017. +        else {
  29018. +            (void) kill_pg(current->pgrp, SIGTTIN, 1);
  29019. +            return -ERESTARTSYS;
  29020. +        }
  29021. +#endif
  29022. +    if (tty->ldisc.read)
  29023. +        /* XXX casts are for what kernel-wide prototypes should be. */
  29024. +        i = (tty->ldisc.read)(tty,file,(unsigned char *)buf,(unsigned int)count);
  29025. +    else
  29026. +        i = -EIO;
  29027. +    if (i > 0)
  29028. +        inode->i_atime = CURRENT_TIME;
  29029. +    return i;
  29030. +}
  29031. +
  29032. +static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
  29033. +{
  29034. +    int i, is_console;
  29035. +    struct tty_struct * tty;
  29036. +
  29037. +    is_console = (inode->i_rdev == CONSOLE_DEV);
  29038. +
  29039. +    if (is_console && redirect)
  29040. +        tty = redirect;
  29041. +    else
  29042. +        tty = (struct tty_struct *)file->private_data;
  29043. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_write"))
  29044. +        return -EIO;
  29045. +    if (!tty || !tty->driver.write || (tty->flags & (1 << TTY_IO_ERROR)))
  29046. +        return -EIO;
  29047. +#if 0
  29048. +    if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
  29049. +        (current->tty == tty) && (tty->pgrp != current->pgrp)) {
  29050. +        if (is_orphaned_pgrp(current->pgrp))
  29051. +            return -EIO;
  29052. +        if (!is_ignored(SIGTTOU)) {
  29053. +            (void) kill_pg(current->pgrp, SIGTTOU, 1);
  29054. +            return -ERESTARTSYS;
  29055. +        }
  29056. +    }
  29057. +#endif
  29058. +    if (tty->ldisc.write)
  29059. +        /* XXX casts are for what kernel-wide prototypes should be. */
  29060. +        i = (tty->ldisc.write)(tty,file,(unsigned char *)buf,(unsigned int)count);
  29061. +    else
  29062. +        i = -EIO;
  29063. +    if (i > 0)
  29064. +        inode->i_mtime = CURRENT_TIME;
  29065. +    return i;
  29066. +}
  29067. +
  29068. +/*
  29069. + * This is so ripe with races that you should *really* not touch this
  29070. + * unless you know exactly what you are doing. All the changes have to be
  29071. + * made atomically, or there may be incorrect pointers all over the place.
  29072. + */
  29073. +static int init_dev(dev_t device, struct tty_struct **ret_tty)
  29074. +{
  29075. +    struct tty_struct *tty, **tty_loc, *o_tty, **o_tty_loc;
  29076. +    struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
  29077. +    struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
  29078. +    struct tty_driver *driver;
  29079. +    int retval;
  29080. +    int idx;
  29081. +
  29082. +    driver = get_tty_driver(device);
  29083. +    if (!driver)
  29084. +        return -ENODEV;
  29085. +
  29086. +    idx = MINOR(device) - driver->minor_start;
  29087. +    tty = o_tty = NULL;
  29088. +    tp = o_tp = NULL;
  29089. +    ltp = o_ltp = NULL;
  29090. +    o_tty_loc = NULL;
  29091. +    o_tp_loc = o_ltp_loc = NULL;
  29092. +
  29093. +    tty_loc = &driver->table[idx];
  29094. +    tp_loc = &driver->termios[idx];
  29095. +    ltp_loc = &driver->termios_locked[idx];
  29096. +repeat:
  29097. +    retval = -EAGAIN;
  29098. +    if (driver->type == TTY_DRIVER_TYPE_PTY &&
  29099. +        driver->subtype == PTY_TYPE_MASTER &&
  29100. +        *tty_loc && (*tty_loc)->count)
  29101. +        goto end_init;
  29102. +    retval = -ENOMEM;
  29103. +    if (!*tty_loc && !tty) {
  29104. +        if (!(tty = (struct tty_struct*) kmalloc(sizeof(struct tty_struct),
  29105. +                            GFP_KERNEL)))
  29106. +            goto end_init;
  29107. +        initialize_tty_struct(tty);
  29108. +        tty->device = device;
  29109. +        tty->driver = *driver;
  29110. +        goto repeat;
  29111. +    }
  29112. +    if (!*tp_loc && !tp) {
  29113. +        tp = (struct termios *) kmalloc(sizeof(struct termios),
  29114. +                        GFP_KERNEL);
  29115. +        if (!tp)
  29116. +            goto end_init;
  29117. +        *tp = driver->init_termios;
  29118. +        goto repeat;
  29119. +    }
  29120. +    if (!*ltp_loc && !ltp) {
  29121. +        ltp = (struct termios *) kmalloc(sizeof(struct termios),
  29122. +                         GFP_KERNEL);
  29123. +        if (!ltp)
  29124. +            goto end_init;
  29125. +        memset(ltp, 0, sizeof(struct termios));
  29126. +        goto repeat;
  29127. +    }
  29128. +    if (driver->type == TTY_DRIVER_TYPE_PTY) {
  29129. +        o_tty_loc = &driver->other->table[idx];
  29130. +        o_tp_loc = &driver->other->termios[idx];
  29131. +        o_ltp_loc = &driver->other->termios_locked[idx];
  29132. +
  29133. +        if (!*o_tty_loc && !o_tty) {
  29134. +            dev_t     o_device;
  29135. +            o_tty = (struct tty_struct *)
  29136. +                kmalloc(sizeof(struct tty_struct),
  29137. +                    GFP_KERNEL);
  29138. +            if (!o_tty)
  29139. +                goto end_init;
  29140. +            o_device = MKDEV(driver->other->major,
  29141. +                     driver->other->minor_start + idx);
  29142. +            initialize_tty_struct(o_tty);
  29143. +            o_tty->device = o_device;
  29144. +            o_tty->driver = *driver->other;
  29145. +            goto repeat;
  29146. +        }
  29147. +        if (!*o_tp_loc && !o_tp) {
  29148. +            o_tp = (struct termios *)
  29149. +                kmalloc(sizeof(struct termios), GFP_KERNEL);
  29150. +            if (!o_tp)
  29151. +                goto end_init;
  29152. +            *o_tp = driver->other->init_termios;
  29153. +            goto repeat;
  29154. +        }
  29155. +        if (!*o_ltp_loc && !o_ltp) {
  29156. +            o_ltp = (struct termios *)
  29157. +                kmalloc(sizeof(struct termios), GFP_KERNEL);
  29158. +            if (!o_ltp)
  29159. +                goto end_init;
  29160. +            memset(o_ltp, 0, sizeof(struct termios));
  29161. +            goto repeat;
  29162. +        }
  29163. +
  29164. +    }
  29165. +    /* Now we have allocated all the structures: update all the pointers.. */
  29166. +    if (!*tp_loc) {
  29167. +        *tp_loc = tp;
  29168. +        tp = NULL;
  29169. +    }
  29170. +    if (!*ltp_loc) {
  29171. +        *ltp_loc = ltp;
  29172. +        ltp = NULL;
  29173. +    }
  29174. +    if (!*tty_loc) {
  29175. +        tty->termios = *tp_loc;
  29176. +        tty->termios_locked = *ltp_loc;
  29177. +        *tty_loc = tty;
  29178. +        (*driver->refcount)++;
  29179. +        (*tty_loc)->count++;
  29180. +        if (tty->ldisc.open) {
  29181. +            retval = (tty->ldisc.open)(tty);
  29182. +            if (retval < 0) {
  29183. +                (*tty_loc)->count--;
  29184. +                tty = NULL;
  29185. +                goto end_init;
  29186. +            }
  29187. +        }
  29188. +        tty = NULL;
  29189. +    } else
  29190. +        (*tty_loc)->count++;
  29191. +    if (driver->type == TTY_DRIVER_TYPE_PTY) {
  29192. +        if (!*o_tp_loc) {
  29193. +            *o_tp_loc = o_tp;
  29194. +            o_tp = NULL;
  29195. +        }
  29196. +        if (!*o_ltp_loc) {
  29197. +            *o_ltp_loc = o_ltp;
  29198. +            o_ltp = NULL;
  29199. +        }
  29200. +        if (!*o_tty_loc) {
  29201. +            o_tty->termios = *o_tp_loc;
  29202. +            o_tty->termios_locked = *o_ltp_loc;
  29203. +            *o_tty_loc = o_tty;
  29204. +            (*driver->other->refcount)++;
  29205. +            if (o_tty->ldisc.open) {
  29206. +                retval = (o_tty->ldisc.open)(o_tty);
  29207. +                if (retval < 0) {
  29208. +                    (*tty_loc)->count--;
  29209. +                    o_tty = NULL;
  29210. +                    goto end_init;
  29211. +                }
  29212. +            }
  29213. +            o_tty = NULL;
  29214. +        }
  29215. +        (*tty_loc)->link = *o_tty_loc;
  29216. +        (*o_tty_loc)->link = *tty_loc;
  29217. +        if (driver->subtype == PTY_TYPE_MASTER)
  29218. +            (*o_tty_loc)->count++;
  29219. +    }
  29220. +    (*tty_loc)->driver = *driver;
  29221. +    *ret_tty = *tty_loc;
  29222. +    retval = 0;
  29223. +end_init:
  29224. +    if (tty)
  29225. +        kfree_s(tty,sizeof(struct tty_struct));
  29226. +    if (o_tty)
  29227. +        kfree_s(o_tty,sizeof(struct tty_struct));
  29228. +    if (tp)
  29229. +        kfree_s(tp, sizeof(struct termios));
  29230. +    if (o_tp)
  29231. +        kfree_s(o_tp, sizeof(struct termios));
  29232. +    if (ltp)
  29233. +        kfree_s(ltp, sizeof(struct termios));
  29234. +    if (o_ltp)
  29235. +        kfree_s(o_ltp, sizeof(struct termios));
  29236. +    return retval;
  29237. +}
  29238. +
  29239. +/*
  29240. + * Even releasing the tty structures is a tricky business.. We have
  29241. + * to be very careful that the structures are all released at the
  29242. + * same time, as interrupts might otherwise get the wrong pointers.
  29243. + */
  29244. +static void release_dev(struct file * filp)
  29245. +{
  29246. +    struct tty_struct *tty, *o_tty;
  29247. +    struct termios *tp, *o_tp, *ltp, *o_ltp;
  29248. +    struct task_struct **p;
  29249. +    int    idx;
  29250. +
  29251. +
  29252. +    tty = (struct tty_struct *)filp->private_data;
  29253. +    if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "release_dev"))
  29254. +        return;
  29255. +
  29256. +    tty_fasync(filp->f_inode, filp, 0);
  29257. +
  29258. +    tp = tty->termios;
  29259. +    ltp = tty->termios_locked;
  29260. +
  29261. +    idx = MINOR(tty->device) - tty->driver.minor_start;
  29262. +#ifdef TTY_PARANOIA_CHECK
  29263. +    if (idx < 0 || idx >= tty->driver.num) {
  29264. +        printk("release_dev: bad idx when trying to free (%d, %d)\n",
  29265. +               MAJOR(tty->device), MINOR(tty->device));
  29266. +        return;
  29267. +    }
  29268. +    if (tty != tty->driver.table[idx]) {
  29269. +        printk("release_dev: driver.table[%d] not tty for (%d, %d)\n",
  29270. +               idx, MAJOR(tty->device), MINOR(tty->device));
  29271. +        return;
  29272. +    }
  29273. +    if (tp != tty->driver.termios[idx]) {
  29274. +        printk("release_dev: driver.termios[%d] not termios for (%d, %d)\n",
  29275. +               idx, MAJOR(tty->device), MINOR(tty->device));
  29276. +        return;
  29277. +    }
  29278. +    if (ltp != tty->driver.termios_locked[idx]) {
  29279. +        printk("release_dev: driver.termios_locked[%d] not termios_locked for (%d, %d)\n",
  29280. +               idx, MAJOR(tty->device), MINOR(tty->device));
  29281. +        return;
  29282. +    }
  29283. +#endif
  29284. +
  29285. +#ifdef TTY_DEBUG_HANGUP
  29286. +    printk("release_dev of %s (tty count=%d)...", tty_name(tty),
  29287. +           tty->count);
  29288. +#endif
  29289. +
  29290. +    o_tty = tty->link;
  29291. +    o_tp = (o_tty) ? o_tty->termios : NULL;
  29292. +    o_ltp = (o_tty) ? o_tty->termios_locked : NULL;
  29293. +
  29294. +#ifdef TTY_PARANOIA_CHECK
  29295. +    if (tty->driver.other) {
  29296. +        if (o_tty != tty->driver.other->table[idx]) {
  29297. +            printk("release_dev: other->table[%d] not o_tty for (%d, %d)\n",
  29298. +                   idx, MAJOR(tty->device), MINOR(tty->device));
  29299. +            return;
  29300. +        }
  29301. +        if (o_tp != tty->driver.other->termios[idx]) {
  29302. +            printk("release_dev: other->termios[%d] not o_termios for (%d, %d)\n",
  29303. +                   idx, MAJOR(tty->device), MINOR(tty->device));
  29304. +            return;
  29305. +        }
  29306. +        if (o_ltp != tty->driver.other->termios_locked[idx]) {
  29307. +            printk("release_dev: other->termios_locked[%d] not o_termios_locked for (%d, %d)\n",
  29308. +                   idx, MAJOR(tty->device), MINOR(tty->device));
  29309. +            return;
  29310. +        }
  29311. +
  29312. +        if (o_tty->link != tty) {
  29313. +            printk("release_dev: bad pty pointers\n");
  29314. +            return;
  29315. +        }
  29316. +    }
  29317. +#endif
  29318. +
  29319. +    if (tty->driver.close)
  29320. +        tty->driver.close(tty, filp);
  29321. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  29322. +        tty->driver.subtype == PTY_TYPE_MASTER) {
  29323. +        if (--tty->link->count < 0) {
  29324. +            printk("release_dev: bad pty slave count (%d) for %s\n",
  29325. +                   tty->count, tty_name(tty));
  29326. +            tty->link->count = 0;
  29327. +        }
  29328. +    }
  29329. +    if (--tty->count < 0) {
  29330. +        printk("release_dev: bad tty->count (%d) for %s\n",
  29331. +               tty->count, tty_name(tty));
  29332. +        tty->count = 0;
  29333. +    }
  29334. +    if (tty->count)
  29335. +        return;
  29336. +
  29337. +    if (o_tty) {
  29338. +        if (o_tty->count)
  29339. +            return;
  29340. +        tty->driver.other->table[idx] = NULL;
  29341. +        tty->driver.other->termios[idx] = NULL;
  29342. +        kfree_s(o_tp, sizeof(struct termios));
  29343. +    }
  29344. +
  29345. +#ifdef TTY_DEBUG_HANGUP
  29346. +    printk("freeing tty structure...");
  29347. +#endif
  29348. +
  29349. +    /*
  29350. +     * Make sure there aren't any processes that still think this
  29351. +     * tty is their controlling tty.
  29352. +     */
  29353. +    for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  29354. +        if (*p == 0)
  29355. +            continue;
  29356. +        if ((*p)->tty == tty)
  29357. +            (*p)->tty = NULL;
  29358. +        if (o_tty && (*p)->tty == o_tty)
  29359. +            (*p)->tty = NULL;
  29360. +    }
  29361. +
  29362. +    /*
  29363. +     * Shutdown the current line discipline, and reset it to
  29364. +     * N_TTY.
  29365. +     */
  29366. +    if (tty->ldisc.close)
  29367. +        (tty->ldisc.close)(tty);
  29368. +    tty->ldisc = ldiscs[N_TTY];
  29369. +    tty->termios->c_line = N_TTY;
  29370. +
  29371. +    tty->driver.table[idx] = NULL;
  29372. +    if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
  29373. +        tty->driver.termios[idx] = NULL;
  29374. +        kfree_s(tp, sizeof(struct termios));
  29375. +    }
  29376. +    if (tty == redirect || o_tty == redirect)
  29377. +        redirect = NULL;
  29378. +    /*
  29379. +     * Make sure that the tty's task queue isn't activated.  If it
  29380. +     * is, take it out of the linked list.
  29381. +     */
  29382. +    cli();
  29383. +    if (tty->flip.tqueue.sync) {
  29384. +        struct tq_struct *tq, *prev;
  29385. +
  29386. +        for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {
  29387. +            if (tq == &tty->flip.tqueue) {
  29388. +                if (prev)
  29389. +                    prev->next = tq->next;
  29390. +                else
  29391. +                    tq_timer = tq->next;
  29392. +                break;
  29393. +            }
  29394. +        }
  29395. +    }
  29396. +    sti();
  29397. +    tty->magic = 0;
  29398. +    (*tty->driver.refcount)--;
  29399. +    kfree_s(tty,sizeof(struct tty_struct));
  29400. +    if (o_tty) {
  29401. +        o_tty->magic = 0;
  29402. +        (*o_tty->driver.refcount)--;
  29403. +        kfree_s(o_tty,sizeof(struct tty_struct));
  29404. +    }
  29405. +}
  29406. +
  29407. +/*
  29408. + * tty_open and tty_release keep up the tty count that contains the
  29409. + * number of opens done on a tty. We cannot use the inode-count, as
  29410. + * different inodes might point to the same tty.
  29411. + *
  29412. + * Open-counting is needed for pty masters, as well as for keeping
  29413. + * track of serial lines: DTR is dropped when the last close happens.
  29414. + * (This is not done solely through tty->count, now.  - Ted 1/27/92)
  29415. + *
  29416. + * The termios state of a pty is reset on first open so that
  29417. + * settings don't persist across reuse.
  29418. + */
  29419. +static int tty_open(struct inode * inode, struct file * filp)
  29420. +{
  29421. +    struct tty_struct *tty;
  29422. +    int minor;
  29423. +    int noctty, retval;
  29424. +    dev_t device;
  29425. +
  29426. +retry_open:
  29427. +    noctty = filp->f_flags & O_NOCTTY;
  29428. +    device = inode->i_rdev;
  29429. +    if (device == TTY_DEV) {
  29430. +        if (!current->tty)
  29431. +            return -ENXIO;
  29432. +        device = current->tty->device;
  29433. +        /* noctty = 1; */
  29434. +    }
  29435. +    if (device == CONSOLE_DEV) {
  29436. +        device = MKDEV(TTY_MAJOR, fg_console+1);
  29437. +        noctty = 1;
  29438. +    }
  29439. +    minor = MINOR(device);
  29440. +
  29441. +    retval = init_dev(device, &tty);
  29442. +    filp->private_data = tty;
  29443. +    if (retval)
  29444. +        return retval;
  29445. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  29446. +        tty->driver.subtype == PTY_TYPE_MASTER)
  29447. +        noctty = 1;
  29448. +#ifdef TTY_DEBUG_HANGUP
  29449. +    printk("opening %s...", tty_name(tty));
  29450. +#endif
  29451. +    if (tty->driver.open)
  29452. +        retval = tty->driver.open(tty, filp);
  29453. +    else
  29454. +        retval = -ENODEV;
  29455. +
  29456. +    if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())
  29457. +        retval = -EBUSY;
  29458. +
  29459. +    if (retval) {
  29460. +#ifdef TTY_DEBUG_HANGUP
  29461. +        printk("error %d in opening %s...", retval, tty_name(tty));
  29462. +#endif
  29463. +
  29464. +        release_dev(filp);
  29465. +        if (retval != -ERESTARTSYS)
  29466. +            return retval;
  29467. +        if (current->signal & ~current->blocked)
  29468. +            return retval;
  29469. +        schedule();
  29470. +        /*
  29471. +         * Need to reset f_op in case a hangup happened.
  29472. +         */
  29473. +        filp->f_op = &tty_fops;
  29474. +        goto retry_open;
  29475. +    }
  29476. +    if (!noctty &&
  29477. +        current->leader &&
  29478. +        !current->tty &&
  29479. +        tty->session == 0) {
  29480. +        current->tty = tty;
  29481. +        tty->session = current->session;
  29482. +        tty->pgrp = current->pgrp;
  29483. +    }
  29484. +    return 0;
  29485. +}
  29486. +
  29487. +/*
  29488. + * Note that releasing a pty master also releases the child, so
  29489. + * we have to make the redirection checks after that and on both
  29490. + * sides of a pty.
  29491. + */
  29492. +static void tty_release(struct inode * inode, struct file * filp)
  29493. +{
  29494. +    release_dev(filp);
  29495. +}
  29496. +
  29497. +static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
  29498. +{
  29499. +    struct tty_struct * tty;
  29500. +
  29501. +    tty = (struct tty_struct *)filp->private_data;
  29502. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_select"))
  29503. +        return 0;
  29504. +
  29505. +    if (tty->ldisc.select)
  29506. +        return (tty->ldisc.select)(tty, inode, filp, sel_type, wait);
  29507. +    return 0;
  29508. +}
  29509. +
  29510. +static int tty_fasync(struct inode * inode, struct file * filp, int on)
  29511. +{
  29512. +    struct tty_struct * tty;
  29513. +    struct fasync_struct *fa, *prev;
  29514. +
  29515. +    tty = (struct tty_struct *)filp->private_data;
  29516. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync"))
  29517. +        return 0;
  29518. +
  29519. +    for (fa = tty->fasync, prev = 0; fa; prev= fa, fa = fa->fa_next) {
  29520. +        if (fa->fa_file == filp)
  29521. +            break;
  29522. +    }
  29523. +
  29524. +    if (on) {
  29525. +        if (fa)
  29526. +            return 0;
  29527. +        fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
  29528. +        if (!fa)
  29529. +            return -ENOMEM;
  29530. +        fa->magic = FASYNC_MAGIC;
  29531. +        fa->fa_file = filp;
  29532. +        fa->fa_next = tty->fasync;
  29533. +        tty->fasync = fa;
  29534. +        if (!tty->read_wait)
  29535. +            tty->minimum_to_wake = 1;
  29536. +        if (filp->f_owner == 0) {
  29537. +            if (tty->pgrp)
  29538. +                filp->f_owner = -tty->pgrp;
  29539. +            else
  29540. +                filp->f_owner = current->pid;
  29541. +        }
  29542. +    } else {
  29543. +        if (!fa)
  29544. +            return 0;
  29545. +        if (prev)
  29546. +            prev->fa_next = fa->fa_next;
  29547. +        else
  29548. +            tty->fasync = fa->fa_next;
  29549. +        kfree_s(fa, sizeof(struct fasync_struct));
  29550. +        if (!tty->fasync && !tty->read_wait)
  29551. +            tty->minimum_to_wake = N_TTY_BUF_SIZE;
  29552. +    }
  29553. +    return 0;
  29554. +}
  29555. +
  29556. +/*
  29557. + * XXX does anyone use this anymore?!?
  29558. + */
  29559. +static int do_get_ps_info(int arg)
  29560. +{
  29561. +    struct tstruct {
  29562. +        int flag;
  29563. +        int present[NR_TASKS];
  29564. +        struct task_struct tasks[NR_TASKS];
  29565. +    };
  29566. +    struct tstruct *ts = (struct tstruct *)arg;
  29567. +    struct task_struct **p;
  29568. +    char *c, *d;
  29569. +    int i, n = 0;
  29570. +
  29571. +    i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
  29572. +    if (i)
  29573. +        return i;
  29574. +    for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
  29575. +        if (*p)
  29576. +        {
  29577. +            c = (char *)(*p);
  29578. +            d = (char *)(ts->tasks+n);
  29579. +            for (i=0 ; i<sizeof(struct task_struct) ; i++)
  29580. +                put_fs_byte(*c++, d++);
  29581. +            put_fs_long(1, (unsigned long *)(ts->present+n));
  29582. +        }
  29583. +        else
  29584. +            put_fs_long(0, (unsigned long *)(ts->present+n));
  29585. +    return(0);
  29586. +}
  29587. +
  29588. +static int tty_ioctl(struct inode * inode, struct file * file,
  29589. +             unsigned int cmd, unsigned long arg)
  29590. +{
  29591. +    int    retval;
  29592. +    struct tty_struct * tty;
  29593. +    struct tty_struct * real_tty;
  29594. +    struct winsize tmp_ws;
  29595. +    pid_t pgrp;
  29596. +    unsigned char    ch;
  29597. +    char    mbz = 0;
  29598. +
  29599. +    tty = (struct tty_struct *)file->private_data;
  29600. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
  29601. +        return -EINVAL;
  29602. +
  29603. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  29604. +        tty->driver.subtype == PTY_TYPE_MASTER)
  29605. +        real_tty = tty->link;
  29606. +    else
  29607. +        real_tty = tty;
  29608. +
  29609. +    switch (cmd) {
  29610. +        case TIOCSTI:
  29611. +            if ((current->tty != tty) && !suser())
  29612. +                return -EPERM;
  29613. +            retval = verify_area(VERIFY_READ, (void *) arg, 1);
  29614. +            if (retval)
  29615. +                return retval;
  29616. +            ch = get_fs_byte((char *) arg);
  29617. +            tty->ldisc.receive_buf(tty, &ch, &mbz, 1);
  29618. +            return 0;
  29619. +        case TIOCGWINSZ:
  29620. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  29621. +                         sizeof (struct winsize));
  29622. +            if (retval)
  29623. +                return retval;
  29624. +            memcpy_tofs((struct winsize *) arg, &tty->winsize,
  29625. +                    sizeof (struct winsize));
  29626. +            return 0;
  29627. +        case TIOCSWINSZ:
  29628. +            retval = verify_area(VERIFY_READ, (void *) arg,
  29629. +                         sizeof (struct winsize));
  29630. +            if (retval)
  29631. +                return retval;
  29632. +            memcpy_fromfs(&tmp_ws, (struct winsize *) arg,
  29633. +                      sizeof (struct winsize));
  29634. +            if (memcmp(&tmp_ws, &tty->winsize,
  29635. +                   sizeof(struct winsize))) {
  29636. +                if (tty->pgrp > 0)
  29637. +                    kill_pg(tty->pgrp, SIGWINCH, 1);
  29638. +                if ((real_tty->pgrp != tty->pgrp) &&
  29639. +                    (real_tty->pgrp > 0))
  29640. +                    kill_pg(real_tty->pgrp, SIGWINCH, 1);
  29641. +            }
  29642. +            tty->winsize = tmp_ws;
  29643. +            real_tty->winsize = tmp_ws;
  29644. +            return 0;
  29645. +        case TIOCCONS:
  29646. +            if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE) {
  29647. +                if (!suser())
  29648. +                    return -EPERM;
  29649. +                redirect = NULL;
  29650. +                return 0;
  29651. +            }
  29652. +            if (redirect)
  29653. +                return -EBUSY;
  29654. +            redirect = real_tty;
  29655. +            return 0;
  29656. +        case FIONBIO:
  29657. +            retval = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
  29658. +            if (retval)
  29659. +                return retval;
  29660. +            arg = get_fs_long((unsigned long *) arg);
  29661. +            if (arg)
  29662. +                file->f_flags |= O_NONBLOCK;
  29663. +            else
  29664. +                file->f_flags &= ~O_NONBLOCK;
  29665. +            return 0;
  29666. +        case TIOCEXCL:
  29667. +            set_bit(TTY_EXCLUSIVE, &tty->flags);
  29668. +            return 0;
  29669. +        case TIOCNXCL:
  29670. +            clear_bit(TTY_EXCLUSIVE, &tty->flags);
  29671. +            return 0;
  29672. +        case TIOCNOTTY:
  29673. +            if (current->tty != tty)
  29674. +                return -ENOTTY;
  29675. +            if (current->leader)
  29676. +                disassociate_ctty(0);
  29677. +            current->tty = NULL;
  29678. +            return 0;
  29679. +        case TIOCSCTTY:
  29680. +            if (current->leader &&
  29681. +                (current->session == tty->session))
  29682. +                return 0;
  29683. +            /*
  29684. +             * The process must be a session leader and
  29685. +             * not have a controlling tty already.
  29686. +             */
  29687. +            if (!current->leader || current->tty)
  29688. +                return -EPERM;
  29689. +            if (tty->session > 0) {
  29690. +                /*
  29691. +                 * This tty is already the controlling
  29692. +                 * tty for another session group!
  29693. +                 */
  29694. +                if ((arg == 1) && suser()) {
  29695. +                    /*
  29696. +                     * Steal it away
  29697. +                     */
  29698. +                    struct task_struct *p;
  29699. +
  29700. +                    for_each_task(p)
  29701. +                        if (p->tty == tty)
  29702. +                            p->tty = NULL;
  29703. +                } else
  29704. +                    return -EPERM;
  29705. +            }
  29706. +            current->tty = tty;
  29707. +            tty->session = current->session;
  29708. +            tty->pgrp = current->pgrp;
  29709. +            return 0;
  29710. +        case TIOCGPGRP:
  29711. +            /*
  29712. +             * (tty == real_tty) is a cheap way of
  29713. +             * testing if the tty is NOT a master pty.
  29714. +             */
  29715. +            if (tty == real_tty && current->tty != real_tty)
  29716. +                return -ENOTTY;
  29717. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  29718. +                         sizeof (pid_t));
  29719. +            if (retval)
  29720. +                return retval;
  29721. +            put_fs_long(real_tty->pgrp, (pid_t *) arg);
  29722. +            return 0;
  29723. +        case TIOCSPGRP:
  29724. +            retval = tty_check_change(real_tty);
  29725. +            if (retval)
  29726. +                return retval;
  29727. +            if (!current->tty ||
  29728. +                (current->tty != real_tty) ||
  29729. +                (real_tty->session != current->session))
  29730. +                return -ENOTTY;
  29731. +            pgrp = get_fs_long((pid_t *) arg);
  29732. +            if (pgrp < 0)
  29733. +                return -EINVAL;
  29734. +            if (session_of_pgrp(pgrp) != current->session)
  29735. +                return -EPERM;
  29736. +            real_tty->pgrp = pgrp;
  29737. +            return 0;
  29738. +        case TIOCGETD:
  29739. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  29740. +                         sizeof (unsigned long));
  29741. +            if (retval)
  29742. +                return retval;
  29743. +            put_fs_long(tty->ldisc.num, (unsigned long *) arg);
  29744. +            return 0;
  29745. +        case TIOCSETD:
  29746. +            retval = tty_check_change(tty);
  29747. +            if (retval)
  29748. +                return retval;
  29749. +            arg = get_fs_long((unsigned long *) arg);
  29750. +            return tty_set_ldisc(tty, arg);
  29751. +        case TIOCLINUX:
  29752. +            retval = verify_area(VERIFY_READ, (void *) arg, 1);
  29753. +            if (retval)
  29754. +                return retval;
  29755. +            switch (get_fs_byte((char *)arg))
  29756. +            {
  29757. +                case 0:
  29758. +                    return do_screendump(arg);
  29759. +                case 1:
  29760. +                    printk("Deprecated TIOCLINUX (1) ioctl\n");
  29761. +                    return do_get_ps_info(arg);
  29762. +                case 2:
  29763. +                    return set_selection(arg, tty);
  29764. +                case 3:
  29765. +                    return paste_selection(tty);
  29766. +                case 4:
  29767. +                    unblank_screen();
  29768. +                    return 0;
  29769. +                case 5:
  29770. +                    return sel_loadlut(arg);
  29771. +                case 6:
  29772. +            /* Make it possible to react to Shift+Mousebutton */
  29773. +            /* Note that shift_state is an undocumented
  29774. +               kernel-internal variable; programs not closely
  29775. +               related to the kernel should not use this. */
  29776. +                    put_fs_byte(0, arg);
  29777. +/*                     put_fs_byte(shift_state,arg); */
  29778. +                    return 0;
  29779. +                case 7:
  29780. +                    put_fs_byte(mouse_reporting(),arg);
  29781. +                    return 0;
  29782. +                default:
  29783. +                    return -EINVAL;
  29784. +            }
  29785. +        default:
  29786. +            if (tty->driver.ioctl) {
  29787. +                retval = (tty->driver.ioctl)(tty, file,
  29788. +                                 cmd, arg);
  29789. +                if (retval != -ENOIOCTLCMD)
  29790. +                    return retval;
  29791. +            }
  29792. +            if (tty->ldisc.ioctl) {
  29793. +                retval = (tty->ldisc.ioctl)(tty, file,
  29794. +                                cmd, arg);
  29795. +                if (retval != -ENOIOCTLCMD)
  29796. +                    return retval;
  29797. +            }
  29798. +            return -EINVAL;
  29799. +        }
  29800. +}
  29801. +
  29802. +
  29803. +/*
  29804. + * This implements the "Secure Attention Key" ---  the idea is to
  29805. + * prevent trojan horses by killing all processes associated with this
  29806. + * tty when the user hits the "Secure Attention Key".  Required for
  29807. + * super-paranoid applications --- see the Orange Book for more details.
  29808. + *
  29809. + * This code could be nicer; ideally it should send a HUP, wait a few
  29810. + * seconds, then send a INT, and then a KILL signal.  But you then
  29811. + * have to coordinate with the init process, since all processes associated
  29812. + * with the current tty must be dead before the new getty is allowed
  29813. + * to spawn.
  29814. + */
  29815. +void do_SAK( struct tty_struct *tty)
  29816. +{
  29817. +#ifdef TTY_SOFT_SAK
  29818. +    tty_hangup(tty);
  29819. +#else
  29820. +    struct task_struct **p;
  29821. +    int session;
  29822. +    int        i;
  29823. +    struct file    *filp;
  29824. +
  29825. +    if (!tty)
  29826. +        return;
  29827. +    session  = tty->session;
  29828. +    if (tty->ldisc.flush_buffer)
  29829. +        tty->ldisc.flush_buffer(tty);
  29830. +    if (tty->driver.flush_buffer)
  29831. +        tty->driver.flush_buffer(tty);
  29832. +     for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  29833. +        if (!(*p))
  29834. +            continue;
  29835. +        if (((*p)->tty == tty) ||
  29836. +            ((session > 0) && ((*p)->session == session)))
  29837. +            send_sig(SIGKILL, *p, 1);
  29838. +        else {
  29839. +            for (i=0; i < NR_OPEN; i++) {
  29840. +                filp = (*p)->files->fd[i];
  29841. +                if (filp && (filp->f_op == &tty_fops) &&
  29842. +                    (filp->private_data == tty)) {
  29843. +                    send_sig(SIGKILL, *p, 1);
  29844. +                    break;
  29845. +                }
  29846. +            }
  29847. +        }
  29848. +    }
  29849. +#endif
  29850. +}
  29851. +
  29852. +/*
  29853. + * This routine is called out of the software interrupt to flush data
  29854. + * from the flip buffer to the line discipline.
  29855. + */
  29856. +static void flush_to_ldisc(void *private_)
  29857. +{
  29858. +    struct tty_struct *tty = (struct tty_struct *) private_;
  29859. +    unsigned char    *cp;
  29860. +    char        *fp;
  29861. +    int        count;
  29862. +
  29863. +    if (tty->flip.buf_num) {
  29864. +        cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
  29865. +        fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
  29866. +        tty->flip.buf_num = 0;
  29867. +
  29868. +        cli();
  29869. +        tty->flip.char_buf_ptr = tty->flip.char_buf;
  29870. +        tty->flip.flag_buf_ptr = tty->flip.flag_buf;
  29871. +    } else {
  29872. +        cp = tty->flip.char_buf;
  29873. +        fp = tty->flip.flag_buf;
  29874. +        tty->flip.buf_num = 1;
  29875. +
  29876. +        cli();
  29877. +        tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
  29878. +        tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
  29879. +    }
  29880. +    count = tty->flip.count;
  29881. +    tty->flip.count = 0;
  29882. +    sti();
  29883. +
  29884. +#if 0
  29885. +    if (count > tty->max_flip_cnt)
  29886. +        tty->max_flip_cnt = count;
  29887. +#endif
  29888. +    tty->ldisc.receive_buf(tty, cp, fp, count);
  29889. +}
  29890. +
  29891. +/*
  29892. + * This subroutine initializes a tty structure.
  29893. + */
  29894. +static void initialize_tty_struct(struct tty_struct *tty)
  29895. +{
  29896. +    memset(tty, 0, sizeof(struct tty_struct));
  29897. +    tty->magic = TTY_MAGIC;
  29898. +    tty->ldisc = ldiscs[N_TTY];
  29899. +    tty->pgrp = -1;
  29900. +    tty->flip.char_buf_ptr = tty->flip.char_buf;
  29901. +    tty->flip.flag_buf_ptr = tty->flip.flag_buf;
  29902. +    tty->flip.tqueue.routine = flush_to_ldisc;
  29903. +    tty->flip.tqueue.data = tty;
  29904. +}
  29905. +
  29906. +/*
  29907. + * The default put_char routine if the driver did not define one.
  29908. + */
  29909. +void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
  29910. +{
  29911. +    tty->driver.write(tty, 0, &ch, 1);
  29912. +}
  29913. +
  29914. +/*
  29915. + * Called by a tty driver to register itself.
  29916. + */
  29917. +int tty_register_driver(struct tty_driver *driver)
  29918. +{
  29919. +    int error;
  29920. +
  29921. +    if (driver->flags & TTY_DRIVER_INSTALLED)
  29922. +        return 0;
  29923. +
  29924. +    error = register_chrdev(driver->major, driver->name, &tty_fops);
  29925. +    if (error < 0)
  29926. +        return error;
  29927. +    else if(driver->major == 0)
  29928. +        driver->major = error;
  29929. +
  29930. +    if (!driver->put_char)
  29931. +        driver->put_char = tty_default_put_char;
  29932. +
  29933. +    driver->prev = 0;
  29934. +    driver->next = tty_drivers;
  29935. +    tty_drivers->prev = driver;
  29936. +    tty_drivers = driver;
  29937. +    return error;
  29938. +}
  29939. +
  29940. +/*
  29941. + * Called by a tty driver to unregister itself.
  29942. + */
  29943. +int tty_unregister_driver(struct tty_driver *driver)
  29944. +{
  29945. +    int    retval;
  29946. +    struct tty_driver *p;
  29947. +    int    found = 0;
  29948. +    int    major_inuse = 0;
  29949. +
  29950. +    if (driver->refcount)
  29951. +        return -EBUSY;
  29952. +
  29953. +    for (p = tty_drivers; p; p = p->next) {
  29954. +        if (p == driver)
  29955. +            found++;
  29956. +        else if (p->major == driver->major)
  29957. +            major_inuse++;
  29958. +    }
  29959. +
  29960. +    if (!major_inuse) {
  29961. +        retval = unregister_chrdev(driver->major, driver->name);
  29962. +        if (retval)
  29963. +            return retval;
  29964. +    }
  29965. +
  29966. +    if (driver->prev)
  29967. +        driver->prev->next = driver->next;
  29968. +    else
  29969. +        tty_drivers = driver->next;
  29970. +
  29971. +    if (driver->next)
  29972. +        driver->next = driver->next->prev;
  29973. +
  29974. +    return 0;
  29975. +}
  29976. +
  29977. +
  29978. +/*
  29979. + * Initialize the console device. This is called *early*, so
  29980. + * we can't necessarily depend on lots of kernel help here.
  29981. + * Just do some early initializations, and do the complex setup
  29982. + * later.
  29983. + */
  29984. +long console_init(long kmem_start, long kmem_end)
  29985. +{
  29986. +    /* Setup the default TTY line discipline. */
  29987. +    memset(ldiscs, 0, sizeof(ldiscs));
  29988. +    (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
  29989. +
  29990. +    /*
  29991. +     * Set up the standard termios.  Individual tty drivers may
  29992. +     * deviate from this; this is used as a template.
  29993. +     */
  29994. +
  29995. +    memset(&tty_std_termios, 0, sizeof(struct termios));
  29996. +    memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
  29997. +
  29998. +    tty_std_termios.c_iflag = ICRNL | IXON;
  29999. +    tty_std_termios.c_oflag = OPOST | ONLCR;
  30000. +    tty_std_termios.c_cflag = B38400 | CS8 | CREAD;
  30001. +    tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
  30002. +        ECHOCTL | ECHOKE | IEXTEN;
  30003. +    /*
  30004. +     * set up the console device so that later boot sequences can
  30005. +     * inform about problems etc..
  30006. +     */
  30007. +    return con_init(kmem_start);
  30008. +}
  30009. +
  30010. +/*
  30011. + * Ok, now we can initialize the rest of the tty devices and can count
  30012. + * on memory allocations, interrupts etc..
  30013. + */
  30014. +long tty_init(long kmem_start)
  30015. +{
  30016. +    if (sizeof(struct tty_struct) > PAGE_SIZE)
  30017. +        panic("size of tty structure > PAGE_SIZE!");
  30018. +    if (register_chrdev(TTY_MAJOR,"tty",&tty_fops))
  30019. +        panic("unable to get major %d for tty device", TTY_MAJOR);
  30020. +    if (register_chrdev(TTYAUX_MAJOR,"cua",&tty_fops))
  30021. +        panic("unable to get major %d for tty device", TTYAUX_MAJOR);
  30022. +
  30023. +    kmem_start = kbd_init(kmem_start);
  30024. +    kmem_start = rs_init(kmem_start);
  30025. +    kmem_start = pty_init(kmem_start);
  30026. +    return kmem_start;
  30027. +}
  30028. diff -r -u -N linux.orig/arch/arm/drivers/char/tty_ioctl.c linux.arm/arch/arm/drivers/char/tty_ioctl.c
  30029. --- linux.orig/arch/arm/drivers/char/tty_ioctl.c    Thu Jan  1 01:00:00 1970
  30030. +++ linux.arm/arch/arm/drivers/char/tty_ioctl.c    Fri Oct 27 23:14:27 1995
  30031. @@ -0,0 +1,374 @@
  30032. +/*
  30033. + *  linux/drivers/char/tty_ioctl.c
  30034. + *
  30035. + *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  30036. + *
  30037. + * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
  30038. + * which can be dynamically activated and de-activated by the line
  30039. + * discipline handling modules (like SLIP).
  30040. + */
  30041. +
  30042. +#include <linux/types.h>
  30043. +#include <linux/termios.h>
  30044. +#include <linux/errno.h>
  30045. +#include <linux/sched.h>
  30046. +#include <linux/kernel.h>
  30047. +#include <linux/major.h>
  30048. +#include <linux/tty.h>
  30049. +#include <linux/fcntl.h>
  30050. +#include <linux/string.h>
  30051. +#include <linux/mm.h>
  30052. +
  30053. +#include <asm/io.h>
  30054. +#include <asm/bitops.h>
  30055. +#include <asm/segment.h>
  30056. +#include <asm/system.h>
  30057. +
  30058. +#undef TTY_DEBUG_WAIT_UNTIL_SENT
  30059. +
  30060. +#undef    DEBUG
  30061. +#ifdef DEBUG
  30062. +# define    PRINTK(x)    printk (x)
  30063. +#else
  30064. +# define    PRINTK(x)    /**/
  30065. +#endif
  30066. +
  30067. +/*
  30068. + * Internal flag options for termios setting behavior
  30069. + */
  30070. +#define TERMIOS_FLUSH    1
  30071. +#define TERMIOS_WAIT    2
  30072. +#define TERMIOS_TERMIO    4
  30073. +
  30074. +void tty_wait_until_sent(struct tty_struct * tty, int timeout)
  30075. +{
  30076. +    struct wait_queue wait = { current, NULL };
  30077. +
  30078. +#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
  30079. +    printk("%s wait until sent...\n", tty_name(tty));
  30080. +#endif
  30081. +    if (!tty->driver.chars_in_buffer ||
  30082. +        !tty->driver.chars_in_buffer(tty))
  30083. +        return;
  30084. +    add_wait_queue(&tty->write_wait, &wait);
  30085. +    current->counter = 0;    /* make us low-priority */
  30086. +    if (timeout)
  30087. +        current->timeout = timeout + jiffies;
  30088. +    else
  30089. +        current->timeout = (unsigned) -1;
  30090. +    do {
  30091. +#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
  30092. +        printk("waiting %s...(%d)\n", tty_name(tty), tty->driver.chars_in_buffer(tty));
  30093. +#endif
  30094. +        current->state = TASK_INTERRUPTIBLE;
  30095. +        if (current->signal & ~current->blocked)
  30096. +            break;
  30097. +        if (!tty->driver.chars_in_buffer(tty))
  30098. +            break;
  30099. +        schedule();
  30100. +    } while (current->timeout);
  30101. +    current->state = TASK_RUNNING;
  30102. +    remove_wait_queue(&tty->write_wait, &wait);
  30103. +}
  30104. +
  30105. +static void unset_locked_termios(struct termios *termios,
  30106. +                 struct termios *old,
  30107. +                 struct termios *locked)
  30108. +{
  30109. +    int    i;
  30110. +    
  30111. +#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
  30112. +
  30113. +    if (!locked) {
  30114. +        printk("Warning?!? termios_locked is NULL.\n");
  30115. +        return;
  30116. +    }
  30117. +
  30118. +    NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
  30119. +    NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
  30120. +    NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
  30121. +    NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
  30122. +    termios->c_line = locked->c_line ? old->c_line : termios->c_line;
  30123. +    for (i=0; i < NCCS; i++)
  30124. +        termios->c_cc[i] = locked->c_cc[i] ?
  30125. +            old->c_cc[i] : termios->c_cc[i];
  30126. +}
  30127. +
  30128. +static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
  30129. +{
  30130. +    struct termio tmp_termio;
  30131. +    struct termios tmp_termios;
  30132. +    struct termios old_termios = *tty->termios;
  30133. +    int retval, canon_change;
  30134. +
  30135. +    retval = tty_check_change(tty);
  30136. +    if (retval)
  30137. +        return retval;
  30138. +
  30139. +    if (opt & TERMIOS_TERMIO) {
  30140. +        retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio));
  30141. +        if (retval)
  30142. +            return retval;
  30143. +        tmp_termios = *tty->termios;
  30144. +        memcpy_fromfs(&tmp_termio, (struct termio *) arg,
  30145. +                  sizeof (struct termio));
  30146. +
  30147. +#define SET_LOW_BITS(x,y)    ((x) = (0xffff0000 & (x)) | (y))
  30148. +        SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
  30149. +        SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
  30150. +        SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
  30151. +        SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
  30152. +        memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
  30153. +#undef SET_LOW_BITS
  30154. +    } else {
  30155. +        retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termios));
  30156. +        if (retval)
  30157. +            return retval;
  30158. +        memcpy_fromfs(&tmp_termios, (struct termios *) arg,
  30159. +                  sizeof (struct termios));
  30160. +    }
  30161. +
  30162. +    if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
  30163. +        tty->ldisc.flush_buffer(tty);
  30164. +
  30165. +    if (opt & TERMIOS_WAIT)
  30166. +        tty_wait_until_sent(tty, 0);
  30167. +
  30168. +    cli();
  30169. +    *tty->termios = tmp_termios;
  30170. +    unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
  30171. +    canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
  30172. +    if (canon_change) {
  30173. +        memset(&tty->read_flags, 0, sizeof tty->read_flags);
  30174. +        tty->canon_head = tty->read_tail;
  30175. +        tty->canon_data = 0;
  30176. +        tty->erasing = 0;
  30177. +    }
  30178. +    sti();
  30179. +    if (canon_change && !L_ICANON(tty) && tty->read_cnt)
  30180. +        /* Get characters left over from canonical mode. */
  30181. +        wake_up_interruptible(&tty->read_wait);
  30182. +
  30183. +    /* see if packet mode change of state */
  30184. +
  30185. +    if (tty->link && tty->link->packet) {
  30186. +        int old_flow = ((old_termios.c_iflag & IXON) &&
  30187. +                (old_termios.c_cc[VSTOP] == '\023') &&
  30188. +                (old_termios.c_cc[VSTART] == '\021'));
  30189. +        int new_flow = (I_IXON(tty) &&
  30190. +                STOP_CHAR(tty) == '\023' &&
  30191. +                START_CHAR(tty) == '\021');
  30192. +        if (old_flow != new_flow) {
  30193. +            tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
  30194. +            if (new_flow)
  30195. +                tty->ctrl_status |= TIOCPKT_DOSTOP;
  30196. +            else
  30197. +                tty->ctrl_status |= TIOCPKT_NOSTOP;
  30198. +            wake_up_interruptible(&tty->link->read_wait);
  30199. +        }
  30200. +    }
  30201. +
  30202. +    if (tty->driver.set_termios)
  30203. +        (*tty->driver.set_termios)(tty, &old_termios);
  30204. +
  30205. +    if (tty->ldisc.set_termios)
  30206. +        (*tty->ldisc.set_termios)(tty, &old_termios);
  30207. +        
  30208. +    return 0;
  30209. +}
  30210. +
  30211. +static int get_termio(struct tty_struct * tty, struct termio * termio)
  30212. +{
  30213. +    int i;
  30214. +    struct termio tmp_termio;
  30215. +
  30216. +    i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
  30217. +    if (i)
  30218. +        return i;
  30219. +    tmp_termio.c_iflag = tty->termios->c_iflag;
  30220. +    tmp_termio.c_oflag = tty->termios->c_oflag;
  30221. +    tmp_termio.c_cflag = tty->termios->c_cflag;
  30222. +    tmp_termio.c_lflag = tty->termios->c_lflag;
  30223. +    tmp_termio.c_line = tty->termios->c_line;
  30224. +    for(i=0 ; i < NCC ; i++)
  30225. +        tmp_termio.c_cc[i] = tty->termios->c_cc[i];
  30226. +    memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
  30227. +    return 0;
  30228. +}
  30229. +
  30230. +static unsigned long inq_canon(struct tty_struct * tty)
  30231. +{
  30232. +    int nr, head, tail;
  30233. +
  30234. +    if (!tty->canon_data || !tty->read_buf)
  30235. +        return 0;
  30236. +    head = tty->canon_head;
  30237. +    tail = tty->read_tail;
  30238. +    nr = (head - tail) & (N_TTY_BUF_SIZE-1);
  30239. +    /* Skip EOF-chars.. */
  30240. +    while (head != tail) {
  30241. +        if (test_bit(tail, &tty->read_flags) &&
  30242. +            tty->read_buf[tail] == __DISABLED_CHAR)
  30243. +            nr--;
  30244. +        tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  30245. +    }
  30246. +    return nr;
  30247. +}
  30248. +
  30249. +int n_tty_ioctl(struct tty_struct * tty, struct file * file,
  30250. +               unsigned int cmd, unsigned long arg)
  30251. +{
  30252. +    struct tty_struct * real_tty;
  30253. +    int retval;
  30254. +    int opt = 0;
  30255. +
  30256. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  30257. +        tty->driver.subtype == PTY_TYPE_MASTER)
  30258. +        real_tty = tty->link;
  30259. +    else
  30260. +        real_tty = tty;
  30261. +
  30262. +    switch (cmd) {
  30263. +        case TCGETS:
  30264. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  30265. +                         sizeof (struct termios));
  30266. +            if (retval)
  30267. +                return retval;
  30268. +            memcpy_tofs((struct termios *) arg,
  30269. +                    real_tty->termios,
  30270. +                    sizeof (struct termios));
  30271. +            return 0;
  30272. +        case TCSETSF:
  30273. +            opt |= TERMIOS_FLUSH;
  30274. +        case TCSETSW:
  30275. +            opt |= TERMIOS_WAIT;
  30276. +        case TCSETS:
  30277. +            return set_termios(real_tty, arg, opt);
  30278. +        case TCGETA:
  30279. +            return get_termio(real_tty,(struct termio *) arg);
  30280. +        case TCSETAF:
  30281. +            opt |= TERMIOS_FLUSH;
  30282. +        case TCSETAW:
  30283. +            opt |= TERMIOS_WAIT;
  30284. +        case TCSETA:
  30285. +            return set_termios(real_tty, arg, opt|TERMIOS_TERMIO);
  30286. +        case TCXONC:
  30287. +            retval = tty_check_change(tty);
  30288. +            if (retval)
  30289. +                return retval;
  30290. +            switch (arg) {
  30291. +            case TCOOFF:
  30292. +                stop_tty(tty);
  30293. +                break;
  30294. +            case TCOON:
  30295. +                start_tty(tty);
  30296. +                break;
  30297. +            case TCIOFF:
  30298. +                if (STOP_CHAR(tty) != __DISABLED_CHAR)
  30299. +                    tty->driver.write(tty, 0,
  30300. +                              &STOP_CHAR(tty), 1);
  30301. +                break;
  30302. +            case TCION:
  30303. +                if (START_CHAR(tty) != __DISABLED_CHAR)
  30304. +                    tty->driver.write(tty, 0,
  30305. +                              &START_CHAR(tty), 1);
  30306. +                break;
  30307. +            default:
  30308. +                return -EINVAL;
  30309. +            }
  30310. +            return 0;
  30311. +        case TCFLSH:
  30312. +            retval = tty_check_change(tty);
  30313. +            if (retval)
  30314. +                return retval;
  30315. +            switch (arg) {
  30316. +            case TCIFLUSH:
  30317. +                if (tty->ldisc.flush_buffer)
  30318. +                    tty->ldisc.flush_buffer(tty);
  30319. +                break;
  30320. +            case TCIOFLUSH:
  30321. +                if (tty->ldisc.flush_buffer)
  30322. +                    tty->ldisc.flush_buffer(tty);
  30323. +                /* fall through */
  30324. +            case TCOFLUSH:
  30325. +                if (tty->driver.flush_buffer)
  30326. +                    tty->driver.flush_buffer(tty);
  30327. +                break;
  30328. +            default:
  30329. +                return -EINVAL;
  30330. +            }
  30331. +            return 0;
  30332. +        case TIOCOUTQ:
  30333. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  30334. +                         sizeof (unsigned long));
  30335. +            if (retval)
  30336. +                return retval;
  30337. +            if (tty->driver.chars_in_buffer)
  30338. +                put_fs_long(tty->driver.chars_in_buffer(tty),
  30339. +                        (unsigned long *) arg);
  30340. +            else
  30341. +                put_fs_long(0, (unsigned long *) arg);
  30342. +            return 0;
  30343. +        case TIOCINQ:
  30344. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  30345. +                         sizeof (unsigned long));
  30346. +            if (retval)
  30347. +                return retval;
  30348. +            if (L_ICANON(tty))
  30349. +                put_fs_long(inq_canon(tty),
  30350. +                    (unsigned long *) arg);
  30351. +            else
  30352. +                put_fs_long(tty->read_cnt,
  30353. +                        (unsigned long *) arg);
  30354. +            return 0;
  30355. +        case TIOCGLCKTRMIOS:
  30356. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  30357. +                         sizeof (struct termios));
  30358. +            if (retval)
  30359. +                return retval;
  30360. +            memcpy_tofs((struct termios *) arg,
  30361. +                    real_tty->termios_locked,
  30362. +                    sizeof (struct termios));
  30363. +            return 0;
  30364. +        case TIOCSLCKTRMIOS:
  30365. +            if (!suser())
  30366. +                return -EPERM;
  30367. +            retval = verify_area(VERIFY_READ, (void *) arg,
  30368. +                         sizeof (struct termios));
  30369. +            if (retval)
  30370. +                return retval;
  30371. +            memcpy_fromfs(real_tty->termios_locked,
  30372. +                      (struct termios *) arg,
  30373. +                      sizeof (struct termios));
  30374. +            return 0;
  30375. +        case TIOCPKT:
  30376. +            if (tty->driver.type != TTY_DRIVER_TYPE_PTY ||
  30377. +                tty->driver.subtype != PTY_TYPE_MASTER)
  30378. +                return -ENOTTY;
  30379. +            retval = verify_area(VERIFY_READ, (void *) arg,
  30380. +                         sizeof (unsigned long));
  30381. +            if (retval)
  30382. +                return retval;
  30383. +            if (get_fs_long(arg)) {
  30384. +                if (!tty->packet) {
  30385. +                    tty->packet = 1;
  30386. +                    tty->link->ctrl_status = 0;
  30387. +                }
  30388. +            } else
  30389. +                tty->packet = 0;
  30390. +            return 0;
  30391. +        /* These two ioctl's always return success; even if */
  30392. +        /* the driver doesn't support them. */
  30393. +        case TCSBRK: case TCSBRKP:
  30394. +            retval = tty_check_change(tty);
  30395. +            if (retval)
  30396. +                return retval;
  30397. +            tty_wait_until_sent(tty, 0);
  30398. +            if (!tty->driver.ioctl)
  30399. +                return 0;
  30400. +            tty->driver.ioctl(tty, file, cmd, arg);
  30401. +            return 0;
  30402. +        default:
  30403. +            return -ENOIOCTLCMD;
  30404. +        }
  30405. +}
  30406. diff -r -u -N linux.orig/arch/arm/drivers/char/vc_screen.c linux.arm/arch/arm/drivers/char/vc_screen.c
  30407. --- linux.orig/arch/arm/drivers/char/vc_screen.c    Thu Jan  1 01:00:00 1970
  30408. +++ linux.arm/arch/arm/drivers/char/vc_screen.c    Fri Oct 27 23:14:41 1995
  30409. @@ -0,0 +1,226 @@
  30410. +/*
  30411. + * linux/drivers/char/vc_screen.c
  30412. + *
  30413. + * Provide access to virtual console memory.
  30414. + * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
  30415. + * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
  30416. + *            [minor: N]
  30417. + *
  30418. + * /dev/vcsaN: idem, but including attributes, and prefixed with
  30419. + *    the 4 bytes lines,columns,x,y (as screendump used to give)
  30420. + *            [minor: N+128]
  30421. + *
  30422. + * This replaces screendump and part of selection, so that the system
  30423. + * administrator can control access using file system permissions.
  30424. + *
  30425. + * aeb@cwi.nl - efter Friedas begravelse - 950211
  30426. + */
  30427. +
  30428. +#include <linux/kernel.h>
  30429. +#include <linux/major.h>
  30430. +#include <linux/errno.h>
  30431. +#include <linux/tty.h>
  30432. +#include <linux/fs.h>
  30433. +#include <asm/segment.h>
  30434. +#include "vt_kern.h"
  30435. +/*#include "selection.h"*/
  30436. +
  30437. +#define HEADER_SIZE    4
  30438. +#define video_num_lines 75
  30439. +#define video_num_columns 100
  30440. +static inline int
  30441. +vcs_size(struct inode *inode)
  30442. +{
  30443. +    int size = video_num_lines * video_num_columns;
  30444. +    if (MINOR(inode->i_rdev) & 128)
  30445. +        size = 4*size + HEADER_SIZE;
  30446. +    return size;
  30447. +}
  30448. +
  30449. +static int
  30450. +vcs_lseek(struct inode *inode, struct file *file, off_t offset, int orig)
  30451. +{
  30452. +    int size = vcs_size(inode);
  30453. +
  30454. +    switch (orig) {
  30455. +        case 0:
  30456. +            file->f_pos = offset;
  30457. +            break;
  30458. +        case 1:
  30459. +            file->f_pos += offset;
  30460. +            break;
  30461. +        case 2:
  30462. +            file->f_pos = size + offset;
  30463. +            break;
  30464. +        default:
  30465. +            return -EINVAL;
  30466. +    }
  30467. +    if (file->f_pos < 0 || file->f_pos > size)
  30468. +        return -EINVAL;
  30469. +    return file->f_pos;
  30470. +}
  30471. +
  30472. +static int
  30473. +vcs_read(struct inode *inode, struct file *file, char *buf, int count)
  30474. +{
  30475. +    unsigned long p = file->f_pos;
  30476. +    unsigned int cons = MINOR(inode->i_rdev);
  30477. +    int attr, size, read;
  30478. +    char *buf0;
  30479. +    unsigned long *org, d;
  30480. +
  30481. +    attr = (cons & 128);
  30482. +    cons = (cons & 127);
  30483. +    if (cons == 0)
  30484. +        cons = fg_console;
  30485. +    else
  30486. +        cons--;
  30487. +    if (!vc_cons_allocated(cons))
  30488. +        return -ENXIO;
  30489. +
  30490. +    size = vcs_size(inode);
  30491. +    if (count < 0 || p > size)
  30492. +        return -EINVAL;
  30493. +    if (count > size - p)
  30494. +        count = size - p;
  30495. +
  30496. +    buf0 = buf;
  30497. +    if (!attr) {
  30498. +        org = screen_pos(cons, p);
  30499. +        while (count-- > 0)
  30500. +            put_fs_byte(*org++ & 0xff, buf++);
  30501. +    } else {
  30502. +        if (p < HEADER_SIZE) {
  30503. +            char header[HEADER_SIZE];
  30504. +            header[0] = (char) video_num_lines;
  30505. +            header[1] = (char) video_num_columns;
  30506. +            getconsxy(cons, header+2);
  30507. +            while (p < HEADER_SIZE && count-- > 0)
  30508. +                put_fs_byte(header[p++], buf++);
  30509. +        }
  30510. +        p -= HEADER_SIZE;
  30511. +        org = screen_pos(cons, p>>2);
  30512. +        if (p & 3)
  30513. +            d = *org++;
  30514. +        if ((p & 3)>0 && count-- > 0)
  30515. +            put_fs_byte(d >> 24, buf++);
  30516. +        if ((p & 3)>1 && count-- > 0)
  30517. +            put_fs_byte((d >> 16) & 0xff, buf++);
  30518. +        if ((p & 3)>2 && count-- > 0)
  30519. +            put_fs_byte((d >> 8) & 0xff, buf++);
  30520. +        while (count > 1) {
  30521. +            put_fs_long(*org++, buf);
  30522. +            buf += 4;
  30523. +            count -= 4;
  30524. +        }
  30525. +        if (count > 0)
  30526. +        {
  30527. +            d = *org;
  30528. +            put_fs_byte(d & 0xff, buf++);
  30529. +            if (count > 1)
  30530. +                put_fs_byte((d >> 8) & 0xff, buf++);
  30531. +            if (count > 2)
  30532. +                put_fs_byte((d >> 16) & 0xff, buf++);
  30533. +        }
  30534. +    }
  30535. +    read = buf - buf0;
  30536. +    file->f_pos += read;
  30537. +    return read;
  30538. +}
  30539. +
  30540. +static int
  30541. +vcs_write(struct inode *inode, struct file *file, char *buf, int count)
  30542. +{
  30543. +    unsigned long p = file->f_pos;
  30544. +    unsigned int cons = MINOR(inode->i_rdev);
  30545. +    int viewed, attr, size, written;
  30546. +    char *buf0;
  30547. +    unsigned long *org, d;
  30548. +
  30549. +    attr = (cons & 128);
  30550. +    cons = (cons & 127);
  30551. +    if (cons == 0) {
  30552. +        cons = fg_console;
  30553. +        viewed = 1;
  30554. +    } else {
  30555. +        cons--;
  30556. +        viewed = 0;
  30557. +    }
  30558. +    if (!vc_cons_allocated(cons))
  30559. +        return -ENXIO;
  30560. +
  30561. +    size = vcs_size(inode);
  30562. +    if (count < 0 || p > size)
  30563. +        return -EINVAL;
  30564. +    if (count > size - p)
  30565. +        count = size - p;
  30566. +
  30567. +    buf0 = buf;
  30568. +    if (!attr) {
  30569. +        org = screen_pos(cons, p);
  30570. +        while (count-- > 0) {
  30571. +            *org = (*org & 0xffffff00) | get_fs_byte(buf++);
  30572. +            ll_char_write (*org);
  30573. +            org++;
  30574. +        }
  30575. +    } else {
  30576. +#if 0
  30577. +        if (p < HEADER_SIZE) {
  30578. +            char header[HEADER_SIZE];
  30579. +            getconsxy(cons, header+2);
  30580. +            while (p < HEADER_SIZE && count-- > 0)
  30581. +                header[p++] = get_fs_byte(buf++);
  30582. +            if (!viewed)
  30583. +                putconsxy(cons, header+2);
  30584. +        }
  30585. +        p -= HEADER_SIZE;
  30586. +        org = screen_pos(cons, p>>2, viewed);
  30587. +        if ((p & 1) && count-- > 0) {
  30588. +            scr_writew((get_fs_byte(buf++) << 8) |
  30589. +                   (scr_readw(org) & 0xff), org);
  30590. +            org++;
  30591. +        }
  30592. +        while (count > 1) {
  30593. +            scr_writew(get_fs_word(buf), org++);
  30594. +            buf += 2;
  30595. +            count -= 2;
  30596. +        }
  30597. +        if (count > 0)
  30598. +            scr_writew((scr_readw(org) & 0xff00) |
  30599. +                   get_fs_byte(buf++), org);
  30600. +#endif
  30601. +    }
  30602. +    written = buf - buf0;
  30603. +    update_scrmem (cons, file->f_pos, written);
  30604. +    file->f_pos += written;
  30605. +    return written;
  30606. +}
  30607. +
  30608. +static int
  30609. +vcs_open(struct inode *inode, struct file *filp)
  30610. +{
  30611. +    unsigned int cons = (MINOR(inode->i_rdev) & 127);
  30612. +    if(cons && !vc_cons_allocated(cons-1))
  30613. +        return -ENXIO;
  30614. +    return 0;
  30615. +}
  30616. +
  30617. +static struct file_operations vcs_fops = {
  30618. +    vcs_lseek,    /* lseek */
  30619. +    vcs_read,    /* read */
  30620. +    vcs_write,    /* write */
  30621. +    NULL,        /* readdir */
  30622. +    NULL,        /* select */
  30623. +    NULL,        /* ioctl */
  30624. +    NULL,        /* mmap */
  30625. +    vcs_open,    /* open */
  30626. +    NULL,        /* release */
  30627. +    NULL        /* fsync */
  30628. +};
  30629. +
  30630. +long vcs_init(long kmem_start)
  30631. +{
  30632. +    if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
  30633. +        printk("unable to get major %d for vcs device", VCS_MAJOR);
  30634. +    return kmem_start;
  30635. +}
  30636. diff -r -u -N linux.orig/arch/arm/drivers/char/vt.c linux.arm/arch/arm/drivers/char/vt.c
  30637. --- linux.orig/arch/arm/drivers/char/vt.c    Thu Jan  1 01:00:00 1970
  30638. +++ linux.arm/arch/arm/drivers/char/vt.c    Fri Oct 27 23:14:21 1995
  30639. @@ -0,0 +1,920 @@
  30640. +/*
  30641. + *  linux/drivers/char/vt.c
  30642. + *
  30643. + *  Copyright (C) 1992 obz under the linux copyright
  30644. + *
  30645. + *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
  30646. + *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
  30647. + *  Ported to ARM - rmk92@ecs.soton.ac.uk - July 1995
  30648. + */
  30649. +
  30650. +#include <linux/types.h>
  30651. +#include <linux/errno.h>
  30652. +#include <linux/sched.h>
  30653. +#include <linux/tty.h>
  30654. +#include <linux/timer.h>
  30655. +#include <linux/kernel.h>
  30656. +#include <linux/kd.h>
  30657. +#include <linux/vt.h>
  30658. +#include <linux/string.h>
  30659. +#include <linux/malloc.h>
  30660. +
  30661. +/* #include <asm/io.h> */
  30662. +#include <asm/segment.h>
  30663. +
  30664. +#include "kbd_kern.h"
  30665. +#include "vt_kern.h"
  30666. +#include "diacr.h"
  30667. +
  30668. +extern struct tty_driver console_driver;
  30669. +extern int sel_cons;
  30670. +
  30671. +#define VT_IS_IN_USE(i)    (console_driver.table[i] && console_driver.table[i]->count)
  30672. +#define VT_BUSY(i)    (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons)
  30673. +
  30674. +/*
  30675. + * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
  30676. + * experimentation and study of X386 SYSV handling.
  30677. + *
  30678. + * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
  30679. + * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
  30680. + * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
  30681. + * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
  30682. + * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
  30683. + * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
  30684. + * to the current console is done by the main ioctl code.
  30685. + */
  30686. +
  30687. +struct vt_struct *vt_cons[MAX_NR_CONSOLES];
  30688. +
  30689. +asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
  30690. +
  30691. +extern int getkeycode(unsigned int scancode);
  30692. +extern int setkeycode(unsigned int scancode, unsigned int keycode);
  30693. +extern void compute_shiftstate(void);
  30694. +extern void change_console(unsigned int new_console);
  30695. +extern void complete_change_console(unsigned int new_console);
  30696. +extern int vt_waitactive(void);
  30697. +extern void do_blank_screen(int nopowersave);
  30698. +extern void do_unblank_screen(void);
  30699. +extern unsigned int keymap_count;
  30700. +
  30701. +/*
  30702. + * routines to load custom translation table and EGA/VGA font from console.c
  30703. + */
  30704. +extern int con_set_trans(char * table);
  30705. +extern int con_get_trans(char * table);
  30706. +extern void con_clear_unimap(struct unimapinit *ui);
  30707. +extern int con_set_unimap(ushort ct, struct unipair *list);
  30708. +extern int con_get_unimap(ushort ct, ushort *uct, struct unipair *list);
  30709. +extern int con_set_font(char * fontmap);
  30710. +extern int con_get_font(char * fontmap);
  30711. +
  30712. +/*
  30713. + * these are the valid i/o ports we're allowed to change. they map all the
  30714. + * video ports
  30715. + */
  30716. +#define GPFIRST 0x3b4
  30717. +#define GPLAST 0x3df
  30718. +#define GPNUM (GPLAST - GPFIRST + 1)
  30719. +
  30720. +/*
  30721. + * Generates sound of some count for some number of clock ticks
  30722. + * [count = 1193180 / frequency]
  30723. + *
  30724. + * If freq is 0, will turn off sound, else will turn it on for that time.
  30725. + * If msec is 0, will return immediately, else will sleep for msec time, then
  30726. + * turn sound off.
  30727. + *
  30728. + * We use the BEEP_TIMER vector since we're using the same method to
  30729. + * generate sound, and we'll overwrite any beep in progress. That may
  30730. + * be something to fix later, if we like.
  30731. + *
  30732. + * We also return immediately, which is what was implied within the X
  30733. + * comments - KDMKTONE doesn't put the process to sleep.
  30734. + */
  30735. +void
  30736. +kd_mksound2(unsigned int count, unsigned int vol, unsigned int ticks)
  30737. +{
  30738. +    int freq;
  30739. +    
  30740. +    if(count)
  30741. +        freq = 1193180/count;
  30742. +    else
  30743. +        freq = 0;
  30744. +    mk_beep(freq, vol, ticks);
  30745. +}
  30746. +
  30747. +void
  30748. +kd_mksound(unsigned int count, unsigned int ticks)
  30749. +{
  30750. +    kd_mksound2(count, 64, ticks);
  30751. +}
  30752. +
  30753. +/*
  30754. + * We handle the console-specific ioctl's here.  We allow the
  30755. + * capability to modify any console, not just the fg_console.
  30756. + */
  30757. +int vt_ioctl(struct tty_struct *tty, struct file * file,
  30758. +         unsigned int cmd, unsigned long arg)
  30759. +{
  30760. +    int i, perm;
  30761. +    unsigned int console;
  30762. +    unsigned char ucval;
  30763. +    struct kbd_struct * kbd;
  30764. +    struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
  30765. +
  30766. +    console = vt->vc_num;
  30767. +
  30768. +    if (!vc_cons_allocated(console))     /* impossible? */
  30769. +        return -ENOIOCTLCMD;
  30770. +
  30771. +    /*
  30772. +     * To have permissions to do most of the vt ioctls, we either have
  30773. +     * to be the owner of the tty, or super-user.
  30774. +     */
  30775. +    perm = 0;
  30776. +    if (current->tty == tty || suser())
  30777. +        perm = 1;
  30778. +
  30779. +    kbd = kbd_table + console;
  30780. +    switch (cmd) {
  30781. +    case KIOCSOUND:
  30782. +        if (!perm)
  30783. +            return -EPERM;
  30784. +        kd_mksound((unsigned int)arg, 5);
  30785. +        return 0;
  30786. +
  30787. +    case KDMKTONE:
  30788. +        if (!perm)
  30789. +            return -EPERM;
  30790. +    {
  30791. +        unsigned int freq  = ((unsigned long *)arg)[0];
  30792. +        unsigned int vol   = ((unsigned long *)arg)[1];
  30793. +        unsigned int ticks = HZ * ((((unsigned long *)arg)[2] >> 16) & 0xffff) / 1000;
  30794. +
  30795. +        /*
  30796. +         * Generate the tone for the appropriate number of ticks.
  30797. +         * If the time is zero, turn off sound ourselves.
  30798. +         */
  30799. +        kd_mksound2(freq, vol, ticks);
  30800. +        return 0;
  30801. +    }
  30802. +
  30803. +    case KDGKBTYPE:
  30804. +        /*
  30805. +         * this is naive.
  30806. +         */
  30807. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  30808. +        if (!i)
  30809. +            put_fs_byte(KB_101, (char *) arg);
  30810. +        return i;
  30811. +
  30812. +    case KDADDIO:
  30813. +    case KDDELIO:
  30814. +        /*
  30815. +         * KDADDIO and KDDELIO may be able to add ports beyond what
  30816. +         * we reject here, but to be safe...
  30817. +         */
  30818. +        if (arg < GPFIRST || arg > GPLAST)
  30819. +            return -EINVAL;
  30820. +        return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
  30821. +
  30822. +    case KDENABIO:
  30823. +    case KDDISABIO:
  30824. +        return sys_ioperm(GPFIRST, GPNUM,
  30825. +                  (cmd == KDENABIO)) ? -ENXIO : 0;
  30826. +
  30827. +    case KDSETMODE:
  30828. +        /*
  30829. +         * currently, setting the mode from KD_TEXT to KD_GRAPHICS
  30830. +         * doesn't do a whole lot. i'm not sure if it should do any
  30831. +         * restoration of modes or what...
  30832. +         */
  30833. +        if (!perm)
  30834. +            return -EPERM;
  30835. +        switch (arg) {
  30836. +        case KD_GRAPHICS:
  30837. +            break;
  30838. +        case KD_TEXT0:
  30839. +        case KD_TEXT1:
  30840. +            arg = KD_TEXT;
  30841. +        case KD_TEXT:
  30842. +            break;
  30843. +        default:
  30844. +            return -EINVAL;
  30845. +        }
  30846. +        if (vt_cons[console]->vc_mode == (unsigned char) arg)
  30847. +            return 0;
  30848. +        vt_cons[console]->vc_mode = (unsigned char) arg;
  30849. +        if (console != fg_console)
  30850. +            return 0;
  30851. +        /*
  30852. +         * explicitly blank/unblank the screen if switching modes
  30853. +         */
  30854. +        if (arg == KD_TEXT)
  30855. +            do_unblank_screen();
  30856. +        else
  30857. +            do_blank_screen(1);
  30858. +        return 0;
  30859. +
  30860. +    case KDGETMODE:
  30861. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
  30862. +        if (!i)
  30863. +            put_fs_long(vt_cons[console]->vc_mode, (unsigned long *) arg);
  30864. +        return i;
  30865. +
  30866. +    case KDMAPDISP:
  30867. +    case KDUNMAPDISP:
  30868. +        /*
  30869. +         * these work like a combination of mmap and KDENABIO.
  30870. +         * this could be easily finished.
  30871. +         */
  30872. +        return -EINVAL;
  30873. +
  30874. +    case KDSKBMODE:
  30875. +        if (!perm)
  30876. +            return -EPERM;
  30877. +        switch(arg) {
  30878. +          case K_RAW:
  30879. +            kbd->kbdmode = VC_RAW;
  30880. +            break;
  30881. +          case K_MEDIUMRAW:
  30882. +            kbd->kbdmode = VC_MEDIUMRAW;
  30883. +            break;
  30884. +          case K_XLATE:
  30885. +            kbd->kbdmode = VC_XLATE;
  30886. +            compute_shiftstate();
  30887. +            break;
  30888. +          case K_UNICODE:
  30889. +            kbd->kbdmode = VC_UNICODE;
  30890. +            compute_shiftstate();
  30891. +            break;
  30892. +          default:
  30893. +            return -EINVAL;
  30894. +        }
  30895. +        if (tty->ldisc.flush_buffer)
  30896. +            tty->ldisc.flush_buffer(tty);
  30897. +        return 0;
  30898. +
  30899. +    case KDGKBMODE:
  30900. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
  30901. +        if (!i) {
  30902. +            ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
  30903. +                 (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
  30904. +                 (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
  30905. +                 K_XLATE);
  30906. +            put_fs_long(ucval, (unsigned long *) arg);
  30907. +        }
  30908. +        return i;
  30909. +
  30910. +    /* this could be folded into KDSKBMODE, but for compatibility
  30911. +       reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
  30912. +    case KDSKBMETA:
  30913. +        switch(arg) {
  30914. +          case K_METABIT:
  30915. +            clr_vc_kbd_mode(kbd, VC_META);
  30916. +            break;
  30917. +          case K_ESCPREFIX:
  30918. +            set_vc_kbd_mode(kbd, VC_META);
  30919. +            break;
  30920. +          default:
  30921. +            return -EINVAL;
  30922. +        }
  30923. +        return 0;
  30924. +
  30925. +    case KDGKBMETA:
  30926. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
  30927. +        if (!i) {
  30928. +            ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX :
  30929. +                 K_METABIT);
  30930. +            put_fs_long(ucval, (unsigned long *) arg);
  30931. +        }
  30932. +        return i;
  30933. +
  30934. +    case KDGETKEYCODE:
  30935. +    {
  30936. +        struct kbkeycode * const a = (struct kbkeycode *)arg;
  30937. +        unsigned int sc;
  30938. +        int kc;
  30939. +
  30940. +        i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbkeycode));
  30941. +        if (i)
  30942. +            return i;
  30943. +        sc = get_fs_long((int *) &a->scancode);
  30944. +        kc = getkeycode(sc);
  30945. +        if (kc < 0)
  30946. +            return kc;
  30947. +        put_fs_long(kc, (int *) &a->keycode);
  30948. +        return 0;
  30949. +    }
  30950. +
  30951. +    case KDSETKEYCODE:
  30952. +    {
  30953. +        struct kbkeycode * const a = (struct kbkeycode *)arg;
  30954. +        unsigned int sc, kc;
  30955. +
  30956. +        if (!perm)
  30957. +            return -EPERM;
  30958. +        i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbkeycode));
  30959. +        if (i)
  30960. +            return i;
  30961. +        sc = get_fs_long((int *) &a->scancode);
  30962. +        kc = get_fs_long((int *) &a->keycode);
  30963. +        return setkeycode(sc, kc);
  30964. +    }
  30965. +
  30966. +    case KDGKBENT:
  30967. +    {
  30968. +        struct kbentry * const a = (struct kbentry *)arg;
  30969. +        ushort *key_map, val;
  30970. +        u_char s;
  30971. +
  30972. +        i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
  30973. +        if (i)
  30974. +            return i;
  30975. +        if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
  30976. +            return -EINVAL;
  30977. +        if ((s = get_fs_byte((char *) &a->kb_table)) >= MAX_NR_KEYMAPS)
  30978. +            return -EINVAL;
  30979. +        key_map = key_maps[s];
  30980. +        if (key_map) {
  30981. +            val = U(key_map[i]);
  30982. +            if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
  30983. +            val = K_HOLE;
  30984. +        } else
  30985. +            val = (i ? K_HOLE : K_NOSUCHMAP);
  30986. +        put_fs_word(val, (short *) &a->kb_value);
  30987. +        return 0;
  30988. +    }
  30989. +
  30990. +    case KDSKBENT:
  30991. +    {
  30992. +        const struct kbentry * a = (struct kbentry *)arg;
  30993. +        ushort *key_map;
  30994. +        u_char s;
  30995. +        u_short v, ov;
  30996. +
  30997. +        if (!perm)
  30998. +            return -EPERM;
  30999. +        i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbentry));
  31000. +        if (i)
  31001. +            return i;
  31002. +        if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
  31003. +            return -EINVAL;
  31004. +        if ((s = get_fs_byte((char *) &a->kb_table)) >= MAX_NR_KEYMAPS)
  31005. +            return -EINVAL;
  31006. +        v = get_fs_word(&a->kb_value);
  31007. +        if (!i && v == K_NOSUCHMAP) {
  31008. +            /* disallocate map */
  31009. +            key_map = key_maps[s];
  31010. +            if (s && key_map) {
  31011. +                key_maps[s] = 0;
  31012. +                if (key_map[0] == U(K_ALLOCATED)) {
  31013. +                kfree_s(key_map, sizeof(plain_map));
  31014. +                keymap_count--;
  31015. +                }
  31016. +            }
  31017. +            return 0;
  31018. +        }
  31019. +
  31020. +        if (KTYP(v) < NR_TYPES) {
  31021. +            if (KVAL(v) > max_vals[KTYP(v)])
  31022. +            return -EINVAL;
  31023. +        } else
  31024. +            if (kbd->kbdmode != VC_UNICODE)
  31025. +            return -EINVAL;
  31026. +
  31027. +        /* assignment to entry 0 only tests validity of args */
  31028. +        if (!i)
  31029. +            return 0;
  31030. +
  31031. +        if (!(key_map = key_maps[s])) {
  31032. +            int j;
  31033. +            
  31034. +            if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && !suser())
  31035. +                return -EPERM;
  31036. +
  31037. +            key_map = (ushort *) kmalloc(sizeof(plain_map),
  31038. +                             GFP_KERNEL);
  31039. +            if (!key_map)
  31040. +                return -ENOMEM;
  31041. +            key_maps[s] = key_map;
  31042. +            key_map[0] = U(K_ALLOCATED);
  31043. +            for (j = 1; j < NR_KEYS; j++)
  31044. +                key_map[j] = U(K_HOLE);
  31045. +            keymap_count++;
  31046. +        }
  31047. +        ov = U(key_map[i]);
  31048. +        if (v == ov)
  31049. +            return 0;    /* nothing to do */
  31050. +        /*
  31051. +         * Only the Superuser can set or unset the Secure
  31052. +         * Attention Key.
  31053. +         */
  31054. +        if (((ov == K_SAK) || (v == K_SAK)) && !suser())
  31055. +            return -EPERM;
  31056. +        key_map[i] = U(v);
  31057. +        if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
  31058. +            compute_shiftstate();
  31059. +        return 0;
  31060. +    }
  31061. +
  31062. +    case KDGKBSENT:
  31063. +    {
  31064. +        struct kbsentry *a = (struct kbsentry *)arg;
  31065. +        char *p;
  31066. +        u_char *q;
  31067. +        int sz;
  31068. +
  31069. +        i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
  31070. +        if (i)
  31071. +            return i;
  31072. +        if ((i = get_fs_byte(&a->kb_func)) >= MAX_NR_FUNC || i < 0)
  31073. +            return -EINVAL;
  31074. +        sz = sizeof(a->kb_string) - 1; /* sz should have been
  31075. +                          a struct member */
  31076. +        q = a->kb_string;
  31077. +        p = func_table[i];
  31078. +        if(p)
  31079. +            for ( ; *p && sz; p++, sz--)
  31080. +                put_fs_byte(*p, q++);
  31081. +        put_fs_byte(0, q);
  31082. +        return ((p && *p) ? -EOVERFLOW : 0);
  31083. +    }
  31084. +
  31085. +    case KDSKBSENT:
  31086. +    {
  31087. +        struct kbsentry * const a = (struct kbsentry *)arg;
  31088. +        int delta;
  31089. +        char *first_free, *fj, *fnw;
  31090. +        int j, k, sz;
  31091. +        u_char *p;
  31092. +        char *q;
  31093. +
  31094. +        if (!perm)
  31095. +            return -EPERM;
  31096. +        i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
  31097. +        if (i)
  31098. +            return i;
  31099. +        if ((i = get_fs_byte(&a->kb_func)) >= MAX_NR_FUNC)
  31100. +            return -EINVAL;
  31101. +        q = func_table[i];
  31102. +
  31103. +        first_free = funcbufptr + (funcbufsize - funcbufleft);
  31104. +        for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) ;
  31105. +        if (j < MAX_NR_FUNC)
  31106. +            fj = func_table[j];
  31107. +        else
  31108. +            fj = first_free;
  31109. +
  31110. +        delta = (q ? -strlen(q) : 1);
  31111. +        sz = sizeof(a->kb_string);     /* sz should have been
  31112. +                           a struct member */
  31113. +        for (p = a->kb_string; get_fs_byte(p) && sz; p++,sz--)
  31114. +            delta++;
  31115. +        if (!sz)
  31116. +            return -EOVERFLOW;
  31117. +        if (delta <= funcbufleft) {     /* it fits in current buf */
  31118. +            if (j < MAX_NR_FUNC) {
  31119. +            memmove(fj + delta, fj, first_free - fj);
  31120. +            for (k = j; k < MAX_NR_FUNC; k++)
  31121. +                if (func_table[k])
  31122. +                func_table[k] += delta;
  31123. +            }
  31124. +            if (!q)
  31125. +              func_table[i] = fj;
  31126. +            funcbufleft -= delta;
  31127. +        } else {            /* allocate a larger buffer */
  31128. +            sz = 256;
  31129. +            while (sz < funcbufsize - funcbufleft + delta)
  31130. +              sz <<= 1;
  31131. +            fnw = (char *) kmalloc(sz, GFP_KERNEL);
  31132. +            if(!fnw)
  31133. +              return -ENOMEM;
  31134. +
  31135. +            if (!q)
  31136. +              func_table[i] = fj;
  31137. +            if (fj > funcbufptr)
  31138. +            memmove(fnw, funcbufptr, fj - funcbufptr);
  31139. +            for (k = 0; k < j; k++)
  31140. +              if (func_table[k])
  31141. +            func_table[k] = fnw + (func_table[k] - funcbufptr);
  31142. +
  31143. +            if (first_free > fj) {
  31144. +            memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
  31145. +            for (k = j; k < MAX_NR_FUNC; k++)
  31146. +              if (func_table[k])
  31147. +                func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
  31148. +            }
  31149. +            if (funcbufptr != func_buf)
  31150. +              kfree_s(funcbufptr, funcbufsize);
  31151. +            funcbufptr = fnw;
  31152. +            funcbufleft = funcbufleft - delta + sz - funcbufsize;
  31153. +            funcbufsize = sz;
  31154. +        }
  31155. +        for (p = a->kb_string, q = func_table[i]; ; p++, q++)
  31156. +            if (!(*q = get_fs_byte(p)))
  31157. +                break;
  31158. +        return 0;
  31159. +    }
  31160. +
  31161. +    case KDGKBDIACR:
  31162. +    {
  31163. +        struct kbdiacrs *a = (struct kbdiacrs *)arg;
  31164. +
  31165. +        i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs));
  31166. +        if (i)
  31167. +            return i;
  31168. +        put_fs_long(accent_table_size, &a->kb_cnt);
  31169. +        memcpy_tofs(a->kbdiacr, accent_table,
  31170. +                accent_table_size*sizeof(struct kbdiacr));
  31171. +        return 0;
  31172. +    }
  31173. +
  31174. +    case KDSKBDIACR:
  31175. +    {
  31176. +        struct kbdiacrs *a = (struct kbdiacrs *)arg;
  31177. +        unsigned int ct;
  31178. +
  31179. +        if (!perm)
  31180. +            return -EPERM;
  31181. +        i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
  31182. +        if (i)
  31183. +            return i;
  31184. +        ct = get_fs_long(&a->kb_cnt);
  31185. +        if (ct >= MAX_DIACR)
  31186. +            return -EINVAL;
  31187. +        accent_table_size = ct;
  31188. +        memcpy_fromfs(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr));
  31189. +        return 0;
  31190. +    }
  31191. +
  31192. +    /* the ioctls below read/set the flags usually shown in the leds */
  31193. +    /* don't use them - they will go away without warning */
  31194. +    case KDGKBLED:
  31195. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  31196. +        if (i)
  31197. +            return i;
  31198. +        put_fs_byte(kbd->ledflagstate |
  31199. +                (kbd->default_ledflagstate << 4), (char *) arg);
  31200. +        return 0;
  31201. +
  31202. +    case KDSKBLED:
  31203. +        if (!perm)
  31204. +            return -EPERM;
  31205. +        if (arg & ~0x77)
  31206. +            return -EINVAL;
  31207. +        kbd->ledflagstate = (arg & 7);
  31208. +        kbd->default_ledflagstate = ((arg >> 4) & 7);
  31209. +        set_leds();
  31210. +        return 0;
  31211. +
  31212. +    /* the ioctls below only set the lights, not the functions */
  31213. +    /* for those, see KDGKBLED and KDSKBLED above */
  31214. +    case KDGETLED:
  31215. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  31216. +        if (i)
  31217. +            return i;
  31218. +        put_fs_byte(getledstate(), (char *) arg);
  31219. +        return 0;
  31220. +
  31221. +    case KDSETLED:
  31222. +        if (!perm)
  31223. +            return -EPERM;
  31224. +        setledstate(kbd, arg);
  31225. +        return 0;
  31226. +
  31227. +    /*
  31228. +     * A process can indicate its willingness to accept signals
  31229. +     * generated by pressing an appropriate key combination.
  31230. +     * Thus, one can have a daemon that e.g. spawns a new console
  31231. +     * upon a keypess and then changes to it.
  31232. +     * Probably init should be changed to do this (and have a
  31233. +     * field ks (`keyboard signal') in inittab describing the
  31234. +     * desired acion), so that the number of background daemons
  31235. +     * does not increase.
  31236. +     */
  31237. +    case KDSIGACCEPT:
  31238. +    {
  31239. +        extern int spawnpid, spawnsig;
  31240. +        if (!perm)
  31241. +          return -EPERM;
  31242. +        if (arg < 1 || arg > NSIG || arg == SIGKILL)
  31243. +          return -EINVAL;
  31244. +        spawnpid = current->pid;
  31245. +        spawnsig = arg;
  31246. +        return 0;
  31247. +    }
  31248. +
  31249. +    case VT_SETMODE:
  31250. +    {
  31251. +        struct vt_mode *vtmode = (struct vt_mode *)arg;
  31252. +        char mode;
  31253. +
  31254. +        if (!perm)
  31255. +            return -EPERM;
  31256. +        i = verify_area(VERIFY_WRITE, (void *)vtmode, sizeof(struct vt_mode));
  31257. +        if (i)
  31258. +            return i;
  31259. +        mode = get_fs_byte(&vtmode->mode);
  31260. +        if (mode != VT_AUTO && mode != VT_PROCESS)
  31261. +            return -EINVAL;
  31262. +        vt_cons[console]->vt_mode.mode = mode;
  31263. +        vt_cons[console]->vt_mode.waitv = get_fs_byte(&vtmode->waitv);
  31264. +        vt_cons[console]->vt_mode.relsig = get_fs_word(&vtmode->relsig);
  31265. +        vt_cons[console]->vt_mode.acqsig = get_fs_word(&vtmode->acqsig);
  31266. +        /* the frsig is ignored, so we set it to 0 */
  31267. +        vt_cons[console]->vt_mode.frsig = 0;
  31268. +        vt_cons[console]->vt_pid = current->pid;
  31269. +        vt_cons[console]->vt_newvt = 0;
  31270. +        return 0;
  31271. +    }
  31272. +
  31273. +    case VT_GETMODE:
  31274. +    {
  31275. +        struct vt_mode *vtmode = (struct vt_mode *)arg;
  31276. +
  31277. +        i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct vt_mode));
  31278. +        if (i)
  31279. +            return i;
  31280. +        put_fs_byte(vt_cons[console]->vt_mode.mode, &vtmode->mode);
  31281. +        put_fs_byte(vt_cons[console]->vt_mode.waitv, &vtmode->waitv);
  31282. +        put_fs_word(vt_cons[console]->vt_mode.relsig, &vtmode->relsig);
  31283. +        put_fs_word(vt_cons[console]->vt_mode.acqsig, &vtmode->acqsig);
  31284. +        put_fs_word(vt_cons[console]->vt_mode.frsig, &vtmode->frsig);
  31285. +        return 0;
  31286. +    }
  31287. +
  31288. +    /*
  31289. +     * Returns global vt state. Note that VT 0 is always open, since
  31290. +     * it's an alias for the current VT, and people can't use it here.
  31291. +     * We cannot return state for more than 16 VTs, since v_state is short.
  31292. +     */
  31293. +    case VT_GETSTATE:
  31294. +    {
  31295. +        struct vt_stat *vtstat = (struct vt_stat *)arg;
  31296. +        unsigned short state, mask;
  31297. +
  31298. +        i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
  31299. +        if (i)
  31300. +            return i;
  31301. +        put_fs_word(fg_console + 1, &vtstat->v_active);
  31302. +        state = 1;    /* /dev/tty0 is always open */
  31303. +        for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
  31304. +            if (VT_IS_IN_USE(i))
  31305. +                state |= mask;
  31306. +        put_fs_word(state, &vtstat->v_state);
  31307. +        return 0;
  31308. +    }
  31309. +
  31310. +    /*
  31311. +     * Returns the first available (non-opened) console.
  31312. +     */
  31313. +    case VT_OPENQRY:
  31314. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
  31315. +        if (i)
  31316. +            return i;
  31317. +        for (i = 0; i < MAX_NR_CONSOLES; ++i)
  31318. +            if (! VT_IS_IN_USE(i))
  31319. +                break;
  31320. +        put_fs_long(i < MAX_NR_CONSOLES ? (i+1) : -1,
  31321. +                (unsigned long *)arg);
  31322. +        return 0;
  31323. +
  31324. +    /*
  31325. +     * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
  31326. +     * with num >= 1 (switches to vt 0, our console, are not allowed, just
  31327. +     * to preserve sanity).
  31328. +     */
  31329. +    case VT_ACTIVATE:
  31330. +        if (!perm)
  31331. +            return -EPERM;
  31332. +        if (arg == 0 || arg > MAX_NR_CONSOLES)
  31333. +            return -ENXIO;
  31334. +        arg--;
  31335. +        i = vc_allocate(arg);
  31336. +        if (i)
  31337. +            return i;
  31338. +        change_console(arg);
  31339. +        return 0;
  31340. +
  31341. +    /*
  31342. +     * wait until the specified VT has been activated
  31343. +     */
  31344. +    case VT_WAITACTIVE:
  31345. +        if (!perm)
  31346. +            return -EPERM;
  31347. +        if (arg == 0 || arg > MAX_NR_CONSOLES)
  31348. +            return -ENXIO;
  31349. +        arg--;
  31350. +        while (fg_console != arg)
  31351. +        {
  31352. +            if (vt_waitactive() < 0)
  31353. +                return -EINTR;
  31354. +        }
  31355. +        return 0;
  31356. +
  31357. +    /*
  31358. +     * If a vt is under process control, the kernel will not switch to it
  31359. +     * immediately, but postpone the operation until the process calls this
  31360. +     * ioctl, allowing the switch to complete.
  31361. +     *
  31362. +     * According to the X sources this is the behavior:
  31363. +     *    0:    pending switch-from not OK
  31364. +     *    1:    pending switch-from OK
  31365. +     *    2:    completed switch-to OK
  31366. +     */
  31367. +    case VT_RELDISP:
  31368. +        if (!perm)
  31369. +            return -EPERM;
  31370. +        if (vt_cons[console]->vt_mode.mode != VT_PROCESS)
  31371. +            return -EINVAL;
  31372. +
  31373. +        /*
  31374. +         * Switching-from response
  31375. +         */
  31376. +        if (vt_cons[console]->vt_newvt >= 0)
  31377. +        {
  31378. +            if (arg == 0)
  31379. +                /*
  31380. +                 * Switch disallowed, so forget we were trying
  31381. +                 * to do it.
  31382. +                 */
  31383. +                vt_cons[console]->vt_newvt = -1;
  31384. +
  31385. +            else
  31386. +            {
  31387. +                /*
  31388. +                 * The current vt has been released, so
  31389. +                 * complete the switch.
  31390. +                 */
  31391. +                int newvt = vt_cons[console]->vt_newvt;
  31392. +                vt_cons[console]->vt_newvt = -1;
  31393. +                i = vc_allocate(newvt);
  31394. +                if (i)
  31395. +                    return i;
  31396. +                complete_change_console(newvt);
  31397. +            }
  31398. +        }
  31399. +
  31400. +        /*
  31401. +         * Switched-to response
  31402. +         */
  31403. +        else
  31404. +        {
  31405. +            /*
  31406. +             * If it's just an ACK, ignore it
  31407. +             */
  31408. +            if (arg != VT_ACKACQ)
  31409. +                return -EINVAL;
  31410. +        }
  31411. +
  31412. +        return 0;
  31413. +
  31414. +     /*
  31415. +      * Disallocate memory associated to VT (but leave VT1)
  31416. +      */
  31417. +     case VT_DISALLOCATE:
  31418. +        if (arg > MAX_NR_CONSOLES)
  31419. +            return -ENXIO;
  31420. +        if (arg == 0) {
  31421. +            /* disallocate all unused consoles, but leave 0 */
  31422. +            for (i = 1; i<MAX_NR_CONSOLES; i++)
  31423. +              if (! VT_BUSY(i))
  31424. +              vc_disallocate(i);
  31425. +        } else {
  31426. +            /* disallocate a single console, if possible */
  31427. +            arg--;
  31428. +            if (VT_BUSY(arg))
  31429. +              return -EBUSY;
  31430. +            if (arg)                /* leave 0 */
  31431. +            vc_disallocate(arg);
  31432. +        }
  31433. +        return 0;
  31434. +
  31435. +    case VT_RESIZE:
  31436. +    {
  31437. +        struct vt_sizes *vtsizes = (struct vt_sizes *) arg;
  31438. +        ushort ll,cc;
  31439. +        if (!perm)
  31440. +            return -EPERM;
  31441. +        i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
  31442. +        if (i)
  31443. +            return i;
  31444. +        ll = get_fs_word(&vtsizes->v_rows);
  31445. +        cc = get_fs_word(&vtsizes->v_cols);
  31446. +        return vc_resize(ll, cc);
  31447. +    }
  31448. +    
  31449. +    case VT_GETPALETTE:
  31450. +    {
  31451. +        unsigned long pix, num, *val;
  31452. +        
  31453. +            i = verify_area(VERIFY_WRITE, (void *)arg, 12);
  31454. +            if (i)
  31455. +                return i;
  31456. +            pix = get_fs_long((unsigned long *)arg);
  31457. +            num = get_fs_long((unsigned long *)(arg + 4));
  31458. +            val = (unsigned long *)get_fs_long((unsigned long *)(arg + 8));
  31459. +        return palette_getentries(console, pix, num, val);
  31460. +    }
  31461. +
  31462. +    case VT_SETPALETTE:
  31463. +    {
  31464. +        unsigned long pix, num, *val;
  31465. +
  31466. +            i = verify_area(VERIFY_READ, (void *)arg, 12);
  31467. +            if (i)
  31468. +                return i;
  31469. +
  31470. +            pix = get_fs_long((unsigned long *)arg);
  31471. +            num = get_fs_long((unsigned long *)(arg + 4));
  31472. +            val = (unsigned long *)get_fs_long((unsigned long *)(arg + 8));
  31473. +        return palette_setentries(console, pix, num, val);
  31474. +    }
  31475. +
  31476. +    case VT_GETSCRINFO:
  31477. +        i = verify_area(VERIFY_WRITE, (void *)arg, 20);
  31478. +            if (i)
  31479. +                return i;
  31480. +        return console_getparams(console, arg);
  31481. +
  31482. +    case PIO_FONT:
  31483. +        if (!perm)
  31484. +            return -EPERM;
  31485. +        if (vt_cons[fg_console]->vc_mode != KD_TEXT)
  31486. +            return -EINVAL;
  31487. +        return con_set_font((char *)arg);
  31488. +        /* con_set_font() defined in console.c */
  31489. +
  31490. +    case GIO_FONT:
  31491. +        if (vt_cons[fg_console]->vc_mode != KD_TEXT)
  31492. +            return -EINVAL;
  31493. +        return con_get_font((char *)arg);
  31494. +        /* con_get_font() defined in console.c */
  31495. +
  31496. +    case PIO_SCRNMAP:
  31497. +        if (!perm)
  31498. +            return -EPERM;
  31499. +        return con_set_trans((char *)arg);
  31500. +
  31501. +    case GIO_SCRNMAP:
  31502. +        return con_get_trans((char *)arg);
  31503. +
  31504. +    case PIO_UNIMAPCLR:
  31505. +          {    struct unimapinit ui;
  31506. +        if (!perm)
  31507. +            return -EPERM;
  31508. +        i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapinit));
  31509. +        if (i)
  31510. +          return i;
  31511. +        memcpy_fromfs(&ui, (void *)arg, sizeof(struct unimapinit));
  31512. +        con_clear_unimap(&ui);
  31513. +        return 0;
  31514. +          }
  31515. +
  31516. +    case PIO_UNIMAP:
  31517. +          {    struct unimapdesc *ud;
  31518. +        u_short ct;
  31519. +        struct unipair *list;
  31520. +
  31521. +        if (!perm)
  31522. +            return -EPERM;
  31523. +        i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapdesc));
  31524. +        if (i == 0) {
  31525. +            ud = (struct unimapdesc *) arg;
  31526. +            ct = get_fs_word(&ud->entry_ct);
  31527. +            list = (struct unipair *) get_fs_long(&ud->entries);
  31528. +            i = verify_area(VERIFY_READ, (void *) list,
  31529. +                        ct*sizeof(struct unipair));
  31530. +        }
  31531. +        if (i)
  31532. +          return i;
  31533. +        return con_set_unimap(ct, list);
  31534. +          }
  31535. +
  31536. +    case GIO_UNIMAP:
  31537. +          {    struct unimapdesc *ud;
  31538. +        u_short ct;
  31539. +        struct unipair *list;
  31540. +
  31541. +        i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct unimapdesc));
  31542. +        if (i == 0) {
  31543. +            ud = (struct unimapdesc *) arg;
  31544. +            ct = get_fs_word(&ud->entry_ct);
  31545. +            list = (struct unipair *) get_fs_long(&ud->entries);
  31546. +            if (ct)
  31547. +              i = verify_area(VERIFY_WRITE, (void *) list,
  31548. +                          ct*sizeof(struct unipair));
  31549. +        }
  31550. +        if (i)
  31551. +          return i;
  31552. +        return con_get_unimap(ct, &(ud->entry_ct), list);
  31553. +          }
  31554. +
  31555. +    default:
  31556. +        return -ENOIOCTLCMD;
  31557. +    }
  31558. +}
  31559. diff -r -u -N linux.orig/arch/arm/drivers/char/vt_kern.h linux.arm/arch/arm/drivers/char/vt_kern.h
  31560. --- linux.orig/arch/arm/drivers/char/vt_kern.h    Thu Jan  1 01:00:00 1970
  31561. +++ linux.arm/arch/arm/drivers/char/vt_kern.h    Fri Oct 27 23:14:27 1995
  31562. @@ -0,0 +1,29 @@
  31563. +#ifndef _VT_KERN_H
  31564. +#define _VT_KERN_H
  31565. +
  31566. +/*
  31567. + * this really is an extension of the vc_cons structure in console.c, but
  31568. + * with information needed by the vt package
  31569. + */
  31570. +
  31571. +#include <linux/vt.h>
  31572. +
  31573. +extern struct vt_struct {
  31574. +    int vc_num;                /* The console number */
  31575. +    unsigned char    vc_mode;        /* KD_TEXT, ... */
  31576. +    unsigned char    vc_kbdraw;
  31577. +    unsigned char    vc_kbde0;
  31578. +    unsigned char   vc_kbdleds;
  31579. +    struct vt_mode    vt_mode;
  31580. +    int        vt_pid;
  31581. +    int        vt_newvt;
  31582. +    struct wait_queue *paste_wait;
  31583. +} *vt_cons[MAX_NR_CONSOLES];
  31584. +
  31585. +void kd_mksound(unsigned int count, unsigned int ticks);
  31586. +int vc_allocate(unsigned int console);
  31587. +int vc_cons_allocated(unsigned int console);
  31588. +int vc_resize(unsigned long lines, unsigned long cols);
  31589. +void vc_disallocate(unsigned int console);
  31590. +
  31591. +#endif /* _VT_KERN_H */
  31592. diff -r -u -N linux.orig/arch/arm/drivers/net/Makefile linux.arm/arch/arm/drivers/net/Makefile
  31593. --- linux.orig/arch/arm/drivers/net/Makefile    Thu Jan  1 01:00:00 1970
  31594. +++ linux.arm/arch/arm/drivers/net/Makefile    Fri Oct 27 23:15:04 1995
  31595. @@ -0,0 +1,105 @@
  31596. +# File: drivers/net/Makefile
  31597. +#
  31598. +# Makefile for the Linux network (ethercard) device drivers.
  31599. +#
  31600. +
  31601. +# This will go away in some future future: hidden configuration files
  31602. +# are difficult for users to deal with.
  31603. +include CONFIG
  31604. +
  31605. +# Build MODULES by appending to this string for every driver below
  31606. +#MODULES :=
  31607. +
  31608. +NETDRV_OBJS := Space.o auto_irq.o net_init.o loopback.o
  31609. +CFLAGS :=$(CFLAGS) -I../../../../net/inet
  31610. +CPP :=$(CPP) -I../../../../net/inet
  31611. +
  31612. +.c.o:
  31613. +    $(CC) $(CFLAGS) -c $<
  31614. +
  31615. +
  31616. +# The point of the makefile...
  31617. +all: net.a
  31618. +
  31619. +Space.o: Space.c ../../../../include/linux/autoconf.h
  31620. +    $(CC) $(CFLAGS) $(OPTS) -c $<
  31621. +
  31622. +net_init.o: ../../../../include/linux/autoconf.h
  31623. +
  31624. +ifdef CONFIG_ETHER3
  31625. +NETDRV_OBJS := $(NETDRV_OBJS) nq8005.o
  31626. +else
  31627. +MODULES := $(MODULES) nq8005.o
  31628. +endif
  31629. +
  31630. +ifdef CONFIG_PLIP
  31631. +NETDRV_OBJS := $(NETDRV_OBJS) plip.o
  31632. +else
  31633. +MODULES := $(MODULES) plip.o
  31634. +endif
  31635. +plip.o:    plip.c CONFIG
  31636. +    $(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $<
  31637. +
  31638. +ifdef CONFIG_PPP
  31639. +NETDRV_OBJS := $(NETDRV_OBJS) ppp.o
  31640. +CONFIG_SLHC = CONFIG_SLHC
  31641. +else
  31642. +MODULES := $(MODULES) ppp.o
  31643. +endif
  31644. +
  31645. +ifdef CONFIG_SLIP
  31646. +NETDRV_OBJS := $(NETDRV_OBJS) slip.o
  31647. +CONFIG_SLHC = CONFIG_SLHC
  31648. +else
  31649. +MODULES := $(MODULES) slip.o
  31650. +endif
  31651. +slip.o:    slip.c CONFIG
  31652. +    $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
  31653. +
  31654. +ifdef CONFIG_DUMMY
  31655. +NETDRV_OBJS := $(NETDRV_OBJS) dummy.o
  31656. +else
  31657. +MODULES := $(MODULES) dummy.o
  31658. +endif
  31659. +dummy.o: dummy.c CONFIG
  31660. +    $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
  31661. +
  31662. +ifdef CONFIG_SLHC
  31663. +NETDRV_OBJS := $(NETDRV_OBJS) slhc.o
  31664. +else
  31665. +MODULES := slhc.o $(MODULES)
  31666. +endif
  31667. +
  31668. +net.a: $(NETDRV_OBJS)
  31669. +    rm -f net.a
  31670. +    $(AR) rcs net.a $(NETDRV_OBJS)
  31671. +
  31672. +clean:
  31673. +    rm -f core *.o *.a *.s
  31674. +
  31675. +dep:
  31676. +    $(CPP) -M $(NETDRV_OBJS:.o=.c) > .depend
  31677. +ifdef MODULES
  31678. +    $(CPP) -M -DMODULE $(MODULES:.o=.c) >> .depend
  31679. +endif
  31680. +
  31681. +tar:
  31682. +
  31683. +ifdef MODULES
  31684. +
  31685. +modules: $(MODULES)
  31686. +    echo $(MODULES) > ../../../../modules/NET_MODULES
  31687. +    cd ../../../../modules; \
  31688. +        for i in $(MODULES); do ln -sf ../arch/arm/drivers/net/$$i .; done
  31689. +
  31690. +else
  31691. +
  31692. +modules:
  31693. +
  31694. +endif
  31695. +
  31696. +# include a dependency file if one exists
  31697. +
  31698. +ifeq (.depend,$(wildcard .depend))
  31699. +include .depend
  31700. +endif
  31701. diff -r -u -N linux.orig/arch/arm/drivers/net/Space.c linux.arm/arch/arm/drivers/net/Space.c
  31702. --- linux.orig/arch/arm/drivers/net/Space.c    Thu Jan  1 01:00:00 1970
  31703. +++ linux.arm/arch/arm/drivers/net/Space.c    Fri Oct 27 23:15:03 1995
  31704. @@ -0,0 +1,202 @@
  31705. +/*
  31706. + * INET        An implementation of the TCP/IP protocol suite for the LINUX
  31707. + *        operating system.  INET is implemented using the  BSD Socket
  31708. + *        interface as the means of communication with the user level.
  31709. + *
  31710. + *        Holds initial configuration information for devices.
  31711. + *
  31712. + * NOTE:    This file is a nice idea, but its current format does not work
  31713. + *        well for drivers that support multiple units, like the SLIP
  31714. + *        driver.  We should actually have only one pointer to a driver
  31715. + *        here, with the driver knowing how many units it supports.
  31716. + *        Currently, the SLIP driver abuses the "base_addr" integer
  31717. + *        field of the 'device' structure to store the unit number...
  31718. + *        -FvK
  31719. + *
  31720. + * Version:    @(#)Space.c    1.0.7    08/12/93
  31721. + *
  31722. + * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  31723. + *        Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  31724. + *        Donald J. Becker, <becker@super.org>
  31725. + *
  31726. + *        This program is free software; you can redistribute it and/or
  31727. + *        modify it under the terms of the GNU General Public License
  31728. + *        as published by the Free Software Foundation; either version
  31729. + *        2 of the License, or (at your option) any later version.
  31730. + */
  31731. +#include <linux/config.h>
  31732. +#include <linux/netdevice.h>
  31733. +#include <linux/errno.h>
  31734. +
  31735. +#define    NEXT_DEV    NULL
  31736. +
  31737. +
  31738. +/* A unified ethernet device probe.  This is the easiest way to have every
  31739. +   ethernet adaptor have the name "eth[0123...]".
  31740. +   */
  31741. +extern int ether3_probe(struct device *dev);
  31742. +
  31743. +static int
  31744. +ethif_probe(struct device *dev)
  31745. +{
  31746. +    short base_addr = dev->base_addr;
  31747. +
  31748. +    if (base_addr < 0  ||  base_addr == 1)
  31749. +    return 1;        /* ENXIO */
  31750. +
  31751. +    if (1
  31752. +#ifdef CONFIG_ETHER3
  31753. +        && ether3_probe(dev)
  31754. +#endif
  31755. +    && 1 ) {
  31756. +    return 1;    /* -ENODEV or -EAGAIN would be more accurate. */
  31757. +    }
  31758. +    return 0;
  31759. +}
  31760. +
  31761. +/* The first device defaults to I/O base '0', which means autoprobe. */
  31762. +#ifndef ETH0_ADDR
  31763. +# define ETH0_ADDR 0
  31764. +#endif
  31765. +#ifndef ETH0_IRQ
  31766. +# define ETH0_IRQ 0
  31767. +#endif
  31768. +/* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20),
  31769. +   which means "don't probe".  These entries exist to only to provide empty
  31770. +   slots which may be enabled at boot-time. */
  31771. +
  31772. +static struct device eth3_dev = {
  31773. +    "eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
  31774. +static struct device eth2_dev = {
  31775. +    "eth2", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, ð3_dev, ethif_probe };
  31776. +static struct device eth1_dev = {
  31777. +    "eth1", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, ð2_dev, ethif_probe };
  31778. +
  31779. +static struct device eth0_dev = {
  31780. +    "eth0", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, ð1_dev, ethif_probe };
  31781. +
  31782. +#   undef NEXT_DEV
  31783. +#   define NEXT_DEV    (ð0_dev)
  31784. +
  31785. +#if defined(PLIP) || defined(CONFIG_PLIP)
  31786. +    extern int plip_init(struct device *);
  31787. +    static struct device plip2_dev = {
  31788. +    "plip2", 0, 0, 0, 0, 0x278, 2, 0, 0, 0, NEXT_DEV, plip_init, };
  31789. +    static struct device plip1_dev = {
  31790. +    "plip1", 0, 0, 0, 0, 0x378, 7, 0, 0, 0, &plip2_dev, plip_init, };
  31791. +    static struct device plip0_dev = {
  31792. +    "plip0", 0, 0, 0, 0, 0x3BC, 5, 0, 0, 0, &plip1_dev, plip_init, };
  31793. +#   undef NEXT_DEV
  31794. +#   define NEXT_DEV    (&plip0_dev)
  31795. +#endif  /* PLIP */
  31796. +
  31797. +#if defined(SLIP) || defined(CONFIG_SLIP)
  31798. +    extern int slip_init(struct device *);
  31799. +    
  31800. +#ifdef SL_SLIP_LOTS
  31801. +
  31802. +    static struct device slip15_dev={"sl15",0,0,0,0,15,0,0,0,0,NEXT_DEV,slip_init};
  31803. +    static struct device slip14_dev={"sl14",0,0,0,0,14,0,0,0,0,&slip15_dev,slip_init};
  31804. +    static struct device slip13_dev={"sl13",0,0,0,0,13,0,0,0,0,&slip14_dev,slip_init};
  31805. +    static struct device slip12_dev={"sl12",0,0,0,0,12,0,0,0,0,&slip13_dev,slip_init};
  31806. +    static struct device slip11_dev={"sl11",0,0,0,0,11,0,0,0,0,&slip12_dev,slip_init};
  31807. +    static struct device slip10_dev={"sl10",0,0,0,0,10,0,0,0,0,&slip11_dev,slip_init};
  31808. +    static struct device slip9_dev={"sl9",0,0,0,0,9,0,0,0,0,&slip10_dev,slip_init};
  31809. +    static struct device slip8_dev={"sl8",0,0,0,0,8,0,0,0,0,&slip9_dev,slip_init};
  31810. +    static struct device slip7_dev={"sl7",0,0,0,0,7,0,0,0,0,&slip8_dev,slip_init};
  31811. +    static struct device slip6_dev={"sl6",0,0,0,0,6,0,0,0,0,&slip7_dev,slip_init};
  31812. +    static struct device slip5_dev={"sl5",0,0,0,0,5,0,0,0,0,&slip6_dev,slip_init};
  31813. +    static struct device slip4_dev={"sl4",0,0,0,0,4,0,0,0,0,&slip5_dev,slip_init};
  31814. +#   undef    NEXT_DEV
  31815. +#   define    NEXT_DEV    (&slip4_dev)
  31816. +#endif    /* SL_SLIP_LOTS */
  31817. +    
  31818. +    static struct device slip3_dev = {
  31819. +    "sl3",            /* Internal SLIP driver, channel 3    */
  31820. +    0x0,            /* recv memory end            */
  31821. +    0x0,            /* recv memory start            */
  31822. +    0x0,            /* memory end                */
  31823. +    0x0,            /* memory start                */
  31824. +    0x3,            /* base I/O address            */
  31825. +    0,            /* IRQ                    */
  31826. +    0, 0, 0,        /* flags                */
  31827. +    NEXT_DEV,        /* next device                */
  31828. +    slip_init        /* slip_init should set up the rest    */
  31829. +    };
  31830. +    static struct device slip2_dev = {
  31831. +    "sl2",            /* Internal SLIP driver, channel 2    */
  31832. +    0x0,            /* recv memory end            */
  31833. +    0x0,            /* recv memory start            */
  31834. +    0x0,            /* memory end                */
  31835. +    0x0,            /* memory start                */
  31836. +    0x2,            /* base I/O address            */
  31837. +    0,            /* IRQ                    */
  31838. +    0, 0, 0,        /* flags                */
  31839. +    &slip3_dev,        /* next device                */
  31840. +    slip_init        /* slip_init should set up the rest    */
  31841. +    };
  31842. +    static struct device slip1_dev = {
  31843. +    "sl1",            /* Internal SLIP driver, channel 1    */
  31844. +    0x0,            /* recv memory end            */
  31845. +    0x0,            /* recv memory start            */
  31846. +    0x0,            /* memory end                */
  31847. +    0x0,            /* memory start                */
  31848. +    0x1,            /* base I/O address            */
  31849. +    0,            /* IRQ                    */
  31850. +    0, 0, 0,        /* flags                */
  31851. +    &slip2_dev,        /* next device                */
  31852. +    slip_init        /* slip_init should set up the rest    */
  31853. +    };
  31854. +    static struct device slip0_dev = {
  31855. +    "sl0",            /* Internal SLIP driver, channel 0    */
  31856. +    0x0,            /* recv memory end            */
  31857. +    0x0,            /* recv memory start            */
  31858. +    0x0,            /* memory end                */
  31859. +    0x0,            /* memory start                */
  31860. +    0x0,            /* base I/O address            */
  31861. +    0,            /* IRQ                    */
  31862. +    0, 0, 0,        /* flags                */
  31863. +    &slip1_dev,        /* next device                */
  31864. +    slip_init        /* slip_init should set up the rest    */
  31865. +    };
  31866. +#   undef    NEXT_DEV
  31867. +#   define    NEXT_DEV    (&slip0_dev)
  31868. +#endif    /* SLIP */
  31869. +  
  31870. +#if defined(CONFIG_PPP)
  31871. +extern int ppp_init(struct device *);
  31872. +static struct device ppp3_dev = {
  31873. +    "ppp3", 0x0, 0x0, 0x0, 0x0, 3, 0, 0, 0, 0, NEXT_DEV,  ppp_init, };
  31874. +static struct device ppp2_dev = {
  31875. +    "ppp2", 0x0, 0x0, 0x0, 0x0, 2, 0, 0, 0, 0, &ppp3_dev, ppp_init, };
  31876. +static struct device ppp1_dev = {
  31877. +    "ppp1", 0x0, 0x0, 0x0, 0x0, 1, 0, 0, 0, 0, &ppp2_dev, ppp_init, };
  31878. +static struct device ppp0_dev = {
  31879. +    "ppp0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, &ppp1_dev, ppp_init, };
  31880. +#undef NEXT_DEV
  31881. +#define NEXT_DEV (&ppp0_dev)
  31882. +#endif   /* PPP */
  31883. +
  31884. +#ifdef CONFIG_DUMMY
  31885. +    extern int dummy_init(struct device *dev);
  31886. +    static struct device dummy_dev = {
  31887. +    "dummy", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, dummy_init, };
  31888. +#   undef    NEXT_DEV
  31889. +#   define    NEXT_DEV    (&dummy_dev)
  31890. +#endif
  31891. +
  31892. +extern int loopback_init(struct device *dev);
  31893. +struct device loopback_dev = {
  31894. +    "lo",            /* Software Loopback interface        */
  31895. +    0x0,            /* recv memory end            */
  31896. +    0x0,            /* recv memory start            */
  31897. +    0x0,            /* memory end                */
  31898. +    0x0,            /* memory start                */
  31899. +    0,            /* base I/O address            */
  31900. +    0,            /* IRQ                    */
  31901. +    0, 0, 0,        /* flags                */
  31902. +    NEXT_DEV,        /* next device                */
  31903. +    loopback_init        /* loopback_init should set up the rest    */
  31904. +};
  31905. +
  31906. +struct device *dev_base = &loopback_dev;
  31907. diff -r -u -N linux.orig/arch/arm/drivers/net/auto_irq.c linux.arm/arch/arm/drivers/net/auto_irq.c
  31908. --- linux.orig/arch/arm/drivers/net/auto_irq.c    Thu Jan  1 01:00:00 1970
  31909. +++ linux.arm/arch/arm/drivers/net/auto_irq.c    Fri Oct 27 23:14:59 1995
  31910. @@ -0,0 +1,122 @@
  31911. +/* auto_irq.c: Auto-configure IRQ lines for linux. */
  31912. +/*
  31913. +    Written 1994 by Donald Becker.
  31914. +
  31915. +    The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
  31916. +    Center of Excellence in Space Data and Information Sciences
  31917. +      Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
  31918. +
  31919. +    This code is a general-purpose IRQ line detector for devices with
  31920. +    jumpered IRQ lines.  If you can make the device raise an IRQ (and
  31921. +    that IRQ line isn't already being used), these routines will tell
  31922. +    you what IRQ line it's using -- perfect for those oh-so-cool boot-time
  31923. +    device probes!
  31924. +
  31925. +    To use this, first call autoirq_setup(timeout). TIMEOUT is how many
  31926. +    'jiffies' (1/100 sec.) to detect other devices that have active IRQ lines,
  31927. +    and can usually be zero at boot.  'autoirq_setup()' returns the bit
  31928. +    vector of nominally-available IRQ lines (lines may be physically in-use,
  31929. +    but not yet registered to a device).
  31930. +    Next, set up your device to trigger an interrupt.
  31931. +    Finally call autoirq_report(TIMEOUT) to find out which IRQ line was
  31932. +    most recently active.  The TIMEOUT should usually be zero, but may
  31933. +    be set to the number of jiffies to wait for a slow device to raise an IRQ.
  31934. +
  31935. +    The idea of using the setup timeout to filter out bogus IRQs came from
  31936. +    the serial driver.
  31937. +*/
  31938. +
  31939. +
  31940. +#ifdef version
  31941. +static char *version=
  31942. +"auto_irq.c:v1.11 Donald Becker (becker@cesdis.gsfc.nasa.gov)";
  31943. +#endif
  31944. +
  31945. +#include <linux/sched.h>
  31946. +#include <linux/delay.h>
  31947. +#include <asm/bitops.h>
  31948. +#include <asm/io.h>
  31949. +#include <asm/irq.h>
  31950. +#include <linux/netdevice.h>
  31951. +
  31952. +struct device *irq2dev_map[32] = {0, 0, /* ... zeroed */};
  31953. +
  31954. +int irqs_busy = 0x2147;        /* The set of fixed IRQs (keyboard, timer, etc) */
  31955. +int irqs_used = 0x0001;        /* The set of fixed IRQs sometimes enabled. */
  31956. +int irqs_reserved = 0x0000;    /* An advisory "reserved" table. */
  31957. +int irqs_shared = 0x0000;    /* IRQ lines "shared" among conforming cards.*/
  31958. +
  31959. +static volatile int irq_number;    /* The latest irq number we actually found. */
  31960. +static volatile int irq_bitmap; /* The irqs we actually found. */
  31961. +static int irq_handled;        /* The irq lines we have a handler on. */
  31962. +
  31963. +static void autoirq_probe(int irq, struct pt_regs * regs)
  31964. +{
  31965. +    irq_number = irq;
  31966. +    set_bit(irq, (void *)&irq_bitmap);    /* irq_bitmap |= 1 << irq; */
  31967. +    disable_irq(irq);
  31968. +    return;
  31969. +}
  31970. +
  31971. +int autoirq_setup(int waittime)
  31972. +{
  31973. +    int i, mask;
  31974. +    int timeout = jiffies + waittime;
  31975. +    int boguscount = (waittime*loops_per_sec) / 100;
  31976. +
  31977. +    irq_handled = 0;
  31978. +    for (i = 0; i < 16; i++) {
  31979. +        if (test_bit(i, &irqs_busy) == 0
  31980. +            && request_irq(i, autoirq_probe, SA_INTERRUPT, "irq probe") == 0)
  31981. +            set_bit(i, (void *)&irq_handled);    /* irq_handled |= 1 << i;*/
  31982. +    }
  31983. +    /* Update our USED lists. */
  31984. +    irqs_used |= ~irq_handled;
  31985. +    irq_number = 0;
  31986. +    irq_bitmap = 0;
  31987. +
  31988. +    /* Hang out at least <waittime> jiffies waiting for bogus IRQ hits. */
  31989. +    while (timeout > jiffies  &&  --boguscount > 0)
  31990. +        ;
  31991. +
  31992. +    for (i = 0, mask = 0x01; i < 16; i++, mask <<= 1) {
  31993. +        if (irq_bitmap & irq_handled & mask) {
  31994. +            irq_handled &= ~mask;
  31995. +#ifdef notdef
  31996. +            printk(" Spurious interrupt on IRQ %d\n", i);
  31997. +#endif
  31998. +            free_irq(i);
  31999. +        }
  32000. +    }
  32001. +    return irq_handled;
  32002. +}
  32003. +
  32004. +int autoirq_report(int waittime)
  32005. +{
  32006. +    int i;
  32007. +    int timeout = jiffies+waittime;
  32008. +    int boguscount = (waittime*loops_per_sec) / 100;
  32009. +
  32010. +    /* Hang out at least <waittime> jiffies waiting for the IRQ. */
  32011. +
  32012. +    while (timeout > jiffies  &&  --boguscount > 0)
  32013. +        if (irq_number)
  32014. +            break;
  32015. +
  32016. +    /* Retract the irq handlers that we installed. */
  32017. +    for (i = 0; i < 16; i++) {
  32018. +        if (test_bit(i, (void *)&irq_handled))
  32019. +            free_irq(i);
  32020. +    }
  32021. +    return irq_number;
  32022. +}
  32023. +
  32024. +/*
  32025. + * Local variables:
  32026. + *  compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c auto_irq.c"
  32027. + *  version-control: t
  32028. + *  kept-new-versions: 5
  32029. + *  c-indent-level: 4
  32030. + *  tab-width: 4
  32031. + * End:
  32032. + */
  32033. diff -r -u -N linux.orig/arch/arm/drivers/net/dummy.c linux.arm/arch/arm/drivers/net/dummy.c
  32034. --- linux.orig/arch/arm/drivers/net/dummy.c    Thu Jan  1 01:00:00 1970
  32035. +++ linux.arm/arch/arm/drivers/net/dummy.c    Fri Oct 27 23:14:59 1995
  32036. @@ -0,0 +1,175 @@
  32037. +/* dummy.c: a dummy net driver
  32038. +
  32039. +    The purpose of this driver is to provide a device to point a
  32040. +    route through, but not to actually transmit packets.
  32041. +
  32042. +    Why?  If you have a machine whose only connection is an occasional
  32043. +    PPP/SLIP/PLIP link, you can only connect to your own hostname
  32044. +    when the link is up.  Otherwise you have to use localhost.
  32045. +    This isn't very consistent.
  32046. +
  32047. +    One solution is to set up a dummy link using PPP/SLIP/PLIP,
  32048. +    but this seems (to me) too much overhead for too little gain.
  32049. +    This driver provides a small alternative. Thus you can do
  32050. +    
  32051. +    [when not running slip]
  32052. +        ifconfig dummy slip.addr.ess.here up
  32053. +    [to go to slip]
  32054. +        ifconfig dummy down
  32055. +        dip whatever
  32056. +
  32057. +    This was written by looking at Donald Becker's skeleton driver
  32058. +    and the loopback driver.  I then threw away anything that didn't
  32059. +    apply!    Thanks to Alan Cox for the key clue on what to do with
  32060. +    misguided packets.
  32061. +
  32062. +            Nick Holloway, 27th May 1994
  32063. +    [I tweaked this explanation a little but thats all]
  32064. +            Alan Cox, 30th May 1994
  32065. +*/
  32066. +
  32067. +/* To have statistics (just packets sent) define this */
  32068. +#undef DUMMY_STATS
  32069. +
  32070. +#ifdef MODULE
  32071. +#include <linux/module.h>
  32072. +#include <linux/version.h>
  32073. +#endif
  32074. +
  32075. +#include <linux/kernel.h>
  32076. +#include <linux/sched.h>
  32077. +#include <linux/types.h>
  32078. +#include <linux/fcntl.h>
  32079. +#include <linux/interrupt.h>
  32080. +#include <linux/ptrace.h>
  32081. +#include <linux/ioport.h>
  32082. +#include <linux/in.h>
  32083. +#include <linux/malloc.h>
  32084. +#include <linux/string.h>
  32085. +#include <asm/system.h>
  32086. +#include <asm/bitops.h>
  32087. +#include <asm/io.h>
  32088. +#include <asm/dma.h>
  32089. +#include <linux/errno.h>
  32090. +
  32091. +#include <linux/netdevice.h>
  32092. +#include <linux/etherdevice.h>
  32093. +#include <linux/skbuff.h>
  32094. +
  32095. +static int dummy_xmit(struct sk_buff *skb, struct device *dev);
  32096. +#ifdef DUMMY_STATS
  32097. +static struct enet_statistics *dummy_get_stats(struct device *dev);
  32098. +#endif
  32099. +
  32100. +#ifdef MODULE
  32101. +static int dummy_open(struct device *dev)
  32102. +{
  32103. +    MOD_INC_USE_COUNT;
  32104. +    return 0;
  32105. +}
  32106. +
  32107. +static int dummy_close(struct device *dev)
  32108. +{
  32109. +    MOD_DEC_USE_COUNT;
  32110. +    return 0;
  32111. +}
  32112. +
  32113. +#endif
  32114. +
  32115. +
  32116. +int dummy_init(struct device *dev)
  32117. +{
  32118. +/* I commented this out as bootup is noisy enough anyway and this driver
  32119. +   seems pretty reliable 8) 8) 8) */
  32120. +/*    printk ( KERN_INFO "Dummy net driver (94/05/27 v1.0)\n" ); */
  32121. +
  32122. +    /* Initialize the device structure. */
  32123. +    dev->hard_start_xmit    = dummy_xmit;
  32124. +
  32125. +#if DUMMY_STATS
  32126. +    dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
  32127. +    memset(dev->priv, 0, sizeof(struct enet_statistics));
  32128. +    dev->get_stats        = dummy_get_stats;
  32129. +#endif
  32130. +#ifdef MODULE
  32131. +    dev->open = &dummy_open;
  32132. +    dev->stop = &dummy_close;
  32133. +#endif
  32134. +
  32135. +    /* Fill in the fields of the device structure with ethernet-generic values. */
  32136. +    ether_setup(dev);
  32137. +    dev->flags |= IFF_NOARP;
  32138. +
  32139. +    return 0;
  32140. +}
  32141. +
  32142. +static int
  32143. +dummy_xmit(struct sk_buff *skb, struct device *dev)
  32144. +{
  32145. +#if DUMMY_STATS
  32146. +    struct enet_statistics *stats;
  32147. +#endif
  32148. +
  32149. +    if (skb == NULL || dev == NULL)
  32150. +        return 0;
  32151. +
  32152. +    dev_kfree_skb(skb, FREE_WRITE);
  32153. +
  32154. +#if DUMMY_STATS
  32155. +    stats = (struct enet_statistics *)dev->priv;
  32156. +    stats->tx_packets++;
  32157. +#endif
  32158. +
  32159. +    return 0;
  32160. +}
  32161. +
  32162. +#if DUMMY_STATS
  32163. +static struct enet_statistics *
  32164. +dummy_get_stats(struct device *dev)
  32165. +{
  32166. +    struct enet_statistics *stats = (struct enet_statistics*) dev->priv;
  32167. +    return stats;
  32168. +}
  32169. +#endif
  32170. +
  32171. +#ifdef MODULE
  32172. +char kernel_version[] = UTS_RELEASE;
  32173. +
  32174. +static int dummy_probe(struct device *dev)
  32175. +{
  32176. +    dummy_init(dev);
  32177. +    return 0;
  32178. +}
  32179. +
  32180. +static struct device dev_dummy = {
  32181. +    "dummy0\0   ", 
  32182. +        0, 0, 0, 0,
  32183. +         0x0, 0,
  32184. +         0, 0, 0, NULL, dummy_probe };
  32185. +
  32186. +int init_module(void)
  32187. +{
  32188. +    /* Find a name for this unit */
  32189. +    int ct= 1;
  32190. +    
  32191. +    while(dev_get(dev_dummy.name)!=NULL && ct<100)
  32192. +    {
  32193. +        sprintf(dev_dummy.name,"dummy%d",ct);
  32194. +        ct++;
  32195. +    }
  32196. +    
  32197. +    if (register_netdev(&dev_dummy) != 0)
  32198. +        return -EIO;
  32199. +    return 0;
  32200. +}
  32201. +
  32202. +void cleanup_module(void)
  32203. +{
  32204. +    if (MOD_IN_USE)
  32205. +        printk("dummy: device busy, remove delayed\n");
  32206. +    else
  32207. +    {
  32208. +        unregister_netdev(&dev_dummy);
  32209. +    }
  32210. +}
  32211. +#endif /* MODULE */
  32212. diff -r -u -N linux.orig/arch/arm/drivers/net/ether3.c linux.arm/arch/arm/drivers/net/ether3.c
  32213. --- linux.orig/arch/arm/drivers/net/ether3.c    Thu Jan  1 01:00:00 1970
  32214. +++ linux.arm/arch/arm/drivers/net/ether3.c    Fri Oct 27 23:15:07 1995
  32215. @@ -0,0 +1,860 @@
  32216. +/*
  32217. + * linux/drivers/net/ether3.c
  32218. + *
  32219. + * SEEQ nq8005 ethernet driver
  32220. + *
  32221. + */
  32222. +
  32223. +#ifdef MODULE
  32224. +#include <linux/module.h>
  32225. +#include <linux/version.h>
  32226. +#define CLAIM_IRQ_AT_OPEN
  32227. +#else
  32228. +#define MOD_INC_USE_COUNT
  32229. +#define MOD_DEC_USE_COUNT
  32230. +#endif
  32231. +
  32232. +#include <linux/config.h>
  32233. +#include <linux/kernel.h>
  32234. +#include <linux/sched.h>
  32235. +#include <linux/types.h>
  32236. +#include <linux/fcntl.h>
  32237. +#include <linux/interrupt.h>
  32238. +#include <linux/ptrace.h>
  32239. +#include <linux/ioport.h>
  32240. +#include <linux/in.h>
  32241. +#include <linux/malloc.h>
  32242. +#include <linux/string.h>
  32243. +#include <asm/system.h>
  32244. +#include <asm/bitops.h>
  32245. +#include <asm/io.h>
  32246. +#include <asm/dma.h>
  32247. +#include <linux/errno.h>
  32248. +
  32249. +#include <linux/netdevice.h>
  32250. +#include <linux/etherdevice.h>
  32251. +#include <linux/skbuff.h>
  32252. +
  32253. +#include <asm/ecard.h>
  32254. +
  32255. +#include "ether3.h"
  32256. +
  32257. +#define FUNC_PROLOGUE \
  32258. +    struct arc_net *an = (struct arc_net *)dev->priv
  32259. +
  32260. +static unsigned int net_debug = NET_DEBUG;
  32261. +
  32262. +#define tx_done(dev) 0
  32263. +/* ------------------------------------------------------------------------------- */
  32264. +static char *version = "ether3 ethernet driver (c) 1995 R.M.King V1.00\n";
  32265. +
  32266. +#define BUS_16 16
  32267. +#define BUS_8  8
  32268. +
  32269. +extern int inswb(int reg, void *buffer, int len);
  32270. +extern int outswb(int reg, void *buffer, int len);
  32271. +
  32272. +unsigned char def_eth_addr[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
  32273. +
  32274. +static int ether3_prods[] = { 0x00A4 };
  32275. +static int ether3_manus[] = { 0x0011 };
  32276. +
  32277. +/* --------------------------------------------------------------------------- */
  32278. +
  32279. +static void check_dev(struct device *dev, char *s)
  32280. +{
  32281. +    struct device *dev2;
  32282. +
  32283. +    dev2 = dev->next;
  32284. +    
  32285. +    while (dev2 && dev2 != dev)
  32286. +        dev2 = dev2->next;
  32287. +
  32288. +    if (dev2 == dev)
  32289. +        printk("eek! - %s\n", s);
  32290. +}
  32291. +
  32292. +/*
  32293. + * set one of the receive address registers in the chip
  32294. + */
  32295. +
  32296. +static void
  32297. +ether3_setrxaddr(struct device *dev, int address, unsigned char *addr)
  32298. +{
  32299. +    FUNC_PROLOGUE;
  32300. +    unsigned long flags;
  32301. +    int stat, i;
  32302. +
  32303. +    save_flags(flags);
  32304. +    cli();
  32305. +
  32306. +    stat = inw(REG_STATUS);
  32307. +    if(stat & STAT_RXON)
  32308. +        outw(an->regs.command | CMD_RXOFF, REG_COMMAND);
  32309. +
  32310. +    outw(an->regs.config1 | address, REG_CONFIG1);
  32311. +    for(i=0; i<6; i++)
  32312. +        outb(addr[i], REG_BUFWIN);
  32313. +
  32314. +    if(stat & STAT_RXON)
  32315. +        outw(an->regs.command | CMD_RXON, REG_COMMAND);
  32316. +
  32317. +    restore_flags(flags);
  32318. +}
  32319. +
  32320. +/*
  32321. + * write data to the buffer memory
  32322. + */
  32323. +
  32324. +static void
  32325. +ether3_writebuffer(struct device *dev, void *data, int start, int length)
  32326. +{
  32327. +    FUNC_PROLOGUE;
  32328. +    int timeout = 1000000;
  32329. +    if(start != -1)
  32330. +    {
  32331. +        outw(an->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  32332. +        outw(an->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  32333. +        while((inw(REG_STATUS) & STAT_FIFOEMPTY) == 0)
  32334. +            if(!timeout--)
  32335. +            {
  32336. +                printk("settxlim_16 broken\n");
  32337. +                an->broken = 1;
  32338. +                return;
  32339. +            }
  32340. +        outw(an->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  32341. +        outw(start, REG_DMAADDR);
  32342. +    }
  32343. +    if(length != 0)
  32344. +        outswb(REG_BUFWIN, data, length);
  32345. +}
  32346. +
  32347. +/*
  32348. + * read data from the buffer memory
  32349. + */
  32350. +
  32351. +static void
  32352. +ether3_readbuffer(struct device *dev, void *data, int start, int length)
  32353. +{
  32354. +    FUNC_PROLOGUE;
  32355. +    int timeout = 1000000;
  32356. +    if(start != -1)
  32357. +    {
  32358. +        outw(an->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  32359. +        outw(an->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  32360. +        while((inw(REG_STATUS) & STAT_FIFOEMPTY) == 0)
  32361. +            if(!timeout--)
  32362. +            {
  32363. +                printk("setrxlim_16 broken\n");
  32364. +                an->broken = 1;
  32365. +                return;
  32366. +            }
  32367. +        outw(start, REG_DMAADDR);
  32368. +        outw(an->regs.command | CMD_FIFOREAD, REG_COMMAND);
  32369. +    }
  32370. +    if(length != 0)
  32371. +        inswb(REG_BUFWIN, data, length);
  32372. +}
  32373. +
  32374. +/* --------------------------------------------------------------------------- */
  32375. +
  32376. +static int
  32377. +ether3_ramtest(struct device *dev, unsigned char byte)
  32378. +{
  32379. +    unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL);
  32380. +    unsigned long flags;
  32381. +    int i,ret=0;
  32382. +    int max_errors = 4;
  32383. +    int bad=-1;
  32384. +
  32385. +    if(!buffer)
  32386. +        return 1;
  32387. +
  32388. +    save_flags(flags);
  32389. +    cli();
  32390. +
  32391. +    memset(buffer, byte, RX_END);
  32392. +    ether3_writebuffer(dev, buffer, 0, TX_END);
  32393. +    ether3_writebuffer(dev, buffer+RX_START, RX_START, RX_LEN);
  32394. +
  32395. +    memset(buffer, byte ^ 0xff, RX_END);
  32396. +    ether3_readbuffer(dev, buffer, 0, TX_END);
  32397. +    ether3_readbuffer(dev, buffer+RX_START, RX_START, RX_LEN);
  32398. +
  32399. +    for(i=0; i<RX_END; i++)
  32400. +    {
  32401. +        if(buffer[i] != byte)
  32402. +        {
  32403. +            if(max_errors>=0 && bad!=buffer[i])
  32404. +            {
  32405. +                printk("%s: RAM failed with (%02X instead of %02X) at 0x%04X",
  32406. +                    dev->name, buffer[i], byte, i);
  32407. +                ret = 2;
  32408. +                max_errors--;
  32409. +                bad=buffer[i];
  32410. +            }
  32411. +        }
  32412. +        else
  32413. +        {
  32414. +            if(bad != -1)
  32415. +            {
  32416. +                printk(" - 0x%04X\n", i);
  32417. +                bad = -1;
  32418. +            }
  32419. +        }
  32420. +    }
  32421. +    if(bad != -1)
  32422. +        printk(" - 0x10000\n");
  32423. +    kfree(buffer);
  32424. +    restore_flags(flags);
  32425. +
  32426. +    return ret;
  32427. +}
  32428. +
  32429. +/* ------------------------------------------------------------------------------- */
  32430. +
  32431. +static int
  32432. +ether3_init_1(struct device *dev)
  32433. +{
  32434. +    outb(0x80, REG_CONFIG2);
  32435. +    outb(0, REG_COMMAND);
  32436. +
  32437. +    outb(1, REG_CONFIG1);
  32438. +    if(inb(REG_CONFIG1+1)==1 && inb(REG_CONFIG1)==0)
  32439. +        return BUS_8;
  32440. +    if(inw(REG_CONFIG1)==0x101)
  32441. +        return BUS_16;
  32442. +    return 0;
  32443. +}
  32444. +
  32445. +static int
  32446. +ether3_init_2(struct device *dev)
  32447. +{
  32448. +    FUNC_PROLOGUE;
  32449. +    unsigned long a=0;
  32450. +    int i;
  32451. +
  32452. +    ether3_setrxaddr(dev, CFG1_BUFSELSTAT0, dev->dev_addr);
  32453. +
  32454. +    an->regs.config1 = CFG1_RECVSPECBROAD|CFG1_RECVCOMPSTAT0|CFG1_DMABURST8;
  32455. +    an->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC;
  32456. +
  32457. +    outw(an->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
  32458. +    outw((TX_END>>8) - 1, REG_BUFWIN);
  32459. +    outw(an->regs.recvptr    , REG_RECVPTR);
  32460. +    outw(an->regs.transmitptr    , REG_TRANSMITPTR);
  32461. +    outw(an->regs.recvptr >> 8, REG_RECVEND);
  32462. +    outw(an->regs.config2    , REG_CONFIG2);
  32463. +    outw(an->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  32464. +    ether3_writebuffer(dev, &a, an->regs.transmitptr, 4);
  32465. +    outw(an->regs.command    , REG_COMMAND);
  32466. +
  32467. +    i = ether3_ramtest(dev, 0x5A);
  32468. +    if(i)
  32469. +        return i;
  32470. +    return ether3_ramtest(dev, 0x1E);
  32471. +}
  32472. +
  32473. +/* This is the real probe routine. */
  32474. +
  32475. +static int
  32476. +ether3_probe1(struct device *dev)
  32477. +{
  32478. +    static unsigned version_printed = 0;
  32479. +    struct arc_net *an;
  32480. +    int i;
  32481. +
  32482. +    if(!dev->priv)
  32483. +        dev->priv = kmalloc(sizeof(struct arc_net), GFP_KERNEL);
  32484. +
  32485. +    if(!dev->priv)
  32486. +        return 1;
  32487. +
  32488. +    an = (struct arc_net *) dev->priv;
  32489. +    memset(an, 0, sizeof(struct arc_net));
  32490. +    an->bus_type    = BUS_16;
  32491. +    an->broken    = 0;
  32492. +
  32493. +    if((an->bus_type=ether3_init_1(dev))==0)
  32494. +    {
  32495. +        kfree(dev->priv);
  32496. +        return 1;
  32497. +    }
  32498. +
  32499. +    if (net_debug  &&  version_printed++ == 0)
  32500. +        printk(version);
  32501. +
  32502. +    printk("%s: ether3 found (bus width %d), ", dev->name, an->bus_type);
  32503. +
  32504. +    /* Retrive and print the ethernet address. */
  32505. +    for (i = 0; i < 6; i++)
  32506. +        printk(i==0?" %2.2x":i==5?":%2.2x\n":":%2.2x", dev->dev_addr[i]);
  32507. +
  32508. +    if(ether3_init_2(dev))
  32509. +    {
  32510. +        kfree(dev->priv);
  32511. +        return 1;
  32512. +    }
  32513. +
  32514. +    dev->open        = ether3_open;
  32515. +    dev->stop        = ether3_close;
  32516. +    dev->hard_start_xmit    = ether3_send_packet;
  32517. +    dev->get_stats            = ether3_get_stats;
  32518. +    dev->set_multicast_list = set_multicast_list;
  32519. +
  32520. +    /* Fill in the fields of the device structure with ethernet values. */
  32521. +    ether_setup(dev);
  32522. +#ifndef CLAIM_IRQ_AT_OPEN
  32523. +    if (request_irq(dev->irq, ether3_interrupt, 0, "ether3")) {
  32524. +        kfree(dev->priv);
  32525. +        return -EAGAIN;
  32526. +    }
  32527. +
  32528. +    irq2dev_map[dev->irq] = dev;
  32529. +#endif
  32530. +    return 0;
  32531. +}
  32532. +
  32533. +/* --------------------------------------------------------------------------- */
  32534. +
  32535. +static void
  32536. +ether3_addr(char *addr, struct expansion_card *ec)
  32537. +{
  32538. +    struct chunk_dir cd;
  32539. +    char *s;
  32540. +    
  32541. +    if(ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '(')))
  32542. +    {
  32543. +        int i;
  32544. +        for (i = 0; i<6; i++)
  32545. +        {
  32546. +            addr[i] = simple_strtoul(s + 1, &s, 0x10);
  32547. +            if(*s != (i==5?')' : ':' ))
  32548. +                break;
  32549. +        }
  32550. +        if(i == 6)
  32551. +            return;
  32552. +    }
  32553. +    memcpy(addr, def_eth_addr, 6);
  32554. +}
  32555. +int
  32556. +ether3_probe(struct device *dev)
  32557. +{
  32558. +#ifndef MODULE
  32559. +    struct expansion_card *ec;
  32560. +    unsigned char *eth_addr;
  32561. +    int base_addr;
  32562. +
  32563. +    if(!dev)
  32564. +        return ENODEV;
  32565. +
  32566. +    if((ec = ecard_find(0, sizeof(ether3_prods), ether3_prods, ether3_manus)) == NULL)
  32567. +        return ENODEV;
  32568. +
  32569. +    dev->base_addr    = ((unsigned long)ec->r_podaddr & ~0x003c0000UL) >> 2;
  32570. +    dev->irq    = ec->irq;
  32571. +
  32572. +    ecard_claim (ec);
  32573. +
  32574. +    ether3_addr(dev->dev_addr, ec);
  32575. +#endif
  32576. +    if(ether3_probe1(dev) == 0)
  32577. +        return 0;
  32578. +    return ENODEV;
  32579. +}
  32580. +
  32581. +/* ------------------------------------------------------------------------ */
  32582. +
  32583. +static void
  32584. +ether3_init_for_open(struct device *dev)
  32585. +{
  32586. +    FUNC_PROLOGUE;
  32587. +    unsigned long a=0;
  32588. +
  32589. +    an->regs.command = 0;
  32590. +    outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
  32591. +    while(inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
  32592. +
  32593. +    ether3_setrxaddr(dev, CFG1_BUFSELSTAT0, dev->dev_addr);
  32594. +    an->regs.transmitptr = 0;    /* address that transmitter has processed to */
  32595. +    an->txinsert = 0;        /* address of next available packet for tx */
  32596. +    an->txed = 0;            /* transmitted length index */
  32597. +    an->txto = 0;            /* to transmit length index */
  32598. +    an->tx_ends[0] = 0;
  32599. +    an->use = 0;
  32600. +
  32601. +    an->regs.config2 |= CFG2_CTRLO;
  32602. +
  32603. +    outw(an->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
  32604. +    outw((TX_END>>8) - 1, REG_BUFWIN);
  32605. +
  32606. +    an->regs.recvptr    = RX_START;
  32607. +    outw(an->regs.recvptr    , REG_RECVPTR);
  32608. +    outw(an->regs.recvptr>>8, REG_RECVEND);
  32609. +
  32610. +    outw(0, REG_TRANSMITPTR);
  32611. +    outw(an->regs.config2 , REG_CONFIG2);
  32612. +    outw(an->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  32613. +
  32614. +    ether3_writebuffer(dev, &a, an->regs.transmitptr, 4);
  32615. +
  32616. +
  32617. +    an->regs.command = CMD_ENINTRX|CMD_ENINTTX;
  32618. +    outw(an->regs.command | CMD_RXON, REG_COMMAND);
  32619. +}
  32620. +
  32621. +/* Open/initialize the board.  This is called (in the current kernel)
  32622. +   sometime after booting when the 'ifconfig' program is run.
  32623. +
  32624. +   This routine should set everything up anew at each open, even
  32625. +   registers that "should" only need to be set once at boot, so that
  32626. +   there is non-reboot way to recover if something goes wrong.
  32627. +   */
  32628. +static int
  32629. +ether3_open(struct device *dev)
  32630. +{
  32631. +    ether3_init_for_open(dev);
  32632. +
  32633. +#ifdef CLAIM_IRQ_AT_OPEN
  32634. +    if (request_irq(dev->irq, ether3_interrupt, 0, "ether3")) {
  32635. +        kfree(dev->priv);
  32636. +        return -EAGAIN;
  32637. +    }
  32638. +
  32639. +    irq2dev_map[dev->irq] = dev;
  32640. +#endif
  32641. +
  32642. +    MOD_INC_USE_COUNT;
  32643. +
  32644. +    dev->tbusy = 0;
  32645. +    dev->interrupt = 0;
  32646. +    dev->start = 1;
  32647. +    return 0;
  32648. +}
  32649. +
  32650. +static int
  32651. +ether3_send_packet(struct sk_buff *skb, struct device *dev)
  32652. +{
  32653. +    FUNC_PROLOGUE;
  32654. +
  32655. +    if (dev->tbusy) {
  32656. +        /* If we get here, some higher level has decided we are broken.
  32657. +           There should really be a "kick me" function call instead. */
  32658. +        int tickssofar = jiffies - dev->trans_start;
  32659. +        if (tickssofar < 5)
  32660. +            return 1;
  32661. +        printk("%s: transmit timed out, %s?\n", dev->name,
  32662. +               tx_done(dev) ? "IRQ conflict" : "network cable problem");
  32663. +        /* Try to restart the adaptor. */
  32664. +        dev->tbusy = 0;
  32665. +        an->use = 0;
  32666. +        an->regs.config2 |= CFG2_CTRLO;
  32667. +        outw(an->regs.config2 , REG_CONFIG2);
  32668. +        dev->trans_start = jiffies;
  32669. +    }
  32670. +
  32671. +    /* If some higher layer thinks we've missed an tx-done interrupt
  32672. +       we are passed NULL. Caution: dev_tint() handles the cli()/sti()
  32673. +       itself. */
  32674. +    if (skb == NULL) {
  32675. +        dev_tint(dev);
  32676. +        return 0;
  32677. +    }
  32678. +
  32679. +    /* Block a timer-based transmit from overlapping.  This could better be
  32680. +       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
  32681. +    if (set_bit(0, (void*)&dev->tbusy) != 0)
  32682. +        printk("%s: Transmitter access conflict.\n", dev->name);
  32683. +    else {
  32684. +        short length = ETH_ZLEN < (skb->len-2) ? (skb->len-2) : ETH_ZLEN;
  32685. +        unsigned char *buf = skb->data;
  32686. +        unsigned long flags;
  32687. +        unsigned long thisinfo, nextinfo=0;
  32688. +        int thisdata, thisstart, nextpacket;
  32689. +
  32690. +        if(an->broken)
  32691. +        {
  32692. +          dev_kfree_skb(skb, FREE_WRITE);
  32693. +          an->stats.tx_dropped ++;
  32694. +          return 1;
  32695. +        }
  32696. +
  32697. +        thisstart = an->txinsert;
  32698. +        thisdata = thisstart + 4;
  32699. +        if(thisdata >= TX_END)
  32700. +            thisdata -= TX_END;
  32701. +        nextpacket = thisdata + length;
  32702. +        if(nextpacket >= TX_END)
  32703. +            nextpacket -= TX_END;
  32704. +        an->txinsert = nextpacket;
  32705. +        an->tx_ends[an->txto++] = nextpacket;
  32706. +        if(an->txto >= MAX_TXED)
  32707. +          an->txto = 0;
  32708. +
  32709. +        thisinfo = 0x00E80000 | ((nextpacket >> 8) & 0xff) | ((nextpacket << 8) & 0xff00);
  32710. +
  32711. +        save_flags(flags);
  32712. +        cli();
  32713. +        an->use++;
  32714. +        an->regs.config2 &= ~CFG2_CTRLO;
  32715. +        outw(an->regs.config2 , REG_CONFIG2);
  32716. +
  32717. +        ether3_writebuffer(dev, buf + 2, thisdata, length&1?(length+1):length);
  32718. +        ether3_writebuffer(dev, &nextinfo, -1, 4);
  32719. +        ether3_writebuffer(dev, &thisinfo, thisstart, 4);
  32720. +        restore_flags(flags);
  32721. +
  32722. +        if((inw(REG_STATUS) & STAT_TXON)==0) {
  32723. +          outw(thisstart, REG_TRANSMITPTR);
  32724. +          outw(an->regs.command | CMD_TXON, REG_COMMAND);
  32725. +        }
  32726. +        dev->trans_start = jiffies;
  32727. +    }
  32728. +    dev_kfree_skb (skb, FREE_WRITE);
  32729. +
  32730. +    /* You might need to clean up and record Tx statistics here. */
  32731. +
  32732. +    return 0;
  32733. +}
  32734. +
  32735. +/* The typical workload of the driver:
  32736. +   Handle the network interface interrupts. */
  32737. +static void
  32738. +ether3_interrupt(int irq, struct pt_regs *regs)
  32739. +{
  32740. +    struct device *dev = (struct device *)(irq2dev_map[irq]);
  32741. +    struct arc_net *an = (struct arc_net *)dev->priv;
  32742. +    int status, boguscount = 0, done = 0;
  32743. +#if NET_DEBUG > 1
  32744. +    if(net_debug & DEBUG_INT)
  32745. +             printk("ether3_interrupt: irq %d\n", irq);
  32746. +#endif
  32747. +
  32748. +    if (dev == NULL) {
  32749. +        printk ("ether3_interrupt(): irq %d for unknown device.\n", irq);
  32750. +        return;
  32751. +    }
  32752. +    dev->interrupt = 1;
  32753. +
  32754. +    do {
  32755. +        status = inw(REG_STATUS);
  32756. +        if (status & STAT_INTRX) {
  32757. +            /* Got a packet(s). */
  32758. +            ether3_rx(dev);
  32759. +            done = 1;
  32760. +        }
  32761. +        if (status & STAT_INTTX) {
  32762. +            ether3_tx(dev);
  32763. +            done = 1;
  32764. +        }
  32765. +        outw((status & (STAT_INTRX|STAT_INTTX|STAT_INTBUFWIN))
  32766. +          | an->regs.command, REG_COMMAND);
  32767. +    } while (++boguscount < 20 && !done) ;
  32768. +
  32769. +    dev->interrupt = 0;
  32770. +
  32771. +#if NET_DEBUG > 1
  32772. +    if(net_debug & DEBUG_INT)
  32773. +             printk("ether3_interrupt: done\n", irq);
  32774. +#endif
  32775. +}
  32776. +
  32777. +/* We have a good packet(s), get it/them out of the buffers. */
  32778. +static void
  32779. +ether3_rx(struct device *dev)
  32780. +{
  32781. +    FUNC_PROLOGUE;
  32782. +    struct sk_buff *skb=NULL;
  32783. +    unsigned int end;
  32784. +    unsigned int length;
  32785. +
  32786. +    an->use++;
  32787. +    if(an->use == 1)
  32788. +    {
  32789. +        an->regs.config2 &= ~CFG2_CTRLO;
  32790. +        outw(an->regs.config2 , REG_CONFIG2);
  32791. +    }
  32792. +    do {
  32793. +        unsigned char buffer[20];
  32794. +        ether3_readbuffer(dev, buffer, an->regs.recvptr, 20);
  32795. +
  32796. +        if(buffer[0] == 0 || (buffer[3] & 0x80)==0)
  32797. +            goto rx_fin;
  32798. +#if NET_DEBUG > 1
  32799. +        if(net_debug & DEBUG_RX) {
  32800. +        {
  32801. +            int i;
  32802. +            printk("ether3_rx:", an->regs.recvptr);
  32803. +            for(i=3; i<18; i++)
  32804. +                printk("%02X ",(unsigned int)buffer[i]);
  32805. +            printk("\n");
  32806. +        }
  32807. +#endif
  32808. +
  32809. +        end = (buffer[0]<<8) | buffer[1];
  32810. +
  32811. +        if((buffer[2] & 0xC0) != 0x40)
  32812. +          /* no data follows */
  32813. +          goto done;
  32814. +
  32815. +        if(buffer[3] & 15) {
  32816. +            an->stats.rx_errors++;
  32817. +            if(buffer[3] & 1) an->stats.rx_fifo_errors ++;
  32818. +            if(buffer[3] & 2) an->stats.rx_crc_errors ++;
  32819. +            if(buffer[3] & 4) an->stats.rx_fifo_errors ++;
  32820. +            if(buffer[3] & 8) an->stats.rx_length_errors ++;
  32821. +            goto done;
  32822. +        }
  32823. +
  32824. +        if(end > an->regs.recvptr)
  32825. +            length = end - an->regs.recvptr;
  32826. +        else
  32827. +            length = (end - RX_START) + (RX_END - an->regs.recvptr);
  32828. +
  32829. +        skb = alloc_skb(length + 4, GFP_ATOMIC);
  32830. +        if(skb == NULL) {
  32831. +            printk("%s: memory squeeze, dropping packet.\n", dev->name);
  32832. +            an->stats.rx_dropped++;
  32833. +            an->regs.recvptr = end;
  32834. +            outw(an->regs.recvptr >> 8, REG_RECVEND);
  32835. +            goto rx_fin;
  32836. +        }
  32837. +
  32838. +        skb->len = length - 4;
  32839. +        skb->dev = dev;
  32840. +        memcpy(skb->data + 2, buffer + 4, 20-4);
  32841. +        ether3_readbuffer(dev, skb->data+18, -1, length-20);
  32842. +    done:
  32843. +        an->regs.recvptr = end;
  32844. +        outw(an->regs.recvptr >> 8, REG_RECVEND);
  32845. +        if(skb) {
  32846. +            netif_rx(skb);
  32847. +            skb=NULL;
  32848. +            an->stats.rx_packets++;
  32849. +        }
  32850. +    }
  32851. +    while(inw(REG_STATUS) & STAT_RXON);
  32852. +
  32853. +    outw(an->regs.recvptr, REG_RECVPTR);
  32854. +    outw(an->regs.command | CMD_RXON, REG_COMMAND);
  32855. +
  32856. +    /* If any worth-while packets have been received, dev_rint()
  32857. +       has done a mark_bh(NET_BH) for us and will work on them
  32858. +       when we get to the bottom-half routine. */
  32859. +rx_fin:
  32860. +    if(an->use)
  32861. +    {
  32862. +        an->use--;
  32863. +        if(an->use == 0)
  32864. +        {
  32865. +            an->regs.config2 |= CFG2_CTRLO;
  32866. +            outw(an->regs.config2 , REG_CONFIG2);
  32867. +        }
  32868. +    }
  32869. +}
  32870. +
  32871. +/* ----------------------------------------------------------------------------- */
  32872. +
  32873. +static void
  32874. +ether3_tx(struct device *dev)
  32875. +{
  32876. +    FUNC_PROLOGUE;
  32877. +    unsigned char buffer[4];
  32878. +
  32879. +    if(an->regs.transmitptr + 4 > TX_END) {
  32880. +        int len = TX_END - an->regs.transmitptr;
  32881. +        ether3_readbuffer(dev, buffer, an->regs.transmitptr, len);
  32882. +        ether3_readbuffer(dev, buffer+len, 0, 4 - len);
  32883. +    }
  32884. +    else
  32885. +        ether3_readbuffer(dev, buffer, an->regs.transmitptr, 4);
  32886. +
  32887. +    if(!(buffer[3] & 0x80))
  32888. +        return;
  32889. +
  32890. +    if(buffer[3] & 7) {
  32891. +        if(buffer[3] & 5) an->stats.tx_errors ++;
  32892. +        if(buffer[3] & 4) an->stats.collisions += 16;
  32893. +        if(buffer[3] & 2) an->stats.collisions += (buffer[3] & 0x78)>>3;
  32894. +        if(buffer[3] & 1) an->stats.tx_fifo_errors ++;
  32895. +    }
  32896. +    if(!(buffer[3] & 5))
  32897. +        an->stats.tx_packets++;
  32898. +
  32899. +    an->regs.transmitptr = an->tx_ends[an->txed++];
  32900. +    if(an->txed >= MAX_TXED)
  32901. +        an->txed = 0;
  32902. +    if(an->regs.transmitptr >= TX_END)
  32903. +        an->regs.transmitptr -= TX_END;
  32904. +/* if(an->regs.transmitptr != ((buffer[0]<<8)|buffer[1])) */
  32905. +/* printk("%p:%p\n",an->regs.transmitptr, (buffer[2]<<24)|(buffer[3]<<16)|(buffer[0]<<8)|buffer[1]); */
  32906. +    dev->tbusy = 0;
  32907. +    mark_bh(NET_BH);    /* Inform upper layers. */
  32908. +    if(an->use)
  32909. +    {
  32910. +        an->use--;
  32911. +        if(an->use == 0)
  32912. +        {
  32913. +            an->regs.config2 |= CFG2_CTRLO;
  32914. +            outw(an->regs.config2 , REG_CONFIG2);
  32915. +        }
  32916. +    }
  32917. +}
  32918. +
  32919. +/* The inverse routine to net_open(). */
  32920. +static int
  32921. +ether3_close(struct device *dev)
  32922. +{
  32923. +    FUNC_PROLOGUE;
  32924. +    unsigned long flags;
  32925. +
  32926. +    dev->tbusy = 1;
  32927. +    dev->start = 0;
  32928. +
  32929. +    save_flags(flags);
  32930. +    cli();
  32931. +
  32932. +    outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
  32933. +    an->regs.command = 0;
  32934. +    while(inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
  32935. +    ether3_init_1(dev);
  32936. +
  32937. +    restore_flags(flags);
  32938. +
  32939. +    /* Flush the Tx */
  32940. +#ifdef CLAIM_IRQ_AT_OPEN
  32941. +    free_irq(dev->irq);
  32942. +
  32943. +    irq2dev_map[dev->irq] = NULL;
  32944. +#endif
  32945. +
  32946. +    MOD_DEC_USE_COUNT;
  32947. +
  32948. +    return 0;
  32949. +
  32950. +}
  32951. +
  32952. +/* Get the current statistics.    This may be called with the card open or
  32953. +   closed. */
  32954. +static struct enet_statistics *
  32955. +ether3_get_stats(struct device *dev)
  32956. +{
  32957. +    FUNC_PROLOGUE;
  32958. +    return &an->stats;
  32959. +}
  32960. +
  32961. +/* Set or clear the multicast filter for this adaptor.
  32962. +   num_addrs == -1    Promiscuous mode, receive all packets
  32963. +   num_addrs == 0    Normal mode, clear multicast list
  32964. +   num_addrs > 0    Multicast mode, receive normal and MC packets, and do
  32965. +            best-effort filtering.
  32966. + */
  32967. +static void
  32968. +set_multicast_list(struct device *dev, int num_addrs, void *addrs)
  32969. +{
  32970. +    FUNC_PROLOGUE;
  32971. +
  32972. +    if(num_addrs == -1)
  32973. +        an->regs.config1 |= CFG1_RECVPROMISC;
  32974. +    else
  32975. +        an->regs.config1 = (an->regs.config1 & ~CFG1_RECVPROMISC)
  32976. +                    | CFG1_RECVSPECBROAD;
  32977. +
  32978. +    outw(an->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  32979. +}
  32980. +
  32981. +#ifdef MODULE
  32982. +char kernel_version[] = UTS_RELEASE;
  32983. +static struct device ether3 = {
  32984. +    "        ",
  32985. +    0, 0, 0, 0,
  32986. +    0, 0,
  32987. +    0, 0, 0, NULL, ether3_probe
  32988. +};
  32989. +
  32990. +char *ethernames[4] = {
  32991. +    "        ",
  32992. +    "        ",
  32993. +    "        ",
  32994. +    "        "
  32995. +};
  32996. +static struct device *my_ethers[4];
  32997. +static struct expansion_card *ec[4];
  32998. +
  32999. +int
  33000. +init_module(void)
  33001. +{
  33002. +    int i;
  33003. +
  33004. +    for(i = 0; i < 4; i++)
  33005. +    {
  33006. +        my_ethers[i] = NULL;
  33007. +        ec[i] = NULL;
  33008. +    }
  33009. +
  33010. +    i = 0;
  33011. +
  33012. +    do
  33013. +    {
  33014. +        if ((ec[i] = ecard_find(0, sizeof(ether3_prods), ether3_prods, ether3_manus)) == NULL)
  33015. +            break;
  33016. +
  33017. +        my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL);
  33018. +        memset(my_ethers[i], 0, sizeof(struct device));
  33019. +
  33020. +        my_ethers[i]->irq = ec[i]->irq;
  33021. +        my_ethers[i]->base_addr= ((unsigned long)ec[i]->r_podaddr & ~0x003c0000UL)>>2;
  33022. +        my_ethers[i]->init = ether3_probe;
  33023. +        my_ethers[i]->name = ethernames[i];
  33024. +
  33025. +        ether3_addr(my_ethers[i]->dev_addr, ec[i]);
  33026. +
  33027. +        ecard_claim(ec[i]);
  33028. +
  33029. +        if(register_netdev(my_ethers[i]) != 0)
  33030. +        {
  33031. +            for (i = 0; i < 4; i++)
  33032. +            {
  33033. +                if(my_ethers[i])
  33034. +                {
  33035. +                    kfree(my_ethers[i]);
  33036. +                    my_ethers[i] = NULL;
  33037. +                }
  33038. +                if(ec[i])
  33039. +                {
  33040. +                    ecard_release(ec[i]);
  33041. +                    ec[i] = NULL;
  33042. +                }
  33043. +            }
  33044. +            return -EIO;
  33045. +        }
  33046. +        i++;
  33047. +    }
  33048. +    while(i < 4);
  33049. +
  33050. +    return i != 0 ? 0 : -ENODEV;
  33051. +}
  33052. +
  33053. +void
  33054. +cleanup_module(void)
  33055. +{
  33056. +    if (MOD_IN_USE) {
  33057. +        printk("%s: device busy, remove delayed\n", ether3.name);
  33058. +    } else {
  33059. +        int i;
  33060. +        for(i = 0; i < 4; i++)
  33061. +        {
  33062. +            if(my_ethers[i])
  33063. +            {
  33064. +                unregister_netdev(my_ethers[i]);
  33065. +                my_ethers[i] = NULL;
  33066. +            }
  33067. +            if(ec[i])
  33068. +            {
  33069. +                ecard_release(ec[i]);
  33070. +                ec[i] = NULL;
  33071. +            }
  33072. +        }
  33073. +    }
  33074. +}
  33075. +#endif /* MODULE */
  33076. diff -r -u -N linux.orig/arch/arm/drivers/net/ether3.h linux.arm/arch/arm/drivers/net/ether3.h
  33077. --- linux.orig/arch/arm/drivers/net/ether3.h    Thu Jan  1 01:00:00 1970
  33078. +++ linux.arm/arch/arm/drivers/net/ether3.h    Fri Oct 27 23:15:07 1995
  33079. @@ -0,0 +1,153 @@
  33080. +/*
  33081. + * linux/drivers/net/ether3.h
  33082. + *
  33083. + * network driver for Acorn Ether3 cards
  33084. + */
  33085. +
  33086. +#ifndef _LINUX_ether3_H
  33087. +#define _LINUX_ether3_H
  33088. +
  33089. +/* use 0 for production, 1 for verification, >2 for debug. debug flags: */
  33090. +#define DEBUG_TX     2
  33091. +#define DEBUG_RX     4
  33092. +#define DEBUG_INT     8
  33093. +#define DEBUG_IC    16
  33094. +#ifndef NET_DEBUG
  33095. +#define NET_DEBUG 1
  33096. +#endif
  33097. +
  33098. +/* Command register definitions & bits */
  33099. +#define REG_COMMAND        (dev->base_addr + 0x00)
  33100. +#define CMD_ENINTDMA        0x0001
  33101. +#define CMD_ENINTRX        0x0002
  33102. +#define CMD_ENINTTX        0x0004
  33103. +#define CMD_ENINTBUFWIN        0x0008
  33104. +#define CMD_ACKINTDMA        0x0010
  33105. +#define CMD_ACKINTRX        0x0020
  33106. +#define CMD_ACKINTTX        0x0040
  33107. +#define CMD_ACKINTBUFWIN    0x0080
  33108. +#define CMD_DMAON        0x0100
  33109. +#define CMD_RXON        0x0200
  33110. +#define CMD_TXON        0x0400
  33111. +#define CMD_DMAOFF        0x0800
  33112. +#define CMD_RXOFF        0x1000
  33113. +#define CMD_TXOFF        0x2000
  33114. +#define CMD_FIFOREAD        0x4000
  33115. +#define CMD_FIFOWRITE        0x8000
  33116. +
  33117. +/* status register */
  33118. +#define REG_STATUS        (dev->base_addr + 0x00)
  33119. +#define STAT_ENINTSTAT        0x0001
  33120. +#define STAT_ENINTRX        0x0002
  33121. +#define STAT_ENINTTX        0x0004
  33122. +#define STAT_ENINTBUFWIN    0x0008
  33123. +#define STAT_INTDMA        0x0010
  33124. +#define STAT_INTRX        0x0020
  33125. +#define STAT_INTTX        0x0040
  33126. +#define STAT_INTBUFWIN        0x0080
  33127. +#define STAT_DMAON        0x0100
  33128. +#define STAT_RXON        0x0200
  33129. +#define STAT_TXON        0x0400
  33130. +#define STAT_FIFOFULL        0x2000
  33131. +#define STAT_FIFOEMPTY        0x4000
  33132. +#define STAT_FIFODIR        0x8000
  33133. +
  33134. +/* configuration register 1 */
  33135. +#define REG_CONFIG1        (dev->base_addr + 0x10)
  33136. +#define CFG1_BUFSELSTAT0    0x0000
  33137. +#define CFG1_BUFSELSTAT1    0x0001
  33138. +#define CFG1_BUFSELSTAT2    0x0002
  33139. +#define CFG1_BUFSELSTAT3    0x0003
  33140. +#define CFG1_BUFSELSTAT4    0x0004
  33141. +#define CFG1_BUFSELSTAT5    0x0005
  33142. +#define CFG1_ADDRPROM        0x0006
  33143. +#define CFG1_TRANSEND        0x0007
  33144. +#define CFG1_LOCBUFMEM        0x0008
  33145. +#define CFG1_INTVECTOR        0x0009
  33146. +#define CFG1_DMABURSTCONT    0x0000
  33147. +#define CFG1_DMABURST800NS    0x0010
  33148. +#define CFG1_DMABURST1600NS    0x0020
  33149. +#define CFG1_DMABURST3200NS    0x0030
  33150. +#define CFG1_DMABURST1        0x0000
  33151. +#define CFG1_DMABURST4        0x0040
  33152. +#define CFG1_DMABURST8        0x0080
  33153. +#define CFG1_DMABURST16        0x00C0
  33154. +#define CFG1_RECVCOMPSTAT0    0x0100
  33155. +#define CFG1_RECVCOMPSTAT1    0x0200
  33156. +#define CFG1_RECVCOMPSTAT2    0x0400
  33157. +#define CFG1_RECVCOMPSTAT3    0x0800
  33158. +#define CFG1_RECVCOMPSTAT4    0x1000
  33159. +#define CFG1_RECVCOMPSTAT5    0x2000
  33160. +#define CFG1_RECVSPECONLY    0x0000
  33161. +#define CFG1_RECVSPECBROAD    0x4000
  33162. +#define CFG1_RECVSPECBRMULTI    0x8000
  33163. +#define CFG1_RECVPROMISC    0xC000
  33164. +
  33165. +/* configuration register 2 */
  33166. +#define REG_CONFIG2        (dev->base_addr + 0x20)
  33167. +#define CFG2_BYTESWAP        0x0001
  33168. +#define CFG2_ERRENCRC        0x0008
  33169. +#define CFG2_ERRENDRIBBLE    0x0010
  33170. +#define CFG2_ERRSHORTFRAME    0x0020
  33171. +#define CFG2_SLOTSELECT        0x0040
  33172. +#define CFG2_PREAMSELECT    0x0080
  33173. +#define CFG2_ADDRLENGTH        0x0100
  33174. +#define CFG2_RECVCRC        0x0200
  33175. +#define CFG2_XMITNOCRC        0x0400
  33176. +#define CFG2_LOOPBACK        0x0800
  33177. +#define CFG2_CTRLO        0x1000
  33178. +#define CFG2_RESET        0x8000
  33179. +
  33180. +#define REG_RECVEND        (dev->base_addr + 0x30)
  33181. +
  33182. +#define REG_BUFWIN        (dev->base_addr + 0x40)
  33183. +
  33184. +#define REG_RECVPTR        (dev->base_addr + 0x50)
  33185. +
  33186. +#define REG_TRANSMITPTR        (dev->base_addr + 0x60)
  33187. +
  33188. +#define REG_DMAADDR        (dev->base_addr + 0x70)
  33189. +
  33190. +
  33191. +#define TX_END          0x6000
  33192. +#define RX_START        0x6000
  33193. +#define RX_LEN          0xA000
  33194. +#define RX_END          0x10000
  33195. +#define MAX_TXED    360
  33196. +
  33197. +struct arc_net
  33198. +{
  33199. +    int bus_type;
  33200. +    struct
  33201. +    {
  33202. +      int command;
  33203. +      int config1;
  33204. +      int config2;
  33205. +      int transmitptr;
  33206. +      int recvptr;
  33207. +    } regs;
  33208. +    int txinsert;
  33209. +    struct enet_statistics stats;
  33210. +    int txed;
  33211. +    int txto;
  33212. +    int tx_ends[MAX_TXED];
  33213. +    int broken;
  33214. +    int use;
  33215. +};
  33216. +
  33217. +extern struct device *init_etherdev(struct device *dev, int sizeof_private,
  33218. +            unsigned long *mem_startp);
  33219. +
  33220. +extern int    ether3_probe(struct device *dev);
  33221. +
  33222. +static int    ether3_probe1(struct device *dev);
  33223. +static int    ether3_open(struct device *dev);
  33224. +static int    ether3_send_packet(struct sk_buff *skb, struct device *dev);
  33225. +static void    ether3_interrupt(int irq, struct pt_regs *regs);
  33226. +static void    ether3_rx(struct device *dev);
  33227. +static void    ether3_tx(struct device *dev);
  33228. +static int    ether3_close(struct device *dev);
  33229. +static struct enet_statistics *ether3_get_stats(struct device *dev);
  33230. +static void    set_multicast_list(struct device *dev, int num_addrs, void *addrs);
  33231. +
  33232. +#endif
  33233. diff -r -u -N linux.orig/arch/arm/drivers/net/loopback.c linux.arm/arch/arm/drivers/net/loopback.c
  33234. --- linux.orig/arch/arm/drivers/net/loopback.c    Thu Jan  1 01:00:00 1970
  33235. +++ linux.arm/arch/arm/drivers/net/loopback.c    Fri Oct 27 23:14:59 1995
  33236. @@ -0,0 +1,140 @@
  33237. +/*
  33238. + * INET        An implementation of the TCP/IP protocol suite for the LINUX
  33239. + *        operating system.  INET is implemented using the  BSD Socket
  33240. + *        interface as the means of communication with the user level.
  33241. + *
  33242. + *        Pseudo-driver for the loopback interface.
  33243. + *
  33244. + * Version:    @(#)loopback.c    1.0.4b    08/16/93
  33245. + *
  33246. + * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  33247. + *        Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  33248. + *        Donald Becker, <becker@cesdis.gsfc.nasa.gov>
  33249. + *
  33250. + *        Alan Cox    :    Fixed oddments for NET3.014
  33251. + *
  33252. + *        This program is free software; you can redistribute it and/or
  33253. + *        modify it under the terms of the GNU General Public License
  33254. + *        as published by the Free Software Foundation; either version
  33255. + *        2 of the License, or (at your option) any later version.
  33256. + */
  33257. +#include <linux/config.h>
  33258. +#include <linux/kernel.h>
  33259. +#include <linux/sched.h>
  33260. +#include <linux/interrupt.h>
  33261. +#include <linux/fs.h>
  33262. +#include <linux/types.h>
  33263. +#include <linux/string.h>
  33264. +#include <linux/socket.h>
  33265. +#include <linux/errno.h>
  33266. +#include <linux/fcntl.h>
  33267. +#include <linux/in.h>
  33268. +#include <linux/if_ether.h>    /* For the statistics structure. */
  33269. +
  33270. +#include <asm/system.h>
  33271. +#include <asm/segment.h>
  33272. +#include <asm/io.h>
  33273. +
  33274. +#include <linux/inet.h>
  33275. +#include <linux/netdevice.h>
  33276. +#include <linux/etherdevice.h>
  33277. +#include <linux/skbuff.h>
  33278. +
  33279. +
  33280. +static int
  33281. +loopback_xmit(struct sk_buff *skb, struct device *dev)
  33282. +{
  33283. +  struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
  33284. +  int done;
  33285. +
  33286. +  if (skb == NULL || dev == NULL) return(0);
  33287. +
  33288. +  cli();
  33289. +  if (dev->tbusy != 0) {
  33290. +    sti();
  33291. +    stats->tx_errors++;
  33292. +    return(1);
  33293. +  }
  33294. +  dev->tbusy = 1;
  33295. +  sti();
  33296. +  
  33297. +  /* FIXME: Optimise so buffers with skb->free=1 are not copied but
  33298. +     instead are lobbed from tx queue to rx queue */
  33299. +
  33300. +  done = dev_rint(skb->data, skb->len, 0, dev);
  33301. +  dev_kfree_skb(skb, FREE_WRITE);
  33302. +
  33303. +  while (done != 1) {
  33304. +    done = dev_rint(NULL, 0, 0, dev);
  33305. +  }
  33306. +  stats->tx_packets++;
  33307. +
  33308. +  dev->tbusy = 0;
  33309. +
  33310. +  if (!intr_count && (bh_active & bh_mask)) {
  33311. +    start_bh_atomic();
  33312. +    do_bottom_half();
  33313. +    end_bh_atomic();
  33314. +  }
  33315. +
  33316. +  return(0);
  33317. +}
  33318. +
  33319. +static struct enet_statistics *
  33320. +get_stats(struct device *dev)
  33321. +{
  33322. +    return (struct enet_statistics *)dev->priv;
  33323. +}
  33324. +
  33325. +static int loopback_open(struct device *dev)
  33326. +{
  33327. +    dev->flags|=IFF_LOOPBACK;
  33328. +    return 0;
  33329. +}
  33330. +
  33331. +/* Initialize the rest of the LOOPBACK device. */
  33332. +int
  33333. +loopback_init(struct device *dev)
  33334. +{
  33335. +  int i;
  33336. +
  33337. +  dev->mtu        = 2000;            /* MTU            */
  33338. +  dev->tbusy        = 0;
  33339. +  dev->hard_start_xmit    = loopback_xmit;
  33340. +  dev->open        = NULL;
  33341. +#if 1
  33342. +  dev->hard_header    = eth_header;
  33343. +  dev->hard_header_len    = ETH_HLEN;        /* 14            */
  33344. +  dev->addr_len        = ETH_ALEN;        /* 6            */
  33345. +  dev->type        = ARPHRD_ETHER;        /* 0x0001        */
  33346. +  dev->type_trans    = eth_type_trans;
  33347. +  dev->rebuild_header    = eth_rebuild_header;
  33348. +  dev->open        = loopback_open;
  33349. +#else
  33350. +  dev->hard_header_length = 0;
  33351. +  dev->addr_len        = 0;
  33352. +  dev->type        = 0;            /* loopback_type (0)    */
  33353. +  dev->hard_header    = NULL;
  33354. +  dev->type_trans    = NULL;
  33355. +  dev->rebuild_header    = NULL;
  33356. +#endif
  33357. +
  33358. +  /* New-style flags. */
  33359. +  dev->flags        = IFF_LOOPBACK|IFF_BROADCAST;
  33360. +  dev->family        = AF_INET;
  33361. +#ifdef CONFIG_INET    
  33362. +  dev->pa_addr        = in_aton("127.0.0.1");
  33363. +  dev->pa_brdaddr    = in_aton("127.255.255.255");
  33364. +  dev->pa_mask        = in_aton("255.0.0.0");
  33365. +  dev->pa_alen        = sizeof(unsigned long);
  33366. +#endif  
  33367. +  dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
  33368. +  memset(dev->priv, 0, sizeof(struct enet_statistics));
  33369. +  dev->get_stats = get_stats;
  33370. +
  33371. +  /* Fill in the generic fields of the device structure. */
  33372. +  for (i = 0; i < DEV_NUMBUFFS; i++)
  33373. +    skb_queue_head_init(&dev->buffs[i]);
  33374. +  
  33375. +  return(0);
  33376. +};
  33377. diff -r -u -N linux.orig/arch/arm/drivers/net/net_init.c linux.arm/arch/arm/drivers/net/net_init.c
  33378. --- linux.orig/arch/arm/drivers/net/net_init.c    Thu Jan  1 01:00:00 1970
  33379. +++ linux.arm/arch/arm/drivers/net/net_init.c    Fri Oct 27 23:14:59 1995
  33380. @@ -0,0 +1,320 @@
  33381. +/* netdrv_init.c: Initialization for network devices. */
  33382. +/*
  33383. +    Written 1993,1994,1995 by Donald Becker.
  33384. +
  33385. +    The author may be reached as becker@cesdis.gsfc.nasa.gov or
  33386. +    C/O Center of Excellence in Space Data and Information Sciences
  33387. +        Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
  33388. +
  33389. +    This file contains the initialization for the "pl14+" style ethernet
  33390. +    drivers.  It should eventually replace most of drivers/net/Space.c.
  33391. +    It's primary advantage is that it's able to allocate low-memory buffers.
  33392. +    A secondary advantage is that the dangerous NE*000 netcards can reserve
  33393. +    their I/O port region before the SCSI probes start.
  33394. +
  33395. +    Modifications/additions by Bjorn Ekwall <bj0rn@blox.se>:
  33396. +        ethdev_index[MAX_ETH_CARDS]
  33397. +        register_netdev() / unregister_netdev()
  33398. +*/
  33399. +
  33400. +#include <linux/config.h>
  33401. +#include <linux/kernel.h>
  33402. +#include <linux/sched.h>
  33403. +#include <linux/types.h>
  33404. +#include <linux/fs.h>
  33405. +#include <linux/malloc.h>
  33406. +#include <linux/if_ether.h>
  33407. +#include <linux/string.h>
  33408. +#include <linux/netdevice.h>
  33409. +#include <linux/etherdevice.h>
  33410. +
  33411. +/* The network devices currently exist only in the socket namespace, so these
  33412. +   entries are unused.  The only ones that make sense are
  33413. +    open    start the ethercard
  33414. +    close    stop  the ethercard
  33415. +    ioctl    To get statistics, perhaps set the interface port (AUI, BNC, etc.)
  33416. +   One can also imagine getting raw packets using
  33417. +    read & write
  33418. +   but this is probably better handled by a raw packet socket.
  33419. +
  33420. +   Given that almost all of these functions are handled in the current
  33421. +   socket-based scheme, putting ethercard devices in /dev/ seems pointless.
  33422. +   
  33423. +   [Removed all support for /dev network devices. When someone adds
  33424. +    streams then by magic we get them, but otherwise they are un-needed
  33425. +    and a space waste]
  33426. +*/
  33427. +
  33428. +/* The list of used and available "eth" slots (for "eth0", "eth1", etc.) */
  33429. +#define MAX_ETH_CARDS 16 /* same as the number if irq's in irq2dev[] */
  33430. +static struct device *ethdev_index[MAX_ETH_CARDS];
  33431. +
  33432. +unsigned long lance_init(unsigned long mem_start, unsigned long mem_end);
  33433. +unsigned long pi_init(unsigned long mem_start, unsigned long mem_end);
  33434. +unsigned long apricot_init(unsigned long mem_start, unsigned long mem_end);
  33435. +unsigned long dec21040_init(unsigned long mem_start, unsigned long mem_end);
  33436. +
  33437. +/*
  33438. +  net_dev_init() is our network device initialization routine.
  33439. +  It's called from init/main.c with the start and end of free memory,
  33440. +  and returns the new start of free memory.
  33441. +  */
  33442. +
  33443. +unsigned long net_dev_init (unsigned long mem_start, unsigned long mem_end)
  33444. +{
  33445. +
  33446. +    /* Network device initialization for devices that must allocate
  33447. +       low-memory or contiguous DMA buffers.
  33448. +       */
  33449. +#if defined(CONFIG_LANCE)
  33450. +    mem_start = lance_init(mem_start, mem_end);
  33451. +#endif
  33452. +#if defined(CONFIG_PI)
  33453. +    mem_start = pi_init(mem_start, mem_end);
  33454. +#endif    
  33455. +#if defined(CONFIG_DEC_ELCP)
  33456. +    mem_start = dec21040_init(mem_start, mem_end);
  33457. +#endif    
  33458. +    return mem_start;
  33459. +}
  33460. +
  33461. +/* Fill in the fields of the device structure with ethernet-generic values.
  33462. +
  33463. +   If no device structure is passed, a new one is constructed, complete with
  33464. +   a SIZEOF_PRIVATE private data area.
  33465. +
  33466. +   If an empty string area is passed as dev->name, or a new structure is made,
  33467. +   a new name string is constructed.  The passed string area should be 8 bytes
  33468. +   long.
  33469. + */
  33470. +
  33471. +struct device *
  33472. +init_etherdev(struct device *dev, int sizeof_priv, unsigned long *mem_startp)
  33473. +{
  33474. +    int new_device = 0;
  33475. +    int i;
  33476. +
  33477. +    /* Use an existing correctly named device in Space.c:dev_base. */
  33478. +    if (dev == NULL) {
  33479. +        int alloc_size = sizeof(struct device) + sizeof("eth%d  ")
  33480. +            + sizeof_priv + 3;
  33481. +        struct device *cur_dev;
  33482. +        char pname[8];        /* Putative name for the device.  */
  33483. +
  33484. +        for (i = 0; i < MAX_ETH_CARDS; ++i)
  33485. +            if (ethdev_index[i] == NULL) {
  33486. +                sprintf(pname, "eth%d", i);
  33487. +                for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next)
  33488. +                    if (strcmp(pname, cur_dev->name) == 0) {
  33489. +                        dev = cur_dev;
  33490. +                        dev->init = NULL;
  33491. +                        sizeof_priv = (sizeof_priv + 3) & ~3;
  33492. +                        if (mem_startp && *mem_startp ) {
  33493. +                            dev->priv = (void*) *mem_startp;
  33494. +                            *mem_startp += sizeof_priv;
  33495. +                        } else
  33496. +                            dev->priv = kmalloc(sizeof_priv, GFP_KERNEL);
  33497. +                        memset(dev->priv, 0, sizeof_priv);
  33498. +                        goto found;
  33499. +                    }
  33500. +            }
  33501. +
  33502. +        alloc_size &= ~3;        /* Round to dword boundary. */
  33503. +
  33504. +        if (mem_startp && *mem_startp ) {
  33505. +            dev = (struct device *)*mem_startp;
  33506. +            *mem_startp += alloc_size;
  33507. +        } else
  33508. +            dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
  33509. +        memset(dev, 0, alloc_size);
  33510. +        if (sizeof_priv)
  33511. +            dev->priv = (void *) (dev + 1);
  33512. +        dev->name = sizeof_priv + (char *)(dev + 1);
  33513. +        new_device = 1;
  33514. +    }
  33515. +
  33516. +    found:                        /* From the double loop above. */
  33517. +
  33518. +    if (dev->name &&
  33519. +        ((dev->name[0] == '\0') || (dev->name[0] == ' '))) {
  33520. +        for (i = 0; i < MAX_ETH_CARDS; ++i)
  33521. +            if (ethdev_index[i] == NULL) {
  33522. +                sprintf(dev->name, "eth%d", i);
  33523. +                ethdev_index[i] = dev;
  33524. +                break;
  33525. +            }
  33526. +    }
  33527. +
  33528. +    ether_setup(dev);     /* Hmmm, should this be called here? */
  33529. +    
  33530. +    if (new_device) {
  33531. +        /* Append the device to the device queue. */
  33532. +        struct device **old_devp = &dev_base;
  33533. +        while ((*old_devp)->next)
  33534. +            old_devp = & (*old_devp)->next;
  33535. +        (*old_devp)->next = dev;
  33536. +        dev->next = 0;
  33537. +    }
  33538. +    return dev;
  33539. +}
  33540. +
  33541. +void ether_setup(struct device *dev)
  33542. +{
  33543. +    int i;
  33544. +    /* Fill in the fields of the device structure with ethernet-generic values.
  33545. +       This should be in a common file instead of per-driver.  */
  33546. +    for (i = 0; i < DEV_NUMBUFFS; i++)
  33547. +        skb_queue_head_init(&dev->buffs[i]);
  33548. +
  33549. +    /* register boot-defined "eth" devices */
  33550. +    if (dev->name && (strncmp(dev->name, "eth", 3) == 0)) {
  33551. +        i = simple_strtoul(dev->name + 3, NULL, 0);
  33552. +        if (ethdev_index[i] == NULL) {
  33553. +            ethdev_index[i] = dev;
  33554. +        }
  33555. +        else if (dev != ethdev_index[i]) {
  33556. +            /* Really shouldn't happen! */
  33557. +            printk("ether_setup: Ouch! Someone else took %s\n",
  33558. +                dev->name);
  33559. +        }
  33560. +    }
  33561. +
  33562. +    dev->hard_header    = eth_header;
  33563. +    dev->rebuild_header = eth_rebuild_header;
  33564. +    dev->type_trans = eth_type_trans;
  33565. +
  33566. +    dev->type        = ARPHRD_ETHER;
  33567. +#ifndef __arm__
  33568. +    dev->hard_header_len = ETH_HLEN;
  33569. +#else
  33570. +    dev->hard_header_len = (ETH_HLEN | 3) + 1;
  33571. +#endif
  33572. +    dev->mtu        = 1500; /* eth_mtu */
  33573. +    dev->addr_len    = ETH_ALEN;
  33574. +    for (i = 0; i < ETH_ALEN; i++) {
  33575. +        dev->broadcast[i]=0xff;
  33576. +    }
  33577. +
  33578. +    /* New-style flags. */
  33579. +    dev->flags        = IFF_BROADCAST|IFF_MULTICAST;
  33580. +    dev->family        = AF_INET;
  33581. +    dev->pa_addr    = 0;
  33582. +    dev->pa_brdaddr = 0;
  33583. +    dev->pa_mask    = 0;
  33584. +    dev->pa_alen    = sizeof(unsigned long);
  33585. +}
  33586. +
  33587. +int ether_config(struct device *dev, struct ifmap *map)
  33588. +{
  33589. +    if (map->mem_start != (u_long)(-1))
  33590. +        dev->mem_start = map->mem_start;
  33591. +    if (map->mem_end != (u_long)(-1))
  33592. +        dev->mem_end = map->mem_end;
  33593. +    if (map->base_addr != (u_short)(-1))
  33594. +        dev->base_addr = map->base_addr;
  33595. +    if (map->irq != (u_char)(-1))
  33596. +        dev->irq = map->irq;
  33597. +    if (map->dma != (u_char)(-1))
  33598. +        dev->dma = map->dma;
  33599. +    if (map->port != (u_char)(-1))
  33600. +        dev->if_port = map->port;
  33601. +    return 0;
  33602. +}
  33603. +
  33604. +int register_netdev(struct device *dev)
  33605. +{
  33606. +    struct device *d = dev_base;
  33607. +    unsigned long flags;
  33608. +    int i=MAX_ETH_CARDS;
  33609. +
  33610. +    save_flags(flags);
  33611. +    cli();
  33612. +
  33613. +    if (dev && dev->init) {
  33614. +        if (dev->name &&
  33615. +            ((dev->name[0] == '\0') || (dev->name[0] == ' '))) {
  33616. +            for (i = 0; i < MAX_ETH_CARDS; ++i)
  33617. +                if (ethdev_index[i] == NULL) {
  33618. +                    sprintf(dev->name, "eth%d", i);
  33619. +                    printk("loading device '%s'...\n", dev->name);
  33620. +                    ethdev_index[i] = dev;
  33621. +                    break;
  33622. +                }
  33623. +        }
  33624. +
  33625. +        if (dev->init(dev) != 0) {
  33626. +            if (i < MAX_ETH_CARDS) ethdev_index[i] = NULL;
  33627. +            restore_flags(flags);
  33628. +            return -EIO;
  33629. +        }
  33630. +
  33631. +        /* Add device to end of chain */
  33632. +        if (dev_base) {
  33633. +            while (d->next)
  33634. +                d = d->next;
  33635. +            d->next = dev;
  33636. +        }
  33637. +        else
  33638. +            dev_base = dev;
  33639. +        dev->next = NULL;
  33640. +    }
  33641. +    restore_flags(flags);
  33642. +    return 0;
  33643. +}
  33644. +
  33645. +void unregister_netdev(struct device *dev)
  33646. +{
  33647. +    struct device *d = dev_base;
  33648. +    unsigned long flags;
  33649. +    int i;
  33650. +
  33651. +    save_flags(flags);
  33652. +    cli();
  33653. +
  33654. +    printk("unregister_netdev: device ");
  33655. +
  33656. +    if (dev == NULL) {
  33657. +        printk("was NULL\n");
  33658. +        restore_flags(flags);
  33659. +        return;
  33660. +    }
  33661. +    /* else */
  33662. +    if (dev->start)
  33663. +        printk("'%s' busy\n", dev->name);
  33664. +    else {
  33665. +        if (dev_base == dev)
  33666. +            dev_base = dev->next;
  33667. +        else {
  33668. +            while (d && (d->next != dev))
  33669. +                d = d->next;
  33670. +
  33671. +            if (d && (d->next == dev)) {
  33672. +                d->next = dev->next;
  33673. +                printk("'%s' unlinked\n", dev->name);
  33674. +            }
  33675. +            else {
  33676. +                printk("'%s' not found\n", dev->name);
  33677. +                restore_flags(flags);
  33678. +                return;
  33679. +            }
  33680. +        }
  33681. +        for (i = 0; i < MAX_ETH_CARDS; ++i) {
  33682. +            if (ethdev_index[i] == dev) {
  33683. +                ethdev_index[i] = NULL;
  33684. +                break;
  33685. +            }
  33686. +        }
  33687. +    }
  33688. +    restore_flags(flags);
  33689. +}
  33690. +
  33691. +
  33692. +
  33693. +/*
  33694. + * Local variables:
  33695. + *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c net_init.c"
  33696. + *  version-control: t
  33697. + *  kept-new-versions: 5
  33698. + *  tab-width: 4
  33699. + * End:
  33700. + */
  33701. diff -r -u -N linux.orig/arch/arm/drivers/net/nq8005.c linux.arm/arch/arm/drivers/net/nq8005.c
  33702. --- linux.orig/arch/arm/drivers/net/nq8005.c    Thu Jan  1 01:00:00 1970
  33703. +++ linux.arm/arch/arm/drivers/net/nq8005.c    Fri Oct 27 23:15:00 1995
  33704. @@ -0,0 +1,860 @@
  33705. +/*
  33706. + * linux/drivers/net/ether3.c
  33707. + *
  33708. + * SEEQ nq8005 ethernet driver
  33709. + *
  33710. + */
  33711. +
  33712. +#ifdef MODULE
  33713. +#include <linux/module.h>
  33714. +#include <linux/version.h>
  33715. +#define CLAIM_IRQ_AT_OPEN
  33716. +#else
  33717. +#define MOD_INC_USE_COUNT
  33718. +#define MOD_DEC_USE_COUNT
  33719. +#endif
  33720. +
  33721. +#include <linux/config.h>
  33722. +#include <linux/kernel.h>
  33723. +#include <linux/sched.h>
  33724. +#include <linux/types.h>
  33725. +#include <linux/fcntl.h>
  33726. +#include <linux/interrupt.h>
  33727. +#include <linux/ptrace.h>
  33728. +#include <linux/ioport.h>
  33729. +#include <linux/in.h>
  33730. +#include <linux/malloc.h>
  33731. +#include <linux/string.h>
  33732. +#include <asm/system.h>
  33733. +#include <asm/bitops.h>
  33734. +#include <asm/io.h>
  33735. +#include <asm/dma.h>
  33736. +#include <linux/errno.h>
  33737. +
  33738. +#include <linux/netdevice.h>
  33739. +#include <linux/etherdevice.h>
  33740. +#include <linux/skbuff.h>
  33741. +
  33742. +#include <asm/ecard.h>
  33743. +
  33744. +#include "ether3.h"
  33745. +
  33746. +#define FUNC_PROLOGUE \
  33747. +    struct arc_net *an = (struct arc_net *)dev->priv
  33748. +
  33749. +static unsigned int net_debug = NET_DEBUG;
  33750. +
  33751. +#define tx_done(dev) 0
  33752. +/* ------------------------------------------------------------------------------- */
  33753. +static char *version = "ether3 ethernet driver (c) 1995 R.M.King V1.00\n";
  33754. +
  33755. +#define BUS_16 16
  33756. +#define BUS_8  8
  33757. +
  33758. +extern int inswb(int reg, void *buffer, int len);
  33759. +extern int outswb(int reg, void *buffer, int len);
  33760. +
  33761. +unsigned char def_eth_addr[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
  33762. +
  33763. +static int ether3_prods[] = { 0x00A4 };
  33764. +static int ether3_manus[] = { 0x0011 };
  33765. +
  33766. +/* --------------------------------------------------------------------------- */
  33767. +
  33768. +static void check_dev(struct device *dev, char *s)
  33769. +{
  33770. +    struct device *dev2;
  33771. +
  33772. +    dev2 = dev->next;
  33773. +    
  33774. +    while (dev2 && dev2 != dev)
  33775. +        dev2 = dev2->next;
  33776. +
  33777. +    if (dev2 == dev)
  33778. +        printk("eek! - %s\n", s);
  33779. +}
  33780. +
  33781. +/*
  33782. + * set one of the receive address registers in the chip
  33783. + */
  33784. +
  33785. +static void
  33786. +ether3_setrxaddr(struct device *dev, int address, unsigned char *addr)
  33787. +{
  33788. +    FUNC_PROLOGUE;
  33789. +    unsigned long flags;
  33790. +    int stat, i;
  33791. +
  33792. +    save_flags(flags);
  33793. +    cli();
  33794. +
  33795. +    stat = inw(REG_STATUS);
  33796. +    if(stat & STAT_RXON)
  33797. +        outw(an->regs.command | CMD_RXOFF, REG_COMMAND);
  33798. +
  33799. +    outw(an->regs.config1 | address, REG_CONFIG1);
  33800. +    for(i=0; i<6; i++)
  33801. +        outb(addr[i], REG_BUFWIN);
  33802. +
  33803. +    if(stat & STAT_RXON)
  33804. +        outw(an->regs.command | CMD_RXON, REG_COMMAND);
  33805. +
  33806. +    restore_flags(flags);
  33807. +}
  33808. +
  33809. +/*
  33810. + * write data to the buffer memory
  33811. + */
  33812. +
  33813. +static void
  33814. +ether3_writebuffer(struct device *dev, void *data, int start, int length)
  33815. +{
  33816. +    FUNC_PROLOGUE;
  33817. +    int timeout = 1000000;
  33818. +    if(start != -1)
  33819. +    {
  33820. +        outw(an->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  33821. +        outw(an->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  33822. +        while((inw(REG_STATUS) & STAT_FIFOEMPTY) == 0)
  33823. +            if(!timeout--)
  33824. +            {
  33825. +                printk("settxlim_16 broken\n");
  33826. +                an->broken = 1;
  33827. +                return;
  33828. +            }
  33829. +        outw(an->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  33830. +        outw(start, REG_DMAADDR);
  33831. +    }
  33832. +    if(length != 0)
  33833. +        outswb(REG_BUFWIN, data, length);
  33834. +}
  33835. +
  33836. +/*
  33837. + * read data from the buffer memory
  33838. + */
  33839. +
  33840. +static void
  33841. +ether3_readbuffer(struct device *dev, void *data, int start, int length)
  33842. +{
  33843. +    FUNC_PROLOGUE;
  33844. +    int timeout = 1000000;
  33845. +    if(start != -1)
  33846. +    {
  33847. +        outw(an->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  33848. +        outw(an->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  33849. +        while((inw(REG_STATUS) & STAT_FIFOEMPTY) == 0)
  33850. +            if(!timeout--)
  33851. +            {
  33852. +                printk("setrxlim_16 broken\n");
  33853. +                an->broken = 1;
  33854. +                return;
  33855. +            }
  33856. +        outw(start, REG_DMAADDR);
  33857. +        outw(an->regs.command | CMD_FIFOREAD, REG_COMMAND);
  33858. +    }
  33859. +    if(length != 0)
  33860. +        inswb(REG_BUFWIN, data, length);
  33861. +}
  33862. +
  33863. +/* --------------------------------------------------------------------------- */
  33864. +
  33865. +static int
  33866. +ether3_ramtest(struct device *dev, unsigned char byte)
  33867. +{
  33868. +    unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL);
  33869. +    unsigned long flags;
  33870. +    int i,ret=0;
  33871. +    int max_errors = 4;
  33872. +    int bad=-1;
  33873. +
  33874. +    if(!buffer)
  33875. +        return 1;
  33876. +
  33877. +    save_flags(flags);
  33878. +    cli();
  33879. +
  33880. +    memset(buffer, byte, RX_END);
  33881. +    ether3_writebuffer(dev, buffer, 0, TX_END);
  33882. +    ether3_writebuffer(dev, buffer+RX_START, RX_START, RX_LEN);
  33883. +
  33884. +    memset(buffer, byte ^ 0xff, RX_END);
  33885. +    ether3_readbuffer(dev, buffer, 0, TX_END);
  33886. +    ether3_readbuffer(dev, buffer+RX_START, RX_START, RX_LEN);
  33887. +
  33888. +    for(i=0; i<RX_END; i++)
  33889. +    {
  33890. +        if(buffer[i] != byte)
  33891. +        {
  33892. +            if(max_errors>=0 && bad!=buffer[i])
  33893. +            {
  33894. +                printk("%s: RAM failed with (%02X instead of %02X) at 0x%04X",
  33895. +                    dev->name, buffer[i], byte, i);
  33896. +                ret = 2;
  33897. +                max_errors--;
  33898. +                bad=buffer[i];
  33899. +            }
  33900. +        }
  33901. +        else
  33902. +        {
  33903. +            if(bad != -1)
  33904. +            {
  33905. +                printk(" - 0x%04X\n", i);
  33906. +                bad = -1;
  33907. +            }
  33908. +        }
  33909. +    }
  33910. +    if(bad != -1)
  33911. +        printk(" - 0x10000\n");
  33912. +    kfree(buffer);
  33913. +    restore_flags(flags);
  33914. +
  33915. +    return ret;
  33916. +}
  33917. +
  33918. +/* ------------------------------------------------------------------------------- */
  33919. +
  33920. +static int
  33921. +ether3_init_1(struct device *dev)
  33922. +{
  33923. +    outb(0x80, REG_CONFIG2);
  33924. +    outb(0, REG_COMMAND);
  33925. +
  33926. +    outb(1, REG_CONFIG1);
  33927. +    if(inb(REG_CONFIG1+1)==1 && inb(REG_CONFIG1)==0)
  33928. +        return BUS_8;
  33929. +    if(inw(REG_CONFIG1)==0x101)
  33930. +        return BUS_16;
  33931. +    return 0;
  33932. +}
  33933. +
  33934. +static int
  33935. +ether3_init_2(struct device *dev)
  33936. +{
  33937. +    FUNC_PROLOGUE;
  33938. +    unsigned long a=0;
  33939. +    int i;
  33940. +
  33941. +    ether3_setrxaddr(dev, CFG1_BUFSELSTAT0, dev->dev_addr);
  33942. +
  33943. +    an->regs.config1 = CFG1_RECVSPECBROAD|CFG1_RECVCOMPSTAT0|CFG1_DMABURST8;
  33944. +    an->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC;
  33945. +
  33946. +    outw(an->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
  33947. +    outw((TX_END>>8) - 1, REG_BUFWIN);
  33948. +    outw(an->regs.recvptr    , REG_RECVPTR);
  33949. +    outw(an->regs.transmitptr    , REG_TRANSMITPTR);
  33950. +    outw(an->regs.recvptr >> 8, REG_RECVEND);
  33951. +    outw(an->regs.config2    , REG_CONFIG2);
  33952. +    outw(an->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  33953. +    ether3_writebuffer(dev, &a, an->regs.transmitptr, 4);
  33954. +    outw(an->regs.command    , REG_COMMAND);
  33955. +
  33956. +    i = ether3_ramtest(dev, 0x5A);
  33957. +    if(i)
  33958. +        return i;
  33959. +    return ether3_ramtest(dev, 0x1E);
  33960. +}
  33961. +
  33962. +/* This is the real probe routine. */
  33963. +
  33964. +static int
  33965. +ether3_probe1(struct device *dev)
  33966. +{
  33967. +    static unsigned version_printed = 0;
  33968. +    struct arc_net *an;
  33969. +    int i;
  33970. +
  33971. +    if(!dev->priv)
  33972. +        dev->priv = kmalloc(sizeof(struct arc_net), GFP_KERNEL);
  33973. +
  33974. +    if(!dev->priv)
  33975. +        return 1;
  33976. +
  33977. +    an = (struct arc_net *) dev->priv;
  33978. +    memset(an, 0, sizeof(struct arc_net));
  33979. +    an->bus_type    = BUS_16;
  33980. +    an->broken    = 0;
  33981. +
  33982. +    if((an->bus_type=ether3_init_1(dev))==0)
  33983. +    {
  33984. +        kfree(dev->priv);
  33985. +        return 1;
  33986. +    }
  33987. +
  33988. +    if (net_debug  &&  version_printed++ == 0)
  33989. +        printk(version);
  33990. +
  33991. +    printk("%s: ether3 found (bus width %d), ", dev->name, an->bus_type);
  33992. +
  33993. +    /* Retrive and print the ethernet address. */
  33994. +    for (i = 0; i < 6; i++)
  33995. +        printk(i==0?" %2.2x":i==5?":%2.2x\n":":%2.2x", dev->dev_addr[i]);
  33996. +
  33997. +    if(ether3_init_2(dev))
  33998. +    {
  33999. +        kfree(dev->priv);
  34000. +        return 1;
  34001. +    }
  34002. +
  34003. +    dev->open        = ether3_open;
  34004. +    dev->stop        = ether3_close;
  34005. +    dev->hard_start_xmit    = ether3_send_packet;
  34006. +    dev->get_stats            = ether3_get_stats;
  34007. +    dev->set_multicast_list = set_multicast_list;
  34008. +
  34009. +    /* Fill in the fields of the device structure with ethernet values. */
  34010. +    ether_setup(dev);
  34011. +#ifndef CLAIM_IRQ_AT_OPEN
  34012. +    if (request_irq(dev->irq, ether3_interrupt, 0, "ether3")) {
  34013. +        kfree(dev->priv);
  34014. +        return -EAGAIN;
  34015. +    }
  34016. +
  34017. +    irq2dev_map[dev->irq] = dev;
  34018. +#endif
  34019. +    return 0;
  34020. +}
  34021. +
  34022. +/* --------------------------------------------------------------------------- */
  34023. +
  34024. +static void
  34025. +ether3_addr(char *addr, struct expansion_card *ec)
  34026. +{
  34027. +    struct chunk_dir cd;
  34028. +    char *s;
  34029. +    
  34030. +    if(ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '(')))
  34031. +    {
  34032. +        int i;
  34033. +        for (i = 0; i<6; i++)
  34034. +        {
  34035. +            addr[i] = simple_strtoul(s + 1, &s, 0x10);
  34036. +            if(*s != (i==5?')' : ':' ))
  34037. +                break;
  34038. +        }
  34039. +        if(i == 6)
  34040. +            return;
  34041. +    }
  34042. +    memcpy(addr, def_eth_addr, 6);
  34043. +}
  34044. +int
  34045. +ether3_probe(struct device *dev)
  34046. +{
  34047. +#ifndef MODULE
  34048. +    struct expansion_card *ec;
  34049. +    unsigned char *eth_addr;
  34050. +    int base_addr;
  34051. +
  34052. +    if(!dev)
  34053. +        return ENODEV;
  34054. +
  34055. +    if((ec = ecard_find(0, sizeof(ether3_prods), ether3_prods, ether3_manus)) == NULL)
  34056. +        return ENODEV;
  34057. +
  34058. +    dev->base_addr    = ((unsigned long)ec->r_podaddr & ~0x003c0000UL) >> 2;
  34059. +    dev->irq    = ec->irq;
  34060. +
  34061. +    ecard_claim (ec);
  34062. +
  34063. +    ether3_addr(dev->dev_addr, ec);
  34064. +#endif
  34065. +    if(ether3_probe1(dev) == 0)
  34066. +        return 0;
  34067. +    return ENODEV;
  34068. +}
  34069. +
  34070. +/* ------------------------------------------------------------------------ */
  34071. +
  34072. +static void
  34073. +ether3_init_for_open(struct device *dev)
  34074. +{
  34075. +    FUNC_PROLOGUE;
  34076. +    unsigned long a=0;
  34077. +
  34078. +    an->regs.command = 0;
  34079. +    outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
  34080. +    while(inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
  34081. +
  34082. +    ether3_setrxaddr(dev, CFG1_BUFSELSTAT0, dev->dev_addr);
  34083. +    an->regs.transmitptr = 0;    /* address that transmitter has processed to */
  34084. +    an->txinsert = 0;        /* address of next available packet for tx */
  34085. +    an->txed = 0;            /* transmitted length index */
  34086. +    an->txto = 0;            /* to transmit length index */
  34087. +    an->tx_ends[0] = 0;
  34088. +    an->use = 0;
  34089. +
  34090. +    an->regs.config2 |= CFG2_CTRLO;
  34091. +
  34092. +    outw(an->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
  34093. +    outw((TX_END>>8) - 1, REG_BUFWIN);
  34094. +
  34095. +    an->regs.recvptr    = RX_START;
  34096. +    outw(an->regs.recvptr    , REG_RECVPTR);
  34097. +    outw(an->regs.recvptr>>8, REG_RECVEND);
  34098. +
  34099. +    outw(0, REG_TRANSMITPTR);
  34100. +    outw(an->regs.config2 , REG_CONFIG2);
  34101. +    outw(an->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  34102. +
  34103. +    ether3_writebuffer(dev, &a, an->regs.transmitptr, 4);
  34104. +
  34105. +
  34106. +    an->regs.command = CMD_ENINTRX|CMD_ENINTTX;
  34107. +    outw(an->regs.command | CMD_RXON, REG_COMMAND);
  34108. +}
  34109. +
  34110. +/* Open/initialize the board.  This is called (in the current kernel)
  34111. +   sometime after booting when the 'ifconfig' program is run.
  34112. +
  34113. +   This routine should set everything up anew at each open, even
  34114. +   registers that "should" only need to be set once at boot, so that
  34115. +   there is non-reboot way to recover if something goes wrong.
  34116. +   */
  34117. +static int
  34118. +ether3_open(struct device *dev)
  34119. +{
  34120. +    ether3_init_for_open(dev);
  34121. +
  34122. +#ifdef CLAIM_IRQ_AT_OPEN
  34123. +    if (request_irq(dev->irq, ether3_interrupt, 0, "ether3")) {
  34124. +        kfree(dev->priv);
  34125. +        return -EAGAIN;
  34126. +    }
  34127. +
  34128. +    irq2dev_map[dev->irq] = dev;
  34129. +#endif
  34130. +
  34131. +    MOD_INC_USE_COUNT;
  34132. +
  34133. +    dev->tbusy = 0;
  34134. +    dev->interrupt = 0;
  34135. +    dev->start = 1;
  34136. +    return 0;
  34137. +}
  34138. +
  34139. +static int
  34140. +ether3_send_packet(struct sk_buff *skb, struct device *dev)
  34141. +{
  34142. +    FUNC_PROLOGUE;
  34143. +
  34144. +    if (dev->tbusy) {
  34145. +        /* If we get here, some higher level has decided we are broken.
  34146. +           There should really be a "kick me" function call instead. */
  34147. +        int tickssofar = jiffies - dev->trans_start;
  34148. +        if (tickssofar < 5)
  34149. +            return 1;
  34150. +        printk("%s: transmit timed out, %s?\n", dev->name,
  34151. +               tx_done(dev) ? "IRQ conflict" : "network cable problem");
  34152. +        /* Try to restart the adaptor. */
  34153. +        dev->tbusy = 0;
  34154. +        an->use = 0;
  34155. +        an->regs.config2 |= CFG2_CTRLO;
  34156. +        outw(an->regs.config2 , REG_CONFIG2);
  34157. +        dev->trans_start = jiffies;
  34158. +    }
  34159. +
  34160. +    /* If some higher layer thinks we've missed an tx-done interrupt
  34161. +       we are passed NULL. Caution: dev_tint() handles the cli()/sti()
  34162. +       itself. */
  34163. +    if (skb == NULL) {
  34164. +        dev_tint(dev);
  34165. +        return 0;
  34166. +    }
  34167. +
  34168. +    /* Block a timer-based transmit from overlapping.  This could better be
  34169. +       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
  34170. +    if (set_bit(0, (void*)&dev->tbusy) != 0)
  34171. +        printk("%s: Transmitter access conflict.\n", dev->name);
  34172. +    else {
  34173. +        short length = ETH_ZLEN < (skb->len-2) ? (skb->len-2) : ETH_ZLEN;
  34174. +        unsigned char *buf = skb->data;
  34175. +        unsigned long flags;
  34176. +        unsigned long thisinfo, nextinfo=0;
  34177. +        int thisdata, thisstart, nextpacket;
  34178. +
  34179. +        if(an->broken)
  34180. +        {
  34181. +          dev_kfree_skb(skb, FREE_WRITE);
  34182. +          an->stats.tx_dropped ++;
  34183. +          return 1;
  34184. +        }
  34185. +
  34186. +        thisstart = an->txinsert;
  34187. +        thisdata = thisstart + 4;
  34188. +        if(thisdata >= TX_END)
  34189. +            thisdata -= TX_END;
  34190. +        nextpacket = thisdata + length;
  34191. +        if(nextpacket >= TX_END)
  34192. +            nextpacket -= TX_END;
  34193. +        an->txinsert = nextpacket;
  34194. +        an->tx_ends[an->txto++] = nextpacket;
  34195. +        if(an->txto >= MAX_TXED)
  34196. +          an->txto = 0;
  34197. +
  34198. +        thisinfo = 0x00E80000 | ((nextpacket >> 8) & 0xff) | ((nextpacket << 8) & 0xff00);
  34199. +
  34200. +        save_flags(flags);
  34201. +        cli();
  34202. +        an->use++;
  34203. +        an->regs.config2 &= ~CFG2_CTRLO;
  34204. +        outw(an->regs.config2 , REG_CONFIG2);
  34205. +
  34206. +        ether3_writebuffer(dev, buf + 2, thisdata, length&1?(length+1):length);
  34207. +        ether3_writebuffer(dev, &nextinfo, -1, 4);
  34208. +        ether3_writebuffer(dev, &thisinfo, thisstart, 4);
  34209. +        restore_flags(flags);
  34210. +
  34211. +        if((inw(REG_STATUS) & STAT_TXON)==0) {
  34212. +          outw(thisstart, REG_TRANSMITPTR);
  34213. +          outw(an->regs.command | CMD_TXON, REG_COMMAND);
  34214. +        }
  34215. +        dev->trans_start = jiffies;
  34216. +    }
  34217. +    dev_kfree_skb (skb, FREE_WRITE);
  34218. +
  34219. +    /* You might need to clean up and record Tx statistics here. */
  34220. +
  34221. +    return 0;
  34222. +}
  34223. +
  34224. +/* The typical workload of the driver:
  34225. +   Handle the network interface interrupts. */
  34226. +static void
  34227. +ether3_interrupt(int irq, struct pt_regs *regs)
  34228. +{
  34229. +    struct device *dev = (struct device *)(irq2dev_map[irq]);
  34230. +    struct arc_net *an = (struct arc_net *)dev->priv;
  34231. +    int status, boguscount = 0, done = 0;
  34232. +#if NET_DEBUG > 1
  34233. +    if(net_debug & DEBUG_INT)
  34234. +             printk("ether3_interrupt: irq %d\n", irq);
  34235. +#endif
  34236. +
  34237. +    if (dev == NULL) {
  34238. +        printk ("ether3_interrupt(): irq %d for unknown device.\n", irq);
  34239. +        return;
  34240. +    }
  34241. +    dev->interrupt = 1;
  34242. +
  34243. +    do {
  34244. +        status = inw(REG_STATUS);
  34245. +        if (status & STAT_INTRX) {
  34246. +            /* Got a packet(s). */
  34247. +            ether3_rx(dev);
  34248. +            done = 1;
  34249. +        }
  34250. +        if (status & STAT_INTTX) {
  34251. +            ether3_tx(dev);
  34252. +            done = 1;
  34253. +        }
  34254. +        outw((status & (STAT_INTRX|STAT_INTTX|STAT_INTBUFWIN))
  34255. +          | an->regs.command, REG_COMMAND);
  34256. +    } while (++boguscount < 20 && !done) ;
  34257. +
  34258. +    dev->interrupt = 0;
  34259. +
  34260. +#if NET_DEBUG > 1
  34261. +    if(net_debug & DEBUG_INT)
  34262. +             printk("ether3_interrupt: done\n", irq);
  34263. +#endif
  34264. +}
  34265. +
  34266. +/* We have a good packet(s), get it/them out of the buffers. */
  34267. +static void
  34268. +ether3_rx(struct device *dev)
  34269. +{
  34270. +    FUNC_PROLOGUE;
  34271. +    struct sk_buff *skb=NULL;
  34272. +    unsigned int end;
  34273. +    unsigned int length;
  34274. +
  34275. +    an->use++;
  34276. +    if(an->use == 1)
  34277. +    {
  34278. +        an->regs.config2 &= ~CFG2_CTRLO;
  34279. +        outw(an->regs.config2 , REG_CONFIG2);
  34280. +    }
  34281. +    do {
  34282. +        unsigned char buffer[20];
  34283. +        ether3_readbuffer(dev, buffer, an->regs.recvptr, 20);
  34284. +
  34285. +        if(buffer[0] == 0 || (buffer[3] & 0x80)==0)
  34286. +            goto rx_fin;
  34287. +#if NET_DEBUG > 1
  34288. +        if(net_debug & DEBUG_RX) {
  34289. +        {
  34290. +            int i;
  34291. +            printk("ether3_rx:", an->regs.recvptr);
  34292. +            for(i=3; i<18; i++)
  34293. +                printk("%02X ",(unsigned int)buffer[i]);
  34294. +            printk("\n");
  34295. +        }
  34296. +#endif
  34297. +
  34298. +        end = (buffer[0]<<8) | buffer[1];
  34299. +
  34300. +        if((buffer[2] & 0xC0) != 0x40)
  34301. +          /* no data follows */
  34302. +          goto done;
  34303. +
  34304. +        if(buffer[3] & 15) {
  34305. +            an->stats.rx_errors++;
  34306. +            if(buffer[3] & 1) an->stats.rx_fifo_errors ++;
  34307. +            if(buffer[3] & 2) an->stats.rx_crc_errors ++;
  34308. +            if(buffer[3] & 4) an->stats.rx_fifo_errors ++;
  34309. +            if(buffer[3] & 8) an->stats.rx_length_errors ++;
  34310. +            goto done;
  34311. +        }
  34312. +
  34313. +        if(end > an->regs.recvptr)
  34314. +            length = end - an->regs.recvptr;
  34315. +        else
  34316. +            length = (end - RX_START) + (RX_END - an->regs.recvptr);
  34317. +
  34318. +        skb = alloc_skb(length + 4, GFP_ATOMIC);
  34319. +        if(skb == NULL) {
  34320. +            printk("%s: memory squeeze, dropping packet.\n", dev->name);
  34321. +            an->stats.rx_dropped++;
  34322. +            an->regs.recvptr = end;
  34323. +            outw(an->regs.recvptr >> 8, REG_RECVEND);
  34324. +            goto rx_fin;
  34325. +        }
  34326. +
  34327. +        skb->len = length - 4;
  34328. +        skb->dev = dev;
  34329. +        memcpy(skb->data + 2, buffer + 4, 20-4);
  34330. +        ether3_readbuffer(dev, skb->data+18, -1, length-20);
  34331. +    done:
  34332. +        an->regs.recvptr = end;
  34333. +        outw(an->regs.recvptr >> 8, REG_RECVEND);
  34334. +        if(skb) {
  34335. +            netif_rx(skb);
  34336. +            skb=NULL;
  34337. +            an->stats.rx_packets++;
  34338. +        }
  34339. +    }
  34340. +    while(inw(REG_STATUS) & STAT_RXON);
  34341. +
  34342. +    outw(an->regs.recvptr, REG_RECVPTR);
  34343. +    outw(an->regs.command | CMD_RXON, REG_COMMAND);
  34344. +
  34345. +    /* If any worth-while packets have been received, dev_rint()
  34346. +       has done a mark_bh(NET_BH) for us and will work on them
  34347. +       when we get to the bottom-half routine. */
  34348. +rx_fin:
  34349. +    if(an->use)
  34350. +    {
  34351. +        an->use--;
  34352. +        if(an->use == 0)
  34353. +        {
  34354. +            an->regs.config2 |= CFG2_CTRLO;
  34355. +            outw(an->regs.config2 , REG_CONFIG2);
  34356. +        }
  34357. +    }
  34358. +}
  34359. +
  34360. +/* ----------------------------------------------------------------------------- */
  34361. +
  34362. +static void
  34363. +ether3_tx(struct device *dev)
  34364. +{
  34365. +    FUNC_PROLOGUE;
  34366. +    unsigned char buffer[4];
  34367. +
  34368. +    if(an->regs.transmitptr + 4 > TX_END) {
  34369. +        int len = TX_END - an->regs.transmitptr;
  34370. +        ether3_readbuffer(dev, buffer, an->regs.transmitptr, len);
  34371. +        ether3_readbuffer(dev, buffer+len, 0, 4 - len);
  34372. +    }
  34373. +    else
  34374. +        ether3_readbuffer(dev, buffer, an->regs.transmitptr, 4);
  34375. +
  34376. +    if(!(buffer[3] & 0x80))
  34377. +        return;
  34378. +
  34379. +    if(buffer[3] & 7) {
  34380. +        if(buffer[3] & 5) an->stats.tx_errors ++;
  34381. +        if(buffer[3] & 4) an->stats.collisions += 16;
  34382. +        if(buffer[3] & 2) an->stats.collisions += (buffer[3] & 0x78)>>3;
  34383. +        if(buffer[3] & 1) an->stats.tx_fifo_errors ++;
  34384. +    }
  34385. +    if(!(buffer[3] & 5))
  34386. +        an->stats.tx_packets++;
  34387. +
  34388. +    an->regs.transmitptr = an->tx_ends[an->txed++];
  34389. +    if(an->txed >= MAX_TXED)
  34390. +        an->txed = 0;
  34391. +    if(an->regs.transmitptr >= TX_END)
  34392. +        an->regs.transmitptr -= TX_END;
  34393. +/* if(an->regs.transmitptr != ((buffer[0]<<8)|buffer[1])) */
  34394. +/* printk("%p:%p\n",an->regs.transmitptr, (buffer[2]<<24)|(buffer[3]<<16)|(buffer[0]<<8)|buffer[1]); */
  34395. +    dev->tbusy = 0;
  34396. +    mark_bh(NET_BH);    /* Inform upper layers. */
  34397. +    if(an->use)
  34398. +    {
  34399. +        an->use--;
  34400. +        if(an->use == 0)
  34401. +        {
  34402. +            an->regs.config2 |= CFG2_CTRLO;
  34403. +            outw(an->regs.config2 , REG_CONFIG2);
  34404. +        }
  34405. +    }
  34406. +}
  34407. +
  34408. +/* The inverse routine to net_open(). */
  34409. +static int
  34410. +ether3_close(struct device *dev)
  34411. +{
  34412. +    FUNC_PROLOGUE;
  34413. +    unsigned long flags;
  34414. +
  34415. +    dev->tbusy = 1;
  34416. +    dev->start = 0;
  34417. +
  34418. +    save_flags(flags);
  34419. +    cli();
  34420. +
  34421. +    outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
  34422. +    an->regs.command = 0;
  34423. +    while(inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
  34424. +    ether3_init_1(dev);
  34425. +
  34426. +    restore_flags(flags);
  34427. +
  34428. +    /* Flush the Tx */
  34429. +#ifdef CLAIM_IRQ_AT_OPEN
  34430. +    free_irq(dev->irq);
  34431. +
  34432. +    irq2dev_map[dev->irq] = NULL;
  34433. +#endif
  34434. +
  34435. +    MOD_DEC_USE_COUNT;
  34436. +
  34437. +    return 0;
  34438. +
  34439. +}
  34440. +
  34441. +/* Get the current statistics.    This may be called with the card open or
  34442. +   closed. */
  34443. +static struct enet_statistics *
  34444. +ether3_get_stats(struct device *dev)
  34445. +{
  34446. +    FUNC_PROLOGUE;
  34447. +    return &an->stats;
  34448. +}
  34449. +
  34450. +/* Set or clear the multicast filter for this adaptor.
  34451. +   num_addrs == -1    Promiscuous mode, receive all packets
  34452. +   num_addrs == 0    Normal mode, clear multicast list
  34453. +   num_addrs > 0    Multicast mode, receive normal and MC packets, and do
  34454. +            best-effort filtering.
  34455. + */
  34456. +static void
  34457. +set_multicast_list(struct device *dev, int num_addrs, void *addrs)
  34458. +{
  34459. +    FUNC_PROLOGUE;
  34460. +
  34461. +    if(num_addrs == -1)
  34462. +        an->regs.config1 |= CFG1_RECVPROMISC;
  34463. +    else
  34464. +        an->regs.config1 = (an->regs.config1 & ~CFG1_RECVPROMISC)
  34465. +                    | CFG1_RECVSPECBROAD;
  34466. +
  34467. +    outw(an->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  34468. +}
  34469. +
  34470. +#ifdef MODULE
  34471. +char kernel_version[] = UTS_RELEASE;
  34472. +static struct device ether3 = {
  34473. +    "        ",
  34474. +    0, 0, 0, 0,
  34475. +    0, 0,
  34476. +    0, 0, 0, NULL, ether3_probe
  34477. +};
  34478. +
  34479. +char *ethernames[4] = {
  34480. +    "        ",
  34481. +    "        ",
  34482. +    "        ",
  34483. +    "        "
  34484. +};
  34485. +static struct device *my_ethers[4];
  34486. +static struct expansion_card *ec[4];
  34487. +
  34488. +int
  34489. +init_module(void)
  34490. +{
  34491. +    int i;
  34492. +
  34493. +    for(i = 0; i < 4; i++)
  34494. +    {
  34495. +        my_ethers[i] = NULL;
  34496. +        ec[i] = NULL;
  34497. +    }
  34498. +
  34499. +    i = 0;
  34500. +
  34501. +    do
  34502. +    {
  34503. +        if ((ec[i] = ecard_find(0, sizeof(ether3_prods), ether3_prods, ether3_manus)) == NULL)
  34504. +            break;
  34505. +
  34506. +        my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL);
  34507. +        memset(my_ethers[i], 0, sizeof(struct device));
  34508. +
  34509. +        my_ethers[i]->irq = ec[i]->irq;
  34510. +        my_ethers[i]->base_addr= ((unsigned long)ec[i]->r_podaddr & ~0x003c0000UL)>>2;
  34511. +        my_ethers[i]->init = ether3_probe;
  34512. +        my_ethers[i]->name = ethernames[i];
  34513. +
  34514. +        ether3_addr(my_ethers[i]->dev_addr, ec[i]);
  34515. +
  34516. +        ecard_claim(ec[i]);
  34517. +
  34518. +        if(register_netdev(my_ethers[i]) != 0)
  34519. +        {
  34520. +            for (i = 0; i < 4; i++)
  34521. +            {
  34522. +                if(my_ethers[i])
  34523. +                {
  34524. +                    kfree(my_ethers[i]);
  34525. +                    my_ethers[i] = NULL;
  34526. +                }
  34527. +                if(ec[i])
  34528. +                {
  34529. +                    ecard_release(ec[i]);
  34530. +                    ec[i] = NULL;
  34531. +                }
  34532. +            }
  34533. +            return -EIO;
  34534. +        }
  34535. +        i++;
  34536. +    }
  34537. +    while(i < 4);
  34538. +
  34539. +    return i != 0 ? 0 : -ENODEV;
  34540. +}
  34541. +
  34542. +void
  34543. +cleanup_module(void)
  34544. +{
  34545. +    if (MOD_IN_USE) {
  34546. +        printk("%s: device busy, remove delayed\n", ether3.name);
  34547. +    } else {
  34548. +        int i;
  34549. +        for(i = 0; i < 4; i++)
  34550. +        {
  34551. +            if(my_ethers[i])
  34552. +            {
  34553. +                unregister_netdev(my_ethers[i]);
  34554. +                my_ethers[i] = NULL;
  34555. +            }
  34556. +            if(ec[i])
  34557. +            {
  34558. +                ecard_release(ec[i]);
  34559. +                ec[i] = NULL;
  34560. +            }
  34561. +        }
  34562. +    }
  34563. +}
  34564. +#endif /* MODULE */
  34565. diff -r -u -N linux.orig/arch/arm/drivers/net/plip.c linux.arm/arch/arm/drivers/net/plip.c
  34566. --- linux.orig/arch/arm/drivers/net/plip.c    Thu Jan  1 01:00:00 1970
  34567. +++ linux.arm/arch/arm/drivers/net/plip.c    Fri Oct 27 23:15:01 1995
  34568. @@ -0,0 +1,1104 @@
  34569. +/* $Id: plip.c,v 1.12 1995/02/11 10:26:05 gniibe Exp $ */
  34570. +/* PLIP: A parallel port "network" driver for Linux. */
  34571. +/* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */
  34572. +/*
  34573. + * Authors:    Donald Becker,  <becker@super.org>
  34574. + *        Tommy Thorn, <thorn@daimi.aau.dk>
  34575. + *        Tanabe Hiroyasu, <hiro@sanpo.t.u-tokyo.ac.jp>
  34576. + *        Alan Cox, <gw4pts@gw4pts.ampr.org>
  34577. + *        Peter Bauer, <100136.3530@compuserve.com>
  34578. + *        Niibe Yutaka, <gniibe@mri.co.jp>
  34579. + *
  34580. + *        Modularization and ifreq/ifmap support by Alan Cox.
  34581. + *        Rewritten by Niibe Yutaka.
  34582. + *
  34583. + *        This program is free software; you can redistribute it and/or
  34584. + *        modify it under the terms of the GNU General Public License
  34585. + *        as published by the Free Software Foundation; either version
  34586. + *        2 of the License, or (at your option) any later version.
  34587. + */
  34588. +
  34589. +/*
  34590. + * Original version and the name 'PLIP' from Donald Becker <becker@super.org>
  34591. + * inspired by Russ Nelson's parallel port packet driver.
  34592. + *
  34593. + * NOTE:
  34594. + *     Tanabe Hiroyasu had changed the protocol, and it was in Linux v1.0.
  34595. + *     Because of the necessity to communicate to DOS machines with the
  34596. + *     Crynwr packet driver, Peter Bauer changed the protocol again
  34597. + *     back to original protocol.
  34598. + *
  34599. + *     This version follows original PLIP protocol. 
  34600. + *     So, this PLIP can't communicate the PLIP of Linux v1.0.
  34601. + */
  34602. +
  34603. +static char *version = "NET3 PLIP version 2.0 gniibe@mri.co.jp\n";
  34604. +
  34605. +/*
  34606. +  Sources:
  34607. +    Ideas and protocols came from Russ Nelson's <nelson@crynwr.com>
  34608. +    "parallel.asm" parallel port packet driver.
  34609. +
  34610. +  The "Crynwr" parallel port standard specifies the following protocol:
  34611. +    Trigger by sending '0x08' (this cause interrupt on other end)
  34612. +    count-low octet
  34613. +    count-high octet
  34614. +    ... data octets
  34615. +    checksum octet
  34616. +  Each octet is sent as <wait for rx. '0x1?'> <send 0x10+(octet&0x0F)>
  34617. +            <wait for rx. '0x0?'> <send 0x00+((octet>>4)&0x0F)>
  34618. +
  34619. +  The packet is encapsulated as if it were ethernet.
  34620. +
  34621. +  The cable used is a de facto standard parallel null cable -- sold as
  34622. +  a "LapLink" cable by various places.  You'll need a 12-conductor cable to
  34623. +  make one yourself.  The wiring is:
  34624. +    SLCTIN    17 - 17
  34625. +    GROUND    25 - 25
  34626. +    D0->ERROR    2 - 15        15 - 2
  34627. +    D1->SLCT    3 - 13        13 - 3
  34628. +    D2->PAPOUT    4 - 12        12 - 4
  34629. +    D3->ACK    5 - 10        10 - 5
  34630. +    D4->BUSY    6 - 11        11 - 6
  34631. +  Do not connect the other pins.  They are
  34632. +    D5,D6,D7 are 7,8,9
  34633. +    STROBE is 1, FEED is 14, INIT is 16
  34634. +    extra grounds are 18,19,20,21,22,23,24
  34635. +*/
  34636. +
  34637. +#ifdef MODULE
  34638. +#include <linux/module.h>
  34639. +#include <linux/version.h>
  34640. +#else
  34641. +#define MOD_INC_USE_COUNT
  34642. +#define MOD_DEC_USE_COUNT
  34643. +#endif
  34644. +
  34645. +#include <linux/kernel.h>
  34646. +#include <linux/sched.h>
  34647. +#include <linux/types.h>
  34648. +#include <linux/fcntl.h>
  34649. +#include <linux/interrupt.h>
  34650. +#include <linux/string.h>
  34651. +#include <linux/ptrace.h>
  34652. +#include <linux/if_ether.h>
  34653. +#include <asm/system.h>
  34654. +#include <asm/io.h>
  34655. +#include <linux/in.h>
  34656. +#include <linux/errno.h>
  34657. +#include <linux/delay.h>
  34658. +#include <linux/lp.h>
  34659. +
  34660. +#include <linux/netdevice.h>
  34661. +#include <linux/etherdevice.h>
  34662. +#include <linux/skbuff.h>
  34663. +#include <linux/if_plip.h>
  34664. +
  34665. +#include <linux/tqueue.h>
  34666. +#include <linux/ioport.h>
  34667. +#include <asm/bitops.h>
  34668. +#include <asm/irq.h>
  34669. +#include <asm/byteorder.h>
  34670. +
  34671. +/* Use 0 for production, 1 for verification, >2 for debug */
  34672. +#ifndef NET_DEBUG
  34673. +#define NET_DEBUG 1
  34674. +#endif
  34675. +static unsigned int net_debug = NET_DEBUG;
  34676. +
  34677. +/* In micro second */
  34678. +#define PLIP_DELAY_UNIT           1
  34679. +
  34680. +/* Connection time out = PLIP_TRIGGER_WAIT * PLIP_DELAY_UNIT usec */
  34681. +#define PLIP_TRIGGER_WAIT     500
  34682. +
  34683. +/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */
  34684. +#define PLIP_NIBBLE_WAIT        3000
  34685. +
  34686. +#define PAR_INTR_ON        (LP_PINITP|LP_PSELECP|LP_PINTEN)
  34687. +#define PAR_INTR_OFF        (LP_PINITP|LP_PSELECP)
  34688. +#define PAR_DATA(dev)        ((dev)->base_addr+0)
  34689. +#define PAR_STATUS(dev)        ((dev)->base_addr+1)
  34690. +#define PAR_CONTROL(dev)    ((dev)->base_addr+2)
  34691. +
  34692. +/* Bottom halfs */
  34693. +static void plip_kick_bh(struct device *dev);
  34694. +static void plip_bh(struct device *dev);
  34695. +
  34696. +/* Interrupt handler */
  34697. +static void plip_interrupt(int irq, struct pt_regs *regs);
  34698. +
  34699. +/* Functions for DEV methods */
  34700. +static int plip_rebuild_header(void *buff, struct device *dev,
  34701. +                   unsigned long raddr, struct sk_buff *skb);
  34702. +static int plip_tx_packet(struct sk_buff *skb, struct device *dev);
  34703. +static int plip_open(struct device *dev);
  34704. +static int plip_close(struct device *dev);
  34705. +static struct enet_statistics *plip_get_stats(struct device *dev);
  34706. +static int plip_config(struct device *dev, struct ifmap *map);
  34707. +static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
  34708. +
  34709. +enum plip_connection_state {
  34710. +    PLIP_CN_NONE=0,
  34711. +    PLIP_CN_RECEIVE,
  34712. +    PLIP_CN_SEND,
  34713. +    PLIP_CN_CLOSING,
  34714. +    PLIP_CN_ERROR
  34715. +};
  34716. +
  34717. +enum plip_packet_state {
  34718. +    PLIP_PK_DONE=0,
  34719. +    PLIP_PK_TRIGGER,
  34720. +    PLIP_PK_LENGTH_LSB,
  34721. +    PLIP_PK_LENGTH_MSB,
  34722. +    PLIP_PK_DATA,
  34723. +    PLIP_PK_CHECKSUM
  34724. +};
  34725. +
  34726. +enum plip_nibble_state {
  34727. +    PLIP_NB_BEGIN,
  34728. +    PLIP_NB_1,
  34729. +    PLIP_NB_2,
  34730. +};
  34731. +
  34732. +struct plip_local {
  34733. +    enum plip_packet_state state;
  34734. +    enum plip_nibble_state nibble;
  34735. +    union {
  34736. +        struct {
  34737. +#if defined(LITTLE_ENDIAN)
  34738. +            unsigned char lsb;
  34739. +            unsigned char msb;
  34740. +#elif defined(BIG_ENDIAN)
  34741. +            unsigned char msb;
  34742. +            unsigned char lsb;
  34743. +#else
  34744. +#error    "Please fix endianness defines in <asm/byteorder.h>"
  34745. +#endif                        
  34746. +        } b;
  34747. +        unsigned short h;
  34748. +    } length;
  34749. +    unsigned short byte;
  34750. +    unsigned char  checksum;
  34751. +    unsigned char  data;
  34752. +    struct sk_buff *skb;
  34753. +};
  34754. +
  34755. +struct net_local {
  34756. +    struct enet_statistics enet_stats;
  34757. +    struct tq_struct immediate;
  34758. +    struct tq_struct deferred;
  34759. +    struct plip_local snd_data;
  34760. +    struct plip_local rcv_data;
  34761. +    unsigned long  trigger;
  34762. +    unsigned long  nibble;
  34763. +    enum plip_connection_state connection;
  34764. +    unsigned short timeout_count;
  34765. +    char is_deferred;
  34766. +    int (*orig_rebuild_header)(void *eth, struct device *dev,
  34767. +                   unsigned long raddr, struct sk_buff *skb);
  34768. +};
  34769. +
  34770. +/* Entry point of PLIP driver.
  34771. +   Probe the hardware, and register/initialize the driver. */
  34772. +int
  34773. +plip_init(struct device *dev)
  34774. +{
  34775. +    struct net_local *nl;
  34776. +
  34777. +    /* Check region before the probe */
  34778. +    if (check_region(PAR_DATA(dev), 3) < 0)
  34779. +        return -ENODEV;
  34780. +
  34781. +    /* Check that there is something at base_addr. */
  34782. +    outb(0, PAR_DATA(dev));
  34783. +    udelay(1000);
  34784. +    if (inb(PAR_DATA(dev)) != 0)
  34785. +        return -ENODEV;
  34786. +
  34787. +    printk(version);
  34788. +    printk("%s: Parallel port at %#3lx, ", dev->name, dev->base_addr);
  34789. +    if (dev->irq) {
  34790. +        printk("using assigned IRQ %d.\n", dev->irq);
  34791. +    } else {
  34792. +        int irq = 0;
  34793. +#ifdef MODULE
  34794. +        /* dev->irq==0 means autoprobe, but we don't try to do so
  34795. +           with module.  We can change it by ifconfig */
  34796. +#else
  34797. +        unsigned int irqs = probe_irq_on();
  34798. +
  34799. +        outb(0x00, PAR_CONTROL(dev));
  34800. +        udelay(1000);
  34801. +        outb(PAR_INTR_OFF, PAR_CONTROL(dev));
  34802. +        outb(PAR_INTR_ON, PAR_CONTROL(dev));
  34803. +        outb(PAR_INTR_OFF, PAR_CONTROL(dev));
  34804. +        udelay(1000);
  34805. +        irq = probe_irq_off(irqs);
  34806. +#endif
  34807. +        if (irq > 0) {
  34808. +            dev->irq = irq;
  34809. +            printk("using probed IRQ %d.\n", dev->irq);
  34810. +        } else
  34811. +            printk("failed to detect IRQ(%d) --"
  34812. +                   " Please set IRQ by ifconfig.\n", irq);
  34813. +    }
  34814. +
  34815. +    request_region(PAR_DATA(dev), 3, dev->name);
  34816. +
  34817. +    /* Fill in the generic fields of the device structure. */
  34818. +    ether_setup(dev);
  34819. +
  34820. +    /* Then, override parts of it */
  34821. +    dev->hard_start_xmit    = plip_tx_packet;
  34822. +    dev->open        = plip_open;
  34823. +    dev->stop        = plip_close;
  34824. +    dev->get_stats         = plip_get_stats;
  34825. +    dev->set_config        = plip_config;
  34826. +    dev->do_ioctl        = plip_ioctl;
  34827. +    dev->flags            = IFF_POINTOPOINT|IFF_NOARP;
  34828. +
  34829. +    /* Set the private structure */
  34830. +    dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
  34831. +    if (dev->priv == NULL)
  34832. +        return EAGAIN;
  34833. +    memset(dev->priv, 0, sizeof(struct net_local));
  34834. +    nl = (struct net_local *) dev->priv;
  34835. +
  34836. +    nl->orig_rebuild_header = dev->rebuild_header;
  34837. +    dev->rebuild_header     = plip_rebuild_header;
  34838. +
  34839. +    /* Initialize constants */
  34840. +    nl->trigger    = PLIP_TRIGGER_WAIT;
  34841. +    nl->nibble    = PLIP_NIBBLE_WAIT;
  34842. +
  34843. +    /* Initialize task queue structures */
  34844. +    nl->immediate.next = &tq_last;
  34845. +    nl->immediate.sync = 0;
  34846. +    nl->immediate.routine = (void *)(void *)plip_bh;
  34847. +    nl->immediate.data = dev;
  34848. +
  34849. +    nl->deferred.next = &tq_last;
  34850. +    nl->deferred.sync = 0;
  34851. +    nl->deferred.routine = (void *)(void *)plip_kick_bh;
  34852. +    nl->deferred.data = dev;
  34853. +
  34854. +    return 0;
  34855. +}
  34856. +
  34857. +/* Bottom half handler for the delayed request.
  34858. +   This routine is kicked by do_timer().
  34859. +   Request `plip_bh' to be invoked. */
  34860. +static void
  34861. +plip_kick_bh(struct device *dev)
  34862. +{
  34863. +    struct net_local *nl = (struct net_local *)dev->priv;
  34864. +
  34865. +    if (nl->is_deferred) {
  34866. +        queue_task(&nl->immediate, &tq_immediate);
  34867. +        mark_bh(IMMEDIATE_BH);
  34868. +    }
  34869. +}
  34870. +
  34871. +/* Forward declarations of internal routines */
  34872. +static int plip_none(struct device *, struct net_local *,
  34873. +             struct plip_local *, struct plip_local *);
  34874. +static int plip_receive_packet(struct device *, struct net_local *,
  34875. +                   struct plip_local *, struct plip_local *);
  34876. +static int plip_send_packet(struct device *, struct net_local *,
  34877. +                struct plip_local *, struct plip_local *);
  34878. +static int plip_connection_close(struct device *, struct net_local *,
  34879. +                 struct plip_local *, struct plip_local *);
  34880. +static int plip_error(struct device *, struct net_local *,
  34881. +              struct plip_local *, struct plip_local *);
  34882. +static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,
  34883. +                 struct plip_local *snd,
  34884. +                 struct plip_local *rcv,
  34885. +                 int error);
  34886. +
  34887. +#define OK        0
  34888. +#define TIMEOUT   1
  34889. +#define ERROR     2
  34890. +
  34891. +typedef int (*plip_func)(struct device *dev, struct net_local *nl,
  34892. +             struct plip_local *snd, struct plip_local *rcv);
  34893. +
  34894. +static plip_func connection_state_table[] =
  34895. +{
  34896. +    plip_none,
  34897. +    plip_receive_packet,
  34898. +    plip_send_packet,
  34899. +    plip_connection_close,
  34900. +    plip_error
  34901. +};
  34902. +
  34903. +/* Bottom half handler of PLIP. */
  34904. +static void
  34905. +plip_bh(struct device *dev)
  34906. +{
  34907. +    struct net_local *nl = (struct net_local *)dev->priv;
  34908. +    struct plip_local *snd = &nl->snd_data;
  34909. +    struct plip_local *rcv = &nl->rcv_data;
  34910. +    plip_func f;
  34911. +    int r;
  34912. +
  34913. +    nl->is_deferred = 0;
  34914. +    f = connection_state_table[nl->connection];
  34915. +    if ((r = (*f)(dev, nl, snd, rcv)) != OK
  34916. +        && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
  34917. +        nl->is_deferred = 1;
  34918. +        queue_task(&nl->deferred, &tq_timer);
  34919. +    }
  34920. +}
  34921. +
  34922. +static int
  34923. +plip_bh_timeout_error(struct device *dev, struct net_local *nl,
  34924. +              struct plip_local *snd, struct plip_local *rcv,
  34925. +              int error)
  34926. +{
  34927. +    unsigned char c0;
  34928. +
  34929. +    cli();
  34930. +    if (nl->connection == PLIP_CN_SEND) {
  34931. +
  34932. +        if (error != ERROR) { /* Timeout */
  34933. +            nl->timeout_count++;
  34934. +            if ((snd->state == PLIP_PK_TRIGGER
  34935. +                 && nl->timeout_count <= 10)
  34936. +                || nl->timeout_count <= 3) {
  34937. +                sti();
  34938. +                /* Try again later */
  34939. +                return TIMEOUT;
  34940. +            }
  34941. +            c0 = inb(PAR_STATUS(dev));
  34942. +            printk("%s: transmit timeout(%d,%02x)\n",
  34943. +                   dev->name, snd->state, c0);
  34944. +        }
  34945. +        nl->enet_stats.tx_errors++;
  34946. +        nl->enet_stats.tx_aborted_errors++;
  34947. +    } else if (nl->connection == PLIP_CN_RECEIVE) {
  34948. +        if (rcv->state == PLIP_PK_TRIGGER) {
  34949. +            /* Transmission was interrupted. */
  34950. +            sti();
  34951. +            return OK;
  34952. +        }
  34953. +        if (error != ERROR) { /* Timeout */
  34954. +            if (++nl->timeout_count <= 3) {
  34955. +                sti();
  34956. +                /* Try again later */
  34957. +                return TIMEOUT;
  34958. +            }
  34959. +            c0 = inb(PAR_STATUS(dev));
  34960. +            printk("%s: receive timeout(%d,%02x)\n",
  34961. +                   dev->name, rcv->state, c0);
  34962. +        }
  34963. +        nl->enet_stats.rx_dropped++;
  34964. +    }
  34965. +    rcv->state = PLIP_PK_DONE;
  34966. +    if (rcv->skb) {
  34967. +        rcv->skb->free = 1;
  34968. +        kfree_skb(rcv->skb, FREE_READ);
  34969. +        rcv->skb = NULL;
  34970. +    }
  34971. +    snd->state = PLIP_PK_DONE;
  34972. +    if (snd->skb) {
  34973. +        dev_kfree_skb(snd->skb, FREE_WRITE);
  34974. +        snd->skb = NULL;
  34975. +    }
  34976. +    disable_irq(dev->irq);
  34977. +    outb(PAR_INTR_OFF, PAR_CONTROL(dev));
  34978. +    dev->tbusy = 1;
  34979. +    nl->connection = PLIP_CN_ERROR;
  34980. +    outb(0x00, PAR_DATA(dev));
  34981. +    sti();
  34982. +
  34983. +    return TIMEOUT;
  34984. +}
  34985. +
  34986. +static int
  34987. +plip_none(struct device *dev, struct net_local *nl,
  34988. +      struct plip_local *snd, struct plip_local *rcv)
  34989. +{
  34990. +    return OK;
  34991. +}
  34992. +
  34993. +/* PLIP_RECEIVE --- receive a byte(two nibbles)
  34994. +   Returns OK on success, TIMEOUT on timeout */
  34995. +inline static int
  34996. +plip_receive(unsigned short nibble_timeout, unsigned short status_addr,
  34997. +         enum plip_nibble_state *ns_p, unsigned char *data_p)
  34998. +{
  34999. +    unsigned char c0, c1;
  35000. +    unsigned int cx;
  35001. +
  35002. +    switch (*ns_p) {
  35003. +    case PLIP_NB_BEGIN:
  35004. +        cx = nibble_timeout;
  35005. +        while (1) {
  35006. +            c0 = inb(status_addr);
  35007. +            udelay(PLIP_DELAY_UNIT);
  35008. +            if ((c0 & 0x80) == 0) {
  35009. +                c1 = inb(status_addr);
  35010. +                if (c0 == c1)
  35011. +                    break;
  35012. +            }
  35013. +            if (--cx == 0)
  35014. +                return TIMEOUT;
  35015. +        }
  35016. +        *data_p = (c0 >> 3) & 0x0f;
  35017. +        outb(0x10, --status_addr); /* send ACK */
  35018. +        status_addr++;
  35019. +        *ns_p = PLIP_NB_1;
  35020. +
  35021. +    case PLIP_NB_1:
  35022. +        cx = nibble_timeout;
  35023. +        while (1) {
  35024. +            c0 = inb(status_addr);
  35025. +            udelay(PLIP_DELAY_UNIT);
  35026. +            if (c0 & 0x80) {
  35027. +                c1 = inb(status_addr);
  35028. +                if (c0 == c1)
  35029. +                    break;
  35030. +            }
  35031. +            if (--cx == 0)
  35032. +                return TIMEOUT;
  35033. +        }
  35034. +        *data_p |= (c0 << 1) & 0xf0;
  35035. +        outb(0x00, --status_addr); /* send ACK */
  35036. +        status_addr++;
  35037. +        *ns_p = PLIP_NB_BEGIN;
  35038. +        return OK;
  35039. +
  35040. +    case PLIP_NB_2:
  35041. +    }
  35042. +}
  35043. +
  35044. +/* PLIP_RECEIVE_PACKET --- receive a packet */
  35045. +static int
  35046. +plip_receive_packet(struct device *dev, struct net_local *nl,
  35047. +            struct plip_local *snd, struct plip_local *rcv)
  35048. +{
  35049. +    unsigned short status_addr = PAR_STATUS(dev);
  35050. +    unsigned short nibble_timeout = nl->nibble;
  35051. +    unsigned char *lbuf;
  35052. +
  35053. +    switch (rcv->state) {
  35054. +    case PLIP_PK_TRIGGER:
  35055. +        disable_irq(dev->irq);
  35056. +        outb(PAR_INTR_OFF, PAR_CONTROL(dev));
  35057. +        dev->interrupt = 0;
  35058. +        outb(0x01, PAR_DATA(dev)); /* send ACK */
  35059. +        if (net_debug > 2)
  35060. +            printk("%s: receive start\n", dev->name);
  35061. +        rcv->state = PLIP_PK_LENGTH_LSB;
  35062. +        rcv->nibble = PLIP_NB_BEGIN;
  35063. +
  35064. +    case PLIP_PK_LENGTH_LSB:
  35065. +        if (snd->state != PLIP_PK_DONE) {
  35066. +            if (plip_receive(nl->trigger, status_addr,
  35067. +                     &rcv->nibble, &rcv->length.b.lsb)) {
  35068. +                /* collision, here dev->tbusy == 1 */
  35069. +                rcv->state = PLIP_PK_DONE;
  35070. +                nl->is_deferred = 1;
  35071. +                nl->connection = PLIP_CN_SEND;
  35072. +                queue_task(&nl->deferred, &tq_timer);
  35073. +                outb(PAR_INTR_ON, PAR_CONTROL(dev));
  35074. +                enable_irq(dev->irq);
  35075. +                return OK;
  35076. +            }
  35077. +        } else {
  35078. +            if (plip_receive(nibble_timeout, status_addr,
  35079. +                     &rcv->nibble, &rcv->length.b.lsb))
  35080. +                return TIMEOUT;
  35081. +        }
  35082. +        rcv->state = PLIP_PK_LENGTH_MSB;
  35083. +
  35084. +    case PLIP_PK_LENGTH_MSB:
  35085. +        if (plip_receive(nibble_timeout, status_addr,
  35086. +                 &rcv->nibble, &rcv->length.b.msb))
  35087. +            return TIMEOUT;
  35088. +        if (rcv->length.h > dev->mtu || rcv->length.h < 8) {
  35089. +            printk("%s: bogus packet size %d.\n", dev->name, rcv->length.h);
  35090. +            return ERROR;
  35091. +        }
  35092. +        /* Malloc up new buffer. */
  35093. +        rcv->skb = alloc_skb(rcv->length.h, GFP_ATOMIC);
  35094. +        if (rcv->skb == NULL) {
  35095. +            printk("%s: Memory squeeze.\n", dev->name);
  35096. +            return ERROR;
  35097. +        }
  35098. +        rcv->skb->len = rcv->length.h;
  35099. +        rcv->skb->dev = dev;
  35100. +        rcv->state = PLIP_PK_DATA;
  35101. +        rcv->byte = 0;
  35102. +        rcv->checksum = 0;
  35103. +
  35104. +    case PLIP_PK_DATA:
  35105. +        lbuf = rcv->skb->data;
  35106. +        do
  35107. +            if (plip_receive(nibble_timeout, status_addr, 
  35108. +                     &rcv->nibble, &lbuf[rcv->byte]))
  35109. +                return TIMEOUT;
  35110. +        while (++rcv->byte < rcv->length.h);
  35111. +        do
  35112. +            rcv->checksum += lbuf[--rcv->byte];
  35113. +        while (rcv->byte);
  35114. +        rcv->state = PLIP_PK_CHECKSUM;
  35115. +
  35116. +    case PLIP_PK_CHECKSUM:
  35117. +        if (plip_receive(nibble_timeout, status_addr,
  35118. +                 &rcv->nibble, &rcv->data))
  35119. +            return TIMEOUT;
  35120. +        if (rcv->data != rcv->checksum) {
  35121. +            nl->enet_stats.rx_crc_errors++;
  35122. +            if (net_debug)
  35123. +                printk("%s: checksum error\n", dev->name);
  35124. +            return ERROR;
  35125. +        }
  35126. +        rcv->state = PLIP_PK_DONE;
  35127. +
  35128. +    case PLIP_PK_DONE:
  35129. +        /* Inform the upper layer for the arrival of a packet. */
  35130. +        netif_rx(rcv->skb);
  35131. +        nl->enet_stats.rx_packets++;
  35132. +        rcv->skb = NULL;
  35133. +        if (net_debug > 2)
  35134. +            printk("%s: receive end\n", dev->name);
  35135. +
  35136. +        /* Close the connection. */
  35137. +        outb (0x00, PAR_DATA(dev));
  35138. +        cli();
  35139. +        if (snd->state != PLIP_PK_DONE) {
  35140. +            nl->connection = PLIP_CN_SEND;
  35141. +            sti();
  35142. +            queue_task(&nl->immediate, &tq_immediate);
  35143. +            outb(PAR_INTR_ON, PAR_CONTROL(dev));
  35144. +            enable_irq(dev->irq);
  35145. +            return OK;
  35146. +        } else {
  35147. +            nl->connection = PLIP_CN_NONE;
  35148. +            sti();
  35149. +            outb(PAR_INTR_ON, PAR_CONTROL(dev));
  35150. +            enable_irq(dev->irq);
  35151. +            return OK;
  35152. +        }
  35153. +    }
  35154. +    return OK;
  35155. +}
  35156. +
  35157. +/* PLIP_SEND --- send a byte (two nibbles) 
  35158. +   Returns OK on success, TIMEOUT when timeout    */
  35159. +inline static int
  35160. +plip_send(unsigned short nibble_timeout, unsigned short data_addr,
  35161. +      enum plip_nibble_state *ns_p, unsigned char data)
  35162. +{
  35163. +    unsigned char c0;
  35164. +    unsigned int cx;
  35165. +
  35166. +    switch (*ns_p) {
  35167. +    case PLIP_NB_BEGIN:
  35168. +        outb((data & 0x0f), data_addr);
  35169. +        *ns_p = PLIP_NB_1;
  35170. +
  35171. +    case PLIP_NB_1:
  35172. +        outb(0x10 | (data & 0x0f), data_addr);
  35173. +        cx = nibble_timeout;
  35174. +        data_addr++;
  35175. +        while (1) {
  35176. +            c0 = inb(data_addr);
  35177. +            if ((c0 & 0x80) == 0) 
  35178. +                break;
  35179. +            if (--cx == 0)
  35180. +                return TIMEOUT;
  35181. +            udelay(PLIP_DELAY_UNIT);
  35182. +        }
  35183. +        outb(0x10 | (data >> 4), --data_addr);
  35184. +        *ns_p = PLIP_NB_2;
  35185. +
  35186. +    case PLIP_NB_2:
  35187. +        outb((data >> 4), data_addr);
  35188. +        data_addr++;
  35189. +        cx = nibble_timeout;
  35190. +        while (1) {
  35191. +            c0 = inb(data_addr);
  35192. +            if (c0 & 0x80)
  35193. +                break;
  35194. +            if (--cx == 0)
  35195. +                return TIMEOUT;
  35196. +            udelay(PLIP_DELAY_UNIT);
  35197. +        }
  35198. +        data_addr--;
  35199. +        *ns_p = PLIP_NB_BEGIN;
  35200. +        return OK;
  35201. +    }
  35202. +}
  35203. +
  35204. +/* PLIP_SEND_PACKET --- send a packet */
  35205. +static int
  35206. +plip_send_packet(struct device *dev, struct net_local *nl,
  35207. +         struct plip_local *snd, struct plip_local *rcv)
  35208. +{
  35209. +    unsigned short data_addr = PAR_DATA(dev);
  35210. +    unsigned short nibble_timeout = nl->nibble;
  35211. +    unsigned char *lbuf;
  35212. +    unsigned char c0;
  35213. +    unsigned int cx;
  35214. +
  35215. +    if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
  35216. +        printk("%s: send skb lost\n", dev->name);
  35217. +        snd->state = PLIP_PK_DONE;
  35218. +        snd->skb = NULL;
  35219. +        return ERROR;
  35220. +    }
  35221. +
  35222. +    switch (snd->state) {
  35223. +    case PLIP_PK_TRIGGER:
  35224. +        /* Trigger remote rx interrupt. */
  35225. +        outb(0x08, data_addr);
  35226. +        cx = nl->trigger;
  35227. +        while (1) {
  35228. +            udelay(PLIP_DELAY_UNIT);
  35229. +            cli();
  35230. +            if (nl->connection == PLIP_CN_RECEIVE) {
  35231. +                sti();
  35232. +                /* interrupted */
  35233. +                nl->enet_stats.collisions++;
  35234. +                if (net_debug > 1)
  35235. +                    printk("%s: collision.\n", dev->name);
  35236. +                return OK;
  35237. +            }
  35238. +            c0 = inb(PAR_STATUS(dev));
  35239. +            if (c0 & 0x08) {
  35240. +                disable_irq(dev->irq);
  35241. +                outb(PAR_INTR_OFF, PAR_CONTROL(dev));
  35242. +                if (net_debug > 2)
  35243. +                    printk("%s: send start\n", dev->name);
  35244. +                snd->state = PLIP_PK_LENGTH_LSB;
  35245. +                snd->nibble = PLIP_NB_BEGIN;
  35246. +                nl->timeout_count = 0;
  35247. +                sti();
  35248. +                break;
  35249. +            }
  35250. +            sti();
  35251. +            if (--cx == 0) {
  35252. +                outb(0x00, data_addr);
  35253. +                return TIMEOUT;
  35254. +            }
  35255. +        }
  35256. +
  35257. +    case PLIP_PK_LENGTH_LSB:
  35258. +        if (plip_send(nibble_timeout, data_addr,
  35259. +                  &snd->nibble, snd->length.b.lsb))
  35260. +            return TIMEOUT;
  35261. +        snd->state = PLIP_PK_LENGTH_MSB;
  35262. +
  35263. +    case PLIP_PK_LENGTH_MSB:
  35264. +        if (plip_send(nibble_timeout, data_addr,
  35265. +                  &snd->nibble, snd->length.b.msb))
  35266. +            return TIMEOUT;
  35267. +        snd->state = PLIP_PK_DATA;
  35268. +        snd->byte = 0;
  35269. +        snd->checksum = 0;
  35270. +
  35271. +    case PLIP_PK_DATA:
  35272. +        do
  35273. +            if (plip_send(nibble_timeout, data_addr,
  35274. +                      &snd->nibble, lbuf[snd->byte]))
  35275. +                return TIMEOUT;
  35276. +        while (++snd->byte < snd->length.h);
  35277. +        do
  35278. +            snd->checksum += lbuf[--snd->byte];
  35279. +        while (snd->byte);
  35280. +        snd->state = PLIP_PK_CHECKSUM;
  35281. +
  35282. +    case PLIP_PK_CHECKSUM:
  35283. +        if (plip_send(nibble_timeout, data_addr,
  35284. +                  &snd->nibble, snd->checksum))
  35285. +            return TIMEOUT;
  35286. +
  35287. +        dev_kfree_skb(snd->skb, FREE_WRITE);
  35288. +        nl->enet_stats.tx_packets++;
  35289. +        snd->state = PLIP_PK_DONE;
  35290. +
  35291. +    case PLIP_PK_DONE:
  35292. +        /* Close the connection */
  35293. +        outb (0x00, data_addr);
  35294. +        snd->skb = NULL;
  35295. +        if (net_debug > 2)
  35296. +            printk("%s: send end\n", dev->name);
  35297. +        nl->connection = PLIP_CN_CLOSING;
  35298. +        nl->is_deferred = 1;
  35299. +        queue_task(&nl->deferred, &tq_timer);
  35300. +        outb(PAR_INTR_ON, PAR_CONTROL(dev));
  35301. +        enable_irq(dev->irq);
  35302. +        return OK;
  35303. +    }
  35304. +    return OK;
  35305. +}
  35306. +
  35307. +static int
  35308. +plip_connection_close(struct device *dev, struct net_local *nl,
  35309. +              struct plip_local *snd, struct plip_local *rcv)
  35310. +{
  35311. +    cli();
  35312. +    if (nl->connection == PLIP_CN_CLOSING) {
  35313. +        nl->connection = PLIP_CN_NONE;
  35314. +        dev->tbusy = 0;
  35315. +        mark_bh(NET_BH);
  35316. +    }
  35317. +    sti();
  35318. +    return OK;
  35319. +}
  35320. +
  35321. +/* PLIP_ERROR --- wait till other end settled */
  35322. +static int
  35323. +plip_error(struct device *dev, struct net_local *nl,
  35324. +       struct plip_local *snd, struct plip_local *rcv)
  35325. +{
  35326. +    unsigned char status;
  35327. +
  35328. +    status = inb(PAR_STATUS(dev));
  35329. +    if ((status & 0xf8) == 0x80) {
  35330. +        if (net_debug > 2)
  35331. +            printk("%s: reset interface.\n", dev->name);
  35332. +        nl->connection = PLIP_CN_NONE;
  35333. +        dev->tbusy = 0;
  35334. +        dev->interrupt = 0;
  35335. +        outb(PAR_INTR_ON, PAR_CONTROL(dev));
  35336. +        enable_irq(dev->irq);
  35337. +        mark_bh(NET_BH);
  35338. +    } else {
  35339. +        nl->is_deferred = 1;
  35340. +        queue_task(&nl->deferred, &tq_timer);
  35341. +    }
  35342. +
  35343. +    return OK;
  35344. +}
  35345. +
  35346. +/* Handle the parallel port interrupts. */
  35347. +static void
  35348. +plip_interrupt(int irq, struct pt_regs * regs)
  35349. +{
  35350. +    struct device *dev = (struct device *) irq2dev_map[irq];
  35351. +    struct net_local *nl = (struct net_local *)dev->priv;
  35352. +    struct plip_local *rcv = &nl->rcv_data;
  35353. +    unsigned char c0;
  35354. +
  35355. +    if (dev == NULL) {
  35356. +        printk ("plip_interrupt: irq %d for unknown device.\n", irq);
  35357. +        return;
  35358. +    }
  35359. +
  35360. +    if (dev->interrupt)
  35361. +        return;
  35362. +
  35363. +    c0 = inb(PAR_STATUS(dev));
  35364. +    if ((c0 & 0xf8) != 0xc0) {
  35365. +        if (net_debug > 1)
  35366. +            printk("%s: spurious interrupt\n", dev->name);
  35367. +        return;
  35368. +    }
  35369. +    dev->interrupt = 1;
  35370. +    if (net_debug > 3)
  35371. +        printk("%s: interrupt.\n", dev->name);
  35372. +
  35373. +    cli();
  35374. +    switch (nl->connection) {
  35375. +    case PLIP_CN_CLOSING:
  35376. +        dev->tbusy = 0;
  35377. +    case PLIP_CN_NONE:
  35378. +    case PLIP_CN_SEND:
  35379. +        dev->last_rx = jiffies;
  35380. +        rcv->state = PLIP_PK_TRIGGER;
  35381. +        nl->connection = PLIP_CN_RECEIVE;
  35382. +        nl->timeout_count = 0;
  35383. +        queue_task(&nl->immediate, &tq_immediate);
  35384. +        mark_bh(IMMEDIATE_BH);
  35385. +        sti();
  35386. +        break;
  35387. +
  35388. +    case PLIP_CN_RECEIVE:
  35389. +        sti();
  35390. +        printk("%s: receive interrupt when receiving packet\n", dev->name);
  35391. +        break;
  35392. +
  35393. +    case PLIP_CN_ERROR:
  35394. +        sti();
  35395. +        printk("%s: receive interrupt in error state\n", dev->name);
  35396. +        break;
  35397. +    }
  35398. +}
  35399. +
  35400. +/* We don't need to send arp, for plip is point-to-point. */
  35401. +static int
  35402. +plip_rebuild_header(void *buff, struct device *dev, unsigned long dst,
  35403. +            struct sk_buff *skb)
  35404. +{
  35405. +    struct net_local *nl = (struct net_local *)dev->priv;
  35406. +    struct ethhdr *eth = (struct ethhdr *)buff;
  35407. +    int i;
  35408. +
  35409. +    if ((dev->flags & IFF_NOARP)==0)
  35410. +        return nl->orig_rebuild_header(buff, dev, dst, skb);
  35411. +
  35412. +    if (eth->h_proto != htons(ETH_P_IP)) {
  35413. +        printk("plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
  35414. +        memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
  35415. +        return 0;
  35416. +    }
  35417. +
  35418. +    for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
  35419. +        eth->h_dest[i] = 0xfc;
  35420. +    memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long));
  35421. +    return 0;
  35422. +}
  35423. +
  35424. +static int
  35425. +plip_tx_packet(struct sk_buff *skb, struct device *dev)
  35426. +{
  35427. +    struct net_local *nl = (struct net_local *)dev->priv;
  35428. +    struct plip_local *snd = &nl->snd_data;
  35429. +
  35430. +    if (dev->tbusy)
  35431. +        return 1;
  35432. +
  35433. +    /* If some higher layer thinks we've missed an tx-done interrupt
  35434. +       we are passed NULL. Caution: dev_tint() handles the cli()/sti()
  35435. +       itself. */
  35436. +    if (skb == NULL) {
  35437. +        dev_tint(dev);
  35438. +        return 0;
  35439. +    }
  35440. +
  35441. +    if (set_bit(0, (void*)&dev->tbusy) != 0) {
  35442. +        printk("%s: Transmitter access conflict.\n", dev->name);
  35443. +        return 1;
  35444. +    }
  35445. +
  35446. +    if (skb->len > dev->mtu) {
  35447. +        printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
  35448. +        dev->tbusy = 0;
  35449. +        return 0;
  35450. +    }
  35451. +
  35452. +    if (net_debug > 2)
  35453. +        printk("%s: send request\n", dev->name);
  35454. +
  35455. +    cli();
  35456. +    dev->trans_start = jiffies;
  35457. +    snd->skb = skb;
  35458. +    snd->length.h = skb->len;
  35459. +    snd->state = PLIP_PK_TRIGGER;
  35460. +    if (nl->connection == PLIP_CN_NONE) {
  35461. +        nl->connection = PLIP_CN_SEND;
  35462. +        nl->timeout_count = 0;
  35463. +    }
  35464. +    queue_task(&nl->immediate, &tq_immediate);
  35465. +    mark_bh(IMMEDIATE_BH);
  35466. +    sti();
  35467. +
  35468. +    return 0;
  35469. +}
  35470. +
  35471. +/* Open/initialize the board.  This is called (in the current kernel)
  35472. +   sometime after booting when the 'ifconfig' program is run.
  35473. +
  35474. +   This routine gets exclusive access to the parallel port by allocating
  35475. +   its IRQ line.
  35476. + */
  35477. +static int
  35478. +plip_open(struct device *dev)
  35479. +{
  35480. +    struct net_local *nl = (struct net_local *)dev->priv;
  35481. +    int i;
  35482. +
  35483. +    if (dev->irq == 0) {
  35484. +        printk("%s: IRQ is not set.  Please set it by ifconfig.\n", dev->name);
  35485. +        return -EAGAIN;
  35486. +    }
  35487. +    cli();
  35488. +    if (request_irq(dev->irq , plip_interrupt, 0, dev->name) != 0) {
  35489. +        sti();
  35490. +        printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
  35491. +        return -EAGAIN;
  35492. +    }
  35493. +    irq2dev_map[dev->irq] = dev;
  35494. +    sti();
  35495. +
  35496. +    /* Clear the data port. */
  35497. +    outb (0x00, PAR_DATA(dev));
  35498. +
  35499. +    /* Enable rx interrupt. */
  35500. +    outb(PAR_INTR_ON, PAR_CONTROL(dev));
  35501. +
  35502. +    /* Initialize the state machine. */
  35503. +    nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;
  35504. +    nl->rcv_data.skb = nl->snd_data.skb = NULL;
  35505. +    nl->connection = PLIP_CN_NONE;
  35506. +    nl->is_deferred = 0;
  35507. +
  35508. +    /* Fill in the MAC-level header. */
  35509. +    for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
  35510. +        dev->dev_addr[i] = 0xfc;
  35511. +    memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(unsigned long));
  35512. +
  35513. +    dev->interrupt = 0;
  35514. +    dev->start = 1;
  35515. +    dev->tbusy = 0;
  35516. +    MOD_INC_USE_COUNT;
  35517. +    return 0;
  35518. +}
  35519. +
  35520. +/* The inverse routine to plip_open (). */
  35521. +static int
  35522. +plip_close(struct device *dev)
  35523. +{
  35524. +    struct net_local *nl = (struct net_local *)dev->priv;
  35525. +    struct plip_local *snd = &nl->snd_data;
  35526. +    struct plip_local *rcv = &nl->rcv_data;
  35527. +
  35528. +    dev->tbusy = 1;
  35529. +    dev->start = 0;
  35530. +    cli();
  35531. +    free_irq(dev->irq);
  35532. +    irq2dev_map[dev->irq] = NULL;
  35533. +    nl->is_deferred = 0;
  35534. +    nl->connection = PLIP_CN_NONE;
  35535. +    sti();
  35536. +    outb(0x00, PAR_DATA(dev));
  35537. +
  35538. +    snd->state = PLIP_PK_DONE;
  35539. +    if (snd->skb) {
  35540. +        dev_kfree_skb(snd->skb, FREE_WRITE);
  35541. +        snd->skb = NULL;
  35542. +    }
  35543. +    rcv->state = PLIP_PK_DONE;
  35544. +    if (rcv->skb) {
  35545. +        rcv->skb->free = 1;
  35546. +        kfree_skb(rcv->skb, FREE_READ);
  35547. +        rcv->skb = NULL;
  35548. +    }
  35549. +
  35550. +    /* Reset. */
  35551. +    outb(0x00, PAR_CONTROL(dev));
  35552. +    MOD_DEC_USE_COUNT;
  35553. +    return 0;
  35554. +}
  35555. +
  35556. +static struct enet_statistics *
  35557. +plip_get_stats(struct device *dev)
  35558. +{
  35559. +    struct net_local *nl = (struct net_local *)dev->priv;
  35560. +    struct enet_statistics *r = &nl->enet_stats;
  35561. +
  35562. +    return r;
  35563. +}
  35564. +
  35565. +static int
  35566. +plip_config(struct device *dev, struct ifmap *map)
  35567. +{
  35568. +    if (dev->flags & IFF_UP)
  35569. +        return -EBUSY;
  35570. +
  35571. +    if (map->base_addr != (unsigned long)-1
  35572. +        && map->base_addr != dev->base_addr)
  35573. +        printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
  35574. +
  35575. +    if (map->irq != (unsigned char)-1)
  35576. +        dev->irq = map->irq;
  35577. +    return 0;
  35578. +}
  35579. +
  35580. +static int
  35581. +plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
  35582. +{
  35583. +    struct net_local *nl = (struct net_local *) dev->priv;
  35584. +    struct plipconf *pc = (struct plipconf *) &rq->ifr_data;
  35585. +    
  35586. +    switch(pc->pcmd) {
  35587. +    case PLIP_GET_TIMEOUT:
  35588. +        pc->trigger = nl->trigger;
  35589. +        pc->nibble  = nl->nibble;
  35590. +        break;
  35591. +    case PLIP_SET_TIMEOUT:
  35592. +        nl->trigger = pc->trigger;
  35593. +        nl->nibble  = pc->nibble;
  35594. +        break;
  35595. +    default:
  35596. +        return -EOPNOTSUPP;
  35597. +    }
  35598. +    return 0;
  35599. +}
  35600. +
  35601. +#ifdef MODULE
  35602. +char kernel_version[] = UTS_RELEASE;
  35603. +
  35604. +static struct device dev_plip0 = 
  35605. +{
  35606. +    "plip0" /*"plip"*/,
  35607. +    0, 0, 0, 0,        /* memory */
  35608. +    0x3BC, 5,        /* base, irq */
  35609. +    0, 0, 0, NULL, plip_init 
  35610. +};
  35611. +
  35612. +static struct device dev_plip1 = 
  35613. +{
  35614. +    "plip1" /*"plip"*/,
  35615. +    0, 0, 0, 0,        /* memory */
  35616. +    0x378, 7,        /* base, irq */
  35617. +    0, 0, 0, NULL, plip_init 
  35618. +};
  35619. +
  35620. +static struct device dev_plip2 = 
  35621. +{
  35622. +    "plip2" /*"plip"*/,
  35623. +    0, 0, 0, 0,        /* memory */
  35624. +    0x278, 2,        /* base, irq */
  35625. +    0, 0, 0, NULL, plip_init 
  35626. +};
  35627. +
  35628. +int
  35629. +init_module(void)
  35630. +{
  35631. +    int devices=0;
  35632. +
  35633. +    if (register_netdev(&dev_plip0) != 0)
  35634. +        devices++;
  35635. +    if (register_netdev(&dev_plip1) != 0)
  35636. +        devices++;
  35637. +    if (register_netdev(&dev_plip2) != 0)
  35638. +        devices++;
  35639. +    if (devices == 0)
  35640. +        return -EIO;
  35641. +    return 0;
  35642. +}
  35643. +
  35644. +void
  35645. +cleanup_module(void)
  35646. +{
  35647. +    if (dev_plip0.priv) {
  35648. +        unregister_netdev(&dev_plip0);
  35649. +        release_region(PAR_DATA(&dev_plip0), 3);
  35650. +        kfree_s(dev_plip0.priv, sizeof(struct net_local));
  35651. +        dev_plip0.priv = NULL;
  35652. +    }
  35653. +    if (dev_plip1.priv) {
  35654. +        unregister_netdev(&dev_plip1);
  35655. +        release_region(PAR_DATA(&dev_plip1), 3);
  35656. +        kfree_s(dev_plip1.priv, sizeof(struct net_local));
  35657. +        dev_plip1.priv = NULL;
  35658. +    }
  35659. +    if (dev_plip2.priv) {
  35660. +        unregister_netdev(&dev_plip2);
  35661. +        release_region(PAR_DATA(&dev_plip2), 3);
  35662. +        kfree_s(dev_plip2.priv, sizeof(struct net_local));
  35663. +        dev_plip2.priv = NULL;
  35664. +    }
  35665. +}
  35666. +#endif /* MODULE */
  35667. +
  35668. +/*
  35669. + * Local variables:
  35670. + * compile-command: "gcc -DMODULE -DCONFIG_MODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c plip.c"
  35671. + * End:
  35672. + */
  35673. diff -r -u -N linux.orig/arch/arm/drivers/net/ppp.c linux.arm/arch/arm/drivers/net/ppp.c
  35674. --- linux.orig/arch/arm/drivers/net/ppp.c    Thu Jan  1 01:00:00 1970
  35675. +++ linux.arm/arch/arm/drivers/net/ppp.c    Fri Oct 27 23:15:02 1995
  35676. @@ -0,0 +1,2126 @@
  35677. +/*
  35678. +   PPP for Linux
  35679. +*/
  35680. +
  35681. +/*
  35682. +   Sources:
  35683. +
  35684. +   slip.c
  35685. +
  35686. +   RFC1331: The Point-to-Point Protocol (PPP) for the Transmission of
  35687. +   Multi-protocol Datagrams over Point-to-Point Links
  35688. +
  35689. +   RFC1332: IPCP
  35690. +
  35691. +   ppp-2.0
  35692. +
  35693. +   Flags for this module (any combination is acceptable for testing.):
  35694. +
  35695. +   NET02D          -    Define if using Net-2-Debugged in kernels earlier
  35696. +               than v1.1.4.
  35697. +
  35698. +   NEW_TTY_DRIVERS    -    Define if using new Ted Ts'o's alpha TTY drivers
  35699. +               from tsx-11.mit.edu. From Ted Ts'o.
  35700. +
  35701. +   OPTIMIZE_FLAG_TIME -    Number of jiffies to force sending of leading flag
  35702. +            character. This is normally set to ((HZ * 3) / 2).
  35703. +            This is 1.5 seconds. If not defined then the leading
  35704. +            flag is always sent.  
  35705. +*/
  35706. +
  35707. +/* #define NET02D                -* */
  35708. +#define NEW_TTY_DRIVERS                /* */
  35709. +#define OPTIMIZE_FLAG_TIME  ((HZ * 3)/2)    /* */
  35710. +#define CHECK_CHARACTERS
  35711. +
  35712. +#ifdef MODULE
  35713. +#include <linux/module.h>
  35714. +#include <linux/version.h>
  35715. +#endif
  35716. +
  35717. +#include <linux/kernel.h>
  35718. +#include <linux/sched.h>
  35719. +#include <linux/types.h>
  35720. +#include <linux/fcntl.h>
  35721. +#include <linux/interrupt.h>
  35722. +#include <linux/ptrace.h>
  35723. +#include <linux/ioport.h>
  35724. +#include <linux/in.h>
  35725. +#include <linux/malloc.h>
  35726. +#include <linux/tty.h>
  35727. +#include <linux/errno.h>
  35728. +#include <linux/sched.h>   /* to get the struct task_struct */
  35729. +#include <linux/string.h>  /* used in new tty drivers */
  35730. +#include <linux/signal.h>  /* used in new tty drivers */
  35731. +#include <asm/system.h>
  35732. +#include <asm/bitops.h>
  35733. +#include <asm/segment.h>
  35734. +
  35735. +#ifdef NET02D                /* v1.1.4 net code and earlier */
  35736. +#include <dev.h>
  35737. +#include <skbuff.h>
  35738. +#include <inet.h>
  35739. +#define    skb_queue_head_init(buf)    *(buf) = NULL
  35740. +#else                    /* v1.1.5 and later */
  35741. +#include <linux/netdevice.h>
  35742. +#include <linux/skbuff.h>
  35743. +#include <linux/inet.h>
  35744. +#endif
  35745. +
  35746. +#include <linux/ppp.h>
  35747. +
  35748. +#include <linux/ip.h>
  35749. +#include <linux/tcp.h>
  35750. +
  35751. +#include "slhc.h"
  35752. +
  35753. +#include <linux/if_arp.h>
  35754. +#ifndef ARPHRD_PPP
  35755. +#define ARPHRD_PPP 0
  35756. +#endif
  35757. +
  35758. +#define PRINTK(p) printk p ;
  35759. +#define ASSERT(p) if (!p) PRINTK ((KERN_CRIT "assertion failed: " # p))
  35760. +#define PRINTKN(n,p) {if (ppp_debug >= n) PRINTK (p)}
  35761. +#define CHECK_PPP(a)  if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return a;}
  35762. +#define CHECK_PPP_VOID()  if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return;}
  35763. +
  35764. +#define in_xmap(ppp,c)    (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
  35765. +#define in_rmap(ppp,c)    ((((unsigned int) (unsigned char) (c)) < 0x20) && \
  35766. +            ppp->recv_async_map & (1 << (c)))
  35767. +
  35768. +#define bset(p,b)    ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
  35769. +
  35770. +int ppp_debug = 2;
  35771. +int ppp_debug_netpackets = 0;
  35772. +
  35773. +/* Define this string only once for all macro invocations */
  35774. +static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
  35775. +
  35776. +int ppp_init(struct device *);
  35777. +static void ppp_init_ctrl_blk(struct ppp *);
  35778. +static int ppp_dev_open(struct device *);
  35779. +static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
  35780. +static int ppp_dev_close(struct device *);
  35781. +static void ppp_kick_tty(struct ppp *);
  35782. +
  35783. +#ifdef NEW_TTY_DRIVERS
  35784. +#define ppp_find(tty) ((struct ppp *) tty->disc_data)
  35785. +#else
  35786. +static void ppp_output_done(void *);
  35787. +static void ppp_unesc(struct ppp *ppp, unsigned char *c, int n);
  35788. +static struct ppp *ppp_find(struct tty_struct *);
  35789. +#endif
  35790. +
  35791. +static void ppp_doframe(struct ppp *);
  35792. +static int ppp_do_ip(struct ppp *, unsigned short, unsigned char *, int);
  35793. +static int ppp_us_queue(struct ppp *, unsigned short, unsigned char *, int);
  35794. +static int ppp_xmit(struct sk_buff *, struct device *);
  35795. +static unsigned short ppp_type_trans(struct sk_buff *, struct device *);
  35796. +
  35797. +#ifdef NET02D
  35798. +static int ppp_header(unsigned char *buff, struct device *dev,
  35799. +              unsigned short type, unsigned long daddr,
  35800. +              unsigned long saddr, unsigned len);
  35801. +static int ppp_rebuild_header(void *buff, struct device *dev);
  35802. +static void ppp_add_arp(unsigned long addr, struct sk_buff *skb,
  35803. +            struct device *dev);
  35804. +#else
  35805. +static int ppp_header(unsigned char *, struct device *, unsigned short,
  35806. +              void *, void *, unsigned, struct sk_buff *);
  35807. +static int ppp_rebuild_header(void *, struct device *, unsigned long,
  35808. +                  struct sk_buff *);
  35809. +#endif
  35810. +
  35811. +static struct enet_statistics *ppp_get_stats (struct device *);
  35812. +static struct ppp *ppp_alloc(void);
  35813. +static int ppp_lock(struct ppp *);
  35814. +static void ppp_unlock(struct ppp *);
  35815. +static void ppp_add_fcs(struct ppp *);
  35816. +static int ppp_check_fcs(struct ppp *);
  35817. +static void ppp_print_buffer(const char *,char *,int,int);
  35818. +
  35819. +static int ppp_read(struct tty_struct *, struct file *, unsigned char *,
  35820. +            unsigned int);
  35821. +static int ppp_write(struct tty_struct *, struct file *, unsigned char *,
  35822. +             unsigned int);
  35823. +static int ppp_ioctl(struct tty_struct *, struct file *, unsigned int,
  35824. +             unsigned long);
  35825. +static int ppp_select(struct tty_struct *tty, struct inode * inode,
  35826. +              struct file * filp, int sel_type, select_table * wait);
  35827. +static int ppp_open(struct tty_struct *);
  35828. +static void ppp_close(struct tty_struct *);
  35829. +
  35830. +#ifdef NEW_TTY_DRIVERS
  35831. +static int ppp_receive_room(struct tty_struct *tty);
  35832. +static void ppp_receive_buf(struct tty_struct *tty, unsigned char *cp,
  35833. +                char *fp, int count);
  35834. +static void ppp_write_wakeup(struct tty_struct *tty);
  35835. +#else
  35836. +static void ppp_tty_input_ready(struct tty_struct *);
  35837. +#endif
  35838. +
  35839. +/* FCS table from RFC1331 */
  35840. +
  35841. +static unsigned short fcstab[256] = {
  35842. +  0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
  35843. +  0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
  35844. +  0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
  35845. +  0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
  35846. +  0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
  35847. +  0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
  35848. +  0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
  35849. +  0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
  35850. +  0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
  35851. +  0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
  35852. +  0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
  35853. +  0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
  35854. +  0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
  35855. +  0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
  35856. +  0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
  35857. +  0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
  35858. +  0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
  35859. +  0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
  35860. +  0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
  35861. +  0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
  35862. +  0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
  35863. +  0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
  35864. +  0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
  35865. +  0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
  35866. +  0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
  35867. +  0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
  35868. +  0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
  35869. +  0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
  35870. +  0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
  35871. +  0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
  35872. +  0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
  35873. +  0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
  35874. +  };
  35875. +
  35876. +struct tty_ldisc ppp_ldisc;
  35877. +
  35878. +static struct ppp ppp_ctrl[PPP_NRUNIT];
  35879. +
  35880. +/*************************************************************
  35881. + * INITIALIZATION
  35882. + *************************************************************/
  35883. +
  35884. +static int first_time = 1;
  35885. +
  35886. +/* called at boot time for each ppp device */
  35887. +
  35888. +int
  35889. +ppp_init(struct device *dev)
  35890. +{
  35891. +  struct ppp *ppp;
  35892. +  int i;
  35893. +
  35894. +  ppp = &ppp_ctrl[dev->base_addr];
  35895. +
  35896. +  if (first_time) {
  35897. +    first_time = 0;
  35898. +
  35899. +    printk (KERN_INFO "PPP: version %s (%d channels)"
  35900. +#ifdef NET02D
  35901. +       " NET02D"
  35902. +#endif
  35903. +#ifdef NEW_TTY_DRIVERS
  35904. +       " NEW_TTY_DRIVERS"
  35905. +#endif
  35906. +#ifdef OPTIMIZE_FLAG_TIME
  35907. +       " OPTIMIZE_FLAGS"
  35908. +#endif
  35909. +       "\n", PPP_VERSION, PPP_NRUNIT);
  35910. +
  35911. +    printk (KERN_INFO
  35912. +       "TCP compression code copyright 1989 Regents of the "
  35913. +       "University of California\n");
  35914. +
  35915. +    (void) memset(&ppp_ldisc, 0, sizeof(ppp_ldisc));
  35916. +    ppp_ldisc.open    = ppp_open;
  35917. +    ppp_ldisc.close   = ppp_close;
  35918. +    ppp_ldisc.read    = ppp_read;
  35919. +    ppp_ldisc.write   = ppp_write;
  35920. +    ppp_ldisc.ioctl   = ppp_ioctl;
  35921. +    ppp_ldisc.select  = ppp_select;
  35922. +
  35923. +#ifdef NEW_TTY_DRIVERS
  35924. +    ppp_ldisc.magic       = TTY_LDISC_MAGIC;
  35925. +    ppp_ldisc.receive_room = ppp_receive_room;
  35926. +    ppp_ldisc.receive_buf = ppp_receive_buf;
  35927. +    ppp_ldisc.write_wakeup = ppp_write_wakeup;
  35928. +#else
  35929. +    ppp_ldisc.handler     = ppp_tty_input_ready;
  35930. +#endif
  35931. +
  35932. +    if ((i = tty_register_ldisc(N_PPP, &ppp_ldisc)) == 0)
  35933. +      printk(KERN_INFO "PPP line discipline registered.\n");
  35934. +    else
  35935. +      printk(KERN_ERR "error registering line discipline: %d\n", i);
  35936. +  }
  35937. +
  35938. +  /* initialize PPP control block */
  35939. +  ppp_init_ctrl_blk (ppp);
  35940. +  ppp->inuse = 0;
  35941. +  ppp->line  = dev->base_addr;
  35942. +  ppp->tty   = NULL;
  35943. +  ppp->dev   = dev;
  35944. +
  35945. +  /* clear statistics */
  35946. +  memset (&ppp->stats, '\0', sizeof (struct ppp_stats));
  35947. +
  35948. +  /* device INFO */
  35949. +  dev->mtu             = PPP_MTU;
  35950. +  dev->hard_start_xmit = ppp_xmit;
  35951. +  dev->open            = ppp_dev_open;
  35952. +  dev->stop            = ppp_dev_close;
  35953. +  dev->get_stats       = ppp_get_stats;
  35954. +  dev->hard_header     = ppp_header;
  35955. +  dev->type_trans      = ppp_type_trans;
  35956. +  dev->rebuild_header  = ppp_rebuild_header;
  35957. +  dev->hard_header_len = 0;
  35958. +  dev->addr_len        = 0;
  35959. +  dev->type            = ARPHRD_PPP;
  35960. +
  35961. +#ifdef NET02D
  35962. +  dev->add_arp         = ppp_add_arp;
  35963. +  dev->queue_xmit      = dev_queue_xmit;
  35964. +#else
  35965. +  dev->do_ioctl        = ppp_dev_ioctl;
  35966. +#endif
  35967. +
  35968. +  for (i = 0; i < DEV_NUMBUFFS; i++)
  35969. +    skb_queue_head_init(&dev->buffs[i]);  /* = NULL if NET02D */
  35970. +
  35971. +  /* New-style flags */
  35972. +  dev->flags      = IFF_POINTOPOINT;
  35973. +  dev->family     = AF_INET;
  35974. +  dev->pa_addr    = 0;
  35975. +  dev->pa_brdaddr = 0;
  35976. +  dev->pa_mask    = 0;
  35977. +  dev->pa_alen    = sizeof(unsigned long);
  35978. +
  35979. +  return 0;
  35980. +}
  35981. +
  35982. +static void
  35983. +ppp_init_ctrl_blk(struct ppp *ppp)
  35984. +{
  35985. +  ppp->magic        = PPP_MAGIC;
  35986. +  ppp->sending        = 0;
  35987. +  ppp->toss        = 0xFE;
  35988. +  ppp->escape        = 0;
  35989. +
  35990. +  ppp->flags        = 0;
  35991. +  ppp->mtu        = PPP_MTU;
  35992. +  ppp->mru        = PPP_MRU;
  35993. +  ppp->fcs        = 0;
  35994. +
  35995. +  memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map));
  35996. +  ppp->xmit_async_map[0] = 0xffffffff;
  35997. +  ppp->xmit_async_map[3] = 0x60000000;
  35998. +  ppp->recv_async_map     = 0x00000000;
  35999. +
  36000. +  ppp->slcomp        = NULL;
  36001. +  ppp->rbuff        = NULL;
  36002. +  ppp->xbuff        = NULL;
  36003. +  ppp->cbuff        = NULL;
  36004. +
  36005. +  ppp->rhead        = NULL;
  36006. +  ppp->rend        = NULL;
  36007. +  ppp->rcount        = 0;
  36008. +  ppp->xhead        = NULL;
  36009. +  ppp->xtail        = NULL;
  36010. +
  36011. +  ppp->us_rbuff        = NULL;
  36012. +  ppp->us_rbuff_end    = NULL;
  36013. +  ppp->us_rbuff_head    = NULL;
  36014. +  ppp->us_rbuff_tail    = NULL;
  36015. +  ppp->read_wait    = NULL;
  36016. +  ppp->write_wait    = NULL;
  36017. +  ppp->us_rbuff_lock    = 0;
  36018. +  ppp->inp_sig        = 0;
  36019. +  ppp->inp_sig_pid    = 0;
  36020. +
  36021. +#ifdef OPTIMIZE_FLAG_TIME /* ensure flag will always be sent first time */
  36022. +  ppp->last_xmit    = jiffies - OPTIMIZE_FLAG_TIME;
  36023. +#else
  36024. +  ppp->last_xmit    = 0;
  36025. +#endif
  36026. +
  36027. +  /* clear statistics */
  36028. +  memset (&ppp->stats, '\0', sizeof (struct ppp_stats));
  36029. +
  36030. +  /* Reset the demand dial information */
  36031. +  ppp->ddinfo.ip_sjiffies  =
  36032. +  ppp->ddinfo.ip_rjiffies  =
  36033. +  ppp->ddinfo.nip_sjiffies =
  36034. +  ppp->ddinfo.nip_rjiffies = jiffies;
  36035. +}
  36036. +
  36037. +/*
  36038. + * MTU has been changed by the IP layer. Unfortunately we are not told
  36039. + * about this, but we spot it ourselves and fix things up. We could be
  36040. + * in an upcall from the tty driver, or in an ip packet queue.
  36041. + */
  36042. +   
  36043. +static void
  36044. +ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
  36045. +{
  36046. +  struct device *dev;
  36047. +  unsigned char *new_rbuff, *new_xbuff, *new_cbuff;
  36048. +  unsigned char *old_rbuff, *old_xbuff, *old_cbuff;
  36049. +  int mtu, mru;
  36050. +/*
  36051. + *  Allocate the buffer from the kernel for the data
  36052. + */
  36053. +  dev = ppp->dev;
  36054. +  mru = new_mru;
  36055. +  mtu = new_mtu;
  36056. +
  36057. +  /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
  36058. +  if (mru < PPP_MRU)
  36059. +    mru = PPP_MRU;
  36060. +
  36061. +  mtu = (mtu * 2) + 20;
  36062. +  mru = (mru * 2) + 20;
  36063. +
  36064. +  PRINTKN (2,(KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
  36065. +          dev->name, new_mtu, new_mru));
  36066. +    
  36067. +  new_xbuff = (unsigned char *) kmalloc(mtu + 4, GFP_ATOMIC);
  36068. +  new_rbuff = (unsigned char *) kmalloc(mru + 4, GFP_ATOMIC);
  36069. +  new_cbuff = (unsigned char *) kmalloc(mru + 4, GFP_ATOMIC);
  36070. +/*
  36071. + *  If the buffers failed to allocate then complain.
  36072. + */
  36073. +  if (new_xbuff == NULL || new_rbuff == NULL || new_cbuff == NULL)
  36074. +    {
  36075. +      PRINTKN (2,(KERN_ERR "ppp: failed to allocate new buffers\n"));
  36076. +/*
  36077. + *  Release new buffer pointers if the updates were not performed
  36078. + */
  36079. +      if (new_rbuff != NULL)
  36080. +    kfree (new_rbuff);
  36081. +
  36082. +      if (new_xbuff != NULL)
  36083. +    kfree (new_xbuff);
  36084. +
  36085. +      if (new_cbuff != NULL)
  36086. +    kfree (new_cbuff);
  36087. +    }
  36088. +/*
  36089. + *  Update the pointers to the new buffer structures.
  36090. + */
  36091. +  else
  36092. +    {
  36093. +      cli();
  36094. +      old_xbuff       = ppp->xbuff;
  36095. +      old_rbuff       = ppp->rbuff;
  36096. +      old_cbuff       = ppp->cbuff;
  36097. +
  36098. +      ppp->xbuff      = new_xbuff;
  36099. +      ppp->rbuff      = new_rbuff;
  36100. +      ppp->cbuff      = new_cbuff;
  36101. +
  36102. +      dev->mem_start  = (unsigned long) new_xbuff;
  36103. +      dev->mem_end    = (unsigned long) (dev->mem_start + mtu);
  36104. +
  36105. +      dev->rmem_start = (unsigned long) new_rbuff;
  36106. +      ppp->rend       = (unsigned char *)
  36107. +      dev->rmem_end   = (unsigned long) (dev->rmem_start + mru);
  36108. +
  36109. +      ppp->rhead      = new_rbuff;
  36110. +/*
  36111. + *  Update the parameters for the new buffer sizes
  36112. + */
  36113. +      ppp->toss        = 0xFE;
  36114. +      ppp->escape    = 0;
  36115. +      ppp->sending    = 0;
  36116. +      ppp->rcount    = 0;
  36117. +
  36118. +      ppp->mru        = new_mru;
  36119. +
  36120. +      ppp->mtu        =
  36121. +      dev->mtu        = new_mtu;
  36122. +
  36123. +      sti();
  36124. +/*
  36125. + *  Release old buffer pointers
  36126. + */
  36127. +      if (old_rbuff != NULL)
  36128. +    kfree (old_rbuff);
  36129. +
  36130. +      if (old_xbuff != NULL)
  36131. +    kfree (old_xbuff);
  36132. +
  36133. +      if (old_cbuff != NULL)
  36134. +    kfree (old_cbuff);
  36135. +    }
  36136. +}
  36137. +
  36138. +/* called when we abandon the PPP line discipline */
  36139. +
  36140. +static void
  36141. +ppp_release(struct ppp *ppp)
  36142. +{
  36143. +#ifdef NEW_TTY_DRIVERS
  36144. +  if (ppp->tty != NULL && ppp->tty->disc_data == ppp)
  36145. +    ppp->tty->disc_data = NULL; /* Break the tty->ppp link */
  36146. +#endif
  36147. +
  36148. +  if (ppp->dev) {
  36149. +    dev_close (ppp->dev);
  36150. +    ppp->dev->flags = 0;
  36151. +  }
  36152. +
  36153. +  kfree (ppp->xbuff);
  36154. +  kfree (ppp->cbuff);
  36155. +  kfree (ppp->rbuff);
  36156. +  kfree (ppp->us_rbuff);
  36157. +
  36158. +  ppp->xbuff    =
  36159. +  ppp->cbuff    =
  36160. +  ppp->rbuff    =
  36161. +  ppp->us_rbuff = NULL;
  36162. +
  36163. +  if (ppp->slcomp) {
  36164. +    slhc_free(ppp->slcomp);
  36165. +    ppp->slcomp = NULL;
  36166. +  }
  36167. +
  36168. +  ppp->inuse = 0;
  36169. +  ppp->tty   = NULL;
  36170. +}
  36171. +
  36172. +static void
  36173. +ppp_close(struct tty_struct *tty)
  36174. +{
  36175. +  struct ppp *ppp = ppp_find(tty);
  36176. +
  36177. +  if (ppp == NULL || ppp->magic != PPP_MAGIC) {
  36178. +    PRINTKN (1,(KERN_WARNING "ppp: trying to close unopened tty!\n"));
  36179. +  } else {
  36180. +    CHECK_PPP_VOID();
  36181. +    ppp_release (ppp);
  36182. +
  36183. +    PRINTKN (2,(KERN_INFO "ppp: channel %s closing.\n", ppp->dev->name));
  36184. +  }
  36185. +}
  36186. +
  36187. +/* called when PPP line discipline is selected on a tty */
  36188. +static int
  36189. +ppp_open(struct tty_struct *tty)
  36190. +{
  36191. +  struct ppp *ppp = ppp_find(tty);
  36192. +
  36193. +  if (ppp) {
  36194. +    PRINTKN (1,(KERN_ERR "ppp_open: gack! tty already associated to %s!\n",
  36195. +        ppp->magic == PPP_MAGIC ? ppp->dev->name : "unknown"));
  36196. +    return -EEXIST;
  36197. +  }
  36198. +
  36199. +  ppp = ppp_alloc();
  36200. +  if (ppp == NULL) {
  36201. +    PRINTKN (1,(KERN_ERR "ppp_open: couldn't allocate ppp channel\n"));
  36202. +    return -ENFILE;
  36203. +  }
  36204. +
  36205. +  /* make sure the channel is actually open */
  36206. +  ppp_init_ctrl_blk (ppp);
  36207. +
  36208. +  ppp->tty = tty;
  36209. +
  36210. +#ifdef NEW_TTY_DRIVERS
  36211. +  tty->disc_data = ppp;
  36212. +  if (tty->driver.flush_buffer)
  36213. +    tty->driver.flush_buffer(tty);
  36214. +  if (tty->ldisc.flush_buffer)
  36215. +    tty->ldisc.flush_buffer(tty);
  36216. +#else
  36217. +  tty_read_flush (tty);
  36218. +  tty_write_flush (tty);
  36219. +#endif
  36220. +
  36221. +  if ((ppp->slcomp = slhc_init(16, 16)) == NULL) {
  36222. +    PRINTKN (1,(KERN_ERR "ppp: no space for compression buffers!\n"));
  36223. +    ppp_release (ppp);
  36224. +    return -ENOMEM;
  36225. +  }
  36226. +
  36227. +  /* Define the buffers for operation */
  36228. +  ppp_changedmtu (ppp, ppp->dev->mtu, ppp->mru);
  36229. +  if (ppp->rbuff == NULL) {
  36230. +    ppp_release (ppp);
  36231. +    return -ENOMEM;
  36232. +  }
  36233. +
  36234. +  /* Allocate a user-level receive buffer */
  36235. +  ppp->us_rbuff = (unsigned char *) kmalloc (RBUFSIZE, GFP_KERNEL);
  36236. +  if (ppp->us_rbuff == NULL) {
  36237. +    PRINTKN (1,(KERN_ERR "ppp: no space for user receive buffer\n"));
  36238. +    ppp_release (ppp);
  36239. +    return -ENOMEM;
  36240. +  }
  36241. +
  36242. +  ppp->us_rbuff_head =
  36243. +  ppp->us_rbuff_tail = ppp->us_rbuff;
  36244. +  ppp->us_rbuff_end  = ppp->us_rbuff + RBUFSIZE;
  36245. +
  36246. +  PRINTKN (2,(KERN_INFO "ppp: channel %s open\n", ppp->dev->name));
  36247. +
  36248. +#ifdef MODULE
  36249. +  MOD_INC_USE_COUNT;
  36250. +#endif
  36251. +
  36252. +  return (ppp->line);
  36253. +}
  36254. +
  36255. +/* called when ppp interface goes "up".  here this just means we start
  36256. +   passing IP packets */
  36257. +static int
  36258. +ppp_dev_open(struct device *dev)
  36259. +{
  36260. +  struct ppp *ppp = &ppp_ctrl[dev->base_addr];
  36261. +
  36262. +  /* reset POINTOPOINT every time, since dev_close zaps it! */
  36263. +  dev->flags |= IFF_POINTOPOINT;
  36264. +
  36265. +  if (ppp->tty == NULL) {
  36266. +    PRINTKN (1,(KERN_ERR "ppp: %s not connected to a TTY! can't go open!\n",
  36267. +        dev->name));
  36268. +    return -ENXIO;
  36269. +  }
  36270. +
  36271. +  PRINTKN (2,(KERN_INFO "ppp: channel %s going up for IP packets!\n",
  36272. +          dev->name));
  36273. +
  36274. +  CHECK_PPP(-ENXIO);
  36275. +  return 0;
  36276. +}
  36277. +
  36278. +static int
  36279. +ppp_dev_close(struct device *dev)
  36280. +{
  36281. +  struct ppp *ppp = &ppp_ctrl[dev->base_addr];
  36282. +
  36283. +  if (ppp->tty == NULL) {
  36284. +    PRINTKN (1,(KERN_ERR "ppp: %s not connected to a TTY! can't go down!\n",
  36285. +        dev->name));
  36286. +    return -ENXIO;
  36287. +  }
  36288. +
  36289. +  PRINTKN (2,(KERN_INFO "ppp: channel %s going down for IP packets!\n",
  36290. +          dev->name));
  36291. +  CHECK_PPP(-ENXIO);
  36292. +#ifdef MODULE
  36293. +  MOD_DEC_USE_COUNT;
  36294. +#endif
  36295. +  return 0;
  36296. +}
  36297. +
  36298. +#ifndef NET02D
  36299. +static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
  36300. +{
  36301. +  struct ppp *ppp = &ppp_ctrl[dev->base_addr];
  36302. +  int    error;
  36303. +
  36304. +  struct stats
  36305. +  {
  36306. +    struct ppp_stats  ppp_stats;
  36307. +    struct slcompress slhc;
  36308. +  } *result;
  36309. +
  36310. +  error = verify_area (VERIFY_READ,
  36311. +               ifr->ifr_ifru.ifru_data,
  36312. +               sizeof (struct stats));
  36313. +
  36314. +  if (error == 0) {
  36315. +    result = (struct stats *) ifr->ifr_ifru.ifru_data;
  36316. +
  36317. +    memcpy_tofs (&result->ppp_stats, &ppp->stats, sizeof (struct ppp_stats));
  36318. +    if (ppp->slcomp)
  36319. +      memcpy_tofs (&result->slhc,    ppp->slcomp, sizeof (struct slcompress));
  36320. +  }
  36321. +
  36322. +  return error;
  36323. +}
  36324. +#endif
  36325. +
  36326. +/*************************************************************
  36327. + * TTY OUTPUT
  36328. + *    The following function delivers a fully-formed PPP
  36329. + *    frame in ppp->xbuff to the TTY for output.
  36330. + *************************************************************/
  36331. +
  36332. +#ifdef NEW_TTY_DRIVERS
  36333. +static inline void
  36334. +#else
  36335. +static void
  36336. +#endif
  36337. +ppp_output_done (void *ppp)
  36338. +{
  36339. +  /* unlock the transmitter queue */
  36340. +  ppp_unlock ((struct ppp *) ppp);
  36341. +
  36342. +  /* If the device is still up then enable the transmitter of the
  36343. +     next frame. */
  36344. +  if (((struct ppp *) ppp)->dev->flags & IFF_UP)
  36345. +#ifndef NET02D
  36346. +    mark_bh (NET_BH);
  36347. +#else
  36348. +    dev_tint (((struct ppp *) ppp)->dev);
  36349. +#endif
  36350. +
  36351. +  /* enable any blocked process pending transmission */
  36352. +  wake_up_interruptible (&((struct ppp *) ppp)->write_wait);
  36353. +}
  36354. +
  36355. +#ifndef NEW_TTY_DRIVERS
  36356. +static void
  36357. +ppp_kick_tty (struct ppp *ppp)
  36358. +{
  36359. +  register int count = ppp->xhead - ppp->xbuff;
  36360. +  register int answer;
  36361. +
  36362. +  ppp->stats.sbytes += count;
  36363. +
  36364. +  answer = tty_write_data (ppp->tty,
  36365. +               ppp->xbuff,
  36366. +               count,
  36367. +               ppp_output_done,
  36368. +               (void *) ppp);
  36369. +
  36370. +  if (answer == 0)
  36371. +    ppp_output_done (ppp);   /* Should not happen */
  36372. +  else
  36373. +    if (answer < 0) {
  36374. +      ppp->stats.serrors++;
  36375. +      ppp_output_done (ppp); /* unlock the transmitter */
  36376. +    }
  36377. +}
  36378. +
  36379. +#else
  36380. +
  36381. +static void
  36382. +ppp_kick_tty (struct ppp *ppp)
  36383. +{
  36384. +    register int count, actual;
  36385. +    
  36386. +    count = ppp->xhead - ppp->xbuff;
  36387. +    
  36388. +    actual = ppp->tty->driver.write(ppp->tty, 0, ppp->xbuff, count);
  36389. +    ppp->stats.sbytes += actual;
  36390. +    if (actual == count) {
  36391. +        ppp_output_done(ppp);
  36392. +    } else {
  36393. +        ppp->xtail = ppp->xbuff + actual;
  36394. +        ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
  36395. +    }
  36396. +}
  36397. +
  36398. +static void ppp_write_wakeup(struct tty_struct *tty)
  36399. +{
  36400. +    register int count, actual;
  36401. +    struct ppp *ppp = ppp_find(tty);
  36402. +
  36403. +    if (!ppp || ppp->magic != PPP_MAGIC) {
  36404. +        PRINTKN (1,
  36405. +             (KERN_ERR "PPP: write_wakeup called but couldn't "
  36406. +              "find PPP struct.\n"));
  36407. +        return;
  36408. +    }
  36409. +
  36410. +    if (!ppp->xtail)
  36411. +        return;
  36412. +
  36413. +    cli();
  36414. +    if (ppp->flags & SC_XMIT_BUSY) {
  36415. +        sti();
  36416. +        return;
  36417. +    }
  36418. +    ppp->flags |= SC_XMIT_BUSY;
  36419. +    sti();
  36420. +    
  36421. +    count = ppp->xhead - ppp->xtail;
  36422. +    
  36423. +    actual = tty->driver.write(tty, 0, ppp->xtail, count);
  36424. +    ppp->stats.sbytes += actual;
  36425. +    if (actual == count) {
  36426. +        ppp->xtail = 0;
  36427. +        tty->flags &= ~TTY_DO_WRITE_WAKEUP;
  36428. +
  36429. +        ppp_output_done(ppp);
  36430. +    } else {
  36431. +        ppp->xtail += actual;
  36432. +    }
  36433. +    ppp->flags &= ~SC_XMIT_BUSY;
  36434. +}
  36435. +#endif
  36436. +
  36437. +/*************************************************************
  36438. + * TTY INPUT
  36439. + *    The following functions handle input that arrives from
  36440. + *    the TTY.  It recognizes PPP frames and either hands them
  36441. + *    to the network layer or queues them for delivery to a
  36442. + *    user process reading this TTY.
  36443. + *************************************************************/
  36444. +
  36445. +/* stuff a single character into the receive buffer */
  36446. +
  36447. +static inline void
  36448. +ppp_enqueue(struct ppp *ppp, unsigned char c)
  36449. +{
  36450. +  unsigned long flags;
  36451. +
  36452. +  save_flags(flags);
  36453. +  cli();
  36454. +  if (ppp->rhead < ppp->rend) {
  36455. +    *ppp->rhead = c;
  36456. +    ppp->rhead++;
  36457. +    ppp->rcount++;
  36458. +  } else
  36459. +    ppp->stats.roverrun++;
  36460. +  restore_flags(flags);
  36461. +}
  36462. +
  36463. +#ifdef CHECK_CHARACTERS
  36464. +static unsigned paritytab[8] = {
  36465. +    0x96696996, 0x69969669, 0x69969669, 0x96696996,
  36466. +    0x69969669, 0x96696996, 0x96696996, 0x69969669
  36467. +};
  36468. +#endif
  36469. +
  36470. +#ifndef NEW_TTY_DRIVERS
  36471. +static void
  36472. +ppp_dump_inqueue(struct tty_struct *tty)
  36473. +{
  36474. +  int  head = tty->read_q.head,
  36475. +       tail = tty->read_q.tail,
  36476. +       i, count;
  36477. +  char buffer[8];
  36478. +
  36479. +  PRINTK ((KERN_DEBUG "INQUEUE: head %d tail %d imode %x:\n", head, tail, 
  36480. +       (unsigned int) tty->termios->c_iflag))
  36481. +
  36482. +  i     = tail;
  36483. +  count = 0;
  36484. +
  36485. +  while (i != head) {
  36486. +    buffer [count] = tty->read_q.buf[i];
  36487. +    if (++count == 8) {
  36488. +      ppp_print_buffer (NULL, buffer, 8, KERNEL_DS);
  36489. +      count = 0;
  36490. +    }
  36491. +    i = (i + 1) & (TTY_BUF_SIZE - 1);
  36492. +  }
  36493. +  ppp_print_buffer (NULL, buffer, count, KERNEL_DS);
  36494. +}
  36495. +
  36496. +/* called by lower levels of TTY driver when data becomes available.
  36497. +   all incoming data comes through this function. */
  36498. +
  36499. +void ppp_tty_input_ready(struct tty_struct *tty)
  36500. +{
  36501. +  struct ppp *ppp = ppp_find(tty);
  36502. +  int n, error;
  36503. +  unsigned char buff[128];
  36504. +
  36505. +/*  PRINTK( (KERN_DEBUG "PPP: handler called.\n") ) */
  36506. +  if (!ppp || ppp->magic != PPP_MAGIC) {
  36507. +    PRINTKN (1,
  36508. +         (KERN_ERR "PPP: handler called but couldn't find PPP struct.\n"));
  36509. +    return;
  36510. +  }
  36511. +
  36512. +  CHECK_PPP_VOID();
  36513. +
  36514. +  /* ZZZ */
  36515. +  if (ppp_debug >= 5)
  36516. +    ppp_dump_inqueue(ppp->tty);
  36517. +
  36518. +  do {
  36519. +    n = tty_read_raw_data(tty, buff, 128);
  36520. +    if ( n == 0 )        /* nothing there */
  36521. +      break;
  36522. +
  36523. +    if (ppp_debug >= 5)
  36524. +      ppp_print_buffer ("receive buffer", buff, n > 0 ? n : -n, KERNEL_DS);
  36525. +
  36526. +    if ( n < 0 ) {
  36527. +      /* Last character is error flag.
  36528. +     Process the previous characters, then set toss flag. */
  36529. +      n = (-n) - 1;
  36530. +      error = buff[n];
  36531. +    } else error = 0;
  36532. +    ppp->stats.rbytes += n;
  36533. +    ppp_unesc(ppp,buff,n);
  36534. +    if (error)
  36535. +      ppp->toss = error;
  36536. +  } while (1);
  36537. +}
  36538. +
  36539. +/* recover frame by undoing PPP escape mechanism;
  36540. +   copies N chars of input data from C into PPP->rbuff
  36541. +   calls ppp_doframe to dispose of any frames it finds
  36542. +*/
  36543. +
  36544. +static void
  36545. +ppp_unesc(struct ppp *ppp, unsigned char *c, int n)
  36546. +{
  36547. +  int i;
  36548. +
  36549. +  for (i = 0; i < n; i++, c++) {
  36550. +    PRINTKN (6,(KERN_DEBUG "(%x)", (unsigned int) *c));
  36551. +
  36552. +#ifdef CHECK_CHARACTERS
  36553. +    if (*c & 0x80)
  36554. +    sc->sc_flags |= SC_RCV_B7_1;
  36555. +    else
  36556. +    sc->sc_flags |= SC_RCV_B7_0;
  36557. +
  36558. +    if (paritytab[*c >> 5] & (1 << (*c & 0x1F)))
  36559. +    sc->sc_flags |= SC_RCV_ODDP;
  36560. +    else
  36561. +    sc->sc_flags |= SC_RCV_EVNP;
  36562. +#endif
  36563. +
  36564. +    switch (*c) {
  36565. +    case PPP_ESC:        /* PPP_ESC: invert 0x20 in next character */
  36566. +      ppp->escape = PPP_TRANS;
  36567. +      break;
  36568. +
  36569. +    case PPP_FLAG:        /* PPP_FLAG: end of frame */
  36570. +      if (ppp->escape)        /* PPP_ESC just before PPP_FLAG is illegal */
  36571. +    ppp->toss = 0xFF;
  36572. +
  36573. +      if ((ppp->toss & 0x80) == 0)
  36574. +    ppp_doframe(ppp);    /* pass frame on to next layers */
  36575. +
  36576. +      ppp->rcount = 0;
  36577. +      ppp->rhead  = ppp->rbuff;
  36578. +      ppp->escape = 0;
  36579. +      ppp->toss   = 0;
  36580. +      break;
  36581. +
  36582. +    default:            /* regular character */
  36583. +      if (!in_rmap (ppp, *c)) {
  36584. +    if (ppp->toss == 0)
  36585. +      ppp_enqueue (ppp, *c ^ ppp->escape);
  36586. +    ppp->escape = 0;
  36587. +      }
  36588. +      break;
  36589. +    }
  36590. +  }
  36591. +}
  36592. +
  36593. +#else
  36594. +static int ppp_receive_room(struct tty_struct *tty)
  36595. +{
  36596. +    return 65536;  /* We can handle an infinite amount of data. :-) */
  36597. +}
  36598. +
  36599. +
  36600. +static void ppp_receive_buf(struct tty_struct *tty, unsigned char *cp,
  36601. +                char *fp, int count)
  36602. +{
  36603. +  register struct ppp *ppp = ppp_find (tty);
  36604. +  unsigned char c;
  36605. +/*  PRINTK( ("PPP: handler called.\n") ); */
  36606. +
  36607. +  if (!ppp || ppp->magic != PPP_MAGIC) {
  36608. +    PRINTKN (1,("PPP: handler called but couldn't find "
  36609. +        "PPP struct.\n"));
  36610. +    return;
  36611. +  }
  36612. +
  36613. +  CHECK_PPP_VOID();
  36614. +  if (ppp_debug >= 5) {
  36615. +    ppp_print_buffer ("receive buffer", cp, count, KERNEL_DS);
  36616. +  }
  36617. +
  36618. +  ppp->stats.rbytes += count;
  36619. +  while (count-- > 0) {
  36620. +    c = *cp++;
  36621. +
  36622. +    if (fp) {
  36623. +      if (*fp && ppp->toss == 0)
  36624. +    ppp->toss = *fp;
  36625. +      fp++;
  36626. +    }
  36627. +
  36628. +#ifdef CHECK_CHARACTERS
  36629. +    if (c & 0x80)
  36630. +    ppp->flags |= SC_RCV_B7_1;
  36631. +    else
  36632. +    ppp->flags |= SC_RCV_B7_0;
  36633. +
  36634. +    if (paritytab[c >> 5] & (1 << (c & 0x1F)))
  36635. +    ppp->flags |= SC_RCV_ODDP;
  36636. +    else
  36637. +    ppp->flags |= SC_RCV_EVNP;
  36638. +#endif
  36639. +
  36640. +    switch (c) {
  36641. +    case PPP_ESC:        /* PPP_ESC: invert 0x20 in next character */
  36642. +      ppp->escape = PPP_TRANS;
  36643. +      break;
  36644. +
  36645. +    case PPP_FLAG:        /* PPP_FLAG: end of frame */
  36646. +      if (ppp->escape)        /* PPP_ESC just before PPP_FLAG is "cancel"*/
  36647. +    ppp->toss = 0xFF;
  36648. +
  36649. +      if ((ppp->toss & 0x80) == 0)
  36650. +    ppp_doframe(ppp);    /* pass frame on to next layers */
  36651. +
  36652. +      ppp->rcount = 0;
  36653. +      ppp->rhead  = ppp->rbuff;
  36654. +      ppp->escape = 0;
  36655. +      ppp->toss   = 0;
  36656. +      break;
  36657. +
  36658. +    default:            /* regular character */
  36659. +      if (!in_rmap (ppp, c)) {
  36660. +    if (ppp->toss == 0)
  36661. +      ppp_enqueue (ppp, c ^ ppp->escape);
  36662. +    ppp->escape = 0;
  36663. +      }
  36664. +    }
  36665. +  }
  36666. +}
  36667. +#endif
  36668. +
  36669. +/* on entry, a received frame is in ppp->rbuff
  36670. +   check it and dispose as appropriate */
  36671. +static void
  36672. +ppp_doframe(struct ppp *ppp)
  36673. +{
  36674. +  u_char *c = ppp->rbuff;
  36675. +  u_short proto;
  36676. +  int count = ppp->rcount;
  36677. +
  36678. +  /* forget it if we've already noticed an error */
  36679. +  if (ppp->toss) {
  36680. +    PRINTKN (1, (KERN_WARNING "ppp_toss: tossing frame, reason = %d\n",
  36681. +         ppp->toss));
  36682. +    slhc_toss (ppp->slcomp);
  36683. +    ppp->stats.rerrors++;
  36684. +    return;
  36685. +  }
  36686. +
  36687. +  /* do this before printing buffer to avoid generating copious output */
  36688. +  if (count == 0)
  36689. +    return;
  36690. +
  36691. +  if (ppp_debug >= 3)
  36692. +    ppp_print_buffer ("receive frame", c, count, KERNEL_DS);
  36693. +
  36694. +  if (count < 4) {
  36695. +    PRINTKN (1,(KERN_WARNING "ppp: got runt ppp frame, %d chars\n", count));
  36696. +    slhc_toss (ppp->slcomp);
  36697. +    ppp->stats.runts++;
  36698. +    return;
  36699. +  }
  36700. +
  36701. +  /* check PPP error detection field */
  36702. +  if (!ppp_check_fcs(ppp)) {
  36703. +    PRINTKN (1,(KERN_WARNING "ppp: frame with bad fcs\n"));
  36704. +    slhc_toss (ppp->slcomp);
  36705. +    ppp->stats.rerrors++;
  36706. +    return;
  36707. +  }
  36708. +
  36709. +  count -= 2;            /* ignore last two characters */
  36710. +
  36711. +  /* now we have a good frame */
  36712. +  /* figure out the protocol field */
  36713. +  if ((c[0] == PPP_ADDRESS) && (c[1] == PPP_CONTROL)) {
  36714. +    c = c + 2;            /* ADDR/CTRL not compressed, so skip */
  36715. +    count -= 2;
  36716. +  }
  36717. +
  36718. +  proto = (u_short) *c++;        /* PROTO compressed */
  36719. +  if (proto & 1) {
  36720. +    count--;
  36721. +  } else {
  36722. +    proto = (proto << 8) | (u_short) *c++; /* PROTO uncompressed */
  36723. +    count -= 2;
  36724. +  }
  36725. +
  36726. +  /* Send the frame to the network if the ppp device is up */
  36727. +  if ((ppp->dev->flags & IFF_UP) && ppp_do_ip(ppp, proto, c, count)) {
  36728. +    ppp->ddinfo.ip_rjiffies = jiffies;
  36729. +    return;
  36730. +  }
  36731. +
  36732. +  /* If we got here, it has to go to a user process doing a read,
  36733. +     so queue it.
  36734. +
  36735. +     User process expects to get whole frame (for some reason), so
  36736. +     use count+2 so as to include FCS field. */
  36737. +
  36738. +  if (ppp_us_queue (ppp, proto, c, count+2)) {
  36739. +    ppp->ddinfo.nip_rjiffies = jiffies;
  36740. +    ppp->stats.rothers++;
  36741. +    return;
  36742. +  }
  36743. +
  36744. +  /* couldn't cope. */
  36745. +  PRINTKN (1,(KERN_WARNING
  36746. +          "ppp: dropping packet on the floor: nobody could take it.\n"));
  36747. +  slhc_toss (ppp->slcomp);
  36748. +  ppp->stats.tossed++;
  36749. +}
  36750. +
  36751. +/* Examine packet at C, attempt to pass up to net layer. 
  36752. +   PROTO is the protocol field from the PPP frame.
  36753. +   Return 1 if could handle it, 0 otherwise.  */
  36754. +
  36755. +static int
  36756. +ppp_do_ip (struct ppp *ppp, unsigned short proto, unsigned char *c,
  36757. +      int count)
  36758. +{
  36759. +  int flags, done;
  36760. +
  36761. +  PRINTKN (4,(KERN_DEBUG "ppp_do_ip: proto %x len %d first byte %x\n",
  36762. +          (int) proto, count, c[0]));
  36763. +
  36764. +  if (ppp_debug_netpackets) {
  36765. +    PRINTK (("KERN_DEBUG %s <-- proto %x len %d\n", ppp->dev->name,
  36766. +         (int) proto, count));
  36767. +  }
  36768. +    
  36769. +  if (proto == PROTO_IP) {
  36770. +    ppp->stats.runcomp++;
  36771. +    goto sendit;
  36772. +  }
  36773. +
  36774. +  if ((proto == PROTO_VJCOMP) && !(ppp->flags & SC_REJ_COMP_TCP)) {
  36775. +    /* get space for uncompressing the header */
  36776. +    done = 0;
  36777. +    save_flags (flags);
  36778. +    cli();
  36779. +    if ((ppp->rhead + 80) < ppp->rend) {
  36780. +      ppp->rhead += 80;
  36781. +      ppp->rcount += 80;
  36782. +      done = 1;
  36783. +    }
  36784. +    restore_flags(flags);
  36785. +
  36786. +    if (! done)    {
  36787. +      PRINTKN (1,(KERN_NOTICE
  36788. +          "ppp: no space to decompress VJ compressed TCP header.\n"));
  36789. +      ppp->stats.roverrun++;
  36790. +      slhc_toss (ppp->slcomp);
  36791. +      return 1;
  36792. +    }
  36793. +
  36794. +    count = slhc_uncompress(ppp->slcomp, c, count);
  36795. +    if (count <= 0) {
  36796. +      ppp->stats.rerrors++;
  36797. +      PRINTKN (1,(KERN_NOTICE "ppp: error in VJ decompression\n"));
  36798. +      slhc_toss (ppp->slcomp);
  36799. +      return 1;
  36800. +    }
  36801. +    ppp->stats.rcomp++;
  36802. +    goto sendit;
  36803. +  }
  36804. +  
  36805. +  if ((proto == PROTO_VJUNCOMP) && !(ppp->flags & SC_REJ_COMP_TCP)) {
  36806. +    if (slhc_remember(ppp->slcomp, c, count) <= 0) {
  36807. +      ppp->stats.rerrors++;
  36808. +      PRINTKN (1,(KERN_NOTICE "ppp: error in VJ memorizing\n"));
  36809. +      slhc_toss (ppp->slcomp);
  36810. +      return 1;
  36811. +    }
  36812. +    ppp->stats.runcomp++;
  36813. +    goto sendit;
  36814. +  }
  36815. +
  36816. +  /* not ours */
  36817. +  return 0;
  36818. +
  36819. + sendit:
  36820. +  if (ppp_debug_netpackets) {
  36821. +    struct iphdr *iph = (struct iphdr *) c;
  36822. +    PRINTK ((KERN_INFO "%s <--    src %lx dst %lx len %d\n", ppp->dev->name, 
  36823. +         iph->saddr, iph->daddr, count))
  36824. +  }
  36825. +
  36826. +  /* receive the frame through the network software */
  36827. +  (void) dev_rint (c, count, 0, ppp->dev);
  36828. +  return 1;
  36829. +}
  36830. +
  36831. +/* stuff packet at BUF, length LEN, into the us_rbuff buffer
  36832. +   prepend PROTO information */
  36833. +
  36834. +#define PUTC(c,label) *ppp->us_rbuff_head++ = c; \
  36835. +                if (ppp->us_rbuff_head == ppp->us_rbuff_end) \
  36836. +                     ppp->us_rbuff_head = ppp->us_rbuff; \
  36837. +                if (ppp->us_rbuff_head == ppp->us_rbuff_tail) \
  36838. +                     goto label;
  36839. +#define GETC(c) c = *ppp->us_rbuff_tail++; \
  36840. +                if (ppp->us_rbuff_tail == ppp->us_rbuff_end) \
  36841. +                     ppp->us_rbuff_tail = ppp->us_rbuff;
  36842. +
  36843. +static int
  36844. +ppp_us_queue(struct ppp *ppp, unsigned short proto, 
  36845. +         unsigned char *buf, int len)
  36846. +{
  36847. +  int totlen;
  36848. +  unsigned char *saved_head;
  36849. +
  36850. +  totlen = len+2;        /* including protocol */
  36851. +
  36852. +  if (set_bit(1, &ppp->us_rbuff_lock)) {
  36853. +    PRINTKN (1, (KERN_NOTICE "ppp_us_queue: can't get lock\n"));
  36854. +    return 0;
  36855. +  }
  36856. +  saved_head = ppp->us_rbuff_head;
  36857. +
  36858. +  PUTC((totlen & 0xff00) >> 8, failure);
  36859. +  PUTC(totlen & 0x00ff, failure);
  36860. +  PUTC((proto & 0xff00) >> 8, failure);
  36861. +  PUTC(proto & 0x00ff, failure);
  36862. +
  36863. +  while (len-- > 0) {
  36864. +    PUTC(*buf++, failure);
  36865. +  }
  36866. +
  36867. +  PRINTKN (3, (KERN_INFO "ppp: successfully queued %d bytes\n", totlen));
  36868. +  clear_bit(1, &ppp->us_rbuff_lock);
  36869. +  wake_up_interruptible (&ppp->read_wait);
  36870. +
  36871. +#ifdef NEW_TTY_DRIVERS
  36872. +  kill_fasync(ppp->tty->fasync, SIGIO);
  36873. +#endif
  36874. +
  36875. +  if (ppp->inp_sig && ppp->inp_sig_pid)
  36876. +    if (kill_proc (ppp->inp_sig_pid, ppp->inp_sig, 1) != 0) {
  36877. +      /* process is gone */
  36878. +      PRINTKN (2,(KERN_NOTICE
  36879. +          "ppp: process that requested notification is gone\n"));
  36880. +      ppp->inp_sig = 0;
  36881. +      ppp->inp_sig_pid = 0;
  36882. +    }
  36883. +  return 1;
  36884. +
  36885. + failure:
  36886. +  ppp->us_rbuff_head = saved_head;
  36887. +  clear_bit(1, &ppp->us_rbuff_lock);
  36888. +
  36889. +  PRINTKN (1, (KERN_NOTICE "ppp_us_queue: ran out of buffer space.\n"));
  36890. +
  36891. +  return 0;
  36892. +}
  36893. +
  36894. +/*************************************************************
  36895. + * LINE DISCIPLINE SUPPORT
  36896. + *    The following functions form support user programs
  36897. + *    which read and write data on a TTY with the PPP line
  36898. + *    discipline.  Reading is done from a circular queue,
  36899. + *    filled by the lower TTY levels.
  36900. + *************************************************************/
  36901. +
  36902. +/* read a PPP frame from the us_rbuff circular buffer, 
  36903. +   waiting if necessary
  36904. +*/
  36905. +
  36906. +static int
  36907. +ppp_read(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigned int nr)
  36908. +{
  36909. +  struct ppp *ppp = ppp_find(tty);
  36910. +  unsigned char c;
  36911. +  int len, i;
  36912. +
  36913. +  if (!ppp || ppp->magic != PPP_MAGIC) {
  36914. +    PRINTKN (1,(KERN_ERR "ppp_read: cannot find ppp channel\n"));
  36915. +    return -EIO;
  36916. +  }
  36917. +
  36918. +  CHECK_PPP(-ENXIO);
  36919. +
  36920. +  PRINTKN (4,(KERN_DEBUG "ppp_read: called %x num %u\n",
  36921. +          (unsigned int) buf,
  36922. +          nr));
  36923. +
  36924. +  do {
  36925. +    /* try to acquire read lock */
  36926. +    if (set_bit(0, &ppp->us_rbuff_lock) == 0) {
  36927. +      /* got lock */
  36928. +      if (ppp->us_rbuff_head == ppp->us_rbuff_tail) {
  36929. +    /* no data */
  36930. +    PRINTKN (4,(KERN_DEBUG "ppp_read: no data\n"));
  36931. +    clear_bit(0, &ppp->us_rbuff_lock);
  36932. +        if (ppp->inp_sig) {
  36933. +      PRINTKN (4,(KERN_DEBUG "ppp_read: EWOULDBLOCK\n"));
  36934. +      return -EWOULDBLOCK;
  36935. +        } else goto wait;
  36936. +      }
  36937. +
  36938. +      /* reset the time of the last read operation */
  36939. +      ppp->ddinfo.nip_rjiffies = jiffies;
  36940. +
  36941. +      GETC (c); len = c << 8; GETC (c); len += c;
  36942. +
  36943. +      PRINTKN (4,(KERN_DEBUG "ppp_read: len = %d\n", len));
  36944. +
  36945. +      if (len + 2 > nr) {
  36946. +    /* frame too big; can't copy it, but do update us_rbuff_head */
  36947. +    PRINTKN (1,(KERN_DEBUG
  36948. +            "ppp: read of %u bytes too small for %d frame\n",
  36949. +            nr, len+2));
  36950. +    ppp->us_rbuff_head += len;
  36951. +    if (ppp->us_rbuff_head > ppp->us_rbuff_end)
  36952. +      ppp->us_rbuff_head += - (ppp->us_rbuff_end - ppp->us_rbuff);
  36953. +    clear_bit(0, &ppp->us_rbuff_lock);
  36954. +    wake_up_interruptible (&ppp->read_wait);
  36955. +    ppp->stats.rgiants++;
  36956. +    return -EOVERFLOW;        /* ZZZ; HACK! */
  36957. +      } else {
  36958. +    /* have the space: copy the packet, faking the first two bytes */
  36959. +    put_fs_byte (PPP_ADDRESS, buf++);
  36960. +    put_fs_byte (PPP_CONTROL, buf++);
  36961. +    i = len;
  36962. +    while (i-- > 0) {
  36963. +      GETC (c);
  36964. +      put_fs_byte (c, buf++);
  36965. +    }
  36966. +      }
  36967. +
  36968. +      clear_bit(0, &ppp->us_rbuff_lock);
  36969. +      PRINTKN (3,(KERN_DEBUG "ppp_read: passing %d bytes up\n", len + 2));
  36970. +      ppp->stats.rothers++;
  36971. +      return len + 2;
  36972. +    }
  36973. +
  36974. +    /* need to wait */
  36975. +  wait:
  36976. +    current->timeout = 0;
  36977. +    PRINTKN (3,(KERN_DEBUG "ppp_read: sleeping\n"));
  36978. +    interruptible_sleep_on (&ppp->read_wait);
  36979. +    if (current->signal & ~current->blocked)
  36980. +      return -EINTR;
  36981. +  } while (1);
  36982. +}
  36983. +
  36984. +/* stuff a character into the transmit buffer, using PPP's way of escaping
  36985. +   special characters.
  36986. +   also, update ppp->fcs to take account of new character */
  36987. +static inline void
  36988. +ppp_stuff_char(struct ppp *ppp, unsigned char c)
  36989. +{
  36990. +  int curpt = ppp->xhead - ppp->xbuff;
  36991. +  if ((curpt < 0) || (curpt > 3000)) {
  36992. +    PRINTK ((KERN_DEBUG "ppp_stuff_char: %x %x %d\n",
  36993. +         (unsigned int) ppp->xbuff, (unsigned int) ppp->xhead, curpt))
  36994. +  }
  36995. +  if (in_xmap (ppp, c)) {
  36996. +    *ppp->xhead++ = PPP_ESC;
  36997. +    *ppp->xhead++ = c ^ PPP_TRANS;
  36998. +  } else
  36999. +    *ppp->xhead++ = c;
  37000. +  ppp->fcs = (ppp->fcs >> 8) ^ fcstab[(ppp->fcs ^ c) & 0xff];
  37001. +}
  37002. +
  37003. +/* write a frame with NR chars from BUF to TTY
  37004. +   we have to put the FCS field on ourselves
  37005. +*/
  37006. +
  37007. +static int
  37008. +ppp_write(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigned int nr)
  37009. +{
  37010. +  struct ppp *ppp = ppp_find(tty);
  37011. +  int i;
  37012. +
  37013. +  if (!ppp || ppp->magic != PPP_MAGIC) {
  37014. +    PRINTKN (1,(KERN_ERR "ppp_write: cannot find ppp unit\n"));
  37015. +    return -EIO;
  37016. +  }
  37017. +
  37018. +  CHECK_PPP(-ENXIO);
  37019. +  
  37020. +  if (ppp->mtu != ppp->dev->mtu)    /* Someone has been ifconfigging */
  37021. +    ppp_changedmtu (ppp, ppp->dev->mtu, ppp->mru);
  37022. +
  37023. +  if (nr > ppp->mtu) {
  37024. +    PRINTKN (1,(KERN_WARNING
  37025. +        "ppp_write: truncating user packet from %u to mtu %d\n",
  37026. +        nr, ppp->mtu));
  37027. +    nr = ppp->mtu;
  37028. +  }
  37029. +
  37030. +  if (ppp_debug >= 3)
  37031. +    ppp_print_buffer ("write frame", buf, nr, USER_DS);
  37032. +
  37033. +  /* lock this PPP unit so we will be the only writer;
  37034. +     sleep if necessary */
  37035. +  while ((ppp->sending == 1) || !ppp_lock(ppp)) {
  37036. +    current->timeout = 0;
  37037. +    PRINTKN (3,(KERN_DEBUG "ppp_write: sleeping\n"));
  37038. +    interruptible_sleep_on(&ppp->write_wait);
  37039. +    if (current->signal & ~current->blocked)
  37040. +      return -EINTR;
  37041. +  }
  37042. +
  37043. +  /* OK, locked.  Stuff the given bytes into the buffer. */
  37044. +
  37045. +  PRINTKN(4,(KERN_DEBUG "ppp_write: acquired write lock\n"));
  37046. +  ppp->xhead = ppp->xbuff;
  37047. +
  37048. +#ifdef OPTIMIZE_FLAG_TIME
  37049. +  if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
  37050. +    *ppp->xhead++ = PPP_FLAG;
  37051. +  ppp->last_xmit = jiffies;
  37052. +#else      
  37053. +  *ppp->xhead++ = PPP_FLAG;
  37054. +#endif
  37055. +
  37056. +  ppp->fcs = PPP_FCS_INIT;
  37057. +  i = nr;
  37058. +  while (i-- > 0)
  37059. +    ppp_stuff_char(ppp,get_fs_byte(buf++));
  37060. +
  37061. +  ppp_add_fcs(ppp);        /* concatenate FCS at end */
  37062. +
  37063. +  *ppp->xhead++ = PPP_FLAG;
  37064. +  
  37065. +  /* reset the time of the last write operation */
  37066. +  ppp->ddinfo.nip_sjiffies = jiffies;
  37067. +
  37068. +  if (ppp_debug >= 6)
  37069. +    ppp_print_buffer ("xmit buffer", ppp->xbuff, ppp->xhead - ppp->xbuff, KERNEL_DS);
  37070. +  else {
  37071. +    PRINTKN (4,(KERN_DEBUG
  37072. +        "ppp_write: writing %d chars\n", ppp->xhead - ppp->xbuff));
  37073. +  }
  37074. +
  37075. +  /* packet is ready-to-go */
  37076. +  ++ppp->stats.sothers;
  37077. +  ppp_kick_tty(ppp);
  37078. +
  37079. +  return((int)nr);
  37080. +}
  37081. +static int
  37082. +ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
  37083. +      unsigned long l)
  37084. +{
  37085. +  struct ppp *ppp = ppp_find(tty);
  37086. +  register int temp_i = 0;
  37087. +  int error;
  37088. +
  37089. +  if (!ppp || ppp->magic != PPP_MAGIC) {
  37090. +    PRINTK ((KERN_ERR "ppp_ioctl: can't find PPP block from tty!\n"))
  37091. +    return -EBADF;
  37092. +  }
  37093. +
  37094. +  CHECK_PPP(-ENXIO);
  37095. +
  37096. +  /* This must be root user */
  37097. +  if (!suser())
  37098. +    return -EPERM;
  37099. +
  37100. +  switch (i) {
  37101. +  case PPPIOCSMRU:
  37102. +    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
  37103. +    if (error == 0) {
  37104. +      temp_i = (int) get_fs_long (l);
  37105. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %d\n", temp_i));
  37106. +      if (ppp->mru != temp_i)
  37107. +    ppp_changedmtu (ppp, ppp->dev->mtu, temp_i);
  37108. +    }
  37109. +    break;
  37110. +
  37111. +  case PPPIOCGFLAGS:
  37112. +    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
  37113. +    if (error == 0) {
  37114. +      temp_i = (ppp->flags & SC_MASK);
  37115. +#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
  37116. +      temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | SC_RCV_ODDP | SC_RCV_EVNP;
  37117. +#endif
  37118. +      put_fs_long ((long) temp_i, l);
  37119. +      PRINTKN (3,(KERN_DEBUG "ppp_ioctl: get flags: addr %lx flags %x\n",
  37120. +          l,
  37121. +          temp_i));
  37122. +    }
  37123. +    break;
  37124. +
  37125. +  case PPPIOCSFLAGS:
  37126. +    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
  37127. +    if (error == 0) {
  37128. +      temp_i      = (int) get_fs_long (l);
  37129. +      ppp->flags ^= ((ppp->flags ^ temp_i) & SC_MASK);
  37130. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: set flags to %x\n", temp_i));
  37131. +    }
  37132. +    break;
  37133. +
  37134. +  case PPPIOCGASYNCMAP:
  37135. +    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
  37136. +    if (error == 0) {
  37137. +      put_fs_long (ppp->xmit_async_map[0], l);
  37138. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: get asyncmap: addr %lx asyncmap %lx\n",
  37139. +          l, ppp->xmit_async_map[0]));
  37140. +    }
  37141. +    break;
  37142. +
  37143. +  case PPPIOCSASYNCMAP:
  37144. +    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
  37145. +    if (error == 0) {
  37146. +      ppp->xmit_async_map[0] = get_fs_long (l);
  37147. +      bset (ppp->xmit_async_map, PPP_FLAG);
  37148. +      bset (ppp->xmit_async_map, PPP_ESC);
  37149. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: set xmit asyncmap %lx\n",
  37150. +          ppp->xmit_async_map[0]));
  37151. +    }
  37152. +    break;
  37153. +
  37154. +  case PPPIOCRASYNCMAP:
  37155. +    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
  37156. +    if (error == 0) {
  37157. +      ppp->recv_async_map = get_fs_long (l);
  37158. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: set recv asyncmap %lx\n",
  37159. +          ppp->recv_async_map));
  37160. +    }
  37161. +    break;
  37162. +
  37163. +  case PPPIOCGUNIT:
  37164. +    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
  37165. +    if (error == 0) {
  37166. +      put_fs_long (ppp->dev->base_addr, l);
  37167. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: get unit: %ld", ppp->dev->base_addr));
  37168. +    }
  37169. +    break;
  37170. +
  37171. +  case PPPIOCSINPSIG:
  37172. +    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
  37173. +    if (error == 0) {
  37174. +      ppp->inp_sig     = (int) get_fs_long (l);
  37175. +      ppp->inp_sig_pid = current->pid;
  37176. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: set input signal %d\n", ppp->inp_sig));
  37177. +    }
  37178. +    break;
  37179. +
  37180. +  case PPPIOCSDEBUG:
  37181. +    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
  37182. +    if (error == 0) {
  37183. +      ppp_debug = (int) get_fs_long (l);
  37184. +      ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8;
  37185. +      ppp_debug &= 0xff;
  37186. +      PRINTKN (1, (KERN_INFO "ppp_ioctl: set debug level %d, netpacket %d\n", 
  37187. +           ppp_debug, ppp_debug_netpackets));
  37188. +    }
  37189. +    break;
  37190. +
  37191. +  case PPPIOCGDEBUG:
  37192. +    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
  37193. +    if (error == 0) {
  37194. +      put_fs_long ((long) (ppp_debug | (ppp_debug_netpackets << 8)), l);
  37195. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: get debug level %d\n", 
  37196. +          ppp_debug | (ppp_debug_netpackets << 8)));
  37197. +    }
  37198. +    break;
  37199. +
  37200. +  case PPPIOCGSTAT:
  37201. +    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (struct ppp_stats));
  37202. +    if (error == 0) {
  37203. +      memcpy_tofs ((void *) l, &ppp->stats, sizeof (struct ppp_stats));
  37204. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: read statistics\n"));
  37205. +    }
  37206. +    break;
  37207. +
  37208. +  case PPPIOCGTIME:
  37209. +    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (struct ppp_ddinfo));
  37210. +    if (error == 0) {
  37211. +      struct ppp_ddinfo cur_ddinfo;
  37212. +      unsigned long cur_jiffies = jiffies;
  37213. +
  37214. +      /* change absolute times to relative times. */
  37215. +      cur_ddinfo.ip_sjiffies  = cur_jiffies - ppp->ddinfo.ip_sjiffies;
  37216. +      cur_ddinfo.ip_rjiffies  = cur_jiffies - ppp->ddinfo.ip_rjiffies;
  37217. +      cur_ddinfo.nip_sjiffies = cur_jiffies - ppp->ddinfo.nip_sjiffies;
  37218. +      cur_ddinfo.nip_rjiffies = cur_jiffies - ppp->ddinfo.nip_rjiffies;
  37219. +      
  37220. +      memcpy_tofs ((void *) l, &cur_ddinfo, sizeof (struct ppp_ddinfo));
  37221. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: read demand dial info\n"));
  37222. +    }
  37223. +    break;
  37224. +
  37225. +  case PPPIOCGXASYNCMAP:
  37226. +    error = verify_area (VERIFY_WRITE,
  37227. +             (void *) l,
  37228. +             sizeof (ppp->xmit_async_map));
  37229. +    if (error == 0) {
  37230. +      memcpy_tofs ((void *) l,
  37231. +           ppp->xmit_async_map,
  37232. +           sizeof (ppp->xmit_async_map));
  37233. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: get xasyncmap: addr %lx\n", l));
  37234. +    }
  37235. +    break;
  37236. +
  37237. +  case PPPIOCSXASYNCMAP:
  37238. +    error = verify_area (VERIFY_READ, (void *) l,
  37239. +             sizeof (ppp->xmit_async_map));
  37240. +    if (error == 0) {
  37241. +      unsigned long temp_tbl [8];
  37242. +
  37243. +      memcpy_fromfs (temp_tbl, (void *) l, sizeof (ppp->xmit_async_map));
  37244. +      temp_tbl[1]  =  0x00000000; /* must not escape 0x20 - 0x3f */
  37245. +      temp_tbl[2] &= ~0x40000000; /* must not escape 0x5e        */
  37246. +      temp_tbl[3] |=  0x60000000; /* must escape 0x7d and 0x7e   */
  37247. +
  37248. +      if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
  37249. +      (temp_tbl[4] & temp_tbl[5]) != 0 ||
  37250. +      (temp_tbl[6] & temp_tbl[7]) != 0)
  37251. +    error = -EINVAL;
  37252. +      else {
  37253. +    memcpy (ppp->xmit_async_map, temp_tbl, sizeof (ppp->xmit_async_map));
  37254. +    PRINTKN (3,(KERN_INFO "ppp_ioctl: set xasyncmap\n"));
  37255. +      }
  37256. +    }
  37257. +    break;
  37258. +
  37259. +  case PPPIOCSMAXCID:
  37260. +    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
  37261. +    if (error == 0) {
  37262. +      temp_i = (int) get_fs_long (l) + 1;
  37263. +      PRINTKN (3,(KERN_INFO "ppp_ioctl: set maxcid to %d\n", temp_i));
  37264. +      if (ppp->slcomp != NULL)
  37265. +    slhc_free (ppp->slcomp);
  37266. +
  37267. +      ppp->slcomp = slhc_init (temp_i, temp_i);
  37268. +
  37269. +      if (ppp->slcomp == NULL) {
  37270. +    PRINTKN (1,(KERN_ERR "ppp: no space for compression buffers!\n"));
  37271. +    ppp_release (ppp);
  37272. +    error = -ENOMEM;
  37273. +      }
  37274. +    }
  37275. +    break;
  37276. +
  37277. +#ifdef NEW_TTY_DRIVERS
  37278. +    /* Allow stty to read, but not set, the serial port */
  37279. +  case TCGETS:
  37280. +  case TCGETA:
  37281. +    error = n_tty_ioctl(tty, file, i, l);
  37282. +    break;
  37283. +#endif
  37284. +
  37285. +/*
  37286. + *  All other ioctl() events will come here.
  37287. + */
  37288. +
  37289. +  default:
  37290. +    PRINTKN (1,(KERN_ERR "ppp_ioctl: invalid ioctl: %x, addr %lx\n",
  37291. +        i,
  37292. +        l));
  37293. +#ifdef NEW_TTY_DRIVERS
  37294. +    error = -ENOIOCTLCMD;
  37295. +#else
  37296. +    error = -EINVAL;
  37297. +#endif
  37298. +    break;
  37299. +  }
  37300. +  return error;
  37301. +}
  37302. +
  37303. +static int
  37304. +ppp_select (struct tty_struct *tty, struct inode * inode,
  37305. +        struct file * filp, int sel_type, select_table * wait)
  37306. +{
  37307. +  struct ppp *ppp = ppp_find (tty);
  37308. +  
  37309. +  if (!ppp || ppp->magic != PPP_MAGIC) {
  37310. +    PRINTK ((KERN_ERR "ppp_select: can't find PPP block from tty!\n"))
  37311. +    return -EBADF;
  37312. +  }
  37313. +  
  37314. +  /* If the PPP protocol is no longer active, return false */
  37315. +  CHECK_PPP (0);
  37316. +  
  37317. +  /* Process the request based upon the type desired */
  37318. +  switch (sel_type) {
  37319. +  case SEL_IN:
  37320. +    if (set_bit(0, &ppp->us_rbuff_lock) == 0) {
  37321. +      /* Test for the presence of data in the queue */
  37322. +      if (ppp->us_rbuff_head != ppp->us_rbuff_tail) {
  37323. +    clear_bit (0, &ppp->us_rbuff_lock);
  37324. +    return 1;
  37325. +      }
  37326. +      clear_bit (0, &ppp->us_rbuff_lock);
  37327. +    } /* fall through */
  37328. +
  37329. +  case SEL_EX:
  37330. +    /* Is there a pending error condition? */
  37331. +    if (tty->packet && tty->link->ctrl_status)
  37332. +      return 1;
  37333. +    
  37334. +    /* closed? */
  37335. +    if (tty->flags & (1 << TTY_SLAVE_CLOSED))
  37336. +      return 1;
  37337. +    
  37338. +    /* If the tty is disconnected, then this is an exception too */
  37339. +    if (tty_hung_up_p(filp))
  37340. +      return 1;
  37341. +
  37342. +    select_wait (&ppp->read_wait, wait);
  37343. +    break;
  37344. +    
  37345. +  case SEL_OUT:
  37346. +    if (ppp_lock (ppp)) {
  37347. +      if (ppp->sending == 0) {
  37348. +    ppp_unlock (ppp);
  37349. +    return 1;
  37350. +      }
  37351. +      ppp_unlock (ppp);
  37352. +    }
  37353. +    select_wait (&ppp->write_wait, wait);
  37354. +    break;
  37355. +  }
  37356. +  return 0;
  37357. +}
  37358. +
  37359. +/*************************************************************
  37360. + * NETWORK OUTPUT
  37361. + *    This routine accepts requests from the network layer
  37362. + *    and attempts to deliver the packets.
  37363. + *    It also includes various routines we are compelled to
  37364. + *    have to make the network layer work (arp, etc...).
  37365. + *************************************************************/
  37366. +
  37367. +int
  37368. +ppp_xmit(struct sk_buff *skb, struct device *dev)
  37369. +{
  37370. +  struct tty_struct *tty;
  37371. +  struct ppp *ppp;
  37372. +  unsigned char *p;
  37373. +  unsigned short proto;
  37374. +  int len;
  37375. +
  37376. +  /* just a little sanity check. */
  37377. +  if (skb == NULL) {
  37378. +    PRINTKN(3,(KERN_WARNING "ppp_xmit: null packet!\n"));
  37379. +    return 0;
  37380. +  }
  37381. +
  37382. +  /* Get pointers to the various components */
  37383. +  ppp   = &ppp_ctrl[dev->base_addr];
  37384. +  tty   = ppp->tty;
  37385. +  p     = (unsigned char *) (skb + 1);
  37386. +  len   = skb->len;
  37387. +  proto = PROTO_IP;
  37388. +
  37389. +  PRINTKN(4,(KERN_DEBUG "ppp_xmit [%s]: skb %lX busy %d\n", dev->name, 
  37390. +         (unsigned long int) skb, ppp->sending));
  37391. +
  37392. +  /* avoid race conditions when the link fails */
  37393. +  if (!ppp->inuse) {
  37394. +    dev_kfree_skb(skb, FREE_WRITE);
  37395. +    dev_close (dev);
  37396. +    return 0;
  37397. +  }
  37398. +
  37399. +  if (tty == NULL) {
  37400. +    PRINTKN(1,(KERN_ERR "ppp_xmit: %s not connected to a TTY!\n", dev->name));
  37401. +    goto done;
  37402. +  }
  37403. +
  37404. +  if (!(dev->flags & IFF_UP)) {
  37405. +    PRINTKN(1,(KERN_WARNING
  37406. +           "ppp_xmit: packet sent on interface %s, which is down for IP\n",
  37407. +           dev->name));
  37408. +    goto done;
  37409. +  }
  37410. +
  37411. +  /* get length from IP header as per Alan Cox bugfix for slip.c */
  37412. +  if (len < sizeof(struct iphdr)) {
  37413. +    PRINTKN(0,(KERN_ERR "ppp_xmit: given runt packet, ignoring\n"));
  37414. +    goto done;
  37415. +  }
  37416. +  len = ntohs( ((struct iphdr *)(skb->data)) -> tot_len );
  37417. +
  37418. +  /* If doing demand dial then divert the first frame to pppd. */
  37419. +  if (ppp->flags & SC_IP_DOWN) {
  37420. +    if (ppp->flags & SC_IP_FLUSH == 0) {
  37421. +      if (ppp_us_queue (ppp, proto, p, len))
  37422. +    ppp->flags |= SC_IP_FLUSH;
  37423. +    }
  37424. +    goto done;
  37425. +  }
  37426. +
  37427. +  /* Attempt to acquire send lock */
  37428. +  if (ppp->sending || !ppp_lock(ppp)) {
  37429. +    PRINTKN(3,(KERN_WARNING "ppp_xmit: busy\n"));
  37430. +    ppp->stats.sbusy++;
  37431. +    return 1;
  37432. +  }
  37433. +
  37434. +  ppp->xhead = ppp->xbuff;
  37435. +
  37436. +  /* try to compress, if VJ compression mode is on */
  37437. +  if (ppp->flags & SC_COMP_TCP) {
  37438. +    len = slhc_compress(ppp->slcomp, p, len, ppp->cbuff, &p, 
  37439. +            !(ppp->flags & SC_NO_TCP_CCID));
  37440. +    if (p[0] & SL_TYPE_COMPRESSED_TCP)
  37441. +      proto = PROTO_VJCOMP;
  37442. +    else {
  37443. +      if (p[0] >= SL_TYPE_UNCOMPRESSED_TCP) {
  37444. +    proto = PROTO_VJUNCOMP;
  37445. +    p[0] = (p[0] & 0x0f) | 0x40; 
  37446. +      }
  37447. +    }
  37448. +  }
  37449. +
  37450. +  /* increment appropriate counter */
  37451. +  if (proto == PROTO_VJCOMP)
  37452. +    ++ppp->stats.scomp;
  37453. +  else
  37454. +    ++ppp->stats.suncomp;
  37455. +      
  37456. +  if (ppp_debug_netpackets) {
  37457. +    struct iphdr *iph = (struct iphdr *) (skb + 1);
  37458. +    PRINTK ((KERN_DEBUG "%s ==> proto %x len %d src %x dst %x proto %d\n",
  37459. +        dev->name, (int) proto, (int) len, (int) iph->saddr,
  37460. +        (int) iph->daddr, (int) iph->protocol))
  37461. +  }
  37462. +
  37463. +  /* start of frame:   FLAG  ALL_STATIONS  CONTROL  <protohi> <protolo> */
  37464. +#ifdef OPTIMIZE_FLAG_TIME
  37465. +  if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
  37466. +    *ppp->xhead++ = PPP_FLAG;
  37467. +  ppp->last_xmit = jiffies;
  37468. +#else      
  37469. +  *ppp->xhead++ = PPP_FLAG;
  37470. +#endif
  37471. +
  37472. +  ppp->fcs = PPP_FCS_INIT;
  37473. +  if (!(ppp->flags & SC_COMP_AC)) { 
  37474. +    ppp_stuff_char(ppp, PPP_ADDRESS);
  37475. +    ppp_stuff_char(ppp, PPP_CONTROL);
  37476. +  }
  37477. +
  37478. +  if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xff00))
  37479. +    ppp_stuff_char(ppp, proto>>8);
  37480. +  ppp_stuff_char(ppp, proto&0xff);
  37481. +
  37482. +  /* data part */
  37483. +  while (len-- > 0)
  37484. +    ppp_stuff_char(ppp, *p++);
  37485. +
  37486. +  /* fcs and flag */
  37487. +  ppp_add_fcs(ppp);
  37488. +  *ppp->xhead++ = PPP_FLAG;
  37489. +
  37490. +  /* update the time for demand dial function */
  37491. +  ppp->ddinfo.ip_sjiffies = jiffies;
  37492. +
  37493. +  /* send it! */
  37494. +  if (ppp_debug >= 6)
  37495. +    ppp_print_buffer ("xmit buffer", ppp->xbuff, ppp->xhead - ppp->xbuff, KERNEL_DS);
  37496. +  else {
  37497. +    PRINTKN (4,(KERN_DEBUG
  37498. +        "ppp_write: writing %d chars\n", ppp->xhead - ppp->xbuff));
  37499. +  }
  37500. +
  37501. +  ppp_kick_tty(ppp);
  37502. +
  37503. + done:
  37504. +  dev_kfree_skb(skb, FREE_WRITE);
  37505. +  return 0;
  37506. +}
  37507. +  
  37508. +static unsigned short
  37509. +ppp_type_trans (struct sk_buff *skb, struct device *dev)
  37510. +{
  37511. +  return(htons(ETH_P_IP));
  37512. +}
  37513. +
  37514. +#ifdef NET02D
  37515. +static int
  37516. +ppp_header(unsigned char *buff, struct device *dev, unsigned short type,
  37517. +       unsigned long daddr, unsigned long saddr, unsigned len)
  37518. +{
  37519. +  return(0);
  37520. +}
  37521. +
  37522. +static int
  37523. +ppp_rebuild_header(void *buff, struct device *dev)
  37524. +{
  37525. +  return(0);
  37526. +}
  37527. +
  37528. +static void
  37529. +ppp_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
  37530. +{
  37531. +}
  37532. +
  37533. +#else
  37534. +
  37535. +static int
  37536. +ppp_header(unsigned char *buff, struct device *dev, unsigned short type,
  37537. +       void *daddr, void *saddr, unsigned len, struct sk_buff *skb)
  37538. +{
  37539. +  return(0);
  37540. +}
  37541. +
  37542. +static int
  37543. +ppp_rebuild_header(void *buff, struct device *dev, unsigned long raddr,
  37544. +           struct sk_buff *skb)
  37545. +{
  37546. +  return(0);
  37547. +}
  37548. +#endif
  37549. +
  37550. +static struct enet_statistics *
  37551. +ppp_get_stats (struct device *dev)
  37552. +{
  37553. +  struct ppp *ppp = &ppp_ctrl[dev->base_addr];
  37554. +  static struct enet_statistics ppp_stats;
  37555. +
  37556. +  ppp_stats.rx_packets = ppp->stats.rcomp + ppp->stats.runcomp;
  37557. +  ppp_stats.rx_errors = ppp->stats.rerrors;
  37558. +  ppp_stats.rx_dropped = ppp->stats.tossed;
  37559. +  ppp_stats.rx_fifo_errors = 0;
  37560. +  ppp_stats.rx_length_errors = ppp->stats.runts;
  37561. +  ppp_stats.rx_over_errors = ppp->stats.roverrun;
  37562. +  ppp_stats.rx_crc_errors = 0;
  37563. +  ppp_stats.rx_frame_errors = 0;
  37564. +  ppp_stats.tx_packets = ppp->stats.scomp + ppp->stats.suncomp;
  37565. +  ppp_stats.tx_errors = ppp->stats.serrors;
  37566. +  ppp_stats.tx_dropped = 0;
  37567. +  ppp_stats.tx_fifo_errors = 0;
  37568. +  ppp_stats.collisions = ppp->stats.sbusy;
  37569. +  ppp_stats.tx_carrier_errors = 0;
  37570. +  ppp_stats.tx_aborted_errors = 0;
  37571. +  ppp_stats.tx_window_errors = 0;
  37572. +  ppp_stats.tx_heartbeat_errors = 0;
  37573. +
  37574. +  PRINTKN (3, (KERN_INFO "ppp_get_stats called"));
  37575. +  return &ppp_stats;
  37576. +}
  37577. +
  37578. +/*************************************************************
  37579. + * UTILITIES
  37580. + *    Miscellany called by various functions above.
  37581. + *************************************************************/
  37582. +
  37583. +#ifndef NEW_TTY_DRIVERS
  37584. +/* find a PPP channel given a TTY */
  37585. +struct ppp *
  37586. +ppp_find(struct tty_struct *tty)
  37587. +{
  37588. +  int i;
  37589. +  for (i = 0; i < PPP_NRUNIT; i++)
  37590. +    if (ppp_ctrl[i].inuse && (ppp_ctrl[i].tty == tty)) return &ppp_ctrl[i];
  37591. +
  37592. +  return NULL;
  37593. +}
  37594. +#endif
  37595. +
  37596. +/* allocate a PPP channel */
  37597. +static struct ppp *
  37598. +ppp_alloc(void)
  37599. +{
  37600. +  int i;
  37601. +  for (i = 0; i < PPP_NRUNIT; i++)
  37602. +    if (!set_bit(0, &ppp_ctrl[i].inuse)) return &ppp_ctrl[i];
  37603. +
  37604. +  return NULL;
  37605. +}
  37606. +
  37607. +/* marks a PPP interface 'busy'.  user processes will wait, if
  37608. +   they try to write, and the network code will refrain from sending
  37609. +   return nonzero if succeeded in acquiring lock
  37610. +*/
  37611. +
  37612. +static int
  37613. +ppp_lock(struct ppp *ppp)
  37614. +{
  37615. +  int flags, locked;
  37616. +  save_flags(flags);
  37617. +  cli();
  37618. +  locked = ppp->sending;
  37619. +  ppp->sending = 1;
  37620. +  if (ppp->dev->flags & IFF_UP)
  37621. +    ppp->dev->tbusy = 1;
  37622. +  restore_flags(flags);
  37623. +  return locked == 0;
  37624. +}
  37625. +
  37626. +static void
  37627. +ppp_unlock(struct ppp *ppp)
  37628. +{
  37629. +  int flags;
  37630. +  save_flags(flags);
  37631. +  cli();
  37632. +  ppp->sending = 0;
  37633. +  if (ppp->dev->flags & IFF_UP)
  37634. +    ppp->dev->tbusy = 0;
  37635. +  restore_flags(flags);
  37636. +}
  37637. +
  37638. +/* FCS support functions */
  37639. +
  37640. +static void
  37641. +ppp_add_fcs(struct ppp *ppp)
  37642. +{
  37643. +  unsigned short fcs = ppp->fcs;
  37644. +
  37645. +  fcs ^= 0xffff;
  37646. +  ppp_stuff_char(ppp, fcs & 0x00ff);
  37647. +  ppp_stuff_char(ppp, (fcs & 0xff00) >> 8);
  37648. +  ASSERT (ppp->fcs == PPP_FCS_GOOD);
  37649. +  PRINTKN (4,(KERN_DEBUG "ppp_add_fcs: fcs is %lx\n",
  37650. +          (long) (unsigned long) fcs));
  37651. +}
  37652. +
  37653. +static int
  37654. +ppp_check_fcs(struct ppp *ppp)
  37655. +{
  37656. +  unsigned short fcs = PPP_FCS_INIT, msgfcs;
  37657. +  unsigned char *c = ppp->rbuff;
  37658. +  int i;
  37659. +
  37660. +  for (i = 0; i < ppp->rcount - 2; i++, c++)
  37661. +    fcs = (fcs >> 8) ^ fcstab[(fcs ^ *c) & 0xff];
  37662. +
  37663. +  fcs ^= 0xffff;
  37664. +  msgfcs = (c[1] << 8) + c[0];
  37665. +  PRINTKN (4,(KERN_INFO "ppp_check_fcs: got %lx want %lx\n",
  37666. +          (unsigned long) msgfcs, (unsigned long) fcs));
  37667. +  return fcs == msgfcs;
  37668. +}
  37669. +
  37670. +static char hex[] = "0123456789ABCDEF";
  37671. +
  37672. +static inline void ppp_print_hex (register char *out, char *in, int count)
  37673. +{
  37674. +  register unsigned char next_ch;
  37675. +
  37676. +  while (count-- > 0) {
  37677. +    next_ch = (unsigned char) get_fs_byte (in);
  37678. +
  37679. +    *out++  = hex[(next_ch >> 4) & 0x0F];
  37680. +    *out++  = hex[next_ch        & 0x0F];
  37681. +    ++out;
  37682. +    ++in;
  37683. +  }
  37684. +}
  37685. +
  37686. +static inline void ppp_print_char (register char *out, char *in, int count)
  37687. +{
  37688. +  register unsigned char next_ch;
  37689. +
  37690. +  while (count-- > 0) {
  37691. +    next_ch = (unsigned char) get_fs_byte (in);
  37692. +
  37693. +    if (next_ch < 0x20 || next_ch > 0x7e)
  37694. +      *out++ = '.';
  37695. +    else {
  37696. +      *out++ = next_ch;
  37697. +      if (next_ch == '%')    /* printk/syslogd has a bug !! */
  37698. +    *out++ = '%';
  37699. +    }
  37700. +    ++in;
  37701. +  }
  37702. +  *out = '\0';
  37703. +}
  37704. +
  37705. +static void ppp_print_buffer(const char *name, char *buf, int count, int seg)
  37706. +{
  37707. +  char line [44];
  37708. +  int  old_fs = get_fs();
  37709. +
  37710. +  set_fs (seg);
  37711. +
  37712. +  if (name != NULL)
  37713. +    PRINTK ((KERN_DEBUG "ppp: %s, count = %d\n", name, count));
  37714. +
  37715. +  while (count > 8) {
  37716. +    memset         (line, ' ', sizeof (line));
  37717. +    ppp_print_hex  (line, buf, 8);
  37718. +    ppp_print_char (&line[8 * 3], buf, 8);
  37719. +    PRINTK ((KERN_DEBUG "%s\n", line));
  37720. +    count -= 8;
  37721. +    buf   += 8;
  37722. +  }
  37723. +
  37724. +  if (count > 0) {
  37725. +    memset         (line, ' ', sizeof (line));
  37726. +    ppp_print_hex  (line, buf, count);
  37727. +    ppp_print_char (&line[8 * 3], buf, count);
  37728. +    PRINTK ((KERN_DEBUG "%s\n", line));
  37729. +  }
  37730. +
  37731. +  set_fs (old_fs);
  37732. +}
  37733. +
  37734. +#ifdef MODULE
  37735. +char kernel_version[] = UTS_RELEASE;
  37736. +
  37737. +static struct device dev_ppp[PPP_NRUNIT] = {
  37738. +    {
  37739. +        "ppp0",        /* ppp */
  37740. +        0, 0, 0, 0,    /* memory */
  37741. +        0, 0,        /* base, irq */
  37742. +        0, 0, 0, NULL, ppp_init,
  37743. +    }
  37744. +    , { "ppp1" , 0, 0, 0, 0,  1, 0, 0, 0, 0, NULL, ppp_init }
  37745. +    , { "ppp2" , 0, 0, 0, 0,  2, 0, 0, 0, 0, NULL, ppp_init }
  37746. +    , { "ppp3" , 0, 0, 0, 0,  3, 0, 0, 0, 0, NULL, ppp_init }
  37747. +
  37748. +#ifdef PPP_PPP_LOTS
  37749. +    , { "ppp4" , 0, 0, 0, 0,  4, 0, 0, 0, 0, NULL, ppp_init }
  37750. +    , { "ppp5" , 0, 0, 0, 0,  5, 0, 0, 0, 0, NULL, ppp_init }
  37751. +    , { "ppp6" , 0, 0, 0, 0,  6, 0, 0, 0, 0, NULL, ppp_init }
  37752. +    , { "ppp7" , 0, 0, 0, 0,  7, 0, 0, 0, 0, NULL, ppp_init }
  37753. +    , { "ppp8" , 0, 0, 0, 0,  8, 0, 0, 0, 0, NULL, ppp_init }
  37754. +    , { "ppp9" , 0, 0, 0, 0,  9, 0, 0, 0, 0, NULL, ppp_init }
  37755. +    , { "ppp10" , 0, 0, 0, 0, 10, 0, 0, 0, 0, NULL, ppp_init }
  37756. +    , { "ppp11" , 0, 0, 0, 0, 11, 0, 0, 0, 0, NULL, ppp_init }
  37757. +    , { "ppp12" , 0, 0, 0, 0, 12, 0, 0, 0, 0, NULL, ppp_init }
  37758. +    , { "ppp13" , 0, 0, 0, 0, 13, 0, 0, 0, 0, NULL, ppp_init }
  37759. +    , { "ppp14" , 0, 0, 0, 0, 14, 0, 0, 0, 0, NULL, ppp_init }
  37760. +    , { "ppp15" , 0, 0, 0, 0, 15, 0, 0, 0, 0, NULL, ppp_init }
  37761. +#endif
  37762. +};
  37763. +
  37764. +int
  37765. +init_module(void)
  37766. +{
  37767. +    int err;
  37768. +    int i;
  37769. +
  37770. +    for (i = 0; i < PPP_NRUNIT; i++)  {
  37771. +        if ((err = register_netdev(&dev_ppp[i])))  {
  37772. +            if (err == -EEXIST)  {
  37773. +                printk("PPP: devices already present. Module not loaded.\n");
  37774. +            }
  37775. +            return err;
  37776. +        }
  37777. +    }
  37778. +    return 0;
  37779. +}
  37780. +
  37781. +void
  37782. +cleanup_module(void)
  37783. +{
  37784. +    int i;
  37785. +
  37786. +    if (MOD_IN_USE)  {
  37787. +        printk("PPP: device busy, remove delayed\n");
  37788. +        return;
  37789. +    }
  37790. +    for (i = 0; i < PPP_NRUNIT; i++)  {
  37791. +        unregister_netdev(&dev_ppp[i]);
  37792. +    }
  37793. +    if ((i = tty_register_ldisc(N_PPP, NULL)))  {
  37794. +        printk("PPP: can't unregister line discipline (err = %d)\n", i);
  37795. +    }
  37796. +}
  37797. +
  37798. +#endif
  37799. diff -r -u -N linux.orig/arch/arm/drivers/net/slhc.c linux.arm/arch/arm/drivers/net/slhc.c
  37800. --- linux.orig/arch/arm/drivers/net/slhc.c    Thu Jan  1 01:00:00 1970
  37801. +++ linux.arm/arch/arm/drivers/net/slhc.c    Fri Oct 27 23:15:05 1995
  37802. @@ -0,0 +1,747 @@
  37803. +/*
  37804. + * Routines to compress and uncompress tcp packets (for transmission
  37805. + * over low speed serial lines).
  37806. + *
  37807. + * Copyright (c) 1989 Regents of the University of California.
  37808. + * All rights reserved.
  37809. + *
  37810. + * Redistribution and use in source and binary forms are permitted
  37811. + * provided that the above copyright notice and this paragraph are
  37812. + * duplicated in all such forms and that any documentation,
  37813. + * advertising materials, and other materials related to such
  37814. + * distribution and use acknowledge that the software was developed
  37815. + * by the University of California, Berkeley.  The name of the
  37816. + * University may not be used to endorse or promote products derived
  37817. + * from this software without specific prior written permission.
  37818. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  37819. + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  37820. + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  37821. + *
  37822. + *    Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
  37823. + *    - Initial distribution.
  37824. + *
  37825. + *
  37826. + * modified for KA9Q Internet Software Package by
  37827. + * Katie Stevens (dkstevens@ucdavis.edu)
  37828. + * University of California, Davis
  37829. + * Computing Services
  37830. + *    - 01-31-90    initial adaptation (from 1.19)
  37831. + *    PPP.05    02-15-90 [ks]
  37832. + *    PPP.08    05-02-90 [ks]    use PPP protocol field to signal compression
  37833. + *    PPP.15    09-90     [ks]    improve mbuf handling
  37834. + *    PPP.16    11-02     [karn]    substantially rewritten to use NOS facilities
  37835. + *
  37836. + *    - Feb 1991    Bill_Simpson@um.cc.umich.edu
  37837. + *            variable number of conversation slots
  37838. + *            allow zero or one slots
  37839. + *            separate routines
  37840. + *            status display
  37841. + *    - Jul 1994    Dmitry Gorodchanin
  37842. + *            Fixes for memory leaks.
  37843. + *      - Oct 1994      Dmitry Gorodchanin
  37844. + *                      Modularization.
  37845. + *    - Jan 1995    Bjorn Ekwall
  37846. + *            Use ip_fast_csum from ip.h
  37847. + *
  37848. + *
  37849. + *    This module is a difficult issue. It's clearly inet code but it's also clearly
  37850. + *    driver code belonging close to PPP and SLIP
  37851. + */
  37852. +
  37853. +#include <linux/config.h>
  37854. +#ifdef CONFIG_INET
  37855. +/* Entire module is for IP only */
  37856. +#ifdef MODULE
  37857. +#include <linux/module.h>
  37858. +#include <linux/version.h>
  37859. +#endif
  37860. +
  37861. +#include <linux/types.h>
  37862. +#include <linux/sched.h>
  37863. +#include <linux/mm.h>
  37864. +#include <linux/string.h>
  37865. +#include <linux/socket.h>
  37866. +#include <linux/sockios.h>
  37867. +#include <linux/termios.h>
  37868. +#include <linux/in.h>
  37869. +#include <linux/fcntl.h>
  37870. +#include <linux/inet.h>
  37871. +#include <linux/netdevice.h>
  37872. +#include "ip.h"
  37873. +#include "protocol.h"
  37874. +#include "icmp.h"
  37875. +#include "tcp.h"
  37876. +#include <linux/skbuff.h>
  37877. +#include "sock.h"
  37878. +#include <linux/errno.h>
  37879. +#include <linux/timer.h>
  37880. +#include <asm/system.h>
  37881. +#include <asm/segment.h>
  37882. +#include <linux/mm.h>
  37883. +#include "slhc.h"
  37884. +
  37885. +int last_retran;
  37886. +
  37887. +static unsigned char *encode(unsigned char *cp, unsigned short n);
  37888. +static long decode(unsigned char **cpp);
  37889. +static unsigned char * put16(unsigned char *cp, unsigned short x);
  37890. +static unsigned short pull16(unsigned char **cpp);
  37891. +
  37892. +/* Initialize compression data structure
  37893. + *    slots must be in range 0 to 255 (zero meaning no compression)
  37894. + */
  37895. +struct slcompress *
  37896. +slhc_init(int rslots, int tslots)
  37897. +{
  37898. +    register short i;
  37899. +    register struct cstate *ts;
  37900. +    struct slcompress *comp;
  37901. +
  37902. +    comp = (struct slcompress *)kmalloc(sizeof(struct slcompress),
  37903. +                        GFP_KERNEL);
  37904. +    if (! comp)
  37905. +        return NULL;
  37906. +
  37907. +    memset(comp, 0, sizeof(struct slcompress));
  37908. +
  37909. +    if ( rslots > 0  &&  rslots < 256 ) {
  37910. +        comp->rstate =
  37911. +          (struct cstate *)kmalloc(rslots * sizeof(struct cstate),
  37912. +                       GFP_KERNEL);
  37913. +        if (! comp->rstate)
  37914. +        {
  37915. +            kfree((unsigned char *)comp);
  37916. +            return NULL;
  37917. +        }
  37918. +        memset(comp->rstate, 0, rslots * sizeof(struct cstate));
  37919. +        comp->rslot_limit = rslots - 1;
  37920. +    }
  37921. +
  37922. +    if ( tslots > 0  &&  tslots < 256 ) {
  37923. +        comp->tstate =
  37924. +          (struct cstate *)kmalloc(tslots * sizeof(struct cstate),
  37925. +                       GFP_KERNEL);
  37926. +        if (! comp->tstate)
  37927. +        {
  37928. +            kfree((unsigned char *)comp->rstate);
  37929. +            kfree((unsigned char *)comp);
  37930. +            return NULL;
  37931. +        }
  37932. +        memset(comp->tstate, 0, rslots * sizeof(struct cstate));
  37933. +        comp->tslot_limit = tslots - 1;
  37934. +    }
  37935. +
  37936. +    comp->xmit_oldest = 0;
  37937. +    comp->xmit_current = 255;
  37938. +    comp->recv_current = 255;
  37939. +    /*
  37940. +     * don't accept any packets with implicit index until we get
  37941. +     * one with an explicit index.  Otherwise the uncompress code
  37942. +     * will try to use connection 255, which is almost certainly
  37943. +     * out of range
  37944. +     */
  37945. +    comp->flags |= SLF_TOSS;
  37946. +
  37947. +    if ( tslots > 0 ) {
  37948. +        ts = comp->tstate;
  37949. +        for(i = comp->tslot_limit; i > 0; --i){
  37950. +            ts[i].cs_this = i;
  37951. +            ts[i].next = &(ts[i - 1]);
  37952. +        }
  37953. +        ts[0].next = &(ts[comp->tslot_limit]);
  37954. +        ts[0].cs_this = 0;
  37955. +    }
  37956. +#ifdef MODULE
  37957. +    MOD_INC_USE_COUNT;
  37958. +#endif
  37959. +    return comp;
  37960. +}
  37961. +
  37962. +
  37963. +/* Free a compression data structure */
  37964. +void
  37965. +slhc_free(struct slcompress *comp)
  37966. +{
  37967. +    if ( comp == NULLSLCOMPR )
  37968. +        return;
  37969. +
  37970. +    if ( comp->rstate != NULLSLSTATE )
  37971. +        kfree( comp->rstate );
  37972. +
  37973. +    if ( comp->tstate != NULLSLSTATE )
  37974. +        kfree( comp->tstate );
  37975. +
  37976. +#ifdef MODULE
  37977. +    MOD_DEC_USE_COUNT;
  37978. +#endif
  37979. +    kfree( comp );
  37980. +}
  37981. +
  37982. +
  37983. +/* Put a short in host order into a char array in network order */
  37984. +static inline unsigned char *
  37985. +put16(unsigned char *cp, unsigned short x)
  37986. +{
  37987. +    *cp++ = x >> 8;
  37988. +    *cp++ = x;
  37989. +
  37990. +    return cp;
  37991. +}
  37992. +
  37993. +
  37994. +/* Encode a number */
  37995. +unsigned char *
  37996. +encode(unsigned char *cp, unsigned short n)
  37997. +{
  37998. +    if(n >= 256 || n == 0){
  37999. +        *cp++ = 0;
  38000. +        cp = put16(cp,n);
  38001. +    } else {
  38002. +        *cp++ = n;
  38003. +    }
  38004. +    return cp;
  38005. +}
  38006. +
  38007. +/* Pull a 16-bit integer in host order from buffer in network byte order */
  38008. +static unsigned short
  38009. +pull16(unsigned char **cpp)
  38010. +{
  38011. +    short rval;
  38012. +
  38013. +    rval = *(*cpp)++;
  38014. +    rval <<= 8;
  38015. +    rval |= *(*cpp)++;
  38016. +    return rval;
  38017. +}
  38018. +
  38019. +/* Decode a number */
  38020. +long
  38021. +decode(unsigned char **cpp)
  38022. +{
  38023. +    register int x;
  38024. +
  38025. +    x = *(*cpp)++;
  38026. +    if(x == 0){
  38027. +        return pull16(cpp) & 0xffff;    /* pull16 returns -1 on error */
  38028. +    } else {
  38029. +        return x & 0xff;        /* -1 if PULLCHAR returned error */
  38030. +    }
  38031. +}
  38032. +
  38033. +/*
  38034. + * icp and isize are the original packet.
  38035. + * ocp is a place to put a copy if necessary.
  38036. + * cpp is initially a pointer to icp.  If the copy is used,
  38037. + *    change it to ocp.
  38038. + */
  38039. +
  38040. +int
  38041. +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
  38042. +    unsigned char *ocp, unsigned char **cpp, int compress_cid)
  38043. +{
  38044. +    register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
  38045. +    register struct cstate *lcs = ocs;
  38046. +    register struct cstate *cs = lcs->next;
  38047. +    register unsigned long deltaS, deltaA;
  38048. +    register short changes = 0;
  38049. +    int hlen;
  38050. +    unsigned char new_seq[16];
  38051. +    register unsigned char *cp = new_seq;
  38052. +    struct iphdr *ip;
  38053. +    struct tcphdr *th, *oth;
  38054. +
  38055. +    ip = (struct iphdr *) icp;
  38056. +
  38057. +    /* Bail if this packet isn't TCP, or is an IP fragment */
  38058. +    if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) ||
  38059. +                       (ip->frag_off & 32)){
  38060. +        /* Send as regular IP */
  38061. +        if(ip->protocol != IPPROTO_TCP)
  38062. +            comp->sls_o_nontcp++;
  38063. +        else
  38064. +            comp->sls_o_tcp++;
  38065. +        return isize;
  38066. +    }
  38067. +    /* Extract TCP header */
  38068. +
  38069. +    th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
  38070. +    hlen = ip->ihl*4 + th->doff*4;
  38071. +
  38072. +    /*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
  38073. +     *  some other control bit is set).
  38074. +     */
  38075. +    if(th->syn || th->fin || th->rst ||
  38076. +        ! (th->ack)){
  38077. +        /* TCP connection stuff; send as regular IP */
  38078. +        comp->sls_o_tcp++;
  38079. +        return isize;
  38080. +    }
  38081. +    /*
  38082. +     * Packet is compressible -- we're going to send either a
  38083. +     * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way,
  38084. +     * we need to locate (or create) the connection state.
  38085. +     *
  38086. +     * States are kept in a circularly linked list with
  38087. +     * xmit_oldest pointing to the end of the list.  The
  38088. +     * list is kept in lru order by moving a state to the
  38089. +     * head of the list whenever it is referenced.  Since
  38090. +     * the list is short and, empirically, the connection
  38091. +     * we want is almost always near the front, we locate
  38092. +     * states via linear search.  If we don't find a state
  38093. +     * for the datagram, the oldest state is (re-)used.
  38094. +     */
  38095. +    for ( ; ; ) {
  38096. +        if( ip->saddr == cs->cs_ip.saddr
  38097. +         && ip->daddr == cs->cs_ip.daddr
  38098. +         && th->source == cs->cs_tcp.source
  38099. +         && th->dest == cs->cs_tcp.dest)
  38100. +            goto found;
  38101. +
  38102. +        /* if current equal oldest, at end of list */
  38103. +        if ( cs == ocs )
  38104. +            break;
  38105. +        lcs = cs;
  38106. +        cs = cs->next;
  38107. +        comp->sls_o_searches++;
  38108. +    };
  38109. +    /*
  38110. +     * Didn't find it -- re-use oldest cstate.  Send an
  38111. +     * uncompressed packet that tells the other side what
  38112. +     * connection number we're using for this conversation.
  38113. +     *
  38114. +     * Note that since the state list is circular, the oldest
  38115. +     * state points to the newest and we only need to set
  38116. +     * xmit_oldest to update the lru linkage.
  38117. +     */
  38118. +    comp->sls_o_misses++;
  38119. +    comp->xmit_oldest = lcs->cs_this;
  38120. +    goto uncompressed;
  38121. +
  38122. +found:
  38123. +    /*
  38124. +     * Found it -- move to the front on the connection list.
  38125. +     */
  38126. +    if(lcs == ocs) {
  38127. +         /* found at most recently used */
  38128. +    } else if (cs == ocs) {
  38129. +        /* found at least recently used */
  38130. +        comp->xmit_oldest = lcs->cs_this;
  38131. +    } else {
  38132. +        /* more than 2 elements */
  38133. +        lcs->next = cs->next;
  38134. +        cs->next = ocs->next;
  38135. +        ocs->next = cs;
  38136. +    }
  38137. +
  38138. +    /*
  38139. +     * Make sure that only what we expect to change changed.
  38140. +     * Check the following:
  38141. +     * IP protocol version, header length & type of service.
  38142. +     * The "Don't fragment" bit.
  38143. +     * The time-to-live field.
  38144. +     * The TCP header length.
  38145. +     * IP options, if any.
  38146. +     * TCP options, if any.
  38147. +     * If any of these things are different between the previous &
  38148. +     * current datagram, we send the current datagram `uncompressed'.
  38149. +     */
  38150. +    oth = &cs->cs_tcp;
  38151. +
  38152. +    if(last_retran
  38153. +     || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
  38154. +     || ip->tos != cs->cs_ip.tos
  38155. +     || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64)
  38156. +     || ip->ttl != cs->cs_ip.ttl
  38157. +     || th->doff != cs->cs_tcp.doff
  38158. +     || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
  38159. +     || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4 != 0))){
  38160. +        goto uncompressed;
  38161. +    }
  38162. +
  38163. +    /*
  38164. +     * Figure out which of the changing fields changed.  The
  38165. +     * receiver expects changes in the order: urgent, window,
  38166. +     * ack, seq (the order minimizes the number of temporaries
  38167. +     * needed in this section of code).
  38168. +     */
  38169. +    if(th->urg){
  38170. +        deltaS = ntohs(th->urg_ptr);
  38171. +        cp = encode(cp,deltaS);
  38172. +        changes |= NEW_U;
  38173. +    } else if(th->urg_ptr != oth->urg_ptr){
  38174. +        /* argh! URG not set but urp changed -- a sensible
  38175. +         * implementation should never do this but RFC793
  38176. +         * doesn't prohibit the change so we have to deal
  38177. +         * with it. */
  38178. +        goto uncompressed;
  38179. +    }
  38180. +    if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
  38181. +        cp = encode(cp,deltaS);
  38182. +        changes |= NEW_W;
  38183. +    }
  38184. +    if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
  38185. +        if(deltaA > 0x0000ffff)
  38186. +            goto uncompressed;
  38187. +        cp = encode(cp,deltaA);
  38188. +        changes |= NEW_A;
  38189. +    }
  38190. +    if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
  38191. +        if(deltaS > 0x0000ffff)
  38192. +            goto uncompressed;
  38193. +        cp = encode(cp,deltaS);
  38194. +        changes |= NEW_S;
  38195. +    }
  38196. +
  38197. +    switch(changes){
  38198. +    case 0:    /* Nothing changed. If this packet contains data and the
  38199. +         * last one didn't, this is probably a data packet following
  38200. +         * an ack (normal on an interactive connection) and we send
  38201. +         * it compressed.  Otherwise it's probably a retransmit,
  38202. +         * retransmitted ack or window probe.  Send it uncompressed
  38203. +         * in case the other side missed the compressed version.
  38204. +         */
  38205. +        if(ip->tot_len != cs->cs_ip.tot_len &&
  38206. +           ntohs(cs->cs_ip.tot_len) == hlen)
  38207. +            break;
  38208. +        goto uncompressed;
  38209. +        break;
  38210. +    case SPECIAL_I:
  38211. +    case SPECIAL_D:
  38212. +        /* actual changes match one of our special case encodings --
  38213. +         * send packet uncompressed.
  38214. +         */
  38215. +        goto uncompressed;
  38216. +    case NEW_S|NEW_A:
  38217. +        if(deltaS == deltaA &&
  38218. +            deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
  38219. +            /* special case for echoed terminal traffic */
  38220. +            changes = SPECIAL_I;
  38221. +            cp = new_seq;
  38222. +        }
  38223. +        break;
  38224. +    case NEW_S:
  38225. +        if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
  38226. +            /* special case for data xfer */
  38227. +            changes = SPECIAL_D;
  38228. +            cp = new_seq;
  38229. +        }
  38230. +        break;
  38231. +    }
  38232. +    deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
  38233. +    if(deltaS != 1){
  38234. +        cp = encode(cp,deltaS);
  38235. +        changes |= NEW_I;
  38236. +    }
  38237. +    if(th->psh)
  38238. +        changes |= TCP_PUSH_BIT;
  38239. +    /* Grab the cksum before we overwrite it below.  Then update our
  38240. +     * state with this packet's header.
  38241. +     */
  38242. +    deltaA = ntohs(th->check);
  38243. +    memcpy(&cs->cs_ip,ip,20);
  38244. +    memcpy(&cs->cs_tcp,th,20);
  38245. +    /* We want to use the original packet as our compressed packet.
  38246. +     * (cp - new_seq) is the number of bytes we need for compressed
  38247. +     * sequence numbers.  In addition we need one byte for the change
  38248. +     * mask, one for the connection id and two for the tcp checksum.
  38249. +     * So, (cp - new_seq) + 4 bytes of header are needed.
  38250. +     */
  38251. +    deltaS = cp - new_seq;
  38252. +    if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
  38253. +        cp = ocp;
  38254. +        *cpp = ocp;
  38255. +        *cp++ = changes | NEW_C;
  38256. +        *cp++ = cs->cs_this;
  38257. +        comp->xmit_current = cs->cs_this;
  38258. +    } else {
  38259. +        cp = ocp;
  38260. +        *cpp = ocp;
  38261. +        *cp++ = changes;
  38262. +    }
  38263. +    cp = put16(cp,(short)deltaA);    /* Write TCP checksum */
  38264. +/* deltaS is now the size of the change section of the compressed header */
  38265. +    memcpy(cp,new_seq,deltaS);    /* Write list of deltas */
  38266. +    memcpy(cp+deltaS,icp+hlen,isize-hlen);
  38267. +    comp->sls_o_compressed++;
  38268. +    ocp[0] |= SL_TYPE_COMPRESSED_TCP;
  38269. +    return isize - hlen + deltaS + (cp - ocp);
  38270. +
  38271. +    /* Update connection state cs & send uncompressed packet (i.e.,
  38272. +     * a regular ip/tcp packet but with the 'conversation id' we hope
  38273. +     * to use on future compressed packets in the protocol field).
  38274. +     */
  38275. +uncompressed:
  38276. +    memcpy(&cs->cs_ip,ip,20);
  38277. +    memcpy(&cs->cs_tcp,th,20);
  38278. +    if (ip->ihl > 5)
  38279. +      memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
  38280. +    if (th->doff > 5)
  38281. +      memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
  38282. +    comp->xmit_current = cs->cs_this;
  38283. +    comp->sls_o_uncompressed++;
  38284. +    memcpy(ocp, icp, isize);
  38285. +    *cpp = ocp;
  38286. +    ocp[9] = cs->cs_this;
  38287. +    ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
  38288. +    return isize;
  38289. +}
  38290. +
  38291. +
  38292. +int
  38293. +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
  38294. +{
  38295. +    register int changes;
  38296. +    long x;
  38297. +    register struct tcphdr *thp;
  38298. +    register struct iphdr *ip;
  38299. +    register struct cstate *cs;
  38300. +    int len, hdrlen;
  38301. +    unsigned char *cp = icp;
  38302. +
  38303. +    /* We've got a compressed packet; read the change byte */
  38304. +    comp->sls_i_compressed++;
  38305. +    if(isize < 3){
  38306. +        comp->sls_i_error++;
  38307. +        return 0;
  38308. +    }
  38309. +    changes = *cp++;
  38310. +    if(changes & NEW_C){
  38311. +        /* Make sure the state index is in range, then grab the state.
  38312. +         * If we have a good state index, clear the 'discard' flag.
  38313. +         */
  38314. +        x = *cp++;    /* Read conn index */
  38315. +        if(x < 0 || x > comp->rslot_limit)
  38316. +            goto bad;
  38317. +
  38318. +        comp->flags &=~ SLF_TOSS;
  38319. +        comp->recv_current = x;
  38320. +    } else {
  38321. +        /* this packet has an implicit state index.  If we've
  38322. +         * had a line error since the last time we got an
  38323. +         * explicit state index, we have to toss the packet. */
  38324. +        if(comp->flags & SLF_TOSS){
  38325. +            comp->sls_i_tossed++;
  38326. +            return 0;
  38327. +        }
  38328. +    }
  38329. +    cs = &comp->rstate[comp->recv_current];
  38330. +    thp = &cs->cs_tcp;
  38331. +    ip = &cs->cs_ip;
  38332. +
  38333. +    if((x = pull16(&cp)) == -1) {    /* Read the TCP checksum */
  38334. +        goto bad;
  38335. +        }
  38336. +    thp->check = htons(x);
  38337. +
  38338. +    thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
  38339. +/*
  38340. + * we can use the same number for the length of the saved header and
  38341. + * the current one, because the packet wouldn't have been sent
  38342. + * as compressed unless the options were the same as the previous one
  38343. + */
  38344. +
  38345. +    hdrlen = ip->ihl * 4 + thp->doff * 4;
  38346. +
  38347. +    switch(changes & SPECIALS_MASK){
  38348. +    case SPECIAL_I:        /* Echoed terminal traffic */
  38349. +        {
  38350. +        register short i;
  38351. +        i = ntohs(ip->tot_len) - hdrlen;
  38352. +        thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
  38353. +        thp->seq = htonl( ntohl(thp->seq) + i);
  38354. +        }
  38355. +        break;
  38356. +
  38357. +    case SPECIAL_D:            /* Unidirectional data */
  38358. +        thp->seq = htonl( ntohl(thp->seq) +
  38359. +                  ntohs(ip->tot_len) - hdrlen);
  38360. +        break;
  38361. +
  38362. +    default:
  38363. +        if(changes & NEW_U){
  38364. +            thp->urg = 1;
  38365. +            if((x = decode(&cp)) == -1) {
  38366. +                goto bad;
  38367. +            }
  38368. +            thp->urg_ptr = htons(x);
  38369. +        } else
  38370. +            thp->urg = 0;
  38371. +        if(changes & NEW_W){
  38372. +            if((x = decode(&cp)) == -1) {
  38373. +                goto bad;
  38374. +            }
  38375. +            thp->window = htons( ntohs(thp->window) + x);
  38376. +        }
  38377. +        if(changes & NEW_A){
  38378. +            if((x = decode(&cp)) == -1) {
  38379. +                goto bad;
  38380. +            }
  38381. +            thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
  38382. +        }
  38383. +        if(changes & NEW_S){
  38384. +            if((x = decode(&cp)) == -1) {
  38385. +                goto bad;
  38386. +            }
  38387. +            thp->seq = htonl( ntohl(thp->seq) + x);
  38388. +        }
  38389. +        break;
  38390. +    }
  38391. +    if(changes & NEW_I){
  38392. +        if((x = decode(&cp)) == -1) {
  38393. +            goto bad;
  38394. +        }
  38395. +        ip->id = htons (ntohs (ip->id) + x);
  38396. +    } else
  38397. +        ip->id = htons (ntohs (ip->id) + 1);
  38398. +
  38399. +    /*
  38400. +     * At this point, cp points to the first byte of data in the
  38401. +     * packet.  Put the reconstructed TCP and IP headers back on the
  38402. +     * packet.  Recalculate IP checksum (but not TCP checksum).
  38403. +     */
  38404. +
  38405. +    len = isize - (cp - icp);
  38406. +    if (len < 0)
  38407. +        goto bad;
  38408. +    len += hdrlen;
  38409. +    ip->tot_len = htons(len);
  38410. +    ip->check = 0;
  38411. +
  38412. +    memmove(icp + hdrlen, cp, len - hdrlen);
  38413. +
  38414. +    cp = icp;
  38415. +    memcpy(cp, ip, 20);
  38416. +    cp += 20;
  38417. +
  38418. +    if (ip->ihl > 5) {
  38419. +      memcpy(cp, cs->cs_ipopt, ((ip->ihl) - 5) * 4);
  38420. +      cp += ((ip->ihl) - 5) * 4;
  38421. +    }
  38422. +
  38423. +    ((struct iphdr *)icp)->check = ip_fast_csum(icp, ((struct iphdr*)icp)->ihl);
  38424. +
  38425. +    memcpy(cp, thp, 20);
  38426. +    cp += 20;
  38427. +
  38428. +    if (thp->doff > 5) {
  38429. +      memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
  38430. +      cp += ((thp->doff) - 5) * 4;
  38431. +    }
  38432. +
  38433. +    return len;
  38434. +bad:
  38435. +    comp->sls_i_error++;
  38436. +    return slhc_toss( comp );
  38437. +}
  38438. +
  38439. +
  38440. +int
  38441. +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
  38442. +{
  38443. +    register struct cstate *cs;
  38444. +    short ip_len;
  38445. +    struct iphdr *ip;
  38446. +    struct tcphdr *thp;
  38447. +
  38448. +    unsigned char index;
  38449. +
  38450. +    if(isize < 20) {
  38451. +        /* The packet is shorter than a legal IP header */
  38452. +        comp->sls_i_runt++;
  38453. +        return slhc_toss( comp );
  38454. +    }
  38455. +    /* Sneak a peek at the IP header's IHL field to find its length */
  38456. +    ip_len = (icp[0] & 0xf) << 2;
  38457. +    if(ip_len < 20){
  38458. +        /* The IP header length field is too small */
  38459. +        comp->sls_i_runt++;
  38460. +        return slhc_toss( comp );
  38461. +    }
  38462. +    index = icp[9];
  38463. +    icp[9] = IPPROTO_TCP;
  38464. +    ip = (struct iphdr *) icp;
  38465. +
  38466. +    if (ip_fast_csum(icp, ip->ihl)) {
  38467. +        /* Bad IP header checksum; discard */
  38468. +        comp->sls_i_badcheck++;
  38469. +        return slhc_toss( comp );
  38470. +    }
  38471. +    thp = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
  38472. +    if(index > comp->rslot_limit) {
  38473. +        comp->sls_i_error++;
  38474. +        return slhc_toss(comp);
  38475. +    }
  38476. +
  38477. +    /* Update local state */
  38478. +    cs = &comp->rstate[comp->recv_current = index];
  38479. +    comp->flags &=~ SLF_TOSS;
  38480. +    memcpy(&cs->cs_ip,ip,20);
  38481. +    memcpy(&cs->cs_tcp,thp,20);
  38482. +    if (ip->ihl > 5)
  38483. +      memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
  38484. +    if (thp->doff > 5)
  38485. +      memcpy(cs->cs_tcpopt, thp+1, ((thp->doff) - 5) * 4);
  38486. +    cs->cs_hsize = ip->ihl*2 + thp->doff*2;
  38487. +    /* Put headers back on packet
  38488. +     * Neither header checksum is recalculated
  38489. +     */
  38490. +    comp->sls_i_uncompressed++;
  38491. +    return isize;
  38492. +}
  38493. +
  38494. +
  38495. +int
  38496. +slhc_toss(struct slcompress *comp)
  38497. +{
  38498. +    if ( comp == NULLSLCOMPR )
  38499. +        return 0;
  38500. +
  38501. +    comp->flags |= SLF_TOSS;
  38502. +    return 0;
  38503. +}
  38504. +
  38505. +
  38506. +void slhc_i_status(struct slcompress *comp)
  38507. +{
  38508. +    if (comp != NULLSLCOMPR) {
  38509. +        printk("\t%ld Cmp, %ld Uncmp, %ld Bad, %ld Tossed\n",
  38510. +            comp->sls_i_compressed,
  38511. +            comp->sls_i_uncompressed,
  38512. +            comp->sls_i_error,
  38513. +            comp->sls_i_tossed);
  38514. +    }
  38515. +}
  38516. +
  38517. +
  38518. +void slhc_o_status(struct slcompress *comp)
  38519. +{
  38520. +    if (comp != NULLSLCOMPR) {
  38521. +        printk("\t%ld Cmp, %ld Uncmp, %ld AsIs, %ld NotTCP\n",
  38522. +            comp->sls_o_compressed,
  38523. +            comp->sls_o_uncompressed,
  38524. +            comp->sls_o_tcp,
  38525. +            comp->sls_o_nontcp);
  38526. +        printk("\t%10ld Searches, %10ld Misses\n",
  38527. +            comp->sls_o_searches,
  38528. +            comp->sls_o_misses);
  38529. +    }
  38530. +}
  38531. +
  38532. +#ifdef MODULE
  38533. +char kernel_version[] = UTS_RELEASE;
  38534. +
  38535. +int init_module(void)
  38536. +{
  38537. +    printk("CSLIP: code copyright 1989 Regents of the University of California\n");
  38538. +    return 0;
  38539. +}
  38540. +
  38541. +void cleanup_module(void)
  38542. +{
  38543. +    if (MOD_IN_USE)  {
  38544. +        printk("CSLIP: module in use, remove delayed");
  38545. +    }
  38546. +    return;
  38547. +}
  38548. +#endif /* MODULE */
  38549. +#endif /* CONFIG_INET */
  38550. diff -r -u -N linux.orig/arch/arm/drivers/net/slhc.h linux.arm/arch/arm/drivers/net/slhc.h
  38551. --- linux.orig/arch/arm/drivers/net/slhc.h    Thu Jan  1 01:00:00 1970
  38552. +++ linux.arm/arch/arm/drivers/net/slhc.h    Fri Oct 27 23:15:03 1995
  38553. @@ -0,0 +1,187 @@
  38554. +#ifndef _SLHC_H
  38555. +#define _SLHC_H
  38556. +/*
  38557. + * Definitions for tcp compression routines.
  38558. + *
  38559. + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $
  38560. + *
  38561. + * Copyright (c) 1989 Regents of the University of California.
  38562. + * All rights reserved.
  38563. + *
  38564. + * Redistribution and use in source and binary forms are permitted
  38565. + * provided that the above copyright notice and this paragraph are
  38566. + * duplicated in all such forms and that any documentation,
  38567. + * advertising materials, and other materials related to such
  38568. + * distribution and use acknowledge that the software was developed
  38569. + * by the University of California, Berkeley.  The name of the
  38570. + * University may not be used to endorse or promote products derived
  38571. + * from this software without specific prior written permission.
  38572. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  38573. + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  38574. + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  38575. + *
  38576. + *    Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
  38577. + *    - Initial distribution.
  38578. + *
  38579. + *
  38580. + * modified for KA9Q Internet Software Package by
  38581. + * Katie Stevens (dkstevens@ucdavis.edu)
  38582. + * University of California, Davis
  38583. + * Computing Services
  38584. + *    - 01-31-90    initial adaptation
  38585. + *
  38586. + *    - Feb 1991    Bill_Simpson@um.cc.umich.edu
  38587. + *            variable number of conversation slots
  38588. + *            allow zero or one slots
  38589. + *            separate routines
  38590. + *            status display
  38591. + */
  38592. +
  38593. +/*
  38594. + * Compressed packet format:
  38595. + *
  38596. + * The first octet contains the packet type (top 3 bits), TCP
  38597. + * 'push' bit, and flags that indicate which of the 4 TCP sequence
  38598. + * numbers have changed (bottom 5 bits).  The next octet is a
  38599. + * conversation number that associates a saved IP/TCP header with
  38600. + * the compressed packet.  The next two octets are the TCP checksum
  38601. + * from the original datagram.  The next 0 to 15 octets are
  38602. + * sequence number changes, one change per bit set in the header
  38603. + * (there may be no changes and there are two special cases where
  38604. + * the receiver implicitly knows what changed -- see below).
  38605. + *
  38606. + * There are 5 numbers which can change (they are always inserted
  38607. + * in the following order): TCP urgent pointer, window,
  38608. + * acknowledgment, sequence number and IP ID.  (The urgent pointer
  38609. + * is different from the others in that its value is sent, not the
  38610. + * change in value.)  Since typical use of SLIP links is biased
  38611. + * toward small packets (see comments on MTU/MSS below), changes
  38612. + * use a variable length coding with one octet for numbers in the
  38613. + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
  38614. + * range 256 - 65535 or 0.  (If the change in sequence number or
  38615. + * ack is more than 65535, an uncompressed packet is sent.)
  38616. + */
  38617. +
  38618. +/*
  38619. + * Packet types (must not conflict with IP protocol version)
  38620. + *
  38621. + * The top nibble of the first octet is the packet type.  There are
  38622. + * three possible types: IP (not proto TCP or tcp with one of the
  38623. + * control flags set); uncompressed TCP (a normal IP/TCP packet but
  38624. + * with the 8-bit protocol field replaced by an 8-bit connection id --
  38625. + * this type of packet syncs the sender & receiver); and compressed
  38626. + * TCP (described above).
  38627. + *
  38628. + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
  38629. + * is logically part of the 4-bit "changes" field that follows.  Top
  38630. + * three bits are actual packet type.  For backward compatibility
  38631. + * and in the interest of conserving bits, numbers are chosen so the
  38632. + * IP protocol version number (4) which normally appears in this nibble
  38633. + * means "IP packet".
  38634. + */
  38635. +
  38636. +/* SLIP compression masks for len/vers byte */
  38637. +#define SL_TYPE_IP 0x40
  38638. +#define SL_TYPE_UNCOMPRESSED_TCP 0x70
  38639. +#define SL_TYPE_COMPRESSED_TCP 0x80
  38640. +#define SL_TYPE_ERROR 0x00
  38641. +
  38642. +/* Bits in first octet of compressed packet */
  38643. +#define NEW_C    0x40    /* flag bits for what changed in a packet */
  38644. +#define NEW_I    0x20
  38645. +#define NEW_S    0x08
  38646. +#define NEW_A    0x04
  38647. +#define NEW_W    0x02
  38648. +#define NEW_U    0x01
  38649. +
  38650. +/* reserved, special-case values of above */
  38651. +#define SPECIAL_I (NEW_S|NEW_W|NEW_U)        /* echoed interactive traffic */
  38652. +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U)    /* unidirectional data */
  38653. +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
  38654. +
  38655. +#define TCP_PUSH_BIT 0x10
  38656. +
  38657. +/*
  38658. + * data type and sizes conversion assumptions:
  38659. + *
  38660. + *    VJ code        KA9Q style    generic
  38661. + *    u_char        byte_t        unsigned char     8 bits
  38662. + *    u_short        int16        unsigned short    16 bits
  38663. + *    u_int        int16        unsigned short    16 bits
  38664. + *    u_long        unsigned long    unsigned long    32 bits
  38665. + *    int        int32        long        32 bits
  38666. + */
  38667. +
  38668. +typedef unsigned char byte_t;
  38669. +typedef unsigned long int32;
  38670. +
  38671. +/*
  38672. + * "state" data for each active tcp conversation on the wire.  This is
  38673. + * basically a copy of the entire IP/TCP header from the last packet
  38674. + * we saw from the conversation together with a small identifier
  38675. + * the transmit & receive ends of the line use to locate saved header.
  38676. + */
  38677. +struct cstate {
  38678. +    byte_t    cs_this;    /* connection id number (xmit) */
  38679. +    struct cstate *next;    /* next in ring (xmit) */
  38680. +    struct iphdr cs_ip;    /* ip/tcp hdr from most recent packet */
  38681. +    struct tcphdr cs_tcp;
  38682. +    unsigned char cs_ipopt[64];
  38683. +    unsigned char cs_tcpopt[64];
  38684. +    int cs_hsize;
  38685. +};
  38686. +#define NULLSLSTATE    (struct cstate *)0
  38687. +
  38688. +/*
  38689. + * all the state data for one serial line (we need one of these per line).
  38690. + */
  38691. +struct slcompress {
  38692. +    struct cstate *tstate;    /* transmit connection states (array)*/
  38693. +    struct cstate *rstate;    /* receive connection states (array)*/
  38694. +
  38695. +    byte_t tslot_limit;    /* highest transmit slot id (0-l)*/
  38696. +    byte_t rslot_limit;    /* highest receive slot id (0-l)*/
  38697. +
  38698. +    byte_t xmit_oldest;    /* oldest xmit in ring */
  38699. +    byte_t xmit_current;    /* most recent xmit id */
  38700. +    byte_t recv_current;    /* most recent rcvd id */
  38701. +
  38702. +    byte_t flags;
  38703. +#define SLF_TOSS    0x01    /* tossing rcvd frames until id received */
  38704. +
  38705. +    int32 sls_o_nontcp;    /* outbound non-TCP packets */
  38706. +    int32 sls_o_tcp;    /* outbound TCP packets */
  38707. +    int32 sls_o_uncompressed;    /* outbound uncompressed packets */
  38708. +    int32 sls_o_compressed;    /* outbound compressed packets */
  38709. +    int32 sls_o_searches;    /* searches for connection state */
  38710. +    int32 sls_o_misses;    /* times couldn't find conn. state */
  38711. +
  38712. +    int32 sls_i_uncompressed;    /* inbound uncompressed packets */
  38713. +    int32 sls_i_compressed;    /* inbound compressed packets */
  38714. +    int32 sls_i_error;    /* inbound error packets */
  38715. +    int32 sls_i_tossed;    /* inbound packets tossed because of error */
  38716. +
  38717. +    int32 sls_i_runt;
  38718. +    int32 sls_i_badcheck;
  38719. +};
  38720. +#define NULLSLCOMPR    (struct slcompress *)0
  38721. +
  38722. +#define __ARGS(x) x
  38723. +
  38724. +/* In slhc.c: */
  38725. +struct slcompress *slhc_init __ARGS((int rslots, int tslots));
  38726. +void slhc_free __ARGS((struct slcompress *comp));
  38727. +
  38728. +int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp,
  38729. +              int isize, unsigned char *ocp, unsigned char **cpp,
  38730. +              int compress_cid));
  38731. +int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp,
  38732. +                int isize));
  38733. +int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp,
  38734. +              int isize));
  38735. +int slhc_toss __ARGS((struct slcompress *comp));
  38736. +
  38737. +void slhc_i_status __ARGS((struct slcompress *comp));
  38738. +void slhc_o_status __ARGS((struct slcompress *comp));
  38739. +
  38740. +#endif    /* _SLHC_H */
  38741. diff -r -u -N linux.orig/arch/arm/drivers/net/slip.c linux.arm/arch/arm/drivers/net/slip.c
  38742. --- linux.orig/arch/arm/drivers/net/slip.c    Thu Jan  1 01:00:00 1970
  38743. +++ linux.arm/arch/arm/drivers/net/slip.c    Fri Oct 27 23:15:03 1995
  38744. @@ -0,0 +1,1212 @@
  38745. +/*
  38746. + * slip.c    This module implements the SLIP protocol for kernel-based
  38747. + *        devices like TTY.  It interfaces between a raw TTY, and the
  38748. + *        kernel's INET protocol layers (via DDI).
  38749. + *
  38750. + * Version:    @(#)slip.c    0.8.3    12/24/94
  38751. + *
  38752. + * Authors:    Laurence Culhane, <loz@holmes.demon.co.uk>
  38753. + *        Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  38754. + *
  38755. + * Fixes:
  38756. + *        Alan Cox    :     Sanity checks and avoid tx overruns.
  38757. + *                    Has a new sl->mtu field.
  38758. + *        Alan Cox    :     Found cause of overrun. ifconfig sl0 mtu upwards.
  38759. + *                    Driver now spots this and grows/shrinks its buffers(hack!).
  38760. + *                    Memory leak if you run out of memory setting up a slip driver fixed.
  38761. + *        Matt Dillon    :    Printable slip (borrowed from NET2E)
  38762. + *    Pauline Middelink    :    Slip driver fixes.
  38763. + *        Alan Cox    :    Honours the old SL_COMPRESSED flag
  38764. + *        Alan Cox    :    KISS AX.25 and AXUI IP support
  38765. + *        Michael Riepe    :    Automatic CSLIP recognition added
  38766. + *        Charles Hedrick :    CSLIP header length problem fix.
  38767. + *        Alan Cox    :    Corrected non-IP cases of the above.
  38768. + *        Alan Cox    :    Now uses hardware type as per FvK.
  38769. + *        Alan Cox    :    Default to 192.168.0.0 (RFC 1597)
  38770. + *        A.N.Kuznetsov    :    dev_tint() recursion fix.
  38771. + *    Dmitry Gorodchanin    :    SLIP memory leaks
  38772. + *      Dmitry Gorodchanin      :       Code cleanup. Reduce tty driver
  38773. + *                                      buffering from 4096 to 256 bytes.
  38774. + *                                      Improving SLIP response time.
  38775. + *                                      CONFIG_SLIP_MODE_SLIP6.
  38776. + *                                      ifconfig sl? up & down now works correctly.
  38777. + *                    Modularization.
  38778. + *              Alan Cox        :       Oops - fix AX.25 buffer lengths
  38779. + *      Dmitry Gorodchanin      :       Even more cleanups. Preserve CSLIP
  38780. + *                                      statistics. Include CSLIP code only
  38781. + *                                      if it really needed.
  38782. + *        Alan Cox    :    Free slhc buffers in the right place.
  38783. + *
  38784. + *
  38785. + *
  38786. + *    FIXME:    This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without
  38787. + *    CONFIG_INET defined.
  38788. + *      I hope now it is fixed ;)
  38789. + */
  38790. +
  38791. +#define SL_CHECK_TRANSMIT
  38792. +#include <linux/config.h>
  38793. +#ifdef MODULE
  38794. +#include <linux/module.h>
  38795. +#include <linux/version.h>
  38796. +#endif
  38797. +
  38798. +/* Undef this, if you don't need 6bit encapsulation code in the driver */
  38799. +#define CONFIG_SLIP_MODE_SLIP6
  38800. +
  38801. +#include <asm/system.h>
  38802. +#include <asm/segment.h>
  38803. +#include <asm/bitops.h>
  38804. +#include <linux/string.h>
  38805. +#include <linux/mm.h>
  38806. +#include <linux/interrupt.h>
  38807. +#include <linux/in.h>
  38808. +#include <linux/tty.h>
  38809. +#include <linux/errno.h>
  38810. +#include <linux/netdevice.h>
  38811. +#ifdef CONFIG_AX25
  38812. +#include "ax25.h"
  38813. +#endif
  38814. +#include <linux/etherdevice.h>
  38815. +#include <linux/skbuff.h>
  38816. +#include <linux/if_arp.h>
  38817. +#include "slip.h"
  38818. +#ifdef CONFIG_INET
  38819. +#include <linux/ip.h>
  38820. +#include <linux/tcp.h>
  38821. +#include "slhc.h"
  38822. +#endif
  38823. +
  38824. +#ifdef MODULE
  38825. +#define SLIP_VERSION    "0.8.3-NET3.019-NEWTTY-MODULAR"
  38826. +#else
  38827. +#define    SLIP_VERSION    "0.8.3-NET3.019-NEWTTY"
  38828. +#endif
  38829. +
  38830. +
  38831. +static struct slip    sl_ctrl[SL_NRUNIT];
  38832. +static struct tty_ldisc    sl_ldisc;
  38833. +static int        already = 0;
  38834. +
  38835. +static int slip_esc(unsigned char *p, unsigned char *d, int len);
  38836. +static void slip_unesc(struct slip *sl, unsigned char c);
  38837. +#ifdef CONFIG_SLIP_MODE_SLIP6
  38838. +static int slip_esc6(unsigned char *p, unsigned char *d, int len);
  38839. +static void slip_unesc6(struct slip *sl, unsigned char c);
  38840. +#endif
  38841. +
  38842. +
  38843. +/* Find a free SLIP channel, and link in this `tty' line. */
  38844. +static inline struct slip *
  38845. +sl_alloc(void)
  38846. +{
  38847. +    struct slip *sl;
  38848. +    int i;
  38849. +
  38850. +    for (i = 0; i < SL_NRUNIT; i++) {
  38851. +        sl = &sl_ctrl[i];
  38852. +        if (!set_bit(SLF_INUSE, &sl->flags)) {
  38853. +            return sl;
  38854. +        }
  38855. +    }
  38856. +    return NULL;
  38857. +}
  38858. +
  38859. +
  38860. +/* Free a SLIP channel. */
  38861. +static inline void
  38862. +sl_free(struct slip *sl)
  38863. +{
  38864. +    /* Free all SLIP frame buffers. */
  38865. +    if (sl->rbuff)  {
  38866. +        kfree(sl->rbuff);
  38867. +    }
  38868. +    sl->rbuff = NULL;
  38869. +    if (sl->xbuff)  {
  38870. +        kfree(sl->xbuff);
  38871. +    }
  38872. +    sl->xbuff = NULL;
  38873. +#ifdef SL_INCLUDE_CSLIP
  38874. +    /* Save CSLIP statistics */
  38875. +    if (sl->slcomp)  {
  38876. +        sl->rx_compressed += sl->slcomp->sls_i_compressed;
  38877. +        sl->rx_dropped    += sl->slcomp->sls_i_tossed;
  38878. +        sl->tx_compressed += sl->slcomp->sls_o_compressed;
  38879. +        sl->tx_misses     += sl->slcomp->sls_o_misses;
  38880. +    }
  38881. +    if (sl->cbuff)  {
  38882. +        kfree(sl->cbuff);
  38883. +    }
  38884. +    sl->cbuff = NULL;
  38885. +    if(sl->slcomp)
  38886. +        slhc_free(sl->slcomp);
  38887. +    sl->slcomp = NULL;
  38888. +#endif
  38889. +
  38890. +    if (!clear_bit(SLF_INUSE, &sl->flags)) {
  38891. +        printk("%s: sl_free for already free unit.\n", sl->dev->name);
  38892. +    }
  38893. +}
  38894. +
  38895. +/* MTU has been changed by the IP layer. Unfortunately we are not told about this, but
  38896. +   we spot it ourselves and fix things up. We could be in an upcall from the tty
  38897. +   driver, or in an ip packet queue. */
  38898. +
  38899. +static void sl_changedmtu(struct slip *sl)
  38900. +{
  38901. +    struct device *dev = sl->dev;
  38902. +    unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
  38903. +#ifdef SL_INCLUDE_CSLIP
  38904. +    unsigned char *cbuff, *ocbuff;
  38905. +#endif
  38906. +    int len;
  38907. +    unsigned long flags;
  38908. +
  38909. +    len = dev->mtu * 2;
  38910. +/*
  38911. + * allow for arrival of larger UDP packets, even if we say not to
  38912. + * also fixes a bug in which SunOS sends 512-byte packets even with
  38913. + * an MSS of 128
  38914. + */
  38915. +    if (len < 576 * 2)  {
  38916. +        len = 576 * 2;
  38917. +    }
  38918. +
  38919. +    xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
  38920. +    rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
  38921. +#ifdef SL_INCLUDE_CSLIP
  38922. +    cbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
  38923. +#endif
  38924. +
  38925. +#ifdef SL_INCLUDE_CSLIP
  38926. +    if (xbuff == NULL || rbuff == NULL || cbuff == NULL)  {
  38927. +#else
  38928. +    if (xbuff == NULL || rbuff == NULL)  {
  38929. +#endif
  38930. +        printk("%s: unable to grow slip buffers, MTU change cancelled.\n",
  38931. +               sl->dev->name);
  38932. +        dev->mtu = sl->mtu;
  38933. +        if (xbuff != NULL)  {
  38934. +            kfree(xbuff);
  38935. +        }
  38936. +        if (rbuff != NULL)  {
  38937. +            kfree(rbuff);
  38938. +        }
  38939. +#ifdef SL_INCLUDE_CSLIP
  38940. +        if (cbuff != NULL)  {
  38941. +            kfree(cbuff);
  38942. +        }
  38943. +#endif
  38944. +        return;
  38945. +    }
  38946. +
  38947. +    save_flags(flags); cli();
  38948. +
  38949. +    oxbuff    = sl->xbuff;
  38950. +    sl->xbuff = xbuff;
  38951. +    orbuff    = sl->rbuff;
  38952. +    sl->rbuff = rbuff;
  38953. +#ifdef SL_INCLUDE_CSLIP
  38954. +    ocbuff    = sl->cbuff;
  38955. +    sl->cbuff = cbuff;
  38956. +#endif
  38957. +    if (sl->xleft)  {
  38958. +        if (sl->xleft <= len)  {
  38959. +            memcpy(sl->xbuff, sl->xhead, sl->xleft);
  38960. +        } else  {
  38961. +            sl->xleft = 0;
  38962. +            sl->tx_dropped++;
  38963. +        }
  38964. +    }
  38965. +    sl->xhead = sl->xbuff;
  38966. +
  38967. +    if (sl->rcount)  {
  38968. +        if (sl->rcount <= len) {
  38969. +            memcpy(sl->rbuff, orbuff, sl->rcount);
  38970. +        } else  {
  38971. +            sl->rcount = 0;
  38972. +            sl->rx_over_errors++;
  38973. +            set_bit(SLF_ERROR, &sl->flags);
  38974. +        }
  38975. +    }
  38976. +#ifdef CONFIG_AX25
  38977. +    sl->mtu      = dev->mtu + 73;
  38978. +#else
  38979. +    sl->mtu      = dev->mtu;
  38980. +#endif
  38981. +    sl->buffsize = len;
  38982. +
  38983. +    restore_flags(flags);
  38984. +
  38985. +    if (oxbuff != NULL)   {
  38986. +        kfree(oxbuff);
  38987. +    }
  38988. +    if (orbuff != NULL)    {
  38989. +        kfree(orbuff);
  38990. +    }
  38991. +#ifdef SL_INCLUDE_CSLIP
  38992. +    if (ocbuff != NULL)  {
  38993. +        kfree(ocbuff);
  38994. +    }
  38995. +#endif
  38996. +}
  38997. +
  38998. +
  38999. +/* Set the "sending" flag.  This must be atomic, hence the ASM. */
  39000. +static inline void
  39001. +sl_lock(struct slip *sl)
  39002. +{
  39003. +    if (set_bit(0, (void *) &sl->dev->tbusy))  {
  39004. +        printk("%s: trying to lock already locked device!\n", sl->dev->name);
  39005. +        }
  39006. +}
  39007. +
  39008. +
  39009. +/* Clear the "sending" flag.  This must be atomic, hence the ASM. */
  39010. +static inline void
  39011. +sl_unlock(struct slip *sl)
  39012. +{
  39013. +    if (!clear_bit(0, (void *)&sl->dev->tbusy))  {
  39014. +        printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
  39015. +        }
  39016. +}
  39017. +
  39018. +/* Send one completely decapsulated IP datagram to the IP layer. */
  39019. +static void
  39020. +sl_bump(struct slip *sl)
  39021. +{
  39022. +    struct sk_buff *skb;
  39023. +    int count;
  39024. +
  39025. +    count = sl->rcount;
  39026. +#ifdef SL_INCLUDE_CSLIP
  39027. +    if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {
  39028. +        unsigned char c;
  39029. +        if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) {
  39030. +            /* ignore compressed packets when CSLIP is off */
  39031. +            if (!(sl->mode & SL_MODE_CSLIP)) {
  39032. +                printk("%s: compressed packet ignored\n", sl->dev->name);
  39033. +                return;
  39034. +            }
  39035. +            /* make sure we've reserved enough space for uncompress to use */
  39036. +            if (count + 80 > sl->buffsize) {
  39037. +                sl->rx_over_errors++;
  39038. +                return;
  39039. +            }
  39040. +            count = slhc_uncompress(sl->slcomp, sl->rbuff, count);
  39041. +            if (count <= 0) {
  39042. +                return;
  39043. +            }
  39044. +        } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
  39045. +            if (!(sl->mode & SL_MODE_CSLIP)) {
  39046. +                /* turn on header compression */
  39047. +                sl->mode |= SL_MODE_CSLIP;
  39048. +                sl->mode &= ~SL_MODE_ADAPTIVE;
  39049. +                printk("%s: header compression turned on\n", sl->dev->name);
  39050. +            }
  39051. +            sl->rbuff[0] &= 0x4f;
  39052. +            if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) {
  39053. +                return;
  39054. +            }
  39055. +        }
  39056. +    }
  39057. +#endif  /* SL_INCLUDE_CSLIP */
  39058. +
  39059. +    skb = alloc_skb(count, GFP_ATOMIC);
  39060. +    if (skb == NULL)  {
  39061. +        printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
  39062. +        sl->rx_dropped++;
  39063. +        return;
  39064. +    }
  39065. +    skb->len = count;
  39066. +    skb->dev = sl->dev;
  39067. +    memcpy(skb->data, sl->rbuff, count);
  39068. +    netif_rx(skb);
  39069. +    sl->rx_packets++;
  39070. +}
  39071. +
  39072. +/* Encapsulate one IP datagram and stuff into a TTY queue. */
  39073. +static void
  39074. +sl_encaps(struct slip *sl, unsigned char *icp, int len)
  39075. +{
  39076. +    unsigned char *p;
  39077. +    int actual, count;
  39078. +
  39079. +
  39080. +#ifdef CONFIG_AX25
  39081. +    if (sl->mtu != sl->dev->mtu + 73) {    /* Someone has been ifconfigging */
  39082. +#else
  39083. +    if (sl->mtu != sl->dev->mtu) {    /* Someone has been ifconfigging */
  39084. +#endif
  39085. +        sl_changedmtu(sl);
  39086. +    }
  39087. +
  39088. +    if (len > sl->mtu) {        /* Sigh, shouldn't occur BUT ... */
  39089. +        len = sl->mtu;
  39090. +        printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);
  39091. +        sl->tx_dropped++;
  39092. +        sl_unlock(sl);
  39093. +        return;
  39094. +    }
  39095. +
  39096. +    p = icp;
  39097. +#ifdef SL_INCLUDE_CSLIP
  39098. +    if (sl->mode & SL_MODE_CSLIP)  {
  39099. +        len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
  39100. +    }
  39101. +#endif
  39102. +#ifdef CONFIG_SLIP_MODE_SLIP6
  39103. +    if(sl->mode & SL_MODE_SLIP6)
  39104. +        count = slip_esc6(p, (unsigned char *) sl->xbuff, len);
  39105. +    else
  39106. +#endif
  39107. +        count = slip_esc(p, (unsigned char *) sl->xbuff, len);
  39108. +
  39109. +    /* Order of next two lines is *very* important.
  39110. +     * When we are sending a little amount of data,
  39111. +     * the transfer may be completed inside driver.write()
  39112. +     * routine, because it's running with interrupts enabled.
  39113. +     * In this case we *never* got WRITE_WAKEUP event,
  39114. +     * if we did not request it before write operation.
  39115. +     *       14 Oct 1994  Dmitry Gorodchanin.
  39116. +     */
  39117. +    sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
  39118. +    actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count);
  39119. +#ifdef SL_CHECK_TRANSMIT
  39120. +    sl->dev->trans_start = jiffies;
  39121. +#endif
  39122. +    sl->xleft = count - actual;
  39123. +    sl->xhead = sl->xbuff + actual;
  39124. +}
  39125. +
  39126. +/*
  39127. + * Called by the driver when there's room for more data.  If we have
  39128. + * more packets to send, we send them here.
  39129. + */
  39130. +static void slip_write_wakeup(struct tty_struct *tty)
  39131. +{
  39132. +    int actual;
  39133. +    struct slip *sl = (struct slip *) tty->disc_data;
  39134. +
  39135. +    /* First make sure we're connected. */
  39136. +    if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start) {
  39137. +        return;
  39138. +    }
  39139. +
  39140. +    if (sl->xleft <= 0)  {
  39141. +        /* Now serial buffer is almost free & we can start
  39142. +         * transmission of another packet */
  39143. +        sl->tx_packets++;
  39144. +        tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
  39145. +        sl_unlock(sl);
  39146. +        mark_bh(NET_BH);
  39147. +        return;
  39148. +    }
  39149. +
  39150. +    actual = tty->driver.write(tty, 0, sl->xhead, sl->xleft);
  39151. +    sl->xleft -= actual;
  39152. +    sl->xhead += actual;
  39153. +}
  39154. +
  39155. +/* Encapsulate an IP datagram and kick it into a TTY queue. */
  39156. +static int
  39157. +sl_xmit(struct sk_buff *skb, struct device *dev)
  39158. +{
  39159. +    struct slip *sl = &sl_ctrl[dev->base_addr];
  39160. +
  39161. +    if (!dev->start)  {
  39162. +        printk("%s: xmit call when iface is down\n", dev->name);
  39163. +        return 1;
  39164. +    }
  39165. +    /*
  39166. +     * If we are busy already- too bad.  We ought to be able
  39167. +     * to queue things at this point, to allow for a little
  39168. +     * frame buffer.  Oh well...
  39169. +     * -----------------------------------------------------
  39170. +     * I hate queues in SLIP driver. May be it's efficient,
  39171. +     * but for me latency is more important. ;)
  39172. +     * So, no queues !
  39173. +     *        14 Oct 1994  Dmitry Gorodchanin.
  39174. +     */
  39175. +    if (dev->tbusy) {
  39176. +        /* May be we must check transmitter timeout here ?
  39177. +         *      14 Oct 1994 Dmitry Gorodchanin.
  39178. +         */
  39179. +#ifdef SL_CHECK_TRANSMIT
  39180. +        if (jiffies - dev->trans_start  < 20 * HZ)  {
  39181. +            /* 20 sec timeout not reached */
  39182. +            return 1;
  39183. +        }
  39184. +        printk("%s: transmit timed out, %s?\n", dev->name,
  39185. +               (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?
  39186. +               "bad line quality" : "driver error");
  39187. +        sl->xleft = 0;
  39188. +        sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
  39189. +        sl_unlock(sl);
  39190. +#else
  39191. +        return 1;
  39192. +#endif
  39193. +    }
  39194. +
  39195. +    /* We were not busy, so we are now... :-) */
  39196. +    if (skb != NULL) {
  39197. +        sl_lock(sl);
  39198. +        sl_encaps(sl, skb->data, skb->len);
  39199. +        dev_kfree_skb(skb, FREE_WRITE);
  39200. +    }
  39201. +    return 0;
  39202. +}
  39203. +
  39204. +
  39205. +/* Return the frame type ID.  This is normally IP but maybe be AX.25. */
  39206. +static unsigned short
  39207. +sl_type_trans (struct sk_buff *skb, struct device *dev)
  39208. +{
  39209. +#ifdef CONFIG_AX25
  39210. +    struct slip *sl = &sl_ctrl[dev->base_addr];
  39211. +
  39212. +    if (sl->mode & SL_MODE_AX25)  {
  39213. +        return htons(ETH_P_AX25);
  39214. +    }
  39215. +#endif
  39216. +    return htons(ETH_P_IP);
  39217. +}
  39218. +
  39219. +
  39220. +/* Fill in the MAC-level header. Not used by SLIP. */
  39221. +static int
  39222. +sl_header(unsigned char *buff, struct device *dev, unsigned short type,
  39223. +      void *daddr, void *saddr, unsigned len, struct sk_buff *skb)
  39224. +{
  39225. +#ifdef CONFIG_AX25
  39226. +#ifdef CONFIG_INET
  39227. +    struct slip *sl = &sl_ctrl[dev->base_addr];
  39228. +
  39229. +    if ((sl->mode & SL_MODE_AX25) && type != htons(ETH_P_AX25))  {
  39230. +        return ax25_encapsulate(buff, dev, type, daddr, saddr, len, skb);
  39231. +    }
  39232. +#endif
  39233. +#endif
  39234. +    return 0;
  39235. +}
  39236. +
  39237. +
  39238. +/* Rebuild the MAC-level header.  Not used by SLIP. */
  39239. +static int
  39240. +sl_rebuild_header(void *buff, struct device *dev, unsigned long raddr,
  39241. +          struct sk_buff *skb)
  39242. +{
  39243. +#ifdef CONFIG_AX25
  39244. +#ifdef CONFIG_INET
  39245. +    struct slip *sl = &sl_ctrl[dev->base_addr];
  39246. +
  39247. +    if (sl->mode & SL_MODE_AX25)  {
  39248. +        return ax25_rebuild_header(buff, dev, raddr, skb);
  39249. +    }
  39250. +#endif
  39251. +#endif
  39252. +    return 0;
  39253. +}
  39254. +
  39255. +
  39256. +/* Open the low-level part of the SLIP channel. Easy! */
  39257. +static int
  39258. +sl_open(struct device *dev)
  39259. +{
  39260. +    struct slip *sl = &sl_ctrl[dev->base_addr];
  39261. +    unsigned long len;
  39262. +
  39263. +    if (sl->tty == NULL) {
  39264. +        return -ENODEV;
  39265. +    }
  39266. +
  39267. +    /*
  39268. +     * Allocate the SLIP frame buffers:
  39269. +     *
  39270. +     * rbuff    Receive buffer.
  39271. +     * xbuff    Transmit buffer.
  39272. +     * cbuff        Temporary compression buffer.
  39273. +     */
  39274. +    len = dev->mtu * 2;
  39275. +    /*
  39276. +     * allow for arrival of larger UDP packets, even if we say not to
  39277. +     * also fixes a bug in which SunOS sends 512-byte packets even with
  39278. +     * an MSS of 128
  39279. +     */
  39280. +    if (len < 576 * 2)  {
  39281. +        len = 576 * 2;
  39282. +    }
  39283. +    sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
  39284. +    if (sl->rbuff == NULL)   {
  39285. +        goto norbuff;
  39286. +    }
  39287. +    sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
  39288. +    if (sl->xbuff == NULL)   {
  39289. +        goto noxbuff;
  39290. +    }
  39291. +#ifdef SL_INCLUDE_CSLIP
  39292. +    sl->cbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
  39293. +    if (sl->cbuff == NULL)   {
  39294. +        goto nocbuff;
  39295. +    }
  39296. +    sl->slcomp = slhc_init(16, 16);
  39297. +    if (sl->slcomp == NULL)  {
  39298. +        goto noslcomp;
  39299. +    }
  39300. +#endif
  39301. +
  39302. +#ifdef CONFIG_AX25
  39303. +    sl->mtu         = dev->mtu + 73;
  39304. +#else
  39305. +    sl->mtu         = dev->mtu;
  39306. +#endif
  39307. +    sl->buffsize = len;
  39308. +    sl->rcount   = 0;
  39309. +    sl->xleft    = 0;
  39310. +#ifdef CONFIG_SLIP_MODE_SLIP6
  39311. +    sl->xdata    = 0;
  39312. +    sl->xbits    = 0;
  39313. +#endif
  39314. +    sl->flags   &= (1 << SLF_INUSE);      /* Clear ESCAPE & ERROR flags */
  39315. +
  39316. +    /* Needed because address '0' is special */
  39317. +    if (dev->pa_addr == 0)  {
  39318. +        dev->pa_addr=ntohl(0xC0A80001);
  39319. +    }
  39320. +    dev->tbusy  = 0;
  39321. +/*    dev->flags |= IFF_UP; */
  39322. +    dev->start  = 1;
  39323. +
  39324. +    return 0;
  39325. +
  39326. +    /* Cleanup */
  39327. +#ifdef SL_INCLUDE_CSLIP
  39328. +noslcomp:
  39329. +    kfree(sl->cbuff);
  39330. +nocbuff:
  39331. +#endif
  39332. +    kfree(sl->xbuff);
  39333. +noxbuff:
  39334. +    kfree(sl->rbuff);
  39335. +norbuff:
  39336. +    return -ENOMEM;
  39337. +}
  39338. +
  39339. +
  39340. +/* Close the low-level part of the SLIP channel. Easy! */
  39341. +static int
  39342. +sl_close(struct device *dev)
  39343. +{
  39344. +    struct slip *sl = &sl_ctrl[dev->base_addr];
  39345. +
  39346. +    if (sl->tty == NULL) {
  39347. +        return -EBUSY;
  39348. +    }
  39349. +    sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
  39350. +    dev->tbusy = 1;
  39351. +    dev->start = 0;
  39352. +    
  39353. +/*    dev->flags &= ~IFF_UP; */
  39354. +
  39355. +    return 0;
  39356. +}
  39357. +
  39358. +static int
  39359. +slip_receive_room(struct tty_struct *tty)
  39360. +{
  39361. +    return 65536;  /* We can handle an infinite amount of data. :-) */
  39362. +}
  39363. +
  39364. +/*
  39365. + * Handle the 'receiver data ready' interrupt.
  39366. + * This function is called by the 'tty_io' module in the kernel when
  39367. + * a block of SLIP data has been received, which can now be decapsulated
  39368. + * and sent on to some IP layer for further processing.
  39369. + */
  39370. +static void
  39371. +slip_receive_buf(struct tty_struct *tty, unsigned char *cp, char *fp, int count)
  39372. +{
  39373. +    struct slip *sl = (struct slip *) tty->disc_data;
  39374. +
  39375. +    if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start)
  39376. +        return;
  39377. +
  39378. +    /*
  39379. +     * Argh! mtu change time! - costs us the packet part received
  39380. +     * at the change
  39381. +     */
  39382. +#ifdef CONFIG_AX25
  39383. +    if (sl->mtu != sl->dev->mtu + 73)  {
  39384. +#else
  39385. +    if (sl->mtu != sl->dev->mtu)  {
  39386. +#endif
  39387. +        sl_changedmtu(sl);
  39388. +    }
  39389. +
  39390. +    /* Read the characters out of the buffer */
  39391. +    while (count--) {
  39392. +        if (fp && *fp++) {
  39393. +            if (!set_bit(SLF_ERROR, &sl->flags))  {
  39394. +                sl->rx_errors++;
  39395. +            }
  39396. +            cp++;
  39397. +            continue;
  39398. +        }
  39399. +#ifdef CONFIG_SLIP_MODE_SLIP6
  39400. +        if (sl->mode & SL_MODE_SLIP6)
  39401. +            slip_unesc6(sl, *cp++);
  39402. +        else
  39403. +#endif
  39404. +            slip_unesc(sl, *cp++);
  39405. +    }
  39406. +}
  39407. +
  39408. +/*
  39409. + * Open the high-level part of the SLIP channel.
  39410. + * This function is called by the TTY module when the
  39411. + * SLIP line discipline is called for.  Because we are
  39412. + * sure the tty line exists, we only have to link it to
  39413. + * a free SLIP channel...
  39414. + */
  39415. +static int
  39416. +slip_open(struct tty_struct *tty)
  39417. +{
  39418. +    struct slip *sl = (struct slip *) tty->disc_data;
  39419. +    int err;
  39420. +
  39421. +    /* First make sure we're not already connected. */
  39422. +    if (sl && sl->magic == SLIP_MAGIC) {
  39423. +        return -EEXIST;
  39424. +    }
  39425. +
  39426. +    /* OK.  Find a free SLIP channel to use. */
  39427. +    if ((sl = sl_alloc()) == NULL) {
  39428. +        return -ENFILE;
  39429. +    }
  39430. +
  39431. +    sl->tty = tty;
  39432. +    tty->disc_data = sl;
  39433. +    if (tty->driver.flush_buffer)  {
  39434. +        tty->driver.flush_buffer(tty);
  39435. +    }
  39436. +    if (tty->ldisc.flush_buffer)  {
  39437. +        tty->ldisc.flush_buffer(tty);
  39438. +    }
  39439. +
  39440. +    /* Restore default settings */
  39441. +    sl->mode      = SL_MODE_DEFAULT;
  39442. +    sl->dev->type = ARPHRD_SLIP + sl->mode;
  39443. +#ifdef CONFIG_AX25    
  39444. +    if (sl->dev->type == 260) {    /* KISS */
  39445. +        sl->dev->type = ARPHRD_AX25;
  39446. +    }
  39447. +#endif    
  39448. +    /* Perform the low-level SLIP initialization. */
  39449. +    if ((err = sl_open(sl->dev)))  {
  39450. +        return err;
  39451. +    }
  39452. +    
  39453. +#ifdef MODULE
  39454. +    MOD_INC_USE_COUNT;
  39455. +#endif
  39456. +
  39457. +    /* Done.  We have linked the TTY line to a channel. */
  39458. +    return sl->dev->base_addr;
  39459. +}
  39460. +
  39461. +
  39462. +/*
  39463. + * Close down a SLIP channel.
  39464. + * This means flushing out any pending queues, and then restoring the
  39465. + * TTY line discipline to what it was before it got hooked to SLIP
  39466. + * (which usually is TTY again).
  39467. + */
  39468. +static void
  39469. +slip_close(struct tty_struct *tty)
  39470. +{
  39471. +    struct slip *sl = (struct slip *) tty->disc_data;
  39472. +
  39473. +    /* First make sure we're connected. */
  39474. +    if (!sl || sl->magic != SLIP_MAGIC) {
  39475. +        return;
  39476. +    }
  39477. +
  39478. +    (void) dev_close(sl->dev);
  39479. +    
  39480. +    tty->disc_data = 0;
  39481. +    sl->tty = NULL;
  39482. +    sl_free(sl);
  39483. +#ifdef MODULE
  39484. +    MOD_DEC_USE_COUNT;
  39485. +#endif
  39486. +}
  39487. +
  39488. +
  39489. +static struct enet_statistics *
  39490. +sl_get_stats(struct device *dev)
  39491. +{
  39492. +    static struct enet_statistics stats;
  39493. +    struct slip *sl = &sl_ctrl[dev->base_addr];
  39494. +#ifdef SL_INCLUDE_CSLIP
  39495. +    struct slcompress *comp;
  39496. +#endif
  39497. +
  39498. +    memset(&stats, 0, sizeof(struct enet_statistics));
  39499. +
  39500. +    stats.rx_packets     = sl->rx_packets;
  39501. +    stats.tx_packets     = sl->tx_packets;
  39502. +    stats.rx_dropped     = sl->rx_dropped;
  39503. +    stats.tx_dropped     = sl->tx_dropped;
  39504. +    stats.tx_errors      = sl->tx_errors;
  39505. +    stats.rx_errors      = sl->rx_errors;
  39506. +    stats.rx_over_errors = sl->rx_over_errors;
  39507. +#ifdef SL_INCLUDE_CSLIP
  39508. +    stats.rx_fifo_errors = sl->rx_compressed;
  39509. +    stats.tx_fifo_errors = sl->tx_compressed;
  39510. +    stats.collisions     = sl->tx_misses;
  39511. +    comp = sl->slcomp;
  39512. +    if (comp) {
  39513. +        stats.rx_fifo_errors += comp->sls_i_compressed;
  39514. +        stats.rx_dropped     += comp->sls_i_tossed;
  39515. +        stats.tx_fifo_errors += comp->sls_o_compressed;
  39516. +        stats.collisions     += comp->sls_o_misses;
  39517. +    }
  39518. +#endif /* CONFIG_INET */
  39519. +    return (&stats);
  39520. +}
  39521. +
  39522. +
  39523. + /************************************************************************
  39524. +  *            STANDARD SLIP ENCAPSULATION               *
  39525. +  ************************************************************************/
  39526. +
  39527. +int
  39528. +slip_esc(unsigned char *s, unsigned char *d, int len)
  39529. +{
  39530. +    unsigned char *ptr = d;
  39531. +    unsigned char