home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 4 / DATAFILE_PDCD4.iso / unix / armlinux / kernel_src / LINUX-1_3 / linux-1.3.35-arm.diff
Encoding:
Text File  |  1996-03-03  |  1.5 MB  |  56,931 lines

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. diff -urNwbB linux/Makefile linux.arm/Makefile
  2. --- linux/Makefile    Sun Mar  3 11:42:06 1996
  3. +++ linux.arm/Makefile    Sun Feb 11 13:47:34 1996
  4. @@ -2,7 +2,7 @@
  5.  PATCHLEVEL = 3
  6.  SUBLEVEL = 35
  7.  
  8. -ARCH = i386
  9. +ARCH = arm
  10.  
  11.  .EXPORT_ALL_VARIABLES:
  12.  
  13. @@ -86,13 +86,19 @@
  14.  # Include the make variables (CC, etc...)
  15.  #
  16.  
  17. +# Modified 11/02/96 by Russell King
  18. +#    - Doesn't include the drivers subdirectory as standard.
  19. +#    - Modified the 'nm' line in vmlinux so that we remove local and absolute symbols.
  20. +
  21.  ARCHIVES    =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o net/network.a
  22.  FILESYSTEMS    =fs/filesystems.a
  23. -DRIVERS        =drivers/block/block.a \
  24. +DRIVERS        =
  25. +LIBS        =$(TOPDIR)/lib/lib.a
  26. +SUBDIRS        =kernel mm fs net ipc lib
  27. +
  28. +DRIVERS :=drivers/block/block.a \
  29.           drivers/char/char.a \
  30.           drivers/net/net.a
  31. -LIBS        =$(TOPDIR)/lib/lib.a
  32. -SUBDIRS        =kernel drivers mm fs net ipc lib
  33.  
  34.  ifdef CONFIG_SCSI
  35.  DRIVERS := $(DRIVERS) drivers/scsi/scsi.a
  36. @@ -108,6 +114,10 @@
  37.  
  38.  include arch/$(ARCH)/Makefile
  39.  
  40. +ifndef CONFIG_ARM
  41. +SUBDIRS := drivers $(SUBDIRS)
  42. +endif
  43. +
  44.  .S.s:
  45.      $(CC) -D__ASSEMBLY__ -traditional -E -o $*.s $<
  46.  .S.o:
  47. @@ -125,7 +135,7 @@
  48.          $(FILESYSTEMS) \
  49.          $(DRIVERS) \
  50.          $(LIBS) -o vmlinux
  51. -    $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | sort > System.map
  52. +    $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)\|\( A \)\|\( t L\)' | sort > System.map
  53.  
  54.  symlinks:
  55.      rm -f include/asm
  56. diff -urNwbB linux/arch/arm/Makefile linux.arm/arch/arm/Makefile
  57. --- linux/arch/arm/Makefile    Thu Jan  1 01:00:00 1970
  58. +++ linux.arm/arch/arm/Makefile    Sat Feb 24 13:08:03 1996
  59. @@ -0,0 +1,70 @@
  60. +#
  61. +# arch/arm/Makefile
  62. +#
  63. +# This file is included by the global makefile so that you can add your own
  64. +# architecture-specific flags and dependencies. Remember to do have actions
  65. +# for "archclean" and "archdep" for cleaning up and making dependencies for
  66. +# this architecture
  67. +#
  68. +# This file is subject to the terms and conditions of the GNU General Public
  69. +# License.  See the file "COPYING" in the main directory of this archive
  70. +# for more details.
  71. +#
  72. +# Copyright (C) 1995 by Russell King
  73. +#
  74. +
  75. +#
  76. +# Set these to indicate how to link it..
  77. +# -qmagic (we need to remove the 32 byte header for bootup purposes)
  78. +#
  79. +
  80. +SUBARCH         = -m3
  81. +
  82. +CPP         = $(CC) -E $(SUBARCH)
  83. +CFLAGS        := $(CFLAGS:-fomit-frame-pointer=) $(SUBARCH)
  84. +LINKFLAGS     = -Ttext 0x01800000
  85. +ZLINKFLAGS     = -N -Ttext 0x01800000
  86. +
  87. +HEAD        := arch/arm/kernel/head.o
  88. +SUBDIRS        := arch/arm/drivers arch/arm/kernel arch/arm/mm arch/arm/lib $(SUBDIRS)
  89. +ARCHIVES    := arch/arm/kernel/kernel.o arch/arm/mm/mm.o arch/arm/lib/lib.o $(ARCHIVES)
  90. +LIBS        := $(LIBS) `gcc --print-libgcc-file-name`
  91. +
  92. +DRIVERS := arch/arm/drivers/block/block.a arch/arm/drivers/char/char.a \
  93. +           arch/arm/drivers/net/net.a
  94. +
  95. +ifdef CONFIG_SOUND
  96. +DRIVERS := $(DRIVERS) arch/arm/drivers/sound/sound.a
  97. +endif
  98. +
  99. +ifdef CONFIG_SCSI
  100. +DRIVERS := $(DRIVERS) arch/arm/drivers/scsi/scsi.a
  101. +endif
  102. +
  103. +
  104. +arch/arm/kernel: dummy
  105. +    $(MAKE) linuxsubdirs SUBDIRS=arch/arm/kernel
  106. +
  107. +arch/arm/mm: dummy
  108. +    $(MAKE) linuxsubdirs SUBDIRS=arch/arm/mm
  109. +
  110. +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
  111. +
  112. +install:
  113. +    @$(MAKEBOOT) install
  114. +
  115. +zinstall:
  116. +    @$(MAKEBOOT) zinstall
  117. +
  118. +zImage:
  119. +    @$(MAKEBOOT) zImage
  120. +
  121. +archclean:
  122. +    @$(MAKEBOOT) clean
  123. +    @$(MAKE) -C arch/$(ARCH)/drivers/block LINKCLEAN
  124. +    @$(MAKE) -C arch/$(ARCH)/drivers/char LINKCLEAN
  125. +    @$(MAKE) -C arch/$(ARCH)/drivers/net LINKCLEAN
  126. +    @$(MAKE) -C arch/$(ARCH)/drivers/scsi LINKCLEAN
  127. +
  128. +archdep:
  129. +    @$(MAKEBOOT) dep
  130. diff -urNwbB linux/arch/arm/boot/Makefile linux.arm/arch/arm/boot/Makefile
  131. --- linux/arch/arm/boot/Makefile    Thu Jan  1 01:00:00 1970
  132. +++ linux.arm/arch/arm/boot/Makefile    Sun Feb 11 21:59:54 1996
  133. @@ -0,0 +1,47 @@
  134. +#
  135. +# arch/i386/boot/Makefile
  136. +#
  137. +# This file is subject to the terms and conditions of the GNU General Public
  138. +# License.  See the file "COPYING" in the main directory of this archive
  139. +# for more details.
  140. +#
  141. +# Copyright (C) 1994 by Linus Torvalds
  142. +#
  143. +
  144. +Image:    $(CONFIGURE) tools/build $(TOPDIR)/vmlinux
  145. +    tools/build $(TOPDIR)/vmlinux > Image
  146. +    sync
  147. +
  148. +zImage:    $(CONFIGURE) tools/build compressed/vmlinux
  149. +    tools/build compressed/vmlinux > zImage
  150. +
  151. +compressed/vmlinux: $(TOPDIR)/vmlinux dep
  152. +    @$(MAKE) -C compressed vmlinux
  153. +
  154. +install: $(CONFIGURE) Image
  155. +    sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) Image $(TOPDIR)/System.map "$(INSTALL_PATH)"
  156. +
  157. +zinstall: $(CONFIGURE) zImage
  158. +    sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
  159. +
  160. +tools/build: tools/build.c
  161. +    $(HOSTCC) $(CFLAGS) -o $@ $< -I$(TOPDIR)/include
  162. +
  163. +clean:
  164. +    rm -f Image zImage tools/build
  165. +    @$(MAKE) -C compressed clean
  166. +
  167. +dep:
  168. +
  169. +#zdisk: zImage
  170. +#    dd bs=8192 if=zImage of=/dev/fd0
  171. +
  172. +#zlilo: $(CONFIGURE) zImage
  173. +#    if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
  174. +#    if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
  175. +#    cat zImage > $(INSTALL_PATH)/vmlinuz
  176. +#    cp $(TOPDIR)/System.map $(INSTALL_PATH)/
  177. +#    if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
  178. +
  179. +#install: $(CONFIGURE) zImage
  180. +#    sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
  181. diff -urNwbB linux/arch/arm/boot/compressed/Makefile linux.arm/arch/arm/boot/compressed/Makefile
  182. --- linux/arch/arm/boot/compressed/Makefile    Thu Jan  1 01:00:00 1970
  183. +++ linux.arm/arch/arm/boot/compressed/Makefile    Sun Mar  3 13:35:37 1996
  184. @@ -0,0 +1,56 @@
  185. +#
  186. +# linux/arch/arm/boot/compressed/Makefile
  187. +#
  188. +# create a compressed vmlinux image from the original vmlinux
  189. +#
  190. +
  191. +CFLAGS = -O2 -DSTDC_HEADERS
  192. +LOADADDR = 0x01800000
  193. +RELADDR = 0x01960000
  194. +
  195. +SYSTEM = $(TOPDIR)/vmlinux
  196. +DECOMP_OBJS = inflate.o unzip.o misc.o ../../lib/ll_char_wr.o
  197. +
  198. +
  199. +all:        vmlinux
  200. +
  201. +vmlinux:    head.o piggy.o
  202. +        $(LD) -Ttext=$(LOADADDR) -o vmlinux head.o piggy.o
  203. +
  204. +head.o:     head.S
  205. +        $(CC) -traditional -DRELADDR=$(RELADDR) -c head.S
  206. +
  207. +piggy.o:    decomphead.o decompress.a compressed.o
  208. +        $(LD) -s -Ttext=$(RELADDR) -o a.out decomphead.o compressed.o decompress.a
  209. +        strip a.out
  210. +        ./piggyback < a.out > piggy.o
  211. +        rm -f a.out
  212. +
  213. +compressed.o:    $(SYSTEM) xtract piggyback
  214. +        ./xtract $(SYSTEM) | gzip -9 | ./piggyback > compressed.o
  215. +
  216. +
  217. +# rules for decompression part of kernel
  218. +
  219. +decompress.a:    $(DECOMP_OBJS)
  220. +        $(AR) $(ARFLAGS) decompress.a $(DECOMP_OBJS)
  221. +
  222. +decomphead.o:    decomphead.S
  223. +        $(CC) -traditional -DLOADADDR=$(LOADADDR) -c decomphead.S
  224. +
  225. +../../lib/ll_char_wr.o:
  226. +        make -C ../../lib ll_char_wr.o
  227. +
  228. +
  229. +# rules for extracting & piggybacking the kernel
  230. +
  231. +xtract:     xtract.c
  232. +        $(HOSTCC) $(CFLAGS) -o xtract xtract.c
  233. +
  234. +piggyback:    piggyback.c
  235. +        $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
  236. +
  237. +
  238. +clean:
  239. +        rm -f xtract piggyback vmlinux decompress.a a.out
  240. +
  241. diff -urNwbB linux/arch/arm/boot/compressed/crypt.h linux.arm/arch/arm/boot/compressed/crypt.h
  242. --- linux/arch/arm/boot/compressed/crypt.h    Thu Jan  1 01:00:00 1970
  243. +++ linux.arm/arch/arm/boot/compressed/crypt.h    Sun Feb 11 09:32:10 1996
  244. @@ -0,0 +1,12 @@
  245. +/* crypt.h (dummy version) -- do not perform encryption
  246. + * Hardly worth copyrighting :-)
  247. + */
  248. +
  249. +#ifdef CRYPT
  250. +#  undef CRYPT      /* dummy version */
  251. +#endif
  252. +
  253. +#define RAND_HEAD_LEN  12  /* length of encryption random header */
  254. +
  255. +#define zencode
  256. +#define zdecode
  257. diff -urNwbB linux/arch/arm/boot/compressed/decomphead.S linux.arm/arch/arm/boot/compressed/decomphead.S
  258. --- linux/arch/arm/boot/compressed/decomphead.S    Thu Jan  1 01:00:00 1970
  259. +++ linux.arm/arch/arm/boot/compressed/decomphead.S    Sun Feb 11 09:32:10 1996
  260. @@ -0,0 +1,25 @@
  261. +/*
  262. + *  linux/arch/arm/boot/decomphead.S
  263. + */
  264. +
  265. +.text
  266. +    .global    __stext
  267. +__stext:
  268. +    b    start
  269. +LC0:
  270. +    .word    __edata
  271. +    .word    __end
  272. +    .word    LOADADDR + 0x23
  273. +    .word    __stack_start+16384
  274. +start:
  275. +    adr    r1, LC0
  276. +    ldmia    r1, {r2, r3, r4, sp}
  277. +    mov    r1, #0
  278. +clrzlp:    str    r1, [r2], #4
  279. +    cmp    r2, r3
  280. +    blt    clrzlp
  281. +    bic    r0, r4, #3
  282. +    bl    _decompress_kernel
  283. +    mov    r0, #0
  284. +    mov    pc, r4
  285. +
  286. diff -urNwbB linux/arch/arm/boot/compressed/gzip.h linux.arm/arch/arm/boot/compressed/gzip.h
  287. --- linux/arch/arm/boot/compressed/gzip.h    Thu Jan  1 01:00:00 1970
  288. +++ linux.arm/arch/arm/boot/compressed/gzip.h    Sun Feb 11 09:32:10 1996
  289. @@ -0,0 +1,284 @@
  290. +/* gzip.h -- common declarations for all gzip modules
  291. + * Copyright (C) 1992-1993 Jean-loup Gailly.
  292. + * This is free software; you can redistribute it and/or modify it under the
  293. + * terms of the GNU General Public License, see the file COPYING.
  294. + */
  295. +
  296. +#if defined(__STDC__) || defined(PROTO)
  297. +#  define OF(args)  args
  298. +#else
  299. +#  define OF(args)  ()
  300. +#endif
  301. +
  302. +#ifdef __STDC__
  303. +   typedef void *voidp;
  304. +#else
  305. +   typedef char *voidp;
  306. +#endif
  307. +
  308. +/* I don't like nested includes, but the string functions are used too often */
  309. +#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
  310. +#  include <string.h>
  311. +#  define memzero(s, n)     memset ((s), 0, (n))
  312. +#else
  313. +#  include <strings.h>
  314. +#  define strchr            index 
  315. +#  define strrchr           rindex
  316. +#  define memcpy(d, s, n)   bcopy((s), (d), (n)) 
  317. +#  define memcmp(s1, s2, n) bcmp((s1), (s2), (n)) 
  318. +#  define memzero(s, n)     bzero((s), (n))
  319. +#endif
  320. +
  321. +#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
  322. +#  include <memory.h>
  323. +#endif
  324. +
  325. +#ifndef RETSIGTYPE
  326. +#  define RETSIGTYPE void
  327. +#endif
  328. +
  329. +#define local static
  330. +
  331. +typedef unsigned char  uch;
  332. +typedef unsigned short ush;
  333. +typedef unsigned long  ulg;
  334. +
  335. +/* Return codes from gzip */
  336. +#define OK      0
  337. +#define ERROR   1
  338. +#define WARNING 2
  339. +
  340. +/* Compression methods (see algorithm.doc) */
  341. +#define STORED     0
  342. +#define COMPRESSED 1
  343. +#define PACKED     2
  344. +/* methods 3 to 7 reserved */
  345. +#define DEFLATED   8
  346. +extern int method;         /* compression method */
  347. +
  348. +/* To save memory for 16 bit systems, some arrays are overlayed between
  349. + * the various modules:
  350. + * deflate:  prev+head   window      d_buf  l_buf  outbuf
  351. + * unlzw:    tab_prefix  tab_suffix  stack  inbuf  outbuf
  352. + * inflate:              window             inbuf
  353. + * unpack:               window             inbuf
  354. + * For compression, input is done in window[]. For decompression, output
  355. + * is done in window except for unlzw.
  356. + */
  357. +
  358. +#ifndef    INBUFSIZ
  359. +#  define INBUFSIZ  0x8000  /* input buffer size */
  360. +#endif
  361. +#define INBUF_EXTRA  64     /* required by unlzw() */
  362. +
  363. +#ifndef    OUTBUFSIZ
  364. +#  define OUTBUFSIZ  16384  /* output buffer size */
  365. +#endif
  366. +#define OUTBUF_EXTRA 2048   /* required by unlzw() */
  367. +
  368. +#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
  369. +
  370. +#ifdef DYN_ALLOC
  371. +#  define EXTERN(type, array)  extern type * near array
  372. +#  define DECLARE(type, array, size)  type * near array
  373. +#  define ALLOC(type, array, size) { \
  374. +      array = (type*)fcalloc((unsigned)(((size)+1L)/2), 2*sizeof(type)); \
  375. +      if (array == NULL) error("insufficient memory"); \
  376. +   }
  377. +#  define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
  378. +#else
  379. +#  define EXTERN(type, array)  extern type array[]
  380. +#  define DECLARE(type, array, size)  type array[size]
  381. +#  define ALLOC(type, array, size)
  382. +#  define FREE(array)
  383. +#endif
  384. +
  385. +EXTERN(uch, inbuf);          /* input buffer */
  386. +EXTERN(uch, outbuf);         /* output buffer */
  387. +EXTERN(ush, d_buf);          /* buffer for distances, see trees.c */
  388. +EXTERN(uch, window);         /* Sliding window and suffix table (unlzw) */
  389. +#define tab_suffix window
  390. +#ifndef MAXSEG_64K
  391. +#  define tab_prefix prev    /* hash link (see deflate.c) */
  392. +#  define head (prev+WSIZE)  /* hash head (see deflate.c) */
  393. +   EXTERN(ush, tab_prefix);  /* prefix code (see unlzw.c) */
  394. +#else
  395. +#  define tab_prefix0 prev
  396. +#  define head tab_prefix1
  397. +   EXTERN(ush, tab_prefix0); /* prefix for even codes */
  398. +   EXTERN(ush, tab_prefix1); /* prefix for odd  codes */
  399. +#endif
  400. +
  401. +extern unsigned insize; /* valid bytes in inbuf */
  402. +extern unsigned inptr;  /* index of next byte to be processed in inbuf */
  403. +extern unsigned outcnt; /* bytes in output buffer */
  404. +
  405. +extern long bytes_in;   /* number of input bytes */
  406. +extern long bytes_out;  /* number of output bytes */
  407. +extern long overhead;   /* number of bytes in gzip header */
  408. +
  409. +#define isize bytes_in
  410. +/* for compatibility with old zip sources (to be cleaned) */
  411. +
  412. +extern int  ifd;        /* input file descriptor */
  413. +extern int  ofd;        /* output file descriptor */
  414. +extern char ifname[];   /* input filename or "stdin" */
  415. +extern char ofname[];   /* output filename or "stdout" */
  416. +
  417. +extern ulg time_stamp;  /* original time stamp (modification time) */
  418. +extern long ifile_size; /* input file size, -1 for devices (debug only) */
  419. +
  420. +extern int exit_code;   /* program exit code */
  421. +
  422. +typedef int file_t;     /* Do not use stdio */
  423. +#define NO_FILE  (-1)   /* in memory compression */
  424. +
  425. +
  426. +#define    GZIP_MAGIC     "\037\213" /* Magic header for gzip files, 1F 8B */
  427. +#define    OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
  428. +#define    PKZIP_MAGIC  "PK\003\004" /* Magic header for pkzip files */
  429. +#define    PACK_MAGIC     "\037\036" /* Magic header for packed files */
  430. +
  431. +/* gzip flag byte */
  432. +#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
  433. +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
  434. +#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
  435. +#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
  436. +#define COMMENT      0x10 /* bit 4 set: file comment present */
  437. +#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
  438. +#define RESERVED     0xC0 /* bit 6,7:   reserved */
  439. +
  440. +/* internal file attribute */
  441. +#define UNKNOWN (-1)
  442. +#define BINARY  0
  443. +#define ASCII   1
  444. +
  445. +#ifndef WSIZE
  446. +#  define WSIZE 0x8000     /* window size--must be a power of two, and */
  447. +#endif                     /*  at least 32K for zip's deflate method */
  448. +
  449. +#define MIN_MATCH  3
  450. +#define MAX_MATCH  258
  451. +/* The minimum and maximum match lengths */
  452. +
  453. +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
  454. +/* Minimum amount of lookahead, except at the end of the input file.
  455. + * See deflate.c for comments about the MIN_MATCH+1.
  456. + */
  457. +
  458. +#define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
  459. +/* In order to simplify the code, particularly on 16 bit machines, match
  460. + * distances are limited to MAX_DIST instead of WSIZE.
  461. + */
  462. +
  463. +extern int decrypt;        /* flag to turn on decryption */
  464. +extern int save_orig_name; /* set if original name must be saved */
  465. +extern int verbose;        /* be verbose (-v) */
  466. +extern int level;          /* compression level */
  467. +extern int test;           /* check .z file integrity */
  468. +extern int to_stdout;      /* output to stdout (-c) */
  469. +
  470. +#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
  471. +
  472. +/* put_byte is used for the compressed output, put_char for the
  473. + * uncompressed output. However unlzw() uses window for its
  474. + * suffix table instead of its output buffer, so it does not use put_char.
  475. + * (to be cleaned up).
  476. + */
  477. +#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
  478. +   flush_outbuf();}
  479. +#define put_char(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
  480. +   flush_window();}
  481. +
  482. +/* Output a 16 bit value, lsb first */
  483. +#define put_short(w) \
  484. +{ if (outcnt < OUTBUFSIZ-2) { \
  485. +    outbuf[outcnt++] = (uch) ((w) & 0xff); \
  486. +    outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
  487. +  } else { \
  488. +    put_byte((uch)((w) & 0xff)); \
  489. +    put_byte((uch)((ush)(w) >> 8)); \
  490. +  } \
  491. +}
  492. +
  493. +/* Output a 32 bit value to the bit stream, lsb first */
  494. +#define put_long(n) { \
  495. +    put_short((n) & 0xffff); \
  496. +    put_short(((ulg)(n)) >> 16); \
  497. +}
  498. +
  499. +#define seekable()    0  /* force sequential output */
  500. +#define translate_eol 0  /* no option -a yet */
  501. +
  502. +#define tolow(c)  (isupper(c) ? (c)-'A'+'a' : (c))    /* force to lower case */
  503. +
  504. +/* Macros for getting two-byte and four-byte header values */
  505. +#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
  506. +#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
  507. +
  508. +/* Diagnostic functions */
  509. +#ifdef DEBUG
  510. +#  define Assert(cond,msg) {if(!(cond)) error(msg);}
  511. +#  define Trace(x) fprintf x
  512. +#  define Tracev(x) {if (verbose) fprintf x ;}
  513. +#  define Tracevv(x) {if (verbose>1) fprintf x ;}
  514. +#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
  515. +#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
  516. +#else
  517. +#  define Assert(cond,msg)
  518. +#  define Trace(x)
  519. +#  define Tracev(x)
  520. +#  define Tracevv(x)
  521. +#  define Tracec(c,x)
  522. +#  define Tracecv(c,x)
  523. +#endif
  524. +
  525. +    /* in zip.c: */
  526. +extern void zip    OF((int in, int out));
  527. +extern int file_read  OF((char *buf,  unsigned size));
  528. +
  529. +    /* in unzip.c */
  530. +extern void unzip        OF((int in, int out));
  531. +extern int check_zipfile OF((int in));
  532. +
  533. +    /* in unpack.c */
  534. +extern void unpack        OF((int in, int out));
  535. +
  536. +    /* in gzip.c */
  537. +RETSIGTYPE abort_gzip   OF((void));
  538. +
  539. +        /* in deflate.c */
  540. +void lm_init OF((int pack_level, ush *flags));
  541. +ulg  deflate OF((void));
  542. +
  543. +        /* in trees.c */
  544. +void ct_init     OF((ush *attr, int *method));
  545. +int  ct_tally    OF((int dist, int lc));
  546. +ulg  flush_block OF((char *buf, ulg stored_len, int eof));
  547. +
  548. +        /* in bits.c */
  549. +void     bi_init    OF((file_t zipfile));
  550. +void     send_bits  OF((int value, int length));
  551. +unsigned bi_reverse OF((unsigned value, int length));
  552. +void     bi_windup  OF((void));
  553. +void     copy_block OF((char *buf, unsigned len, int header));
  554. +extern   int (*read_buf) OF((char *buf, unsigned size));
  555. +
  556. +    /* in util.c: */
  557. +extern ulg  updcrc        OF((uch *s, unsigned n));
  558. +extern void clear_bufs    OF((void));
  559. +extern int  fill_inbuf    OF((void));
  560. +extern void flush_outbuf  OF((void));
  561. +extern void flush_window  OF((void));
  562. +extern char *strlwr       OF((char *s));
  563. +extern char *basename     OF((char *fname));
  564. +extern char *add_envopt   OF((int *argcp, char ***argvp, char *env));
  565. +extern void error         OF((char *m));
  566. +extern void warn          OF((char *a, char *b));
  567. +extern void read_error    OF((void));
  568. +extern void write_error   OF((void));
  569. +extern void display_ratio OF((long num, long den));
  570. +extern voidp xmalloc      OF((unsigned int size));
  571. +
  572. +    /* in inflate.c */
  573. +extern int inflate OF((void));
  574. diff -urNwbB linux/arch/arm/boot/compressed/head.S linux.arm/arch/arm/boot/compressed/head.S
  575. --- linux/arch/arm/boot/compressed/head.S    Thu Jan  1 01:00:00 1970
  576. +++ linux.arm/arch/arm/boot/compressed/head.S    Sun Feb 11 09:32:10 1996
  577. @@ -0,0 +1,36 @@
  578. +        .text
  579. +        .align
  580. +
  581. +@ Entry point
  582. +@ r0 = kernel info page
  583. +@ r1 = kernel length (length of this code+data)
  584. +
  585. +        .global __stext
  586. +__stext:
  587. +        b    start
  588. +LC0:
  589. +        .word    _input_data
  590. +        .word    _input_end
  591. +        .word    RELADDR
  592. +start:
  593. +        teq    r0, #0
  594. +        beq    newparams
  595. +        mov    r4,     #0x02000000
  596. +        add    r4, r4, #0x0007C000    @ = 0x0207C000 [new param location]
  597. +        mov    r3,     #0x4000
  598. +        sub    r3, r3, #4
  599. +lp2:        ldmia    r0!, {r5, r6, r7, r8, r9, r10, r11, r12}
  600. +        stmia    r4!, {r5, r6, r7, r8, r9, r10, r11, r12}
  601. +        subs    r3, r3, #32
  602. +        bpl    lp2
  603. +newparams:    adr    r3, LC0
  604. +        ldmia    r3, {r2, r3, r4}
  605. +        sub    r3, r3, r2
  606. +        mov    r1, r4
  607. +lp:        ldmia    r2!, {r5, r6, r7, r8, r9, r10, r11, r12}
  608. +        stmia    r4!, {r5, r6, r7, r8, r9, r10, r11, r12}
  609. +        subs    r3, r3, #32
  610. +        bpl    lp
  611. +        ldr    r1, [r1, #0x14]
  612. +        mov    pc, r1
  613. +
  614. diff -urNwbB linux/arch/arm/boot/compressed/inflate.c linux.arm/arch/arm/boot/compressed/inflate.c
  615. --- linux/arch/arm/boot/compressed/inflate.c    Thu Jan  1 01:00:00 1970
  616. +++ linux.arm/arch/arm/boot/compressed/inflate.c    Sat Feb 24 09:36:43 1996
  617. @@ -0,0 +1,810 @@
  618. +#define DEBG(x)
  619. +#define DEBG1(x)
  620. +/* inflate.c -- Not copyrighted 1992 by Mark Adler
  621. +   version c10p1, 10 January 1993 */
  622. +
  623. +/* 
  624. + * Adapted for booting Linux by Hannu Savolainen 1993
  625. + * based on gzip-1.0.3 
  626. + */
  627. +
  628. +#ifndef lint
  629. +static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $";
  630. +#endif
  631. +
  632. +#include "gzip.h"
  633. +#define slide window
  634. +
  635. +#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
  636. +#  include <sys/types.h>
  637. +#  include <stdlib.h>
  638. +#endif
  639. +
  640. +struct huft {
  641. +  uch e;                /* number of extra bits or operation */
  642. +  uch b;                /* number of bits in this code or subcode */
  643. +  union {
  644. +    ush n;              /* literal, length base, or distance base */
  645. +    struct huft *t;     /* pointer to next level of table */
  646. +  } v;
  647. +};
  648. +
  649. +
  650. +/* Function prototypes */
  651. +int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
  652. +                   struct huft **, int *));
  653. +int huft_free OF((struct huft *));
  654. +int inflate_codes OF((struct huft *, struct huft *, int, int));
  655. +int inflate_stored OF((void));
  656. +int inflate_fixed OF((void));
  657. +int inflate_dynamic OF((void));
  658. +int inflate_block OF((int *));
  659. +int inflate OF((void));
  660. +
  661. +
  662. +#define wp outcnt
  663. +#define flush_output(w) (wp=(w),flush_window())
  664. +
  665. +/* Tables for deflate from PKZIP's appnote.txt. */
  666. +static unsigned border[] = {    /* Order of the bit length code lengths */
  667. +        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
  668. +static ush cplens[] = {         /* Copy lengths for literal codes 257..285 */
  669. +        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
  670. +        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
  671. +        /* note: see note #13 above about the 258 in this list. */
  672. +static ush cplext[] = {         /* Extra bits for literal codes 257..285 */
  673. +        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
  674. +        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
  675. +static ush cpdist[] = {         /* Copy offsets for distance codes 0..29 */
  676. +        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
  677. +        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
  678. +        8193, 12289, 16385, 24577};
  679. +static ush cpdext[] = {         /* Extra bits for distance codes */
  680. +        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
  681. +        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
  682. +        12, 12, 13, 13};
  683. +
  684. +
  685. +ulg bb;                         /* bit buffer */
  686. +unsigned bk;                    /* bits in bit buffer */
  687. +
  688. +ush mask_bits[] = {
  689. +    0x0000,
  690. +    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
  691. +    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
  692. +};
  693. +
  694. +#ifdef CRYPT
  695. +  uch cc;
  696. +#  define NEXTBYTE() \
  697. +     (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
  698. +#else
  699. +#  define NEXTBYTE()  (uch)get_byte()
  700. +#endif
  701. +#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
  702. +#define DUMPBITS(n) {b>>=(n);k-=(n);}
  703. +
  704. +int lbits = 9;          /* bits in base literal/length lookup table */
  705. +int dbits = 6;          /* bits in base distance lookup table */
  706. +
  707. +
  708. +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
  709. +#define BMAX 16         /* maximum bit length of any code (16 for explode) */
  710. +#define N_MAX 288       /* maximum number of codes in any set */
  711. +
  712. +
  713. +unsigned hufts;         /* track memory usage */
  714. +
  715. +
  716. +int huft_build(b, n, s, d, e, t, m)
  717. +unsigned *b;            /* code lengths in bits (all assumed <= BMAX) */
  718. +unsigned n;             /* number of codes (assumed <= N_MAX) */
  719. +unsigned s;             /* number of simple-valued codes (0..s-1) */
  720. +ush *d;                 /* list of base values for non-simple codes */
  721. +ush *e;                 /* list of extra bits for non-simple codes */
  722. +struct huft **t;        /* result: starting table */
  723. +int *m;                 /* maximum lookup bits, returns actual */
  724. +/* Given a list of code lengths and a maximum table size, make a set of
  725. +   tables to decode that set of codes.  Return zero on success, one if
  726. +   the given code set is incomplete (the tables are still built in this
  727. +   case), two if the input is invalid (all zero length codes or an
  728. +   oversubscribed set of lengths), and three if not enough memory. */
  729. +{
  730. +  unsigned a;                   /* counter for codes of length k */
  731. +  unsigned c[BMAX+1];           /* bit length count table */
  732. +  unsigned f;                   /* i repeats in table every f entries */
  733. +  int g;                        /* maximum code length */
  734. +  int h;                        /* table level */
  735. +  register unsigned i;          /* counter, current code */
  736. +  register unsigned j;          /* counter */
  737. +  register int k;               /* number of bits in current code */
  738. +  int l;                        /* bits per table (returned in m) */
  739. +  register unsigned *p;         /* pointer into c[], b[], or v[] */
  740. +  register struct huft *q;      /* points to current table */
  741. +  struct huft r;                /* table entry for structure assignment */
  742. +  struct huft *u[BMAX];         /* table stack */
  743. +  unsigned v[N_MAX];            /* values in order of bit length */
  744. +  register int w;               /* bits before this table == (l * h) */
  745. +  unsigned x[BMAX+1];           /* bit offsets, then code stack */
  746. +  unsigned *xp;                 /* pointer into x */
  747. +  int y;                        /* number of dummy codes added */
  748. +  unsigned z;                   /* number of entries in current table */
  749. +
  750. +DEBG("huft1 ");
  751. +
  752. +  /* Generate counts for each bit length */
  753. +  memzero(c, sizeof(c));
  754. +  p = b;  i = n;
  755. +  do {
  756. +    c[*p++]++;                  /* assume all entries <= BMAX */
  757. +  } while (--i);
  758. +  if (c[0] == n)                /* null input--all zero length codes */
  759. +  {
  760. +    *t = (struct huft *)NULL;
  761. +    *m = 0;
  762. +    return 0;
  763. +  }
  764. +
  765. +DEBG("huft2 ");
  766. +
  767. +  /* Find minimum and maximum length, bound *m by those */
  768. +  l = *m;
  769. +  for (j = 1; j <= BMAX; j++)
  770. +    if (c[j])
  771. +      break;
  772. +  k = j;                        /* minimum code length */
  773. +  if ((unsigned)l < j)
  774. +    l = j;
  775. +  for (i = BMAX; i; i--)
  776. +    if (c[i])
  777. +      break;
  778. +  g = i;                        /* maximum code length */
  779. +  if ((unsigned)l > i)
  780. +    l = i;
  781. +  *m = l;
  782. +
  783. +DEBG("huft3 ");
  784. +
  785. +  /* Adjust last length count to fill out codes, if needed */
  786. +  for (y = 1 << j; j < i; j++, y <<= 1)
  787. +    if ((y -= c[j]) < 0)
  788. +      return 2;                 /* bad input: more codes than bits */
  789. +  if ((y -= c[i]) < 0)
  790. +    return 2;
  791. +  c[i] += y;
  792. +
  793. +DEBG("huft4 ");
  794. +
  795. +  /* Generate starting offsets into the value table for each length */
  796. +  x[1] = j = 0;
  797. +  p = c + 1;  xp = x + 2;
  798. +  while (--i) {                 /* note that i == g from above */
  799. +    *xp++ = (j += *p++);
  800. +  }
  801. +
  802. +DEBG("huft5 ");
  803. +
  804. +  /* Make a table of values in order of bit lengths */
  805. +  p = b;  i = 0;
  806. +  do {
  807. +    if ((j = *p++) != 0)
  808. +      v[x[j]++] = i;
  809. +  } while (++i < n);
  810. +
  811. +DEBG("h6 ");
  812. +
  813. +  /* Generate the Huffman codes and for each, make the table entries */
  814. +  x[0] = i = 0;                 /* first Huffman code is zero */
  815. +  p = v;                        /* grab values in bit order */
  816. +  h = -1;                       /* no tables yet--level -1 */
  817. +  w = -l;                       /* bits decoded == (l * h) */
  818. +  u[0] = (struct huft *)NULL;   /* just to keep compilers happy */
  819. +  q = (struct huft *)NULL;      /* ditto */
  820. +  z = 0;                        /* ditto */
  821. +DEBG("h6a ");
  822. +
  823. +  /* go through the bit lengths (k already is bits in shortest code) */
  824. +  for (; k <= g; k++)
  825. +  {
  826. +DEBG("h6b ");
  827. +    a = c[k];
  828. +    while (a--)
  829. +    {
  830. +DEBG("h6b1 ");
  831. +      /* here i is the Huffman code of length k bits for value *p */
  832. +      /* make tables up to required level */
  833. +      while (k > w + l)
  834. +      {
  835. +DEBG1("1 ");
  836. +        h++;
  837. +        w += l;                 /* previous table always l bits */
  838. +
  839. +        /* compute minimum size table less than or equal to l bits */
  840. +        z = (z = g - w) > (unsigned)l ? l : z;  /* upper limit on table size */
  841. +        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
  842. +        {                       /* too few codes for k-w bit table */
  843. +DEBG1("2 ");
  844. +          f -= a + 1;           /* deduct codes from patterns left */
  845. +          xp = c + k;
  846. +          while (++j < z)       /* try smaller tables up to z bits */
  847. +          {
  848. +            if ((f <<= 1) <= *++xp)
  849. +              break;            /* enough codes to use up j bits */
  850. +            f -= *xp;           /* else deduct codes from patterns */
  851. +          }
  852. +        }
  853. +DEBG1("3 ");
  854. +        z = 1 << j;             /* table entries for j-bit table */
  855. +
  856. +        /* allocate and link in new table */
  857. +        q = (struct huft *)malloc((z + 1)*sizeof(struct huft));
  858. +DEBG1("4 ");
  859. +        hufts += z + 1;         /* track memory usage */
  860. +        *t = q + 1;             /* link to list for huft_free() */
  861. +        *(t = &(q->v.t)) = (struct huft *)NULL;
  862. +        u[h] = ++q;             /* table starts after link */
  863. +
  864. +DEBG1("5 ");
  865. +        /* connect to last table, if there is one */
  866. +        if (h)
  867. +        {
  868. +          x[h] = i;             /* save pattern for backing up */
  869. +          r.b = (uch)l;         /* bits to dump before this table */
  870. +          r.e = (uch)(16 + j);  /* bits in this table */
  871. +          r.v.t = q;            /* pointer to this table */
  872. +          j = i >> (w - l);     /* (get around Turbo C bug) */
  873. +          u[h-1][j] = r;        /* connect to last table */
  874. +        }
  875. +DEBG1("6 ");
  876. +      }
  877. +DEBG("h6c ");
  878. +
  879. +      /* set up table entry in r */
  880. +      r.b = (uch)(k - w);
  881. +      if (p >= v + n)
  882. +        r.e = 99;               /* out of values--invalid code */
  883. +      else if (*p < s)
  884. +      {
  885. +        r.e = (uch)(*p < 256 ? 16 : 15);    /* 256 is end-of-block code */
  886. +        r.v.n = *p++;           /* simple code is just the value */
  887. +      }
  888. +      else
  889. +      {
  890. +        r.e = (uch)e[*p - s];   /* non-simple--look up in lists */
  891. +        r.v.n = d[*p++ - s];
  892. +      }
  893. +DEBG("h6d ");
  894. +
  895. +      /* fill code-like entries with r */
  896. +      f = 1 << (k - w);
  897. +      for (j = i >> w; j < z; j += f)
  898. +        q[j] = r;
  899. +
  900. +      /* backwards increment the k-bit code i */
  901. +      for (j = 1 << (k - 1); i & j; j >>= 1)
  902. +        i ^= j;
  903. +      i ^= j;
  904. +
  905. +      /* backup over finished tables */
  906. +      while ((i & ((1 << w) - 1)) != x[h])
  907. +      {
  908. +        h--;                    /* don't need to update q */
  909. +        w -= l;
  910. +      }
  911. +DEBG("h6e ");
  912. +    }
  913. +DEBG("h6f ");
  914. +  }
  915. +
  916. +DEBG("huft7 ");
  917. +
  918. +  /* Return true (1) if we were given an incomplete table */
  919. +  return y != 0 && g != 1;
  920. +}
  921. +
  922. +
  923. +
  924. +int huft_free(t)
  925. +struct huft *t;         /* table to free */
  926. +/* Free the malloc'ed tables built by huft_build(), which makes a linked
  927. +   list of the tables it made, with the links in a dummy first entry of
  928. +   each table. */
  929. +{
  930. +  register struct huft *p, *q;
  931. +
  932. +
  933. +  /* Go through linked list, freeing from the malloced (t[-1]) address. */
  934. +  p = t;
  935. +  while (p != (struct huft *)NULL)
  936. +  {
  937. +    q = (--p)->v.t;
  938. +    free(p);
  939. +    p = q;
  940. +  } 
  941. +  return 0;
  942. +}
  943. +
  944. +
  945. +int inflate_codes(tl, td, bl, bd)
  946. +struct huft *tl, *td;   /* literal/length and distance decoder tables */
  947. +int bl, bd;             /* number of bits decoded by tl[] and td[] */
  948. +/* inflate (decompress) the codes in a deflated (compressed) block.
  949. +   Return an error code or zero if it all goes ok. */
  950. +{
  951. +  register unsigned e;  /* table entry flag/number of extra bits */
  952. +  unsigned n, d;        /* length and index for copy */
  953. +  unsigned w;           /* current window position */
  954. +  struct huft *t;       /* pointer to table entry */
  955. +  unsigned ml, md;      /* masks for bl and bd bits */
  956. +  register ulg b;       /* bit buffer */
  957. +  register unsigned k;  /* number of bits in bit buffer */
  958. +
  959. +
  960. +  /* make local copies of globals */
  961. +  b = bb;                       /* initialize bit buffer */
  962. +  k = bk;
  963. +  w = wp;                       /* initialize window position */
  964. +
  965. +  /* inflate the coded data */
  966. +  ml = mask_bits[bl];           /* precompute masks for speed */
  967. +  md = mask_bits[bd];
  968. +  for (;;)                      /* do until end of block */
  969. +  {
  970. +    NEEDBITS((unsigned)bl)
  971. +    if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
  972. +      do {
  973. +        if (e == 99)
  974. +          return 1;
  975. +        DUMPBITS(t->b)
  976. +        e -= 16;
  977. +        NEEDBITS(e)
  978. +      } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
  979. +    DUMPBITS(t->b)
  980. +    if (e == 16)                /* then it's a literal */
  981. +    {
  982. +      slide[w++] = (uch)t->v.n;
  983. +      if (w == WSIZE)
  984. +      {
  985. +        flush_output(w);
  986. +        w = 0;
  987. +      }
  988. +    }
  989. +    else                        /* it's an EOB or a length */
  990. +    {
  991. +      /* exit if end of block */
  992. +      if (e == 15)
  993. +        break;
  994. +
  995. +      /* get length of block to copy */
  996. +      NEEDBITS(e)
  997. +      n = t->v.n + ((unsigned)b & mask_bits[e]);
  998. +      DUMPBITS(e);
  999. +
  1000. +      /* decode distance of block to copy */
  1001. +      NEEDBITS((unsigned)bd)
  1002. +      if ((e = (t = td + ((unsigned)b & md))->e) > 16)
  1003. +        do {
  1004. +          if (e == 99)
  1005. +            return 1;
  1006. +          DUMPBITS(t->b)
  1007. +          e -= 16;
  1008. +          NEEDBITS(e)
  1009. +        } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
  1010. +      DUMPBITS(t->b)
  1011. +      NEEDBITS(e)
  1012. +      d = w - t->v.n - ((unsigned)b & mask_bits[e]);
  1013. +      DUMPBITS(e)
  1014. +
  1015. +      /* do the copy */
  1016. +      do {
  1017. +        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
  1018. +#if !defined(NOMEMCPY) && !defined(DEBUG)
  1019. +        if (w - d >= e)         /* (this test assumes unsigned comparison) */
  1020. +        {
  1021. +          memcpy(slide + w, slide + d, e);
  1022. +          w += e;
  1023. +          d += e;
  1024. +        }
  1025. +        else                      /* do it slow to avoid memcpy() overlap */
  1026. +#endif /* !NOMEMCPY */
  1027. +          do {
  1028. +            slide[w++] = slide[d++];
  1029. +          } while (--e);
  1030. +        if (w == WSIZE)
  1031. +        {
  1032. +          flush_output(w);
  1033. +          w = 0;
  1034. +        }
  1035. +      } while (n);
  1036. +    }
  1037. +  }
  1038. +
  1039. +
  1040. +  /* restore the globals from the locals */
  1041. +  wp = w;                       /* restore global window pointer */
  1042. +  bb = b;                       /* restore global bit buffer */
  1043. +  bk = k;
  1044. +
  1045. +  /* done */
  1046. +  return 0;
  1047. +}
  1048. +
  1049. +
  1050. +
  1051. +int inflate_stored()
  1052. +/* "decompress" an inflated type 0 (stored) block. */
  1053. +{
  1054. +  unsigned n;           /* number of bytes in block */
  1055. +  unsigned w;           /* current window position */
  1056. +  register ulg b;       /* bit buffer */
  1057. +  register unsigned k;  /* number of bits in bit buffer */
  1058. +
  1059. +DEBG("<stor");
  1060. +
  1061. +  /* make local copies of globals */
  1062. +  b = bb;                       /* initialize bit buffer */
  1063. +  k = bk;
  1064. +  w = wp;                       /* initialize window position */
  1065. +
  1066. +
  1067. +  /* go to byte boundary */
  1068. +  n = k & 7;
  1069. +  DUMPBITS(n);
  1070. +
  1071. +
  1072. +  /* get the length and its complement */
  1073. +  NEEDBITS(16)
  1074. +  n = ((unsigned)b & 0xffff);
  1075. +  DUMPBITS(16)
  1076. +  NEEDBITS(16)
  1077. +  if (n != (unsigned)((~b) & 0xffff))
  1078. +    return 1;                   /* error in compressed data */
  1079. +  DUMPBITS(16)
  1080. +
  1081. +
  1082. +  /* read and output the compressed data */
  1083. +  while (n--)
  1084. +  {
  1085. +    NEEDBITS(8)
  1086. +    slide[w++] = (uch)b;
  1087. +    if (w == WSIZE)
  1088. +    {
  1089. +      flush_output(w);
  1090. +      w = 0;
  1091. +    }
  1092. +    DUMPBITS(8)
  1093. +  }
  1094. +
  1095. +
  1096. +  /* restore the globals from the locals */
  1097. +  wp = w;                       /* restore global window pointer */
  1098. +  bb = b;                       /* restore global bit buffer */
  1099. +  bk = k;
  1100. +
  1101. +  DEBG(">");
  1102. +  return 0;
  1103. +}
  1104. +
  1105. +
  1106. +
  1107. +int inflate_fixed()
  1108. +/* decompress an inflated type 1 (fixed Huffman codes) block.  We should
  1109. +   either replace this with a custom decoder, or at least precompute the
  1110. +   Huffman tables. */
  1111. +{
  1112. +  int i;                /* temporary variable */
  1113. +  struct huft *tl;      /* literal/length code table */
  1114. +  struct huft *td;      /* distance code table */
  1115. +  int bl;               /* lookup bits for tl */
  1116. +  int bd;               /* lookup bits for td */
  1117. +  unsigned l[288];      /* length list for huft_build */
  1118. +
  1119. +DEBG("<fix");
  1120. +
  1121. +  /* set up literal table */
  1122. +  for (i = 0; i < 144; i++)
  1123. +    l[i] = 8;
  1124. +  for (; i < 256; i++)
  1125. +    l[i] = 9;
  1126. +  for (; i < 280; i++)
  1127. +    l[i] = 7;
  1128. +  for (; i < 288; i++)          /* make a complete, but wrong code set */
  1129. +    l[i] = 8;
  1130. +  bl = 7;
  1131. +  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
  1132. +    return i;
  1133. +
  1134. +
  1135. +  /* set up distance table */
  1136. +  for (i = 0; i < 30; i++)      /* make an incomplete code set */
  1137. +    l[i] = 5;
  1138. +  bd = 5;
  1139. +  if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
  1140. +  {
  1141. +    huft_free(tl);
  1142. +
  1143. +    DEBG(">");
  1144. +    return i;
  1145. +  }
  1146. +
  1147. +
  1148. +  /* decompress until an end-of-block code */
  1149. +  if (inflate_codes(tl, td, bl, bd))
  1150. +    return 1;
  1151. +
  1152. +
  1153. +  /* free the decoding tables, return */
  1154. +  huft_free(tl);
  1155. +  huft_free(td);
  1156. +  return 0;
  1157. +}
  1158. +
  1159. +
  1160. +
  1161. +int inflate_dynamic()
  1162. +/* decompress an inflated type 2 (dynamic Huffman codes) block. */
  1163. +{
  1164. +  int i;                /* temporary variables */
  1165. +  unsigned j;
  1166. +  unsigned l;           /* last length */
  1167. +  unsigned m;           /* mask for bit lengths table */
  1168. +  unsigned n;           /* number of lengths to get */
  1169. +  struct huft *tl;      /* literal/length code table */
  1170. +  struct huft *td;      /* distance code table */
  1171. +  int bl;               /* lookup bits for tl */
  1172. +  int bd;               /* lookup bits for td */
  1173. +  unsigned nb;          /* number of bit length codes */
  1174. +  unsigned nl;          /* number of literal/length codes */
  1175. +  unsigned nd;          /* number of distance codes */
  1176. +#ifdef PKZIP_BUG_WORKAROUND
  1177. +  unsigned ll[288+32];  /* literal/length and distance code lengths */
  1178. +#else
  1179. +  unsigned ll[286+30];  /* literal/length and distance code lengths */
  1180. +#endif
  1181. +  register ulg b;       /* bit buffer */
  1182. +  register unsigned k;  /* number of bits in bit buffer */
  1183. +
  1184. +DEBG("<dyn");
  1185. +
  1186. +  /* make local bit buffer */
  1187. +  b = bb;
  1188. +  k = bk;
  1189. +
  1190. +
  1191. +  /* read in table lengths */
  1192. +  NEEDBITS(5)
  1193. +  nl = 257 + ((unsigned)b & 0x1f);      /* number of literal/length codes */
  1194. +  DUMPBITS(5)
  1195. +  NEEDBITS(5)
  1196. +  nd = 1 + ((unsigned)b & 0x1f);        /* number of distance codes */
  1197. +  DUMPBITS(5)
  1198. +  NEEDBITS(4)
  1199. +  nb = 4 + ((unsigned)b & 0xf);         /* number of bit length codes */
  1200. +  DUMPBITS(4)
  1201. +#ifdef PKZIP_BUG_WORKAROUND
  1202. +  if (nl > 288 || nd > 32)
  1203. +#else
  1204. +  if (nl > 286 || nd > 30)
  1205. +#endif
  1206. +    return 1;                   /* bad lengths */
  1207. +
  1208. +DEBG("dyn1 ");
  1209. +
  1210. +  /* read in bit-length-code lengths */
  1211. +  for (j = 0; j < nb; j++)
  1212. +  {
  1213. +    NEEDBITS(3)
  1214. +    ll[border[j]] = (unsigned)b & 7;
  1215. +    DUMPBITS(3)
  1216. +  }
  1217. +  for (; j < 19; j++)
  1218. +    ll[border[j]] = 0;
  1219. +
  1220. +DEBG("dyn2 ");
  1221. +
  1222. +  /* build decoding table for trees--single level, 7 bit lookup */
  1223. +  bl = 7;
  1224. +  if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
  1225. +  {
  1226. +    if (i == 1)
  1227. +      huft_free(tl);
  1228. +    return i;                   /* incomplete code set */
  1229. +  }
  1230. +
  1231. +DEBG("dyn3 ");
  1232. +
  1233. +  /* read in literal and distance code lengths */
  1234. +  n = nl + nd;
  1235. +  m = mask_bits[bl];
  1236. +  i = l = 0;
  1237. +  while ((unsigned)i < n)
  1238. +  {
  1239. +    NEEDBITS((unsigned)bl)
  1240. +    j = (td = tl + ((unsigned)b & m))->b;
  1241. +    DUMPBITS(j)
  1242. +    j = td->v.n;
  1243. +    if (j < 16)                 /* length of code in bits (0..15) */
  1244. +      ll[i++] = l = j;          /* save last length in l */
  1245. +    else if (j == 16)           /* repeat last length 3 to 6 times */
  1246. +    {
  1247. +      NEEDBITS(2)
  1248. +      j = 3 + ((unsigned)b & 3);
  1249. +      DUMPBITS(2)
  1250. +      if ((unsigned)i + j > n)
  1251. +        return 1;
  1252. +      while (j--)
  1253. +        ll[i++] = l;
  1254. +    }
  1255. +    else if (j == 17)           /* 3 to 10 zero length codes */
  1256. +    {
  1257. +      NEEDBITS(3)
  1258. +      j = 3 + ((unsigned)b & 7);
  1259. +      DUMPBITS(3)
  1260. +      if ((unsigned)i + j > n)
  1261. +        return 1;
  1262. +      while (j--)
  1263. +        ll[i++] = 0;
  1264. +      l = 0;
  1265. +    }
  1266. +    else                        /* j == 18: 11 to 138 zero length codes */
  1267. +    {
  1268. +      NEEDBITS(7)
  1269. +      j = 11 + ((unsigned)b & 0x7f);
  1270. +      DUMPBITS(7)
  1271. +      if ((unsigned)i + j > n)
  1272. +        return 1;
  1273. +      while (j--)
  1274. +        ll[i++] = 0;
  1275. +      l = 0;
  1276. +    }
  1277. +  }
  1278. +
  1279. +DEBG("dyn4 ");
  1280. +
  1281. +  /* free decoding table for trees */
  1282. +  huft_free(tl);
  1283. +
  1284. +DEBG("dyn5 ");
  1285. +
  1286. +  /* restore the global bit buffer */
  1287. +  bb = b;
  1288. +  bk = k;
  1289. +
  1290. +DEBG("dyn5a ");
  1291. +
  1292. +  /* build the decoding tables for literal/length and distance codes */
  1293. +  bl = lbits;
  1294. +  if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
  1295. +  {
  1296. +DEBG("dyn5b ");
  1297. +    if (i == 1) {
  1298. +      error(" incomplete literal tree\n");
  1299. +      huft_free(tl);
  1300. +    }
  1301. +    return i;                   /* incomplete code set */
  1302. +  }
  1303. +DEBG("dyn5c ");
  1304. +  bd = dbits;
  1305. +  if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
  1306. +  {
  1307. +DEBG("dyn5d ");
  1308. +    if (i == 1) {
  1309. +      error(" incomplete distance tree\n");
  1310. +#ifdef PKZIP_BUG_WORKAROUND
  1311. +      i = 0;
  1312. +    }
  1313. +#else
  1314. +      huft_free(td);
  1315. +    }
  1316. +    huft_free(tl);
  1317. +    return i;                   /* incomplete code set */
  1318. +#endif
  1319. +  }
  1320. +
  1321. +DEBG("dyn6 ");
  1322. +
  1323. +  /* decompress until an end-of-block code */
  1324. +  if (inflate_codes(tl, td, bl, bd))
  1325. +    return 1;
  1326. +
  1327. +DEBG("dyn7 ");
  1328. +
  1329. +  /* free the decoding tables, return */
  1330. +  huft_free(tl);
  1331. +  huft_free(td);
  1332. +
  1333. +  DEBG(">");
  1334. +  return 0;
  1335. +}
  1336. +
  1337. +
  1338. +
  1339. +int inflate_block(e)
  1340. +int *e;                 /* last block flag */
  1341. +/* decompress an inflated block */
  1342. +{
  1343. +  unsigned t;           /* block type */
  1344. +  register ulg b;       /* bit buffer */
  1345. +  register unsigned k;  /* number of bits in bit buffer */
  1346. +
  1347. +  DEBG("<blk");
  1348. +
  1349. +  /* make local bit buffer */
  1350. +  b = bb;
  1351. +  k = bk;
  1352. +
  1353. +
  1354. +  /* read in last block bit */
  1355. +  NEEDBITS(1)
  1356. +  *e = (int)b & 1;
  1357. +  DUMPBITS(1)
  1358. +
  1359. +
  1360. +  /* read in block type */
  1361. +  NEEDBITS(2)
  1362. +  t = (unsigned)b & 3;
  1363. +  DUMPBITS(2)
  1364. +
  1365. +
  1366. +  /* restore the global bit buffer */
  1367. +  bb = b;
  1368. +  bk = k;
  1369. +
  1370. +  /* inflate that block type */
  1371. +  if (t == 2)
  1372. +    return inflate_dynamic();
  1373. +  if (t == 0)
  1374. +    return inflate_stored();
  1375. +  if (t == 1)
  1376. +    return inflate_fixed();
  1377. +
  1378. +  DEBG(">");
  1379. +
  1380. +  /* bad block type */
  1381. +  return 2;
  1382. +}
  1383. +
  1384. +
  1385. +
  1386. +int inflate()
  1387. +/* decompress an inflated entry */
  1388. +{
  1389. +  int e;                /* last block flag */
  1390. +  int r;                /* result code */
  1391. +  unsigned h;           /* maximum struct huft's malloc'ed */
  1392. +
  1393. +
  1394. +  /* initialize window, bit buffer */
  1395. +  wp = 0;
  1396. +  bk = 0;
  1397. +  bb = 0;
  1398. +
  1399. +
  1400. +  /* decompress until the last block */
  1401. +  h = 0;
  1402. +  do {
  1403. +    hufts = 0;
  1404. +    if ((r = inflate_block(&e)) != 0)
  1405. +      return r;
  1406. +    if (hufts > h)
  1407. +      h = hufts;
  1408. +  } while (!e);
  1409. +
  1410. +  /* Undo too much lookahead. The next read will be byte aligned so we
  1411. +   * can discard unused bits in the last meaningful byte.
  1412. +   */
  1413. +  while (bk >= 8) {
  1414. +    bk -= 8;
  1415. +    inptr--;
  1416. +  }
  1417. +
  1418. +  /* flush out slide */
  1419. +  flush_output(wp);
  1420. +
  1421. +
  1422. +  /* return success */
  1423. +#ifdef DEBUG
  1424. +  fprintf(stderr, "<%u> ", h);
  1425. +#endif /* DEBUG */
  1426. +  return 0;
  1427. +}
  1428. diff -urNwbB linux/arch/arm/boot/compressed/lzw.h linux.arm/arch/arm/boot/compressed/lzw.h
  1429. --- linux/arch/arm/boot/compressed/lzw.h    Thu Jan  1 01:00:00 1970
  1430. +++ linux.arm/arch/arm/boot/compressed/lzw.h    Sun Feb 11 09:32:11 1996
  1431. @@ -0,0 +1,42 @@
  1432. +/* lzw.h -- define the lzw functions.
  1433. + * Copyright (C) 1992-1993 Jean-loup Gailly.
  1434. + * This is free software; you can redistribute it and/or modify it under the
  1435. + * terms of the GNU General Public License, see the file COPYING.
  1436. + */
  1437. +
  1438. +#if !defined(OF) && defined(lint)
  1439. +#  include "gzip.h"
  1440. +#endif
  1441. +
  1442. +#ifndef BITS
  1443. +#  define BITS 16
  1444. +#endif
  1445. +#define INIT_BITS 9              /* Initial number of bits per code */
  1446. +
  1447. +#define    LZW_MAGIC  "\037\235"   /* Magic header for lzw files, 1F 9D */
  1448. +
  1449. +#define BIT_MASK    0x1f /* Mask for 'number of compression bits' */
  1450. +/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
  1451. + * It's a pity that old uncompress does not check bit 0x20. That makes
  1452. + * extension of the format actually undesirable because old compress
  1453. + * would just crash on the new format instead of giving a meaningful
  1454. + * error message. It does check the number of bits, but it's more
  1455. + * helpful to say "unsupported format, get a new version" than
  1456. + * "can only handle 16 bits".
  1457. + */
  1458. +
  1459. +#define BLOCK_MODE  0x80
  1460. +/* Block compression: if table is full and compression rate is dropping,
  1461. + * clear the dictionary.
  1462. + */
  1463. +
  1464. +#define LZW_RESERVED 0x60 /* reserved bits */
  1465. +
  1466. +#define    CLEAR  256       /* flush the dictionary */
  1467. +#define FIRST  (CLEAR+1) /* first free entry */
  1468. +
  1469. +extern int maxbits;      /* max bits per code for LZW */
  1470. +extern int block_mode;   /* block compress mode -C compatible with 2.0 */
  1471. +
  1472. +extern void lzw    OF((int in, int out));
  1473. +extern void unlzw  OF((int in, int out));
  1474. diff -urNwbB linux/arch/arm/boot/compressed/misc.c linux.arm/arch/arm/boot/compressed/misc.c
  1475. --- linux/arch/arm/boot/compressed/misc.c    Thu Jan  1 01:00:00 1970
  1476. +++ linux.arm/arch/arm/boot/compressed/misc.c    Sun Feb 11 09:32:12 1996
  1477. @@ -0,0 +1,534 @@
  1478. +/*
  1479. + * misc.c
  1480. + * 
  1481. + * This is a collection of several routines from gzip-1.0.3 
  1482. + * adapted for Linux.
  1483. + *
  1484. + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
  1485. + * puts by Nick Holloway 1993
  1486. + */
  1487. +
  1488. +#include "gzip.h"
  1489. +#include "lzw.h"
  1490. +
  1491. +/*#include <asm/segment.h>*/
  1492. +
  1493. +/*
  1494. + * These are set up by the setup-routine at boot-time:
  1495. + */
  1496. +
  1497. +struct param_struct
  1498. +{
  1499. +    unsigned long page_size;
  1500. +    unsigned long nr_pages;
  1501. +    unsigned long ramdisk_size;
  1502. +    unsigned long mountrootrdonly;
  1503. +    unsigned long rootdev;
  1504. +    unsigned long video_num_cols;
  1505. +    unsigned long video_num_rows;
  1506. +    unsigned long video_x;
  1507. +    unsigned long video_y;
  1508. +    unsigned long memc_control_reg;
  1509. +    unsigned char sounddefault;
  1510. +    unsigned char adfsdrives;
  1511. +    unsigned char bytes_per_char_h;
  1512. +    unsigned char bytes_per_char_v;
  1513. +    unsigned long unused[256/4-11];
  1514. +    char paths[8][128];
  1515. +    char commandline[256];
  1516. +};
  1517. +
  1518. +static struct param_struct *params=(struct param_struct *)0x0207C000; 
  1519. +
  1520. +#define EOF -1
  1521. +
  1522. +DECLARE(uch, inbuf, INBUFSIZ);
  1523. +DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
  1524. +DECLARE(uch, window, WSIZE);
  1525. +
  1526. +unsigned outcnt;
  1527. +unsigned insize;
  1528. +unsigned inptr;
  1529. +
  1530. +extern char input_data[], input_end[];
  1531. +int input_len;
  1532. +
  1533. +int input_ptr;
  1534. +
  1535. +int method, exit_code, part_nb, last_member;
  1536. +int test = 0;
  1537. +int force = 0;
  1538. +int verbose = 1;
  1539. +long bytes_in, bytes_out;
  1540. +
  1541. +char *output_data;
  1542. +unsigned long output_ptr;
  1543. +
  1544. +extern int end;
  1545. +long free_mem_ptr = (long)&end;
  1546. +
  1547. +int to_stdout = 0;
  1548. +int hard_math = 0;
  1549. +
  1550. +void (*work)(int inf, int outf);
  1551. +void makecrc(void);
  1552. +
  1553. +local int get_method(int);
  1554. +
  1555. +char *vidmem;
  1556. +int video_num_lines, video_num_columns;
  1557. +int bytes_per_char_h;
  1558. +int white;
  1559. +
  1560. +static void puts(const char *);
  1561. +
  1562. +const char cmap_80[][8]=
  1563. +{
  1564. + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /*   */
  1565. + {0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x00}, /* ! */
  1566. + {0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, /* " */
  1567. + {0x36,0x36,0x7F,0x36,0x7F,0x36,0x36,0x00}, /* # */
  1568. + {0x0C,0x3F,0x68,0x3E,0x0B,0x7E,0x18,0x00}, /* $ */
  1569. + {0x60,0x66,0x0C,0x18,0x30,0x66,0x06,0x00}, /* % */
  1570. + {0x38,0x6C,0x6C,0x38,0x6D,0x66,0x3B,0x00}, /* & */
  1571. + {0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, /* ' */
  1572. + {0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, /* ( */
  1573. + {0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, /* ) */
  1574. + {0x00,0x18,0x7E,0x3C,0x7E,0x18,0x00,0x00}, /* * */
  1575. + {0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00}, /* + */
  1576. + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, /* , */
  1577. + {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, /* - */
  1578. + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, /* . */
  1579. + {0x00,0x06,0x0C,0x18,0x30,0x60,0x00,0x00}, /* / */
  1580. + {0x3C,0x66,0x6E,0x7E,0x76,0x66,0x3C,0x00}, /* 0 */
  1581. + {0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00}, /* 1 */
  1582. + {0x3C,0x66,0x06,0x0C,0x18,0x30,0x7E,0x00}, /* 2 */
  1583. + {0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, /* 3 */
  1584. + {0x0C,0x1C,0x3C,0x6C,0x7E,0x0C,0x0C,0x00}, /* 4 */
  1585. + {0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, /* 5 */
  1586. + {0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, /* 6 */
  1587. + {0x7E,0x06,0x0C,0x18,0x30,0x30,0x30,0x00}, /* 7 */
  1588. + {0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, /* 8 */
  1589. + {0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, /* 9 */
  1590. + {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x00}, /* : */
  1591. + {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x30}, /* ; */
  1592. + {0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, /* < */
  1593. + {0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00}, /* = */
  1594. + {0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, /* > */
  1595. + {0x3C,0x66,0x0C,0x18,0x18,0x00,0x18,0x00}, /* ? */
  1596. + {0x3C,0x66,0x6E,0x6A,0x6E,0x60,0x3C,0x00}, /* @ */
  1597. + {0x3C,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, /* A */
  1598. + {0x7C,0x66,0x66,0x7C,0x66,0x66,0x7C,0x00}, /* B */
  1599. + {0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x00}, /* C */
  1600. + {0x78,0x6C,0x66,0x66,0x66,0x6C,0x78,0x00}, /* D */
  1601. + {0x7E,0x60,0x60,0x7C,0x60,0x60,0x7E,0x00}, /* E */
  1602. + {0x7E,0x60,0x60,0x7C,0x60,0x60,0x60,0x00}, /* F */
  1603. + {0x3C,0x66,0x60,0x6E,0x66,0x66,0x3C,0x00}, /* G */
  1604. + {0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, /* H */
  1605. + {0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00}, /* I */
  1606. + {0x3E,0x0C,0x0C,0x0C,0x0C,0x6C,0x38,0x00}, /* J */
  1607. + {0x66,0x6C,0x78,0x70,0x78,0x6C,0x66,0x00}, /* K */
  1608. + {0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00}, /* L */
  1609. + {0x63,0x77,0x7F,0x6B,0x6B,0x63,0x63,0x00}, /* M */
  1610. + {0x66,0x66,0x76,0x7E,0x6E,0x66,0x66,0x00}, /* N */
  1611. + {0x3C,0x66,0x66,0x66,0x66,0x66,0x3C,0x00}, /* O */
  1612. + {0x7C,0x66,0x66,0x7C,0x60,0x60,0x60,0x00}, /* P */
  1613. + {0x3C,0x66,0x66,0x66,0x6A,0x6C,0x36,0x00}, /* Q */
  1614. + {0x7C,0x66,0x66,0x7C,0x6C,0x66,0x66,0x00}, /* R */
  1615. + {0x3C,0x66,0x60,0x3C,0x06,0x66,0x3C,0x00}, /* S */
  1616. + {0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, /* T */
  1617. + {0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00}, /* U */
  1618. + {0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, /* V */
  1619. + {0x63,0x63,0x6B,0x6B,0x7F,0x77,0x63,0x00}, /* W */
  1620. + {0x66,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00}, /* X */
  1621. + {0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00}, /* Y */
  1622. + {0x7E,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00}, /* Z */
  1623. + {0x7C,0x60,0x60,0x60,0x60,0x60,0x7C,0x00}, /* [ */
  1624. + {0x00,0x60,0x30,0x18,0x0C,0x06,0x00,0x00}, /* \ */
  1625. + {0x3E,0x06,0x06,0x06,0x06,0x06,0x3E,0x00}, /* ] */
  1626. + {0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00}, /* ^ */
  1627. + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, /* _ */
  1628. + {0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00}, /* ` */
  1629. + {0x00,0x00,0x3C,0x06,0x3E,0x66,0x3E,0x00}, /* a */
  1630. + {0x60,0x60,0x7C,0x66,0x66,0x66,0x7C,0x00}, /* b */
  1631. + {0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, /* c */
  1632. + {0x06,0x06,0x3E,0x66,0x66,0x66,0x3E,0x00}, /* d */
  1633. + {0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, /* e */
  1634. + {0x1C,0x30,0x30,0x7C,0x30,0x30,0x30,0x00}, /* f */
  1635. + {0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x3C}, /* g */
  1636. + {0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x00}, /* h */
  1637. + {0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, /* i */
  1638. + {0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x70}, /* j */
  1639. + {0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00}, /* k */
  1640. + {0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, /* l */
  1641. + {0x00,0x00,0x36,0x7F,0x6B,0x6B,0x63,0x00}, /* m */
  1642. + {0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, /* n */
  1643. + {0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, /* o */
  1644. + {0x00,0x00,0x7C,0x66,0x66,0x7C,0x60,0x60}, /* p */
  1645. + {0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x07}, /* q */
  1646. + {0x00,0x00,0x6C,0x76,0x60,0x60,0x60,0x00}, /* r */
  1647. + {0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, /* s */
  1648. + {0x30,0x30,0x7C,0x30,0x30,0x30,0x1C,0x00}, /* t */
  1649. + {0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x00}, /* u */
  1650. + {0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, /* v */
  1651. + {0x00,0x00,0x63,0x6B,0x6B,0x7F,0x36,0x00}, /* w */
  1652. + {0x00,0x00,0x66,0x3C,0x18,0x3C,0x66,0x00}, /* x */
  1653. + {0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x3C}, /* y */
  1654. + {0x00,0x00,0x7E,0x0C,0x18,0x30,0x7E,0x00}, /* z */
  1655. + {0x0C,0x18,0x18,0x70,0x18,0x18,0x0C,0x00}, /* { */
  1656. + {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, /* | */
  1657. + {0x30,0x18,0x18,0x0E,0x18,0x18,0x30,0x00}, /* } */
  1658. + {0x31,0x6B,0x46,0x00,0x00,0x00,0x00,0x00}, /* ~ */
  1659. + {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}  /*  */
  1660. +};
  1661. +
  1662. +void *malloc(int size)
  1663. +{
  1664. +    void *p;
  1665. +
  1666. +    if (size <0) error("Malloc error\n");
  1667. +    if (free_mem_ptr <= 0) error("Memory error\n");
  1668. +
  1669. +    while(1) {
  1670. +        free_mem_ptr = (free_mem_ptr + 3) & ~3;    /* Align */
  1671. +
  1672. +        p = (void *)free_mem_ptr;
  1673. +        free_mem_ptr += size;
  1674. +
  1675. +        /*
  1676. +           * The part of the compressed kernel which has already been expanded
  1677. +         * is no longer needed. Therefore we can reuse it for malloc.
  1678. +         * With bigger kernels, this is necessary.
  1679. +         */
  1680. +        if (free_mem_ptr < (long)&end) {
  1681. +            if (free_mem_ptr > (long)&input_data[input_ptr])
  1682. +                error("\nOut of memory\n");
  1683. +
  1684. +            return p;
  1685. +        }
  1686. +        if (free_mem_ptr < 0x01a00000)
  1687. +            return p;
  1688. +        puts("large kernel, memory tight...");
  1689. +        free_mem_ptr = (long)input_data;
  1690. +    }
  1691. +}
  1692. +
  1693. +void free(void *where)
  1694. +{    /* Don't care */
  1695. +}
  1696. +
  1697. +static void scroll()
  1698. +{
  1699. +#if 0
  1700. +    int i;
  1701. +
  1702. +    memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
  1703. +    for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
  1704. +        vidmem[i] = ' ';
  1705. +#endif
  1706. +}
  1707. +
  1708. +static void puts(const char *s)
  1709. +{
  1710. +    extern void ll_char_write(char *, char, char, char, char);
  1711. +    int x,y;
  1712. +    char c;
  1713. +    char *ptr;
  1714. +
  1715. +    x = params->video_x;
  1716. +    y = params->video_y;
  1717. +
  1718. +    while ( ( c = *s++ ) != '\0' ) {
  1719. +        if ( c == '\n' ) {
  1720. +            x = 0;
  1721. +            if ( ++y >= video_num_lines ) {
  1722. +                scroll();
  1723. +                y--;
  1724. +            }
  1725. +        } else {
  1726. +            ptr = vidmem + (y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h;
  1727. +            ll_char_write(ptr, c, white, 0, 0);
  1728. +            if ( ++x >= video_num_columns ) {
  1729. +                x = 0;
  1730. +                if ( ++y >= video_num_lines ) {
  1731. +                    scroll();
  1732. +                    y--;
  1733. +                }
  1734. +            }
  1735. +        }
  1736. +    }
  1737. +
  1738. +    params->video_x = x;
  1739. +    params->video_y = y;
  1740. +}
  1741. +
  1742. +__ptr_t memset(__ptr_t s, int c, size_t n)
  1743. +{
  1744. +    int i;
  1745. +    char *ss = (char*)s;
  1746. +
  1747. +    for (i=0;i<n;i++) ss[i] = c;
  1748. +}
  1749. +
  1750. +__ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
  1751. +                size_t __n)
  1752. +{
  1753. +    int i;
  1754. +    char *d = (char *)__dest, *s = (char *)__src;
  1755. +
  1756. +    for (i=0;i<__n;i++) d[i] = s[i];
  1757. +}
  1758. +
  1759. +extern ulg crc_32_tab[];   /* crc table, defined below */
  1760. +
  1761. +/* ===========================================================================
  1762. + * Run a set of bytes through the crc shift register.  If s is a NULL
  1763. + * pointer, then initialize the crc shift register contents instead.
  1764. + * Return the current crc in either case.
  1765. + */
  1766. +ulg updcrc(s, n)
  1767. +    uch *s;                 /* pointer to bytes to pump through */
  1768. +    unsigned n;             /* number of bytes in s[] */
  1769. +{
  1770. +    register ulg c;         /* temporary variable */
  1771. +
  1772. +    static ulg crc = (ulg)0xffffffffL; /* shift register contents */
  1773. +
  1774. +    if (s == NULL) {
  1775. +    c = 0xffffffffL;
  1776. +    } else {
  1777. +    c = crc;
  1778. +    while (n--) {
  1779. +        c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
  1780. +    }
  1781. +    }
  1782. +    crc = c;
  1783. +    return c ^ 0xffffffffL;       /* (instead of ~c for 64-bit machines) */
  1784. +}
  1785. +
  1786. +/* ===========================================================================
  1787. + * Clear input and output buffers
  1788. + */
  1789. +void clear_bufs()
  1790. +{
  1791. +    outcnt = 0;
  1792. +    insize = inptr = 0;
  1793. +    bytes_in = bytes_out = 0L;
  1794. +}
  1795. +
  1796. +/* ===========================================================================
  1797. + * Fill the input buffer. This is called only when the buffer is empty
  1798. + * and at least one byte is really needed.
  1799. + */
  1800. +int fill_inbuf()
  1801. +{
  1802. +    int len, i;
  1803. +
  1804. +    /* Read as much as possible */
  1805. +    insize = 0;
  1806. +    do {
  1807. +    len = INBUFSIZ-insize;
  1808. +    if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
  1809. +        if (len == 0 || len == EOF) break;
  1810. +
  1811. +        for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
  1812. +    insize += len;
  1813. +    input_ptr += len;
  1814. +    } while (insize < INBUFSIZ);
  1815. +
  1816. +    if (insize == 0) {
  1817. +    error("unable to fill buffer\n");
  1818. +    }
  1819. +    bytes_in += (ulg)insize;
  1820. +    inptr = 1;
  1821. +    return inbuf[0];
  1822. +}
  1823. +
  1824. +/* ===========================================================================
  1825. + * Write the output window window[0..outcnt-1] and update crc and bytes_out.
  1826. + * (Used for the decompressed data only.)
  1827. + */
  1828. +void flush_window()
  1829. +{
  1830. +    if (outcnt == 0) return;
  1831. +    updcrc(window, outcnt);
  1832. +
  1833. +    memcpy(&output_data[output_ptr], (char *)window, outcnt);
  1834. +
  1835. +    bytes_out += (ulg)outcnt;
  1836. +    output_ptr += (ulg)outcnt;
  1837. +    outcnt = 0;
  1838. +}
  1839. +
  1840. +/*
  1841. + * Code to compute the CRC-32 table. Borrowed from 
  1842. + * gzip-1.0.3/makecrc.c.
  1843. + */
  1844. +
  1845. +ulg crc_32_tab[256];
  1846. +
  1847. +void
  1848. +makecrc(void)
  1849. +{
  1850. +/* Not copyrighted 1990 Mark Adler    */
  1851. +
  1852. +  unsigned long c;      /* crc shift register */
  1853. +  unsigned long e;      /* polynomial exclusive-or pattern */
  1854. +  int i;                /* counter for all possible eight bit values */
  1855. +  int k;                /* byte being shifted into crc apparatus */
  1856. +
  1857. +  /* terms of polynomial defining this crc (except x^32): */
  1858. +  static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
  1859. +
  1860. +  /* Make exclusive-or pattern from polynomial */
  1861. +  e = 0;
  1862. +  for (i = 0; i < sizeof(p)/sizeof(int); i++)
  1863. +    e |= 1L << (31 - p[i]);
  1864. +
  1865. +  crc_32_tab[0] = 0;
  1866. +
  1867. +  for (i = 1; i < 256; i++)
  1868. +  {
  1869. +    c = 0;
  1870. +    for (k = i | 256; k != 1; k >>= 1)
  1871. +    {
  1872. +      c = c & 1 ? (c >> 1) ^ e : c >> 1;
  1873. +      if (k & 1)
  1874. +        c ^= e;
  1875. +    }
  1876. +    crc_32_tab[i] = c;
  1877. +  }
  1878. +}
  1879. +
  1880. +void error(char *x)
  1881. +{
  1882. +    puts("\n\n");
  1883. +    puts(x);
  1884. +    puts("\n\n -- System halted");
  1885. +
  1886. +    while(1);    /* Halt */
  1887. +}
  1888. +
  1889. +#define STACK_SIZE (4096)
  1890. +
  1891. +long _stack_start [STACK_SIZE];
  1892. +
  1893. +void decompress_kernel(int output_start)
  1894. +{
  1895. +    input_len = input_end - input_data;
  1896. +    vidmem = (char *)0x02000000;
  1897. +
  1898. +    video_num_lines = params->video_num_rows;
  1899. +    video_num_columns  = params->video_num_cols;
  1900. +    bytes_per_char_h = params->bytes_per_char_h;
  1901. +    white = bytes_per_char_h == 8 ? 0xfc : 7;
  1902. +    
  1903. +    if (params->nr_pages * params->page_size < 2048*1024) error("<2M of mem\n");
  1904. +
  1905. +    output_data = (char *)output_start;    /* Points to kernel start */
  1906. +    output_ptr = 0;
  1907. +
  1908. +    exit_code = 0;
  1909. +    test = 0;
  1910. +    input_ptr = 0;
  1911. +    part_nb = 0;
  1912. +
  1913. +    clear_bufs();
  1914. +    makecrc();
  1915. +
  1916. +    puts("Uncompressing Linux...");
  1917. +
  1918. +    method = get_method(0);
  1919. +
  1920. +    work(0, 0);
  1921. +
  1922. +    puts("done.\n");
  1923. +
  1924. +    puts("Now booting the kernel\n");
  1925. +}
  1926. +
  1927. +/* ========================================================================
  1928. + * Check the magic number of the input file and update ofname if an
  1929. + * original name was given and to_stdout is not set.
  1930. + * Return the compression method, -1 for error, -2 for warning.
  1931. + * Set inptr to the offset of the next byte to be processed.
  1932. + * This function may be called repeatedly for an input file consisting
  1933. + * of several contiguous gzip'ed members.
  1934. + * IN assertions: there is at least one remaining compressed member.
  1935. + *   If the member is a zip file, it must be the only one.
  1936. + */
  1937. +
  1938. +union magic
  1939. +{
  1940. +    char magic[2];
  1941. +    short s_magic;
  1942. +};
  1943. +
  1944. +local int get_method(in)
  1945. +    int in;        /* input file descriptor */
  1946. +{
  1947. +    uch flags;
  1948. +    union magic magic; /* magic header */
  1949. +    union magic gzip_magic = { GZIP_MAGIC };
  1950. +    union magic old_gzip_magic = { OLD_GZIP_MAGIC };
  1951. +
  1952. +    magic.magic[0] = (char)get_byte();
  1953. +    magic.magic[1] = (char)get_byte();
  1954. +
  1955. +    method = -1;                 /* unknown yet */
  1956. +    part_nb++;                   /* number of parts in gzip file */
  1957. +    last_member = 0;
  1958. +    /* assume multiple members in gzip file except for record oriented I/O */
  1959. +
  1960. +    if (magic.s_magic == gzip_magic.s_magic
  1961. +        || magic.s_magic == old_gzip_magic.s_magic) {
  1962. +
  1963. +    work = unzip;
  1964. +    method = (int)get_byte();
  1965. +    flags  = (uch)get_byte();
  1966. +
  1967. +    if ((flags & ENCRYPTED) != 0)
  1968. +        error("Input is encrypted\n");
  1969. +
  1970. +    if ((flags & CONTINUATION) != 0)
  1971. +        error("Multi part input\n");
  1972. +
  1973. +    if ((flags & RESERVED) != 0) {
  1974. +        error("Input has invalid flags\n");
  1975. +        exit_code = ERROR;
  1976. +        if (force <= 1)
  1977. +            return -1;
  1978. +    }
  1979. +
  1980. +    (ulg)get_byte();    /* Get timestamp */
  1981. +    ((ulg)get_byte()) << 8;
  1982. +    ((ulg)get_byte()) << 16;
  1983. +    ((ulg)get_byte()) << 24;
  1984. +
  1985. +    (void)get_byte();  /* Ignore extra flags for the moment */
  1986. +    (void)get_byte();  /* Ignore OS type for the moment */
  1987. +
  1988. +    if ((flags & EXTRA_FIELD) != 0) {
  1989. +        unsigned len = (unsigned)get_byte();
  1990. +        len |= ((unsigned)get_byte())<<8;
  1991. +        while (len--) (void)get_byte();
  1992. +    }
  1993. +
  1994. +    /* Get original file name if it was truncated */
  1995. +    if ((flags & ORIG_NAME) != 0) {
  1996. +        if (to_stdout || part_nb > 1) {
  1997. +            /* Discard the old name */
  1998. +            while (get_byte() != 0) /* null */ ;
  1999. +        } else {
  2000. +        } /* to_stdout */
  2001. +    } /* orig_name */
  2002. +
  2003. +    /* Discard file comment if any */
  2004. +    if ((flags & COMMENT) != 0) {
  2005. +        while (get_byte() != 0) /* null */ ;
  2006. +    }
  2007. +    } else
  2008. +    error("unknown compression method");
  2009. +    return method;
  2010. +}
  2011. diff -urNwbB linux/arch/arm/boot/compressed/piggyback.c linux.arm/arch/arm/boot/compressed/piggyback.c
  2012. --- linux/arch/arm/boot/compressed/piggyback.c    Thu Jan  1 01:00:00 1970
  2013. +++ linux.arm/arch/arm/boot/compressed/piggyback.c    Sun Feb 11 09:32:12 1996
  2014. @@ -0,0 +1,83 @@
  2015. +/*
  2016. + *    linux/zBoot/piggyback.c
  2017. + *
  2018. + *    (C) 1993 Hannu Savolainen
  2019. + */
  2020. +
  2021. +/*
  2022. + *    This program reads the compressed system image from stdin and
  2023. + *    encapsulates it into an object file written to the stdout.
  2024. + */
  2025. +
  2026. +#include <stdio.h>
  2027. +#include <unistd.h>
  2028. +#include <a.out.h>
  2029. +
  2030. +int main(int argc, char *argv[])
  2031. +{
  2032. +    int c, n=0, len=0;
  2033. +    char tmp_buf[512*1024];
  2034. +    
  2035. +    struct exec obj = {0x00670107};    /* object header */
  2036. +    char string_names[] = {"_input_data\0_input_end\0"};
  2037. +
  2038. +    struct nlist var_names[2] = /* Symbol table */
  2039. +        {    
  2040. +            {    /* _input_data    */
  2041. +                (char *)4, 7, 0, 0, 0
  2042. +            },
  2043. +            {    /* _input_len */
  2044. +                (char *)16, 7, 0, 0, 0
  2045. +            }
  2046. +        };
  2047. +
  2048. +
  2049. +    len = 0;
  2050. +    while ((n = read(0, &tmp_buf[len], sizeof(tmp_buf)-len+1)) > 0)
  2051. +          len += n;
  2052. +
  2053. +    len = (len + 3) & ~3;
  2054. +
  2055. +    if (n==-1)
  2056. +    {
  2057. +        perror("stdin");
  2058. +        exit(-1);
  2059. +    }
  2060. +
  2061. +    if (len >= sizeof(tmp_buf))
  2062. +    {
  2063. +        fprintf(stderr, "%s: Input too large\n", argv[0]);
  2064. +        exit(-1);
  2065. +    }
  2066. +
  2067. +    fprintf(stderr, "Compressed size %d.\n", len);
  2068. +
  2069. +/*
  2070. + *    Output object header
  2071. + */
  2072. +    obj.a_data = len /* + sizeof(long) */;
  2073. +    obj.a_syms = sizeof(var_names);
  2074. +    write(1, (char *)&obj, sizeof(obj));
  2075. +
  2076. +/*
  2077. + *    Output data segment (compressed system & len)
  2078. + */
  2079. +    write(1, tmp_buf, len);
  2080. +/*    write(1, (char *)&len, sizeof(len));*/
  2081. +
  2082. +/*
  2083. + *    Output symbol table
  2084. + */
  2085. +    var_names[1].n_value = len;
  2086. +    write(1, (char *)&var_names, sizeof(var_names));
  2087. +
  2088. +/*
  2089. + *    Output string table
  2090. + */
  2091. +    len = sizeof(string_names) + sizeof(len);
  2092. +    write(1, (char *)&len, sizeof(len));
  2093. +    write(1, string_names, sizeof(string_names));
  2094. +
  2095. +    exit(0);
  2096. +
  2097. +}
  2098. diff -urNwbB linux/arch/arm/boot/compressed/unzip.c linux.arm/arch/arm/boot/compressed/unzip.c
  2099. --- linux/arch/arm/boot/compressed/unzip.c    Thu Jan  1 01:00:00 1970
  2100. +++ linux.arm/arch/arm/boot/compressed/unzip.c    Sat Feb 24 09:36:43 1996
  2101. @@ -0,0 +1,180 @@
  2102. +/* unzip.c -- decompress files in gzip or pkzip format.
  2103. + * Copyright (C) 1992-1993 Jean-loup Gailly
  2104. + *
  2105. + * Adapted for Linux booting by Hannu Savolainen 1993
  2106. + *
  2107. + * This is free software; you can redistribute it and/or modify it under the
  2108. + * terms of the GNU General Public License, see the file COPYING.
  2109. + *
  2110. + * The code in this file is derived from the file funzip.c written
  2111. + * and put in the public domain by Mark Adler.
  2112. + */
  2113. +
  2114. +/*
  2115. +   This version can extract files in gzip or pkzip format.
  2116. +   For the latter, only the first entry is extracted, and it has to be
  2117. +   either deflated or stored.
  2118. + */
  2119. +
  2120. +#ifndef lint
  2121. +static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $";
  2122. +#endif
  2123. +
  2124. +#include "gzip.h"
  2125. +#include "crypt.h"
  2126. +
  2127. +#include <stdio.h>
  2128. +
  2129. +/* PKZIP header definitions */
  2130. +#define LOCSIG 0x04034b50L      /* four-byte lead-in (lsb first) */
  2131. +#define LOCFLG 6                /* offset of bit flag */
  2132. +#define  CRPFLG 1               /*  bit for encrypted entry */
  2133. +#define  EXTFLG 8               /*  bit for extended local header */
  2134. +#define LOCHOW 8                /* offset of compression method */
  2135. +#define LOCTIM 10               /* file mod time (for decryption) */
  2136. +#define LOCCRC 14               /* offset of crc */
  2137. +#define LOCSIZ 18               /* offset of compressed size */
  2138. +#define LOCLEN 22               /* offset of uncompressed length */
  2139. +#define LOCFIL 26               /* offset of file name field length */
  2140. +#define LOCEXT 28               /* offset of extra field length */
  2141. +#define LOCHDR 30               /* size of local header, including sig */
  2142. +#define EXTHDR 16               /* size of extended local header, inc sig */
  2143. +
  2144. +
  2145. +/* Globals */
  2146. +
  2147. +int decrypt;      /* flag to turn on decryption */
  2148. +char *key;        /* not used--needed to link crypt.c */
  2149. +int pkzip = 0;    /* set for a pkzip file */
  2150. +int extended = 0; /* set if extended local header */
  2151. +
  2152. +/* ===========================================================================
  2153. + * Check zip file and advance inptr to the start of the compressed data.
  2154. + * Get ofname from the local header if necessary.
  2155. + */
  2156. +int check_zipfile(in)
  2157. +    int in;   /* input file descriptors */
  2158. +{
  2159. +    uch *h = inbuf + inptr; /* first local header */
  2160. +
  2161. +    /* ifd = in; */
  2162. +
  2163. +    /* Check validity of local header, and skip name and extra fields */
  2164. +    inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
  2165. +
  2166. +    if (inptr > insize || LG(h) != LOCSIG) {
  2167. +    error("input not a zip");
  2168. +    }
  2169. +    method = h[LOCHOW];
  2170. +    if (method != STORED && method != DEFLATED) {
  2171. +    error("first entry not deflated or stored--can't extract");
  2172. +    }
  2173. +
  2174. +    /* If entry encrypted, decrypt and validate encryption header */
  2175. +    if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
  2176. +    error("encrypted file\n");
  2177. +    exit_code = ERROR;
  2178. +    return -1;
  2179. +    }
  2180. +
  2181. +    /* Save flags for unzip() */
  2182. +    extended = (h[LOCFLG] & EXTFLG) != 0;
  2183. +    pkzip = 1;
  2184. +
  2185. +    /* Get ofname and time stamp from local header (to be done) */
  2186. +    return 0;
  2187. +}
  2188. +
  2189. +/* ===========================================================================
  2190. + * Unzip in to out.  This routine works on both gzip and pkzip files.
  2191. + *
  2192. + * IN assertions: the buffer inbuf contains already the beginning of
  2193. + *   the compressed data, from offsets inptr to insize-1 included.
  2194. + *   The magic header has already been checked. The output buffer is cleared.
  2195. + */
  2196. +void unzip(in, out)
  2197. +    int in, out;   /* input and output file descriptors */
  2198. +{
  2199. +    ulg orig_crc = 0;       /* original crc */
  2200. +    ulg orig_len = 0;       /* original uncompressed length */
  2201. +    int n;
  2202. +    uch buf[EXTHDR];        /* extended local header */
  2203. +
  2204. +    /* ifd = in;
  2205. +    ofd = out; */
  2206. +
  2207. +    updcrc(NULL, 0);           /* initialize crc */
  2208. +
  2209. +    if (pkzip && !extended) {  /* crc and length at the end otherwise */
  2210. +    orig_crc = LG(inbuf + LOCCRC);
  2211. +    orig_len = LG(inbuf + LOCLEN);
  2212. +    }
  2213. +
  2214. +    /* Decompress */
  2215. +    if (method == DEFLATED)  {
  2216. +
  2217. +    int res = inflate();
  2218. +
  2219. +    if (res == 3) {
  2220. +        error("out of memory");
  2221. +    } else if (res != 0) {
  2222. +        error("invalid compressed format");
  2223. +    }
  2224. +
  2225. +    } else if (pkzip && method == STORED) {
  2226. +
  2227. +    register ulg n = LG(inbuf + LOCLEN);
  2228. +
  2229. +    if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
  2230. +
  2231. +        error("length mismatch");
  2232. +    }
  2233. +    while (n--) {
  2234. +        uch c = (uch)get_byte();
  2235. +#ifdef CRYPT
  2236. +        if (decrypt) zdecode(c);
  2237. +#endif
  2238. +        if (!test) put_char(c);
  2239. +    }
  2240. +    } else {
  2241. +    error("internal error, invalid method");
  2242. +    }
  2243. +
  2244. +    /* Get the crc and original length */
  2245. +    if (!pkzip) {
  2246. +        /* crc32  (see algorithm.doc)
  2247. +     * uncompressed input size modulo 2^32
  2248. +         */
  2249. +    for (n = 0; n < 8; n++) {
  2250. +        buf[n] = (uch)get_byte(); /* may cause an error if EOF */
  2251. +    }
  2252. +    orig_crc = LG(buf);
  2253. +    orig_len = LG(buf+4);
  2254. +
  2255. +    } else if (extended) {  /* If extended header, check it */
  2256. +    /* signature - 4bytes: 0x50 0x4b 0x07 0x08
  2257. +     * CRC-32 value
  2258. +         * compressed size 4-bytes
  2259. +         * uncompressed size 4-bytes
  2260. +     */
  2261. +    for (n = 0; n < EXTHDR; n++) {
  2262. +        buf[n] = (uch)get_byte(); /* may cause an error if EOF */
  2263. +    }
  2264. +    orig_crc = LG(buf+4);
  2265. +    orig_len = LG(buf+12);
  2266. +    }
  2267. +
  2268. +    /* Validate decompression */
  2269. +    if (orig_crc != updcrc(outbuf, 0)) {
  2270. +    error("crc error");
  2271. +    }
  2272. +    if (orig_len != bytes_out) {
  2273. +    error("length error");
  2274. +    }
  2275. +
  2276. +    /* Check if there are more entries in a pkzip file */
  2277. +    if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
  2278. +        error("zip file has more than one entry");
  2279. +    }
  2280. +    extended = pkzip = 0; /* for next file */
  2281. +}
  2282. diff -urNwbB linux/arch/arm/boot/compressed/xtract.c linux.arm/arch/arm/boot/compressed/xtract.c
  2283. --- linux/arch/arm/boot/compressed/xtract.c    Thu Jan  1 01:00:00 1970
  2284. +++ linux.arm/arch/arm/boot/compressed/xtract.c    Sun Feb 11 09:32:12 1996
  2285. @@ -0,0 +1,86 @@
  2286. +/*
  2287. + *  linux/zBoot/xtract.c
  2288. + *
  2289. + *  Copyright (C) 1993  Hannu Savolainen
  2290. + *
  2291. + *    Extracts the system image and writes it to the stdout.
  2292. + *    based on tools/build.c by Linus Torvalds
  2293. + */
  2294. +
  2295. +#include <stdio.h>    /* fprintf */
  2296. +#include <string.h>
  2297. +#include <stdlib.h>    /* contains exit */
  2298. +#include <sys/types.h>    /* unistd.h needs this */
  2299. +#include <sys/stat.h>
  2300. +#include <sys/sysmacros.h>
  2301. +#include <unistd.h>    /* contains read/write */
  2302. +#include <fcntl.h>
  2303. +#include <a.out.h>
  2304. +
  2305. +#define N_MAGIC_OFFSET 1024
  2306. +
  2307. +static int GCC_HEADER = sizeof(struct exec);
  2308. +
  2309. +#define STRINGIFY(x) #x
  2310. +
  2311. +void die(char * str)
  2312. +{
  2313. +    fprintf(stderr,"%s\n",str);
  2314. +    exit(1);
  2315. +}
  2316. +
  2317. +void usage(void)
  2318. +{
  2319. +    die("Usage: xtract system [ | gzip | piggyback > piggy.s]");
  2320. +}
  2321. +
  2322. +int main(int argc, char ** argv)
  2323. +{
  2324. +    int i,c,id, sz;
  2325. +    char buf[1024];
  2326. +    char major_root, minor_root;
  2327. +    struct stat sb;
  2328. +
  2329. +    struct exec *ex = (struct exec *)buf;
  2330. +
  2331. +    if (argc  != 2)
  2332. +        usage();
  2333. +    
  2334. +    if ((id=open(argv[1],O_RDONLY,0))<0)
  2335. +        die("Unable to open 'system'");
  2336. +    if (read(id,buf,GCC_HEADER) != GCC_HEADER)
  2337. +        die("Unable to read header of 'system'");
  2338. +    if (N_MAGIC(*ex) == ZMAGIC) {
  2339. +        GCC_HEADER = N_MAGIC_OFFSET;
  2340. +        lseek(id, GCC_HEADER, SEEK_SET);
  2341. +    } else if (N_MAGIC(*ex) != QMAGIC)
  2342. +        die("Non-GCC header of 'system'");
  2343. +
  2344. +    sz = N_SYMOFF(*ex) - GCC_HEADER + 4;    /* +4 to get the same result than tools/build */
  2345. +
  2346. +    fprintf(stderr, "System size is %d\n", sz);
  2347. +
  2348. +    while (sz)
  2349. +    {
  2350. +        int l, n;
  2351. +
  2352. +        l = sz;
  2353. +        if (l > sizeof(buf)) l = sizeof(buf);
  2354. +
  2355. +        if ((n=read(id, buf, l)) !=l)
  2356. +        {
  2357. +            if (n == -1) 
  2358. +               perror(argv[1]);
  2359. +            else
  2360. +               fprintf(stderr, "Unexpected EOF\n");
  2361. +
  2362. +            die("Can't read system");
  2363. +        }
  2364. +
  2365. +        write(1, buf, l);
  2366. +        sz -= l;
  2367. +    }
  2368. +
  2369. +    close(id);
  2370. +    return(0);
  2371. +}
  2372. diff -urNwbB linux/arch/arm/boot/install.sh linux.arm/arch/arm/boot/install.sh
  2373. --- linux/arch/arm/boot/install.sh    Thu Jan  1 01:00:00 1970
  2374. +++ linux.arm/arch/arm/boot/install.sh    Sun Mar  3 12:16:58 1996
  2375. @@ -0,0 +1,60 @@
  2376. +#!/bin/sh
  2377. +#
  2378. +# arch/i386/boot/install.sh
  2379. +#
  2380. +# This file is subject to the terms and conditions of the GNU General Public
  2381. +# License.  See the file "COPYING" in the main directory of this archive
  2382. +# for more details.
  2383. +#
  2384. +# Copyright (C) 1995 by Linus Torvalds
  2385. +#
  2386. +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
  2387. +#
  2388. +# "make install" script for i386 architecture
  2389. +#
  2390. +# Arguments:
  2391. +#   $1 - kernel version
  2392. +#   $2 - kernel image file
  2393. +#   $3 - kernel map file
  2394. +#   $4 - default install path (blank if root directory)
  2395. +#
  2396. +
  2397. +# User may have a custom install script
  2398. +
  2399. +if [ -x /sbin/installkernel ]; then
  2400. +  exec /sbin/installkernel "$@"
  2401. +fi
  2402. +
  2403. +if [ "$2" = "zImage" ]; then
  2404. +# Compressed install
  2405. +  echo "Installing compressed kernel"
  2406. +  if [ -f $4/vmlinuz-$1 ]; then
  2407. +    mv $4/vmlinuz-$1 $4/vmlinuz.old
  2408. +  fi
  2409. +
  2410. +  if [ -f $4/System.map-$1 ]; then
  2411. +    mv $4/System.map-$1 $4/System.old
  2412. +  fi
  2413. +
  2414. +  cat $2 > $4/vmlinuz-$1
  2415. +  cp $3 $4/System.map-$1
  2416. +else
  2417. +# Normal install
  2418. +  echo "Installing normal kernel"
  2419. +  if [ -f $4/vmlinux-$1 ]; then
  2420. +    mv $4/vmlinux-$1 $4/vmlinux.old
  2421. +  fi
  2422. +
  2423. +  if [ -f $4/System.map ]; then
  2424. +    mv $4/System.map $4/System.old
  2425. +  fi
  2426. +
  2427. +  cat $2 > $4/vmlinux-$1
  2428. +  cp $3 $4/System.map
  2429. +fi
  2430. +
  2431. +if [ -x /sbin/loadmap ]; then
  2432. +  /sbin/loadmap
  2433. +else
  2434. +  echo "You have to install it yourself"
  2435. +fi
  2436. diff -urNwbB linux/arch/arm/boot/tools/build.c linux.arm/arch/arm/boot/tools/build.c
  2437. --- linux/arch/arm/boot/tools/build.c    Thu Jan  1 01:00:00 1970
  2438. +++ linux.arm/arch/arm/boot/tools/build.c    Sun Feb 11 22:01:19 1996
  2439. @@ -0,0 +1,56 @@
  2440. +#include <stdio.h>
  2441. +#include <stdlib.h>
  2442. +#include <a.out.h>
  2443. +#include <string.h>
  2444. +
  2445. +int main(int argc, char **argv)
  2446. +{
  2447. +    void *data;
  2448. +    struct exec ex;
  2449. +    FILE *f;
  2450. +    int totlen;
  2451. +
  2452. +    if (argc < 2) {
  2453. +        fprintf(stderr, "Usage: build kernel-name\n");
  2454. +        exit(1);
  2455. +    }
  2456. +
  2457. +    f = fopen(argv[1], "rb");
  2458. +
  2459. +    fread(&ex, 1, sizeof(ex), f);
  2460. +
  2461. +    if(N_MAGIC(ex) == ZMAGIC) {
  2462. +        fseek(f, 4096, SEEK_SET);
  2463. +        totlen = ex.a_text + ex.a_data + ex.a_bss;
  2464. +    } else
  2465. +    if(N_MAGIC(ex) == QMAGIC) {
  2466. +        unsigned long my_header[8];
  2467. +        
  2468. +        fseek(f, 0x20, SEEK_SET);
  2469. +
  2470. +        memset(my_header, 0, 0x20);
  2471. +
  2472. +        my_header[0] = 0xea000006;
  2473. +        
  2474. +        fwrite(my_header, 4, 8, stdout);
  2475. +        
  2476. +        totlen = ex.a_text + ex.a_data + ex.a_bss - 0x20;
  2477. +    } else {
  2478. +        fprintf(stderr, "Unacceptable a.out header on kernel\n");
  2479. +        fclose(f);
  2480. +        exit(1);
  2481. +    }
  2482. +
  2483. +    fprintf(stderr, "Kernel is %dk (%dk text, %dk data, %dk bss)\n",
  2484. +        (ex.a_text + ex.a_data + ex.a_bss)/1024,
  2485. +         ex.a_text/1024, ex.a_data/1024, ex.a_bss/1024);
  2486. +
  2487. +    data = malloc(totlen);
  2488. +    fread(data, 1, totlen, f);
  2489. +    fwrite(data, 1, totlen, stdout);
  2490. +
  2491. +    free(data);
  2492. +    fclose(f);
  2493. +    fflush(stdout);
  2494. +    return 0;
  2495. +}
  2496. diff -urNwbB linux/arch/arm/config.in linux.arm/arch/arm/config.in
  2497. --- linux/arch/arm/config.in    Thu Jan  1 01:00:00 1970
  2498. +++ linux.arm/arch/arm/config.in    Sat Feb 24 21:32:58 1996
  2499. @@ -0,0 +1,202 @@
  2500. +#
  2501. +# For a description of the syntax of this configuration file,
  2502. +# see the Configure script.
  2503. +#
  2504. +# This is to tell configure not to execute the sound configuration.
  2505. +#
  2506. +CONFIG_ARM=1
  2507. +
  2508. +mainmenu_name "Linux kernel configuration"
  2509. +
  2510. +echo "/* Automatically generated by configure.  Use Make config to change */" >> $CONFIG_H
  2511. +#
  2512. +# These are to alter the behaviour of various Makefiles and init/main.c
  2513. +# in the architecture-independent areas.
  2514. +#
  2515. +echo "#define CONFIG_ARM 1" >> $CONFIG_H
  2516. +echo "CONFIG_ARM=1" >> $CONFIG
  2517. +
  2518. +mainmenu_option next_comment
  2519. +comment 'General setup'
  2520. +bool 'Compile for arm3' CONFIG_ARM3 y
  2521. +if [ "$CONFIG_ARM3" = "n" ]; then
  2522. +  bool 'Compile for arm610/710' CONFIG_ARM610 y
  2523. +  if [ "$CONFIG_ARM610" = "n" ]; then
  2524. +    bool 'Compile for StrongARM' CONFIG_ARMSTRONG y
  2525. +  fi
  2526. +else
  2527. +  bool 'Page size as 32K' CONFIG_PAGE_32K y
  2528. +  if [ "$CONFIG_PAGE_32K" = "n" ]; then
  2529. +    bool 'Page size as 16K' CONFIG_PAGE_16K y
  2530. +    if [ "$CONFIG_PAGE_16K" = "n" ]; then
  2531. +      echo "Auto detected page size"
  2532. +    fi
  2533. +  fi
  2534. +fi
  2535. +
  2536. +comment 'Math emulation is provided by a run-time loadable module'
  2537. +
  2538. +tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD y
  2539. +bool 'Normal IDE disk/cdrom support' CONFIG_ST506 y
  2540. +if [ "$CONFIG_ST506" = "y" ]; then
  2541. +  comment 'Please see drivers/block/README.ide for help/info on IDE drives'
  2542. +  bool '   Use old disk-only driver for primary i/f' CONFIG_BLK_DEV_HD y
  2543. +#  if [ "$CONFIG_BLK_DEV_HD" = "y" ]; then
  2544. +#    bool '   Include new IDE driver for secondary i/f support' CONFIG_BLK_DEV_IDE n
  2545. +#  else
  2546. +#    bool '   Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE y
  2547. +#  fi
  2548. +#  if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
  2549. +#    bool '   Include support for IDE/ATAPI CDROMs' CONFIG_BLK_DEV_IDECD n
  2550. +#  fi
  2551. +fi
  2552. +tristate 'MFM harddisk support' CONFIG_BLK_DEV_XD n
  2553. +
  2554. +bool 'Networking support' CONFIG_NET y
  2555. +bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
  2556. +bool 'System V IPC' CONFIG_SYSVIPC y
  2557. +#tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF n
  2558. +
  2559. +mainmenu_option next_comment
  2560. +comment 'Loadable module support'
  2561. +bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS y
  2562. +
  2563. +if [ "$CONFIG_NET" = "y" ]; then
  2564. +  mainmenu_option next_comment
  2565. +  comment 'Networking options'
  2566. +  bool 'TCP/IP networking' CONFIG_INET y
  2567. +  if [ "$CONFIG_INET" = "y" ]; then
  2568. +    bool 'IP: forwarding/gatewaying' CONFIG_IP_FORWARD n
  2569. +    bool 'IP: multicasting' CONFIG_IP_MULTICAST n
  2570. +    bool 'IP: firewalling' CONFIG_IP_FIREWALL n
  2571. +    bool 'IP: accounting' CONFIG_IP_ACCT n
  2572. +    tristate 'IP: tunneling' CONFIG_NET_IPIP n
  2573. +    if [ "$CONFIG_IP_FORWARD" = "y" -a "$CONFIG_IP_FIREWALL" = "y" ]; then
  2574. +      bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE y
  2575. +      bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE n
  2576. +    fi
  2577. +    comment '(it is safe to leave these untouched)'
  2578. +    bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP n
  2579. +    tristate 'IP: Reverse ARP' CONFIG_INET_RARP n
  2580. +    bool 'IP: Assume subnets are local' CONFIG_INET_SNARL y
  2581. +    bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
  2582. +    bool 'IP: Drop source routed frames' CONFIG_IP_NOSR y
  2583. +    bool 'IP: Allow large windows (not recommended if <16MB of memory)' CONFIG_SKB_LARGE n
  2584. +  fi
  2585. +  bool 'The IPX protocol' CONFIG_IPX n
  2586. +  bool 'Appletalk DDP' CONFIG_ATALK n
  2587. +  bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
  2588. +  if [ "$CONFIG_AX25" = "y" ]; then
  2589. +    bool 'Amateur Radio NET/ROM' CONFIG_NETROM n
  2590. +  fi
  2591. +  bool 'Kernel/User network link driver(ALPHA)' CONFIG_NETLINK n
  2592. +  if [ "$CONFIG_NETLINK" = "y" ]; then
  2593. +    bool 'Routing messages' CONFIG_RTNETLINK y
  2594. +  fi
  2595. +fi
  2596. +
  2597. +mainmenu_option next_comment
  2598. +comment 'SCSI support'
  2599. +
  2600. +tristate 'SCSI support?' CONFIG_SCSI n
  2601. +
  2602. +if [ "$CONFIG_SCSI" = "n" ]; then
  2603. +
  2604. +  comment 'Skipping SCSI configuration options...'
  2605. +
  2606. +else
  2607. +
  2608. +  comment 'SCSI support type (disk, tape, CDrom)'
  2609. +
  2610. +  dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD y $CONFIG_SCSI
  2611. +  dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST y $CONFIG_SCSI
  2612. +  dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR y $CONFIG_SCSI
  2613. +  dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG n $CONFIG_SCSI
  2614. +
  2615. +  comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
  2616. +
  2617. +  bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN n
  2618. +
  2619. +  mainmenu_option next_comment
  2620. +  comment 'SCSI low-level drivers'
  2621. +
  2622. +  dep_tristate 'Acorn SCSI card (aka30) support' CONFIG_SCSI_ACORNSCSI_3 y $CONFIG_SCSI
  2623. +  dep_tristate 'Cumana 1 support' CONFIG_SCSI_CUMANA_1 n $CONFIG_SCSI
  2624. +  dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI n $CONFIG_SCSI
  2625. +  dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK n $CONFIG_SCSI
  2626. +  dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n $CONFIG_SCSI
  2627. +fi
  2628. +
  2629. +if [ "$CONFIG_NET" = "y" ]; then
  2630. +
  2631. +  mainmenu_option next_comment
  2632. +  comment 'Network device support'
  2633. +
  2634. +  bool 'Network device support?' CONFIG_NETDEVICES y
  2635. +  if [ "$CONFIG_NETDEVICES" = "n" ]; then
  2636. +
  2637. +  comment 'Skipping network driver configuration options...'
  2638. +
  2639. +  else
  2640. +    tristate 'Dummy net driver support' CONFIG_DUMMY y
  2641. +    tristate 'SLIP (serial line) support' CONFIG_SLIP y
  2642. +    if [ "$CONFIG_SLIP" = "y" ]; then
  2643. +      bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
  2644. +    fi
  2645. +    tristate 'PPP (point-to-point) support' CONFIG_PPP y
  2646. +    if [ ! "$CONFIG_PPP" = "n" ]; then
  2647. +      comment 'CCP compressors for PPP are only built as modules.'
  2648. +    fi
  2649. +    tristate 'PLIP (parallel port) support' CONFIG_PLIP y
  2650. +    tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER n
  2651. +    tristate 'Ether1 (82586) support' CONFIG_ETHER1 n
  2652. +    tristate 'Ether3 (NQ8005) support' CONFIG_ETHER3 n
  2653. +  fi
  2654. +fi
  2655. +
  2656. +mainmenu_option next_comment
  2657. +comment 'Filesystems'
  2658. +
  2659. +tristate 'Standard (minix) fs support' CONFIG_MINIX_FS n
  2660. +tristate 'Extended fs support' CONFIG_EXT_FS n
  2661. +tristate 'Second extended fs support' CONFIG_EXT2_FS y
  2662. +tristate 'xiafs filesystem support' CONFIG_XIA_FS n
  2663. +tristate 'msdos fs support' CONFIG_MSDOS_FS y
  2664. +if [ "$CONFIG_MSDOS_FS" = "y" ]; then
  2665. +  tristate 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
  2666. +fi
  2667. +tristate '/proc filesystem support' CONFIG_PROC_FS y
  2668. +tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
  2669. +tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
  2670. +tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
  2671. +if [ "$CONFIG_INET" = "y" ]; then
  2672. +  tristate 'NFS filesystem support' CONFIG_NFS_FS y
  2673. +  tristate 'SMB filesystem (to mount WfW shares etc...) support' CONFIG_SMB_FS n
  2674. +fi
  2675. +
  2676. +mainmenu_option next_comment
  2677. +comment 'Character devices'
  2678. +
  2679. +tristate 'Parallel printer support' CONFIG_PRINTER y
  2680. +tristate 'Mouse support' CONFIG_MOUSE y
  2681. +if [ "$CONFIG_MOUSE" = "n" ]; then
  2682. +  comment 'Skipping mouse options...'
  2683. +else
  2684. +  tristate 'Keyboard mouse [all but RiscPC]' CONFIG_KBDMOUSE y
  2685. +fi
  2686. +
  2687. +mainmenu_option next_comment
  2688. +comment 'Sound'
  2689. +
  2690. +tristate 'Sound support' CONFIG_SOUND n
  2691. +
  2692. +mainmenu_option next_comment
  2693. +comment 'Kernel hacking'
  2694. +
  2695. +bool 'Kernel profiling support' CONFIG_PROFILE n
  2696. +if [ "$CONFIG_PROFILE" = "y" ]; then
  2697. +  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
  2698. +fi
  2699. +if [ "$CONFIG_SCSI" = "y" ]; then
  2700. +bool 'Verbose scsi error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
  2701. +fi
  2702. diff -urNwbB linux/arch/arm/drivers/Makefile linux.arm/arch/arm/drivers/Makefile
  2703. --- linux/arch/arm/drivers/Makefile    Thu Jan  1 01:00:00 1970
  2704. +++ linux.arm/arch/arm/drivers/Makefile    Sun Feb 11 09:32:13 1996
  2705. @@ -0,0 +1,33 @@
  2706. +#
  2707. +# Makefile for the linux kernel device drivers.
  2708. +#
  2709. +# Note! Dependencies are done automagically by 'make dep', which also
  2710. +# removes any old dependencies. DON'T put your own dependencies here
  2711. +# unless it's something special (ie not a .c file).
  2712. +#
  2713. +# Note 2! The CFLAGS definitions are now in the main makefile...
  2714. +
  2715. +SUB_DIRS     := block char net #streams
  2716. +MOD_SUB_DIRS := $(SUB_DIRS)
  2717. +ALL_SUB_DIRS := $(SUB_DIRS) scsi sound
  2718. +
  2719. +# If CONFIG_SCSI is set, the core of scsi support will be added to the kernel,
  2720. +# but some of the low-level things may also be modules.
  2721. +ifeq ($(CONFIG_SCSI),y)
  2722. +SUB_DIRS += scsi
  2723. +MOD_SUB_DIRS += scsi
  2724. +else
  2725. +  ifeq ($(CONFIG_SCSI),m)
  2726. +  MOD_SUB_DIRS += scsi
  2727. +  endif
  2728. +endif
  2729. +
  2730. +ifeq ($(CONFIG_SOUND),y)
  2731. +SUB_DIRS += sound
  2732. +else
  2733. +  ifeq ($(CONFIG_SOUND),m)
  2734. +  MOD_SUB_DIRS += sound
  2735. +  endif
  2736. +endif
  2737. +
  2738. +include $(TOPDIR)/Rules.make
  2739. diff -urNwbB linux/arch/arm/drivers/block/Makefile linux.arm/arch/arm/drivers/block/Makefile
  2740. --- linux/arch/arm/drivers/block/Makefile    Thu Jan  1 01:00:00 1970
  2741. +++ linux.arm/arch/arm/drivers/block/Makefile    Sat Feb 24 13:17:05 1996
  2742. @@ -0,0 +1,63 @@
  2743. +#
  2744. +# Makefile for the kernel block device drivers.
  2745. +#
  2746. +# Note! Dependencies are done automagically by 'make dep', which also
  2747. +# removes any old dependencies. DON'T put your own dependencies here
  2748. +# unless it's something special (ie not a .c file).
  2749. +#
  2750. +# Note 2! The CFLAGS definition is now inherited from the
  2751. +# parent makefile.
  2752. +#
  2753. +
  2754. +all: links first_rule
  2755. +
  2756. +L_TARGET := block.a
  2757. +L_OBJS   := ll_rw_blk.o ramdisk.o genhd.o hdsrch.o
  2758. +M_OBJS   :=
  2759. +MOD_LIST_NAME := BLOCK_MODULES
  2760. +
  2761. +ifeq ($(CONFIG_BLK_DEV_FD),y)
  2762. +L_OBJS += floppy.o
  2763. +else
  2764. +  ifeq ($(CONFIG_BLK_DEV_FD),m)
  2765. +  M_OBJS += floppy.o
  2766. +  endif
  2767. +endif
  2768. +
  2769. +ifeq ($(CONFIG_BLK_DEV_HD),y)
  2770. +L_OBJS += hd.o
  2771. +endif
  2772. +
  2773. +ifeq ($(CONFIG_BLK_DEV_IDE),y)
  2774. +L_OBJS += ide.o
  2775. +endif
  2776. +
  2777. +ifeq ($(CONFIG_BLK_DEV_MFM),y)
  2778. +L_OBJS += mfmhd.o
  2779. +else
  2780. +  ifeq ($(CONFIG_BLK_DEV_MFM),m)
  2781. +  M_OBJS += mfmhd_mod.o
  2782. +  endif
  2783. +endif
  2784. +
  2785. +include $(TOPDIR)/Rules.make
  2786. +
  2787. +fastdep: links
  2788. +
  2789. +mfmhd_mod.o: mfmhd.o
  2790. +    ld -r -o $@ mfmhd.o `gcc --print-libgcc-file-name`
  2791. +
  2792. +LK = blk.h ll_rw_blk.c ramdisk.c README.fd README.hd
  2793. +
  2794. +links:
  2795. +    -@for f in $(LK); do \
  2796. +        ln -s ../../../../drivers/block/$$f .; \
  2797. +    done
  2798. +    touch links
  2799. +
  2800. +LINKCLEAN:
  2801. +    -@for f in $(LK); do \
  2802. +        if [ -L $$f ]; then rm -f $$f; fi; \
  2803. +    done
  2804. +    rm -f links
  2805. +
  2806. diff -urNwbB linux/arch/arm/drivers/block/floppy.c linux.arm/arch/arm/drivers/block/floppy.c
  2807. --- linux/arch/arm/drivers/block/floppy.c    Thu Jan  1 01:00:00 1970
  2808. +++ linux.arm/arch/arm/drivers/block/floppy.c    Sun Mar  3 12:20:41 1996
  2809. @@ -0,0 +1,4120 @@
  2810. +/*
  2811. + *  linux/arch/arm/drivers/block/floppy.c
  2812. + *  [ was linux/drivers/block/floppy.c ]
  2813. + *
  2814. + *  Copyright (C) 1991, 1992  Linus Torvalds
  2815. + *  Copyright (C) 1993, 1994  Alain Knaff
  2816. + *  Modifications Copyright (C) 1995 Russell King
  2817. + */
  2818. +/*
  2819. + * 02.12.91 - Changed to static variables to indicate need for reset
  2820. + * and recalibrate. This makes some things easier (output_byte reset
  2821. + * checking etc), and means less interrupt jumping in case of errors,
  2822. + * so the code is hopefully easier to understand.
  2823. + */
  2824. +
  2825. +/*
  2826. + * This file is certainly a mess. I've tried my best to get it working,
  2827. + * but I don't like programming floppies, and I have only one anyway.
  2828. + * Urgel. I should check for more errors, and do more graceful error
  2829. + * recovery. Seems there are problems with several drives. I've tried to
  2830. + * correct them. No promises.
  2831. + */
  2832. +
  2833. +/*
  2834. + * As with hd.c, all routines within this file can (and will) be called
  2835. + * by interrupts, so extreme caution is needed. A hardware interrupt
  2836. + * handler may not sleep, or a kernel panic will happen. Thus I cannot
  2837. + * call "floppy-on" directly, but have to set a special timer interrupt
  2838. + * etc.
  2839. + */
  2840. +
  2841. +/*
  2842. + * 28.02.92 - made track-buffering routines, based on the routines written
  2843. + * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
  2844. + */
  2845. +
  2846. +/*
  2847. + * Automatic floppy-detection and formatting written by Werner Almesberger
  2848. + * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
  2849. + * the floppy-change signal detection.
  2850. + */
  2851. +
  2852. +/*
  2853. + * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
  2854. + * FDC data overrun bug, added some preliminary stuff for vertical
  2855. + * recording support.
  2856. + *
  2857. + * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
  2858. + *
  2859. + * TODO: Errors are still not counted properly.
  2860. + */
  2861. +
  2862. +/* 1992/9/20
  2863. + * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
  2864. + * modelled after the freeware MS/DOS program fdformat/88 V1.8 by
  2865. + * Christoph H. Hochst\"atter.
  2866. + * I have fixed the shift values to the ones I always use. Maybe a new
  2867. + * ioctl() should be created to be able to modify them.
  2868. + * There is a bug in the driver that makes it impossible to format a
  2869. + * floppy as the first thing after bootup.
  2870. + */
  2871. +
  2872. +/*
  2873. + * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
  2874. + * this helped the floppy driver as well. Much cleaner, and still seems to
  2875. + * work.
  2876. + */
  2877. +
  2878. +/* 1994/6/24 --bbroad-- added the floppy table entries and made
  2879. + * minor modifications to allow 2.88 floppies to be run.
  2880. + */
  2881. +
  2882. +/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
  2883. + * disk types.
  2884. + */
  2885. +
  2886. +/*
  2887. + * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
  2888. + * format bug fixes, but unfortunately some new bugs too...
  2889. + */
  2890. +
  2891. +/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
  2892. + * errors to allow safe writing by specialized programs.
  2893. + */
  2894. +
  2895. +/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
  2896. + * by defining bit 1 of the "stretch" parameter to mean put sectors on the
  2897. + * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
  2898. + * drives are "upside-down").
  2899. + */
  2900. +
  2901. +/*
  2902. + * 1995/8/16 -- Russell King -- altered method for turning floppy drives on
  2903. + * for the arm.
  2904. + */
  2905. +#define CONFIG_FLOPPY_SANITY
  2906. +#undef  CONFIG_FLOPPY_SILENT_DCL_CLEAR
  2907. +
  2908. +#define DEBUGT 2
  2909. +#define DCL_DEBUG /* debug disk change line */
  2910. +
  2911. +#include <linux/config.h>
  2912. +
  2913. +/* do print messages for unexpected interrupts */
  2914. +static int print_unex=1;
  2915. +
  2916. +#ifdef MODULE
  2917. +#define FD_MODULE
  2918. +
  2919. +#include <linux/module.h>
  2920. +/*
  2921. + * NB. we must include the kernel identification string to install the module.
  2922. + */
  2923. +#include <linux/version.h>
  2924. +char kernel_version[] = UTS_RELEASE;
  2925. +
  2926. +int FLOPPY_IRQ=12;
  2927. +int FLOPPY_DMA=2;
  2928. +int ALLOWED_DRIVE_MASK = 0x33;
  2929. +int FDC1 = 0x3f0;
  2930. +int FDC2 = -1;
  2931. +
  2932. +#endif
  2933. +
  2934. +#ifndef FD_MODULE
  2935. +/* the following is the mask of allowed drives. By default units 2 and
  2936. + * 3 of both floppy controllers are disabled, because switching on the
  2937. + * motor of these drives causes system hangs on some PCI computers. drive
  2938. + * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
  2939. + * a drive is allowed. */
  2940. +static int ALLOWED_DRIVE_MASK=0x33;
  2941. +
  2942. +#define FLOPPY_IRQ 12
  2943. +#define FLOPPY_DMA 2
  2944. +#define FDC1 0x3f0
  2945. +static int FDC2=-1;
  2946. +#endif
  2947. +
  2948. +#define MODULE_AWARE_DRIVER
  2949. +
  2950. +#include <linux/sched.h>
  2951. +#include <linux/fs.h>
  2952. +#include <linux/kernel.h>
  2953. +#include <linux/timer.h>
  2954. +#include <linux/tqueue.h>
  2955. +#define FDPATCHES
  2956. +#include <linux/fdreg.h>
  2957. +
  2958. +/* ============================================ *
  2959. + * old fd.h                                     *
  2960. + * =========================================== */
  2961. +
  2962. +#define OLDFDCLRPRM 0 /* clear user-defined parameters */
  2963. +#define OLDFDSETPRM 1 /* set user-defined parameters for current media */
  2964. +#define OLDFDSETMEDIAPRM 1
  2965. +#define OLDFDDEFPRM 2 /* set user-defined parameters until explicitly cleared */
  2966. +#define OLDFDDEFMEDIAPRM 2
  2967. +#define OLDFDGETPRM 3 /* get disk parameters */
  2968. +#define OLDFDGETMEDIAPRM 3
  2969. +#define OLDFDMSGON  4 /* issue kernel messages on media type change */
  2970. +#define OLDFDMSGOFF 5 /* don't issue kernel messages on media type change */
  2971. +#define OLDFDFMTBEG 6 /* begin formatting a disk */
  2972. +#define OLDFDFMTTRK 7 /* format the specified track */
  2973. +#define OLDFDFMTEND 8 /* end formatting a disk */
  2974. +#define OLDFDSETEMSGTRESH       10      /* set fdc error reporting threshold */
  2975. +#define OLDFDFLUSH  11 /* flush buffers for media; either for verifying media, or for
  2976. +                       handling a media change without closing the file
  2977. +                                              descriptor */
  2978. +#define OLDFDSETMAXERRS 12 /* set abortion and read_track threshold */
  2979. +#define OLDFDGETMAXERRS 14 /* get abortion and read_track threshold */
  2980. +#define OLDFDGETDRVTYP 16          /* get drive type: 5 1/4 or 3 1/2 */
  2981. +
  2982. +#define OLDFDSETDRVPRM 20 /* set drive parameters */
  2983. +#define OLDFDGETDRVPRM 21 /* get drive parameters */
  2984. +#define OLDFDGETDRVSTAT 22 /* get drive state */
  2985. +#define OLDFDPOLLDRVSTAT 23 /* get drive state */
  2986. +#define OLDFDRESET 24 /* reset FDC */
  2987. +
  2988. +#define OLDFD_RESET_IF_NEEDED 0
  2989. +#define OLDFD_RESET_IF_RAWCMD 1
  2990. +#define OLDFD_RESET_ALWAYS 2
  2991. +
  2992. +#define OLDFDGETFDCSTAT 25 /* get fdc state */
  2993. +#define OLDFDWERRORCLR  27 /* clear write error and badness information */
  2994. +#define OLDFDWERRORGET  28 /* get write error and badness information */
  2995. +
  2996. +#define OLDFDRAWCMD 30 /* send a raw command to the fdc */
  2997. +
  2998. +#define OLDFDTWADDLE 40 /* flicker motor-on bit before reading a sector */
  2999. +
  3000. +struct old_floppy_raw_cmd {
  3001. +  void *data;
  3002. +  long length;
  3003. +
  3004. +  unsigned char rate;
  3005. +  unsigned char flags;
  3006. +  unsigned char cmd_count;
  3007. +  unsigned char cmd[9];
  3008. +  unsigned char reply_count;
  3009. +  unsigned char reply[7];
  3010. +  int track;
  3011. +};
  3012. +
  3013. +struct old_floppy_fdc_state {
  3014. +    int spec1; /* spec1 value last used */
  3015. +    int spec2; /* spec2 value last used */
  3016. +    int dtr;
  3017. +    unsigned char version;  /* FDC version code */
  3018. +    unsigned char dor;
  3019. +    int address; /* io address */
  3020. +    unsigned int rawcmd:2;
  3021. +    unsigned int reset:1;
  3022. +    unsigned int need_configure:1;
  3023. +    unsigned int perp_mode:2;
  3024. +    unsigned int has_fifo:1;
  3025. +};
  3026. +
  3027. +
  3028. +#include <linux/fd.h>
  3029. +#include <linux/errno.h>
  3030. +#include <linux/malloc.h>
  3031. +#include <linux/mm.h>
  3032. +#include <linux/string.h>
  3033. +#include <linux/fcntl.h>
  3034. +#include <linux/delay.h>
  3035. +
  3036. +#include <linux/ioport.h>
  3037. +
  3038. +#include <asm/dma.h>
  3039. +#include <asm/irq.h>
  3040. +#include <asm/system.h>
  3041. +#include <asm/io.h>
  3042. +#include <asm/segment.h>
  3043. +
  3044. +#define MAJOR_NR FLOPPY_MAJOR
  3045. +#include "blk.h"
  3046. +
  3047. +
  3048. +/* Dma Memory related stuff */
  3049. +
  3050. +/* Pure 2^n version of get_order */
  3051. +static inline int __get_order (int size)
  3052. +{
  3053. +    int order;
  3054. +
  3055. +    for (order = 0; order < NR_MEM_LISTS; ++order)
  3056. +        if (size <= (PAGE_SIZE << order))
  3057. +            return order;
  3058. +    return NR_MEM_LISTS;
  3059. +}
  3060. +
  3061. +static unsigned long dma_mem_alloc(int size)
  3062. +{
  3063. +    int order = __get_order(size);
  3064. +
  3065. +    if (order >= NR_MEM_LISTS)
  3066. +        return(0);
  3067. +    return __get_dma_pages(GFP_KERNEL,order);
  3068. +}
  3069. +
  3070. +/* End dma memory related stuff */
  3071. +
  3072. +static unsigned int fake_change = 0;
  3073. +static int initialising=1;
  3074. +
  3075. +#define FLOPPY0_TYPE 4
  3076. +#define FLOPPY1_TYPE 0
  3077. +
  3078. +#define N_FDC 2
  3079. +#define N_DRIVE 8
  3080. +
  3081. +static inline int TYPE(kdev_t x) {
  3082. +    return  (MINOR(x)>>2) & 0x1f;
  3083. +}
  3084. +static inline int DRIVE(kdev_t x) {
  3085. +    return (MINOR(x)&0x03) | ((MINOR(x)&0x80)>>5);
  3086. +}
  3087. +#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
  3088. +#define UNIT(x) ( (x) & 0x03 )        /* drive on fdc */
  3089. +#define FDC(x) ( ((x) & 0x04) >> 2 )  /* fdc of drive */
  3090. +#define REVDRIVE(fdc, unit) ( (unit) + ((fdc) << 2 ))
  3091. +                /* reverse mapping from unit and fdc to drive */
  3092. +#define DP (&drive_params[current_drive])
  3093. +#define DRS (&drive_state[current_drive])
  3094. +#define DRWE (&write_errors[current_drive])
  3095. +#define FDCS (&fdc_state[fdc])
  3096. +#define CLEARF(x) (clear_bit(x##_BIT, &DRS->flags))
  3097. +#define SETF(x) (set_bit(x##_BIT, &DRS->flags))
  3098. +#define TESTF(x) (test_bit(x##_BIT, &DRS->flags))
  3099. +
  3100. +#define UDP (&drive_params[drive])
  3101. +#define UDRS (&drive_state[drive])
  3102. +#define UDRWE (&write_errors[drive])
  3103. +#define UFDCS (&fdc_state[FDC(drive)])
  3104. +#define UCLEARF(x) (clear_bit(x##_BIT, &UDRS->flags))
  3105. +#define USETF(x) (set_bit(x##_BIT, &UDRS->flags))
  3106. +#define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags))
  3107. +
  3108. +#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive)
  3109. +
  3110. +#define DPRINT1(x,x1) printk(DEVICE_NAME "%d: " x,current_drive,(x1))
  3111. +
  3112. +#define DPRINT2(x,x1,x2) printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2))
  3113. +
  3114. +#define DPRINT3(x,x1,x2,x3) printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
  3115. +
  3116. +#define PH_HEAD(floppy,head) (((((floppy)->stretch & 2) >>1) ^ head) << 2)
  3117. +#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
  3118. +
  3119. +/* read/write */
  3120. +#define COMMAND raw_cmd->cmd[0]
  3121. +#define DR_SELECT raw_cmd->cmd[1]
  3122. +#define TRACK raw_cmd->cmd[2]
  3123. +#define HEAD raw_cmd->cmd[3]
  3124. +#define SECTOR raw_cmd->cmd[4]
  3125. +#define SIZECODE raw_cmd->cmd[5]
  3126. +#define SECT_PER_TRACK raw_cmd->cmd[6]
  3127. +#define GAP raw_cmd->cmd[7]
  3128. +#define SIZECODE2 raw_cmd->cmd[8]
  3129. +#define NR_RW 9
  3130. +
  3131. +/* format */
  3132. +#define F_SIZECODE raw_cmd->cmd[2]
  3133. +#define F_SECT_PER_TRACK raw_cmd->cmd[3]
  3134. +#define F_GAP raw_cmd->cmd[4]
  3135. +#define F_FILL raw_cmd->cmd[5]
  3136. +#define NR_F 6
  3137. +
  3138. +/*
  3139. + * Maximum disk size (in kilobytes). This default is used whenever the
  3140. + * current disk size is unknown.
  3141. + * [Now it is rather a minimum]
  3142. + */
  3143. +#define MAX_DISK_SIZE 2 /* 3984*/
  3144. +
  3145. +
  3146. +#define K_64    0x10000        /* 64kB */
  3147. +
  3148. +/*
  3149. + * The DMA channel used by the floppy controller cannot access data at
  3150. + * addresses >= 16MB
  3151. + *
  3152. + * Went back to the 1MB limit, as some people had problems with the floppy
  3153. + * driver otherwise. It doesn't matter much for performance anyway, as most
  3154. + * floppy accesses go through the track buffer.
  3155. + */
  3156. +#define CROSS_64KB(a,s) (0)
  3157. +#undef LAST_DMA_ADDR
  3158. +#define LAST_DMA_ADDR    (0x1)
  3159. +
  3160. +/*
  3161. + * globals used by 'result()'
  3162. + */
  3163. +#define MAX_REPLIES 10
  3164. +static unsigned char reply_buffer[MAX_REPLIES];
  3165. +static int inr; /* size of reply buffer, when called from interrupt */
  3166. +#define ST0 (reply_buffer[0])
  3167. +#define ST1 (reply_buffer[1])
  3168. +#define ST2 (reply_buffer[2])
  3169. +#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
  3170. +#define R_TRACK (reply_buffer[3])
  3171. +#define R_HEAD (reply_buffer[4])
  3172. +#define R_SECTOR (reply_buffer[5])
  3173. +#define R_SIZECODE (reply_buffer[6])
  3174. +
  3175. +#define SEL_DLY (2*HZ/100)
  3176. +
  3177. +#define ARRAY_SIZE(x) (sizeof(x) / sizeof( (x)[0] ))
  3178. +/*
  3179. + * this struct defines the different floppy drive types.
  3180. + */
  3181. +static struct {
  3182. +    struct floppy_drive_params params;
  3183. +    const char *name; /* name printed while booting */
  3184. +} default_drive_params[]= {
  3185. +/* NOTE: the time values in jiffies should be in msec!
  3186. + CMOS drive type
  3187. +  |     Maximum data rate supported by drive type
  3188. +  |     |   Head load time, msec
  3189. +  |     |   |   Head unload time, msec (not used)
  3190. +  |     |   |   |     Step rate interval, usec
  3191. +  |     |   |   |     |       Time needed for spinup time (jiffies)
  3192. +  |     |   |   |     |       |      Timeout for spinning down (jiffies)
  3193. +  |     |   |   |     |       |      |   Spindown offset (where disk stops)
  3194. +  |     |   |   |     |       |      |   |     Select delay
  3195. +  |     |   |   |     |       |      |   |     |     RPS
  3196. +  |     |   |   |     |       |      |   |     |     |    Max number of tracks
  3197. +  |     |   |   |     |       |      |   |     |     |    |     Interrupt timeout
  3198. +  |     |   |   |     |       |      |   |     |     |    |     |   Max nonintlv. sectors
  3199. +  |     |   |   |     |       |      |   |     |     |    |     |   | -Max Errors- flags */
  3200. +{{0,  500, 16, 16, 8000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  80, 3*HZ, 20, {3,1,2,0,2}, 0,
  3201. +      0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
  3202. +
  3203. +{{1,  300, 16, 16, 8000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  40, 3*HZ, 17, {3,1,2,0,2}, 0,
  3204. +      0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
  3205. +
  3206. +{{2,  500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6,  83, 3*HZ, 17, {3,1,2,0,2}, 0,
  3207. +      0, { 2, 5, 6,23,10,20,11, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
  3208. +
  3209. +{{3,  250, 16, 16, 3000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
  3210. +      0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
  3211. +#if 0
  3212. +{{4,  500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
  3213. +      0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
  3214. +#else
  3215. +{{4,  500, 16, 16, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 20, {3,1,2,0,0}, FTD_MSG,
  3216. +      0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
  3217. +#endif
  3218. +{{5, 1000, 15,  8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
  3219. +      0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
  3220. +
  3221. +{{6, 1000, 15,  8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
  3222. +      0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
  3223. +/*    |  --autodetected formats---   |      |      |
  3224. + *    read_track                     |      |    Name printed when booting
  3225. + *                                   |     Native format
  3226. + *                                 Frequency of disk change checks */
  3227. +};
  3228. +
  3229. +static struct floppy_drive_params drive_params[N_DRIVE];
  3230. +static struct floppy_drive_struct drive_state[N_DRIVE];
  3231. +static struct floppy_write_errors write_errors[N_DRIVE];
  3232. +static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
  3233. +
  3234. +/*
  3235. + * This struct defines the different floppy types.
  3236. + *
  3237. + * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
  3238. + * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
  3239. + * tells if the disk is in Commodore 1581 format, which means side 0 sectors
  3240. + * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
  3241. + * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
  3242. + * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
  3243. + * side 0 is on physical side 0 (but with the misnamed sector IDs).
  3244. + * 'stretch' should probably be renamed to something more general, like
  3245. + * 'options'.  Other parameters should be self-explanatory (see also
  3246. + * setfdprm(8)).
  3247. + */
  3248. +/*
  3249. +             Size
  3250. +             |  Sectors per track
  3251. +             |  | Head
  3252. +             |  | |  Tracks
  3253. +             |  | |  | Stretch
  3254. +             |  | |  | |  Gap 1 size
  3255. +             |  | |  | |    |  Data rate, | 0x40 for perp
  3256. +         |  | |  | |    |    |  Spec1 (stepping rate, head unload
  3257. +             |  | |  | |    |    |    |    /fmt gap (gap2) */
  3258. +static struct floppy_struct floppy_type[32] = {
  3259. +    {    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL    },    /*  0 no testing    */
  3260. +    {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360"  }, /*  1 360KB PC      */
  3261. +    { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" },    /*  2 1.2MB AT      */
  3262. +    {  720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360"  },    /*  3 360KB SS 3.5" */
  3263. +    { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720"  },    /*  4 720KB 3.5"    */
  3264. +    {  720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360"  },    /*  5 360KB AT      */
  3265. +    { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720"  },    /*  6 720KB AT      */
  3266. +    { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" },    /*  7 1.44MB 3.5"   */
  3267. +    { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" },    /*  8 2.88MB 3.5"   */
  3268. +    { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"CompaQ"},    /*  9 2.88MB 3.5"   */
  3269. +
  3270. +    { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25"  */
  3271. +    { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5"   */
  3272. +    {  820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410"  },    /* 12 410KB 5.25"   */
  3273. +    { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820"  },    /* 13 820KB 3.5"    */
  3274. +    { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" },    /* 14 1.48MB 5.25"  */
  3275. +    { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" },    /* 15 1.72MB 3.5"   */
  3276. +    {  840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420"  },    /* 16 420KB 5.25"   */
  3277. +    { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830"  },    /* 17 830KB 3.5"    */
  3278. +    { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" },    /* 18 1.49MB 5.25"  */
  3279. +    { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5"  */
  3280. +
  3281. +    { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880"  }, /* 20 880KB 5.25"   */
  3282. +    { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5"   */
  3283. +    { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5"   */
  3284. +    { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25"   */
  3285. +    { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5"   */
  3286. +    { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5"   */
  3287. +    { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5"   */
  3288. +    { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5"   */
  3289. +    { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5"   */
  3290. +
  3291. +    { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5"   */
  3292. +    { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800"  },    /* 30 800KB 3.5"    */
  3293. +    { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5"    */
  3294. +};
  3295. +
  3296. +#define    NUMBER(x)    (sizeof(x) / sizeof(*(x)))
  3297. +#define SECTSIZE ( _FD_SECTSIZE(*floppy))
  3298. +
  3299. +/* Auto-detection: Disk type used until the next media change occurs. */
  3300. +struct floppy_struct *current_type[N_DRIVE] = {
  3301. +    NULL, NULL, NULL, NULL,
  3302. +    NULL, NULL, NULL, NULL
  3303. +};
  3304. +
  3305. +/*
  3306. + * User-provided type information. current_type points to
  3307. + * the respective entry of this array.
  3308. + */
  3309. +struct floppy_struct user_params[N_DRIVE];
  3310. +
  3311. +static int floppy_sizes[256];
  3312. +static int floppy_blocksizes[256] = { 0, };
  3313. +
  3314. +/*
  3315. + * The driver is trying to determine the correct media format
  3316. + * while probing is set. rw_interrupt() clears it after a
  3317. + * successful access.
  3318. + */
  3319. +static int probing = 0;
  3320. +
  3321. +/* Synchronization of FDC access. */
  3322. +#define FD_COMMAND_DETECT -2
  3323. +#define FD_COMMAND_NONE -1
  3324. +#define FD_COMMAND_ERROR 2
  3325. +#define FD_COMMAND_OKAY 3
  3326. +
  3327. +static volatile int command_status = FD_COMMAND_NONE, fdc_busy = 0;
  3328. +static struct wait_queue *fdc_wait = NULL, *command_done = NULL;
  3329. +#define NO_SIGNAL (!(current->signal & ~current->blocked) || !interruptible)
  3330. +#define CALL(x) if( (x) == -EINTR) return -EINTR
  3331. +#define ECALL(x) if ((ret = (x))) return ret;
  3332. +#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
  3333. +#define WAIT(x) _WAIT((x),interruptible)
  3334. +#define IWAIT(x) _WAIT((x),1)
  3335. +
  3336. +/* Errors during formatting are counted here. */
  3337. +static int format_errors;
  3338. +
  3339. +/* Format request descriptor. */
  3340. +static struct format_descr format_req;
  3341. +
  3342. +/*
  3343. + * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
  3344. + * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
  3345. + * H is head unload time (1=16ms, 2=32ms, etc)
  3346. + */
  3347. +
  3348. +/*
  3349. + * Track buffer
  3350. + * Because these are written to by the DMA controller, they must
  3351. + * not contain a 64k byte boundary crossing, or data will be
  3352. + * corrupted/lost. Alignment of these is enforced in boot/head.S.
  3353. + * Note that you must not change the sizes below without updating head.S.
  3354. + */
  3355. +char *floppy_track_buffer=NULL;
  3356. +int max_buffer_sectors=0;
  3357. +
  3358. +int *errors;
  3359. +typedef void (*done_f)(int);
  3360. +struct cont_t {
  3361. +    void (*interrupt)(void); /* this is called after the interrupt of the
  3362. +                  * main command */
  3363. +    void (*redo)(void); /* this is called to retry the operation */
  3364. +    void (*error)(void); /* this is called to tally an error */
  3365. +    done_f done; /* this is called to say if the operation has
  3366. +              * succeeded/failed */
  3367. +} *cont=NULL;
  3368. +
  3369. +static void floppy_ready(void);
  3370. +static void floppy_start(void);
  3371. +static void process_fd_request(void);
  3372. +static void recalibrate_floppy(void);
  3373. +static void floppy_shutdown(void);
  3374. +
  3375. +static int floppy_grab_irq_and_dma(void);
  3376. +static void floppy_release_irq_and_dma(void);
  3377. +
  3378. +/*
  3379. + * The "reset" variable should be tested whenever an interrupt is scheduled,
  3380. + * after the commands have been sent. This is to ensure that the driver doesn't
  3381. + * get wedged when the interrupt doesn't come because of a failed command.
  3382. + * reset doesn't need to be tested before sending commands, because
  3383. + * output_byte is automatically disabled when reset is set.
  3384. + */
  3385. +#define CHECK_RESET { if ( FDCS->reset ){ reset_fdc(); return ; } }
  3386. +static void reset_fdc(void);
  3387. +
  3388. +/*
  3389. + * These are global variables, as that's the easiest way to give
  3390. + * information to interrupts. They are the data used for the current
  3391. + * request.
  3392. + */
  3393. +#define NO_TRACK -1
  3394. +#define NEED_1_RECAL -2
  3395. +#define NEED_2_RECAL -3
  3396. +
  3397. +/* */
  3398. +static int usage_count = 0;
  3399. +
  3400. +
  3401. +/* buffer related variables */
  3402. +static int buffer_track = -1;
  3403. +static int buffer_drive = -1;
  3404. +static int buffer_min = -1;
  3405. +static int buffer_max = -1;
  3406. +
  3407. +/* fdc related variables, should end up in a struct */
  3408. +static struct floppy_fdc_state fdc_state[N_FDC];
  3409. +static int fdc; /* current fdc */
  3410. +
  3411. +static struct floppy_struct * floppy = floppy_type;
  3412. +static unsigned char current_drive = 0;
  3413. +static long current_count_sectors = 0;
  3414. +static unsigned char sector_t; /* sector in track */
  3415. +
  3416. +#ifdef DEBUGT
  3417. +long unsigned debugtimer;
  3418. +#endif
  3419. +
  3420. +/*
  3421. + * Floppy_selects1 is the list of DOR's to select a drive n
  3422. + * Floppy_selects2 is the list of DOR's to select drive fd
  3423. + * On initialisation, the floppy list is scanned, and the drives allocated
  3424. + * in the order that they are found.  This is done by seeking the drive
  3425. + * to a non-zero track, and then restoring it to track 0.  If an error occurs,
  3426. + * then there is no floppy drive present.
  3427. + */
  3428. +/*extern*/ int no_floppies;
  3429. +unsigned char floppy_selects1[]={ 0x10, 0x21, 0x23, 0x33 };
  3430. +unsigned char floppy_selects2[]={ 0   , 0   , 0   , 0    };
  3431. +
  3432. +/*
  3433. + * Debugging
  3434. + * =========
  3435. + */
  3436. +static inline void set_debugt(void)
  3437. +{
  3438. +#ifdef DEBUGT
  3439. +    debugtimer = jiffies;
  3440. +#endif
  3441. +}
  3442. +
  3443. +static inline void debugt(const char *message)
  3444. +{
  3445. +#ifdef DEBUGT
  3446. +  if ( DP->flags & DEBUGT )
  3447. +    printk("%s dtime=%lu\n", message, jiffies-debugtimer );
  3448. +#endif
  3449. +}
  3450. +
  3451. +typedef void (*timeout_fn)(unsigned long);
  3452. +static struct timer_list fd_timeout ={ NULL, NULL, 0, 0,
  3453. +                    (timeout_fn) floppy_shutdown };
  3454. +
  3455. +static const char *timeout_message;
  3456. +
  3457. +#ifdef CONFIG_FLOPPY_SANITY
  3458. +static void is_alive(const char *message)
  3459. +{
  3460. +    /* this routine checks whether the floppy driver is "alive" */
  3461. +    if (fdc_busy && command_status < 2 && !fd_timeout.prev){
  3462. +        DPRINT1("timeout handler died: %s\n",message);
  3463. +    }
  3464. +}
  3465. +
  3466. +
  3467. +#define OLOGSIZE 20
  3468. +
  3469. +void (*lasthandler)(void) = NULL;
  3470. +int interruptjiffies=0;
  3471. +int resultjiffies=0;
  3472. +int resultsize=0;
  3473. +int lastredo=0;
  3474. +
  3475. +static struct output_log {
  3476. +    unsigned char data;
  3477. +    unsigned char status;
  3478. +    unsigned long jiffies;
  3479. +} output_log[OLOGSIZE];
  3480. +
  3481. +static int output_log_pos=0;
  3482. +#endif
  3483. +
  3484. +#define CURRENTD -1
  3485. +#define MAXTIMEOUT -2
  3486. +
  3487. +
  3488. +
  3489. +static void reschedule_timeout(int drive, const char *message, int marg)
  3490. +{
  3491. +    if (drive == CURRENTD )
  3492. +        drive = current_drive;
  3493. +    del_timer(&fd_timeout);
  3494. +    if (drive < 0 || drive > N_DRIVE) {
  3495. +        fd_timeout.expires = jiffies + 20*HZ;
  3496. +        drive = 0;
  3497. +    } else
  3498. +        fd_timeout.expires = jiffies + UDP->timeout;
  3499. +    add_timer(&fd_timeout);
  3500. +    if (UDP->flags & FD_DEBUG) {
  3501. +        DPRINT("reschedule timeout ");
  3502. +        printk(message, marg);
  3503. +        printk("\n");
  3504. +    }
  3505. +    timeout_message = message;
  3506. +}
  3507. +
  3508. +/*
  3509. + * Bottom half floppy driver.
  3510. + * ==========================
  3511. + *
  3512. + * This part of the file contains the code talking directly to the hardware,
  3513. + * and also the main service loop (seek-configure-spinup-command)
  3514. + */
  3515. +
  3516. +/*
  3517. + * disk change.
  3518. + * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
  3519. + * and the last_checked date.
  3520. + *
  3521. + * last_checked is the date of the last check which showed 'no disk change'
  3522. + * FD_DISK_CHANGE is set under two conditions:
  3523. + * 1. The floppy has been changed after some i/o to that floppy already
  3524. + *    took place.
  3525. + * 2. No floppy disk is in the drive. This is done in order to ensure that
  3526. + *    requests are quickly flushed in case there is no disk in the drive. It
  3527. + *    follows that FD_DISK_CHANGE can only be cleared if there is a disk in
  3528. + *    the drive.
  3529. + *
  3530. + * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
  3531. + * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
  3532. + *  each seek. If a disk is present, the disk change line should also be
  3533. + *  cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
  3534. + *  change line is set, this means either that no disk is in the drive, or
  3535. + *  that it has been removed since the last seek.
  3536. + *
  3537. + * This means that we really have a third possibility too:
  3538. + *  The floppy has been changed after the last seek.
  3539. + */
  3540. +
  3541. +static int disk_change(int drive)
  3542. +{
  3543. +    int fdc=FDC(drive);
  3544. +#ifdef CONFIG_FLOPPY_SANITY
  3545. +    if(jiffies < UDP->select_delay + UDRS->select_date)
  3546. +        DPRINT("WARNING disk change called early\n");
  3547. +    if(! (FDCS->dor & (0x10 << UNIT(drive))) ||
  3548. +       (FDCS->dor & 3) != UNIT(drive) ||
  3549. +       fdc != FDC(drive)){
  3550. +           DPRINT("probing disk change on unselected drive\n");
  3551. +           DPRINT3("drive=%d fdc=%d dor=%x\n",drive, FDC(drive),
  3552. +               FDCS->dor);
  3553. +    }
  3554. +#endif
  3555. +
  3556. +#ifdef DCL_DEBUG
  3557. +    if (UDP->flags & FD_DEBUG){
  3558. +        DPRINT1("checking disk change line for drive %d\n",drive);
  3559. +        DPRINT1("jiffies=%ld\n", jiffies);
  3560. +        DPRINT1("disk change line=%x\n", inb_p(FD_DIR)&0x80);
  3561. +        DPRINT1("flags=%x\n",UDRS->flags);
  3562. +    }
  3563. +#endif
  3564. +    if (UDP->flags & FD_BROKEN_DCL)
  3565. +        return UTESTF(FD_DISK_CHANGED);
  3566. +    if( (inb_p(FD_DIR) ^ UDP->flags) & 0x80){
  3567. +        USETF(FD_VERIFY); /* verify write protection */
  3568. +        if(UDRS->maxblock){
  3569. +            /* mark it changed */
  3570. +            USETF(FD_DISK_CHANGED);
  3571. +
  3572. +            /* invalidate its geometry */
  3573. +            if (UDRS->keep_data >= 0) {
  3574. +                if ((UDP->flags & FTD_MSG) &&
  3575. +                    current_type[drive] != NULL)
  3576. +                    DPRINT("Disk type is undefined after "
  3577. +                           "disk change\n");
  3578. +                current_type[drive] = NULL;
  3579. +                floppy_sizes[TOMINOR(current_drive)] = MAX_DISK_SIZE;
  3580. +            }
  3581. +        }
  3582. +        /*USETF(FD_DISK_NEWCHANGE);*/
  3583. +        return 1;
  3584. +    } else {
  3585. +        UDRS->last_checked=jiffies;
  3586. +        UCLEARF(FD_DISK_NEWCHANGE);
  3587. +    }
  3588. +    return 0;
  3589. +}
  3590. +
  3591. +static inline int is_selected(int dor, int unit)
  3592. +{
  3593. +    return ( (dor  & (0x10 << unit)) && (dor &3) == unit);
  3594. +}
  3595. +
  3596. +static inline void arm_set_dor(int dor)
  3597. +{
  3598. +    if(dor & 0xf0)
  3599. +        outb_p((dor & 0x0c) | floppy_selects1[dor & 3], FD_DOR);
  3600. +    else
  3601. +        outb_p((dor & 0x0c), FD_DOR);
  3602. +}
  3603. +
  3604. +static int set_dor(int fdc, char mask, char data)
  3605. +{
  3606. +    register unsigned char drive, unit, newdor,olddor;
  3607. +
  3608. +    if (FDCS->address == -1)
  3609. +        return -1;
  3610. +
  3611. +    olddor = FDCS->dor;
  3612. +    newdor =  (olddor & mask) | data;
  3613. +    if ( newdor != olddor ){
  3614. +        unit = olddor & 0x3;
  3615. +        if(is_selected(olddor, unit) && !is_selected(newdor, unit)){
  3616. +            drive = REVDRIVE(fdc,unit);
  3617. +#ifdef DCL_DEBUG
  3618. +            if (UDP->flags & FD_DEBUG){
  3619. +                DPRINT("calling disk change from set_dor\n");
  3620. +            }
  3621. +#endif
  3622. +            disk_change(drive);
  3623. +        }
  3624. +        FDCS->dor = newdor;
  3625. +        arm_set_dor(newdor);
  3626. +
  3627. +        unit = newdor & 0x3;
  3628. +        if(!is_selected(olddor, unit) && is_selected(newdor, unit)){
  3629. +            drive = REVDRIVE(fdc,unit);
  3630. +            UDRS->select_date = jiffies;
  3631. +        }
  3632. +    }
  3633. +    if ( newdor & 0xf0 )
  3634. +        floppy_grab_irq_and_dma();
  3635. +    if( olddor & 0xf0 )
  3636. +        floppy_release_irq_and_dma();
  3637. +    return olddor;
  3638. +}
  3639. +
  3640. +static void twaddle(void)
  3641. +{
  3642. +    if (DP->select_delay)
  3643. +        return;
  3644. +    arm_set_dor(FDCS->dor & ~(0x10<<UNIT(current_drive)));
  3645. +    arm_set_dor(FDCS->dor);
  3646. +    DRS->select_date = jiffies;
  3647. +}
  3648. +
  3649. +/* reset all driver information about the current fdc. This is needed after
  3650. + * a reset, and after a raw command. */
  3651. +static void reset_fdc_info(int mode)
  3652. +{
  3653. +    int drive;
  3654. +
  3655. +    FDCS->spec1 = FDCS->spec2 = -1;
  3656. +    FDCS->need_configure = 1;
  3657. +    FDCS->perp_mode = 1;
  3658. +    FDCS->rawcmd = 0;
  3659. +    for ( drive = 0; drive < N_DRIVE; drive++)
  3660. +        if (FDC(drive) == fdc &&
  3661. +            ( mode || UDRS->track != NEED_1_RECAL))
  3662. +            UDRS->track = NEED_2_RECAL;
  3663. +}
  3664. +
  3665. +/* selects the fdc and drive, and enables the fdc's input/dma. */
  3666. +static void set_fdc(int drive)
  3667. +{
  3668. +    if ( drive >= 0 && drive < N_DRIVE){
  3669. +        fdc = FDC(drive);
  3670. +        current_drive = drive;
  3671. +    }
  3672. +    set_dor(fdc,~0,8);
  3673. +    set_dor(1-fdc, ~8, 0);
  3674. +    if ( FDCS->rawcmd == 2 )
  3675. +        reset_fdc_info(1);
  3676. +    if( inb_p(FD_STATUS) != STATUS_READY )
  3677. +        FDCS->reset = 1;
  3678. +}
  3679. +
  3680. +/* locks the driver */
  3681. +static int lock_fdc(int drive, int interruptible)
  3682. +{
  3683. +    if(!usage_count){
  3684. +        printk("trying to lock fdc while usage count=0\n");
  3685. +        return -1;
  3686. +    }
  3687. +    floppy_grab_irq_and_dma();
  3688. +    cli();
  3689. +    while (fdc_busy && NO_SIGNAL)
  3690. +        interruptible_sleep_on(&fdc_wait);
  3691. +    if(fdc_busy){
  3692. +        sti();
  3693. +        return -EINTR;
  3694. +    }
  3695. +    fdc_busy = 1;
  3696. +    sti();
  3697. +    command_status = FD_COMMAND_NONE;
  3698. +    set_fdc(drive);
  3699. +    reschedule_timeout(drive, "lock fdc", 0);
  3700. +    return 0;
  3701. +}
  3702. +
  3703. +#define LOCK_FDC(drive,interruptible) \
  3704. +if(lock_fdc(drive,interruptible)) return -EINTR;
  3705. +
  3706. +
  3707. +/* unlocks the driver */
  3708. +static inline void unlock_fdc(void)
  3709. +{
  3710. +    raw_cmd = NULL;
  3711. +    if (!fdc_busy)
  3712. +        DPRINT("FDC access conflict!\n");
  3713. +
  3714. +    if ( DEVICE_INTR )
  3715. +        DPRINT1("device interrupt still active at FDC release: %p!\n",
  3716. +            DEVICE_INTR);
  3717. +    command_status = FD_COMMAND_NONE;
  3718. +    del_timer(&fd_timeout);
  3719. +    cont = NULL;
  3720. +    fdc_busy = 0;
  3721. +    floppy_release_irq_and_dma();
  3722. +    wake_up(&fdc_wait);
  3723. +}
  3724. +
  3725. +/* switches the motor off after a given timeout */
  3726. +static void motor_off_callback(unsigned long nr)
  3727. +{
  3728. +    unsigned char mask = ~(0x10 << UNIT(nr));
  3729. +
  3730. +    set_dor( FDC(nr), mask, 0 );
  3731. +}
  3732. +
  3733. +static struct timer_list motor_off_timer[N_DRIVE] = {
  3734. +    { NULL, NULL, 0, 0, motor_off_callback },
  3735. +    { NULL, NULL, 0, 1, motor_off_callback },
  3736. +    { NULL, NULL, 0, 2, motor_off_callback },
  3737. +    { NULL, NULL, 0, 3, motor_off_callback },
  3738. +    { NULL, NULL, 0, 4, motor_off_callback },
  3739. +    { NULL, NULL, 0, 5, motor_off_callback },
  3740. +    { NULL, NULL, 0, 6, motor_off_callback },
  3741. +    { NULL, NULL, 0, 7, motor_off_callback }
  3742. +};
  3743. +
  3744. +/* schedules motor off */
  3745. +static void floppy_off(unsigned int drive)
  3746. +{
  3747. +    unsigned long volatile delta;
  3748. +    register int fdc=FDC(drive);
  3749. +
  3750. +    if( !(FDCS->dor & ( 0x10 << UNIT(drive))))
  3751. +        return;
  3752. +
  3753. +    del_timer(motor_off_timer+drive);
  3754. +
  3755. +    /* make spindle stop in a position which minimizes spinup time
  3756. +     * next time */
  3757. +    if ( UDP->rps ){
  3758. +        delta = jiffies - UDRS->first_read_date + HZ -
  3759. +            UDP->spindown_offset;
  3760. +        delta = (( delta * UDP->rps) % HZ ) / UDP->rps;
  3761. +        motor_off_timer[drive].expires = jiffies + UDP->spindown - delta;
  3762. +    }
  3763. +    add_timer(motor_off_timer+drive);
  3764. +}
  3765. +
  3766. +/*
  3767. + * cycle through all N_DRIVE floppy drives, for disk change testing.
  3768. + * stopping at current drive. This is done before any long operation, to
  3769. + * be sure to have up to date disk change information.
  3770. + */
  3771. +static void scandrives(void)
  3772. +{
  3773. +    int i, drive, saved_drive;
  3774. +
  3775. +    if (DP->select_delay)
  3776. +        return;
  3777. +
  3778. +    saved_drive = current_drive;
  3779. +    for(i=0; i< N_DRIVE; i++){
  3780. +        drive = (saved_drive + i + 1 ) % N_DRIVE;
  3781. +        if ( UDRS->fd_ref == 0 || UDP->select_delay != 0)
  3782. +            continue; /* skip closed drives */
  3783. +        set_fdc(drive);
  3784. +        if(! (set_dor( fdc, ~3, UNIT(drive) | ( 0x10 << UNIT(drive))) &
  3785. +              (0x10 << UNIT(drive))))
  3786. +            /* switch the motor off again, if it was off to
  3787. +             * begin with */
  3788. +            set_dor( fdc, ~( 0x10 << UNIT(drive) ), 0 );
  3789. +    }
  3790. +    set_fdc(saved_drive);
  3791. +}
  3792. +
  3793. +static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 };
  3794. +
  3795. +/* this function makes sure that the disk stays in the drive during the
  3796. + * transfer */
  3797. +static void fd_watchdog(void)
  3798. +{
  3799. +#ifdef DCL_DEBUG
  3800. +    if (DP->flags & FD_DEBUG){
  3801. +        DPRINT("calling disk change from watchdog\n");
  3802. +    }
  3803. +#endif
  3804. +
  3805. +    if ( disk_change(current_drive) ){
  3806. +        DPRINT("disk removed during i/o\n");
  3807. +        floppy_shutdown();
  3808. +    } else {
  3809. +        del_timer(&fd_timer);
  3810. +        fd_timer.function = (timeout_fn) fd_watchdog;
  3811. +        fd_timer.expires = jiffies + HZ / 10;
  3812. +        add_timer(&fd_timer);
  3813. +    }
  3814. +}
  3815. +
  3816. +static void main_command_interrupt(void)
  3817. +{
  3818. +    del_timer(&fd_timer);
  3819. +    cont->interrupt();
  3820. +}
  3821. +
  3822. +/* waits for a delay (spinup or select) to pass */
  3823. +static int wait_for_completion(int delay, timeout_fn function)
  3824. +{
  3825. +    if ( FDCS->reset ){
  3826. +        reset_fdc(); /* do the reset during sleep to win time
  3827. +                  * if we don't need to sleep, it's a good
  3828. +                  * occasion anyways */
  3829. +        return 1;
  3830. +    }
  3831. +
  3832. +    if ( jiffies < delay ){
  3833. +        del_timer(&fd_timer);
  3834. +        fd_timer.function = function;
  3835. +        fd_timer.expires = delay;
  3836. +        add_timer(&fd_timer);
  3837. +        return 1;
  3838. +    }
  3839. +    return 0;
  3840. +}
  3841. +
  3842. +static int hlt_disabled=0;
  3843. +static void floppy_disable_hlt(void)
  3844. +{
  3845. +    unsigned long flags;
  3846. +    save_flags(flags);
  3847. +    cli();
  3848. +    if(!hlt_disabled){
  3849. +        hlt_disabled=1;
  3850. +#ifdef HAVE_DISABLE_HLT
  3851. +        disable_hlt();
  3852. +#endif
  3853. +    }
  3854. +    restore_flags(flags);
  3855. +}
  3856. +
  3857. +static void floppy_enable_hlt(void)
  3858. +{
  3859. +    unsigned long flags;
  3860. +    save_flags(flags);
  3861. +    cli();
  3862. +    if(hlt_disabled){
  3863. +        hlt_disabled=0;
  3864. +#ifdef HAVE_DISABLE_HLT
  3865. +        enable_hlt();
  3866. +#endif
  3867. +    }
  3868. +    restore_flags(flags);
  3869. +}
  3870. +
  3871. +
  3872. +static void setup_DMA(void)
  3873. +{
  3874. +#ifdef CONFIG_FLOPPY_SANITY
  3875. +    if (raw_cmd->length == 0){
  3876. +        int i;
  3877. +
  3878. +        printk("zero dma transfer size:");
  3879. +        for(i=0; i< raw_cmd->cmd_count; i++)
  3880. +            printk("%x,", raw_cmd->cmd[i]);
  3881. +        printk("\n");
  3882. +        cont->done(0);
  3883. +        FDCS->reset = 1;
  3884. +        return;
  3885. +    }
  3886. +#if 0
  3887. +    /* disabled because of new buffer location for raw cmd */
  3888. +    if ((!CURRENT ||
  3889. +         CURRENT->buffer != raw_cmd->kernel_data ||
  3890. +         raw_cmd->length > 512 * CURRENT->nr_sectors) &&
  3891. +        (raw_cmd->kernel_data < floppy_track_buffer ||
  3892. +         raw_cmd->kernel_data + raw_cmd->length >
  3893. +         floppy_track_buffer + 1024 * max_buffer_sectors)){
  3894. +        printk("bad address. start=%p lg=%lx tb=%p\n",
  3895. +               raw_cmd->kernel_data, raw_cmd->length,
  3896. +               floppy_track_buffer);
  3897. +        if ( CURRENT ){
  3898. +            printk("buffer=%p nr=%lx cnr=%lx\n",
  3899. +                   CURRENT->buffer, CURRENT->nr_sectors,
  3900. +                   CURRENT->current_nr_sectors);
  3901. +        }
  3902. +        cont->done(0);
  3903. +        FDCS->reset=1;
  3904. +        return;
  3905. +    }
  3906. +    if ((long) raw_cmd->kernel_data % 512 ){
  3907. +        printk("non aligned address: %p\n", raw_cmd->kernel_data );
  3908. +        cont->done(0);
  3909. +        FDCS->reset=1;
  3910. +        return;
  3911. +    }
  3912. +    if (CROSS_64KB(raw_cmd->kernel_data, raw_cmd->length)) {
  3913. +        printk("DMA crossing 64-K boundary %p-%p\n",
  3914. +               raw_cmd->kernel_data,
  3915. +               raw_cmd->kernel_data + raw_cmd->length);
  3916. +        cont->done(0);
  3917. +        FDCS->reset=1;
  3918. +        return;
  3919. +    }
  3920. +#endif
  3921. +#endif
  3922. +    cli();
  3923. +    disable_dma(FLOPPY_DMA);
  3924. +    clear_dma_ff(FLOPPY_DMA);
  3925. +    set_dma_mode(FLOPPY_DMA,
  3926. +             (raw_cmd->flags & FD_RAW_READ)?
  3927. +             DMA_MODE_READ : DMA_MODE_WRITE);
  3928. +    set_dma_addr(FLOPPY_DMA, virt_to_bus(raw_cmd->kernel_data));
  3929. +    set_dma_count(FLOPPY_DMA, raw_cmd->length);
  3930. +    enable_dma(FLOPPY_DMA);
  3931. +    sti();
  3932. +    floppy_disable_hlt();
  3933. +}
  3934. +
  3935. +/* sends a command byte to the fdc */
  3936. +static int output_byte(char byte)
  3937. +{
  3938. +    int counter;
  3939. +    unsigned char status=0;
  3940. +    unsigned char rstatus;
  3941. +
  3942. +    if (FDCS->reset)
  3943. +        return -1;
  3944. +    for(counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
  3945. +        rstatus = inb_p(FD_STATUS);
  3946. +        status = rstatus &(STATUS_READY|STATUS_DIR|STATUS_DMA);
  3947. +        if (!(status & STATUS_READY))
  3948. +            continue;
  3949. +        if (status == STATUS_READY){
  3950. +            outb_p(byte,FD_DATA);
  3951. +
  3952. +#ifdef CONFIG_FLOPPY_SANITY
  3953. +            output_log[output_log_pos].data = byte;
  3954. +            output_log[output_log_pos].status = rstatus;
  3955. +            output_log[output_log_pos].jiffies = jiffies;
  3956. +            output_log_pos = (output_log_pos + 1) % OLOGSIZE;
  3957. +#endif
  3958. +            return 0;
  3959. +        } else
  3960. +            break;
  3961. +    }
  3962. +    FDCS->reset = 1;
  3963. +    if ( !initialising )
  3964. +        DPRINT2("Unable to send byte %x to FDC. Status=%x\n",
  3965. +            byte, status);
  3966. +    return -1;
  3967. +}
  3968. +#define LAST_OUT(x) if(output_byte(x)){ reset_fdc();return;}
  3969. +
  3970. +/* gets the response from the fdc */
  3971. +static int result(void)
  3972. +{
  3973. +    int i = 0, counter, status = 0;
  3974. +
  3975. +    if (FDCS->reset)
  3976. +        return -1;
  3977. +    for (counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
  3978. +        status = inb_p(FD_STATUS)&
  3979. +            (STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA);
  3980. +        if (!(status & STATUS_READY))
  3981. +            continue;
  3982. +        if (status == STATUS_READY){
  3983. +#ifdef CONFIG_FLOPPY_SANITY
  3984. +            resultjiffies = jiffies;
  3985. +            resultsize = i;
  3986. +#endif
  3987. +            return i;
  3988. +        }
  3989. +        if (status & STATUS_DMA )
  3990. +            break;
  3991. +        if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
  3992. +            if (i >= MAX_REPLIES) {
  3993. +                DPRINT("floppy_stat reply overrun\n");
  3994. +                break;
  3995. +            }
  3996. +            reply_buffer[i++] = inb_p(FD_DATA);
  3997. +        }
  3998. +    }
  3999. +    FDCS->reset = 1;
  4000. +    if ( !initialising )
  4001. +        DPRINT3("Getstatus times out (%x) on fdc %d [%d]\n",
  4002. +            status, fdc, i);
  4003. +    return -1;
  4004. +}
  4005. +
  4006. +/* Set perpendicular mode as required, based on data rate, if supported.
  4007. + * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
  4008. + */
  4009. +static inline void perpendicular_mode(void)
  4010. +{
  4011. +    unsigned char perp_mode;
  4012. +
  4013. +    if (!floppy)
  4014. +        return;
  4015. +    if (floppy->rate & 0x40){
  4016. +        switch(raw_cmd->rate){
  4017. +            case 0:
  4018. +                perp_mode=2;
  4019. +                break;
  4020. +            case 3:
  4021. +                perp_mode=3;
  4022. +                break;
  4023. +            default:
  4024. +                DPRINT("Invalid data rate for perpendicular mode!\n");
  4025. +                cont->done(0);
  4026. +                FDCS->reset = 1; /* convenient way to return to
  4027. +                          * redo without to much hassle (deep
  4028. +                          * stack et al. */
  4029. +                return;
  4030. +        }
  4031. +    } else
  4032. +        perp_mode = 0;
  4033. +
  4034. +    if ( FDCS->perp_mode == perp_mode )
  4035. +        return;
  4036. +    if (FDCS->version >= FDC_82077_ORIG && FDCS->has_fifo) {
  4037. +        output_byte(FD_PERPENDICULAR);
  4038. +        output_byte(perp_mode);
  4039. +        FDCS->perp_mode = perp_mode;
  4040. +    } else if (perp_mode) {
  4041. +        DPRINT("perpendicular mode not supported by this FDC.\n");
  4042. +    }
  4043. +} /* perpendicular_mode */
  4044. +
  4045. +#define NOMINAL_DTR 500
  4046. +
  4047. +/* Issue a "SPECIFY" command to set the step rate time, head unload time,
  4048. + * head load time, and DMA disable flag to values needed by floppy.
  4049. + *
  4050. + * The value "dtr" is the data transfer rate in Kbps.  It is needed
  4051. + * to account for the data rate-based scaling done by the 82072 and 82077
  4052. + * FDC types.  This parameter is ignored for other types of FDCs (i.e.
  4053. + * 8272a).
  4054. + *
  4055. + * Note that changing the data transfer rate has a (probably deleterious)
  4056. + * effect on the parameters subject to scaling for 82072/82077 FDCs, so
  4057. + * fdc_specify is called again after each data transfer rate
  4058. + * change.
  4059. + *
  4060. + * srt: 1000 to 16000 in microseconds
  4061. + * hut: 16 to 240 milliseconds
  4062. + * hlt: 2 to 254 milliseconds
  4063. + *
  4064. + * These values are rounded up to the next highest available delay time.
  4065. + */
  4066. +static void fdc_specify(void)
  4067. +{
  4068. +    unsigned char spec1, spec2;
  4069. +    int srt, hlt, hut;
  4070. +    unsigned long dtr = NOMINAL_DTR;
  4071. +    unsigned long scale_dtr = NOMINAL_DTR;
  4072. +    int hlt_max_code = 0x7f;
  4073. +    int hut_max_code = 0xf;
  4074. +
  4075. +    if (FDCS->need_configure && FDCS->has_fifo) {
  4076. +        if ( FDCS->reset )
  4077. +            return;
  4078. +        /* Turn on FIFO for 82077-class FDC (improves performance) */
  4079. +        /* TODO: lock this in via LOCK during initialization */
  4080. +        output_byte(FD_CONFIGURE);
  4081. +        output_byte(0);
  4082. +        output_byte(0x2A);    /* FIFO on, polling off, 10 byte threshold */
  4083. +        output_byte(0);        /* precompensation from track 0 upwards */
  4084. +        if ( FDCS->reset ){
  4085. +            FDCS->has_fifo=0;
  4086. +            return;
  4087. +        }
  4088. +        FDCS->need_configure = 0;
  4089. +        /*DPRINT("FIFO enabled\n");*/
  4090. +    }
  4091. +
  4092. +    switch (raw_cmd->rate & 0x03) {
  4093. +        case 3:
  4094. +            dtr = 1000;
  4095. +            break;
  4096. +        case 1:
  4097. +            dtr = 300;
  4098. +            break;
  4099. +        case 2:
  4100. +            dtr = 250;
  4101. +            break;
  4102. +    }
  4103. +
  4104. +    if (FDCS->version >= FDC_82072) {
  4105. +        scale_dtr = dtr;
  4106. +        hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
  4107. +        hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
  4108. +    }
  4109. +
  4110. +    /* Convert step rate from microseconds to milliseconds and 4 bits */
  4111. +    srt = 16 - (DP->srt*scale_dtr/1000 + NOMINAL_DTR - 1)/NOMINAL_DTR;
  4112. +    if (srt > 0xf)
  4113. +        srt = 0xf;
  4114. +    else if (srt < 0)
  4115. +        srt = 0;
  4116. +
  4117. +    hlt = (DP->hlt*scale_dtr/2 + NOMINAL_DTR - 1)/NOMINAL_DTR;
  4118. +    if (hlt < 0x01)
  4119. +        hlt = 0x01;
  4120. +    else if (hlt > 0x7f)
  4121. +        hlt = hlt_max_code;
  4122. +
  4123. +    hut = (DP->hut*scale_dtr/16 + NOMINAL_DTR - 1)/NOMINAL_DTR;
  4124. +    if (hut < 0x1)
  4125. +        hut = 0x1;
  4126. +    else if (hut > 0xf)
  4127. +        hut = hut_max_code;
  4128. +
  4129. +    spec1 = (srt << 4) | hut;
  4130. +    spec2 = (hlt << 1);
  4131. +
  4132. +    /* If these parameters did not change, just return with success */
  4133. +    if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
  4134. +        /* Go ahead and set spec1 and spec2 */
  4135. +        output_byte(FD_SPECIFY);
  4136. +        output_byte(FDCS->spec1 = spec1);
  4137. +        output_byte(FDCS->spec2 = spec2);
  4138. +    }
  4139. +} /* fdc_specify */
  4140. +
  4141. +/* Set the FDC's data transfer rate on behalf of the specified drive.
  4142. + * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
  4143. + * of the specify command (i.e. using the fdc_specify function).
  4144. + */
  4145. +static int fdc_dtr(void)
  4146. +{
  4147. +    /* If data rate not already set to desired value, set it. */
  4148. +    if ( raw_cmd->rate == FDCS->dtr)
  4149. +        return 0;
  4150. +
  4151. +    /* Set dtr */
  4152. +    outb_p(raw_cmd->rate, FD_DCR);
  4153. +
  4154. +    /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
  4155. +     * need a stabilization period of several milliseconds to be
  4156. +     * enforced after data rate changes before R/W operations.
  4157. +     * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
  4158. +     */
  4159. +    FDCS->dtr = raw_cmd->rate;
  4160. +    return(wait_for_completion(jiffies+2*HZ/100,
  4161. +                   (timeout_fn) floppy_ready));
  4162. +} /* fdc_dtr */
  4163. +
  4164. +static void tell_sector(void)
  4165. +{
  4166. +    printk(": track %d, head %d, sector %d, size %d",
  4167. +           R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
  4168. +} /* tell_sector */
  4169. +
  4170. +
  4171. +/*
  4172. + * Ok, this error interpreting routine is called after a
  4173. + * DMA read/write has succeeded
  4174. + * or failed, so we check the results, and copy any buffers.
  4175. + * hhb: Added better error reporting.
  4176. + * ak: Made this into a separate routine.
  4177. + */
  4178. +static int interpret_errors(void)
  4179. +{
  4180. +    char bad;
  4181. +int res = get_dma_residue(FLOPPY_DMA);
  4182. +if(res) {printk("\n-- DMA residue (%d)",res); tell_sector(); printk("\n");}
  4183. +    if (inr!=7) {
  4184. +        DPRINT("-- FDC reply error");
  4185. +        FDCS->reset = 1;
  4186. +        return 1;
  4187. +    }
  4188. +
  4189. +    /* check IC to find cause of interrupt */
  4190. +    switch (ST0 & ST0_INTR) {
  4191. +        case 0x40:    /* error occurred during command execution */
  4192. +            bad = 1;
  4193. +            if (ST1 & ST1_WP) {
  4194. +                DPRINT("Drive is write protected\n");
  4195. +                CLEARF(FD_DISK_WRITABLE);
  4196. +                cont->done(0);
  4197. +                bad = 2;
  4198. +            } else if (ST1 & ST1_ND) {
  4199. +                SETF(FD_NEED_TWADDLE);
  4200. +            } else if (ST1 & ST1_OR) {
  4201. +                if (DP->flags & FTD_MSG )
  4202. +                    DPRINT("Over/Underrun - retrying\n");
  4203. +                bad = 0;
  4204. +            }else if(*errors >= DP->max_errors.reporting){
  4205. +                DPRINT("");
  4206. +                if (ST0 & ST0_ECE) {
  4207. +                    printk("Recalibrate failed!");
  4208. +                } else if (ST2 & ST2_CRC) {
  4209. +                    printk("data CRC error");
  4210. +                    tell_sector();
  4211. +                } else if (ST1 & ST1_CRC) {
  4212. +                    printk("CRC error");
  4213. +                    tell_sector();
  4214. +                } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) {
  4215. +                    if (!probing) {
  4216. +                        printk("sector not found");
  4217. +                        tell_sector();
  4218. +                    } else
  4219. +                        printk("probe failed...");
  4220. +                } else if (ST2 & ST2_WC) {    /* seek error */
  4221. +                    printk("wrong cylinder");
  4222. +                } else if (ST2 & ST2_BC) {    /* cylinder marked as bad */
  4223. +                    printk("bad cylinder");
  4224. +                } else {
  4225. +                    printk("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x", ST0, ST1, ST2);
  4226. +                    tell_sector();
  4227. +                }
  4228. +                printk("\n");
  4229. +
  4230. +            }
  4231. +            if ( ST2 & ST2_WC || ST2 & ST2_BC)
  4232. +                /* wrong cylinder => recal */
  4233. +                DRS->track = NEED_2_RECAL;
  4234. +            return bad;
  4235. +        case 0x80: /* invalid command given */
  4236. +            DPRINT("Invalid FDC command given!\n");
  4237. +            cont->done(0);
  4238. +            return 2;
  4239. +        case 0xc0:
  4240. +            DPRINT("Abnormal termination caused by polling\n");
  4241. +            cont->error();
  4242. +            return 2;
  4243. +        default: /* (0) Normal command termination */
  4244. +            return 0;
  4245. +    }
  4246. +}
  4247. +
  4248. +/*
  4249. + * This routine is called when everything should be correctly set up
  4250. + * for the transfer (ie floppy motor is on, the correct floppy is
  4251. + * selected, and the head is sitting on the right track).
  4252. + */
  4253. +static void setup_rw_floppy(void)
  4254. +{
  4255. +    int i,ready_date,r, flags,dflags;
  4256. +    timeout_fn function;
  4257. +
  4258. +    flags = raw_cmd->flags;
  4259. +    if ( flags & ( FD_RAW_READ | FD_RAW_WRITE))
  4260. +        flags |= FD_RAW_INTR;
  4261. +
  4262. +    if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)){
  4263. +        ready_date = DRS->spinup_date + DP->spinup;
  4264. +        /* If spinup will take a long time, rerun scandrives
  4265. +         * again just before spinup completion. Beware that
  4266. +         * after scandrives, we must again wait for selection.
  4267. +         */
  4268. +        if ( ready_date > jiffies + DP->select_delay){
  4269. +            ready_date -= DP->select_delay;
  4270. +            function = (timeout_fn) floppy_start;
  4271. +        } else
  4272. +            function = (timeout_fn) setup_rw_floppy;
  4273. +
  4274. +        /* wait until the floppy is spinning fast enough */
  4275. +        if (wait_for_completion(ready_date,function))
  4276. +            return;
  4277. +    }
  4278. +    dflags = DRS->flags;
  4279. +
  4280. +    if ( (flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
  4281. +        setup_DMA();
  4282. +
  4283. +    if ( flags & FD_RAW_INTR )
  4284. +        SET_INTR(main_command_interrupt);
  4285. +
  4286. +    r=0;
  4287. +    for(i=0; i< raw_cmd->cmd_count; i++)
  4288. +        r|=output_byte( raw_cmd->cmd[i] );
  4289. +
  4290. +#ifdef DEBUGT
  4291. +    debugt("rw_command: ");
  4292. +#endif
  4293. +    if ( r ){
  4294. +        reset_fdc();
  4295. +        return;
  4296. +    }
  4297. +
  4298. +    if ( ! ( flags & FD_RAW_INTR )){
  4299. +        inr = result();
  4300. +        cont->interrupt();
  4301. +    } else if ( flags & FD_RAW_NEED_DISK )
  4302. +        fd_watchdog();
  4303. +}
  4304. +
  4305. +static int blind_seek;
  4306. +
  4307. +/*
  4308. + * This is the routine called after every seek (or recalibrate) interrupt
  4309. + * from the floppy controller.
  4310. + */
  4311. +static void seek_interrupt(void)
  4312. +{
  4313. +#ifdef DEBUGT
  4314. +    debugt("seek interrupt:");
  4315. +#endif
  4316. +    if (inr != 2 || (ST0 & 0xF8) != 0x20 ) {
  4317. +        DPRINT("seek failed\n");
  4318. +        DRS->track = NEED_2_RECAL;
  4319. +        cont->error();
  4320. +        cont->redo();
  4321. +        return;
  4322. +    }
  4323. +    if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek){
  4324. +#ifdef DCL_DEBUG
  4325. +        if (DP->flags & FD_DEBUG){
  4326. +            DPRINT("clearing NEWCHANGE flag because of effective seek\n");
  4327. +            DPRINT1("jiffies=%ld\n", jiffies);
  4328. +        }
  4329. +#endif
  4330. +        CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
  4331. +        DRS->select_date = jiffies;
  4332. +    }
  4333. +    DRS->track = ST1;
  4334. +    floppy_ready();
  4335. +}
  4336. +
  4337. +static void check_wp(void)
  4338. +{
  4339. +    if (TESTF(FD_VERIFY)) {
  4340. +        /* check write protection */
  4341. +        output_byte( FD_GETSTATUS );
  4342. +        output_byte( UNIT(current_drive) );
  4343. +        if ( result() != 1 ){
  4344. +            FDCS->reset = 1;
  4345. +            return;
  4346. +        }
  4347. +        CLEARF(FD_VERIFY);
  4348. +        CLEARF(FD_NEED_TWADDLE);
  4349. +#ifdef DCL_DEBUG
  4350. +        if (DP->flags & FD_DEBUG){
  4351. +            DPRINT("checking whether disk is write protected\n");
  4352. +            DPRINT1("wp=%x\n",ST3 & 0x40);
  4353. +        }
  4354. +#endif
  4355. +        if (!( ST3  & 0x40))
  4356. +            SETF(FD_DISK_WRITABLE);
  4357. +        else
  4358. +            CLEARF(FD_DISK_WRITABLE);
  4359. +    }
  4360. +}
  4361. +
  4362. +static void seek_floppy(void)
  4363. +{
  4364. +    int track;
  4365. +
  4366. +    blind_seek=0;
  4367. +
  4368. +#ifdef DCL_DEBUG
  4369. +    if (DP->flags & FD_DEBUG){
  4370. +        DPRINT("calling disk change from seek\n");
  4371. +    }
  4372. +#endif
  4373. +
  4374. +    if (!TESTF(FD_DISK_NEWCHANGE) &&
  4375. +        disk_change(current_drive) &&
  4376. +        (raw_cmd->flags & FD_RAW_NEED_DISK)){
  4377. +        /* the media changed flag should be cleared after the seek.
  4378. +         * If it isn't, this means that there is really no disk in
  4379. +         * the drive.
  4380. +         */
  4381. +        SETF(FD_DISK_CHANGED);
  4382. +        cont->done(0);
  4383. +        cont->redo();
  4384. +        return;
  4385. +    }
  4386. +    if ( DRS->track <= NEED_1_RECAL ){
  4387. +        recalibrate_floppy();
  4388. +        return;
  4389. +    } else if (TESTF(FD_DISK_NEWCHANGE) &&
  4390. +           (raw_cmd->flags & FD_RAW_NEED_DISK) &&
  4391. +           (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
  4392. +        /* we seek to clear the media-changed condition. Does anybody
  4393. +         * know a more elegant way, which works on all drives? */
  4394. +        if ( raw_cmd->track )
  4395. +            track = raw_cmd->track - 1;
  4396. +        else {
  4397. +            if(DP->flags & FD_SILENT_DCL_CLEAR){
  4398. +                set_dor(fdc, ~ (0x10 << UNIT(current_drive)), 0);
  4399. +                blind_seek = 1;
  4400. +                raw_cmd->flags |= FD_RAW_NEED_SEEK;
  4401. +            }
  4402. +            track = 1;
  4403. +        }
  4404. +    } else {
  4405. +        check_wp();
  4406. +        if (raw_cmd->track != DRS->track &&
  4407. +            (raw_cmd->flags & FD_RAW_NEED_SEEK))
  4408. +            track = raw_cmd->track;
  4409. +        else {
  4410. +            setup_rw_floppy();
  4411. +            return;
  4412. +        }
  4413. +    }
  4414. +
  4415. +    SET_INTR(seek_interrupt);
  4416. +    output_byte(FD_SEEK);
  4417. +    output_byte(UNIT(current_drive));
  4418. +    LAST_OUT(track);
  4419. +#ifdef DEBUGT
  4420. +    debugt("seek command:");
  4421. +#endif
  4422. +}
  4423. +
  4424. +static void recal_interrupt(void)
  4425. +{
  4426. +#ifdef DEBUGT
  4427. +    debugt("recal interrupt:");
  4428. +#endif
  4429. +    if (inr !=2 )
  4430. +        FDCS->reset = 1;
  4431. +    else if (ST0 & ST0_ECE) {
  4432. +               switch(DRS->track){
  4433. +                   case NEED_1_RECAL:
  4434. +#ifdef DEBUGT
  4435. +                debugt("recal interrupt need 1 recal:");
  4436. +#endif
  4437. +                /* after a second recalibrate, we still haven't
  4438. +                 * reached track 0. Probably no drive. Raise an
  4439. +                 * error, as failing immediately might upset
  4440. +                 * computers possessed by the Devil :-) */
  4441. +                cont->error();
  4442. +                cont->redo();
  4443. +                return;
  4444. +            case NEED_2_RECAL:
  4445. +#ifdef DEBUGT
  4446. +                debugt("recal interrupt need 2 recal:");
  4447. +#endif
  4448. +                /* If we already did a recalibrate,
  4449. +                 * and we are not at track 0, this
  4450. +                 * means we have moved. (The only way
  4451. +                 * not to move at recalibration is to
  4452. +                 * be already at track 0.) Clear the
  4453. +                 * new change flag */
  4454. +#ifdef DCL_DEBUG
  4455. +                if (DP->flags & FD_DEBUG){
  4456. +                    DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
  4457. +                }
  4458. +#endif
  4459. +
  4460. +                CLEARF(FD_DISK_NEWCHANGE);
  4461. +                DRS->select_date = jiffies;
  4462. +                /* fall through */
  4463. +            default:
  4464. +#ifdef DEBUGT
  4465. +                debugt("recal interrupt default:");
  4466. +#endif
  4467. +                /* Recalibrate moves the head by at
  4468. +                 * most 80 steps. If after one
  4469. +                 * recalibrate we don't have reached
  4470. +                 * track 0, this might mean that we
  4471. +                 * started beyond track 80.  Try
  4472. +                 * again.  */
  4473. +                DRS->track = NEED_1_RECAL;
  4474. +                break;
  4475. +        }
  4476. +    } else
  4477. +        DRS->track = ST1;
  4478. +    floppy_ready();
  4479. +}
  4480. +
  4481. +/*
  4482. + * Unexpected interrupt - Print as much debugging info as we can...
  4483. + * All bets are off...
  4484. + */
  4485. +static void unexpected_floppy_interrupt(void)
  4486. +{
  4487. +    int i;
  4488. +    if ( initialising )
  4489. +        return;
  4490. +    if(print_unex){
  4491. +        DPRINT("unexpected interrupt\n");
  4492. +        if ( inr >= 0 )
  4493. +            for(i=0; i<inr; i++)
  4494. +                printk("%d %x\n", i, reply_buffer[i] );
  4495. +    }
  4496. +    while(1){
  4497. +        output_byte(FD_SENSEI);
  4498. +        inr=result();
  4499. +        if ( inr != 2 )
  4500. +            break;
  4501. +        if(print_unex){
  4502. +            printk("sensei\n");
  4503. +            for(i=0; i<inr; i++)
  4504. +                printk("%d %x\n", i, reply_buffer[i] );
  4505. +        }
  4506. +    }
  4507. +    FDCS->reset = 1;
  4508. +}
  4509. +
  4510. +struct tq_struct floppy_tq =
  4511. +{ 0, 0, (void *) (void *) unexpected_floppy_interrupt, 0 };
  4512. +
  4513. +/* interrupt handler */
  4514. +static void floppy_interrupt(int irq, struct pt_regs *regs)
  4515. +{
  4516. +    void (*handler)(void) = DEVICE_INTR;
  4517. +
  4518. +    lasthandler = handler;
  4519. +    interruptjiffies = jiffies;
  4520. +
  4521. +    floppy_enable_hlt();
  4522. +    CLEAR_INTR;
  4523. +    if ( fdc >= N_FDC || FDCS->address == -1){
  4524. +        /* we don't even know which FDC is the culprit */
  4525. +        printk("DOR0=%x\n", fdc_state[0].dor);
  4526. +        printk("floppy interrupt on bizarre fdc %d\n",fdc);
  4527. +        printk("handler=%p\n", handler);
  4528. +        is_alive("bizarre fdc");
  4529. +        return;
  4530. +    }
  4531. +    inr = result();
  4532. +    if (!handler){
  4533. +        unexpected_floppy_interrupt();
  4534. +        is_alive("unexpected");
  4535. +        return;
  4536. +    }
  4537. +    if ( inr == 0 ){
  4538. +        do {
  4539. +            output_byte(FD_SENSEI);
  4540. +            inr = result();
  4541. +        } while ( (ST0 & 0x83) != UNIT(current_drive) && inr == 2);
  4542. +    }
  4543. +    floppy_tq.routine = (void *)(void *) handler;
  4544. +    queue_task_irq(&floppy_tq, &tq_timer);
  4545. +    is_alive("normal interrupt end");
  4546. +}
  4547. +
  4548. +static void recalibrate_floppy(void)
  4549. +{
  4550. +#ifdef DEBUGT
  4551. +    debugt("recalibrate floppy:");
  4552. +#endif
  4553. +    SET_INTR(recal_interrupt);
  4554. +    output_byte(FD_RECALIBRATE);
  4555. +    LAST_OUT(UNIT(current_drive));
  4556. +}
  4557. +
  4558. +/*
  4559. + * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
  4560. + */
  4561. +static void reset_interrupt(void)
  4562. +{
  4563. +#ifdef DEBUGT
  4564. +    debugt("reset interrupt:");
  4565. +#endif
  4566. +    /* fdc_specify();       reprogram fdc */
  4567. +    result();        /* get the status ready for set_fdc */
  4568. +    if ( FDCS->reset )
  4569. +        cont->error(); /* a reset just after a reset. BAD! */
  4570. +    cont->redo();
  4571. +}
  4572. +
  4573. +/*
  4574. + * reset is done by pulling bit 2 of DOR low for a while (old FDC's),
  4575. + * or by setting the self clearing bit 7 of STATUS (newer FDC's)
  4576. + */
  4577. +static void reset_fdc(void)
  4578. +{
  4579. +    SET_INTR(reset_interrupt);
  4580. +    FDCS->reset = 0;
  4581. +    reset_fdc_info(0);
  4582. +    if ( FDCS->version >= FDC_82077 )
  4583. +        outb_p(0x80 | ( FDCS->dtr &3), FD_STATUS);
  4584. +    else {
  4585. +        arm_set_dor(FDCS->dor & ~0x04);
  4586. +        udelay(FD_RESET_DELAY);
  4587. +        arm_set_dor(FDCS->dor);
  4588. +    }
  4589. +}
  4590. +
  4591. +static void empty(void)
  4592. +{
  4593. +}
  4594. +
  4595. +void show_floppy(void)
  4596. +{
  4597. +    int i;
  4598. +
  4599. +    printk("\n");
  4600. +    printk("floppy driver state\n");
  4601. +    printk("-------------------\n");
  4602. +    printk("now=%ld last interrupt=%d last called handler=%p\n",
  4603. +        jiffies, interruptjiffies, lasthandler);
  4604. +
  4605. +
  4606. +#ifdef CONFIG_FLOPPY_SANITY
  4607. +    printk("timeout_message=%s\n", timeout_message);
  4608. +    printk("last output bytes:\n");
  4609. +    for(i=0; i < OLOGSIZE; i++)
  4610. +        printk("%2x %2x %ld\n",
  4611. +            output_log[(i+output_log_pos) % OLOGSIZE].data,
  4612. +            output_log[(i+output_log_pos) % OLOGSIZE].status,
  4613. +            output_log[(i+output_log_pos) % OLOGSIZE].jiffies);
  4614. +    printk("last result at %d\n", resultjiffies);
  4615. +    printk("last redo_fd_request at %d\n", lastredo);
  4616. +    for(i=0; i<resultsize; i++){
  4617. +        printk("%2x ", reply_buffer[i]);
  4618. +    }
  4619. +    printk("\n");
  4620. +#endif
  4621. +
  4622. +#if 0
  4623. +    for(i=0; i<N_FDC; i++){
  4624. +        if(FDCS->address != -1){
  4625. +            printk("dor %d = %x\n", i, fdc_state[i].dor );
  4626. +            outb_p(fdc_state[i].address+2, fdc_state[i].dor);
  4627. +            udelay(1000); /* maybe we'll catch an interrupt... */
  4628. +        }
  4629. +    }
  4630. +#endif
  4631. +    printk("status=%x\n", inb_p(FD_STATUS));
  4632. +    printk("fdc_busy=%d\n", fdc_busy);
  4633. +    if( DEVICE_INTR)
  4634. +        printk("DEVICE_INTR=%p\n", DEVICE_INTR);
  4635. +    if(floppy_tq.sync)
  4636. +        printk("floppy_tq.routine=%p\n", floppy_tq.routine);
  4637. +    if(fd_timer.prev)
  4638. +        printk("fd_timer.function=%p\n", fd_timer.function);
  4639. +    if(fd_timeout.prev){
  4640. +        printk("timer_table=%p\n",fd_timeout.function);
  4641. +        printk("expires=%ld\n",fd_timeout.expires-jiffies);
  4642. +        printk("now=%ld\n",jiffies);
  4643. +    }
  4644. +    printk("cont=%p\n", cont);
  4645. +    printk("CURRENT=%p\n", CURRENT);
  4646. +    printk("command_status=%d\n", command_status);
  4647. +    printk("\n");
  4648. +}
  4649. +
  4650. +static void floppy_shutdown(void)
  4651. +{
  4652. +    if (!initialising)
  4653. +        show_floppy();
  4654. +    CLEAR_INTR;
  4655. +    floppy_tq.routine = (void *)(void *) empty;
  4656. +    del_timer( &fd_timer);
  4657. +    sti();
  4658. +
  4659. +    floppy_enable_hlt();
  4660. +    disable_dma(FLOPPY_DMA);
  4661. +    /* avoid dma going to a random drive after shutdown */
  4662. +    
  4663. +    if(!initialising)
  4664. +        DPRINT("floppy timeout\n");
  4665. +    FDCS->reset = 1;
  4666. +    if (cont){
  4667. +        cont->done(0);
  4668. +        cont->redo(); /* this will recall reset when needed */
  4669. +    } else {
  4670. +        printk("no cont in shutdown!\n");
  4671. +        process_fd_request();
  4672. +    }
  4673. +    is_alive("floppy shutdown");
  4674. +}
  4675. +/*typedef void (*timeout_fn)(unsigned long);*/
  4676. +
  4677. +/* start motor, check media-changed condition and write protection */
  4678. +static int start_motor( void (*function)(void)  )
  4679. +{
  4680. +    int mask, data;
  4681. +
  4682. +    mask = 0xfc;
  4683. +    data = UNIT(current_drive);
  4684. +    if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)){
  4685. +        if(!(FDCS->dor & ( 0x10 << UNIT(current_drive) ) )){
  4686. +            set_debugt();
  4687. +            /* no read since this drive is running */
  4688. +            DRS->first_read_date = 0;
  4689. +            /* note motor start time if motor is not yet running */
  4690. +            DRS->spinup_date = jiffies;
  4691. +            data |= (0x10 << UNIT(current_drive));
  4692. +        }
  4693. +    } else
  4694. +        if (FDCS->dor & ( 0x10 << UNIT(current_drive) ) )
  4695. +            mask &= ~(0x10 << UNIT(current_drive));
  4696. +
  4697. +    /* starts motor and selects floppy */
  4698. +    del_timer(motor_off_timer + current_drive);
  4699. +    set_dor( fdc, mask, data);
  4700. +
  4701. +    /* wait_for_completion also schedules reset if needed. */
  4702. +    return(wait_for_completion(DRS->select_date+DP->select_delay,
  4703. +                   (timeout_fn) function));
  4704. +}
  4705. +
  4706. +static void floppy_ready(void)
  4707. +{
  4708. +    CHECK_RESET;
  4709. +    if(start_motor(floppy_ready)) return;
  4710. +    if(fdc_dtr()) return;
  4711. +
  4712. +#ifdef DCL_DEBUG
  4713. +    if (DP->flags & FD_DEBUG){
  4714. +        DPRINT("calling disk change from floppy_ready\n");
  4715. +    }
  4716. +#endif
  4717. +
  4718. +    if(!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
  4719. +       disk_change(current_drive) &&
  4720. +       !DP->select_delay)
  4721. +           twaddle(); /* this clears the dcl on certain drive/controller
  4722. +                   * combinations */
  4723. +
  4724. +    if ( raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){
  4725. +        perpendicular_mode();
  4726. +        fdc_specify(); /* must be done here because of hut, hlt ... */
  4727. +        seek_floppy();
  4728. +    } else
  4729. +        setup_rw_floppy();
  4730. +}
  4731. +
  4732. +static void floppy_start(void)
  4733. +{
  4734. +    reschedule_timeout(CURRENTD, "floppy start", 0);
  4735. +
  4736. +    scandrives();
  4737. +#ifdef DCL_DEBUG
  4738. +    if (DP->flags & FD_DEBUG){
  4739. +        DPRINT("setting NEWCHANGE in floppy_start\n");
  4740. +    }
  4741. +#endif
  4742. +    SETF(FD_DISK_NEWCHANGE);
  4743. +    floppy_ready();
  4744. +}
  4745. +
  4746. +/*
  4747. + * ========================================================================
  4748. + * here ends the bottom half. Exported routines are:
  4749. + * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
  4750. + * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
  4751. + * Initialisation also uses output_byte, result, set_dor, floppy_interrupt
  4752. + * and set_dor.
  4753. + * ========================================================================
  4754. + */
  4755. +/*
  4756. + * General purpose continuations.
  4757. + * ==============================
  4758. + */
  4759. +
  4760. +static void do_wakeup(void)
  4761. +{
  4762. +    reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
  4763. +    cont = 0;
  4764. +    command_status += 2;
  4765. +    wake_up(&command_done);
  4766. +}
  4767. +
  4768. +static struct cont_t wakeup_cont={
  4769. +    empty,
  4770. +    do_wakeup,
  4771. +    empty,
  4772. +    (done_f)empty
  4773. +};
  4774. +
  4775. +static int wait_til_done( void (*handler)(void ), int interruptible )
  4776. +{
  4777. +    int ret;
  4778. +
  4779. +    floppy_tq.routine = (void *)(void *) handler;
  4780. +    queue_task(&floppy_tq, &tq_timer);
  4781. +
  4782. +    cli();
  4783. +    while(command_status < 2 && NO_SIGNAL){
  4784. +        is_alive("wait_til_done");
  4785. +        if (interruptible)
  4786. +            interruptible_sleep_on(&command_done);
  4787. +        else
  4788. +            sleep_on(&command_done);
  4789. +    }
  4790. +    if(command_status < 2){
  4791. +        floppy_shutdown();
  4792. +        sti();
  4793. +        process_fd_request();
  4794. +        return -EINTR;
  4795. +    }
  4796. +    sti();
  4797. +
  4798. +    if ( FDCS->reset )
  4799. +        command_status = FD_COMMAND_ERROR;
  4800. +    if ( command_status == FD_COMMAND_OKAY )
  4801. +        ret=0;
  4802. +    else
  4803. +        ret=-EIO;
  4804. +    command_status = FD_COMMAND_NONE;
  4805. +    return ret;
  4806. +}
  4807. +
  4808. +static void generic_done(int result)
  4809. +{
  4810. +    command_status = result;
  4811. +    cont = &wakeup_cont;
  4812. +}
  4813. +
  4814. +static void generic_success(void)
  4815. +{
  4816. +    cont->done(1);
  4817. +}
  4818. +
  4819. +static void generic_failure(void)
  4820. +{
  4821. +    cont->done(0);
  4822. +}
  4823. +
  4824. +static void success_and_wakeup(void)
  4825. +{
  4826. +    generic_success();
  4827. +    cont->redo();
  4828. +}
  4829. +
  4830. +
  4831. +/*
  4832. + * formatting and rw support.
  4833. + * ==========================
  4834. + */
  4835. +
  4836. +static int next_valid_format(void)
  4837. +{
  4838. +    int probed_format;
  4839. +
  4840. +    probed_format = DRS->probed_format;
  4841. +    while(1){
  4842. +        if ( probed_format >= 8 ||
  4843. +            ! DP->autodetect[probed_format] ){
  4844. +            DRS->probed_format = 0;
  4845. +            return 1;
  4846. +        }
  4847. +        if ( floppy_type[DP->autodetect[probed_format]].sect ){
  4848. +            DRS->probed_format = probed_format;
  4849. +            return 0;
  4850. +        }
  4851. +        probed_format++;
  4852. +    }
  4853. +}
  4854. +
  4855. +static void bad_flp_intr(void)
  4856. +{
  4857. +    if ( probing ){
  4858. +        DRS->probed_format++;
  4859. +        if ( !next_valid_format())
  4860. +            return;
  4861. +    }
  4862. +    (*errors)++;
  4863. +    if (*errors > DRWE->badness)
  4864. +            DRWE->badness = *errors;
  4865. +    if (*errors > DP->max_errors.abort)
  4866. +        cont->done(0);
  4867. +    if (*errors > DP->max_errors.reset)
  4868. +        FDCS->reset = 1;
  4869. +    else if (*errors > DP->max_errors.recal)
  4870. +        DRS->track = NEED_2_RECAL;
  4871. +}
  4872. +
  4873. +static void set_floppy(kdev_t device)
  4874. +{
  4875. +    if (TYPE(device))
  4876. +        floppy = TYPE(device) + floppy_type;
  4877. +    else
  4878. +        floppy = current_type[ DRIVE(device) ];
  4879. +}
  4880. +
  4881. +/*
  4882. + * formatting and support.
  4883. + * =======================
  4884. + */
  4885. +static void format_interrupt(void)
  4886. +{
  4887. +    switch (interpret_errors()){
  4888. +        case 1:
  4889. +            cont->error();
  4890. +        case 2:
  4891. +            break;
  4892. +        case 0:
  4893. +            cont->done(1);
  4894. +    }
  4895. +    cont->redo();
  4896. +}
  4897. +
  4898. +#define CODE2SIZE (ssize = ( ( 1 << SIZECODE ) + 3 ) >> 2)
  4899. +#define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80 ) >>1))
  4900. +#define CT(x) ( (x) | 0x40 )
  4901. +static void setup_format_params(int track)
  4902. +{
  4903. +    struct fparm {
  4904. +        unsigned char track,head,sect,size;
  4905. +    } *here = (struct fparm *)floppy_track_buffer;
  4906. +    int il,n;
  4907. +    int count,head_shift,track_shift;
  4908. +
  4909. +    raw_cmd = &default_raw_cmd;
  4910. +    raw_cmd->track = track;
  4911. +    
  4912. +    raw_cmd->flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
  4913. +        /*FD_RAW_NEED_DISK |*/ FD_RAW_NEED_SEEK;
  4914. +    raw_cmd->rate = floppy->rate & 0x3;
  4915. +    raw_cmd->cmd_count = NR_F;
  4916. +    COMMAND = FM_MODE(floppy,FD_FORMAT);
  4917. +    DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,format_req.head);
  4918. +    F_SIZECODE = FD_SIZECODE(floppy);
  4919. +    F_SECT_PER_TRACK = floppy->sect << 2 >> F_SIZECODE;
  4920. +    F_GAP = floppy->fmt_gap;
  4921. +    F_FILL = FD_FILL_BYTE;
  4922. +
  4923. +    raw_cmd->kernel_data = floppy_track_buffer;
  4924. +    raw_cmd->length = 4 * F_SECT_PER_TRACK;
  4925. +
  4926. +    /* allow for about 30ms for data transport per track */
  4927. +    head_shift  = (F_SECT_PER_TRACK + 5) / 6;
  4928. +
  4929. +    /* a ``cylinder'' is two tracks plus a little stepping time */
  4930. +    track_shift = 2 * head_shift + 3;
  4931. +
  4932. +    /* position of logical sector 1 on this track */
  4933. +    n = (track_shift * format_req.track + head_shift * format_req.head )
  4934. +        % F_SECT_PER_TRACK;
  4935. +
  4936. +    /* determine interleave */
  4937. +    il = 1;
  4938. +    if (floppy->sect > DP->interleave_sect && F_SIZECODE == 2)
  4939. +        il++;
  4940. +
  4941. +    /* initialize field */
  4942. +    for (count = 0; count < F_SECT_PER_TRACK; ++count) {
  4943. +        here[count].track = format_req.track;
  4944. +        here[count].head = format_req.head;
  4945. +        here[count].sect = 0;
  4946. +        here[count].size = F_SIZECODE;
  4947. +    }
  4948. +    /* place logical sectors */
  4949. +    for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
  4950. +        here[n].sect = count;
  4951. +        n = (n+il) % F_SECT_PER_TRACK;
  4952. +        if (here[n].sect) { /* sector busy, find next free sector */
  4953. +            ++n;
  4954. +            if (n>= F_SECT_PER_TRACK) {
  4955. +                n-=F_SECT_PER_TRACK;
  4956. +                while (here[n].sect) ++n;
  4957. +            }
  4958. +        }
  4959. +    }
  4960. +}
  4961. +
  4962. +static void redo_format(void)
  4963. +{
  4964. +    buffer_track = -1;
  4965. +    setup_format_params(format_req.track << STRETCH(floppy));
  4966. +    floppy_start();
  4967. +#ifdef DEBUGT
  4968. +    debugt("queue format request");
  4969. +#endif
  4970. +}
  4971. +
  4972. +static struct cont_t format_cont={
  4973. +    format_interrupt,
  4974. +    redo_format,
  4975. +    bad_flp_intr,
  4976. +    generic_done };
  4977. +
  4978. +static int do_format(kdev_t device, struct format_descr *tmp_format_req)
  4979. +{
  4980. +    int ret;
  4981. +    int drive=DRIVE(device);
  4982. +
  4983. +    LOCK_FDC(drive,1);
  4984. +    set_floppy(device);
  4985. +    if (!floppy ||
  4986. +        floppy->track > DP->tracks ||
  4987. +        tmp_format_req->track >= floppy->track ||
  4988. +        tmp_format_req->head >= floppy->head ||
  4989. +        (floppy->sect << 2) % (1 << FD_SIZECODE(floppy)) ||
  4990. +        !floppy->fmt_gap) {
  4991. +        process_fd_request();
  4992. +        return -EINVAL;
  4993. +    }
  4994. +    format_req = *tmp_format_req;
  4995. +    format_errors = 0;
  4996. +    cont = &format_cont;
  4997. +    errors = &format_errors;
  4998. +    IWAIT(redo_format);
  4999. +    process_fd_request();
  5000. +    return ret;
  5001. +}
  5002. +
  5003. +/*
  5004. + * Buffer read/write and support
  5005. + * =============================
  5006. + */
  5007. +
  5008. +/* new request_done. Can handle physical sectors which are smaller than a
  5009. + * logical buffer */
  5010. +static void request_done(int uptodate)
  5011. +{
  5012. +    int block;
  5013. +
  5014. +    probing = 0;
  5015. +    reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate);
  5016. +
  5017. +    if (!CURRENT){
  5018. +        DPRINT("request list destroyed in floppy request done\n");
  5019. +        return;
  5020. +    }
  5021. +    if (uptodate){
  5022. +        /* maintain values for invalidation on geometry
  5023. +         * change */
  5024. +        block = current_count_sectors + CURRENT->sector;
  5025. +        if (block > DRS->maxblock)
  5026. +            DRS->maxblock=block;
  5027. +        if ( block > floppy->sect)
  5028. +            DRS->maxtrack = 1;
  5029. +
  5030. +        /* unlock chained buffers */
  5031. +        while (current_count_sectors && CURRENT &&
  5032. +               current_count_sectors >= CURRENT->current_nr_sectors ){
  5033. +            current_count_sectors -= CURRENT->current_nr_sectors;
  5034. +            CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
  5035. +            CURRENT->sector += CURRENT->current_nr_sectors;
  5036. +            end_request(1);
  5037. +        }
  5038. +        if ( current_count_sectors && CURRENT){
  5039. +            /* "unlock" last subsector */
  5040. +            CURRENT->buffer += current_count_sectors <<9;
  5041. +            CURRENT->current_nr_sectors -= current_count_sectors;
  5042. +            CURRENT->nr_sectors -= current_count_sectors;
  5043. +            CURRENT->sector += current_count_sectors;
  5044. +            return;
  5045. +        }
  5046. +
  5047. +        if ( current_count_sectors && ! CURRENT )
  5048. +            DPRINT("request list destroyed in floppy request done\n");
  5049. +
  5050. +    } else {
  5051. +        if(CURRENT->cmd == WRITE) {
  5052. +            /* record write error information */
  5053. +            DRWE->write_errors++;
  5054. +            if(DRWE->write_errors == 1) {
  5055. +                DRWE->first_error_sector = CURRENT->sector;
  5056. +                DRWE->first_error_generation = DRS->generation;
  5057. +            }
  5058. +            DRWE->last_error_sector = CURRENT->sector;
  5059. +            DRWE->last_error_generation = DRS->generation;
  5060. +        }
  5061. +        end_request(0);
  5062. +    }
  5063. +}
  5064. +
  5065. +/* Interrupt handler evaluating the result of the r/w operation */
  5066. +static void rw_interrupt(void)
  5067. +{
  5068. +    int nr_sectors, ssize;
  5069. +
  5070. +    if ( ! DRS->first_read_date )
  5071. +        DRS->first_read_date = jiffies;
  5072. +
  5073. +    nr_sectors = 0;
  5074. +    CODE2SIZE;
  5075. +    nr_sectors = ((R_TRACK-TRACK)*floppy->head+R_HEAD-HEAD) *
  5076. +        floppy->sect + ((R_SECTOR-SECTOR) <<  SIZECODE >> 2) -
  5077. +        (sector_t % floppy->sect) % ssize;
  5078. +
  5079. +#ifdef CONFIG_FLOPPY_SANITY
  5080. +    if ( nr_sectors > current_count_sectors + ssize -
  5081. +         (current_count_sectors + sector_t) % ssize +
  5082. +         sector_t % ssize){
  5083. +        DPRINT2("long rw: %x instead of %lx\n",
  5084. +            nr_sectors, current_count_sectors);
  5085. +        printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
  5086. +        printk("rh=%d h=%d\n", R_HEAD, HEAD);
  5087. +        printk("rt=%d t=%d\n", R_TRACK, TRACK);
  5088. +        printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,
  5089. +               sector_t, ssize);
  5090. +    }
  5091. +#endif
  5092. +    if ( nr_sectors < 0 )
  5093. +        nr_sectors = 0;
  5094. +    if ( nr_sectors < current_count_sectors )
  5095. +        current_count_sectors = nr_sectors;
  5096. +
  5097. +    switch (interpret_errors()){
  5098. +        case 2:
  5099. +            cont->redo();
  5100. +            return;
  5101. +        case 1:
  5102. +            if (  !current_count_sectors){
  5103. +                cont->error();
  5104. +                cont->redo();
  5105. +                return;
  5106. +            }
  5107. +            break;
  5108. +        case 0:
  5109. +            if (  !current_count_sectors){
  5110. +                cont->redo();
  5111. +                return;
  5112. +            }
  5113. +            current_type[current_drive] = floppy;
  5114. +            floppy_sizes[TOMINOR(current_drive) ]= floppy->size>>1;
  5115. +            break;
  5116. +    }
  5117. +
  5118. +    if (probing) {
  5119. +        if (DP->flags & FTD_MSG)
  5120. +            DPRINT2("Auto-detected floppy type %s in fd%d\n",
  5121. +                floppy->name,current_drive);
  5122. +        current_type[current_drive] = floppy;
  5123. +        floppy_sizes[TOMINOR(current_drive)] = floppy->size >> 1;
  5124. +        probing = 0;
  5125. +    }
  5126. +
  5127. +    if ( CT(COMMAND) != FD_READ ||
  5128. +         raw_cmd->kernel_data == CURRENT->buffer ){
  5129. +        /* transfer directly from buffer */
  5130. +        cont->done(1);
  5131. +    } else if ( CT(COMMAND) == FD_READ){
  5132. +        buffer_track = raw_cmd->track;
  5133. +        buffer_drive = current_drive;
  5134. +        if ( nr_sectors + sector_t > buffer_max )
  5135. +            buffer_max = nr_sectors + sector_t;
  5136. +    }
  5137. +    cont->redo();
  5138. +}
  5139. +
  5140. +/* Compute maximal contiguous buffer size. */
  5141. +static int buffer_chain_size(void)
  5142. +{
  5143. +    struct buffer_head *bh;
  5144. +    int size;
  5145. +    char *base;
  5146. +
  5147. +    base = CURRENT->buffer;
  5148. +    size = CURRENT->current_nr_sectors << 9;
  5149. +    bh = CURRENT->bh;
  5150. +
  5151. +    if(bh){
  5152. +        bh = bh->b_reqnext;
  5153. +        while ( bh && bh->b_data == base + size ){
  5154. +            size += bh->b_size;
  5155. +            bh = bh->b_reqnext;
  5156. +        }
  5157. +    }
  5158. +    return size >> 9;
  5159. +}
  5160. +
  5161. +/* Compute the maximal transfer size */
  5162. +static int transfer_size(int ssize, int max_sector, int max_size)
  5163. +{
  5164. +    if ( max_sector > sector_t + max_size)
  5165. +        max_sector = sector_t + max_size;
  5166. +
  5167. +    /* alignment */
  5168. +    max_sector -= (max_sector % floppy->sect ) % ssize;
  5169. +
  5170. +    /* transfer size, beginning not aligned */
  5171. +    current_count_sectors = max_sector - sector_t ;
  5172. +
  5173. +    return max_sector;
  5174. +}
  5175. +
  5176. +/*
  5177. + * Move data from/to the track buffer to/from the buffer cache.
  5178. + */
  5179. +static void copy_buffer(int ssize, int max_sector, int max_sector_2)
  5180. +{
  5181. +    int remaining; /* number of transferred 512-byte sectors */
  5182. +    struct buffer_head *bh;
  5183. +    char *buffer, *dma_buffer;
  5184. +    int size;
  5185. +
  5186. +    if ( max_sector > max_sector_2 )
  5187. +        max_sector = max_sector_2;
  5188. +
  5189. +    max_sector = transfer_size(ssize, max_sector, CURRENT->nr_sectors);
  5190. +
  5191. +    if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
  5192. +        buffer_max > sector_t + CURRENT->nr_sectors){
  5193. +        current_count_sectors = buffer_max - sector_t;
  5194. +        if ( current_count_sectors > CURRENT->nr_sectors )
  5195. +            current_count_sectors = CURRENT->nr_sectors;
  5196. +    }
  5197. +    remaining = current_count_sectors << 9;
  5198. +#ifdef CONFIG_FLOPPY_SANITY
  5199. +    if ((remaining >> 9) > CURRENT->nr_sectors  &&
  5200. +        CT(COMMAND) == FD_WRITE ){
  5201. +        DPRINT("in copy buffer\n");
  5202. +        printk("current_count_sectors=%ld\n", current_count_sectors);
  5203. +        printk("remaining=%d\n", remaining >> 9);
  5204. +        printk("CURRENT->nr_sectors=%ld\n",CURRENT->nr_sectors);
  5205. +        printk("CURRENT->current_nr_sectors=%ld\n",
  5206. +               CURRENT->current_nr_sectors);
  5207. +        printk("max_sector=%d\n", max_sector);
  5208. +        printk("ssize=%d\n", ssize);
  5209. +    }
  5210. +#endif
  5211. +
  5212. +    if ( max_sector > buffer_max )
  5213. +        buffer_max = max_sector;
  5214. +
  5215. +    dma_buffer = floppy_track_buffer + ((sector_t - buffer_min) << 9);
  5216. +
  5217. +    bh = CURRENT->bh;
  5218. +    size = CURRENT->current_nr_sectors << 9;
  5219. +    buffer = CURRENT->buffer;
  5220. +
  5221. +    while ( remaining > 0){
  5222. +        if ( size > remaining )
  5223. +            size = remaining;
  5224. +#ifdef CONFIG_FLOPPY_SANITY
  5225. +        if (dma_buffer + size >
  5226. +            floppy_track_buffer + (max_buffer_sectors << 10) ||
  5227. +            dma_buffer < floppy_track_buffer ){
  5228. +            DPRINT1("buffer overrun in copy buffer %d\n",
  5229. +                (int) ((floppy_track_buffer - dma_buffer) >>9));
  5230. +            printk("sector_t=%d buffer_min=%d\n",
  5231. +                   sector_t, buffer_min);
  5232. +            printk("current_count_sectors=%ld\n",
  5233. +                   current_count_sectors);
  5234. +            if ( CT(COMMAND) == FD_READ )
  5235. +                printk("read\n");
  5236. +            if ( CT(COMMAND) == FD_READ )
  5237. +                printk("write\n");
  5238. +            break;
  5239. +        }
  5240. +        if ( ((unsigned long)buffer) % 512 )
  5241. +            DPRINT1("%p buffer not aligned\n", buffer);
  5242. +#endif
  5243. +        if ( CT(COMMAND) == FD_READ )
  5244. +            memcpy( buffer, dma_buffer, size);
  5245. +        else
  5246. +            memcpy( dma_buffer, buffer, size);
  5247. +        remaining -= size;
  5248. +        if ( !remaining)
  5249. +            break;
  5250. +
  5251. +        dma_buffer += size;
  5252. +        bh = bh->b_reqnext;
  5253. +#ifdef CONFIG_FLOPPY_SANITY
  5254. +        if ( !bh){
  5255. +            DPRINT("bh=null in copy buffer after copy\n");
  5256. +            break;
  5257. +        }
  5258. +#endif
  5259. +        size = bh->b_size;
  5260. +        buffer = bh->b_data;
  5261. +    }
  5262. +#ifdef CONFIG_FLOPPY_SANITY
  5263. +    if ( remaining ){
  5264. +        if ( remaining > 0 )
  5265. +            max_sector -= remaining >> 9;
  5266. +        DPRINT1("weirdness: remaining %d\n", remaining>>9);
  5267. +    }
  5268. +#endif
  5269. +}
  5270. +
  5271. +/*
  5272. + * Formulate a read/write request.
  5273. + * this routine decides where to load the data (directly to buffer, or to
  5274. + * tmp floppy area), how much data to load (the size of the buffer, the whole
  5275. + * track, or a single sector)
  5276. + * All floppy_track_buffer handling goes in here. If we ever add track buffer
  5277. + * allocation on the fly, it should be done here. No other part should need
  5278. + * modification.
  5279. + */
  5280. +
  5281. +static int make_raw_rw_request(void)
  5282. +{
  5283. +    int aligned_sector_t;
  5284. +    int max_sector, max_size, tracksize, ssize;
  5285. +
  5286. +    set_fdc(DRIVE(CURRENT->rq_dev));
  5287. +
  5288. +    raw_cmd = &default_raw_cmd;
  5289. +    raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
  5290. +        FD_RAW_NEED_SEEK;
  5291. +    raw_cmd->cmd_count = NR_RW;
  5292. +    if (CURRENT->cmd == READ){
  5293. +        raw_cmd->flags |= FD_RAW_READ;
  5294. +        COMMAND = FM_MODE(floppy,FD_READ);
  5295. +    } else if (CURRENT->cmd == WRITE){
  5296. +        raw_cmd->flags |= FD_RAW_WRITE;
  5297. +        COMMAND = FM_MODE(floppy,FD_WRITE);
  5298. +    } else {
  5299. +        DPRINT("make_raw_rw_request: unknown command\n");
  5300. +        return 0;
  5301. +    }
  5302. +
  5303. +    max_sector = floppy->sect * floppy->head;
  5304. +    
  5305. +    TRACK = CURRENT->sector / max_sector;
  5306. +    sector_t = CURRENT->sector % max_sector;
  5307. +    if ( floppy->track && TRACK >= floppy->track )
  5308. +        return 0;
  5309. +    HEAD = sector_t / floppy->sect;
  5310. +
  5311. +    if (((floppy->stretch & FD_SWAPSIDES) || TESTF( FD_NEED_TWADDLE)) &&
  5312. +        sector_t < floppy->sect )
  5313. +        max_sector = floppy->sect;
  5314. +
  5315. +    /* 2M disks have phantom sectors on the first track */
  5316. +    if ( (floppy->rate & FD_2M ) && (!TRACK) && (!HEAD)){
  5317. +        max_sector = 2 * floppy->sect / 3;
  5318. +        if (sector_t >= max_sector){
  5319. +            current_count_sectors =  (floppy->sect - sector_t);
  5320. +            if ( current_count_sectors > CURRENT->nr_sectors )
  5321. +                current_count_sectors = CURRENT->nr_sectors;
  5322. +            return 1;
  5323. +        }
  5324. +        SIZECODE = 2;
  5325. +    } else
  5326. +        SIZECODE = FD_SIZECODE(floppy);
  5327. +    raw_cmd->rate = floppy->rate & 3;
  5328. +    if ((floppy->rate & FD_2M) &&
  5329. +        (TRACK || HEAD ) &&
  5330. +        raw_cmd->rate == 2)
  5331. +        raw_cmd->rate = 1;
  5332. +
  5333. +    if ( SIZECODE )
  5334. +        SIZECODE2 = 0xff;
  5335. +    else
  5336. +        SIZECODE2 = 0x80;
  5337. +    raw_cmd->track = TRACK << STRETCH(floppy);
  5338. +    DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,HEAD);
  5339. +    GAP = floppy->gap;
  5340. +    CODE2SIZE;
  5341. +    SECT_PER_TRACK = floppy->sect << 2 >> SIZECODE;
  5342. +    SECTOR = ((sector_t % floppy->sect) << 2 >> SIZECODE) + 1;
  5343. +    tracksize = floppy->sect - floppy->sect % ssize;
  5344. +    if ( tracksize < floppy->sect ){
  5345. +        SECT_PER_TRACK ++;
  5346. +        if (  tracksize <= sector_t % floppy->sect)
  5347. +            SECTOR--;
  5348. +        while ( tracksize <= sector_t % floppy->sect){
  5349. +            while( tracksize + ssize > floppy->sect ){
  5350. +                SIZECODE--;
  5351. +                ssize >>= 1;
  5352. +            }
  5353. +            SECTOR++; SECT_PER_TRACK ++;
  5354. +            tracksize += ssize;
  5355. +        }
  5356. +        max_sector = HEAD * floppy->sect + tracksize;
  5357. +    } else if ( !TRACK && !HEAD && !( floppy->rate & FD_2M ) && probing)
  5358. +        max_sector = floppy->sect;
  5359. +
  5360. +    aligned_sector_t = sector_t - ( sector_t % floppy->sect ) % ssize;
  5361. +    max_size = CURRENT->nr_sectors;
  5362. +    if ((raw_cmd->track == buffer_track) && (current_drive == buffer_drive) &&
  5363. +        (sector_t >= buffer_min) && (sector_t < buffer_max)) {
  5364. +        /* data already in track buffer */
  5365. +        if (CT(COMMAND) == FD_READ) {
  5366. +            copy_buffer(1, max_sector, buffer_max);
  5367. +            return 1;
  5368. +        }
  5369. +    } else if (aligned_sector_t != sector_t || CURRENT->nr_sectors < ssize){
  5370. +        if (CT(COMMAND) == FD_WRITE){
  5371. +            if(sector_t + CURRENT->nr_sectors > ssize &&
  5372. +               sector_t + CURRENT->nr_sectors < ssize + ssize)
  5373. +                max_size = ssize + ssize;
  5374. +            else
  5375. +                max_size = ssize;
  5376. +        }
  5377. +        raw_cmd->flags &= ~FD_RAW_WRITE;
  5378. +        raw_cmd->flags |= FD_RAW_READ;
  5379. +        COMMAND = FM_MODE(floppy,FD_READ);
  5380. +    } else if ((unsigned long)CURRENT->buffer < MAX_DMA_ADDRESS ) {
  5381. +        int direct, indirect;
  5382. +
  5383. +        indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) -
  5384. +            sector_t;
  5385. +
  5386. +        max_size = buffer_chain_size();
  5387. +#if 0
  5388. +        if ( max_size > ( MAX_DMA_ADDRESS - ((unsigned long) CURRENT->buffer))>>9)
  5389. +            max_size=(MAX_DMA_ADDRESS - ((unsigned long) CURRENT->buffer))>>9;
  5390. +        /* 64 kb boundaries */
  5391. +        if (CROSS_64KB(CURRENT->buffer, max_size << 9))
  5392. +            max_size = ( K_64 - ((long) CURRENT->buffer) % K_64)>>9;
  5393. +#endif
  5394. +        direct = transfer_size(ssize,max_sector,max_size) - sector_t;
  5395. +        /*
  5396. +         * We try to read tracks, but if we get too many errors, we
  5397. +         * go back to reading just one sector at a time.
  5398. +         *
  5399. +         * This means we should be able to read a sector even if there
  5400. +         * are other bad sectors on this track.
  5401. +         */
  5402. +        if (!direct ||
  5403. +            (indirect * 2 > direct * 3 &&
  5404. +             *errors < DP->max_errors.read_track &&
  5405. +             /*!TESTF( FD_NEED_TWADDLE) &&*/
  5406. +             ((!probing || (DP->read_track&(1<<DRS->probed_format)))))){
  5407. +            max_size = CURRENT->nr_sectors;
  5408. +        } else {
  5409. +            raw_cmd->kernel_data = CURRENT->buffer;
  5410. +            raw_cmd->length = current_count_sectors << 9;
  5411. +            if (raw_cmd->length == 0){
  5412. +                DPRINT("zero dma transfer attempted from make_raw_request\n");
  5413. +                DPRINT3("indirect=%d direct=%d sector_t=%d",
  5414. +                    indirect, direct, sector_t);
  5415. +                return 0;
  5416. +            }
  5417. +            return 2;
  5418. +        }
  5419. +    }
  5420. +
  5421. +    if ( CT(COMMAND) == FD_READ )
  5422. +        max_size = max_sector; /* unbounded */
  5423. +
  5424. +    /* claim buffer track if needed */
  5425. +    if (buffer_track != raw_cmd->track ||  /* bad track */
  5426. +        buffer_drive !=current_drive || /* bad drive */
  5427. +        sector_t > buffer_max ||
  5428. +        sector_t < buffer_min ||
  5429. +        ((CT(COMMAND) == FD_READ ||
  5430. +          (aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize ))&&
  5431. +         max_sector > 2 * max_buffer_sectors + buffer_min &&
  5432. +         max_size + sector_t > 2 * max_buffer_sectors + buffer_min)
  5433. +        /* not enough space */ ){
  5434. +        buffer_track = -1;
  5435. +        buffer_drive = current_drive;
  5436. +        buffer_max = buffer_min = aligned_sector_t;
  5437. +    }
  5438. +    raw_cmd->kernel_data = floppy_track_buffer +
  5439. +        ((aligned_sector_t-buffer_min )<<9);
  5440. +
  5441. +    if ( CT(COMMAND) == FD_WRITE ){
  5442. +        /* copy write buffer to track buffer.
  5443. +         * if we get here, we know that the write
  5444. +         * is either aligned or the data already in the buffer
  5445. +         * (buffer will be overwritten) */
  5446. +#ifdef CONFIG_FLOPPY_SANITY
  5447. +        if (sector_t != aligned_sector_t && buffer_track == -1 )
  5448. +            DPRINT("internal error offset !=0 on write\n");
  5449. +#endif
  5450. +        buffer_track = raw_cmd->track;
  5451. +        buffer_drive = current_drive;
  5452. +        copy_buffer(ssize, max_sector, 2*max_buffer_sectors+buffer_min);
  5453. +    } else
  5454. +        transfer_size(ssize, max_sector,
  5455. +                  2*max_buffer_sectors+buffer_min-aligned_sector_t);
  5456. +
  5457. +    /* round up current_count_sectors to get dma xfer size */
  5458. +    raw_cmd->length = sector_t+current_count_sectors-aligned_sector_t;
  5459. +    raw_cmd->length = ((raw_cmd->length -1)|(ssize-1))+1;
  5460. +    raw_cmd->length <<= 9;
  5461. +#ifdef CONFIG_FLOPPY_SANITY
  5462. +    if ((raw_cmd->length < current_count_sectors << 9) ||
  5463. +        (raw_cmd->kernel_data != CURRENT->buffer &&
  5464. +         CT(COMMAND) == FD_WRITE &&
  5465. +         (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
  5466. +          aligned_sector_t < buffer_min )) ||
  5467. +        raw_cmd->length % ( 128 << SIZECODE ) ||
  5468. +        raw_cmd->length <= 0 || current_count_sectors <= 0){
  5469. +        DPRINT2("fractionary current count b=%lx s=%lx\n",
  5470. +            raw_cmd->length, current_count_sectors);
  5471. +        if ( raw_cmd->kernel_data != CURRENT->buffer )
  5472. +            printk("addr=%d, length=%ld\n",
  5473. +                   (int) ((raw_cmd->kernel_data -
  5474. +                       floppy_track_buffer ) >> 9),
  5475. +                   current_count_sectors);
  5476. +        printk("st=%d ast=%d mse=%d msi=%d\n",
  5477. +               sector_t, aligned_sector_t, max_sector, max_size);
  5478. +        printk("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
  5479. +        printk("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
  5480. +               COMMAND, SECTOR, HEAD, TRACK);
  5481. +        printk("buffer drive=%d\n", buffer_drive);
  5482. +        printk("buffer track=%d\n", buffer_track);
  5483. +        printk("buffer_min=%d\n", buffer_min );
  5484. +        printk("buffer_max=%d\n", buffer_max );
  5485. +        return 0;
  5486. +    }
  5487. +
  5488. +    if (raw_cmd->kernel_data != CURRENT->buffer ){
  5489. +        if (raw_cmd->kernel_data < floppy_track_buffer ||
  5490. +            current_count_sectors < 0 ||
  5491. +            raw_cmd->length < 0 ||
  5492. +            raw_cmd->kernel_data + raw_cmd->length >
  5493. +            floppy_track_buffer + (max_buffer_sectors  << 10)){
  5494. +            DPRINT("buffer overrun in schedule dma\n");
  5495. +            printk("sector_t=%d buffer_min=%d current_count=%ld\n",
  5496. +                   sector_t, buffer_min,
  5497. +                   raw_cmd->length >> 9 );
  5498. +            printk("current_count_sectors=%ld\n",
  5499. +                   current_count_sectors);
  5500. +            if ( CT(COMMAND) == FD_READ )
  5501. +                printk("read\n");
  5502. +            if ( CT(COMMAND) == FD_READ )
  5503. +                printk("write\n");
  5504. +            return 0;
  5505. +        }
  5506. +    } else if (raw_cmd->length > CURRENT->nr_sectors << 9 ||
  5507. +           current_count_sectors > CURRENT->nr_sectors){
  5508. +        DPRINT("buffer overrun in direct transfer\n");
  5509. +        return 0;
  5510. +    } else if ( raw_cmd->length < current_count_sectors << 9 ){
  5511. +        DPRINT("more sectors than bytes\n");
  5512. +        printk("bytes=%ld\n", raw_cmd->length >> 9 );
  5513. +        printk("sectors=%ld\n", current_count_sectors);
  5514. +    }
  5515. +    if (raw_cmd->length == 0){
  5516. +        DPRINT("zero dma transfer attempted from make_raw_request\n");
  5517. +        return 0;
  5518. +    }
  5519. +#endif
  5520. +    return 2;
  5521. +}
  5522. +
  5523. +static void redo_fd_request(void)
  5524. +{
  5525. +#define REPEAT {request_done(0); continue; }
  5526. +    kdev_t device;
  5527. +    int tmp;
  5528. +
  5529. +    lastredo = jiffies;
  5530. +    if (current_drive < N_DRIVE)
  5531. +        floppy_off(current_drive);
  5532. +
  5533. +    if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){
  5534. +        DPRINT("current not active!\n");
  5535. +        return;
  5536. +    }
  5537. +
  5538. +    while(1){
  5539. +        if (!CURRENT) {
  5540. +            CLEAR_INTR;
  5541. +            unlock_fdc();
  5542. +            return;
  5543. +        }
  5544. +        if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
  5545. +            panic(DEVICE_NAME ": request list destroyed");
  5546. +        if (CURRENT->bh && !CURRENT->bh->b_lock)
  5547. +            panic(DEVICE_NAME ": block not locked");
  5548. +
  5549. +        device = CURRENT->rq_dev;
  5550. +        set_fdc( DRIVE(device));
  5551. +        reschedule_timeout(CURRENTD, "redo fd request", 0);
  5552. +
  5553. +        set_floppy(device);
  5554. +        raw_cmd = & default_raw_cmd;
  5555. +        raw_cmd->flags = 0;
  5556. +        if(start_motor(redo_fd_request)) return;
  5557. +        if(test_bit(current_drive, &fake_change) ||
  5558. +           TESTF(FD_DISK_CHANGED)){
  5559. +            DPRINT("disk absent or changed during operation\n");
  5560. +            REPEAT;
  5561. +        }
  5562. +        if (!floppy) { /* Autodetection */
  5563. +            if (!probing){
  5564. +                DRS->probed_format = 0;
  5565. +                if ( next_valid_format() ){
  5566. +                    DPRINT("no autodetectable formats\n");
  5567. +                    floppy = NULL;
  5568. +                    REPEAT;
  5569. +                }
  5570. +            }
  5571. +            probing = 1;
  5572. +            floppy = floppy_type+DP->autodetect[DRS->probed_format];
  5573. +        } else
  5574. +            probing = 0;
  5575. +        errors = & (CURRENT->errors);
  5576. +        tmp = make_raw_rw_request();
  5577. +        if ( tmp < 2 ){
  5578. +            request_done(tmp);
  5579. +            continue;
  5580. +        }
  5581. +
  5582. +        if (TESTF(FD_NEED_TWADDLE))
  5583. +            twaddle();
  5584. +        floppy_tq.routine = (void *)(void *) floppy_start;
  5585. +        queue_task(&floppy_tq, &tq_timer);
  5586. +#ifdef DEBUGT
  5587. +        debugt("queue fd request");
  5588. +#endif
  5589. +        return;
  5590. +    }
  5591. +#undef REPEAT
  5592. +}
  5593. +
  5594. +static struct cont_t rw_cont={
  5595. +    rw_interrupt,
  5596. +    redo_fd_request,
  5597. +    bad_flp_intr,
  5598. +    request_done };
  5599. +
  5600. +struct tq_struct request_tq =
  5601. +{ 0, 0, (void *) (void *) redo_fd_request, 0 };
  5602. +
  5603. +static void process_fd_request(void)
  5604. +{
  5605. +    cont = &rw_cont;
  5606. +    queue_task(&request_tq, &tq_timer);
  5607. +}
  5608. +
  5609. +static void do_fd_request(void)
  5610. +{
  5611. +    if (fdc_busy){
  5612. +        /* fdc busy, this new request will be treated when the
  5613. +           current one is done */
  5614. +        is_alive("do fd request, old request running");
  5615. +        return;
  5616. +    }
  5617. +    /* fdc_busy cannot be set by an interrupt or a bh */
  5618. +    floppy_grab_irq_and_dma();
  5619. +    fdc_busy=1;
  5620. +    reschedule_timeout(MAXTIMEOUT, "do fd request",0);
  5621. +    process_fd_request();
  5622. +    is_alive("do fd request");
  5623. +}
  5624. +
  5625. +static struct cont_t poll_cont={
  5626. +    success_and_wakeup,
  5627. +    floppy_ready,
  5628. +    generic_failure,
  5629. +    generic_done };
  5630. +
  5631. +static int poll_drive(int interruptible, int flag)
  5632. +{
  5633. +    int ret;
  5634. +    /* no auto-sense, just clear dcl */
  5635. +    raw_cmd = &default_raw_cmd;
  5636. +    raw_cmd->flags= flag;
  5637. +    raw_cmd->track=0;
  5638. +    raw_cmd->cmd_count=0;
  5639. +    cont = &poll_cont;
  5640. +#ifdef DCL_DEBUG
  5641. +    if (DP->flags & FD_DEBUG){
  5642. +        DPRINT("setting NEWCHANGE in poll_drive\n");
  5643. +    }
  5644. +#endif
  5645. +    SETF(FD_DISK_NEWCHANGE);
  5646. +    WAIT(floppy_ready);
  5647. +    return ret;
  5648. +}
  5649. +
  5650. +/*
  5651. + * User triggered reset
  5652. + * ====================
  5653. + */
  5654. +
  5655. +static void reset_intr(void)
  5656. +{
  5657. +    printk("weird, reset interrupt called\n");
  5658. +}
  5659. +
  5660. +static struct cont_t reset_cont={
  5661. +    reset_intr,
  5662. +    success_and_wakeup,
  5663. +    generic_failure,
  5664. +    generic_done };
  5665. +
  5666. +static int user_reset_fdc(int drive, int arg, int interruptible)
  5667. +{
  5668. +    int ret;
  5669. +
  5670. +    ret=0;
  5671. +    if(arg == FD_RESET_IF_NEEDED && !FDCS->reset)
  5672. +        return 0;
  5673. +    LOCK_FDC(drive,interruptible);
  5674. +    if(arg == FD_RESET_ALWAYS)
  5675. +        FDCS->reset=1;
  5676. +    if ( FDCS->reset ){
  5677. +        cont = &reset_cont;
  5678. +        reschedule_timeout(CURRENTD, "user reset fdc", 0);
  5679. +        WAIT(reset_fdc);
  5680. +    }
  5681. +    process_fd_request();
  5682. +    return ret;
  5683. +}
  5684. +
  5685. +/*
  5686. + * Misc Ioctl's and support
  5687. + * ========================
  5688. + */
  5689. +static int fd_copyout(void *param, volatile void *address, int size)
  5690. +{
  5691. +    int i;
  5692. +
  5693. +    i = verify_area(VERIFY_WRITE,param,size);
  5694. +    if (i)
  5695. +        return i;
  5696. +    memcpy_tofs(param,(void *) address, size);
  5697. +    return 0;
  5698. +}
  5699. +
  5700. +static int fd_copyin(void *param, volatile void *address, int size)
  5701. +{
  5702. +    int i;
  5703. +
  5704. +    i = verify_area(VERIFY_READ,param,size);
  5705. +    if (i)
  5706. +        return i;
  5707. +    memcpy_fromfs((void *) address, param, size);
  5708. +    return 0;
  5709. +}
  5710. +
  5711. +#define COPYOUT(x) ECALL(fd_copyout( (void *)param, &(x), sizeof(x)))
  5712. +#define COPYIN(x) ECALL(fd_copyin( (void *)param, &(x), sizeof(x)))
  5713. +
  5714. +static const char *drive_name(int type, int drive )
  5715. +{
  5716. +    struct floppy_struct *floppy;
  5717. +
  5718. +    if ( type )
  5719. +        floppy = floppy_type + type;
  5720. +    else {
  5721. +        if ( UDP->native_format )
  5722. +            floppy = floppy_type + UDP->native_format;
  5723. +        else
  5724. +            return "(null)";
  5725. +    }
  5726. +    if ( floppy->name )
  5727. +        return floppy->name;
  5728. +    else
  5729. +        return "(null)";
  5730. +}
  5731. +
  5732. +
  5733. +/* raw commands */
  5734. +static void raw_cmd_done(int flag)
  5735. +{
  5736. +    int i;
  5737. +
  5738. +    if(!flag) {
  5739. +        raw_cmd->flags = FD_RAW_FAILURE;
  5740. +        raw_cmd->flags |= FD_RAW_HARDFAILURE;
  5741. +    } else {
  5742. +        raw_cmd->reply_count = inr;
  5743. +        for( i=0; i< raw_cmd->reply_count; i++)
  5744. +            raw_cmd->reply[i] = reply_buffer[i];
  5745. +
  5746. +        if ( raw_cmd->flags & ( FD_RAW_READ | FD_RAW_WRITE ))
  5747. +            raw_cmd->length = get_dma_residue(FLOPPY_DMA);
  5748. +
  5749. +        if( (raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
  5750. +            (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
  5751. +            raw_cmd->flags |= FD_RAW_FAILURE;
  5752. +
  5753. +        if( disk_change(current_drive) )
  5754. +            raw_cmd->flags |= FD_RAW_DISK_CHANGE;
  5755. +        else
  5756. +            raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
  5757. +        if(raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
  5758. +            motor_off_callback(current_drive);
  5759. +
  5760. +        if(raw_cmd->next &&
  5761. +           (!(raw_cmd->flags & FD_RAW_FAILURE) ||
  5762. +            !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
  5763. +           ((raw_cmd->flags & FD_RAW_FAILURE) ||
  5764. +            !(raw_cmd->flags &FD_RAW_STOP_IF_SUCCESS))) {
  5765. +            raw_cmd = raw_cmd->next;
  5766. +            return;
  5767. +        }
  5768. +    }
  5769. +    generic_done(flag);
  5770. +}
  5771. +
  5772. +
  5773. +static struct cont_t raw_cmd_cont={
  5774. +    success_and_wakeup,
  5775. +    floppy_start,
  5776. +    generic_failure,
  5777. +    raw_cmd_done
  5778. +};
  5779. +
  5780. +static inline int raw_cmd_copyout(int cmd, char *param,
  5781. +                  struct floppy_raw_cmd *ptr)
  5782. +{
  5783. +    struct old_floppy_raw_cmd old_raw_cmd;
  5784. +    int ret;
  5785. +
  5786. +    while(ptr) {
  5787. +        if(cmd == OLDFDRAWCMD) {
  5788. +            old_raw_cmd.flags = ptr->flags;
  5789. +            old_raw_cmd.data = ptr->data;
  5790. +            old_raw_cmd.length = ptr->length;
  5791. +            old_raw_cmd.rate = ptr->rate;
  5792. +            old_raw_cmd.reply_count = ptr->reply_count;
  5793. +            memcpy(old_raw_cmd.reply, ptr->reply, 7);
  5794. +            COPYOUT(old_raw_cmd);
  5795. +            param += sizeof(old_raw_cmd);
  5796. +        } else {
  5797. +            COPYOUT(*ptr);
  5798. +            param += sizeof(struct floppy_raw_cmd);
  5799. +        }
  5800. +
  5801. +        if ( (ptr->flags & FD_RAW_READ) && ptr->buffer_length){
  5802. +            if(ptr->length>=0 && ptr->length<=ptr->buffer_length)
  5803. +                ECALL(fd_copyout(ptr->data,
  5804. +                         ptr->kernel_data,
  5805. +                         ptr->buffer_length -
  5806. +                         ptr->length));
  5807. +        }
  5808. +        ptr = ptr->next;
  5809. +    }
  5810. +    return 0;
  5811. +}
  5812. +
  5813. +
  5814. +static void raw_cmd_free(struct floppy_raw_cmd **ptr)
  5815. +{
  5816. +    struct floppy_raw_cmd **next;
  5817. +
  5818. +    while(*ptr) {
  5819. +        next = & (*ptr)->next;
  5820. +        if((*ptr)->buffer_length) {
  5821. +            free_pages((unsigned long)(*ptr)->kernel_data,
  5822. +                   __get_order((*ptr)->buffer_length));
  5823. +            (*ptr)->buffer_length = 0;
  5824. +        }
  5825. +        kfree(*ptr);
  5826. +        *ptr = 0;
  5827. +        ptr = next;
  5828. +    }
  5829. +}
  5830. +
  5831. +
  5832. +static inline int raw_cmd_copyin(int cmd, char *param,
  5833. +                 struct floppy_raw_cmd **rcmd)
  5834. +{
  5835. +    struct floppy_raw_cmd *ptr;
  5836. +    struct old_floppy_raw_cmd old_raw_cmd;
  5837. +    int ret;
  5838. +    int i;
  5839. +
  5840. +    *rcmd = 0;
  5841. +    while(1) {
  5842. +        ptr = (struct floppy_raw_cmd *)
  5843. +            kmalloc(sizeof (struct floppy_raw_cmd ), GFP_USER);
  5844. +        if (!ptr)
  5845. +            return -ENOMEM;
  5846. +        ptr->next = 0;
  5847. +        ptr->buffer_length = 0;
  5848. +        *rcmd = ptr;
  5849. +        if(cmd == OLDFDRAWCMD){
  5850. +            COPYIN(old_raw_cmd);
  5851. +            ptr->flags = old_raw_cmd.flags;
  5852. +            ptr->data = old_raw_cmd.data;
  5853. +            ptr->length = old_raw_cmd.length;
  5854. +            ptr->rate = old_raw_cmd.rate;
  5855. +            ptr->cmd_count = old_raw_cmd.cmd_count;
  5856. +            ptr->track = old_raw_cmd.track;
  5857. +            memcpy(ptr->cmd, old_raw_cmd.cmd, 9);
  5858. +            if(ptr->cmd_count > 9)
  5859. +                return -EINVAL;
  5860. +            ptr->next = 0;
  5861. +            ptr->phys_length = 0;
  5862. +            param += sizeof(struct old_floppy_raw_cmd);
  5863. +        } else {
  5864. +            COPYIN(*ptr);
  5865. +            param += sizeof(struct floppy_raw_cmd);
  5866. +            if(ptr->cmd_count > 16)
  5867. +                return -EINVAL;
  5868. +        }
  5869. +
  5870. +        for(i=0; i< 16; i++)
  5871. +            ptr->reply[i] = 0;
  5872. +        ptr->resultcode = 0;
  5873. +
  5874. +        ptr->next = 0;
  5875. +        ptr->buffer_length = 0;
  5876. +        ptr->kernel_data = 0;
  5877. +
  5878. +        if(ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
  5879. +            if(!ptr->length)
  5880. +                return -EINVAL;
  5881. +
  5882. +            ptr->kernel_data =(char *)dma_mem_alloc(ptr->length);
  5883. +            if(!ptr->kernel_data)
  5884. +                return -ENOMEM;
  5885. +            ptr->buffer_length = ptr->length;
  5886. +        }
  5887. +        if(ptr->flags & FD_RAW_WRITE)
  5888. +            fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
  5889. +        rcmd = & (ptr->next);
  5890. +        if( ! (ptr->flags & FD_RAW_MORE))
  5891. +            return 0;
  5892. +        ptr->rate &= 0x03;
  5893. +
  5894. +    }
  5895. +}
  5896. +
  5897. +
  5898. +static int raw_cmd_ioctl(int cmd, void *param)
  5899. +{
  5900. +    int drive, ret, ret2;
  5901. +    struct floppy_raw_cmd *my_raw_cmd;
  5902. +
  5903. +    if ( FDCS->rawcmd <= 1 )
  5904. +        FDCS->rawcmd = 1;
  5905. +    for ( drive= 0; drive < N_DRIVE; drive++){
  5906. +        if ( FDC(drive) != fdc)
  5907. +            continue;
  5908. +        if ( drive == current_drive ){
  5909. +            if ( UDRS->fd_ref > 1 ){
  5910. +                FDCS->rawcmd = 2;
  5911. +                break;
  5912. +            }
  5913. +        } else if ( UDRS->fd_ref ){
  5914. +            FDCS->rawcmd = 2;
  5915. +            break;
  5916. +        }
  5917. +    }
  5918. +
  5919. +    if(FDCS->reset)
  5920. +        return -EIO;
  5921. +
  5922. +    ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
  5923. +    if (ret) {
  5924. +        raw_cmd_free(&my_raw_cmd);
  5925. +        return ret;
  5926. +    }
  5927. +    
  5928. +    raw_cmd = my_raw_cmd;
  5929. +    cont = &raw_cmd_cont;
  5930. +    ret=wait_til_done(floppy_start,1);
  5931. +#ifdef DCL_DEBUG
  5932. +    if (DP->flags & FD_DEBUG){
  5933. +        DPRINT("calling disk change from raw_cmd ioctl\n");
  5934. +    }
  5935. +#endif
  5936. +
  5937. +    if (ret != -EINTR && FDCS->reset)
  5938. +        ret = -EINTR;
  5939. +
  5940. +    DRS->track = NO_TRACK;
  5941. +
  5942. +    ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
  5943. +    if(!ret)
  5944. +        ret = ret2;
  5945. +    raw_cmd_free(&my_raw_cmd);
  5946. +    return ret;
  5947. +}
  5948. +
  5949. +static int invalidate_drive(kdev_t rdev)
  5950. +{
  5951. +    /* invalidate the buffer track to force a reread */
  5952. +    set_bit( DRIVE(rdev), &fake_change);
  5953. +    process_fd_request();
  5954. +    check_disk_change(rdev);
  5955. +    return 0;
  5956. +}
  5957. +
  5958. +static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
  5959. +            unsigned long param)
  5960. +{
  5961. +#define IOCTL_MODE_BIT 8
  5962. +#define OPEN_WRITE_BIT 16
  5963. +#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
  5964. +
  5965. +    struct floppy_struct newparams;
  5966. +    struct format_descr tmp_format_req;
  5967. +    int i,drive,type,cnt;
  5968. +    kdev_t device;
  5969. +    struct floppy_struct *this_floppy;
  5970. +    const char *name;
  5971. +    int ret;
  5972. +
  5973. +    device = inode->i_rdev;
  5974. +    switch (cmd) {
  5975. +        RO_IOCTLS(device,param);
  5976. +    }
  5977. +    type = TYPE(device);
  5978. +    drive = DRIVE(device);
  5979. +    switch (cmd) {
  5980. +        case OLDFDGETDRVTYP:
  5981. +        case FDGETDRVTYP:
  5982. +            i=verify_area(VERIFY_WRITE,(void *) param,16);
  5983. +            if (i)
  5984. +                return i;
  5985. +            name = drive_name(type,drive);
  5986. +            for ( cnt=0; cnt<16; cnt++){
  5987. +                put_user(name[cnt], ((char*)param)+cnt);
  5988. +                if ( ! *name )
  5989. +                    break;
  5990. +            }
  5991. +            return 0;
  5992. +        case OLDFDGETMAXERRS:
  5993. +        case FDGETMAXERRS:
  5994. +            COPYOUT(UDP->max_errors);
  5995. +            return 0;
  5996. +        case OLDFDGETPRM:
  5997. +        case FDGETPRM:
  5998. +            if (type)
  5999. +                this_floppy = &floppy_type[type];
  6000. +            else if ((this_floppy = current_type[drive]) == NULL)
  6001. +                return -ENODEV;
  6002. +            COPYOUT(this_floppy[0]);
  6003. +            return 0;
  6004. +        case OLDFDPOLLDRVSTAT:
  6005. +        case FDPOLLDRVSTAT:
  6006. +            LOCK_FDC(drive,1);
  6007. +            CALL(poll_drive(1, FD_RAW_NEED_DISK));
  6008. +            process_fd_request();
  6009. +            /* fall through */
  6010. +        case OLDFDGETDRVSTAT:
  6011. +        case FDGETDRVSTAT:
  6012. +            COPYOUT(*UDRS);
  6013. +            return 0;
  6014. +        case OLDFDGETFDCSTAT:
  6015. +            COPYOUT(* (struct old_floppy_fdc_state *) UFDCS);
  6016. +            return 0;
  6017. +        case FDGETFDCSTAT:
  6018. +            COPYOUT(*UFDCS);
  6019. +            return 0;
  6020. +        case OLDFDGETDRVPRM:
  6021. +        case FDGETDRVPRM:
  6022. +            COPYOUT(*UDP);
  6023. +            return 0;
  6024. +        case OLDFDWERRORGET:
  6025. +        case FDWERRORGET:
  6026. +            COPYOUT(*UDRWE);
  6027. +            return 0;
  6028. +    }
  6029. +    if (!IOCTL_ALLOWED)
  6030. +        return -EPERM;
  6031. +    switch (cmd) {
  6032. +        case OLDFDWERRORCLR:
  6033. +        case FDWERRORCLR:
  6034. +            UDRWE->write_errors = 0;
  6035. +            UDRWE->first_error_sector = 0;
  6036. +            UDRWE->first_error_generation = 0;
  6037. +            UDRWE->last_error_sector = 0;
  6038. +            UDRWE->last_error_generation = 0;
  6039. +            UDRWE->badness = 0;
  6040. +            return 0;
  6041. +            case OLDFDRAWCMD:
  6042. +        case FDRAWCMD:
  6043. +            if (type)
  6044. +                return -EINVAL;
  6045. +            LOCK_FDC(drive,1);
  6046. +            set_floppy(device);
  6047. +            CALL(i = raw_cmd_ioctl(cmd,(void *) param));
  6048. +            process_fd_request();
  6049. +            return i;
  6050. +        case OLDFDFMTTRK:
  6051. +        case FDFMTTRK:
  6052. +            if (UDRS->fd_ref != 1)
  6053. +                return -EBUSY;
  6054. +            COPYIN(tmp_format_req);
  6055. +            return do_format(device, &tmp_format_req);
  6056. +        case OLDFDSETMAXERRS:
  6057. +        case FDSETMAXERRS:
  6058. +            COPYIN(UDP->max_errors);
  6059. +            return 0;
  6060. +        case OLDFDFMTBEG:
  6061. +        case FDFMTBEG:
  6062. +            return 0;
  6063. +        case OLDFDCLRPRM:
  6064. +        case FDCLRPRM:
  6065. +            LOCK_FDC(drive,1);
  6066. +            current_type[drive] = NULL;
  6067. +            floppy_sizes[drive] = MAX_DISK_SIZE;
  6068. +            UDRS->keep_data = 0;
  6069. +            return invalidate_drive(device);
  6070. +        case OLDFDFMTEND:
  6071. +        case FDFMTEND:
  6072. +        case OLDFDFLUSH:
  6073. +        case FDFLUSH:
  6074. +            LOCK_FDC(drive,1);
  6075. +            return invalidate_drive(device);
  6076. +        case OLDFDSETPRM:
  6077. +        case FDSETPRM:
  6078. +        case OLDFDDEFPRM:
  6079. +        case FDDEFPRM:
  6080. +            COPYIN(newparams);
  6081. +            /* sanity checking for parameters.*/
  6082. +            if(newparams.sect <= 0 ||
  6083. +               newparams.head <= 0 ||
  6084. +               newparams.track <= 0 ||
  6085. +               newparams.track > UDP->tracks>> STRETCH(&newparams) ||
  6086. +               /* check if reserved bits are set */
  6087. +               (newparams.stretch & ~(FD_STRETCH | FD_SWAPSIDES)) != 0)
  6088. +                return -EINVAL;
  6089. +            if ( type){
  6090. +                if ( !suser() )
  6091. +                    return -EPERM;
  6092. +                LOCK_FDC(drive,1);
  6093. +                for ( cnt = 0; cnt < N_DRIVE; cnt++){
  6094. +                    if (TYPE(drive_state[cnt].fd_device) == type &&
  6095. +                        drive_state[cnt].fd_ref)
  6096. +                        set_bit(drive, &fake_change);
  6097. +                }
  6098. +                floppy_type[type] = newparams;
  6099. +                floppy_type[type].name="user format";
  6100. +                for (cnt = type << 2 ;
  6101. +                     cnt < (type << 2 ) + 4 ;
  6102. +                     cnt++)
  6103. +                    floppy_sizes[cnt]=
  6104. +                        floppy_sizes[cnt+0x80]=
  6105. +                        floppy_type[type].size>>1;
  6106. +                process_fd_request();
  6107. +                for ( cnt = 0; cnt < N_DRIVE; cnt++){
  6108. +                    if (TYPE(drive_state[cnt].fd_device) == type &&
  6109. +                        drive_state[cnt].fd_ref)
  6110. +                        check_disk_change(drive_state[cnt].
  6111. +                                  fd_device);
  6112. +                }
  6113. +                return 0;
  6114. +            }
  6115. +
  6116. +            LOCK_FDC(drive,1);
  6117. +            if ( cmd != FDDEFPRM )
  6118. +                /* notice a disk change immediately, else
  6119. +                 * we loose our settings immediately*/
  6120. +                CALL(poll_drive(1,0));
  6121. +            user_params[drive] = newparams;
  6122. +            if (buffer_drive == drive &&
  6123. +                buffer_max > user_params[drive].sect)
  6124. +                buffer_max=user_params[drive].sect;
  6125. +            current_type[drive] = &user_params[drive];
  6126. +            floppy_sizes[drive] = user_params[drive].size >> 1;
  6127. +            if (cmd == FDDEFPRM)
  6128. +                DRS->keep_data = -1;
  6129. +            else
  6130. +                DRS->keep_data = 1;
  6131. +            /* invalidation. Invalidate only when needed, i.e.
  6132. +             * when there are already sectors in the buffer cache
  6133. +             * whose number will change. This is useful, because
  6134. +             * mtools often changes the geometry of the disk after
  6135. +             * looking at the boot block */
  6136. +            if (DRS->maxblock >
  6137. +                user_params[drive].sect ||
  6138. +                DRS->maxtrack )
  6139. +                invalidate_drive(device);
  6140. +            else
  6141. +                process_fd_request();
  6142. +            return 0;
  6143. +        case OLDFDRESET:
  6144. +        case FDRESET:
  6145. +            return user_reset_fdc( drive, (int)param, 1);
  6146. +        case OLDFDMSGON:
  6147. +        case FDMSGON:
  6148. +            UDP->flags |= FTD_MSG;
  6149. +            return 0;
  6150. +        case OLDFDMSGOFF:
  6151. +        case FDMSGOFF:
  6152. +            UDP->flags &= ~FTD_MSG;
  6153. +            return 0;
  6154. +        case OLDFDSETEMSGTRESH:
  6155. +        case FDSETEMSGTRESH:
  6156. +            UDP->max_errors.reporting =
  6157. +            (unsigned short) (param & 0x0f);
  6158. +            return 0;
  6159. +        case OLDFDTWADDLE:
  6160. +        case FDTWADDLE:
  6161. +            LOCK_FDC(drive,1);
  6162. +            twaddle();
  6163. +            process_fd_request();
  6164. +    }
  6165. +    if ( ! suser() )
  6166. +        return -EPERM;
  6167. +    switch(cmd){
  6168. +        case OLDFDSETDRVPRM:
  6169. +        case FDSETDRVPRM:
  6170. +            COPYIN(*UDP);
  6171. +            return 0;
  6172. +        default:
  6173. +            return -EINVAL;
  6174. +    }
  6175. +    return 0;
  6176. +#undef IOCTL_ALLOWED
  6177. +}
  6178. +
  6179. +static void config_types(void)
  6180. +{
  6181. +    int first=1;
  6182. +    int drive;
  6183. +
  6184. +    /* read drive info out of physical cmos */
  6185. +    drive=0;
  6186. +    if (!UDP->cmos )
  6187. +        UDP->cmos= FLOPPY0_TYPE;
  6188. +    drive=1;
  6189. +    if (!UDP->cmos && FLOPPY1_TYPE)
  6190. +        UDP->cmos = FLOPPY1_TYPE;
  6191. +
  6192. +    /* XXX */
  6193. +    /* additional physical CMOS drive detection should go here */
  6194. +
  6195. +    for (drive=0; drive < N_DRIVE; drive++){
  6196. +        if (UDP->cmos >= 0 && UDP->cmos <= NUMBER(default_drive_params))
  6197. +            memcpy((char *) UDP,
  6198. +                   (char *) (&default_drive_params[(int)UDP->cmos].params),
  6199. +                   sizeof(struct floppy_drive_params));
  6200. +        if (UDP->cmos){
  6201. +            if (first)
  6202. +                printk("Floppy drive(s): ");
  6203. +            else
  6204. +                printk(", ");
  6205. +            first=0;
  6206. +            if (UDP->cmos > 0 ){
  6207. +                ALLOWED_DRIVE_MASK |= 1 << drive;
  6208. +                printk("fd%d is %s", drive,
  6209. +                    default_drive_params[(int)UDP->cmos].name);
  6210. +            } else
  6211. +                printk("fd%d is unknown type %d",drive,
  6212. +                       UDP->cmos);
  6213. +        }
  6214. +    }
  6215. +    if(!first)
  6216. +        printk("\n");
  6217. +}
  6218. +
  6219. +static int floppy_read(struct inode * inode, struct file * filp,
  6220. +               char * buf, int count)
  6221. +{
  6222. +    int drive = DRIVE(inode->i_rdev);
  6223. +
  6224. +    check_disk_change(inode->i_rdev);
  6225. +    if (UTESTF(FD_DISK_CHANGED))
  6226. +        return -ENXIO;
  6227. +    return block_read(inode, filp, buf, count);
  6228. +}
  6229. +
  6230. +static int floppy_write(struct inode * inode, struct file * filp,
  6231. +                const char * buf, int count)
  6232. +{
  6233. +    int block;
  6234. +    int ret;
  6235. +    int drive = DRIVE(inode->i_rdev);
  6236. +
  6237. +    if (!UDRS->maxblock)
  6238. +        UDRS->maxblock=1;/* make change detectable */
  6239. +    check_disk_change(inode->i_rdev);
  6240. +    if (UTESTF(FD_DISK_CHANGED))
  6241. +        return -ENXIO;
  6242. +    if (!UTESTF(FD_DISK_WRITABLE))
  6243. +        return -EROFS;
  6244. +    block = (filp->f_pos + count) >> 9;
  6245. +    if (block > UDRS->maxblock)
  6246. +        UDRS->maxblock = block;
  6247. +    ret= block_write(inode, filp, buf, count);
  6248. +    return ret;
  6249. +}
  6250. +
  6251. +static void floppy_release(struct inode * inode, struct file * filp)
  6252. +{
  6253. +    int drive;
  6254. +
  6255. +    drive = DRIVE(inode->i_rdev);
  6256. +
  6257. +    if( !filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
  6258. +        /* if the file is mounted OR (writable now AND writable at
  6259. +         * open time) Linus: Does this cover all cases? */
  6260. +        block_fsync(inode,filp);
  6261. +
  6262. +    if (UDRS->fd_ref < 0)
  6263. +        UDRS->fd_ref=0;
  6264. +    else if (!UDRS->fd_ref--) {
  6265. +        DPRINT("floppy_release with fd_ref == 0");
  6266. +        UDRS->fd_ref = 0;
  6267. +    }
  6268. +    floppy_release_irq_and_dma();
  6269. +}
  6270. +
  6271. +/*
  6272. + * floppy_open check for aliasing (/dev/fd0 can be the same as
  6273. + * /dev/PS0 etc), and disallows simultaneous access to the same
  6274. + * drive with different device numbers.
  6275. + */
  6276. +#define RETERR(x) do{floppy_release(inode,filp); return -(x);}while(0)
  6277. +
  6278. +static int floppy_open(struct inode * inode, struct file * filp)
  6279. +{
  6280. +    int drive;
  6281. +    int old_dev;
  6282. +    int try;
  6283. +    char *tmp;
  6284. +
  6285. +    if (!filp) {
  6286. +        DPRINT("Weird, open called with filp=0\n");
  6287. +        return -EIO;
  6288. +    }
  6289. +
  6290. +    drive = DRIVE(inode->i_rdev);
  6291. +
  6292. +    if (drive >= N_DRIVE ||
  6293. +        !( ALLOWED_DRIVE_MASK & ( 1 << drive)) ||
  6294. +        fdc_state[FDC(drive)].version == FDC_NONE)
  6295. +        return -ENXIO;
  6296. +
  6297. +    if (TYPE(inode->i_rdev) >= NUMBER(floppy_type))
  6298. +        return -ENXIO;
  6299. +    old_dev = UDRS->fd_device;
  6300. +    if (UDRS->fd_ref && old_dev != MINOR(inode->i_rdev))
  6301. +        return -EBUSY;
  6302. +
  6303. +    if(!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){
  6304. +        USETF(FD_DISK_CHANGED);
  6305. +        USETF(FD_VERIFY);
  6306. +    }
  6307. +
  6308. +    if(UDRS->fd_ref == -1 ||
  6309. +       (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
  6310. +        return -EBUSY;
  6311. +
  6312. +    if (floppy_grab_irq_and_dma())
  6313. +        return -EBUSY;
  6314. +
  6315. +    if (filp->f_flags & O_EXCL)
  6316. +        UDRS->fd_ref = -1;
  6317. +    else
  6318. +        UDRS->fd_ref++;
  6319. +
  6320. +    if (!floppy_track_buffer){
  6321. +        /* if opening an ED drive, reserve a big buffer,
  6322. +         * else reserve a small one */
  6323. +        if ((UDP->cmos == 6) || (UDP->cmos == 5))
  6324. +            try = 64; /* Only 48 actually useful */
  6325. +        else
  6326. +            try = 32; /* Only 24 actually useful */
  6327. +
  6328. +        tmp=(char *)dma_mem_alloc(1024 * try);
  6329. +        if (!tmp) {
  6330. +            try >>= 1; /* buffer only one side */
  6331. +            if (try < 16)
  6332. +                try=16;
  6333. +            tmp= (char *)dma_mem_alloc(1024*try);
  6334. +        }
  6335. +        if (!tmp) {
  6336. +            DPRINT("Unable to allocate DMA memory\n");
  6337. +            RETERR(ENXIO);
  6338. +        }
  6339. +        if (floppy_track_buffer){
  6340. +            free_pages((unsigned long)tmp,__get_order(try*1024));
  6341. +        }else {
  6342. +            floppy_track_buffer = tmp;
  6343. +            max_buffer_sectors = try;
  6344. +        }
  6345. +    }
  6346. +
  6347. +    UDRS->fd_device = MINOR(inode->i_rdev);
  6348. +
  6349. +    if (old_dev && old_dev != inode->i_rdev) {
  6350. +        if (buffer_drive == drive)
  6351. +            buffer_track = -1;
  6352. +        invalidate_buffers(old_dev);
  6353. +    }
  6354. +
  6355. +    /* Allow ioctls if we have write-permissions even if read-only open */
  6356. +    if ((filp->f_mode & 2) || (permission(inode,2) == 0))
  6357. +        filp->f_mode |= IOCTL_MODE_BIT;
  6358. +    if (filp->f_mode & 2)
  6359. +        filp->f_mode |= OPEN_WRITE_BIT;
  6360. +
  6361. +    if (UFDCS->rawcmd == 1)
  6362. +           UFDCS->rawcmd = 2;
  6363. +
  6364. +    if (filp->f_flags & O_NDELAY)
  6365. +        return 0;
  6366. +    if (filp->f_mode & 3) {
  6367. +        UDRS->last_checked = 0;
  6368. +        check_disk_change(inode->i_rdev);
  6369. +        if (UTESTF(FD_DISK_CHANGED))
  6370. +            RETERR(ENXIO);
  6371. +    }
  6372. +    if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE)))
  6373. +        RETERR(EROFS);
  6374. +    return 0;
  6375. +#undef RETERR
  6376. +}
  6377. +
  6378. +/*
  6379. + * Check if the disk has been changed or if a change has been faked.
  6380. + */
  6381. +static int check_floppy_change(kdev_t dev)
  6382. +{
  6383. +    int drive = DRIVE( dev );
  6384. +
  6385. +    if (MAJOR(dev) != MAJOR_NR) {
  6386. +        DPRINT("floppy_changed: not a floppy\n");
  6387. +        return 0;
  6388. +    }
  6389. +
  6390. +    if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
  6391. +        return 1;
  6392. +
  6393. +    if(UDRS->last_checked + UDP->checkfreq < jiffies){
  6394. +        lock_fdc(drive,0);
  6395. +        poll_drive(0,0);
  6396. +        process_fd_request();
  6397. +    }
  6398. +
  6399. +    if(UTESTF(FD_DISK_CHANGED) ||
  6400. +       UTESTF(FD_VERIFY) ||
  6401. +       test_bit(drive, &fake_change) ||
  6402. +       (!TYPE(dev) && !current_type[drive]))
  6403. +        return 1;
  6404. +    return 0;
  6405. +}
  6406. +
  6407. +/* revalidate the floppy disk, i.e. trigger format autodetection by reading
  6408. + * the bootblock (block 0). "Autodetection" is also needed to check whether
  6409. + * there is a disk in the drive at all... Thus we also do it for fixed
  6410. + * geometry formats */
  6411. +static int floppy_revalidate(kdev_t dev)
  6412. +{
  6413. +#define NO_GEOM (!current_type[drive] && !TYPE(dev))
  6414. +    struct buffer_head * bh;
  6415. +    int drive=DRIVE(dev);
  6416. +    int cf;
  6417. +
  6418. +    if(UTESTF(FD_DISK_CHANGED) ||
  6419. +       UTESTF(FD_VERIFY) ||
  6420. +       test_bit(drive, &fake_change) ||
  6421. +       NO_GEOM){
  6422. +        lock_fdc(drive,0);
  6423. +        cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
  6424. +        if(! (cf || test_bit(drive, &fake_change) || NO_GEOM)){
  6425. +            process_fd_request(); /* already done by another thread */
  6426. +            return 0;
  6427. +        }
  6428. +        UDRS->maxblock = 0;
  6429. +        UDRS->maxtrack = 0;
  6430. +        if ( buffer_drive == drive)
  6431. +            buffer_track = -1;
  6432. +        clear_bit(drive, &fake_change);
  6433. +        UCLEARF(FD_DISK_CHANGED);
  6434. +        if(cf)
  6435. +            UDRS->generation++;
  6436. +        if(NO_GEOM){
  6437. +            /* auto-sensing */
  6438. +            int size = floppy_blocksizes[MINOR(dev)];
  6439. +            if (!size)
  6440. +                size = 1024;
  6441. +            if (!(bh = getblk(dev,0,size))){
  6442. +                process_fd_request();
  6443. +                return 1;
  6444. +            }
  6445. +            if ( bh && ! bh->b_uptodate)
  6446. +                ll_rw_block(READ, 1, &bh);
  6447. +            process_fd_request();
  6448. +            wait_on_buffer(bh);
  6449. +            brelse(bh);
  6450. +            return 0;
  6451. +        }
  6452. +        if(cf)
  6453. +            poll_drive(0, FD_RAW_NEED_DISK);
  6454. +        process_fd_request();
  6455. +    }
  6456. +    return 0;
  6457. +}
  6458. +
  6459. +static struct file_operations floppy_fops = {
  6460. +    NULL,            /* lseek - default */
  6461. +    floppy_read,        /* read - general block-dev read */
  6462. +    floppy_write,        /* write - general block-dev write */
  6463. +    NULL,                   /* readdir - bad */
  6464. +    NULL,            /* select */
  6465. +    fd_ioctl,        /* ioctl */
  6466. +    NULL,            /* mmap */
  6467. +    floppy_open,        /* open */
  6468. +    floppy_release,        /* release */
  6469. +    block_fsync,        /* fsync */
  6470. +    NULL,            /* fasync */
  6471. +    check_floppy_change,    /* media_change */
  6472. +    floppy_revalidate,    /* revalidate */
  6473. +};
  6474. +
  6475. +/*
  6476. + * Floppy Driver initialisation
  6477. + * =============================
  6478. + */
  6479. +
  6480. +/* Determine the floppy disk controller type */
  6481. +/* This routine was written by David C. Niemi */
  6482. +static char get_fdc_version(void)
  6483. +{
  6484. +    int r;
  6485. +
  6486. +    output_byte(FD_DUMPREGS);    /* 82072 and better know DUMPREGS */
  6487. +    if ( FDCS->reset )
  6488. +        return FDC_NONE;
  6489. +    if ( (r = result()) <= 0x00)
  6490. +        return FDC_NONE;    /* No FDC present ??? */
  6491. +    if ((r==1) && (reply_buffer[0] == 0x80)){
  6492. +        printk("FDC %d is a 8272A\n",fdc);
  6493. +        return FDC_8272A;        /* 8272a/765 don't know DUMPREGS */
  6494. +    }
  6495. +    if (r != 10) {
  6496. +        printk("FDC init: DUMPREGS: unexpected return of %d bytes.\n", r);
  6497. +        return FDC_UNKNOWN;
  6498. +    }
  6499. +    output_byte(FD_VERSION);
  6500. +    r = result();
  6501. +    if ((r == 1) && (reply_buffer[0] == 0x80)){
  6502. +        printk("FDC %d is a 82072\n",fdc);
  6503. +        return FDC_82072;        /* 82072 doesn't know VERSION */
  6504. +    }
  6505. +    if ((r != 1) || (reply_buffer[0] != 0x90)) {
  6506. +        printk("FDC init: VERSION: unexpected return of %d bytes.\n", r);
  6507. +        return FDC_UNKNOWN;
  6508. +    }
  6509. +    output_byte(FD_UNLOCK);
  6510. +    r = result();
  6511. +    if ((r == 1) && (reply_buffer[0] == 0x80)){
  6512. +        printk("FDC %d is a pre-1991 82077\n", fdc);
  6513. +        return FDC_82077_ORIG;    /* Pre-1991 82077 doesn't know LOCK/UNLOCK */
  6514. +    }
  6515. +    if ((r != 1) || (reply_buffer[0] != 0x00)) {
  6516. +        printk("FDC init: UNLOCK: unexpected return of %d bytes.\n", r);
  6517. +        return FDC_UNKNOWN;
  6518. +    }
  6519. +    printk("FDC %d is a post-1991 82077\n",fdc);
  6520. +    return FDC_82077;    /* Revised 82077AA passes all the tests */
  6521. +} /* get_fdc_version */
  6522. +
  6523. +/* lilo configuration */
  6524. +
  6525. +/* we make the invert_dcl function global. One day, somebody might
  6526. +want to centralize all thinkpad related options into one lilo option,
  6527. +there are just so many thinkpad related quirks! */
  6528. +void floppy_invert_dcl(int *ints,int param)
  6529. +{
  6530. +    int i;
  6531. +
  6532. +    for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
  6533. +        if (param)
  6534. +            default_drive_params[i].params.flags |= 0x80;
  6535. +        else
  6536. +            default_drive_params[i].params.flags &= ~0x80;
  6537. +    }
  6538. +    DPRINT("Configuring drives for inverted dcl\n");
  6539. +}
  6540. +
  6541. +static void daring(int *ints,int param)
  6542. +{
  6543. +    int i;
  6544. +
  6545. +    for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
  6546. +        if (param){
  6547. +            default_drive_params[i].params.select_delay = 0;
  6548. +            default_drive_params[i].params.flags |= FD_SILENT_DCL_CLEAR;
  6549. +        } else {
  6550. +            default_drive_params[i].params.select_delay = 2*HZ/100;
  6551. +            default_drive_params[i].params.flags &= ~FD_SILENT_DCL_CLEAR;
  6552. +        }
  6553. +    }
  6554. +    DPRINT1("Assuming %s floppy hardware\n", param ? "standard" : "broken");
  6555. +}
  6556. +
  6557. +static void allow_drives(int *ints, int param)
  6558. +{
  6559. +    ALLOWED_DRIVE_MASK=param;
  6560. +    DPRINT1("setting allowed_drive_mask to 0x%x\n", param);
  6561. +}
  6562. +
  6563. +static void fdc2_adr(int *ints, int param)
  6564. +{
  6565. +    FDC2 = param;
  6566. +    if(param){
  6567. +        DPRINT1("enabling second fdc at address 0x%3x\n", FDC2);
  6568. +    } else
  6569. +        DPRINT("disabling second fdc\n");
  6570. +}
  6571. +
  6572. +static void unex(int *ints,int param)
  6573. +{
  6574. +    print_unex = param;
  6575. +    DPRINT1("%sprinting messages for unexpected interrupts\n",
  6576. +        param ? "" : "not ");
  6577. +}
  6578. +
  6579. +static void set_cmos(int *ints, int dummy)
  6580. +{
  6581. +    int current_drive=0;
  6582. +
  6583. +    if ( ints[0] != 2 ){
  6584. +        DPRINT("wrong number of parameters for cmos\n");
  6585. +        return;
  6586. +    }
  6587. +    current_drive = ints[1];
  6588. +    if (current_drive < 0 || current_drive >= 8 ){
  6589. +        DPRINT("bad drive for set_cmos\n");
  6590. +        return;
  6591. +    }
  6592. +    if(current_drive >= 4 && !FDC2)
  6593. +        fdc2_adr(0, 0x370);
  6594. +    if(ints[2] <= 0 || ints[2] >= NUMBER(default_drive_params)){
  6595. +        DPRINT1("bad cmos code %d\n", ints[2]);
  6596. +        return;
  6597. +    }
  6598. +    DP->cmos = ints[2];
  6599. +    DPRINT1("setting cmos code to %d\n", ints[2]);
  6600. +}
  6601. +
  6602. +static struct param_table {
  6603. +    const char *name;
  6604. +    void (*fn)(int *ints, int param);
  6605. +    int def_param;
  6606. +} config_params[]={
  6607. +    { "allowed_drive_mask", allow_drives, 0xff },
  6608. +    { "all_drives", allow_drives, 0xff },
  6609. +    { "asus_pci", allow_drives, 0x33 },
  6610. +
  6611. +    { "daring", daring, 1 },
  6612. +
  6613. +    { "two_fdc", fdc2_adr, 0x370 },
  6614. +    { "one_fdc", fdc2_adr, 0 },
  6615. +
  6616. +    { "thinkpad", floppy_invert_dcl, 1 },
  6617. +
  6618. +    { "cmos", set_cmos, 0 },
  6619. +
  6620. +    { "unexpected_interrupts", unex, 1 },
  6621. +    { "no_unexpected_interrupts", unex, 0 },
  6622. +    { "L40SX", unex, 0 } };
  6623. +
  6624. +#define FLOPPY_SETUP
  6625. +void floppy_setup(char *str, int *ints)
  6626. +{
  6627. +    int i;
  6628. +    int param;
  6629. +    if(str)
  6630. +        for(i=0; i< ARRAY_SIZE(config_params); i++){
  6631. +            if (strcmp(str,config_params[i].name) == 0 ){
  6632. +                if (ints[0] )
  6633. +                    param = ints[1];
  6634. +                else
  6635. +                    param = config_params[i].def_param;
  6636. +                config_params[i].fn(ints,param);
  6637. +                return;
  6638. +            }
  6639. +        }
  6640. +    if(str) {
  6641. +        DPRINT1("unknown floppy option [%s]\n", str);
  6642. +
  6643. +        DPRINT("allowed options are:");
  6644. +        for(i=0; i< ARRAY_SIZE(config_params); i++)
  6645. +            printk(" %s",config_params[i].name);
  6646. +        printk("\n");
  6647. +    } else
  6648. +        DPRINT("botched floppy option\n");
  6649. +    DPRINT("Read linux/arch/arm/drivers/block/README.fd\n");
  6650. +}
  6651. +
  6652. +int floppy_init(void)
  6653. +{
  6654. +    int i,unit,drive;
  6655. +    int have_no_fdc=0;
  6656. +
  6657. +    raw_cmd = NULL;
  6658. +
  6659. +    sti();
  6660. +
  6661. +    if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
  6662. +        printk("Unable to get major %d for floppy\n",MAJOR_NR);
  6663. +        return -EBUSY;
  6664. +    }
  6665. +
  6666. +    for(i=0; i<256; i++)
  6667. +        if (TYPE(i))
  6668. +            floppy_sizes[i] = floppy_type[TYPE(i)].size >> 1;
  6669. +        else
  6670. +            floppy_sizes[i] = MAX_DISK_SIZE;
  6671. +
  6672. +    blk_size[MAJOR_NR] = floppy_sizes;
  6673. +    blksize_size[MAJOR_NR] = floppy_blocksizes;
  6674. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  6675. +    reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
  6676. +    config_types();
  6677. +
  6678. +    fdc_state[0].address = FDC1;
  6679. +    fdc_state[0].dor = 0;
  6680. +#if N_FDC > 1
  6681. +    fdc_state[1].address = FDC2;
  6682. +    fdc_state[1].dor = 0;
  6683. +#endif
  6684. +
  6685. +    for (i = 0 ; i < N_FDC ; i++) {
  6686. +        fdc = i;
  6687. +        FDCS->dtr = -1;
  6688. +        FDCS->dor = 0x4;
  6689. +        FDCS->reset = 0;
  6690. +        FDCS->version = FDC_NONE;
  6691. +    }
  6692. +
  6693. +    if(floppy_grab_irq_and_dma()){
  6694. +        unregister_blkdev(MAJOR_NR,"fd");
  6695. +        return -EBUSY;
  6696. +    }
  6697. +
  6698. +    /* initialise drive state */
  6699. +    for (drive = 0; drive < N_DRIVE ; drive++) {
  6700. +        UDRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE | FD_DISK_CHANGED;
  6701. +        UDRS->generation = 0;
  6702. +        UDRS->keep_data = 0;
  6703. +        UDRS->fd_ref = 0;
  6704. +        UDRS->fd_device = 0;
  6705. +        floppy_track_buffer = NULL;
  6706. +        max_buffer_sectors = 0;
  6707. +        UDRWE->write_errors = 0;
  6708. +        UDRWE->first_error_sector = 0;
  6709. +        UDRWE->first_error_generation = 0;
  6710. +        UDRWE->last_error_sector = 0;
  6711. +        UDRWE->last_error_generation = 0;
  6712. +        UDRWE->badness = 0;
  6713. +    }
  6714. +
  6715. +    for (i = 0 ; i < N_FDC ; i++) {
  6716. +        fdc = i;
  6717. +        FDCS->driver_version = FD_DRIVER_VERSION;
  6718. +        for(unit=0; unit<4; unit++)
  6719. +            FDCS->track[unit] = 0;
  6720. +        if (FDCS->address == -1 )
  6721. +            continue;
  6722. +        FDCS->rawcmd = 2;
  6723. +        if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0)){
  6724. +            FDCS->address = -1;
  6725. +            continue;
  6726. +        }
  6727. +        /* Try to determine the floppy controller type */
  6728. +        FDCS->version = get_fdc_version();
  6729. +        if (FDCS->version == FDC_NONE){
  6730. +            FDCS->address = -1;
  6731. +            continue;
  6732. +        }
  6733. +
  6734. +        request_region(FDCS->address, 6, "floppy");
  6735. +        request_region(FDCS->address+7, 1, "floppy DIR");
  6736. +        /* address + 6 is reserved, and may be taken by IDE.
  6737. +         * Unfortunately, Adaptec doesn't know this :-(, */
  6738. +
  6739. +        have_no_fdc = 0;
  6740. +        /* Not all FDCs seem to be able to handle the version command
  6741. +         * properly, so force a reset for the standard FDC clones,
  6742. +         * to avoid interrupt garbage.
  6743. +         */
  6744. +        FDCS->has_fifo = FDCS->version >= FDC_82077_ORIG;
  6745. +        user_reset_fdc(-1,FD_RESET_ALWAYS,0);
  6746. +    }
  6747. +    fdc=0;
  6748. +    del_timer(&fd_timeout);
  6749. +    current_drive = 0;
  6750. +    floppy_release_irq_and_dma();
  6751. +    initialising=0;
  6752. +    if(have_no_fdc)
  6753. +        unregister_blkdev(MAJOR_NR,"fd");
  6754. +    return have_no_fdc;
  6755. +}
  6756. +
  6757. +static int floppy_grab_irq_and_dma(void)
  6758. +{
  6759. +    int i;
  6760. +    cli();
  6761. +    if (usage_count++){
  6762. +        sti();
  6763. +        return 0;
  6764. +    }
  6765. +    sti();
  6766. +#ifdef FD_MODULE
  6767. +    MOD_INC_USE_COUNT;
  6768. +#endif
  6769. +    for(i=0; i< N_FDC; i++){
  6770. +        if(FDCS->address != -1){
  6771. +            fdc = i;
  6772. +            reset_fdc_info(1);
  6773. +            arm_set_dor(FDCS->dor);
  6774. +        }
  6775. +    }
  6776. +    set_dor(0, ~0, 8);  /* avoid immediate interrupt */
  6777. +
  6778. +    if (request_irq(FLOPPY_IRQ, floppy_interrupt, 
  6779. +            SA_INTERRUPT|SA_SAMPLE_RANDOM, "floppy")) {
  6780. +        DPRINT1("Unable to grab IRQ%d for the floppy driver\n",
  6781. +            FLOPPY_IRQ);
  6782. +        return -1;
  6783. +    }
  6784. +    if (request_dma(FLOPPY_DMA,"floppy")) {
  6785. +        DPRINT1("Unable to grab DMA%d for the floppy driver\n",
  6786. +            FLOPPY_DMA);
  6787. +        free_irq(FLOPPY_IRQ);
  6788. +        return -1;
  6789. +    }
  6790. +    for(fdc = 0; fdc < N_FDC ; fdc++)
  6791. +        if(FDCS->address != -1)
  6792. +            arm_set_dor(FDCS->dor);
  6793. +    fdc = 0;
  6794. +    enable_irq(FLOPPY_IRQ);
  6795. +    return 0;
  6796. +}
  6797. +
  6798. +static void floppy_release_irq_and_dma(void)
  6799. +{
  6800. +#ifdef CONFIG_FLOPPY_SANITY
  6801. +    int drive;
  6802. +#endif
  6803. +    long tmpsize;
  6804. +    void *tmpaddr;
  6805. +
  6806. +    cli();
  6807. +    if (--usage_count){
  6808. +        sti();
  6809. +        return;
  6810. +    }
  6811. +    sti();
  6812. +#ifdef FD_MODULE
  6813. +    MOD_DEC_USE_COUNT;
  6814. +#endif
  6815. +    disable_dma(FLOPPY_DMA);
  6816. +    free_dma(FLOPPY_DMA);
  6817. +    disable_irq(FLOPPY_IRQ);
  6818. +    free_irq(FLOPPY_IRQ);
  6819. +
  6820. +    set_dor(0, ~0, 8);
  6821. +#if N_FDC > 1
  6822. +    set_dor(1, ~8, 0);
  6823. +#endif
  6824. +    floppy_enable_hlt();
  6825. +
  6826. +    if (floppy_track_buffer && max_buffer_sectors) {
  6827. +        tmpsize = max_buffer_sectors*1024;
  6828. +        tmpaddr = (void *)floppy_track_buffer;
  6829. +        floppy_track_buffer = NULL;
  6830. +        max_buffer_sectors = 0;
  6831. +        free_pages((unsigned long)tmpaddr, __get_order(tmpsize));
  6832. +    }
  6833. +
  6834. +#ifdef CONFIG_FLOPPY_SANITY
  6835. +    for(drive=0; drive < N_FDC * 4; drive++)
  6836. +        if( motor_off_timer[drive].next )
  6837. +            printk("motor off timer %d still active\n", drive);
  6838. +
  6839. +    if(fd_timeout.next)
  6840. +        printk("floppy timer still active:%s\n", timeout_message);
  6841. +    if (fd_timer.next)
  6842. +        printk("auxillary floppy timer still active\n");
  6843. +    if(floppy_tq.sync)
  6844. +        printk("task queue still active\n");
  6845. +#endif
  6846. +}
  6847. +
  6848. +
  6849. +#ifdef MODULE
  6850. +
  6851. +extern char *get_options(char *str, int *ints);
  6852. +
  6853. +static void mod_setup(char *pattern, void (*setup)(char *, int *))
  6854. +{
  6855. +    int i;
  6856. +    char c;
  6857. +    int j;
  6858. +    int match;
  6859. +    char buffer[100];
  6860. +    int ints[11];
  6861. +    int length = strlen(pattern)+1;
  6862. +
  6863. +    match=0;
  6864. +    j=1;
  6865. +
  6866. +    for(i=current->mm->env_start; i< current->mm->env_end; i ++){
  6867. +        c= get_fs_byte(i);
  6868. +        if(match){
  6869. +            if(j==99)
  6870. +                c='\0';
  6871. +            buffer[j] = c;
  6872. +            if(!c || c == ' ' || c == '\t'){
  6873. +                if(j){
  6874. +                    buffer[j] = '\0';
  6875. +                    setup(get_options(buffer,ints),ints);
  6876. +                }
  6877. +                j=0;
  6878. +            } else
  6879. +                j++;
  6880. +            if(!c)
  6881. +                break;
  6882. +            continue;
  6883. +        }
  6884. +        if( (!j && !c) || ( j && c == pattern[j-1]))
  6885. +            j++;
  6886. +        else
  6887. +            j=0;
  6888. +        if(j==length){
  6889. +            match=1;
  6890. +            j=0;
  6891. +        }
  6892. +    }
  6893. +}
  6894. +
  6895. +
  6896. +#ifdef __cplusplus
  6897. +extern "C" {
  6898. +#endif
  6899. +int init_module(void)
  6900. +{
  6901. +    int ret;
  6902. +    printk("inserting floppy driver for %s\n", kernel_version);
  6903. +
  6904. +    mod_setup("floppy=", floppy_setup);
  6905. +
  6906. +    ret = floppy_init();
  6907. +        return 0;
  6908. +}
  6909. +
  6910. +void cleanup_module(void)
  6911. +{
  6912. +    int fdc;
  6913. +
  6914. +    for(fdc=0; fdc<2; fdc++)
  6915. +        if (FDCS->address != -1){
  6916. +            release_region(FDCS->address, 6);
  6917. +            release_region(FDCS->address+7, 1);
  6918. +        }
  6919. +
  6920. +    unregister_blkdev(MAJOR_NR, "fd");
  6921. +
  6922. +    blk_dev[MAJOR_NR].request_fn = 0;
  6923. +}
  6924. +
  6925. +#ifdef __cplusplus
  6926. +}
  6927. +#endif
  6928. +
  6929. +#endif
  6930. diff -urNwbB linux/arch/arm/drivers/block/genhd.c linux.arm/arch/arm/drivers/block/genhd.c
  6931. --- linux/arch/arm/drivers/block/genhd.c    Thu Jan  1 01:00:00 1970
  6932. +++ linux.arm/arch/arm/drivers/block/genhd.c    Sun Mar  3 12:22:14 1996
  6933. @@ -0,0 +1,506 @@
  6934. +/*
  6935. + *  Code extracted from
  6936. + *  linux/kernel/hd.c
  6937. + *
  6938. + *  Copyright (C) 1991, 1992  Linus Torvalds
  6939. + *
  6940. + *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  6941. + *  in the early extended-partition checks and added DM partitions
  6942. + *
  6943. + *  Support for DiskManager v6.0x added by Mark Lord (mlord@bnr.ca)
  6944. + *  with information provided by OnTrack.  This now works for linux fdisk
  6945. + *  and LILO, as well as loadlin and bootln.  Note that disks other than
  6946. + *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
  6947. + *
  6948. + *  More flexible handling of extended partitions - aeb, 950831
  6949. + *
  6950. + *  Modifications Copyright (C) 1995, 1996 Russell King
  6951. + *
  6952. + *  Origional from linux/drivers/genhd.c
  6953. + *
  6954. + *  Altered to find image files on ADFS-formatted hard drives.
  6955. + */
  6956. +
  6957. +#include <linux/config.h>
  6958. +#include <linux/fs.h>
  6959. +#include <linux/genhd.h>
  6960. +#include <linux/kernel.h>
  6961. +#include <linux/major.h>
  6962. +#include <linux/string.h>
  6963. +
  6964. +#include <asm/system.h>
  6965. +
  6966. +struct gendisk *gendisk_head = NULL;
  6967. +
  6968. +static int current_minor = 0;
  6969. +extern int *blk_size[];
  6970. +extern void rd_load(void);
  6971. +extern int ramdisk_size;
  6972. +
  6973. +extern int chr_dev_init(void);
  6974. +extern int blk_dev_init(void);
  6975. +extern int scsi_dev_init(void);
  6976. +extern int net_dev_init(void);
  6977. +
  6978. +static void print_minor_name (struct gendisk *hd, int minor)
  6979. +{
  6980. +    unsigned int unit = minor >> hd->minor_shift;
  6981. +    unsigned int part = minor & ((1 << hd->minor_shift) - 1);
  6982. +
  6983. +#ifdef CONFIG_BLK_DEV_IDE
  6984. +    /*
  6985. +     * IDE devices use multiple major numbers, but the drives
  6986. +     * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
  6987. +     * This requires some creative handling here to find the
  6988. +     * correct name to use, with some help from ide.c
  6989. +     */
  6990. +    if (!strcmp(hd->major_name, "ide")) {
  6991. +        char name[16];        /* more than large enough */
  6992. +        strcpy(name, hd->real_devices); /* courtesy ide.c */
  6993. +        name[strlen(name)-1] += unit;
  6994. +        printk(" %s", name);
  6995. +    } else
  6996. +#endif
  6997. +        printk(" %s%c", hd->major_name, 'a' + unit);
  6998. +    if (part)
  6999. +        printk("%d", part);
  7000. +    else
  7001. +        printk(":");
  7002. +}
  7003. +
  7004. +static void add_partition (struct gendisk *hd, int minor, int start, int size)
  7005. +{
  7006. +    hd->part[minor].start_sect = start;
  7007. +    hd->part[minor].nr_sects   = size;
  7008. +    print_minor_name(hd, minor);
  7009. +}
  7010. +
  7011. +static inline unsigned long get_word(const unsigned int *addr)
  7012. +{
  7013. +    const unsigned char *ac = (const unsigned char *)addr;
  7014. +    if ((int)addr & 3)
  7015. +        return ac[0] | ac[1]<<8 | ac[2]<<16 | ac[3]<<24;
  7016. +    else
  7017. +        return addr[0];
  7018. +}
  7019. +
  7020. +#ifdef CONFIG_MSDOS_PARTITION
  7021. +static inline int is_extended_partition(struct partition *p)
  7022. +{
  7023. +    return (p->sys_ind == DOS_EXTENDED_PARTITION ||
  7024. +        p->sys_ind == LINUX_EXTENDED_PARTITION);
  7025. +}
  7026. +
  7027. +/*
  7028. + * Create devices for each logical partition in an extended partition.
  7029. + * The logical partitions form a linked list, with each entry being
  7030. + * a partition table with two entries.  The first entry
  7031. + * is the real data partition (with a start relative to the partition
  7032. + * table start).  The second is a pointer to the next logical partition
  7033. + * (with a start relative to the entire extended partition).
  7034. + * We do not create a Linux partition for the partition tables, but
  7035. + * only for the actual data partitions.
  7036. + */
  7037. +
  7038. +static void extended_partition(struct gendisk *hd, kdev_t dev)
  7039. +{
  7040. +    struct buffer_head *bh;
  7041. +    struct partition *p;
  7042. +    unsigned long first_sector, first_size, this_sector, this_size;
  7043. +    unsigned long start_sect, nr_sects;
  7044. +    int mask = (1 << hd->minor_shift) - 1;
  7045. +    int i;
  7046. +
  7047. +    first_sector = hd->part[MINOR(dev)].start_sect;
  7048. +    first_size = hd->part[MINOR(dev)].nr_sects;
  7049. +    this_sector = first_sector;
  7050. +
  7051. +    while (1) {
  7052. +        if ((current_minor & mask) == 0)
  7053. +            return;
  7054. +        if (!(bh = bread(dev,0,1024)))
  7055. +            return;
  7056. +      /*
  7057. +       * This block is from a device that we're about to stomp on.
  7058. +       * So make sure nobody thinks this block is usable.
  7059. +       */
  7060. +        bh->b_dirt = 0;
  7061. +        bh->b_uptodate = 0;
  7062. +        bh->b_req = 0;
  7063. +        
  7064. +        if (*(unsigned short *) (bh->b_data+510) != 0xAA55)
  7065. +            goto done;
  7066. +
  7067. +        p = (struct partition *) (0x1BE + bh->b_data);
  7068. +
  7069. +        this_size = hd->part[MINOR(dev)].nr_sects;
  7070. +
  7071. +        /*
  7072. +         * Usually, the first entry is the real data partition,
  7073. +         * the 2nd entry is the next extended partition, or empty,
  7074. +         * and the 3rd and 4th entries are unused.
  7075. +         * However, DRDOS sometimes has an extended partition as
  7076. +         * the first entry (when the data partition is empty),
  7077. +         * and OS/2 seems to use all four entries.
  7078. +         */
  7079. +         
  7080. +        /*
  7081. +         * First process the data partition(s)
  7082. +         */
  7083. +        for (i = 0; i < 4; i++, p++) {
  7084. +            nr_sects = get_word (&p->nr_sects);
  7085. +            if (!nr_sects || is_extended_partition(p))
  7086. +                continue;
  7087. +
  7088. +            /*
  7089. +             * Check the 3rd and 4th entries -
  7090. +             * these sometimes contain random garbage
  7091. +             */
  7092. +            start_sect = get_word (&p->start_sect);
  7093. +            if (i >= 2
  7094. +                && start_sect + nr_sects > this_size
  7095. +                && (this_sector + start_sect < first_sector ||
  7096. +                    this_sector + start_sect + first_sector >
  7097. +                     first_sector + first_size))
  7098. +                continue;
  7099. +
  7100. +            add_partition(hd, current_minor, this_sector+start_sect, nr_sects);
  7101. +            current_minor++;
  7102. +            if ((current_minor & mask) == 0)
  7103. +                goto done;
  7104. +        }
  7105. +        /*
  7106. +         * Next, process the (first) extended partition, if present/
  7107. +         * (So far, there seems to be no reason to make
  7108. +         *  extended_partition() recurse and allow a tree
  7109. +         *  of extended partitions.)
  7110. +         * It should be a link to the next logical partition.
  7111. +         * Create a minor for this just long enough to get the next
  7112. +         * partition table.  The minor will be reused for the next
  7113. +         * data partition.
  7114. +         */
  7115. +        p -= 4;
  7116. +        for (i=0; i<4; i++) {
  7117. +            nr_sects = get_word (&p->nr_sects);
  7118. +            if (nr_sects && is_extended_partition(p))
  7119. +                break;
  7120. +        }
  7121. +        
  7122. +        if (i == 4)
  7123. +            goto done;    /* nothing left to do */
  7124. +
  7125. +        start_sect = get_word (&p->start_sect);
  7126. +        hd->part[current_minor].nr_sects = nr_sects;
  7127. +        hd->part[current_minor].start_sect = first_sector + start_sect;
  7128. +        this_sector = first_sector + start_sect;
  7129. +        dev = MKDEV(hd->major, current_minor);
  7130. +        brelse(bh);
  7131. +    }
  7132. +done:
  7133. +    brelse(bh);
  7134. +}
  7135. +
  7136. +static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
  7137. +{
  7138. +    int i, minor = current_minor;
  7139. +    struct buffer_head *bh;
  7140. +    struct partition *p;
  7141. +    unsigned char *data;
  7142. +    int mask = (1 << hd->minor_shift) - 1;
  7143. +    unsigned long start_sect, nr_sects;
  7144. +#ifdef CONFIG_BLK_DEV_IDE
  7145. +    int tested_for_dm6 = 0;
  7146. +
  7147. +read_mbr:
  7148. +#endif
  7149. +    if (!(bh = bread(dev,0,1024))) {
  7150. +        printk(" unable to read partition table\n");
  7151. +        return -1;
  7152. +    }
  7153. +    data = bh->b_data;
  7154. +    bh->b_dirt = 0;        /* In some cases we modify the geometry    */
  7155. +    bh->b_uptodate = 0;    /*  of the drive (below), so ensure that   */ 
  7156. +    bh->b_req = 0;        /*  nobody else tries to re-use this data. */
  7157. +#ifdef CONFIG_BLK_DEV_IDE
  7158. +check_table:
  7159. +#endif
  7160. +    if (*(unsigned short *)  (0x1fe + data) != 0xAA55) {
  7161. +        brelse(bh);
  7162. +        return 0;
  7163. +    }
  7164. +    p = (struct partition *) (0x1be + data);
  7165. +
  7166. +#ifdef CONFIG_BLK_DEV_IDE
  7167. +    /*
  7168. +     * Check for Disk Manager v6.0x (or EZ-DRIVE) with geometry translation
  7169. +     */
  7170. +    if (!tested_for_dm6++) {    /* Only check for DM6 *once* */
  7171. +        extern int ide_xlate_1024(kdev_t, int, const char *);
  7172. +        /* check for various "disk managers" which do strange things */
  7173. +        if (p->sys_ind == EZD_PARTITION) {
  7174. +            /*
  7175. +             * The remainder of the disk must be accessed using
  7176. +             * a translated geometry that reduces the number of
  7177. +             * apparant cylinders to less than 1024 if possible.
  7178. +             *
  7179. +             * ide_xlate_1024() will take care of the necessary
  7180. +             * adjustments to fool fdisk/LILO and partition check.
  7181. +             */
  7182. +            if (ide_xlate_1024(dev, -1, " [EZD]")) {
  7183. +                data += 512;
  7184. +                goto check_table;
  7185. +            }
  7186. +        } else if (p->sys_ind == DM6_PARTITION) {
  7187. +            /*
  7188. +             * Everything on the disk is offset by 63 sectors,
  7189. +             * including the "new" MBR with its own partition table,
  7190. +             * and the remainder of the disk must be accessed using
  7191. +             * a translated geometry that reduces the number of
  7192. +             * apparant cylinders to less than 1024 if possible.
  7193. +             *
  7194. +             * ide_xlate_1024() will take care of the necessary
  7195. +             * adjustments to fool fdisk/LILO and partition check.
  7196. +             */
  7197. +            if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) {
  7198. +                brelse(bh);
  7199. +                goto read_mbr;
  7200. +            }
  7201. +        } else {
  7202. +            /*
  7203. +             * look for DM6 signature in MBR, courtesy of OnTrack
  7204. +             */
  7205. +            unsigned int sig = *(unsigned short *)(data + 2);
  7206. +            if (sig <= 0x1ae && *(unsigned short *)(data + sig) = 0x55AA
  7207. +                && (1 & *(unsigned char *)(data + sig + 2)))
  7208. +                    ide_xlate_1024(dev, 0, " [DM6:MBR]");
  7209. +            else if (p->sys_ind == DM6_AUX1PARTITION
  7210. +                  || p->sys_ind == DM6_AUX3PARTITION)
  7211. +                ide_xlate_1024(dev, 0, " [DM6:AUX]");
  7212. +        }
  7213. +    }
  7214. +#endif /* CONFIG_BLK_DEV_IDE */
  7215. +
  7216. +    current_minor += 4;
  7217. +    for (i=1 ; i<=4 ; minor++, i++, p++) {
  7218. +        nr_sects = get_word (&p->nr_sects);
  7219. +        if(!nr_sects)
  7220. +            continue;
  7221. +        start_sect = get_word (&p->start_sect);
  7222. +        add_partition(hd, minor, first_sector+start_sect, nr_sects);
  7223. +        if (is_extended_partition(p)) {
  7224. +            printk(" <");
  7225. +            /*
  7226. +             * If we are rereading the partition table, we need
  7227. +             * to set the size of the partition so that we will
  7228. +             * be able to bread the block containing the extended
  7229. +             * partition info.
  7230. +             */
  7231. +            hd->sizes[minor] = hd->part[minor].nr_sects >> (BLOCK_SIZE_BITS - 9);
  7232. +            extended_partition(hd, MKDEV(hd->major, minor));
  7233. +            printk(" >");
  7234. +            /*
  7235. +             * prevent someone doing mkfs or mkswap on an
  7236. +             * extended partition, but leave room for LILO
  7237. +             */
  7238. +            if (hd->part[minor].nr_sects > 2)
  7239. +                hd->part[minor].nr_sects = 2;
  7240. +        }
  7241. +    }
  7242. +    /*
  7243. +     * Check for old-style Disk Manager partition table
  7244. +     */
  7245. +    if (*(unsigned short *) (data + 0xfc) == 0x55AA) {
  7246. +        p = (struct partition *) (0x1be + data);
  7247. +        for (i = 4 ; i < 16 ; i++, current_minor++) {
  7248. +            p--;
  7249. +            if ((current_minor & mask) == 0)
  7250. +                break;
  7251. +            nr_sects = get_word (&p->nr_sects);
  7252. +            start_sect = get_word (&p->start_sect);
  7253. +            if (!(start_sect && nr_sects))
  7254. +                continue;
  7255. +            add_partition(hd, current_minor, start_sect, nr_sects);
  7256. +        }
  7257. +    }
  7258. +    printk("\n");
  7259. +    brelse(bh);
  7260. +    return 1;
  7261. +}             
  7262. +
  7263. +#endif /* CONFIG_MSDOS_PARTITION */
  7264. +
  7265. +/* 'ARM hard drives' minor allocation:
  7266. + *   physical hd    = minor >> hd->minor_shift
  7267. + *   image file        = (minor-1) & 3
  7268. + *   extra file        = image file + n<<2
  7269. + */
  7270. +
  7271. +extern int image_allocate_list(int dev,int minor,struct hd_struct *);
  7272. +extern void image_release_dev(int dev);
  7273. +
  7274. +static void pc_check_hd(struct gendisk *hd, int minor)
  7275. +{ /* minor is the whole device minor */
  7276. +    int dev = (hd->major << 8)+minor;
  7277. +    int i;
  7278. +    struct buffer_head *bh;
  7279. +    struct partition *p;
  7280. +    
  7281. +    minor+=4;
  7282. +#define GET_WORD(n) (((unsigned char *)&n)[0] + (((unsigned char *)&n)[1] << 8) + \
  7283. +            (((unsigned char *)&n)[2] << 16) + (((unsigned char *)&n)[3] << 24))
  7284. +
  7285. +    if (!(bh = bread(dev,0,1024))) {
  7286. +        printk("  unable to read partition table of device %04x\n",dev);
  7287. +        return;
  7288. +    }
  7289. +    if (*(unsigned short *) (bh->b_data + 510) == 0xAA55) {
  7290. +        printk(" <");
  7291. +        p = (struct partition *) (0x1BE + bh->b_data);
  7292. +        for (i=1 ; i<=4 ; minor+=4,i++,p++) {
  7293. +            if (!(hd->part[minor].nr_sects = GET_WORD(p->nr_sects)))
  7294. +                continue;
  7295. +            hd->part[minor].start_sect = GET_WORD(p->start_sect);
  7296. +            print_minor_name (hd, minor);
  7297. +        }
  7298. +        printk(" >");
  7299. +    }
  7300. +#undef GET_WORD
  7301. +}
  7302. +
  7303. +static int arm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
  7304. +{
  7305. +    int i, minor = current_minor;
  7306. +
  7307. +    current_minor += 4;
  7308. +    
  7309. +    for (i = 1; i <= 4; minor++, i++) {
  7310. +        int len;
  7311. +        len = image_allocate_list (dev, minor, &hd->part[minor]);
  7312. +        if (len) {
  7313. +            print_minor_name(hd, minor);
  7314. +            pc_check_hd(hd, minor);
  7315. +        }
  7316. +    }
  7317. +    printk("\n");
  7318. +    image_release_dev (dev);
  7319. +    return 1;
  7320. +}
  7321. +
  7322. +static void check_partition(struct gendisk *hd, kdev_t dev)
  7323. +{
  7324. +    static int first_time = 1;
  7325. +    unsigned long first_sector;
  7326. +    struct buffer_head *bh;
  7327. +
  7328. +    if (first_time)
  7329. +        printk("Partition check:\n");
  7330. +    first_time = 0;
  7331. +    first_sector = hd->part[MINOR(dev)].start_sect;
  7332. +
  7333. +    /*
  7334. +     * This is a kludge to allow the partition check to be
  7335. +     * skipped for specific drives (e.g. IDE cd-rom drives)
  7336. +     */
  7337. +    if ((int)first_sector == -1) {
  7338. +        hd->part[MINOR(dev)].start_sect = 0;
  7339. +        return;
  7340. +    }
  7341. +
  7342. +    /*
  7343. +     * kludge - read a k of data from the drive so that hd.c can
  7344. +     * print its bits
  7345. +     */
  7346. +    bh = bread (dev, 0, 1024);
  7347. +    brelse (bh);
  7348. +
  7349. +    printk(" ");
  7350. +    print_minor_name(hd, MINOR(dev));
  7351. +
  7352. +#ifdef CONFIG_MSDOS_PARTITION
  7353. +    if (msdos_partition(hd, dev, first_sector))
  7354. +        return;
  7355. +#endif
  7356. +    if (arm_partition(hd, dev, first_sector))
  7357. +        return;
  7358. +
  7359. +    printk(" unknown partition table\n");
  7360. +}
  7361. +
  7362. +/* This function is used to re-read partition tables for removable disks.
  7363. +   Much of the cleanup from the old partition tables should have already been
  7364. +   done */
  7365. +
  7366. +/* This function will re-read the partition tables for a given device,
  7367. +and set things back up again.  There are some important caveats,
  7368. +however.  You must ensure that no one is using the device, and no one
  7369. +can start using the device while this function is being executed. */
  7370. +
  7371. +void resetup_one_dev(struct gendisk *dev, int drive)
  7372. +{
  7373. +    int i;
  7374. +    int first_minor = drive << dev->minor_shift;
  7375. +    int end_minor   = first_minor + dev->max_p;
  7376. +
  7377. +    blk_size[dev->major] = NULL;
  7378. +    current_minor = 1 + first_minor;
  7379. +    check_partition(dev, MKDEV(dev->major, first_minor));
  7380. +
  7381. +    /*
  7382. +     * We need to set the sizes array before we will be able to access
  7383. +     * any of the partitions on this device.
  7384. +     */
  7385. +    if (dev->sizes != NULL) {    /* optional safeguard in ll_rw_blk.c */
  7386. +        for (i = first_minor; i < end_minor; i++)
  7387. +            dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
  7388. +        blk_size[dev->major] = dev->sizes;
  7389. +    }
  7390. +}
  7391. +
  7392. +static void setup_dev(struct gendisk *dev)
  7393. +{
  7394. +    int i, drive;
  7395. +    int end_minor    = dev->max_nr * dev->max_p;
  7396. +
  7397. +    blk_size[dev->major] = NULL;
  7398. +    for (i = 0 ; i < end_minor; i++)  {
  7399. +        dev->part[i].start_sect = 0;
  7400. +        dev->part[i].nr_sects = 0;
  7401. +    }
  7402. +    dev->init(dev);
  7403. +    for (drive=0 ; drive < dev->nr_real ; drive++) {
  7404. +        int first_minor = drive << dev->minor_shift;
  7405. +        current_minor = 1 + first_minor;
  7406. +        check_partition(dev, MKDEV(dev->major, first_minor));
  7407. +    }
  7408. +    if (dev->sizes != NULL) {    /* optional safeguard in ll_rw_blk.c */
  7409. +        for (i = 0 ; i < end_minor; i++)
  7410. +            dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
  7411. +        blk_size[dev->major] = dev->sizes;
  7412. +    }
  7413. +}
  7414. +
  7415. +void device_setup(void)
  7416. +{
  7417. +    extern void console_map_init(void);
  7418. +    struct gendisk *p;
  7419. +    int nr=0;
  7420. +
  7421. +    chr_dev_init();
  7422. +    blk_dev_init();
  7423. +    sti();
  7424. +#ifdef CONFIG_SCSI
  7425. +    scsi_dev_init();
  7426. +#endif
  7427. +#ifdef CONFIG_INET
  7428. +    net_dev_init();
  7429. +#endif
  7430. +    console_map_init();
  7431. +
  7432. +    for (p = gendisk_head ; p ; p=p->next) {
  7433. +        setup_dev(p);
  7434. +        nr += p->nr_real;
  7435. +    }
  7436. +
  7437. +    if (ramdisk_size)
  7438. +        rd_load();
  7439. +}
  7440. diff -urNwbB linux/arch/arm/drivers/block/hd.c linux.arm/arch/arm/drivers/block/hd.c
  7441. --- linux/arch/arm/drivers/block/hd.c    Thu Jan  1 01:00:00 1970
  7442. +++ linux.arm/arch/arm/drivers/block/hd.c    Sun Mar  3 12:24:12 1996
  7443. @@ -0,0 +1,1238 @@
  7444. +/*
  7445. + *  linux/arch/arm/drivers/block/hd.c
  7446. + *   [ origional file: linux/drivers/block/hd.c ]
  7447. + *
  7448. + *  Copyright (C) 1991, 1992  Linus Torvalds
  7449. + *  Modified 1995  Russell King for ARM.
  7450. + */
  7451. +
  7452. +/*
  7453. + * This is the low-level hd interrupt support. It traverses the
  7454. + * request-list, using interrupts to jump between functions. As
  7455. + * all the functions are called within interrupts, we may not
  7456. + * sleep. Special care is recommended.
  7457. + * 
  7458. + *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
  7459. + *
  7460. + *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  7461. + *  in the early extended-partition checks and added DM partitions
  7462. + *
  7463. + *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
  7464. + *  and general streamlining by mlord@bnr.ca (Mark Lord).
  7465. + *
  7466. + * Majorly hacked request routines to support image files. (RMK)
  7467. + *  I am quite confident about these changes for the ARM, so long as
  7468. + *  Multimode is not turned on...
  7469. + */
  7470. +
  7471. +/* This is the maximum number of fragments accessed in one go */
  7472. +int no_hds;
  7473. +#define MAX_FRAGS    16
  7474. +static unsigned long frag_start[MAX_FRAGS];    /* Start of fragments */
  7475. +static unsigned long frag_len[MAX_FRAGS];    /* Fragment length */
  7476. +static int frag_count;                /* Number of fragments to go */
  7477. +static int frag_pos;                /* Position in fragment arrays */
  7478. +static unsigned int frag_sectors;
  7479. +
  7480. +#define DEFAULT_MULT_COUNT  0    /* set to 0 to disable multiple mode at boot */
  7481. +#define DEFAULT_UNMASK_INTR 0    /* set to 0 to *NOT* unmask irq's more often */
  7482. +
  7483. +#include <asm/irq.h>
  7484. +#include <linux/errno.h>
  7485. +#include <linux/signal.h>
  7486. +#include <linux/sched.h>
  7487. +#include <linux/timer.h>
  7488. +#include <linux/fs.h>
  7489. +#include <linux/kernel.h>
  7490. +#include <linux/hdreg.h>
  7491. +#include <linux/genhd.h>
  7492. +#include <linux/config.h>
  7493. +#include <linux/malloc.h>
  7494. +#include <linux/string.h>
  7495. +#include <linux/ioport.h>
  7496. +
  7497. +#define REALLY_SLOW_IO
  7498. +#include <asm/system.h>
  7499. +#include <asm/io.h>
  7500. +#include <asm/segment.h>
  7501. +
  7502. +#define MAJOR_NR HD_MAJOR
  7503. +#include "blk.h"
  7504. +
  7505. +void reissue_request(struct request *current_req);
  7506. +int issue_request(int dev, unsigned int block, unsigned int nsect, struct request *current_req);
  7507. +#undef  HD_IRQ
  7508. +#define HD_IRQ 11
  7509. +
  7510. +static int revalidate_hddisk(int, int);
  7511. +
  7512. +#define    HD_DELAY    0
  7513. +
  7514. +#define MAX_ERRORS     16    /* Max read/write errors/sector */
  7515. +#define RESET_FREQ      8    /* Reset controller every 8th retry */
  7516. +#define RECAL_FREQ      4    /* Recalibrate every 4th retry */
  7517. +#define MAX_HD        2
  7518. +
  7519. +#define STAT_OK        (READY_STAT|SEEK_STAT)
  7520. +#define OK_STATUS(s)    (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
  7521. +
  7522. +static void recal_intr(void);
  7523. +static void bad_rw_intr(void);
  7524. +
  7525. +static char recalibrate[MAX_HD] = { 0, };
  7526. +static char special_op[MAX_HD] = { 0, };
  7527. +static int access_count[MAX_HD] = {0, };
  7528. +static char busy[MAX_HD] = {0, };
  7529. +static struct wait_queue * busy_wait = NULL;
  7530. +
  7531. +static int reset = 0;
  7532. +static int hd_error = 0;
  7533. +
  7534. +/*
  7535. + *  This struct defines the HD's and their types.
  7536. + */
  7537. +struct hd_i_struct {
  7538. +    unsigned int head,sect,cyl,wpcom,lzone,ctl;
  7539. +    };
  7540. +static struct hd_driveid *hd_ident_info[MAX_HD] = {0, };
  7541. +    
  7542. +#ifdef HD_TYPE
  7543. +static struct hd_i_struct hd_info[] = { HD_TYPE };
  7544. +struct hd_i_struct bios_info[] = { HD_TYPE };
  7545. +static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
  7546. +#else
  7547. +static struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
  7548. +struct hd_i_struct bios_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
  7549. +static int NR_HD = 0;
  7550. +#endif
  7551. +
  7552. +static struct hd_struct hd[MAX_HD<<6]={{0,0},};
  7553. +static int hd_sizes[MAX_HD<<6] = {0, };
  7554. +static int hd_blocksizes[MAX_HD<<6] = {0, };
  7555. +
  7556. +#if (HD_DELAY > 0)
  7557. +unsigned long last_req;
  7558. +
  7559. +unsigned long read_timer(void)
  7560. +{
  7561. +    unsigned long t, flags;
  7562. +    int i;
  7563. +
  7564. +    save_flags(flags);
  7565. +    cli();
  7566. +    t = jiffies * 11932;
  7567. +        outb_p(0, 0x43);
  7568. +    i = inb_p(0x40);
  7569. +    i |= inb(0x40) << 8;
  7570. +    restore_flags(flags);
  7571. +    return(t - i);
  7572. +}
  7573. +#endif
  7574. +
  7575. +void hd_setup(char *str, int *ints)
  7576. +{
  7577. +    int hdind = 0;
  7578. +
  7579. +    if (ints[0] != 3)
  7580. +        return;
  7581. +    if (bios_info[0].head != 0)
  7582. +        hdind=1;
  7583. +    bios_info[hdind].head  = hd_info[hdind].head = ints[2];
  7584. +    bios_info[hdind].sect  = hd_info[hdind].sect = ints[3];
  7585. +    bios_info[hdind].cyl   = hd_info[hdind].cyl = ints[1];
  7586. +    bios_info[hdind].wpcom = hd_info[hdind].wpcom = 0;
  7587. +    bios_info[hdind].lzone = hd_info[hdind].lzone = ints[1];
  7588. +    bios_info[hdind].ctl   = hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
  7589. +    NR_HD = hdind+1;
  7590. +}
  7591. +
  7592. +static void dump_status (char *msg, unsigned int stat)
  7593. +{
  7594. +    unsigned long flags;
  7595. +    char devc;
  7596. +
  7597. +    devc = CURRENT ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
  7598. +    save_flags (flags);
  7599. +    sti();
  7600. +    printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
  7601. +    if (stat & BUSY_STAT)    printk("Busy ");
  7602. +    if (stat & READY_STAT)    printk("DriveReady ");
  7603. +    if (stat & WRERR_STAT)    printk("WriteFault ");
  7604. +    if (stat & SEEK_STAT)    printk("SeekComplete ");
  7605. +    if (stat & DRQ_STAT)    printk("DataRequest ");
  7606. +    if (stat & ECC_STAT)    printk("CorrectedError ");
  7607. +    if (stat & INDEX_STAT)    printk("Index ");
  7608. +    if (stat & ERR_STAT)    printk("Error ");
  7609. +    printk("}\n");
  7610. +    if ((stat & ERR_STAT) == 0) {
  7611. +        hd_error = 0;
  7612. +    } else {
  7613. +        hd_error = inb(HD_ERROR);
  7614. +        printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
  7615. +        if (hd_error & BBD_ERR)        printk("BadSector ");
  7616. +        if (hd_error & ECC_ERR)        printk("UncorrectableError ");
  7617. +        if (hd_error & ID_ERR)        printk("SectorIdNotFound ");
  7618. +        if (hd_error & ABRT_ERR)    printk("DriveStatusError ");
  7619. +        if (hd_error & TRK0_ERR)    printk("TrackZeroNotFound ");
  7620. +        if (hd_error & MARK_ERR)    printk("AddrMarkNotFound ");
  7621. +        printk("}");
  7622. +        if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
  7623. +            printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
  7624. +                inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
  7625. +            if (CURRENT)
  7626. +                printk(", sector=%ld", CURRENT->sector);
  7627. +        }
  7628. +        printk("\n");
  7629. +    }
  7630. +    restore_flags (flags);
  7631. +}
  7632. +
  7633. +void check_status(void)
  7634. +{
  7635. +    int i = inb_p(HD_STATUS);
  7636. +
  7637. +    if (!OK_STATUS(i)) {
  7638. +        dump_status("check_status", i);
  7639. +        bad_rw_intr();
  7640. +    }
  7641. +}
  7642. +
  7643. +static int controller_busy(void)
  7644. +{
  7645. +    int retries = 100000;
  7646. +    unsigned char status;
  7647. +
  7648. +    do {
  7649. +        status = inb_p(HD_STATUS);
  7650. +    } while ((status & BUSY_STAT) && --retries);
  7651. +    return status;
  7652. +}
  7653. +
  7654. +static int status_ok(void)
  7655. +{
  7656. +    unsigned char status = inb_p(HD_STATUS);
  7657. +
  7658. +    if (status & BUSY_STAT)
  7659. +        return 1;    /* Ancient, but does it make sense??? */
  7660. +    if (status & WRERR_STAT)
  7661. +        return 0;
  7662. +    if (!(status & READY_STAT))
  7663. +        return 0;
  7664. +    if (!(status & SEEK_STAT))
  7665. +        return 0;
  7666. +    return 1;
  7667. +}
  7668. +
  7669. +static int controller_ready(unsigned int drive, unsigned int head)
  7670. +{
  7671. +    int retry = 100;
  7672. +
  7673. +    do {
  7674. +        if (controller_busy() & BUSY_STAT)
  7675. +            return 0;
  7676. +        outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
  7677. +        if (status_ok())
  7678. +            return 1;
  7679. +    } while (--retry);
  7680. +    return 0;
  7681. +}
  7682. +
  7683. +static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
  7684. +        unsigned int head,unsigned int cyl,unsigned int cmd,
  7685. +        void (*intr_addr)(void))
  7686. +{
  7687. +    unsigned short port;
  7688. +
  7689. +#if (HD_DELAY > 0)
  7690. +    while (read_timer() - last_req < HD_DELAY)
  7691. +        /* nothing */;
  7692. +#endif
  7693. +    if (reset)
  7694. +        return;
  7695. +    if (!controller_ready(drive, head)) {
  7696. +        reset = 1;
  7697. +        return;
  7698. +    }
  7699. +    SET_INTR(intr_addr);
  7700. +    outb_p(hd_info[drive].ctl,HD_CMD);
  7701. +    port=HD_DATA;
  7702. +    outb_p(hd_info[drive].wpcom>>2,++port);
  7703. +    outb_p(nsect,++port);
  7704. +    outb_p(sect,++port);
  7705. +    outb_p(cyl,++port);
  7706. +    outb_p(cyl>>8,++port);
  7707. +    outb_p(0xA0|(drive<<4)|head,++port);
  7708. +    outb_p(cmd,++port);
  7709. +}
  7710. +
  7711. +static void hd_request (void);
  7712. +static unsigned int identified  [MAX_HD] = {0,}; /* 1 = drive ID already displayed   */
  7713. +static unsigned int unmask_intr [MAX_HD] = {0,}; /* 1 = unmask IRQs during I/O       */
  7714. +static unsigned int max_mult    [MAX_HD] = {0,}; /* max sectors for MultMode         */
  7715. +static unsigned int mult_req    [MAX_HD] = {0,}; /* requested MultMode count         */
  7716. +static unsigned int mult_count  [MAX_HD] = {0,}; /* currently enabled MultMode count */
  7717. +static struct request WCURRENT;
  7718. +
  7719. +static void fixstring (unsigned char *s, int bytecount)
  7720. +{
  7721. +    unsigned char *p, *end = &s[bytecount &= ~1];    /* bytecount must be even */
  7722. +
  7723. +    /* convert from big-endian to little-endian */
  7724. +    for (p = end ; p != s;) {
  7725. +        unsigned short *pp = (unsigned short *) (p -= 2);
  7726. +        *pp = (*pp >> 8) | (*pp << 8);
  7727. +    }
  7728. +
  7729. +    /* strip leading blanks */
  7730. +    while (s != end && *s == ' ')
  7731. +        ++s;
  7732. +
  7733. +    /* compress internal blanks and strip trailing blanks */
  7734. +    while (s != end && *s) {
  7735. +        if (*s++ != ' ' || (s != end && *s && *s != ' '))
  7736. +            *p++ = *(s-1);
  7737. +    }
  7738. +
  7739. +    /* wipe out trailing garbage */
  7740. +    while (p != end)
  7741. +        *p++ = '\0';
  7742. +}
  7743. +
  7744. +static void identify_intr(void)
  7745. +{
  7746. +    unsigned int dev = DEVICE_NR(CURRENT->rq_dev);
  7747. +    unsigned short stat = inb_p(HD_STATUS);
  7748. +    struct hd_driveid *id = hd_ident_info[dev];
  7749. +
  7750. +    if (unmask_intr[dev])
  7751. +        sti();
  7752. +    if (stat & (BUSY_STAT|ERR_STAT)) {
  7753. +        printk ("  hd%c: non-IDE device, %dMB, CHS=%d/%d/%d\n", dev+'a',
  7754. +            hd_info[dev].cyl*hd_info[dev].head*hd_info[dev].sect / 2048,
  7755. +            hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect);
  7756. +        if (id != NULL) {
  7757. +            hd_ident_info[dev] = NULL;
  7758. +            kfree_s (id, 512);
  7759. +        }
  7760. +    } else {
  7761. +        insw(HD_DATA, id, 256); /* get ID info */
  7762. +        max_mult[dev] = id->max_multsect;
  7763. +        if ((id->field_valid&1) && id->cur_cyls && id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
  7764. +            /*
  7765. +             * Extract the physical drive geometry for our use.
  7766. +             * Note that we purposely do *not* update the bios_info.
  7767. +             * This way, programs that use it (like fdisk) will 
  7768. +             * still have the same logical view as the BIOS does,
  7769. +             * which keeps the partition table from being screwed.
  7770. +             */
  7771. +            hd_info[dev].cyl  = id->cur_cyls;
  7772. +            hd_info[dev].head = id->cur_heads;
  7773. +            hd_info[dev].sect = id->cur_sectors; 
  7774. +        }
  7775. +        fixstring (id->serial_no, sizeof(id->serial_no));
  7776. +        fixstring (id->fw_rev, sizeof(id->fw_rev));
  7777. +        fixstring (id->model, sizeof(id->model));
  7778. +        printk ("  hd%c: %.40s, %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n",
  7779. +            dev+'a', id->model, id->cyls*id->heads*id->sectors/2048,
  7780. +            id->buf_size/2, hd_info[dev].cyl, hd_info[dev].head,
  7781. +            hd_info[dev].sect, id->max_multsect);
  7782. +        /*
  7783. +         * Early model Quantum drives go weird at this point,
  7784. +         *   but doing a recalibrate seems to "fix" them.
  7785. +         * (Doing a full reset confuses some other model Quantums)
  7786. +         */
  7787. +        if (!strncmp(id->model, "QUANTUM", 7))
  7788. +            special_op[dev] = recalibrate[dev] = 1;
  7789. +    }
  7790. +#if (HD_DELAY > 0)
  7791. +    last_req = read_timer();
  7792. +#endif
  7793. +    hd_request();
  7794. +    return;
  7795. +}
  7796. +
  7797. +static void set_multmode_intr(void)
  7798. +{
  7799. +    unsigned int dev = DEVICE_NR(CURRENT->rq_dev), stat = inb_p(HD_STATUS);
  7800. +
  7801. +    if (unmask_intr[dev])
  7802. +        sti();
  7803. +    if (stat & (BUSY_STAT|ERR_STAT)) {
  7804. +        mult_req[dev] = mult_count[dev] = 0;
  7805. +        dump_status("set multmode failed", stat);
  7806. +    } else {
  7807. +        if ((mult_count[dev] = mult_req[dev]))
  7808. +            printk ("  hd%c: enabled %d-sector multiple mode\n",
  7809. +                dev+'a', mult_count[dev]);
  7810. +        else
  7811. +            printk ("  hd%c: disabled multiple mode\n", dev+'a');
  7812. +    }
  7813. +#if (HD_DELAY > 0)
  7814. +    last_req = read_timer();
  7815. +#endif
  7816. +    hd_request();
  7817. +    return;
  7818. +}
  7819. +
  7820. +static int drive_busy(void)
  7821. +{
  7822. +    unsigned int i;
  7823. +    unsigned char c;
  7824. +
  7825. +    for (i = 0; i < 500000 ; i++) {
  7826. +        c = inb_p(HD_STATUS);
  7827. +        if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
  7828. +            return 0;
  7829. +    }
  7830. +    dump_status("reset timed out", c);
  7831. +    return 1;
  7832. +}
  7833. +
  7834. +static void reset_controller(void)
  7835. +{
  7836. +    int    i;
  7837. +
  7838. +    outb_p(4,HD_CMD);
  7839. +    for(i = 0; i < 1000; i++) nop();
  7840. +    outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
  7841. +    for(i = 0; i < 1000; i++) nop();
  7842. +    if (drive_busy())
  7843. +        printk("hd: controller still busy\n");
  7844. +    else if ((hd_error = inb(HD_ERROR)) != 1)
  7845. +        printk("hd: controller reset failed: %02x\n",hd_error);
  7846. +}
  7847. +
  7848. +static void reset_hd(void)
  7849. +{
  7850. +    static int i;
  7851. +
  7852. +repeat:
  7853. +    if (reset) {
  7854. +        reset = 0;
  7855. +        i = -1;
  7856. +        reset_controller();
  7857. +    } else {
  7858. +        check_status();
  7859. +        if (reset)
  7860. +            goto repeat;
  7861. +    }
  7862. +    if (++i < NR_HD) {
  7863. +        special_op[i] = recalibrate[i] = 1;
  7864. +        if (unmask_intr[i]) {
  7865. +            unmask_intr[i] = DEFAULT_UNMASK_INTR;
  7866. +            printk("hd%c: reset irq-unmasking to %d\n",i+'a',
  7867. +                DEFAULT_UNMASK_INTR);
  7868. +        }
  7869. +        if (mult_req[i] || mult_count[i]) {
  7870. +            mult_count[i] = 0;
  7871. +            mult_req[i] = DEFAULT_MULT_COUNT;
  7872. +            printk("hd%c: reset multiple mode to %d\n",i+'a',
  7873. +                DEFAULT_MULT_COUNT);
  7874. +        }
  7875. +        hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
  7876. +            hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
  7877. +        if (reset)
  7878. +            goto repeat;
  7879. +    } else
  7880. +        hd_request();
  7881. +}
  7882. +
  7883. +/*
  7884. + * Ok, don't know what to do with the unexpected interrupts: on some machines
  7885. + * doing a reset and a retry seems to result in an eternal loop. Right now I
  7886. + * ignore it, and just set the timeout.
  7887. + *
  7888. + * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
  7889. + * drive enters "idle", "standby", or "sleep" mode, so if the status looks
  7890. + * "good", we just ignore the interrupt completely.
  7891. + */
  7892. +void unexpected_hd_interrupt(void)
  7893. +{
  7894. +    unsigned int stat = inb_p(HD_STATUS);
  7895. +
  7896. +    if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
  7897. +        dump_status ("unexpected interrupt", stat);
  7898. +        SET_TIMER;
  7899. +    }
  7900. +}
  7901. +
  7902. +/*
  7903. + * bad_rw_intr() now tries to be a bit smarter and does things
  7904. + * according to the error returned by the controller.
  7905. + * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
  7906. + */
  7907. +static void bad_rw_intr(void)
  7908. +{
  7909. +    int dev;
  7910. +
  7911. +    if (!CURRENT)
  7912. +        return;
  7913. +    dev = DEVICE_NR(CURRENT->rq_dev);
  7914. +    if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
  7915. +        end_request(0);
  7916. +        special_op[dev] = recalibrate[dev] = 1;
  7917. +    } else if (CURRENT->errors % RESET_FREQ == 0)
  7918. +        reset = 1;
  7919. +    else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
  7920. +        special_op[dev] = recalibrate[dev] = 1;
  7921. +    /* Otherwise just retry */
  7922. +}
  7923. +
  7924. +static inline int wait_DRQ(void)
  7925. +{
  7926. +    int retries = 100000, stat;
  7927. +
  7928. +    while (--retries > 0)
  7929. +        if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
  7930. +            return 0;
  7931. +    dump_status("wait_DRQ", stat);
  7932. +    return -1;
  7933. +}
  7934. +
  7935. +static void read_intr(void)
  7936. +{
  7937. +    unsigned int dev = DEVICE_NR(CURRENT->rq_dev);
  7938. +    int i, retries = 100000, msect = mult_count[dev], nsect;
  7939. +
  7940. +    if (unmask_intr[dev])
  7941. +        sti();            /* permit other IRQs during xfer */
  7942. +    do {
  7943. +        i = (unsigned) inb_p(HD_STATUS);
  7944. +        if (i & BUSY_STAT)
  7945. +            continue;
  7946. +        if (!OK_STATUS(i))
  7947. +            break;
  7948. +        if (i & DRQ_STAT)
  7949. +            goto ok_to_read;
  7950. +    } while (--retries > 0);
  7951. +    dump_status("read_intr", i);
  7952. +    bad_rw_intr();
  7953. +    hd_request();
  7954. +    return;
  7955. +ok_to_read:
  7956. +    if (msect) {
  7957. +        if ((nsect = CURRENT->current_nr_sectors) > msect)
  7958. +            nsect = msect;
  7959. +        msect -= nsect;
  7960. +    } else
  7961. +        nsect = 1;
  7962. +    insw(HD_DATA,CURRENT->buffer,nsect<<8);
  7963. +    CURRENT->sector += nsect;
  7964. +    CURRENT->buffer += nsect<<9;
  7965. +    CURRENT->errors = 0;
  7966. +    i = (CURRENT->nr_sectors -= nsect);
  7967. +
  7968. +#ifdef DEBUG
  7969. +    printk("hd%c: read: sectors(%ld-%ld), remaining=%ld, buffer=0x%08lx\n",
  7970. +        dev+'a', CURRENT->sector, CURRENT->sector+nsect,
  7971. +        CURRENT->nr_sectors, (unsigned long) CURRENT->buffer+(nsect<<9));
  7972. +#endif
  7973. +    if ((CURRENT->current_nr_sectors -= nsect) <= 0)
  7974. +        end_request(1);
  7975. +    if (i > 0) {
  7976. +        if (msect)
  7977. +            goto ok_to_read;
  7978. +        if(!(--frag_sectors))
  7979. +         /* Next fragment req.d */
  7980. +            reissue_request(CURRENT);
  7981. +        else
  7982. +        {
  7983. +            SET_INTR(&read_intr);
  7984. +        }
  7985. +        return;
  7986. +    }
  7987. +    (void) inb_p(HD_STATUS);
  7988. +#if (HD_DELAY > 0)
  7989. +    last_req = read_timer();
  7990. +#endif
  7991. +    if (CURRENT)
  7992. +        hd_request();
  7993. +    return;
  7994. +}
  7995. +
  7996. +static inline void multwrite (unsigned int dev)
  7997. +{
  7998. +    unsigned int mcount = mult_count[dev];
  7999. +
  8000. +    while (mcount--) {
  8001. +        outsw(HD_DATA,WCURRENT.buffer,256);
  8002. +        if (!--WCURRENT.nr_sectors)
  8003. +            return;
  8004. +        WCURRENT.buffer += 512;
  8005. +        if (!--WCURRENT.current_nr_sectors) {
  8006. +            WCURRENT.bh = WCURRENT.bh->b_reqnext;
  8007. +            if (WCURRENT.bh == NULL)
  8008. +                panic("buffer list corrupted\n");
  8009. +            WCURRENT.current_nr_sectors = WCURRENT.bh->b_size>>9;
  8010. +            WCURRENT.buffer             = WCURRENT.bh->b_data;
  8011. +        }
  8012. +    }
  8013. +}
  8014. +
  8015. +static void multwrite_intr(void)
  8016. +{
  8017. +    int i;
  8018. +    unsigned int dev = DEVICE_NR(WCURRENT.rq_dev);
  8019. +
  8020. +    if (unmask_intr[dev])
  8021. +        sti();
  8022. +    if (OK_STATUS(i=inb_p(HD_STATUS))) {
  8023. +        if (i & DRQ_STAT) {
  8024. +            if (WCURRENT.nr_sectors) {
  8025. +                multwrite(dev);
  8026. +                SET_INTR(&multwrite_intr);
  8027. +                return;
  8028. +            }
  8029. +        } else {
  8030. +            if (!WCURRENT.nr_sectors) {    /* all done? */
  8031. +                for (i = CURRENT->nr_sectors; i > 0;){
  8032. +                    i -= CURRENT->current_nr_sectors;
  8033. +                    end_request(1);
  8034. +                }
  8035. +#if (HD_DELAY > 0)
  8036. +                last_req = read_timer();
  8037. +#endif
  8038. +                if (CURRENT)
  8039. +                    hd_request();
  8040. +                return;
  8041. +            }
  8042. +        }
  8043. +    }
  8044. +    dump_status("multwrite_intr", i);
  8045. +    bad_rw_intr();
  8046. +    hd_request();
  8047. +}
  8048. +
  8049. +static void write_intr(void)
  8050. +{
  8051. +    int i;
  8052. +    int retries = 100000;
  8053. +
  8054. +    if (unmask_intr[DEVICE_NR(WCURRENT.rq_dev)])
  8055. +        sti();
  8056. +    do {
  8057. +        i = (unsigned) inb_p(HD_STATUS);
  8058. +        if (i & BUSY_STAT)
  8059. +            continue;
  8060. +        if (!OK_STATUS(i))
  8061. +            break;
  8062. +        if ((CURRENT->nr_sectors <= 1) || (frag_sectors <= 1) || (i & DRQ_STAT))
  8063. +            goto ok_to_write;
  8064. +    } while (--retries > 0);
  8065. +    dump_status("write_intr", i);
  8066. +    bad_rw_intr();
  8067. +    hd_request();
  8068. +    return;
  8069. +ok_to_write:
  8070. +    CURRENT->sector++;
  8071. +    i = --CURRENT->nr_sectors;
  8072. +    --CURRENT->current_nr_sectors;
  8073. +    CURRENT->buffer += 512;
  8074. +    if (!i || (CURRENT->bh && !SUBSECTOR(i)))
  8075. +        end_request(1);
  8076. +    if (i > 0) {
  8077. +        if(!(--frag_sectors))
  8078. +         /* Next fragment req.d */
  8079. +            reissue_request(CURRENT);
  8080. +        else
  8081. +        {
  8082. +            SET_INTR(&write_intr);
  8083. +            outsw(HD_DATA,CURRENT->buffer,256);
  8084. +            sti();
  8085. +        }
  8086. +    } else {
  8087. +#if (HD_DELAY > 0)
  8088. +        last_req = read_timer();
  8089. +#endif
  8090. +        hd_request();
  8091. +    }
  8092. +    return;
  8093. +}
  8094. +
  8095. +static void recal_intr(void)
  8096. +{
  8097. +    check_status();
  8098. +#if (HD_DELAY > 0)
  8099. +    last_req = read_timer();
  8100. +#endif
  8101. +    hd_request();
  8102. +}
  8103. +
  8104. +/*
  8105. + * This is another of the error-routines I don't know what to do with. The
  8106. + * best idea seems to just set reset, and start all over again.
  8107. + */
  8108. +static void hd_times_out(void)
  8109. +{
  8110. +    unsigned int dev;
  8111. +
  8112. +    DEVICE_INTR = NULL;
  8113. +    if (!CURRENT)
  8114. +        return;
  8115. +    disable_irq(HD_IRQ);
  8116. +    sti();
  8117. +    reset = 1;
  8118. +    dev = DEVICE_NR(CURRENT->rq_dev);
  8119. +    printk("hd%c: timeout\n", dev+'a');
  8120. +    if (++CURRENT->errors >= MAX_ERRORS) {
  8121. +#ifdef DEBUG
  8122. +        printk("hd%c: too many errors\n", dev+'a');
  8123. +#endif
  8124. +        end_request(0);
  8125. +    }
  8126. +    cli();
  8127. +    hd_request();
  8128. +    enable_irq(HD_IRQ);
  8129. +}
  8130. +
  8131. +int do_special_op (unsigned int dev)
  8132. +{
  8133. +    if (recalibrate[dev]) {
  8134. +        recalibrate[dev] = 0;
  8135. +        hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
  8136. +        return reset;
  8137. +    }
  8138. +    if (!identified[dev]) {
  8139. +        identified[dev]  = 1;
  8140. +        unmask_intr[dev] = DEFAULT_UNMASK_INTR;
  8141. +        mult_req[dev]    = DEFAULT_MULT_COUNT;
  8142. +        hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
  8143. +        return reset;
  8144. +    }
  8145. +    if (mult_req[dev] != mult_count[dev]) {
  8146. +        hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
  8147. +        return reset;
  8148. +    }
  8149. +    if (hd_info[dev].head > 16) {
  8150. +        printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
  8151. +        end_request(0);
  8152. +    }
  8153. +    special_op[dev] = 0;
  8154. +    return 1;
  8155. +}
  8156. +
  8157. +/*
  8158. + * The driver enables interrupts as much as possible.  In order to do this,
  8159. + * (a) the device-interrupt is disabled before entering hd_request(),
  8160. + * and (b) the timeout-interrupt is disabled before the sti().
  8161. + *
  8162. + * Interrupts are still masked (by default) whenever we are exchanging
  8163. + * data/cmds with a drive, because some drives seem to have very poor
  8164. + * tolerance for latency during I/O.  For devices which don't suffer from
  8165. + * that problem (most don't), the unmask_intr[] flag can be set to unmask
  8166. + * other interrupts during data/cmd transfers (by defining DEFAULT_UNMASK_INTR
  8167. + * to 1, or by using "hdparm -u1 /dev/hd?" from the shell).
  8168. + */
  8169. +static void hd_request(void)
  8170. +{
  8171. +    unsigned int dev, block, nsect;
  8172. +
  8173. +    if (CURRENT && CURRENT->rq_status == RQ_INACTIVE) return;
  8174. +    if (DEVICE_INTR)
  8175. +        return;
  8176. +repeat:
  8177. +    timer_active &= ~(1<<HD_TIMER);
  8178. +    sti();
  8179. +    INIT_REQUEST;
  8180. +    if (reset) {
  8181. +        cli();
  8182. +        reset_hd();
  8183. +        return;
  8184. +    }
  8185. +    dev = MINOR(CURRENT->rq_dev);
  8186. +    block = CURRENT->sector;
  8187. +    nsect = CURRENT->nr_sectors;
  8188. +    if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
  8189. +#ifdef DEBUG
  8190. +        if (dev >= (NR_HD<<6))
  8191. +            printk("hd: bad minor number: device=0x%04x\n", CURRENT->rq_dev);
  8192. +        else
  8193. +            printk("hd%c: bad access: block=%d, count=%d\n",
  8194. +                (dev>>6)+'a', block, nsect);
  8195. +#endif
  8196. +        end_request(0);
  8197. +        goto repeat;
  8198. +    }
  8199. +    block += hd[dev].start_sect;
  8200. +    if(dev & 0x3f)
  8201. +    { /* map sectors block to block+nsect to frags, 
  8202. +       */
  8203. +        if(!image_file_check(CURRENT->rq_dev,CURRENT->cmd))
  8204. +            goto repeat;
  8205. +        frag_count = image_file_map(CURRENT->rq_dev, block, nsect, MAX_FRAGS, 
  8206. +                        frag_start, frag_len);
  8207. +        if(!frag_count)
  8208. +        {
  8209. +            goto repeat;
  8210. +        }
  8211. +        
  8212. +        block = frag_start[0];
  8213. +        frag_sectors = nsect = frag_len[0];
  8214. +        frag_pos = 0;
  8215. +    }
  8216. +    else
  8217. +    {
  8218. +        frag_pos = 0;
  8219. +        frag_count = 1;
  8220. +        frag_sectors = nsect;
  8221. +        if(CURRENT->cmd == WRITE)
  8222. +        { /* Protect normal HD from writes */
  8223. +            printk("hd%d : attempted write on protected drive\n",dev);
  8224. +            end_request(0);
  8225. +            goto repeat;
  8226. +        }
  8227. +    }
  8228. +    if(issue_request(dev,block,nsect, CURRENT))
  8229. +        goto repeat;
  8230. +}
  8231. +
  8232. +void reissue_request(struct request *current_req)
  8233. +{
  8234. +    unsigned int dev, block, nsect;
  8235. +
  8236. +    dev = MINOR(current_req->rq_dev);
  8237. +    frag_pos++;
  8238. +    if(frag_pos >= MAX_FRAGS)
  8239. +    {
  8240. +        block = current_req->sector;
  8241. +        block += hd[dev].start_sect;
  8242. +        nsect = current_req->nr_sectors;
  8243. +        if(!image_file_check(current_req->rq_dev,current_req->cmd))
  8244. +        {
  8245. +            end_request(0);
  8246. +            hd_request();
  8247. +            return;
  8248. +        }
  8249. +        frag_count = image_file_map(current_req->rq_dev, block, nsect, MAX_FRAGS, 
  8250. +                        frag_start, frag_len);
  8251. +        if(!frag_count)
  8252. +        {
  8253. +            end_request(0);
  8254. +            hd_request();
  8255. +            return;
  8256. +        }
  8257. +        
  8258. +        frag_pos = 0;
  8259. +        }        
  8260. +    frag_sectors = frag_len[frag_pos];
  8261. +repeat:
  8262. +    if(issue_request(dev, frag_start[frag_pos], frag_len[frag_pos], current_req))
  8263. +    {
  8264. +        printk("EEEEK - going round the loop\n");
  8265. +        goto repeat;
  8266. +    }
  8267. +}
  8268. +
  8269. +/* 
  8270. + * This routine actually issues a request to the hard disk itself
  8271. + */
  8272. +int issue_request(int dev, unsigned int block, unsigned int nsect, struct request *current_req)
  8273. +{
  8274. +    unsigned int sec, track, head, cyl;
  8275. +int d = dev;
  8276. +    dev >>= 6;
  8277. +    if (special_op[dev]) {
  8278. +        if (do_special_op(dev))
  8279. +            return 1;
  8280. +        return 0;
  8281. +    }
  8282. +    sec   = block % hd_info[dev].sect + 1;
  8283. +    track = block / hd_info[dev].sect;
  8284. +    head  = track % hd_info[dev].head;
  8285. +    cyl   = track / hd_info[dev].head;
  8286. +#ifdef DEBUG
  8287. +    printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
  8288. +        dev+'a', (current_req->cmd == READ)?"read":"writ",
  8289. +        cyl, head, sec, nsect, (unsigned long) current_req->buffer,current_req);
  8290. +#endif
  8291. +    frag_sectors = nsect;
  8292. +    if (!unmask_intr[dev])
  8293. +        cli();
  8294. +    if (current_req->cmd == READ) {
  8295. +        unsigned int cmd = mult_count[dev] > 1 ? WIN_MULTREAD : WIN_READ;
  8296. +        hd_out(dev,nsect,sec,head,cyl,cmd,&read_intr);
  8297. +        if (reset)
  8298. +            return 1;
  8299. +        return 0;
  8300. +    }
  8301. +    if (current_req->cmd == WRITE) {
  8302. +#if 1
  8303. +#if 0
  8304. +        if (mult_count[dev])
  8305. +            hd_out(dev,nsect,sec,head,cyl,WIN_MULTWRITE,&multwrite_intr);
  8306. +        else
  8307. +#endif
  8308. +            hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
  8309. +        if (reset)
  8310. +            return 1;
  8311. +        if (wait_DRQ()) {
  8312. +            bad_rw_intr();
  8313. +            return 1;
  8314. +        }
  8315. +#if 0
  8316. +        if (mult_count[dev]) {
  8317. +            WCURRENT = *current;
  8318. +            multwrite(dev);
  8319. +        } else
  8320. +#endif
  8321. +            outsw(HD_DATA,current_req->buffer,256);
  8322. +if(d == 1 && block < 10) while(1);
  8323. +#else
  8324. +if(d == 1)
  8325. +        printk("write: buffer = %p (%08lX)\n", current_req->buffer, *(unsigned long *)current_req->buffer);
  8326. +{int i; for(i=0; i<0x003fffff; i++); }
  8327. +        end_request(0);
  8328. +        return 1;
  8329. +#endif
  8330. +        return 0;
  8331. +    }
  8332. +    panic("unknown hd-command");
  8333. +    return 0;
  8334. +}
  8335. +
  8336. +static void do_hd_request (void)
  8337. +{
  8338. +    disable_irq(HD_IRQ);
  8339. +    hd_request();
  8340. +    enable_irq(HD_IRQ);
  8341. +}
  8342. +
  8343. +static int hd_ioctl(struct inode * inode, struct file * file,
  8344. +    unsigned int cmd, unsigned long arg)
  8345. +{
  8346. +    struct hd_geometry *loc = (struct hd_geometry *) arg;
  8347. +    int dev, err;
  8348. +    unsigned long flags;
  8349. +
  8350. +    if ((!inode) || (!inode->i_rdev))
  8351. +        return -EINVAL;
  8352. +    dev = DEVICE_NR(inode->i_rdev);
  8353. +    if (dev >= NR_HD)
  8354. +        return -EINVAL;
  8355. +    switch (cmd) {
  8356. +        case HDIO_GETGEO:
  8357. +            if (!loc)  return -EINVAL;
  8358. +            err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
  8359. +            if (err)
  8360. +                return err;
  8361. +            put_fs_byte(bios_info[dev].head,
  8362. +                (char *) &loc->heads);
  8363. +            put_fs_byte(bios_info[dev].sect,
  8364. +                (char *) &loc->sectors);
  8365. +            put_fs_word(bios_info[dev].cyl,
  8366. +                (short *) &loc->cylinders);
  8367. +            put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
  8368. +                (long *) &loc->start);
  8369. +            return 0;
  8370. +        case BLKRASET:
  8371. +            if(!suser())  return -EACCES;
  8372. +            if(arg > 0xff) return -EINVAL;
  8373. +            read_ahead[MAJOR(inode->i_rdev)] = arg;
  8374. +            return 0;
  8375. +        case BLKRAGET:
  8376. +            if (!arg)  return -EINVAL;
  8377. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  8378. +            if (err)
  8379. +                return err;
  8380. +            put_fs_long(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
  8381. +            return 0;
  8382. +             case BLKGETSIZE:   /* Return device size */
  8383. +            if (!arg)  return -EINVAL;
  8384. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  8385. +            if (err)
  8386. +                return err;
  8387. +            put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
  8388. +            return 0;
  8389. +        case BLKFLSBUF:
  8390. +            if(!suser())  return -EACCES;
  8391. +            fsync_dev(inode->i_rdev);
  8392. +            invalidate_buffers(inode->i_rdev);
  8393. +            return 0;
  8394. +
  8395. +        case BLKRRPART: /* Re-read partition tables */
  8396. +            return revalidate_hddisk(inode->i_rdev, 1);
  8397. +
  8398. +        case HDIO_SET_UNMASKINTR:
  8399. +            if (!suser()) return -EACCES;
  8400. +            if ((arg > 1) || (MINOR(inode->i_rdev) & 0x3F))
  8401. +                return -EINVAL;
  8402. +            unmask_intr[dev] = arg;
  8403. +            return 0;
  8404. +
  8405. +                case HDIO_GET_UNMASKINTR:
  8406. +            if (!arg)  return -EINVAL;
  8407. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  8408. +            if (err)
  8409. +                return err;
  8410. +            put_fs_long(unmask_intr[dev], (long *) arg);
  8411. +            return 0;
  8412. +
  8413. +                case HDIO_GET_MULTCOUNT:
  8414. +            if (!arg)  return -EINVAL;
  8415. +            err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  8416. +            if (err)
  8417. +                return err;
  8418. +            put_fs_long(mult_count[dev], (long *) arg);
  8419. +            return 0;
  8420. +
  8421. +        case HDIO_SET_MULTCOUNT:
  8422. +            if (!suser()) return -EACCES;
  8423. +            if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
  8424. +            save_flags(flags);
  8425. +            cli();    /* a prior request might still be in progress */
  8426. +            if (arg > max_mult[dev])
  8427. +                err = -EINVAL;    /* out of range for device */
  8428. +            else if (mult_req[dev] != mult_count[dev]) {
  8429. +                special_op[dev] = 1;
  8430. +                err = -EBUSY;    /* busy, try again */
  8431. +            } else {
  8432. +                mult_req[dev] = arg;
  8433. +                special_op[dev] = 1;
  8434. +                err = 0;
  8435. +            }
  8436. +            restore_flags(flags);
  8437. +            return err;
  8438. +
  8439. +        case HDIO_GET_IDENTITY:
  8440. +            if (!arg)  return -EINVAL;
  8441. +            if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
  8442. +            if (hd_ident_info[dev] == NULL)  return -ENOMSG;
  8443. +            err = verify_area(VERIFY_WRITE, (char *) arg, sizeof(struct hd_driveid));
  8444. +            if (err)
  8445. +                return err;
  8446. +            memcpy_tofs((char *)arg, (char *) hd_ident_info[dev], sizeof(struct hd_driveid));
  8447. +            return 0;
  8448. +
  8449. +        RO_IOCTLS(inode->i_rdev,arg);
  8450. +        default:
  8451. +            return -EINVAL;
  8452. +    }
  8453. +}
  8454. +
  8455. +static int hd_open(struct inode * inode, struct file * filp)
  8456. +{
  8457. +    int target;
  8458. +
  8459. +    target =  DEVICE_NR(inode->i_rdev);
  8460. +
  8461. +    if (target >= NR_HD)
  8462. +        return -ENODEV;
  8463. +
  8464. +    while (busy[target])
  8465. +        sleep_on(&busy_wait);
  8466. +    access_count[target]++;
  8467. +    return 0;
  8468. +}
  8469. +
  8470. +/*
  8471. + * Releasing a block device means we sync() it, so that it can safely
  8472. + * be forgotten about...
  8473. + */
  8474. +static void hd_release(struct inode * inode, struct file * file)
  8475. +{
  8476. +        int target;
  8477. +    sync_dev(inode->i_rdev);
  8478. +
  8479. +    target =  DEVICE_NR(inode->i_rdev);
  8480. +    access_count[target]--;
  8481. +
  8482. +}
  8483. +
  8484. +static void hd_geninit(struct gendisk *);
  8485. +
  8486. +static struct gendisk hd_gendisk = {
  8487. +    MAJOR_NR,    /* Major number */    
  8488. +    "hd",        /* Major name */
  8489. +    6,        /* Bits to shift to get real from partition */
  8490. +    1 << 6,        /* Number of partitions per real */
  8491. +    MAX_HD,        /* maximum number of real */
  8492. +    hd_geninit,    /* init function */
  8493. +    hd,        /* hd struct */
  8494. +    hd_sizes,    /* block sizes */
  8495. +    0,        /* number */
  8496. +    (void *) bios_info,    /* internal */
  8497. +    NULL        /* next */
  8498. +};
  8499. +    
  8500. +static void hd_interrupt(int irq, struct pt_regs *regs)
  8501. +{
  8502. +    void (*handler)(void) = DEVICE_INTR;
  8503. +
  8504. +    DEVICE_INTR = NULL;
  8505. +    timer_active &= ~(1<<HD_TIMER);
  8506. +    if (!handler)
  8507. +        handler = unexpected_hd_interrupt;
  8508. +    handler();
  8509. +    sti();
  8510. +}
  8511. +
  8512. +
  8513. +void set_hdinfo(int dev,unsigned char secsptrack,unsigned char heads,
  8514. +                    unsigned long discsize,unsigned int secsize)
  8515. +{
  8516. +  dev=MINOR(dev);
  8517. +  if(hd_info[dev>>6].cyl==1)
  8518. +  {
  8519. +    hd_info[dev>>6].cyl=discsize/(secsptrack*heads*secsize);
  8520. +    hd_info[dev>>6].head=heads;
  8521. +    hd_info[dev>>6].wpcom=-1;
  8522. +    hd_info[dev>>6].ctl=8;
  8523. +    hd_info[dev>>6].lzone=hd_info[dev>>6].cyl-1;
  8524. +    hd_info[dev>>6].sect=secsptrack;
  8525. +  }
  8526. +  hd[dev].start_sect=0;
  8527. +  hd[dev].nr_sects=discsize/secsize;
  8528. +#if 0
  8529. +  printk("hd%c: %d cylinders, %d heads, %d sectors (%d total)\n",'a'+(dev>>6),
  8530. +    hd_info[dev>>6].cyl, heads, secsptrack, discsize);
  8531. +#endif
  8532. +}
  8533. +
  8534. +/*
  8535. + * This is the harddisk IRQ description. The SA_INTERRUPT in sa_flags
  8536. + * means we run the IRQ-handler with interrupts disabled: this is bad for
  8537. + * interrupt latency, but anything else has led to problems on some
  8538. + * machines...
  8539. + *
  8540. + * We enable interrupts in some of the routines after making sure it's
  8541. + * safe.
  8542. + */
  8543. +static void hd_geninit(struct gendisk *dev)
  8544. +{
  8545. +    int drive, i;
  8546. +
  8547. +NR_HD = 0;
  8548. +    if (!NR_HD) {
  8549. +    /* Default settings */
  8550. +        for (drive=0 ; drive<2 ; drive++) {
  8551. +            bios_info[drive].cyl    = hd_info[drive].cyl    = 1;
  8552. +            bios_info[drive].head    = hd_info[drive].head    = 1;
  8553. +            bios_info[drive].wpcom    = hd_info[drive].wpcom    = -1;
  8554. +            bios_info[drive].ctl    = hd_info[drive].ctl    = 8;
  8555. +            bios_info[drive].lzone    = hd_info[drive].lzone    = 1;
  8556. +            bios_info[drive].sect    = hd_info[drive].sect    = 17;
  8557. +            if(hd_info[drive].cyl && NR_HD == drive)
  8558. +                NR_HD++;
  8559. +        }
  8560. +        }
  8561. +
  8562. +    NR_HD = no_hds;
  8563. +
  8564. +    i = NR_HD;
  8565. +    while (i-- > 0) {
  8566. +        /*
  8567. +         * The newer E-IDE BIOSs handle drives larger than 1024
  8568. +         * cylinders by increasing the number of logical heads
  8569. +         * to keep the number of logical cylinders below the
  8570. +         * sacred INT13 limit of 1024 (10 bits).  If that is
  8571. +         * what's happening here, we'll find out and correct
  8572. +         * it later when "identifying" the drive.
  8573. +         */
  8574. +        hd[i<<6].nr_sects = bios_info[i].head *
  8575. +                bios_info[i].sect * bios_info[i].cyl;
  8576. +        hd_ident_info[i] = (struct hd_driveid *) kmalloc(512,GFP_KERNEL);
  8577. +        special_op[i] = 1;
  8578. +    }
  8579. +    if (NR_HD) {
  8580. +        if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd")) {
  8581. +            printk("hd: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
  8582. +            NR_HD = 0;
  8583. +        } else {
  8584. +            request_region(HD_DATA, 8, "hd");
  8585. +            request_region(HD_CMD, 1, "hd(cmd)");
  8586. +        }
  8587. +    }
  8588. +    hd_gendisk.nr_real = NR_HD;
  8589. +
  8590. +    for(i=0;i<(MAX_HD << 6);i++) hd_blocksizes[i] = 1024;
  8591. +    blksize_size[MAJOR_NR] = hd_blocksizes;
  8592. +}
  8593. +
  8594. +static struct file_operations hd_fops = {
  8595. +    NULL,            /* lseek - default */
  8596. +    block_read,        /* read - general block-dev read */
  8597. +    block_write,        /* write - general block-dev write */
  8598. +    NULL,            /* readdir - bad */
  8599. +    NULL,            /* select */
  8600. +    hd_ioctl,        /* ioctl */
  8601. +    NULL,            /* mmap */
  8602. +    hd_open,        /* open */
  8603. +    hd_release,        /* release */
  8604. +    block_fsync        /* fsync */
  8605. +};
  8606. +
  8607. +int hd_init(void)
  8608. +{
  8609. +    if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
  8610. +        printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);
  8611. +        return -1;
  8612. +    }
  8613. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  8614. +    read_ahead[MAJOR_NR] = 8;        /* 8 sector (4kB) read-ahead */
  8615. +    hd_gendisk.next = gendisk_head;
  8616. +    gendisk_head = &hd_gendisk;
  8617. +    timer_table[HD_TIMER].fn = hd_times_out;
  8618. +    return 0;
  8619. +}
  8620. +
  8621. +#define DEVICE_BUSY busy[target]
  8622. +#define USAGE access_count[target]
  8623. +#define CAPACITY (bios_info[target].head*bios_info[target].sect*bios_info[target].cyl)
  8624. +/* We assume that the the bios parameters do not change, so the disk capacity
  8625. +   will not change */
  8626. +#undef MAYBE_REINIT
  8627. +#define GENDISK_STRUCT hd_gendisk
  8628. +
  8629. +/*
  8630. + * This routine is called to flush all partitions and partition tables
  8631. + * for a changed scsi disk, and then re-read the new partition table.
  8632. + * If we are revalidating a disk because of a media change, then we
  8633. + * enter with usage == 0.  If we are using an ioctl, we automatically have
  8634. + * usage == 1 (we need an open channel to use an ioctl :-), so this
  8635. + * is our limit.
  8636. + */
  8637. +static int revalidate_hddisk(int dev, int maxusage)
  8638. +{
  8639. +    int target, major;
  8640. +    struct gendisk * gdev;
  8641. +    int max_p;
  8642. +    int start;
  8643. +    int i;
  8644. +    unsigned long flags;
  8645. +
  8646. +    target =  DEVICE_NR(dev);
  8647. +    gdev = &GENDISK_STRUCT;
  8648. +
  8649. +    save_flags(flags);
  8650. +    cli();
  8651. +    if (DEVICE_BUSY || USAGE > maxusage) {
  8652. +        restore_flags(flags);
  8653. +        return -EBUSY;
  8654. +    };
  8655. +    DEVICE_BUSY = 1;
  8656. +    restore_flags(flags);
  8657. +
  8658. +    max_p = gdev->max_p;
  8659. +    start = target << gdev->minor_shift;
  8660. +    major = MAJOR_NR << 8;
  8661. +
  8662. +    for (i=max_p - 1; i >=0 ; i--) {
  8663. +        sync_dev(major | start | i);
  8664. +        invalidate_inodes(major | start | i);
  8665. +        invalidate_buffers(major | start | i);
  8666. +        gdev->part[start+i].start_sect = 0;
  8667. +        gdev->part[start+i].nr_sects = 0;
  8668. +    };
  8669. +
  8670. +#ifdef MAYBE_REINIT
  8671. +    MAYBE_REINIT;
  8672. +#endif
  8673. +
  8674. +    gdev->part[start].nr_sects = CAPACITY;
  8675. +    resetup_one_dev(gdev, target);
  8676. +
  8677. +    DEVICE_BUSY = 0;
  8678. +    wake_up(&busy_wait);
  8679. +    return 0;
  8680. +}
  8681. +
  8682. diff -urNwbB linux/arch/arm/drivers/block/hdsrch.c linux.arm/arch/arm/drivers/block/hdsrch.c
  8683. --- linux/arch/arm/drivers/block/hdsrch.c    Thu Jan  1 01:00:00 1970
  8684. +++ linux.arm/arch/arm/drivers/block/hdsrch.c    Sun Mar  3 12:29:41 1996
  8685. @@ -0,0 +1,665 @@
  8686. +/*
  8687. + * linux/arch/arm/drivers/block/hdsrch.c
  8688. + *
  8689. + * Copyright (C) 1995, 1996 Russell King
  8690. + *
  8691. + * Find image files on ADFS hard drives.
  8692. + *  This currently only supports new map, 77 entry directory hard disks... (E format).
  8693. + */
  8694. +
  8695. +#include <linux/config.h>
  8696. +#include <linux/ctype.h>
  8697. +#include <linux/kernel.h>
  8698. +#include <linux/mm.h>
  8699. +#include <linux/malloc.h>
  8700. +#include <linux/string.h>
  8701. +#include <linux/genhd.h>
  8702. +
  8703. +#define RECSIZE 60
  8704. +
  8705. +#define MAX_BLK_FRAGS 64
  8706. +
  8707. +extern void print_minor_name (struct gendisk *hd, int minor);
  8708. +
  8709. +struct boot_block
  8710. +{
  8711. +  unsigned char  log2secsize;
  8712. +  unsigned char  secspertrack;
  8713. +  unsigned char  heads;
  8714. +  unsigned char  density;
  8715. +  unsigned char  idlen;
  8716. +  unsigned char  log2bpmb;
  8717. +  unsigned char  shew;
  8718. +  unsigned char  bootoption;
  8719. +  unsigned char  lowsector;
  8720. +  unsigned char  nzones;
  8721. +  unsigned short zone_spare;
  8722. +  unsigned long  root;
  8723. +  unsigned long  disc_size;
  8724. +  unsigned short disc_id;
  8725. +  unsigned char  disc_name[32-22];
  8726. +  unsigned long  disctype;
  8727. +};
  8728. +
  8729. +static struct boot_block *boot=NULL;
  8730. +static unsigned int zonesize;
  8731. +static unsigned int idsperzone;
  8732. +static long rootaddr;
  8733. +static long mapaddr;
  8734. +static long maplen;
  8735. +static void *map=NULL;
  8736. +static char ignoring;
  8737. +
  8738. +static int read_sectors(int dev,void *ptr,long address,int size)
  8739. +{
  8740. +  struct buffer_head *bh;
  8741. +  char *p=ptr;
  8742. +  while(size>0) {
  8743. +    if((bh=bread(dev,address/1024,1024))) {
  8744. +      memcpy(p,bh->b_data+((address & 0x200)?512:0),(address & 0x200 || size<1024)?512:1024);
  8745. +      if(address & 0x200) {
  8746. +          p -= 512;
  8747. +        address -= 512;
  8748. +        size += 512;
  8749. +      }
  8750. +    } else {
  8751. +      printk("hda%c: bread failed\n",'a'+((dev & 0xc0)>>6));
  8752. +      return 0;
  8753. +    }
  8754. +    brelse(bh);
  8755. +    p += 1024;
  8756. +    address += 1024;
  8757. +    size -= 1024;
  8758. +  }
  8759. +  return 1;
  8760. +}
  8761. +
  8762. +/* + Read boot block at disc address &C00 (sector 6)
  8763. + * + Calculate map address & length
  8764. + */
  8765. +
  8766. +static int getdiskinfo(int dev)
  8767. +{
  8768. +  char *ptr;
  8769. +  extern void set_hdinfo(int,unsigned char,unsigned char,unsigned long,unsigned int);
  8770. +
  8771. +  if(boot)
  8772. +      return 1;
  8773. +
  8774. +  boot=(struct boot_block *)kmalloc(sizeof(struct boot_block),GFP_KERNEL);
  8775. +  if(!boot) {
  8776. +    printk("hda%c: out of memory for bootblock\n",(dev>>6)+'a');
  8777. +    return 0;
  8778. +  }
  8779. +
  8780. +  ptr=(char *)kmalloc(1024,GFP_KERNEL);
  8781. +  if(!ptr) {
  8782. +    printk("hda%c: out of memory for bootblock\n",(dev>>6)+'a');
  8783. +    return 0;
  8784. +  }
  8785. +
  8786. +  if(!read_sectors(dev,ptr,0xC00,1024)) {
  8787. +    kfree_s(ptr,1024);
  8788. +    return 0;
  8789. +  }
  8790. +  memcpy(boot,(ptr+0x1C0),sizeof(struct boot_block));
  8791. +  kfree_s(ptr,1024);
  8792. +
  8793. +  set_hdinfo(dev,boot->secspertrack,boot->heads,boot->disc_size,1<<boot->log2secsize);
  8794. +
  8795. +  zonesize=(8<<boot->log2secsize)-boot->zone_spare;
  8796. +  idsperzone=zonesize/(boot->idlen+1);
  8797. +  mapaddr=((boot->nzones>>1)*zonesize-((boot->nzones>1)?RECSIZE*8:0))<<boot->log2bpmb;
  8798. +  maplen=boot->nzones<<boot->log2secsize;
  8799. +  return 1;
  8800. +}
  8801. +
  8802. +static unsigned char map_cross_valid_byte(void)
  8803. +{
  8804. +  unsigned char const *const map_base=map;
  8805. +  unsigned int check=0;
  8806. +  unsigned int i;
  8807. +
  8808. +  for(i=0;i<boot->nzones;i++)
  8809. +    check^=map_base[(i<<boot->log2secsize)+3];
  8810. +
  8811. +  return check;
  8812. +}
  8813. +
  8814. +static int get_map(int dev)
  8815. +{
  8816. +  if(!getdiskinfo(dev))
  8817. +    return 0;
  8818. +
  8819. +  if(map)
  8820. +    return 1;
  8821. +
  8822. +  map = (unsigned long *)vmalloc(maplen);
  8823. +  if(!map)
  8824. +    return 0;
  8825. +
  8826. +  if(!read_sectors(dev,map,mapaddr,maplen))
  8827. +    return 0;
  8828. +  if(map_cross_valid_byte()!=0xFF) {
  8829. +    printk("Map 1 has invalid cross check - trying second map\n");
  8830. +    if(!read_sectors(dev,map,mapaddr+maplen,maplen))
  8831. +      return 0;
  8832. +    if(map_cross_valid_byte()!=0xFF) {
  8833. +      printk("Map 2 has invalid cross check - ignoring drive\n");
  8834. +      ignoring=dev;
  8835. +      return 0;
  8836. +    }
  8837. +  }
  8838. +
  8839. +  memcpy(boot,(char*)map+4,sizeof(struct boot_block));
  8840. +
  8841. +  rootaddr=mapaddr+2*maplen;
  8842. +  return 1;
  8843. +}
  8844. +
  8845. +static int readmap(int sin,int *fzone,int *fstart,int *fend,int max_frags)
  8846. +{
  8847. +    static int startzone;    /* Start zone             */
  8848. +    static int fragment;    /* Fragment id to look for     */
  8849. +    static int curzone;    /* Current zone             */
  8850. +    static int curmapp;    /* Current map bit position     */
  8851. +  
  8852. +    register unsigned int t,z,frag,czone,cmap;
  8853. +    register unsigned char const *mapaddr;
  8854. +    register int *fz,*fs,*fe;
  8855. +    register unsigned char n;
  8856. +    
  8857. +  
  8858. +    if(sin) {/* If we have new address, start from new position */
  8859. +        fragment = sin >> 8;
  8860. +        curzone = startzone = fragment / idsperzone;
  8861. +        curmapp=0;
  8862. +    }
  8863. +    if(curzone == -1)
  8864. +        return 0;
  8865. +    frag = fragment;
  8866. +    czone = curzone;
  8867. +    cmap = curmapp;
  8868. +    fz = fzone;
  8869. +    fs = fstart;
  8870. +    fe = fend;
  8871. +
  8872. +/*   printk("readmap: internal_address: %p, fragment: %p, zone: %p\n",sin,frag, */
  8873. +/*     czone); */
  8874. +
  8875. +    while(1) {
  8876. +        mapaddr=(unsigned char const *)map+
  8877. +                (czone<<boot->log2secsize)+4+((czone==0)?RECSIZE:0);
  8878. +        while(cmap<zonesize-((czone==0)?RECSIZE*8:0))/* ? */ {
  8879. +            *fs=cmap;
  8880. +            z=cmap>>3;
  8881. +            t=((mapaddr[z]|(mapaddr[z+1]<<8)|(mapaddr[z+2]<<16))>>(cmap & 7)) &
  8882. +                ((1<<boot->idlen)-1);
  8883. +            cmap+=boot->idlen;
  8884. +            
  8885. +            while((cmap & 7)!=0 && (mapaddr[cmap>>3] & (1<<(cmap & 7)))==0)
  8886. +                cmap+=1;
  8887. +
  8888. +            while((n=mapaddr[cmap>>3]) == 0)
  8889. +                cmap+=8;
  8890. +
  8891. +            while((n & (1<<(cmap & 7)))==0)
  8892. +                cmap+=1;
  8893. +            cmap+=1;
  8894. +            if(t==frag) {
  8895. +                *fz++=czone;
  8896. +                *fe++=cmap;
  8897. +                fs++;
  8898. +                if(!--max_frags) {
  8899. +/*                     printf("Breaking out\n"); */
  8900. +                    curmapp = cmap;
  8901. +                    curzone = czone;
  8902. +                    return fs - fstart;
  8903. +                }
  8904. +            }
  8905. +        }
  8906. +        czone+=1;
  8907. +        if(czone==boot->nzones)
  8908. +            czone=0;
  8909. +        if(czone==startzone)
  8910. +            break;
  8911. +        cmap=0;
  8912. +    }
  8913. +    curzone = -1;
  8914. +    return fs - fstart;
  8915. +}
  8916. +
  8917. +static unsigned long calcaddr(int zone,int offset)
  8918. +{
  8919. +  if(zone)
  8920. +    return (zone*zonesize-RECSIZE*8+offset)<<boot->log2bpmb;
  8921. +  else
  8922. +    return offset<<boot->log2bpmb;
  8923. +}
  8924. +
  8925. +static void scan_name(char *name,int len)
  8926. +{
  8927. +  int i;
  8928. +  for(i=0;i<len+1;i++) {
  8929. +    if(name[i]<32 || name[i]=='.' || i==len) {
  8930. +      name[i]=0;
  8931. +      break;
  8932. +    }
  8933. +    if(islower(name[i]))
  8934. +      name[i]=toupper(name[i]);
  8935. +  }
  8936. +}
  8937. +
  8938. +static unsigned long scandir(int dev,unsigned long diraddress,char *file,int *type,
  8939. +       unsigned long *length)
  8940. +{
  8941. +  unsigned char *dir;
  8942. +  unsigned char *dd;
  8943. +  unsigned long addr;
  8944. +
  8945. +  scan_name(file,10);
  8946. +
  8947. +  dir=(unsigned char *)kmalloc(2048,GFP_KERNEL);
  8948. +
  8949. +  read_sectors(dev,dir,diraddress,2048);
  8950. +
  8951. +  if(strncmp((char*)dir+1,"Nick",4)!=0 && strncmp((char*)dir+1,"Hugo",4)!=0) {
  8952. +    printk("Broken directory - skipping\n");
  8953. +    return 0;
  8954. +  }
  8955. +
  8956. +  dd=dir+5-26;
  8957. +  do {
  8958. +    dd+=26;
  8959. +    scan_name((char*)dd,10);
  8960. +    if(strcmp(file,(char*)dd)==0)
  8961. +      break;
  8962. +  }
  8963. +  while(*dd!=0);
  8964. +  if(*dd==0)
  8965. +    return 0;
  8966. +  else
  8967. +  if(dd[25] & 8)
  8968. +    *type=0;
  8969. +  *length=(unsigned long)dd[18]|(dd[19]<<8)|(dd[20]<<16)|(dd[21]<<24);
  8970. +  addr=(unsigned long)dd[22]|(dd[23]<<8)|(dd[24]<<16);
  8971. +
  8972. +  kfree_s(dir,2048);
  8973. +
  8974. +  return addr;
  8975. +}
  8976. +
  8977. +static int search_path(int dev,char *path,unsigned long *start,unsigned long *length, int maxbits)
  8978. +{
  8979. +  unsigned long dir,iad,len;
  8980. +  int type,i,n,fzones[MAX_BLK_FRAGS],fstart[MAX_BLK_FRAGS],fend[MAX_BLK_FRAGS];
  8981. +  char *p;
  8982. +
  8983. +  if(!get_map(dev))
  8984. +    return 0;
  8985. +
  8986. +  dir=rootaddr;
  8987. +  while(path) {
  8988. +    type=1;
  8989. +    p=strchr(path,'.');
  8990. +    if(p!=NULL) {
  8991. +      p[0]=0;
  8992. +    }
  8993. +    if(path[0]!='\0') {
  8994. +      iad=scandir(dev,dir,path,&type,&len);
  8995. +      if(iad==0) {
  8996. +        printk("%s '%s' not found - skipping\n",p==NULL?"File":"Directory",path);
  8997. +        return 0;
  8998. +      }
  8999. +      if(type==0) {
  9000. +        n=readmap(iad,fzones,fstart,fend,1);
  9001. +        dir=calcaddr(fzones[0],fstart[0]);
  9002. +      } else
  9003. +      if(p!=NULL) {
  9004. +        printk("'%s' is a directory - skipping\n",path);
  9005. +        return 0;
  9006. +      } else {
  9007. +        int j=0;
  9008. +        unsigned int secoff;
  9009. +        secoff=(iad & 0xFF)?(unsigned int)((iad & 0xFF)-1)<<boot->log2secsize:0;
  9010. +        len=((len-1)|((1<<boot->log2secsize)-1))+1;
  9011. +        n=readmap(iad,fzones,fstart,fend,MAX_BLK_FRAGS); /* Handle 64 entries at a time */
  9012. +        do {
  9013. +          for(i=0;i<n;i++) {
  9014. +            start[j]=calcaddr(fzones[i],fstart[i]);
  9015. +            length[j]=calcaddr(fzones[i],fend[i])-start[j];
  9016. +            if(secoff!=0) {
  9017. +              if(length[j]>secoff) {
  9018. +                start[j]+=secoff;
  9019. +                length[j]-=secoff;
  9020. +                secoff=0;
  9021. +              } else {
  9022. +                secoff-=length[j];
  9023. +                continue;
  9024. +              }
  9025. +            }
  9026. +        
  9027. +            if(j > 0 && start[j]==(start[j-1]+length[j-1])) {/* Combine parts */
  9028. +              len += length[j-1];
  9029. +              length[j-1]+=length[j];
  9030. +              j--;
  9031. +            }
  9032. +        
  9033. +            if(length[j]>len) {
  9034. +              length[j]=len;
  9035. +              j++;
  9036. +              break;
  9037. +            } else
  9038. +              len-=length[j];
  9039. +            j++;
  9040. +            if(j >= maxbits) {
  9041. +#ifdef NOT_YET_TESTED
  9042. +        unsigned long **sn,**ln;
  9043. +        sn=(unsigned long*)kmalloc(maxbits+BLK_INCREMENT,GFP_KERNEL);
  9044. +        ln=(unsigned long*)kmalloc(maxbits+BLK_INCREMENT,GFP_KERNEL);
  9045. +        if(maxbits && start && length) {
  9046. +          memcpy(sn,start,maxbits);
  9047. +          memcpy(ln,length,maxbits);
  9048. +          kfree_s((void *)start, maxbits);
  9049. +          kfree_s((void *)length, maxbits);
  9050. +        }
  9051. +        maxbits+=BLK_INCREMENT;
  9052. +#else
  9053. +                printk("**** EEEK!!!! - Image file is in too many chunks!\n");
  9054. +                return 0;
  9055. +#endif
  9056. +            }
  9057. +          }
  9058. +        }
  9059. +        while((n=readmap(0,fzones,fstart,fend,MAX_BLK_FRAGS))>0);
  9060. +        return j;
  9061. +      }
  9062. +    }
  9063. +    if(p) {
  9064. +      path=p+1;
  9065. +      p[0]='.';
  9066. +    } else
  9067. +      path=0;
  9068. +  }
  9069. +  printk("Pathname invalid?!?\n");
  9070. +  return 0;
  9071. +}
  9072. +
  9073. +#define MAX_HD_IMAGES    8
  9074. +#define TWO_HDS
  9075. +#define MAX_HD_BITS    128
  9076. +
  9077. +static int initialised[MAX_HD_IMAGES];
  9078. +static int maxblock[MAX_HD_IMAGES];
  9079. +static unsigned long startchk[MAX_HD_IMAGES],lengthchk[MAX_HD_IMAGES];
  9080. +#ifndef NOT_YET_TESTED
  9081. +static unsigned long startaddr[MAX_HD_IMAGES][MAX_HD_BITS],
  9082. +            lengthaddr[MAX_HD_IMAGES][MAX_HD_BITS];
  9083. +#else
  9084. +static unsigned long *startaddr[MAX_HD_IMAGES],
  9085. +                    *lengthaddr[MAX_HD_IMAGES];
  9086. +#endif
  9087. +
  9088. +/* --------------------------------------------------------------------------------- */
  9089. +/*  Externally visible functions/variables
  9090. + * --------------------------------------------------------------------------------- */
  9091. +
  9092. +char arc_hd_files[MAX_HD_IMAGES][128]=
  9093. +{
  9094. +  {0,},
  9095. +  {0,},
  9096. +  {0,},
  9097. +  {0,}
  9098. +};
  9099. +
  9100. +/*
  9101. + * Get the sectors used by device 'dev'
  9102. + */
  9103. +int image_allocate_list(int dev,int devno,struct hd_struct *part)
  9104. +{
  9105. +    unsigned long chk1=0,chk2=0;
  9106. +    int i,sects=0;
  9107. +
  9108. +#ifndef TWO_HDS
  9109. +    if(dev!=0x300)
  9110. +    {
  9111. +        printk("Can't cope with >1 hd!\n");
  9112. +        return 0;
  9113. +    }
  9114. +#else
  9115. +    if(dev!=0x300 && dev!=0x340)
  9116. +    {
  9117. +        printk("Can't cope with >2 hds! (device %02X:%02X)\n",dev>>8,dev & 255);
  9118. +        return 0;
  9119. +    }
  9120. +    if(dev == 0x340)
  9121. +      devno=(devno & 0x3f) + 4;
  9122. +#endif
  9123. +
  9124. +    if(ignoring==dev)
  9125. +        return 0;
  9126. +
  9127. +    devno--;
  9128. +
  9129. +    if(devno > MAX_HD_IMAGES)
  9130. +        return 0;
  9131. +
  9132. +    if(!arc_hd_files[devno][0])
  9133. +        return 0;
  9134. +
  9135. +#ifndef NOT_YET_TESTED
  9136. +    maxblock[devno]=search_path(dev,arc_hd_files[devno],startaddr[devno],lengthaddr[devno],MAX_HD_BITS);
  9137. +#else
  9138. +    maxblock[devno]=search_path(dev,arc_hd_files[devno],startaddr[devno],lengthaddr[devno],0);
  9139. +#endif
  9140. +    if(maxblock[devno]>MAX_HD_BITS)
  9141. +        panic("image allocator: image file is too fragmented\n");
  9142. +    if(!maxblock[devno])
  9143. +        return 0;
  9144. +
  9145. +    for(i=0; i<maxblock[devno]; i++)
  9146. +    {
  9147. +        /* convert to blocks & calculate checksums */
  9148. +#define ADDR2BLOCK(x) ((x)>>9)
  9149. +        startaddr[devno][i]=ADDR2BLOCK(startaddr[devno][i]);
  9150. +        lengthaddr[devno][i]=ADDR2BLOCK(lengthaddr[devno][i]);
  9151. +        chk1^=startaddr[devno][i];
  9152. +        chk2^=lengthaddr[devno][i];
  9153. +        sects+=lengthaddr[devno][i];
  9154. +    }
  9155. +    startchk[devno]=chk1;
  9156. +    lengthchk[devno]=chk2;
  9157. +    initialised[devno]=1;
  9158. +    part->start_sect=0;
  9159. +    part->nr_sects=sects;
  9160. +
  9161. +#ifdef DEBUG
  9162. +    for(i=0;i<n;i++)
  9163. +        printk("%10X : %10X\n",start[devno][i],length[devno][i]);
  9164. +#endif
  9165. +    return 1;
  9166. +}
  9167. +
  9168. +/*
  9169. + * This is called to release all the memory with this device
  9170. + *
  9171. + * This must be called before accessing a new device
  9172. + */
  9173. +
  9174. +void image_release_dev(int dev)
  9175. +{
  9176. +  if(boot) {
  9177. +    kfree_s(boot,sizeof(struct boot_block));
  9178. +    boot=NULL;
  9179. +  }
  9180. +
  9181. +  if(map) {
  9182. +    vfree(map);
  9183. +    map = NULL;
  9184. +  }
  9185. +
  9186. +  ignoring=0;
  9187. +}
  9188. +
  9189. +/* 
  9190. + * This macro maps a device major/minor to the internal image file number
  9191. + */
  9192. +#ifndef TWO_HDS
  9193. +#define GET_DEV(dev) \
  9194. +    if((dev)<0x301 || (dev)>0x314) \
  9195. +    { \
  9196. +        printk("Bad device %X passed to image_file_check\n",(dev)); \
  9197. +        return 0; \
  9198. +    } \
  9199. +    (dev)=((dev)-1) & 3;
  9200. +#else
  9201. +#define GET_DEV(dev) \
  9202. +    if(((dev) & 0x33F)<0x301 || ((dev) & 0x33F)>0x314) \
  9203. +    { \
  9204. +        printk("Bad device %X passed to image_file_check\n",(dev)); \
  9205. +        return 0; \
  9206. +    } \
  9207. +    switch((dev) & 0xC0) \
  9208. +    { \
  9209. +        case 0x00: (dev)=((dev) -1) & 3;     break;\
  9210. +        case 0x40: (dev)=(((dev) -1) & 3)+4; break;\
  9211. +    }
  9212. +#endif
  9213. +
  9214. +/* 
  9215. + * This function is called to perform checks on the image file.
  9216. + *  Checks made: Image file has been initialised, and
  9217. + *     for writes, the checksums on the start/length data are correct.
  9218. + */
  9219. +int image_file_check(int dev,int cmd)
  9220. +{
  9221. +    long chk1=0,chk2=0;
  9222. +    int i;
  9223. +
  9224. +    GET_DEV(dev);
  9225. +
  9226. +    if (!initialised[dev]) {
  9227. +        printk("hd%c%d: %s of uninitialised image file.\n",(dev>>6)+'a',dev & 0x3f,
  9228. +          cmd==WRITE?"write":"read");
  9229. +        return 0;
  9230. +    }
  9231. +
  9232. +    if (cmd==WRITE) {
  9233. +        /*
  9234. +         * Check the table! Just in case. We don't want to write to a part of the HD that
  9235. +         * is not allocated to us! It might be the map or something!
  9236. +         */
  9237. +        for(i=0; i<maxblock[dev]; i++) {
  9238. +              chk1^=startaddr[dev][i];
  9239. +              chk2^=lengthaddr[dev][i];
  9240. +        }
  9241. +        if(chk1!=startchk[dev] || chk2!=lengthchk[dev]) {
  9242. +            printk("hda%c%d: mapping tables corrupted on write.",
  9243. +                (dev>>6)+'a',dev & 0x3f);
  9244. +            return 0;
  9245. +        }
  9246. +    }
  9247. +    return 1;
  9248. +}
  9249. +
  9250. +/*
  9251. + * Map an image file block to a physical device returns 0 on error,
  9252. + * or the number of entries.  This is called quite often when accessing
  9253. + * image files.
  9254. + */
  9255. +int image_file_map(int dev,unsigned long reqblock,unsigned long reqlength,
  9256. +            unsigned long max_reqs,
  9257. +                    unsigned long *block,unsigned long *length)
  9258. +{
  9259. +    int i,num=0;
  9260. +    unsigned long blk=reqblock,totlen=0;
  9261. +
  9262. +    GET_DEV(dev);
  9263. +
  9264. +    for(i=0; i<maxblock[dev]; i++)
  9265. +    {
  9266. +        long remainder;
  9267. +        totlen+=lengthaddr[dev][i];
  9268. +        if(reqblock >= lengthaddr[dev][i])
  9269. +        {
  9270. +            reqblock-=lengthaddr[dev][i];
  9271. +            continue;
  9272. +        }
  9273. +        block[num]=reqblock+startaddr[dev][i];
  9274. +        remainder=reqblock+reqlength-lengthaddr[dev][i];
  9275. +        if(remainder<=0)
  9276. +        {
  9277. +            length[num]=reqlength;
  9278. +            return num+1;
  9279. +        }
  9280. +        length[num]=lengthaddr[dev][i]-reqblock;
  9281. +        if(num+1 >= max_reqs)
  9282. +            return num+1;
  9283. +        reqblock=0;
  9284. +        reqlength=remainder;
  9285. +        num++;
  9286. +    }
  9287. +
  9288. +    printk("hd%c%d: attempted read for sector %ld past end if image file at %ld.\n",
  9289. +        (dev>>6)+'a',dev & 0x3f,blk,totlen);
  9290. +        /* Should never happen! */
  9291. +    return 0;
  9292. +}
  9293. +
  9294. +
  9295. +
  9296. +#if 0
  9297. +static inline int check_bb(unsigned char *ptr)
  9298. +{
  9299. +    unsigned int result;
  9300. +    
  9301. +    __asm__("
  9302. +    adds    %3, %2, %3
  9303. +    sub    %3, %3, #1
  9304. +    b    LC02
  9305. +LC01:    ldrb    %4, [%3, #-1]!
  9306. +    adc    %0, %0, %4
  9307. +    movs    %0, %0, lsl #24
  9308. +    mov    %0, %0, lsr #24
  9309. +LC02:    teqs    %2, %3
  9310. +    bne    LC01
  9311. +    " : "=r" (result) : "0" (0), "r" (ptr), "r" (512), "r" (256));
  9312. +    return result != ptr[511];
  9313. +}
  9314. +
  9315. +static struct bootblock *bb;
  9316. +
  9317. +int arm_partition (struct gendisk *hd, kdev_t dev, unsigned long first_sector, int minor)
  9318. +{
  9319. +    int i;
  9320. +    struct buffer_head *bh;
  9321. +
  9322. +    current_minor = minor;
  9323. +
  9324. +    if (!(bh = bread (dev, 3, 1024))) {
  9325. +    printk (" unable to read boot sectors\n");
  9326. +    return -1;
  9327. +    }
  9328. +
  9329. +    if (check_bb (bh->b_data))
  9330. +    {
  9331. +    brelse (bh);
  9332. +    return 0;
  9333. +    }
  9334. +
  9335. +    bb = (struct bootblock *)(bh->b_data + 0x1c0);
  9336. +
  9337. +    set_hdinfo(dev,bb->secspertrack,bb->heads,bb->disc_size,1<<bb->log2secsize);
  9338. +
  9339. +    zonesize   = (8 << bb->log2secsize) - bb->zone_spare;
  9340. +    idsperzone = zonesize / (bb->idlen + 1);
  9341. +    mapaddr    = ((bb->nzones >> 1) * zonesize - ((bb->nzones > 1)? RECSIZE*8 : 0)) << bb->log2bpmb;
  9342. +    maplen     = bb->nzones << bb->log2secsize;
  9343. +
  9344. +    
  9345. +
  9346. +    brelse (bh);
  9347. +    return 1;
  9348. +}
  9349. +#endif
  9350. +
  9351. diff -urNwbB linux/arch/arm/drivers/block/mfmhd.c linux.arm/arch/arm/drivers/block/mfmhd.c
  9352. --- linux/arch/arm/drivers/block/mfmhd.c    Thu Jan  1 01:00:00 1970
  9353. +++ linux.arm/arch/arm/drivers/block/mfmhd.c    Sun Mar  3 12:30:30 1996
  9354. @@ -0,0 +1,778 @@
  9355. +/*
  9356. + * linux/arch/arm/drivers/block/mfmhd.c
  9357. + *
  9358. + * Copyright (C) 1995, 1996 Russell King
  9359. + *
  9360. + * MFM hard drive code [experimental]
  9361. + */
  9362. +
  9363. +#ifdef MODULE
  9364. +#include <linux/module.h>
  9365. +#include <linux/version.h>
  9366. +#endif
  9367. +
  9368. +#include <linux/config.h>
  9369. +#include <linux/sched.h>
  9370. +#include <linux/fs.h>
  9371. +#include <linux/kernel.h>
  9372. +#include <linux/timer.h>
  9373. +#include <linux/tqueue.h>
  9374. +#include <linux/mm.h>
  9375. +
  9376. +#include <linux/xd.h>
  9377. +#include <linux/errno.h>
  9378. +#include <linux/genhd.h>
  9379. +#include <linux/major.h>
  9380. +
  9381. +#include <asm/system.h>
  9382. +#include <asm/io.h>
  9383. +#include <asm/segment.h>
  9384. +#include <asm/dma.h>
  9385. +
  9386. +#include <asm/ecard.h>
  9387. +
  9388. +#define MFM_DISK_MAJOR    13
  9389. +#undef  XT_DISK_MAJOR
  9390. +#define XT_DISK_MAJOR    -1
  9391. +#define MAJOR_NR    MFM_DISK_MAJOR
  9392. +#include "blk.h"
  9393. +
  9394. +XD_INFO mfm_info[XD_MAXDRIVES];
  9395. +
  9396. +#define DEBUG
  9397. +
  9398. +#define MFM_COMMAND (mfm_addr + 0)
  9399. +#define MFM_DATAOUT (mfm_addr + 1)
  9400. +#define MFM_STATUS  (mfm_addr + 8)
  9401. +#define MFM_DATAIN  (mfm_addr + 9)
  9402. +
  9403. +static void mfm_geninit (void);
  9404. +static int  mfm_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg);
  9405. +static int  mfm_open (struct inode *inode,struct file *file);
  9406. +static void mfm_release (struct inode *inode, struct file *file);
  9407. +static void mfm_interrupt_handler (int, struct pt_regs *);
  9408. +static void mfm_seek (void);
  9409. +static void mfm_unexpected_interrupt (void);
  9410. +static void mfm_request (void);
  9411. +static int  mfm_reread_partitions (int dev);
  9412. +static void mfm_request (void);
  9413. +
  9414. +#define mfm_init xd_init
  9415. +
  9416. +static struct hd_struct mfm[XD_MAXDRIVES << 6];
  9417. +static int mfm_sizes[XD_MAXDRIVES << 6], mfm_access[XD_MAXDRIVES] = { 0, 0 };
  9418. +static int mfm_blocksizes[XD_MAXDRIVES << 6];
  9419. +static unsigned char mfm_valid[XD_MAXDRIVES] = { -1, };
  9420. +static struct wait_queue *mfm_wait_open = NULL;
  9421. +
  9422. +static int mfm_irq;        /* Interrupt number */
  9423. +static int mfm_addr;        /* Controller address */
  9424. +static int mfm_drives = 0;    /* drives available */
  9425. +static int mfm_status = 0;    /* interrupt status */
  9426. +static char mfm_busy = 0;    /* mfm busy */
  9427. +static int *errors;
  9428. +
  9429. +static struct rawcmd
  9430. +{
  9431. +  unsigned int flags;
  9432. +  unsigned int dev;
  9433. +  unsigned int cylinder;
  9434. +  unsigned int head;
  9435. +  unsigned int sector;
  9436. +  unsigned int cmdtype;
  9437. +  unsigned int cmdcode;
  9438. +  unsigned char cmddata[16];
  9439. +  unsigned int cmdlen;
  9440. +} raw_cmd;
  9441. +
  9442. +#define NEED_SEEK 1
  9443. +unsigned char result[16];
  9444. +unsigned char resultlen;
  9445. +
  9446. +static struct cont
  9447. +{
  9448. +    void (*interrupt)(void);/* interrupt handler */
  9449. +    void (*error)(void);    /* error handler */
  9450. +    void (*redo)(void);    /* redo handler */
  9451. +    void (*done)(int st);    /* done handler */
  9452. +} *cont = NULL;
  9453. +
  9454. +static struct drvparam
  9455. +{
  9456. +    int cylinder;
  9457. +    unsigned int nocylinders;
  9458. +    unsigned int lowcurrentcylinder;
  9459. +    unsigned int precompcylinder;
  9460. +    unsigned char noheads;
  9461. +    unsigned char nosectors;
  9462. +    struct
  9463. +    {
  9464. +        char recal;
  9465. +        char report;
  9466. +        char abort;
  9467. +    } errors;
  9468. +} mfm_drive_param[8] =
  9469. +{
  9470. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  9471. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  9472. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  9473. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  9474. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  9475. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  9476. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } },
  9477. +    { -1, 616, 616, 129, 4, 32, { 0,0,1 } }
  9478. +};
  9479. +
  9480. +#define MFM_DRV_PARAM mfm_drive_param[raw_cmd.dev]
  9481. +
  9482. +struct tq_struct mfm_tq =
  9483. +{ 0, 0, (void (*) (void *)) mfm_unexpected_interrupt, 0 };
  9484. +
  9485. +#define NO_TRACK -1
  9486. +#define NEED_1_RECAL -2
  9487. +#define NEED_2_RECAL -3
  9488. +
  9489. +
  9490. +/* ------------------------------------------------------------------------------------------ */
  9491. +/*
  9492. + * From the HD63463 data sheet from Hitachi Ltd.
  9493. + */
  9494. +
  9495. +#define CMD_ABT        0xF0        /* Abort */
  9496. +#define CMD_SPC        0xE8        /* Specify */
  9497. +#define CMD_TST        0xE0        /* Test */
  9498. +#define CMD_RCLB    0xC8        /* Recalibrate */
  9499. +#define CMD_SEK        0xC0        /* Seek */
  9500. +#define CMD_WFS        0xAB        /* Write Format Skew */
  9501. +#define CMD_WFM        0xA3        /* Write Format */
  9502. +#define CMD_MTB        0x90        /* Memory to buffer */
  9503. +#define CMD_CMPD    0x88        /* Compare data */
  9504. +#define CMD_WD        0x87        /* Write data */
  9505. +#define CMD_RED        0x70        /* Read erroneous data */
  9506. +#define CMD_RIS        0x68        /* Read ID skew */
  9507. +#define CMD_FID        0x61        /* Find ID */
  9508. +#define CMD_RID        0x60        /* Read ID */
  9509. +#define CMD_BTM        0x50        /* Buffer to memory */
  9510. +#define CMD_CKD        0x48        /* Check data */
  9511. +#define CMD_RD        0x40        /* Read data */
  9512. +#define CMD_OPBW    0x38        /* Open buffer write */
  9513. +#define CMD_OPBR    0x30        /* Open buffer read */
  9514. +#define CMD_CKV        0x28        /* Check drive */
  9515. +#define CMD_CKE        0x20        /* Check ECC */
  9516. +#define CMD_POD        0x18        /* Polling disable */
  9517. +#define CMD_POL        0x10        /* Polling enable */
  9518. +#define CMD_RCAL    0x08        /* Recall */
  9519. +
  9520. +#define STAT_BSY    0x8000        /* Busy */
  9521. +#define STAT_CPR    0x4000        /* Command Parameter Rejection */
  9522. +#define STAT_CED    0x2000        /* Command end */
  9523. +#define STAT_SED    0x1000        /* Seek end */
  9524. +#define STAT_DER    0x0800        /* Drive error */
  9525. +#define STAT_ABN    0x0400        /* Abnormal end */
  9526. +#define STAT_POL    0x0200        /* Polling */
  9527. +
  9528. +/* ------------------------------------------------------------------------------------------ */
  9529. +
  9530. +static struct gendisk mfm_gendisk = {
  9531. +    MAJOR_NR,    /* Major number */
  9532. +    "mfm",        /* Major name */
  9533. +    6,        /* Bits to shift to get real from partition */
  9534. +    1 << 6,        /* Number of partitions per real */
  9535. +    XD_MAXDRIVES,    /* maximum number of real */
  9536. +    mfm_geninit,    /* init function */
  9537. +    mfm,        /* hd struct */
  9538. +    mfm_sizes,    /* block sizes */
  9539. +    0,        /* number */
  9540. +    (void *)mfm_info,/* internal */
  9541. +    NULL        /* next */
  9542. +};
  9543. +
  9544. +static struct file_operations mfm_fops = {
  9545. +    NULL,            /* lseek - default */
  9546. +    block_read,        /* read - general block-dev read */
  9547. +    block_write,        /* write - general block-dev write */
  9548. +    NULL,            /* readdir - bad */
  9549. +    NULL,            /* select */
  9550. +    mfm_ioctl,        /* ioctl */
  9551. +    NULL,            /* mmap */
  9552. +    mfm_open,        /* open */
  9553. +    mfm_release,        /* release */
  9554. +    block_fsync        /* fsync */
  9555. +};
  9556. +
  9557. +static struct expansion_card *ecs;
  9558. +static int mfm_prods[] = { 0x000b };
  9559. +static int mfm_manus[] = { 0x0000 };
  9560. +
  9561. +unsigned long mfm_init (unsigned long mem_start, unsigned long mem_end)
  9562. +{
  9563. +    ecs = ecard_find(0, sizeof(mfm_prods), mfm_prods, mfm_manus);
  9564. +    if(!ecs)
  9565. +        return mem_start;
  9566. +
  9567. +    mfm_irq = ecs->irq;
  9568. +    mfm_addr= ((((int)ecs->r_podaddr) & 0x03eff000) + 0x2000)>>2;
  9569. +
  9570. +    ecard_claim(ecs);
  9571. +
  9572. +    printk("mfm: controller found at address %X, interrupt %d\n", mfm_addr, mfm_irq);
  9573. +
  9574. +    if(register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) {
  9575. +        printk("mfm_init: unable to get major number %d\n", MAJOR_NR);
  9576. +        return mem_start;
  9577. +    }
  9578. +    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  9579. +    read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahread */
  9580. +#ifndef MODULE
  9581. +    mfm_gendisk.next = gendisk_head;
  9582. +    gendisk_head = & mfm_gendisk;
  9583. +#endif
  9584. +
  9585. +    return mem_start;
  9586. +}
  9587. +
  9588. +static int mfm_initdrives (void)
  9589. +{
  9590. +    mfm_info[0].heads = 4;
  9591. +    mfm_info[0].cylinders = 615;
  9592. +    mfm_info[0].sectors = 32;
  9593. +    mfm_info[0].control = 0;
  9594. +    return 1;
  9595. +}
  9596. +
  9597. +static void mfm_geninit (void)
  9598. +{
  9599. +    int i;
  9600. +
  9601. +    mfm_drives = mfm_initdrives();
  9602. +    printk("mfm: detected %d hard drive%s\n", mfm_drives, mfm_drives == 1?"":"s");
  9603. +    for(i = 0; i < mfm_drives; i++)
  9604. +        printk("mfm%d: heads = %d, cylinders = %d, sectors = %d\n", i,
  9605. +             mfm_info[i].heads, mfm_info[i].cylinders, mfm_info[i].sectors);
  9606. +
  9607. +    if(request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk"))
  9608. +        printk("mfm: unable to get IRQ%d\n", mfm_irq);
  9609. +
  9610. +    outw(0x80, mfm_addr + (0x1000 >> 2));
  9611. +
  9612. +    for(i = 0; i < mfm_drives; i++) {
  9613. +        mfm[i << 6].nr_sects = mfm_info[i].heads * mfm_info[i].cylinders *
  9614. +                mfm_info[i].sectors;
  9615. +        mfm[i << 6].start_sect = 0;
  9616. +        mfm_valid[i] = 1;
  9617. +    }
  9618. +    mfm_gendisk.nr_real = mfm_drives;
  9619. +
  9620. +    for(i=0; i<(XD_MAXDRIVES << 6); i++)
  9621. +        mfm_blocksizes[i] = 1024;
  9622. +    blksize_size[MAJOR_NR] = mfm_blocksizes;
  9623. +}
  9624. +
  9625. +static int mfm_open (struct inode *inode,struct file *file)
  9626. +{
  9627. +    int dev = DEVICE_NR(MINOR(inode->i_rdev));
  9628. +
  9629. +    if (dev < mfm_drives) {
  9630. +        while (!mfm_valid[dev])
  9631. +            sleep_on(&mfm_wait_open);
  9632. +
  9633. +        mfm_access[dev]++;
  9634. +
  9635. +        return (0);
  9636. +    }
  9637. +    else
  9638. +        return (-ENODEV);
  9639. +}
  9640. +
  9641. +static int mfm_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
  9642. +{
  9643. +    XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg;
  9644. +    int dev = DEVICE_NR(MINOR(inode->i_rdev)),err;
  9645. +
  9646. +    if (inode && (dev < mfm_drives))
  9647. +        switch (cmd) {
  9648. +            case HDIO_GETGEO:
  9649. +                if (arg) {
  9650. +                    if ((err = verify_area(VERIFY_WRITE, geometry, sizeof(*geometry))))
  9651. +                        return (err);
  9652. +                    put_fs_byte(mfm_info[dev].heads,(char *) &geometry->heads);
  9653. +                    put_fs_byte(mfm_info[dev].sectors,(char *) &geometry->sectors);
  9654. +                    put_fs_word(mfm_info[dev].cylinders,(short *) &geometry->cylinders);
  9655. +                    put_fs_long(mfm[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start);
  9656. +
  9657. +                    return (0);
  9658. +                }
  9659. +                break;
  9660. +            case BLKRASET:
  9661. +              if(!suser())  return -EACCES;
  9662. +              if(!inode->i_rdev) return -EINVAL;
  9663. +              if(arg > 0xff) return -EINVAL;
  9664. +              read_ahead[MAJOR(inode->i_rdev)] = arg;
  9665. +              return 0;
  9666. +            case BLKGETSIZE:
  9667. +                if (arg) {
  9668. +                    if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
  9669. +                        return (err);
  9670. +                    put_fs_long(mfm[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
  9671. +
  9672. +                    return (0);
  9673. +                }
  9674. +                break;
  9675. +            case BLKFLSBUF:
  9676. +                if(!suser())  return -EACCES;
  9677. +                if(!inode->i_rdev) return -EINVAL;
  9678. +                fsync_dev(inode->i_rdev);
  9679. +                invalidate_buffers(inode->i_rdev);
  9680. +                return 0;
  9681. +
  9682. +            case BLKRRPART:
  9683. +                return (mfm_reread_partitions(inode->i_rdev));
  9684. +            RO_IOCTLS(inode->i_rdev,arg);
  9685. +        }
  9686. +    return (-EINVAL);
  9687. +}
  9688. +
  9689. +static void mfm_release (struct inode *inode, struct file *file)
  9690. +{
  9691. +    int dev = DEVICE_NR(MINOR(inode->i_rdev));
  9692. +
  9693. +    if (dev < mfm_drives) {
  9694. +        sync_dev(dev);
  9695. +        mfm_access[dev]--;
  9696. +    }
  9697. +}
  9698. +
  9699. +static int mfm_reread_partitions (int dev)
  9700. +{
  9701. +    int target = DEVICE_NR(MINOR(dev)),start = target << mfm_gendisk.minor_shift,partition;
  9702. +
  9703. +    cli();
  9704. +
  9705. +    mfm_valid[target] = (mfm_access[target] != 1);
  9706. +
  9707. +    sti();
  9708. +
  9709. +    if (mfm_valid[target])
  9710. +        return -EBUSY;
  9711. +
  9712. +    for (partition = mfm_gendisk.max_p - 1; partition >= 0; partition--) {
  9713. +        sync_dev(MAJOR_NR << 8 | start | partition);
  9714. +        invalidate_inodes(MAJOR_NR << 8 | start | partition);
  9715. +        invalidate_buffers(MAJOR_NR << 8 | start | partition);
  9716. +        mfm_gendisk.part[start + partition].start_sect = 0;
  9717. +        mfm_gendisk.part[start + partition].nr_sects = 0;
  9718. +    };
  9719. +
  9720. +    mfm_gendisk.part[start].nr_sects = mfm_info[target].heads *
  9721. +        mfm_info[target].cylinders * mfm_info[target].sectors;
  9722. +    resetup_one_dev(&mfm_gendisk,target);
  9723. +
  9724. +    mfm_valid[target] = 1;
  9725. +    wake_up(&mfm_wait_open);
  9726. +
  9727. +    return 0;
  9728. +}
  9729. +
  9730. +static void print_status (void)
  9731. +{
  9732. +    char *error;
  9733. +    static char *errors[] =
  9734. +    { "no error",
  9735. +      "command aborted",
  9736. +      "invalid command",
  9737. +      "parameter error",
  9738. +      "not initialised",
  9739. +      "rejected TEST",
  9740. +      "no useld",
  9741. +      "write fault",
  9742. +      "not ready",
  9743. +      "no scp",
  9744. +      "in seek",
  9745. +      "invalid NCA",
  9746. +      "invalid step rate",
  9747. +      "seek error",
  9748. +      "over run",
  9749. +      "invalid PHA",
  9750. +      "data field EEC error",
  9751. +      "data field CRC error",
  9752. +      "error corrected",
  9753. +      "data field fatal error",
  9754. +      "no data am",
  9755. +      "not hit",
  9756. +      "ID field CRC error",
  9757. +      "time over",
  9758. +      "no ID am",
  9759. +      "not writable"
  9760. +    };
  9761. +    if(result[1] < 0x65)
  9762. +        error = errors[result[1] >> 2];
  9763. +    else
  9764. +        error = "unknown";
  9765. +    printk("(");
  9766. +    if(mfm_status & STAT_BSY)
  9767. +        printk("BSY ");
  9768. +    if(mfm_status & STAT_CPR)
  9769. +        printk("CPR ");
  9770. +    if(mfm_status & STAT_CED)
  9771. +        printk("CED ");
  9772. +    if(mfm_status & STAT_SED)
  9773. +        printk("SED ");
  9774. +    if(mfm_status & STAT_DER)
  9775. +        printk("DER ");
  9776. +    if(mfm_status & STAT_ABN)
  9777. +        printk("ABN ");
  9778. +    if(mfm_status & STAT_POL)
  9779. +        printk("POL ");
  9780. +    printk(") SSB = %X (%s)\n", result[1], error);
  9781. +
  9782. +}
  9783. +
  9784. +/* ------------------------------------------------------------------------------------- */
  9785. +
  9786. +static void issue_command (int command, unsigned char *cmdb, int len)
  9787. +{
  9788. +    int status;
  9789. +#ifdef DEBUG
  9790. +    int i;
  9791. +    printk("issue_command: %02X: ",command);
  9792. +    for(i=0; i<len; i++)
  9793. +      printk("%02X ", cmdb[i]);
  9794. +    printk("\n");
  9795. +#endif
  9796. +
  9797. +    do {
  9798. +        status = inw(MFM_STATUS);
  9799. +    } while(status & (STAT_BSY|STAT_POL));
  9800. +    if(status & STAT_CPR)
  9801. +    {
  9802. +        outw(CMD_RCAL, MFM_COMMAND);
  9803. +        while(inw(MFM_STATUS) & STAT_BSY);
  9804. +    }
  9805. +
  9806. +    while(len > 0)
  9807. +    {
  9808. +        outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT);
  9809. +        len -= 2;
  9810. +        cmdb += 2;
  9811. +    }
  9812. +    outw(command, MFM_COMMAND);
  9813. +}
  9814. +
  9815. +static void wait_for_completion (void)
  9816. +{
  9817. +    while((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
  9818. +}
  9819. +
  9820. +/* ------------------------------------------------------------------------------------- */
  9821. +
  9822. +static void mfm_rw_intr (void)
  9823. +{
  9824. +    printk("mfm_rw_intr...\n");
  9825. +    if (cont)
  9826. +    {
  9827. +        cont->done(1);
  9828. +    }
  9829. +    mfm_request();
  9830. +}
  9831. +
  9832. +static void mfm_setup_rw (void)
  9833. +{
  9834. +    printk("setting up for rw...\n");
  9835. +#if 1
  9836. +    SET_INTR(mfm_rw_intr);
  9837. +    issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);
  9838. +#else
  9839. +    if(cont)
  9840. +    {
  9841. +        cont->done(0);
  9842. +        cont->redo();
  9843. +    }
  9844. +#endif
  9845. +}
  9846. +
  9847. +static void mfm_recal_intr (void)
  9848. +{
  9849. +    printk("recal intr - status = ");
  9850. +    print_status();
  9851. +    if(mfm_status & (STAT_DER|STAT_ABN)) {
  9852. +        printk("recal failed\n");
  9853. +        MFM_DRV_PARAM.cylinder = NEED_2_RECAL;
  9854. +        if(cont)
  9855. +        {
  9856. +            cont->error();
  9857. +            cont->redo();
  9858. +        }
  9859. +        return;
  9860. +    }
  9861. +    if(mfm_status & STAT_SED) {
  9862. +        issue_command(CMD_POD, NULL, 0);
  9863. +        MFM_DRV_PARAM.cylinder = 0;
  9864. +        mfm_seek();
  9865. +        return;
  9866. +    }
  9867. +    if(mfm_status & STAT_CED) {
  9868. +        SET_INTR(mfm_recal_intr);
  9869. +        issue_command(CMD_POL, NULL, 0);
  9870. +        return;
  9871. +    }
  9872. +    printk("recal: unknown status\n");
  9873. +}
  9874. +
  9875. +static void mfm_seek_intr (void)
  9876. +{
  9877. +    printk("seek intr - status = ");
  9878. +    print_status();
  9879. +    if(mfm_status & (STAT_DER|STAT_ABN)) {
  9880. +        printk("seek failed\n");
  9881. +        MFM_DRV_PARAM.cylinder = NEED_2_RECAL;
  9882. +        if(cont)
  9883. +        {
  9884. +            cont->error();
  9885. +            cont->redo();
  9886. +        }
  9887. +        return;
  9888. +    }
  9889. +    if(mfm_status & STAT_SED) {
  9890. +        issue_command(CMD_POD, NULL, 0);
  9891. +        MFM_DRV_PARAM.cylinder = raw_cmd.cylinder;
  9892. +        mfm_seek();
  9893. +        return;
  9894. +    }
  9895. +    if(mfm_status & STAT_CED) {
  9896. +        SET_INTR(mfm_seek_intr);
  9897. +        issue_command(CMD_POL, NULL, 0);
  9898. +        return;
  9899. +    }
  9900. +    printk("seek: unknown status\n");
  9901. +}
  9902. +
  9903. +static void mfm_specify (void)
  9904. +{
  9905. +    unsigned char cmdb[16];
  9906. +    printk("specify...\n");
  9907. +    cmdb[0] = 0x1F;
  9908. +    cmdb[1] = 0xC3;
  9909. +    cmdb[2] = 0x16;
  9910. +    cmdb[3] = 0x02;
  9911. +    cmdb[4] = 0xFC | ((MFM_DRV_PARAM.nocylinders - 1) >> 8);
  9912. +    cmdb[5] = MFM_DRV_PARAM.nocylinders - 1;
  9913. +    cmdb[6] = MFM_DRV_PARAM.noheads - 1;
  9914. +    cmdb[7] = MFM_DRV_PARAM.nosectors - 1;
  9915. +    cmdb[8] = 0xA9;
  9916. +    cmdb[9] = 0x0A;
  9917. +    cmdb[10]= 0x0D;
  9918. +    cmdb[11]= 0x0C;
  9919. +    cmdb[12]= (MFM_DRV_PARAM.precompcylinder - 1) >> 8;
  9920. +    cmdb[13]= MFM_DRV_PARAM.precompcylinder - 1;
  9921. +    cmdb[14]= (MFM_DRV_PARAM.lowcurrentcylinder - 1) >> 8;
  9922. +    cmdb[15]= MFM_DRV_PARAM.lowcurrentcylinder - 1;
  9923. +
  9924. +    issue_command(CMD_SPC, cmdb, 16);
  9925. +    wait_for_completion();
  9926. +}
  9927. +
  9928. +static void mfm_seek (void)
  9929. +{
  9930. +    unsigned char cmdb[4];
  9931. +    printk("seeking...\n");
  9932. +    if(MFM_DRV_PARAM.cylinder < 0) {
  9933. +        cmdb[0] = raw_cmd.dev + 1;
  9934. +        cmdb[1] = raw_cmd.head;
  9935. +
  9936. +        SET_INTR(mfm_recal_intr);
  9937. +        issue_command(CMD_RCLB, cmdb, 2);
  9938. +        return;
  9939. +    }
  9940. +    mfm_specify();
  9941. +    if(MFM_DRV_PARAM.cylinder != raw_cmd.cylinder)
  9942. +    {
  9943. +        cmdb[0] = raw_cmd.dev + 1;
  9944. +        cmdb[1] = raw_cmd.head;
  9945. +        cmdb[2] = raw_cmd.cylinder >> 8;
  9946. +        cmdb[3] = raw_cmd.cylinder;
  9947. +
  9948. +        SET_INTR(mfm_seek_intr);
  9949. +        issue_command(CMD_SEK, cmdb, 4);
  9950. +    }
  9951. +    else
  9952. +        mfm_setup_rw();
  9953. +}
  9954. +
  9955. +static void mfm_initialise (void)
  9956. +{
  9957. +    printk("init...\n");
  9958. +    if(raw_cmd.flags & NEED_SEEK)
  9959. +        mfm_seek();
  9960. +    else
  9961. +        mfm_setup_rw();
  9962. +}
  9963. +
  9964. +/* ------------------------------------------------------------------------------------- */
  9965. +
  9966. +static void request_done(int uptodate)
  9967. +{
  9968. +    if(!CURRENT) {
  9969. +        printk("mfm: request list destroyed\n");
  9970. +        return;
  9971. +    }
  9972. +    if(uptodate) {
  9973. +        end_request (1);
  9974. +    }
  9975. +    else {
  9976. +        end_request (0);
  9977. +    }
  9978. +}
  9979. +
  9980. +static void error_handler (void)
  9981. +{
  9982. +    int i;
  9983. +    printk("error detected... status = ");
  9984. +    print_status();
  9985. +    (*errors) ++;
  9986. +    if(*errors > MFM_DRV_PARAM.errors.abort)
  9987. +        cont->done(0);
  9988. +    if(*errors > MFM_DRV_PARAM.errors.recal)
  9989. +        MFM_DRV_PARAM.cylinder = NEED_2_RECAL;
  9990. +}
  9991. +
  9992. +static void rw_interrupt(void)
  9993. +{
  9994. +}
  9995. +
  9996. +static struct cont rw_cont ={
  9997. +    rw_interrupt,
  9998. +    error_handler,
  9999. +    mfm_request,
  10000. +    request_done
  10001. +};
  10002. +
  10003. +static void mfm_request (void)
  10004. +{
  10005. +    unsigned int dev, block, nsect, track;
  10006. +
  10007. +    if(CURRENT && CURRENT->dev < 0)
  10008. +        return;
  10009. +
  10010. +    while(1){
  10011. +        sti();
  10012. +
  10013. +        INIT_REQUEST;
  10014. +        dev = MINOR(CURRENT->dev);
  10015. +        block = CURRENT->sector;
  10016. +        nsect = CURRENT->nr_sectors;
  10017. +
  10018. +        if(dev >= (mfm_drives << 6) ||
  10019. +            block >= mfm[dev].nr_sects || ((block+nsect) > mfm[dev].nr_sects)) {
  10020. +#ifdef DEBUG
  10021. +            if(dev >= (mfm_drives << 6))
  10022. +                printk("mfm: bad minor number: device=0x%04x\n", CURRENT->dev);
  10023. +            else
  10024. +                printk("mfm%c: bad access: block=%d, count=%d\n", (dev>>6)+'a',
  10025. +                    block, nsect);
  10026. +#endif
  10027. +            end_request(0);
  10028. +            continue;
  10029. +        }
  10030. +        block += mfm[dev].start_sect;
  10031. +
  10032. +        if(CURRENT->cmd != READ && CURRENT->cmd != WRITE)
  10033. +        {
  10034. +            printk("unknown mfm-command %d\n", CURRENT->cmd);
  10035. +            end_request(0);
  10036. +            continue;
  10037. +        }
  10038. +
  10039. +        dev >>= 6;
  10040. +
  10041. +        track = block / mfm_info[dev].sectors;
  10042. +        raw_cmd.flags        = NEED_SEEK;
  10043. +        raw_cmd.dev        = dev;
  10044. +        raw_cmd.sector        = block % mfm_info[dev].sectors;
  10045. +        raw_cmd.head        = track % mfm_info[dev].heads;
  10046. +        raw_cmd.cylinder    = track / mfm_info[dev].heads;
  10047. +        raw_cmd.cmdtype     = CURRENT->cmd;
  10048. +        raw_cmd.cmdcode     = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD;
  10049. +        raw_cmd.cmddata[0]    = dev;
  10050. +        raw_cmd.cmddata[1]    = raw_cmd.head;
  10051. +        raw_cmd.cmddata[2]    = raw_cmd.cylinder >> 8;
  10052. +        raw_cmd.cmddata[3]    = raw_cmd.cylinder;
  10053. +        raw_cmd.cmddata[4]    = raw_cmd.head;
  10054. +        raw_cmd.cmddata[5]    = raw_cmd.sector;
  10055. +        raw_cmd.cmddata[6]    = nsect >> 8;
  10056. +        raw_cmd.cmddata[7]    = nsect;
  10057. +        raw_cmd.cmdlen        = 8;
  10058. +
  10059. +#ifdef DEBUG
  10060. +        printk("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
  10061. +            raw_cmd.dev+'a', (CURRENT->cmd == READ)?"read":"writ",
  10062. +            raw_cmd.cylinder,
  10063. +            raw_cmd.head,
  10064. +            raw_cmd.sector, nsect, (unsigned long)CURRENT->buffer, CURRENT);
  10065. +#endif
  10066. +        cont = &rw_cont;
  10067. +        errors = &(CURRENT->errors);
  10068. +        mfm_tq.routine = (void (*)(void *))mfm_initialise;
  10069. +        queue_task(&mfm_tq, &tq_timer);
  10070. +        break;
  10071. +    }
  10072. +}
  10073. +
  10074. +static void do_mfm_request (void)
  10075. +{
  10076. +    mfm_request();
  10077. +}
  10078. +
  10079. +static void mfm_unexpected_interrupt (void)
  10080. +{
  10081. +    printk("mfm: unexpected interrupt - status = ");
  10082. +    print_status();
  10083. +}
  10084. +
  10085. +static void mfm_interrupt_handler (int unused, struct pt_regs *regs)
  10086. +{
  10087. +    int i;
  10088. +    void (*handler)(void) = DEVICE_INTR;
  10089. +
  10090. +    CLEAR_INTR;
  10091. +    mfm_status = inw(MFM_STATUS);
  10092. +
  10093. +    if((mfm_status & (STAT_CPR|STAT_BSY)) == STAT_CPR)
  10094. +    {
  10095. +        int len = 0;
  10096. +        while(len <16)
  10097. +        {
  10098. +            int in;
  10099. +            in = inw(MFM_DATAIN);
  10100. +            result[len++] = in>>8;
  10101. +            result[len++] = in;
  10102. +        }
  10103. +    }
  10104. +
  10105. +    outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
  10106. +
  10107. +    if(!handler) {
  10108. +        mfm_unexpected_interrupt();
  10109. +        return;
  10110. +    }
  10111. +    mfm_tq.routine = (void (*)(void *))handler;
  10112. +    queue_task_irq(&mfm_tq, &tq_timer);
  10113. +}
  10114. +
  10115. +#ifdef MODULE
  10116. +
  10117. +char kernel_version[] = UTS_RELEASE;
  10118. +
  10119. +int init_module (void)
  10120. +{
  10121. +    mfm_init(0, 0);
  10122. +    mfm_geninit();
  10123. +    return 0;
  10124. +}
  10125. +
  10126. +void cleanup_module (void)
  10127. +{
  10128. +    if (ecs)
  10129. +        ecard_release(ecs);
  10130. +}
  10131. +    
  10132. +#endif
  10133. diff -urNwbB linux/arch/arm/drivers/char/Makefile linux.arm/arch/arm/drivers/char/Makefile
  10134. --- linux/arch/arm/drivers/char/Makefile    Thu Jan  1 01:00:00 1970
  10135. +++ linux.arm/arch/arm/drivers/char/Makefile    Sat Feb 24 14:18:57 1996
  10136. @@ -0,0 +1,87 @@
  10137. +#
  10138. +# Makefile for the kernel character device drivers.
  10139. +#
  10140. +# Note! Dependencies are done automagically by 'make dep', which also
  10141. +# removes any old dependencies. DON'T put your own dependencies here
  10142. +# unless it's something special (ie not a .c file).
  10143. +#
  10144. +# Note 2! The CFLAGS definitions are now inherited from the
  10145. +# parent makes..
  10146. +#
  10147. +
  10148. +#
  10149. +# This file contains the font map for the default font
  10150. +#
  10151. +
  10152. +all: links first_rule
  10153. +
  10154. +FONTMAPFILE = cp437.uni
  10155. +
  10156. +L_TARGET := char.a
  10157. +M_OBJS   :=
  10158. +L_OBJS   := tty_io.o n_tty.o console.o keyboard.o serial.o \
  10159. +    tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \
  10160. +    defkeymap.o consolemap.o iic.o
  10161. +
  10162. +# vesa_blank.o selection.o
  10163. +
  10164. +
  10165. +ifeq ($(CONFIG_PRINTER),y)
  10166. +  L_OBJS += lp.o
  10167. +else
  10168. +  ifeq ($(CONFIG_PRINTER),m)
  10169. +    M_OBJS += lp.o
  10170. +  endif
  10171. +endif
  10172. +
  10173. +ifeq ($(CONFIG_MOUSE),y)
  10174. +  M = y
  10175. +else
  10176. +  ifeq ($(CONFIG_MOUSE),m)
  10177. +    M = mm
  10178. +  endif
  10179. +endif
  10180. +
  10181. +ifeq ($(CONFIG_KBDMOUSE),y)
  10182. +  M = y
  10183. +  L_OBJS += kbdmouse.o
  10184. +else
  10185. +  ifeq ($(CONFIG_KBDMOUSE),m)
  10186. +    MM = m
  10187. +    M_OBJS += kbdmouse.o
  10188. +  endif
  10189. +endif
  10190. +
  10191. +ifdef M
  10192. +  L_OBJS += mouse.o
  10193. +else
  10194. +  ifdef MM
  10195. +    M_OBJS += mouse.o
  10196. +  endif
  10197. +endif
  10198. +
  10199. +include $(TOPDIR)/Rules.make
  10200. +
  10201. +fastdep: links uni_hash.tbl
  10202. +
  10203. +consolemap.o:
  10204. +
  10205. +conmakehash: conmakehash.c
  10206. +    $(HOSTCC) -o conmakehash conmakehash.c
  10207. +
  10208. +uni_hash.tbl: $(FONTMAPFILE) conmakehash
  10209. +    ./conmakehash $(FONTMAPFILE) > uni_hash.tbl
  10210. +
  10211. +LK = conmakehash.c consolemap.c consolemap.h cp437.uni kbd_kern.h lp.c random.c
  10212. +
  10213. +links:
  10214. +    -@for f in $(LK); do \
  10215. +        ln -s ../../../../drivers/char/$$f .; \
  10216. +    done
  10217. +    touch links
  10218. +
  10219. +LINKCLEAN:
  10220. +    -@for f in $(LK); do \
  10221. +        if [ -L $$f ]; then rm -f $$f; fi; \
  10222. +    done
  10223. +    rm -f links
  10224. diff -urNwbB linux/arch/arm/drivers/char/console.c linux.arm/arch/arm/drivers/char/console.c
  10225. --- linux/arch/arm/drivers/char/console.c    Thu Jan  1 01:00:00 1970
  10226. +++ linux.arm/arch/arm/drivers/char/console.c    Sun Mar  3 12:31:06 1996
  10227. @@ -0,0 +1,2722 @@
  10228. +/*
  10229. + * linux/arch/arm/drivers/char/console.c
  10230. + *
  10231. + * Modifications (C) 1995, 1996 Russell King
  10232. + */
  10233. +
  10234. +/*
  10235. + * This module exports the console io functions:
  10236. + *
  10237. + *    'int vc_allocate(unsigned int console)'
  10238. + *    'int vc_cons_allocated(unsigned int console)'
  10239. + *    'int vc_resize(unsigned long lines,unsigned long cols)'
  10240. + *    'void vc_disallocate(unsigned int currcons)'
  10241. + *
  10242. + *    'unsigned long con_init(unsigned long)'
  10243. + * S    'int con_open(struct tty_struct *tty,struct file *filp)'
  10244. + * S    'void con_write(struct tty_struct *tty)'
  10245. + * S    'void console_print(const char *b)'
  10246. + *    'void update_screen(int new_console)'
  10247. + *
  10248. + *    'void blank_screen(void)'
  10249. + *    'void unblank_screen(void)'
  10250. + *    'void poke_blanked_console(void)'
  10251. + *    'void scrollback(int lines)'            *
  10252. + *    'void scrollfront(int lines)'            *
  10253. + *    'int do_screendump(int arg)'
  10254. + *
  10255. + *    'int con_get_font(char *)'
  10256. + *    'int con_set_font(char *)'
  10257. + *    'int con_get_trans(char *)'
  10258. + *    'int con_set_trans(char *)'
  10259. + *
  10260. + *    'int set_selection(const int arg)'        *
  10261. + *    'int paste_selection(struct tty_struct *tty)'    *
  10262. + *    'int sel_loadlut(const int arg)'        *
  10263. + *    'int mouse_reporting(void)'            *
  10264. + *
  10265. + */
  10266. +
  10267. +#define BLANK 0x0020
  10268. +
  10269. +/* A bitmap for codes <32. A bit of 1 indicates that the code
  10270. + * corresponding to that bit number invokes a special action
  10271. + * (such as cursor movement) and should not be displayed as a
  10272. + * glyph unless the disp_ctrl mode is explicitly enabled.
  10273. + */
  10274. +#define CTRL_ACTION 0x0d00ff81
  10275. +#define CTRL_ALWAYS 0x0800f501  /* Cannot be overriden by disp_ctrl */
  10276. +#include <linux/config.h>
  10277. +#include <linux/sched.h>
  10278. +#include <linux/timer.h>
  10279. +#include <linux/interrupt.h>
  10280. +#include <linux/tty.h>
  10281. +#include <linux/tty_flip.h>
  10282. +#include <linux/kernel.h>
  10283. +#include <linux/errno.h>
  10284. +#include <linux/kd.h>
  10285. +#include <linux/major.h>
  10286. +#include <linux/mm.h>
  10287. +#include <linux/malloc.h>
  10288. +
  10289. +#include <asm/segment.h>
  10290. +#include <asm/irq-no.h>
  10291. +
  10292. +#include "kbd_kern.h"
  10293. +#include "vt_kern.h"
  10294. +#include "consolemap.h"
  10295. +
  10296. +/* ARM Extensions */
  10297. +extern void memc_write (int reg, int val);
  10298. +extern void vidc_write (int reg, int val);
  10299. +extern void ll_char_write(unsigned long ps, int ch, unsigned char forec,
  10300. +             unsigned char backc, unsigned char flgs);
  10301. +extern void memfastset (void *ptr, unsigned long word, int length);
  10302. +extern void prints (const char *, ...);
  10303. +extern void map_screen_mem (unsigned long vid_base, int remap);
  10304. +static void ll_erase(int currcons,unsigned char sx,unsigned char sy,
  10305. +            unsigned char cx,unsigned char cy);
  10306. +static void vsync_irq(int irq, struct pt_regs *regs);
  10307. +static void put_cursor(char on_off,unsigned long cpp);
  10308. +unsigned char bytes_per_char_h;
  10309. +unsigned char bytes_per_char_v;
  10310. +unsigned long video_addr_mask;
  10311. +/* MUST get rid of these */
  10312. +#define BOLD        0x01
  10313. +#define ITALIC        0x02
  10314. +#define UNDERLINE    0x04
  10315. +#define FLASH        0x08
  10316. +#define INVERSE        0x10
  10317. +#define FLAGS ((underline?UNDERLINE:0)|(reverse?INVERSE:0)|(blink?FLASH:0)|intensity)
  10318. +
  10319. +#include <linux/ctype.h>
  10320. +
  10321. +/* Routines for selection control. */
  10322. +int set_selection(const int arg, struct tty_struct *tty);
  10323. +int paste_selection(struct tty_struct *tty);
  10324. +static void clear_selection(void);
  10325. +static void highlight_pointer(const int currcons,const int where);
  10326. +
  10327. +#define SEL_BUFFER_SIZE 4096
  10328. +int sel_cons = 0;
  10329. +static int sel_start = -1;
  10330. +static int sel_end;
  10331. +static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' };
  10332. +
  10333. +
  10334. +
  10335. +#ifndef MIN
  10336. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  10337. +#endif
  10338. +
  10339. +struct tty_driver console_driver;
  10340. +static int console_refcount;
  10341. +static struct tty_struct *console_table[MAX_NR_CONSOLES];
  10342. +static struct termios *console_termios[MAX_NR_CONSOLES];
  10343. +static struct termios *console_termios_locked[MAX_NR_CONSOLES];
  10344. +
  10345. +#define NPAR 16
  10346. +
  10347. +static void con_setsize(unsigned long rows, unsigned long cols);
  10348. +static void vc_init(unsigned int console, unsigned long rows, unsigned long cols,
  10349. +            int do_clear);
  10350. +static void get_scrmem(int currcons);
  10351. +static void set_scrmem(int currcons, long offset);
  10352. +static void set_origin(int currcons);
  10353. +static void blank_screen(void);
  10354. +static void unblank_screen(void);
  10355. +void poke_blanked_console(void);
  10356. +static void gotoxy(int currcons, int new_x, int new_y);
  10357. +static void save_cur(int currcons);
  10358. +static inline void set_cursor(int currcons);
  10359. +static void reset_terminal(int currcons, int do_clear);
  10360. +extern void reset_vc(unsigned int new_console);
  10361. +extern void vt_init(void);
  10362. +extern void register_console(void (*proc)(const char *));
  10363. +extern void compute_shiftstate(void);
  10364. +extern void reset_palette (int currcons) ;
  10365. +extern void set_palette (void) ;
  10366. +
  10367. +/* Description of the hardware situation */
  10368. +static unsigned long    video_mem_base;        /* Base of video memory        */
  10369. +static unsigned long    video_mem_term;        /* End of video memory        */
  10370. +       unsigned long    video_num_columns;    /* Number of text columns    */
  10371. +static unsigned long    video_num_lines;    /* Number of text lines        */
  10372. +static unsigned long    video_size_row;
  10373. +static unsigned long    video_screen_size;
  10374. +static unsigned long    video_buf_size;
  10375. +static int can_do_color = 1;
  10376. +static int printable = 0;            /* Is console ready for printing? */
  10377. +
  10378. +static unsigned short console_charmask = 0x0ff;
  10379. +
  10380. +static unsigned char *vc_scrbuf[MAX_NR_CONSOLES];
  10381. +
  10382. +static int console_blanked = 0;
  10383. +static int blankinterval = 10*60*HZ;
  10384. +
  10385. +struct vc_data {
  10386. +    unsigned long    vc_screenbuf_size;
  10387. +    unsigned short    vc_video_erase_char;    /* Background erase character */
  10388. +    unsigned char    vc_attr;        /* Current attributes */
  10389. +    unsigned char    vc_def_forecol;
  10390. +    unsigned char    vc_def_backcol;
  10391. +    unsigned char    vc_forecol;
  10392. +    unsigned char    vc_backcol;
  10393. +    unsigned char    vc_s_forecol;
  10394. +    unsigned char    vc_s_backcol;
  10395. +    unsigned char    vc_cursoron;        /* Cursor on/off */
  10396. +    unsigned char    vc_ulcolor;        /* Colour for underline mode */
  10397. +    unsigned char    vc_halfcolor;        /* Colour for half intensity mode */
  10398. +    unsigned long    vc_origin;        /* Used for EGA/VGA fast scroll    */
  10399. +    unsigned long    vc_scr_end;        /* Used for EGA/VGA fast scroll    */
  10400. +    unsigned long    vc_pos;
  10401. +    unsigned long    vc_x,vc_y;
  10402. +    unsigned long    vc_top,vc_bottom;
  10403. +    unsigned long    vc_cstate;
  10404. +    unsigned long    vc_npar,vc_par[NPAR];
  10405. +    unsigned long    vc_video_mem_start;    /* Start of video RAM        */
  10406. +    unsigned long    vc_video_mem_end;    /* End of video RAM (sort of)    */
  10407. +    unsigned long    vc_saved_x;
  10408. +    unsigned long    vc_saved_y;
  10409. +    /* mode flags */
  10410. +    unsigned long    vc_charset    : 1;    /* Character set G0 / G1 */
  10411. +    unsigned long    vc_s_charset    : 1;    /* Saved character set */
  10412. +    unsigned long    vc_disp_ctrl    : 1;    /* Display chars < 32? */
  10413. +    unsigned long    vc_toggle_meta    : 1;    /* Toggle high bit? */
  10414. +    unsigned long    vc_decscnm    : 1;    /* Screen Mode */
  10415. +    unsigned long    vc_decom    : 1;    /* Origin Mode */
  10416. +    unsigned long    vc_decawm    : 1;    /* Autowrap Mode */
  10417. +    unsigned long    vc_deccm    : 1;    /* Cursor Visible */
  10418. +    unsigned long    vc_decim    : 1;    /* Insert Mode */
  10419. +    unsigned long    vc_deccolm    : 1;    /* 80/132 Column Mode */
  10420. +    /* attribute flags */
  10421. +    unsigned long    vc_intensity    : 2;    /* 0=half-bright, 1=normal, 2=bold */
  10422. +    unsigned long    vc_underline    : 1;
  10423. +    unsigned long    vc_blink    : 1;
  10424. +    unsigned long    vc_reverse    : 1;
  10425. +    unsigned long    vc_s_intensity    : 2;    /* saved rendition */
  10426. +    unsigned long    vc_s_underline    : 1;
  10427. +    unsigned long    vc_s_blink    : 1;
  10428. +    unsigned long    vc_s_reverse    : 1;
  10429. +    /* misc */
  10430. +    unsigned long    vc_ques        : 1;
  10431. +    unsigned long    vc_need_wrap    : 1;
  10432. +    unsigned long    vc_has_scrolled : 1;    /* Info for unblank_screen */
  10433. +    unsigned long    vc_kmalloced    : 1;    /* kfree_s() needed */
  10434. +    unsigned long    vc_report_mouse : 2;
  10435. +    unsigned char    vc_utf        : 1;    /* Unicode UTF-8 encoding */
  10436. +    unsigned char    vc_utf_count;
  10437. +    unsigned long    vc_utf_char;
  10438. +    unsigned long    vc_tab_stop[5];        /* Tab stops. 160 columns. */
  10439. +    unsigned short *vc_translate;
  10440. +    unsigned char     vc_G0_charset;
  10441. +    unsigned char     vc_G1_charset;
  10442. +    unsigned char     vc_saved_G0;
  10443. +    unsigned char     vc_saved_G1;
  10444. +    unsigned long * vc_paletteentries;
  10445. +    /* additional information is in vt_kern.h */
  10446. +};
  10447. +
  10448. +static struct vc {
  10449. +    struct vc_data *d;
  10450. +
  10451. +    /* might add  scrmem, vt_struct, kbd  at some time,
  10452. +       to have everything in one place - the disadvantage
  10453. +       would be that vc_cons etc can no longer be static */
  10454. +} vc_cons [MAX_NR_CONSOLES];
  10455. +
  10456. +#define screenbuf_size    (vc_cons[currcons].d->vc_screenbuf_size)
  10457. +#define origin        (vc_cons[currcons].d->vc_origin)
  10458. +#define scr_end        (vc_cons[currcons].d->vc_scr_end)
  10459. +#define pos        (vc_cons[currcons].d->vc_pos)
  10460. +#define top        (vc_cons[currcons].d->vc_top)
  10461. +#define bottom        (vc_cons[currcons].d->vc_bottom)
  10462. +#define x        (vc_cons[currcons].d->vc_x)
  10463. +#define y        (vc_cons[currcons].d->vc_y)
  10464. +#define vc_state    (vc_cons[currcons].d->vc_cstate)
  10465. +#define npar        (vc_cons[currcons].d->vc_npar)
  10466. +#define par        (vc_cons[currcons].d->vc_par)
  10467. +#define ques        (vc_cons[currcons].d->vc_ques)
  10468. +#define attr        (vc_cons[currcons].d->vc_attr)
  10469. +#define saved_x        (vc_cons[currcons].d->vc_saved_x)
  10470. +#define saved_y        (vc_cons[currcons].d->vc_saved_y)
  10471. +#define translate    (vc_cons[currcons].d->vc_translate)
  10472. +#define G0_charset    (vc_cons[currcons].d->vc_G0_charset)
  10473. +#define G1_charset    (vc_cons[currcons].d->vc_G1_charset)
  10474. +#define saved_G0    (vc_cons[currcons].d->vc_saved_G0)
  10475. +#define saved_G1    (vc_cons[currcons].d->vc_saved_G1)
  10476. +#define utf        (vc_cons[currcons].d->vc_utf)
  10477. +#define utf_count    (vc_cons[currcons].d->vc_utf_count)
  10478. +#define utf_char    (vc_cons[currcons].d->vc_utf_char)
  10479. +#define video_mem_start    (vc_cons[currcons].d->vc_video_mem_start)
  10480. +#define video_mem_end    (vc_cons[currcons].d->vc_video_mem_end)
  10481. +#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)
  10482. +#define disp_ctrl    (vc_cons[currcons].d->vc_disp_ctrl)
  10483. +#define toggle_meta    (vc_cons[currcons].d->vc_toggle_meta)
  10484. +#define decscnm        (vc_cons[currcons].d->vc_decscnm)
  10485. +#define decom        (vc_cons[currcons].d->vc_decom)
  10486. +#define decawm        (vc_cons[currcons].d->vc_decawm)
  10487. +#define deccm        (vc_cons[currcons].d->vc_deccm)
  10488. +#define decim        (vc_cons[currcons].d->vc_decim)
  10489. +#define deccolm         (vc_cons[currcons].d->vc_deccolm)
  10490. +#define need_wrap    (vc_cons[currcons].d->vc_need_wrap)
  10491. +#define has_scrolled    (vc_cons[currcons].d->vc_has_scrolled)
  10492. +#define kmalloced    (vc_cons[currcons].d->vc_kmalloced)
  10493. +#define report_mouse    (vc_cons[currcons].d->vc_report_mouse)
  10494. +#define forecol        (vc_cons[currcons].d->vc_forecol)
  10495. +#define backcol        (vc_cons[currcons].d->vc_backcol)
  10496. +#define s_forecol    (vc_cons[currcons].d->vc_s_forecol)
  10497. +#define s_backcol    (vc_cons[currcons].d->vc_s_backcol)
  10498. +#define def_forecol    (vc_cons[currcons].d->vc_def_forecol)
  10499. +#define def_backcol    (vc_cons[currcons].d->vc_def_backcol)
  10500. +#define cursoron    (vc_cons[currcons].d->vc_cursoron)
  10501. +#define charset        (vc_cons[currcons].d->vc_charset)
  10502. +#define s_charset    (vc_cons[currcons].d->vc_s_charset)
  10503. +#define    intensity    (vc_cons[currcons].d->vc_intensity)
  10504. +#define    underline    (vc_cons[currcons].d->vc_underline)
  10505. +#define    blink        (vc_cons[currcons].d->vc_blink)
  10506. +#define    reverse        (vc_cons[currcons].d->vc_reverse)
  10507. +#define    s_intensity    (vc_cons[currcons].d->vc_s_intensity)
  10508. +#define    s_underline    (vc_cons[currcons].d->vc_s_underline)
  10509. +#define    s_blink        (vc_cons[currcons].d->vc_s_blink)
  10510. +#define    s_reverse    (vc_cons[currcons].d->vc_s_reverse)
  10511. +#define tab_stop    (vc_cons[currcons].d->vc_tab_stop)
  10512. +#define paletteentries    (vc_cons[currcons].d->vc_paletteentries)
  10513. +
  10514. +#define vcmode        (vt_cons[currcons]->vc_mode)
  10515. +#define structsize    (sizeof(struct vc_data) + sizeof(struct vt_struct))
  10516. +
  10517. +/* ARC Extention */
  10518. +char cmap_80[][8]=
  10519. +{
  10520. + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /*   */
  10521. + {0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x00}, /* ! */
  10522. + {0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, /* " */
  10523. + {0x36,0x36,0x7F,0x36,0x7F,0x36,0x36,0x00}, /* # */
  10524. + {0x0C,0x3F,0x68,0x3E,0x0B,0x7E,0x18,0x00}, /* $ */
  10525. + {0x60,0x66,0x0C,0x18,0x30,0x66,0x06,0x00}, /* % */
  10526. + {0x38,0x6C,0x6C,0x38,0x6D,0x66,0x3B,0x00}, /* & */
  10527. + {0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, /* ' */
  10528. + {0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, /* ( */
  10529. + {0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, /* ) */
  10530. + {0x00,0x18,0x7E,0x3C,0x7E,0x18,0x00,0x00}, /* * */
  10531. + {0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00}, /* + */
  10532. + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, /* , */
  10533. + {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, /* - */
  10534. + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, /* . */
  10535. + {0x00,0x06,0x0C,0x18,0x30,0x60,0x00,0x00}, /* / */
  10536. + {0x3C,0x66,0x6E,0x7E,0x76,0x66,0x3C,0x00}, /* 0 */
  10537. + {0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00}, /* 1 */
  10538. + {0x3C,0x66,0x06,0x0C,0x18,0x30,0x7E,0x00}, /* 2 */
  10539. + {0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, /* 3 */
  10540. + {0x0C,0x1C,0x3C,0x6C,0x7E,0x0C,0x0C,0x00}, /* 4 */
  10541. + {0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, /* 5 */
  10542. + {0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, /* 6 */
  10543. + {0x7E,0x06,0x0C,0x18,0x30,0x30,0x30,0x00}, /* 7 */
  10544. + {0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, /* 8 */
  10545. + {0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, /* 9 */
  10546. + {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x00}, /* : */
  10547. + {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x30}, /* ; */
  10548. + {0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, /* < */
  10549. + {0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00}, /* = */
  10550. + {0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, /* > */
  10551. + {0x3C,0x66,0x0C,0x18,0x18,0x00,0x18,0x00}, /* ? */
  10552. + {0x3C,0x66,0x6E,0x6A,0x6E,0x60,0x3C,0x00}, /* @ */
  10553. + {0x3C,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, /* A */
  10554. + {0x7C,0x66,0x66,0x7C,0x66,0x66,0x7C,0x00}, /* B */
  10555. + {0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x00}, /* C */
  10556. + {0x78,0x6C,0x66,0x66,0x66,0x6C,0x78,0x00}, /* D */
  10557. + {0x7E,0x60,0x60,0x7C,0x60,0x60,0x7E,0x00}, /* E */
  10558. + {0x7E,0x60,0x60,0x7C,0x60,0x60,0x60,0x00}, /* F */
  10559. + {0x3C,0x66,0x60,0x6E,0x66,0x66,0x3C,0x00}, /* G */
  10560. + {0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, /* H */
  10561. + {0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00}, /* I */
  10562. + {0x3E,0x0C,0x0C,0x0C,0x0C,0x6C,0x38,0x00}, /* J */
  10563. + {0x66,0x6C,0x78,0x70,0x78,0x6C,0x66,0x00}, /* K */
  10564. + {0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00}, /* L */
  10565. + {0x63,0x77,0x7F,0x6B,0x6B,0x63,0x63,0x00}, /* M */
  10566. + {0x66,0x66,0x76,0x7E,0x6E,0x66,0x66,0x00}, /* N */
  10567. + {0x3C,0x66,0x66,0x66,0x66,0x66,0x3C,0x00}, /* O */
  10568. + {0x7C,0x66,0x66,0x7C,0x60,0x60,0x60,0x00}, /* P */
  10569. + {0x3C,0x66,0x66,0x66,0x6A,0x6C,0x36,0x00}, /* Q */
  10570. + {0x7C,0x66,0x66,0x7C,0x6C,0x66,0x66,0x00}, /* R */
  10571. + {0x3C,0x66,0x60,0x3C,0x06,0x66,0x3C,0x00}, /* S */
  10572. + {0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, /* T */
  10573. + {0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00}, /* U */
  10574. + {0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, /* V */
  10575. + {0x63,0x63,0x6B,0x6B,0x7F,0x77,0x63,0x00}, /* W */
  10576. + {0x66,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00}, /* X */
  10577. + {0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00}, /* Y */
  10578. + {0x7E,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00}, /* Z */
  10579. + {0x7C,0x60,0x60,0x60,0x60,0x60,0x7C,0x00}, /* [ */
  10580. + {0x00,0x60,0x30,0x18,0x0C,0x06,0x00,0x00}, /* \ */
  10581. + {0x3E,0x06,0x06,0x06,0x06,0x06,0x3E,0x00}, /* ] */
  10582. + {0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00}, /* ^ */
  10583. + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, /* _ */
  10584. + {0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00}, /* ` */
  10585. + {0x00,0x00,0x3C,0x06,0x3E,0x66,0x3E,0x00}, /* a */
  10586. + {0x60,0x60,0x7C,0x66,0x66,0x66,0x7C,0x00}, /* b */
  10587. + {0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, /* c */
  10588. + {0x06,0x06,0x3E,0x66,0x66,0x66,0x3E,0x00}, /* d */
  10589. + {0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, /* e */
  10590. + {0x1C,0x30,0x30,0x7C,0x30,0x30,0x30,0x00}, /* f */
  10591. + {0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x3C}, /* g */
  10592. + {0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x00}, /* h */
  10593. + {0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, /* i */
  10594. + {0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x70}, /* j */
  10595. + {0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00}, /* k */
  10596. + {0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, /* l */
  10597. + {0x00,0x00,0x36,0x7F,0x6B,0x6B,0x63,0x00}, /* m */
  10598. + {0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, /* n */
  10599. + {0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, /* o */
  10600. + {0x00,0x00,0x7C,0x66,0x66,0x7C,0x60,0x60}, /* p */
  10601. + {0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x07}, /* q */
  10602. + {0x00,0x00,0x6C,0x76,0x60,0x60,0x60,0x00}, /* r */
  10603. + {0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, /* s */
  10604. + {0x30,0x30,0x7C,0x30,0x30,0x30,0x1C,0x00}, /* t */
  10605. + {0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x00}, /* u */
  10606. + {0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, /* v */
  10607. + {0x00,0x00,0x63,0x6B,0x6B,0x7F,0x36,0x00}, /* w */
  10608. + {0x00,0x00,0x66,0x3C,0x18,0x3C,0x66,0x00}, /* x */
  10609. + {0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x3C}, /* y */
  10610. + {0x00,0x00,0x7E,0x0C,0x18,0x30,0x7E,0x00}, /* z */
  10611. + {0x0C,0x18,0x18,0x70,0x18,0x18,0x0C,0x00}, /* { */
  10612. + {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, /* | */
  10613. + {0x30,0x18,0x18,0x0E,0x18,0x18,0x30,0x00}, /* } */
  10614. + {0x31,0x6B,0x46,0x00,0x00,0x00,0x00,0x00}, /* ~ */
  10615. + {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}  /*  */
  10616. +};
  10617. +
  10618. +static unsigned long palette_4[]=
  10619. +{
  10620. +    0x1000,       /* Black */
  10621. +    0x100c,       /* Red */
  10622. +    0x10c0,       /* Green */
  10623. +    0x10cc,       /* Yellow */
  10624. +    0x1c00,       /* Blue */
  10625. +    0x1c0c,       /* Magenta */
  10626. +    0x1cc0,       /* Cyan */
  10627. +    0x1ccc,       /* White */
  10628. +    0x1000,
  10629. +    0x100f,
  10630. +    0x10f0,
  10631. +    0x10ff,
  10632. +    0x1f00,
  10633. +    0x1f0F,
  10634. +    0x1ff0,
  10635. +    0x1fff,
  10636. +    0x1000
  10637. +};
  10638. +
  10639. +static unsigned long palette_8[]=
  10640. +{
  10641. +    0x1000,
  10642. +    0x1111,
  10643. +    0x1222,
  10644. +    0x1333,
  10645. +    0x1400,
  10646. +    0x1511,
  10647. +    0x1622,
  10648. +    0x1733,
  10649. +    0x1004,
  10650. +    0x1115,
  10651. +    0x1226,
  10652. +    0x1337,
  10653. +    0x1404,
  10654. +    0x1515,
  10655. +    0x1626,
  10656. +    0x1737,
  10657. +    0x1000
  10658. +};
  10659. +
  10660. +static unsigned long *default_palette_entries = palette_4;
  10661. +
  10662. +/* -------------------------------------------------------------------------------
  10663. + * Low level char write
  10664. + * ------------------------------------------------------------------------------- */
  10665. +
  10666. +static inline void charwrite(int currcons,unsigned long ps,int ch)
  10667. +{
  10668. +  unsigned long *buffer = (unsigned long *)vc_scrbuf[currcons];
  10669. +  unsigned int index;
  10670. +  unsigned char flgs;
  10671. +
  10672. +  flgs=FLAGS;
  10673. +
  10674. +  if(currcons == fg_console)
  10675. +    ll_char_write(ps, ch, forecol, backcol, flgs);
  10676. +
  10677. +  index = (x + y * video_num_columns);
  10678. +
  10679. +  buffer[index] = (flgs<<24)|(backcol<<16)|(forecol<<8)|ch;
  10680. +}
  10681. +
  10682. +static char cursor_on=0;
  10683. +unsigned long cp;
  10684. +
  10685. +static inline void remove_cursors(int currcons)
  10686. +{
  10687. +  unsigned long flags;
  10688. +
  10689. +  save_flags(flags);
  10690. +  cli();
  10691. +  if(--cursoron==0 && currcons == fg_console)
  10692. +    put_cursor(0, cp);
  10693. +  restore_flags(flags);
  10694. +}
  10695. +
  10696. +static inline void restore_cursors(int currcons)
  10697. +{
  10698. +  unsigned long flags;
  10699. +
  10700. +  save_flags(flags);
  10701. +  cli();
  10702. +  if(++cursoron==1 && cursor_on && currcons == fg_console)
  10703. +    put_cursor(1,cp);
  10704. +  restore_flags(flags);
  10705. +}
  10706. +
  10707. +/* -----------------------------------------------------------------------------------------
  10708. + * VC stuff
  10709. + * ----------------------------------------------------------------------------------------- */
  10710. +
  10711. +int vc_cons_allocated(unsigned int i)
  10712. +{
  10713. +      return (i < MAX_NR_CONSOLES && vc_cons[i].d);
  10714. +}
  10715. +
  10716. +int vc_allocate(unsigned int i)
  10717. +{
  10718. +    if (i >= MAX_NR_CONSOLES)
  10719. +      return -ENODEV;
  10720. +    if (!vc_cons[i].d) {
  10721. +        long p, q;
  10722. +
  10723. +        /* prevent users from taking too much memory */
  10724. +        if (i >= MAX_NR_USER_CONSOLES && !suser())
  10725. +          return -EPERM;
  10726. +
  10727. +        /* due to the granularity of kmalloc, we waste some memory here */
  10728. +        /* the alloc is done in two steps, to optimize the common situation
  10729. +           of a 25x80 console (structsize=216, video_screen_size=4000) */
  10730. +        q = (long) kmalloc(video_buf_size, GFP_KERNEL);
  10731. +        if (!q)
  10732. +          return -ENOMEM;
  10733. +        p = (long) kmalloc(structsize, GFP_KERNEL);
  10734. +        if (!p) {
  10735. +        kfree_s((char *) q, video_buf_size);
  10736. +        return -ENOMEM;
  10737. +        }
  10738. +
  10739. +        memset((void *)q, 0, video_buf_size);
  10740. +
  10741. +        vc_cons[i].d = (struct vc_data *) p;
  10742. +        p += sizeof(struct vc_data);
  10743. +        vt_cons[i] = (struct vt_struct *) p;
  10744. +        vc_scrbuf[i] = (unsigned char *) q;
  10745. +        vc_cons[i].d->vc_kmalloced = 1;
  10746. +        vc_cons[i].d->vc_screenbuf_size = video_buf_size;
  10747. +        vc_init (i, video_num_lines, video_num_columns, 1);
  10748. +    }
  10749. +    return 0;
  10750. +}
  10751. +
  10752. +int vc_resize(unsigned long lines, unsigned long cols)
  10753. +{/* TODO */
  10754. +    return -ENOMEM;
  10755. +}
  10756. +
  10757. +void vc_disallocate(unsigned int currcons)
  10758. +{
  10759. +    if(vc_cons_allocated(currcons))
  10760. +    {
  10761. +      if(kmalloced)
  10762. +        kfree_s(vc_scrbuf[currcons], screenbuf_size);
  10763. +      if(currcons >= MIN_NR_CONSOLES)
  10764. +        kfree_s(vc_cons[currcons].d, structsize);
  10765. +      vc_cons[currcons].d = 0;
  10766. +    }
  10767. +}
  10768. +
  10769. +#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
  10770. +#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
  10771. +#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
  10772. +
  10773. +#define decarm        VC_REPEAT
  10774. +#define decckm        VC_CKMODE
  10775. +#define kbdapplic    VC_APPLIC
  10776. +#define lnm        VC_CRLF
  10777. +
  10778. +/*
  10779. + * this is what the terminal answers to a ESC-Z or csi0c query.
  10780. + */
  10781. +#define VT100ID "\033[?1;2c"
  10782. +#define VT102ID "\033[?6c"
  10783. +
  10784. +static unsigned char color_4[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 };
  10785. +static unsigned char color_8[] = {0x00, 0x18, 0x60, 0x78, 0x84, 0x9C, 0xE4, 0xFC,
  10786. +                                  0x00, 0x1B, 0x63, 0x7B, 0x87, 0x9F, 0xE7, 0xFF};
  10787. +static unsigned char *color_table = color_4;
  10788. +
  10789. +/*
  10790. + * gotoxy() must verify all boundaries, because the arguments
  10791. + * might also be negative. If a given position is out of
  10792. + * bounds, the cursor is placed at the nearest margin.
  10793. + */
  10794. +static void gotoxy(int currcons,int new_x,int new_y)
  10795. +{
  10796. +  int max_y;
  10797. +
  10798. +  if(new_x<0)
  10799. +    x = 0;
  10800. +  else
  10801. +  if(new_x>=video_num_columns)
  10802. +    x = video_num_columns-1;
  10803. +  else
  10804. +    x = new_x;
  10805. +
  10806. +  if(decom)
  10807. +  {
  10808. +    new_y += top;
  10809. +    max_y = bottom;
  10810. +  }
  10811. +  else
  10812. +    max_y=video_num_lines;
  10813. +
  10814. +  if(new_y < 0)
  10815. +    y = 0;
  10816. +  else
  10817. +  if(new_y >= max_y)
  10818. +    y = max_y-1;
  10819. +  else
  10820. +    y = new_y;
  10821. +
  10822. +  pos = origin + (y*video_num_columns*bytes_per_char_v+x)*bytes_per_char_h;
  10823. +  need_wrap=0;
  10824. +}
  10825. +
  10826. +static unsigned long __real_origin;
  10827. +static unsigned long __origin;        /* Offset of currently displayed screen */
  10828. +
  10829. +static void __set_origin(unsigned long offset)
  10830. +{
  10831. +  unsigned long flags;
  10832. +  clear_selection();
  10833. +  save_flags(flags); cli();
  10834. +  __origin = offset;
  10835. +
  10836. +  memc_write(0,offset>>2);
  10837. +  memc_write(1,0);
  10838. +  memc_write(2,video_addr_mask>>2);
  10839. +  restore_flags(flags);
  10840. +}
  10841. +
  10842. +/*
  10843. +void scrollback(int lines)
  10844. +{
  10845. +}
  10846. +
  10847. +void scrollfront(int lines)
  10848. +{
  10849. +}
  10850. + */
  10851. +
  10852. +static void set_origin(int currcons)
  10853. +{
  10854. +    if(currcons != fg_console || vcmode == KD_GRAPHICS)
  10855. +        return;
  10856. +    __real_origin = origin - video_mem_start;
  10857. +    if(__real_origin >= video_addr_mask)
  10858. +        __real_origin -= video_addr_mask;
  10859. +    __set_origin(__real_origin);
  10860. +}
  10861. +
  10862. +static void hide_cursor(void)
  10863. +{
  10864. +    put_cursor(0,-1);
  10865. +}
  10866. +
  10867. +static void set_cursor(int currcons)
  10868. +{
  10869. +    unsigned long flags;
  10870. +
  10871. +    if(currcons != fg_console || vcmode == KD_GRAPHICS)
  10872. +        return;
  10873. +
  10874. +    if(__real_origin != __origin)
  10875. +        __set_origin(__real_origin);
  10876. +    save_flags(flags);
  10877. +    cli();
  10878. +
  10879. +    if(deccm)
  10880. +        cp = pos + video_num_columns * bytes_per_char_h * (bytes_per_char_v - 1);
  10881. +    else
  10882. +        hide_cursor();
  10883. +    restore_flags(flags);
  10884. +}
  10885. +
  10886. +/* --------------------------------------------------------------------------------
  10887. + * Screen scrolling
  10888. + * -------------------------------------------------------------------------------- */
  10889. +
  10890. +static void scrup(int currcons,unsigned int t, unsigned int b,unsigned char l)
  10891. +{
  10892. +    unsigned char flgs;
  10893. +
  10894. +    if(b > video_num_columns || t >= b)
  10895. +        return;
  10896. +
  10897. +    if(currcons == fg_console)
  10898. +    {
  10899. +        if(t || b != video_num_lines)
  10900. +        {
  10901. +            if(l<t-b)
  10902. +                memmove((void*)(origin+t*video_size_row),
  10903. +                        (void*)(origin+(t+l)*video_size_row),
  10904. +                        (b-t-l)*video_size_row);
  10905. +            else
  10906. +            if(l>b-t)
  10907. +                l=b-t;
  10908. +
  10909. +            memfastset((void*)(origin+(b-l)*video_size_row),
  10910. +                    0x11111111*backcol,l*video_size_row);
  10911. +        }
  10912. +        else
  10913. +        {
  10914. +            memfastset((void*)(origin+l*video_size_row*video_num_lines),
  10915. +                0x11111111L*backcol,l*video_size_row);
  10916. +            pos-=origin;
  10917. +            origin+=l*video_size_row;
  10918. +            if(origin>=video_mem_term)
  10919. +                origin=origin-video_mem_term+video_mem_base;
  10920. +            pos+=origin;
  10921. +            set_origin(currcons);
  10922. +        }
  10923. +    }
  10924. +    else
  10925. +    {
  10926. +        if(!t && b == video_num_lines)
  10927. +        {
  10928. +            pos-=origin;
  10929. +            origin+=l*video_size_row;
  10930. +            if(origin>=video_mem_term)
  10931. +                origin=origin-video_mem_term+video_mem_base;
  10932. +            pos+=origin;
  10933. +        }
  10934. +        }
  10935. +    if(l < t-b)
  10936. +        memmove((void*)(vc_scrbuf[currcons]+t*video_num_columns*4),
  10937. +            (void*)(vc_scrbuf[currcons]+(t+l)*video_num_columns*4),
  10938. +            (b-t-l)*video_num_columns*4);
  10939. +    else
  10940. +    if(l > b-t)
  10941. +        l=b-t;
  10942. +
  10943. +    flgs=FLAGS;
  10944. +
  10945. +    memfastset((void*)(vc_scrbuf[currcons]+(b-l)*video_num_columns*4),
  10946. +        (flgs << 24)|(backcol << 16)|(forecol << 8)|32,
  10947. +        l*video_num_columns*4);
  10948. +}
  10949. +
  10950. +static void scrdown(int currcons,unsigned int t,unsigned int b,unsigned char l)
  10951. +{
  10952. +    unsigned char flgs;
  10953. +
  10954. +    if(b>video_num_columns || t >= b)
  10955. +        return;
  10956. +
  10957. +    if(currcons == fg_console)
  10958. +    {
  10959. +        if(t || b != video_num_lines)
  10960. +        {
  10961. +            if(l<t-b)
  10962. +                memmove((void*)(origin+(t+l)*video_size_row),
  10963. +                        (void*)(origin+t*video_size_row),
  10964. +                        (b-t-l)*video_size_row);
  10965. +            else
  10966. +            if(l>b-t)
  10967. +                l=b-t;
  10968. +
  10969. +            memfastset((void*)(origin+t*video_size_row),
  10970. +                    0x11111111*backcol,l*video_size_row);
  10971. +        }
  10972. +        else
  10973. +        {
  10974. +            pos-=origin;
  10975. +            origin-=l*video_size_row;
  10976. +            if(origin<video_mem_base)
  10977. +                origin=origin-video_mem_base+video_mem_term;
  10978. +            pos+=origin;
  10979. +            memfastset((void*)origin,0x11111111L*backcol,l*video_size_row);
  10980. +            set_origin(currcons);
  10981. +        }
  10982. +    }
  10983. +    else
  10984. +    {
  10985. +        if(!t && b == video_num_lines)
  10986. +        {
  10987. +            pos-=origin;
  10988. +            origin-=l*video_size_row;
  10989. +            if(origin<video_mem_base)
  10990. +                origin=origin-video_mem_base+video_mem_term;
  10991. +            pos+=origin;
  10992. +        }
  10993. +    }
  10994. +    if(l < t-b)
  10995. +        memmove((void*)(vc_scrbuf[currcons]+(t+l)*video_num_columns*4),
  10996. +            (void*)(vc_scrbuf[currcons]+t*video_num_columns*4),
  10997. +            (b-t-l)*video_num_columns*4);
  10998. +    else
  10999. +    if(l > b-t)
  11000. +        l = b-t;
  11001. +
  11002. +    flgs=FLAGS;
  11003. +    memfastset((void*)(vc_scrbuf[currcons]+t*video_num_columns*4),
  11004. +        (flgs << 24)|(backcol << 16)|(forecol << 8)|32,
  11005. +        l*video_num_columns*4);
  11006. +}
  11007. +
  11008. +static void lf(int currcons)
  11009. +{
  11010. +    if (y + 1 < bottom) {
  11011. +        y++;
  11012. +        pos += video_size_row;
  11013. +        return;
  11014. +    }
  11015. +    scrup(currcons,top,bottom,1);
  11016. +    need_wrap=0;
  11017. +}
  11018. +
  11019. +static void ri(int currcons)
  11020. +{
  11021. +    if (y > top) {
  11022. +        y--;
  11023. +        pos -= video_size_row;
  11024. +        return;
  11025. +    }
  11026. +    scrdown(currcons,top,bottom,1);
  11027. +    need_wrap=0;
  11028. +}
  11029. +
  11030. +static inline void cr(int currcons)
  11031. +{
  11032. +    pos -= x*bytes_per_char_h;
  11033. +    need_wrap = x = 0;
  11034. +}
  11035. +
  11036. +static inline void bs(int currcons)
  11037. +{
  11038. +    if (x) {
  11039. +        if (!need_wrap) {
  11040. +            pos -= bytes_per_char_h;
  11041. +            x--;
  11042. +        }
  11043. +        need_wrap = 0;
  11044. +    }
  11045. +}
  11046. +
  11047. +static inline void del(int currcons)
  11048. +{
  11049. +  /* ignored */
  11050. +}
  11051. +
  11052. +static void csi_J(int currcons, int vpar)
  11053. +{
  11054. +    unsigned char countx,county;
  11055. +    unsigned char startx,starty;
  11056. +
  11057. +    switch(vpar) {
  11058. +        case 0: /* erase from cursor to bottom of screen */
  11059. +            startx=x;
  11060. +            starty=y;
  11061. +            countx=video_num_columns-x;
  11062. +            county=video_num_lines-y-1;
  11063. +            break;
  11064. +        case 1: /* erase from top of screen to cursor */
  11065. +            startx=0;
  11066. +            starty=0;
  11067. +            countx=x;
  11068. +            county=y;
  11069. +            break;
  11070. +        case 2: /* erase entire screen */
  11071. +            startx=0;
  11072. +            starty=0;
  11073. +            countx=video_num_columns;
  11074. +            county=video_num_lines-1;
  11075. +            origin=video_mem_base;
  11076. +            set_origin(currcons);
  11077. +            gotoxy(currcons,x,y);
  11078. +            break;
  11079. +        default:
  11080. +            return;
  11081. +    }
  11082. +    ll_erase(currcons,startx,starty,countx,county);
  11083. +    need_wrap = 0;
  11084. +}
  11085. +
  11086. +static void csi_K(int currcons, int vpar)
  11087. +{
  11088. +    unsigned char countx;
  11089. +    unsigned char startx;
  11090. +
  11091. +    switch(vpar) {
  11092. +        case 0: /* erase from cursor to end of line */
  11093. +            startx = x;
  11094. +            countx = video_num_columns - x;
  11095. +            break;
  11096. +        case 1: /* erase from beginning of line to cursor */
  11097. +            startx = 0;
  11098. +            countx = x;
  11099. +            break;
  11100. +        case 2: /* erase entire line */
  11101. +            startx=0;
  11102. +            countx=video_num_columns;
  11103. +            break;
  11104. +        default:
  11105. +            return;
  11106. +    }
  11107. +    ll_erase(currcons,startx,y,countx,0);
  11108. +    need_wrap = 0;
  11109. +}
  11110. +
  11111. +static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
  11112. +{                      /* not vt100? */
  11113. +    unsigned char countx,county;
  11114. +    unsigned char startx,starty;
  11115. +
  11116. +    if (!vpar)
  11117. +        vpar++;
  11118. +
  11119. +    startx = x;
  11120. +    starty = y;
  11121. +    countx = 0;
  11122. +    county = 0;
  11123. +#if 0 /* TODO */
  11124. +    ll_erase(currcons,startx,starty,countx,county);
  11125. +#endif
  11126. +    need_wrap = 0;
  11127. +}
  11128. +
  11129. +
  11130. +/*
  11131. +static void update_addr(int currcons)
  11132. +{
  11133. +
  11134. +}
  11135. + */
  11136. +static void default_attr(int currcons)
  11137. +{
  11138. +    underline = 0;
  11139. +    reverse = 0;
  11140. +    blink = 0;
  11141. +    intensity = 0;
  11142. +
  11143. +    forecol = def_forecol;
  11144. +    backcol = def_backcol;
  11145. +}
  11146. +
  11147. +static void csi_m(int currcons)
  11148. +{
  11149. +  int i;
  11150. +
  11151. +  for(i=0;i<=npar;i++)
  11152. +  {
  11153. +    switch(par[i])
  11154. +    {
  11155. +      case 0:    default_attr(currcons); break;
  11156. +      case 1:    intensity|=BOLD;    break;    /* Bold */
  11157. +      case 2:    intensity&=~BOLD;    break;    /* Feint */
  11158. +      case 3:    intensity|=ITALIC;    break;    /* Italic */
  11159. +      case 4:    underline = 1;        break;    /* Underline */
  11160. +      case 5:
  11161. +      case 6:    blink = 1;        break;    /* Flash */
  11162. +      case 7:    reverse = 1;        break;    /* Inverse chars */
  11163. +
  11164. +            case 10: /* ANSI X3.64-1979 (SCO-ish?)
  11165. +                  * Select primary font, don't display
  11166. +                  * control chars if defined, don't set
  11167. +                  * bit 8 on output.
  11168. +                  */
  11169. +                translate = set_translate(charset == 0
  11170. +                        ? G0_charset
  11171. +                        : G1_charset);
  11172. +                disp_ctrl = 0;
  11173. +                toggle_meta = 0;
  11174. +                break;
  11175. +            case 11: /* ANSI X3.64-1979 (SCO-ish?)
  11176. +                  * Select first alternate font, let's
  11177. +                  * chars < 32 be displayed as ROM chars.
  11178. +                  */
  11179. +                translate = set_translate(IBMPC_MAP);
  11180. +                disp_ctrl = 1;
  11181. +                toggle_meta = 0;
  11182. +                break;
  11183. +            case 12: /* ANSI X3.64-1979 (SCO-ish?)
  11184. +                  * Select second alternate font, toggle
  11185. +                  * high bit before displaying as ROM char.
  11186. +                  */
  11187. +                translate = set_translate(IBMPC_MAP);
  11188. +                disp_ctrl = 1;
  11189. +                toggle_meta = 1;
  11190. +                break;
  11191. +
  11192. +      case 21:
  11193. +      case 22:  intensity = 0;    break;
  11194. +      case 24:  underline = 0;    break;
  11195. +      case 25:  blink = 0;    break;
  11196. +      case 27:    reverse = 0;    break;
  11197. +      case 30:
  11198. +      case 31:
  11199. +      case 32:
  11200. +      case 33:
  11201. +      case 34:
  11202. +      case 35:
  11203. +      case 36:
  11204. +      case 37:  forecol=color_table[par[i]-30];        break;    /* Foreground colour */
  11205. +      case 38:  forecol=def_forecol; underline = 1;    break;
  11206. +      case 39:  forecol=def_forecol; underline = 0;    break;    /* Default foreground colour */
  11207. +      case 40:
  11208. +      case 41:
  11209. +      case 42:
  11210. +      case 43:
  11211. +      case 44:
  11212. +      case 45:
  11213. +      case 46:
  11214. +      case 47:  backcol=color_table[par[i]-40];    break;    /* Background colour */
  11215. +      case 49:  backcol=def_backcol;        break;    /* Default background colour */
  11216. +    }
  11217. +  }
  11218. +}
  11219. +
  11220. +static void respond_string(char *p,struct tty_struct *tty)
  11221. +{
  11222. +    while(*p)
  11223. +        tty_insert_flip_char(tty, *p++, 0);
  11224. +    tty_schedule_flip(tty);
  11225. +}
  11226. +
  11227. +static void cursor_report(int currcons,struct tty_struct *tty)
  11228. +{
  11229. +    char buf[40];
  11230. +
  11231. +    sprintf(buf, "\033[%ld;%ldR",y + (decom ? top+1 : 1),
  11232. +                     x + 1);
  11233. +    respond_string(buf, tty);
  11234. +}
  11235. +
  11236. +static void status_report(struct tty_struct *tty)
  11237. +{
  11238. +    respond_string("\033[0n",tty);
  11239. +}
  11240. +
  11241. +static void respond_ID(struct tty_struct *tty)
  11242. +{
  11243. +    respond_string(VT102ID,tty);
  11244. +}
  11245. +
  11246. +static void mouse_report(int currcons, struct tty_struct *tty, int butt, int mrx, int mry)
  11247. +{
  11248. +    char buf[8];
  11249. +
  11250. +    sprintf(buf,"\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
  11251. +        (char)('!'+mry));
  11252. +    respond_string(buf,tty);
  11253. +}
  11254. +
  11255. +/* invoked by ioctl(TIOCLINUX) */
  11256. +int mouse_reporting(void)
  11257. +{
  11258. +    int currcons = fg_console;
  11259. +
  11260. +    return report_mouse;
  11261. +}
  11262. +
  11263. +static void invert_screen(void)
  11264. +{
  11265. +  /* Todo */
  11266. +}
  11267. +
  11268. +unsigned long *screen_pos(int currcons, int screen_offset)
  11269. +{
  11270. +    return (unsigned long *)(vc_scrbuf[currcons] + screen_offset * 4);
  11271. +}
  11272. +
  11273. +void getconsxy(int currcons, char *p)
  11274. +{
  11275. +    p[0] = x;
  11276. +    p[1] = y;
  11277. +}
  11278. +
  11279. +void putconsxy(int currcons, char *p)
  11280. +{
  11281. +    gotoxy(currcons, p[0], p[1]);
  11282. +    set_cursor(currcons);
  11283. +}
  11284. +
  11285. +static void set_mode(int currcons, int on_off)
  11286. +{
  11287. +    int i;
  11288. +
  11289. +    for(i=0;i<=npar;i++)
  11290. +        if(ques) switch(par[i]) {    /* DEC private modes set/reset */
  11291. +            case 1:            /* Cursor keys send ^[Ox/^[[x */
  11292. +                if (on_off)
  11293. +                    set_kbd(decckm);
  11294. +                else
  11295. +                    clr_kbd(decckm);
  11296. +                break;
  11297. +            case 3:         /* 80/132 mode switch unimplemented */
  11298. +                deccolm = on_off;
  11299. +#if 0
  11300. +                csi_J(currcons,2);
  11301. +                gotoxy(currcons,0,0);
  11302. +#endif
  11303. +                break;
  11304. +            case 5:            /* Inverted screen on/off */
  11305. +                if (decscnm != on_off) {
  11306. +                    decscnm = on_off;
  11307. +                    invert_screen();
  11308. +/*                     update_attr(); */
  11309. +                }
  11310. +                break;
  11311. +            case 6:            /* Origin relative/absolute */
  11312. +                decom = on_off;
  11313. +                gotoxy(currcons,0,0);
  11314. +                break;
  11315. +            case 7:            /* Autowrap on/off */
  11316. +                decawm = on_off;
  11317. +                break;
  11318. +            case 8:            /* Autorepeat on/off */
  11319. +                if (on_off)
  11320. +                    set_kbd(decarm);
  11321. +                else
  11322. +                    clr_kbd(decarm);
  11323. +                break;
  11324. +            case 9:
  11325. +                report_mouse = on_off ? 1 : 0;
  11326. +                break;
  11327. +            case 25:        /* Cursor on/off */
  11328. +                deccm = on_off;
  11329. +                set_cursor(currcons);
  11330. +                break;
  11331. +            case 1000:
  11332. +                report_mouse = on_off ? 2 : 0;
  11333. +                break;
  11334. +        } else switch(par[i]) {        /* ANSI modes set/reset */
  11335. +            case 3:            /* Monitor (display ctrls) */
  11336. +                disp_ctrl = on_off;
  11337. +                break;
  11338. +            case 4:            /* Insert mode on/off */
  11339. +                decim = on_off;
  11340. +                break;
  11341. +            case 20:        /* Lf, Enter = CrLf/Lf */
  11342. +                if (on_off)
  11343. +                    set_kbd(lnm);
  11344. +                else
  11345. +                    clr_kbd(lnm);
  11346. +                break;
  11347. +        }
  11348. +}
  11349. +
  11350. +static void setterm_command(int currcons)
  11351. +{
  11352. +    switch(par[0]) {
  11353. +        case 1: /* Set colour for underline mode (implemented as an underline) */
  11354. +            break;
  11355. +        case 2: /* set colour for half intensity mode (implemented as half) */
  11356. +            break;
  11357. +        case 8:
  11358. +            def_forecol = forecol;
  11359. +            def_backcol = backcol;
  11360. +            break;
  11361. +        case 9:
  11362. +            blankinterval=((par[1]<60)?par[1]:60)*60*HZ;
  11363. +            break;
  11364. +    }
  11365. +}
  11366. +
  11367. +static void insert_char(int currcons)
  11368. +{
  11369. +    register unsigned char *c,*cc;
  11370. +    register unsigned char row;
  11371. +    register int col;
  11372. +
  11373. +    c = (unsigned char*)pos;
  11374. +    cc = (unsigned char*)pos + bytes_per_char_h;
  11375. +
  11376. +    for (row = 0; row < bytes_per_char_v; row++) {
  11377. +        for(col = (video_num_columns - x - 1) * bytes_per_char_h - 1; col >= 0; col--)
  11378. +            cc[col] = c[col];
  11379. +        *c = 0x11*backcol;
  11380. +        c += video_num_columns * bytes_per_char_h;
  11381. +        cc += video_num_columns * bytes_per_char_h;
  11382. +    }
  11383. +}
  11384. +
  11385. +static void insert_line(int currcons,int n)
  11386. +{
  11387. +    scrdown(currcons,y,bottom,n);
  11388. +    need_wrap = 0;
  11389. +}
  11390. +
  11391. +static void delete_char(int currcons)
  11392. +{
  11393. +    register unsigned char *c, *cc;
  11394. +    register unsigned char row;
  11395. +    register unsigned int  col;
  11396. +
  11397. +    c = (unsigned char*)pos;
  11398. +    cc = (unsigned char*)pos + bytes_per_char_h;
  11399. +
  11400. +    for (row=0; row < bytes_per_char_v; row++) {
  11401. +        for (col=0; col < bytes_per_char_h * (video_num_columns - x - 1); col++) {
  11402. +            c[col] = cc[col];
  11403. +            cc[col] = 0x11*backcol;
  11404. +        }
  11405. +        c += video_num_columns * bytes_per_char_h;
  11406. +        cc += video_num_columns * bytes_per_char_h;
  11407. +    }
  11408. +}
  11409. +
  11410. +static void delete_line(int currcons,int n)
  11411. +{
  11412. +    scrup(currcons,y,bottom,n);
  11413. +    need_wrap = 0;
  11414. +}
  11415. +
  11416. +static void csi_at(int currcons,int nr)
  11417. +{
  11418. +    if (nr > video_num_columns - x)
  11419. +        nr = video_num_columns-x;
  11420. +    else if (!nr)
  11421. +        nr = 1;
  11422. +    while(nr--)
  11423. +        insert_char(currcons);
  11424. +}
  11425. +
  11426. +static void csi_L(int currcons,int nr)
  11427. +{
  11428. +    if (nr > video_num_lines - y)
  11429. +        nr = video_num_lines - y;
  11430. +    else if (!nr)
  11431. +        nr = 1;
  11432. +    insert_line(currcons,nr);
  11433. +}
  11434. +
  11435. +static void csi_P(int currcons,int nr)
  11436. +{
  11437. +    if (nr > video_num_columns)
  11438. +        nr = video_num_columns;
  11439. +    else if (!nr)
  11440. +        nr = 1;
  11441. +    while(nr--)
  11442. +        delete_char(currcons);
  11443. +}
  11444. +
  11445. +static void csi_M(int currcons,int nr)
  11446. +{
  11447. +    if (nr > video_num_lines)
  11448. +        nr = video_num_lines;
  11449. +    else if (!nr)
  11450. +        nr = 1;
  11451. +    delete_line(currcons,nr);
  11452. +}
  11453. +
  11454. +static void save_cur(int currcons)
  11455. +{
  11456. +    saved_x        = x;
  11457. +    saved_y        = y;
  11458. +    saved_G0    = G0_charset;
  11459. +    saved_G1    = G1_charset;
  11460. +    s_intensity    = intensity;
  11461. +    s_blink        = blink;
  11462. +    s_underline    = underline;
  11463. +    s_reverse    = reverse;
  11464. +    s_forecol    = forecol;
  11465. +    s_backcol    = backcol;
  11466. +}
  11467. +
  11468. +static void restore_cur(int currcons)
  11469. +{
  11470. +    gotoxy(currcons,saved_x,saved_y);
  11471. +    intensity    = s_intensity;
  11472. +    underline    = s_underline;
  11473. +    blink        = s_blink;
  11474. +    reverse        = s_reverse;
  11475. +    forecol        = s_forecol;
  11476. +    backcol        = s_backcol;
  11477. +    G0_charset    = saved_G0;
  11478. +    G1_charset    = saved_G1;
  11479. +    need_wrap    = 0;
  11480. +}
  11481. +
  11482. +enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
  11483. +    EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
  11484. +    ESpalette };
  11485. +
  11486. +static void reset_terminal(int currcons,int do_clear)
  11487. +{
  11488. +    top        = 0;
  11489. +    bottom        = video_num_lines;
  11490. +    vc_state    = ESnormal;
  11491. +    ques        = 0;
  11492. +    translate    = set_translate(LAT1_MAP);
  11493. +    G0_charset    = LAT1_MAP;
  11494. +    G1_charset    = GRAF_MAP;
  11495. +    charset        = 0;
  11496. +    need_wrap    = 0;
  11497. +    report_mouse    = 0;
  11498. +    utf        = 0; /* ? *** */
  11499. +    utf_count    = 0;
  11500. +
  11501. +    paletteentries    = 0;
  11502. +    disp_ctrl    = 0;
  11503. +    toggle_meta    = 0;
  11504. +
  11505. +    def_forecol    = color_table[7];
  11506. +    def_backcol    = color_table[0];
  11507. +    forecol    = color_table[7];
  11508. +    backcol    = color_table[0];
  11509. +
  11510. +    decscnm        = 0;
  11511. +    decom        = 0;
  11512. +    decawm        = 1;
  11513. +    deccm        = 1;
  11514. +    decim        = 0;
  11515. +
  11516. +    set_kbd(decarm);
  11517. +    clr_kbd(decckm);
  11518. +    clr_kbd(kbdapplic);
  11519. +    clr_kbd(lnm);
  11520. +    kbd_table[currcons].lockstate = 0;
  11521. +    kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
  11522. +    kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
  11523. +    set_leds();
  11524. +
  11525. +    default_attr(currcons);
  11526. +
  11527. +    tab_stop[0]    = 0x01010100;
  11528. +    tab_stop[1]    =
  11529. +    tab_stop[2]    =
  11530. +    tab_stop[3]    =
  11531. +    tab_stop[4]    = 0x01010101;
  11532. +
  11533. +    gotoxy(currcons,0,0);
  11534. +    save_cur(currcons);
  11535. +    if (do_clear)
  11536. +        csi_J(currcons,2);
  11537. +}
  11538. +
  11539. +/*
  11540. + * Turn the Scroll-Lock LED on when the tty is stopped
  11541. + */
  11542. +static void con_stop(struct tty_struct *tty)
  11543. +{
  11544. +    int console_num;
  11545. +    if (!tty)
  11546. +        return;
  11547. +    console_num = MINOR(tty->device) - (tty->driver.minor_start);
  11548. +    if (!vc_cons_allocated(console_num))
  11549. +        return;
  11550. +    set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
  11551. +    set_leds();
  11552. +}
  11553. +
  11554. +/*
  11555. + * Turn the Scroll-Lock LED off when the console is started
  11556. + */
  11557. +static void con_start(struct tty_struct *tty)
  11558. +{
  11559. +    int console_num;
  11560. +    if(!tty)
  11561. +        return;
  11562. +    console_num = MINOR(tty->device) - (tty->driver.minor_start);
  11563. +    if (!vc_cons_allocated(console_num))
  11564. +        return;
  11565. +    clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
  11566. +    set_leds();
  11567. +}
  11568. +
  11569. +static int con_write(struct tty_struct * tty, int from_user,
  11570. +             const unsigned char *buf, int count)
  11571. +{
  11572. +    int c, tc, ok, n = 0, r = 0;
  11573. +    unsigned int currcons;
  11574. +    struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
  11575. +    unsigned char buffer[32], *p = buffer;
  11576. +
  11577. +    currcons = vt->vc_num;
  11578. +    if (!vc_cons_allocated(currcons)) {
  11579. +        /* could this happen? */
  11580. +        static int error = 0;
  11581. +        if(!error) {
  11582. +        error = 1;
  11583. +        printk("con_write: tty %d not allocated\n", currcons+1);
  11584. +        }
  11585. +        return 0;
  11586. +    }
  11587. +
  11588. +    remove_cursors(currcons);
  11589. +    if(currcons == sel_cons)
  11590. +        clear_selection();
  11591. +
  11592. +    disable_bh(KEYBOARD_BH);
  11593. +    while(!tty->stopped && count) {
  11594. +        if(from_user && r == 0)
  11595. +        {
  11596. +            r = count;
  11597. +            if(r > 32) r = 32;
  11598. +            memcpy_fromfs(buffer, buf, r);
  11599. +            p = buffer;
  11600. +            }
  11601. +        c = from_user ? *p++ : *buf;
  11602. +        buf++; n++; count--;
  11603. +        if(from_user) r--;
  11604. +
  11605. +        if (utf) {
  11606. +            /* Combine UTF-8 into Unicode */
  11607. +            /* Incomplete characters silently ignored */
  11608. +            if(c > 0x7f) {
  11609. +            if (utf_count > 0 && (c & 0xc0) == 0x80) {
  11610. +                utf_char = (utf_char << 6) | (c & 0x3f);
  11611. +                utf_count--;
  11612. +                if (utf_count == 0)
  11613. +                    tc = c = utf_char;
  11614. +                else continue;
  11615. +            } else {
  11616. +                if ((c & 0xe0) == 0xc0) {
  11617. +                    utf_count = 1;
  11618. +                    utf_char = (c & 0x1f);
  11619. +                } else if ((c & 0xf0) == 0xe0) {
  11620. +                    utf_count = 2;
  11621. +                    utf_char = (c & 0x0f);
  11622. +                } else if ((c & 0xf8) == 0xf0) {
  11623. +                    utf_count = 3;
  11624. +                    utf_char = (c & 0x07);
  11625. +                } else if ((c & 0xfc) == 0xf8) {
  11626. +                    utf_count = 4;
  11627. +                    utf_char = (c & 0x03);
  11628. +                } else if ((c & 0xfe) == 0xfc) {
  11629. +                    utf_count = 5;
  11630. +                    utf_char = (c & 0x01);
  11631. +                } else
  11632. +                    utf_count = 0;
  11633. +                continue;
  11634. +            }
  11635. +            } else {
  11636. +              tc = c;
  11637. +              utf_count = 0;
  11638. +            }
  11639. +        } else {    /* no utf */
  11640. +          tc = translate[toggle_meta ? (c | 0x80) : c];
  11641. +        }
  11642. +        
  11643. +        /* If the origional code was < 32 we only allow a
  11644. +         * glyph to be displayed if the code is not normally
  11645. +         * used (such as for cursor movement) or if the
  11646. +         * disp_ctrl mode has been explicitly enabled.
  11647. +         * Note: ESC is *never* allowed to be displayed as
  11648. +         * that would disable all escape sequences!
  11649. +         * To display font position 0x1B, go into UTF mode
  11650. +         * and display character U+F01B, or change the mapping.
  11651. +         */
  11652. +        ok = (tc && (c >= 32 || (!utf && !(((disp_ctrl ? CTRL_ALWAYS
  11653. +                        : CTRL_ACTION) >> c) & 1))));
  11654. +
  11655. +        if (vc_state == ESnormal && ok) {
  11656. +            /* Now try to find out how to display it */
  11657. +            tc = conv_uni_to_pc(tc);
  11658. +            if (tc == -4) {
  11659. +              /* If we got -4 (not found) then see if we have
  11660. +                 defined a replacement character (U+FFFD) */
  11661. +                tc = conv_uni_to_pc(0xfffd);
  11662. +            } else if (tc == -3) {
  11663. +                /* Bad hash table -- hope for the best */
  11664. +                tc = c;
  11665. +            }
  11666. +            if (tc & ~console_charmask)
  11667. +                continue; /* Conversion failed */
  11668. +
  11669. +            if (need_wrap) {
  11670. +                cr(currcons);
  11671. +                lf(currcons);
  11672. +                  }
  11673. +            if(decim)
  11674. +                insert_char(currcons);
  11675. +            charwrite(currcons, pos, tc);
  11676. +            if (x == video_num_columns - 1)
  11677. +                need_wrap = decawm;
  11678. +            else {
  11679. +                x++;
  11680. +                pos+=bytes_per_char_h;
  11681. +            }
  11682. +            continue;
  11683. +        }
  11684. +
  11685. +        /*
  11686. +         *  Control characters can be used in the _middle_
  11687. +         *  of an escape sequence.
  11688. +         */
  11689. +        switch(c) {
  11690. +            case 7:
  11691. +                kd_mksound(0x637, HZ/8);
  11692. +                continue;
  11693. +            case 8:
  11694. +                bs(currcons);
  11695. +                continue;
  11696. +            case 9:
  11697. +                pos -= x * bytes_per_char_h;
  11698. +                while (x < video_num_columns - 1) {
  11699. +                    x++;
  11700. +                    if (tab_stop[x >> 5] & (1 << (x & 31)))
  11701. +                        break;
  11702. +                }
  11703. +                pos += x * bytes_per_char_h;
  11704. +                continue;
  11705. +            case 10: case 11: case 12:
  11706. +                lf(currcons);
  11707. +                if(!is_kbd(lnm))
  11708. +                    continue;
  11709. +            case 13:
  11710. +                cr(currcons);
  11711. +                continue;
  11712. +            case 14:
  11713. +                charset = 1;
  11714. +                translate = set_translate(G1_charset);
  11715. +                disp_ctrl = 1;
  11716. +                continue;
  11717. +            case 15:
  11718. +                charset = 0;
  11719. +                translate = set_translate(G0_charset);
  11720. +                disp_ctrl = 0;
  11721. +                continue;
  11722. +            case 24: case 26:
  11723. +                vc_state = ESnormal;
  11724. +                continue;
  11725. +            case 27:
  11726. +                vc_state = ESesc;
  11727. +                continue;
  11728. +            case 127:
  11729. +                del(currcons);
  11730. +                continue;
  11731. +            case 128+27:
  11732. +                vc_state = ESsquare;
  11733. +                continue;
  11734. +            }
  11735. +        switch(vc_state) {
  11736. +            case ESesc:
  11737. +                vc_state = ESnormal;
  11738. +                switch (c) {
  11739. +                    case '[':
  11740. +                        vc_state = ESsquare;
  11741. +                        continue;
  11742. +                    case '%':
  11743. +                        vc_state = ESpercent;
  11744. +                        continue;
  11745. +                    case 'E':
  11746. +                        cr(currcons);
  11747. +                        lf(currcons);
  11748. +                        continue;
  11749. +                    case 'M':
  11750. +                        ri(currcons);
  11751. +                        continue;
  11752. +                    case 'D':
  11753. +                        lf(currcons);
  11754. +                        continue;
  11755. +                    case 'H':
  11756. +                        tab_stop[x >> 5] |= (1 << (x & 31));
  11757. +                        continue;
  11758. +                    case 'Z':
  11759. +                        respond_ID(tty);
  11760. +                        continue;
  11761. +                    case '7':
  11762. +                        save_cur(currcons);
  11763. +                        continue;
  11764. +                    case '8':
  11765. +                        restore_cur(currcons);
  11766. +                        continue;
  11767. +                    case '(':
  11768. +                        vc_state = ESsetG0;
  11769. +                        continue;
  11770. +                    case ')':
  11771. +                        vc_state = ESsetG1;
  11772. +                        continue;
  11773. +                    case '#':
  11774. +                        vc_state = EShash;
  11775. +                        continue;
  11776. +                    case 'c':
  11777. +                        reset_terminal(currcons,1);
  11778. +                        continue;
  11779. +                    case '>': /* Numeric keypad */
  11780. +                        clr_kbd(kbdapplic);
  11781. +                        continue;
  11782. +                    case '=': /* Appl. keypad */
  11783. +                        set_kbd(kbdapplic);
  11784. +                        continue;
  11785. +                }
  11786. +                continue;
  11787. +            case ESnonstd:
  11788. +                if (c=='P') {   /* palette escape sequence */
  11789. +                    for (npar = 0; npar<NPAR; npar++)
  11790. +                        par[npar] = 0;
  11791. +                    npar = 0 ;
  11792. +                    vc_state = ESpalette;
  11793. +                    continue;
  11794. +                } else if (c=='R') { /* reset palette */
  11795. +                    reset_palette (currcons);
  11796. +                    vc_state = ESnormal;
  11797. +                } else
  11798. +                    vc_state = ESnormal;
  11799. +                continue;
  11800. +            case ESpalette:
  11801. +                if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
  11802. +                    par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
  11803. +                    if(npar==7) {
  11804. +#if 0
  11805. +                        int i = par[0]*3, j = 1;
  11806. +                        palette[i] = 16*par[j++];
  11807. +                        palette[i++] += par[j++];
  11808. +                        palette[i] = 16*par[j++];
  11809. +                        palette[i++] += par[j++];
  11810. +                        palette[i] = 16*par[j++];
  11811. +                        palette[i++] += par[j];
  11812. +#endif
  11813. +                        set_palette() ;
  11814. +                        vc_state = ESnormal;
  11815. +                    }
  11816. +                } else
  11817. +                    vc_state = ESnormal;
  11818. +                continue;
  11819. +            case ESsquare:
  11820. +                for(npar = 0; npar < NPAR ; npar++)
  11821. +                    par[npar] = 0;
  11822. +                npar = 0;
  11823. +                vc_state = ESgetpars;
  11824. +                if (c == '[') { /* Function key */
  11825. +                    vc_state=ESfunckey;
  11826. +                    continue;
  11827. +                }
  11828. +                ques = (c == '?');
  11829. +                if (ques)
  11830. +                    continue;
  11831. +            case ESgetpars:
  11832. +                if(c==';' && npar<NPAR-1) {
  11833. +                    npar++;
  11834. +                    continue;
  11835. +                } else if (c>='0' && c<='9') {
  11836. +                    par[npar] = par[npar] * 10 + c - '0';
  11837. +                    continue;
  11838. +                } else vc_state=ESgotpars;
  11839. +            case ESgotpars:
  11840. +                vc_state=ESnormal;
  11841. +                switch (c) {
  11842. +                    case 'h':
  11843. +                        set_mode(currcons,1);
  11844. +                        continue;
  11845. +                    case 'l':
  11846. +                        set_mode(currcons,0);
  11847. +                        continue;
  11848. +                    case 'n':
  11849. +                        if (!ques) {
  11850. +                            if (par[0] == 5)
  11851. +                                status_report(tty);
  11852. +                            else if (par[0] == 6)
  11853. +                                cursor_report(currcons,tty);
  11854. +                        }
  11855. +                        continue;
  11856. +                }
  11857. +                if (ques) {
  11858. +                    ques = 0;
  11859. +                    continue;
  11860. +                }
  11861. +                switch(c) {
  11862. +                    case 'G': case '`':
  11863. +                        if (par[0]) par[0]--;
  11864. +                        gotoxy(currcons,par[0],y);
  11865. +                        continue;
  11866. +                    case 'A':
  11867. +                        if (!par[0]) par[0]++;
  11868. +                        gotoxy(currcons,x,y-par[0]);
  11869. +                        continue;
  11870. +                    case 'B': case 'e':
  11871. +                        if (!par[0]) par[0]++;
  11872. +                        gotoxy(currcons,x,y+par[0]);
  11873. +                        continue;
  11874. +                    case 'C': case 'a':
  11875. +                        if (!par[0]) par[0]++;
  11876. +                        gotoxy(currcons,x+par[0],y);
  11877. +                        continue;
  11878. +                    case 'D':
  11879. +                        if (!par[0]) par[0]++;
  11880. +                        gotoxy(currcons,x-par[0],y);
  11881. +                        continue;
  11882. +                    case 'E':
  11883. +                        if (!par[0]) par[0]++;
  11884. +                        gotoxy(currcons,0,y+par[0]);
  11885. +                        continue;
  11886. +                    case 'F':
  11887. +                        if (!par[0]) par[0]++;
  11888. +                        gotoxy(currcons,0,y-par[0]);
  11889. +                        continue;
  11890. +                    case 'd':
  11891. +                        if (par[0]) par[0]--;
  11892. +                        gotoxy(currcons,x,par[0]);
  11893. +                        continue;
  11894. +                    case 'H': case 'f':
  11895. +                        if (par[0]) par[0]--;
  11896. +                        if (par[1]) par[1]--;
  11897. +                        gotoxy(currcons,par[1],par[0]);
  11898. +                        continue;
  11899. +                    case 'J':
  11900. +                        csi_J(currcons,par[0]);
  11901. +                        continue;
  11902. +                    case 'K':
  11903. +                        csi_K(currcons,par[0]);
  11904. +                        continue;
  11905. +                    case 'L':
  11906. +                        csi_L(currcons,par[0]);
  11907. +                        continue;
  11908. +                    case 'M':
  11909. +                        csi_M(currcons,par[0]);
  11910. +                        continue;
  11911. +                    case 'P':
  11912. +                        csi_P(currcons,par[0]);
  11913. +                        continue;
  11914. +                    case 'c':
  11915. +                        if (!par[0])
  11916. +                            respond_ID(tty);
  11917. +                        continue;
  11918. +                    case 'g':
  11919. +                        if (!par[0])
  11920. +                            tab_stop[x >> 5] &= ~(1 << (x & 31));
  11921. +                        else if (par[0] == 3) {
  11922. +                            tab_stop[0] =
  11923. +                            tab_stop[1] =
  11924. +                            tab_stop[2] =
  11925. +                            tab_stop[3] =
  11926. +                            tab_stop[4] = 0;
  11927. +                        }
  11928. +                        continue;
  11929. +                    case 'm':
  11930. +                        csi_m(currcons);
  11931. +                        continue;
  11932. +                    case 'q': /* DECLL - but only 3 leds */
  11933. +                        /* map 0,1,2,3 to 0,1,2,4 */
  11934. +                        if (par[0] < 4)
  11935. +                          setledstate(kbd_table + currcons,
  11936. +                                    (par[0] < 3 ? par[0] : 4));
  11937. +                        continue;
  11938. +                    case 'r':
  11939. +                        if (!par[0])
  11940. +                            par[0]++;
  11941. +                        if (!par[1])
  11942. +                            par[1] = video_num_lines;
  11943. +                        if (par[0] < par[1] &&
  11944. +                            par[1] <= video_num_lines) {
  11945. +                            top=par[0]-1;
  11946. +                            bottom=par[1];
  11947. +                            gotoxy(currcons,0,0);
  11948. +                        }
  11949. +                        continue;
  11950. +                    case 's':
  11951. +                        save_cur(currcons);
  11952. +                        continue;
  11953. +                    case 'u':
  11954. +                        restore_cur(currcons);
  11955. +                        continue;
  11956. +                    case 'X':
  11957. +                        csi_X(currcons, par[0]);
  11958. +                        continue;
  11959. +                    case '@':
  11960. +                        csi_at(currcons,par[0]);
  11961. +                        continue;
  11962. +                    case ']': /* setterm functions */
  11963. +                        setterm_command(currcons);
  11964. +                        continue;
  11965. +                }
  11966. +                continue;
  11967. +            case ESpercent:
  11968. +                vc_state = ESnormal;
  11969. +                switch (c) {
  11970. +                    case '@': /* defined in ISO 2022 */
  11971. +                        utf = 0;
  11972. +                        continue;
  11973. +                    case 'G': /* prelim official escape code */
  11974. +                    case '8': /* retained for compatibility */
  11975. +                        utf = 1;
  11976. +                        continue;
  11977. +                }
  11978. +                continue;
  11979. +            case ESfunckey:
  11980. +                vc_state = ESnormal;
  11981. +                continue;
  11982. +            case EShash:
  11983. +                vc_state = ESnormal;
  11984. +                if (c == '8') {
  11985. +                    /* DEC screen alignment test. kludge :-) */
  11986. +                }
  11987. +                continue;
  11988. +            case ESsetG0:
  11989. +                if (c == '0')
  11990. +                    G0_charset = GRAF_MAP;
  11991. +                else if (c == 'B')
  11992. +                    G0_charset = LAT1_MAP;
  11993. +                else if (c == 'U')
  11994. +                    G0_charset = IBMPC_MAP;
  11995. +                else if (c == 'K')
  11996. +                    G0_charset = USER_MAP;
  11997. +                if (charset == 0)
  11998. +                    translate = set_translate(G0_charset);
  11999. +                vc_state = ESnormal;
  12000. +                continue;
  12001. +            case ESsetG1:
  12002. +                if (c == '0')
  12003. +                    G1_charset = GRAF_MAP;
  12004. +                else if (c == 'B')
  12005. +                    G1_charset = LAT1_MAP;
  12006. +                else if (c == 'U')
  12007. +                    G1_charset = IBMPC_MAP;
  12008. +                else if (c == 'K')
  12009. +                    G1_charset = USER_MAP;
  12010. +                if (charset == 1)
  12011. +                    translate = set_translate(G1_charset);
  12012. +                vc_state = ESnormal;
  12013. +                continue;
  12014. +            default:
  12015. +                vc_state = ESnormal;
  12016. +        }
  12017. +    }
  12018. +    if (vcmode != KD_GRAPHICS)
  12019. +        set_cursor(currcons);
  12020. +    enable_bh(KEYBOARD_BH);
  12021. +    restore_cursors(currcons);
  12022. +    return n;
  12023. +}
  12024. +
  12025. +static int con_write_room(struct tty_struct *tty)
  12026. +{
  12027. +    if (tty->stopped)
  12028. +        return 0;
  12029. +    return 4096;        /* No limit, really; we're not buffering */
  12030. +}
  12031. +
  12032. +static int con_chars_in_buffer(struct tty_struct *tty)
  12033. +{
  12034. +    return 0;        /* we're not buffering */
  12035. +}
  12036. +
  12037. +void poke_blanked_console(void)
  12038. +{
  12039. +    timer_active&=~(1<<BLANK_TIMER);
  12040. +    if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
  12041. +        return;
  12042. +    if (console_blanked) {
  12043. +        timer_table[BLANK_TIMER].expires = 0;
  12044. +        timer_active |= 1<<BLANK_TIMER;
  12045. +    } else if(blankinterval) {
  12046. +        timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
  12047. +        timer_active |= 1<<BLANK_TIMER;
  12048. +    }
  12049. +}
  12050. +
  12051. +static void console_print(const char *b)
  12052. +{
  12053. +    int currcons = fg_console;
  12054. +    unsigned char c;
  12055. +    static int printing = 0;
  12056. +
  12057. +  if(vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
  12058. +  {
  12059. +    prints(b);
  12060. +    return;
  12061. +  }
  12062. +
  12063. +    if (!printable || printing)
  12064. +        return;  /* console not yet initialized */
  12065. +    printing = 1;
  12066. +
  12067. +    if(!vc_cons_allocated(currcons)) {
  12068. +        /* impossible */
  12069. +          printk("console_print: tty %d not allocated ??\n",currcons+1);
  12070. +          return;
  12071. +    }
  12072. +
  12073. +    remove_cursors(currcons);
  12074. +
  12075. +    while ((c = *b++) != 0) {
  12076. +        if (c == 10 || c == 13 || need_wrap) {
  12077. +            if (c != 13)
  12078. +                lf(currcons);
  12079. +            cr(currcons);
  12080. +            if(c==10 || c==13)
  12081. +                continue;
  12082. +        }
  12083. +        charwrite(currcons,pos,c);
  12084. +        if (x == video_num_columns - 1) {
  12085. +            need_wrap=1;
  12086. +            continue;
  12087. +        }
  12088. +        x++;
  12089. +        pos += bytes_per_char_h;
  12090. +    }
  12091. +    set_cursor(currcons);
  12092. +
  12093. +    restore_cursors(currcons);
  12094. +
  12095. +    poke_blanked_console();
  12096. +    printing = 0;
  12097. +}
  12098. +
  12099. +/*
  12100. + * con_throttle and con_unthrottle are only used for
  12101. + * paste_selection(), which has to stuff in a large number of
  12102. + * characters...
  12103. + */
  12104. +static void con_throttle(struct tty_struct *tty)
  12105. +{
  12106. +}
  12107. +
  12108. +static void con_unthrottle(struct tty_struct *tty)
  12109. +{
  12110. +      struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
  12111. +
  12112. +      wake_up_interruptible(&vt->paste_wait);
  12113. +}
  12114. +
  12115. +static void vc_init(unsigned int currcons, unsigned long rows, unsigned long cols, int do_clear)
  12116. +{
  12117. +    long base = (long) vc_scrbuf[currcons];
  12118. +
  12119. +    video_num_columns = cols;
  12120. +    video_num_lines   = rows;
  12121. +    video_size_row    = video_num_columns*bytes_per_char_h*bytes_per_char_v;
  12122. +    video_screen_size = video_num_lines * video_size_row;
  12123. +    video_buf_size    = video_num_lines * video_num_columns * 4;
  12124. +    video_mem_start   = video_mem_base;
  12125. +    video_mem_end      = video_mem_term;
  12126. +
  12127. +    pos = origin      = video_mem_start;
  12128. +    scr_end          = video_mem_start + video_num_lines * video_size_row;
  12129. +    video_mem_end     = base + video_screen_size;
  12130. +    reset_vc(currcons);
  12131. +    def_forecol      = color_table[7];
  12132. +    def_backcol      = color_table[0];
  12133. +    vt_cons[currcons]->paste_wait = 0;
  12134. +    cursoron      = 0;
  12135. +
  12136. +    reset_terminal(currcons,do_clear);
  12137. +}
  12138. +
  12139. +static void con_setsize(unsigned long rows,unsigned long cols)
  12140. +{
  12141. +    video_num_lines   = rows;
  12142. +    video_num_columns = cols;
  12143. +    video_size_row    = video_num_columns*bytes_per_char_h*bytes_per_char_v;
  12144. +    video_screen_size = video_num_lines * video_size_row;
  12145. +    video_buf_size    = video_num_lines * video_num_columns * 4;
  12146. +}
  12147. +
  12148. +static int con_ioctl(struct tty_struct *tty, struct file * file,
  12149. +         unsigned int cmd, unsigned long arg)
  12150. +{
  12151. +    return vt_ioctl(tty, file, cmd, arg);
  12152. +}
  12153. +
  12154. +/*
  12155. + *  unsigned long con_init(unsigned long);
  12156. + *
  12157. + * This routine initialises console interrupts, and does nothing
  12158. + * else. If you want the screen to clear, call tty_write with
  12159. + * the apropriate escape-sequence.
  12160. + *
  12161. + */
  12162. +unsigned long con_init(unsigned long kmem_start)
  12163. +{
  12164. +    int currcons = 0, i;
  12165. +
  12166. +    memset(&console_driver, 0, sizeof(struct tty_driver));
  12167. +    console_driver.magic = TTY_DRIVER_MAGIC;
  12168. +    console_driver.name = "tty";
  12169. +    console_driver.name_base = 1;
  12170. +    console_driver.major = TTY_MAJOR;
  12171. +    console_driver.minor_start = 1;
  12172. +    console_driver.num = MAX_NR_CONSOLES;
  12173. +    console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
  12174. +    console_driver.init_termios = tty_std_termios;
  12175. +    console_driver.flags = TTY_DRIVER_REAL_RAW;
  12176. +    console_driver.refcount = &console_refcount;
  12177. +    console_driver.table = console_table;
  12178. +    console_driver.termios = console_termios;
  12179. +    console_driver.termios_locked = console_termios_locked;
  12180. +
  12181. +    console_driver.open = con_open;
  12182. +    console_driver.write = con_write;
  12183. +    console_driver.write_room = con_write_room;
  12184. +    console_driver.chars_in_buffer = con_chars_in_buffer;
  12185. +    console_driver.ioctl = con_ioctl;
  12186. +    console_driver.stop = con_stop;
  12187. +    console_driver.start = con_start;
  12188. +    console_driver.throttle = con_throttle;
  12189. +    console_driver.unthrottle = con_unthrottle;
  12190. +
  12191. +    if(tty_register_driver(&console_driver))
  12192. +          panic("Couldn't register console driver\n");
  12193. +
  12194. +    con_setsize(ORIG_VIDEO_LINES,ORIG_VIDEO_COLS);
  12195. +
  12196. +    timer_table[BLANK_TIMER].fn=blank_screen;
  12197. +    timer_table[BLANK_TIMER].expires=0;
  12198. +    if(blankinterval) {
  12199. +          timer_table[BLANK_TIMER].expires=jiffies+blankinterval;
  12200. +        timer_active|=1<<BLANK_TIMER;
  12201. +    }
  12202. +
  12203. +    for(i=0; i<17; i++)
  12204. +        vidc_write(i<<2, default_palette_entries[i]);
  12205. +
  12206. +    /* Use ORIG_VIDEO_MODE */
  12207. +    video_addr_mask= (video_num_lines * video_num_columns * bytes_per_char_h *
  12208. +                 bytes_per_char_v - 1) | (PAGE_SIZE-1);
  12209. +    video_mem_term = 0x02000000;
  12210. +    video_mem_base = video_mem_term - video_addr_mask - 1;
  12211. +
  12212. +    map_screen_mem (video_mem_base, 1);
  12213. +
  12214. +    can_do_color=1;
  12215. +    if(bytes_per_char_h == 8)
  12216. +    {
  12217. +        default_palette_entries = palette_8;
  12218. +        color_table = color_8;
  12219. +    }
  12220. +
  12221. +    for(currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
  12222. +        vc_cons[currcons].d = (struct vc_data *) kmem_start;
  12223. +        kmem_start += sizeof(struct vc_data);
  12224. +        vt_cons[currcons] = (struct vt_struct *) kmem_start;
  12225. +        kmem_start += sizeof(struct vt_struct);
  12226. +        vc_scrbuf[currcons] = (unsigned char *) kmem_start;
  12227. +        memfastset(vc_scrbuf[currcons],    0x00000720, video_buf_size);
  12228. +        kmem_start += video_buf_size;
  12229. +        kmalloced = 0;
  12230. +        screenbuf_size = video_buf_size;
  12231. +        vc_init(currcons, video_num_lines, video_num_columns,currcons);
  12232. +    }
  12233. +
  12234. +    currcons = fg_console = 0;
  12235. +
  12236. +    video_mem_start = video_mem_base;
  12237. +    video_mem_end    = video_mem_term;
  12238. +    pos=origin=cp    = video_mem_start;
  12239. +    scr_end        = video_mem_start + video_num_lines * video_size_row;
  12240. +    cursoron    = 1;
  12241. +
  12242. +    gotoxy (currcons,ORIG_X,ORIG_Y);
  12243. +    csi_J (currcons, 0);
  12244. +    printable=1;
  12245. +    printk ("Console: %s %s %ldx%ldx%d, %d virtual console%s (max %d)\n","colour", "A5000",
  12246. +          video_num_columns,
  12247. +          video_num_lines,
  12248. +          bytes_per_char_h == 8 ? 256:16,
  12249. +          MIN_NR_CONSOLES,
  12250. +          (MIN_NR_CONSOLES == 1) ? "":"s",
  12251. +          MAX_NR_CONSOLES);
  12252. +    register_console (console_print);
  12253. +    if(request_irq (IRQ_VSYNCPULSE, vsync_irq, 0, "console"))
  12254. +        panic ("Unable to get VSYNC irq for console\n");
  12255. +    return kmem_start;
  12256. +}
  12257. +
  12258. +static void get_scrmem(int currcons)
  12259. +{
  12260. +}
  12261. +
  12262. +void update_scrmem(int currcons, int start, int length)
  12263. +{
  12264. +    unsigned long p, pp, sx, sy, ex, ey;
  12265. +    unsigned long *buffer;
  12266. +
  12267. +    sy = start / video_num_columns;
  12268. +    sx = start % video_num_columns;
  12269. +    length += start;
  12270. +    ey = length / video_num_columns;
  12271. +    ex = length % video_num_columns;
  12272. +
  12273. +    if (ey > video_num_lines)
  12274. +        ey = video_num_lines;
  12275. +
  12276. +    p = origin + sy * video_size_row;
  12277. +    buffer = ((unsigned long *)vc_scrbuf[currcons]) + start;
  12278. +
  12279. +    if (ey > sy)
  12280. +    {
  12281. +        for (; sy < ey; sy++)
  12282. +        {
  12283. +            pp = p + sx * bytes_per_char_h;
  12284. +            for (; sx < video_num_columns; sx++)
  12285. +            {
  12286. +                ll_char_write (pp, buffer[0] & 0xff, (buffer[0] >> 8) & 0xff,
  12287. +                    (buffer[0] >> 16) & 0xff, (buffer[0] >> 24) & 0xff);
  12288. +                pp += bytes_per_char_h;
  12289. +                buffer ++;
  12290. +            }
  12291. +            p += video_size_row;
  12292. +            sx = 0;
  12293. +        }
  12294. +    }
  12295. +    if (ey == sy && ex)
  12296. +    {
  12297. +        for (; sx < ex; sx++)
  12298. +        {
  12299. +            ll_char_write (p, buffer[0] & 0xff, (buffer[0] >> 8) & 0xff,
  12300. +                (buffer[0] >> 16) & 0xff, (buffer[0] >> 24) & 0xff);
  12301. +            p += bytes_per_char_h;
  12302. +            buffer ++;
  12303. +        }
  12304. +    }
  12305. +}
  12306. +
  12307. +void set_scrmem(int currcons,long offset)
  12308. +{
  12309. +    unsigned long p,pp,mx,my;
  12310. +    unsigned long *buffer;
  12311. +    int i;
  12312. +
  12313. +    p = origin;
  12314. +    buffer = (unsigned long *)vc_scrbuf[currcons];
  12315. +
  12316. +    for(my = 0; my < video_num_lines ; my++)
  12317. +    {
  12318. +        pp = p;
  12319. +        for(mx = 0; mx < video_num_columns; mx++)
  12320. +        {
  12321. +            ll_char_write(pp,buffer[0] & 0xff,(buffer[0] >> 8) & 0xff,
  12322. +                     (buffer[0] >> 16) & 0xff,(buffer[0] >> 24) & 0xff);
  12323. +            pp+=bytes_per_char_h;
  12324. +            buffer+=1;
  12325. +        }
  12326. +        p+=video_size_row;
  12327. +    }
  12328. +    pp = origin + ((video_screen_size + 0x7FFF) & PAGE_MASK);
  12329. +    while(p<pp)
  12330. +    {
  12331. +        *(unsigned long *)p=0;
  12332. +        p+=4;
  12333. +    }
  12334. +    if(!paletteentries || vcmode != KD_GRAPHICS)
  12335. +        for(i=0; i<17; i++)
  12336. +            vidc_write(i<<2, default_palette_entries[i]);
  12337. +    else
  12338. +        for(i=0; i<17; i++)
  12339. +            vidc_write(i<<2, paletteentries[i] & 0x1fff);
  12340. +}
  12341. +
  12342. +/* ------------------------------------------------------------------------------------- *
  12343. + * Screen blanking routines
  12344. + * ------------------------------------------------------------------------------------- */
  12345. +
  12346. +void do_blank_screen(int nopowersave)
  12347. +{
  12348. +    int i;
  12349. +
  12350. +    if (console_blanked)
  12351. +        return;
  12352. +
  12353. +    timer_active &= ~(1<<BLANK_TIMER);
  12354. +    timer_table[BLANK_TIMER].fn = unblank_screen;
  12355. +
  12356. +    /* DISABLE VIDEO */
  12357. +    for (i = 0; i < 17; i++)
  12358. +        vidc_write(i<<2, 0);
  12359. +
  12360. +    console_blanked = fg_console + 1;
  12361. +}
  12362. +
  12363. +void do_unblank_screen(void)
  12364. +{
  12365. +    int i;
  12366. +    int currcons;
  12367. +
  12368. +    if (!console_blanked)
  12369. +        return;
  12370. +    if (!vc_cons_allocated(fg_console)) {
  12371. +        /* impossible */
  12372. +        printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
  12373. +        return;
  12374. +    }
  12375. +    timer_table[BLANK_TIMER].fn = blank_screen;
  12376. +    if (blankinterval)
  12377. +    {
  12378. +        timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
  12379. +        timer_active |= 1<<BLANK_TIMER;
  12380. +    }
  12381. +
  12382. +    currcons = fg_console;
  12383. +    console_blanked = 0;
  12384. +
  12385. +    if(!paletteentries || vcmode != KD_GRAPHICS)
  12386. +        for(i=0; i<17; i++)
  12387. +            vidc_write(i<<2, default_palette_entries[i]);
  12388. +    else
  12389. +        for(i=0; i<17; i++)
  12390. +            vidc_write(i<<2, paletteentries[i] & 0x1fff);
  12391. +}
  12392. +
  12393. +/*
  12394. + * If a blank_screen is due to a timer, then a power save is allowed.
  12395. + * If it is related to console_switching, then avoid power save.
  12396. + */
  12397. +static void blank_screen(void)
  12398. +{
  12399. +    do_blank_screen(0);
  12400. +}
  12401. +
  12402. +static void unblank_screen(void)
  12403. +{
  12404. +    do_unblank_screen();
  12405. +}
  12406. +
  12407. +void update_screen(int new_console)
  12408. +{
  12409. +    static int lock = 0;
  12410. +
  12411. +    if(new_console == fg_console || lock)
  12412. +        return;
  12413. +    if(!vc_cons_allocated(new_console)) {
  12414. +        /* strange ... */
  12415. +        printk("update_screen: tty %d not allocated ??\n",new_console);
  12416. +        return;
  12417. +    }
  12418. +    lock = 1;
  12419. +    
  12420. +    highlight_pointer(fg_console,-1);
  12421. +    
  12422. +    remove_cursors(fg_console);
  12423. +    
  12424. +    if(!console_blanked)
  12425. +        get_scrmem(fg_console);
  12426. +    else
  12427. +        console_blanked = -1;        /* no longer of the form console+1 */
  12428. +    fg_console = new_console;    /* this is the only (nonzero) assignment to fg_console */
  12429. +                    /* consequently, fg_console will always be allocated */
  12430. +    set_scrmem(fg_console, 0);
  12431. +    set_origin(fg_console);
  12432. +    set_cursor(fg_console);
  12433. +    restore_cursors(fg_console);
  12434. +    set_leds();
  12435. +    compute_shiftstate();
  12436. +    lock = 0;
  12437. +}
  12438. +
  12439. +/*
  12440. + * Allocate the console screen memory
  12441. + */
  12442. +int con_open(struct tty_struct *tty,struct file *filp)
  12443. +{
  12444. +    unsigned int idx;
  12445. +    int i;
  12446. +    
  12447. +    idx = MINOR(tty->device) - tty->driver.minor_start;
  12448. +
  12449. +    i = vc_allocate(idx);
  12450. +    if(i)
  12451. +        return i;
  12452. +
  12453. +    vt_cons[idx]->vc_num = idx;
  12454. +    tty->driver_data = vt_cons[idx];
  12455. +
  12456. +    if(!tty->winsize.ws_row && !tty->winsize.ws_col) {
  12457. +        tty->winsize.ws_row = video_num_lines;
  12458. +        tty->winsize.ws_col = video_num_columns;
  12459. +    }
  12460. +    return 0;
  12461. +}
  12462. +
  12463. +/*
  12464. + * PIO_FONT support
  12465. + */
  12466. +int con_set_font (char *arg)
  12467. +{
  12468. +    return -EINVAL;
  12469. +}
  12470. +
  12471. +int con_get_font (char *arg)
  12472. +{
  12473. +    return -EINVAL;
  12474. +}
  12475. +
  12476. +void reset_palette (int currcons)
  12477. +{
  12478. +}
  12479. +
  12480. +void set_palette (void)
  12481. +{
  12482. +}
  12483. +
  12484. +/* == arm specific console code ============================================================== */
  12485. +
  12486. +int palette_getentries(int currcons, int offset, int size, unsigned long *entries)
  12487. +{
  12488. +  int i;
  12489. +
  12490. +  if(offset>18 || offset<0 || size<1)
  12491. +    return -EINVAL;
  12492. +
  12493. +  if(size>19)
  12494. +    size=19;
  12495. +
  12496. +  verify_area(VERIFY_WRITE,entries,size);
  12497. +
  12498. +  if(!paletteentries)
  12499. +    for(i=offset; i<offset+size; i++)
  12500. +      *entries++=default_palette_entries[i];
  12501. +  else
  12502. +    for(i=offset; i<offset+size; i++)
  12503. +      *entries++=(paletteentries[i] & 0x1FFF);
  12504. +
  12505. +  return size;
  12506. +}
  12507. +
  12508. +int palette_setentries(int currcons, int offset, int size, unsigned long *entries)
  12509. +{
  12510. +  int i;
  12511. +
  12512. +  if(offset>18 || offset<0 || size<1)
  12513. +    return -EINVAL;
  12514. +
  12515. +  if(size>19)
  12516. +    size=19;
  12517. +
  12518. +  verify_area(VERIFY_READ, entries, size);
  12519. +
  12520. +  if(!paletteentries)
  12521. +  {
  12522. +    paletteentries = (unsigned long *)kmalloc(sizeof(unsigned long)*19,GFP_KERNEL);
  12523. +    if(!paletteentries)
  12524. +      return -ENOMEM;
  12525. +
  12526. +    for(i=0; i<19; i++)
  12527. +      paletteentries[i]=default_palette_entries[i];
  12528. +  }
  12529. +
  12530. +  for(i=offset; i<offset+size; i++)
  12531. +    paletteentries[i]=(*entries++);
  12532. +
  12533. +  if(vcmode == KD_GRAPHICS && currcons == fg_console)
  12534. +    for(i=0; i<17; i++)
  12535. +      vidc_write(i<<2, paletteentries[i] & 0x1fff);
  12536. +
  12537. +  return size;
  12538. +}
  12539. +
  12540. +void palette_update(int currcons)
  12541. +{
  12542. +  int i;
  12543. +  if(vcmode == KD_GRAPHICS && paletteentries)
  12544. +    for(i=0; i<17; i++)
  12545. +      vidc_write(i<<2, paletteentries[i] & 0x1fff);
  12546. +  else
  12547. +    for(i=0; i<17; i++)
  12548. +      vidc_write(i<<2, default_palette_entries[i]);
  12549. +}
  12550. +
  12551. +int console_getparams(int con, unsigned long *data)
  12552. +{
  12553. +    data[0] = 0;                    /* version      */
  12554. +    data[1] = video_num_columns * 8;        /* horiz pixels */
  12555. +    data[2] = video_num_lines * 8;            /* vert. pixels */
  12556. +    data[3] = bytes_per_char_h == 4 ? 4 : 8;    /* bits per pix */
  12557. +    data[4] = 4;                    /* depth        */
  12558. +    return 0;
  12559. +}
  12560. +
  12561. +static void put_cursor(char on_off,unsigned long newcp)
  12562. +{
  12563. +  static char con=0;
  12564. +  unsigned long cp_p=cp;
  12565. +  int c = bytes_per_char_h == 8 ? color_table[15] : 0x11 * color_table[15];
  12566. +  int i;
  12567. +
  12568. +  if(vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
  12569. +    return;
  12570. +
  12571. +  cp=newcp;
  12572. +
  12573. +  if(con!=on_off)
  12574. +  {
  12575. +    if(cp_p!=-1)
  12576. +      for(i=0;i<bytes_per_char_h;i++)
  12577. +        ((unsigned char*)cp_p)[i]^=c;
  12578. +    con=on_off;
  12579. +  }
  12580. +}
  12581. +
  12582. +static void vsync_irq(int irq, struct pt_regs *regs)
  12583. +{
  12584. +  static char cursor_flash=0;
  12585. +  int currcons = fg_console;
  12586. +
  12587. +  if(++cursor_flash==16)
  12588. +  {
  12589. +    cursor_flash=0;
  12590. +    cursor_on=cursor_on?0:1;
  12591. +    if(cursoron>0)
  12592. +      put_cursor(cursor_on,cp);
  12593. +  }
  12594. +}
  12595. +
  12596. +int do_screendump(int arg)
  12597. +{
  12598. +  char *buf=(char *)arg;
  12599. +  int l;
  12600. +  if(!suser())
  12601. +    return -EPERM;
  12602. +  l=verify_area(VERIFY_WRITE,buf,2);
  12603. +  if(l)
  12604. +    return l;
  12605. +  return -ENOSYS;
  12606. +}
  12607. +
  12608. +/* This routine reverses the highlight on s-e position */
  12609. +
  12610. +static void highlight(const int currcons, int s, int e)
  12611. +{
  12612. +    int i;
  12613. +    unsigned char *buffer = (unsigned char *)vc_scrbuf[currcons];
  12614. +
  12615. +    for(i = s; i <= e; i++)
  12616. +        buffer[4*i+3] ^= INVERSE;
  12617. +
  12618. +
  12619. +    if(currcons == fg_console)
  12620. +    {
  12621. +        unsigned long p,pp;
  12622. +        int hx,hy,hex,hey,mx,my;
  12623. +
  12624. +        buffer += (s*4);
  12625. +
  12626. +        hx = s % video_num_columns;
  12627. +        hy = s / video_num_columns;
  12628. +        hex = e % video_num_columns;
  12629. +        hey = e / video_num_columns;
  12630. +
  12631. +        p = origin + (hy * video_size_row);
  12632. +        for(my = hy; my <= hey ; my++)
  12633. +        {
  12634. +            pp = p + (hx * bytes_per_char_h);
  12635. +            for(mx = hx; mx < ((my == hey)?hex+1:video_num_columns); mx++)
  12636. +            {
  12637. +                ll_char_write(pp,buffer[0],buffer[1],buffer[2],buffer[3]);
  12638. +                pp+=bytes_per_char_h;
  12639. +                buffer+=4;
  12640. +                hx = 0;
  12641. +            }
  12642. +            p+=video_size_row;
  12643. +        }
  12644. +    }
  12645. +}
  12646. +
  12647. +static void highlight_pointer(const int currcons,const int where)
  12648. +{
  12649. +}
  12650. +
  12651. +static unsigned long inwordLut[4]={
  12652. +  0x00000000, /* control char      */
  12653. +  0x03FF0000, /* digits            */
  12654. +  0x87FFFFFE, /* uppercase and '_' */
  12655. +  0x07FFFFFE  /* lowercase         */
  12656. +};
  12657. +
  12658. +static inline int inword(const char c)
  12659. +{
  12660. +  return ( inwordLut[(c>>5)&3] >> (c&0x1F) ) & 1;
  12661. +}
  12662. +
  12663. +int sel_loadlut(const int arg)
  12664. +{
  12665. +    memcpy_fromfs(inwordLut, (unsigned long *)(arg+4), 16);
  12666. +    return 0;
  12667. +}
  12668. +
  12669. +static inline int atedge(const int p)
  12670. +{
  12671. +    return (!(p % video_num_columns) || !((p + 1) % video_num_columns));
  12672. +}
  12673. +
  12674. +/* constrain v such that l <= v <= u */
  12675. +static inline short limit(const int v, const int l, const int u)
  12676. +{
  12677. +    return (v < l) ? l : ((v > u) ? u : v);
  12678. +}
  12679. +
  12680. +int set_selection(const int arg, struct tty_struct *tty)
  12681. +{
  12682. +    unsigned short *args, xs, ys, xe, ye;
  12683. +    int sel_mode, new_sel_start, new_sel_end;
  12684. +    int ps, pe, i;
  12685. +    int currcons = fg_console;
  12686. +    char spc, *obp, *bp, *spos;
  12687. +
  12688. +    char *off = (char *)vc_scrbuf[currcons];
  12689. +
  12690. +    unblank_screen();
  12691. +    args = (unsigned short *)(arg + 1);
  12692. +    xs = limit(get_fs_word(args++) - 1, 0, video_num_columns - 1);
  12693. +    ys = limit(get_fs_word(args++) - 1, 0, video_num_lines - 1);
  12694. +    xe = limit(get_fs_word(args++) - 1, 0, video_num_columns - 1);
  12695. +    ye = limit(get_fs_word(args++) - 1, 0, video_num_lines - 1);
  12696. +    sel_mode = get_fs_word(args);
  12697. +
  12698. +    ps = ys * video_num_columns + xs;
  12699. +    pe = ye * video_num_columns + xe;
  12700. +
  12701. +    if (report_mouse && (sel_mode & 16))
  12702. +    {
  12703. +        mouse_report(currcons, tty, sel_mode & 15, xs, ys);
  12704. +        return 0;
  12705. +    }
  12706. +
  12707. +    if ( ps > pe )
  12708. +    {
  12709. +        ps ^= pe;
  12710. +        pe ^= ps;
  12711. +        ps ^= pe;
  12712. +    }
  12713. +
  12714. +    switch (sel_mode)
  12715. +    {
  12716. +        case 0: /* character-by-character selection */
  12717. +            new_sel_start = ps;
  12718. +            new_sel_end = pe;
  12719. +            break;
  12720. +        case 1:    /* word-by-word selection */
  12721. +            spc = isspace(*off + (ps << 2));
  12722. +            for (new_sel_start = ps; ; ps -= 1)
  12723. +            {
  12724. +                if ((spc && !isspace(*(off + (ps << 2)))) ||
  12725. +                    (!spc && !inword(*(off + (ps << 2)))))
  12726. +                    break;
  12727. +                new_sel_start = ps;
  12728. +                if (!(ps % video_num_columns))
  12729. +                    break;
  12730. +            }
  12731. +            spc = isspace(*(off + (pe << 2)));
  12732. +            for (new_sel_end = pe; ; pe += 1)
  12733. +            {
  12734. +                if ((spc && !isspace(*(off + (pe << 2)))) ||
  12735. +                    (!spc && !inword(*(off + (pe << 2)))))
  12736. +                    break;
  12737. +                new_sel_end = pe;
  12738. +                if (!((pe + 1) % video_num_columns))
  12739. +                    break;
  12740. +            }
  12741. +            break;
  12742. +        case 2: /* line-by-line selection */
  12743. +            new_sel_start = ps - ps % video_num_columns;
  12744. +            new_sel_end   = pe + video_num_columns - pe % video_num_columns - 1;
  12745. +            break;
  12746. +        case 3:    /* pointer highlight */
  12747. +            if (sel_cons != currcons)
  12748. +            {
  12749. +                highlight_pointer(sel_cons, -1);
  12750. +                clear_selection();
  12751. +                sel_cons = currcons;
  12752. +            }
  12753. +            highlight_pointer(sel_cons, pe);
  12754. +            return 0;
  12755. +        default:
  12756. +            return -EINVAL;
  12757. +    }
  12758. +    if(new_sel_end > new_sel_start && !atedge(new_sel_end) &&
  12759. +            isspace(*(off + (new_sel_end << 2))))
  12760. +    {
  12761. +        for (pe = new_sel_end + 1; ; pe += 1)
  12762. +        {
  12763. +            if (!isspace(*(off + (pe << 2))) || atedge(pe))
  12764. +                break;
  12765. +        }
  12766. +        if (isspace(*(off + (pe << 2))))
  12767. +            new_sel_end = pe;
  12768. +    }
  12769. +    if (sel_cons != currcons)
  12770. +    {
  12771. +        clear_selection();
  12772. +        sel_cons = currcons;
  12773. +    }
  12774. +    if(sel_start == -1)
  12775. +        highlight(sel_cons, new_sel_start, new_sel_end);
  12776. +    else if (new_sel_start == sel_start)
  12777. +    {
  12778. +        if (new_sel_end == sel_end)    /* no action required */
  12779. +            return 0;
  12780. +        else if (new_sel_end > sel_end)    /* extend to right/down */
  12781. +            highlight(sel_cons, sel_end + 1, new_sel_end);
  12782. +        else                /* contract from right/up */
  12783. +            highlight(sel_cons, new_sel_end + 1, sel_end);
  12784. +    }
  12785. +    else if (new_sel_end == sel_end)
  12786. +    {
  12787. +        if (new_sel_start < sel_start)    /* extend to left */
  12788. +            highlight(sel_cons, new_sel_start, sel_start - 1);
  12789. +        else
  12790. +            highlight(sel_cons, sel_start, new_sel_start - 1);
  12791. +    }
  12792. +    else
  12793. +    {
  12794. +        clear_selection();
  12795. +        highlight(sel_cons, new_sel_start, new_sel_end);
  12796. +    }
  12797. +    sel_start = new_sel_start;
  12798. +    sel_end = new_sel_end;
  12799. +
  12800. +    obp = bp = sel_buffer;
  12801. +
  12802. +    for (i = sel_start; i <= sel_end; i+=1)
  12803. +    {
  12804. +        spos = (char *)off + (i << 2);
  12805. +        *bp++ = *spos;
  12806. +        if (!isspace(*spos))
  12807. +            obp = bp;
  12808. +        if (! ((i+1) % video_num_columns))
  12809. +        {
  12810. +             /* strip trailing spaces from line and add newline,
  12811. +                unless non-space at end of line. */
  12812. +             if (obp != bp)
  12813. +             {
  12814. +                 bp = obp;
  12815. +                 *bp++ = '\r';
  12816. +             }
  12817. +             obp = bp;
  12818. +        }
  12819. +        /* check for space, leaving room for next character, possible
  12820. +           newline, and null at end. */
  12821. +        if (bp - sel_buffer > SEL_BUFFER_SIZE - 3)
  12822. +            break;
  12823. +    }
  12824. +    *bp = '\0';
  12825. +    return 0;
  12826. +}
  12827. +
  12828. +int paste_selection(struct tty_struct *tty)
  12829. +{
  12830. +    struct wait_queue wait;
  12831. +    char *bp = sel_buffer;
  12832. +    int c,l;
  12833. +    struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
  12834. +
  12835. +    if(!sel_buffer[0])
  12836. +        return 0;
  12837. +    unblank_screen();
  12838. +    c = strlen(sel_buffer);
  12839. +    current->state = TASK_INTERRUPTIBLE;
  12840. +    add_wait_queue(&vt->paste_wait, &wait);
  12841. +    while (c) {
  12842. +        if (test_bit(TTY_THROTTLED, &tty->flags)) {
  12843. +            schedule();
  12844. +            continue;
  12845. +        }
  12846. +        l = MIN(c, tty->ldisc.receive_room(tty));
  12847. +        tty->ldisc.receive_buf(tty,(unsigned char *) bp, 0, l);
  12848. +        c -= l;
  12849. +        bp += l;
  12850. +    }
  12851. +    current->state = TASK_RUNNING;
  12852. +    return 0;
  12853. +}
  12854. +
  12855. +static void clear_selection()
  12856. +{
  12857. +    highlight_pointer(sel_cons, -1); /* hide the pointer */
  12858. +    if (sel_start != -1)
  12859. +    {
  12860. +        highlight(sel_cons, sel_start, sel_end);
  12861. +        sel_start = -1;
  12862. +    }
  12863. +}
  12864. +
  12865. +/* -------------------------------------------------------------------------------
  12866. + * erasing
  12867. + * ------------------------------------------------------------------------------- */
  12868. +
  12869. +static void ll_erasebuf(int currcons,unsigned char sx,unsigned char sy,
  12870. +            unsigned char cx,unsigned char cy)
  12871. +{
  12872. +    unsigned char *buffer = vc_scrbuf[currcons];
  12873. +    if(sx!=0) /* Erase to end of line */
  12874. +    {
  12875. +        register unsigned char c;
  12876. +        if(cy!=0)
  12877. +            c=video_num_columns-sx;
  12878. +        else
  12879. +            c=video_num_columns-sx<cx?video_num_columns-sx:cx;
  12880. +        memfastset((void*)(buffer+4*(sx+sy*video_num_columns)),
  12881. +            (backcol<<16) | (forecol<<8) | 32, 4*c);
  12882. +        cx-=c;
  12883. +        sy++;
  12884. +        if(cy>0)
  12885. +            cy--;
  12886. +        sx=0;
  12887. +    }
  12888. +    if(cy!=0)
  12889. +    {
  12890. +        memfastset((void*)(buffer+sy*video_num_columns*4),
  12891. +            (backcol<<16) | (forecol<<8) | 32,cy*video_num_columns*4);
  12892. +    }
  12893. +    if(cx!=0)
  12894. +    {
  12895. +        memfastset((void*)(buffer+(sy+cy)*video_num_columns*4),
  12896. +            (backcol<<16) | (forecol<<8) | 32,cx*4);
  12897. +    }
  12898. +}
  12899. +
  12900. +static void ll_erase(int currcons,unsigned char sx,unsigned char sy,
  12901. +                      unsigned char cx,unsigned char cy)
  12902. +{
  12903. +    register unsigned char *p,cc;
  12904. +    register unsigned int i1,i2;
  12905. +
  12906. +    ll_erasebuf(currcons,sx,sy,cx,cy);
  12907. +
  12908. +    if(currcons==fg_console)
  12909. +    {
  12910. +        cc=0x11*backcol;
  12911. +
  12912. +        if(sx!=0) /* Erase to end of line */
  12913. +        {
  12914. +            register unsigned char c;
  12915. +            if(cy!=0)
  12916. +                c=video_num_columns-sx;
  12917. +            else
  12918. +                c=video_num_columns-sx<cx?video_num_columns-sx:cx;
  12919. +            p=(unsigned char*)(origin+sy*video_num_columns*
  12920. +                        bytes_per_char_h*bytes_per_char_v+
  12921. +                                sx*bytes_per_char_h);
  12922. +            for(i1=0;i1<c*bytes_per_char_h;i1++)
  12923. +                for(i2=0;i2<bytes_per_char_v;i2++)
  12924. +                    p[i1+i2*video_num_columns*bytes_per_char_h]=cc;
  12925. +            cx-=c;
  12926. +            if(cy>0)
  12927. +                cy--;
  12928. +            sy++;
  12929. +            sx=0;
  12930. +        }
  12931. +        if(cy!=0)
  12932. +        {
  12933. +            memfastset((void*)(origin+sy*video_num_columns*
  12934. +                        bytes_per_char_h*bytes_per_char_v),
  12935. +                0x11111111L*backcol,
  12936. +                cy*bytes_per_char_h*bytes_per_char_v*video_num_columns);
  12937. +        }
  12938. +        if(cx!=0)
  12939. +        {
  12940. +            p=(unsigned char*)(origin+(sy+cy)*video_num_columns*
  12941. +                        bytes_per_char_h*bytes_per_char_v);
  12942. +            for(i1=0;i1<cx*bytes_per_char_h;i1++)
  12943. +                for(i2=0;i2<bytes_per_char_v;i2++)
  12944. +                    p[i1+i2*video_num_columns*bytes_per_char_h]=cc;
  12945. +        }
  12946. +    }
  12947. +}
  12948. +
  12949. diff -urNwbB linux/arch/arm/drivers/char/defkeymap.c linux.arm/arch/arm/drivers/char/defkeymap.c
  12950. --- linux/arch/arm/drivers/char/defkeymap.c    Thu Jan  1 01:00:00 1970
  12951. +++ linux.arm/arch/arm/drivers/char/defkeymap.c    Sun Mar  3 12:31:45 1996
  12952. @@ -0,0 +1,337 @@
  12953. +/*
  12954. + * linux/arch/arm/drivers/char/defkeymap.c
  12955. + *
  12956. + * Copyright (C) 1995, 1996 Russell King
  12957. + */
  12958. +
  12959. +#include <linux/types.h>
  12960. +#include <linux/keyboard.h>
  12961. +#include <linux/kd.h>
  12962. +
  12963. +/* Normal (maps 1:1 with no processing) */
  12964. +#define KTn    0xF0
  12965. +/* Function keys */
  12966. +#define KTf    0xF1
  12967. +/* Special (Performs special house-keeping funcs) */
  12968. +#define KTs    0xF2
  12969. +#define KIGNORE        K(KTs, 0)    /* Ignore */
  12970. +#define KENTER        K(KTs, 1)    /* Enter */
  12971. +#define KREGS        K(KTs, 2)    /* Regs */
  12972. +#define KMEM        K(KTs, 3)    /* Mem */
  12973. +#define KSTAT        K(KTs, 4)    /* State */
  12974. +#define KINTR        K(KTs, 5)    /* Intr */
  12975. +#define Ksl    6    /* Last console */
  12976. +#define KCAPSLK        K(KTs, 7)    /* Caps lock */
  12977. +#define KNUMLK        K(KTs, 8)    /* Num-lock */
  12978. +#define KSCRLLK        K(KTs, 9)    /* Scroll-lock */
  12979. +#define KSCRLFOR    K(KTs,10)    /* Scroll forward */
  12980. +#define KSCRLBAK    K(KTs,11)    /* Scroll back */
  12981. +#define KREBOOT        K(KTs,12)    /* Reboot */
  12982. +#define KCAPSON        K(KTs,13)    /* Caps on */
  12983. +#define KCOMPOSE    K(KTs,14)    /* Compose */
  12984. +#define KSAK        K(KTs,15)    /* SAK */
  12985. +#define CONS_DEC    K(KTs,16)    /* Dec console */
  12986. +#define CONS_INC    K(KTs,17)    /* Incr console */
  12987. +#define KFLOPPY        K(KTs,18)    /* Floppy */
  12988. +/* Key pad (0-9 = digits, 10=+, 11=-, 12=*, 13=/, 14=enter, 16=., 17=# */
  12989. +#define KTp    0xF3
  12990. +#define KPAD_0        K(KTp, 0 )
  12991. +#define KPAD_1      K(KTp, 1 )
  12992. +#define KPAD_2        K(KTp, 2 )
  12993. +#define KPAD_3        K(KTp, 3 )
  12994. +#define KPAD_4        K(KTp, 4 )
  12995. +#define KPAD_5        K(KTp, 5 )
  12996. +#define KPAD_6        K(KTp, 6 )
  12997. +#define KPAD_7        K(KTp, 7 )
  12998. +#define KPAD_8        K(KTp, 8 )
  12999. +#define KPAD_9        K(KTp, 9 )
  13000. +#define KPAD_PL        K(KTp,10 )
  13001. +#define KPAD_MI        K(KTp,11 )
  13002. +#define KPAD_ML        K(KTp,12 )
  13003. +#define KPAD_DV        K(KTp,13 )
  13004. +#define KPAD_EN        K(KTp,14 )
  13005. +#define KPAD_DT        K(KTp,16 )
  13006. +#define KPAD_HS        K(KTp,18 )
  13007. +/* Console switching */
  13008. +#define KCn    0xF5
  13009. +/* Cursor */
  13010. +#define KTc    0xF6
  13011. +#define Kcd    0    /* Cursor down */
  13012. +#define Kcl    1    /* Cursor left */
  13013. +#define Kcr    2    /* Cursor right */
  13014. +#define Kcu    3    /* Cursor up */
  13015. +/* Shift/alt modifiers etc */
  13016. +#define KMd    0xF7
  13017. +#define KSHIFT        K(KMd, 0 )
  13018. +#define KALTGR        K(KMd, 1 )
  13019. +#define KCTRL        K(KMd, 2 )
  13020. +#define KALT        K(KMd, 3 )
  13021. +/* Meta */
  13022. +#define KMt    0xF8
  13023. +#define KAs    0xF9
  13024. +#define KPADA_0        K(KAs, 0 )
  13025. +#define KPADA_1        K(KAs, 1 )
  13026. +#define KPADA_2        K(KAs, 2 )
  13027. +#define KPADA_3        K(KAs, 3 )
  13028. +#define KPADA_4        K(KAs, 4 )
  13029. +#define KPADA_5        K(KAs, 5 )
  13030. +#define KPADA_6        K(KAs, 6 )
  13031. +#define KPADA_7        K(KAs, 7 )
  13032. +#define KPADA_8        K(KAs, 8 )
  13033. +#define KPADA_9        K(KAs, 9 )
  13034. +#define KPADB_0        K(KAs,10 )
  13035. +#define KPADB_1        K(KAs,11 )
  13036. +#define KPADB_2        K(KAs,12 )
  13037. +#define KPADB_3        K(KAs,13 )
  13038. +#define KPADB_4        K(KAs,14 )
  13039. +#define KPADB_5        K(KAs,15 )
  13040. +#define KPADB_6        K(KAs,16 )
  13041. +#define KPADB_7        K(KAs,17 )
  13042. +#define KPADB_8        K(KAs,18 )
  13043. +#define KPADB_9        K(KAs,19 )
  13044. +/* Locking keys */
  13045. +#define KLk    0xFA
  13046. +/* Letters */
  13047. +#define KTl    0xFB
  13048. +
  13049. +u_short plain_map[]=
  13050. +{
  13051. +  K(KTn, 27),K(KTf,  0),K(KTf,  1),K(KTf,  2 ),K(KTf,  3),K(KTf,  4),K(KTf,  5 ),K(KTf,  6),
  13052. +  K(KTf,  7),K(KTf,  8),K(KTf,  9),K(KTf, 10 ),K(KTf, 11),KIGNORE   ,KSCRLLK    ,KINTR     ,
  13053. +  K(KTn,'`'),K(KTn,'1'),K(KTn,'2'),K(KTn,'3' ),K(KTn,'4'),K(KTn,'5'),K(KTn,'6' ),K(KTn,'7'),
  13054. +  K(KTn,'8'),K(KTn,'9'),K(KTn,'0'),K(KTn,'-' ),K(KTn,'='),K(KTn,'£'),K(KTn,127 ),K(KTf,21 ),
  13055. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,K(KTn,  9 ),K(KTl,'q'),
  13056. +  K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
  13057. +  K(KTl,'p'),K(KTn,'['),K(KTn,']'),K(KTn,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  13058. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTl,'a'),K(KTl,'s'),K(KTl,'d' ),K(KTl,'f'),
  13059. +  K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),K(KTn,';'),K(KTn,'\''),KENTER    ,
  13060. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTl,'z' ),K(KTl,'x'),
  13061. +  K(KTl,'c'),K(KTl,'v'),K(KTl,'b'),K(KTl,'n' ),K(KTl,'m'),K(KTn,','),K(KTn,'.' ),K(KTn,'/'),
  13062. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn,' '),
  13063. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  13064. +};
  13065. +
  13066. +u_short shift_map[]=
  13067. +{
  13068. +  K(KTn, 27),K(KTf, 10),K(KTf, 11),K(KTf, 12 ),K(KTf, 13),K(KTf, 14),K(KTf, 15 ),K(KTf, 16),
  13069. +  K(KTf, 17),K(KTf, 18),K(KTf, 19),K(KTf, 20 ),K(KTf, 21),KIGNORE   ,KMEM       ,KINTR     ,
  13070. +  K(KTn,'~'),K(KTn,'!'),K(KTn,'@'),K(KTn,'#' ),K(KTn,'$'),K(KTn,'%'),K(KTn,'^' ),K(KTn,'&'),
  13071. +  K(KTn,'*'),K(KTn,'('),K(KTn,')'),K(KTn,'_' ),K(KTn,'+'),K(KTn,'¤'),K(KTn,127 ),K(KTf,21 ),
  13072. +  K(KTf,20 ),KSCRLBAK  ,KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,K(KTn,  9 ),K(KTl,'Q'),
  13073. +  K(KTl,'W'),K(KTl,'E'),K(KTl,'R'),K(KTl,'T' ),K(KTl,'Y'),K(KTl,'U'),K(KTl,'I' ),K(KTl,'O'),
  13074. +  K(KTl,'P'),K(KTn,'{'),K(KTn,'}'),K(KTn,'|' ),K(KTf,22 ),K(KTf,23 ),KSCRLFOR   ,KPAD_7    ,
  13075. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTl,'A'),K(KTl,'S'),K(KTl,'D' ),K(KTl,'F'),
  13076. +  K(KTl,'G'),K(KTl,'H'),K(KTl,'J'),K(KTl,'K' ),K(KTl,'L'),K(KTn,':'),K(KTn,'"' ),KENTER    ,
  13077. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTl,'Z' ),K(KTl,'X'),
  13078. +  K(KTl,'C'),K(KTl,'V'),K(KTl,'B'),K(KTl,'N' ),K(KTl,'M'),K(KTn,'<'),K(KTn,'>' ),K(KTn,'?'),
  13079. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn,' '),
  13080. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  13081. +};
  13082. +
  13083. +u_short altgr_map[]=
  13084. +{
  13085. +  KIGNORE   ,K(KCn,12 ),K(KCn,13 ),K(KCn,14  ),K(KCn,15 ),K(KCn,16 ),K(KCn,17  ),K(KCn, 18),
  13086. +  K(KCn, 19),K(KCn,20 ),K(KCn,21 ),K(KCn,22  ),K(KCn,23 ),KIGNORE   ,KREGS      ,KINTR     ,
  13087. +  KIGNORE   ,KIGNORE   ,K(KTn,'@'),KIGNORE    ,K(KTn,'$'),KIGNORE   ,KIGNORE    ,K(KTn,'{'),
  13088. +  K(KTn,'['),K(KTn,']'),K(KTn,'}'),K(KTn,'\\'),KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,21 ),
  13089. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KTl,'q'),
  13090. +  K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
  13091. +  K(KTl,'p'),KIGNORE   ,K(KTn,'~'),KIGNORE    ,K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPADB_7   ,
  13092. +  KPADB_8   ,KPADB_9   ,KPAD_MI   ,KCTRL      ,K(KAs,20 ),K(KTl,'s'),K(KAs,23  ),K(KAs,25 ),
  13093. +  K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),KIGNORE   ,KIGNORE    ,KENTER    ,
  13094. +  KPADB_4   ,KPADB_5   ,KPADB_6   ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTl,'z' ),K(KTl,'x'),
  13095. +  K(KAs,22 ),K(KTl,'v'),K(KTl,21 ),K(KTl,'n' ),K(KTl,'m'),KIGNORE   ,KIGNORE    ,KIGNORE   ,
  13096. +  KSHIFT    ,K(KTc,Kcu),KPADB_1   ,KPADB_2    ,KPADB_3   ,KCAPSLK   ,KALT       ,KIGNORE   ,
  13097. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPADB_0   ,KPAD_DT    ,KPAD_EN
  13098. +};
  13099. +
  13100. +u_short ctrl_map[]=
  13101. +{
  13102. +  KIGNORE   ,K(KTf,  0),K(KTf,  1),K(KTf,  2 ),K(KTf,  3),K(KTf,  4),K(KTf, 5  ),K(KTf,  6),
  13103. +  K(KTf,  7),K(KTf,  8),K(KTf,  9),K(KTf, 10 ),K(KTf, 11),KIGNORE   ,KSTAT      ,KINTR     ,
  13104. +  KIGNORE   ,K(KTn, 1 ),K(KTn, 2 ),K(KTn, 3  ),K(KTn, 4 ),K(KTn, 5 ),K(KTn, 6  ),K(KTn, 7 ),
  13105. +  K(KTn, 8 ),K(KTn, 9 ),K(KTn, 0 ),K(KTn,31  ),KIGNORE   ,KIGNORE   ,K(KTn, 8  ),K(KTf,21 ),
  13106. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KTn,17 ),
  13107. +  K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20  ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9  ),K(KTn,15 ),
  13108. +  K(KTn,16 ),K(KTn,27 ),K(KTn,29 ),K(KTn,28  ),K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  13109. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4  ),K(KTn, 6 ),
  13110. +  K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11  ),K(KTn,12 ),KIGNORE   ,K(KTn, 7  ),KENTER    ,
  13111. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTn,26  ),K(KTn,24 ),
  13112. +  K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14  ),K(KTn,13 ),KIGNORE   ,KCOMPOSE   ,K(KTn,127),
  13113. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn, 0 ),
  13114. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  13115. +};
  13116. +
  13117. +u_short shift_ctrl_map[]=
  13118. +{
  13119. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,
  13120. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KFLOPPY    ,KINTR     ,
  13121. +  KIGNORE   ,KIGNORE   ,K(KTn, 0 ),KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,
  13122. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,K(KTn,31  ),KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,21 ),
  13123. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KTn,17 ),
  13124. +  K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20  ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9  ),K(KTn,15 ),
  13125. +  K(KTn,16 ),KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  13126. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4  ),K(KTn, 6 ),
  13127. +  K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11  ),K(KTn,12 ),KIGNORE   ,K(KTn, 7  ),KENTER    ,
  13128. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KTn,26  ),K(KTn,24 ),
  13129. +  K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14  ),K(KTn,13 ),KIGNORE   ,KIGNORE    ,KIGNORE   ,
  13130. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,K(KTn, 0 ),
  13131. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KPAD_DT    ,KPAD_EN   
  13132. +};
  13133. +
  13134. +u_short alt_map[]=
  13135. +{
  13136. +  K(KMt,27 ),K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2  ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5  ),K(KCn, 6 ),
  13137. +  K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10  ),K(KCn,11 ),KIGNORE   ,KSCRLLK    ,KINTR     ,
  13138. +  K(KMt,'`'),K(KMt,'1'),K(KMt,'2'),K(KMt,'3' ),K(KMt,'4'),K(KMt,'5'),K(KMt,'6' ),K(KMt,'7'),
  13139. +  K(KMt,'8'),K(KMt,'9'),K(KMt,'0'),K(KMt,'-' ),K(KMt,'='),K(KMt,'£'),K(KMt,127 ),K(KTf,21 ),
  13140. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,K(KMt, 9  ),K(KMt,'q'),
  13141. +  K(KMt,'w'),K(KMt,'e'),K(KMt,'r'),K(KMt,'t' ),K(KMt,'y'),K(KMt,'u'),K(KMt,'i' ),K(KMt,'o'),
  13142. +  K(KMt,'p'),K(KMt,'['),K(KMt,']'),K(KMt,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25  ),KPADA_7   ,
  13143. +  KPADA_8   ,KPADA_9   ,KPAD_MI   ,KCTRL      ,K(KMt,'a'),K(KMt,'s'),K(KMt,'d' ),K(KMt,'f'),
  13144. +  K(KMt,'g'),K(KMt,'h'),K(KMt,'j'),K(KMt,'k' ),K(KMt,'l'),K(KMt,';'),K(KMt,'\''),K(KMt,13 ),
  13145. +  KPADA_4   ,KPADA_5   ,KPADA_6   ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KMt,'z' ),K(KMt,'x'),
  13146. +  K(KMt,'c'),K(KMt,'v'),K(KMt,'b'),K(KMt,'n' ),K(KMt,'m'),K(KMt,','),K(KMt,'.' ),KIGNORE   ,
  13147. +  KSHIFT    ,K(KTc,Kcu),KPADA_1   ,KPADA_2    ,KPADA_3   ,KCAPSLK   ,KALT       ,K(KMt,' '),
  13148. +  KALTGR    ,KCTRL     ,CONS_DEC  ,K(KTc,Kcd ),CONS_INC  ,KPADA_0   ,KPAD_DT    ,KPAD_EN
  13149. +};
  13150. +
  13151. +u_short ctrl_alt_map[]=
  13152. +{
  13153. +  KIGNORE   ,K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2  ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5  ),K(KCn, 6 ),
  13154. +  K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10  ),K(KCn,11 ),KIGNORE   ,KIGNORE    ,KINTR     ,
  13155. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,
  13156. +  KIGNORE   ,KIGNORE   ,KIGNORE   ,KIGNORE    ,KIGNORE   ,KIGNORE   ,KIGNORE    ,K(KTf,21 ),
  13157. +  K(KTf,20 ),K(KTf,24 ),KNUMLK    ,KPAD_DV    ,KPAD_ML   ,KPAD_HS   ,KIGNORE    ,K(KMt,17 ),
  13158. +  K(KMt,23 ),K(KMt, 5 ),K(KMt,18 ),K(KMt,20  ),K(KMt,25 ),K(KMt,21 ),K(KMt, 9  ),K(KMt,15 ),
  13159. +  K(KMt,16 ),KIGNORE   ,KIGNORE   ,KIGNORE    ,KREBOOT   ,K(KTf,23 ),K(KTf,25  ),KPAD_7    ,
  13160. +  KPAD_8    ,KPAD_9    ,KPAD_MI   ,KCTRL      ,K(KMt, 1 ),K(KMt,19 ),K(KMt, 4  ),K(KMt, 6 ),
  13161. +  K(KMt, 7 ),K(KMt, 8 ),K(KMt,10 ),K(KMt,11  ),K(KMt,12 ),KIGNORE   ,KIGNORE    ,KENTER    ,
  13162. +  KPAD_4    ,KPAD_5    ,KPAD_6    ,KPAD_PL    ,KSHIFT    ,KIGNORE   ,K(KMt,26  ),K(KMt,24 ),
  13163. +  K(KMt, 3 ),K(KMt,22 ),K(KMt, 2 ),K(KMt,14  ),K(KMt,13 ),KIGNORE   ,KIGNORE    ,KIGNORE   ,
  13164. +  KSHIFT    ,K(KTc,Kcu),KPAD_1    ,KPAD_2     ,KPAD_3    ,KCAPSLK   ,KALT       ,KIGNORE   ,
  13165. +  KALTGR    ,KCTRL     ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0    ,KREBOOT    ,KPAD_EN
  13166. +};
  13167. +
  13168. +ushort *key_maps[MAX_NR_KEYMAPS] = {
  13169. +    plain_map, shift_map, altgr_map, 0,
  13170. +    ctrl_map, shift_ctrl_map, 0, 0,
  13171. +    alt_map, 0, 0, 0,
  13172. +    ctrl_alt_map,    0
  13173. +};
  13174. +
  13175. +unsigned int keymap_count = 7;
  13176. +
  13177. +/*
  13178. + * Philosophy: most people do not define more strings, but they who do
  13179. + * often want quite a lot of string space. So, we statically allocate
  13180. + * the default and allocate dynamically in chunks of 512 bytes.
  13181. + */
  13182. +
  13183. +char func_buf[] = {
  13184. +    '\033', '[', '[', 'A', 0,
  13185. +    '\033', '[', '[', 'B', 0,
  13186. +    '\033', '[', '[', 'C', 0,
  13187. +    '\033', '[', '[', 'D', 0,
  13188. +    '\033', '[', '[', 'E', 0,
  13189. +    '\033', '[', '1', '7', '~', 0,
  13190. +    '\033', '[', '1', '8', '~', 0,
  13191. +    '\033', '[', '1', '9', '~', 0,
  13192. +    '\033', '[', '2', '0', '~', 0,
  13193. +    '\033', '[', '2', '1', '~', 0,
  13194. +    '\033', '[', '2', '3', '~', 0,
  13195. +    '\033', '[', '2', '4', '~', 0,
  13196. +    '\033', '[', '2', '5', '~', 0,
  13197. +    '\033', '[', '2', '6', '~', 0,
  13198. +    '\033', '[', '2', '8', '~', 0,
  13199. +    '\033', '[', '2', '9', '~', 0,
  13200. +    '\033', '[', '3', '1', '~', 0,
  13201. +    '\033', '[', '3', '2', '~', 0,
  13202. +    '\033', '[', '3', '3', '~', 0,
  13203. +    '\033', '[', '3', '4', '~', 0,
  13204. +    '\033', '[', '1', '~', 0,
  13205. +    '\033', '[', '2', '~', 0,
  13206. +    '\033', '[', '3', '~', 0,
  13207. +    '\033', '[', '4', '~', 0,
  13208. +    '\033', '[', '5', '~', 0,
  13209. +    '\033', '[', '6', '~', 0,
  13210. +    '\033', '[', 'M', 0,
  13211. +    '\033', '[', 'P', 0,
  13212. +};
  13213. +
  13214. +char *funcbufptr = func_buf;
  13215. +int funcbufsize = sizeof(func_buf);
  13216. +int funcbufleft = 0;          /* space left */
  13217. +
  13218. +char *func_table[MAX_NR_FUNC] = {
  13219. +    func_buf + 0,
  13220. +    func_buf + 5,
  13221. +    func_buf + 10,
  13222. +    func_buf + 15,
  13223. +    func_buf + 20,
  13224. +    func_buf + 25,
  13225. +    func_buf + 31,
  13226. +    func_buf + 37,
  13227. +    func_buf + 43,
  13228. +    func_buf + 49,
  13229. +    func_buf + 55,
  13230. +    func_buf + 61,
  13231. +    func_buf + 67,
  13232. +    func_buf + 73,
  13233. +    func_buf + 79,
  13234. +    func_buf + 85,
  13235. +    func_buf + 91,
  13236. +    func_buf + 97,
  13237. +    func_buf + 103,
  13238. +    func_buf + 109,
  13239. +    func_buf + 115,
  13240. +    func_buf + 120,
  13241. +    func_buf + 125,
  13242. +    func_buf + 130,
  13243. +    func_buf + 135,
  13244. +    func_buf + 140,
  13245. +    func_buf + 145,
  13246. +    0,
  13247. +    0,
  13248. +    func_buf + 149,
  13249. +    0,
  13250. +};
  13251. +
  13252. +struct kbdiacr accent_table[MAX_DIACR] = {
  13253. +    {'`', 'A', '\300'},    {'`', 'a', '\340'},
  13254. +    {'\'', 'A', '\301'},    {'\'', 'a', '\341'},
  13255. +    {'^', 'A', '\302'},    {'^', 'a', '\342'},
  13256. +    {'~', 'A', '\303'},    {'~', 'a', '\343'},
  13257. +    {'"', 'A', '\304'},    {'"', 'a', '\344'},
  13258. +    {'O', 'A', '\305'},    {'o', 'a', '\345'},
  13259. +    {'0', 'A', '\305'},    {'0', 'a', '\345'},
  13260. +    {'A', 'A', '\305'},    {'a', 'a', '\345'},
  13261. +    {'A', 'E', '\306'},    {'a', 'e', '\346'},
  13262. +    {',', 'C', '\307'},    {',', 'c', '\347'},
  13263. +    {'`', 'E', '\310'},    {'`', 'e', '\350'},
  13264. +    {'\'', 'E', '\311'},    {'\'', 'e', '\351'},
  13265. +    {'^', 'E', '\312'},    {'^', 'e', '\352'},
  13266. +    {'"', 'E', '\313'},    {'"', 'e', '\353'},
  13267. +    {'`', 'I', '\314'},    {'`', 'i', '\354'},
  13268. +    {'\'', 'I', '\315'},    {'\'', 'i', '\355'},
  13269. +    {'^', 'I', '\316'},    {'^', 'i', '\356'},
  13270. +    {'"', 'I', '\317'},    {'"', 'i', '\357'},
  13271. +    {'-', 'D', '\320'},    {'-', 'd', '\360'},
  13272. +    {'~', 'N', '\321'},    {'~', 'n', '\361'},
  13273. +    {'`', 'O', '\322'},    {'`', 'o', '\362'},
  13274. +    {'\'', 'O', '\323'},    {'\'', 'o', '\363'},
  13275. +    {'^', 'O', '\324'},    {'^', 'o', '\364'},
  13276. +    {'~', 'O', '\325'},    {'~', 'o', '\365'},
  13277. +    {'"', 'O', '\326'},    {'"', 'o', '\366'},
  13278. +    {'/', 'O', '\330'},    {'/', 'o', '\370'},
  13279. +    {'`', 'U', '\331'},    {'`', 'u', '\371'},
  13280. +    {'\'', 'U', '\332'},    {'\'', 'u', '\372'},
  13281. +    {'^', 'U', '\333'},    {'^', 'u', '\373'},
  13282. +    {'"', 'U', '\334'},    {'"', 'u', '\374'},
  13283. +    {'\'', 'Y', '\335'},    {'\'', 'y', '\375'},
  13284. +    {'T', 'H', '\336'},    {'t', 'h', '\376'},
  13285. +    {'s', 's', '\337'},    {'"', 'y', '\377'},
  13286. +    {'s', 'z', '\337'},    {'i', 'j', '\377'},
  13287. +};
  13288. +
  13289. +unsigned int accent_table_size = 68;
  13290. diff -urNwbB linux/arch/arm/drivers/char/diacr.h linux.arm/arch/arm/drivers/char/diacr.h
  13291. --- linux/arch/arm/drivers/char/diacr.h    Thu Jan  1 01:00:00 1970
  13292. +++ linux.arm/arch/arm/drivers/char/diacr.h    Sun Feb 11 19:43:56 1996
  13293. @@ -0,0 +1,8 @@
  13294. +#ifndef _DIACR_H
  13295. +#define _DIACR_H
  13296. +#include <linux/kd.h>
  13297. +
  13298. +extern struct kbdiacr accent_table[];
  13299. +extern unsigned int accent_table_size;
  13300. +
  13301. +#endif /* _DIACR_H */
  13302. diff -urNwbB linux/arch/arm/drivers/char/iic.c linux.arm/arch/arm/drivers/char/iic.c
  13303. --- linux/arch/arm/drivers/char/iic.c    Thu Jan  1 01:00:00 1970
  13304. +++ linux.arm/arch/arm/drivers/char/iic.c    Sun Mar  3 12:33:06 1996
  13305. @@ -0,0 +1,137 @@
  13306. +/*
  13307. + * linux/arch/arm/drivers/char/iic.c
  13308. + *
  13309. + * Copyright (C) 1995, 1996 Russell King
  13310. + *
  13311. + * IIC is used to get the current time from the CMOS rtc.
  13312. + */
  13313. +
  13314. +#include <asm/system.h>
  13315. +#include <asm/delay.h>
  13316. +#include <asm/io.h>
  13317. +
  13318. +extern unsigned char volatile *const ioc;
  13319. +
  13320. +#define DELAY udelay(10)
  13321. +
  13322. +static void iic_start (void)
  13323. +{
  13324. +    unsigned char out;
  13325. +
  13326. +    out = ioc[0] | 0xc2;
  13327. +
  13328. +    ioc[0] = out;
  13329. +    DELAY;
  13330. +
  13331. +    ioc[0] = out ^ 1;
  13332. +    DELAY;
  13333. +}
  13334. +
  13335. +static void iic_stop (void)
  13336. +{
  13337. +    unsigned char out;
  13338. +
  13339. +    out = ioc[0] | 0xc3;
  13340. +
  13341. +    DELAY;
  13342. +    ioc[0] = out ^ 1;
  13343. +
  13344. +    DELAY;
  13345. +    ioc[0] = out;
  13346. +}
  13347. +
  13348. +static int iic_sendbyte (unsigned char b)
  13349. +{
  13350. +    unsigned char out, in;
  13351. +    int i;
  13352. +
  13353. +    out = (ioc[0] & 0xFC) | 0xC0;
  13354. +
  13355. +    ioc[0] = out;
  13356. +    for (i = 7; i >= 0; i--) {
  13357. +    ioc[0] = out | ((b & (1 << i)) ? 1 : 0);
  13358. +    DELAY;
  13359. +
  13360. +    ioc[0] = out | ((b & (1 << i)) ? 1 : 0) | 2;
  13361. +    DELAY;
  13362. +
  13363. +    ioc[0] = out | ((b & (1 << i)) ? 1 : 0);
  13364. +    }
  13365. +    ioc[0] = out | 1;
  13366. +    DELAY;
  13367. +
  13368. +    ioc[0] = out | 3;
  13369. +    DELAY;
  13370. +
  13371. +    in = ioc[0] & 1;
  13372. +
  13373. +    ioc[0] = out | 1;
  13374. +    DELAY;
  13375. +
  13376. +    ioc[0] = out;
  13377. +    DELAY;
  13378. +
  13379. +    if(in) {
  13380. +    printk("No acknowledge from RTC\n");
  13381. +    return 1;
  13382. +    } else
  13383. +    return 0;
  13384. +}
  13385. +
  13386. +static unsigned char iic_recvbyte (void)
  13387. +{
  13388. +    unsigned char out, in;
  13389. +    int i;
  13390. +
  13391. +    out = (ioc[0] & 0xFC) | 0xC0;
  13392. +
  13393. +    ioc[0] = out;
  13394. +    in = 0;
  13395. +    for (i = 7; i >= 0; i--) {
  13396. +    ioc[0] = out | 1;
  13397. +    DELAY;
  13398. +
  13399. +    ioc[0] = out | 3;
  13400. +    DELAY;
  13401. +
  13402. +    in = (in << 1) | (ioc[0] & 1);
  13403. +    ioc[0] = out | 1;
  13404. +    DELAY;
  13405. +    }
  13406. +    ioc[0] = out;
  13407. +    DELAY;
  13408. +
  13409. +    ioc[0] = out | 2;
  13410. +    DELAY;
  13411. +
  13412. +    return in;
  13413. +}
  13414. +
  13415. +void iic_control (unsigned char addr, unsigned char loc, unsigned char *buf, int len)
  13416. +{
  13417. +    iic_start();
  13418. +
  13419. +    if (iic_sendbyte(addr & 0xfe))
  13420. +    goto error;
  13421. +
  13422. +    if (iic_sendbyte(loc))
  13423. +    goto error;
  13424. +
  13425. +    if (addr & 1) {
  13426. +    int i;
  13427. +
  13428. +    for (i = 0; i < len; i++)
  13429. +        if (iic_sendbyte (buf[i]))
  13430. +        break;
  13431. +    } else {
  13432. +    int i;
  13433. +
  13434. +    iic_stop();
  13435. +    iic_start();
  13436. +    iic_sendbyte(addr|1);
  13437. +    for (i = 0; i < len; i++)
  13438. +        buf[i] = iic_recvbyte ();
  13439. +    }
  13440. +error:
  13441. +    iic_stop();
  13442. +}
  13443. diff -urNwbB linux/arch/arm/drivers/char/kbdmouse.c linux.arm/arch/arm/drivers/char/kbdmouse.c
  13444. --- linux/arch/arm/drivers/char/kbdmouse.c    Thu Jan  1 01:00:00 1970
  13445. +++ linux.arm/arch/arm/drivers/char/kbdmouse.c    Sun Mar  3 12:39:09 1996
  13446. @@ -0,0 +1,188 @@
  13447. +/*
  13448. + * linux/arch/arm/drivers/char/kbdmouse.c
  13449. + *
  13450. + * Copyright (C) 1995, 1996 Russell King
  13451. + *
  13452. + * Medium-level interface for quadrature mouse connected to the keyboard.
  13453. + */
  13454. +
  13455. +#ifdef MODULE
  13456. +#include <linux/module.h>
  13457. +#include <linux/version.h>
  13458. +
  13459. +char kernel_version[] = UTS_RELEASE;
  13460. +#define arch_mouse_init init_module
  13461. +#else
  13462. +#define MOD_INC_USE_COUNT
  13463. +#define MOD_DEC_USE_COUNT
  13464. +#endif
  13465. +
  13466. +#include <linux/config.h>
  13467. +#include <linux/kernel.h>
  13468. +#include <linux/sched.h>
  13469. +#include <linux/signal.h>
  13470. +#include <linux/errno.h>
  13471. +#include <linux/mm.h>
  13472. +#include <linux/mouse.h>
  13473. +#include <linux/random.h>
  13474. +
  13475. +#include <asm/system.h>
  13476. +#include <asm/segment.h>
  13477. +
  13478. +char   mouse_buttons;
  13479. +int    mouse_dxpos;
  13480. +int    mouse_dypos;
  13481. +int    mouse_present;
  13482. +char   mouse_ready;
  13483. +char   mouse_active;
  13484. +struct wait_queue *mouse_wait;
  13485. +struct fasync_struct *fasyncptr;
  13486. +
  13487. +static int fasync_mouse(struct inode *inode, struct file *filp, int on)
  13488. +{
  13489. +    int retval;
  13490. +
  13491. +    retval = fasync_helper(inode, filp, on, &fasyncptr);
  13492. +    if (retval < 0)
  13493. +    return retval;
  13494. +    return 0;
  13495. +}
  13496. +
  13497. +static void close_mouse(struct inode *inode, struct file *file)
  13498. +{
  13499. +    fasync_mouse (inode, file, 0);
  13500. +    if (--mouse_active)
  13501. +    return;
  13502. +    mouse_ready = 0;
  13503. +
  13504. +    MOD_DEC_USE_COUNT;
  13505. +}
  13506. +
  13507. +static int open_mouse(struct inode *inode,struct file *file)
  13508. +{
  13509. +    unsigned long flags;
  13510. +
  13511. +    if (!mouse_present)
  13512. +    return -EINVAL;
  13513. +    if (mouse_active++)
  13514. +    return 0;
  13515. +
  13516. +    save_flags (flags);
  13517. +    cli ();
  13518. +    mouse_active  = 1;
  13519. +    mouse_ready   = 0;
  13520. +    mouse_dxpos   = 0;
  13521. +    mouse_dypos   = 0;
  13522. +    mouse_buttons = 0;
  13523. +    restore_flags (flags);
  13524. +
  13525. +    MOD_INC_USE_COUNT;
  13526. +
  13527. +    return 0;
  13528. +}
  13529. +
  13530. +static int write_mouse(struct inode *inode,struct file *file,const char *buffer,int count)
  13531. +{
  13532. +    return -EINVAL;
  13533. +}
  13534. +
  13535. +static int read_mouse(struct inode *inode,struct file *file,char *buffer,int count)
  13536. +{
  13537. +    unsigned long flags;
  13538. +    int dxpos, dypos, i, buttons;
  13539. +
  13540. +    if (count < 3)
  13541. +    return -EINVAL;
  13542. +    if ((i = verify_area(VERIFY_WRITE, buffer, count)))
  13543. +    return i;
  13544. +    if (!mouse_ready)
  13545. +    return -EAGAIN;
  13546. +
  13547. +    save_flags (flags);
  13548. +    cli ();
  13549. +
  13550. +    dxpos = mouse_dxpos;
  13551. +    dypos = mouse_dypos;
  13552. +    buttons = mouse_buttons ^ 7;
  13553. +
  13554. +    if (dxpos < -127)
  13555. +    dxpos =- 127;
  13556. +    if (dxpos > 127)
  13557. +    dxpos = 127;
  13558. +    if (dypos <- 127)
  13559. +    dypos =- 127;
  13560. +    if (dypos > 127)
  13561. +    dypos = 127;
  13562. +
  13563. +    mouse_dxpos -= dxpos;
  13564. +    mouse_dypos -= dypos;
  13565. +    mouse_ready = 0;
  13566. +
  13567. +    restore_flags (flags);
  13568. +
  13569. +    put_fs_byte ((char) buttons | 0x80, buffer);
  13570. +    put_fs_byte ((char) dxpos, buffer + 1);
  13571. +    put_fs_byte ((char) dypos, buffer + 2);
  13572. +    for(i = 3; i < count; i++)
  13573. +    put_fs_byte (0x00, buffer + i);
  13574. +
  13575. +    return i;
  13576. +}
  13577. +
  13578. +static int select_mouse(struct inode *inode,struct file *file,int sel_type,select_table *wait)
  13579. +{
  13580. +    if (sel_type == SEL_IN) {
  13581. +    if (mouse_ready)
  13582. +        return 1;
  13583. +    select_wait (&mouse_wait,wait);
  13584. +    }
  13585. +    return 0;
  13586. +}
  13587. +
  13588. +struct file_operations kbd_mouse_fops=
  13589. +{
  13590. +    NULL,            /* mouse_seek */
  13591. +    read_mouse,
  13592. +    write_mouse,
  13593. +    NULL,            /* mouse_readdir */
  13594. +    select_mouse,
  13595. +    NULL,            /* mouse_ioctl */
  13596. +    NULL,            /* mouse_mmap */
  13597. +    open_mouse,
  13598. +    close_mouse,
  13599. +    NULL,
  13600. +    fasync_mouse,
  13601. +};
  13602. +
  13603. +static struct mouse kbd_mouse = {
  13604. +    4, "kbdmouse", &kbd_mouse_fops
  13605. +};
  13606. +
  13607. +int arch_mouse_init(void)
  13608. +{
  13609. +    unsigned long flags;
  13610. +
  13611. +    save_flags (flags);
  13612. +    cli ();
  13613. +
  13614. +    mouse_buttons=0;
  13615. +    mouse_dxpos  =0;
  13616. +    mouse_dypos  =0;
  13617. +    mouse_present=1;
  13618. +    mouse_ready  =0;
  13619. +    mouse_active =0;
  13620. +    mouse_wait   =NULL;
  13621. +
  13622. +    restore_flags (flags);
  13623. +    mouse_register (&kbd_mouse);
  13624. +    return 0;
  13625. +}
  13626. +
  13627. +#ifdef MODULE
  13628. +void cleanup_module(void)
  13629. +{
  13630. +    if (MOD_IN_USE)
  13631. +    printk ("kcdmouse: in use - remove delayed\n");
  13632. +    mouse_deregister (&kbd_mouse);
  13633. +}
  13634. +#endif
  13635. diff -urNwbB linux/arch/arm/drivers/char/keyboard.c linux.arm/arch/arm/drivers/char/keyboard.c
  13636. --- linux/arch/arm/drivers/char/keyboard.c    Thu Jan  1 01:00:00 1970
  13637. +++ linux.arm/arch/arm/drivers/char/keyboard.c    Sun Mar  3 12:39:34 1996
  13638. @@ -0,0 +1,1302 @@
  13639. +/*
  13640. + * linux/arch/arm/drivers/block/keyboard.c
  13641. + *
  13642. + * Keyboard driver for Linux using Latin-1.
  13643. + *
  13644. + * Written for linux by Johan Myreen as a translation from
  13645. + * the assembly version by Linus (with diacriticals added)
  13646. + *
  13647. + * Some additional features added by Christoph Niemann (ChN), March 1993
  13648. + *
  13649. + * Loadable keymaps by Risto Kankkunen, May 1993
  13650. + *
  13651. + * Diacriticals redone & other small changes, aeb@cwi.nl, June 93
  13652. + * Added decr/incr_console, dynamic keymaps, unicode support,
  13653. + * dynamic function/string keys, led setting,  Sept 1994
  13654. + * `Sticky' modifier keys, 951006
  13655. + *
  13656. + * Majorly altered for use with arm Russell King (rmk92@ecs.soton.ac.uk).
  13657. + */
  13658. +
  13659. +#define IRQ_KEYBOARDRX 15
  13660. +#define IRQ_KEYBOARDTX 14
  13661. +
  13662. +#define VERSION 102
  13663. +
  13664. +#include <linux/config.h>
  13665. +#include <linux/sched.h>
  13666. +#include <linux/interrupt.h>
  13667. +#include <linux/tty.h>
  13668. +#include <linux/tty_flip.h>
  13669. +#include <linux/mm.h>
  13670. +#include <linux/ptrace.h>
  13671. +#include <linux/signal.h>
  13672. +#include <linux/timer.h>
  13673. +#include <linux/random.h>
  13674. +#include <linux/ctype.h>
  13675. +
  13676. +#include <asm/bitops.h>
  13677. +#include <asm/irq.h>
  13678. +
  13679. +#include "kbd_kern.h"
  13680. +#include "diacr.h"
  13681. +#include "vt_kern.h"
  13682. +
  13683. +#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
  13684. +
  13685. +#define KBD_REPORT_ERR
  13686. +#define KBD_REPORT_UNKN
  13687. +
  13688. +#ifndef KBD_DEFMODE
  13689. +#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
  13690. +#endif
  13691. +
  13692. +#ifndef KBD_DEFLEDS
  13693. +/*
  13694. + * Starts with NumLock off.
  13695. + */
  13696. +#define KBD_DEFLEDS 0
  13697. +#endif
  13698. +
  13699. +#ifndef KBD_DEFLOCK
  13700. +#define KBD_DEFLOCK 0
  13701. +#endif
  13702. +
  13703. +#define REPEAT_TIMEOUT HZ*300/1000
  13704. +#define REPEAT_RATE    HZ*30/1000
  13705. +
  13706. +extern void poke_blanked_console (void);
  13707. +extern void ctrl_alt_del (void);
  13708. +extern void reset_vc (unsigned int new_console);
  13709. +extern void change_console (unsigned int console);
  13710. +
  13711. +/*
  13712. + * global state includes the following, and various static variables
  13713. + * in this module: shift_state, diacr, npadch, dead_key_next.
  13714. + * (last console is now a global variable).
  13715. + */
  13716. +
  13717. +/* shift state counters.. */
  13718. +static unsigned char k_down[NR_SHIFT] = {0, };
  13719. +/*
  13720. + * Key down counters
  13721. + */
  13722. +#define BITS_PER_SHORT (8*sizeof (unsigned short))
  13723. +static unsigned short key_down[256/BITS_PER_SHORT] = {0, };
  13724. +
  13725. +extern int last_console;
  13726. +static int want_console    = -1;
  13727. +static int dead_key_next   = 0;
  13728. +/*
  13729. + * In order to retrieve the shift_state (for the mouse server), either
  13730. + * the variable must be global, or a new procedure must be created to
  13731. + * return the value. I chose the former way.
  13732. + */
  13733. +/*static*/ int shift_state   = 0;
  13734. +static int npadch            = -1;        /* -1 or number assembled on pad */
  13735. +static unsigned char diacr   = 0;
  13736. +static char rep              = 0;        /* Flag telling character repeat */
  13737. +static int kbd_repeatkey     = -1;
  13738. +static int kbd_repeattimeout = REPEAT_TIMEOUT;
  13739. +static int kbd_repeatrate    = REPEAT_RATE;
  13740. +
  13741. +struct kbd_struct kbd_table[MAX_NR_CONSOLES];
  13742. +static struct tty_struct **ttytab;
  13743. +static struct kbd_struct * kbd = kbd_table;
  13744. +static struct tty_struct * tty = NULL;
  13745. +
  13746. +extern void compute_shiftstate (void);
  13747. +
  13748. +typedef void (*k_hand)(unsigned char value, char up_flag);
  13749. +typedef void (k_handfn)(unsigned char value, char up_flag);
  13750. +
  13751. +static k_handfn
  13752. +    do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
  13753. +    do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
  13754. +
  13755. +static k_hand key_handler[16] = {
  13756. +    do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
  13757. +    do_meta, do_ascii, do_lock, do_lowercase, do_slock,
  13758. +    do_ignore, do_ignore, do_ignore
  13759. +};
  13760. +
  13761. +typedef void (*void_fnp)(void);
  13762. +typedef void (void_fn)(void);
  13763. +
  13764. +static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
  13765. +    num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
  13766. +    SAK, decr_console, incr_console, spawn_console, show_stack, bare_num;
  13767. +
  13768. +static void_fnp spec_fn_table[] = {
  13769. +    do_null,    enter,        show_ptregs,    show_mem,
  13770. +    show_state,    send_intr,    lastcons,    caps_toggle,
  13771. +    num,        hold,        scroll_forw,    scroll_back,
  13772. +    boot_it,    caps_on,    compose,    SAK,
  13773. +    decr_console,    incr_console,    show_stack,     bare_num
  13774. +};
  13775. +
  13776. +/* maximum values each key_handler can handle */
  13777. +const int max_vals[] = {
  13778. +    255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
  13779. +    NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
  13780. +    255, NR_ASCII - 1, NR_LOCK - 1, 255,
  13781. +    NR_LOCK - 1
  13782. +};
  13783. +
  13784. +const int NR_TYPES = SIZE(max_vals);
  13785. +
  13786. +static void put_queue(int);
  13787. +static unsigned char handle_diacr(unsigned char);
  13788. +
  13789. +/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
  13790. +static struct pt_regs * pt_regs;
  13791. +
  13792. +/*
  13793. + * Many other routines do put_queue, but I think either
  13794. + * they produce ASCII, or they produce some user-assigned
  13795. + * string, and in both cases we might assume that it is
  13796. + * in utf-8 already.
  13797. + */
  13798. +void to_utf8(ushort c) {
  13799. +    if (c < 0x80)
  13800. +    put_queue(c);            /*  0*******  */
  13801. +    else if (c < 0x800) {
  13802. +    put_queue(0xc0 | (c >> 6));     /*  110***** 10******  */
  13803. +    put_queue(0x80 | (c & 0x3f));
  13804. +    } else {
  13805. +    put_queue(0xe0 | (c >> 12));     /*  1110**** 10****** 10******  */
  13806. +    put_queue(0x80 | ((c >> 6) & 0x3f));
  13807. +    put_queue(0x80 | (c & 0x3f));
  13808. +    }
  13809. +     /* uft-8 is defined for words of up to 36 bits,
  13810. +       but we need only 16 bits here */
  13811. +}
  13812. +
  13813. +/*
  13814. + * ARM mouse specifics stuff.
  13815. + *
  13816. + * Since the mouse movements and buttons are part of the
  13817. + * keyboard protocol, we have to handle this part in this
  13818. + * driver.  The mouse specific parts are in arcmouse.c.
  13819. + */
  13820. +#ifdef CONFIG_KBDMOUSE
  13821. +extern struct wait_queue *mouse_wait;
  13822. +extern char        mouse_buttons;
  13823. +extern int        mouse_dxpos;
  13824. +extern int        mouse_dypos;
  13825. +extern char        mouse_ready;
  13826. +#endif
  13827. +/*
  13828. + * Protocol codes to send the keyboard.
  13829. + */
  13830. +/* reset keyboard */
  13831. +#define HRST 0xff
  13832. +/* reset response */
  13833. +#define RAK1 0xfe
  13834. +/* reset response */
  13835. +#define RAK2 0xfd
  13836. +/* Ack for first keyboard pair */
  13837. +#define BACK 0x3f
  13838. +/* Last data byte ack (key scanning + mouse movement scanning) */
  13839. +#define SMAK 0x33
  13840. +/* Last data byte ack (mouse movement scanning) */
  13841. +#define MACK 0x32
  13842. +/* Last data byte ack (key scanning) */
  13843. +#define SACK 0x31
  13844. +/* Request mouse data */
  13845. +#define RQMP 0x22
  13846. +/* nothing */
  13847. +#define PRST 0x21
  13848. +/* Request ID */
  13849. +#define RQID 0x20
  13850. +
  13851. +#define UP_FLAG 0x0100
  13852. +
  13853. +static unsigned char    kbd_sendvala[4];
  13854. +static unsigned char    kbd_sendptri;
  13855. +static unsigned char    kbd_sendptro;
  13856. +static unsigned char    ledstate = 0xff;
  13857. +static unsigned char getleds(void);
  13858. +extern unsigned char    *ioc;
  13859. +
  13860. +/*
  13861. + * This array converts the scancode that we get from the keyboard to the
  13862. + * real rows/columns on the A5000 keyboard.  This might be keyboard specific...
  13863. + *
  13864. + * It is these values that we use to maintain the key down array.  That way, we
  13865. + * should pick up on the ghost key presses (which is what happens when you press
  13866. + * three keys, and the keyboard thinks you have pressed four!)
  13867. + *
  13868. + * Row 8 (0x80+c) is actually a column with one key per row.  It is isolated from
  13869. + * the other keys, and can't cause these problems (its used for shift, ctrl, alt etc).
  13870. + *
  13871. + * Illegal scancodes are denoted by an 0xff (in other words, we don't know about
  13872. + * them, and can't process them for ghosts).  This does however, cause problems with
  13873. + * autorepeat processing...
  13874. + */
  13875. +static unsigned char scancode_2_colrow[256] = {
  13876. +  0x01, 0x42, 0x32, 0x33, 0x43, 0x56, 0x5a, 0x6c, 0x7c, 0x5c, 0x5b, 0x6b, 0x7b, 0x84, 0x70, 0x60,
  13877. +  0x11, 0x51, 0x62, 0x63, 0x44, 0x54, 0x55, 0x45, 0x46, 0x4a, 0x3c, 0x4b, 0x59, 0x49, 0x69, 0x79,
  13878. +  0x83, 0x40, 0x30, 0x3b, 0x39, 0x38, 0x31, 0x61, 0x72, 0x73, 0x64, 0x74, 0x75, 0x65, 0x66, 0x6a,
  13879. +  0x1c, 0x2c, 0x7a, 0x36, 0x48, 0x68, 0x78, 0x20, 0x2b, 0x29, 0x28, 0x81, 0x71, 0x22, 0x23, 0x34,
  13880. +  0x24, 0x25, 0x35, 0x26, 0x3a, 0x0c, 0x2a, 0x76, 0x10, 0x1b, 0x19, 0x18, 0x82, 0xff, 0x21, 0x12,
  13881. +  0x13, 0x14, 0x04, 0x05, 0x15, 0x16, 0x1a, 0x0a, 0x85, 0x77, 0x00, 0x0b, 0x09, 0x02, 0x80, 0x03,
  13882. +  0x87, 0x86, 0x06, 0x17, 0x27, 0x07, 0x37, 0x08, 0xff,
  13883. +};
  13884. +
  13885. +static unsigned short ghost_down[128/BITS_PER_SHORT];
  13886. +
  13887. +/*
  13888. + * As yet, we don't support setting and getting the
  13889. + * key codes.  I'll have to find out where this is used.
  13890. + */
  13891. +int setkeycode(unsigned int scancode, unsigned int keycode)
  13892. +{
  13893. +#if 0
  13894. +    if (scancode < SC_LIM || scancode > 255 || keycode > 127)
  13895. +        return -EINVAL;
  13896. +    if (scancode < 128)
  13897. +        high_keys[scancode - SC_LIM] = keycode;
  13898. +    else
  13899. +        e0_keys[scancode - 128] = keycode;
  13900. +    return 0;
  13901. +#else
  13902. +    return -EINVAL;
  13903. +#endif
  13904. +}
  13905. +
  13906. +int getkeycode(unsigned int scancode)
  13907. +{
  13908. +#if 0
  13909. +    return
  13910. +        (scancode < SC_LIM || scancode > 255) ? -EINVAL :
  13911. +        (scancode < 128) ? high_keys[scancode - SC_LIM] :
  13912. +        e0_keys[scancode - 128];
  13913. +#else
  13914. +    return -EINVAL;
  13915. +#endif
  13916. +}
  13917. +
  13918. +
  13919. +/* ----------------------------------------------------------------------------------------- */
  13920. +/*
  13921. + * This is the keyboard specific part.
  13922. + */
  13923. +static void key_callback(unsigned long nr)
  13924. +{
  13925. +  rep = 1;
  13926. +  mark_bh (KEYBOARD_BH);
  13927. +}
  13928. +
  13929. +static struct timer_list key_timer =
  13930. +{
  13931. +  NULL, NULL, 0, 0, key_callback
  13932. +};
  13933. +
  13934. +static void kbd_key(unsigned int raw_keycode, int repeat_timeout)
  13935. +{
  13936. +    unsigned int up_flag;
  13937. +    unsigned int keycode;
  13938. +    unsigned char real_keycode;
  13939. +
  13940. +    up_flag = raw_keycode & UP_FLAG;
  13941. +    keycode = raw_keycode & 255;
  13942. +
  13943. +    /*
  13944. +     * Separate out the mouse stuff first
  13945. +     */
  13946. +    if (keycode >= 0x70 && keycode <= 0x72) {
  13947. +#ifdef CONFIG_KBDMOUSE
  13948. +    switch (keycode) {
  13949. +    case 0x70: /* Left mouse button */
  13950. +        if (up_flag)
  13951. +        mouse_buttons &= ~4;
  13952. +        else
  13953. +        mouse_buttons |= 4;
  13954. +        break;
  13955. +
  13956. +    case 0x71: /* Middle mouse button */
  13957. +        if (up_flag)
  13958. +        mouse_buttons &= ~2;
  13959. +        else
  13960. +        mouse_buttons |= 2;
  13961. +        break;
  13962. +
  13963. +    case 0x72:/* Right mouse button */
  13964. +        if (up_flag)
  13965. +        mouse_buttons &= ~1;
  13966. +        else
  13967. +        mouse_buttons |= 1;
  13968. +        break;
  13969. +    default:
  13970. +#ifdef KBD_REPORT_UNKN
  13971. +        printk ("kbd: unknown scancode 0x%04x\n", raw_keycode);
  13972. +#endif
  13973. +        return;
  13974. +    }
  13975. +    add_mouse_randomness (mouse_buttons << 16);
  13976. +    mouse_ready = 1;
  13977. +    wake_up_interruptible (&mouse_wait);
  13978. +#endif
  13979. +    mark_bh (KEYBOARD_BH);
  13980. +    return;
  13981. +    }
  13982. +
  13983. +    if (keycode >= 0x70) {
  13984. +#ifdef KBD_REPORT_UNKN
  13985. +    printk ("kbd: unknown scancode 0x%04x\n", raw_keycode);
  13986. +#endif
  13987. +    return;
  13988. +    }
  13989. +
  13990. +    real_keycode = scancode_2_colrow[keycode];
  13991. +
  13992. +    /*
  13993. +     * We have to work out if we accept this key press as a real key, or
  13994. +     * if it is a ghost.  IE. If you press three keys, the keyboard will think
  13995. +     * that you've pressed a fouth: (@ = key down, # = ghost)
  13996. +     *
  13997. +     *   0 1 2 3 4 5 6 7
  13998. +     *   | | | | | | | |
  13999. +     * 0-+-+-+-+-+-+-+-+-
  14000. +     *   | | | | | | | |
  14001. +     * 1-+-@-+-+-+-@-+-+-
  14002. +     *   | | | | | | | |
  14003. +     * 2-+-+-+-+-+-+-+-+-
  14004. +     *   | | | | | | | |
  14005. +     * 3-+-@-+-+-+-#-+-+-
  14006. +     *   | | | | | | | |
  14007. +     *
  14008. +     * This is what happens when you have a matrix keyboard...
  14009. +     */
  14010. +
  14011. +    if ((real_keycode & 0x80) == 0) {
  14012. +    int rr, kc = (real_keycode >> 4) & 7;
  14013. +    int cc;
  14014. +    unsigned short res, kdownkc;
  14015. +
  14016. +    kdownkc = ghost_down[kc] | (1 << (real_keycode & 15));
  14017. +
  14018. +    for (rr = 0; rr < 128/BITS_PER_SHORT; rr++)
  14019. +        if (rr != kc && (res = ghost_down[rr] & kdownkc)) {
  14020. +            /*
  14021. +         * we have found a second row with at least one key pressed in the
  14022. +             * same column.
  14023. +             */
  14024. +            for (cc = 0; res; res >>= 1)
  14025. +            cc += (res & 1);
  14026. +
  14027. +        if (cc > 1)
  14028. +            return; /* ignore it */
  14029. +        }
  14030. +    if (up_flag)
  14031. +        clear_bit (real_keycode, ghost_down);
  14032. +    else
  14033. +        set_bit (real_keycode, ghost_down);
  14034. +
  14035. +    }
  14036. +
  14037. +    if (kbd_repeatkey == (raw_keycode & ~UP_FLAG) || !up_flag)
  14038. +    kbd_repeatkey = -1;
  14039. +
  14040. +    add_keyboard_randomness (raw_keycode);
  14041. +
  14042. +    /*
  14043. +     * We have to disable interrupts here to prevent the timer from
  14044. +     * being put on the list twice or a key being released during
  14045. +     * the processing of autorepeat
  14046. +     */
  14047. +    del_timer (&key_timer);
  14048. +
  14049. +    tty = ttytab[fg_console];
  14050. +    kbd = kbd_table + fg_console;
  14051. +
  14052. +    if (up_flag) {
  14053. +        rep = 0;
  14054. +    clear_bit (keycode, key_down);
  14055. +    /* don't report an error if key is already up - happens when a ghost key is released */
  14056. +    } else
  14057. +    rep = set_bit (keycode, key_down);
  14058. +
  14059. +    if (kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) {
  14060. +    put_queue (keycode | (up_flag ? 0x80 : 0));
  14061. +    return;
  14062. +    }
  14063. +
  14064. +    /*
  14065. +     * We have to do our own auto-repeat processing...
  14066. +     */
  14067. +    if (!up_flag && repeat_timeout) {
  14068. +        kbd_repeatkey = raw_keycode;
  14069. +    if (vc_kbd_mode(kbd, VC_REPEAT)) {
  14070. +        key_timer.expires = jiffies + repeat_timeout;
  14071. +        add_timer(&key_timer);
  14072. +    }
  14073. +    }
  14074. +
  14075. +    /*
  14076. +     * Repeat a key only if the input buffers are empty or the
  14077. +     * characters get echoed locally.  This makes key repeat
  14078. +     * usable with slow applications and under heavy loads.
  14079. +     */
  14080. +    if (!rep || (vc_kbd_mode (kbd, VC_REPEAT) && tty &&
  14081. +               (L_ECHO(tty) || (tty->driver.chars_in_buffer (tty) == 0)))) {
  14082. +    u_short keysym;
  14083. +    u_char  type;
  14084. +
  14085. +    /* the XOR below used to be an OR */
  14086. +    int     shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
  14087. +    u_short *key_map = key_maps[shift_final];
  14088. +
  14089. +    if (key_map != NULL) {
  14090. +        keysym = key_map[keycode];
  14091. +        type   = KTYP(keysym);
  14092. +
  14093. +        if (type >= 0xf0) {
  14094. +        type -= 0xf0;
  14095. +
  14096. +        if (type == KT_LETTER) {
  14097. +            type = KT_LATIN;
  14098. +            if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
  14099. +            key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
  14100. +            if (key_map)
  14101. +                keysym = key_map[keycode];
  14102. +            }
  14103. +        }
  14104. +        (*key_handler[type])(keysym & 0xff, up_flag ? 0x80 : 0);
  14105. +        if (type != KT_SLOCK)
  14106. +            kbd->slockstate = 0;
  14107. +        } else {
  14108. +        if (!up_flag)
  14109. +            to_utf8(keysym);
  14110. +        }
  14111. +    } else {
  14112. +        /*
  14113. +         * maybe beep?
  14114. +         * we have at least to update shift_state
  14115. +         * how? two almost equivalent choices follow
  14116. +         */
  14117. +#if 1
  14118. +        compute_shiftstate ();
  14119. +#else
  14120. +        keysym = U(plain_map[keycode]);
  14121. +        type   = KTYP(keysym);
  14122. +        if (type == KT_SHIFT)
  14123. +        (*key_handler[type]) (keysym & 0xff, up_flag ? 0x80 : 0);
  14124. +#endif
  14125. +    }
  14126. +    }
  14127. +}
  14128. +
  14129. +static void kbd_sendval(unsigned char val)
  14130. +{
  14131. +    kbd_sendvala[kbd_sendptri] = val;
  14132. +    kbd_sendptri = (kbd_sendptri + 1) & 3;
  14133. +    disable_irq (15);
  14134. +    enable_irq (14);
  14135. +}
  14136. +
  14137. +static void kbd_reset(void)
  14138. +{
  14139. +    int i;
  14140. +
  14141. +    for (i = 0; i < NR_SHIFT; i++)
  14142. +    k_down[i] = 0;
  14143. +
  14144. +    for (i = 0; i < 256/BITS_PER_SHORT; i++)
  14145. +    key_down[i] = 0;
  14146. +
  14147. +    for (i = 0; i < 128/BITS_PER_SHORT; i++)
  14148. +    ghost_down[i] = 0;
  14149. +
  14150. +    shift_state = 0;
  14151. +}
  14152. +
  14153. +/*
  14154. + * Keyboard states:
  14155. + *  0 initial reset condition, sent HRST, wait for HRST
  14156. + *  1 Sent RAK1, wait for RAK1
  14157. + *  2 Sent RAK2, wait for RAK2
  14158. + *  3 Sent SMAK, wait for *
  14159. + *  4 Wait for second keyboard nibble for key pressed
  14160. + *  5 Wait for second keyboard nibble for key released
  14161. + *  6 Wait for second part of mouse data
  14162. + */
  14163. +
  14164. +static void kbd_rx(int irq, struct pt_regs *regs)
  14165. +{
  14166. +    int keyval;
  14167. +    static char kbd_mousedx=0;
  14168. +    char kbd_mousedy;
  14169. +    static unsigned char kbd_state=0;
  14170. +    static unsigned char kbd_keyhigh=0;
  14171. +
  14172. +    pt_regs = regs;
  14173. +
  14174. +    keyval=ioc[4];
  14175. +
  14176. +    switch(kbd_state) {
  14177. +    case 0:/* initial reset condition */
  14178. +    if (keyval == HRST) {
  14179. +        kbd_reset ();
  14180. +        kbd_sendval (RAK1);
  14181. +        kbd_state = 1;
  14182. +    } else
  14183. +        goto kbd_wontreset;
  14184. +    break;
  14185. +
  14186. +    case 1:/* Sent RAK1 */
  14187. +    if (keyval == RAK1) {
  14188. +        kbd_sendval (RAK2);
  14189. +        kbd_state = 2;
  14190. +    } else
  14191. +        goto kbd_wontreset;
  14192. +    break;
  14193. +
  14194. +    case 2:/* Sent RAK2 */
  14195. +    if (keyval == RAK2) {
  14196. +        kbd_sendval (SMAK);
  14197. +        kbd_state = 3;
  14198. +        ledstate  = 0xff;
  14199. +        mark_bh (KEYBOARD_BH);
  14200. +    } else
  14201. +        goto kbd_wontreset;
  14202. +    break;
  14203. +
  14204. +    case 3:/* Send SMAK, ready for any reply */
  14205. +    if (keyval == HRST) {
  14206. +        kbd_sendval (HRST);
  14207. +        kbd_state = 0;
  14208. +    } else
  14209. +    if (keyval & 0x80) {
  14210. +        switch (keyval & 0xf0) {
  14211. +        case 0xc0:
  14212. +        kbd_keyhigh = keyval;
  14213. +        kbd_state   = 4;
  14214. +        kbd_sendval (BACK);
  14215. +        break;
  14216. +
  14217. +        case 0xd0:
  14218. +        kbd_keyhigh = keyval;
  14219. +        kbd_state   = 5;
  14220. +        kbd_sendval (BACK);
  14221. +        break;
  14222. +
  14223. +        default:
  14224. +        kbd_state = 0;
  14225. +        kbd_sendval (HRST);
  14226. +        }
  14227. +    } else {
  14228. +        kbd_mousedx = keyval & 0x40 ? keyval|0x80 : keyval;
  14229. +        kbd_state   = 6;
  14230. +        kbd_sendval (BACK);
  14231. +    }
  14232. +    break;
  14233. +
  14234. +    case 4:
  14235. +    if ((keyval & 0xf0) != 0xc0)
  14236. +        goto kbd_error;
  14237. +    else {
  14238. +        kbd_state = 3;
  14239. +        kbd_sendval (SMAK);
  14240. +        if (((kbd_keyhigh ^ keyval) & 0xf0) == 0) {
  14241. +        kbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), kbd_repeattimeout);
  14242. +        mark_bh (KEYBOARD_BH);
  14243. +        }
  14244. +    }
  14245. +    break;
  14246. +
  14247. +    case 5:
  14248. +    if ((keyval & 0xf0) != 0xd0)
  14249. +        goto kbd_error;
  14250. +    else {
  14251. +        kbd_state = 3;
  14252. +        kbd_sendval (SMAK);
  14253. +        if (((kbd_keyhigh ^ keyval) & 0xf0) == 0) {
  14254. +        kbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0) | UP_FLAG, 0);
  14255. +        mark_bh (KEYBOARD_BH);
  14256. +        }
  14257. +    }
  14258. +    break;
  14259. +
  14260. +    case 6:
  14261. +    if (keyval & 0x80)
  14262. +        goto kbd_error;
  14263. +    else {
  14264. +        kbd_state = 3;
  14265. +        kbd_sendval (SMAK);
  14266. +        kbd_mousedy = (char)(keyval & 0x40 ? keyval | 0x80 : keyval);
  14267. +#ifdef CONFIG_KBDMOUSE
  14268. +        mouse_dypos += (int)kbd_mousedy;
  14269. +        mouse_dxpos += (int)kbd_mousedx;
  14270. +        add_mouse_randomness ((mouse_buttons << 16) + (kbd_mousedy << 8) + kbd_mousedx);
  14271. +        mouse_ready = 1;
  14272. +        wake_up_interruptible (&mouse_wait);
  14273. +#endif
  14274. +        mark_bh (KEYBOARD_BH);
  14275. +    }
  14276. +    break;
  14277. +    }
  14278. +    return;
  14279. +kbd_wontreset:
  14280. +#ifdef KBD_REPORT_ERR
  14281. +    printk ("kbd: keyboard won't reset\n");
  14282. +#endif
  14283. +    kbd_sendval (HRST);
  14284. +    kbd_state = 0;
  14285. +    return;
  14286. +kbd_error:
  14287. +#ifdef KBD_REPORT_ERR
  14288. +    printk ("kbd: keyboard out of sync - resetting\n");
  14289. +#endif
  14290. +    kbd_sendval (HRST);
  14291. +    kbd_state = 0;
  14292. +    return;
  14293. +}
  14294. +
  14295. +static void kbd_tx(int irq, struct pt_regs *regs)
  14296. +{
  14297. +  if(kbd_sendptri!=kbd_sendptro)
  14298. +  {
  14299. +    ioc[0x04]=kbd_sendvala[kbd_sendptro];
  14300. +    kbd_sendptro=(kbd_sendptro+1)&3;
  14301. +  }
  14302. +  if(kbd_sendptri==kbd_sendptro)
  14303. +  {
  14304. +    disable_irq(14);
  14305. +    enable_irq(15);
  14306. +  }
  14307. +}
  14308. +
  14309. +/* ----------------------------------------------------------------------------------------- */
  14310. +/*
  14311. + * Here starts a copy of the PC keyboard code from linux/drivers/char/keyboard.c
  14312. + */
  14313. +
  14314. +static void put_queue (int ch)
  14315. +{
  14316. +    wake_up (&keypress_wait);
  14317. +    if (tty) {
  14318. +    tty_insert_flip_char (tty, ch, 0);
  14319. +    tty_schedule_flip (tty);
  14320. +    }
  14321. +}
  14322. +
  14323. +static void puts_queue(char *cp)
  14324. +{
  14325. +    wake_up (&keypress_wait);
  14326. +    if (!tty)
  14327. +    return;
  14328. +
  14329. +    while (*cp)
  14330. +    tty_insert_flip_char (tty, *cp++, 0);
  14331. +    tty_schedule_flip (tty);
  14332. +}
  14333. +
  14334. +static void applkey(int key, char mode)
  14335. +{
  14336. +    static char buf[] = { 0x1b, 'O', 0x00, 0x00};
  14337. +
  14338. +    buf[1] = (mode ? 'O' : '[');
  14339. +    buf[2] = key;
  14340. +    puts_queue(buf);
  14341. +}
  14342. +
  14343. +static void enter(void)
  14344. +{
  14345. +    put_queue (13);
  14346. +    if (vc_kbd_mode(kbd, VC_CRLF))
  14347. +    put_queue (10);
  14348. +}
  14349. +
  14350. +static void caps_toggle(void)
  14351. +{
  14352. +    if(rep)
  14353. +    return;
  14354. +    chg_vc_kbd_led(kbd, VC_CAPSLOCK);
  14355. +}
  14356. +
  14357. +static void caps_on (void)
  14358. +{
  14359. +    if (rep)
  14360. +    return;
  14361. +    set_vc_kbd_led (kbd, VC_CAPSLOCK);
  14362. +}
  14363. +
  14364. +static void show_ptregs (void)
  14365. +{
  14366. +    extern void register_dump (struct pt_regs *);
  14367. +    if (pt_regs)
  14368. +    register_dump (pt_regs);
  14369. +}
  14370. +
  14371. +static void show_stack (void)
  14372. +{
  14373. +    unsigned long *p;
  14374. +    unsigned long *q = (unsigned long *)((int)current->kernel_stack_page + 4096);
  14375. +    int i;
  14376. +    __asm__("mov %0, sp\n\t": "=r" (p));
  14377. +
  14378. +    for(i=0; p < q; p++, i++) {
  14379. +    if(i && !(i & 7))
  14380. +        printk("\n");
  14381. +    printk("%08lX ", *p);
  14382. +    }
  14383. +}
  14384. +
  14385. +static void hold (void)
  14386. +{
  14387. +    if(rep || !tty)
  14388. +    return;
  14389. +
  14390. +    /*
  14391. +     * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
  14392. +     * these routines are also activated by ^S/^Q.
  14393. +     * (And SCROLLOCK can also be set by the KDSKBLED.)
  14394. +     */
  14395. +    if (tty->stopped)
  14396. +    start_tty (tty);
  14397. +    else
  14398. +    stop_tty (tty);
  14399. +}
  14400. +
  14401. +static void num (void)
  14402. +{
  14403. +    if(vc_kbd_mode(kbd,VC_APPLIC))
  14404. +    applkey('P', 1);
  14405. +    else
  14406. +        bare_num ();
  14407. +}
  14408. +
  14409. +/*
  14410. + * Bind this to Shift-NumLock if you work in application keypad mode
  14411. + * but want to be able to change the NumLock flag.
  14412. + * Bind this to NumLock if you prefer that the NumLock key always
  14413. + * changes the NumLock flag.
  14414. + */
  14415. +static void bare_num (void)
  14416. +{
  14417. +    if (!rep)
  14418. +    chg_vc_kbd_led (kbd, VC_NUMLOCK);
  14419. +}
  14420. +
  14421. +static void lastcons (void)
  14422. +{
  14423. +    want_console = last_console;
  14424. +}
  14425. +
  14426. +static void decr_console (void)
  14427. +{
  14428. +    int i;
  14429. +
  14430. +    for (i = fg_console - 1; i != fg_console; i--) {
  14431. +    if (i == -1)
  14432. +        i = MAX_NR_CONSOLES - 1;
  14433. +    if (vc_cons_allocated (i))
  14434. +        break;
  14435. +    }
  14436. +    want_console = i;
  14437. +}
  14438. +
  14439. +static void incr_console (void)
  14440. +{
  14441. +    int i;
  14442. +
  14443. +    for (i = fg_console + 1; i != fg_console; i++) {
  14444. +    if (i == MAX_NR_CONSOLES)
  14445. +        i = 0;
  14446. +    if (vc_cons_allocated (i))
  14447. +        break;
  14448. +    }
  14449. +    want_console = i;
  14450. +}
  14451. +
  14452. +static void send_intr (void)
  14453. +{
  14454. +    if (!tty)
  14455. +    return;
  14456. +    tty_insert_flip_char (tty, 0, TTY_BREAK);
  14457. +    tty_schedule_flip (tty);
  14458. +}
  14459. +
  14460. +static void scroll_forw (void)
  14461. +{
  14462. +}
  14463. +
  14464. +static void scroll_back (void)
  14465. +{
  14466. +}
  14467. +
  14468. +static void boot_it (void)
  14469. +{
  14470. +    ctrl_alt_del();
  14471. +}
  14472. +
  14473. +static void compose (void)
  14474. +{
  14475. +    dead_key_next = 1;
  14476. +}
  14477. +
  14478. +int spawnpid, spawnsig;
  14479. +
  14480. +static void spawn_console (void)
  14481. +{
  14482. +    if (spawnpid)
  14483. +    if (kill_proc (spawnpid, spawnsig, 1))
  14484. +        spawnpid = 0;
  14485. +}
  14486. +
  14487. +static void SAK (void)
  14488. +{
  14489. +    do_SAK(tty);
  14490. +#if 0
  14491. +    /*
  14492. +     * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and
  14493. +     * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK
  14494. +     * handling.
  14495. +     *
  14496. +     * We should do this some day --- the whole point of a secure
  14497. +     * attention key is that it should be guaranteed to always
  14498. +     * work.
  14499. +     */
  14500. +    reset_vc (fg_console);
  14501. +    do_unblank_screen ();    /* not in interrupt routine? */
  14502. +#endif
  14503. +}
  14504. +
  14505. +static void do_ignore (unsigned char value, char up_flag)
  14506. +{
  14507. +}
  14508. +
  14509. +static void do_null (void)
  14510. +{
  14511. +    compute_shiftstate ();
  14512. +}
  14513. +
  14514. +static void do_spec (unsigned char value,char up_flag)
  14515. +{
  14516. +    if (up_flag)
  14517. +    return;
  14518. +    if (value >= SIZE(spec_fn_table))
  14519. +    return;
  14520. +    if (!spec_fn_table[value])
  14521. +    return;
  14522. +    spec_fn_table[value] ();
  14523. +}
  14524. +
  14525. +static void do_lowercase (unsigned char value, char up_flag)
  14526. +{
  14527. +    printk("keyboard.c: do_lowercase was called - impossible\n");
  14528. +}
  14529. +
  14530. +static void do_self(unsigned char value, char up_flag)
  14531. +{
  14532. +    if (up_flag)
  14533. +    return;        /* no action, if this is a key release */
  14534. +
  14535. +    if (diacr)
  14536. +    value = handle_diacr (value);
  14537. +
  14538. +    if (dead_key_next) {
  14539. +    dead_key_next = 0;
  14540. +    diacr = value;
  14541. +    return;
  14542. +    }
  14543. +    put_queue (value);
  14544. +}
  14545. +
  14546. +#define A_GRAVE '`'
  14547. +#define A_ACUTE '\''
  14548. +#define A_CFLEX '^'
  14549. +#define A_TILDE '~'
  14550. +#define A_DIAER '"'
  14551. +static unsigned char ret_diacr[] = {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
  14552. +
  14553. +static void do_dead(unsigned char value, char up_flag)
  14554. +{
  14555. +    if (up_flag)
  14556. +    return;
  14557. +
  14558. +    value = ret_diacr[value];
  14559. +    if (diacr == value) { /* pressed twice */
  14560. +    diacr = 0;
  14561. +    put_queue (value);
  14562. +    return;
  14563. +    }
  14564. +    diacr = value;
  14565. +}
  14566. +
  14567. +static unsigned char handle_diacr(unsigned char ch)
  14568. +{
  14569. +    int d = diacr;
  14570. +    int i;
  14571. +
  14572. +    diacr = 0;
  14573. +    if (ch == ' ')
  14574. +    return d;
  14575. +
  14576. +    for (i = 0; i < accent_table_size; i++) {
  14577. +    if (accent_table[i].diacr == d && accent_table[i].base == ch)
  14578. +        return accent_table[i].result;
  14579. +    }
  14580. +
  14581. +    put_queue (d);
  14582. +    return ch;
  14583. +}
  14584. +
  14585. +static void do_cons(unsigned char value, char up_flag)
  14586. +{
  14587. +    if (up_flag)
  14588. +    return;
  14589. +    want_console = value;
  14590. +}
  14591. +
  14592. +static void do_fn(unsigned char value, char up_flag)
  14593. +{
  14594. +    if (up_flag)
  14595. +    return;
  14596. +
  14597. +    if (value < SIZE(func_table)) {
  14598. +    if (func_table[value])
  14599. +        puts_queue (func_table[value]);
  14600. +    } else
  14601. +    printk ("do_fn called with value=%d\n",value);
  14602. +}
  14603. +
  14604. +static void do_pad(unsigned char value, char up_flag)
  14605. +{
  14606. +    static char *pad_chars = "0123456789+-*/\015,.?#";
  14607. +    static char *app_map = "pqrstuvwxylSRQMnn?#";
  14608. +
  14609. +    if (up_flag)
  14610. +    return;
  14611. +
  14612. +    if (vc_kbd_mode (kbd, VC_APPLIC) && !k_down[KG_SHIFT]) {
  14613. +    applkey (app_map[value], 1);
  14614. +    return;
  14615. +    }
  14616. +
  14617. +    if (!vc_kbd_led (kbd,VC_NUMLOCK))
  14618. +    switch (value) {
  14619. +        case 15:
  14620. +        case 16: do_fn (22, 0); return;
  14621. +        case 7:  do_fn (20, 0); return;
  14622. +        case 8:  do_cur( 3, 0); return;
  14623. +        case 9:  do_fn (24, 0); return;
  14624. +        case 4:  do_cur( 1, 0); return;
  14625. +        case 6:  do_cur( 2, 0); return;
  14626. +        case 1:  do_fn (23, 0); return;
  14627. +        case 2:  do_cur( 0, 0); return;
  14628. +        case 3:  do_fn (25, 0); return;
  14629. +        case 5:  applkey('G',vc_kbd_mode(kbd, VC_APPLIC)); return;
  14630. +    }
  14631. +
  14632. +    put_queue (pad_chars[value]);
  14633. +    if (value == 14 && vc_kbd_mode (kbd, VC_CRLF))
  14634. +    put_queue (10);
  14635. +}
  14636. +
  14637. +static void do_cur(unsigned char value, char up_flag)
  14638. +{
  14639. +    static char *cur_chars = "BDCA";
  14640. +
  14641. +    if (up_flag)
  14642. +    return;
  14643. +
  14644. +    applkey (cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
  14645. +}
  14646. +
  14647. +static void do_shift(unsigned char value, char up_flag)
  14648. +{
  14649. +    int old_state = shift_state;
  14650. +
  14651. +    if (rep)
  14652. +    return;
  14653. +
  14654. +    /* Mimic typewriter: a CapsShift key acts like Shift but undoes CapsLock */
  14655. +    if (value == KVAL(K_CAPSSHIFT)) {
  14656. +    value = KVAL(K_SHIFT);
  14657. +    if (!up_flag)
  14658. +        clr_vc_kbd_led (kbd, VC_CAPSLOCK);
  14659. +    }
  14660. +
  14661. +    if(up_flag) {
  14662. +    /* handle the case that two shift or control
  14663. +       keys are depressed simultaneously */
  14664. +    if(k_down[value])
  14665. +        k_down[value]--;
  14666. +    } else
  14667. +    k_down[value]++;
  14668. +
  14669. +    if(k_down[value])
  14670. +    shift_state |= (1 << value);
  14671. +    else
  14672. +    shift_state &= ~ (1 << value);
  14673. +
  14674. +    /* kludge */
  14675. +    if(up_flag && shift_state != old_state && npadch != -1) {
  14676. +    if(kbd->kbdmode == VC_UNICODE)
  14677. +        to_utf8(npadch & 0xffff);
  14678. +    else
  14679. +        put_queue(npadch & 0xff);
  14680. +    npadch = -1;
  14681. +    }
  14682. +}
  14683. +
  14684. +/*
  14685. + * Called after returning from RAW mode or when changing consoles -
  14686. + * recompute k_down[] and shift_state from key_down[]
  14687. + * Maybe called when keymap is undefined so that shift key release is seen
  14688. + */
  14689. +void compute_shiftstate(void)
  14690. +{
  14691. +    int i, j, k, sym, val;
  14692. +
  14693. +    shift_state = 0;
  14694. +    for (i = 0; i < SIZE(k_down); i++)
  14695. +    k_down[i] = 0;
  14696. +
  14697. +    for (i = 0; i < SIZE(key_down); i++)
  14698. +    if (key_down[i]) {            /* skip this short word if zero */
  14699. +        k = i * BITS_PER_SHORT;
  14700. +        for (j = 0; j < BITS_PER_SHORT; j++, k++)
  14701. +        if (test_bit (k, key_down)) {
  14702. +            sym = U(plain_map[k]);
  14703. +            if (KTYP(sym) == KT_SHIFT) {
  14704. +            val = KVAL (sym);
  14705. +            if (val == KVAL(K_CAPSSHIFT))
  14706. +                val = KVAL(K_SHIFT);
  14707. +            k_down[val] ++;
  14708. +            shift_state |= (1 << val);
  14709. +            }
  14710. +        }
  14711. +    }
  14712. +}
  14713. +
  14714. +static void do_meta(unsigned char value, char up_flag)
  14715. +{
  14716. +    if(up_flag)
  14717. +    return;
  14718. +
  14719. +    if(vc_kbd_mode(kbd, VC_META)) {
  14720. +    put_queue ('\033');
  14721. +    put_queue (value);
  14722. +    } else
  14723. +    put_queue (value | 0x80);
  14724. +}
  14725. +
  14726. +static void do_ascii(unsigned char value, char up_flag)
  14727. +{
  14728. +    int base;
  14729. +
  14730. +    if(up_flag)
  14731. +    return;
  14732. +
  14733. +    if(value < 10)
  14734. +    base = 10;
  14735. +    else {
  14736. +    value -= 10;
  14737. +    base = 16;
  14738. +    }
  14739. +
  14740. +    if(npadch == -1)
  14741. +    npadch = value;
  14742. +    else
  14743. +    npadch = npadch * base + value;
  14744. +}
  14745. +
  14746. +static void do_lock (unsigned char value, char up_flag)
  14747. +{
  14748. +    if (up_flag || rep)
  14749. +    return;
  14750. +    chg_vc_kbd_lock (kbd, value);
  14751. +}
  14752. +
  14753. +static void do_slock (unsigned char value, char up_flag)
  14754. +{
  14755. +    if (up_flag || rep)
  14756. +    return;
  14757. +    chg_vc_kbd_slock (kbd, value);
  14758. +}
  14759. +
  14760. +/* --------------------------------------------------------------------------------------- *
  14761. + * Led driver                                           *
  14762. + * --------------------------------------------------------------------------------------- */
  14763. +
  14764. +/*
  14765. + * The leds display either
  14766. + * (i)   The status of NumLock, CapsLock and ScrollLock.
  14767. + * (ii)  Whatever pattern of lights people wait to show using KDSETLED.
  14768. + * (iii) Specified bits of specified words in kernel memory.
  14769. + */
  14770. +
  14771. +static unsigned char ledioctl;
  14772. +
  14773. +unsigned char getledstate(void)
  14774. +{
  14775. +    return ledstate;
  14776. +}
  14777. +
  14778. +void setledstate(struct kbd_struct *kbd, unsigned int led)
  14779. +{
  14780. +    if(!(led & ~7)) {
  14781. +    ledioctl = led;
  14782. +    kbd->ledmode = LED_SHOW_IOCTL;
  14783. +    } else
  14784. +    kbd->ledmode = LED_SHOW_FLAGS;
  14785. +    set_leds();
  14786. +}
  14787. +
  14788. +static struct ledptr
  14789. +{
  14790. +    unsigned int *addr;
  14791. +    unsigned int mask;
  14792. +    unsigned char valid:1;
  14793. +} ledptrs[3];
  14794. +
  14795. +void register_leds(int console,unsigned int led,unsigned int *addr,unsigned int mask)
  14796. +{
  14797. +    struct kbd_struct *kbd = kbd_table + console;
  14798. +
  14799. +    if(led < 3) {
  14800. +    ledptrs[led].addr = addr;
  14801. +    ledptrs[led].mask = mask;
  14802. +    ledptrs[led].valid= 1;
  14803. +    kbd->ledmode = LED_SHOW_MEM;
  14804. +    } else
  14805. +    kbd->ledmode = LED_SHOW_FLAGS;
  14806. +}
  14807. +
  14808. +static inline unsigned char getleds(void)
  14809. +{
  14810. +    struct kbd_struct *kbd = kbd_table + fg_console;
  14811. +    unsigned char leds;
  14812. +
  14813. +    if(kbd->ledmode == LED_SHOW_IOCTL)
  14814. +    return ledioctl;
  14815. +
  14816. +    leds = kbd->ledflagstate;
  14817. +    if (kbd->ledmode == LED_SHOW_MEM) {
  14818. +    if (ledptrs[0].valid) {
  14819. +        if (*ledptrs[0].addr & ledptrs[0].mask)
  14820. +        leds |= 1;
  14821. +        else
  14822. +        leds &= ~1;
  14823. +        }
  14824. +    if (ledptrs[1].valid) {
  14825. +        if (*ledptrs[1].addr & ledptrs[1].mask)
  14826. +        leds |= 2;
  14827. +        else
  14828. +        leds &= ~2;
  14829. +        }
  14830. +    if (ledptrs[2].valid) {
  14831. +        if(*ledptrs[2].addr & ledptrs[2].mask)
  14832. +        leds |= 4;
  14833. +        else
  14834. +        leds &= ~4;
  14835. +        }
  14836. +    }
  14837. +    return leds;
  14838. +}
  14839. +
  14840. +/*
  14841. + * This routine is the bottom half of the keyboard interrupt
  14842. + * routine, and runs with all interrupts enabled.  It does
  14843. + * console changing, led setting, and copy_to_cooked, which can
  14844. + * take a reasonably long time.
  14845. + *
  14846. + * Aside from timing (which isn't really that important for
  14847. + * keyboard interrupts as they happen often), using the software
  14848. + * interrupt routines for this thing allows us to easily mask
  14849. + * this when we don't want any of the above to happen.  Not yet
  14850. + * used, but this allows for easy and efficient race-condition
  14851. + * prevention later on.
  14852. + */
  14853. +static void kbd_bh(void *unused)
  14854. +{
  14855. +    unsigned char leds;
  14856. +
  14857. +    tty = ttytab[fg_console];
  14858. +    kbd = kbd_table + fg_console;
  14859. +
  14860. +    if (rep && kbd_repeatkey != -1) {
  14861. +        /*
  14862. +         * This prevents the kbd_key routine from being called
  14863. +         * twice, once by this BH, and once by the interrupt
  14864. +         * routine.  Maybe we should put the key press in a
  14865. +         * buffer or variable, and then call the BH...
  14866. +         */
  14867. +        disable_irq (IRQ_KEYBOARDRX);
  14868. +    kbd_key (kbd_repeatkey, kbd_repeatrate);
  14869. +    enable_irq (IRQ_KEYBOARDRX);
  14870. +        rep = 0;
  14871. +    }
  14872. +
  14873. +    if(want_console >= 0) {
  14874. +    if(want_console != fg_console) {
  14875. +        change_console(want_console);
  14876. +        /* we only changed when the console had already
  14877. +         * been allocated - a new console is not created
  14878. +         * in an interrupt routine.
  14879. +         */
  14880. +    }
  14881. +    want_console = -1;
  14882. +    }
  14883. +
  14884. +    leds = getleds ();
  14885. +    if (leds != ledstate) {
  14886. +    unsigned long flags;
  14887. +    ledstate = leds;
  14888. +    leds = ((leds & (1<<VC_SCROLLOCK))?4:0) | ((leds & (1<<VC_NUMLOCK))?2:0) |
  14889. +           ((leds & (1<<VC_CAPSLOCK))?1:0);
  14890. +
  14891. +    save_flags(flags);
  14892. +    cli();
  14893. +    intr_count -= 1;
  14894. +
  14895. +    kbd_sendval(leds);
  14896. +
  14897. +    intr_count += 1;
  14898. +    restore_flags(flags);
  14899. +    }
  14900. +    poke_blanked_console();
  14901. +}
  14902. +
  14903. +int kbd_init (void)
  14904. +{
  14905. +    int i;
  14906. +    struct kbd_struct kbd0;
  14907. +    extern struct tty_driver console_driver;
  14908. +    unsigned long flags;
  14909. +
  14910. +    kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
  14911. +    kbd0.ledmode      = LED_SHOW_FLAGS;
  14912. +    kbd0.lockstate    = KBD_DEFLOCK;
  14913. +    kbd0.slockstate   = 0;
  14914. +    kbd0.modeflags    = KBD_DEFMODE;
  14915. +    kbd0.kbdmode      = VC_XLATE;
  14916. +
  14917. +    for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
  14918. +    kbd_table[i] = kbd0;
  14919. +
  14920. +    ttytab = console_driver.table;
  14921. +
  14922. +    bh_base[KEYBOARD_BH].routine = kbd_bh;
  14923. +
  14924. +    save_flags (flags);
  14925. +    cli ();
  14926. +    if (request_irq (IRQ_KEYBOARDRX, kbd_rx, 0, "keyboard")!=0)
  14927. +    panic("Could not allocate keyboard receive IRQ!");
  14928. +    if (request_irq (IRQ_KEYBOARDTX, kbd_tx, 0, "Keyboard")!=0)
  14929. +    panic("Could not allocate keyboard transmit IRQ!");
  14930. +    disable_irq (IRQ_KEYBOARDTX);
  14931. +    restore_flags(flags);
  14932. +
  14933. +    kbd_sendval(HRST);
  14934. +    mark_bh (KEYBOARD_BH);
  14935. +    enable_bh (KEYBOARD_BH);
  14936. +
  14937. +    printk("Keyboard driver installed (%s) v%d.%02d.\n", "English", VERSION/100, VERSION%100);
  14938. +    return 0;
  14939. +}
  14940. +
  14941. diff -urNwbB linux/arch/arm/drivers/char/mem.c linux.arm/arch/arm/drivers/char/mem.c
  14942. --- linux/arch/arm/drivers/char/mem.c    Thu Jan  1 01:00:00 1970
  14943. +++ linux.arm/arch/arm/drivers/char/mem.c    Sun Mar  3 12:45:19 1996
  14944. @@ -0,0 +1,383 @@
  14945. +/*
  14946. + *  linux/arch/arm/drivers/char/mem.c
  14947. + *
  14948. + *  Copyright (C) 1991, 1992  Linus Torvalds
  14949. + *
  14950. + *  Modifications for ARM Copyright (C) 1995, 1996 Russell King
  14951. + */
  14952. +
  14953. +#include <linux/config.h>
  14954. +#include <linux/types.h>
  14955. +#include <linux/errno.h>
  14956. +#include <linux/sched.h>
  14957. +#include <linux/kernel.h>
  14958. +#include <linux/major.h>
  14959. +#include <linux/tty.h>
  14960. +#include <linux/mouse.h>
  14961. +#include <linux/tpqic02.h>
  14962. +#include <linux/malloc.h>
  14963. +#include <linux/mman.h>
  14964. +#include <linux/mm.h>
  14965. +#include <linux/random.h>
  14966. +
  14967. +#include <asm/segment.h>
  14968. +#include <asm/io.h>
  14969. +#include <asm/pgtable.h>
  14970. +
  14971. +#ifdef CONFIG_SOUND
  14972. +void soundcard_init(void);
  14973. +#endif
  14974. +
  14975. +static int read_ram(struct inode * inode, struct file * file, char * buf, int count)
  14976. +{
  14977. +    return -EIO;
  14978. +}
  14979. +
  14980. +static int write_ram(struct inode * inode, struct file * file, const char * buf, int count)
  14981. +{
  14982. +    return -EIO;
  14983. +}
  14984. +
  14985. +static int read_mem(struct inode * inode, struct file * file, char * buf, int count)
  14986. +{
  14987. +    unsigned long p = file->f_pos;
  14988. +
  14989. +    p += PAGE_OFFSET;
  14990. +    if (count < 0)
  14991. +        return -EINVAL;
  14992. +    if (MAP_NR(p) >= MAP_NR(high_memory))
  14993. +        return 0;
  14994. +    if (count > high_memory - p)
  14995. +        count = high_memory - p;
  14996. +    memcpy_tofs(buf,(void *) p,count);
  14997. +    file->f_pos += count;
  14998. +    return count;
  14999. +}
  15000. +
  15001. +static int write_mem(struct inode * inode, struct file * file, const char * buf, int count)
  15002. +{
  15003. +    unsigned long p = file->f_pos;
  15004. +
  15005. +    p += PAGE_OFFSET;
  15006. +    if (count < 0)
  15007. +        return -EINVAL;
  15008. +    if (MAP_NR(p) >= MAP_NR(high_memory))
  15009. +        return 0;
  15010. +    if (count > high_memory - p)
  15011. +        count = high_memory - p;
  15012. +    memcpy_fromfs((void *) p,buf,count);
  15013. +    file->f_pos += count;
  15014. +    return count;
  15015. +}
  15016. +
  15017. +static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_struct * vma)
  15018. +{
  15019. +    if (vma->vm_offset & ~PAGE_MASK)
  15020. +        return -ENXIO;
  15021. +
  15022. +    if (remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
  15023. +        return -EAGAIN;
  15024. +    vma->vm_inode = inode;
  15025. +    inode->i_count++;
  15026. +    return 0;
  15027. +}
  15028. +
  15029. +static int read_kmem(struct inode *inode, struct file *file, char *buf, int count)
  15030. +{
  15031. +    int read1, read2;
  15032. +
  15033. +    read1 = read_mem(inode, file, buf, count);
  15034. +    if (read1 < 0)
  15035. +        return read1;
  15036. +    read2 = vread(buf + read1, (char *) ((unsigned long) file->f_pos), count - read1);
  15037. +    if (read2 < 0)
  15038. +        return read2;
  15039. +    file->f_pos += read2;
  15040. +    return read1 + read2;
  15041. +}
  15042. +
  15043. +static int read_port(struct inode * inode, struct file * file,char * buf, int count)
  15044. +{
  15045. +    unsigned int i = file->f_pos;
  15046. +    char * tmp = buf;
  15047. +
  15048. +    while (count-- > 0 && i < 65536) {
  15049. +        put_user(inb(i),tmp);
  15050. +        i++;
  15051. +        tmp++;
  15052. +    }
  15053. +    file->f_pos = i;
  15054. +    return tmp-buf;
  15055. +}
  15056. +
  15057. +static int write_port(struct inode * inode, struct file * file, const char * buf, int count)
  15058. +{
  15059. +    unsigned int i = file->f_pos;
  15060. +    const char * tmp = buf;
  15061. +
  15062. +    while (count-- > 0 && i < 65536) {
  15063. +        outb(get_user(tmp),i);
  15064. +        i++;
  15065. +        tmp++;
  15066. +    }
  15067. +    file->f_pos = i;
  15068. +    return tmp-buf;
  15069. +}
  15070. +
  15071. +static int read_null(struct inode * node, struct file * file, char * buf, int count)
  15072. +{
  15073. +    return 0;
  15074. +}
  15075. +
  15076. +static int write_null(struct inode * inode, struct file * file, const char * buf, int count)
  15077. +{
  15078. +    return count;
  15079. +}
  15080. +
  15081. +static int read_zero(struct inode * node, struct file * file, char * buf, int count)
  15082. +{
  15083. +    int left;
  15084. +
  15085. +    for (left = count; left > 0; left--) {
  15086. +        put_user(0,buf);
  15087. +        buf++;
  15088. +    }
  15089. +    return count;
  15090. +}
  15091. +
  15092. +static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_struct * vma)
  15093. +{
  15094. +    if (vma->vm_flags & VM_SHARED)
  15095. +        return -EINVAL;
  15096. +    if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
  15097. +        return -EAGAIN;
  15098. +    return 0;
  15099. +}
  15100. +
  15101. +static int read_full(struct inode * node, struct file * file, char * buf,int count)
  15102. +{
  15103. +    return count;
  15104. +}
  15105. +
  15106. +static int write_full(struct inode * inode, struct file * file, const char * buf, int count)
  15107. +{
  15108. +    return -ENOSPC;
  15109. +}
  15110. +
  15111. +/*
  15112. + * Special lseek() function for /dev/null and /dev/zero.  Most notably, you can fopen()
  15113. + * both devices with "a" now.  This was previously impossible.  SRB.
  15114. + */
  15115. +
  15116. +static int null_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  15117. +{
  15118. +    return file->f_pos=0;
  15119. +}
  15120. +/*
  15121. + * The memory devices use the full 32/64 bits of the offset, and so we cannot
  15122. + * check against negative addresses: they are ok. The return value is weird,
  15123. + * though, in that case (0).
  15124. + *
  15125. + * also note that seeking relative to the "end of file" isn't supported:
  15126. + * it has no meaning, so it returns -EINVAL.
  15127. + */
  15128. +static int memory_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  15129. +{
  15130. +    switch (orig) {
  15131. +        case 0:
  15132. +            file->f_pos = offset;
  15133. +            return file->f_pos;
  15134. +        case 1:
  15135. +            file->f_pos += offset;
  15136. +            return file->f_pos;
  15137. +        default:
  15138. +            return -EINVAL;
  15139. +    }
  15140. +    if (file->f_pos < 0)
  15141. +        return 0;
  15142. +    return file->f_pos;
  15143. +}
  15144. +
  15145. +#define write_kmem    write_mem
  15146. +#define mmap_kmem    mmap_mem
  15147. +#define zero_lseek    null_lseek
  15148. +#define write_zero    write_null
  15149. +
  15150. +static struct file_operations ram_fops = {
  15151. +    memory_lseek,
  15152. +    read_ram,
  15153. +    write_ram,
  15154. +    NULL,        /* ram_readdir */
  15155. +    NULL,        /* ram_select */
  15156. +    NULL,        /* ram_ioctl */
  15157. +    NULL,        /* ram_mmap */
  15158. +    NULL,        /* no special open code */
  15159. +    NULL,        /* no special release code */
  15160. +    NULL        /* fsync */
  15161. +};
  15162. +
  15163. +static struct file_operations mem_fops = {
  15164. +    memory_lseek,
  15165. +    read_mem,
  15166. +    write_mem,
  15167. +    NULL,        /* mem_readdir */
  15168. +    NULL,        /* mem_select */
  15169. +    NULL,        /* mem_ioctl */
  15170. +    mmap_mem,
  15171. +    NULL,        /* no special open code */
  15172. +    NULL,        /* no special release code */
  15173. +    NULL        /* fsync */
  15174. +};
  15175. +
  15176. +static struct file_operations kmem_fops = {
  15177. +    memory_lseek,
  15178. +    read_kmem,
  15179. +    write_kmem,
  15180. +    NULL,        /* kmem_readdir */
  15181. +    NULL,        /* kmem_select */
  15182. +    NULL,        /* kmem_ioctl */
  15183. +    mmap_kmem,
  15184. +    NULL,        /* no special open code */
  15185. +    NULL,        /* no special release code */
  15186. +    NULL        /* fsync */
  15187. +};
  15188. +
  15189. +static struct file_operations null_fops = {
  15190. +    null_lseek,
  15191. +    read_null,
  15192. +    write_null,
  15193. +    NULL,        /* null_readdir */
  15194. +    NULL,        /* null_select */
  15195. +    NULL,        /* null_ioctl */
  15196. +    NULL,        /* null_mmap */
  15197. +    NULL,        /* no special open code */
  15198. +    NULL,        /* no special release code */
  15199. +    NULL        /* fsync */
  15200. +};
  15201. +
  15202. +static struct file_operations port_fops = {
  15203. +    memory_lseek,
  15204. +    read_port,
  15205. +    write_port,
  15206. +    NULL,        /* port_readdir */
  15207. +    NULL,        /* port_select */
  15208. +    NULL,        /* port_ioctl */
  15209. +    NULL,        /* port_mmap */
  15210. +    NULL,        /* no special open code */
  15211. +    NULL,        /* no special release code */
  15212. +    NULL        /* fsync */
  15213. +};
  15214. +
  15215. +static struct file_operations zero_fops = {
  15216. +    zero_lseek,
  15217. +    read_zero,
  15218. +    write_zero,
  15219. +    NULL,        /* zero_readdir */
  15220. +    NULL,        /* zero_select */
  15221. +    NULL,        /* zero_ioctl */
  15222. +    mmap_zero,
  15223. +    NULL,        /* no special open code */
  15224. +    NULL        /* no special release code */
  15225. +};
  15226. +
  15227. +static struct file_operations full_fops = {
  15228. +    memory_lseek,
  15229. +    read_full,
  15230. +    write_full,
  15231. +    NULL,        /* full_readdir */
  15232. +    NULL,        /* full_select */
  15233. +    NULL,        /* full_ioctl */
  15234. +    NULL,        /* full_mmap */
  15235. +    NULL,        /* no special open code */
  15236. +    NULL        /* no special release code */
  15237. +};
  15238. +
  15239. +static struct file_operations random_fops = {
  15240. +    memory_lseek,
  15241. +    read_random,
  15242. +    write_random,
  15243. +    NULL,        /* random_readdir */
  15244. +    NULL,        /* random_select */
  15245. +    random_ioctl,
  15246. +    NULL,        /* random_mmap */
  15247. +    NULL,        /* no special open code */
  15248. +    NULL        /* no special release code */
  15249. +};
  15250. +
  15251. +static struct file_operations urandom_fops = {
  15252. +    memory_lseek,
  15253. +    read_random_unlimited,
  15254. +    write_random,
  15255. +    NULL,        /* urandom_readdir */
  15256. +    NULL,        /* urandom_select */
  15257. +    random_ioctl,
  15258. +    NULL,        /* urandom_mmap */
  15259. +    NULL,        /* no special open code */
  15260. +    NULL        /* no special release code */
  15261. +};
  15262. +
  15263. +static int memory_open(struct inode * inode, struct file * filp)
  15264. +{
  15265. +    switch (MINOR(inode->i_rdev)) {
  15266. +        case 0:
  15267. +            filp->f_op = &ram_fops;
  15268. +            break;
  15269. +        case 1:
  15270. +            filp->f_op = &mem_fops;
  15271. +            break;
  15272. +        case 2:
  15273. +            filp->f_op = &kmem_fops;
  15274. +            break;
  15275. +        case 3:
  15276. +            filp->f_op = &null_fops;
  15277. +            break;
  15278. +        case 4:
  15279. +            filp->f_op = &port_fops;
  15280. +            break;
  15281. +        case 5:
  15282. +            filp->f_op = &zero_fops;
  15283. +            break;
  15284. +        case 7:
  15285. +            filp->f_op = &full_fops;
  15286. +            break;
  15287. +        case 8:
  15288. +            filp->f_op = &random_fops;
  15289. +            break;
  15290. +        case 9:
  15291. +            filp->f_op = &urandom_fops;
  15292. +            break;
  15293. +        default:
  15294. +            return -ENODEV;
  15295. +    }
  15296. +    if (filp->f_op && filp->f_op->open)
  15297. +        return filp->f_op->open(inode,filp);
  15298. +    return 0;
  15299. +}
  15300. +
  15301. +static struct file_operations memory_fops = {
  15302. +    NULL,        /* lseek */
  15303. +    NULL,        /* read */
  15304. +    NULL,        /* write */
  15305. +    NULL,        /* readdir */
  15306. +    NULL,        /* select */
  15307. +    NULL,        /* ioctl */
  15308. +    NULL,        /* mmap */
  15309. +    memory_open,    /* just a selector for the real open */
  15310. +    NULL,        /* release */
  15311. +    NULL        /* fsync */
  15312. +};
  15313. +
  15314. +int chr_dev_init(void)
  15315. +{
  15316. +    if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
  15317. +        printk("unable to get major %d for memory devs\n", MEM_MAJOR);
  15318. +    rand_initialize();
  15319. +    tty_init();
  15320. +#ifdef CONFIG_PRINTER
  15321. +    lp_init();
  15322. +#endif
  15323. +#ifdef CONFIG_MOUSE
  15324. +    mouse_init();
  15325. +#endif
  15326. +    return 0;
  15327. +}
  15328. diff -urNwbB linux/arch/arm/drivers/char/mouse.c linux.arm/arch/arm/drivers/char/mouse.c
  15329. --- linux/arch/arm/drivers/char/mouse.c    Thu Jan  1 01:00:00 1970
  15330. +++ linux.arm/arch/arm/drivers/char/mouse.c    Sat Feb 24 09:49:56 1996
  15331. @@ -0,0 +1,116 @@
  15332. +/*
  15333. + * linux/arch/arm/drivers/char/mouse.c
  15334. + *
  15335. + * Generic mouse open routine by Johan Myreen
  15336. + *
  15337. + * Based on code from Linus
  15338. + *
  15339. + * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
  15340. + *   changes incorporated into 0.97pl4
  15341. + *   by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
  15342. + *   See busmouse.c for particulars.
  15343. + *
  15344. + * Made things a lot mode modular - easy to compile in just one or two
  15345. + * of the mouse drivers, as they are now completely independent. Linus.
  15346. + *
  15347. + * Support for loadable modules. 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
  15348. + */
  15349. +
  15350. +#ifdef MODULE
  15351. +#include <linux/module.h>
  15352. +#include <linux/version.h>
  15353. +#else
  15354. +#define MOD_INC_USE_COUNT
  15355. +#define MOD_DEC_USE_COUNT
  15356. +#endif
  15357. +
  15358. +#include <linux/fs.h>
  15359. +#include <linux/errno.h>
  15360. +#include <linux/mouse.h>
  15361. +#include <linux/config.h>
  15362. +#include <linux/kernel.h>
  15363. +#include <linux/major.h>
  15364. +#include <linux/malloc.h>
  15365. +
  15366. +/*
  15367. + * Head entry for the doubly linked mouse list
  15368. + */
  15369. +static struct mouse mouse_list = { 0, "head", NULL, &mouse_list, &mouse_list };
  15370. +
  15371. +extern int arch_mouse_init(void);
  15372. +extern struct file_operations arch_mouse_fops;
  15373. +
  15374. +static int mouse_open(struct inode * inode, struct file * file)
  15375. +{
  15376. +    int minor = MINOR(inode->i_rdev);
  15377. +    struct mouse *c = mouse_list.next;
  15378. +    file->f_op = NULL;
  15379. +
  15380. +    while (c != &mouse_list) {
  15381. +        if (c->minor == minor) {
  15382. +            file->f_op = c->fops;
  15383. +            break;
  15384. +        }
  15385. +        c = c->next;
  15386. +    }
  15387. +
  15388. +    if (file->f_op == NULL)
  15389. +        return -ENODEV;
  15390. +
  15391. +        return file->f_op->open(inode,file);
  15392. +}
  15393. +
  15394. +static struct file_operations mouse_fops = {
  15395. +        NULL,        /* seek */
  15396. +    NULL,        /* read */
  15397. +    NULL,        /* write */
  15398. +    NULL,        /* readdir */
  15399. +    NULL,        /* select */
  15400. +    NULL,        /* ioctl */
  15401. +    NULL,        /* mmap */
  15402. +        mouse_open,
  15403. +        NULL        /* release */
  15404. +};
  15405. +
  15406. +int mouse_register(struct mouse * mouse)
  15407. +{
  15408. +    if (mouse->next || mouse->prev)
  15409. +        return -EBUSY;
  15410. +    MOD_INC_USE_COUNT;
  15411. +    mouse->next = &mouse_list;
  15412. +    mouse->prev = mouse_list.prev;
  15413. +    mouse->prev->next = mouse;
  15414. +    mouse->next->prev = mouse;
  15415. +    return 0;
  15416. +}
  15417. +
  15418. +int mouse_deregister(struct mouse * mouse)
  15419. +{
  15420. +    if (!mouse->next || !mouse->prev)
  15421. +        return -EINVAL;
  15422. +    MOD_DEC_USE_COUNT;
  15423. +    mouse->prev->next = mouse->next;
  15424. +    mouse->next->prev = mouse->prev;
  15425. +    mouse->next = NULL;
  15426. +    mouse->prev = NULL;
  15427. +    return 0;
  15428. +}
  15429. +
  15430. +#ifdef MODULE
  15431. +char kernel_version[] = UTS_RELEASE;
  15432. +#define mouse_init init_module
  15433. +#endif
  15434. +
  15435. +int mouse_init(void)
  15436. +{
  15437. +#ifdef CONFIG_KBDMOUSE
  15438. +    arch_mouse_init();
  15439. +#endif
  15440. +    if (register_chrdev(MOUSE_MAJOR, "mouse", &mouse_fops))
  15441. +    {
  15442. +        printk("unable to get major %d for mouse devices\n",
  15443. +               MOUSE_MAJOR);
  15444. +        return -EIO;
  15445. +    }
  15446. +    return 0;
  15447. +}
  15448. diff -urNwbB linux/arch/arm/drivers/char/n_tty.c linux.arm/arch/arm/drivers/char/n_tty.c
  15449. --- linux/arch/arm/drivers/char/n_tty.c    Thu Jan  1 01:00:00 1970
  15450. +++ linux.arm/arch/arm/drivers/char/n_tty.c    Sun Mar  3 12:46:05 1996
  15451. @@ -0,0 +1,1019 @@
  15452. +/*
  15453. + * n_tty.c --- implements the N_TTY line discipline.
  15454. + * 
  15455. + * This code used to be in tty_io.c, but things are getting hairy
  15456. + * enough that it made sense to split things off.  (The N_TTY
  15457. + * processing has changed so much that it's hardly recognizable,
  15458. + * anyway...)
  15459. + *
  15460. + * Note that the open routine for N_TTY is guaranteed never to return
  15461. + * an error.  This is because Linux will fall back to setting a line
  15462. + * to N_TTY if it can not switch to any other line discipline.  
  15463. + *
  15464. + * Written by Theodore Ts'o, Copyright 1994.
  15465. + * 
  15466. + * This file also contains code originally written by Linus Torvalds,
  15467. + * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
  15468. + * 
  15469. + * This file may be redistributed under the terms of the GNU Public
  15470. + * License.
  15471. + *
  15472. + * Altered for ARM to reduce memory usage.
  15473. + */
  15474. +
  15475. +#include <linux/types.h>
  15476. +#include <linux/major.h>
  15477. +#include <linux/errno.h>
  15478. +#include <linux/signal.h>
  15479. +#include <linux/fcntl.h>
  15480. +#include <linux/sched.h>
  15481. +#include <linux/interrupt.h>
  15482. +#include <linux/tty.h>
  15483. +#include <linux/timer.h>
  15484. +#include <linux/ctype.h>
  15485. +#include <linux/kd.h>
  15486. +#include <linux/mm.h>
  15487. +#include <linux/string.h>
  15488. +#include <linux/malloc.h>
  15489. +
  15490. +#include <asm/segment.h>
  15491. +#include <asm/system.h>
  15492. +#include <asm/bitops.h>
  15493. +
  15494. +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
  15495. +
  15496. +#ifndef MIN
  15497. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  15498. +#endif
  15499. +
  15500. +/* number of characters left in xmit buffer before select has we have room */
  15501. +#define WAKEUP_CHARS 256
  15502. +
  15503. +/*
  15504. + * This defines the low- and high-watermarks for throttling and
  15505. + * unthrottling the TTY driver.  These watermarks are used for
  15506. + * controlling the space in the read buffer.
  15507. + */
  15508. +#define TTY_THRESHOLD_THROTTLE        (N_TTY_BUF_SIZE - 128)
  15509. +#define TTY_THRESHOLD_UNTHROTTLE     128
  15510. +
  15511. +static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
  15512. +{
  15513. +    if (tty->read_cnt < N_TTY_BUF_SIZE) {
  15514. +        tty->read_buf[tty->read_head] = c;
  15515. +        tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
  15516. +        tty->read_cnt++;
  15517. +    }
  15518. +}
  15519. +
  15520. +/*
  15521. + * Flush the input buffer
  15522. + */
  15523. +void n_tty_flush_buffer(struct tty_struct * tty)
  15524. +{
  15525. +    tty->read_head = tty->read_tail = tty->read_cnt = 0;
  15526. +    tty->canon_head = tty->canon_data = tty->erasing = 0;
  15527. +    memset(&tty->read_flags, 0, sizeof tty->read_flags);
  15528. +    
  15529. +    if (!tty->link)
  15530. +        return;
  15531. +
  15532. +    if (tty->driver.unthrottle)
  15533. +        (tty->driver.unthrottle)(tty);
  15534. +    if (tty->link->packet) {
  15535. +        tty->ctrl_status |= TIOCPKT_FLUSHREAD;
  15536. +        wake_up_interruptible(&tty->link->read_wait);
  15537. +    }
  15538. +}
  15539. +
  15540. +/*
  15541. + * Return number of characters buffered to be delivered to user
  15542. + */
  15543. +int n_tty_chars_in_buffer(struct tty_struct *tty)
  15544. +{
  15545. +    return tty->read_cnt;
  15546. +}
  15547. +
  15548. +/*
  15549. + * Perform OPOST processing.  Returns -1 when the output device is
  15550. + * full and the character must be retried.
  15551. + */
  15552. +static int opost(unsigned char c, struct tty_struct *tty)
  15553. +{
  15554. +    int    space, spaces;
  15555. +
  15556. +    space = tty->driver.write_room(tty);
  15557. +    if (!space)
  15558. +        return -1;
  15559. +
  15560. +    if (O_OPOST(tty)) {
  15561. +        switch (c) {
  15562. +        case '\n':
  15563. +            if (O_ONLRET(tty))
  15564. +                tty->column = 0;
  15565. +            if (O_ONLCR(tty)) {
  15566. +                if (space < 2)
  15567. +                    return -1;
  15568. +                tty->driver.put_char(tty, '\r');
  15569. +                tty->column = 0;
  15570. +            }
  15571. +            tty->canon_column = tty->column;
  15572. +            break;
  15573. +        case '\r':
  15574. +            if (O_ONOCR(tty) && tty->column == 0)
  15575. +                return 0;
  15576. +            if (O_OCRNL(tty)) {
  15577. +                c = '\n';
  15578. +                if (O_ONLRET(tty))
  15579. +                    tty->canon_column = tty->column = 0;
  15580. +                break;
  15581. +            }
  15582. +            tty->canon_column = tty->column = 0;
  15583. +            break;
  15584. +        case '\t':
  15585. +            spaces = 8 - (tty->column & 7);
  15586. +            if (O_TABDLY(tty) == XTABS) {
  15587. +                if (space < spaces)
  15588. +                    return -1;
  15589. +                tty->column += spaces;
  15590. +                tty->driver.write(tty, 0, "        ", spaces);
  15591. +                return 0;
  15592. +            }
  15593. +            tty->column += spaces;
  15594. +            break;
  15595. +        case '\b':
  15596. +            if (tty->column > 0)
  15597. +                tty->column--;
  15598. +            break;
  15599. +        default:
  15600. +            if (O_OLCUC(tty))
  15601. +                c = toupper(c);
  15602. +            if (!iscntrl(c))
  15603. +                tty->column++;
  15604. +            break;
  15605. +        }
  15606. +    }
  15607. +    tty->driver.put_char(tty, c);
  15608. +    return 0;
  15609. +}
  15610. +
  15611. +static inline void put_char(unsigned char c, struct tty_struct *tty)
  15612. +{
  15613. +    tty->driver.put_char(tty, c);
  15614. +}
  15615. +
  15616. +/* Must be called only when L_ECHO(tty) is true. */
  15617. +
  15618. +static void echo_char(unsigned char c, struct tty_struct *tty)
  15619. +{
  15620. +    if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
  15621. +        put_char('^', tty);
  15622. +        put_char(c ^ 0100, tty);
  15623. +        tty->column += 2;
  15624. +    } else
  15625. +        opost(c, tty);
  15626. +}
  15627. +
  15628. +static inline void finish_erasing(struct tty_struct *tty)
  15629. +{
  15630. +    if (tty->erasing) {
  15631. +        put_char('/', tty);
  15632. +        tty->column += 2;
  15633. +        tty->erasing = 0;
  15634. +    }
  15635. +}
  15636. +
  15637. +static void eraser(unsigned char c, struct tty_struct *tty)
  15638. +{
  15639. +    enum { ERASE, WERASE, KILL } kill_type;
  15640. +    int head, seen_alnums;
  15641. +
  15642. +    if (tty->read_head == tty->canon_head) {
  15643. +        /* opost('\a', tty); */        /* what do you think? */
  15644. +        return;
  15645. +    }
  15646. +    if (c == ERASE_CHAR(tty))
  15647. +        kill_type = ERASE;
  15648. +    else if (c == WERASE_CHAR(tty))
  15649. +        kill_type = WERASE;
  15650. +    else {
  15651. +        if (!L_ECHO(tty)) {
  15652. +            tty->read_cnt -= ((tty->read_head - tty->canon_head) &
  15653. +                      (N_TTY_BUF_SIZE - 1));
  15654. +            tty->read_head = tty->canon_head;
  15655. +            return;
  15656. +        }
  15657. +        if (!L_ECHOK(tty) || !L_ECHOKE(tty)) {
  15658. +            tty->read_cnt -= ((tty->read_head - tty->canon_head) &
  15659. +                      (N_TTY_BUF_SIZE - 1));
  15660. +            tty->read_head = tty->canon_head;
  15661. +            finish_erasing(tty);
  15662. +            echo_char(KILL_CHAR(tty), tty);
  15663. +            /* Add a newline if ECHOK is on and ECHOKE is off. */
  15664. +            if (L_ECHOK(tty))
  15665. +                opost('\n', tty);
  15666. +            return;
  15667. +        }
  15668. +        kill_type = KILL;
  15669. +    }
  15670. +
  15671. +    seen_alnums = 0;
  15672. +    while (tty->read_head != tty->canon_head) {
  15673. +        head = (tty->read_head - 1) & (N_TTY_BUF_SIZE-1);
  15674. +        c = tty->read_buf[head];
  15675. +        if (kill_type == WERASE) {
  15676. +            /* Equivalent to BSD's ALTWERASE. */
  15677. +            if (isalnum(c) || c == '_')
  15678. +                seen_alnums++;
  15679. +            else if (seen_alnums)
  15680. +                break;
  15681. +        }
  15682. +        tty->read_head = head;
  15683. +        tty->read_cnt--;
  15684. +        if (L_ECHO(tty)) {
  15685. +            if (L_ECHOPRT(tty)) {
  15686. +                if (!tty->erasing) {
  15687. +                    put_char('\\', tty);
  15688. +                    tty->column++;
  15689. +                    tty->erasing = 1;
  15690. +                }
  15691. +                echo_char(c, tty);
  15692. +            } else if (!L_ECHOE(tty)) {
  15693. +                echo_char(ERASE_CHAR(tty), tty);
  15694. +            } else if (c == '\t') {
  15695. +                unsigned int col = tty->canon_column;
  15696. +                unsigned long tail = tty->canon_head;
  15697. +
  15698. +                /* Find the column of the last char. */
  15699. +                while (tail != tty->read_head) {
  15700. +                    c = tty->read_buf[tail];
  15701. +                    if (c == '\t')
  15702. +                        col = (col | 7) + 1;
  15703. +                    else if (iscntrl(c)) {
  15704. +                        if (L_ECHOCTL(tty))
  15705. +                            col += 2;
  15706. +                    } else
  15707. +                        col++;
  15708. +                    tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  15709. +                }
  15710. +
  15711. +                /* Now backup to that column. */
  15712. +                while (tty->column > col) {
  15713. +                    /* Can't use opost here. */
  15714. +                    put_char('\b', tty);
  15715. +                    tty->column--;
  15716. +                }
  15717. +            } else {
  15718. +                if (iscntrl(c) && L_ECHOCTL(tty)) {
  15719. +                    put_char('\b', tty);
  15720. +                    put_char(' ', tty);
  15721. +                    put_char('\b', tty);
  15722. +                    tty->column--;
  15723. +                }
  15724. +                if (!iscntrl(c) || L_ECHOCTL(tty)) {
  15725. +                    put_char('\b', tty);
  15726. +                    put_char(' ', tty);
  15727. +                    put_char('\b', tty);
  15728. +                    tty->column--;
  15729. +                }
  15730. +            }
  15731. +        }
  15732. +        if (kill_type == ERASE)
  15733. +            break;
  15734. +    }
  15735. +    if (tty->read_head == tty->canon_head)
  15736. +        finish_erasing(tty);
  15737. +}
  15738. +
  15739. +static void isig(int sig, struct tty_struct *tty)
  15740. +{
  15741. +    if (tty->pgrp > 0)
  15742. +        kill_pg(tty->pgrp, sig, 1);
  15743. +    if (!L_NOFLSH(tty)) {
  15744. +        n_tty_flush_buffer(tty);
  15745. +        if (tty->driver.flush_buffer)
  15746. +            tty->driver.flush_buffer(tty);
  15747. +    }
  15748. +}
  15749. +
  15750. +static inline void n_tty_receive_break(struct tty_struct *tty)
  15751. +{
  15752. +    if (I_IGNBRK(tty))
  15753. +        return;
  15754. +    if (I_BRKINT(tty)) {
  15755. +        isig(SIGINT, tty);
  15756. +        return;
  15757. +    }
  15758. +    if (I_PARMRK(tty)) {
  15759. +        put_tty_queue('\377', tty);
  15760. +        put_tty_queue('\0', tty);
  15761. +    }
  15762. +    put_tty_queue('\0', tty);
  15763. +    wake_up_interruptible(&tty->read_wait);
  15764. +}
  15765. +
  15766. +static inline void n_tty_receive_overrun(struct tty_struct *tty)
  15767. +{
  15768. +    char buf[64];
  15769. +
  15770. +    tty->num_overrun++;
  15771. +    if (tty->overrun_time < (jiffies - HZ)) {
  15772. +        printk("%s: %d input overrun(s)\n", _tty_name(tty, buf),
  15773. +               tty->num_overrun);
  15774. +        tty->overrun_time = jiffies;
  15775. +        tty->num_overrun = 0;
  15776. +    }
  15777. +}
  15778. +
  15779. +static inline void n_tty_receive_parity_error(struct tty_struct *tty,
  15780. +                          unsigned char c)
  15781. +{
  15782. +    if (I_IGNPAR(tty)) {
  15783. +        return;
  15784. +    }
  15785. +    if (I_PARMRK(tty)) {
  15786. +        put_tty_queue('\377', tty);
  15787. +        put_tty_queue('\0', tty);
  15788. +        put_tty_queue(c, tty);
  15789. +    } else
  15790. +        put_tty_queue('\0', tty);
  15791. +    wake_up_interruptible(&tty->read_wait);
  15792. +}
  15793. +
  15794. +static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
  15795. +{
  15796. +    if (tty->raw) {
  15797. +        put_tty_queue(c, tty);
  15798. +        return;
  15799. +    }
  15800. +    
  15801. +    if (tty->stopped && I_IXON(tty) && I_IXANY(tty)) {
  15802. +        start_tty(tty);
  15803. +        return;
  15804. +    }
  15805. +    
  15806. +    if (I_ISTRIP(tty))
  15807. +        c &= 0x7f;
  15808. +    if (I_IUCLC(tty) && L_IEXTEN(tty))
  15809. +        c=tolower(c);
  15810. +
  15811. +    if (tty->closing) {
  15812. +        if (I_IXON(tty)) {
  15813. +            if (c == START_CHAR(tty))
  15814. +                start_tty(tty);
  15815. +            else if (c == STOP_CHAR(tty))
  15816. +                stop_tty(tty);
  15817. +        }
  15818. +        return;
  15819. +    }
  15820. +
  15821. +    /*
  15822. +     * If the previous character was LNEXT, or we know that this
  15823. +     * character is not one of the characters that we'll have to
  15824. +     * handle specially, do shortcut processing to speed things
  15825. +     * up.
  15826. +     */
  15827. +    if (!test_bit(c, &tty->process_char_map) || tty->lnext) {
  15828. +        finish_erasing(tty);
  15829. +        tty->lnext = 0;
  15830. +        if (L_ECHO(tty)) {
  15831. +            if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  15832. +                put_char('\a', tty); /* beep if no space */
  15833. +                return;
  15834. +            }
  15835. +            /* Record the column of first canon char. */
  15836. +            if (tty->canon_head == tty->read_head)
  15837. +                tty->canon_column = tty->column;
  15838. +            echo_char(c, tty);
  15839. +        }
  15840. +        if (I_PARMRK(tty) && c == (unsigned char) '\377')
  15841. +            put_tty_queue(c, tty);
  15842. +        put_tty_queue(c, tty);
  15843. +        return;
  15844. +    }
  15845. +        
  15846. +    if (c == '\r') {
  15847. +        if (I_IGNCR(tty))
  15848. +            return;
  15849. +        if (I_ICRNL(tty))
  15850. +            c = '\n';
  15851. +    } else if (c == '\n' && I_INLCR(tty))
  15852. +        c = '\r';
  15853. +    if (I_IXON(tty)) {
  15854. +        if (c == START_CHAR(tty)) {
  15855. +            start_tty(tty);
  15856. +            return;
  15857. +        }
  15858. +        if (c == STOP_CHAR(tty)) {
  15859. +            stop_tty(tty);
  15860. +            return;
  15861. +        }
  15862. +    }
  15863. +    if (L_ISIG(tty)) {
  15864. +        if (c == INTR_CHAR(tty)) {
  15865. +            isig(SIGINT, tty);
  15866. +            return;
  15867. +        }
  15868. +        if (c == QUIT_CHAR(tty)) {
  15869. +            isig(SIGQUIT, tty);
  15870. +            return;
  15871. +        }
  15872. +        if (c == SUSP_CHAR(tty)) {
  15873. +            if (!is_orphaned_pgrp(tty->pgrp))
  15874. +                isig(SIGTSTP, tty);
  15875. +            return;
  15876. +        }
  15877. +    }
  15878. +    if (L_ICANON(tty)) {
  15879. +        if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
  15880. +            (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
  15881. +            eraser(c, tty);
  15882. +            return;
  15883. +        }
  15884. +        if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
  15885. +            tty->lnext = 1;
  15886. +            if (L_ECHO(tty)) {
  15887. +                finish_erasing(tty);
  15888. +                if (L_ECHOCTL(tty)) {
  15889. +                    put_char('^', tty);
  15890. +                    put_char('\b', tty);
  15891. +                }
  15892. +            }
  15893. +            return;
  15894. +        }
  15895. +        if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
  15896. +            L_IEXTEN(tty)) {
  15897. +            unsigned long tail = tty->canon_head;
  15898. +
  15899. +            finish_erasing(tty);
  15900. +            echo_char(c, tty);
  15901. +            opost('\n', tty);
  15902. +            while (tail != tty->read_head) {
  15903. +                echo_char(tty->read_buf[tail], tty);
  15904. +                tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  15905. +            }
  15906. +            return;
  15907. +        }
  15908. +        if (c == '\n') {
  15909. +            if (L_ECHO(tty) || L_ECHONL(tty)) {
  15910. +                if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  15911. +                    put_char('\a', tty);
  15912. +                    return;
  15913. +                }
  15914. +                opost('\n', tty);
  15915. +            }
  15916. +            goto handle_newline;
  15917. +        }
  15918. +        if (c == EOF_CHAR(tty)) {
  15919. +                if (tty->canon_head != tty->read_head)
  15920. +                    set_bit(TTY_PUSH, &tty->flags);
  15921. +            c = __DISABLED_CHAR;
  15922. +            goto handle_newline;
  15923. +        }
  15924. +        if ((c == EOL_CHAR(tty)) ||
  15925. +            (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
  15926. +            /*
  15927. +             * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
  15928. +             */
  15929. +            if (L_ECHO(tty)) {
  15930. +                if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  15931. +                    put_char('\a', tty);
  15932. +                    return;
  15933. +                }
  15934. +                /* Record the column of first canon char. */
  15935. +                if (tty->canon_head == tty->read_head)
  15936. +                    tty->canon_column = tty->column;
  15937. +                echo_char(c, tty);
  15938. +            }
  15939. +            /*
  15940. +             * XXX does PARMRK doubling happen for
  15941. +             * EOL_CHAR and EOL2_CHAR?
  15942. +             */
  15943. +            if (I_PARMRK(tty) && c == (unsigned char) '\377')
  15944. +                put_tty_queue(c, tty);
  15945. +
  15946. +        handle_newline:
  15947. +            set_bit(tty->read_head, &tty->read_flags);
  15948. +            put_tty_queue(c, tty);
  15949. +            tty->canon_head = tty->read_head;
  15950. +            tty->canon_data++;
  15951. +            if (tty->fasync)
  15952. +                kill_fasync(tty->fasync, SIGIO);
  15953. +            if (tty->read_wait)
  15954. +                wake_up_interruptible(&tty->read_wait);
  15955. +            return;
  15956. +        }
  15957. +    }
  15958. +    
  15959. +    finish_erasing(tty);
  15960. +    if (L_ECHO(tty)) {
  15961. +        if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
  15962. +            put_char('\a', tty); /* beep if no space */
  15963. +            return;
  15964. +        }
  15965. +        if (c == '\n')
  15966. +            opost('\n', tty);
  15967. +        else {
  15968. +            /* Record the column of first canon char. */
  15969. +            if (tty->canon_head == tty->read_head)
  15970. +                tty->canon_column = tty->column;
  15971. +            echo_char(c, tty);
  15972. +        }
  15973. +    }
  15974. +
  15975. +    if (I_PARMRK(tty) && c == (unsigned char) '\377')
  15976. +        put_tty_queue(c, tty);
  15977. +
  15978. +    put_tty_queue(c, tty);
  15979. +}    
  15980. +
  15981. +static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
  15982. +                  char *fp, int count)
  15983. +{
  15984. +    const unsigned char *p;
  15985. +    char *f, flags = 0;
  15986. +    int    i;
  15987. +
  15988. +    if (!tty->read_buf)
  15989. +        return;
  15990. +
  15991. +    if (tty->real_raw) {
  15992. +        i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,
  15993. +                   N_TTY_BUF_SIZE - tty->read_head));
  15994. +        memcpy(tty->read_buf + tty->read_head, cp, i);
  15995. +        tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
  15996. +        tty->read_cnt += i;
  15997. +        cp += i;
  15998. +        count -= i;
  15999. +
  16000. +        i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,
  16001. +                   N_TTY_BUF_SIZE - tty->read_head));
  16002. +        memcpy(tty->read_buf + tty->read_head, cp, i);
  16003. +        tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
  16004. +        tty->read_cnt += i;
  16005. +    } else {
  16006. +        for (i=count, p = cp, f = fp; i; i--, p++) {
  16007. +            if (f)
  16008. +                flags = *f++;
  16009. +            switch (flags) {
  16010. +            case TTY_NORMAL:
  16011. +                n_tty_receive_char(tty, *p);
  16012. +                break;
  16013. +            case TTY_BREAK:
  16014. +                n_tty_receive_break(tty);
  16015. +                break;
  16016. +            case TTY_PARITY:
  16017. +            case TTY_FRAME:
  16018. +                n_tty_receive_parity_error(tty, *p);
  16019. +                break;
  16020. +            case TTY_OVERRUN:
  16021. +                n_tty_receive_overrun(tty);
  16022. +                break;
  16023. +            default:
  16024. +                printk("%s: unknown flag %d\n", tty_name(tty),
  16025. +                       flags);
  16026. +                break;
  16027. +            }
  16028. +        }
  16029. +        if (tty->driver.flush_chars)
  16030. +            tty->driver.flush_chars(tty);
  16031. +    }
  16032. +
  16033. +    if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {
  16034. +        if (tty->fasync)
  16035. +            kill_fasync(tty->fasync, SIGIO);
  16036. +        if (tty->read_wait)
  16037. +            wake_up_interruptible(&tty->read_wait);
  16038. +    }
  16039. +
  16040. +    if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) &&
  16041. +        tty->driver.throttle &&
  16042. +        !set_bit(TTY_THROTTLED, &tty->flags))
  16043. +        tty->driver.throttle(tty);
  16044. +}
  16045. +
  16046. +static int n_tty_receive_room(struct tty_struct *tty)
  16047. +{
  16048. +    int    left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
  16049. +
  16050. +    /*
  16051. +     * If we are doing input canonicalization, and there are no
  16052. +     * pending newlines, let characters through without limit, so
  16053. +     * that erase characters will be handled.  Other excess
  16054. +     * characters will be beeped.
  16055. +     */
  16056. +    if (tty->icanon && !tty->canon_data)
  16057. +        return N_TTY_BUF_SIZE;
  16058. +
  16059. +    if (left > 0)
  16060. +        return left;
  16061. +    return 0;
  16062. +}
  16063. +
  16064. +int is_ignored(int sig)
  16065. +{
  16066. +    return ((current->blocked & (1<<(sig-1))) ||
  16067. +            (current->sig->action[sig-1].sa_handler == SIG_IGN));
  16068. +}
  16069. +
  16070. +static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
  16071. +{
  16072. +    if (!tty)
  16073. +        return;
  16074. +    
  16075. +    tty->icanon = (L_ICANON(tty) != 0);
  16076. +    if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
  16077. +        I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
  16078. +        I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
  16079. +        I_PARMRK(tty)) {
  16080. +        cli();
  16081. +        memset(tty->process_char_map, 0, 256/8);
  16082. +
  16083. +        if (I_IGNCR(tty) || I_ICRNL(tty))
  16084. +            set_bit('\r', &tty->process_char_map);
  16085. +        if (I_INLCR(tty))
  16086. +            set_bit('\n', &tty->process_char_map);
  16087. +
  16088. +        if (L_ICANON(tty)) {
  16089. +            set_bit(ERASE_CHAR(tty), &tty->process_char_map);
  16090. +            set_bit(KILL_CHAR(tty), &tty->process_char_map);
  16091. +            set_bit(EOF_CHAR(tty), &tty->process_char_map);
  16092. +            set_bit('\n', &tty->process_char_map);
  16093. +            set_bit(EOL_CHAR(tty), &tty->process_char_map);
  16094. +            if (L_IEXTEN(tty)) {
  16095. +                set_bit(WERASE_CHAR(tty),
  16096. +                    &tty->process_char_map);
  16097. +                set_bit(LNEXT_CHAR(tty),
  16098. +                    &tty->process_char_map);
  16099. +                set_bit(EOL2_CHAR(tty),
  16100. +                    &tty->process_char_map);
  16101. +                if (L_ECHO(tty))
  16102. +                    set_bit(REPRINT_CHAR(tty),
  16103. +                        &tty->process_char_map);
  16104. +            }
  16105. +        }
  16106. +        if (I_IXON(tty)) {
  16107. +            set_bit(START_CHAR(tty), &tty->process_char_map);
  16108. +            set_bit(STOP_CHAR(tty), &tty->process_char_map);
  16109. +        }
  16110. +        if (L_ISIG(tty)) {
  16111. +            set_bit(INTR_CHAR(tty), &tty->process_char_map);
  16112. +            set_bit(QUIT_CHAR(tty), &tty->process_char_map);
  16113. +            set_bit(SUSP_CHAR(tty), &tty->process_char_map);
  16114. +        }
  16115. +        clear_bit(__DISABLED_CHAR, &tty->process_char_map);
  16116. +        sti();
  16117. +        tty->raw = 0;
  16118. +        tty->real_raw = 0;
  16119. +    } else {
  16120. +        tty->raw = 1;
  16121. +        if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
  16122. +            (I_IGNPAR(tty) || !I_INPCK(tty)) &&
  16123. +            (tty->driver.flags & TTY_DRIVER_REAL_RAW))
  16124. +            tty->real_raw = 1;
  16125. +        else
  16126. +            tty->real_raw = 0;
  16127. +    }
  16128. +}
  16129. +
  16130. +static void n_tty_close(struct tty_struct *tty)
  16131. +{
  16132. +    n_tty_flush_buffer(tty);
  16133. +    if (tty->read_buf) {
  16134. +        kfree_s (tty->read_buf, N_TTY_BUF_SIZE);
  16135. +        tty->read_buf = 0;
  16136. +    }
  16137. +}
  16138. +
  16139. +static int n_tty_open(struct tty_struct *tty)
  16140. +{
  16141. +    if (!tty)
  16142. +        return -EINVAL;
  16143. +
  16144. +    if (!tty->read_buf) {
  16145. +        tty->read_buf = (unsigned char *)
  16146. +            kmalloc (N_TTY_BUF_SIZE, intr_count ? GFP_ATOMIC : GFP_KERNEL);
  16147. +        if (!tty->read_buf)
  16148. +            return -ENOMEM;
  16149. +    }
  16150. +    memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
  16151. +    tty->read_head = tty->read_tail = tty->read_cnt = 0;
  16152. +    memset(tty->read_flags, 0, sizeof(tty->read_flags));
  16153. +    n_tty_set_termios(tty, 0);
  16154. +    tty->minimum_to_wake = 1;
  16155. +    tty->closing = 0;
  16156. +    return 0;
  16157. +}
  16158. +
  16159. +static inline int input_available_p(struct tty_struct *tty, int amt)
  16160. +{
  16161. +    if (L_ICANON(tty)) {
  16162. +        if (tty->canon_data)
  16163. +            return 1;
  16164. +    } else if (tty->read_cnt >= (amt ? amt : 1))
  16165. +        return 1;
  16166. +
  16167. +    return 0;
  16168. +}
  16169. +
  16170. +/*
  16171. + * Helper function to speed up read_chan.  It is only called when
  16172. + * ICANON is off; it copies characters straight from the tty queue to
  16173. + * user space directly.  It can be profitably called twice; once to
  16174. + * drain the space from the tail pointer to the (physical) end of the
  16175. + * buffer, and once to drain the space from the (physical) beginning of
  16176. + * the buffer to head pointer.
  16177. + */
  16178. +static inline void copy_from_read_buf(struct tty_struct *tty,
  16179. +                      unsigned char **b,
  16180. +                      unsigned int *nr)
  16181. +
  16182. +{
  16183. +    int    n;
  16184. +
  16185. +    n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));
  16186. +    if (!n)
  16187. +        return;
  16188. +    memcpy_tofs(*b, &tty->read_buf[tty->read_tail], n);
  16189. +    tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
  16190. +    tty->read_cnt -= n;
  16191. +    *b += n;
  16192. +    *nr -= n;
  16193. +}
  16194. +
  16195. +static int read_chan(struct tty_struct *tty, struct file *file,
  16196. +             unsigned char *buf, unsigned int nr)
  16197. +{
  16198. +    struct wait_queue wait = { current, NULL };
  16199. +    int c;
  16200. +    unsigned char *b = buf;
  16201. +    int minimum, time;
  16202. +    int retval = 0;
  16203. +    int size;
  16204. +
  16205. +do_it_again:
  16206. +
  16207. +    if (!tty->read_buf) {
  16208. +        printk("n_tty_read_chan: called with read_buf == NULL?!?\n");
  16209. +        return -EIO;
  16210. +    }
  16211. +
  16212. +    /* Job control check -- must be done at start and after
  16213. +       every sleep (POSIX.1 7.1.1.4). */
  16214. +    /* NOTE: not yet done after every sleep pending a thorough
  16215. +       check of the logic of this change. -- jlc */
  16216. +    /* don't stop on /dev/console */
  16217. +    if (file->f_inode->i_rdev != CONSOLE_DEV &&
  16218. +        current->tty == tty) {
  16219. +        if (tty->pgrp <= 0)
  16220. +            printk("read_chan: tty->pgrp <= 0!\n");
  16221. +        else if (current->pgrp != tty->pgrp) {
  16222. +            if (is_ignored(SIGTTIN) ||
  16223. +                is_orphaned_pgrp(current->pgrp))
  16224. +                return -EIO;
  16225. +            kill_pg(current->pgrp, SIGTTIN, 1);
  16226. +            return -ERESTARTSYS;
  16227. +        }
  16228. +    }
  16229. +
  16230. +    if (L_ICANON(tty)) {
  16231. +        minimum = time = 0;
  16232. +        current->timeout = (unsigned long) -1;
  16233. +    } else {
  16234. +        time = (HZ / 10) * TIME_CHAR(tty);
  16235. +        minimum = MIN_CHAR(tty);
  16236. +        if (minimum) {
  16237. +              current->timeout = (unsigned long) -1;
  16238. +            if (time)
  16239. +                tty->minimum_to_wake = 1;
  16240. +            else if (!tty->read_wait ||
  16241. +                 (tty->minimum_to_wake > minimum))
  16242. +                tty->minimum_to_wake = minimum;
  16243. +        } else {
  16244. +            if (time) {
  16245. +                current->timeout = time + jiffies;
  16246. +                time = 0;
  16247. +            } else
  16248. +                current->timeout = 0;
  16249. +            tty->minimum_to_wake = minimum = 1;
  16250. +        }
  16251. +    }
  16252. +
  16253. +    add_wait_queue(&tty->read_wait, &wait);
  16254. +    while (1) {
  16255. +        /* First test for status change. */
  16256. +        if (tty->packet && tty->link->ctrl_status) {
  16257. +            if (b != buf)
  16258. +                break;
  16259. +            put_user(tty->link->ctrl_status, b++);
  16260. +            tty->link->ctrl_status = 0;
  16261. +            break;
  16262. +        }
  16263. +        /* This statement must be first before checking for input
  16264. +           so that any interrupt will set the state back to
  16265. +           TASK_RUNNING. */
  16266. +        current->state = TASK_INTERRUPTIBLE;
  16267. +        
  16268. +        if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
  16269. +            ((minimum - (b - buf)) >= 1))
  16270. +            tty->minimum_to_wake = (minimum - (b - buf));
  16271. +        
  16272. +        if (!input_available_p(tty, 0)) {
  16273. +            if (tty->flags & (1 << TTY_SLAVE_CLOSED)) {
  16274. +                retval = -EIO;
  16275. +                break;
  16276. +            }
  16277. +            if (tty_hung_up_p(file))
  16278. +                break;
  16279. +            if (!current->timeout)
  16280. +                break;
  16281. +            if (file->f_flags & O_NONBLOCK) {
  16282. +                retval = -EAGAIN;
  16283. +                break;
  16284. +            }
  16285. +            if (current->signal & ~current->blocked) {
  16286. +                retval = -ERESTARTSYS;
  16287. +                break;
  16288. +            }
  16289. +            schedule();
  16290. +            continue;
  16291. +        }
  16292. +        current->state = TASK_RUNNING;
  16293. +
  16294. +        /* Deal with packet mode. */
  16295. +        if (tty->packet && b == buf) {
  16296. +            put_user(TIOCPKT_DATA, b++);
  16297. +            nr--;
  16298. +        }
  16299. +
  16300. +        if (L_ICANON(tty)) {
  16301. +            while (1) {
  16302. +                int eol;
  16303. +
  16304. +                disable_bh(TQUEUE_BH);
  16305. +                if (!tty->read_cnt) {
  16306. +                    enable_bh(TQUEUE_BH);
  16307. +                    break;
  16308. +                }
  16309. +                eol = clear_bit(tty->read_tail,
  16310. +                        &tty->read_flags);
  16311. +                c = tty->read_buf[tty->read_tail];
  16312. +                tty->read_tail = ((tty->read_tail+1) &
  16313. +                          (N_TTY_BUF_SIZE-1));
  16314. +                tty->read_cnt--;
  16315. +                enable_bh(TQUEUE_BH);
  16316. +                if (!eol) {
  16317. +                    put_user(c, b++);
  16318. +                    if (--nr)
  16319. +                        continue;
  16320. +                    break;
  16321. +                }
  16322. +                if (--tty->canon_data < 0) {
  16323. +                    tty->canon_data = 0;
  16324. +                }
  16325. +                if (c != __DISABLED_CHAR) {
  16326. +                    put_user(c, b++);
  16327. +                    nr--;
  16328. +                }
  16329. +                break;
  16330. +            }
  16331. +        } else {
  16332. +            disable_bh(TQUEUE_BH);
  16333. +            copy_from_read_buf(tty, &b, &nr);
  16334. +            copy_from_read_buf(tty, &b, &nr);
  16335. +            enable_bh(TQUEUE_BH);
  16336. +        }
  16337. +
  16338. +        /* If there is enough space in the read buffer now, let the
  16339. +           low-level driver know. */
  16340. +        if (tty->driver.unthrottle &&
  16341. +            (tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE)
  16342. +            && clear_bit(TTY_THROTTLED, &tty->flags))
  16343. +            tty->driver.unthrottle(tty);
  16344. +
  16345. +        if (b - buf >= minimum || !nr)
  16346. +            break;
  16347. +        if (time)
  16348. +            current->timeout = time + jiffies;
  16349. +    }
  16350. +    remove_wait_queue(&tty->read_wait, &wait);
  16351. +
  16352. +    if (!tty->read_wait)
  16353. +        tty->minimum_to_wake = minimum;
  16354. +
  16355. +    current->state = TASK_RUNNING;
  16356. +    current->timeout = 0;
  16357. +    size = b - buf;
  16358. +    if (size && nr)
  16359. +            clear_bit(TTY_PUSH, &tty->flags);
  16360. +        if (!size && clear_bit(TTY_PUSH, &tty->flags))
  16361. +                goto do_it_again;
  16362. +    if (!size && !retval)
  16363. +            clear_bit(TTY_PUSH, &tty->flags);
  16364. +        return (size ? size : retval);
  16365. +}
  16366. +
  16367. +static int write_chan(struct tty_struct * tty, struct file * file,
  16368. +              const unsigned char * buf, unsigned int nr)
  16369. +{
  16370. +    struct wait_queue wait = { current, NULL };
  16371. +    int c;
  16372. +    const unsigned char *b = buf;
  16373. +    int retval = 0;
  16374. +
  16375. +    /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
  16376. +    if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) {
  16377. +        retval = tty_check_change(tty);
  16378. +        if (retval)
  16379. +            return retval;
  16380. +    }
  16381. +
  16382. +    add_wait_queue(&tty->write_wait, &wait);
  16383. +    while (1) {
  16384. +        current->state = TASK_INTERRUPTIBLE;
  16385. +        if (current->signal & ~current->blocked) {
  16386. +            retval = -ERESTARTSYS;
  16387. +            break;
  16388. +        }
  16389. +        if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
  16390. +            retval = -EIO;
  16391. +            break;
  16392. +        }
  16393. +        if (O_OPOST(tty)) {
  16394. +            while (nr > 0) {
  16395. +                c = get_user(b);
  16396. +                if (opost(c, tty) < 0)
  16397. +                    break;
  16398. +                b++; nr--;
  16399. +            }
  16400. +            if (tty->driver.flush_chars)
  16401. +                tty->driver.flush_chars(tty);
  16402. +        } else {
  16403. +            c = tty->driver.write(tty, 1, b, nr);
  16404. +            b += c;
  16405. +            nr -= c;
  16406. +        }
  16407. +        if (!nr)
  16408. +            break;
  16409. +        if (file->f_flags & O_NONBLOCK) {
  16410. +            retval = -EAGAIN;
  16411. +            break;
  16412. +        }
  16413. +        schedule();
  16414. +    }
  16415. +    current->state = TASK_RUNNING;
  16416. +    remove_wait_queue(&tty->write_wait, &wait);
  16417. +    return (b - buf) ? b - buf : retval;
  16418. +}
  16419. +
  16420. +static int normal_select(struct tty_struct * tty, struct inode * inode,
  16421. +             struct file * file, int sel_type, select_table *wait)
  16422. +{
  16423. +    switch (sel_type) {
  16424. +        case SEL_IN:
  16425. +            if (input_available_p(tty, TIME_CHAR(tty) ? 0 :
  16426. +                          MIN_CHAR(tty)))
  16427. +                return 1;
  16428. +            /* fall through */
  16429. +        case SEL_EX:
  16430. +            if (tty->packet && tty->link->ctrl_status)
  16431. +                return 1;
  16432. +            if (tty->flags & (1 << TTY_SLAVE_CLOSED))
  16433. +                return 1;
  16434. +            if (tty_hung_up_p(file))
  16435. +                return 1;
  16436. +            if (!tty->read_wait) {
  16437. +                if (MIN_CHAR(tty) && !TIME_CHAR(tty))
  16438. +                    tty->minimum_to_wake = MIN_CHAR(tty);
  16439. +                else
  16440. +                    tty->minimum_to_wake = 1;
  16441. +            }
  16442. +            select_wait(&tty->read_wait, wait);
  16443. +            return 0;
  16444. +        case SEL_OUT:
  16445. +            if (tty->driver.chars_in_buffer(tty) < WAKEUP_CHARS)
  16446. +                return 1;
  16447. +            select_wait(&tty->write_wait, wait);
  16448. +            return 0;
  16449. +    }
  16450. +    return 0;
  16451. +}
  16452. +
  16453. +struct tty_ldisc tty_ldisc_N_TTY = {
  16454. +    TTY_LDISC_MAGIC,    /* magic */
  16455. +    0,            /* num */
  16456. +    0,            /* flags */
  16457. +    n_tty_open,        /* open */
  16458. +    n_tty_close,        /* close */
  16459. +    n_tty_flush_buffer,    /* flush_buffer */
  16460. +    n_tty_chars_in_buffer,    /* chars_in_buffer */
  16461. +    read_chan,        /* read */
  16462. +    write_chan,        /* write */
  16463. +    n_tty_ioctl,        /* ioctl */
  16464. +    n_tty_set_termios,    /* set_termios */
  16465. +    normal_select,        /* select */
  16466. +    n_tty_receive_buf,    /* receive_buf */
  16467. +    n_tty_receive_room,    /* receive_room */
  16468. +    0            /* write_wakeup */
  16469. +};
  16470. +
  16471. diff -urNwbB linux/arch/arm/drivers/char/pty.c linux.arm/arch/arm/drivers/char/pty.c
  16472. --- linux/arch/arm/drivers/char/pty.c    Thu Jan  1 01:00:00 1970
  16473. +++ linux.arm/arch/arm/drivers/char/pty.c    Sun Mar  3 12:46:45 1996
  16474. @@ -0,0 +1,265 @@
  16475. +/*
  16476. + *  linux/arch/arm/drivers/char/pty.c
  16477. + *
  16478. + *  Copyright (C) 1991, 1992  Linus Torvalds
  16479. + *
  16480. + *  Modifications for ARM processor Copyright (C) 1995, 1996 Russell King.
  16481. + */
  16482. +
  16483. +/*
  16484. + *    pty.c
  16485. + *
  16486. + * This module exports the following pty function:
  16487. + *
  16488. + *     int  pty_open(struct tty_struct * tty, struct file * filp);
  16489. + */
  16490. +
  16491. +#include <linux/errno.h>
  16492. +#include <linux/sched.h>
  16493. +#include <linux/interrupt.h>
  16494. +#include <linux/tty.h>
  16495. +#include <linux/tty_flip.h>
  16496. +#include <linux/fcntl.h>
  16497. +#include <linux/string.h>
  16498. +#include <linux/major.h>
  16499. +#include <linux/mm.h>
  16500. +#include <linux/malloc.h>
  16501. +
  16502. +#include <asm/segment.h>
  16503. +#include <asm/system.h>
  16504. +#include <asm/bitops.h>
  16505. +
  16506. +struct pty_struct {
  16507. +    int    magic;
  16508. +    struct wait_queue * open_wait;
  16509. +};
  16510. +
  16511. +#define PTY_MAGIC 0x5001
  16512. +#define PTY_BUF_SIZE 4096/2
  16513. +/*
  16514. + * tmp_buf is used as a temporary buffer by pty_write.  We need to
  16515. + * lock it in case the memcpy_fromfs blocks while swapping in a page,
  16516. + * and some other program tries to do a pty write at the same time.
  16517. + * Since the lock will only come under contention when the system is
  16518. + * swapping and available memory is low, it makes sense to share one
  16519. + * buffer across all the PTY's, since it significantly saves memory if
  16520. + * large numbers of PTY's are open.
  16521. + */
  16522. +static unsigned char *tmp_buf;
  16523. +static struct semaphore tmp_buf_sem = MUTEX;
  16524. +
  16525. +struct tty_driver pty_driver, pty_slave_driver;
  16526. +static int pty_refcount;
  16527. +
  16528. +static struct tty_struct *pty_table[NR_PTYS];
  16529. +static struct termios *pty_termios[NR_PTYS];
  16530. +static struct termios *pty_termios_locked[NR_PTYS];
  16531. +static struct tty_struct *ttyp_table[NR_PTYS];
  16532. +static struct termios *ttyp_termios[NR_PTYS];
  16533. +static struct termios *ttyp_termios_locked[NR_PTYS];
  16534. +static struct pty_struct pty_state[NR_PTYS];
  16535. +
  16536. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  16537. +
  16538. +static void pty_close(struct tty_struct * tty, struct file * filp)
  16539. +{
  16540. +    if (!tty)
  16541. +        return;
  16542. +    if (tty->driver.subtype == PTY_TYPE_MASTER) {
  16543. +        if (tty->count > 1)
  16544. +            printk("master pty_close: count = %d!!\n", tty->count);
  16545. +    } else {
  16546. +        if (tty->count > 2)
  16547. +            return;
  16548. +    }
  16549. +    wake_up_interruptible(&tty->read_wait);
  16550. +    wake_up_interruptible(&tty->write_wait);
  16551. +    if (!tty->link)
  16552. +        return;
  16553. +    wake_up_interruptible(&tty->link->read_wait);
  16554. +    wake_up_interruptible(&tty->link->write_wait);
  16555. +    if (tty->driver.subtype == PTY_TYPE_MASTER)
  16556. +        tty_hangup(tty->link);
  16557. +    else {
  16558. +        start_tty(tty);
  16559. +        set_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
  16560. +    }
  16561. +}
  16562. +
  16563. +/*
  16564. + * The unthrottle routine is called by the line discipline to signal
  16565. + * that it can receive more characters.  For PTY's, the TTY_THROTTLED
  16566. + * flag is always set, to force the line discipline to always call the
  16567. + * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
  16568. + * characters in the queue.  This is necessary since each time this
  16569. + * happens, we need to wake up any sleeping processes that could be
  16570. + * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
  16571. + * for the pty buffer to be drained.
  16572. + */
  16573. +static void pty_unthrottle(struct tty_struct * tty)
  16574. +{
  16575. +    struct tty_struct *o_tty = tty->link;
  16576. +
  16577. +    if (!o_tty)
  16578. +        return;
  16579. +
  16580. +    if ((o_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  16581. +        o_tty->ldisc.write_wakeup)
  16582. +        (o_tty->ldisc.write_wakeup)(o_tty);
  16583. +    wake_up_interruptible(&o_tty->write_wait);
  16584. +    set_bit(TTY_THROTTLED, &tty->flags);
  16585. +}
  16586. +
  16587. +static int pty_write(struct tty_struct * tty, int from_user,
  16588. +               const unsigned char *buf, int count)
  16589. +{
  16590. +    struct tty_struct *to = tty->link;
  16591. +    int    c=0, n, r;
  16592. +    char    *temp_buffer;
  16593. +
  16594. +    if (!to || tty->stopped)
  16595. +        return 0;
  16596. +
  16597. +    if (from_user) {
  16598. +        down(&tmp_buf_sem);
  16599. +        temp_buffer = tmp_buf +
  16600. +            ((tty->driver.subtype-1) * PTY_BUF_SIZE);
  16601. +        while (count > 0) {
  16602. +            n = MIN(count, PTY_BUF_SIZE);
  16603. +            memcpy_fromfs(temp_buffer, buf, n);
  16604. +            r = to->ldisc.receive_room(to);
  16605. +            if (r <= 0)
  16606. +                break;
  16607. +            n = MIN(n, r);
  16608. +            to->ldisc.receive_buf(to, temp_buffer, 0, n);
  16609. +            buf += n;  c+= n;
  16610. +            count -= n;
  16611. +        }
  16612. +        up(&tmp_buf_sem);
  16613. +    } else {
  16614. +        c = MIN(count, to->ldisc.receive_room(to));
  16615. +        to->ldisc.receive_buf(to, buf, 0, c);
  16616. +    }
  16617. +
  16618. +    return c;
  16619. +}
  16620. +
  16621. +static int pty_write_room(struct tty_struct *tty)
  16622. +{
  16623. +    struct tty_struct *to = tty->link;
  16624. +
  16625. +    if (!to || tty->stopped)
  16626. +        return 0;
  16627. +
  16628. +    return to->ldisc.receive_room(to);
  16629. +}
  16630. +
  16631. +static int pty_chars_in_buffer(struct tty_struct *tty)
  16632. +{
  16633. +    struct tty_struct *to = tty->link;
  16634. +
  16635. +    if (!to || !to->ldisc.chars_in_buffer)
  16636. +        return 0;
  16637. +
  16638. +    return to->ldisc.chars_in_buffer(to);
  16639. +}
  16640. +
  16641. +static void pty_flush_buffer(struct tty_struct *tty)
  16642. +{
  16643. +    struct tty_struct *to = tty->link;
  16644. +
  16645. +    if (!to)
  16646. +        return;
  16647. +
  16648. +    if (to->ldisc.flush_buffer)
  16649. +        to->ldisc.flush_buffer(to);
  16650. +
  16651. +    if (to->packet) {
  16652. +        tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
  16653. +        wake_up_interruptible(&to->read_wait);
  16654. +    }
  16655. +}
  16656. +
  16657. +int pty_open(struct tty_struct *tty, struct file * filp)
  16658. +{
  16659. +    int    line;
  16660. +    struct    pty_struct *pty;
  16661. +
  16662. +    if (!tty || !tty->link)
  16663. +        return -ENODEV;
  16664. +    line = MINOR(tty->device) - tty->driver.minor_start;
  16665. +    if ((line < 0) || (line >= NR_PTYS))
  16666. +        return -ENODEV;
  16667. +    pty = pty_state + line;
  16668. +    tty->driver_data = pty;
  16669. +
  16670. +    if (!tmp_buf) {
  16671. +        tmp_buf = (unsigned char *) kmalloc(PTY_BUF_SIZE*2,GFP_KERNEL);
  16672. +        if (!tmp_buf)
  16673. +            return -ENOMEM;
  16674. +    }
  16675. +
  16676. +    if (tty->driver.subtype == PTY_TYPE_SLAVE)
  16677. +        clear_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
  16678. +    wake_up_interruptible(&pty->open_wait);
  16679. +    set_bit(TTY_THROTTLED, &tty->flags);
  16680. +    if (filp->f_flags & O_NDELAY)
  16681. +        return 0;
  16682. +    while (!tty->link->count && !(current->signal & ~current->blocked))
  16683. +        interruptible_sleep_on(&pty->open_wait);
  16684. +    if (!tty->link->count)
  16685. +        return -ERESTARTSYS;
  16686. +    return 0;
  16687. +}
  16688. +
  16689. +int pty_init(void)
  16690. +{
  16691. +    memset(&pty_state, 0, sizeof(pty_state));
  16692. +    memset(&pty_driver, 0, sizeof(struct tty_driver));
  16693. +    pty_driver.magic = TTY_DRIVER_MAGIC;
  16694. +    pty_driver.name = "pty";
  16695. +    pty_driver.major = TTY_MAJOR;
  16696. +    pty_driver.minor_start = 128;
  16697. +    pty_driver.num = NR_PTYS;
  16698. +    pty_driver.type = TTY_DRIVER_TYPE_PTY;
  16699. +    pty_driver.subtype = PTY_TYPE_MASTER;
  16700. +    pty_driver.init_termios = tty_std_termios;
  16701. +    pty_driver.init_termios.c_iflag = 0;
  16702. +    pty_driver.init_termios.c_oflag = 0;
  16703. +    pty_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
  16704. +    pty_driver.init_termios.c_lflag = 0;
  16705. +    pty_driver.flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
  16706. +    pty_driver.refcount = &pty_refcount;
  16707. +    pty_driver.table = pty_table;
  16708. +    pty_driver.termios = pty_termios;
  16709. +    pty_driver.termios_locked = pty_termios_locked;
  16710. +    pty_driver.other = &pty_slave_driver;
  16711. +
  16712. +    pty_driver.open = pty_open;
  16713. +    pty_driver.close = pty_close;
  16714. +    pty_driver.write = pty_write;
  16715. +    pty_driver.write_room = pty_write_room;
  16716. +    pty_driver.flush_buffer = pty_flush_buffer;
  16717. +    pty_driver.chars_in_buffer = pty_chars_in_buffer;
  16718. +    pty_driver.unthrottle = pty_unthrottle;
  16719. +
  16720. +    pty_slave_driver = pty_driver;
  16721. +    pty_slave_driver.name = "ttyp";
  16722. +    pty_slave_driver.subtype = PTY_TYPE_SLAVE;
  16723. +    pty_slave_driver.minor_start = 192;
  16724. +    pty_slave_driver.init_termios = tty_std_termios;
  16725. +    pty_slave_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
  16726. +    pty_slave_driver.table = ttyp_table;
  16727. +    pty_slave_driver.termios = ttyp_termios;
  16728. +    pty_slave_driver.termios_locked = ttyp_termios_locked;
  16729. +    pty_slave_driver.other = &pty_driver;
  16730. +
  16731. +    tmp_buf = 0;
  16732. +
  16733. +    if (tty_register_driver(&pty_driver))
  16734. +        panic("Couldn't register pty driver");
  16735. +    if (tty_register_driver(&pty_slave_driver))
  16736. +        panic("Couldn't register pty slave driver");
  16737. +
  16738. +    return 0;
  16739. +}
  16740. diff -urNwbB linux/arch/arm/drivers/char/selection.h linux.arm/arch/arm/drivers/char/selection.h
  16741. --- linux/arch/arm/drivers/char/selection.h    Thu Jan  1 01:00:00 1970
  16742. +++ linux.arm/arch/arm/drivers/char/selection.h    Sun Feb 11 09:32:21 1996
  16743. @@ -0,0 +1,20 @@
  16744. +/*
  16745. + * selection.h
  16746. + *
  16747. + * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c
  16748. + */
  16749. +extern int sel_cons;
  16750. +
  16751. +extern void clear_selection(void);
  16752. +extern int set_selection(const unsigned long arg, struct tty_struct *tty);
  16753. +extern int paste_selection(struct tty_struct *tty);
  16754. +extern int sel_loadlut(const unsigned long arg);
  16755. +extern int mouse_reporting(void);
  16756. +extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
  16757. +
  16758. +extern unsigned long video_num_columns;
  16759. +extern unsigned long video_num_lines;
  16760. +extern unsigned long video_size_row;
  16761. +
  16762. +extern void do_unblank_screen(void);
  16763. +
  16764. diff -urNwbB linux/arch/arm/drivers/char/serial.c linux.arm/arch/arm/drivers/char/serial.c
  16765. --- linux/arch/arm/drivers/char/serial.c    Thu Jan  1 01:00:00 1970
  16766. +++ linux.arm/arch/arm/drivers/char/serial.c    Sun Mar  3 12:47:09 1996
  16767. @@ -0,0 +1,2715 @@
  16768. +/*
  16769. + *  linux/arch/arm/drivers/char/serial.c
  16770. + *
  16771. + *  Copyright (C) 1991, 1992  Linus Torvalds
  16772. + *
  16773. + *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
  16774. + *  much more extensible to support other serial cards based on the
  16775. + *  16450/16550A UART's.  Added support for the AST FourPort and the
  16776. + *  Accent Async board.  
  16777. + *
  16778. + *  set_serial_info fixed to set the flags, custom divisor, and uart
  16779. + *     type fields.  Fix suggested by Michael K. Johnson 12/12/92.
  16780. + *
  16781. + * This module exports the following rs232 io functions:
  16782. + *
  16783. + *    int rs_init(void);
  16784. + *     int rs_open(struct tty_struct * tty, struct file * filp)
  16785. + *
  16786. + *  Slight modifications for ARM Copyright (C) 1995, 1996 Russell King
  16787. + */
  16788. +
  16789. +#include <linux/errno.h>
  16790. +#include <linux/signal.h>
  16791. +#include <linux/sched.h>
  16792. +#include <linux/timer.h>
  16793. +#include <linux/interrupt.h>
  16794. +#include <linux/tty.h>
  16795. +#include <linux/tty_flip.h>
  16796. +#include <linux/serial.h>
  16797. +#include <linux/serial_reg.h>
  16798. +#include <linux/config.h>
  16799. +#include <linux/major.h>
  16800. +#include <linux/string.h>
  16801. +#include <linux/fcntl.h>
  16802. +#include <linux/ptrace.h>
  16803. +#include <linux/ioport.h>
  16804. +#include <linux/mm.h>
  16805. +
  16806. +#include <asm/system.h>
  16807. +#include <asm/io.h>
  16808. +#include <asm/segment.h>
  16809. +#include <asm/bitops.h>
  16810. +
  16811. +DECLARE_TASK_QUEUE(tq_serial);
  16812. +
  16813. +struct tty_driver serial_driver, callout_driver;
  16814. +static int serial_refcount;
  16815. +
  16816. +/* serial subtype definitions */
  16817. +#define SERIAL_TYPE_NORMAL    1
  16818. +#define SERIAL_TYPE_CALLOUT    2
  16819. +
  16820. +/* number of characters left in xmit buffer before we ask for more */
  16821. +#define WAKEUP_CHARS 256
  16822. +
  16823. +/*
  16824. + * Serial driver configuration section.  Here are the various options:
  16825. + *
  16826. + * CONFIG_HUB6
  16827. + *        Enables support for the venerable Bell Technologies
  16828. + *        HUB6 card.
  16829. + *
  16830. + * SERIAL_PARANOIA_CHECK
  16831. + *         Check the magic number for the async_structure where
  16832. + *         ever possible.
  16833. + */
  16834. +
  16835. +#define SERIAL_PARANOIA_CHECK
  16836. +#define CONFIG_SERIAL_NOPAUSE_IO
  16837. +#define SERIAL_DO_RESTART
  16838. +
  16839. +#undef SERIAL_DEBUG_INTR
  16840. +#undef SERIAL_DEBUG_OPEN
  16841. +#undef SERIAL_DEBUG_FLOW
  16842. +
  16843. +#define RS_STROBE_TIME (10*HZ)
  16844. +#define RS_ISR_PASS_LIMIT 256
  16845. +
  16846. +#define _INLINE_ inline
  16847. +  
  16848. +/*
  16849. + * IRQ_timeout        - How long the timeout should be for each IRQ
  16850. + *                 should be after the IRQ has been active.
  16851. + */
  16852. +
  16853. +static struct async_struct *IRQ_ports[16];
  16854. +static struct rs_multiport_struct rs_multiport[16];
  16855. +static int IRQ_timeout[16];
  16856. +static volatile int rs_irq_triggered;
  16857. +static volatile int rs_triggered;
  16858. +static int rs_wild_int_mask;
  16859. +
  16860. +static void autoconfig(struct async_struct * info);
  16861. +static void change_speed(struct async_struct *info);
  16862. +    
  16863. +/*
  16864. + * This assumes you have a 1.8432 MHz clock for your UART.
  16865. + *
  16866. + * It'd be nice if someone built a serial card with a 24.576 MHz
  16867. + * clock, since the 16550A is capable of handling a top speed of 1.5
  16868. + * megabits/second; but this requires the faster clock.
  16869. + */
  16870. +#define BASE_BAUD ( 1843200 / 16 )
  16871. +
  16872. +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST )
  16873. +
  16874. +struct async_struct rs_table[] = {
  16875. +    /* UART CLK   PORT IRQ     FLAGS        */
  16876. +    { 0, BASE_BAUD, 0x3F8,10, STD_COM_FLAGS },    /* ttyS0 */
  16877. +    { 0, BASE_BAUD, 0x2F8,10, STD_COM_FLAGS },    /* ttyS1 */
  16878. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS2 */
  16879. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS3 */
  16880. +
  16881. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },     /* ttyS4 */
  16882. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS5 */
  16883. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS6 */
  16884. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS7 */
  16885. +
  16886. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS8 */
  16887. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS9 */
  16888. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS10 */
  16889. +    { 0, BASE_BAUD, 0    , 0, STD_COM_FLAGS },    /* ttyS11 */
  16890. +    
  16891. +};
  16892. +
  16893. +#define NR_PORTS    (sizeof(rs_table)/sizeof(struct async_struct))
  16894. +
  16895. +static struct tty_struct *serial_table[NR_PORTS];
  16896. +static struct termios *serial_termios[NR_PORTS];
  16897. +static struct termios *serial_termios_locked[NR_PORTS];
  16898. +
  16899. +#ifndef MIN
  16900. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  16901. +#endif
  16902. +
  16903. +/*
  16904. + * tmp_buf is used as a temporary buffer by serial_write.  We need to
  16905. + * lock it in case the memcpy_fromfs blocks while swapping in a page,
  16906. + * and some other program tries to do a serial write at the same time.
  16907. + * Since the lock will only come under contention when the system is
  16908. + * swapping and available memory is low, it makes sense to share one
  16909. + * buffer across all the serial ports, since it significantly saves
  16910. + * memory if large numbers of serial ports are open.
  16911. + */
  16912. +static unsigned char *tmp_buf = 0;
  16913. +static struct semaphore tmp_buf_sem = MUTEX;
  16914. +
  16915. +static inline int serial_paranoia_check(struct async_struct *info,
  16916. +                    kdev_t device, const char *routine)
  16917. +{
  16918. +#ifdef SERIAL_PARANOIA_CHECK
  16919. +    static const char *badmagic =
  16920. +        "Warning: bad magic number for serial struct (%s) in %s\n";
  16921. +    static const char *badinfo =
  16922. +        "Warning: null async_struct for (%s) in %s\n";
  16923. +
  16924. +    if (!info) {
  16925. +        printk(badinfo, kdevname(device), routine);
  16926. +        return 1;
  16927. +    }
  16928. +    if (info->magic != SERIAL_MAGIC) {
  16929. +        printk(badmagic, kdevname(device), routine);
  16930. +        return 1;
  16931. +    }
  16932. +#endif
  16933. +    return 0;
  16934. +}
  16935. +
  16936. +/*
  16937. + * This is used to figure out the divisor speeds and the timeouts
  16938. + */
  16939. +static int baud_table[] = {
  16940. +    0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
  16941. +    9600, 19200, 38400, 57600, 115200, 0 };
  16942. +
  16943. +static inline unsigned int serial_in(struct async_struct *info, int offset)
  16944. +{
  16945. +#ifdef CONFIG_HUB6
  16946. +    if (info->hub6) {
  16947. +    outb(info->hub6 - 1 + offset, info->port);
  16948. +    return inb(info->port+1);
  16949. +    } else
  16950. +#endif
  16951. +    return inb(info->port + offset);
  16952. +}
  16953. +
  16954. +static inline unsigned int serial_inp(struct async_struct *info, int offset)
  16955. +{
  16956. +#ifdef CONFIG_HUB6
  16957. +    if (info->hub6) {
  16958. +    outb(info->hub6 - 1 + offset, info->port);
  16959. +    return inb_p(info->port+1);
  16960. +    } else
  16961. +#endif
  16962. +#ifdef CONFIG_SERIAL_NOPAUSE_IO
  16963. +    return inb(info->port + offset);
  16964. +#else
  16965. +    return inb_p(info->port + offset);
  16966. +#endif
  16967. +}
  16968. +
  16969. +static inline void serial_out(struct async_struct *info, int offset, int value)
  16970. +{
  16971. +#ifdef CONFIG_HUB6
  16972. +    if (info->hub6) {
  16973. +    outb(info->hub6 - 1 + offset, info->port);
  16974. +    outb(value, info->port+1);
  16975. +    } else
  16976. +#endif
  16977. +    outb(value, info->port+offset);
  16978. +}
  16979. +
  16980. +static inline void serial_outp(struct async_struct *info, int offset,
  16981. +                   int value)
  16982. +{
  16983. +#ifdef CONFIG_HUB6
  16984. +    if (info->hub6) {
  16985. +    outb(info->hub6 - 1 + offset, info->port);
  16986. +    outb_p(value, info->port+1);
  16987. +    } else
  16988. +#endif
  16989. +#ifdef CONFIG_SERIAL_NOPAUSE_IO
  16990. +    outb(value, info->port+offset);
  16991. +#else
  16992. +        outb_p(value, info->port+offset);
  16993. +#endif
  16994. +}
  16995. +
  16996. +/*
  16997. + * ------------------------------------------------------------
  16998. + * rs_stop() and rs_start()
  16999. + *
  17000. + * This routines are called before setting or resetting tty->stopped.
  17001. + * They enable or disable transmitter interrupts, as necessary.
  17002. + * ------------------------------------------------------------
  17003. + */
  17004. +static void rs_stop(struct tty_struct *tty)
  17005. +{
  17006. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  17007. +    unsigned long flags;
  17008. +
  17009. +    if (serial_paranoia_check(info, tty->device, "rs_stop"))
  17010. +        return;
  17011. +    
  17012. +    save_flags(flags); cli();
  17013. +    if (info->IER & UART_IER_THRI) {
  17014. +        info->IER &= ~UART_IER_THRI;
  17015. +        serial_out(info, UART_IER, info->IER);
  17016. +    }
  17017. +    restore_flags(flags);
  17018. +}
  17019. +
  17020. +static void rs_start(struct tty_struct *tty)
  17021. +{
  17022. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  17023. +    unsigned long flags;
  17024. +    
  17025. +    if (serial_paranoia_check(info, tty->device, "rs_start"))
  17026. +        return;
  17027. +    
  17028. +    save_flags(flags); cli();
  17029. +    if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
  17030. +        info->IER |= UART_IER_THRI;
  17031. +        serial_out(info, UART_IER, info->IER);
  17032. +    }
  17033. +    restore_flags(flags);
  17034. +}
  17035. +
  17036. +/*
  17037. + * ----------------------------------------------------------------------
  17038. + *
  17039. + * Here starts the interrupt handling routines.  All of the following
  17040. + * subroutines are declared as inline and are folded into
  17041. + * rs_interrupt().  They were separated out for readability's sake.
  17042. + *
  17043. + * Note: rs_interrupt() is a "fast" interrupt, which means that it
  17044. + * runs with interrupts turned off.  People who may want to modify
  17045. + * rs_interrupt() should try to keep the interrupt handler as fast as
  17046. + * possible.  After you are done making modifications, it is not a bad
  17047. + * idea to do:
  17048. + * 
  17049. + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
  17050. + *
  17051. + * and look at the resulting assemble code in serial.s.
  17052. + *
  17053. + *                 - Ted Ts'o (tytso@mit.edu), 7-Mar-93
  17054. + * -----------------------------------------------------------------------
  17055. + */
  17056. +
  17057. +/*
  17058. + * This is the serial driver's interrupt routine while we are probing
  17059. + * for submarines.
  17060. + */
  17061. +static void rs_probe(int irq, struct pt_regs * regs)
  17062. +{
  17063. +    rs_irq_triggered = irq;
  17064. +    rs_triggered |= 1 << irq;
  17065. +    return;
  17066. +}
  17067. +
  17068. +/*
  17069. + * This routine is used by the interrupt handler to schedule
  17070. + * processing in the software interrupt portion of the driver.
  17071. + */
  17072. +static _INLINE_ void rs_sched_event(struct async_struct *info,
  17073. +                  int event)
  17074. +{
  17075. +    info->event |= 1 << event;
  17076. +    queue_task_irq_off(&info->tqueue, &tq_serial);
  17077. +    mark_bh(SERIAL_BH);
  17078. +}
  17079. +
  17080. +static _INLINE_ void receive_chars(struct async_struct *info,
  17081. +                 int *status)
  17082. +{
  17083. +    struct tty_struct *tty = info->tty;
  17084. +    unsigned char ch;
  17085. +    int ignored = 0;
  17086. +
  17087. +    do {
  17088. +        ch = serial_inp(info, UART_RX);
  17089. +        if (*status & info->ignore_status_mask) {
  17090. +            if (++ignored > 100)
  17091. +                break;
  17092. +            goto ignore_char;
  17093. +        }
  17094. +        if (tty->flip.count >= TTY_FLIPBUF_SIZE)
  17095. +            break;
  17096. +        tty->flip.count++;
  17097. +        if (*status & (UART_LSR_BI)) {
  17098. +            printk("handling break....");
  17099. +            *tty->flip.flag_buf_ptr++ = TTY_BREAK;
  17100. +            if (info->flags & ASYNC_SAK)
  17101. +                do_SAK(tty);
  17102. +        } else if (*status & UART_LSR_PE)
  17103. +            *tty->flip.flag_buf_ptr++ = TTY_PARITY;
  17104. +        else if (*status & UART_LSR_FE)
  17105. +            *tty->flip.flag_buf_ptr++ = TTY_FRAME;
  17106. +        else if (*status & UART_LSR_OE) 
  17107. +            *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
  17108. +        else
  17109. +            *tty->flip.flag_buf_ptr++ = 0;
  17110. +        *tty->flip.char_buf_ptr++ = ch;
  17111. +    ignore_char:
  17112. +        *status = serial_inp(info, UART_LSR) & info->read_status_mask;
  17113. +    } while (*status & UART_LSR_DR);
  17114. +{ unsigned long flags; save_flags (flags); if (!(flags & 0x08000000)) printk ("SERIAL IRQ ON!\n"); }
  17115. +    queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
  17116. +#ifdef SERIAL_DEBUG_INTR
  17117. +    printk("DR...");
  17118. +#endif
  17119. +}
  17120. +
  17121. +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
  17122. +{
  17123. +    int count;
  17124. +    
  17125. +    if (info->x_char) {
  17126. +        serial_outp(info, UART_TX, info->x_char);
  17127. +        info->x_char = 0;
  17128. +        if (intr_done)
  17129. +            *intr_done = 0;
  17130. +        return;
  17131. +    }
  17132. +    if ((info->xmit_cnt <= 0) || info->tty->stopped ||
  17133. +        info->tty->hw_stopped) {
  17134. +        info->IER &= ~UART_IER_THRI;
  17135. +        serial_out(info, UART_IER, info->IER);
  17136. +        return;
  17137. +    }
  17138. +    
  17139. +    count = info->xmit_fifo_size;
  17140. +    do {
  17141. +        serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
  17142. +        info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
  17143. +        if (--info->xmit_cnt <= 0)
  17144. +            break;
  17145. +    } while (--count > 0);
  17146. +    
  17147. +    if (info->xmit_cnt < WAKEUP_CHARS)
  17148. +        rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
  17149. +
  17150. +#ifdef SERIAL_DEBUG_INTR
  17151. +    printk("THRE...");
  17152. +#endif
  17153. +    if (intr_done)
  17154. +        *intr_done = 0;
  17155. +
  17156. +    if (info->xmit_cnt <= 0) {
  17157. +        info->IER &= ~UART_IER_THRI;
  17158. +        serial_out(info, UART_IER, info->IER);
  17159. +    }
  17160. +}
  17161. +
  17162. +static _INLINE_ void check_modem_status(struct async_struct *info)
  17163. +{
  17164. +    int    status;
  17165. +    
  17166. +    status = serial_in(info, UART_MSR);
  17167. +
  17168. +    if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
  17169. +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
  17170. +        printk("ttys%d CD now %s...", info->line,
  17171. +               (status & UART_MSR_DCD) ? "on" : "off");
  17172. +#endif        
  17173. +        if (status & UART_MSR_DCD)
  17174. +            wake_up_interruptible(&info->open_wait);
  17175. +        else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  17176. +               (info->flags & ASYNC_CALLOUT_NOHUP))) {
  17177. +#ifdef SERIAL_DEBUG_OPEN
  17178. +            printk("scheduling hangup...");
  17179. +#endif
  17180. +            queue_task_irq_off(&info->tqueue_hangup,
  17181. +                       &tq_scheduler);
  17182. +        }
  17183. +    }
  17184. +    if (info->flags & ASYNC_CTS_FLOW) {
  17185. +        if (info->tty->hw_stopped) {
  17186. +            if (status & UART_MSR_CTS) {
  17187. +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
  17188. +                printk("CTS tx start...");
  17189. +#endif
  17190. +                info->tty->hw_stopped = 0;
  17191. +                info->IER |= UART_IER_THRI;
  17192. +                serial_out(info, UART_IER, info->IER);
  17193. +                rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
  17194. +                return;
  17195. +            }
  17196. +        } else {
  17197. +            if (!(status & UART_MSR_CTS)) {
  17198. +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
  17199. +                printk("CTS tx stop...");
  17200. +#endif
  17201. +                info->tty->hw_stopped = 1;
  17202. +                info->IER &= ~UART_IER_THRI;
  17203. +                serial_out(info, UART_IER, info->IER);
  17204. +            }
  17205. +        }
  17206. +    }
  17207. +}
  17208. +
  17209. +/*
  17210. + * This is the serial driver's generic interrupt routine
  17211. + */
  17212. +static void rs_interrupt(int irq, struct pt_regs * regs)
  17213. +{
  17214. +    int status;
  17215. +    struct async_struct * info;
  17216. +    int pass_counter = 0;
  17217. +    struct async_struct *end_mark = 0;
  17218. +    int first_multi = 0;
  17219. +    struct rs_multiport_struct *multi;
  17220. +
  17221. +#ifdef SERIAL_DEBUG_INTR
  17222. +    printk("rs_interrupt(%d)...", irq);
  17223. +#endif
  17224. +    
  17225. +    info = IRQ_ports[irq];
  17226. +    if (!info)
  17227. +        return;
  17228. +    
  17229. +    multi = &rs_multiport[irq];
  17230. +    if (multi->port_monitor)
  17231. +        first_multi = inb(multi->port_monitor);
  17232. +
  17233. +    do {
  17234. +        if (!info->tty ||
  17235. +            (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
  17236. +            if (!end_mark)
  17237. +                end_mark = info;
  17238. +            goto next;
  17239. +        }
  17240. +        end_mark = 0;
  17241. +
  17242. +        info->last_active = jiffies;
  17243. +
  17244. +        status = serial_inp(info, UART_LSR) & info->read_status_mask;
  17245. +#ifdef SERIAL_DEBUG_INTR
  17246. +        printk("status = %x...", status);
  17247. +#endif
  17248. +        if (status & UART_LSR_DR)
  17249. +            receive_chars(info, &status);
  17250. +        check_modem_status(info);
  17251. +        if (status & UART_LSR_THRE)
  17252. +            transmit_chars(info, 0);
  17253. +
  17254. +    next:
  17255. +        info = info->next_port;
  17256. +        if (!info) {
  17257. +            info = IRQ_ports[irq];
  17258. +            if (pass_counter++ > RS_ISR_PASS_LIMIT) {
  17259. +#if 0
  17260. +                printk("rs loop break\n");
  17261. +#endif
  17262. +                break;     /* Prevent infinite loops */
  17263. +            }
  17264. +            continue;
  17265. +        }
  17266. +    } while (end_mark != info);
  17267. +    if (multi->port_monitor)
  17268. +        printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
  17269. +               info->irq, first_multi, inb(multi->port_monitor));
  17270. +#ifdef SERIAL_DEBUG_INTR
  17271. +    printk("end.\n");
  17272. +#endif
  17273. +}
  17274. +
  17275. +/*
  17276. + * This is the serial driver's interrupt routine for a single port
  17277. + */
  17278. +static void rs_interrupt_single(int irq, struct pt_regs * regs)
  17279. +{
  17280. +    int status;
  17281. +    int pass_counter = 0;
  17282. +    int first_multi = 0;
  17283. +    struct async_struct * info;
  17284. +    struct rs_multiport_struct *multi;
  17285. +    
  17286. +#ifdef SERIAL_DEBUG_INTR
  17287. +    printk("rs_interrupt_single(%d)...", irq);
  17288. +#endif
  17289. +    
  17290. +    info = IRQ_ports[irq];
  17291. +    if (!info || !info->tty)
  17292. +        return;
  17293. +
  17294. +    multi = &rs_multiport[irq];
  17295. +    if (multi->port_monitor)
  17296. +        first_multi = inb(multi->port_monitor);
  17297. +
  17298. +    do {
  17299. +        status = serial_inp(info, UART_LSR) & info->read_status_mask;
  17300. +#ifdef SERIAL_DEBUG_INTR
  17301. +        printk("status = %x...", status);
  17302. +#endif
  17303. +        if (status & UART_LSR_DR)
  17304. +            receive_chars(info, &status);
  17305. +        check_modem_status(info);
  17306. +        if (status & UART_LSR_THRE)
  17307. +            transmit_chars(info, 0);
  17308. +        if (pass_counter++ > RS_ISR_PASS_LIMIT) {
  17309. +#if 0
  17310. +            printk("rs_single loop break.\n");
  17311. +#endif
  17312. +            break;
  17313. +        }
  17314. +    } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
  17315. +    info->last_active = jiffies;
  17316. +    if (multi->port_monitor)
  17317. +        printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
  17318. +               info->irq, first_multi, inb(multi->port_monitor));
  17319. +#ifdef SERIAL_DEBUG_INTR
  17320. +    printk("end.\n");
  17321. +#endif
  17322. +}
  17323. +
  17324. +/*
  17325. + * This is the serial driver's for multiport boards
  17326. + */
  17327. +static void rs_interrupt_multi(int irq, struct pt_regs * regs)
  17328. +{
  17329. +    int status;
  17330. +    struct async_struct * info;
  17331. +    int pass_counter = 0;
  17332. +    int first_multi= 0;
  17333. +    struct rs_multiport_struct *multi;
  17334. +
  17335. +#ifdef SERIAL_DEBUG_INTR
  17336. +    printk("rs_interrupt_multi(%d)...", irq);
  17337. +#endif
  17338. +    
  17339. +    info = IRQ_ports[irq];
  17340. +    if (!info)
  17341. +        return;
  17342. +    multi = &rs_multiport[irq];
  17343. +    if (!multi->port1) {
  17344. +        /* Should never happen */
  17345. +        printk("rs_interrupt_multi: NULL port1!\n");
  17346. +        return;
  17347. +    }
  17348. +    if (multi->port_monitor)
  17349. +        first_multi = inb(multi->port_monitor);
  17350. +    
  17351. +    while (1) {
  17352. +        if (!info->tty ||
  17353. +            (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
  17354. +            goto next;
  17355. +
  17356. +        info->last_active = jiffies;
  17357. +
  17358. +        status = serial_inp(info, UART_LSR) & info->read_status_mask;
  17359. +#ifdef SERIAL_DEBUG_INTR
  17360. +        printk("status = %x...", status);
  17361. +#endif
  17362. +        if (status & UART_LSR_DR)
  17363. +            receive_chars(info, &status);
  17364. +        check_modem_status(info);
  17365. +        if (status & UART_LSR_THRE)
  17366. +            transmit_chars(info, 0);
  17367. +
  17368. +    next:
  17369. +        info = info->next_port;
  17370. +        if (info)
  17371. +            continue;
  17372. +
  17373. +        info = IRQ_ports[irq];
  17374. +        if (pass_counter++ > RS_ISR_PASS_LIMIT) {
  17375. +#if 1
  17376. +            printk("rs_multi loop break\n");
  17377. +#endif
  17378. +            break;     /* Prevent infinite loops */
  17379. +        }
  17380. +        if (multi->port_monitor)
  17381. +            printk("rs port monitor irq %d: 0x%x, 0x%x\n",
  17382. +                   info->irq, first_multi,
  17383. +                   inb(multi->port_monitor));
  17384. +        if ((inb(multi->port1) & multi->mask1) != multi->match1)
  17385. +            continue;
  17386. +        if (!multi->port2)
  17387. +            break;
  17388. +        if ((inb(multi->port2) & multi->mask2) != multi->match2)
  17389. +            continue;
  17390. +        if (!multi->port3)
  17391. +            break;
  17392. +        if ((inb(multi->port3) & multi->mask3) != multi->match3)
  17393. +            continue;
  17394. +        if (!multi->port4)
  17395. +            break;
  17396. +        if ((inb(multi->port4) & multi->mask4) == multi->match4)
  17397. +            continue;
  17398. +        break;
  17399. +    } 
  17400. +#ifdef SERIAL_DEBUG_INTR
  17401. +    printk("end.\n");
  17402. +#endif
  17403. +}
  17404. +
  17405. +
  17406. +/*
  17407. + * -------------------------------------------------------------------
  17408. + * Here ends the serial interrupt routines.
  17409. + * -------------------------------------------------------------------
  17410. + */
  17411. +
  17412. +/*
  17413. + * This routine is used to handle the "bottom half" processing for the
  17414. + * serial driver, known also the "software interrupt" processing.
  17415. + * This processing is done at the kernel interrupt level, after the
  17416. + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
  17417. + * is where time-consuming activities which can not be done in the
  17418. + * interrupt driver proper are done; the interrupt driver schedules
  17419. + * them using rs_sched_event(), and they get done here.
  17420. + */
  17421. +static void do_serial_bh(void *unused)
  17422. +{
  17423. +    run_task_queue(&tq_serial);
  17424. +}
  17425. +
  17426. +static void do_softint(void *private_)
  17427. +{
  17428. +    struct async_struct    *info = (struct async_struct *) private_;
  17429. +    struct tty_struct    *tty;
  17430. +    
  17431. +    tty = info->tty;
  17432. +    if (!tty)
  17433. +        return;
  17434. +
  17435. +    if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
  17436. +        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  17437. +            tty->ldisc.write_wakeup)
  17438. +            (tty->ldisc.write_wakeup)(tty);
  17439. +        wake_up_interruptible(&tty->write_wait);
  17440. +    }
  17441. +}
  17442. +
  17443. +/*
  17444. + * This routine is called from the scheduler tqueue when the interrupt
  17445. + * routine has signalled that a hangup has occurred.  The path of
  17446. + * hangup processing is:
  17447. + *
  17448. + *     serial interrupt routine -> (scheduler tqueue) ->
  17449. + *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
  17450. + * 
  17451. + */
  17452. +static void do_serial_hangup(void *private_)
  17453. +{
  17454. +    struct async_struct    *info = (struct async_struct *) private_;
  17455. +    struct tty_struct    *tty;
  17456. +    
  17457. +    tty = info->tty;
  17458. +    if (!tty)
  17459. +        return;
  17460. +
  17461. +    tty_hangup(tty);
  17462. +}
  17463. +
  17464. +
  17465. +/*
  17466. + * This subroutine is called when the RS_TIMER goes off.  It is used
  17467. + * by the serial driver to handle ports that do not have an interrupt
  17468. + * (irq=0).  This doesn't work very well for 16450's, but gives barely
  17469. + * passable results for a 16550A.  (Although at the expense of much
  17470. + * CPU overhead).
  17471. + */
  17472. +static void rs_timer(void)
  17473. +{
  17474. +    static unsigned long last_strobe = 0;
  17475. +    struct async_struct *info;
  17476. +    unsigned int    i;
  17477. +
  17478. +    if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
  17479. +        for (i=1; i < 16; i++) {
  17480. +            info = IRQ_ports[i];
  17481. +            if (!info)
  17482. +                continue;
  17483. +            cli();
  17484. +            if (info->next_port) {
  17485. +                do {
  17486. +                    serial_out(info, UART_IER, 0);
  17487. +                    info->IER |= UART_IER_THRI;
  17488. +                    serial_out(info, UART_IER, info->IER);
  17489. +                    info = info->next_port;
  17490. +                } while (info);
  17491. +                if (rs_multiport[i].port1)
  17492. +                    rs_interrupt_multi(i, NULL);
  17493. +                else
  17494. +                    rs_interrupt(i, NULL);
  17495. +            } else
  17496. +                rs_interrupt_single(i, NULL);
  17497. +            sti();
  17498. +        }
  17499. +    }
  17500. +    last_strobe = jiffies;
  17501. +    timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME;
  17502. +    timer_active |= 1 << RS_TIMER;
  17503. +
  17504. +    if (IRQ_ports[0]) {
  17505. +        cli();
  17506. +        rs_interrupt(0, NULL);
  17507. +        sti();
  17508. +
  17509. +        timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
  17510. +    }
  17511. +}
  17512. +
  17513. +/*
  17514. + * ---------------------------------------------------------------
  17515. + * Low level utility subroutines for the serial driver:  routines to
  17516. + * figure out the appropriate timeout for an interrupt chain, routines
  17517. + * to initialize and startup a serial port, and routines to shutdown a
  17518. + * serial port.  Useful stuff like that.
  17519. + * ---------------------------------------------------------------
  17520. + */
  17521. +
  17522. +/*
  17523. + * Grab all interrupts in preparation for doing an automatic irq
  17524. + * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a
  17525. + * mask of irq's which were grabbed and should therefore be freed
  17526. + * using free_all_interrupts().
  17527. + */
  17528. +static int grab_all_interrupts(int dontgrab)
  17529. +{
  17530. +    int             irq_lines = 0;
  17531. +    int            i, mask;
  17532. +    
  17533. +    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
  17534. +        if (!(mask & dontgrab) && !request_irq(i, rs_probe, SA_INTERRUPT, "serial probe")) {
  17535. +            irq_lines |= mask;
  17536. +        }
  17537. +    }
  17538. +    return irq_lines;
  17539. +}
  17540. +
  17541. +/*
  17542. + * Release all interrupts grabbed by grab_all_interrupts
  17543. + */
  17544. +static void free_all_interrupts(int irq_lines)
  17545. +{
  17546. +    int    i;
  17547. +    
  17548. +    for (i = 0; i < 16; i++) {
  17549. +        if (irq_lines & (1 << i))
  17550. +            free_irq(i);
  17551. +    }
  17552. +}
  17553. +
  17554. +/*
  17555. + * This routine figures out the correct timeout for a particular IRQ.
  17556. + * It uses the smallest timeout of all of the serial ports in a
  17557. + * particular interrupt chain.  Now only used for IRQ 0....
  17558. + */
  17559. +static void figure_IRQ_timeout(int irq)
  17560. +{
  17561. +    struct    async_struct    *info;
  17562. +    int    timeout = 60*HZ;    /* 60 seconds === a long time :-) */
  17563. +
  17564. +    info = IRQ_ports[irq];
  17565. +    if (!info) {
  17566. +        IRQ_timeout[irq] = 60*HZ;
  17567. +        return;
  17568. +    }
  17569. +    while (info) {
  17570. +        if (info->timeout < timeout)
  17571. +            timeout = info->timeout;
  17572. +        info = info->next_port;
  17573. +    }
  17574. +    if (!irq)
  17575. +        timeout = timeout / 2;
  17576. +    IRQ_timeout[irq] = timeout ? timeout : 1;
  17577. +}
  17578. +
  17579. +static int startup(struct async_struct * info)
  17580. +{
  17581. +    unsigned short ICP;
  17582. +    unsigned long flags;
  17583. +    int    retval;
  17584. +    void (*handler)(int, struct pt_regs *);
  17585. +
  17586. +    if (info->flags & ASYNC_INITIALIZED)
  17587. +        return 0;
  17588. +
  17589. +    if (!info->port || !info->type) {
  17590. +        if (info->tty)
  17591. +            set_bit(TTY_IO_ERROR, &info->tty->flags);
  17592. +        return 0;
  17593. +    }
  17594. +
  17595. +    if (!info->xmit_buf) {
  17596. +        info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
  17597. +        if (!info->xmit_buf)
  17598. +            return -ENOMEM;
  17599. +    }
  17600. +
  17601. +    save_flags(flags); cli();
  17602. +
  17603. +#ifdef SERIAL_DEBUG_OPEN
  17604. +    printk("starting up ttys%d (irq %d)...", info->line, info->irq);
  17605. +#endif
  17606. +
  17607. +    /*
  17608. +     * Clear the FIFO buffers and disable them
  17609. +     * (they will be reenabled in change_speed())
  17610. +     */
  17611. +    if (info->type == PORT_16650) {
  17612. +        serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  17613. +                         UART_FCR_CLEAR_XMIT));
  17614. +        info->xmit_fifo_size = 1; /* disabled for now */
  17615. +    } else if (info->type == PORT_16550A) {
  17616. +        serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  17617. +                         UART_FCR_CLEAR_XMIT));
  17618. +        info->xmit_fifo_size = 16;
  17619. +    } else
  17620. +        info->xmit_fifo_size = 1;
  17621. +
  17622. +    /*
  17623. +     * At this point there's no way the LSR could still be 0xFF;
  17624. +     * if it is, then bail out, because there's likely no UART
  17625. +     * here.
  17626. +     */
  17627. +    if (serial_inp(info, UART_LSR) == 0xff) {
  17628. +        restore_flags(flags);
  17629. +        if (suser()) {
  17630. +            if (info->tty)
  17631. +                set_bit(TTY_IO_ERROR, &info->tty->flags);
  17632. +            return 0;
  17633. +        } else
  17634. +            return -ENODEV;
  17635. +    }
  17636. +    
  17637. +    /*
  17638. +     * Allocate the IRQ if necessary
  17639. +     */
  17640. +    if (info->irq && (!IRQ_ports[info->irq] ||
  17641. +              !IRQ_ports[info->irq]->next_port)) {
  17642. +        if (IRQ_ports[info->irq]) {
  17643. +            free_irq(info->irq);
  17644. +            if (rs_multiport[info->irq].port1)
  17645. +                handler = rs_interrupt_multi;
  17646. +            else
  17647. +                handler = rs_interrupt;
  17648. +        } else 
  17649. +            handler = rs_interrupt_single;
  17650. +
  17651. +        retval = request_irq(info->irq, handler, SA_INTERRUPT, "serial");
  17652. +        if (retval) {
  17653. +            restore_flags(flags);
  17654. +            if (suser()) {
  17655. +                if (info->tty)
  17656. +                    set_bit(TTY_IO_ERROR,
  17657. +                        &info->tty->flags);
  17658. +                return 0;
  17659. +            } else
  17660. +                return retval;
  17661. +        }
  17662. +    }
  17663. +
  17664. +    /*
  17665. +     * Clear the interrupt registers.
  17666. +     */
  17667. +     /* (void) serial_inp(info, UART_LSR); */   /* (see above) */
  17668. +    (void) serial_inp(info, UART_RX);
  17669. +    (void) serial_inp(info, UART_IIR);
  17670. +    (void) serial_inp(info, UART_MSR);
  17671. +
  17672. +    /*
  17673. +     * Now, initialize the UART 
  17674. +     */
  17675. +    serial_outp(info, UART_LCR, UART_LCR_WLEN8);    /* reset DLAB */
  17676. +    if (info->flags & ASYNC_FOURPORT) {
  17677. +        info->MCR = UART_MCR_DTR | UART_MCR_RTS;
  17678. +        info->MCR_noint = UART_MCR_DTR | UART_MCR_OUT1;
  17679. +    } else {
  17680. +        info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
  17681. +        info->MCR_noint = UART_MCR_DTR | UART_MCR_RTS;
  17682. +    }
  17683. +#if defined(__alpha__) && !defined (CONFIG_PCI)
  17684. +    info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
  17685. +    info->MCR_noint |= UART_MCR_OUT1 | UART_MCR_OUT2;
  17686. +#endif
  17687. +    if (info->irq == 0)
  17688. +        info->MCR = info->MCR_noint;
  17689. +    serial_outp(info, UART_MCR, info->MCR);
  17690. +    
  17691. +    /*
  17692. +     * Finally, enable interrupts
  17693. +     */
  17694. +    info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
  17695. +    serial_outp(info, UART_IER, info->IER);    /* enable interrupts */
  17696. +    
  17697. +    if (info->flags & ASYNC_FOURPORT) {
  17698. +        /* Enable interrupts on the AST Fourport board */
  17699. +        ICP = (info->port & 0xFE0) | 0x01F;
  17700. +        outb_p(0x80, ICP);
  17701. +        (void) inb_p(ICP);
  17702. +    }
  17703. +
  17704. +    /*
  17705. +     * And clear the interrupt registers again for luck.
  17706. +     */
  17707. +    (void)serial_inp(info, UART_LSR);
  17708. +    (void)serial_inp(info, UART_RX);
  17709. +    (void)serial_inp(info, UART_IIR);
  17710. +    (void)serial_inp(info, UART_MSR);
  17711. +
  17712. +    if (info->tty)
  17713. +        clear_bit(TTY_IO_ERROR, &info->tty->flags);
  17714. +    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
  17715. +
  17716. +    /*
  17717. +     * Insert serial port into IRQ chain.
  17718. +     */
  17719. +    info->prev_port = 0;
  17720. +    info->next_port = IRQ_ports[info->irq];
  17721. +    if (info->next_port)
  17722. +        info->next_port->prev_port = info;
  17723. +    IRQ_ports[info->irq] = info;
  17724. +    figure_IRQ_timeout(info->irq);
  17725. +
  17726. +    /*
  17727. +     * Set up serial timers...
  17728. +     */
  17729. +    timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
  17730. +    timer_active |= 1 << RS_TIMER;
  17731. +
  17732. +    /*
  17733. +     * and set the speed of the serial port
  17734. +     */
  17735. +    change_speed(info);
  17736. +
  17737. +    info->flags |= ASYNC_INITIALIZED;
  17738. +    restore_flags(flags);
  17739. +    return 0;
  17740. +}
  17741. +
  17742. +/*
  17743. + * This routine will shutdown a serial port; interrupts are disabled, and
  17744. + * DTR is dropped if the hangup on close termio flag is on.
  17745. + */
  17746. +static void shutdown(struct async_struct * info)
  17747. +{
  17748. +    unsigned long    flags;
  17749. +    int        retval;
  17750. +
  17751. +    if (!(info->flags & ASYNC_INITIALIZED))
  17752. +        return;
  17753. +
  17754. +#ifdef SERIAL_DEBUG_OPEN
  17755. +    printk("Shutting down serial port %d (irq %d)....", info->line,
  17756. +           info->irq);
  17757. +#endif
  17758. +    
  17759. +    save_flags(flags); cli(); /* Disable interrupts */
  17760. +    
  17761. +    /*
  17762. +     * First unlink the serial port from the IRQ chain...
  17763. +     */
  17764. +    if (info->next_port)
  17765. +        info->next_port->prev_port = info->prev_port;
  17766. +    if (info->prev_port)
  17767. +        info->prev_port->next_port = info->next_port;
  17768. +    else
  17769. +        IRQ_ports[info->irq] = info->next_port;
  17770. +    figure_IRQ_timeout(info->irq);
  17771. +    
  17772. +    /*
  17773. +     * Free the IRQ, if necessary
  17774. +     */
  17775. +    if (info->irq && (!IRQ_ports[info->irq] ||
  17776. +              !IRQ_ports[info->irq]->next_port)) {
  17777. +        if (IRQ_ports[info->irq]) {
  17778. +            free_irq(info->irq);
  17779. +            retval = request_irq(info->irq, rs_interrupt_single, SA_INTERRUPT, "serial");
  17780. +            
  17781. +            if (retval)
  17782. +                printk("serial shutdown: request_irq: error %d"
  17783. +                       "  Couldn't reacquire IRQ.\n", retval);
  17784. +        } else
  17785. +            free_irq(info->irq);
  17786. +    }
  17787. +
  17788. +    if (info->xmit_buf) {
  17789. +        free_page((unsigned long) info->xmit_buf);
  17790. +        info->xmit_buf = 0;
  17791. +    }
  17792. +
  17793. +    info->IER = 0;
  17794. +    serial_outp(info, UART_IER, 0x00);    /* disable all intrs */
  17795. +    if (info->flags & ASYNC_FOURPORT) {
  17796. +        /* reset interrupts on the AST Fourport board */
  17797. +        (void) inb((info->port & 0xFE0) | 0x01F);
  17798. +    }
  17799. +    
  17800. +    if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
  17801. +        info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
  17802. +        info->MCR_noint &= ~(UART_MCR_DTR|UART_MCR_RTS);
  17803. +    }
  17804. +    serial_outp(info, UART_MCR, info->MCR_noint);
  17805. +
  17806. +    /* disable FIFO's */    
  17807. +    serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  17808. +                     UART_FCR_CLEAR_XMIT));
  17809. +    (void)serial_in(info, UART_RX);    /* read data port to reset things */
  17810. +    
  17811. +    if (info->tty)
  17812. +        set_bit(TTY_IO_ERROR, &info->tty->flags);
  17813. +    
  17814. +    info->flags &= ~ASYNC_INITIALIZED;
  17815. +    restore_flags(flags);
  17816. +}
  17817. +
  17818. +/*
  17819. + * This routine is called to set the UART divisor registers to match
  17820. + * the specified baud rate for a serial port.
  17821. + */
  17822. +static void change_speed(struct async_struct *info)
  17823. +{
  17824. +    unsigned short port;
  17825. +    int    quot = 0;
  17826. +    unsigned cflag,cval,fcr;
  17827. +    int    i;
  17828. +
  17829. +    if (!info->tty || !info->tty->termios)
  17830. +        return;
  17831. +    cflag = info->tty->termios->c_cflag;
  17832. +    if (!(port = info->port))
  17833. +        return;
  17834. +    i = cflag & CBAUD;
  17835. +    if (i & CBAUDEX) {
  17836. +        i &= ~CBAUDEX;
  17837. +        if (i < 1 || i > 2) 
  17838. +            info->tty->termios->c_cflag &= ~CBAUDEX;
  17839. +        else
  17840. +            i += 15;
  17841. +    }
  17842. +    if (i == 15) {
  17843. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
  17844. +            i += 1;
  17845. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
  17846. +            i += 2;
  17847. +        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
  17848. +            quot = info->custom_divisor;
  17849. +    }
  17850. +    if (quot) {
  17851. +        info->timeout = ((info->xmit_fifo_size*HZ*15*quot) /
  17852. +                 info->baud_base) + 2;
  17853. +    } else if (baud_table[i] == 134) {
  17854. +        quot = (2*info->baud_base / 269);
  17855. +        info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
  17856. +    } else if (baud_table[i]) {
  17857. +        quot = info->baud_base / baud_table[i];
  17858. +        info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
  17859. +    } else {
  17860. +        quot = 0;
  17861. +        info->timeout = 0;
  17862. +    }
  17863. +    if (quot) {
  17864. +        info->MCR |= UART_MCR_DTR;
  17865. +        info->MCR_noint |= UART_MCR_DTR;
  17866. +        cli();
  17867. +        serial_out(info, UART_MCR, info->MCR);
  17868. +        sti();
  17869. +    } else {
  17870. +        info->MCR &= ~UART_MCR_DTR;
  17871. +        info->MCR_noint &= ~UART_MCR_DTR;
  17872. +        cli();
  17873. +        serial_out(info, UART_MCR, info->MCR);
  17874. +        sti();
  17875. +        return;
  17876. +    }
  17877. +    /* byte size and parity */
  17878. +    switch (cflag & CSIZE) {
  17879. +        case CS5: cval = 0x00; break;
  17880. +        case CS6: cval = 0x01; break;
  17881. +        case CS7: cval = 0x02; break;
  17882. +        case CS8: cval = 0x03; break;
  17883. +        default: cval = 0x00; break;   /* too keep GCC shut... */
  17884. +    }
  17885. +    if (cflag & CSTOPB) {
  17886. +        cval |= 0x04;
  17887. +    }    
  17888. +    if (cflag & PARENB)
  17889. +        cval |= UART_LCR_PARITY;
  17890. +    if (!(cflag & PARODD))
  17891. +        cval |= UART_LCR_EPAR;
  17892. +    if (info->type == PORT_16550A) {
  17893. +        if ((info->baud_base / quot) < 2400)
  17894. +            fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
  17895. +        else
  17896. +            fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
  17897. +    } else if (info->type == PORT_16650) {
  17898. +        /*
  17899. +         * On the 16650, we disable the FIFOs altogether
  17900. +         * because of a design bug in how the implement
  17901. +         * things.  We could support it by completely changing
  17902. +         * how we handle the interrupt driver, but not today....
  17903. +         *
  17904. +         * N.B.  Because there's no way to set a FIFO trigger
  17905. +         * at 1 char, we'd probably disable at speed below
  17906. +         * 2400 baud anyway...
  17907. +         */
  17908. +        fcr = 0;
  17909. +    } else
  17910. +        fcr = 0;
  17911. +    
  17912. +    /* CTS flow control flag and modem status interrupts */
  17913. +    info->IER &= ~UART_IER_MSI;
  17914. +    if (cflag & CRTSCTS) {
  17915. +        info->flags |= ASYNC_CTS_FLOW;
  17916. +        info->IER |= UART_IER_MSI;
  17917. +    } else
  17918. +        info->flags &= ~ASYNC_CTS_FLOW;
  17919. +    if (cflag & CLOCAL)
  17920. +        info->flags &= ~ASYNC_CHECK_CD;
  17921. +    else {
  17922. +        info->flags |= ASYNC_CHECK_CD;
  17923. +        info->IER |= UART_IER_MSI;
  17924. +    }
  17925. +    serial_out(info, UART_IER, info->IER);
  17926. +
  17927. +    /*
  17928. +     * Set up parity check flag
  17929. +     */
  17930. +    info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
  17931. +    if (I_INPCK(info->tty))
  17932. +        info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
  17933. +    if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
  17934. +        info->read_status_mask |= UART_LSR_BI;
  17935. +    
  17936. +    info->ignore_status_mask = 0;
  17937. +    if (I_IGNPAR(info->tty)) {
  17938. +        info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
  17939. +        info->read_status_mask |= UART_LSR_PE | UART_LSR_FE;
  17940. +    }
  17941. +    if (I_IGNBRK(info->tty)) {
  17942. +        info->ignore_status_mask |= UART_LSR_BI;
  17943. +        info->read_status_mask |= UART_LSR_BI;
  17944. +        /*
  17945. +         * If we're ignore parity and break indicators, ignore 
  17946. +         * overruns too.  (For real raw support).
  17947. +         */
  17948. +        if (I_IGNPAR(info->tty)) {
  17949. +            info->ignore_status_mask |= UART_LSR_OE;
  17950. +            info->read_status_mask |= UART_LSR_OE;
  17951. +        }
  17952. +    }
  17953. +    
  17954. +    cli();
  17955. +    serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);    /* set DLAB */
  17956. +    serial_outp(info, UART_DLL, quot & 0xff);    /* LS of divisor */
  17957. +    serial_outp(info, UART_DLM, quot >> 8);        /* MS of divisor */
  17958. +    serial_outp(info, UART_LCR, cval);        /* reset DLAB */
  17959. +    serial_outp(info, UART_FCR, fcr);     /* set fcr */
  17960. +    sti();
  17961. +}
  17962. +
  17963. +static void rs_put_char(struct tty_struct *tty, unsigned char ch)
  17964. +{
  17965. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  17966. +    unsigned long flags;
  17967. +
  17968. +    if (serial_paranoia_check(info, tty->device, "rs_put_char"))
  17969. +        return;
  17970. +
  17971. +    if (!tty || !info->xmit_buf)
  17972. +        return;
  17973. +
  17974. +    save_flags(flags); cli();
  17975. +    if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
  17976. +        restore_flags(flags);
  17977. +        return;
  17978. +    }
  17979. +
  17980. +    info->xmit_buf[info->xmit_head++] = ch;
  17981. +    info->xmit_head &= SERIAL_XMIT_SIZE-1;
  17982. +    info->xmit_cnt++;
  17983. +    restore_flags(flags);
  17984. +}
  17985. +
  17986. +static void rs_flush_chars(struct tty_struct *tty)
  17987. +{
  17988. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  17989. +    unsigned long flags;
  17990. +                
  17991. +    if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
  17992. +        return;
  17993. +
  17994. +    if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
  17995. +        !info->xmit_buf)
  17996. +        return;
  17997. +
  17998. +    save_flags(flags); cli();
  17999. +    info->IER |= UART_IER_THRI;
  18000. +    serial_out(info, UART_IER, info->IER);
  18001. +    restore_flags(flags);
  18002. +}
  18003. +
  18004. +static int rs_write(struct tty_struct * tty, int from_user,
  18005. +            const unsigned char *buf, int count)
  18006. +{
  18007. +    int    c, total = 0;
  18008. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  18009. +    unsigned long flags;
  18010. +                
  18011. +    if (serial_paranoia_check(info, tty->device, "rs_write"))
  18012. +        return 0;
  18013. +
  18014. +    if (!tty || !info->xmit_buf || !tmp_buf)
  18015. +        return 0;
  18016. +        
  18017. +    save_flags(flags);
  18018. +    while (1) {
  18019. +        cli();        
  18020. +        c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
  18021. +                   SERIAL_XMIT_SIZE - info->xmit_head));
  18022. +        if (c <= 0)
  18023. +            break;
  18024. +
  18025. +        if (from_user) {
  18026. +            down(&tmp_buf_sem);
  18027. +            memcpy_fromfs(tmp_buf, buf, c);
  18028. +            c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
  18029. +                       SERIAL_XMIT_SIZE - info->xmit_head));
  18030. +            memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
  18031. +            up(&tmp_buf_sem);
  18032. +        } else
  18033. +            memcpy(info->xmit_buf + info->xmit_head, buf, c);
  18034. +        info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
  18035. +        info->xmit_cnt += c;
  18036. +        restore_flags(flags);
  18037. +        buf += c;
  18038. +        count -= c;
  18039. +        total += c;
  18040. +    }
  18041. +    if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
  18042. +        !(info->IER & UART_IER_THRI)) {
  18043. +        info->IER |= UART_IER_THRI;
  18044. +        serial_out(info, UART_IER, info->IER);
  18045. +    }
  18046. +    restore_flags(flags);
  18047. +    return total;
  18048. +}
  18049. +
  18050. +static int rs_write_room(struct tty_struct *tty)
  18051. +{
  18052. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  18053. +    int    ret;
  18054. +                
  18055. +    if (serial_paranoia_check(info, tty->device, "rs_write_room"))
  18056. +        return 0;
  18057. +    ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
  18058. +    if (ret < 0)
  18059. +        ret = 0;
  18060. +    return ret;
  18061. +}
  18062. +
  18063. +static int rs_chars_in_buffer(struct tty_struct *tty)
  18064. +{
  18065. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  18066. +                
  18067. +    if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
  18068. +        return 0;
  18069. +    return info->xmit_cnt;
  18070. +}
  18071. +
  18072. +static void rs_flush_buffer(struct tty_struct *tty)
  18073. +{
  18074. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  18075. +                
  18076. +    if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
  18077. +        return;
  18078. +    cli();
  18079. +    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
  18080. +    sti();
  18081. +    wake_up_interruptible(&tty->write_wait);
  18082. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  18083. +        tty->ldisc.write_wakeup)
  18084. +        (tty->ldisc.write_wakeup)(tty);
  18085. +}
  18086. +
  18087. +/*
  18088. + * ------------------------------------------------------------
  18089. + * rs_throttle()
  18090. + * 
  18091. + * This routine is called by the upper-layer tty layer to signal that
  18092. + * incoming characters should be throttled.
  18093. + * ------------------------------------------------------------
  18094. + */
  18095. +static void rs_throttle(struct tty_struct * tty)
  18096. +{
  18097. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  18098. +#ifdef SERIAL_DEBUG_THROTTLE
  18099. +    char    buf[64];
  18100. +    
  18101. +    printk("throttle %s: %d....\n", _tty_name(tty, buf),
  18102. +           tty->ldisc.chars_in_buffer(tty));
  18103. +#endif
  18104. +
  18105. +    if (serial_paranoia_check(info, tty->device, "rs_throttle"))
  18106. +        return;
  18107. +    
  18108. +    if (I_IXOFF(tty))
  18109. +        info->x_char = STOP_CHAR(tty);
  18110. +
  18111. +    info->MCR &= ~UART_MCR_RTS;
  18112. +    info->MCR_noint &= ~UART_MCR_RTS;
  18113. +    cli();
  18114. +    serial_out(info, UART_MCR, info->MCR);
  18115. +    sti();
  18116. +}
  18117. +
  18118. +static void rs_unthrottle(struct tty_struct * tty)
  18119. +{
  18120. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  18121. +#ifdef SERIAL_DEBUG_THROTTLE
  18122. +    char    buf[64];
  18123. +    
  18124. +    printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
  18125. +           tty->ldisc.chars_in_buffer(tty));
  18126. +#endif
  18127. +
  18128. +    if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
  18129. +        return;
  18130. +    
  18131. +    if (I_IXOFF(tty)) {
  18132. +        if (info->x_char)
  18133. +            info->x_char = 0;
  18134. +        else
  18135. +            info->x_char = START_CHAR(tty);
  18136. +    }
  18137. +    info->MCR |= UART_MCR_RTS;
  18138. +    info->MCR_noint |= UART_MCR_RTS;
  18139. +    cli();
  18140. +    serial_out(info, UART_MCR, info->MCR);
  18141. +    sti();
  18142. +}
  18143. +
  18144. +/*
  18145. + * ------------------------------------------------------------
  18146. + * rs_ioctl() and friends
  18147. + * ------------------------------------------------------------
  18148. + */
  18149. +
  18150. +static int get_serial_info(struct async_struct * info,
  18151. +               struct serial_struct * retinfo)
  18152. +{
  18153. +    struct serial_struct tmp;
  18154. +  
  18155. +    if (!retinfo)
  18156. +        return -EFAULT;
  18157. +    memset(&tmp, 0, sizeof(tmp));
  18158. +    tmp.type = info->type;
  18159. +    tmp.line = info->line;
  18160. +    tmp.port = info->port;
  18161. +    tmp.irq = info->irq;
  18162. +    tmp.flags = info->flags;
  18163. +    tmp.baud_base = info->baud_base;
  18164. +    tmp.close_delay = info->close_delay;
  18165. +    tmp.closing_wait = info->closing_wait;
  18166. +    tmp.custom_divisor = info->custom_divisor;
  18167. +    tmp.hub6 = info->hub6;
  18168. +    memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
  18169. +    return 0;
  18170. +}
  18171. +
  18172. +static int set_serial_info(struct async_struct * info,
  18173. +               struct serial_struct * new_info)
  18174. +{
  18175. +    struct serial_struct new_serial;
  18176. +    struct async_struct old_info;
  18177. +    unsigned int        i,change_irq,change_port;
  18178. +    int             retval = 0;
  18179. +
  18180. +    if (!new_info)
  18181. +        return -EFAULT;
  18182. +    memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
  18183. +    old_info = *info;
  18184. +
  18185. +    change_irq = new_serial.irq != info->irq;
  18186. +    change_port = (new_serial.port != info->port) || (new_serial.hub6 != info->hub6);
  18187. +
  18188. +    if (!suser()) {
  18189. +        if (change_irq || change_port ||
  18190. +            (new_serial.baud_base != info->baud_base) ||
  18191. +            (new_serial.type != info->type) ||
  18192. +            (new_serial.close_delay != info->close_delay) ||
  18193. +            ((new_serial.flags & ~ASYNC_USR_MASK) !=
  18194. +             (info->flags & ~ASYNC_USR_MASK)))
  18195. +            return -EPERM;
  18196. +        info->flags = ((info->flags & ~ASYNC_USR_MASK) |
  18197. +                   (new_serial.flags & ASYNC_USR_MASK));
  18198. +        info->custom_divisor = new_serial.custom_divisor;
  18199. +        goto check_and_exit;
  18200. +    }
  18201. +
  18202. +    if (new_serial.irq == 2)
  18203. +        new_serial.irq = 9;
  18204. +
  18205. +    if ((new_serial.irq > 15) || (new_serial.port > 0xffff) ||
  18206. +        (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
  18207. +        return -EINVAL;
  18208. +    }
  18209. +
  18210. +    /* Make sure address is not already in use */
  18211. +    if (new_serial.type) {
  18212. +        for (i = 0 ; i < NR_PORTS; i++)
  18213. +            if ((info != &rs_table[i]) &&
  18214. +                (rs_table[i].port == new_serial.port) &&
  18215. +                rs_table[i].type)
  18216. +                return -EADDRINUSE;
  18217. +    }
  18218. +
  18219. +    if ((change_port || change_irq) && (info->count > 1))
  18220. +        return -EBUSY;
  18221. +
  18222. +    /*
  18223. +     * OK, past this point, all the error checking has been done.
  18224. +     * At this point, we start making changes.....
  18225. +     */
  18226. +
  18227. +    info->baud_base = new_serial.baud_base;
  18228. +    info->flags = ((info->flags & ~ASYNC_FLAGS) |
  18229. +            (new_serial.flags & ASYNC_FLAGS));
  18230. +    info->custom_divisor = new_serial.custom_divisor;
  18231. +    info->type = new_serial.type;
  18232. +    info->close_delay = new_serial.close_delay * HZ/100;
  18233. +    info->closing_wait = new_serial.closing_wait * HZ/100;
  18234. +
  18235. +    release_region(info->port,8);
  18236. +    if (change_port || change_irq) {
  18237. +        /*
  18238. +         * We need to shutdown the serial port at the old
  18239. +         * port/irq combination.
  18240. +         */
  18241. +        shutdown(info);
  18242. +        info->irq = new_serial.irq;
  18243. +        info->port = new_serial.port;
  18244. +        info->hub6 = new_serial.hub6;
  18245. +    }
  18246. +    if(info->type != PORT_UNKNOWN)
  18247. +        request_region(info->port,8,"serial(set)");
  18248. +
  18249. +    
  18250. +check_and_exit:
  18251. +    if (!info->port || !info->type)
  18252. +        return 0;
  18253. +    if (info->flags & ASYNC_INITIALIZED) {
  18254. +        if (((old_info.flags & ASYNC_SPD_MASK) !=
  18255. +             (info->flags & ASYNC_SPD_MASK)) ||
  18256. +            (old_info.custom_divisor != info->custom_divisor))
  18257. +            change_speed(info);
  18258. +    } else
  18259. +        retval = startup(info);
  18260. +    return retval;
  18261. +}
  18262. +
  18263. +
  18264. +/*
  18265. + * get_lsr_info - get line status register info
  18266. + *
  18267. + * Purpose: Let user call ioctl() to get info when the UART physically
  18268. + *         is emptied.  On bus types like RS485, the transmitter must
  18269. + *         release the bus after transmitting. This must be done when
  18270. + *         the transmit shift register is empty, not be done when the
  18271. + *         transmit holding register is empty.  This functionality
  18272. + *         allows RS485 driver to be written in user space. 
  18273. + */
  18274. +static int get_lsr_info(struct async_struct * info, unsigned int *value)
  18275. +{
  18276. +    unsigned char status;
  18277. +    unsigned int result;
  18278. +
  18279. +    cli();
  18280. +    status = serial_in(info, UART_LSR);
  18281. +    sti();
  18282. +    result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
  18283. +    put_user(result,value);
  18284. +    return 0;
  18285. +}
  18286. +
  18287. +
  18288. +static int get_modem_info(struct async_struct * info, unsigned int *value)
  18289. +{
  18290. +    unsigned char control, status;
  18291. +    unsigned int result;
  18292. +
  18293. +    control = info->MCR;
  18294. +    cli();
  18295. +    status = serial_in(info, UART_MSR);
  18296. +    sti();
  18297. +    result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
  18298. +        | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
  18299. +        | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
  18300. +        | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
  18301. +        | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
  18302. +        | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
  18303. +    put_user(result,value);
  18304. +    return 0;
  18305. +}
  18306. +
  18307. +static int set_modem_info(struct async_struct * info, unsigned int cmd,
  18308. +              unsigned int *value)
  18309. +{
  18310. +    int error;
  18311. +    unsigned int arg;
  18312. +
  18313. +    error = verify_area(VERIFY_READ, value, sizeof(int));
  18314. +    if (error)
  18315. +        return error;
  18316. +    arg = get_user(value);
  18317. +    switch (cmd) {
  18318. +    case TIOCMBIS: 
  18319. +        if (arg & TIOCM_RTS) {
  18320. +            info->MCR |= UART_MCR_RTS;
  18321. +            info->MCR_noint |= UART_MCR_RTS;
  18322. +        }
  18323. +        if (arg & TIOCM_DTR) {
  18324. +            info->MCR |= UART_MCR_DTR;
  18325. +            info->MCR_noint |= UART_MCR_DTR;
  18326. +        }
  18327. +        break;
  18328. +    case TIOCMBIC:
  18329. +        if (arg & TIOCM_RTS) {
  18330. +            info->MCR &= ~UART_MCR_RTS;
  18331. +            info->MCR_noint &= ~UART_MCR_RTS;
  18332. +        }
  18333. +        if (arg & TIOCM_DTR) {
  18334. +            info->MCR &= ~UART_MCR_DTR;
  18335. +            info->MCR_noint &= ~UART_MCR_DTR;
  18336. +        }
  18337. +        break;
  18338. +    case TIOCMSET:
  18339. +        info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR))
  18340. +                 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
  18341. +                 | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
  18342. +        info->MCR_noint = ((info->MCR_noint
  18343. +                    & ~(UART_MCR_RTS | UART_MCR_DTR))
  18344. +                   | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
  18345. +                   | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
  18346. +        break;
  18347. +    default:
  18348. +        return -EINVAL;
  18349. +    }
  18350. +    cli();
  18351. +    serial_out(info, UART_MCR, info->MCR);
  18352. +    sti();
  18353. +    return 0;
  18354. +}
  18355. +
  18356. +static int do_autoconfig(struct async_struct * info)
  18357. +{
  18358. +    int            retval;
  18359. +    
  18360. +    if (!suser())
  18361. +        return -EPERM;
  18362. +    
  18363. +    if (info->count > 1)
  18364. +        return -EBUSY;
  18365. +    
  18366. +    shutdown(info);
  18367. +
  18368. +    cli();
  18369. +    autoconfig(info);
  18370. +    sti();
  18371. +
  18372. +    retval = startup(info);
  18373. +    if (retval)
  18374. +        return retval;
  18375. +    return 0;
  18376. +}
  18377. +
  18378. +
  18379. +/*
  18380. + * This routine sends a break character out the serial port.
  18381. + */
  18382. +static void send_break(    struct async_struct * info, int duration)
  18383. +{
  18384. +    if (!info->port)
  18385. +        return;
  18386. +    current->state = TASK_INTERRUPTIBLE;
  18387. +    current->timeout = jiffies + duration;
  18388. +    cli();
  18389. +    serial_out(info, UART_LCR, serial_inp(info, UART_LCR) | UART_LCR_SBC);
  18390. +    schedule();
  18391. +    serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
  18392. +    sti();
  18393. +}
  18394. +
  18395. +/*
  18396. + * This routine returns a bitfield of "wild interrupts".  Basically,
  18397. + * any unclaimed interrupts which is flapping around.
  18398. + */
  18399. +static int check_wild_interrupts(int doprint)
  18400. +{
  18401. +    int    i, mask;
  18402. +    int    wild_interrupts = 0;
  18403. +    int    irq_lines;
  18404. +    unsigned long timeout;
  18405. +    unsigned long flags;
  18406. +    
  18407. +    /* Turn on interrupts (they may be off) */
  18408. +    save_flags(flags); sti();
  18409. +
  18410. +    irq_lines = grab_all_interrupts(0);
  18411. +    
  18412. +    /*
  18413. +     * Delay for 0.1 seconds -- we use a busy loop since this may 
  18414. +     * occur during the bootup sequence
  18415. +     */
  18416. +    timeout = jiffies+HZ/10;
  18417. +    while (timeout >= jiffies)
  18418. +        ;
  18419. +    
  18420. +    rs_triggered = 0;    /* Reset after letting things settle */
  18421. +
  18422. +    timeout = jiffies+HZ/10;
  18423. +    while (timeout >= jiffies)
  18424. +        ;
  18425. +    
  18426. +    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
  18427. +        if ((rs_triggered & (1 << i)) &&
  18428. +            (irq_lines & (1 << i))) {
  18429. +            wild_interrupts |= mask;
  18430. +            if (doprint)
  18431. +                printk("Wild interrupt?  (IRQ %d)\n", i);
  18432. +        }
  18433. +    }
  18434. +    free_all_interrupts(irq_lines);
  18435. +    restore_flags(flags);
  18436. +    return wild_interrupts;
  18437. +}
  18438. +
  18439. +static int get_multiport_struct(struct async_struct * info,
  18440. +                struct serial_multiport_struct *retinfo)
  18441. +{
  18442. +    struct serial_multiport_struct ret;
  18443. +    struct rs_multiport_struct *multi;
  18444. +    
  18445. +    multi = &rs_multiport[info->irq];
  18446. +
  18447. +    ret.port_monitor = multi->port_monitor;
  18448. +    
  18449. +    ret.port1 = multi->port1;
  18450. +    ret.mask1 = multi->mask1;
  18451. +    ret.match1 = multi->match1;
  18452. +    
  18453. +    ret.port2 = multi->port2;
  18454. +    ret.mask2 = multi->mask2;
  18455. +    ret.match2 = multi->match2;
  18456. +    
  18457. +    ret.port3 = multi->port3;
  18458. +    ret.mask3 = multi->mask3;
  18459. +    ret.match3 = multi->match3;
  18460. +    
  18461. +    ret.port4 = multi->port4;
  18462. +    ret.mask4 = multi->mask4;
  18463. +    ret.match4 = multi->match4;
  18464. +
  18465. +    ret.irq = info->irq;
  18466. +
  18467. +    memcpy_tofs(retinfo,&ret,sizeof(*retinfo));
  18468. +    return 0;
  18469. +    
  18470. +}
  18471. +
  18472. +static int set_multiport_struct(struct async_struct * info,
  18473. +                struct serial_multiport_struct *in_multi)
  18474. +{
  18475. +    struct serial_multiport_struct new_multi;
  18476. +    struct rs_multiport_struct *multi;
  18477. +    int    was_multi, now_multi;
  18478. +    int    retval;
  18479. +    void (*handler)(int, struct pt_regs *);
  18480. +
  18481. +    if (!suser())
  18482. +        return -EPERM;
  18483. +    if (!in_multi)
  18484. +        return -EFAULT;
  18485. +    memcpy_fromfs(&new_multi, in_multi,
  18486. +              sizeof(struct serial_multiport_struct));
  18487. +
  18488. +    if (new_multi.irq != info->irq || info->irq == 0 ||
  18489. +        !IRQ_ports[info->irq])
  18490. +        return -EINVAL;
  18491. +
  18492. +    multi = &rs_multiport[info->irq];
  18493. +    was_multi = (multi->port1 != 0);
  18494. +    
  18495. +    multi->port_monitor = new_multi.port_monitor;
  18496. +    
  18497. +    if (multi->port1)
  18498. +        release_region(multi->port1,1);
  18499. +    multi->port1 = new_multi.port1;
  18500. +    multi->mask1 = new_multi.mask1;
  18501. +    multi->match1 = new_multi.match1;
  18502. +    if (multi->port1)
  18503. +        request_region(multi->port1,1,"serial(multiport1)");
  18504. +
  18505. +    if (multi->port2)
  18506. +        release_region(multi->port2,1);
  18507. +    multi->port2 = new_multi.port2;
  18508. +    multi->mask2 = new_multi.mask2;
  18509. +    multi->match2 = new_multi.match2;
  18510. +    if (multi->port2)
  18511. +        request_region(multi->port2,1,"serial(multiport2)");
  18512. +
  18513. +    if (multi->port3)
  18514. +        release_region(multi->port3,1);
  18515. +    multi->port3 = new_multi.port3;
  18516. +    multi->mask3 = new_multi.mask3;
  18517. +    multi->match3 = new_multi.match3;
  18518. +    if (multi->port3)
  18519. +        request_region(multi->port3,1,"serial(multiport3)");
  18520. +
  18521. +    if (multi->port4)
  18522. +        release_region(multi->port4,1);
  18523. +    multi->port4 = new_multi.port4;
  18524. +    multi->mask4 = new_multi.mask4;
  18525. +    multi->match4 = new_multi.match4;
  18526. +    if (multi->port4)
  18527. +        request_region(multi->port4,1,"serial(multiport4)");
  18528. +
  18529. +    now_multi = (multi->port1 != 0);
  18530. +    
  18531. +    if (IRQ_ports[info->irq]->next_port &&
  18532. +        (was_multi != now_multi)) {
  18533. +        free_irq(info->irq);
  18534. +        if (now_multi)
  18535. +            handler = rs_interrupt_multi;
  18536. +        else
  18537. +            handler = rs_interrupt;
  18538. +
  18539. +        retval = request_irq(info->irq, handler, SA_INTERRUPT,
  18540. +                     "serial");
  18541. +        if (retval) {
  18542. +            printk("Couldn't reallocate serial interrupt "
  18543. +                   "driver!!\n");
  18544. +        }
  18545. +    }
  18546. +
  18547. +    return 0;
  18548. +}
  18549. +
  18550. +static int rs_ioctl(struct tty_struct *tty, struct file * file,
  18551. +            unsigned int cmd, unsigned long arg)
  18552. +{
  18553. +    int error;
  18554. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  18555. +    int retval;
  18556. +
  18557. +    if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
  18558. +        return -ENODEV;
  18559. +
  18560. +    if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
  18561. +        (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
  18562. +        (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
  18563. +        if (tty->flags & (1 << TTY_IO_ERROR))
  18564. +            return -EIO;
  18565. +    }
  18566. +    
  18567. +    switch (cmd) {
  18568. +        case TCSBRK:    /* SVID version: non-zero arg --> no break */
  18569. +            retval = tty_check_change(tty);
  18570. +            if (retval)
  18571. +                return retval;
  18572. +            tty_wait_until_sent(tty, 0);
  18573. +            if (!arg)
  18574. +                send_break(info, HZ/4);    /* 1/4 second */
  18575. +            return 0;
  18576. +        case TCSBRKP:    /* support for POSIX tcsendbreak() */
  18577. +            retval = tty_check_change(tty);
  18578. +            if (retval)
  18579. +                return retval;
  18580. +            tty_wait_until_sent(tty, 0);
  18581. +            send_break(info, arg ? arg*(HZ/10) : HZ/4);
  18582. +            return 0;
  18583. +        case TIOCGSOFTCAR:
  18584. +            error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
  18585. +            if (error)
  18586. +                return error;
  18587. +            put_fs_long(C_CLOCAL(tty) ? 1 : 0,
  18588. +                    (unsigned long *) arg);
  18589. +            return 0;
  18590. +        case TIOCSSOFTCAR:
  18591. +            arg = get_fs_long((unsigned long *) arg);
  18592. +            tty->termios->c_cflag =
  18593. +                ((tty->termios->c_cflag & ~CLOCAL) |
  18594. +                 (arg ? CLOCAL : 0));
  18595. +            return 0;
  18596. +        case TIOCMGET:
  18597. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  18598. +                sizeof(unsigned int));
  18599. +            if (error)
  18600. +                return error;
  18601. +            return get_modem_info(info, (unsigned int *) arg);
  18602. +        case TIOCMBIS:
  18603. +        case TIOCMBIC:
  18604. +        case TIOCMSET:
  18605. +            return set_modem_info(info, cmd, (unsigned int *) arg);
  18606. +        case TIOCGSERIAL:
  18607. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  18608. +                        sizeof(struct serial_struct));
  18609. +            if (error)
  18610. +                return error;
  18611. +            return get_serial_info(info,
  18612. +                           (struct serial_struct *) arg);
  18613. +        case TIOCSSERIAL:
  18614. +            return set_serial_info(info,
  18615. +                           (struct serial_struct *) arg);
  18616. +        case TIOCSERCONFIG:
  18617. +            return do_autoconfig(info);
  18618. +
  18619. +        case TIOCSERGWILD:
  18620. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  18621. +                        sizeof(int));
  18622. +            if (error)
  18623. +                return error;
  18624. +            put_fs_long(rs_wild_int_mask, (unsigned long *) arg);
  18625. +            return 0;
  18626. +
  18627. +        case TIOCSERGETLSR: /* Get line status register */
  18628. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  18629. +                sizeof(unsigned int));
  18630. +            if (error)
  18631. +                return error;
  18632. +            else
  18633. +                return get_lsr_info(info, (unsigned int *) arg);
  18634. +
  18635. +        case TIOCSERSWILD:
  18636. +            if (!suser())
  18637. +                return -EPERM;
  18638. +            rs_wild_int_mask = get_fs_long((unsigned long *) arg);
  18639. +            if (rs_wild_int_mask < 0)
  18640. +                rs_wild_int_mask = check_wild_interrupts(0);
  18641. +            return 0;
  18642. +
  18643. +        case TIOCSERGSTRUCT:
  18644. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  18645. +                        sizeof(struct async_struct));
  18646. +            if (error)
  18647. +                return error;
  18648. +            memcpy_tofs((struct async_struct *) arg,
  18649. +                    info, sizeof(struct async_struct));
  18650. +            return 0;
  18651. +            
  18652. +        case TIOCSERGETMULTI:
  18653. +            error = verify_area(VERIFY_WRITE, (void *) arg,
  18654. +                    sizeof(struct serial_multiport_struct));
  18655. +            if (error)
  18656. +                return error;
  18657. +            return get_multiport_struct(info,
  18658. +                       (struct serial_multiport_struct *) arg);
  18659. +        case TIOCSERSETMULTI:
  18660. +            return set_multiport_struct(info,
  18661. +                       (struct serial_multiport_struct *) arg);
  18662. +        default:
  18663. +            return -ENOIOCTLCMD;
  18664. +        }
  18665. +    return 0;
  18666. +}
  18667. +
  18668. +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
  18669. +{
  18670. +    struct async_struct *info = (struct async_struct *)tty->driver_data;
  18671. +
  18672. +    if (tty->termios->c_cflag == old_termios->c_cflag)
  18673. +        return;
  18674. +
  18675. +    change_speed(info);
  18676. +
  18677. +    if ((old_termios->c_cflag & CRTSCTS) &&
  18678. +        !(tty->termios->c_cflag & CRTSCTS)) {
  18679. +        tty->hw_stopped = 0;
  18680. +        rs_start(tty);
  18681. +    }
  18682. +
  18683. +#if 0
  18684. +    /*
  18685. +     * No need to wake up processes in open wait, since they
  18686. +     * sample the CLOCAL flag once, and don't recheck it.
  18687. +     * XXX  It's not clear whether the current behavior is correct
  18688. +     * or not.  Hence, this may change.....
  18689. +     */
  18690. +    if (!(old_termios->c_cflag & CLOCAL) &&
  18691. +        (tty->termios->c_cflag & CLOCAL))
  18692. +        wake_up_interruptible(&info->open_wait);
  18693. +#endif
  18694. +}
  18695. +
  18696. +/*
  18697. + * ------------------------------------------------------------
  18698. + * rs_close()
  18699. + * 
  18700. + * This routine is called when the serial port gets closed.  First, we
  18701. + * wait for the last remaining data to be sent.  Then, we unlink its
  18702. + * async structure from the interrupt chain if necessary, and we free
  18703. + * that IRQ if nothing is left in the chain.
  18704. + * ------------------------------------------------------------
  18705. + */
  18706. +static void rs_close(struct tty_struct *tty, struct file * filp)
  18707. +{
  18708. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  18709. +    unsigned long flags;
  18710. +    unsigned long timeout;
  18711. +
  18712. +    if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
  18713. +        return;
  18714. +    
  18715. +    save_flags(flags); cli();
  18716. +    
  18717. +    if (tty_hung_up_p(filp)) {
  18718. +        restore_flags(flags);
  18719. +        return;
  18720. +    }
  18721. +    
  18722. +#ifdef SERIAL_DEBUG_OPEN
  18723. +    printk("rs_close ttys%d, count = %d\n", info->line, info->count);
  18724. +#endif
  18725. +    if ((tty->count == 1) && (info->count != 1)) {
  18726. +        /*
  18727. +         * Uh, oh.  tty->count is 1, which means that the tty
  18728. +         * structure will be freed.  Info->count should always
  18729. +         * be one in these conditions.  If it's greater than
  18730. +         * one, we've got real problems, since it means the
  18731. +         * serial port won't be shutdown.
  18732. +         */
  18733. +        printk("rs_close: bad serial port count; tty->count is 1, "
  18734. +               "info->count is %d\n", info->count);
  18735. +        info->count = 1;
  18736. +    }
  18737. +    if (--info->count < 0) {
  18738. +        printk("rs_close: bad serial port count for ttys%d: %d\n",
  18739. +               info->line, info->count);
  18740. +        info->count = 0;
  18741. +    }
  18742. +    if (info->count) {
  18743. +        restore_flags(flags);
  18744. +        return;
  18745. +    }
  18746. +    info->flags |= ASYNC_CLOSING;
  18747. +    /*
  18748. +     * Save the termios structure, since this port may have
  18749. +     * separate termios for callout and dialin.
  18750. +     */
  18751. +    if (info->flags & ASYNC_NORMAL_ACTIVE)
  18752. +        info->normal_termios = *tty->termios;
  18753. +    if (info->flags & ASYNC_CALLOUT_ACTIVE)
  18754. +        info->callout_termios = *tty->termios;
  18755. +    /*
  18756. +     * Now we wait for the transmit buffer to clear; and we notify 
  18757. +     * the line discipline to only process XON/XOFF characters.
  18758. +     */
  18759. +    tty->closing = 1;
  18760. +    if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
  18761. +        tty_wait_until_sent(tty, info->closing_wait);
  18762. +    /*
  18763. +     * At this point we stop accepting input.  To do this, we
  18764. +     * disable the receive line status interrupts, and tell the
  18765. +     * interrupt driver to stop checking the data ready bit in the
  18766. +     * line status register.
  18767. +     */
  18768. +    info->IER &= ~UART_IER_RLSI;
  18769. +    info->read_status_mask &= ~UART_LSR_DR;
  18770. +    if (info->flags & ASYNC_INITIALIZED) {
  18771. +        serial_out(info, UART_IER, info->IER);
  18772. +        /*
  18773. +         * Before we drop DTR, make sure the UART transmitter
  18774. +         * has completely drained; this is especially
  18775. +         * important if there is a transmit FIFO!
  18776. +         */
  18777. +        timeout = jiffies+HZ;
  18778. +        while (!(serial_inp(info, UART_LSR) & UART_LSR_TEMT)) {
  18779. +            current->state = TASK_INTERRUPTIBLE;
  18780. +            current->timeout = jiffies + info->timeout;
  18781. +            schedule();
  18782. +            if (jiffies > timeout)
  18783. +                break;
  18784. +        }
  18785. +    }
  18786. +    shutdown(info);
  18787. +    if (tty->driver.flush_buffer)
  18788. +        tty->driver.flush_buffer(tty);
  18789. +    if (tty->ldisc.flush_buffer)
  18790. +        tty->ldisc.flush_buffer(tty);
  18791. +    tty->closing = 0;
  18792. +    info->event = 0;
  18793. +    info->tty = 0;
  18794. +    if (tty->ldisc.num != ldiscs[N_TTY].num) {
  18795. +        if (tty->ldisc.close)
  18796. +            (tty->ldisc.close)(tty);
  18797. +        tty->ldisc = ldiscs[N_TTY];
  18798. +        tty->termios->c_line = N_TTY;
  18799. +        if (tty->ldisc.open)
  18800. +            (tty->ldisc.open)(tty);
  18801. +    }
  18802. +    if (info->blocked_open) {
  18803. +        if (info->close_delay) {
  18804. +            current->state = TASK_INTERRUPTIBLE;
  18805. +            current->timeout = jiffies + info->close_delay;
  18806. +            schedule();
  18807. +        }
  18808. +        wake_up_interruptible(&info->open_wait);
  18809. +    }
  18810. +    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
  18811. +             ASYNC_CLOSING);
  18812. +    wake_up_interruptible(&info->close_wait);
  18813. +    restore_flags(flags);
  18814. +}
  18815. +
  18816. +/*
  18817. + * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
  18818. + */
  18819. +void rs_hangup(struct tty_struct *tty)
  18820. +{
  18821. +    struct async_struct * info = (struct async_struct *)tty->driver_data;
  18822. +    
  18823. +    if (serial_paranoia_check(info, tty->device, "rs_hangup"))
  18824. +        return;
  18825. +    
  18826. +    rs_flush_buffer(tty);
  18827. +    shutdown(info);
  18828. +    info->event = 0;
  18829. +    info->count = 0;
  18830. +    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
  18831. +    info->tty = 0;
  18832. +    wake_up_interruptible(&info->open_wait);
  18833. +}
  18834. +
  18835. +/*
  18836. + * ------------------------------------------------------------
  18837. + * rs_open() and friends
  18838. + * ------------------------------------------------------------
  18839. + */
  18840. +static int block_til_ready(struct tty_struct *tty, struct file * filp,
  18841. +               struct async_struct *info)
  18842. +{
  18843. +    struct wait_queue wait = { current, NULL };
  18844. +    int        retval;
  18845. +    int        do_clocal = 0;
  18846. +
  18847. +    /*
  18848. +     * If the device is in the middle of being closed, then block
  18849. +     * until it's done, and then try again.
  18850. +     */
  18851. +    if (info->flags & ASYNC_CLOSING) {
  18852. +        interruptible_sleep_on(&info->close_wait);
  18853. +#ifdef SERIAL_DO_RESTART
  18854. +        if (info->flags & ASYNC_HUP_NOTIFY)
  18855. +            return -EAGAIN;
  18856. +        else
  18857. +            return -ERESTARTSYS;
  18858. +#else
  18859. +        return -EAGAIN;
  18860. +#endif
  18861. +    }
  18862. +
  18863. +    /*
  18864. +     * If this is a callout device, then just make sure the normal
  18865. +     * device isn't being used.
  18866. +     */
  18867. +    if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
  18868. +        if (info->flags & ASYNC_NORMAL_ACTIVE)
  18869. +            return -EBUSY;
  18870. +        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  18871. +            (info->flags & ASYNC_SESSION_LOCKOUT) &&
  18872. +            (info->session != current->session))
  18873. +            return -EBUSY;
  18874. +        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  18875. +            (info->flags & ASYNC_PGRP_LOCKOUT) &&
  18876. +            (info->pgrp != current->pgrp))
  18877. +            return -EBUSY;
  18878. +        info->flags |= ASYNC_CALLOUT_ACTIVE;
  18879. +        return 0;
  18880. +    }
  18881. +    
  18882. +    /*
  18883. +     * If non-blocking mode is set, or the port is not enabled,
  18884. +     * then make the check up front and then exit.
  18885. +     */
  18886. +    if ((filp->f_flags & O_NONBLOCK) ||
  18887. +        (tty->flags & (1 << TTY_IO_ERROR))) {
  18888. +        if (info->flags & ASYNC_CALLOUT_ACTIVE)
  18889. +            return -EBUSY;
  18890. +        info->flags |= ASYNC_NORMAL_ACTIVE;
  18891. +        return 0;
  18892. +    }
  18893. +
  18894. +    if (info->flags & ASYNC_CALLOUT_ACTIVE) {
  18895. +        if (info->normal_termios.c_cflag & CLOCAL)
  18896. +            do_clocal = 1;
  18897. +    } else {
  18898. +        if (tty->termios->c_cflag & CLOCAL)
  18899. +            do_clocal = 1;
  18900. +    }
  18901. +    
  18902. +    /*
  18903. +     * Block waiting for the carrier detect and the line to become
  18904. +     * free (i.e., not in use by the callout).  While we are in
  18905. +     * this loop, info->count is dropped by one, so that
  18906. +     * rs_close() knows when to free things.  We restore it upon
  18907. +     * exit, either normal or abnormal.
  18908. +     */
  18909. +    retval = 0;
  18910. +    add_wait_queue(&info->open_wait, &wait);
  18911. +#ifdef SERIAL_DEBUG_OPEN
  18912. +    printk("block_til_ready before block: ttys%d, count = %d\n",
  18913. +           info->line, info->count);
  18914. +#endif
  18915. +    info->count--;
  18916. +    info->blocked_open++;
  18917. +    while (1) {
  18918. +        cli();
  18919. +        if (!(info->flags & ASYNC_CALLOUT_ACTIVE))
  18920. +            serial_out(info, UART_MCR,
  18921. +                   serial_inp(info, UART_MCR) |
  18922. +                   (UART_MCR_DTR | UART_MCR_RTS));
  18923. +        sti();
  18924. +        current->state = TASK_INTERRUPTIBLE;
  18925. +        if (tty_hung_up_p(filp) ||
  18926. +            !(info->flags & ASYNC_INITIALIZED)) {
  18927. +#ifdef SERIAL_DO_RESTART
  18928. +            if (info->flags & ASYNC_HUP_NOTIFY)
  18929. +                retval = -EAGAIN;
  18930. +            else
  18931. +                retval = -ERESTARTSYS;    
  18932. +#else
  18933. +            retval = -EAGAIN;
  18934. +#endif
  18935. +            break;
  18936. +        }
  18937. +        if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
  18938. +            !(info->flags & ASYNC_CLOSING) &&
  18939. +            (do_clocal || (serial_in(info, UART_MSR) &
  18940. +                   UART_MSR_DCD)))
  18941. +            break;
  18942. +        if (current->signal & ~current->blocked) {
  18943. +            retval = -ERESTARTSYS;
  18944. +            break;
  18945. +        }
  18946. +#ifdef SERIAL_DEBUG_OPEN
  18947. +        printk("block_til_ready blocking: ttys%d, count = %d\n",
  18948. +               info->line, info->count);
  18949. +#endif
  18950. +        schedule();
  18951. +    }
  18952. +    current->state = TASK_RUNNING;
  18953. +    remove_wait_queue(&info->open_wait, &wait);
  18954. +    if (!tty_hung_up_p(filp))
  18955. +        info->count++;
  18956. +    info->blocked_open--;
  18957. +#ifdef SERIAL_DEBUG_OPEN
  18958. +    printk("block_til_ready after blocking: ttys%d, count = %d\n",
  18959. +           info->line, info->count);
  18960. +#endif
  18961. +    if (retval)
  18962. +        return retval;
  18963. +    info->flags |= ASYNC_NORMAL_ACTIVE;
  18964. +    return 0;
  18965. +}    
  18966. +
  18967. +/*
  18968. + * This routine is called whenever a serial port is opened.  It
  18969. + * enables interrupts for a serial port, linking in its async structure into
  18970. + * the IRQ chain.   It also performs the serial-specific
  18971. + * initialization for the tty structure.
  18972. + */
  18973. +int rs_open(struct tty_struct *tty, struct file * filp)
  18974. +{
  18975. +    struct async_struct    *info;
  18976. +    int             retval, line;
  18977. +
  18978. +    line = MINOR(tty->device) - tty->driver.minor_start;
  18979. +    if ((line < 0) || (line >= NR_PORTS))
  18980. +        return -ENODEV;
  18981. +    info = rs_table + line;
  18982. +    if (serial_paranoia_check(info, tty->device, "rs_open"))
  18983. +        return -ENODEV;
  18984. +
  18985. +#ifdef SERIAL_DEBUG_OPEN
  18986. +    printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
  18987. +           info->count);
  18988. +#endif
  18989. +    info->count++;
  18990. +    tty->driver_data = info;
  18991. +    info->tty = tty;
  18992. +
  18993. +    if (!tmp_buf) {
  18994. +        tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
  18995. +        if (!tmp_buf)
  18996. +            return -ENOMEM;
  18997. +    }
  18998. +    
  18999. +    /*
  19000. +     * Start up serial port
  19001. +     */
  19002. +    retval = startup(info);
  19003. +    if (retval)
  19004. +        return retval;
  19005. +
  19006. +    retval = block_til_ready(tty, filp, info);
  19007. +    if (retval) {
  19008. +#ifdef SERIAL_DEBUG_OPEN
  19009. +        printk("rs_open returning after block_til_ready with %d\n",
  19010. +               retval);
  19011. +#endif
  19012. +        return retval;
  19013. +    }
  19014. +
  19015. +    if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
  19016. +        if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
  19017. +            *tty->termios = info->normal_termios;
  19018. +        else 
  19019. +            *tty->termios = info->callout_termios;
  19020. +        change_speed(info);
  19021. +    }
  19022. +
  19023. +    info->session = current->session;
  19024. +    info->pgrp = current->pgrp;
  19025. +
  19026. +#ifdef SERIAL_DEBUG_OPEN
  19027. +    printk("rs_open ttys%d successful...", info->line);
  19028. +#endif
  19029. +    return 0;
  19030. +}
  19031. +
  19032. +/*
  19033. + * ---------------------------------------------------------------------
  19034. + * rs_init() and friends
  19035. + *
  19036. + * rs_init() is called at boot-time to initialize the serial driver.
  19037. + * ---------------------------------------------------------------------
  19038. + */
  19039. +
  19040. +/*
  19041. + * This routine prints out the appropriate serial driver version
  19042. + * number, and identifies which options were configured into this
  19043. + * driver.
  19044. + */
  19045. +static void show_serial_version(void)
  19046. +{
  19047. +    printk("Serial driver version 4.11 with");
  19048. +#ifdef CONFIG_HUB6
  19049. +    printk(" HUB-6");
  19050. +#define SERIAL_OPT
  19051. +#endif
  19052. +#ifdef SERIAL_OPT
  19053. +    printk(" enabled\n");
  19054. +#else
  19055. +    printk(" no serial options enabled\n");
  19056. +#endif
  19057. +#undef SERIAL_OPT
  19058. +}
  19059. +
  19060. +/*
  19061. + * This routine is called by do_auto_irq(); it attempts to determine
  19062. + * which interrupt a serial port is configured to use.  It is not
  19063. + * fool-proof, but it works a large part of the time.
  19064. + */
  19065. +static int get_auto_irq(struct async_struct *info)
  19066. +{
  19067. +    unsigned char save_MCR, save_IER, save_ICP=0;
  19068. +    unsigned short ICP=0, port = info->port;
  19069. +    unsigned long timeout;
  19070. +    
  19071. +    /*
  19072. +     * Enable interrupts and see who answers
  19073. +     */
  19074. +    rs_irq_triggered = 0;
  19075. +    cli();
  19076. +    save_IER = serial_inp(info, UART_IER);
  19077. +    save_MCR = serial_inp(info, UART_MCR);
  19078. +    if (info->flags & ASYNC_FOURPORT)  {
  19079. +        serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
  19080. +        serial_outp(info, UART_IER, 0x0f);    /* enable all intrs */
  19081. +        ICP = (port & 0xFE0) | 0x01F;
  19082. +        save_ICP = inb_p(ICP);
  19083. +        outb_p(0x80, ICP);
  19084. +        (void) inb_p(ICP);
  19085. +    } else {
  19086. +        serial_outp(info, UART_MCR,
  19087. +                UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
  19088. +        serial_outp(info, UART_IER, 0x0f);    /* enable all intrs */
  19089. +    }
  19090. +    sti();
  19091. +    /*
  19092. +     * Next, clear the interrupt registers.
  19093. +     */
  19094. +    (void)serial_inp(info, UART_LSR);
  19095. +    (void)serial_inp(info, UART_RX);
  19096. +    (void)serial_inp(info, UART_IIR);
  19097. +    (void)serial_inp(info, UART_MSR);
  19098. +    
  19099. +    timeout = jiffies+2*HZ/100;
  19100. +    while (timeout >= jiffies) {
  19101. +        if (rs_irq_triggered)
  19102. +            break;
  19103. +    }
  19104. +    /*
  19105. +     * Now check to see if we got any business, and clean up.
  19106. +     */
  19107. +    cli();
  19108. +    serial_outp(info, UART_IER, save_IER);
  19109. +    serial_outp(info, UART_MCR, save_MCR);
  19110. +    if (info->flags & ASYNC_FOURPORT)
  19111. +        outb_p(save_ICP, ICP);
  19112. +    sti();
  19113. +    return(rs_irq_triggered);
  19114. +}
  19115. +
  19116. +/*
  19117. + * Calls get_auto_irq() multiple times, to make sure we don't get
  19118. + * faked out by random interrupts
  19119. + */
  19120. +static int do_auto_irq(struct async_struct * info)
  19121. +{
  19122. +    unsigned         port = info->port;
  19123. +    int             irq_lines = 0;
  19124. +    int            irq_try_1 = 0, irq_try_2 = 0;
  19125. +    int            retries;
  19126. +    unsigned long flags;
  19127. +
  19128. +    if (!port)
  19129. +        return 0;
  19130. +
  19131. +    /* Turn on interrupts (they may be off) */
  19132. +    save_flags(flags); sti();
  19133. +
  19134. +    irq_lines = grab_all_interrupts(rs_wild_int_mask);
  19135. +    
  19136. +    for (retries = 0; retries < 5; retries++) {
  19137. +        if (!irq_try_1)
  19138. +            irq_try_1 = get_auto_irq(info);
  19139. +        if (!irq_try_2)
  19140. +            irq_try_2 = get_auto_irq(info);
  19141. +        if (irq_try_1 && irq_try_2) {
  19142. +            if (irq_try_1 == irq_try_2)
  19143. +                break;
  19144. +            irq_try_1 = irq_try_2 = 0;
  19145. +        }
  19146. +    }
  19147. +    restore_flags(flags);
  19148. +    free_all_interrupts(irq_lines);
  19149. +    return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
  19150. +}
  19151. +
  19152. +/*
  19153. + * This routine is called by rs_init() to initialize a specific serial
  19154. + * port.  It determines what type of UART ship this serial port is
  19155. + * using: 8250, 16450, 16550, 16550A.  The important question is
  19156. + * whether or not this UART is a 16550A or not, since this will
  19157. + * determine whether or not we can use its FIFO features or not.
  19158. + */
  19159. +static void autoconfig(struct async_struct * info)
  19160. +{
  19161. +    unsigned char status1, status2, scratch, scratch2;
  19162. +    unsigned port = info->port;
  19163. +    unsigned long flags;
  19164. +
  19165. +    info->type = PORT_UNKNOWN;
  19166. +    
  19167. +    if (!port)
  19168. +        return;
  19169. +
  19170. +    save_flags(flags); cli();
  19171. +    
  19172. +    /*
  19173. +     * Do a simple existence test first; if we fail this, there's
  19174. +     * no point trying anything else.
  19175. +     *
  19176. +     * 0x80 is used as a nonsense port to prevent against false
  19177. +     * positives due to ISA bus float.  The assumption is that
  19178. +     * 0x80 is a non-existent port; which should be safe since
  19179. +     * include/asm/io.h also makes this assumption.
  19180. +     */
  19181. +    scratch = serial_inp(info, UART_IER);
  19182. +    serial_outp(info, UART_IER, 0);
  19183. +    outb(0xff, 0x080);
  19184. +    scratch2 = serial_inp(info, UART_IER);
  19185. +    serial_outp(info, UART_IER, scratch);
  19186. +    if (scratch2) {
  19187. +        restore_flags(flags);
  19188. +        return;        /* We failed; there's nothing here */
  19189. +    }
  19190. +
  19191. +    /* 
  19192. +     * Check to see if a UART is really there.  Certain broken
  19193. +     * internal modems based on the Rockwell chipset fail this
  19194. +     * test, because they apparently don't implement the loopback
  19195. +     * test mode.  So this test is skipped on the COM 1 through
  19196. +     * COM 4 ports.  This *should* be safe, since no board
  19197. +     * manufacturer would be stupid enough to design a board
  19198. +     * that conflicts with COM 1-4 --- we hope!
  19199. +     */
  19200. +    if (!(info->flags & ASYNC_SKIP_TEST)) {
  19201. +        scratch = serial_inp(info, UART_MCR);
  19202. +        serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
  19203. +        scratch2 = serial_inp(info, UART_MSR);
  19204. +        serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
  19205. +        status1 = serial_inp(info, UART_MSR) & 0xF0;
  19206. +        serial_outp(info, UART_MCR, scratch);
  19207. +        serial_outp(info, UART_MSR, scratch2);
  19208. +        if (status1 != 0x90) {
  19209. +            restore_flags(flags);
  19210. +            return;
  19211. +        }
  19212. +    } 
  19213. +    
  19214. +    /*
  19215. +     * If the AUTO_IRQ flag is set, try to do the automatic IRQ
  19216. +     * detection.
  19217. +     */
  19218. +    if (info->flags & ASYNC_AUTO_IRQ)
  19219. +        info->irq = do_auto_irq(info);
  19220. +        
  19221. +    scratch2 = serial_in(info, UART_LCR);
  19222. +    serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
  19223. +    serial_outp(info, UART_EFR, 0);    /* EFR is the same as FCR */
  19224. +    serial_outp(info, UART_LCR, scratch2);
  19225. +    serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
  19226. +    scratch = serial_in(info, UART_IIR) >> 6;
  19227. +    info->xmit_fifo_size = 1;
  19228. +    switch (scratch) {
  19229. +        case 0:
  19230. +            info->type = PORT_16450;
  19231. +            break;
  19232. +        case 1:
  19233. +            info->type = PORT_UNKNOWN;
  19234. +            break;
  19235. +        case 2:
  19236. +            info->type = PORT_16550;
  19237. +            break;
  19238. +        case 3:
  19239. +            serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
  19240. +            if (serial_in(info, UART_EFR) == 0) {
  19241. +                info->type = PORT_16650;
  19242. +                info->xmit_fifo_size = 32;
  19243. +            } else {
  19244. +                info->type = PORT_16550A;
  19245. +                info->xmit_fifo_size = 16;
  19246. +            }
  19247. +            serial_outp(info, UART_LCR, scratch2);
  19248. +            break;
  19249. +    }
  19250. +    if (info->type == PORT_16450) {
  19251. +        scratch = serial_in(info, UART_SCR);
  19252. +        serial_outp(info, UART_SCR, 0xa5);
  19253. +        status1 = serial_in(info, UART_SCR);
  19254. +        serial_outp(info, UART_SCR, 0x5a);
  19255. +        status2 = serial_in(info, UART_SCR);
  19256. +        serial_outp(info, UART_SCR, scratch);
  19257. +
  19258. +        if ((status1 != 0xa5) || (status2 != 0x5a))
  19259. +            info->type = PORT_8250;
  19260. +    }
  19261. +    request_region(info->port,8,"serial(auto)");
  19262. +
  19263. +    /*
  19264. +     * Reset the UART.
  19265. +     */
  19266. +#if defined(__alpha__) && !defined(CONFIG_PCI)
  19267. +    /*
  19268. +     * I wonder what DEC did to the OUT1 and OUT2 lines?
  19269. +     * clearing them results in endless interrupts.
  19270. +     */
  19271. +    serial_outp(info, UART_MCR, 0x0c);
  19272. +#else
  19273. +    serial_outp(info, UART_MCR, 0x00);
  19274. +#endif
  19275. +    serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
  19276. +                     UART_FCR_CLEAR_XMIT));
  19277. +    (void)serial_in(info, UART_RX);
  19278. +    
  19279. +    restore_flags(flags);
  19280. +}
  19281. +
  19282. +/*
  19283. + * The serial driver boot-time initialization code!
  19284. + */
  19285. +int rs_init(void)
  19286. +{
  19287. +    int i;
  19288. +    struct async_struct * info;
  19289. +    
  19290. +    bh_base[SERIAL_BH].routine = do_serial_bh;
  19291. +    enable_bh(SERIAL_BH);
  19292. +    timer_table[RS_TIMER].fn = rs_timer;
  19293. +    timer_table[RS_TIMER].expires = 0;
  19294. +#ifdef CONFIG_AUTO_IRQ
  19295. +    rs_wild_int_mask = check_wild_interrupts(1);
  19296. +#endif
  19297. +
  19298. +    for (i = 0; i < 16; i++) {
  19299. +        IRQ_ports[i] = 0;
  19300. +        IRQ_timeout[i] = 0;
  19301. +        memset(&rs_multiport[i], 0, sizeof(struct rs_multiport_struct));
  19302. +    }
  19303. +    
  19304. +    show_serial_version();
  19305. +
  19306. +    /* Initialize the tty_driver structure */
  19307. +    
  19308. +    memset(&serial_driver, 0, sizeof(struct tty_driver));
  19309. +    serial_driver.magic = TTY_DRIVER_MAGIC;
  19310. +    serial_driver.name = "ttyS";
  19311. +    serial_driver.major = TTY_MAJOR;
  19312. +    serial_driver.minor_start = 64;
  19313. +    serial_driver.num = NR_PORTS;
  19314. +    serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
  19315. +    serial_driver.subtype = SERIAL_TYPE_NORMAL;
  19316. +    serial_driver.init_termios = tty_std_termios;
  19317. +    serial_driver.init_termios.c_cflag =
  19318. +        B9600 | CS8 | CREAD | HUPCL | CLOCAL;
  19319. +    serial_driver.flags = TTY_DRIVER_REAL_RAW;
  19320. +    serial_driver.refcount = &serial_refcount;
  19321. +    serial_driver.table = serial_table;
  19322. +    serial_driver.termios = serial_termios;
  19323. +    serial_driver.termios_locked = serial_termios_locked;
  19324. +
  19325. +    serial_driver.open = rs_open;
  19326. +    serial_driver.close = rs_close;
  19327. +    serial_driver.write = rs_write;
  19328. +    serial_driver.put_char = rs_put_char;
  19329. +    serial_driver.flush_chars = rs_flush_chars;
  19330. +    serial_driver.write_room = rs_write_room;
  19331. +    serial_driver.chars_in_buffer = rs_chars_in_buffer;
  19332. +    serial_driver.flush_buffer = rs_flush_buffer;
  19333. +    serial_driver.ioctl = rs_ioctl;
  19334. +    serial_driver.throttle = rs_throttle;
  19335. +    serial_driver.unthrottle = rs_unthrottle;
  19336. +    serial_driver.set_termios = rs_set_termios;
  19337. +    serial_driver.stop = rs_stop;
  19338. +    serial_driver.start = rs_start;
  19339. +    serial_driver.hangup = rs_hangup;
  19340. +
  19341. +    /*
  19342. +     * The callout device is just like normal device except for
  19343. +     * major number and the subtype code.
  19344. +     */
  19345. +    callout_driver = serial_driver;
  19346. +    callout_driver.name = "cua";
  19347. +    callout_driver.major = TTYAUX_MAJOR;
  19348. +    callout_driver.subtype = SERIAL_TYPE_CALLOUT;
  19349. +
  19350. +    if (tty_register_driver(&serial_driver))
  19351. +        panic("Couldn't register serial driver\n");
  19352. +    if (tty_register_driver(&callout_driver))
  19353. +        panic("Couldn't register callout driver\n");
  19354. +    
  19355. +    for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
  19356. +        info->magic = SERIAL_MAGIC;
  19357. +        info->line = i;
  19358. +        info->tty = 0;
  19359. +        info->type = PORT_UNKNOWN;
  19360. +        info->custom_divisor = 0;
  19361. +        info->close_delay = 5*HZ/10;
  19362. +        info->closing_wait = 30*HZ;
  19363. +        info->x_char = 0;
  19364. +        info->event = 0;
  19365. +        info->count = 0;
  19366. +        info->blocked_open = 0;
  19367. +        info->tqueue.routine = do_softint;
  19368. +        info->tqueue.data = info;
  19369. +        info->tqueue_hangup.routine = do_serial_hangup;
  19370. +        info->tqueue_hangup.data = info;
  19371. +        info->callout_termios =callout_driver.init_termios;
  19372. +        info->normal_termios = serial_driver.init_termios;
  19373. +        info->open_wait = 0;
  19374. +        info->close_wait = 0;
  19375. +        info->next_port = 0;
  19376. +        info->prev_port = 0;
  19377. +        if (info->irq == 2)
  19378. +            info->irq = 9;
  19379. +        if (!(info->flags & ASYNC_BOOT_AUTOCONF))
  19380. +            continue;
  19381. +        autoconfig(info);
  19382. +        if (info->type == PORT_UNKNOWN)
  19383. +            continue;
  19384. +        printk("tty%02d%s at 0x%04x (irq = %d)", info->line, 
  19385. +               (info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
  19386. +               info->port, info->irq);
  19387. +        switch (info->type) {
  19388. +            case PORT_8250:
  19389. +                printk(" is a 8250\n");
  19390. +                break;
  19391. +            case PORT_16450:
  19392. +                printk(" is a 16450\n");
  19393. +                break;
  19394. +            case PORT_16550:
  19395. +                printk(" is a 16550\n");
  19396. +                break;
  19397. +            case PORT_16550A:
  19398. +                printk(" is a 16550A\n");
  19399. +                break;
  19400. +            case PORT_16650:
  19401. +                printk(" is a 16650\n");
  19402. +                break;
  19403. +            default:
  19404. +                printk("\n");
  19405. +                break;
  19406. +        }
  19407. +    }
  19408. +    return 0;
  19409. +}
  19410. +
  19411. +/*
  19412. + * register_serial and unregister_serial allows for serial ports to be
  19413. + * configured at run-time, to support PCMCIA modems.
  19414. + */
  19415. +int register_serial(struct serial_struct *req)
  19416. +{
  19417. +    int i;
  19418. +    unsigned long flags;
  19419. +    struct async_struct *info;
  19420. +
  19421. +    save_flags(flags);
  19422. +    cli();
  19423. +    for (i = 0; i < NR_PORTS; i++) {
  19424. +        if (rs_table[i].port == req->port)
  19425. +            break;
  19426. +    }
  19427. +    if (i == NR_PORTS) {
  19428. +        for (i = 0; i < NR_PORTS; i++)
  19429. +            if ((rs_table[i].type == PORT_UNKNOWN) &&
  19430. +                (rs_table[i].count == 0))
  19431. +                break;
  19432. +    }
  19433. +    if (i == NR_PORTS) {
  19434. +        restore_flags(flags);
  19435. +        return -1;
  19436. +    }
  19437. +    info = &rs_table[i];
  19438. +    if (rs_table[i].count) {
  19439. +        restore_flags(flags);
  19440. +        printk("Couldn't configure serial #%d (port=%d,irq=%d): "
  19441. +               "device already open\n", i, req->port, req->irq);
  19442. +        return -1;
  19443. +    }
  19444. +    info->irq = req->irq;
  19445. +    info->port = req->port;
  19446. +    autoconfig(info);
  19447. +    if (info->type == PORT_UNKNOWN) {
  19448. +        restore_flags(flags);
  19449. +        printk("register_serial(): autoconfig failed\n");
  19450. +        return -1;
  19451. +    }
  19452. +    printk("tty%02d at 0x%04x (irq = %d)", info->line, 
  19453. +           info->port, info->irq);
  19454. +    switch (info->type) {
  19455. +    case PORT_8250:
  19456. +        printk(" is a 8250\n"); break;
  19457. +    case PORT_16450:
  19458. +        printk(" is a 16450\n"); break;
  19459. +    case PORT_16550:
  19460. +        printk(" is a 16550\n"); break;
  19461. +    case PORT_16550A:
  19462. +        printk(" is a 16550A\n"); break;
  19463. +    default:
  19464. +        printk("\n"); break;
  19465. +    }
  19466. +    restore_flags(flags);
  19467. +    return info->line;
  19468. +}
  19469. +
  19470. +void unregister_serial(int line)
  19471. +{
  19472. +    unsigned long flags;
  19473. +    struct async_struct *info = &rs_table[line];
  19474. +
  19475. +    save_flags(flags);
  19476. +    cli();
  19477. +    if (info->tty)
  19478. +        tty_hangup(info->tty);
  19479. +    info->type = PORT_UNKNOWN;
  19480. +    printk("tty%02d unloaded\n", info->line);
  19481. +    restore_flags(flags);
  19482. +}
  19483. diff -urNwbB linux/arch/arm/drivers/char/tty_io.c linux.arm/arch/arm/drivers/char/tty_io.c
  19484. --- linux/arch/arm/drivers/char/tty_io.c    Thu Jan  1 01:00:00 1970
  19485. +++ linux.arm/arch/arm/drivers/char/tty_io.c    Sun Mar  3 12:48:37 1996
  19486. @@ -0,0 +1,1799 @@
  19487. +/*
  19488. + *  linux/arch/arm/drivers/char/tty_io.c
  19489. + *
  19490. + *  Copyright (C) 1991, 1992  Linus Torvalds
  19491. + *
  19492. + *  Modifications for ARM processor Copright (C) 1995, 1996 Russell King.
  19493. + */
  19494. +
  19495. +/*
  19496. + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
  19497. + * or rs-channels. It also implements echoing, cooked mode etc.
  19498. + *
  19499. + * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
  19500. + *
  19501. + * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
  19502. + * tty_struct and tty_queue structures.  Previously there was a array
  19503. + * of 256 tty_struct's which was statically allocated, and the
  19504. + * tty_queue structures were allocated at boot time.  Both are now
  19505. + * dynamically allocated only when the tty is open.
  19506. + *
  19507. + * Also restructured routines so that there is more of a separation
  19508. + * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
  19509. + * the low-level tty routines (serial.c, pty.c, console.c).  This
  19510. + * makes for cleaner and more compact code.  -TYT, 9/17/92 
  19511. + *
  19512. + * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
  19513. + * which can be dynamically activated and de-activated by the line
  19514. + * discipline handling modules (like SLIP).
  19515. + *
  19516. + * NOTE: pay no attention to the line discipline code (yet); its
  19517. + * interface is still subject to change in this version...
  19518. + * -- TYT, 1/31/92
  19519. + *
  19520. + * Added functionality to the OPOST tty handling.  No delays, but all
  19521. + * other bits should be there.
  19522. + *    -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
  19523. + *
  19524. + * Rewrote canonical mode and added more termios flags.
  19525. + *     -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
  19526. + *
  19527. + * Reorganized FASYNC support so mouse code can share it.
  19528. + *    -- ctm@ardi.com, 9Sep 95
  19529. + *
  19530. + * Altered get_free_page to kmalloc's for tty structures to save memory
  19531. + *  on the ARM processor
  19532. + *      -- rmk92@ecs.soton.ac.uk
  19533. + */
  19534. +
  19535. +#include <linux/config.h>
  19536. +#include <linux/types.h>
  19537. +#include <linux/major.h>
  19538. +#include <linux/errno.h>
  19539. +#include <linux/signal.h>
  19540. +#include <linux/fcntl.h>
  19541. +#include <linux/sched.h>
  19542. +#include <linux/interrupt.h>
  19543. +#include <linux/tty.h>
  19544. +#include <linux/tty_flip.h>
  19545. +#include <linux/timer.h>
  19546. +#include <linux/ctype.h>
  19547. +#include <linux/kd.h>
  19548. +#include <linux/mm.h>
  19549. +#include <linux/string.h>
  19550. +#include <linux/malloc.h>
  19551. +
  19552. +#include <asm/segment.h>
  19553. +#include <asm/system.h>
  19554. +#include <asm/bitops.h>
  19555. +
  19556. +/*#include <linux/scc.h>*/
  19557. +
  19558. +#include "kbd_kern.h"
  19559. +#include "vt_kern.h"
  19560. +#include "selection.h"
  19561. +
  19562. +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
  19563. +#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
  19564. +
  19565. +#undef TTY_DEBUG_HANGUP
  19566. +
  19567. +#define TTY_PARANOIA_CHECK
  19568. +#define CHECK_TTY_COUNT
  19569. +
  19570. +extern void do_blank_screen(int nopowersave);
  19571. +/*extern void set_vesa_blanking(const unsigned long arg);*/
  19572. +
  19573. +struct termios tty_std_termios;        /* for the benefit of tty drivers  */
  19574. +struct tty_driver *tty_drivers = NULL;    /* linked list of tty drivers */
  19575. +struct tty_ldisc ldiscs[NR_LDISCS];    /* line disc dispatch table    */
  19576. +
  19577. +/*
  19578. + * fg_console is the current virtual console,
  19579. + * last_console is the last used one
  19580. + * redirect is the pseudo-tty that console output
  19581. + * is redirected to if asked by TIOCCONS.
  19582. + */
  19583. +int fg_console = 0;
  19584. +int last_console = 0;
  19585. +struct tty_struct * redirect = NULL;
  19586. +struct wait_queue * keypress_wait = NULL;
  19587. +
  19588. +static void initialize_tty_struct(struct tty_struct *tty);
  19589. +
  19590. +static int tty_read(struct inode *, struct file *, char *, int);
  19591. +static int tty_write(struct inode *, struct file *, const char *, int);
  19592. +static int tty_select(struct inode *, struct file *, int, select_table *);
  19593. +static int tty_open(struct inode *, struct file *);
  19594. +static void tty_release(struct inode *, struct file *);
  19595. +static int tty_ioctl(struct inode * inode, struct file * file,
  19596. +             unsigned int cmd, unsigned long arg);
  19597. +static int tty_fasync(struct inode * inode, struct file * filp, int on);
  19598. +
  19599. +extern void reset_palette(int currcons) ;
  19600. +extern void set_palette(void) ;
  19601. +
  19602. +#ifndef MIN
  19603. +#define MIN(a,b)    ((a) < (b) ? (a) : (b))
  19604. +#endif
  19605. +
  19606. +/*
  19607. + * These two routines return the name of tty.  tty_name() should NOT
  19608. + * be used in interrupt drivers, since it's not re-entrant.  Use
  19609. + * _tty_name() instead.
  19610. + */
  19611. +char *_tty_name(struct tty_struct *tty, char *buf)
  19612. +{
  19613. +    if (tty)
  19614. +        sprintf(buf, "%s%d", tty->driver.name,
  19615. +            MINOR(tty->device) - tty->driver.minor_start +
  19616. +            tty->driver.name_base);
  19617. +    else
  19618. +        strcpy(buf, "NULL tty");
  19619. +    return buf;
  19620. +}
  19621. +
  19622. +char *tty_name(struct tty_struct *tty)
  19623. +{
  19624. +    static char buf[64];
  19625. +
  19626. +    return(_tty_name(tty, buf));
  19627. +}
  19628. +
  19629. +inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
  19630. +                  const char *routine)
  19631. +{
  19632. +#ifdef TTY_PARANOIA_CHECK
  19633. +    static const char *badmagic =
  19634. +        "Warning: bad magic number for tty struct (%s) in %s\n";
  19635. +    static const char *badtty =
  19636. +        "Warning: null TTY for (%s) in %s\n";
  19637. +
  19638. +    if (!tty) {
  19639. +        printk(badtty, kdevname(device), routine);
  19640. +        return 1;
  19641. +    }
  19642. +    if (tty->magic != TTY_MAGIC) {
  19643. +        printk(badmagic, kdevname(device), routine);
  19644. +        return 1;
  19645. +    }
  19646. +#endif
  19647. +    return 0;
  19648. +}
  19649. +
  19650. +static int check_tty_count(struct tty_struct *tty, const char *routine)
  19651. +{
  19652. +#ifdef CHECK_TTY_COUNT
  19653. +    struct file *f;
  19654. +    int i, count = 0;
  19655. +    
  19656. +    for (f = first_file, i=0; i<nr_files; i++, f = f->f_next) {
  19657. +        if (!f->f_count)
  19658. +            continue;
  19659. +        if (f->private_data == tty) {
  19660. +            count++;
  19661. +        }
  19662. +    }
  19663. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  19664. +        tty->driver.subtype == PTY_TYPE_SLAVE &&
  19665. +        tty->link && tty->link->count)
  19666. +        count++;
  19667. +    if (tty->count != count) {
  19668. +        printk("Warning: dev (%s) tty->count(%d) != #fd's(%d) in %s\n",
  19669. +               kdevname(tty->device), tty->count, count, routine);
  19670. +        return count;
  19671. +       }    
  19672. +#endif
  19673. +    return 0;
  19674. +}
  19675. +
  19676. +int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
  19677. +{
  19678. +    if (disc < N_TTY || disc >= NR_LDISCS)
  19679. +        return -EINVAL;
  19680. +    
  19681. +    if (new_ldisc) {
  19682. +        ldiscs[disc] = *new_ldisc;
  19683. +        ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
  19684. +        ldiscs[disc].num = disc;
  19685. +    } else
  19686. +        memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
  19687. +    
  19688. +    return 0;
  19689. +}
  19690. +
  19691. +/* Set the discipline of a tty line. */
  19692. +static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
  19693. +{
  19694. +    int    retval = 0;
  19695. +    struct    tty_ldisc o_ldisc;
  19696. +
  19697. +    if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
  19698. +        !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
  19699. +        return -EINVAL;
  19700. +
  19701. +    if (tty->ldisc.num == ldisc)
  19702. +        return 0;    /* We are already in the desired discipline */
  19703. +    o_ldisc = tty->ldisc;
  19704. +
  19705. +    tty_wait_until_sent(tty, 0);
  19706. +    
  19707. +    /* Shutdown the current discipline. */
  19708. +    if (tty->ldisc.close)
  19709. +        (tty->ldisc.close)(tty);
  19710. +
  19711. +    /* Now set up the new line discipline. */
  19712. +    tty->ldisc = ldiscs[ldisc];
  19713. +    tty->termios->c_line = ldisc;
  19714. +    if (tty->ldisc.open)
  19715. +        retval = (tty->ldisc.open)(tty);
  19716. +    if (retval < 0) {
  19717. +        tty->ldisc = o_ldisc;
  19718. +        tty->termios->c_line = tty->ldisc.num;
  19719. +        if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
  19720. +            tty->ldisc = ldiscs[N_TTY];
  19721. +            tty->termios->c_line = N_TTY;
  19722. +            if (tty->ldisc.open) {
  19723. +                int r = tty->ldisc.open(tty);
  19724. +
  19725. +                if (r < 0)
  19726. +                    panic("Couldn't open N_TTY ldisc for "
  19727. +                          "%s --- error %d.",
  19728. +                          tty_name(tty), r);
  19729. +            }
  19730. +        }
  19731. +    }
  19732. +    if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc)
  19733. +        tty->driver.set_ldisc(tty);
  19734. +    return retval;
  19735. +}
  19736. +
  19737. +/*
  19738. + * This routine returns a tty driver structure, given a device number
  19739. + */
  19740. +struct tty_driver *get_tty_driver(kdev_t device)
  19741. +{
  19742. +    int    major, minor;
  19743. +    struct tty_driver *p;
  19744. +    
  19745. +    minor = MINOR(device);
  19746. +    major = MAJOR(device);
  19747. +
  19748. +    for (p = tty_drivers; p; p = p->next) {
  19749. +        if (p->major != major)
  19750. +            continue;
  19751. +        if (minor < p->minor_start)
  19752. +            continue;
  19753. +        if (minor >= p->minor_start + p->num)
  19754. +            continue;
  19755. +        return p;
  19756. +    }
  19757. +    return NULL;
  19758. +}
  19759. +
  19760. +/*
  19761. + * If we try to write to, or set the state of, a terminal and we're
  19762. + * not in the foreground, send a SIGTTOU.  If the signal is blocked or
  19763. + * ignored, go ahead and perform the operation.  (POSIX 7.2)
  19764. + */
  19765. +int tty_check_change(struct tty_struct * tty)
  19766. +{
  19767. +    if (current->tty != tty)
  19768. +        return 0;
  19769. +    if (tty->pgrp <= 0) {
  19770. +        printk("tty_check_change: tty->pgrp <= 0!\n");
  19771. +        return 0;
  19772. +    }
  19773. +    if (current->pgrp == tty->pgrp)
  19774. +        return 0;
  19775. +    if (is_ignored(SIGTTOU))
  19776. +        return 0;
  19777. +    if (is_orphaned_pgrp(current->pgrp))
  19778. +        return -EIO;
  19779. +    (void) kill_pg(current->pgrp,SIGTTOU,1);
  19780. +    return -ERESTARTSYS;
  19781. +}
  19782. +
  19783. +static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count)
  19784. +{
  19785. +    return 0;
  19786. +}
  19787. +
  19788. +static int hung_up_tty_write(struct inode * inode, struct file * file, const char * buf, int count)
  19789. +{
  19790. +    return -EIO;
  19791. +}
  19792. +
  19793. +static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
  19794. +{
  19795. +    return 1;
  19796. +}
  19797. +
  19798. +static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
  19799. +                 unsigned int cmd, unsigned long arg)
  19800. +{
  19801. +    return -EIO;
  19802. +}
  19803. +
  19804. +static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  19805. +{
  19806. +    return -ESPIPE;
  19807. +}
  19808. +
  19809. +static struct file_operations tty_fops = {
  19810. +    tty_lseek,
  19811. +    tty_read,
  19812. +    tty_write,
  19813. +    NULL,        /* tty_readdir */
  19814. +    tty_select,
  19815. +    tty_ioctl,
  19816. +    NULL,        /* tty_mmap */
  19817. +    tty_open,
  19818. +    tty_release,
  19819. +    NULL,        /* tty_fsync */
  19820. +    tty_fasync
  19821. +};
  19822. +
  19823. +static struct file_operations hung_up_tty_fops = {
  19824. +    tty_lseek,
  19825. +    hung_up_tty_read,
  19826. +    hung_up_tty_write,
  19827. +    NULL,        /* hung_up_tty_readdir */
  19828. +    hung_up_tty_select,
  19829. +    hung_up_tty_ioctl,
  19830. +    NULL,        /* hung_up_tty_mmap */
  19831. +    NULL,        /* hung_up_tty_open */
  19832. +    tty_release,    /* hung_up_tty_release */
  19833. +    NULL,        /* hung_up_tty_fsync  */
  19834. +    NULL        /* hung_up_tty_fasync */
  19835. +};
  19836. +
  19837. +void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
  19838. +{
  19839. +    int i;
  19840. +    struct file * filp;
  19841. +    struct task_struct *p;
  19842. +
  19843. +    if (!tty)
  19844. +        return;
  19845. +    check_tty_count(tty, "do_tty_hangup");
  19846. +    for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) {
  19847. +        if (!filp->f_count)
  19848. +            continue;
  19849. +        if (filp->private_data != tty)
  19850. +            continue;
  19851. +        if (filp->f_inode
  19852. +            && filp->f_inode->i_rdev == CONSOLE_DEV)
  19853. +            continue;
  19854. +        if (filp->f_op != &tty_fops)
  19855. +            continue;
  19856. +        tty_fasync(filp->f_inode, filp, 0);
  19857. +        filp->f_op = fops;
  19858. +    }
  19859. +    
  19860. +    if (tty->ldisc.flush_buffer)
  19861. +        tty->ldisc.flush_buffer(tty);
  19862. +    if (tty->driver.flush_buffer)
  19863. +        tty->driver.flush_buffer(tty);
  19864. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  19865. +        tty->ldisc.write_wakeup)
  19866. +        (tty->ldisc.write_wakeup)(tty);
  19867. +    wake_up_interruptible(&tty->write_wait);
  19868. +    wake_up_interruptible(&tty->read_wait);
  19869. +
  19870. +    /*
  19871. +     * Shutdown the current line discipline, and reset it to
  19872. +     * N_TTY.
  19873. +     */
  19874. +    if (tty->ldisc.num != ldiscs[N_TTY].num) {
  19875. +        if (tty->ldisc.close)
  19876. +            (tty->ldisc.close)(tty);
  19877. +        tty->ldisc = ldiscs[N_TTY];
  19878. +        tty->termios->c_line = N_TTY;
  19879. +        if (tty->ldisc.open) {
  19880. +            i = (tty->ldisc.open)(tty);
  19881. +            if (i < 0)
  19882. +                printk("do_tty_hangup: N_TTY open: error %d\n",
  19883. +                       -i);
  19884. +        }
  19885. +    }
  19886. +    
  19887. +     for_each_task(p) {
  19888. +        if ((tty->session > 0) && (p->session == tty->session) &&
  19889. +            p->leader) {
  19890. +            send_sig(SIGHUP,p,1);
  19891. +            send_sig(SIGCONT,p,1);
  19892. +            if (tty->pgrp > 0)
  19893. +                p->tty_old_pgrp = tty->pgrp;
  19894. +        }
  19895. +        if (p->tty == tty)
  19896. +            p->tty = NULL;
  19897. +    }
  19898. +    tty->flags = 0;
  19899. +    tty->session = 0;
  19900. +    tty->pgrp = -1;
  19901. +    tty->ctrl_status = 0;
  19902. +    if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
  19903. +        *tty->termios = tty->driver.init_termios;
  19904. +    if (tty->driver.hangup)
  19905. +        (tty->driver.hangup)(tty);
  19906. +}
  19907. +
  19908. +void tty_hangup(struct tty_struct * tty)
  19909. +{
  19910. +#ifdef TTY_DEBUG_HANGUP
  19911. +    printk("%s hangup...\n", tty_name(tty));
  19912. +#endif
  19913. +    do_tty_hangup(tty, &hung_up_tty_fops);
  19914. +}
  19915. +
  19916. +void tty_vhangup(struct tty_struct * tty)
  19917. +{
  19918. +#ifdef TTY_DEBUG_HANGUP
  19919. +    printk("%s vhangup...\n", tty_name(tty));
  19920. +#endif
  19921. +    do_tty_hangup(tty, &hung_up_tty_fops);
  19922. +}
  19923. +
  19924. +int tty_hung_up_p(struct file * filp)
  19925. +{
  19926. +    return (filp->f_op == &hung_up_tty_fops);
  19927. +}
  19928. +
  19929. +/*
  19930. + * This function is typically called only by the session leader, when
  19931. + * it wants to disassociate itself from its controlling tty.
  19932. + *
  19933. + * It performs the following functions:
  19934. + *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
  19935. + *     (2)  Clears the tty from being controlling the session
  19936. + *     (3)  Clears the controlling tty for all processes in the
  19937. + *         session group.
  19938. + */
  19939. +void disassociate_ctty(int priv)
  19940. +{
  19941. +    struct tty_struct *tty = current->tty;
  19942. +    struct task_struct *p;
  19943. +
  19944. +    if (!tty) {
  19945. +        if (current->tty_old_pgrp) {
  19946. +            kill_pg(current->tty_old_pgrp, SIGHUP, priv);
  19947. +            kill_pg(current->tty_old_pgrp, SIGCONT, priv);
  19948. +        }
  19949. +        return;
  19950. +    }
  19951. +    if (tty->pgrp > 0) {
  19952. +        kill_pg(tty->pgrp, SIGHUP, priv);
  19953. +        kill_pg(tty->pgrp, SIGCONT, priv);
  19954. +    }
  19955. +
  19956. +    current->tty_old_pgrp = 0;
  19957. +    tty->session = 0;
  19958. +    tty->pgrp = -1;
  19959. +
  19960. +    for_each_task(p)
  19961. +          if (p->session == current->session)
  19962. +            p->tty = NULL;
  19963. +}
  19964. +
  19965. +/*
  19966. + * Sometimes we want to wait until a particular VT has been activated. We
  19967. + * do it in a very simple manner. Everybody waits on a single queue and
  19968. + * get woken up at once. Those that are satisfied go on with their business,
  19969. + * while those not ready go back to sleep. Seems overkill to add a wait
  19970. + * to each vt just for this - usually this does nothing!
  19971. + */
  19972. +static struct wait_queue *vt_activate_queue = NULL;
  19973. +
  19974. +/*
  19975. + * Sleeps until a vt is activated, or the task is interrupted. Returns
  19976. + * 0 if activation, -1 if interrupted.
  19977. + */
  19978. +int vt_waitactive(void)
  19979. +{
  19980. +    interruptible_sleep_on(&vt_activate_queue);
  19981. +    return (current->signal & ~current->blocked) ? -1 : 0;
  19982. +}
  19983. +
  19984. +#define vt_wake_waitactive() wake_up(&vt_activate_queue)
  19985. +
  19986. +void reset_vc(unsigned int new_console)
  19987. +{
  19988. +    vt_cons[new_console]->vc_mode = KD_TEXT;
  19989. +    kbd_table[new_console].kbdmode = VC_XLATE;
  19990. +    vt_cons[new_console]->vt_mode.mode = VT_AUTO;
  19991. +    vt_cons[new_console]->vt_mode.waitv = 0;
  19992. +    vt_cons[new_console]->vt_mode.relsig = 0;
  19993. +    vt_cons[new_console]->vt_mode.acqsig = 0;
  19994. +    vt_cons[new_console]->vt_mode.frsig = 0;
  19995. +    vt_cons[new_console]->vt_pid = -1;
  19996. +    vt_cons[new_console]->vt_newvt = -1;
  19997. +    reset_palette (new_console) ;
  19998. +}
  19999. +
  20000. +/*
  20001. + * Performs the back end of a vt switch
  20002. + */
  20003. +void complete_change_console(unsigned int new_console)
  20004. +{
  20005. +    unsigned char old_vc_mode;
  20006. +
  20007. +        if (new_console == fg_console)
  20008. +                return;
  20009. +        if (!vc_cons_allocated(new_console))
  20010. +                return;
  20011. +    last_console = fg_console;
  20012. +
  20013. +    /*
  20014. +     * If we're switching, we could be going from KD_GRAPHICS to
  20015. +     * KD_TEXT mode or vice versa, which means we need to blank or
  20016. +     * unblank the screen later.
  20017. +     */
  20018. +    old_vc_mode = vt_cons[fg_console]->vc_mode;
  20019. +    update_screen(new_console);
  20020. +
  20021. +    /*
  20022. +     * If this new console is under process control, send it a signal
  20023. +     * telling it that it has acquired. Also check if it has died and
  20024. +     * clean up (similar to logic employed in change_console())
  20025. +     */
  20026. +    if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS)
  20027. +    {
  20028. +        /*
  20029. +         * Send the signal as privileged - kill_proc() will
  20030. +         * tell us if the process has gone or something else
  20031. +         * is awry
  20032. +         */
  20033. +        if (kill_proc(vt_cons[new_console]->vt_pid,
  20034. +                  vt_cons[new_console]->vt_mode.acqsig,
  20035. +                  1) != 0)
  20036. +        {
  20037. +        /*
  20038. +         * The controlling process has died, so we revert back to
  20039. +         * normal operation. In this case, we'll also change back
  20040. +         * to KD_TEXT mode. I'm not sure if this is strictly correct
  20041. +         * but it saves the agony when the X server dies and the screen
  20042. +         * remains blanked due to KD_GRAPHICS! It would be nice to do
  20043. +         * this outside of VT_PROCESS but there is no single process
  20044. +         * to account for and tracking tty count may be undesirable.
  20045. +         */
  20046. +                reset_vc(new_console);
  20047. +        }
  20048. +    }
  20049. +
  20050. +    /*
  20051. +     * We do this here because the controlling process above may have
  20052. +     * gone, and so there is now a new vc_mode
  20053. +     */
  20054. +    if (old_vc_mode != vt_cons[new_console]->vc_mode)
  20055. +    {
  20056. +        if (vt_cons[new_console]->vc_mode == KD_TEXT)
  20057. +            do_unblank_screen();
  20058. +        else
  20059. +            do_blank_screen(1);
  20060. +    }
  20061. +
  20062. +    /* Set the colour palette for this VT */
  20063. +    if (vt_cons[new_console]->vc_mode == KD_TEXT)
  20064. +        set_palette() ;
  20065. +    
  20066. +    /*
  20067. +     * Wake anyone waiting for their VT to activate
  20068. +     */
  20069. +    vt_wake_waitactive();
  20070. +    return;
  20071. +}
  20072. +
  20073. +/*
  20074. + * Performs the front-end of a vt switch
  20075. + */
  20076. +void change_console(unsigned int new_console)
  20077. +{
  20078. +        if (new_console == fg_console)
  20079. +                return;
  20080. +        if (!vc_cons_allocated(new_console))
  20081. +        return;
  20082. +
  20083. +    /*
  20084. +     * If this vt is in process mode, then we need to handshake with
  20085. +     * that process before switching. Essentially, we store where that
  20086. +     * vt wants to switch to and wait for it to tell us when it's done
  20087. +     * (via VT_RELDISP ioctl).
  20088. +     *
  20089. +     * We also check to see if the controlling process still exists.
  20090. +     * If it doesn't, we reset this vt to auto mode and continue.
  20091. +     * This is a cheap way to track process control. The worst thing
  20092. +     * that can happen is: we send a signal to a process, it dies, and
  20093. +     * the switch gets "lost" waiting for a response; hopefully, the
  20094. +     * user will try again, we'll detect the process is gone (unless
  20095. +     * the user waits just the right amount of time :-) and revert the
  20096. +     * vt to auto control.
  20097. +     */
  20098. +    if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS)
  20099. +    {
  20100. +        /*
  20101. +         * Send the signal as privileged - kill_proc() will
  20102. +         * tell us if the process has gone or something else
  20103. +         * is awry
  20104. +         */
  20105. +        if (kill_proc(vt_cons[fg_console]->vt_pid,
  20106. +                  vt_cons[fg_console]->vt_mode.relsig,
  20107. +                  1) == 0)
  20108. +        {
  20109. +            /*
  20110. +             * It worked. Mark the vt to switch to and
  20111. +             * return. The process needs to send us a
  20112. +             * VT_RELDISP ioctl to complete the switch.
  20113. +             */
  20114. +            vt_cons[fg_console]->vt_newvt = new_console;
  20115. +            return;
  20116. +        }
  20117. +
  20118. +        /*
  20119. +         * The controlling process has died, so we revert back to
  20120. +         * normal operation. In this case, we'll also change back
  20121. +         * to KD_TEXT mode. I'm not sure if this is strictly correct
  20122. +         * but it saves the agony when the X server dies and the screen
  20123. +         * remains blanked due to KD_GRAPHICS! It would be nice to do
  20124. +         * this outside of VT_PROCESS but there is no single process
  20125. +         * to account for and tracking tty count may be undesirable.
  20126. +         */
  20127. +        reset_vc(fg_console);
  20128. +
  20129. +        /*
  20130. +         * Fall through to normal (VT_AUTO) handling of the switch...
  20131. +         */
  20132. +    }
  20133. +
  20134. +    /*
  20135. +     * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
  20136. +     */
  20137. +    if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
  20138. +        return;
  20139. +
  20140. +    complete_change_console(new_console);
  20141. +}
  20142. +
  20143. +void wait_for_keypress(void)
  20144. +{
  20145. +    sleep_on(&keypress_wait);
  20146. +}
  20147. +
  20148. +void stop_tty(struct tty_struct *tty)
  20149. +{
  20150. +    if (tty->stopped)
  20151. +        return;
  20152. +    tty->stopped = 1;
  20153. +    if (tty->link && tty->link->packet) {
  20154. +        tty->ctrl_status &= ~TIOCPKT_START;
  20155. +        tty->ctrl_status |= TIOCPKT_STOP;
  20156. +        wake_up_interruptible(&tty->link->read_wait);
  20157. +    }
  20158. +    if (tty->driver.stop)
  20159. +        (tty->driver.stop)(tty);
  20160. +}
  20161. +
  20162. +void start_tty(struct tty_struct *tty)
  20163. +{
  20164. +    if (!tty->stopped)
  20165. +        return;
  20166. +    tty->stopped = 0;
  20167. +    if (tty->link && tty->link->packet) {
  20168. +        tty->ctrl_status &= ~TIOCPKT_STOP;
  20169. +        tty->ctrl_status |= TIOCPKT_START;
  20170. +        wake_up_interruptible(&tty->link->read_wait);
  20171. +    }
  20172. +    if (tty->driver.start)
  20173. +        (tty->driver.start)(tty);
  20174. +    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
  20175. +        tty->ldisc.write_wakeup)
  20176. +        (tty->ldisc.write_wakeup)(tty);
  20177. +    wake_up_interruptible(&tty->write_wait);
  20178. +}
  20179. +
  20180. +static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
  20181. +{
  20182. +    int i;
  20183. +    struct tty_struct * tty;
  20184. +
  20185. +    tty = (struct tty_struct *)file->private_data;
  20186. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_read"))
  20187. +        return -EIO;
  20188. +    if (!tty || (tty->flags & (1 << TTY_IO_ERROR)))
  20189. +        return -EIO;
  20190. +
  20191. +    /* This check not only needs to be done before reading, but also
  20192. +       whenever read_chan() gets woken up after sleeping, so I've
  20193. +       moved it to there.  This should only be done for the N_TTY
  20194. +       line discipline, anyway.  Same goes for write_chan(). -- jlc. */
  20195. +#if 0
  20196. +    if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
  20197. +        (tty->pgrp > 0) &&
  20198. +        (current->tty == tty) &&
  20199. +        (tty->pgrp != current->pgrp))
  20200. +        if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
  20201. +            return -EIO;
  20202. +        else {
  20203. +            (void) kill_pg(current->pgrp, SIGTTIN, 1);
  20204. +            return -ERESTARTSYS;
  20205. +        }
  20206. +#endif
  20207. +    if (tty->ldisc.read)
  20208. +        /* XXX casts are for what kernel-wide prototypes should be. */
  20209. +        i = (tty->ldisc.read)(tty,file,(unsigned char *)buf,(unsigned int)count);
  20210. +    else
  20211. +        i = -EIO;
  20212. +    if (i > 0)
  20213. +        inode->i_atime = CURRENT_TIME;
  20214. +    return i;
  20215. +}
  20216. +
  20217. +static int tty_write(struct inode * inode, struct file * file, const char * buf, int count)
  20218. +{
  20219. +    int i, is_console;
  20220. +    struct tty_struct * tty;
  20221. +
  20222. +    is_console = (inode->i_rdev == CONSOLE_DEV);
  20223. +
  20224. +    if (is_console && redirect)
  20225. +        tty = redirect;
  20226. +    else
  20227. +        tty = (struct tty_struct *)file->private_data;
  20228. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_write"))
  20229. +        return -EIO;
  20230. +    if (!tty || !tty->driver.write || (tty->flags & (1 << TTY_IO_ERROR)))
  20231. +        return -EIO;
  20232. +#if 0
  20233. +    if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
  20234. +        (current->tty == tty) && (tty->pgrp != current->pgrp)) {
  20235. +        if (is_orphaned_pgrp(current->pgrp))
  20236. +            return -EIO;
  20237. +        if (!is_ignored(SIGTTOU)) {
  20238. +            (void) kill_pg(current->pgrp, SIGTTOU, 1);
  20239. +            return -ERESTARTSYS;
  20240. +        }
  20241. +    }
  20242. +#endif
  20243. +    if (tty->ldisc.write)
  20244. +        /* XXX casts are for what kernel-wide prototypes should be. */
  20245. +        i = (tty->ldisc.write)(tty,file,(const unsigned char *)buf,(unsigned int)count);
  20246. +    else
  20247. +        i = -EIO;
  20248. +    if (i > 0)
  20249. +        inode->i_mtime = CURRENT_TIME;
  20250. +    return i;
  20251. +}
  20252. +
  20253. +/*
  20254. + * This is so ripe with races that you should *really* not touch this
  20255. + * unless you know exactly what you are doing. All the changes have to be
  20256. + * made atomically, or there may be incorrect pointers all over the place.
  20257. + */
  20258. +static int init_dev(kdev_t device, struct tty_struct **ret_tty)
  20259. +{
  20260. +    struct tty_struct *tty, **tty_loc, *o_tty, **o_tty_loc;
  20261. +    struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
  20262. +    struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
  20263. +    struct tty_driver *driver;    
  20264. +    int retval;
  20265. +    int idx;
  20266. +
  20267. +    driver = get_tty_driver(device);
  20268. +    if (!driver)
  20269. +        return -ENODEV;
  20270. +
  20271. +    idx = MINOR(device) - driver->minor_start;
  20272. +    tty = o_tty = NULL;
  20273. +    tp = o_tp = NULL;
  20274. +    ltp = o_ltp = NULL;
  20275. +    o_tty_loc = NULL;
  20276. +    o_tp_loc = o_ltp_loc = NULL;
  20277. +
  20278. +    tty_loc = &driver->table[idx];
  20279. +    tp_loc = &driver->termios[idx];
  20280. +    ltp_loc = &driver->termios_locked[idx];
  20281. +
  20282. +repeat:
  20283. +    retval = -EAGAIN;
  20284. +    if (driver->type == TTY_DRIVER_TYPE_PTY &&
  20285. +        driver->subtype == PTY_TYPE_MASTER &&
  20286. +        *tty_loc && (*tty_loc)->count)
  20287. +        goto end_init;
  20288. +    retval = -ENOMEM;
  20289. +    if (!*tty_loc && !tty) {
  20290. +        if (!(tty = (struct tty_struct*) kmalloc(sizeof(struct tty_struct),GFP_KERNEL)))
  20291. +            goto end_init;
  20292. +        initialize_tty_struct(tty);
  20293. +        tty->device = device;
  20294. +        tty->driver = *driver;
  20295. +        goto repeat;
  20296. +    }
  20297. +    if (!*tp_loc && !tp) {
  20298. +        tp = (struct termios *) kmalloc(sizeof(struct termios),
  20299. +                        GFP_KERNEL);
  20300. +        if (!tp)
  20301. +            goto end_init;
  20302. +        *tp = driver->init_termios;
  20303. +        goto repeat;
  20304. +    }
  20305. +    if (!*ltp_loc && !ltp) {
  20306. +        ltp = (struct termios *) kmalloc(sizeof(struct termios),
  20307. +                         GFP_KERNEL);
  20308. +        if (!ltp)
  20309. +            goto end_init;
  20310. +        memset(ltp, 0, sizeof(struct termios));
  20311. +        goto repeat;
  20312. +    }
  20313. +    if (driver->type == TTY_DRIVER_TYPE_PTY) {
  20314. +        o_tty_loc = &driver->other->table[idx];
  20315. +        o_tp_loc = &driver->other->termios[idx];
  20316. +        o_ltp_loc = &driver->other->termios_locked[idx];
  20317. +
  20318. +        if (!*o_tty_loc && !o_tty) {
  20319. +            kdev_t     o_device;
  20320. +            
  20321. +            o_tty = (struct tty_struct *) kmalloc (sizeof(struct tty_struct),
  20322. +                GFP_KERNEL);
  20323. +            if (!o_tty)
  20324. +                goto end_init;
  20325. +            o_device = MKDEV(driver->other->major,
  20326. +                     driver->other->minor_start + idx);
  20327. +            initialize_tty_struct(o_tty);
  20328. +            o_tty->device = o_device;
  20329. +            o_tty->driver = *driver->other;
  20330. +            goto repeat;
  20331. +        }
  20332. +        if (!*o_tp_loc && !o_tp) {
  20333. +            o_tp = (struct termios *)
  20334. +                kmalloc(sizeof(struct termios), GFP_KERNEL);
  20335. +            if (!o_tp)
  20336. +                goto end_init;
  20337. +            *o_tp = driver->other->init_termios;
  20338. +            goto repeat;
  20339. +        }
  20340. +        if (!*o_ltp_loc && !o_ltp) {
  20341. +            o_ltp = (struct termios *)
  20342. +                kmalloc(sizeof(struct termios), GFP_KERNEL);
  20343. +            if (!o_ltp)
  20344. +                goto end_init;
  20345. +            memset(o_ltp, 0, sizeof(struct termios));
  20346. +            goto repeat;
  20347. +        }
  20348. +        
  20349. +    }
  20350. +    /* Now we have allocated all the structures: update all the pointers.. */
  20351. +    if (!*tp_loc) {
  20352. +        *tp_loc = tp;
  20353. +        tp = NULL;
  20354. +    }
  20355. +    if (!*ltp_loc) {
  20356. +        *ltp_loc = ltp;
  20357. +        ltp = NULL;
  20358. +    }
  20359. +    if (!*tty_loc) {
  20360. +        tty->termios = *tp_loc;
  20361. +        tty->termios_locked = *ltp_loc;
  20362. +        *tty_loc = tty;
  20363. +        (*driver->refcount)++;
  20364. +        (*tty_loc)->count++;
  20365. +        if (tty->ldisc.open) {
  20366. +            retval = (tty->ldisc.open)(tty);
  20367. +            if (retval < 0) {
  20368. +                (*tty_loc)->count--;
  20369. +                tty = NULL;
  20370. +                goto end_init;
  20371. +            }
  20372. +        }
  20373. +        tty = NULL;
  20374. +    } else {
  20375. +        if ((*tty_loc)->flags & (1 << TTY_CLOSING)) {
  20376. +            printk("Attempt to open closing tty %s.\n",
  20377. +                   tty_name(*tty_loc));
  20378. +            printk("Ack!!!!  This should never happen!!\n");
  20379. +            return -EINVAL;
  20380. +        }
  20381. +        (*tty_loc)->count++;
  20382. +    }
  20383. +    if (driver->type == TTY_DRIVER_TYPE_PTY) {
  20384. +        if (!*o_tp_loc) {
  20385. +            *o_tp_loc = o_tp;
  20386. +            o_tp = NULL;
  20387. +        }
  20388. +        if (!*o_ltp_loc) {
  20389. +            *o_ltp_loc = o_ltp;
  20390. +            o_ltp = NULL;
  20391. +        }
  20392. +        if (!*o_tty_loc) {
  20393. +            o_tty->termios = *o_tp_loc;
  20394. +            o_tty->termios_locked = *o_ltp_loc;
  20395. +            *o_tty_loc = o_tty;
  20396. +            (*driver->other->refcount)++;
  20397. +            if (o_tty->ldisc.open) {
  20398. +                retval = (o_tty->ldisc.open)(o_tty);
  20399. +                if (retval < 0) {
  20400. +                    (*tty_loc)->count--;
  20401. +                    o_tty = NULL;
  20402. +                    goto end_init;
  20403. +                }
  20404. +            }
  20405. +            o_tty = NULL;
  20406. +        }
  20407. +        (*tty_loc)->link = *o_tty_loc;
  20408. +        (*o_tty_loc)->link = *tty_loc;
  20409. +        if (driver->subtype == PTY_TYPE_MASTER)
  20410. +            (*o_tty_loc)->count++;
  20411. +    }
  20412. +    (*tty_loc)->driver = *driver;
  20413. +    *ret_tty = *tty_loc;
  20414. +    retval = 0;
  20415. +end_init:
  20416. +    if (tty)
  20417. +        kfree_s(tty, sizeof(struct tty_struct));
  20418. +    if (o_tty)
  20419. +        kfree_s(o_tty, sizeof(struct tty_struct));
  20420. +    if (tp)
  20421. +        kfree_s(tp, sizeof(struct termios));
  20422. +    if (o_tp)
  20423. +        kfree_s(o_tp, sizeof(struct termios));
  20424. +    if (ltp)
  20425. +        kfree_s(ltp, sizeof(struct termios));
  20426. +    if (o_ltp)
  20427. +        kfree_s(o_ltp, sizeof(struct termios));
  20428. +    return retval;
  20429. +}
  20430. +
  20431. +/*
  20432. + * Even releasing the tty structures is a tricky business.. We have
  20433. + * to be very careful that the structures are all released at the
  20434. + * same time, as interrupts might otherwise get the wrong pointers.
  20435. + */
  20436. +static void release_dev(struct file * filp)
  20437. +{
  20438. +    struct tty_struct *tty, *o_tty;
  20439. +    struct termios *tp, *o_tp, *ltp, *o_ltp;
  20440. +    struct task_struct **p;
  20441. +    int    idx;
  20442. +    
  20443. +    tty = (struct tty_struct *)filp->private_data;
  20444. +    if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "release_dev"))
  20445. +        return;
  20446. +
  20447. +    check_tty_count(tty, "release_dev");
  20448. +
  20449. +    tty_fasync(filp->f_inode, filp, 0);
  20450. +
  20451. +    tp = tty->termios;
  20452. +    ltp = tty->termios_locked;
  20453. +
  20454. +    idx = MINOR(tty->device) - tty->driver.minor_start;
  20455. +#ifdef TTY_PARANOIA_CHECK
  20456. +    if (idx < 0 || idx >= tty->driver.num) {
  20457. +        printk("release_dev: bad idx when trying to free (%s)\n",
  20458. +               kdevname(tty->device));
  20459. +        return;
  20460. +    }
  20461. +    if (tty != tty->driver.table[idx]) {
  20462. +        printk("release_dev: driver.table[%d] not tty for (%s)\n",
  20463. +               idx, kdevname(tty->device));
  20464. +        return;
  20465. +    }
  20466. +    if (tp != tty->driver.termios[idx]) {
  20467. +        printk("release_dev: driver.termios[%d] not termios for (%s)\n",
  20468. +               idx, kdevname(tty->device));
  20469. +        return;
  20470. +    }
  20471. +    if (ltp != tty->driver.termios_locked[idx]) {
  20472. +        printk("release_dev: driver.termios_locked[%d] not termios_locked for (%s)\n",
  20473. +               idx, kdevname(tty->device));
  20474. +        return;
  20475. +    }
  20476. +#endif
  20477. +
  20478. +#ifdef TTY_DEBUG_HANGUP
  20479. +    printk("release_dev of %s (tty count=%d)...", tty_name(tty),
  20480. +           tty->count);
  20481. +#endif
  20482. +
  20483. +    o_tty = tty->link;
  20484. +    o_tp = (o_tty) ? o_tty->termios : NULL;
  20485. +    o_ltp = (o_tty) ? o_tty->termios_locked : NULL;
  20486. +
  20487. +#ifdef TTY_PARANOIA_CHECK
  20488. +    if (tty->driver.other) {
  20489. +        if (o_tty != tty->driver.other->table[idx]) {
  20490. +            printk("release_dev: other->table[%d] not o_tty for ("
  20491. +                   "%s)\n",
  20492. +                   idx, kdevname(tty->device));
  20493. +            return;
  20494. +        }
  20495. +        if (o_tp != tty->driver.other->termios[idx]) {
  20496. +            printk("release_dev: other->termios[%d] not o_termios for ("
  20497. +                   "%s)\n",
  20498. +                   idx, kdevname(tty->device));
  20499. +            return;
  20500. +        }
  20501. +        if (o_ltp != tty->driver.other->termios_locked[idx]) {
  20502. +            printk("release_dev: other->termios_locked[%d] not o_termios_locked for ("
  20503. +                   "%s)\n",
  20504. +                   idx, kdevname(tty->device));
  20505. +            return;
  20506. +        }
  20507. +
  20508. +        if (o_tty->link != tty) {
  20509. +            printk("release_dev: bad pty pointers\n");
  20510. +            return;
  20511. +        }
  20512. +    }
  20513. +#endif
  20514. +    
  20515. +    if (tty->driver.close)
  20516. +        tty->driver.close(tty, filp);
  20517. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  20518. +        tty->driver.subtype == PTY_TYPE_MASTER) {
  20519. +        if (--tty->link->count < 0) {
  20520. +            printk("release_dev: bad pty slave count (%d) for %s\n",
  20521. +                   tty->count, tty_name(tty));
  20522. +            tty->link->count = 0;
  20523. +        }
  20524. +    }
  20525. +    if (--tty->count < 0) {
  20526. +        printk("release_dev: bad tty->count (%d) for %s\n",
  20527. +               tty->count, tty_name(tty));
  20528. +        tty->count = 0;
  20529. +    }
  20530. +    if (tty->count)
  20531. +        return;
  20532. +
  20533. +    /*
  20534. +     * We're committed; at this point, we must not block!
  20535. +     */
  20536. +    if (o_tty) {
  20537. +        if (o_tty->count)
  20538. +            return;
  20539. +        tty->driver.other->table[idx] = NULL;
  20540. +        tty->driver.other->termios[idx] = NULL;
  20541. +        kfree_s(o_tp, sizeof(struct termios));
  20542. +    }
  20543. +    
  20544. +#ifdef TTY_DEBUG_HANGUP
  20545. +    printk("freeing tty structure...");
  20546. +#endif
  20547. +    tty->flags |= (1 << TTY_CLOSING);
  20548. +
  20549. +    /*
  20550. +     * Make sure there aren't any processes that still think this
  20551. +     * tty is their controlling tty.
  20552. +     */
  20553. +    for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  20554. +        if (*p == 0)
  20555. +            continue;
  20556. +        if ((*p)->tty == tty)
  20557. +            (*p)->tty = NULL;
  20558. +        if (o_tty && (*p)->tty == o_tty)
  20559. +            (*p)->tty = NULL;
  20560. +    }
  20561. +
  20562. +    /*
  20563. +     * Shutdown the current line discipline, and reset it to
  20564. +     * N_TTY.
  20565. +     */
  20566. +    if (tty->ldisc.close)
  20567. +        (tty->ldisc.close)(tty);
  20568. +    tty->ldisc = ldiscs[N_TTY];
  20569. +    tty->termios->c_line = N_TTY;
  20570. +    if (o_tty) {
  20571. +        if (o_tty->ldisc.close)
  20572. +            (o_tty->ldisc.close)(o_tty);
  20573. +        o_tty->ldisc = ldiscs[N_TTY];
  20574. +    }
  20575. +    
  20576. +    tty->driver.table[idx] = NULL;
  20577. +    if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
  20578. +        tty->driver.termios[idx] = NULL;
  20579. +        kfree_s(tp, sizeof(struct termios));
  20580. +    }
  20581. +    if (tty == redirect || o_tty == redirect)
  20582. +        redirect = NULL;
  20583. +    /*
  20584. +     * Make sure that the tty's task queue isn't activated.  If it
  20585. +     * is, take it out of the linked list.
  20586. +     */
  20587. +    cli();
  20588. +    if (tty->flip.tqueue.sync) {
  20589. +        struct tq_struct *tq, *prev;
  20590. +
  20591. +        for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {
  20592. +            if (tq == &tty->flip.tqueue) {
  20593. +                if (prev)
  20594. +                    prev->next = tq->next;
  20595. +                else
  20596. +                    tq_timer = tq->next;
  20597. +                break;
  20598. +            }
  20599. +        }
  20600. +    }
  20601. +    sti();
  20602. +    tty->magic = 0;
  20603. +    (*tty->driver.refcount)--;
  20604. +    kfree_s(tty, sizeof(struct tty_struct));
  20605. +    filp->private_data = 0;
  20606. +    if (o_tty) {
  20607. +        o_tty->magic = 0;
  20608. +        (*o_tty->driver.refcount)--;
  20609. +        kfree_s(o_tty, sizeof(struct tty_struct));
  20610. +    }
  20611. +}
  20612. +
  20613. +/*
  20614. + * tty_open and tty_release keep up the tty count that contains the
  20615. + * number of opens done on a tty. We cannot use the inode-count, as
  20616. + * different inodes might point to the same tty.
  20617. + *
  20618. + * Open-counting is needed for pty masters, as well as for keeping
  20619. + * track of serial lines: DTR is dropped when the last close happens.
  20620. + * (This is not done solely through tty->count, now.  - Ted 1/27/92)
  20621. + *
  20622. + * The termios state of a pty is reset on first open so that
  20623. + * settings don't persist across reuse.
  20624. + */
  20625. +static int tty_open(struct inode * inode, struct file * filp)
  20626. +{
  20627. +    struct tty_struct *tty;
  20628. +    int minor;
  20629. +    int noctty, retval;
  20630. +    kdev_t device;
  20631. +
  20632. +retry_open:
  20633. +    noctty = filp->f_flags & O_NOCTTY;
  20634. +    device = inode->i_rdev;
  20635. +    if (device == TTY_DEV) {
  20636. +        if (!current->tty)
  20637. +            return -ENXIO;
  20638. +        device = current->tty->device;
  20639. +        /* noctty = 1; */
  20640. +    }
  20641. +    if (device == CONSOLE_DEV) {
  20642. +        device = MKDEV(TTY_MAJOR, fg_console+1);
  20643. +        noctty = 1;
  20644. +    }
  20645. +    minor = MINOR(device);
  20646. +    
  20647. +    retval = init_dev(device, &tty);
  20648. +    if (retval)
  20649. +        return retval;
  20650. +    filp->private_data = tty;
  20651. +    check_tty_count(tty, "tty_open");
  20652. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  20653. +        tty->driver.subtype == PTY_TYPE_MASTER)
  20654. +        noctty = 1;
  20655. +#ifdef TTY_DEBUG_HANGUP
  20656. +    printk("opening %s...", tty_name(tty));
  20657. +#endif
  20658. +    if (tty->driver.open)
  20659. +        retval = tty->driver.open(tty, filp);
  20660. +    else
  20661. +        retval = -ENODEV;
  20662. +
  20663. +    if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())
  20664. +        retval = -EBUSY;
  20665. +
  20666. +    if (retval) {
  20667. +#ifdef TTY_DEBUG_HANGUP
  20668. +        printk("error %d in opening %s...", retval, tty_name(tty));
  20669. +#endif
  20670. +
  20671. +        release_dev(filp);
  20672. +        if (retval != -ERESTARTSYS)
  20673. +            return retval;
  20674. +        if (current->signal & ~current->blocked)
  20675. +            return retval;
  20676. +        schedule();
  20677. +        /*
  20678. +         * Need to reset f_op in case a hangup happened.
  20679. +         */
  20680. +        filp->f_op = &tty_fops;
  20681. +        goto retry_open;
  20682. +    }
  20683. +    if (!noctty &&
  20684. +        current->leader &&
  20685. +        !current->tty &&
  20686. +        tty->session == 0) {
  20687. +        current->tty = tty;
  20688. +        current->tty_old_pgrp = 0;
  20689. +        tty->session = current->session;
  20690. +        tty->pgrp = current->pgrp;
  20691. +    }
  20692. +    return 0;
  20693. +}
  20694. +
  20695. +/*
  20696. + * Note that releasing a pty master also releases the child, so
  20697. + * we have to make the redirection checks after that and on both
  20698. + * sides of a pty.
  20699. + */
  20700. +static void tty_release(struct inode * inode, struct file * filp)
  20701. +{
  20702. +    release_dev(filp);
  20703. +}
  20704. +
  20705. +static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
  20706. +{
  20707. +    struct tty_struct * tty;
  20708. +
  20709. +    tty = (struct tty_struct *)filp->private_data;
  20710. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_select"))
  20711. +        return 0;
  20712. +
  20713. +    if (tty->ldisc.select)
  20714. +        return (tty->ldisc.select)(tty, inode, filp, sel_type, wait);
  20715. +    return 0;
  20716. +}
  20717. +
  20718. +/*
  20719. + * fasync_helper() is used by some character device drivers (mainly mice)
  20720. + * to set up the fasync queue. It returns negative on error, 0 if it did
  20721. + * no changes, and positive if it added/deleted the entry.
  20722. + */
  20723. +int fasync_helper(struct inode * inode, struct file * filp, int on, struct fasync_struct **fapp)
  20724. +{
  20725. +    struct fasync_struct *fa, **fp;
  20726. +    unsigned long flags;
  20727. +
  20728. +    for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
  20729. +        if (fa->fa_file == filp)
  20730. +            break;
  20731. +    }
  20732. +
  20733. +    if (on) {
  20734. +        if (fa)
  20735. +            return 0;
  20736. +        fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
  20737. +        if (!fa)
  20738. +            return -ENOMEM;
  20739. +        fa->magic = FASYNC_MAGIC;
  20740. +        fa->fa_file = filp;
  20741. +        save_flags(flags);
  20742. +        cli();
  20743. +        fa->fa_next = *fapp;
  20744. +        *fapp = fa;
  20745. +        restore_flags(flags);
  20746. +        return 1;
  20747. +    }
  20748. +    if (!fa)
  20749. +        return 0;
  20750. +    save_flags(flags);
  20751. +    cli();
  20752. +    *fp = fa->fa_next;
  20753. +    restore_flags(flags);
  20754. +    kfree(fa);
  20755. +    return 1;
  20756. +}
  20757. +
  20758. +static int tty_fasync(struct inode * inode, struct file * filp, int on)
  20759. +{
  20760. +    struct tty_struct * tty;
  20761. +    int retval;
  20762. +
  20763. +    tty = (struct tty_struct *)filp->private_data;
  20764. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync"))
  20765. +        return 0;
  20766. +
  20767. +    retval = fasync_helper(inode, filp, on, &tty->fasync);
  20768. +    if (retval <= 0)
  20769. +        return retval;
  20770. +
  20771. +    if (on) {
  20772. +        if (!tty->read_wait)
  20773. +            tty->minimum_to_wake = 1;
  20774. +        if (filp->f_owner == 0) {
  20775. +            if (tty->pgrp)
  20776. +                filp->f_owner = -tty->pgrp;
  20777. +            else
  20778. +                filp->f_owner = current->pid;
  20779. +        }
  20780. +    } else {
  20781. +        if (!tty->fasync && !tty->read_wait)
  20782. +            tty->minimum_to_wake = N_TTY_BUF_SIZE;
  20783. +    }
  20784. +    return 0;    
  20785. +}
  20786. +
  20787. +#if 0
  20788. +/*
  20789. + * XXX does anyone use this anymore?!?
  20790. + */
  20791. +static int do_get_ps_info(unsigned long arg)
  20792. +{
  20793. +    struct tstruct {
  20794. +        int flag;
  20795. +        int present[NR_TASKS];
  20796. +        struct task_struct tasks[NR_TASKS];
  20797. +    };
  20798. +    struct tstruct *ts = (struct tstruct *)arg;
  20799. +    struct task_struct **p;
  20800. +    char *c, *d;
  20801. +    int i, n = 0;
  20802. +    
  20803. +    i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
  20804. +    if (i)
  20805. +        return i;
  20806. +    for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
  20807. +        if (*p)
  20808. +        {
  20809. +            c = (char *)(*p);
  20810. +            d = (char *)(ts->tasks+n);
  20811. +            for (i=0 ; i<sizeof(struct task_struct) ; i++)
  20812. +                put_user(*c++, d++);
  20813. +            put_user(1, ts->present+n);
  20814. +        }
  20815. +        else    
  20816. +            put_user(0, ts->present+n);
  20817. +    return(0);            
  20818. +}
  20819. +#endif
  20820. +
  20821. +static int tty_ioctl(struct inode * inode, struct file * file,
  20822. +             unsigned int cmd, unsigned long arg)
  20823. +{
  20824. +    int    retval;
  20825. +    struct tty_struct * tty;
  20826. +    struct tty_struct * real_tty;
  20827. +    struct winsize tmp_ws;
  20828. +    pid_t pgrp;
  20829. +    unsigned char    ch;
  20830. +    char    mbz = 0;
  20831. +    
  20832. +    tty = (struct tty_struct *)file->private_data;
  20833. +    if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
  20834. +        return -EINVAL;
  20835. +
  20836. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  20837. +        tty->driver.subtype == PTY_TYPE_MASTER)
  20838. +        real_tty = tty->link;
  20839. +    else
  20840. +        real_tty = tty;
  20841. +
  20842. +    switch (cmd) {
  20843. +        case TIOCSTI:
  20844. +            if ((current->tty != tty) && !suser())
  20845. +                return -EPERM;
  20846. +            retval = verify_area(VERIFY_READ, (void *) arg, 1);
  20847. +            if (retval)
  20848. +                return retval;
  20849. +            ch = get_user((char *) arg);
  20850. +            tty->ldisc.receive_buf(tty, &ch, &mbz, 1);
  20851. +            return 0;
  20852. +        case TIOCGWINSZ:
  20853. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  20854. +                         sizeof (struct winsize));
  20855. +            if (retval)
  20856. +                return retval;
  20857. +            memcpy_tofs((struct winsize *) arg, &tty->winsize,
  20858. +                    sizeof (struct winsize));
  20859. +            return 0;
  20860. +        case TIOCSWINSZ:
  20861. +            retval = verify_area(VERIFY_READ, (void *) arg,
  20862. +                         sizeof (struct winsize));
  20863. +            if (retval)
  20864. +                return retval;            
  20865. +            memcpy_fromfs(&tmp_ws, (struct winsize *) arg,
  20866. +                      sizeof (struct winsize));
  20867. +            if (memcmp(&tmp_ws, &tty->winsize,
  20868. +                   sizeof(struct winsize))) {
  20869. +                if (tty->pgrp > 0)
  20870. +                    kill_pg(tty->pgrp, SIGWINCH, 1);
  20871. +                if ((real_tty->pgrp != tty->pgrp) &&
  20872. +                    (real_tty->pgrp > 0))
  20873. +                    kill_pg(real_tty->pgrp, SIGWINCH, 1);
  20874. +            }
  20875. +            tty->winsize = tmp_ws;
  20876. +            real_tty->winsize = tmp_ws;
  20877. +            return 0;
  20878. +        case TIOCCONS:
  20879. +            if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE) {
  20880. +                if (!suser())
  20881. +                    return -EPERM;
  20882. +                redirect = NULL;
  20883. +                return 0;
  20884. +            }
  20885. +            if (redirect)
  20886. +                return -EBUSY;
  20887. +            redirect = real_tty;
  20888. +            return 0;
  20889. +        case FIONBIO:
  20890. +            retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int));
  20891. +            if (retval)
  20892. +                return retval;
  20893. +            arg = get_user((unsigned int *) arg);
  20894. +            if (arg)
  20895. +                file->f_flags |= O_NONBLOCK;
  20896. +            else
  20897. +                file->f_flags &= ~O_NONBLOCK;
  20898. +            return 0;
  20899. +        case TIOCEXCL:
  20900. +            set_bit(TTY_EXCLUSIVE, &tty->flags);
  20901. +            return 0;
  20902. +        case TIOCNXCL:
  20903. +            clear_bit(TTY_EXCLUSIVE, &tty->flags);
  20904. +            return 0;
  20905. +        case TIOCNOTTY:
  20906. +            if (current->tty != tty)
  20907. +                return -ENOTTY;
  20908. +            if (current->leader)
  20909. +                disassociate_ctty(0);
  20910. +            current->tty = NULL;
  20911. +            return 0;
  20912. +        case TIOCSCTTY:
  20913. +            if (current->leader &&
  20914. +                (current->session == tty->session))
  20915. +                return 0;
  20916. +            /*
  20917. +             * The process must be a session leader and
  20918. +             * not have a controlling tty already.
  20919. +             */
  20920. +            if (!current->leader || current->tty)
  20921. +                return -EPERM;
  20922. +            if (tty->session > 0) {
  20923. +                /*
  20924. +                 * This tty is already the controlling
  20925. +                 * tty for another session group!
  20926. +                 */
  20927. +                if ((arg == 1) && suser()) {
  20928. +                    /*
  20929. +                     * Steal it away
  20930. +                     */
  20931. +                    struct task_struct *p;
  20932. +
  20933. +                    for_each_task(p)
  20934. +                        if (p->tty == tty)
  20935. +                            p->tty = NULL;
  20936. +                } else
  20937. +                    return -EPERM;
  20938. +            }
  20939. +            current->tty = tty;
  20940. +            current->tty_old_pgrp = 0;
  20941. +            tty->session = current->session;
  20942. +            tty->pgrp = current->pgrp;
  20943. +            return 0;
  20944. +        case TIOCGPGRP:
  20945. +            /*
  20946. +             * (tty == real_tty) is a cheap way of
  20947. +             * testing if the tty is NOT a master pty.
  20948. +             */
  20949. +            if (tty == real_tty && current->tty != real_tty)
  20950. +                return -ENOTTY;
  20951. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  20952. +                         sizeof (pid_t));
  20953. +            if (retval)
  20954. +                return retval;
  20955. +            put_user(real_tty->pgrp, (pid_t *) arg);
  20956. +            return 0;
  20957. +        case TIOCSPGRP:
  20958. +            retval = tty_check_change(real_tty);
  20959. +            if (retval)
  20960. +                return retval;
  20961. +            if (!current->tty ||
  20962. +                (current->tty != real_tty) ||
  20963. +                (real_tty->session != current->session))
  20964. +                return -ENOTTY;
  20965. +            pgrp = get_user((pid_t *) arg);
  20966. +            if (pgrp < 0)
  20967. +                return -EINVAL;
  20968. +            if (session_of_pgrp(pgrp) != current->session)
  20969. +                return -EPERM;
  20970. +            real_tty->pgrp = pgrp;
  20971. +            return 0;
  20972. +        case TIOCGETD:
  20973. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  20974. +                         sizeof (int));
  20975. +            if (retval)
  20976. +                return retval;
  20977. +            put_user(tty->ldisc.num, (int *) arg);
  20978. +            return 0;
  20979. +        case TIOCSETD:
  20980. +            retval = tty_check_change(tty);
  20981. +            if (retval)
  20982. +                return retval;
  20983. +            arg = get_user((int *) arg);
  20984. +            return tty_set_ldisc(tty, arg);
  20985. +        case TIOCLINUX:
  20986. +            if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
  20987. +                return -EINVAL;
  20988. +            if (current->tty != tty && !suser())
  20989. +                return -EPERM;
  20990. +            retval = verify_area(VERIFY_READ, (void *) arg, 1);
  20991. +            if (retval)
  20992. +                return retval;
  20993. +            switch (retval = get_user((char *)arg))
  20994. +            {
  20995. +                case 0:
  20996. +                case 8:
  20997. +                case 9:
  20998. +                    printk("TIOCLINUX (0/8/9) ioctl is gone - use /dev/vcs\n");
  20999. +                    return -EINVAL;
  21000. +#if 0
  21001. +                case 1:
  21002. +                    printk("Deprecated TIOCLINUX (1) ioctl\n");
  21003. +                    return do_get_ps_info(arg);
  21004. +#endif
  21005. +                case 2:
  21006. +                    return set_selection(arg, tty);
  21007. +                case 3:
  21008. +                    return paste_selection(tty);
  21009. +                case 4:
  21010. +                    do_unblank_screen();
  21011. +                    return 0;
  21012. +                case 5:
  21013. +                    return sel_loadlut(arg);
  21014. +                case 6:
  21015. +            /*
  21016. +             * Make it possible to react to Shift+Mousebutton.
  21017. +             * Note that 'shift_state' is an undocumented
  21018. +             * kernel-internal variable; programs not closely
  21019. +             * related to the kernel should not use this.
  21020. +             */
  21021. +                    put_user(shift_state,(char *) arg);
  21022. +                    return 0;
  21023. +                case 7:
  21024. +                    put_user(mouse_reporting(),(char *) arg);
  21025. +                    return 0;
  21026. +/*                case 10:
  21027. +                    set_vesa_blanking(arg);
  21028. +                    return 0;*/
  21029. +                default: 
  21030. +                    return -EINVAL;
  21031. +            }
  21032. +
  21033. +        case TIOCTTYGSTRUCT:
  21034. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  21035. +                        sizeof(struct tty_struct));
  21036. +            if (retval)
  21037. +                return retval;
  21038. +            memcpy_tofs((struct tty_struct *) arg,
  21039. +                    tty, sizeof(struct tty_struct));
  21040. +            return 0;
  21041. +        default:
  21042. +            if (tty->driver.ioctl) {
  21043. +                retval = (tty->driver.ioctl)(tty, file,
  21044. +                                 cmd, arg);
  21045. +                if (retval != -ENOIOCTLCMD)
  21046. +                    return retval;
  21047. +            }
  21048. +            if (tty->ldisc.ioctl) {
  21049. +                retval = (tty->ldisc.ioctl)(tty, file,
  21050. +                                cmd, arg);
  21051. +                if (retval != -ENOIOCTLCMD)
  21052. +                    return retval;
  21053. +            }
  21054. +            return -EINVAL;
  21055. +        }
  21056. +}
  21057. +
  21058. +
  21059. +/*
  21060. + * This implements the "Secure Attention Key" ---  the idea is to
  21061. + * prevent trojan horses by killing all processes associated with this
  21062. + * tty when the user hits the "Secure Attention Key".  Required for
  21063. + * super-paranoid applications --- see the Orange Book for more details.
  21064. + * 
  21065. + * This code could be nicer; ideally it should send a HUP, wait a few
  21066. + * seconds, then send a INT, and then a KILL signal.  But you then
  21067. + * have to coordinate with the init process, since all processes associated
  21068. + * with the current tty must be dead before the new getty is allowed
  21069. + * to spawn.
  21070. + */
  21071. +void do_SAK( struct tty_struct *tty)
  21072. +{
  21073. +#ifdef TTY_SOFT_SAK
  21074. +    tty_hangup(tty);
  21075. +#else
  21076. +    struct task_struct **p;
  21077. +    int session;
  21078. +    int        i;
  21079. +    struct file    *filp;
  21080. +    
  21081. +    if (!tty)
  21082. +        return;
  21083. +    session  = tty->session;
  21084. +    if (tty->ldisc.flush_buffer)
  21085. +        tty->ldisc.flush_buffer(tty);
  21086. +    if (tty->driver.flush_buffer)
  21087. +        tty->driver.flush_buffer(tty);
  21088. +     for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  21089. +        if (!(*p))
  21090. +            continue;
  21091. +        if (((*p)->tty == tty) ||
  21092. +            ((session > 0) && ((*p)->session == session)))
  21093. +            send_sig(SIGKILL, *p, 1);
  21094. +        else {
  21095. +            for (i=0; i < NR_OPEN; i++) {
  21096. +                filp = (*p)->files->fd[i];
  21097. +                if (filp && (filp->f_op == &tty_fops) &&
  21098. +                    (filp->private_data == tty)) {
  21099. +                    send_sig(SIGKILL, *p, 1);
  21100. +                    break;
  21101. +                }
  21102. +            }
  21103. +        }
  21104. +    }
  21105. +#endif
  21106. +}
  21107. +
  21108. +/*
  21109. + * This routine is called out of the software interrupt to flush data
  21110. + * from the flip buffer to the line discipline.
  21111. + */
  21112. +static void flush_to_ldisc(void *private_)
  21113. +{
  21114. +    struct tty_struct *tty = (struct tty_struct *) private_;
  21115. +    unsigned char    *cp;
  21116. +    char        *fp;
  21117. +    int        count;
  21118. +
  21119. +    if (tty->flip.buf_num) {
  21120. +        cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
  21121. +        fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
  21122. +        tty->flip.buf_num = 0;
  21123. +
  21124. +        cli();
  21125. +        tty->flip.char_buf_ptr = tty->flip.char_buf;
  21126. +        tty->flip.flag_buf_ptr = tty->flip.flag_buf;
  21127. +    } else {
  21128. +        cp = tty->flip.char_buf;
  21129. +        fp = tty->flip.flag_buf;
  21130. +        tty->flip.buf_num = 1;
  21131. +
  21132. +        cli();
  21133. +        tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
  21134. +        tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
  21135. +    }
  21136. +    count = tty->flip.count;
  21137. +    tty->flip.count = 0;
  21138. +    sti();
  21139. +    
  21140. +#if 0
  21141. +    if (count > tty->max_flip_cnt)
  21142. +        tty->max_flip_cnt = count;
  21143. +#endif
  21144. +    tty->ldisc.receive_buf(tty, cp, fp, count);
  21145. +}
  21146. +
  21147. +/*
  21148. + * This subroutine initializes a tty structure.
  21149. + */
  21150. +static void initialize_tty_struct(struct tty_struct *tty)
  21151. +{
  21152. +    memset(tty, 0, sizeof(struct tty_struct));
  21153. +    tty->magic = TTY_MAGIC;
  21154. +    tty->ldisc = ldiscs[N_TTY];
  21155. +    tty->pgrp = -1;
  21156. +    tty->flip.char_buf_ptr = tty->flip.char_buf;
  21157. +    tty->flip.flag_buf_ptr = tty->flip.flag_buf;
  21158. +    tty->flip.tqueue.routine = flush_to_ldisc;
  21159. +    tty->flip.tqueue.data = tty;
  21160. +}
  21161. +
  21162. +/*
  21163. + * The default put_char routine if the driver did not define one.
  21164. + */
  21165. +void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
  21166. +{
  21167. +    tty->driver.write(tty, 0, &ch, 1);
  21168. +}
  21169. +
  21170. +/*
  21171. + * Called by a tty driver to register itself.
  21172. + */
  21173. +int tty_register_driver(struct tty_driver *driver)
  21174. +{
  21175. +    int error;
  21176. +
  21177. +    if (driver->flags & TTY_DRIVER_INSTALLED)
  21178. +        return 0;
  21179. +
  21180. +    error = register_chrdev(driver->major, driver->name, &tty_fops);
  21181. +    if (error < 0)
  21182. +        return error;
  21183. +    else if(driver->major == 0)
  21184. +        driver->major = error;
  21185. +
  21186. +    if (!driver->put_char)
  21187. +        driver->put_char = tty_default_put_char;
  21188. +    
  21189. +    driver->prev = 0;
  21190. +    driver->next = tty_drivers;
  21191. +    if (tty_drivers) tty_drivers->prev = driver;
  21192. +    tty_drivers = driver;
  21193. +    return error;
  21194. +}
  21195. +
  21196. +/*
  21197. + * Called by a tty driver to unregister itself.
  21198. + */
  21199. +int tty_unregister_driver(struct tty_driver *driver)
  21200. +{
  21201. +    int    retval;
  21202. +    struct tty_driver *p;
  21203. +    int    found = 0;
  21204. +    const char *othername = NULL;
  21205. +    
  21206. +    if (*driver->refcount)
  21207. +        return -EBUSY;
  21208. +
  21209. +    for (p = tty_drivers; p; p = p->next) {
  21210. +        if (p == driver)
  21211. +            found++;
  21212. +        else if (p->major == driver->major)
  21213. +            othername = p->name;
  21214. +    }
  21215. +
  21216. +    if (othername == NULL) {
  21217. +        retval = unregister_chrdev(driver->major, driver->name);
  21218. +        if (retval)
  21219. +            return retval;
  21220. +    } else
  21221. +        register_chrdev(driver->major, othername, &tty_fops);
  21222. +
  21223. +    if (driver->prev)
  21224. +        driver->prev->next = driver->next;
  21225. +    else
  21226. +        tty_drivers = driver->next;
  21227. +    
  21228. +    if (driver->next)
  21229. +        driver->next->prev = driver->prev;
  21230. +
  21231. +    return 0;
  21232. +}
  21233. +
  21234. +
  21235. +/*
  21236. + * Initialize the console device. This is called *early*, so
  21237. + * we can't necessarily depend on lots of kernel help here.
  21238. + * Just do some early initializations, and do the complex setup
  21239. + * later.
  21240. + */
  21241. +long console_init(long kmem_start, long kmem_end)
  21242. +{
  21243. +    /* Setup the default TTY line discipline. */
  21244. +    memset(ldiscs, 0, sizeof(ldiscs));
  21245. +    (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
  21246. +
  21247. +    /*
  21248. +     * Set up the standard termios.  Individual tty drivers may 
  21249. +     * deviate from this; this is used as a template.
  21250. +     */
  21251. +    memset(&tty_std_termios, 0, sizeof(struct termios));
  21252. +    memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
  21253. +    tty_std_termios.c_iflag = ICRNL | IXON;
  21254. +    tty_std_termios.c_oflag = OPOST | ONLCR;
  21255. +    tty_std_termios.c_cflag = B38400 | CS8 | CREAD;
  21256. +    tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
  21257. +        ECHOCTL | ECHOKE | IEXTEN;
  21258. +
  21259. +    /*
  21260. +     * set up the console device so that later boot sequences can 
  21261. +     * inform about problems etc..
  21262. +     */
  21263. +    return con_init(kmem_start);
  21264. +}
  21265. +
  21266. +/*
  21267. + * Ok, now we can initialize the rest of the tty devices and can count
  21268. + * on memory allocations, interrupts etc..
  21269. + */
  21270. +int tty_init(void)
  21271. +{
  21272. +    if (sizeof(struct tty_struct) > PAGE_SIZE)
  21273. +        panic("size of tty structure > PAGE_SIZE!");
  21274. +    if (register_chrdev(TTY_MAJOR,"tty",&tty_fops))
  21275. +        panic("unable to get major %d for tty device", TTY_MAJOR);
  21276. +    if (register_chrdev(TTYAUX_MAJOR,"cua",&tty_fops))
  21277. +        panic("unable to get major %d for tty device", TTYAUX_MAJOR);
  21278. +
  21279. +    kbd_init();
  21280. +    rs_init();
  21281. +
  21282. +    pty_init();
  21283. +    vcs_init();
  21284. +    return 0;
  21285. +}
  21286. diff -urNwbB linux/arch/arm/drivers/char/tty_ioctl.c linux.arm/arch/arm/drivers/char/tty_ioctl.c
  21287. --- linux/arch/arm/drivers/char/tty_ioctl.c    Thu Jan  1 01:00:00 1970
  21288. +++ linux.arm/arch/arm/drivers/char/tty_ioctl.c    Sun Mar  3 12:49:03 1996
  21289. @@ -0,0 +1,376 @@
  21290. +/*
  21291. + *  linux/drivers/char/tty_ioctl.c
  21292. + *
  21293. + *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  21294. + *
  21295. + *  Modifications for ARM processor (C) 1995, 1996 Russell King.
  21296. + *
  21297. + * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
  21298. + * which can be dynamically activated and de-activated by the line
  21299. + * discipline handling modules (like SLIP).
  21300. + */
  21301. +
  21302. +#include <linux/types.h>
  21303. +#include <linux/termios.h>
  21304. +#include <linux/errno.h>
  21305. +#include <linux/sched.h>
  21306. +#include <linux/kernel.h>
  21307. +#include <linux/major.h>
  21308. +#include <linux/tty.h>
  21309. +#include <linux/fcntl.h>
  21310. +#include <linux/string.h>
  21311. +#include <linux/mm.h>
  21312. +
  21313. +#include <asm/io.h>
  21314. +#include <asm/bitops.h>
  21315. +#include <asm/segment.h>
  21316. +#include <asm/system.h>
  21317. +
  21318. +#undef TTY_DEBUG_WAIT_UNTIL_SENT
  21319. +
  21320. +#undef    DEBUG
  21321. +#ifdef DEBUG
  21322. +# define    PRINTK(x)    printk (x)
  21323. +#else
  21324. +# define    PRINTK(x)    /**/
  21325. +#endif
  21326. +
  21327. +/*
  21328. + * Internal flag options for termios setting behavior
  21329. + */
  21330. +#define TERMIOS_FLUSH    1
  21331. +#define TERMIOS_WAIT    2
  21332. +#define TERMIOS_TERMIO    4
  21333. +
  21334. +void tty_wait_until_sent(struct tty_struct * tty, int timeout)
  21335. +{
  21336. +    struct wait_queue wait = { current, NULL };
  21337. +
  21338. +#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
  21339. +    printk("%s wait until sent...\n", tty_name(tty));
  21340. +#endif
  21341. +    if (!tty->driver.chars_in_buffer ||
  21342. +        !tty->driver.chars_in_buffer(tty))
  21343. +        return;
  21344. +    add_wait_queue(&tty->write_wait, &wait);
  21345. +    current->counter = 0;    /* make us low-priority */
  21346. +    if (timeout)
  21347. +        current->timeout = timeout + jiffies;
  21348. +    else
  21349. +        current->timeout = (unsigned) -1;
  21350. +    do {
  21351. +#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
  21352. +        printk("waiting %s...(%d)\n", tty_name(tty), tty->driver.chars_in_buffer(tty));
  21353. +#endif
  21354. +        current->state = TASK_INTERRUPTIBLE;
  21355. +        if (current->signal & ~current->blocked)
  21356. +            break;
  21357. +        if (!tty->driver.chars_in_buffer(tty))
  21358. +            break;
  21359. +        schedule();
  21360. +    } while (current->timeout);
  21361. +    current->state = TASK_RUNNING;
  21362. +    remove_wait_queue(&tty->write_wait, &wait);
  21363. +}
  21364. +
  21365. +static void unset_locked_termios(struct termios *termios,
  21366. +                 struct termios *old,
  21367. +                 struct termios *locked)
  21368. +{
  21369. +    int    i;
  21370. +    
  21371. +#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
  21372. +
  21373. +    if (!locked) {
  21374. +        printk("Warning?!? termios_locked is NULL.\n");
  21375. +        return;
  21376. +    }
  21377. +
  21378. +    NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
  21379. +    NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
  21380. +    NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
  21381. +    NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
  21382. +    termios->c_line = locked->c_line ? old->c_line : termios->c_line;
  21383. +    for (i=0; i < NCCS; i++)
  21384. +        termios->c_cc[i] = locked->c_cc[i] ?
  21385. +            old->c_cc[i] : termios->c_cc[i];
  21386. +}
  21387. +
  21388. +static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
  21389. +{
  21390. +    struct termio tmp_termio;
  21391. +    struct termios tmp_termios;
  21392. +    struct termios old_termios = *tty->termios;
  21393. +    int retval, canon_change;
  21394. +
  21395. +    retval = tty_check_change(tty);
  21396. +    if (retval)
  21397. +        return retval;
  21398. +
  21399. +    if (opt & TERMIOS_TERMIO) {
  21400. +        retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio));
  21401. +        if (retval)
  21402. +            return retval;
  21403. +        tmp_termios = *tty->termios;
  21404. +        memcpy_fromfs(&tmp_termio, (struct termio *) arg,
  21405. +                  sizeof (struct termio));
  21406. +
  21407. +#define SET_LOW_BITS(x,y)    ((x) = (0xffff0000 & (x)) | (y))
  21408. +        SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
  21409. +        SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
  21410. +        SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
  21411. +        SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
  21412. +        memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
  21413. +#undef SET_LOW_BITS
  21414. +    } else {
  21415. +        retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termios));
  21416. +        if (retval)
  21417. +            return retval;
  21418. +        memcpy_fromfs(&tmp_termios, (struct termios *) arg,
  21419. +                  sizeof (struct termios));
  21420. +    }
  21421. +
  21422. +    if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
  21423. +        tty->ldisc.flush_buffer(tty);
  21424. +
  21425. +    if (opt & TERMIOS_WAIT)
  21426. +        tty_wait_until_sent(tty, 0);
  21427. +
  21428. +    cli();
  21429. +    *tty->termios = tmp_termios;
  21430. +    unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
  21431. +    canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
  21432. +    if (canon_change) {
  21433. +        memset(&tty->read_flags, 0, sizeof tty->read_flags);
  21434. +        tty->canon_head = tty->read_tail;
  21435. +        tty->canon_data = 0;
  21436. +        tty->erasing = 0;
  21437. +    }
  21438. +    sti();
  21439. +    if (canon_change && !L_ICANON(tty) && tty->read_cnt)
  21440. +        /* Get characters left over from canonical mode. */
  21441. +        wake_up_interruptible(&tty->read_wait);
  21442. +
  21443. +    /* see if packet mode change of state */
  21444. +
  21445. +    if (tty->link && tty->link->packet) {
  21446. +        int old_flow = ((old_termios.c_iflag & IXON) &&
  21447. +                (old_termios.c_cc[VSTOP] == '\023') &&
  21448. +                (old_termios.c_cc[VSTART] == '\021'));
  21449. +        int new_flow = (I_IXON(tty) &&
  21450. +                STOP_CHAR(tty) == '\023' &&
  21451. +                START_CHAR(tty) == '\021');
  21452. +        if (old_flow != new_flow) {
  21453. +            tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
  21454. +            if (new_flow)
  21455. +                tty->ctrl_status |= TIOCPKT_DOSTOP;
  21456. +            else
  21457. +                tty->ctrl_status |= TIOCPKT_NOSTOP;
  21458. +            wake_up_interruptible(&tty->link->read_wait);
  21459. +        }
  21460. +    }
  21461. +
  21462. +    if (tty->driver.set_termios)
  21463. +        (*tty->driver.set_termios)(tty, &old_termios);
  21464. +
  21465. +    if (tty->ldisc.set_termios)
  21466. +        (*tty->ldisc.set_termios)(tty, &old_termios);
  21467. +        
  21468. +    return 0;
  21469. +}
  21470. +
  21471. +static int get_termio(struct tty_struct * tty, struct termio * termio)
  21472. +{
  21473. +    int i;
  21474. +    struct termio tmp_termio;
  21475. +
  21476. +    i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
  21477. +    if (i)
  21478. +        return i;
  21479. +    tmp_termio.c_iflag = tty->termios->c_iflag;
  21480. +    tmp_termio.c_oflag = tty->termios->c_oflag;
  21481. +    tmp_termio.c_cflag = tty->termios->c_cflag;
  21482. +    tmp_termio.c_lflag = tty->termios->c_lflag;
  21483. +    tmp_termio.c_line = tty->termios->c_line;
  21484. +    for(i=0 ; i < NCC ; i++)
  21485. +        tmp_termio.c_cc[i] = tty->termios->c_cc[i];
  21486. +    memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
  21487. +    return 0;
  21488. +}
  21489. +
  21490. +static unsigned long inq_canon(struct tty_struct * tty)
  21491. +{
  21492. +    int nr, head, tail;
  21493. +
  21494. +    if (!tty->canon_data || !tty->read_buf)
  21495. +        return 0;
  21496. +    head = tty->canon_head;
  21497. +    tail = tty->read_tail;
  21498. +    nr = (head - tail) & (N_TTY_BUF_SIZE-1);
  21499. +    /* Skip EOF-chars.. */
  21500. +    while (head != tail) {
  21501. +        if (test_bit(tail, &tty->read_flags) &&
  21502. +            tty->read_buf[tail] == __DISABLED_CHAR)
  21503. +            nr--;
  21504. +        tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  21505. +    }
  21506. +    return nr;
  21507. +}
  21508. +
  21509. +int n_tty_ioctl(struct tty_struct * tty, struct file * file,
  21510. +               unsigned int cmd, unsigned long arg)
  21511. +{
  21512. +    struct tty_struct * real_tty;
  21513. +    int retval;
  21514. +    int opt = 0;
  21515. +
  21516. +    if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  21517. +        tty->driver.subtype == PTY_TYPE_MASTER)
  21518. +        real_tty = tty->link;
  21519. +    else
  21520. +        real_tty = tty;
  21521. +
  21522. +    switch (cmd) {
  21523. +        case TCGETS:
  21524. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  21525. +                         sizeof (struct termios));
  21526. +            if (retval)
  21527. +                return retval;
  21528. +            memcpy_tofs((struct termios *) arg,
  21529. +                    real_tty->termios,
  21530. +                    sizeof (struct termios));
  21531. +            return 0;
  21532. +        case TCSETSF:
  21533. +            opt |= TERMIOS_FLUSH;
  21534. +        case TCSETSW:
  21535. +            opt |= TERMIOS_WAIT;
  21536. +        case TCSETS:
  21537. +            return set_termios(real_tty, arg, opt);
  21538. +        case TCGETA:
  21539. +            return get_termio(real_tty,(struct termio *) arg);
  21540. +        case TCSETAF:
  21541. +            opt |= TERMIOS_FLUSH;
  21542. +        case TCSETAW:
  21543. +            opt |= TERMIOS_WAIT;
  21544. +        case TCSETA:
  21545. +            return set_termios(real_tty, arg, opt|TERMIOS_TERMIO);
  21546. +        case TCXONC:
  21547. +            retval = tty_check_change(tty);
  21548. +            if (retval)
  21549. +                return retval;
  21550. +            switch (arg) {
  21551. +            case TCOOFF:
  21552. +                stop_tty(tty);
  21553. +                break;
  21554. +            case TCOON:
  21555. +                start_tty(tty);
  21556. +                break;
  21557. +            case TCIOFF:
  21558. +                if (STOP_CHAR(tty) != __DISABLED_CHAR)
  21559. +                    tty->driver.write(tty, 0,
  21560. +                              &STOP_CHAR(tty), 1);
  21561. +                break;
  21562. +            case TCION:
  21563. +                if (START_CHAR(tty) != __DISABLED_CHAR)
  21564. +                    tty->driver.write(tty, 0,
  21565. +                              &START_CHAR(tty), 1);
  21566. +                break;
  21567. +            default:
  21568. +                return -EINVAL;
  21569. +            }
  21570. +            return 0;
  21571. +        case TCFLSH:
  21572. +            retval = tty_check_change(tty);
  21573. +            if (retval)
  21574. +                return retval;
  21575. +            switch (arg) {
  21576. +            case TCIFLUSH:
  21577. +                if (tty->ldisc.flush_buffer)
  21578. +                    tty->ldisc.flush_buffer(tty);
  21579. +                break;
  21580. +            case TCIOFLUSH:
  21581. +                if (tty->ldisc.flush_buffer)
  21582. +                    tty->ldisc.flush_buffer(tty);
  21583. +                /* fall through */
  21584. +            case TCOFLUSH:
  21585. +                if (tty->driver.flush_buffer)
  21586. +                    tty->driver.flush_buffer(tty);
  21587. +                break;
  21588. +            default:
  21589. +                return -EINVAL;
  21590. +            }
  21591. +            return 0;
  21592. +        case TIOCOUTQ:
  21593. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  21594. +                         sizeof (unsigned long));
  21595. +            if (retval)
  21596. +                return retval;
  21597. +            if (tty->driver.chars_in_buffer)
  21598. +                put_fs_long(tty->driver.chars_in_buffer(tty),
  21599. +                        (unsigned long *) arg);
  21600. +            else
  21601. +                put_fs_long(0, (unsigned long *) arg);
  21602. +            return 0;
  21603. +        case TIOCINQ:
  21604. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  21605. +                         sizeof (unsigned long));
  21606. +            if (retval)
  21607. +                return retval;
  21608. +            if (L_ICANON(tty))
  21609. +                put_fs_long(inq_canon(tty),
  21610. +                    (unsigned long *) arg);
  21611. +            else
  21612. +                put_fs_long(tty->read_cnt,
  21613. +                        (unsigned long *) arg);
  21614. +            return 0;
  21615. +        case TIOCGLCKTRMIOS:
  21616. +            retval = verify_area(VERIFY_WRITE, (void *) arg,
  21617. +                         sizeof (struct termios));
  21618. +            if (retval)
  21619. +                return retval;
  21620. +            memcpy_tofs((struct termios *) arg,
  21621. +                    real_tty->termios_locked,
  21622. +                    sizeof (struct termios));
  21623. +            return 0;
  21624. +        case TIOCSLCKTRMIOS:
  21625. +            if (!suser())
  21626. +                return -EPERM;
  21627. +            retval = verify_area(VERIFY_READ, (void *) arg,
  21628. +                         sizeof (struct termios));
  21629. +            if (retval)
  21630. +                return retval;
  21631. +            memcpy_fromfs(real_tty->termios_locked,
  21632. +                      (struct termios *) arg,
  21633. +                      sizeof (struct termios));
  21634. +            return 0;
  21635. +        case TIOCPKT:
  21636. +            if (tty->driver.type != TTY_DRIVER_TYPE_PTY ||
  21637. +                tty->driver.subtype != PTY_TYPE_MASTER)
  21638. +                return -ENOTTY;
  21639. +            retval = verify_area(VERIFY_READ, (void *) arg,
  21640. +                         sizeof (unsigned long));
  21641. +            if (retval)
  21642. +                return retval;
  21643. +            if (get_fs_long(arg)) {
  21644. +                if (!tty->packet) {
  21645. +                    tty->packet = 1;
  21646. +                    tty->link->ctrl_status = 0;
  21647. +                }
  21648. +            } else
  21649. +                tty->packet = 0;
  21650. +            return 0;
  21651. +        /* These two ioctl's always return success; even if */
  21652. +        /* the driver doesn't support them. */
  21653. +        case TCSBRK: case TCSBRKP:
  21654. +            retval = tty_check_change(tty);
  21655. +            if (retval)
  21656. +                return retval;
  21657. +            tty_wait_until_sent(tty, 0);
  21658. +            if (!tty->driver.ioctl)
  21659. +                return 0;
  21660. +            tty->driver.ioctl(tty, file, cmd, arg);
  21661. +            return 0;
  21662. +        default:
  21663. +            return -ENOIOCTLCMD;
  21664. +        }
  21665. +}
  21666. diff -urNwbB linux/arch/arm/drivers/char/uni_hash.tbl linux.arm/arch/arm/drivers/char/uni_hash.tbl
  21667. --- linux/arch/arm/drivers/char/uni_hash.tbl    Thu Jan  1 01:00:00 1970
  21668. +++ linux.arm/arch/arm/drivers/char/uni_hash.tbl    Sun Feb 11 18:15:12 1996
  21669. @@ -0,0 +1,88 @@
  21670. +/*
  21671. + * uni_hash.tbl
  21672. + *
  21673. + * Do not edit this file; it was automatically generated by
  21674. + *
  21675. + * conmakehash cp437.uni > uni_hash.tbl
  21676. + *
  21677. + */
  21678. +
  21679. +#include <linux/types.h>
  21680. +#include <linux/kd.h>
  21681. +
  21682. +static u8 dfont_unicount[256] = 
  21683. +{
  21684. +      1,   1,   1,   1,   2,   1,   1,   1,
  21685. +      1,   1,   1,   1,   1,   1,   1,   1,
  21686. +      1,   1,   1,   1,   1,   1,   1,   1,
  21687. +      1,   1,   1,   1,   1,   1,   1,   1,
  21688. +      1,   1,   2,   1,   1,   1,   1,   1,
  21689. +      1,   1,   1,   1,   2,   2,   1,   1,
  21690. +      1,   1,   1,   1,   1,   1,   1,   1,
  21691. +      1,   1,   1,   1,   1,   1,   1,   1,
  21692. +      1,   5,   1,   2,   1,   4,   1,   1,
  21693. +      1,   5,   1,   2,   1,   1,   1,   5,
  21694. +      1,   1,   2,   1,   1,   4,   1,   1,
  21695. +      1,   2,   1,   1,   1,   1,   1,   2,
  21696. +      1,   2,   1,   1,   1,   1,   1,   1,
  21697. +      1,   1,   1,   1,   1,   1,   1,   2,
  21698. +      1,   1,   1,   1,   1,   1,   1,   1,
  21699. +      2,   2,   1,   1,   2,   1,   1,   1,
  21700. +      1,   1,   1,   1,   1,   1,   1,   1,
  21701. +      1,   1,   1,   1,   1,   1,   1,   2,
  21702. +      1,   1,   1,   1,   1,   1,   1,   1,
  21703. +      1,   1,   1,   1,   1,   1,   1,   1,
  21704. +      1,   1,   1,   1,   1,   1,   1,   1,
  21705. +      1,   1,   1,   1,   1,   1,   1,   1,
  21706. +      1,   1,   1,   1,   1,   1,   1,   1,
  21707. +      1,   1,   1,   1,   1,   1,   1,   1,
  21708. +      1,   1,   1,   1,   1,   1,   1,   1,
  21709. +      1,   1,   1,   1,   1,   1,   1,   1,
  21710. +      1,   1,   1,   1,   1,   1,   1,   1,
  21711. +      1,   1,   1,   1,   1,   1,   1,   1,
  21712. +      1,   2,   1,   1,   1,   1,   2,   1,
  21713. +      2,   1,   2,   1,   1,   2,   1,   1,
  21714. +      1,   1,   1,   1,   1,   1,   1,   1,
  21715. +      1,   1,   1,   1,   1,   1,   2,   1
  21716. +};
  21717. +
  21718. +static u16 dfont_unitable[295] = 
  21719. +{
  21720. +    0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x25c6, 0x2663, 0x2660,
  21721. +    0x2022, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b,
  21722. +    0x263c, 0x25ba, 0x25c4, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac,
  21723. +    0x21a8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2,
  21724. +    0x25bc, 0x0020, 0x0021, 0x0022, 0x00a8, 0x0023, 0x0024, 0x0025,
  21725. +    0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x00b8,
  21726. +    0x002d, 0x00ad, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033,
  21727. +    0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b,
  21728. +    0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x00c0, 0x00c1,
  21729. +    0x00c2, 0x00c3, 0x0042, 0x0043, 0x00a9, 0x0044, 0x0045, 0x00c8,
  21730. +    0x00ca, 0x00cb, 0x0046, 0x0047, 0x0048, 0x0049, 0x00cc, 0x00cd,
  21731. +    0x00ce, 0x00cf, 0x004a, 0x004b, 0x212a, 0x004c, 0x004d, 0x004e,
  21732. +    0x004f, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x0050, 0x0051, 0x0052,
  21733. +    0x00ae, 0x0053, 0x0054, 0x0055, 0x00d9, 0x00da, 0x00db, 0x0056,
  21734. +    0x0057, 0x0058, 0x0059, 0x00dd, 0x005a, 0x005b, 0x005c, 0x005d,
  21735. +    0x005e, 0x005f, 0xf804, 0x0060, 0x0061, 0x00e3, 0x0062, 0x0063,
  21736. +    0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b,
  21737. +    0x006c, 0x006d, 0x006e, 0x006f, 0x00f5, 0x0070, 0x0071, 0x0072,
  21738. +    0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x00d7, 0x0079,
  21739. +    0x00fd, 0x007a, 0x007b, 0x007c, 0x00a5, 0x007d, 0x007e, 0x2302,
  21740. +    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
  21741. +    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
  21742. +    0x212b, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb,
  21743. +    0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7,
  21744. +    0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa,
  21745. +    0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab,
  21746. +    0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562,
  21747. +    0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b,
  21748. +    0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e,
  21749. +    0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c,
  21750. +    0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553,
  21751. +    0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590,
  21752. +    0x2580, 0x03b1, 0x03b2, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3,
  21753. +    0x00b5, 0x03bc, 0x03c4, 0x03a6, 0x00d8, 0x0398, 0x03a9, 0x2126,
  21754. +    0x03b4, 0x221e, 0x03c6, 0x00f8, 0x03b5, 0x2229, 0x2261, 0x00b1,
  21755. +    0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219,
  21756. +    0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0xfffd, 0x00a0
  21757. +};
  21758. \ No newline at end of file
  21759. diff -urNwbB linux/arch/arm/drivers/char/vc_screen.c linux.arm/arch/arm/drivers/char/vc_screen.c
  21760. --- linux/arch/arm/drivers/char/vc_screen.c    Thu Jan  1 01:00:00 1970
  21761. +++ linux.arm/arch/arm/drivers/char/vc_screen.c    Sat Feb 24 18:12:00 1996
  21762. @@ -0,0 +1,232 @@
  21763. +/*
  21764. + * linux/arch/arm/drivers/char/vc_screen.c
  21765. + *
  21766. + * Provide access to virtual console memory.
  21767. + * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
  21768. + * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
  21769. + *            [minor: N]
  21770. + *
  21771. + * /dev/vcsaN: idem, but including attributes, and prefixed with
  21772. + *    the 4 bytes lines,columns,x,y (as screendump used to give)
  21773. + *            [minor: N+128]
  21774. + *
  21775. + * This replaces screendump and part of selection, so that the system
  21776. + * administrator can control access using file system permissions.
  21777. + *
  21778. + * aeb@cwi.nl - efter Friedas begravelse - 950211
  21779. + *
  21780. + * Modified by Russell King (01/01/96) [experimental + in development]
  21781. + */
  21782. +
  21783. +#include <linux/kernel.h>
  21784. +#include <linux/major.h>
  21785. +#include <linux/errno.h>
  21786. +#include <linux/tty.h>
  21787. +#include <linux/fs.h>
  21788. +#include <asm/segment.h>
  21789. +#include "vt_kern.h"
  21790. +#include "selection.h"
  21791. +
  21792. +#define HEADER_SIZE    4
  21793. +#define video_num_lines 75
  21794. +#define video_num_columns 100
  21795. +
  21796. +static inline int
  21797. +vcs_size(struct inode *inode)
  21798. +{
  21799. +    int size = video_num_lines * video_num_columns;
  21800. +    if (MINOR(inode->i_rdev) & 128)
  21801. +        size = 4*size + HEADER_SIZE;
  21802. +    return size;
  21803. +}
  21804. +
  21805. +static int
  21806. +vcs_lseek(struct inode *inode, struct file *file, off_t offset, int orig)
  21807. +{
  21808. +    int size = vcs_size(inode);
  21809. +
  21810. +    switch (orig) {
  21811. +        case 0:
  21812. +            file->f_pos = offset;
  21813. +            break;
  21814. +        case 1:
  21815. +            file->f_pos += offset;
  21816. +            break;
  21817. +        case 2:
  21818. +            file->f_pos = size + offset;
  21819. +            break;
  21820. +        default:
  21821. +            return -EINVAL;
  21822. +    }
  21823. +    if (file->f_pos < 0 || file->f_pos > size)
  21824. +        return -EINVAL;
  21825. +    return file->f_pos;
  21826. +}
  21827. +
  21828. +static int
  21829. +vcs_read(struct inode *inode, struct file *file, char *buf, int count)
  21830. +{
  21831. +    unsigned long p = file->f_pos;
  21832. +    unsigned int cons = MINOR(inode->i_rdev);
  21833. +    int attr, size, read;
  21834. +    char *buf0;
  21835. +    unsigned long *org, d;
  21836. +
  21837. +    attr = (cons & 128);
  21838. +    cons = (cons & 127);
  21839. +    if (cons == 0)
  21840. +        cons = fg_console;
  21841. +    else
  21842. +        cons--;
  21843. +    if (!vc_cons_allocated(cons))
  21844. +        return -ENXIO;
  21845. +
  21846. +    size = vcs_size(inode);
  21847. +    if (count < 0 || p > size)
  21848. +        return -EINVAL;
  21849. +    if (count > size - p)
  21850. +        count = size - p;
  21851. +
  21852. +    buf0 = buf;
  21853. +    if (!attr) {
  21854. +        org = screen_pos(cons, p);
  21855. +        while (count-- > 0)
  21856. +            put_fs_byte(*org++ & 0xff, buf++);
  21857. +    } else {
  21858. +        if (p < HEADER_SIZE) {
  21859. +            char header[HEADER_SIZE];
  21860. +            header[0] = (char) video_num_lines;
  21861. +            header[1] = (char) video_num_columns;
  21862. +            getconsxy(cons, header+2);
  21863. +            while (p < HEADER_SIZE && count-- > 0)
  21864. +                put_fs_byte(header[p++], buf++);
  21865. +        }
  21866. +        p -= HEADER_SIZE;
  21867. +        org = screen_pos(cons, p>>2);
  21868. +        if (p & 3)
  21869. +            d = *org++;
  21870. +        if ((p & 3)>0 && count-- > 0)
  21871. +            put_fs_byte(d >> 24, buf++);
  21872. +        if ((p & 3)>1 && count-- > 0)
  21873. +            put_fs_byte((d >> 16) & 0xff, buf++);
  21874. +        if ((p & 3)>2 && count-- > 0)
  21875. +            put_fs_byte((d >> 8) & 0xff, buf++);
  21876. +        while (count > 1) {
  21877. +            put_fs_long(*org++, buf);
  21878. +            buf += 4;
  21879. +            count -= 4;
  21880. +        }
  21881. +        if (count > 0)
  21882. +        {
  21883. +            d = *org;
  21884. +            put_fs_byte(d & 0xff, buf++);
  21885. +            if (count > 1)
  21886. +                put_fs_byte((d >> 8) & 0xff, buf++);
  21887. +            if (count > 2)
  21888. +                put_fs_byte((d >> 16) & 0xff, buf++);
  21889. +        }
  21890. +    }
  21891. +    read = buf - buf0;
  21892. +    file->f_pos += read;
  21893. +    return read;
  21894. +}
  21895. +
  21896. +static int
  21897. +vcs_write(struct inode *inode, struct file *file, const char *buf, int count)
  21898. +{
  21899. +    unsigned long p = file->f_pos;
  21900. +    unsigned int cons = MINOR(inode->i_rdev);
  21901. +    int viewed, attr, size, written;
  21902. +    const char *buf0;
  21903. +    unsigned long *org;
  21904. +
  21905. +    attr = (cons & 128);
  21906. +    cons = (cons & 127);
  21907. +    if (cons == 0) {
  21908. +        cons = fg_console;
  21909. +        viewed = 1;
  21910. +    } else {
  21911. +        cons--;
  21912. +        viewed = 0;
  21913. +    }
  21914. +    if (!vc_cons_allocated(cons))
  21915. +        return -ENXIO;
  21916. +
  21917. +    size = vcs_size(inode);
  21918. +    if (count < 0 || p > size)
  21919. +        return -EINVAL;
  21920. +    if (count > size - p)
  21921. +        count = size - p;
  21922. +
  21923. +    buf0 = buf;
  21924. +    if (!attr) {
  21925. +        org = screen_pos(cons, p);
  21926. +        while (count-- > 0) {
  21927. +            *org = (*org & 0xffffff00) | get_fs_byte(buf++);
  21928. +            ll_char_write (*org);
  21929. +            org++;
  21930. +        }
  21931. +    } else {
  21932. +#if 0
  21933. +        if (p < HEADER_SIZE) {
  21934. +            char header[HEADER_SIZE];
  21935. +            getconsxy(cons, header+2);
  21936. +            while (p < HEADER_SIZE && count-- > 0)
  21937. +                header[p++] = get_fs_byte(buf++);
  21938. +            if (!viewed)
  21939. +                putconsxy(cons, header+2);
  21940. +        }
  21941. +        p -= HEADER_SIZE;
  21942. +        org = screen_pos(cons, p>>2, viewed);
  21943. +        if ((p & 1) && count-- > 0) {
  21944. +            scr_writew((get_fs_byte(buf++) << 8) |
  21945. +                   (scr_readw(org) & 0xff), org);
  21946. +            org++;
  21947. +        }
  21948. +        while (count > 1) {
  21949. +            scr_writew(get_fs_word(buf), org++);
  21950. +            buf += 2;
  21951. +            count -= 2;
  21952. +        }
  21953. +        if (count > 0)
  21954. +            scr_writew((scr_readw(org) & 0xff00) |
  21955. +                   get_fs_byte(buf++), org);
  21956. +#endif
  21957. +    }
  21958. +    written = buf - buf0;
  21959. +    update_scrmem (cons, file->f_pos, written);
  21960. +    file->f_pos += written;
  21961. +    return written;
  21962. +}
  21963. +
  21964. +static int
  21965. +vcs_open(struct inode *inode, struct file *filp)
  21966. +{
  21967. +    unsigned int cons = (MINOR(inode->i_rdev) & 127);
  21968. +    if(cons && !vc_cons_allocated(cons-1))
  21969. +        return -ENXIO;
  21970. +    return 0;
  21971. +}
  21972. +
  21973. +static struct file_operations vcs_fops = {
  21974. +    vcs_lseek,    /* lseek */
  21975. +    vcs_read,    /* read */
  21976. +    vcs_write,    /* write */
  21977. +    NULL,        /* readdir */
  21978. +    NULL,        /* select */
  21979. +    NULL,        /* ioctl */
  21980. +    NULL,        /* mmap */
  21981. +    vcs_open,    /* open */
  21982. +    NULL,        /* release */
  21983. +    NULL        /* fsync */
  21984. +};
  21985. +
  21986. +int vcs_init(void)
  21987. +{
  21988. +    int error;
  21989. +
  21990. +    error = register_chrdev(VCS_MAJOR, "vcs", &vcs_fops);
  21991. +    if (error)
  21992. +        printk("unable to get major %d for vcs device", VCS_MAJOR);
  21993. +    return error;
  21994. +}
  21995. diff -urNwbB linux/arch/arm/drivers/char/vt.c linux.arm/arch/arm/drivers/char/vt.c
  21996. --- linux/arch/arm/drivers/char/vt.c    Thu Jan  1 01:00:00 1970
  21997. +++ linux.arm/arch/arm/drivers/char/vt.c    Sun Mar  3 12:49:38 1996
  21998. @@ -0,0 +1,935 @@
  21999. +/*
  22000. + *  linux/arch/arm/drivers/char/vt.c
  22001. + *
  22002. + *  Copyright (C) 1992 obz under the linux copyright
  22003. + *
  22004. + *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
  22005. + *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
  22006. + *  Ported to ARM - rmk92@ecs.soton.ac.uk - July 1995
  22007. + */
  22008. +
  22009. +#include <linux/types.h>
  22010. +#include <linux/errno.h>
  22011. +#include <linux/sched.h>
  22012. +#include <linux/tty.h>
  22013. +#include <linux/timer.h>
  22014. +#include <linux/kernel.h>
  22015. +#include <linux/kd.h>
  22016. +#include <linux/vt.h>
  22017. +#include <linux/string.h>
  22018. +#include <linux/malloc.h>
  22019. +
  22020. +#include <asm/io.h>
  22021. +#include <asm/segment.h>
  22022. +
  22023. +#include "kbd_kern.h"
  22024. +#include "vt_kern.h"
  22025. +#include "diacr.h"
  22026. +
  22027. +
  22028. +extern struct tty_driver console_driver;
  22029. +extern int sel_cons;
  22030. +
  22031. +#define VT_IS_IN_USE(i)    (console_driver.table[i] && console_driver.table[i]->count)
  22032. +#define VT_BUSY(i)    (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons)
  22033. +
  22034. +/*
  22035. + * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
  22036. + * experimentation and study of X386 SYSV handling.
  22037. + *
  22038. + * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
  22039. + * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
  22040. + * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
  22041. + * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
  22042. + * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
  22043. + * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
  22044. + * to the current console is done by the main ioctl code.
  22045. + */
  22046. +
  22047. +struct vt_struct *vt_cons[MAX_NR_CONSOLES];
  22048. +
  22049. +asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
  22050. +
  22051. +extern int getkeycode(unsigned int scancode);
  22052. +extern int setkeycode(unsigned int scancode, unsigned int keycode);
  22053. +extern void compute_shiftstate(void);
  22054. +extern void change_console(unsigned int new_console);
  22055. +extern void complete_change_console(unsigned int new_console);
  22056. +extern int vt_waitactive(void);
  22057. +extern void do_blank_screen(int nopowersave);
  22058. +extern void do_unblank_screen(void);
  22059. +extern unsigned int keymap_count;
  22060. +
  22061. +/*
  22062. + * routines to load custom translation table, EGA/VGA font and
  22063. + * VGA colour palette from console.c
  22064. + */
  22065. +extern int con_set_trans_old(unsigned char * table);
  22066. +extern int con_get_trans_old(unsigned char * table);
  22067. +extern int con_set_trans_new(unsigned short * table);
  22068. +extern int con_get_trans_new(unsigned short * table);
  22069. +extern void con_clear_unimap(struct unimapinit *ui);
  22070. +extern int con_set_unimap(ushort ct, struct unipair *list);
  22071. +extern int con_get_unimap(ushort ct, ushort *uct, struct unipair *list);
  22072. +extern void con_set_default_unimap(void);
  22073. +extern int con_set_font(char * fontmap);
  22074. +extern int con_get_font(char * fontmap);
  22075. +
  22076. +/*
  22077. + * these are the valid i/o ports we're allowed to change. they map all the
  22078. + * video ports
  22079. + */
  22080. +#define GPFIRST 0x3b4
  22081. +#define GPLAST 0x3df
  22082. +#define GPNUM (GPLAST - GPFIRST + 1)
  22083. +
  22084. +/*
  22085. + * Generates sound of some count for some number of clock ticks
  22086. + * [count = 1193180 / frequency]
  22087. + *
  22088. + * If freq is 0, will turn off sound, else will turn it on for that time.
  22089. + * If msec is 0, will return immediately, else will sleep for msec time, then
  22090. + * turn sound off.
  22091. + *
  22092. + * We use the BEEP_TIMER vector since we're using the same method to
  22093. + * generate sound, and we'll overwrite any beep in progress. That may
  22094. + * be something to fix later, if we like.
  22095. + *
  22096. + * We also return immediately, which is what was implied within the X
  22097. + * comments - KDMKTONE doesn't put the process to sleep.
  22098. + */
  22099. +static inline void
  22100. +kd_mksound2(unsigned int count, unsigned int vol, unsigned int ticks)
  22101. +{
  22102. +    extern void mk_beep (unsigned int count, unsigned int vol, unsigned int ticks);
  22103. +#ifdef CONFIG_SOUND
  22104. +    mk_beep(count, vol, ticks);
  22105. +#endif
  22106. +}
  22107. +
  22108. +void
  22109. +kd_mksound(unsigned int count, unsigned int ticks)
  22110. +{
  22111. +    kd_mksound2(count, 72, ticks);
  22112. +}
  22113. +
  22114. +/*
  22115. + * We handle the console-specific ioctl's here.  We allow the
  22116. + * capability to modify any console, not just the fg_console.
  22117. + */
  22118. +int vt_ioctl(struct tty_struct *tty, struct file * file,
  22119. +         unsigned int cmd, unsigned long arg)
  22120. +{
  22121. +    int i, perm;
  22122. +    unsigned int console;
  22123. +    unsigned char ucval;
  22124. +    struct kbd_struct * kbd;
  22125. +    struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
  22126. +
  22127. +    console = vt->vc_num;
  22128. +
  22129. +    if (!vc_cons_allocated(console))     /* impossible? */
  22130. +        return -ENOIOCTLCMD;
  22131. +
  22132. +    /*
  22133. +     * To have permissions to do most of the vt ioctls, we either have
  22134. +     * to be the owner of the tty, or super-user.
  22135. +     */
  22136. +    perm = 0;
  22137. +    if (current->tty == tty || suser())
  22138. +        perm = 1;
  22139. +
  22140. +    kbd = kbd_table + console;
  22141. +    switch (cmd) {
  22142. +    case KIOCSOUND:
  22143. +        if (!perm)
  22144. +            return -EPERM;
  22145. +        kd_mksound((unsigned int)arg, 5);
  22146. +        return 0;
  22147. +
  22148. +    case KDMKTONE:
  22149. +        if (!perm)
  22150. +            return -EPERM;
  22151. +    {
  22152. +        unsigned int freq  = ((unsigned long *)arg)[0];
  22153. +        unsigned int vol   = ((unsigned long *)arg)[1];
  22154. +        unsigned int ticks = HZ * (((unsigned long *)arg)[2] & 0xffff) / 1000;
  22155. +
  22156. +        /*
  22157. +         * Generate the tone for the appropriate number of ticks.
  22158. +         * If the time is zero, turn off sound ourselves.
  22159. +         */
  22160. +        kd_mksound2(freq, vol, ticks);
  22161. +        return 0;
  22162. +    }
  22163. +
  22164. +    case KDGKBTYPE:
  22165. +        /*
  22166. +         * this is naive.
  22167. +         */
  22168. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  22169. +        if (!i)
  22170. +            put_user(KB_101, (char *) arg);
  22171. +        return i;
  22172. +
  22173. +    case KDADDIO:
  22174. +    case KDDELIO:
  22175. +        /*
  22176. +         * KDADDIO and KDDELIO may be able to add ports beyond what
  22177. +         * we reject here, but to be safe...
  22178. +         */
  22179. +        if (arg < GPFIRST || arg > GPLAST)
  22180. +            return -EINVAL;
  22181. +        return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
  22182. +
  22183. +    case KDENABIO:
  22184. +    case KDDISABIO:
  22185. +        return sys_ioperm(GPFIRST, GPNUM,
  22186. +                  (cmd == KDENABIO)) ? -ENXIO : 0;
  22187. +
  22188. +    case KDSETMODE:
  22189. +        /*
  22190. +         * currently, setting the mode from KD_TEXT to KD_GRAPHICS
  22191. +         * doesn't do a whole lot. i'm not sure if it should do any
  22192. +         * restoration of modes or what...
  22193. +         */
  22194. +        if (!perm)
  22195. +            return -EPERM;
  22196. +        switch (arg) {
  22197. +        case KD_GRAPHICS:
  22198. +            break;
  22199. +        case KD_TEXT0:
  22200. +        case KD_TEXT1:
  22201. +            arg = KD_TEXT;
  22202. +        case KD_TEXT:
  22203. +            break;
  22204. +        default:
  22205. +            return -EINVAL;
  22206. +        }
  22207. +        if (vt_cons[console]->vc_mode == (unsigned char) arg)
  22208. +            return 0;
  22209. +        vt_cons[console]->vc_mode = (unsigned char) arg;
  22210. +        if (console != fg_console)
  22211. +            return 0;
  22212. +        /*
  22213. +         * explicitly blank/unblank the screen if switching modes
  22214. +         */
  22215. +        if (arg == KD_TEXT)
  22216. +            do_unblank_screen();
  22217. +        else
  22218. +            do_blank_screen(1);
  22219. +        return 0;
  22220. +
  22221. +    case KDGETMODE:
  22222. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
  22223. +        if (!i)
  22224. +            put_user(vt_cons[console]->vc_mode, (unsigned long *) arg);
  22225. +        return i;
  22226. +
  22227. +    case KDMAPDISP:
  22228. +    case KDUNMAPDISP:
  22229. +        /*
  22230. +         * these work like a combination of mmap and KDENABIO.
  22231. +         * this could be easily finished.
  22232. +         */
  22233. +        return -EINVAL;
  22234. +
  22235. +    case KDSKBMODE:
  22236. +        if (!perm)
  22237. +            return -EPERM;
  22238. +        switch(arg) {
  22239. +          case K_RAW:
  22240. +            kbd->kbdmode = VC_RAW;
  22241. +            break;
  22242. +          case K_MEDIUMRAW:
  22243. +            kbd->kbdmode = VC_MEDIUMRAW;
  22244. +            break;
  22245. +          case K_XLATE:
  22246. +            kbd->kbdmode = VC_XLATE;
  22247. +            compute_shiftstate();
  22248. +            break;
  22249. +          case K_UNICODE:
  22250. +            kbd->kbdmode = VC_UNICODE;
  22251. +            compute_shiftstate();
  22252. +            break;
  22253. +          default:
  22254. +            return -EINVAL;
  22255. +        }
  22256. +        if (tty->ldisc.flush_buffer)
  22257. +            tty->ldisc.flush_buffer(tty);
  22258. +        return 0;
  22259. +
  22260. +    case KDGKBMODE:
  22261. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
  22262. +        if (!i) {
  22263. +            ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
  22264. +                 (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
  22265. +                 (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
  22266. +                 K_XLATE);
  22267. +            put_user(ucval, (int *) arg);
  22268. +        }
  22269. +        return i;
  22270. +
  22271. +    /* this could be folded into KDSKBMODE, but for compatibility
  22272. +       reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
  22273. +    case KDSKBMETA:
  22274. +        switch(arg) {
  22275. +          case K_METABIT:
  22276. +            clr_vc_kbd_mode(kbd, VC_META);
  22277. +            break;
  22278. +          case K_ESCPREFIX:
  22279. +            set_vc_kbd_mode(kbd, VC_META);
  22280. +            break;
  22281. +          default:
  22282. +            return -EINVAL;
  22283. +        }
  22284. +        return 0;
  22285. +
  22286. +    case KDGKBMETA:
  22287. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
  22288. +        if (!i) {
  22289. +            ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX :
  22290. +                 K_METABIT);
  22291. +            put_user(ucval, (int *) arg);
  22292. +        }
  22293. +        return i;
  22294. +
  22295. +    case KDGETKEYCODE:
  22296. +    {
  22297. +        struct kbkeycode * const a = (struct kbkeycode *)arg;
  22298. +        unsigned int sc;
  22299. +        int kc;
  22300. +
  22301. +        i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbkeycode));
  22302. +        if (i)
  22303. +            return i;
  22304. +        sc = get_user(&a->scancode);
  22305. +        kc = getkeycode(sc);
  22306. +        if (kc < 0)
  22307. +            return kc;
  22308. +        put_user(kc, &a->keycode);
  22309. +        return 0;
  22310. +    }
  22311. +
  22312. +    case KDSETKEYCODE:
  22313. +    {
  22314. +        struct kbkeycode * const a = (struct kbkeycode *)arg;
  22315. +        unsigned int sc, kc;
  22316. +
  22317. +        if (!perm)
  22318. +            return -EPERM;
  22319. +        i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbkeycode));
  22320. +        if (i)
  22321. +            return i;
  22322. +        sc = get_user(&a->scancode);
  22323. +        kc = get_user(&a->keycode);
  22324. +        return setkeycode(sc, kc);
  22325. +    }
  22326. +
  22327. +    case KDGKBENT:
  22328. +    {
  22329. +        struct kbentry * const a = (struct kbentry *)arg;
  22330. +        ushort *key_map, val;
  22331. +        u_char s;
  22332. +
  22333. +        i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
  22334. +        if (i)
  22335. +            return i;
  22336. +        if ((i = get_user(&a->kb_index)) >= NR_KEYS)
  22337. +            return -EINVAL;
  22338. +        if ((s = get_user(&a->kb_table)) >= MAX_NR_KEYMAPS)
  22339. +            return -EINVAL;
  22340. +        key_map = key_maps[s];
  22341. +        if (key_map) {
  22342. +            val = U(key_map[i]);
  22343. +            if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
  22344. +            val = K_HOLE;
  22345. +        } else
  22346. +            val = (i ? K_HOLE : K_NOSUCHMAP);
  22347. +        put_user(val, &a->kb_value);
  22348. +        return 0;
  22349. +    }
  22350. +
  22351. +    case KDSKBENT:
  22352. +    {
  22353. +        const struct kbentry * a = (struct kbentry *)arg;
  22354. +        ushort *key_map;
  22355. +        u_char s;
  22356. +        u_short v, ov;
  22357. +
  22358. +        if (!perm)
  22359. +            return -EPERM;
  22360. +        i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbentry));
  22361. +        if (i)
  22362. +            return i;
  22363. +        if ((i = get_user(&a->kb_index)) >= NR_KEYS)
  22364. +            return -EINVAL;
  22365. +        if ((s = get_user(&a->kb_table)) >= MAX_NR_KEYMAPS)
  22366. +            return -EINVAL;
  22367. +        v = get_user(&a->kb_value);
  22368. +        if (!i && v == K_NOSUCHMAP) {
  22369. +            /* disallocate map */
  22370. +            key_map = key_maps[s];
  22371. +            if (s && key_map) {
  22372. +                key_maps[s] = 0;
  22373. +                if (key_map[0] == U(K_ALLOCATED)) {
  22374. +                kfree_s(key_map, sizeof(plain_map));
  22375. +                keymap_count--;
  22376. +                }
  22377. +            }
  22378. +            return 0;
  22379. +        }
  22380. +
  22381. +        if (KTYP(v) < NR_TYPES) {
  22382. +            if (KVAL(v) > max_vals[KTYP(v)])
  22383. +            return -EINVAL;
  22384. +        } else
  22385. +            if (kbd->kbdmode != VC_UNICODE)
  22386. +            return -EINVAL;
  22387. +
  22388. +        /* assignment to entry 0 only tests validity of args */
  22389. +        if (!i)
  22390. +            return 0;
  22391. +
  22392. +        if (!(key_map = key_maps[s])) {
  22393. +            int j;
  22394. +            
  22395. +            if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && !suser())
  22396. +                return -EPERM;
  22397. +
  22398. +            key_map = (ushort *) kmalloc(sizeof(plain_map),
  22399. +                             GFP_KERNEL);
  22400. +            if (!key_map)
  22401. +                return -ENOMEM;
  22402. +            key_maps[s] = key_map;
  22403. +            key_map[0] = U(K_ALLOCATED);
  22404. +            for (j = 1; j < NR_KEYS; j++)
  22405. +                key_map[j] = U(K_HOLE);
  22406. +            keymap_count++;
  22407. +        }
  22408. +        ov = U(key_map[i]);
  22409. +        if (v == ov)
  22410. +            return 0;    /* nothing to do */
  22411. +        /*
  22412. +         * Only the Superuser can set or unset the Secure
  22413. +         * Attention Key.
  22414. +         */
  22415. +        if (((ov == K_SAK) || (v == K_SAK)) && !suser())
  22416. +            return -EPERM;
  22417. +        key_map[i] = U(v);
  22418. +        if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
  22419. +            compute_shiftstate();
  22420. +        return 0;
  22421. +    }
  22422. +
  22423. +    case KDGKBSENT:
  22424. +    {
  22425. +        struct kbsentry *a = (struct kbsentry *)arg;
  22426. +        char *p;
  22427. +        u_char *q;
  22428. +        int sz;
  22429. +
  22430. +        i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
  22431. +        if (i)
  22432. +            return i;
  22433. +        if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC || i < 0)
  22434. +            return -EINVAL;
  22435. +        sz = sizeof(a->kb_string) - 1; /* sz should have been
  22436. +                          a struct member */
  22437. +        q = a->kb_string;
  22438. +        p = func_table[i];
  22439. +        if(p)
  22440. +            for ( ; *p && sz; p++, sz--)
  22441. +                put_user(*p, q++);
  22442. +        put_user('\0', q);
  22443. +        return ((p && *p) ? -EOVERFLOW : 0);
  22444. +    }
  22445. +
  22446. +    case KDSKBSENT:
  22447. +    {
  22448. +        struct kbsentry * const a = (struct kbsentry *)arg;
  22449. +        int delta;
  22450. +        char *first_free, *fj, *fnw;
  22451. +        int j, k, sz;
  22452. +        u_char *p;
  22453. +        char *q;
  22454. +
  22455. +        if (!perm)
  22456. +            return -EPERM;
  22457. +        i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
  22458. +        if (i)
  22459. +            return i;
  22460. +        if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC)
  22461. +            return -EINVAL;
  22462. +        q = func_table[i];
  22463. +
  22464. +        first_free = funcbufptr + (funcbufsize - funcbufleft);
  22465. +        for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) ;
  22466. +        if (j < MAX_NR_FUNC)
  22467. +            fj = func_table[j];
  22468. +        else
  22469. +            fj = first_free;
  22470. +
  22471. +        delta = (q ? -strlen(q) : 1);
  22472. +        sz = sizeof(a->kb_string);     /* sz should have been
  22473. +                           a struct member */
  22474. +        for (p = a->kb_string; get_user(p) && sz; p++,sz--)
  22475. +            delta++;
  22476. +        if (!sz)
  22477. +            return -EOVERFLOW;
  22478. +        if (delta <= funcbufleft) {     /* it fits in current buf */
  22479. +            if (j < MAX_NR_FUNC) {
  22480. +            memmove(fj + delta, fj, first_free - fj);
  22481. +            for (k = j; k < MAX_NR_FUNC; k++)
  22482. +                if (func_table[k])
  22483. +                func_table[k] += delta;
  22484. +            }
  22485. +            if (!q)
  22486. +              func_table[i] = fj;
  22487. +            funcbufleft -= delta;
  22488. +        } else {            /* allocate a larger buffer */
  22489. +            sz = 256;
  22490. +            while (sz < funcbufsize - funcbufleft + delta)
  22491. +              sz <<= 1;
  22492. +            fnw = (char *) kmalloc(sz, GFP_KERNEL);
  22493. +            if(!fnw)
  22494. +              return -ENOMEM;
  22495. +
  22496. +            if (!q)
  22497. +              func_table[i] = fj;
  22498. +            if (fj > funcbufptr)
  22499. +            memmove(fnw, funcbufptr, fj - funcbufptr);
  22500. +            for (k = 0; k < j; k++)
  22501. +              if (func_table[k])
  22502. +            func_table[k] = fnw + (func_table[k] - funcbufptr);
  22503. +
  22504. +            if (first_free > fj) {
  22505. +            memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
  22506. +            for (k = j; k < MAX_NR_FUNC; k++)
  22507. +              if (func_table[k])
  22508. +                func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
  22509. +            }
  22510. +            if (funcbufptr != func_buf)
  22511. +              kfree_s(funcbufptr, funcbufsize);
  22512. +            funcbufptr = fnw;
  22513. +            funcbufleft = funcbufleft - delta + sz - funcbufsize;
  22514. +            funcbufsize = sz;
  22515. +        }
  22516. +        for (p = a->kb_string, q = func_table[i]; ; p++, q++)
  22517. +            if (!(*q = get_user(p)))
  22518. +                break;
  22519. +        return 0;
  22520. +    }
  22521. +
  22522. +    case KDGKBDIACR:
  22523. +    {
  22524. +        struct kbdiacrs *a = (struct kbdiacrs *)arg;
  22525. +
  22526. +        i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs));
  22527. +        if (i)
  22528. +            return i;
  22529. +        put_user(accent_table_size, &a->kb_cnt);
  22530. +        memcpy_tofs(a->kbdiacr, accent_table,
  22531. +                accent_table_size*sizeof(struct kbdiacr));
  22532. +        return 0;
  22533. +    }
  22534. +
  22535. +    case KDSKBDIACR:
  22536. +    {
  22537. +        struct kbdiacrs *a = (struct kbdiacrs *)arg;
  22538. +        unsigned int ct;
  22539. +
  22540. +        if (!perm)
  22541. +            return -EPERM;
  22542. +        i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
  22543. +        if (i)
  22544. +            return i;
  22545. +        ct = get_user(&a->kb_cnt);
  22546. +        if (ct >= MAX_DIACR)
  22547. +            return -EINVAL;
  22548. +        accent_table_size = ct;
  22549. +        memcpy_fromfs(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr));
  22550. +        return 0;
  22551. +    }
  22552. +
  22553. +    /* the ioctls below read/set the flags usually shown in the leds */
  22554. +    /* don't use them - they will go away without warning */
  22555. +    case KDGKBLED:
  22556. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  22557. +        if (i)
  22558. +            return i;
  22559. +        put_user(kbd->ledflagstate |
  22560. +                (kbd->default_ledflagstate << 4), (char *) arg);
  22561. +        return 0;
  22562. +
  22563. +    case KDSKBLED:
  22564. +        if (!perm)
  22565. +            return -EPERM;
  22566. +        if (arg & ~0x77)
  22567. +            return -EINVAL;
  22568. +        kbd->ledflagstate = (arg & 7);
  22569. +        kbd->default_ledflagstate = ((arg >> 4) & 7);
  22570. +        set_leds();
  22571. +        return 0;
  22572. +
  22573. +    /* the ioctls below only set the lights, not the functions */
  22574. +    /* for those, see KDGKBLED and KDSKBLED above */
  22575. +    case KDGETLED:
  22576. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  22577. +        if (i)
  22578. +            return i;
  22579. +        put_user(getledstate(), (char *) arg);
  22580. +        return 0;
  22581. +
  22582. +    case KDSETLED:
  22583. +        if (!perm)
  22584. +            return -EPERM;
  22585. +        setledstate(kbd, arg);
  22586. +        return 0;
  22587. +
  22588. +    /*
  22589. +     * A process can indicate its willingness to accept signals
  22590. +     * generated by pressing an appropriate key combination.
  22591. +     * Thus, one can have a daemon that e.g. spawns a new console
  22592. +     * upon a keypess and then changes to it.
  22593. +     * Probably init should be changed to do this (and have a
  22594. +     * field ks (`keyboard signal') in inittab describing the
  22595. +     * desired acion), so that the number of background daemons
  22596. +     * does not increase.
  22597. +     */
  22598. +    case KDSIGACCEPT:
  22599. +    {
  22600. +        extern int spawnpid, spawnsig;
  22601. +        if (!perm)
  22602. +          return -EPERM;
  22603. +        if (arg < 1 || arg > NSIG || arg == SIGKILL)
  22604. +          return -EINVAL;
  22605. +        spawnpid = current->pid;
  22606. +        spawnsig = arg;
  22607. +        return 0;
  22608. +    }
  22609. +
  22610. +    case VT_SETMODE:
  22611. +    {
  22612. +        struct vt_mode *vtmode = (struct vt_mode *)arg;
  22613. +        char mode;
  22614. +
  22615. +        if (!perm)
  22616. +            return -EPERM;
  22617. +        i = verify_area(VERIFY_WRITE, (void *)vtmode, sizeof(struct vt_mode));
  22618. +        if (i)
  22619. +            return i;
  22620. +        mode = get_user(&vtmode->mode);
  22621. +        if (mode != VT_AUTO && mode != VT_PROCESS)
  22622. +            return -EINVAL;
  22623. +        vt_cons[console]->vt_mode.mode = mode;
  22624. +        vt_cons[console]->vt_mode.waitv = get_user(&vtmode->waitv);
  22625. +        vt_cons[console]->vt_mode.relsig = get_user(&vtmode->relsig);
  22626. +        vt_cons[console]->vt_mode.acqsig = get_user(&vtmode->acqsig);
  22627. +        /* the frsig is ignored, so we set it to 0 */
  22628. +        vt_cons[console]->vt_mode.frsig = 0;
  22629. +        vt_cons[console]->vt_pid = current->pid;
  22630. +        vt_cons[console]->vt_newvt = 0;
  22631. +        return 0;
  22632. +    }
  22633. +
  22634. +    case VT_GETMODE:
  22635. +    {
  22636. +        struct vt_mode *vtmode = (struct vt_mode *)arg;
  22637. +
  22638. +        i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct vt_mode));
  22639. +        if (i)
  22640. +            return i;
  22641. +        put_user(vt_cons[console]->vt_mode.mode, &vtmode->mode);
  22642. +        put_user(vt_cons[console]->vt_mode.waitv, &vtmode->waitv);
  22643. +        put_user(vt_cons[console]->vt_mode.relsig, &vtmode->relsig);
  22644. +        put_user(vt_cons[console]->vt_mode.acqsig, &vtmode->acqsig);
  22645. +        put_user(vt_cons[console]->vt_mode.frsig, &vtmode->frsig);
  22646. +        return 0;
  22647. +    }
  22648. +
  22649. +    /*
  22650. +     * Returns global vt state. Note that VT 0 is always open, since
  22651. +     * it's an alias for the current VT, and people can't use it here.
  22652. +     * We cannot return state for more than 16 VTs, since v_state is short.
  22653. +     */
  22654. +    case VT_GETSTATE:
  22655. +    {
  22656. +        struct vt_stat *vtstat = (struct vt_stat *)arg;
  22657. +        unsigned short state, mask;
  22658. +
  22659. +        i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
  22660. +        if (i)
  22661. +            return i;
  22662. +        put_user(fg_console + 1, &vtstat->v_active);
  22663. +        state = 1;    /* /dev/tty0 is always open */
  22664. +        for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
  22665. +            if (VT_IS_IN_USE(i))
  22666. +                state |= mask;
  22667. +        put_user(state, &vtstat->v_state);
  22668. +        return 0;
  22669. +    }
  22670. +
  22671. +    /*
  22672. +     * Returns the first available (non-opened) console.
  22673. +     */
  22674. +    case VT_OPENQRY:
  22675. +        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
  22676. +        if (i)
  22677. +            return i;
  22678. +        for (i = 0; i < MAX_NR_CONSOLES; ++i)
  22679. +            if (! VT_IS_IN_USE(i))
  22680. +                break;
  22681. +        put_user(i < MAX_NR_CONSOLES ? (i+1) : -1, (int *) arg);
  22682. +        return 0;
  22683. +
  22684. +    /*
  22685. +     * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
  22686. +     * with num >= 1 (switches to vt 0, our console, are not allowed, just
  22687. +     * to preserve sanity).
  22688. +     */
  22689. +    case VT_ACTIVATE:
  22690. +        if (!perm)
  22691. +            return -EPERM;
  22692. +        if (arg == 0 || arg > MAX_NR_CONSOLES)
  22693. +            return -ENXIO;
  22694. +        arg--;
  22695. +        i = vc_allocate(arg);
  22696. +        if (i)
  22697. +            return i;
  22698. +        change_console(arg);
  22699. +        return 0;
  22700. +
  22701. +    /*
  22702. +     * wait until the specified VT has been activated
  22703. +     */
  22704. +    case VT_WAITACTIVE:
  22705. +        if (!perm)
  22706. +            return -EPERM;
  22707. +        if (arg == 0 || arg > MAX_NR_CONSOLES)
  22708. +            return -ENXIO;
  22709. +        arg--;
  22710. +        while (fg_console != arg)
  22711. +        {
  22712. +            if (vt_waitactive() < 0)
  22713. +                return -EINTR;
  22714. +        }
  22715. +        return 0;
  22716. +
  22717. +    /*
  22718. +     * If a vt is under process control, the kernel will not switch to it
  22719. +     * immediately, but postpone the operation until the process calls this
  22720. +     * ioctl, allowing the switch to complete.
  22721. +     *
  22722. +     * According to the X sources this is the behavior:
  22723. +     *    0:    pending switch-from not OK
  22724. +     *    1:    pending switch-from OK
  22725. +     *    2:    completed switch-to OK
  22726. +     */
  22727. +    case VT_RELDISP:
  22728. +        if (!perm)
  22729. +            return -EPERM;
  22730. +        if (vt_cons[console]->vt_mode.mode != VT_PROCESS)
  22731. +            return -EINVAL;
  22732. +
  22733. +        /*
  22734. +         * Switching-from response
  22735. +         */
  22736. +        if (vt_cons[console]->vt_newvt >= 0)
  22737. +        {
  22738. +            if (arg == 0)
  22739. +                /*
  22740. +                 * Switch disallowed, so forget we were trying
  22741. +                 * to do it.
  22742. +                 */
  22743. +                vt_cons[console]->vt_newvt = -1;
  22744. +
  22745. +            else
  22746. +            {
  22747. +                /*
  22748. +                 * The current vt has been released, so
  22749. +                 * complete the switch.
  22750. +                 */
  22751. +                int newvt = vt_cons[console]->vt_newvt;
  22752. +                vt_cons[console]->vt_newvt = -1;
  22753. +                i = vc_allocate(newvt);
  22754. +                if (i)
  22755. +                    return i;
  22756. +                complete_change_console(newvt);
  22757. +            }
  22758. +        }
  22759. +
  22760. +        /*
  22761. +         * Switched-to response
  22762. +         */
  22763. +        else
  22764. +        {
  22765. +            /*
  22766. +             * If it's just an ACK, ignore it
  22767. +             */
  22768. +            if (arg != VT_ACKACQ)
  22769. +                return -EINVAL;
  22770. +        }
  22771. +
  22772. +        return 0;
  22773. +
  22774. +     /*
  22775. +      * Disallocate memory associated to VT (but leave VT1)
  22776. +      */
  22777. +     case VT_DISALLOCATE:
  22778. +        if (arg > MAX_NR_CONSOLES)
  22779. +            return -ENXIO;
  22780. +        if (arg == 0) {
  22781. +            /* disallocate all unused consoles, but leave 0 */
  22782. +            for (i = 1; i<MAX_NR_CONSOLES; i++)
  22783. +              if (! VT_BUSY(i))
  22784. +              vc_disallocate(i);
  22785. +        } else {
  22786. +            /* disallocate a single console, if possible */
  22787. +            arg--;
  22788. +            if (VT_BUSY(arg))
  22789. +              return -EBUSY;
  22790. +            if (arg)                /* leave 0 */
  22791. +            vc_disallocate(arg);
  22792. +        }
  22793. +        return 0;
  22794. +
  22795. +    case VT_RESIZE:
  22796. +    {
  22797. +        struct vt_sizes *vtsizes = (struct vt_sizes *) arg;
  22798. +        ushort ll,cc;
  22799. +        if (!perm)
  22800. +            return -EPERM;
  22801. +        i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
  22802. +        if (i)
  22803. +            return i;
  22804. +        ll = get_user(&vtsizes->v_rows);
  22805. +        cc = get_user(&vtsizes->v_cols);
  22806. +        return vc_resize(ll, cc);
  22807. +    }
  22808. +    
  22809. +    case VT_GETPALETTE:
  22810. +    {
  22811. +        unsigned long pix, num, *val;
  22812. +        extern int palette_getentries (unsigned int, unsigned long,
  22813. +            unsigned long, unsigned long);
  22814. +        
  22815. +            i = verify_area(VERIFY_WRITE, (void *)arg, 12);
  22816. +            if (i)
  22817. +                return i;
  22818. +            pix = get_fs_long((unsigned long *)arg);
  22819. +            num = get_fs_long((unsigned long *)(arg + 4));
  22820. +            val = (unsigned long *)get_fs_long((unsigned long *)(arg + 8));
  22821. +        return palette_getentries(console, pix, num, val);
  22822. +    }
  22823. +
  22824. +    case VT_SETPALETTE:
  22825. +    {
  22826. +        unsigned long pix, num, *val;
  22827. +        extern int palette_setentries (unsigned int, unsigned long,
  22828. +            unsigned long, unsigned long);
  22829. +
  22830. +            i = verify_area(VERIFY_READ, (void *)arg, 12);
  22831. +            if (i)
  22832. +                return i;
  22833. +
  22834. +            pix = get_fs_long((unsigned long *)arg);
  22835. +            num = get_fs_long((unsigned long *)(arg + 4));
  22836. +            val = (unsigned long *)get_fs_long((unsigned long *)(arg + 8));
  22837. +        return palette_setentries(console, pix, num, val);
  22838. +    }
  22839. +
  22840. +    case VT_GETSCRINFO: {
  22841. +        extern int console_getparams (unsigned int, unsigned long arg);
  22842. +        i = verify_area(VERIFY_WRITE, (void *)arg, 20);
  22843. +            if (i)
  22844. +                return i;
  22845. +        return console_getparams(console, arg);
  22846. +    }
  22847. +
  22848. +    case PIO_FONT:
  22849. +        if (!perm)
  22850. +            return -EPERM;
  22851. +        if (vt_cons[fg_console]->vc_mode != KD_TEXT)
  22852. +            return -EINVAL;
  22853. +        return con_set_font((char *)arg);
  22854. +        /* con_set_font() defined in console.c */
  22855. +
  22856. +    case GIO_FONT:
  22857. +        if (vt_cons[fg_console]->vc_mode != KD_TEXT)
  22858. +            return -EINVAL;
  22859. +        return con_get_font((char *)arg);
  22860. +        /* con_get_font() defined in console.c */
  22861. +
  22862. +    case PIO_SCRNMAP:
  22863. +        if (!perm)
  22864. +            return -EPERM;
  22865. +        return con_set_trans_old((char *)arg);
  22866. +
  22867. +    case GIO_SCRNMAP:
  22868. +        return con_get_trans_old((char *)arg);
  22869. +
  22870. +    case PIO_UNISCRNMAP:
  22871. +        if (!perm)
  22872. +            return -EPERM;
  22873. +        return con_set_trans_new((short *)arg);
  22874. +
  22875. +    case GIO_UNISCRNMAP:
  22876. +        return con_get_trans_new((short *)arg);
  22877. +
  22878. +    case PIO_UNIMAPCLR:
  22879. +          {    struct unimapinit ui;
  22880. +        if (!perm)
  22881. +            return -EPERM;
  22882. +        i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapinit));
  22883. +        if (i)
  22884. +          return i;
  22885. +        memcpy_fromfs(&ui, (void *)arg, sizeof(struct unimapinit));
  22886. +        con_clear_unimap(&ui);
  22887. +        return 0;
  22888. +          }
  22889. +
  22890. +    case PIO_UNIMAP:
  22891. +          {    struct unimapdesc *ud;
  22892. +        u_short ct;
  22893. +        struct unipair *list;
  22894. +
  22895. +        if (!perm)
  22896. +            return -EPERM;
  22897. +        i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapdesc));
  22898. +        if (i == 0) {
  22899. +            ud = (struct unimapdesc *) arg;
  22900. +            ct = get_fs_word(&ud->entry_ct);
  22901. +            list = (struct unipair *) get_fs_long(&ud->entries);
  22902. +            i = verify_area(VERIFY_READ, (void *) list,
  22903. +                        ct*sizeof(struct unipair));
  22904. +        }
  22905. +        if (i)
  22906. +          return i;
  22907. +        return con_set_unimap(ct, list);
  22908. +          }
  22909. +
  22910. +    case GIO_UNIMAP:
  22911. +          {    struct unimapdesc *ud;
  22912. +        u_short ct;
  22913. +        struct unipair *list;
  22914. +
  22915. +        i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct unimapdesc));
  22916. +        if (i == 0) {
  22917. +            ud = (struct unimapdesc *) arg;
  22918. +            ct = get_fs_word(&ud->entry_ct);
  22919. +            list = (struct unipair *) get_fs_long(&ud->entries);
  22920. +            if (ct)
  22921. +              i = verify_area(VERIFY_WRITE, (void *) list,
  22922. +                          ct*sizeof(struct unipair));
  22923. +        }
  22924. +        if (i)
  22925. +          return i;
  22926. +        return con_get_unimap(ct, &(ud->entry_ct), list);
  22927. +          }
  22928. +
  22929. +    default:
  22930. +        return -ENOIOCTLCMD;
  22931. +    }
  22932. +}
  22933. diff -urNwbB linux/arch/arm/drivers/char/vt_kern.h linux.arm/arch/arm/drivers/char/vt_kern.h
  22934. --- linux/arch/arm/drivers/char/vt_kern.h    Thu Jan  1 01:00:00 1970
  22935. +++ linux.arm/arch/arm/drivers/char/vt_kern.h    Sun Feb 11 19:37:27 1996
  22936. @@ -0,0 +1,29 @@
  22937. +#ifndef _VT_KERN_H
  22938. +#define _VT_KERN_H
  22939. +
  22940. +/*
  22941. + * this really is an extension of the vc_cons structure in console.c, but
  22942. + * with information needed by the vt package
  22943. + */
  22944. +
  22945. +#include <linux/vt.h>
  22946. +
  22947. +extern struct vt_struct {
  22948. +    int vc_num;                /* The console number */
  22949. +    unsigned char    vc_mode;        /* KD_TEXT, ... */
  22950. +    unsigned char    vc_kbdraw;
  22951. +    unsigned char    vc_kbde0;
  22952. +    unsigned char   vc_kbdleds;
  22953. +    struct vt_mode    vt_mode;
  22954. +    int        vt_pid;
  22955. +    int        vt_newvt;
  22956. +    struct wait_queue *paste_wait;
  22957. +} *vt_cons[MAX_NR_CONSOLES];
  22958. +
  22959. +void kd_mksound(unsigned int count, unsigned int ticks);
  22960. +int vc_allocate(unsigned int console);
  22961. +int vc_cons_allocated(unsigned int console);
  22962. +int vc_resize(unsigned long lines, unsigned long cols);
  22963. +void vc_disallocate(unsigned int console);
  22964. +
  22965. +#endif /* _VT_KERN_H */
  22966. diff -urNwbB linux/arch/arm/drivers/net/Makefile linux.arm/arch/arm/drivers/net/Makefile
  22967. --- linux/arch/arm/drivers/net/Makefile    Thu Jan  1 01:00:00 1970
  22968. +++ linux.arm/arch/arm/drivers/net/Makefile    Sat Feb 24 21:37:51 1996
  22969. @@ -0,0 +1,155 @@
  22970. +# File: drivers/net/Makefile
  22971. +#
  22972. +# Makefile for the Linux network (ethercard) device drivers.
  22973. +#
  22974. +
  22975. +all: links first_rule
  22976. +
  22977. +ifeq (${CFLAGS},)
  22978. +CFLAGS = -D__KERNEL__ \
  22979. +    -Wall -Wstrict-prototypes -I. -I../../../../include \
  22980. +    -O2 -fomit-frame-pointer
  22981. +
  22982. +include ../../../../.config
  22983. +
  22984. +#TOPDIR = ../../../..
  22985. +endif
  22986. +
  22987. +L_TARGET := net.a
  22988. +L_OBJS   := Space.o auto_irq.o net_init.o loopback.o
  22989. +M_OBJS   :=
  22990. +SYMTAB_OBJS =
  22991. +MOD_LIST_NAME := NET_MODULES
  22992. +
  22993. +# Need these to keep track of whether the SLHC module should
  22994. +# really go in the kernel or a module
  22995. +CONFIG_SLHC_BUILTIN :=
  22996. +CONFIG_SLHC_MODULE  :=
  22997. +
  22998. +ifeq ($(CONFIG_ETHER1),y)
  22999. +L_OBJS += ether1.o
  23000. +else
  23001. +  ifeq ($(CONFIG_ETHER1),m)
  23002. +  M_OBJS += ether1.o
  23003. +  endif
  23004. +endif
  23005. +
  23006. +ifeq ($(CONFIG_ETHER3),y)
  23007. +L_OBJS += ether3.o
  23008. +else
  23009. +  ifeq ($(CONFIG_ETHER3),m)
  23010. +  M_OBJS += ether3.o
  23011. +  endif
  23012. +endif
  23013. +
  23014. +ifeq ($(CONFIG_IPIP),y)
  23015. +L_OBJS += tunnel.o
  23016. +else
  23017. +  ifeq ($(CONFIG_IPIP),m)
  23018. +  M_OBJS += tunnel.o
  23019. +  endif
  23020. +endif
  23021. +
  23022. +ifeq ($(CONFIG_PLIP),y)
  23023. +L_OBJS += plip.o
  23024. +else
  23025. +  ifeq ($(CONFIG_PLIP),m)
  23026. +  M_OBJS += plip.o
  23027. +  endif
  23028. +endif
  23029. +
  23030. +ifeq ($(CONFIG_PPP),y)
  23031. +L_OBJS += ppp.o
  23032. +SYMTAB_OBJS += ppp.o
  23033. +CONFIG_SLHC_BUILTIN = y
  23034. +else
  23035. +  ifeq ($(CONFIG_PPP),m)
  23036. +  M_OBJS += ppp.o
  23037. +  SYMTAB_OBJS += ppp.o
  23038. +  CONFIG_SLHC_MODULE = y
  23039. +  endif
  23040. +endif
  23041. +
  23042. +ifneq ($(CONFIG_PPP),n)
  23043. +  M_OBJS += bsd_comp.o
  23044. +endif
  23045. +
  23046. +ifeq ($(CONFIG_SLIP),y)
  23047. +L_OBJS += slip.o
  23048. +CONFIG_SLHC_BUILTIN = y
  23049. +else
  23050. +  ifeq ($(CONFIG_SLIP),m)
  23051. +  M_OBJS += slip.o
  23052. +  CONFIG_SLHC_MODULE = y
  23053. +  endif
  23054. +endif
  23055. +
  23056. +ifeq ($(CONFIG_DUMMY),y)
  23057. +L_OBJS += dummy.o
  23058. +else
  23059. +  ifeq ($(CONFIG_DUMMY),m)
  23060. +  L_OBJS += dummy.o
  23061. +  endif
  23062. +endif
  23063. +
  23064. +# If anything built-in uses slhc, then build it into the kernel also.
  23065. +# If not, but a module uses it, build as a module.
  23066. +ifdef CONFIG_SLHC_BUILTIN
  23067. +L_OBJS += slhc.o
  23068. +else
  23069. +  ifdef CONFIG_SLHC_MODULE
  23070. +  M_OBJS += slhc.o
  23071. +  endif
  23072. +endif
  23073. +
  23074. +ifeq ($(CONFIG_EQUALIZER),y)
  23075. +L_OBJS += eql.o
  23076. +else
  23077. +  ifeq ($(CONFIG_EQUALIZER),m)
  23078. +  M_OBJS += eql.o
  23079. +  endif
  23080. +endif
  23081. +
  23082. +fastdep: links
  23083. +
  23084. +ifdef CONFIG_MODVERSIONS
  23085. +$(L_TARGET): $(SYMTAB_OBJS:.o=.ver)
  23086. +dep: $(SYMTAB_OBJS:.o=.ver)
  23087. +fastdep: $(SYMTAB_OBJS:.o=.ver)
  23088. +endif
  23089. +
  23090. +include $(TOPDIR)/Rules.make
  23091. +
  23092. +include $(TOPDIR)/versions.mk
  23093. +
  23094. +clean:
  23095. +    rm -f core *.o *.a *.s
  23096. +
  23097. +Space.o: Space.c ../../../../include/linux/autoconf.h
  23098. +    $(CC) $(CFLAGS) $(OPTS) -c $<
  23099. +
  23100. +net_init.o: ../../../../include/linux/autoconf.h
  23101. +
  23102. +plip.o:    plip.c
  23103. +    $(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $<
  23104. +
  23105. +slip.o:    slip.c
  23106. +    $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
  23107. +
  23108. +dummy.o: dummy.c
  23109. +    $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
  23110. +
  23111. +LK = README.eql README.multicast README.tunnel README1.PLIP README2.PLIP bsd_comp.c dummy.c \
  23112. +    eql.c loopback.c net_init.c slhc.c slhc.h slip.c slip.h tunnel.c
  23113. +
  23114. +links:
  23115. +    -@for f in $(LK); do \
  23116. +        ln -s ../../../../drivers/net/$$f .; \
  23117. +    done
  23118. +    touch links
  23119. +
  23120. +LINKCLEAN:
  23121. +    -@for f in $(LK); do \
  23122. +        if [ -L $$f ]; then rm $$f; fi; \
  23123. +    done
  23124. +    rm -f links
  23125. diff -urNwbB linux/arch/arm/drivers/net/Space.c linux.arm/arch/arm/drivers/net/Space.c
  23126. --- linux/arch/arm/drivers/net/Space.c    Thu Jan  1 01:00:00 1970
  23127. +++ linux.arm/arch/arm/drivers/net/Space.c    Tue Feb 13 23:09:15 1996
  23128. @@ -0,0 +1,226 @@
  23129. +/*
  23130. + * INET        An implementation of the TCP/IP protocol suite for the LINUX
  23131. + *        operating system.  INET is implemented using the  BSD Socket
  23132. + *        interface as the means of communication with the user level.
  23133. + *
  23134. + *        Holds initial configuration information for devices.
  23135. + *
  23136. + * NOTE:    This file is a nice idea, but its current format does not work
  23137. + *        well for drivers that support multiple units, like the SLIP
  23138. + *        driver.  We should actually have only one pointer to a driver
  23139. + *        here, with the driver knowing how many units it supports.
  23140. + *        Currently, the SLIP driver abuses the "base_addr" integer
  23141. + *        field of the 'device' structure to store the unit number...
  23142. + *        -FvK
  23143. + *
  23144. + * Version:    @(#)Space.c    1.0.7    08/12/93
  23145. + *
  23146. + * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  23147. + *        Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  23148. + *        Donald J. Becker, <becker@super.org>
  23149. + *
  23150. + *        This program is free software; you can redistribute it and/or
  23151. + *        modify it under the terms of the GNU General Public License
  23152. + *        as published by the Free Software Foundation; either version
  23153. + *        2 of the License, or (at your option) any later version.
  23154. + */
  23155. +#include <linux/config.h>
  23156. +#include <linux/netdevice.h>
  23157. +#include <linux/errno.h>
  23158. +
  23159. +/* The first device defaults to I/O base '0', which means autoprobe. */
  23160. +#ifndef ETH0_ADDR
  23161. +# define ETH0_ADDR 0
  23162. +#endif
  23163. +#ifndef ETH0_IRQ
  23164. +# define ETH0_IRQ 0
  23165. +#endif
  23166. +/* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20),
  23167. +   which means "don't probe".  These entries exist to only to provide empty
  23168. +   slots which may be enabled at boot-time. */
  23169. +
  23170. +#define    NEXT_DEV    NULL
  23171. +
  23172. +
  23173. +/* A unified ethernet device probe.  This is the easiest way to have every
  23174. +   ethernet adaptor have the name "eth[0123...]".
  23175. +   */
  23176. +extern int ether1_probe (struct device *dev);
  23177. +extern int ether3_probe (struct device *dev);
  23178. +
  23179. +static int
  23180. +ethif_probe(struct device *dev)
  23181. +{
  23182. +    u_long base_addr = dev->base_addr;
  23183. +
  23184. +    if ((base_addr == 0xffe0)  ||  (base_addr == 1))
  23185. +    return 1;        /* ENXIO */
  23186. +
  23187. +    if (1
  23188. +#ifdef CONFIG_ETHER1
  23189. +    && ether1_probe (dev)
  23190. +#endif
  23191. +#ifdef CONFIG_ETHER3
  23192. +        && ether3_probe (dev)
  23193. +#endif
  23194. +    && 1 ) {
  23195. +    return 1;    /* -ENODEV or -EAGAIN would be more accurate. */
  23196. +    }
  23197. +    return 0;
  23198. +}
  23199. +
  23200. +static struct device eth3_dev = {
  23201. +    "eth3",
  23202. +    0x0, 0x0, 0x0, 0x0,
  23203. +    0xffe0 /* I/O base*/, 0, 0, 0, 0,
  23204. +    NEXT_DEV, ethif_probe,
  23205. +};
  23206. +
  23207. +static struct device eth2_dev = {
  23208. +    "eth2",
  23209. +    0x0, 0x0, 0x0, 0x0,
  23210. +    0xffe0 /* I/O base*/, 0, 0, 0, 0,
  23211. +    ð3_dev, ethif_probe,
  23212. +};
  23213. +
  23214. +static struct device eth1_dev = {
  23215. +    "eth1",
  23216. +    0x0, 0x0, 0x0, 0x0,
  23217. +    0xffe0 /* I/O base*/, 0, 0, 0, 0,
  23218. +    ð2_dev, ethif_probe,
  23219. +};
  23220. +
  23221. +static struct device eth0_dev = {
  23222. +    "eth0",
  23223. +    0x0, 0x0, 0x0, 0x0,
  23224. +    ETH0_ADDR, ETH0_IRQ, 0, 0, 0,
  23225. +    ð1_dev, ethif_probe,
  23226. +};
  23227. +
  23228. +#undef  NEXT_DEV
  23229. +#define NEXT_DEV (ð0_dev)
  23230. +
  23231. +#if defined(PLIP) || defined(CONFIG_PLIP)
  23232. +extern int plip_init(struct device *);
  23233. +
  23234. +static struct device plip2_dev = {
  23235. +    "plip2",
  23236. +    0x0, 0x0, 0x0, 0x0,
  23237. +    0x278, 2, 0, 0, 0,
  23238. +    NEXT_DEV, plip_init,
  23239. +};
  23240. +
  23241. +static struct device plip1_dev = {
  23242. +    "plip1",
  23243. +    0x0, 0x0, 0x0, 0x0,
  23244. +    0x378, 7, 0, 0, 0,
  23245. +    &plip2_dev, plip_init,
  23246. +};
  23247. +
  23248. +static struct device plip0_dev = {
  23249. +    "plip0",
  23250. +    0x0, 0x0, 0x0, 0x0,
  23251. +    0x3BC, 5, 0, 0, 0,
  23252. +    &plip1_dev, plip_init,
  23253. +};
  23254. +
  23255. +#undef  NEXT_DEV
  23256. +#define NEXT_DEV (&plip0_dev)
  23257. +#endif  /* PLIP */
  23258. +
  23259. +#if defined(SLIP) || defined(CONFIG_SLIP)
  23260. +    /* To be exact, this node just hooks the initialization
  23261. +       routines to the device structures.            */
  23262. +extern int slip_init_ctrl_dev(struct device *);
  23263. +
  23264. +static struct device slip_bootstrap = {
  23265. +    "slip_proto",
  23266. +    0x0, 0x0, 0x0, 0x0,
  23267. +    0, 0, 0, 0, 0,
  23268. +    NEXT_DEV, slip_init_ctrl_dev,
  23269. +};
  23270. +
  23271. +#undef  NEXT_DEV
  23272. +#define NEXT_DEV (&slip_bootstrap)
  23273. +#endif /* SLIP */
  23274. +  
  23275. +#if defined(CONFIG_PPP)
  23276. +extern int ppp_init(struct device *);
  23277. +
  23278. +static struct device ppp_bootstrap = {
  23279. +    "ppp_proto",
  23280. +    0x0, 0x0, 0x0, 0x0,
  23281. +    0, 0, 0, 0, 0,
  23282. +    NEXT_DEV, ppp_init,
  23283. +};
  23284. +
  23285. +#undef  NEXT_DEV
  23286. +#define NEXT_DEV (&ppp_bootstrap)
  23287. +#endif   /* PPP */
  23288. +
  23289. +#ifdef CONFIG_DUMMY
  23290. +extern int dummy_init(struct device *dev);
  23291. +
  23292. +static struct device dummy_dev = {
  23293. +    "dummy",
  23294. +    0x0, 0x0, 0x0, 0x0,
  23295. +    0, 0, 0, 0, 0,
  23296. +    NEXT_DEV, dummy_init,
  23297. +};
  23298. +    
  23299. +#undef    NEXT_DEV
  23300. +#define    NEXT_DEV    (&dummy_dev)
  23301. +#endif
  23302. +
  23303. +#ifdef CONFIG_EQUALIZER
  23304. +extern int eql_init(struct device *dev);
  23305. +
  23306. +static struct device eql_dev = {
  23307. +    "eql",
  23308. +    0x0, 0x0, 0x0, 0x0,
  23309. +    0, 0, 0, 0, 0,
  23310. +    NEXT_DEV, eql_init,
  23311. +};
  23312. +
  23313. +#undef  NEXT_DEV
  23314. +#define NEXT_DEV (&eql_dev)
  23315. +#endif
  23316. +
  23317. +#ifdef CONFIG_NET_IPIP
  23318. +#ifdef CONFIG_IP_FORWARD
  23319. +extern int tunnel_init (struct device *dev);
  23320. +
  23321. +static struct device tunnel_dev1 = {
  23322. +    "tunl1",
  23323. +      0x0, 0x0, 0x0, 0x0,
  23324. +    0, 0, 0, 0, 0,
  23325. +    NEXT_DEV, tunnel_init,
  23326. +};
  23327. +
  23328. +static struct device tunnel_dev0 = {
  23329. +    "tunl0",
  23330. +    0x0, 0x0, 0x0, 0x0,
  23331. +    0, 0, 0, 0, 0,
  23332. +    &tunnel_dev1, tunnel_init,
  23333. +};
  23334. +
  23335. +#undef  NEXT_DEV
  23336. +#define NEXT_DEV (&tunnel_dev0)
  23337. +#endif
  23338. +#endif
  23339. +
  23340. +extern int loopback_init(struct device *dev);
  23341. +struct device loopback_dev = {
  23342. +    "lo",            /* Software Loopback interface        */
  23343. +    0x0,            /* recv memory end            */
  23344. +    0x0,            /* recv memory start            */
  23345. +    0x0,            /* memory end                */
  23346. +    0x0,            /* memory start                */
  23347. +    0,            /* base I/O address            */
  23348. +    0,            /* IRQ                    */
  23349. +    0, 0, 0,        /* flags                */
  23350. +    NEXT_DEV,        /* next device                */
  23351. +    loopback_init        /* loopback_init should set up the rest    */
  23352. +};
  23353. +
  23354. +struct device *dev_base = &loopback_dev;
  23355. diff -urNwbB linux/arch/arm/drivers/net/auto_irq.c linux.arm/arch/arm/drivers/net/auto_irq.c
  23356. --- linux/arch/arm/drivers/net/auto_irq.c    Thu Jan  1 01:00:00 1970
  23357. +++ linux.arm/arch/arm/drivers/net/auto_irq.c    Sun Feb 11 09:32:25 1996
  23358. @@ -0,0 +1,122 @@
  23359. +/* auto_irq.c: Auto-configure IRQ lines for linux. */
  23360. +/*
  23361. +    Written 1994 by Donald Becker.
  23362. +
  23363. +    The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
  23364. +    Center of Excellence in Space Data and Information Sciences
  23365. +      Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
  23366. +
  23367. +    This code is a general-purpose IRQ line detector for devices with
  23368. +    jumpered IRQ lines.  If you can make the device raise an IRQ (and
  23369. +    that IRQ line isn't already being used), these routines will tell
  23370. +    you what IRQ line it's using -- perfect for those oh-so-cool boot-time
  23371. +    device probes!
  23372. +
  23373. +    To use this, first call autoirq_setup(timeout). TIMEOUT is how many
  23374. +    'jiffies' (1/100 sec.) to detect other devices that have active IRQ lines,
  23375. +    and can usually be zero at boot.  'autoirq_setup()' returns the bit
  23376. +    vector of nominally-available IRQ lines (lines may be physically in-use,
  23377. +    but not yet registered to a device).
  23378. +    Next, set up your device to trigger an interrupt.
  23379. +    Finally call autoirq_report(TIMEOUT) to find out which IRQ line was
  23380. +    most recently active.  The TIMEOUT should usually be zero, but may
  23381. +    be set to the number of jiffies to wait for a slow device to raise an IRQ.
  23382. +
  23383. +    The idea of using the setup timeout to filter out bogus IRQs came from
  23384. +    the serial driver.
  23385. +*/
  23386. +
  23387. +
  23388. +#ifdef version
  23389. +static char *version=
  23390. +"auto_irq.c:v1.11 Donald Becker (becker@cesdis.gsfc.nasa.gov)";
  23391. +#endif
  23392. +
  23393. +#include <linux/sched.h>
  23394. +#include <linux/delay.h>
  23395. +#include <asm/bitops.h>
  23396. +#include <asm/io.h>
  23397. +#include <asm/irq.h>
  23398. +#include <linux/netdevice.h>
  23399. +
  23400. +struct device *irq2dev_map[32] = {0, 0, /* ... zeroed */};
  23401. +
  23402. +unsigned long irqs_busy = 0x2147;        /* The set of fixed IRQs (keyboard, timer, etc) */
  23403. +unsigned long irqs_used = 0x0001;        /* The set of fixed IRQs sometimes enabled. */
  23404. +unsigned long irqs_reserved = 0x0000;        /* An advisory "reserved" table. */
  23405. +unsigned long irqs_shared = 0x0000;        /* IRQ lines "shared" among conforming cards.*/
  23406. +
  23407. +static volatile unsigned long irq_bitmap;    /* The irqs we actually found. */
  23408. +static unsigned long irq_handled;        /* The irq lines we have a handler on. */
  23409. +static volatile int irq_number;            /* The latest irq number we actually found. */
  23410. +
  23411. +static void autoirq_probe(int irq, struct pt_regs * regs)
  23412. +{
  23413. +    irq_number = irq;
  23414. +    set_bit(irq, (void *)&irq_bitmap);    /* irq_bitmap |= 1 << irq; */
  23415. +    disable_irq(irq);
  23416. +    return;
  23417. +}
  23418. +
  23419. +int autoirq_setup(int waittime)
  23420. +{
  23421. +    int i, mask;
  23422. +    int timeout = jiffies + waittime;
  23423. +    int boguscount = (waittime*loops_per_sec) / 100;
  23424. +
  23425. +    irq_handled = 0;
  23426. +    for (i = 0; i < 16; i++) {
  23427. +        if (test_bit(i, &irqs_busy) == 0
  23428. +            && request_irq(i, autoirq_probe, SA_INTERRUPT, "irq probe") == 0)
  23429. +            set_bit(i, (void *)&irq_handled);    /* irq_handled |= 1 << i;*/
  23430. +    }
  23431. +    /* Update our USED lists. */
  23432. +    irqs_used |= ~irq_handled;
  23433. +    irq_number = 0;
  23434. +    irq_bitmap = 0;
  23435. +
  23436. +    /* Hang out at least <waittime> jiffies waiting for bogus IRQ hits. */
  23437. +    while (timeout > jiffies  &&  --boguscount > 0)
  23438. +        ;
  23439. +
  23440. +    for (i = 0, mask = 0x01; i < 16; i++, mask <<= 1) {
  23441. +        if (irq_bitmap & irq_handled & mask) {
  23442. +            irq_handled &= ~mask;
  23443. +#ifdef notdef
  23444. +            printk(" Spurious interrupt on IRQ %d\n", i);
  23445. +#endif
  23446. +            free_irq(i);
  23447. +        }
  23448. +    }
  23449. +    return irq_handled;
  23450. +}
  23451. +
  23452. +int autoirq_report(int waittime)
  23453. +{
  23454. +    int i;
  23455. +    int timeout = jiffies+waittime;
  23456. +    int boguscount = (waittime*loops_per_sec) / 100;
  23457. +
  23458. +    /* Hang out at least <waittime> jiffies waiting for the IRQ. */
  23459. +
  23460. +    while (timeout > jiffies  &&  --boguscount > 0)
  23461. +        if (irq_number)
  23462. +            break;
  23463. +
  23464. +    /* Retract the irq handlers that we installed. */
  23465. +    for (i = 0; i < 16; i++) {
  23466. +        if (test_bit(i, (void *)&irq_handled))
  23467. +            free_irq(i);
  23468. +    }
  23469. +    return irq_number;
  23470. +}
  23471. +
  23472. +/*
  23473. + * Local variables:
  23474. + *  compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c auto_irq.c"
  23475. + *  version-control: t
  23476. + *  kept-new-versions: 5
  23477. + *  c-indent-level: 4
  23478. + *  tab-width: 4
  23479. + * End:
  23480. + */
  23481. diff -urNwbB linux/arch/arm/drivers/net/ether1.c linux.arm/arch/arm/drivers/net/ether1.c
  23482. --- linux/arch/arm/drivers/net/ether1.c    Thu Jan  1 01:00:00 1970
  23483. +++ linux.arm/arch/arm/drivers/net/ether1.c    Sun Feb 18 09:28:09 1996
  23484. @@ -0,0 +1,1049 @@
  23485. +/*
  23486. + * linux/arch/arm/drivers/net/ether1.c
  23487. + *
  23488. + * Acorn ether1 driver (82586 chip)
  23489. + *
  23490. + * (c) 1996 Russell King
  23491. + */
  23492. +
  23493. +/*
  23494. + * We basically keep two queues in the cards memory - one for transmit
  23495. + * and one for receive.  Each has a head and a tail.  The head is where
  23496. + * we/the chip adds packets to be transmitted/received, and the tail
  23497. + * is where the transmitter has got to/where the receiver will stop.
  23498. + * Both of these queues are circular, and since the chip is running
  23499. + * all the time, we have to be careful when we modify the pointers etc
  23500. + * so that the buffer memory is valid all the time.
  23501. + */
  23502. +#ifdef MODULE
  23503. +#include <linux/module.h>
  23504. +#include <linux/version.h>
  23505. +#define CLAIM_IRQ_AT_OPEN
  23506. +#else
  23507. +#define MOD_INC_USE_COUNT
  23508. +#define MOD_DEC_USE_COUNT
  23509. +#endif
  23510. +
  23511. +#include <linux/config.h>
  23512. +#include <linux/kernel.h>
  23513. +#include <linux/sched.h>
  23514. +#include <linux/types.h>
  23515. +#include <linux/fcntl.h>
  23516. +#include <linux/interrupt.h>
  23517. +#include <linux/ptrace.h>
  23518. +#include <linux/ioport.h>
  23519. +#include <linux/in.h>
  23520. +#include <linux/malloc.h>
  23521. +#include <linux/string.h>
  23522. +#include <asm/system.h>
  23523. +#include <asm/bitops.h>
  23524. +#include <asm/io.h>
  23525. +#include <asm/dma.h>
  23526. +#include <linux/errno.h>
  23527. +
  23528. +#include <linux/netdevice.h>
  23529. +#include <linux/etherdevice.h>
  23530. +#include <linux/skbuff.h>
  23531. +
  23532. +#include <asm/ecard.h>
  23533. +
  23534. +#define __ETHER1_C
  23535. +#include "ether1.h"
  23536. +
  23537. +static unsigned int net_debug = NET_DEBUG;
  23538. +
  23539. +#define FUNC_PROLOGUE \
  23540. +    struct ether1_priv *priv = (struct ether1_priv *)dev->priv
  23541. +
  23542. +#define BUFFER_SIZE    65536
  23543. +#define TX_AREA_START    0x0100
  23544. +#define TX_AREA_END    0x5000
  23545. +#define RX_AREA_START    0x5000
  23546. +#define RX_AREA_END    0xfc00
  23547. +
  23548. +#define tx_done(dev) 0
  23549. +/* ------------------------------------------------------------------------- */
  23550. +static char *version = "ether1 ethernet driver (c) 1995 Russell King V1.00\n";
  23551. +
  23552. +#define BUS_16 16
  23553. +#define BUS_8  8
  23554. +
  23555. +static int ether1_prods[] = { 0x0003 };
  23556. +static int ether1_manus[] = { 0x0000 };
  23557. +
  23558. +/* ------------------------------------------------------------------------- */
  23559. +#define ether1_inw(dev, addr, type, offset) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset))
  23560. +#define ether1_outw(dev, val, addr, type, offset) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset))
  23561. +
  23562. +static inline unsigned short
  23563. +ether1_inw_p (struct device *dev, int addr)
  23564. +{
  23565. +    outb (addr >> 12, REG_PAGE);
  23566. +
  23567. +    return inw (ETHER1_RAM + ((addr & 4095) >> 1));
  23568. +}
  23569. +
  23570. +static inline void
  23571. +ether1_outw_p (struct device *dev, unsigned short val, int addr)
  23572. +{
  23573. +    outb (addr >> 12, REG_PAGE);
  23574. +    outw (val, ETHER1_RAM + ((addr & 4095) >> 1));
  23575. +}
  23576. +
  23577. +static inline void *
  23578. +ether1_inswb (int addr, void *data, unsigned int len)
  23579. +{
  23580. +    int used;
  23581. +
  23582. +    __asm__ __volatile__(
  23583. +    "    subs    %3, %3, #2\n"
  23584. +    "    bmi    2f\n"
  23585. +    "1:    ldr    %0, [%1], #4\n"
  23586. +    "    strb    %0, [%2], #1\n"
  23587. +    "    mov    %0, %0, lsr #8\n"
  23588. +    "    strb    %0, [%2], #1\n"
  23589. +    "    subs    %3, %3, #2\n"
  23590. +    "    bpl    1b\n"
  23591. +    "2:"
  23592. +    : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len)
  23593. +    : "1" (addr << 2), "2" (data), "3" (len));
  23594. +
  23595. +    return data;
  23596. +}
  23597. +
  23598. +static inline void *
  23599. +ether1_outswb (int addr, void *data, unsigned int len)
  23600. +{
  23601. +    int used;
  23602. +
  23603. +    __asm__ __volatile__(
  23604. +    "    subs    %3, %3, #2\n"
  23605. +    "    bmi    2f\n"
  23606. +    "1:    ldr    %0, [%2], #2\n"
  23607. +    "    mov    %0, %0, lsl #16\n"
  23608. +    "    orr    %0, %0, %0, lsr #16\n"
  23609. +    "    str    %0, [%1], #4\n"
  23610. +    "    subs    %3, %3, #2\n"
  23611. +    "    bpl    1b\n"
  23612. +    "2:"
  23613. +    : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len)
  23614. +    : "1" (addr << 2), "2" (data), "3" (len));
  23615. +
  23616. +    return data;
  23617. +}
  23618. +
  23619. +
  23620. +static void
  23621. +ether1_writebuffer (struct device *dev, void *data, unsigned int start, unsigned int length)
  23622. +{
  23623. +    unsigned int page, thislen, offset;
  23624. +
  23625. +    offset = start & 4095;
  23626. +
  23627. +    for (page = start >> 12; length; page++) {
  23628. +    outb (page, REG_PAGE);
  23629. +    if (offset + length > 4096) {
  23630. +        length -= 4096 - offset;
  23631. +        thislen = 4096 - offset;
  23632. +    } else {
  23633. +        thislen = length;
  23634. +        length = 0;
  23635. +    }
  23636. +
  23637. +    data = ether1_outswb (ETHER1_RAM + (offset >> 1), data, thislen);
  23638. +    offset = 0;
  23639. +    }
  23640. +}
  23641. +
  23642. +static void
  23643. +ether1_readbuffer (struct device *dev, void *data, unsigned int start, unsigned int length)
  23644. +{
  23645. +    unsigned int page, thislen, offset;
  23646. +
  23647. +    offset = start & 4095;
  23648. +
  23649. +    for (page = start >> 12; length; page++) {
  23650. +    outb (page, REG_PAGE);
  23651. +    if (offset + length > 4096) {
  23652. +        length -= 4096 - offset;
  23653. +        thislen = 4096 - offset;
  23654. +    } else {
  23655. +        thislen = length;
  23656. +        length = 0;
  23657. +    }
  23658. +
  23659. +    data = ether1_inswb (ETHER1_RAM + (offset >> 1), data, thislen);
  23660. +    offset = 0;
  23661. +    }
  23662. +}
  23663. +
  23664. +static int
  23665. +ether1_ramtest (struct device *dev, unsigned char byte)
  23666. +{
  23667. +    unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
  23668. +    int i, ret = BUFFER_SIZE;
  23669. +    int max_errors = 4;
  23670. +    int bad = -1;
  23671. +
  23672. +    if (!buffer)
  23673. +    return 1;
  23674. +
  23675. +    memset (buffer, byte, BUFFER_SIZE);
  23676. +    ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE);
  23677. +    memset (buffer, byte ^ 0xff, BUFFER_SIZE);
  23678. +    ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE);
  23679. +
  23680. +    for (i = 0; i < BUFFER_SIZE; i++) {
  23681. +    if (buffer[i] != byte) {
  23682. +        if (max_errors >= 0 && bad != buffer[i]) {
  23683. +        if (bad != -1)
  23684. +            printk ("\n");
  23685. +        printk ("%s: RAM failed with (%02X instead of %02X) at 0x%04X",
  23686. +            dev->name, buffer[i], byte, i);
  23687. +        ret = -ENODEV;
  23688. +        max_errors --;
  23689. +        bad = buffer[i];
  23690. +        }
  23691. +    } else {
  23692. +        if (bad != -1) {
  23693. +        printk (" - 0x%04X\n", i);
  23694. +        bad = -1;
  23695. +        }
  23696. +    }
  23697. +    }
  23698. +
  23699. +    if (bad != -1)
  23700. +    printk (" - 0x%04X\n", BUFFER_SIZE);
  23701. +    kfree (buffer);
  23702. +
  23703. +    return ret;
  23704. +}
  23705. +
  23706. +static int
  23707. +ether1_reset (struct device *dev)
  23708. +{
  23709. +    outb (CTRL_RST|CTRL_ACK, REG_CONTROL);
  23710. +    return BUS_16;
  23711. +}
  23712. +
  23713. +static int
  23714. +ether1_init_2 (struct device *dev)
  23715. +{
  23716. +    int i;
  23717. +    dev->mem_start = 0;
  23718. +    
  23719. +    i = ether1_ramtest (dev, 0x5a);
  23720. +
  23721. +    if (i > 0)
  23722. +    i = ether1_ramtest (dev, 0x1e);
  23723. +
  23724. +    if (i <= 0)
  23725. +        return -ENODEV;
  23726. +
  23727. +    dev->mem_end = i;
  23728. +    
  23729. +    return 0;
  23730. +}
  23731. +
  23732. +/*
  23733. + * These are the structures that are loaded into the ether RAM card to
  23734. + * initialise the 82586
  23735. + */
  23736. +
  23737. +/* at 0x0100 */
  23738. +#define NOP_ADDR    (TX_AREA_START)
  23739. +#define NOP_SIZE    (0x06)
  23740. +static nop_t  init_nop  = {
  23741. +    0,
  23742. +    CMD_NOP,
  23743. +    NOP_ADDR
  23744. +};
  23745. +
  23746. +/* at 0x003a */
  23747. +#define TDR_ADDR    (0x003a)
  23748. +#define TDR_SIZE    (0x08)
  23749. +static tdr_t  init_tdr    = {
  23750. +    0,
  23751. +    CMD_TDR | CMD_INTR,
  23752. +    NOP_ADDR,
  23753. +    0
  23754. +};
  23755. +
  23756. +/* at 0x002e */
  23757. +#define MC_ADDR        (0x002e)
  23758. +#define MC_SIZE        (0x0c)
  23759. +static mc_t   init_mc   = {
  23760. +    0,
  23761. +    CMD_SETMULTICAST,
  23762. +    TDR_ADDR,
  23763. +    0,
  23764. +    { { 0, } }
  23765. +};
  23766. +
  23767. +/* at 0x0022 */
  23768. +#define SA_ADDR        (0x0022)
  23769. +#define SA_SIZE        (0x0c)
  23770. +static sa_t   init_sa   = {
  23771. +    0,
  23772. +    CMD_SETADDRESS,
  23773. +    MC_ADDR,
  23774. +    { 0, }
  23775. +};
  23776. +
  23777. +/* at 0x0010 */
  23778. +#define CFG_ADDR    (0x0010)
  23779. +#define CFG_SIZE    (0x12)
  23780. +static cfg_t  init_cfg  = {
  23781. +    0,
  23782. +    CMD_CONFIG,
  23783. +    SA_ADDR,
  23784. +    4,
  23785. +    8,
  23786. +    CFG8_SRDY,
  23787. +    CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6),
  23788. +    0,
  23789. +};
  23790. +
  23791. +/* at 0x0000 */
  23792. +#define SCB_ADDR    (0x0000)
  23793. +#define SCB_SIZE    (0x10)
  23794. +static scb_t  init_scb  = {
  23795. +    0,
  23796. +    0,
  23797. +    CFG_ADDR,
  23798. +    RX_AREA_START,
  23799. +    0,
  23800. +    0,
  23801. +    0,
  23802. +    0
  23803. +};
  23804. +
  23805. +/* at 0xffee */
  23806. +#define ISCP_ADDR    (0xffee)
  23807. +#define ISCP_SIZE    (0x08)
  23808. +static iscp_t init_iscp = {
  23809. +    1,
  23810. +    SCB_ADDR,
  23811. +    0x0000,
  23812. +    0x0000
  23813. +};
  23814. +
  23815. +/* at 0xfff6 */
  23816. +#define SCP_ADDR    (0xfff6)
  23817. +#define SCP_SIZE    (0x0a)
  23818. +static scp_t  init_scp  = {
  23819. +    SCP_SY_16BBUS,
  23820. +    { 0, 0 },
  23821. +    ISCP_ADDR,
  23822. +    0
  23823. +};
  23824. +
  23825. +#define RFD_SIZE    (0x16)
  23826. +static rfd_t  init_rfd    = {
  23827. +    0,
  23828. +    0,
  23829. +    0,
  23830. +    0,
  23831. +    { 0, },
  23832. +    { 0, },
  23833. +    0
  23834. +};
  23835. +
  23836. +#define RBD_SIZE    (0x0a)
  23837. +static rbd_t  init_rbd    = {
  23838. +    0,
  23839. +    0,
  23840. +    0,
  23841. +    0,
  23842. +    ETH_FRAME_LEN + 8
  23843. +};
  23844. +
  23845. +#define TX_SIZE        (0x08)
  23846. +#define TBD_SIZE    (0x08)
  23847. +
  23848. +static int
  23849. +ether1_init_for_open (struct device *dev)
  23850. +{
  23851. +    FUNC_PROLOGUE;
  23852. +    int i, status, addr, next, next2;
  23853. +
  23854. +    for (i = 0; i < 6; i++)
  23855. +    init_sa.sa_addr[i] = dev->dev_addr[i];
  23856. +
  23857. +    /* load data structures into ether1 RAM */
  23858. +    ether1_writebuffer (dev, &init_scp,  SCP_ADDR,  SCP_SIZE);
  23859. +    ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE);
  23860. +    ether1_writebuffer (dev, &init_scb,  SCB_ADDR,  SCB_SIZE);
  23861. +    ether1_writebuffer (dev, &init_cfg,  CFG_ADDR,  CFG_SIZE);
  23862. +    ether1_writebuffer (dev, &init_sa,   SA_ADDR,   SA_SIZE);
  23863. +    ether1_writebuffer (dev, &init_mc,   MC_ADDR,   MC_SIZE);
  23864. +    ether1_writebuffer (dev, &init_tdr,  TDR_ADDR,  TDR_SIZE);
  23865. +    ether1_writebuffer (dev, &init_nop,  NOP_ADDR,  NOP_SIZE);
  23866. +
  23867. +    /*
  23868. +     * setup circularly linked list of { rfd, rbd, buffer }, with
  23869. +     * all rfds circularly linked, rbds circularly linked.
  23870. +     * First rfd is linked to scp, first rbd is linked to first
  23871. +     * rfd.  Last rbd has a suspend command.
  23872. +     */
  23873. +    addr = RX_AREA_START;
  23874. +    do {
  23875. +    next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
  23876. +    next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
  23877. +
  23878. +    if (next2 >= RX_AREA_END) {
  23879. +        next = RX_AREA_START;
  23880. +        init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
  23881. +        priv->rx_tail = addr;
  23882. +    } else
  23883. +        init_rfd.rfd_command = 0;
  23884. +    if (addr == RX_AREA_START)
  23885. +        init_rfd.rfd_rbdoffset = addr + RFD_SIZE;
  23886. +    else
  23887. +        init_rfd.rfd_rbdoffset = 0;
  23888. +    init_rfd.rfd_link = next;
  23889. +    init_rbd.rbd_link = next + RFD_SIZE;
  23890. +    init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE;
  23891. +
  23892. +    ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE);
  23893. +    ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE);
  23894. +    addr = next;
  23895. +    } while (next2 < RX_AREA_END);
  23896. +
  23897. +    priv->tx_link = NOP_ADDR;
  23898. +    priv->tx_head = NOP_ADDR + NOP_SIZE;
  23899. +    priv->tx_tail = TDR_ADDR;
  23900. +    priv->rx_head = RX_AREA_START;
  23901. +
  23902. +    /* release reset & give 586 a prod */
  23903. +    priv->resetting = 1;
  23904. +    outb (CTRL_RST, REG_CONTROL);
  23905. +    outb (0, REG_CONTROL);
  23906. +    outb (CTRL_CA, REG_CONTROL);
  23907. +
  23908. +    /* 586 should now unset iscp.busy */
  23909. +    i = jiffies + HZ/2;
  23910. +    while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy) == 1) {
  23911. +    if (jiffies > i) {
  23912. +        printk ("%s: can't initialise 82586: iscp is busy\n", dev->name);
  23913. +        return 1;
  23914. +    }
  23915. +    }
  23916. +
  23917. +    /* check status of commands that we issued */
  23918. +    i += HZ/10;
  23919. +    while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status)) & STAT_COMPLETE) == 0) {
  23920. +    if (jiffies > i)
  23921. +        break;
  23922. +    }
  23923. +
  23924. +    if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
  23925. +    printk ("%s: can't initialise 82586: config status %04X\n", dev->name, status);
  23926. +    ether1_reset (dev);
  23927. +    return 1;
  23928. +    }
  23929. +
  23930. +    i += HZ/10;
  23931. +    while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status)) & STAT_COMPLETE) == 0) {
  23932. +    if (jiffies > i)
  23933. +        break;
  23934. +    }
  23935. +
  23936. +    if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
  23937. +    printk ("%s: can't initialise 82586: set address status %04X\n", dev->name, status);
  23938. +    ether1_reset (dev);
  23939. +    return 1;
  23940. +    }
  23941. +
  23942. +    i += HZ/10;
  23943. +    while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status)) & STAT_COMPLETE) == 0) {
  23944. +    if (jiffies > i)
  23945. +        break;
  23946. +    }
  23947. +
  23948. +    if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
  23949. +    printk ("%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
  23950. +    ether1_reset (dev);
  23951. +    return 1;
  23952. +    }
  23953. +
  23954. +    i += HZ;
  23955. +    while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status)) & STAT_COMPLETE) == 0) {
  23956. +    if (jiffies > i)
  23957. +        break;
  23958. +    }
  23959. +
  23960. +    if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
  23961. +    printk ("%s: can't tdr (ignored)\n", dev->name);
  23962. +    return 0;
  23963. +    }
  23964. +
  23965. +    status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_result);
  23966. +    if (status & TDR_XCVRPROB)
  23967. +    printk ("%s: i/f failed tdr: transceiver problem\n", dev->name);
  23968. +    else
  23969. +    if (status & (TDR_SHORT|TDR_OPEN)) {
  23970. +#ifdef FANCY
  23971. +    printk ("%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,
  23972. +        status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,
  23973. +        (status & TDR_TIME) % 10);
  23974. +#else
  23975. +    printk ("%s: i/f failed tdr: cable %s %d clks away\n", dev->name,
  23976. +        status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));
  23977. +#endif
  23978. +    }
  23979. +
  23980. +    return 0;
  23981. +}
  23982. +
  23983. +static int
  23984. +ether1_probe1 (struct device *dev)
  23985. +{
  23986. +    static unsigned int version_printed = 0;
  23987. +    struct ether1_priv *priv;
  23988. +    int i;
  23989. +
  23990. +    if (!dev->priv)
  23991. +    dev->priv = kmalloc (sizeof (struct ether1_priv), GFP_KERNEL);
  23992. +
  23993. +    if (!dev->priv)
  23994. +        return 1;
  23995. +
  23996. +    priv = (struct ether1_priv *)dev->priv;
  23997. +    memset (priv, 0, sizeof (struct ether1_priv));
  23998. +
  23999. +    if ((priv->bus_type = ether1_reset (dev)) == 0) {
  24000. +    kfree (dev->priv);
  24001. +    return 1;
  24002. +    }
  24003. +
  24004. +    if (net_debug && version_printed++ == 0)
  24005. +    printk (version);
  24006. +
  24007. +    printk ("%s: ether1 found (bus width %d), ", dev->name, priv->bus_type);
  24008. +
  24009. +    for (i = 0; i < 6; i++)
  24010. +    printk (i==0?" %2.2x":i==5?":%2.2x\n":":%2.2x", dev->dev_addr[i]);
  24011. +
  24012. +    if (ether1_init_2 (dev)) {
  24013. +    kfree (dev->priv);
  24014. +    return 1;
  24015. +    }
  24016. +
  24017. +    dev->open            = ether1_open;
  24018. +    dev->stop            = ether1_close;
  24019. +    dev->hard_start_xmit    = ether1_sendpacket;
  24020. +    dev->get_stats        = ether1_getstats;
  24021. +    dev->set_multicast_list = ether1_setmulticastlist;
  24022. +
  24023. +    /* Fill in the fields of the device structure with ethernet values */
  24024. +    ether_setup (dev);
  24025. +
  24026. +#ifndef CLAIM_IRQ_AT_OPEN
  24027. +    if (request_irq (dev->irq, ether1_interrupt, 0, "ether1")) {
  24028. +    kfree (dev->priv);
  24029. +    return -EAGAIN;
  24030. +    }
  24031. +
  24032. +    irq2dev_map[dev->irq] = dev;
  24033. +#endif
  24034. +    return 0;
  24035. +}    
  24036. +    
  24037. +/* ------------------------------------------------------------------------- */
  24038. +
  24039. +static void
  24040. +ether1_addr (struct device *dev)
  24041. +{
  24042. +    int i;
  24043. +    
  24044. +    for (i = 0; i < 6; i++)
  24045. +    dev->dev_addr[i] = inb (IDPROM_ADDRESS + i);
  24046. +}
  24047. +
  24048. +int
  24049. +ether1_probe (struct device *dev)
  24050. +{
  24051. +#ifndef MODULE
  24052. +    struct expansion_card *ec;
  24053. +
  24054. +    if (!dev)
  24055. +    return ENODEV;
  24056. +
  24057. +    if ((ec = ecard_find (0, sizeof (ether1_prods) / sizeof (int), ether1_prods, ether1_manus)) == NULL)
  24058. +    return ENODEV;
  24059. +
  24060. +    dev->base_addr = (((unsigned long)ec->r_podaddr & ~0x3c0000) + 0x340000) >> 2;
  24061. +    dev->irq       = ec->irq;
  24062. +
  24063. +    ecard_claim (ec);
  24064. +
  24065. +#endif
  24066. +    ether1_addr (dev);
  24067. +
  24068. +    if (ether1_probe1 (dev) == 0)
  24069. +    return 0;
  24070. +    return ENODEV;
  24071. +}
  24072. +
  24073. +/* ------------------------------------------------------------------------- */
  24074. +
  24075. +static int
  24076. +ether1_txalloc (struct device *dev, int size)
  24077. +{
  24078. +    FUNC_PROLOGUE;
  24079. +    int start, tail;
  24080. +
  24081. +    size = (size + 1) & ~1;
  24082. +    tail = priv->tx_tail;
  24083. +
  24084. +    if (priv->tx_head + size > TX_AREA_END) {
  24085. +    if (tail > priv->tx_head)
  24086. +        return -1;
  24087. +    start = TX_AREA_START;
  24088. +    if (start + size > tail)
  24089. +        return -1;
  24090. +    priv->tx_head = start + size;
  24091. +    } else {
  24092. +    if (priv->tx_head < tail && (priv->tx_head + size) < tail)
  24093. +        return -1;
  24094. +    start = priv->tx_head;
  24095. +    priv->tx_head += size;
  24096. +    }
  24097. +
  24098. +    return start;
  24099. +}
  24100. +
  24101. +static int
  24102. +ether1_open (struct device *dev)
  24103. +{
  24104. +    FUNC_PROLOGUE;
  24105. +#ifdef CLAIM_IRQ_AT_OPEN
  24106. +    if (request_irq (dev->irq, ether1_interrupt, 0, "ether1")) {
  24107. +    kfree (dev->priv);
  24108. +    return -EAGAIN;
  24109. +    }
  24110. +
  24111. +    irq2dev_map[dev->irq] = dev;
  24112. +#endif
  24113. +    MOD_INC_USE_COUNT;
  24114. +
  24115. +    memset (&priv->stats, 0, sizeof (struct enet_statistics));
  24116. +
  24117. +    ether1_init_for_open (dev);
  24118. +
  24119. +    dev->tbusy = 0;
  24120. +    dev->interrupt = 0;
  24121. +    dev->start = 1;
  24122. +
  24123. +    return 0;
  24124. +}
  24125. +
  24126. +static int
  24127. +ether1_sendpacket (struct sk_buff *skb, struct device *dev)
  24128. +{
  24129. +    FUNC_PROLOGUE;
  24130. +
  24131. +    if (dev->tbusy) {
  24132. +    /*
  24133. +     * If we get here, some higher level has decided that we are broken.
  24134. +     * There should really be a "kick me" function call instead.
  24135. +     */
  24136. +    int tickssofar = jiffies - dev->trans_start;
  24137. +
  24138. +    if (tickssofar < 5)
  24139. +        return 1;
  24140. +
  24141. +    printk ("%s: transmit timeout, network cable problem?\n", dev->name);
  24142. +
  24143. +    /* Try to restart the adapter. */
  24144. +    dev->tbusy = 0;
  24145. +    dev->trans_start = jiffies;
  24146. +    }
  24147. +
  24148. +    /*
  24149. +     * If some higher layer thinks we've missed a tx-done interrupt
  24150. +     * we are passed NULL.  Caution: dev_tint() handles the cli()/sti()
  24151. +     * itself.
  24152. +     */
  24153. +    if (skb == NULL) {
  24154. +    dev_tint (dev);
  24155. +    return 0;
  24156. +    }
  24157. +
  24158. +    /*
  24159. +     * Block a timer-based transmit from overlapping.  This could better be
  24160. +     * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
  24161. +     */
  24162. +    if (set_bit (0, (void *)&dev->tbusy) != 0)
  24163. +    printk ("%s: transmitter access conflict.\n", dev->name);
  24164. +    else {
  24165. +    int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
  24166. +    int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
  24167. +    tx_t tx;
  24168. +    tbd_t tbd;
  24169. +    nop_t nop;
  24170. +    /*
  24171. +     * insert packet followed by a nop
  24172. +     */
  24173. +    txaddr = ether1_txalloc (dev, TX_SIZE);
  24174. +    tbdaddr = ether1_txalloc (dev, TBD_SIZE);
  24175. +    dataddr = ether1_txalloc (dev, len);
  24176. +    nopaddr = ether1_txalloc (dev, NOP_SIZE);
  24177. +
  24178. +    tx.tx_status = 0;
  24179. +    tx.tx_command = CMD_TX | CMD_INTR;
  24180. +    tx.tx_link = nopaddr;
  24181. +    tx.tx_tbdoffset = tbdaddr;
  24182. +    tbd.tbd_opts = TBD_EOL | len;
  24183. +    tbd.tbd_link = I82586_NULL;
  24184. +    tbd.tbd_bufl = dataddr;
  24185. +    tbd.tbd_bufh = 0;
  24186. +    nop.nop_status = 0;
  24187. +    nop.nop_command = CMD_NOP;
  24188. +    nop.nop_link = nopaddr;
  24189. +
  24190. +    ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
  24191. +    ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
  24192. +    ether1_writebuffer (dev, skb->data, dataddr, len);
  24193. +    ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
  24194. +    tmp = priv->tx_link;
  24195. +    priv->tx_link = nopaddr;
  24196. +
  24197. +    /* now reset the previous nop pointer */
  24198. +    ether1_outw (dev, txaddr, tmp, nop_t, nop_link);
  24199. +
  24200. +    /* handle transmit */
  24201. +    dev->trans_start = jiffies;
  24202. +
  24203. +    /* check to see if we have room for a full sized ether frame */
  24204. +    tmp = priv->tx_head;
  24205. +    tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
  24206. +    priv->tx_head = tmp;
  24207. +    if (tst != -1)
  24208. +        dev->tbusy = 0;
  24209. +    }
  24210. +    dev_kfree_skb (skb, FREE_WRITE);
  24211. +
  24212. +    return 0;
  24213. +}
  24214. +
  24215. +static void
  24216. +ether1_xmit_done (struct device *dev)
  24217. +{
  24218. +    FUNC_PROLOGUE;
  24219. +    nop_t nop;
  24220. +    int caddr, tst;
  24221. +
  24222. +    caddr = priv->tx_tail;
  24223. +
  24224. +again:
  24225. +    ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
  24226. +
  24227. +    switch (nop.nop_command & CMD_MASK) {
  24228. +    case CMD_TDR:
  24229. +    /* special case */
  24230. +    if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset) != (unsigned short)I82586_NULL) {
  24231. +        ether1_outw (dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t, scb_command);
  24232. +        outb (CTRL_CA, REG_CONTROL);
  24233. +    }
  24234. +    priv->tx_tail = NOP_ADDR;
  24235. +    return;
  24236. +
  24237. +    case CMD_NOP:
  24238. +    if (nop.nop_link == caddr) {
  24239. +        printk ("%s: strange command complete with no tx command!\n", dev->name);
  24240. +        return;
  24241. +    }
  24242. +    caddr = nop.nop_link;
  24243. +    goto again;
  24244. +
  24245. +    case CMD_TX:
  24246. +    if (nop.nop_status & STAT_COMPLETE)
  24247. +        break;
  24248. +    printk ("%s: strange command complete without completed command!\n", dev->name);
  24249. +    return;
  24250. +
  24251. +    default:
  24252. +    printk ("%s: strange command %d complete!\n", dev->name, nop.nop_command & CMD_MASK);
  24253. +    return;
  24254. +    }
  24255. +
  24256. +    while (nop.nop_status & STAT_COMPLETE) {
  24257. +    if (nop.nop_status & STAT_OK) {
  24258. +        priv->stats.tx_packets ++;
  24259. +        priv->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
  24260. +    } else {
  24261. +        priv->stats.tx_errors ++;
  24262. +
  24263. +        if (nop.nop_status & STAT_COLLAFTERTX) {
  24264. +        priv->stats.collisions ++;
  24265. +        printk ("%s: late collision detected\n", dev->name);
  24266. +        }
  24267. +        if (nop.nop_status & STAT_NOCARRIER) {
  24268. +        priv->stats.tx_carrier_errors ++;
  24269. +        printk ("%s: no carrier\n", dev->name);
  24270. +        }
  24271. +        if (nop.nop_status & STAT_TXLOSTCTS)
  24272. +        printk ("%s: cts lost\n", dev->name);
  24273. +        if (nop.nop_status & STAT_TXSLOWDMA) {
  24274. +        priv->stats.tx_fifo_errors ++;
  24275. +        printk ("%s: fifo error - dma underrun\n", dev->name);
  24276. +        }
  24277. +        if (nop.nop_status & STAT_COLLEXCESSIVE) {
  24278. +        priv->stats.collisions += 16;
  24279. +        printk ("%s: excessive collisions\n", dev->name);
  24280. +        }
  24281. +    }
  24282. +
  24283. +    if (nop.nop_link == caddr) {
  24284. +        printk ("%s: tx buffer chaining error: tx command points to itself\n", dev->name);
  24285. +        break;
  24286. +    }
  24287. +
  24288. +    caddr = nop.nop_link;
  24289. +    ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
  24290. +    if ((nop.nop_command & CMD_MASK) != CMD_NOP) {
  24291. +        printk ("%s: tx buffer chaining error: no nop after tx command\n", dev->name);
  24292. +        break;
  24293. +    }
  24294. +
  24295. +    if (caddr == nop.nop_link)
  24296. +        break;
  24297. +
  24298. +    caddr = nop.nop_link;
  24299. +    ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
  24300. +    if ((nop.nop_command & CMD_MASK) != CMD_TX) {
  24301. +        printk ("%s: tx buffer chaining error: no tx command after nop\n", dev->name);
  24302. +        break;
  24303. +    }
  24304. +    }
  24305. +    priv->tx_tail = caddr;
  24306. +
  24307. +    caddr = priv->tx_head;
  24308. +    tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
  24309. +    priv->tx_head = caddr;
  24310. +    if (tst != -1)
  24311. +    dev->tbusy = 0;
  24312. +    
  24313. +    mark_bh (NET_BH);
  24314. +}
  24315. +
  24316. +static void
  24317. +ether1_recv_done (struct device *dev)
  24318. +{
  24319. +    FUNC_PROLOGUE;
  24320. +    int status;
  24321. +    int nexttail, rbdaddr;
  24322. +    rbd_t rbd;
  24323. +
  24324. +    do {
  24325. +    status = ether1_inw (dev, priv->rx_head, rfd_t, rfd_status);
  24326. +    if ((status & RFD_COMPLETE) == 0)
  24327. +        break;
  24328. +
  24329. +    rbdaddr = ether1_inw (dev, priv->rx_head, rfd_t, rfd_rbdoffset);
  24330. +    ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
  24331. +
  24332. +    if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
  24333. +        int length = rbd.rbd_status & RBD_ACNT;
  24334. +        struct sk_buff *skb;
  24335. +
  24336. +        length = (length + 1) & ~1;
  24337. +        skb = dev_alloc_skb (length + 2);
  24338. +
  24339. +        if (skb) {
  24340. +        skb->dev = dev;
  24341. +        skb_reserve (skb, 2);
  24342. +
  24343. +        ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);
  24344. +
  24345. +        skb->protocol = eth_type_trans (skb, dev);
  24346. +        netif_rx (skb);
  24347. +        priv->stats.rx_packets ++;
  24348. +        } else
  24349. +        priv->stats.rx_dropped ++;
  24350. +    } else {
  24351. +        printk ("%s: %s\n", dev->name, (rbd.rbd_status & RBD_EOF) ? "oversized packet" :
  24352. +                "acnt not valid");
  24353. +        priv->stats.rx_dropped ++;
  24354. +    }
  24355. +
  24356. +    nexttail = ether1_inw (dev, priv->rx_tail, rfd_t, rfd_link);
  24357. +    /* nexttail should be rx_head */
  24358. +    if (nexttail != priv->rx_head)
  24359. +        printk ("%s: receiver buffer chaining error (%04X != %04X)\n", dev->name, nexttail,
  24360. +            priv->rx_head);
  24361. +    ether1_outw (dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command);
  24362. +    ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_command);
  24363. +    ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_status);
  24364. +    ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_rbdoffset);
  24365. +    
  24366. +    priv->rx_tail = nexttail;
  24367. +    priv->rx_head = ether1_inw (dev, priv->rx_head, rfd_t, rfd_link);
  24368. +    } while (1);
  24369. +}
  24370. +
  24371. +static void
  24372. +ether1_interrupt (int irq, struct pt_regs *regs)
  24373. +{
  24374. +    struct device *dev = irq2dev_map[irq];
  24375. +    FUNC_PROLOGUE;
  24376. +    int status;
  24377. +
  24378. +    if (dev == NULL) {
  24379. +    printk ("ether1: interrupt %d from unknown device\n", irq);
  24380. +    return;
  24381. +    }
  24382. +
  24383. +    dev->interrupt = 1;
  24384. +
  24385. +    status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status);
  24386. +    if (status ) {
  24387. +    ether1_outw (dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
  24388. +            SCB_ADDR, scb_t, scb_command);
  24389. +    outb (CTRL_CA | CTRL_ACK, REG_CONTROL);
  24390. +    if (status & SCB_STCX) {
  24391. +        ether1_xmit_done (dev);
  24392. +    }
  24393. +    if (status & SCB_STCNA) {
  24394. +        if (priv->resetting == 0)
  24395. +        printk ("%s: CU went not ready ???\n", dev->name);
  24396. +        if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset) != (unsigned short)I82586_NULL) {
  24397. +        ether1_outw (dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command);
  24398. +        outb (CTRL_CA, REG_CONTROL);
  24399. +        }
  24400. +        if (priv->resetting == 2)
  24401. +        priv->resetting = 0;
  24402. +    }
  24403. +    if (status & SCB_STFR) {
  24404. +        ether1_recv_done (dev);
  24405. +    }
  24406. +    if (status & SCB_STRNR) {
  24407. +        printk ("%s: RU went not ready\n", dev->name);
  24408. +        printk ("RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset));
  24409. +    }
  24410. +    } else
  24411. +        outb (CTRL_ACK, REG_CONTROL);
  24412. +
  24413. +    dev->interrupt = 0;
  24414. +}
  24415. +
  24416. +static int
  24417. +ether1_close (struct device *dev)
  24418. +{
  24419. +#ifdef CLAIM_IRQ_AT_OPEN
  24420. +    free_irq (dev->irq);
  24421. +    irq2dev_map[dev->irq] = NULL;
  24422. +#endif
  24423. +
  24424. +    ether1_reset (dev);
  24425. +
  24426. +    dev->start = 0;
  24427. +    dev->tbusy = 0;
  24428. +
  24429. +    MOD_DEC_USE_COUNT;
  24430. +
  24431. +    return 0;
  24432. +}
  24433. +
  24434. +static struct enet_statistics *
  24435. +ether1_getstats (struct device *dev)
  24436. +{
  24437. +    FUNC_PROLOGUE;
  24438. +    return &priv->stats;
  24439. +}
  24440. +
  24441. +/*
  24442. + * Set or clear the multicast filter for this adaptor.
  24443. + * num_addrs == -1    Promiscuous mode, receive all packets.
  24444. + * num_addrs == 0    Normal mode, clear multicast list.
  24445. + * num_addrs > 0    Multicast mode, receive normal and MC packets, and do
  24446. + *            best-effort filtering.
  24447. + */
  24448. +static void
  24449. +ether1_setmulticastlist (struct device *dev, int num_addrs, void *addrs)
  24450. +{
  24451. +}
  24452. +
  24453. +/* ------------------------------------------------------------------------- */
  24454. +
  24455. +#ifdef MODULE
  24456. +char kernel_version[] = UTS_RELEASE;
  24457. +
  24458. +static char ethernames[4][9] = {
  24459. +    "        ",
  24460. +    "        ",
  24461. +    "        ",
  24462. +    "        "
  24463. +};
  24464. +static struct device *my_ethers[4];
  24465. +static struct expansion_card *ec[4];
  24466. +
  24467. +int
  24468. +init_module (void)
  24469. +{
  24470. +    int i;
  24471. +
  24472. +    for (i = 0; i < 4; i++) {
  24473. +    my_ethers[i] = NULL;
  24474. +    ec[i] = NULL;
  24475. +    }
  24476. +
  24477. +    i = 0;
  24478. +
  24479. +    do {
  24480. +    if ((ec[i] = ecard_find(0, sizeof(ether1_prods) / sizeof(int), ether1_prods, ether1_manus))
  24481. +        == NULL)
  24482. +        break;
  24483. +
  24484. +    my_ethers[i] = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL);
  24485. +    memset (my_ethers[i], 0, sizeof (struct device));
  24486. +
  24487. +    my_ethers[i]->irq = ec[i]->irq;
  24488. +    my_ethers[i]->base_addr = (((unsigned long)ec[i]->r_podaddr & ~0x3c0000) + 0x340000) >> 2;
  24489. +    my_ethers[i]->init = ether1_probe;
  24490. +    my_ethers[i]->name = ethernames[i];
  24491. +
  24492. +    ecard_claim (ec[i]);
  24493. +
  24494. +    if (register_netdev (my_ethers[i]) != 0) {
  24495. +        for (i = 0; i < 4; i++) {
  24496. +        if (my_ethers[i]) {
  24497. +            kfree (my_ethers[i]);
  24498. +            my_ethers[i] = NULL;
  24499. +        }
  24500. +        if (ec[i]) {
  24501. +            ecard_release (ec[i]);
  24502. +            ec[i] = NULL;
  24503. +        }
  24504. +        }
  24505. +        return -EIO;
  24506. +    }
  24507. +    i++;
  24508. +    } while (i < 4);
  24509. +
  24510. +    return i != 0 ? 0 : -ENODEV;
  24511. +}
  24512. +
  24513. +void
  24514. +cleanup_module (void)
  24515. +{
  24516. +    if (MOD_IN_USE) {
  24517. +    printk ("%s: device busy, remove delayed\n", "ether1");
  24518. +    } else {
  24519. +    int i;
  24520. +
  24521. +    for (i = 0; i < 4; i++) {
  24522. +        if (my_ethers[i]) {
  24523. +        unregister_netdev (my_ethers[i]);
  24524. +        my_ethers[i] = NULL;
  24525. +        }
  24526. +        if (ec[i]) {
  24527. +            ecard_release (ec[i]);
  24528. +            ec[i] = NULL;
  24529. +        }
  24530. +    }
  24531. +    }
  24532. +}
  24533. +#endif /* MODULE */
  24534. diff -urNwbB linux/arch/arm/drivers/net/ether1.h linux.arm/arch/arm/drivers/net/ether1.h
  24535. --- linux/arch/arm/drivers/net/ether1.h    Thu Jan  1 01:00:00 1970
  24536. +++ linux.arm/arch/arm/drivers/net/ether1.h    Sat Feb 17 10:05:58 1996
  24537. @@ -0,0 +1,280 @@
  24538. +/*
  24539. + * linux/arch/arm/drivers/net/ether1.h
  24540. + *
  24541. + * network driver for Acorn Ether1 cards.
  24542. + *
  24543. + * (c) 1996 Russell King
  24544. + */
  24545. +
  24546. +#ifndef _LINUX_ether1_H
  24547. +#define _LINUX_ether1_H
  24548. +
  24549. +#ifdef __ETHER1_C
  24550. +/* use 0 for production, 1 for verification, >2 for debug */
  24551. +#ifndef NET_DEBUG
  24552. +#define NET_DEBUG 1
  24553. +#endif
  24554. +
  24555. +/* Page register */
  24556. +#define REG_PAGE    (dev->base_addr + 0x00)
  24557. +
  24558. +/* Control register */
  24559. +#define REG_CONTROL    (dev->base_addr + 0x01)
  24560. +#define CTRL_RST    0x01
  24561. +#define CTRL_LOOPBACK    0x02
  24562. +#define CTRL_CA        0x04
  24563. +#define CTRL_ACK    0x08
  24564. +
  24565. +#define ETHER1_RAM    (dev->base_addr + 0x800)
  24566. +
  24567. +/* HW address */
  24568. +#define IDPROM_ADDRESS    (dev->base_addr + 0x09)
  24569. +
  24570. +struct ether1_priv {
  24571. +    struct enet_statistics stats;
  24572. +    int tx_link;
  24573. +    int tx_head;
  24574. +    volatile int tx_tail;
  24575. +    volatile int rx_head;
  24576. +    volatile int rx_tail;
  24577. +    char bus_type;
  24578. +    char resetting;
  24579. +};
  24580. +
  24581. +static int ether1_open (struct device *dev);
  24582. +static int ether1_sendpacket (struct sk_buff *skb, struct device *dev);
  24583. +static void ether1_interrupt (int irq, struct pt_regs *regs);
  24584. +static int ether1_close (struct device *dev);
  24585. +static struct enet_statistics *ether1_getstats (struct device *dev);
  24586. +static void ether1_setmulticastlist (struct device *dev, int num_addrs, void *addrs);
  24587. +
  24588. +#define I82586_NULL (-1)
  24589. +
  24590. +typedef struct { /* tdr */
  24591. +    unsigned short tdr_status;
  24592. +    unsigned short tdr_command;
  24593. +    unsigned short tdr_link;
  24594. +    unsigned short tdr_result;
  24595. +#define TDR_TIME    (0x7ff)
  24596. +#define TDR_SHORT    (1 << 12)
  24597. +#define TDR_OPEN    (1 << 13)
  24598. +#define TDR_XCVRPROB    (1 << 14)
  24599. +#define TDR_LNKOK    (1 << 15)
  24600. +} tdr_t;
  24601. +
  24602. +typedef struct { /* transmit */
  24603. +    unsigned short tx_status;
  24604. +    unsigned short tx_command;
  24605. +    unsigned short tx_link;
  24606. +    unsigned short tx_tbdoffset;
  24607. +} tx_t;
  24608. +
  24609. +typedef struct { /* tbd */
  24610. +    unsigned short tbd_opts;
  24611. +#define TBD_CNT        (0x3fff)
  24612. +#define TBD_EOL        (1 << 15)
  24613. +    unsigned short tbd_link;
  24614. +    unsigned short tbd_bufl;
  24615. +    unsigned short tbd_bufh;
  24616. +} tbd_t;
  24617. +
  24618. +typedef struct { /* rfd */
  24619. +    unsigned short rfd_status;
  24620. +#define RFD_NOEOF    (1 << 6)
  24621. +#define RFD_FRAMESHORT    (1 << 7)
  24622. +#define RFD_DMAOVRN    (1 << 8)
  24623. +#define RFD_NORESOURCES    (1 << 9)
  24624. +#define RFD_ALIGNERROR    (1 << 10)
  24625. +#define RFD_CRCERROR    (1 << 11)
  24626. +#define RFD_OK        (1 << 13)
  24627. +#define RFD_FDCONSUMED    (1 << 14)
  24628. +#define RFD_COMPLETE    (1 << 15)
  24629. +    unsigned short rfd_command;
  24630. +#define RFD_CMDSUSPEND    (1 << 14)
  24631. +#define RFD_CMDEL    (1 << 15)
  24632. +    unsigned short rfd_link;
  24633. +    unsigned short rfd_rbdoffset;
  24634. +    unsigned char  rfd_dest[6];
  24635. +    unsigned char  rfd_src[6];
  24636. +    unsigned short rfd_len;
  24637. +} rfd_t;
  24638. +
  24639. +typedef struct { /* rbd */
  24640. +    unsigned short rbd_status;
  24641. +#define RBD_ACNT    (0x3fff)
  24642. +#define RBD_ACNTVALID    (1 << 14)
  24643. +#define RBD_EOF        (1 << 15)
  24644. +    unsigned short rbd_link;
  24645. +    unsigned short rbd_bufl;
  24646. +    unsigned short rbd_bufh;
  24647. +    unsigned short rbd_len;
  24648. +} rbd_t;
  24649. +
  24650. +typedef struct { /* nop */
  24651. +    unsigned short nop_status;
  24652. +    unsigned short nop_command;
  24653. +    unsigned short nop_link;
  24654. +} nop_t;
  24655. +
  24656. +typedef struct { /* set multicast */
  24657. +    unsigned short mc_status;
  24658. +    unsigned short mc_command;
  24659. +    unsigned short mc_link;
  24660. +    unsigned short mc_cnt;
  24661. +    unsigned char  mc_addrs[1][6];
  24662. +} mc_t;
  24663. +
  24664. +typedef struct { /* set address */
  24665. +    unsigned short sa_status;
  24666. +    unsigned short sa_command;
  24667. +    unsigned short sa_link;
  24668. +    unsigned char  sa_addr[6];
  24669. +} sa_t;
  24670. +
  24671. +typedef struct { /* config command */
  24672. +    unsigned short cfg_status;
  24673. +    unsigned short cfg_command;
  24674. +    unsigned short cfg_link;
  24675. +    unsigned char  cfg_bytecnt;    /* size foll data: 4 - 12         */
  24676. +    unsigned char  cfg_fifolim;    /* FIFO threshold             */
  24677. +    unsigned char  cfg_byte8;
  24678. +#define CFG8_SRDY    (1 << 6)
  24679. +#define CFG8_SAVEBADF    (1 << 7)
  24680. +    unsigned char  cfg_byte9;
  24681. +#define CFG9_ADDRLEN(x)    (x)
  24682. +#define CFG9_ADDRLENBUF    (1 << 3)
  24683. +#define CFG9_PREAMB2    (0 << 4)
  24684. +#define CFG9_PREAMB4    (1 << 4)
  24685. +#define CFG9_PREAMB8    (2 << 4)
  24686. +#define CFG9_PREAMB16    (3 << 4)
  24687. +#define CFG9_ILOOPBACK    (1 << 6)
  24688. +#define CFG9_ELOOPBACK    (1 << 7)
  24689. +    unsigned char  cfg_byte10;
  24690. +#define CFG10_LINPRI(x)    (x)
  24691. +#define CFG10_ACR(x)    (x << 4)
  24692. +#define CFG10_BOFMET    (1 << 7)
  24693. +    unsigned char  cfg_ifs;
  24694. +    unsigned char  cfg_slotl;
  24695. +    unsigned char  cfg_byte13;
  24696. +#define CFG13_SLOTH(x)    (x)
  24697. +#define CFG13_RETRY(x)    (x << 4)
  24698. +    unsigned char  cfg_byte14;
  24699. +#define CFG14_PROMISC    (1 << 0)
  24700. +#define CFG14_DISBRD    (1 << 1)
  24701. +#define CFG14_MANCH    (1 << 2)
  24702. +#define CFG14_TNCRS    (1 << 3)
  24703. +#define CFG14_NOCRC    (1 << 4)
  24704. +#define CFG14_CRC16    (1 << 5)
  24705. +#define CFG14_BTSTF    (1 << 6)
  24706. +#define CFG14_FLGPAD    (1 << 7)
  24707. +    unsigned char  cfg_byte15;
  24708. +#define CFG15_CSTF(x)    (x)
  24709. +#define CFG15_ICSS    (1 << 3)
  24710. +#define CFG15_CDTF(x)    (x << 4)
  24711. +#define CFG15_ICDS    (1 << 7)
  24712. +    unsigned short cfg_minfrmlen;
  24713. +} cfg_t;
  24714. +
  24715. +typedef struct { /* scb */
  24716. +    unsigned short scb_status;    /* status of 82586             */
  24717. +#define SCB_STRXMASK        (7 << 4)
  24718. +#define SCB_STRXIDLE        (0 << 4)
  24719. +#define SCB_STRXSUSP        (1 << 4)
  24720. +#define SCB_STRXNRES        (2 << 4)
  24721. +#define SCB_STRXRDY        (4 << 4)
  24722. +#define SCB_STCUMASK        (7 << 8)
  24723. +#define SCB_STCUIDLE        (0 << 8)
  24724. +#define SCB_STCUSUSP        (1 << 8)
  24725. +#define SCB_STCUACTV        (2 << 8)
  24726. +#define SCB_STRNR        (1 << 12)
  24727. +#define SCB_STCNA        (1 << 13)
  24728. +#define SCB_STFR        (1 << 14)
  24729. +#define SCB_STCX        (1 << 15)
  24730. +    unsigned short scb_command;    /* Next command                 */
  24731. +#define SCB_CMDRXSTART        (1 << 4)
  24732. +#define SCB_CMDRXRESUME        (2 << 4)
  24733. +#define SCB_CMDRXSUSPEND    (3 << 4)
  24734. +#define SCB_CMDRXABORT        (4 << 4)
  24735. +#define SCB_CMDCUCSTART        (1 << 8)
  24736. +#define SCB_CMDCUCRESUME    (2 << 8)
  24737. +#define SCB_CMDCUCSUSPEND    (3 << 8)
  24738. +#define SCB_CMDCUCABORT        (4 << 8)
  24739. +#define SCB_CMDACKRNR        (1 << 12)
  24740. +#define SCB_CMDACKCNA        (1 << 13)
  24741. +#define SCB_CMDACKFR        (1 << 14)
  24742. +#define SCB_CMDACKCX        (1 << 15)
  24743. +    unsigned short scb_cbl_offset;    /* Offset of first command unit         */
  24744. +    unsigned short scb_rfa_offset;    /* Offset of first receive frame area     */
  24745. +    unsigned short scb_crc_errors;    /* Properly aligned frame with CRC error */
  24746. +    unsigned short scb_aln_errors;    /* Misaligned frames             */
  24747. +    unsigned short scb_rsc_errors;    /* Frames lost due to no space         */
  24748. +    unsigned short scb_ovn_errors;    /* Frames lost due to slow bus         */
  24749. +} scb_t;
  24750. +
  24751. +typedef struct { /* iscp */
  24752. +    unsigned short iscp_busy;    /* set by CPU before CA             */
  24753. +    unsigned short iscp_offset;    /* offset of SCB             */
  24754. +    unsigned short iscp_basel;    /* base of SCB                 */
  24755. +    unsigned short iscp_baseh;
  24756. +} iscp_t;
  24757. +
  24758. +    /* this address must be 0xfff6 */
  24759. +typedef struct { /* scp */
  24760. +    unsigned short scp_sysbus;    /* bus size */
  24761. +#define SCP_SY_16BBUS    0x00
  24762. +#define SCP_SY_8BBUS    0x01
  24763. +    unsigned short scp_junk[2];    /* junk */
  24764. +    unsigned short scp_iscpl;    /* lower 16 bits of iscp */
  24765. +    unsigned short scp_iscph;    /* upper 16 bits of iscp */
  24766. +} scp_t;
  24767. +
  24768. +/* commands */
  24769. +#define CMD_NOP            0
  24770. +#define CMD_SETADDRESS        1
  24771. +#define CMD_CONFIG        2
  24772. +#define CMD_SETMULTICAST    3
  24773. +#define CMD_TX            4
  24774. +#define CMD_TDR            5
  24775. +#define CMD_DUMP        6
  24776. +#define CMD_DIAGNOSE        7
  24777. +
  24778. +#define CMD_MASK        7
  24779. +
  24780. +#define CMD_INTR        (1 << 13)
  24781. +#define CMD_SUSP        (1 << 14)
  24782. +#define CMD_EOL            (1 << 15)
  24783. +
  24784. +#define STAT_COLLISIONS        (15)
  24785. +#define STAT_COLLEXCESSIVE    (1 << 5)
  24786. +#define STAT_COLLAFTERTX    (1 << 6)
  24787. +#define STAT_TXDEFERRED        (1 << 7)
  24788. +#define STAT_TXSLOWDMA        (1 << 8)
  24789. +#define STAT_TXLOSTCTS        (1 << 9)
  24790. +#define STAT_NOCARRIER        (1 << 10)
  24791. +#define STAT_FAIL        (1 << 11)
  24792. +#define STAT_ABORTED        (1 << 12)
  24793. +#define STAT_OK            (1 << 13)
  24794. +#define STAT_BUSY        (1 << 14)
  24795. +#define STAT_COMPLETE        (1 << 15)
  24796. +#endif
  24797. +#endif
  24798. +
  24799. +/*
  24800. + * Ether1 card definitions:
  24801. + *
  24802. + * FAST accesses:
  24803. + *    +0    Page register
  24804. + *             16 pages
  24805. + *    +4    Control
  24806. + *            '1' = reset
  24807. + *            '2' = loopback
  24808. + *            '4' = CA
  24809. + *            '8' = int ack
  24810. + *
  24811. + * RAM at address + 0x2000
  24812. + * Pod. Prod id = 3
  24813. + * Words after ID block [base + 8 words]
  24814. + *    +0 pcb issue (0x0c and 0xf3 invalid)
  24815. + *    +1 - +6 eth hw address
  24816. + */
  24817. +
  24818. diff -urNwbB linux/arch/arm/drivers/net/ether3.c linux.arm/arch/arm/drivers/net/ether3.c
  24819. --- linux/arch/arm/drivers/net/ether3.c    Thu Jan  1 01:00:00 1970
  24820. +++ linux.arm/arch/arm/drivers/net/ether3.c    Sat Mar  2 18:11:39 1996
  24821. @@ -0,0 +1,914 @@
  24822. +/*
  24823. + * linux/drivers/net/ether3.c
  24824. + *
  24825. + * SEEQ nq8005 ethernet driver
  24826. + *
  24827. + * By Russell King.
  24828. + *
  24829. + * Changelog:
  24830. + *  29/02/96:    RMK    Won't pass packets that are from our ethernet address
  24831. + *            up to the higher levels - they're silently ignored.
  24832. + *            I/F can now be put into multicast mode.  Receiver
  24833. + *            routine optimised.
  24834. + *
  24835. + *  30/02/96:    RMK    Now claims interrupt at open when part of the kernel
  24836. + *            rather than when a module.
  24837. + *
  24838. + *  02/03/96:    RMK    Various code cleanups
  24839. + *
  24840. + * TODO:
  24841. + *  When we detect a fatal error on the interface, we should restart it.
  24842. + */
  24843. +
  24844. +#ifdef MODULE
  24845. +#include <linux/module.h>
  24846. +#include <linux/version.h>
  24847. +#else
  24848. +#define CLAIM_IRQ_AT_OPEN
  24849. +#define MOD_INC_USE_COUNT
  24850. +#define MOD_DEC_USE_COUNT
  24851. +#endif
  24852. +
  24853. +#include <linux/config.h>
  24854. +#include <linux/kernel.h>
  24855. +#include <linux/sched.h>
  24856. +#include <linux/types.h>
  24857. +#include <linux/fcntl.h>
  24858. +#include <linux/interrupt.h>
  24859. +#include <linux/ptrace.h>
  24860. +#include <linux/ioport.h>
  24861. +#include <linux/in.h>
  24862. +#include <linux/malloc.h>
  24863. +#include <linux/string.h>
  24864. +#include <linux/errno.h>
  24865. +#include <linux/netdevice.h>
  24866. +#include <linux/etherdevice.h>
  24867. +#include <linux/skbuff.h>
  24868. +#include <asm/system.h>
  24869. +#include <asm/bitops.h>
  24870. +#include <asm/io.h>
  24871. +#include <asm/dma.h>
  24872. +#include <asm/ecard.h>
  24873. +
  24874. +#include "ether3.h"
  24875. +
  24876. +static unsigned int net_debug = NET_DEBUG;
  24877. +static int ether3_prods[] = { 0x00A4 };
  24878. +static int ether3_manus[] = { 0x0011 };
  24879. +
  24880. +static char *version = "ether3 ethernet driver (c) 1995 R.M.King v1.10\n";
  24881. +
  24882. +extern int inswb(int reg, void *buffer, int len);
  24883. +extern int outswb(int reg, void *buffer, int len);
  24884. +
  24885. +#define FUNC_PROLOGUE \
  24886. +    struct dev_priv *priv = (struct dev_priv *)dev->priv
  24887. +
  24888. +#define BUS_16 16
  24889. +#define BUS_8  8
  24890. +
  24891. +/*
  24892. + * I'm not sure what address we should default to if the internal one
  24893. + * is corrupted...
  24894. + */
  24895. +unsigned char def_eth_addr[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
  24896. +
  24897. +/* --------------------------------------------------------------------------- */
  24898. +
  24899. +/*
  24900. + * write data to the buffer memory
  24901. + */
  24902. +static void
  24903. +ether3_writebuffer(struct device *dev, void *data, int start, int length)
  24904. +{
  24905. +    FUNC_PROLOGUE;
  24906. +    int timeout = 1000000;
  24907. +
  24908. +    if (start != -1) {
  24909. +    outw (priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  24910. +    outw (priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  24911. +    while ((inw (REG_STATUS) & STAT_FIFOEMPTY) == 0)
  24912. +        if (!timeout--) {
  24913. +        printk ("settxlim_16 broken\n");
  24914. +        priv->broken = 1;
  24915. +        return;
  24916. +        }
  24917. +    outw (priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  24918. +    outw (start, REG_DMAADDR);
  24919. +    }
  24920. +    if(length != 0)
  24921. +    outswb (REG_BUFWIN, data, length);
  24922. +}
  24923. +
  24924. +/*
  24925. + * read data from the buffer memory
  24926. + */
  24927. +static void
  24928. +ether3_readbuffer(struct device *dev, void *data, int start, int length)
  24929. +{
  24930. +    FUNC_PROLOGUE;
  24931. +    int timeout = 1000000;
  24932. +
  24933. +    if (start != -1) {
  24934. +    outw (priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  24935. +    outw (priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
  24936. +    while ((inw( REG_STATUS) & STAT_FIFOEMPTY) == 0)
  24937. +        if (!timeout--) {
  24938. +        printk ("setrxlim_16 broken\n");
  24939. +        priv->broken = 1;
  24940. +        return;
  24941. +        }
  24942. +    outw (start, REG_DMAADDR);
  24943. +    outw (priv->regs.command | CMD_FIFOREAD, REG_COMMAND);
  24944. +    }
  24945. +    if(length != 0)
  24946. +    inswb (REG_BUFWIN, data, length);
  24947. +}
  24948. +
  24949. +/*
  24950. + * Increment the use count, and switch LED on if necessary
  24951. + */
  24952. +static inline void
  24953. +ether3_ledincrementuse (struct device *dev)
  24954. +{
  24955. +    FUNC_PROLOGUE;
  24956. +
  24957. +    if (++ priv->use == 1) {
  24958. +    priv->regs.config2 &= ~CFG2_CTRLO;
  24959. +    outw (priv->regs.config2 , REG_CONFIG2);
  24960. +    }
  24961. +}
  24962. +
  24963. +/*
  24964. + * Decrement the use count and switch LED off if necessary
  24965. + */
  24966. +static inline void
  24967. +ether3_leddecrementuse (struct device *dev)
  24968. +{
  24969. +    FUNC_PROLOGUE;
  24970. +
  24971. +    if (priv->use && -- priv->use == 0) {
  24972. +    priv->regs.config2 |= CFG2_CTRLO;
  24973. +    outw (priv->regs.config2, REG_CONFIG2);
  24974. +    }
  24975. +}
  24976. +
  24977. +/*
  24978. + * Read the ethernet address string from the on board rom.
  24979. + * This is an ascii string!!!
  24980. + */
  24981. +static void
  24982. +ether3_addr(char *addr, struct expansion_card *ec)
  24983. +{
  24984. +    struct chunk_dir cd;
  24985. +    char *s;
  24986. +    
  24987. +    if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) {
  24988. +    int i;
  24989. +    for (i = 0; i<6; i++) {
  24990. +        addr[i] = simple_strtoul(s + 1, &s, 0x10);
  24991. +        if (*s != (i==5?')' : ':' ))
  24992. +        break;
  24993. +    }
  24994. +    if (i == 6)
  24995. +        return;
  24996. +    }
  24997. +    memcpy (addr, def_eth_addr, 6);
  24998. +}
  24999. +
  25000. +/* --------------------------------------------------------------------------- */
  25001. +
  25002. +static int
  25003. +ether3_ramtest(struct device *dev, unsigned char byte)
  25004. +{
  25005. +    unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL);
  25006. +    unsigned long flags;
  25007. +    int i,ret=0;
  25008. +    int max_errors = 4;
  25009. +    int bad=-1;
  25010. +
  25011. +    if (!buffer)
  25012. +    return 1;
  25013. +
  25014. +    save_flags (flags);
  25015. +    cli ();
  25016. +
  25017. +    memset (buffer, byte, RX_END);
  25018. +    ether3_writebuffer (dev, buffer, 0, TX_END);
  25019. +    ether3_writebuffer (dev, buffer+RX_START, RX_START, RX_LEN);
  25020. +
  25021. +    memset (buffer, byte ^ 0xff, RX_END);
  25022. +    ether3_readbuffer (dev, buffer, 0, TX_END);
  25023. +    ether3_readbuffer (dev, buffer+RX_START, RX_START, RX_LEN);
  25024. +
  25025. +    for (i=0; i<RX_END; i++) {
  25026. +    if (buffer[i] != byte) {
  25027. +        if (max_errors>=0 && bad!=buffer[i]) {
  25028. +        printk ("%s: RAM failed with (%02X instead of %02X) at 0x%04X",
  25029. +            dev->name, buffer[i], byte, i);
  25030. +        ret = 2;
  25031. +        max_errors--;
  25032. +        bad = buffer[i];
  25033. +        }
  25034. +    } else {
  25035. +        if (bad != -1) {
  25036. +        printk(" - 0x%04X\n", i);
  25037. +        bad = -1;
  25038. +        }
  25039. +    }
  25040. +    }
  25041. +    if (bad != -1)
  25042. +    printk (" - 0x10000\n");
  25043. +    kfree (buffer);
  25044. +    restore_flags (flags);
  25045. +
  25046. +    return ret;
  25047. +}
  25048. +
  25049. +/* ------------------------------------------------------------------------------- */
  25050. +
  25051. +static int
  25052. +ether3_init_2(struct device *dev)
  25053. +{
  25054. +    FUNC_PROLOGUE;
  25055. +    int i;
  25056. +    unsigned long txhdr = 0;
  25057. +
  25058. +    priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8;
  25059. +    priv->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC;
  25060. +    priv->regs.command = 0;
  25061. +    /*
  25062. +     * Set up our hardware address
  25063. +     */
  25064. +    outw (priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
  25065. +    for (i = 0; i < 6; i++)
  25066. +    outb (dev->dev_addr[i], REG_BUFWIN);
  25067. +
  25068. +    if (dev->flags & IFF_PROMISC)
  25069. +    priv->regs.config1 |= CFG1_RECVPROMISC;
  25070. +    else
  25071. +    if (dev->flags & IFF_MULTICAST)
  25072. +    priv->regs.config1 |= CFG1_RECVSPECBRMULTI;
  25073. +    else
  25074. +    priv->regs.config1 |= CFG1_RECVSPECBROAD;
  25075. +
  25076. +    /*
  25077. +     * There is a problem with the NQ8005 in that it occasionally losses the
  25078. +     * last two bytes.  To get round this problem, we receive the CRC as well.
  25079. +     * That way, if we do loose the last two, then it doesn't matter
  25080. +     */
  25081. +    outw (priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
  25082. +    outw ((TX_END>>8) - 1, REG_BUFWIN);
  25083. +    outw (priv->regs.recvptr, REG_RECVPTR);
  25084. +    outw (priv->regs.transmitptr, REG_TRANSMITPTR);
  25085. +    outw (priv->regs.recvptr >> 8, REG_RECVEND);
  25086. +    outw (priv->regs.config2, REG_CONFIG2);
  25087. +    outw (priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  25088. +
  25089. +    ether3_writebuffer (dev, &txhdr, priv->regs.transmitptr, 4);
  25090. +
  25091. +    outw (priv->regs.command, REG_COMMAND);
  25092. +
  25093. +    i = ether3_ramtest (dev, 0x5A);
  25094. +    if(i)
  25095. +    return i;
  25096. +    return ether3_ramtest (dev, 0x1E);
  25097. +}
  25098. +
  25099. +static void
  25100. +ether3_init_for_open(struct device *dev)
  25101. +{
  25102. +    FUNC_PROLOGUE;
  25103. +    unsigned long txhdr = 0;
  25104. +    int i;
  25105. +
  25106. +    memset (&priv->stats, 0, sizeof (struct enet_statistics));
  25107. +
  25108. +    priv->regs.command = 0;
  25109. +    priv->txbuffered = 0;
  25110. +    outw (CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
  25111. +    while (inw (REG_STATUS) & (STAT_RXON|STAT_TXON));
  25112. +
  25113. +    outw (priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
  25114. +    for (i = 0; i < 6; i++)
  25115. +    outb (dev->dev_addr[i], REG_BUFWIN);
  25116. +
  25117. +    priv->regs.transmitptr = 0;    /* address that transmitter has processed to */
  25118. +    priv->txinsert = 0;        /* address of next available packet for tx */
  25119. +    priv->txed = 0;            /* transmitted length index */
  25120. +    priv->txto = 0;            /* to transmit length index */
  25121. +    priv->tx_ends[0] = 0;
  25122. +    priv->use = 0;
  25123. +
  25124. +    priv->regs.config2 |= CFG2_CTRLO;
  25125. +
  25126. +    outw (priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
  25127. +    outw ((TX_END>>8) - 1, REG_BUFWIN);
  25128. +
  25129. +    priv->regs.recvptr    = RX_START;
  25130. +    outw (priv->regs.recvptr, REG_RECVPTR);
  25131. +    outw (priv->regs.recvptr >> 8, REG_RECVEND);
  25132. +
  25133. +    outw (0, REG_TRANSMITPTR);
  25134. +    outw (priv->regs.config2, REG_CONFIG2);
  25135. +    outw (priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  25136. +
  25137. +    ether3_writebuffer (dev, &txhdr, priv->regs.transmitptr, 4);
  25138. +
  25139. +    priv->regs.command = CMD_ENINTRX|CMD_ENINTTX;
  25140. +    outw (priv->regs.command | CMD_RXON, REG_COMMAND);
  25141. +}
  25142. +
  25143. +/*
  25144. + * This is the real probe routine.
  25145. + */
  25146. +static int
  25147. +ether3_probe1(struct device *dev)
  25148. +{
  25149. +    static unsigned version_printed = 0;
  25150. +    struct dev_priv *priv;
  25151. +    int i;
  25152. +
  25153. +    if (!dev->priv)
  25154. +    dev->priv = kmalloc (sizeof (struct dev_priv), GFP_KERNEL);
  25155. +
  25156. +    if (!dev->priv)
  25157. +    return -ENOMEM;
  25158. +
  25159. +    priv = (struct dev_priv *) dev->priv;
  25160. +    memset (priv, 0, sizeof(struct dev_priv));
  25161. +    priv->broken = 0;
  25162. +
  25163. +    outb (0x80, REG_CONFIG2 + 1);
  25164. +    outb (0, REG_COMMAND);
  25165. +
  25166. +    /*
  25167. +     * test to see if we have an 8 or 16-bit IO bus
  25168. +     */
  25169. +    outb (1, REG_CONFIG1);
  25170. +    if (inb (REG_CONFIG1 + 1) == 1 && inb (REG_CONFIG1) == 0)
  25171. +        priv->bus_type = BUS_8;
  25172. +    else
  25173. +    if (inw (REG_CONFIG1) == 0x0101)
  25174. +        priv->bus_type = BUS_16;
  25175. +    else {
  25176. +    kfree(dev->priv);
  25177. +    dev->priv = NULL;
  25178. +    return -ENODEV;
  25179. +    }
  25180. +
  25181. +    if (net_debug  &&  version_printed++ == 0)
  25182. +    printk(version);
  25183. +
  25184. +    printk("%s: ether3 found [%d, %04lx, %d] ", dev->name, priv->bus_type,
  25185. +    dev->base_addr, dev->irq);
  25186. +
  25187. +    if (priv->bus_type == BUS_8) {
  25188. +    printk ("*** 8-bit not supported (yet) ***\n");
  25189. +    kfree (dev->priv);
  25190. +    dev->priv = NULL;
  25191. +    return -ENODEV;
  25192. +    }
  25193. +
  25194. +    /* Retrive and print the ethernet address. */
  25195. +    for (i = 0; i < 6; i++)
  25196. +    printk (i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]);
  25197. +
  25198. +    if (ether3_init_2(dev)) {
  25199. +    kfree (dev->priv);
  25200. +    dev->priv = NULL;
  25201. +    return -ENODEV;
  25202. +    }
  25203. +
  25204. +    dev->open = ether3_open;
  25205. +    dev->stop = ether3_close;
  25206. +    dev->hard_start_xmit = ether3_send_packet;
  25207. +    dev->get_stats = ether3_get_stats;
  25208. +    dev->set_multicast_list = set_multicast_list;
  25209. +
  25210. +    /* Fill in the fields of the device structure with ethernet values. */
  25211. +    ether_setup(dev);
  25212. +#ifndef CLAIM_IRQ_AT_OPEN
  25213. +    if (request_irq(dev->irq, ether3_interrupt, 0, "ether3")) {
  25214. +    kfree (dev->priv);
  25215. +    dev->priv = NULL;
  25216. +    return -EAGAIN;
  25217. +    }
  25218. +
  25219. +    irq2dev_map[dev->irq] = dev;
  25220. +#endif
  25221. +    return 0;
  25222. +}
  25223. +
  25224. +#ifndef MODULE
  25225. +int
  25226. +ether3_probe(struct device *dev)
  25227. +{
  25228. +    struct expansion_card *ec;
  25229. +
  25230. +    if (!dev)
  25231. +    return ENODEV;
  25232. +
  25233. +    if ((ec = ecard_find (0, sizeof(ether3_prods), ether3_prods, ether3_manus)) == NULL)
  25234. +    return ENODEV;
  25235. +
  25236. +    dev->base_addr = ((unsigned long)ec->r_podaddr & ~0x003c0000UL) >> 2;
  25237. +    dev->irq = ec->irq;
  25238. +
  25239. +    ecard_claim (ec);
  25240. +
  25241. +    ether3_addr (dev->dev_addr, ec);
  25242. +    return ether3_probe1(dev);
  25243. +}
  25244. +#endif
  25245. +
  25246. +/*
  25247. + * Open/initialize the board.  This is called (in the current kernel)
  25248. + * sometime after booting when the 'ifconfig' program is run.
  25249. + *
  25250. + * This routine should set everything up anew at each open, even
  25251. + * registers that "should" only need to be set once at boot, so that
  25252. + * there is non-reboot way to recover if something goes wrong.
  25253. + */
  25254. +static int
  25255. +ether3_open(struct device *dev)
  25256. +{
  25257. +    ether3_init_for_open(dev);
  25258. +
  25259. +#ifdef CLAIM_IRQ_AT_OPEN
  25260. +    if (request_irq(dev->irq, ether3_interrupt, 0, "ether3"))
  25261. +    return -EAGAIN;
  25262. +
  25263. +    irq2dev_map[dev->irq] = dev;
  25264. +#endif
  25265. +
  25266. +    MOD_INC_USE_COUNT;
  25267. +
  25268. +    dev->tbusy = 0;
  25269. +    dev->interrupt = 0;
  25270. +    dev->start = 1;
  25271. +    return 0;
  25272. +}
  25273. +
  25274. +/*
  25275. + * The inverse routine to ether3_open().
  25276. + */
  25277. +static int
  25278. +ether3_close(struct device *dev)
  25279. +{
  25280. +    FUNC_PROLOGUE;
  25281. +    unsigned long flags;
  25282. +
  25283. +    dev->tbusy = 1;
  25284. +    dev->start = 0;
  25285. +
  25286. +    save_flags (flags);
  25287. +    cli ();
  25288. +
  25289. +    outw (CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
  25290. +    priv->regs.command = 0;
  25291. +    while (inw (REG_STATUS) & (STAT_RXON|STAT_TXON));
  25292. +    outb (0x80, REG_CONFIG2 + 1);
  25293. +    outw (0, REG_COMMAND);
  25294. +
  25295. +    restore_flags (flags);
  25296. +#ifdef CLAIM_IRQ_AT_OPEN
  25297. +    free_irq (dev->irq);
  25298. +
  25299. +    irq2dev_map[dev->irq] = NULL;
  25300. +#endif
  25301. +
  25302. +    MOD_DEC_USE_COUNT;
  25303. +    return 0;
  25304. +}
  25305. +
  25306. +/*
  25307. + * Get the current statistics.    This may be called with the card open or
  25308. + * closed.
  25309. + */
  25310. +static struct enet_statistics *
  25311. +ether3_get_stats(struct device *dev)
  25312. +{
  25313. +    FUNC_PROLOGUE;
  25314. +    return &priv->stats;
  25315. +}
  25316. +
  25317. +/*
  25318. + * Set or clear the multicast filter for this adaptor.
  25319. + * num_addrs == -1    Promiscuous mode, receive all packets
  25320. + * num_addrs == 0    Normal mode, clear multicast list
  25321. + * num_addrs > 0    Multicast mode, receive normal and MC packets, and do
  25322. + *            best-effort filtering.
  25323. + */
  25324. +static void
  25325. +set_multicast_list(struct device *dev, int num_addrs, void *addrs)
  25326. +{
  25327. +    FUNC_PROLOGUE;
  25328. +
  25329. +    priv->regs.config1 &= ~CFG1_RECVPROMISC;
  25330. +    
  25331. +    switch (num_addrs) {
  25332. +    case -1:    priv->regs.config1 |= CFG1_RECVPROMISC;     break;
  25333. +    case 0:        priv->regs.config1 |= CFG1_RECVSPECBROAD;   break;
  25334. +    default:    priv->regs.config1 |= CFG1_RECVSPECBRMULTI; break;
  25335. +    }
  25336. +
  25337. +    outw (priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
  25338. +}
  25339. +
  25340. +/*
  25341. + * Transmit a packet
  25342. + */
  25343. +static int
  25344. +ether3_send_packet(struct sk_buff *skb, struct device *dev)
  25345. +{
  25346. +    FUNC_PROLOGUE;
  25347. +
  25348. +    if (dev->tbusy) {
  25349. +    /* If we get here, some higher level has decided we are broken.
  25350. +       There should really be a "kick me" function call instead. */
  25351. +    int tickssofar = jiffies - dev->trans_start;
  25352. +    if (tickssofar < 5)
  25353. +        return 1;
  25354. +    printk("%s: transmit timed out, network cable problem?\n", dev->name);
  25355. +    /* Try to restart the adaptor. */
  25356. +    dev->tbusy = 0;
  25357. +    priv->use = 0;
  25358. +    priv->regs.config2 |= CFG2_CTRLO;
  25359. +    outw (priv->regs.config2 , REG_CONFIG2);
  25360. +    dev->trans_start = jiffies;
  25361. +    }
  25362. +
  25363. +    /* If some higher layer thinks we've missed an tx-done interrupt
  25364. +       we are passed NULL. Caution: dev_tint() handles the cli()/sti()
  25365. +       itself. */
  25366. +    if (skb == NULL) {
  25367. +    dev_tint(dev);
  25368. +    return 0;
  25369. +    }
  25370. +
  25371. +    /* Block a timer-based transmit from overlapping.  This could better be
  25372. +       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
  25373. +    if (set_bit(0, (void*)&dev->tbusy) != 0)
  25374. +    printk("%s: Transmitter access conflict.\n", dev->name);
  25375. +    else {
  25376. +    unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
  25377. +    unsigned int thisdata, thisstart, nextpacket;
  25378. +    unsigned long flags;
  25379. +    unsigned long thishdr = TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS
  25380. +                |TXHDR_ENSUCCESS;
  25381. +    unsigned long nexthdr = 0;
  25382. +
  25383. +    if (priv->broken) {
  25384. +        dev_kfree_skb(skb, FREE_WRITE);
  25385. +        priv->stats.tx_dropped ++;
  25386. +        return 1;
  25387. +    }
  25388. +
  25389. +    thisstart = priv->txinsert;
  25390. +    thisdata  = thisstart + 4;
  25391. +    if (thisdata >= TX_END)
  25392. +        thisdata -= TX_END;
  25393. +
  25394. +    nextpacket = thisdata + length;
  25395. +    if (nextpacket >= TX_END)
  25396. +        nextpacket -= TX_END;
  25397. +
  25398. +    priv->txinsert = nextpacket;
  25399. +    priv->tx_ends[priv->txto++] = nextpacket;
  25400. +
  25401. +    if (priv->txto >= MAX_TXED)
  25402. +        priv->txto = 0;
  25403. +
  25404. +    thishdr |= htons (nextpacket);
  25405. +
  25406. +    save_flags(flags);
  25407. +    cli();
  25408. +    ether3_ledincrementuse (dev);
  25409. +    ether3_writebuffer(dev, skb->data, thisdata, length&1?(length+1):length);
  25410. +    ether3_writebuffer(dev, &nexthdr, -1, 4);
  25411. +    ether3_writebuffer(dev, &thishdr, thisstart, 4);
  25412. +
  25413. +    if ((inw (REG_STATUS) & STAT_TXON) == 0) {
  25414. +        outw (thisstart, REG_TRANSMITPTR);
  25415. +        outw (priv->regs.command | CMD_TXON, REG_COMMAND);
  25416. +    }
  25417. +    restore_flags(flags);
  25418. +
  25419. +    dev->trans_start = jiffies;
  25420. +    if (priv->txbuffered ++ < MAX_TX_BUFFERED)
  25421. +        dev->tbusy = 0;
  25422. +    }
  25423. +    dev_kfree_skb (skb, FREE_WRITE);
  25424. +
  25425. +    return 0;
  25426. +}
  25427. +
  25428. +static void
  25429. +ether3_interrupt(int irq, struct pt_regs *regs)
  25430. +{
  25431. +    struct device *dev = (struct device *)(irq2dev_map[irq]);
  25432. +    struct dev_priv *priv;
  25433. +    int boguscount = 20, done = 0;
  25434. +
  25435. +#if NET_DEBUG > 1
  25436. +    if(net_debug & DEBUG_INT)
  25437. +    printk("ether3_interrupt: irq %d\n", irq);
  25438. +#endif
  25439. +
  25440. +    if (dev == NULL) {
  25441. +    printk ("ether3_interrupt(): irq %d for unknown device.\n", irq);
  25442. +    return;
  25443. +    }
  25444. +
  25445. +    priv = (struct dev_priv *)dev->priv;
  25446. +
  25447. +    dev->interrupt = 1;
  25448. +
  25449. +    do {
  25450. +        unsigned int status;
  25451. +    status = inw(REG_STATUS);
  25452. +    outw ((status & (STAT_INTRX|STAT_INTTX|STAT_INTBUFWIN))
  25453. +        | priv->regs.command, REG_COMMAND);
  25454. +
  25455. +    if (status & STAT_INTRX) { /* Got a packet(s). */
  25456. +        ether3_rx (dev, priv);
  25457. +        done = 1;
  25458. +    }
  25459. +    if (status & STAT_INTTX) { /* Packets transmitted */
  25460. +        ether3_tx (dev, priv);
  25461. +        done = 1;
  25462. +    }
  25463. +    } while (-- boguscount && !done) ;
  25464. +
  25465. +    dev->interrupt = 0;
  25466. +
  25467. +#if NET_DEBUG > 1
  25468. +    if(net_debug & DEBUG_INT)
  25469. +    printk("ether3_interrupt: done\n", irq);
  25470. +#endif
  25471. +}
  25472. +
  25473. +/*
  25474. + * If we have a good packet(s), get it/them out of the buffers.
  25475. + */
  25476. +static void
  25477. +ether3_rx(struct device *dev, struct dev_priv *priv)
  25478. +{
  25479. +    unsigned int current_recv_ptr;
  25480. +    unsigned int maxcnt = 10;
  25481. +
  25482. +    ether3_ledincrementuse (dev);
  25483. +
  25484. +    current_recv_ptr = priv->regs.recvptr;
  25485. +
  25486. +    do {
  25487. +        struct t {
  25488. +            unsigned long rxhdr;
  25489. +            unsigned char dst_addr[6];
  25490. +            unsigned char src_addr[6];
  25491. +        } p;
  25492. +    unsigned char *buf;
  25493. +    unsigned int prev_recv_ptr;
  25494. +    unsigned int length;
  25495. +    struct sk_buff *skb;
  25496. +
  25497. +    /*
  25498. +     * read the first 16 bytes from the buffer.
  25499. +     * This contains the status bytes etc and ethernet addresses,
  25500. +     * and we also check the source ethernet address to see if
  25501. +     * it origionated from us.
  25502. +     */
  25503. +    prev_recv_ptr = current_recv_ptr;
  25504. +    ether3_readbuffer (dev, &p, current_recv_ptr, 16);
  25505. +
  25506. +    if ((p.rxhdr & RX_NEXT) == 0 || (p.rxhdr & RXSTAT_DONE) == 0
  25507. +        || (p.rxhdr & (RXHDR_CHAINCONTINUE|RXHDR_RECEIVE)) != RXHDR_CHAINCONTINUE)
  25508. +        break;
  25509. +
  25510. +    current_recv_ptr = ntohs (p.rxhdr & RX_NEXT);
  25511. +
  25512. +    /*
  25513. +      * ignore our own packets...
  25514. +      */
  25515. +    if (memcmp (dev->dev_addr, &p.src_addr, 6) == 0) {
  25516. +        outw (current_recv_ptr >> 8, REG_RECVEND);
  25517. +        continue;
  25518. +    }
  25519. +
  25520. +    if (p.rxhdr & (RXSTAT_OVERSIZE|RXSTAT_CRCERROR|RXSTAT_DRIBBLEERROR|RXSTAT_SHORTPACKET)) {
  25521. +        priv->stats.rx_errors++;
  25522. +        if(p.rxhdr & RXSTAT_OVERSIZE) priv->stats.rx_length_errors ++;
  25523. +        if(p.rxhdr & RXSTAT_CRCERROR) priv->stats.rx_crc_errors ++;
  25524. +        if(p.rxhdr & RXSTAT_DRIBBLEERROR) priv->stats.rx_fifo_errors ++;
  25525. +        if(p.rxhdr & RXSTAT_SHORTPACKET) priv->stats.rx_length_errors ++;
  25526. +        outw (current_recv_ptr >> 8, REG_RECVEND);
  25527. +        continue;
  25528. +    }
  25529. +
  25530. +    if (current_recv_ptr > prev_recv_ptr)
  25531. +        length = current_recv_ptr - prev_recv_ptr - 4;
  25532. +    else
  25533. +        length = (current_recv_ptr - RX_START) + (RX_END - prev_recv_ptr) - 4;
  25534. +
  25535. +    skb = dev_alloc_skb(length + 2);
  25536. +    if (skb == NULL) {
  25537. +        printk("%s: memory squeeze, dropping packet.\n", dev->name);
  25538. +        priv->stats.rx_dropped ++;
  25539. +        break;
  25540. +    }
  25541. +
  25542. +    skb->dev = dev;
  25543. +    skb_reserve (skb, 2);
  25544. +    buf = skb_put (skb, length);
  25545. +    /*
  25546. +     * buf isn't word aligned, and it is probably faster to
  25547. +     * copy the address this way
  25548. +     */
  25549. +    *(unsigned short *)&buf[0] = *(unsigned short *)&p.dst_addr[0];
  25550. +    *(unsigned short *)&buf[2] = *(unsigned short *)&p.dst_addr[2];
  25551. +    *(unsigned short *)&buf[4] = *(unsigned short *)&p.dst_addr[4];
  25552. +    *(unsigned short *)&buf[6] = *(unsigned short *)&p.src_addr[0];
  25553. +    *(unsigned short *)&buf[8] = *(unsigned short *)&p.src_addr[2];
  25554. +    *(unsigned short *)&buf[10] = *(unsigned short *)&p.src_addr[4];
  25555. +    
  25556. +    ether3_readbuffer (dev, buf + 12, -1, length - 12);
  25557. +
  25558. +    outw (current_recv_ptr >> 8, REG_RECVEND);
  25559. +
  25560. +    skb->protocol = eth_type_trans(skb, dev);
  25561. +    netif_rx (skb);
  25562. +    priv->stats.rx_packets++;
  25563. +    }
  25564. +    while (-- maxcnt);
  25565. +
  25566. +    priv->regs.recvptr = current_recv_ptr;
  25567. +    if (!(inw (REG_STATUS) & STAT_RXON)) {
  25568. +        outw (priv->regs.recvptr, REG_RECVPTR);
  25569. +    outw (priv->regs.command | CMD_RXON, REG_COMMAND);
  25570. +    }
  25571. +
  25572. +    /* If any worth-while packets have been received, dev_rint()
  25573. +       has done a mark_bh(NET_BH) for us and will work on them
  25574. +       when we get to the bottom-half routine. */
  25575. +
  25576. +    ether3_leddecrementuse (dev);
  25577. +}
  25578. +
  25579. +/*
  25580. + * Update stats for the transmitted packet
  25581. + */
  25582. +static void
  25583. +ether3_tx(struct device *dev, struct dev_priv *priv)
  25584. +{
  25585. +    unsigned long txhdr;
  25586. +    unsigned char *buffer = (unsigned char *)&txhdr;
  25587. +    unsigned int txptr;
  25588. +
  25589. +    txptr = priv->regs.transmitptr;
  25590. +
  25591. +    do {
  25592. +        /*
  25593. +         * Read the packet header
  25594. +         */
  25595. +    if (txptr + 4 > TX_END) {
  25596. +        int len = TX_END - priv->regs.transmitptr;
  25597. +        if (len)
  25598. +        ether3_readbuffer (dev, buffer, txptr, len);
  25599. +        ether3_readbuffer (dev, buffer + len, 0, 4 - len);
  25600. +    } else
  25601. +        ether3_readbuffer (dev, buffer, txptr, 4);
  25602. +
  25603. +    /*
  25604. +     * Check to see if this packet has been transmitted
  25605. +     */
  25606. +    if (!(txhdr & TXSTAT_DONE) || !(txhdr & TXHDR_TRANSMIT)) {
  25607. +        priv->regs.transmitptr = txptr;
  25608. +        return;
  25609. +    }
  25610. +
  25611. +    /*
  25612. +     * Update collision count (undocumented in datasheet)
  25613. +     */
  25614. +    if (txhdr & TXSTAT_COLLISION)
  25615. +        priv->stats.collisions += (txhdr >> (3+24)) & 15;
  25616. +
  25617. +    /*
  25618. +     * Update errors
  25619. +     */
  25620. +    if (txhdr & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS)) {
  25621. +        priv->stats.tx_errors ++;
  25622. +        if (txhdr & TXSTAT_16COLLISIONS) priv->stats.collisions += 16;
  25623. +        if (txhdr & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++;
  25624. +    } else
  25625. +        priv->stats.tx_packets++;
  25626. +
  25627. +    /*
  25628. +     * Get next packet address
  25629. +     */
  25630. +    txptr = priv->tx_ends[priv->txed++]; /* next packet address */
  25631. +
  25632. +    if (priv->txed >= MAX_TXED)
  25633. +        priv->txed = 0;
  25634. +
  25635. +    if (txptr != ntohs (txhdr & TX_NEXT)) {
  25636. +        printk ("%s: TX: bad next pointer - %04X instead of %04X\n",
  25637. +        dev->name, ntohs (txhdr & TX_NEXT), txptr);
  25638. +        return;
  25639. +    }
  25640. +
  25641. +    if (priv->regs.transmitptr >= TX_END)
  25642. +        priv->regs.transmitptr -= TX_END;
  25643. +
  25644. +    if (priv->txbuffered)
  25645. +        priv->txbuffered -= 1;
  25646. +
  25647. +    dev->tbusy = 0;
  25648. +
  25649. +    ether3_leddecrementuse (dev);
  25650. +
  25651. +    mark_bh (NET_BH);    /* Inform upper layers. */
  25652. +    } while (1);
  25653. +}
  25654. +
  25655. +#ifdef MODULE
  25656. +char kernel_version[] = UTS_RELEASE;
  25657. +
  25658. +char *ethernames[4] = {
  25659. +    "        ",
  25660. +    "        ",
  25661. +    "        ",
  25662. +    "        "
  25663. +};
  25664. +
  25665. +static struct device *my_ethers[4];
  25666. +static struct expansion_card *ec[4];
  25667. +
  25668. +int
  25669. +init_module(void)
  25670. +{
  25671. +    int i;
  25672. +
  25673. +    for(i = 0; i < 4; i++) {
  25674. +    my_ethers[i] = NULL;
  25675. +    ec[i] = NULL;
  25676. +    }
  25677. +
  25678. +    i = 0;
  25679. +
  25680. +    do {
  25681. +    if ((ec[i] = ecard_find(0, sizeof(ether3_prods), ether3_prods, ether3_manus)) == NULL)
  25682. +        break;
  25683. +
  25684. +    my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL);
  25685. +    memset(my_ethers[i], 0, sizeof(struct device));
  25686. +
  25687. +    my_ethers[i]->irq = ec[i]->irq;
  25688. +    my_ethers[i]->base_addr= ((unsigned long)ec[i]->r_podaddr & ~0x003c0000UL)>>2;
  25689. +    my_ethers[i]->init = ether3_probe1;
  25690. +    my_ethers[i]->name = ethernames[i];
  25691. +
  25692. +    ether3_addr(my_ethers[i]->dev_addr, ec[i]);
  25693. +
  25694. +    ecard_claim(ec[i]);
  25695. +
  25696. +    if(register_netdev(my_ethers[i]) != 0) {
  25697. +        for (i = 0; i < 4; i++) {
  25698. +        if(my_ethers[i]) {
  25699. +            kfree(my_ethers[i]);
  25700. +            my_ethers[i] = NULL;
  25701. +        }
  25702. +        if(ec[i]) {
  25703. +            ecard_release(ec[i]);
  25704. +            ec[i] = NULL;
  25705. +        }
  25706. +        }
  25707. +        return -EIO;
  25708. +    }
  25709. +    i++;
  25710. +    }
  25711. +    while(i < 4);
  25712. +
  25713. +    return i != 0 ? 0 : -ENODEV;
  25714. +}
  25715. +
  25716. +void
  25717. +cleanup_module(void)
  25718. +{
  25719. +    if (MOD_IN_USE) {
  25720. +    printk("ether3: device busy, remove delayed\n");
  25721. +    } else {
  25722. +    int i;
  25723. +    for (i = 0; i < 4; i++) {
  25724. +        if (my_ethers[i]) {
  25725. +        unregister_netdev(my_ethers[i]);
  25726. +        my_ethers[i] = NULL;
  25727. +        }
  25728. +        if (ec[i]) {
  25729. +        ecard_release(ec[i]);
  25730. +        ec[i] = NULL;
  25731. +        }
  25732. +    }
  25733. +    }
  25734. +}
  25735. +#endif /* MODULE */
  25736. diff -urNwbB linux/arch/arm/drivers/net/ether3.h linux.arm/arch/arm/drivers/net/ether3.h
  25737. --- linux/arch/arm/drivers/net/ether3.h    Thu Jan  1 01:00:00 1970
  25738. +++ linux.arm/arch/arm/drivers/net/ether3.h    Sat Mar  2 13:07:27 1996
  25739. @@ -0,0 +1,174 @@
  25740. +/*
  25741. + * linux/drivers/net/ether3.h
  25742. + *
  25743. + * network driver for Acorn Ether3 cards
  25744. + */
  25745. +
  25746. +#ifndef _LINUX_ether3_H
  25747. +#define _LINUX_ether3_H
  25748. +
  25749. +/* use 0 for production, 1 for verification, >2 for debug. debug flags: */
  25750. +#define DEBUG_TX     2
  25751. +#define DEBUG_RX     4
  25752. +#define DEBUG_INT     8
  25753. +#define DEBUG_IC    16
  25754. +#ifndef NET_DEBUG
  25755. +#define NET_DEBUG     0
  25756. +#endif
  25757. +
  25758. +/* Command register definitions & bits */
  25759. +#define REG_COMMAND        (dev->base_addr + 0x00)
  25760. +#define CMD_ENINTDMA        0x0001
  25761. +#define CMD_ENINTRX        0x0002
  25762. +#define CMD_ENINTTX        0x0004
  25763. +#define CMD_ENINTBUFWIN        0x0008
  25764. +#define CMD_ACKINTDMA        0x0010
  25765. +#define CMD_ACKINTRX        0x0020
  25766. +#define CMD_ACKINTTX        0x0040
  25767. +#define CMD_ACKINTBUFWIN    0x0080
  25768. +#define CMD_DMAON        0x0100
  25769. +#define CMD_RXON        0x0200
  25770. +#define CMD_TXON        0x0400
  25771. +#define CMD_DMAOFF        0x0800
  25772. +#define CMD_RXOFF        0x1000
  25773. +#define CMD_TXOFF        0x2000
  25774. +#define CMD_FIFOREAD        0x4000
  25775. +#define CMD_FIFOWRITE        0x8000
  25776. +
  25777. +/* status register */
  25778. +#define REG_STATUS        (dev->base_addr + 0x00)
  25779. +#define STAT_ENINTSTAT        0x0001
  25780. +#define STAT_ENINTRX        0x0002
  25781. +#define STAT_ENINTTX        0x0004
  25782. +#define STAT_ENINTBUFWIN    0x0008
  25783. +#define STAT_INTDMA        0x0010
  25784. +#define STAT_INTRX        0x0020
  25785. +#define STAT_INTTX        0x0040
  25786. +#define STAT_INTBUFWIN        0x0080
  25787. +#define STAT_DMAON        0x0100
  25788. +#define STAT_RXON        0x0200
  25789. +#define STAT_TXON        0x0400
  25790. +#define STAT_FIFOFULL        0x2000
  25791. +#define STAT_FIFOEMPTY        0x4000
  25792. +#define STAT_FIFODIR        0x8000
  25793. +
  25794. +/* configuration register 1 */
  25795. +#define REG_CONFIG1        (dev->base_addr + 0x10)
  25796. +#define CFG1_BUFSELSTAT0    0x0000
  25797. +#define CFG1_BUFSELSTAT1    0x0001
  25798. +#define CFG1_BUFSELSTAT2    0x0002
  25799. +#define CFG1_BUFSELSTAT3    0x0003
  25800. +#define CFG1_BUFSELSTAT4    0x0004
  25801. +#define CFG1_BUFSELSTAT5    0x0005
  25802. +#define CFG1_ADDRPROM        0x0006
  25803. +#define CFG1_TRANSEND        0x0007
  25804. +#define CFG1_LOCBUFMEM        0x0008
  25805. +#define CFG1_INTVECTOR        0x0009
  25806. +#define CFG1_DMABURSTCONT    0x0000
  25807. +#define CFG1_DMABURST800NS    0x0010
  25808. +#define CFG1_DMABURST1600NS    0x0020
  25809. +#define CFG1_DMABURST3200NS    0x0030
  25810. +#define CFG1_DMABURST1        0x0000
  25811. +#define CFG1_DMABURST4        0x0040
  25812. +#define CFG1_DMABURST8        0x0080
  25813. +#define CFG1_DMABURST16        0x00C0
  25814. +#define CFG1_RECVCOMPSTAT0    0x0100
  25815. +#define CFG1_RECVCOMPSTAT1    0x0200
  25816. +#define CFG1_RECVCOMPSTAT2    0x0400
  25817. +#define CFG1_RECVCOMPSTAT3    0x0800
  25818. +#define CFG1_RECVCOMPSTAT4    0x1000
  25819. +#define CFG1_RECVCOMPSTAT5    0x2000
  25820. +#define CFG1_RECVSPECONLY    0x0000
  25821. +#define CFG1_RECVSPECBROAD    0x4000
  25822. +#define CFG1_RECVSPECBRMULTI    0x8000
  25823. +#define CFG1_RECVPROMISC    0xC000
  25824. +
  25825. +/* configuration register 2 */
  25826. +#define REG_CONFIG2        (dev->base_addr + 0x20)
  25827. +#define CFG2_BYTESWAP        0x0001
  25828. +#define CFG2_ERRENCRC        0x0008
  25829. +#define CFG2_ERRENDRIBBLE    0x0010
  25830. +#define CFG2_ERRSHORTFRAME    0x0020
  25831. +#define CFG2_SLOTSELECT        0x0040
  25832. +#define CFG2_PREAMSELECT    0x0080
  25833. +#define CFG2_ADDRLENGTH        0x0100
  25834. +#define CFG2_RECVCRC        0x0200
  25835. +#define CFG2_XMITNOCRC        0x0400
  25836. +#define CFG2_LOOPBACK        0x0800
  25837. +#define CFG2_CTRLO        0x1000
  25838. +#define CFG2_RESET        0x8000
  25839. +
  25840. +#define REG_RECVEND        (dev->base_addr + 0x30)
  25841. +
  25842. +#define REG_BUFWIN        (dev->base_addr + 0x40)
  25843. +
  25844. +#define REG_RECVPTR        (dev->base_addr + 0x50)
  25845. +
  25846. +#define REG_TRANSMITPTR        (dev->base_addr + 0x60)
  25847. +
  25848. +#define REG_DMAADDR        (dev->base_addr + 0x70)
  25849. +
  25850. +/*
  25851. + * Cards transmit/receive headers
  25852. + */
  25853. +#define TX_NEXT            (0xffff)
  25854. +#define TXHDR_ENBABBLEINT    (1 << 16)
  25855. +#define TXHDR_ENCOLLISIONINT    (1 << 17)
  25856. +#define TXHDR_EN16COLLISION    (1 << 18)
  25857. +#define TXHDR_ENSUCCESS        (1 << 19)
  25858. +#define TXHDR_DATAFOLLOWS    (1 << 21)
  25859. +#define TXHDR_CHAINCONTINUE    (1 << 22)
  25860. +#define TXHDR_TRANSMIT        (1 << 23)
  25861. +#define TXSTAT_BABBLED        (1 << 24)
  25862. +#define TXSTAT_COLLISION    (1 << 25)
  25863. +#define TXSTAT_16COLLISIONS    (1 << 26)
  25864. +#define TXSTAT_DONE        (1 << 31)
  25865. +
  25866. +#define RX_NEXT            (0xffff)
  25867. +#define RXHDR_CHAINCONTINUE    (1 << 22)
  25868. +#define RXHDR_RECEIVE        (1 << 23)
  25869. +#define RXSTAT_OVERSIZE        (1 << 24)
  25870. +#define RXSTAT_CRCERROR        (1 << 25)
  25871. +#define RXSTAT_DRIBBLEERROR    (1 << 26)
  25872. +#define RXSTAT_SHORTPACKET    (1 << 27)
  25873. +#define RXSTAT_DONE        (1 << 31)
  25874. +
  25875. +
  25876. +#define TX_END          0x6000
  25877. +#define RX_START        0x6000
  25878. +#define RX_LEN          0xA000
  25879. +#define RX_END          0x10000
  25880. +#define MAX_TXED    360
  25881. +#define MAX_TX_BUFFERED    10
  25882. +
  25883. +struct dev_priv {
  25884. +    int bus_type;            /* type of bus (not currently used)     */
  25885. +    struct {
  25886. +    unsigned int command;
  25887. +    unsigned int config1;
  25888. +    unsigned int config2;
  25889. +    unsigned int transmitptr;
  25890. +    unsigned int recvptr;
  25891. +    } regs;
  25892. +    struct enet_statistics stats;
  25893. +    unsigned int txinsert;        /* address to insert next packet     */
  25894. +    unsigned int txed;            /* transmitted index in tx_ends         */
  25895. +    unsigned int txto;            /* to transmit index in tx_ends         */
  25896. +    unsigned int txbuffered;        /* number of packets currently buffered     */
  25897. +    unsigned int tx_ends[MAX_TXED];    /* addresses of transmit packets     */
  25898. +    unsigned int use;            /* 0 = card not in use, >0 packet transferring */
  25899. +    int broken;                /* 0 = ok, 1 = something went wrong     */
  25900. +};
  25901. +
  25902. +extern int    ether3_probe(struct device *dev);
  25903. +static int    ether3_probe1(struct device *dev);
  25904. +static int    ether3_open(struct device *dev);
  25905. +static int    ether3_send_packet(struct sk_buff *skb, struct device *dev);
  25906. +static void    ether3_interrupt(int irq, struct pt_regs *regs);
  25907. +static void    ether3_rx(struct device *dev, struct dev_priv *priv);
  25908. +static void    ether3_tx(struct device *dev, struct dev_priv *priv);
  25909. +static int    ether3_close(struct device *dev);
  25910. +static struct enet_statistics *ether3_get_stats(struct device *dev);
  25911. +static void    set_multicast_list(struct device *dev, int num_addrs, void *addrs);
  25912. +
  25913. +#endif
  25914. diff -urNwbB linux/arch/arm/drivers/net/plip.c linux.arm/arch/arm/drivers/net/plip.c
  25915. --- linux/arch/arm/drivers/net/plip.c    Thu Jan  1 01:00:00 1970
  25916. +++ linux.arm/arch/arm/drivers/net/plip.c    Sat Feb 24 09:36:44 1996
  25917. @@ -0,0 +1,1272 @@
  25918. +/* $Id: plip.c,v 1.15 1995/10/03 01:47:09 gniibe Exp $ */
  25919. +/* PLIP: A parallel port "network" driver for Linux. */
  25920. +/* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */
  25921. +/*
  25922. + * Authors:    Donald Becker,  <becker@super.org>
  25923. + *        Tommy Thorn, <thorn@daimi.aau.dk>
  25924. + *        Tanabe Hiroyasu, <hiro@sanpo.t.u-tokyo.ac.jp>
  25925. + *        Alan Cox, <gw4pts@gw4pts.ampr.org>
  25926. + *        Peter Bauer, <100136.3530@compuserve.com>
  25927. + *        Niibe Yutaka, <gniibe@mri.co.jp>
  25928. + *
  25929. + *        Modularization and ifreq/ifmap support by Alan Cox.
  25930. + *        Rewritten by Niibe Yutaka.
  25931. + *
  25932. + * Fixes:
  25933. + *        9-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
  25934. + *          - only claim 3 bytes of I/O space for port at 0x3bc
  25935. + *          - treat NULL return from register_netdev() as success in
  25936. + *            init_module()
  25937. + *          - added message if driver loaded as a module but no
  25938. + *            interfaces present.
  25939. + *          - release claimed I/O ports if malloc() fails during init.
  25940. + *        
  25941. + *        Niibe Yutaka
  25942. + *          - Module initialization.  You can specify I/O addr and IRQ:
  25943. + *            # insmod plip.o io=0x3bc irq=7
  25944. + *          - MTU fix.
  25945. + *          - Make sure other end is OK, before sending a packet.
  25946. + *
  25947. + *        This program is free software; you can redistribute it and/or
  25948. + *        modify it under the terms of the GNU General Public License
  25949. + *        as published by the Free Software Foundation; either version
  25950. + *        2 of the License, or (at your option) any later version.
  25951. + */
  25952. +
  25953. +/*
  25954. + * Original version and the name 'PLIP' from Donald Becker <becker@super.org>
  25955. + * inspired by Russ Nelson's parallel port packet driver.
  25956. + *
  25957. + * NOTE:
  25958. + *     Tanabe Hiroyasu had changed the protocol, and it was in Linux v1.0.
  25959. + *     Because of the necessity to communicate to DOS machines with the
  25960. + *     Crynwr packet driver, Peter Bauer changed the protocol again
  25961. + *     back to original protocol.
  25962. + *
  25963. + *     This version follows original PLIP protocol. 
  25964. + *     So, this PLIP can't communicate the PLIP of Linux v1.0.
  25965. + */
  25966. +
  25967. +/*
  25968. + *     To use with DOS box, please do (Turn on ARP switch):
  25969. + *    # ifconfig plip[0-2] arp
  25970. + */
  25971. +static const char *version = "NET3 PLIP version 2.1 gniibe@mri.co.jp\n";
  25972. +
  25973. +/*
  25974. +  Sources:
  25975. +    Ideas and protocols came from Russ Nelson's <nelson@crynwr.com>
  25976. +    "parallel.asm" parallel port packet driver.
  25977. +
  25978. +  The "Crynwr" parallel port standard specifies the following protocol:
  25979. +    Trigger by sending '0x08' (this cause interrupt on other end)
  25980. +    count-low octet
  25981. +    count-high octet
  25982. +    ... data octets
  25983. +    checksum octet
  25984. +  Each octet is sent as <wait for rx. '0x1?'> <send 0x10+(octet&0x0F)>
  25985. +            <wait for rx. '0x0?'> <send 0x00+((octet>>4)&0x0F)>
  25986. +
  25987. +  The packet is encapsulated as if it were ethernet.
  25988. +
  25989. +  The cable used is a de facto standard parallel null cable -- sold as
  25990. +  a "LapLink" cable by various places.  You'll need a 12-conductor cable to
  25991. +  make one yourself.  The wiring is:
  25992. +    SLCTIN    17 - 17
  25993. +    GROUND    25 - 25
  25994. +    D0->ERROR    2 - 15        15 - 2
  25995. +    D1->SLCT    3 - 13        13 - 3
  25996. +    D2->PAPOUT    4 - 12        12 - 4
  25997. +    D3->ACK    5 - 10        10 - 5
  25998. +    D4->BUSY    6 - 11        11 - 6
  25999. +  Do not connect the other pins.  They are
  26000. +    D5,D6,D7 are 7,8,9
  26001. +    STROBE is 1, FEED is 14, INIT is 16
  26002. +    extra grounds are 18,19,20,21,22,23,24
  26003. +*/
  26004. +
  26005. +#define NO_IRQ 255
  26006. +
  26007. +#ifdef MODULE
  26008. +#include <linux/module.h>
  26009. +#include <linux/version.h>
  26010. +#else
  26011. +#define MOD_INC_USE_COUNT
  26012. +#define MOD_DEC_USE_COUNT
  26013. +#endif
  26014. +
  26015. +#include <linux/kernel.h>
  26016. +#include <linux/sched.h>
  26017. +#include <linux/types.h>
  26018. +#include <linux/fcntl.h>
  26019. +#include <linux/interrupt.h>
  26020. +#include <linux/string.h>
  26021. +#include <linux/ptrace.h>
  26022. +#include <linux/if_ether.h>
  26023. +#include <asm/system.h>
  26024. +#include <asm/io.h>
  26025. +#include <linux/in.h>
  26026. +#include <linux/errno.h>
  26027. +#include <linux/delay.h>
  26028. +#include <linux/lp.h>
  26029. +
  26030. +#include <linux/netdevice.h>
  26031. +#include <linux/etherdevice.h>
  26032. +#include <linux/skbuff.h>
  26033. +#include <linux/if_plip.h>
  26034. +
  26035. +#include <linux/tqueue.h>
  26036. +#include <linux/ioport.h>
  26037. +#include <asm/bitops.h>
  26038. +#include <asm/irq.h>
  26039. +#include <asm/byteorder.h>
  26040. +
  26041. +/* Use 0 for production, 1 for verification, >2 for debug */
  26042. +#ifndef NET_DEBUG
  26043. +#define NET_DEBUG 1
  26044. +#endif
  26045. +static unsigned int net_debug = NET_DEBUG;
  26046. +
  26047. +/* In micro second */
  26048. +#define PLIP_DELAY_UNIT           1
  26049. +
  26050. +/* Connection time out = PLIP_TRIGGER_WAIT * PLIP_DELAY_UNIT usec */
  26051. +#define PLIP_TRIGGER_WAIT     500
  26052. +
  26053. +/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */
  26054. +#define PLIP_NIBBLE_WAIT        3000
  26055. +
  26056. +#define PAR_INTR_ON        (LP_PINITP|LP_PSELECP|LP_PINTEN)
  26057. +#define PAR_INTR_OFF        (LP_PINITP|LP_PSELECP)
  26058. +#define PAR_DATA(dev)        ((dev)->base_addr+0)
  26059. +#define PAR_STATUS(dev)        ((dev)->base_addr+1)
  26060. +#define PAR_CONTROL(dev)    ((dev)->base_addr+2)
  26061. +
  26062. +/* Bottom halfs */
  26063. +static void plip_kick_bh(struct device *dev);
  26064. +static void plip_bh(struct device *dev);
  26065. +
  26066. +/* Interrupt handler */
  26067. +static void plip_interrupt(int irq, struct pt_regs *regs);
  26068. +
  26069. +/* Functions for DEV methods */
  26070. +static int plip_rebuild_header(void *buff, struct device *dev,
  26071. +                   unsigned long raddr, struct sk_buff *skb);
  26072. +static int plip_tx_packet(struct sk_buff *skb, struct device *dev);
  26073. +static int plip_open(struct device *dev);
  26074. +static int plip_close(struct device *dev);
  26075. +static struct enet_statistics *plip_get_stats(struct device *dev);
  26076. +static int plip_config(struct device *dev, struct ifmap *map);
  26077. +static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
  26078. +
  26079. +enum plip_connection_state {
  26080. +    PLIP_CN_NONE=0,
  26081. +    PLIP_CN_RECEIVE,
  26082. +    PLIP_CN_SEND,
  26083. +    PLIP_CN_CLOSING,
  26084. +    PLIP_CN_ERROR
  26085. +};
  26086. +
  26087. +enum plip_packet_state {
  26088. +    PLIP_PK_DONE=0,
  26089. +    PLIP_PK_TRIGGER,
  26090. +    PLIP_PK_LENGTH_LSB,
  26091. +    PLIP_PK_LENGTH_MSB,
  26092. +    PLIP_PK_DATA,
  26093. +    PLIP_PK_CHECKSUM
  26094. +};
  26095. +
  26096. +enum plip_nibble_state {
  26097. +    PLIP_NB_BEGIN,
  26098. +    PLIP_NB_1,
  26099. +    PLIP_NB_2,
  26100. +};
  26101. +
  26102. +struct plip_local {
  26103. +    enum plip_packet_state state;
  26104. +    enum plip_nibble_state nibble;
  26105. +    union {
  26106. +        struct {
  26107. +#if defined(__LITTLE_ENDIAN)
  26108. +            unsigned char lsb;
  26109. +            unsigned char msb;
  26110. +#elif defined(__BIG_ENDIAN)
  26111. +            unsigned char msb;
  26112. +            unsigned char lsb;
  26113. +#else
  26114. +#error    "Please fix the endianness defines in <asm/byteorder.h>"
  26115. +#endif                        
  26116. +        } b;
  26117. +        unsigned short h;
  26118. +    } length;
  26119. +    unsigned short byte;
  26120. +    unsigned char  checksum;
  26121. +    unsigned char  data;
  26122. +    struct sk_buff *skb;
  26123. +};
  26124. +
  26125. +struct net_local {
  26126. +    struct enet_statistics enet_stats;
  26127. +    struct tq_struct immediate;
  26128. +    struct tq_struct deferred;
  26129. +    struct plip_local snd_data;
  26130. +    struct plip_local rcv_data;
  26131. +    unsigned long  trigger;
  26132. +    unsigned long  nibble;
  26133. +    enum plip_connection_state connection;
  26134. +    unsigned short timeout_count;
  26135. +    char is_deferred;
  26136. +    char iostate;
  26137. +    int (*orig_rebuild_header)(void *eth, struct device *dev,
  26138. +                   unsigned long raddr, struct sk_buff *skb);
  26139. +};
  26140. +
  26141. +#define IOSTATE(x) ((x)->iostate)
  26142. +#define RACK_STATE    0x03
  26143. +#define RACK_UNKNOWN    0x00
  26144. +#define RACK_ACTIVEHIGH    0x01
  26145. +#define RACK_ACTIVELOW    0x02
  26146. +
  26147. +#define TACK_HIGH    0x10
  26148. +#define TACK_UNKNOWN    0x20
  26149. +
  26150. +#define RESET_INTERRUPT ({ int rstirq = 0x3350058 >> 2; (void)inb (rstirq); })
  26151. +
  26152. +
  26153. +/* Entry point of PLIP driver.
  26154. +   Probe the hardware, and register/initialize the driver. */
  26155. +int
  26156. +plip_init(struct device *dev)
  26157. +{
  26158. +    struct net_local *nl;
  26159. +    int iosize = (PAR_DATA(dev) == 0x3bc) ? 3 : 8;
  26160. +
  26161. +    /* Check region before the probe */
  26162. +    if (check_region(PAR_DATA(dev), iosize) < 0)
  26163. +        return -ENODEV;
  26164. +
  26165. +    /* Check that there is something at base_addr. */
  26166. +    outb(0, PAR_DATA(dev));
  26167. +    udelay(1000);
  26168. +    if (inb(PAR_DATA(dev)) != 0)
  26169. +        return -ENODEV;
  26170. +
  26171. +    printk(version);
  26172. +    printk("%s: Parallel port at %#3lx, ", dev->name, dev->base_addr);
  26173. +    if (dev->irq != NO_IRQ) {
  26174. +        printk("using assigned IRQ %d.\n", dev->irq);
  26175. +    } else {
  26176. +        int irq = NO_IRQ;
  26177. +#ifdef MODULE
  26178. +        /* dev->irq==NO_IRQ means autoprobe, but we don't try to do so
  26179. +           with module.  We can change it by ifconfig */
  26180. +#else
  26181. +        unsigned int irqs = probe_irq_on();
  26182. +
  26183. +        outb(0x00, PAR_CONTROL(dev));
  26184. +        udelay(1000);
  26185. +        outb(PAR_INTR_OFF, PAR_CONTROL(dev));
  26186. +        outb(PAR_INTR_ON, PAR_CONTROL(dev));
  26187. +        outb(PAR_INTR_OFF, PAR_CONTROL(dev));
  26188. +        udelay(1000);
  26189. +        irq = probe_irq_off(irqs);
  26190. +#endif
  26191. +        if (irq != NO_IRQ) {
  26192. +            dev->irq = irq;
  26193. +            printk("using probed IRQ %d.\n", dev->irq);
  26194. +        } else
  26195. +            printk("failed to detect IRQ(%d) --"
  26196. +                   " Please set IRQ by ifconfig.\n", irq);
  26197. +    }
  26198. +
  26199. +    request_region(PAR_DATA(dev), iosize, dev->name);
  26200. +
  26201. +    /* Fill in the generic fields of the device structure. */
  26202. +    ether_setup(dev);
  26203. +
  26204. +    /* Then, override parts of it */
  26205. +    dev->hard_start_xmit    = plip_tx_packet;
  26206. +    dev->open        = plip_open;
  26207. +    dev->stop        = plip_close;
  26208. +    dev->get_stats         = plip_get_stats;
  26209. +    dev->set_config        = plip_config;
  26210. +    dev->do_ioctl        = plip_ioctl;
  26211. +    dev->flags            = IFF_POINTOPOINT|IFF_NOARP;
  26212. +
  26213. +    /* Set the private structure */
  26214. +    dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
  26215. +    if (dev->priv == NULL) {
  26216. +        printk(KERN_ERR "%s: out of memory\n", dev->name);
  26217. +        release_region(PAR_DATA(dev), iosize);
  26218. +        return -ENOMEM;
  26219. +    }
  26220. +    memset(dev->priv, 0, sizeof(struct net_local));
  26221. +    nl = (struct net_local *) dev->priv;
  26222. +
  26223. +    nl->orig_rebuild_header = dev->rebuild_header;
  26224. +    dev->rebuild_header     = plip_rebuild_header;
  26225. +
  26226. +    /* Initialize constants */
  26227. +    nl->trigger    = PLIP_TRIGGER_WAIT;
  26228. +    nl->nibble    = PLIP_NIBBLE_WAIT;
  26229. +    nl->iostate    = RACK_UNKNOWN | TACK_UNKNOWN | TACK_HIGH;
  26230. +
  26231. +    /* Initialize task queue structures */
  26232. +    nl->immediate.next = &tq_last;
  26233. +    nl->immediate.sync = 0;
  26234. +    nl->immediate.routine = (void *)(void *)plip_bh;
  26235. +    nl->immediate.data = dev;
  26236. +
  26237. +    nl->deferred.next = &tq_last;
  26238. +    nl->deferred.sync = 0;
  26239. +    nl->deferred.routine = (void *)(void *)plip_kick_bh;
  26240. +    nl->deferred.data = dev;
  26241. +
  26242. +    return 0;
  26243. +}
  26244. +
  26245. +/* Bottom half handler for the delayed request.
  26246. +   This routine is kicked by do_timer().
  26247. +   Request `plip_bh' to be invoked. */
  26248. +static void
  26249. +plip_kick_bh(struct device *dev)
  26250. +{
  26251. +    struct net_local *nl = (struct net_local *)dev->priv;
  26252. +
  26253. +    if (nl->is_deferred) {
  26254. +        queue_task(&nl->immediate, &tq_immediate);
  26255. +        mark_bh(IMMEDIATE_BH);
  26256. +    }
  26257. +}
  26258. +
  26259. +/* Forward declarations of internal routines */
  26260. +static int plip_none(struct device *, struct net_local *,
  26261. +             struct plip_local *, struct plip_local *);
  26262. +static int plip_receive_packet(struct device *, struct net_local *,
  26263. +                   struct plip_local *, struct plip_local *);
  26264. +static int plip_send_packet(struct device *, struct net_local *,
  26265. +                struct plip_local *, struct plip_local *);
  26266. +static int plip_connection_close(struct device *, struct net_local *,
  26267. +                 struct plip_local *, struct plip_local *);
  26268. +static int plip_error(struct device *, struct net_local *,
  26269. +              struct plip_local *, struct plip_local *);
  26270. +static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,
  26271. +                 struct plip_local *snd,
  26272. +                 struct plip_local *rcv,
  26273. +                 int error);
  26274. +
  26275. +#define OK        0
  26276. +#define TIMEOUT   1
  26277. +#define ERROR     2
  26278. +
  26279. +typedef int (*plip_func)(struct device *dev, struct net_local *nl,
  26280. +             struct plip_local *snd, struct plip_local *rcv);
  26281. +
  26282. +static plip_func connection_state_table[] =
  26283. +{
  26284. +    plip_none,
  26285. +    plip_receive_packet,
  26286. +    plip_send_packet,
  26287. +    plip_connection_close,
  26288. +    plip_error
  26289. +};
  26290. +
  26291. +/* Bottom half handler of PLIP. */
  26292. +static void
  26293. +plip_bh(struct device *dev)
  26294. +{
  26295. +    struct net_local *nl = (struct net_local *)dev->priv;
  26296. +    struct plip_local *snd = &nl->snd_data;
  26297. +    struct plip_local *rcv = &nl->rcv_data;
  26298. +    plip_func f;
  26299. +    int r;
  26300. +
  26301. +    nl->is_deferred = 0;
  26302. +    f = connection_state_table[nl->connection];
  26303. +    if ((r = (*f)(dev, nl, snd, rcv)) != OK
  26304. +        && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
  26305. +        nl->is_deferred = 1;
  26306. +        queue_task(&nl->deferred, &tq_timer);
  26307. +    }
  26308. +}
  26309. +
  26310. +static int
  26311. +plip_bh_timeout_error(struct device *dev, struct net_local *nl,
  26312. +              struct plip_local *snd, struct plip_local *rcv,
  26313. +              int error)
  26314. +{
  26315. +    unsigned char c0;
  26316. +
  26317. +    cli();
  26318. +    if (nl->connection == PLIP_CN_SEND) {
  26319. +
  26320. +        if (error != ERROR) { /* Timeout */
  26321. +            nl->timeout_count++;
  26322. +            if (snd->state == PLIP_PK_TRIGGER) {
  26323. +                if (IOSTATE(nl) & TACK_UNKNOWN)
  26324. +                    IOSTATE(nl) ^= TACK_HIGH;
  26325. +            }
  26326. +            if ((snd->state == PLIP_PK_TRIGGER
  26327. +                 && nl->timeout_count <= 10)
  26328. +                || nl->timeout_count <= 3) {
  26329. +                sti();
  26330. +                /* Try again later */
  26331. +                return TIMEOUT;
  26332. +            }
  26333. +            c0 = inb(PAR_STATUS(dev));
  26334. +            printk("%s: transmit timeout(%d,%02x)\n",
  26335. +                   dev->name, snd->state, c0);
  26336. +        }
  26337. +        nl->enet_stats.tx_errors++;
  26338. +        nl->enet_stats.tx_aborted_errors++;
  26339. +    } else if (nl->connection == PLIP_CN_RECEIVE) {
  26340. +        if (rcv->state == PLIP_PK_TRIGGER) {
  26341. +            /* Transmission was interrupted. */
  26342. +            sti();
  26343. +            return OK;
  26344. +        }
  26345. +        if (error != ERROR) { /* Timeout */
  26346. +            if (++nl->timeout_count <= 3) {
  26347. +                sti();
  26348. +                /* Try again later */
  26349. +                return TIMEOUT;
  26350. +            }
  26351. +            c0 = inb(PAR_STATUS(dev));
  26352. +            printk("%s: receive timeout(%d,%02x)\n",
  26353. +                   dev->name, rcv->state, c0);
  26354. +        }
  26355. +        nl->enet_stats.rx_dropped++;
  26356. +    }
  26357. +    rcv->state = PLIP_PK_DONE;
  26358. +    if (rcv->skb) {
  26359. +        rcv->skb->free = 1;
  26360. +        kfree_skb(rcv->skb, FREE_READ);
  26361. +        rcv->skb = NULL;
  26362. +    }
  26363. +    snd->state = PLIP_PK_DONE;
  26364. +    if (snd->skb) {
  26365. +        dev_kfree_skb(snd->skb, FREE_WRITE);
  26366. +        snd->skb = NULL;
  26367. +    }
  26368. +    disable_irq(dev->irq);
  26369. +    outb(PAR_INTR_OFF, PAR_CONTROL(dev));
  26370. +    dev->tbusy = 1;
  26371. +    nl->connection = PLIP_CN_ERROR;
  26372. +    if (IOSTATE(nl) & TACK_HIGH)
  26373. +        outb(0x00, PAR_DATA(dev));
  26374. +    else
  26375. +        outb(0x08, PAR_DATA(dev));
  26376. +    sti();
  26377. +
  26378. +    return TIMEOUT;
  26379. +}
  26380. +
  26381. +static int
  26382. +plip_none(struct device *dev, struct net_local *nl,
  26383. +      struct plip_local *snd, struct plip_local *rcv)
  26384. +{
  26385. +    return OK;
  26386. +}
  26387. +
  26388. +/* PLIP_RECEIVE --- receive a byte(two nibbles)
  26389. +   Returns OK on success, TIMEOUT on timeout */
  26390. +inline static int
  26391. +plip_receive(unsigned short nibble_timeout, unsigned short status_addr,
  26392. +         enum plip_nibble_state *ns_p, unsigned char *data_p)
  26393. +{
  26394. +    unsigned char c0, c1;
  26395. +    unsigned int cx;
  26396. +
  26397. +    switch (*ns_p) {
  26398. +    case PLIP_NB_BEGIN:
  26399. +        cx = nibble_timeout;
  26400. +        while (1) {
  26401. +            c0 = inb(status_addr);
  26402. +            udelay(PLIP_DELAY_UNIT);
  26403. +            if ((c0 & 0x80) == 0) {
  26404. +                c1 = inb(status_addr);
  26405. +                if (c0 == c1)
  26406. +                    break;
  26407. +            }
  26408. +            if (--cx == 0)
  26409. +                return TIMEOUT;
  26410. +        }
  26411. +        *data_p = (c0 >> 3) & 0x0f;
  26412. +        outb(0x10, --status_addr); /* send ACK */
  26413. +        status_addr++;
  26414. +        *ns_p = PLIP_NB_1;
  26415. +
  26416. +    case PLIP_NB_1:
  26417. +        cx = nibble_timeout;
  26418. +        while (1) {
  26419. +            c0 = inb(status_addr);
  26420. +            udelay(PLIP_DELAY_UNIT);
  26421. +            if (c0 & 0x80) {
  26422. +                c1 = inb(status_addr);
  26423. +                if (c0 == c1)
  26424. +                    break;
  26425. +            }
  26426. +            if (--cx == 0)
  26427. +                return TIMEOUT;
  26428. +        }
  26429. +        *data_p |= (c0 << 1) & 0xf0;
  26430. +        outb(0x00, --status_addr); /* send ACK */
  26431. +        status_addr++;
  26432. +        *ns_p = PLIP_NB_BEGIN;
  26433. +    case PLIP_NB_2:
  26434. +        break;
  26435. +    }
  26436. +    return OK;
  26437. +}
  26438. +
  26439. +/* PLIP_RECEIVE_PACKET --- receive a packet */
  26440. +static int
  26441. +plip_receive_packet(struct device *dev, struct net_local *nl,
  26442. +            struct plip_local *snd, struct plip_local *rcv)
  26443. +{
  26444. +    unsigned short status_addr = PAR_STATUS(dev);
  26445. +    unsigned short nibble_timeout = nl->nibble;
  26446. +    unsigned char *lbuf;
  26447. +
  26448. +    switch (rcv->state) {
  26449. +    case PLIP_PK_TRIGGER:
  26450. +        disable_irq(dev->irq);
  26451. +        outb(PAR_INTR_OFF, PAR_CONTROL(dev));
  26452. +        dev->interrupt = 0;
  26453. +        if (IOSTATE(nl) & TACK_HIGH)
  26454. +            outb(0x01, PAR_DATA(dev)); /* send ACK */
  26455. +        else
  26456. +            outb(0x09, PAR_DATA(dev)); /* send ACK */
  26457. +        if (net_debug > 2)
  26458. +            printk("%s: receive start\n", dev->name);
  26459. +        rcv->state = PLIP_PK_LENGTH_LSB;
  26460. +        rcv->nibble = PLIP_NB_BEGIN;
  26461. +
  26462. +    case PLIP_PK_LENGTH_LSB:
  26463. +        if (snd->state != PLIP_PK_DONE) {
  26464. +            if (plip_receive(nl->trigger, status_addr,
  26465. +                     &rcv->nibble, &rcv->length.b.lsb)) {
  26466. +                /* collision, here dev->tbusy == 1 */
  26467. +                rcv->state = PLIP_PK_DONE;
  26468. +                nl->is_deferred = 1;
  26469. +                nl->connection = PLIP_CN_SEND;
  26470. +                queue_task(&nl->deferred, &tq_timer);
  26471. +                outb(PAR_INTR_ON, PAR_CONTROL(dev));
  26472. +                RESET_INTERRUPT;
  26473. +                enable_irq(dev->irq);
  26474. +                return OK;
  26475. +            }
  26476. +        } else {
  26477. +            if (plip_receive(nibble_timeout, status_addr,
  26478. +                     &rcv->nibble, &rcv->length.b.lsb))
  26479. +                return TIMEOUT;
  26480. +        }
  26481. +        rcv->state = PLIP_PK_LENGTH_MSB;
  26482. +
  26483. +    case PLIP_PK_LENGTH_MSB:
  26484. +        if (plip_receive(nibble_timeout, status_addr,
  26485. +                 &rcv->nibble, &rcv->length.b.msb))
  26486. +            return TIMEOUT;
  26487. +        if (rcv->length.h > dev->mtu + dev->hard_header_len
  26488. +            || rcv->length.h < 8) {
  26489. +            printk("%s: bogus packet size %d.\n", dev->name, rcv->length.h);
  26490. +            return ERROR;
  26491. +        }
  26492. +        /* Malloc up new buffer. */
  26493. +        rcv->skb = dev_alloc_skb(rcv->length.h);
  26494. +        if (rcv->skb == NULL) {
  26495. +            printk("%s: Memory squeeze.\n", dev->name);
  26496. +            return ERROR;
  26497. +        }
  26498. +        skb_reserve (rcv->skb, -2);
  26499. +        skb_put(rcv->skb,rcv->length.h);
  26500. +        rcv->skb->dev = dev;
  26501. +        rcv->state = PLIP_PK_DATA;
  26502. +        rcv->byte = 0;
  26503. +        rcv->checksum = 0;
  26504. +
  26505. +    case PLIP_PK_DATA:
  26506. +        lbuf = rcv->skb->data;
  26507. +        do
  26508. +            if (plip_receive(nibble_timeout, status_addr, 
  26509. +                     &rcv->nibble, &lbuf[rcv->byte]))
  26510. +                return TIMEOUT;
  26511. +        while (++rcv->byte < rcv->length.h);
  26512. +        do
  26513. +            rcv->checksum += lbuf[--rcv->byte];
  26514. +        while (rcv->byte);
  26515. +        rcv->state = PLIP_PK_CHECKSUM;
  26516. +
  26517. +    case PLIP_PK_CHECKSUM:
  26518. +        if (plip_receive(nibble_timeout, status_addr,
  26519. +                 &rcv->nibble, &rcv->data))
  26520. +            return TIMEOUT;
  26521. +        if (rcv->data != rcv->checksum) {
  26522. +            nl->enet_stats.rx_crc_errors++;
  26523. +            if (net_debug)
  26524. +                printk("%s: checksum error\n", dev->name);
  26525. +            return ERROR;
  26526. +        }
  26527. +        rcv->state = PLIP_PK_DONE;
  26528. +
  26529. +    case PLIP_PK_DONE:
  26530. +        /* Inform the upper layer for the arrival of a packet. */
  26531. +        rcv->skb->protocol=eth_type_trans(rcv->skb, dev);
  26532. +        netif_rx(rcv->skb);
  26533. +        nl->enet_stats.rx_packets++;
  26534. +        rcv->skb = NULL;
  26535. +        if (net_debug > 2)
  26536. +            printk("%s: receive end\n", dev->name);
  26537. +
  26538. +        /* Close the connection. */
  26539. +        if (IOSTATE(nl) & TACK_HIGH)
  26540. +            outb (0x00, PAR_DATA(dev));
  26541. +        else
  26542. +            outb (0x08, PAR_DATA(dev));
  26543. +        cli();
  26544. +        if (snd->state != PLIP_PK_DONE) {
  26545. +            nl->connection = PLIP_CN_SEND;
  26546. +            sti();
  26547. +            queue_task(&nl->immediate, &tq_immediate);
  26548. +            outb(PAR_INTR_ON, PAR_CONTROL(dev));
  26549. +            RESET_INTERRUPT;
  26550. +            enable_irq(dev->irq);
  26551. +            return OK;
  26552. +        } else {
  26553. +            nl->connection = PLIP_CN_NONE;
  26554. +            sti();
  26555. +            outb(PAR_INTR_ON, PAR_CONTROL(dev));
  26556. +            RESET_INTERRUPT;
  26557. +            enable_irq(dev->irq);
  26558. +            return OK;
  26559. +        }
  26560. +    }
  26561. +    return OK;
  26562. +}
  26563. +
  26564. +/* PLIP_SEND --- send a byte (two nibbles) 
  26565. +   Returns OK on success, TIMEOUT when timeout    */
  26566. +inline static int
  26567. +plip_send(unsigned short nibble_timeout, unsigned short data_addr,
  26568. +      enum plip_nibble_state *ns_p, unsigned char data)
  26569. +{
  26570. +    unsigned char c0;
  26571. +    unsigned int cx;
  26572. +
  26573. +    switch (*ns_p) {
  26574. +    case PLIP_NB_BEGIN:
  26575. +        outb((data & 0x0f), data_addr);
  26576. +        *ns_p = PLIP_NB_1;
  26577. +
  26578. +    case PLIP_NB_1:
  26579. +        outb(0x10 | (data & 0x0f), data_addr);
  26580. +        cx = nibble_timeout;
  26581. +        data_addr++;
  26582. +        while (1) {
  26583. +            c0 = inb(data_addr);
  26584. +            if ((c0 & 0x80) == 0) 
  26585. +                break;
  26586. +            if (--cx == 0)
  26587. +                return TIMEOUT;
  26588. +            udelay(PLIP_DELAY_UNIT);
  26589. +        }
  26590. +        outb(0x10 | (data >> 4), --data_addr);
  26591. +        *ns_p = PLIP_NB_2;
  26592. +
  26593. +    case PLIP_NB_2:
  26594. +        outb((data >> 4), data_addr);
  26595. +        data_addr++;
  26596. +        cx = nibble_timeout;
  26597. +        while (1) {
  26598. +            c0 = inb(data_addr);
  26599. +            if (c0 & 0x80)
  26600. +                break;
  26601. +            if (--cx == 0)
  26602. +                return TIMEOUT;
  26603. +            udelay(PLIP_DELAY_UNIT);
  26604. +        }
  26605. +        data_addr--;
  26606. +        *ns_p = PLIP_NB_BEGIN;
  26607. +        return OK;
  26608. +    }
  26609. +    return OK;
  26610. +}
  26611. +
  26612. +/* PLIP_SEND_PACKET --- send a packet */
  26613. +static int
  26614. +plip_send_packet(struct device *dev, struct net_local *nl,
  26615. +         struct plip_local *snd, struct plip_local *rcv)
  26616. +{
  26617. +    unsigned short data_addr = PAR_DATA(dev);
  26618. +    unsigned short nibble_timeout = nl->nibble;
  26619. +    unsigned char *lbuf;
  26620. +    unsigned char c0;
  26621. +    unsigned int cx;
  26622. +
  26623. +    if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
  26624. +        printk("%s: send skb lost\n", dev->name);
  26625. +        snd->state = PLIP_PK_DONE;
  26626. +        snd->skb = NULL;
  26627. +        return ERROR;
  26628. +    }
  26629. +
  26630. +    switch (snd->state) {
  26631. +    case PLIP_PK_TRIGGER:
  26632. +        switch (IOSTATE(nl) & RACK_STATE) {
  26633. +            case RACK_UNKNOWN: /* we don't know the active edge of ACK */
  26634. +                if ((inb(PAR_STATUS(dev)) & 0xb8) != 0x80)
  26635. +                    return TIMEOUT;
  26636. +                break;
  26637. +
  26638. +            case RACK_ACTIVEHIGH: /* PC-style intr when ACK 0 -> 1 */
  26639. +                if ((inb(PAR_STATUS(dev)) & 0xf8) != 0x80)
  26640. +                    return TIMEOUT;
  26641. +                break;
  26642. +
  26643. +            case RACK_ACTIVELOW: /* ARM-style intr when ACK 1 -> 0 */
  26644. +                if ((inb(PAR_STATUS(dev)) & 0xf8) != 0xc0)
  26645. +                    return TIMEOUT;
  26646. +                break;
  26647. +        }
  26648. +
  26649. +        /* Trigger remote rx interrupt. */
  26650. +        if (IOSTATE(nl) & TACK_HIGH)
  26651. +            outb(0x08, data_addr);
  26652. +        else
  26653. +            outb(0x00, data_addr);
  26654. +        cx = nl->trigger;
  26655. +        while (1) {
  26656. +            udelay(PLIP_DELAY_UNIT);
  26657. +            cli();
  26658. +            if (nl->connection == PLIP_CN_RECEIVE) {
  26659. +                sti();
  26660. +                /* interrupted */
  26661. +                nl->enet_stats.collisions++;
  26662. +                if (net_debug > 1)
  26663. +                    printk("%s: collision.\n", dev->name);
  26664. +                return OK;
  26665. +            }
  26666. +            c0 = inb(PAR_STATUS(dev));
  26667. +            if (c0 & 0x08) {
  26668. +                disable_irq(dev->irq);
  26669. +                outb(PAR_INTR_OFF, PAR_CONTROL(dev));
  26670. +                if (net_debug > 2)
  26671. +                    printk("%s: send start\n", dev->name);
  26672. +                snd->state = PLIP_PK_LENGTH_LSB;
  26673. +                snd->nibble = PLIP_NB_BEGIN;
  26674. +                nl->timeout_count = 0;
  26675. +                sti();
  26676. +                break;
  26677. +            }
  26678. +            sti();
  26679. +            if (--cx == 0) {
  26680. +                if (IOSTATE(nl) & TACK_HIGH)
  26681. +                    outb(0x00, data_addr);
  26682. +                else
  26683. +                    outb(0x08, data_addr);
  26684. +                return TIMEOUT;
  26685. +            }
  26686. +        }
  26687. +        if (IOSTATE(nl) & TACK_UNKNOWN) {
  26688. +            if (net_debug > 1)
  26689. +                printk ("%s: remote ACK active %s\n", dev->name, IOSTATE(nl) & TACK_HIGH ? "high" : "low");
  26690. +            IOSTATE(nl) &= ~TACK_UNKNOWN;
  26691. +        }
  26692. +
  26693. +    case PLIP_PK_LENGTH_LSB:
  26694. +        if (plip_send(nibble_timeout, data_addr,
  26695. +                  &snd->nibble, snd->length.b.lsb))
  26696. +            return TIMEOUT;
  26697. +        snd->state = PLIP_PK_LENGTH_MSB;
  26698. +
  26699. +    case PLIP_PK_LENGTH_MSB:
  26700. +        if (plip_send(nibble_timeout, data_addr,
  26701. +                  &snd->nibble, snd->length.b.msb))
  26702. +            return TIMEOUT;
  26703. +        snd->state = PLIP_PK_DATA;
  26704. +        snd->byte = 0;
  26705. +        snd->checksum = 0;
  26706. +
  26707. +    case PLIP_PK_DATA:
  26708. +        do
  26709. +            if (plip_send(nibble_timeout, data_addr,
  26710. +                      &snd->nibble, lbuf[snd->byte]))
  26711. +                return TIMEOUT;
  26712. +        while (++snd->byte < snd->length.h);
  26713. +        do
  26714. +            snd->checksum += lbuf[--snd->byte];
  26715. +        while (snd->byte);
  26716. +        snd->state = PLIP_PK_CHECKSUM;
  26717. +
  26718. +    case PLIP_PK_CHECKSUM:
  26719. +        if (plip_send(nibble_timeout, data_addr,
  26720. +                  &snd->nibble, snd->checksum))
  26721. +            return TIMEOUT;
  26722. +
  26723. +        dev_kfree_skb(snd->skb, FREE_WRITE);
  26724. +        nl->enet_stats.tx_packets++;
  26725. +        snd->state = PLIP_PK_DONE;
  26726. +
  26727. +    case PLIP_PK_DONE:
  26728. +        /* Close the connection */
  26729. +        if (IOSTATE(nl) & TACK_HIGH)
  26730. +            outb (0x00, data_addr);
  26731. +        else
  26732. +            outb (0x08, data_addr);
  26733. +        snd->skb = NULL;
  26734. +        if (net_debug > 2)
  26735. +            printk("%s: send end\n", dev->name);
  26736. +        nl->connection = PLIP_CN_CLOSING;
  26737. +        nl->is_deferred = 1;
  26738. +        queue_task(&nl->deferred, &tq_timer);
  26739. +        outb(PAR_INTR_ON, PAR_CONTROL(dev));
  26740. +        RESET_INTERRUPT;
  26741. +        enable_irq(dev->irq);
  26742. +        return OK;
  26743. +    }
  26744. +    return OK;
  26745. +}
  26746. +
  26747. +static int
  26748. +plip_connection_close(struct device *dev, struct net_local *nl,
  26749. +              struct plip_local *snd, struct plip_local *rcv)
  26750. +{
  26751. +    cli();
  26752. +    if (nl->connection == PLIP_CN_CLOSING) {
  26753. +        nl->connection = PLIP_CN_NONE;
  26754. +        dev->tbusy = 0;
  26755. +        mark_bh(NET_BH);
  26756. +    }
  26757. +    sti();
  26758. +    return OK;
  26759. +}
  26760. +
  26761. +/* PLIP_ERROR --- wait till other end settled */
  26762. +static int
  26763. +plip_error(struct device *dev, struct net_local *nl,
  26764. +       struct plip_local *snd, struct plip_local *rcv)
  26765. +{
  26766. +    unsigned char status;
  26767. +
  26768. +    status = inb(PAR_STATUS(dev));
  26769. +    switch (IOSTATE(nl) & RACK_STATE) {
  26770. +        case RACK_UNKNOWN:    /* we can't reset the interface */
  26771. +            nl->is_deferred = 1;
  26772. +            queue_task(&nl->deferred, &tq_timer);
  26773. +            return OK;
  26774. +
  26775. +        case RACK_ACTIVEHIGH:    /* PC-style */
  26776. +            if ((status & 0xf8) != 0x80) {
  26777. +                nl->is_deferred = 1;
  26778. +                queue_task(&nl->deferred, &tq_timer);
  26779. +                return OK;
  26780. +            }
  26781. +            break;
  26782. +        case RACK_ACTIVELOW:    /* ARM-style */
  26783. +            if ((status & 0xf8) != 0xc0) {
  26784. +                nl->is_deferred = 1;
  26785. +                queue_task(&nl->deferred, &tq_timer);
  26786. +                return OK;
  26787. +            }
  26788. +            break;
  26789. +    }
  26790. +    if (net_debug > 2)
  26791. +        printk("%s: reset interface.\n", dev->name);
  26792. +    nl->connection = PLIP_CN_NONE;
  26793. +    dev->tbusy = 0;
  26794. +    dev->interrupt = 0;
  26795. +    outb(PAR_INTR_ON, PAR_CONTROL(dev));
  26796. +    RESET_INTERRUPT;
  26797. +    enable_irq(dev->irq);
  26798. +    mark_bh(NET_BH);
  26799. +    return OK;
  26800. +}
  26801. +
  26802. +/* Handle the parallel port interrupts. */
  26803. +static void
  26804. +plip_interrupt(int irq, struct pt_regs * regs)
  26805. +{
  26806. +    struct device *dev = (struct device *) irq2dev_map[irq];
  26807. +    struct net_local *nl = (struct net_local *)dev->priv;
  26808. +    struct plip_local *rcv = &nl->rcv_data;
  26809. +    unsigned char c0;
  26810. +
  26811. +    RESET_INTERRUPT;
  26812. +
  26813. +    if (dev == NULL) {
  26814. +        printk ("plip_interrupt: irq %d for unknown device.\n", irq);
  26815. +        return;
  26816. +    }
  26817. +
  26818. +    if (dev->interrupt)
  26819. +        return;
  26820. +
  26821. +    c0 = inb(PAR_STATUS(dev));
  26822. +    switch (IOSTATE(nl) & RACK_STATE) {
  26823. +        case RACK_UNKNOWN:    /* don't know */
  26824. +            /*
  26825. +             * Here, we rely on the first interrupt being correct
  26826. +             * and not spurious...  This is only used if we don't know
  26827. +             * which edge that the ACK interrupt triggers on.
  26828. +             */
  26829. +            if ((c0 & 0xf8) == 0xc0) {
  26830. +                IOSTATE(nl) = (IOSTATE(nl) & ~RACK_STATE) | RACK_ACTIVEHIGH;
  26831. +                printk ("%s: ACK active high\n", dev->name);
  26832. +            } else
  26833. +            if ((c0 & 0xf8) == 0x80) {
  26834. +                IOSTATE(nl) = (IOSTATE(nl) & ~RACK_STATE) | RACK_ACTIVELOW;
  26835. +                printk ("%s: ACK active low\n", dev->name);
  26836. +            } else {
  26837. +                if (net_debug > 1)
  26838. +                    printk ("%s: spurious interrupt\n", dev->name);
  26839. +                return;
  26840. +            }
  26841. +            break;
  26842. +
  26843. +        case RACK_ACTIVEHIGH:    /* ACK intr when ACK 0 -> 1 */
  26844. +            if ((c0 & 0xf8) != 0xc0) {
  26845. +                if (net_debug > 1)
  26846. +                    printk ("%s: spurious interrupt\n", dev->name);
  26847. +                return;
  26848. +            }
  26849. +            break;
  26850. +
  26851. +        case RACK_ACTIVELOW:    /* ACK intr when ACK 1 -> 0 */
  26852. +            if ((c0 & 0xf8) != 0x80) {
  26853. +                if (net_debug > 1)
  26854. +                    printk ("%s: spurious interrupt\n", dev->name);
  26855. +                return;
  26856. +            }
  26857. +            break;
  26858. +    }
  26859. +    dev->interrupt = 1;
  26860. +    if (net_debug > 3)
  26861. +        printk("%s: interrupt.\n", dev->name);
  26862. +
  26863. +    cli();
  26864. +    switch (nl->connection) {
  26865. +    case PLIP_CN_CLOSING:
  26866. +        dev->tbusy = 0;
  26867. +    case PLIP_CN_NONE:
  26868. +    case PLIP_CN_SEND:
  26869. +        dev->last_rx = jiffies;
  26870. +        rcv->state = PLIP_PK_TRIGGER;
  26871. +        nl->connection = PLIP_CN_RECEIVE;
  26872. +        nl->timeout_count = 0;
  26873. +        queue_task(&nl->immediate, &tq_immediate);
  26874. +        mark_bh(IMMEDIATE_BH);
  26875. +        sti();
  26876. +        break;
  26877. +
  26878. +    case PLIP_CN_RECEIVE:
  26879. +        sti();
  26880. +        printk("%s: receive interrupt when receiving packet\n", dev->name);
  26881. +        break;
  26882. +
  26883. +    case PLIP_CN_ERROR:
  26884. +        sti();
  26885. +        printk("%s: receive interrupt in error state\n", dev->name);
  26886. +        break;
  26887. +    }
  26888. +}
  26889. +
  26890. +/* We don't need to send arp, for plip is point-to-point. */
  26891. +static int
  26892. +plip_rebuild_header(void *buff, struct device *dev, unsigned long dst,
  26893. +            struct sk_buff *skb)
  26894. +{
  26895. +    struct net_local *nl = (struct net_local *)dev->priv;
  26896. +    struct ethhdr *eth = (struct ethhdr *)buff;
  26897. +    int i;
  26898. +
  26899. +    if ((dev->flags & IFF_NOARP)==0)
  26900. +        return nl->orig_rebuild_header(buff, dev, dst, skb);
  26901. +
  26902. +    if (eth->h_proto != htons(ETH_P_IP)) {
  26903. +        printk("plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
  26904. +        memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
  26905. +        return 0;
  26906. +    }
  26907. +
  26908. +    for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
  26909. +        eth->h_dest[i] = 0xfc;
  26910. +    memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long));
  26911. +    return 0;
  26912. +}
  26913. +
  26914. +static int
  26915. +plip_tx_packet(struct sk_buff *skb, struct device *dev)
  26916. +{
  26917. +    struct net_local *nl = (struct net_local *)dev->priv;
  26918. +    struct plip_local *snd = &nl->snd_data;
  26919. +
  26920. +    if (dev->tbusy)
  26921. +        return 1;
  26922. +
  26923. +    /* If some higher layer thinks we've missed an tx-done interrupt
  26924. +       we are passed NULL. Caution: dev_tint() handles the cli()/sti()
  26925. +       itself. */
  26926. +    if (skb == NULL) {
  26927. +        dev_tint(dev);
  26928. +        return 0;
  26929. +    }
  26930. +
  26931. +    if (set_bit(0, (void*)&dev->tbusy) != 0) {
  26932. +        printk("%s: Transmitter access conflict.\n", dev->name);
  26933. +        return 1;
  26934. +    }
  26935. +
  26936. +    if (skb->len > dev->mtu + dev->hard_header_len) {
  26937. +        printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
  26938. +        dev->tbusy = 0;
  26939. +        return 0;
  26940. +    }
  26941. +
  26942. +    if (net_debug > 2)
  26943. +        printk("%s: send request\n", dev->name);
  26944. +
  26945. +    cli();
  26946. +    dev->trans_start = jiffies;
  26947. +    snd->skb = skb;
  26948. +    snd->length.h = skb->len;
  26949. +    snd->state = PLIP_PK_TRIGGER;
  26950. +    if (nl->connection == PLIP_CN_NONE) {
  26951. +        nl->connection = PLIP_CN_SEND;
  26952. +        nl->timeout_count = 0;
  26953. +    }
  26954. +    queue_task(&nl->immediate, &tq_immediate);
  26955. +    mark_bh(IMMEDIATE_BH);
  26956. +    sti();
  26957. +
  26958. +    return 0;
  26959. +}
  26960. +
  26961. +/* Open/initialize the board.  This is called (in the current kernel)
  26962. +   sometime after booting when the 'ifconfig' program is run.
  26963. +
  26964. +   This routine gets exclusive access to the parallel port by allocating
  26965. +   its IRQ line.
  26966. + */
  26967. +static int
  26968. +plip_open(struct device *dev)
  26969. +{
  26970. +    struct net_local *nl = (struct net_local *)dev->priv;
  26971. +    int i;
  26972. +
  26973. +    if (dev->irq == NO_IRQ) {
  26974. +        printk("%s: IRQ is not set.  Please set it by ifconfig.\n", dev->name);
  26975. +        return -EAGAIN;
  26976. +    }
  26977. +    cli();
  26978. +    if (request_irq(dev->irq , plip_interrupt, 0, dev->name) != 0) {
  26979. +        sti();
  26980. +        printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
  26981. +        return -EAGAIN;
  26982. +    }
  26983. +    irq2dev_map[dev->irq] = dev;
  26984. +    sti();
  26985. +
  26986. +    /* Clear the data port. */
  26987. +    if (IOSTATE(nl) & TACK_HIGH)
  26988. +        outb (0x00, PAR_DATA(dev));
  26989. +    else
  26990. +        outb (0x08, PAR_DATA(dev));
  26991. +
  26992. +    /* Enable rx interrupt. */
  26993. +    cli ();
  26994. +    outb(PAR_INTR_ON, PAR_CONTROL(dev));
  26995. +    RESET_INTERRUPT;
  26996. +    sti ();
  26997. +
  26998. +    /* Initialize the state machine. */
  26999. +    nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;
  27000. +    nl->rcv_data.skb = nl->snd_data.skb = NULL;
  27001. +    nl->connection = PLIP_CN_NONE;
  27002. +    nl->is_deferred = 0;
  27003. +    nl->iostate = RACK_ACTIVELOW | TACK_UNKNOWN | TACK_HIGH;
  27004. +
  27005. +    /* Fill in the MAC-level header. */
  27006. +    for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
  27007. +        dev->dev_addr[i] = 0xfc;
  27008. +    memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(unsigned long));
  27009. +
  27010. +    dev->interrupt = 0;
  27011. +    dev->start = 1;
  27012. +    dev->tbusy = 0;
  27013. +    MOD_INC_USE_COUNT;
  27014. +    return 0;
  27015. +}
  27016. +
  27017. +/* The inverse routine to plip_open (). */
  27018. +static int
  27019. +plip_close(struct device *dev)
  27020. +{
  27021. +    struct net_local *nl = (struct net_local *)dev->priv;
  27022. +    struct plip_local *snd = &nl->snd_data;
  27023. +    struct plip_local *rcv = &nl->rcv_data;
  27024. +
  27025. +    dev->tbusy = 1;
  27026. +    dev->start = 0;
  27027. +    cli();
  27028. +    free_irq(dev->irq);
  27029. +    irq2dev_map[dev->irq] = NULL;
  27030. +    nl->is_deferred = 0;
  27031. +    nl->connection = PLIP_CN_NONE;
  27032. +    sti();
  27033. +    if (IOSTATE(nl) & TACK_HIGH)
  27034. +        outb(0x00, PAR_DATA(dev));
  27035. +    else
  27036. +        outb(0x08, PAR_DATA(dev));
  27037. +
  27038. +    snd->state = PLIP_PK_DONE;
  27039. +    if (snd->skb) {
  27040. +        dev_kfree_skb(snd->skb, FREE_WRITE);
  27041. +        snd->skb = NULL;
  27042. +    }
  27043. +    rcv->state = PLIP_PK_DONE;
  27044. +    if (rcv->skb) {
  27045. +        rcv->skb->free = 1;
  27046. +        kfree_skb(rcv->skb, FREE_READ);
  27047. +        rcv->skb = NULL;
  27048. +    }
  27049. +
  27050. +    /* Reset. */
  27051. +    outb(0x00, PAR_CONTROL(dev));
  27052. +    MOD_DEC_USE_COUNT;
  27053. +    return 0;
  27054. +}
  27055. +
  27056. +static struct enet_statistics *
  27057. +plip_get_stats(struct device *dev)
  27058. +{
  27059. +    struct net_local *nl = (struct net_local *)dev->priv;
  27060. +    struct enet_statistics *r = &nl->enet_stats;
  27061. +
  27062. +    return r;
  27063. +}
  27064. +
  27065. +static int
  27066. +plip_config(struct device *dev, struct ifmap *map)
  27067. +{
  27068. +    if (dev->flags & IFF_UP)
  27069. +        return -EBUSY;
  27070. +
  27071. +    if (map->base_addr != (unsigned long)-1
  27072. +        && map->base_addr != dev->base_addr)
  27073. +        printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
  27074. +
  27075. +    if (map->irq != (unsigned char)-1)
  27076. +        dev->irq = map->irq;
  27077. +    return 0;
  27078. +}
  27079. +
  27080. +static int
  27081. +plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
  27082. +{
  27083. +    struct net_local *nl = (struct net_local *) dev->priv;
  27084. +    struct plipconf *pc = (struct plipconf *) &rq->ifr_data;
  27085. +    
  27086. +    switch(pc->pcmd) {
  27087. +    case PLIP_GET_TIMEOUT:
  27088. +        pc->trigger = nl->trigger;
  27089. +        pc->nibble  = nl->nibble;
  27090. +        break;
  27091. +    case PLIP_SET_TIMEOUT:
  27092. +        nl->trigger = pc->trigger;
  27093. +        nl->nibble  = pc->nibble;
  27094. +        break;
  27095. +    default:
  27096. +        return -EOPNOTSUPP;
  27097. +    }
  27098. +    return 0;
  27099. +}
  27100. +
  27101. +#ifdef MODULE
  27102. +char kernel_version[] = UTS_RELEASE;
  27103. +int io[] = {0, 0, 0};
  27104. +int irq[] = {NO_IRQ, NO_IRQ, NO_IRQ};
  27105. +
  27106. +static struct device dev_plip[] = {
  27107. +    {
  27108. +        "plip0",
  27109. +        0, 0, 0, 0,        /* memory */
  27110. +        0x3BC, NO_IRQ,        /* base, irq */
  27111. +        0, 0, 0, NULL, plip_init 
  27112. +    },
  27113. +    {
  27114. +        "plip1",
  27115. +        0, 0, 0, 0,        /* memory */
  27116. +        0x378, NO_IRQ,        /* base, irq */
  27117. +        0, 0, 0, NULL, plip_init 
  27118. +    },
  27119. +    {
  27120. +        "plip2",
  27121. +        0, 0, 0, 0,        /* memory */
  27122. +        0x278, 0,        /* base, irq */
  27123. +        0, 0, 0, NULL, plip_init 
  27124. +    }
  27125. +};
  27126. +
  27127. +int
  27128. +init_module(void)
  27129. +{
  27130. +    int no_parameters=1;
  27131. +    int devices=0;
  27132. +    int i;
  27133. +
  27134. +    /* When user feeds parameters, use them */
  27135. +    for (i=0; i < 3; i++) {
  27136. +        int specified=0;
  27137. +
  27138. +        if (io[i] != 0) {
  27139. +            dev_plip[i].base_addr = io[i];
  27140. +            specified++;
  27141. +        }
  27142. +        if (irq[i] != NO_IRQ) {
  27143. +            dev_plip[i].irq = irq[i];
  27144. +            specified++;
  27145. +        }
  27146. +        if (specified) {
  27147. +            if (register_netdev(&dev_plip[i]) != 0) {
  27148. +                printk(KERN_INFO "plip%d: Not found\n", i);
  27149. +                return -EIO;
  27150. +            }
  27151. +            no_parameters = 0;
  27152. +        }
  27153. +    }
  27154. +    if (!no_parameters)
  27155. +        return 0;
  27156. +
  27157. +    /* No parameters.  Default action is probing all interfaces. */
  27158. +    for (i=0; i < 3; i++) { 
  27159. +        if (register_netdev(&dev_plip[i]) == 0)
  27160. +            devices++;
  27161. +    }
  27162. +    if (devices == 0) {
  27163. +        printk(KERN_INFO "plip: no interfaces found\n");
  27164. +        return -EIO;
  27165. +    }
  27166. +    return 0;
  27167. +}
  27168. +
  27169. +void
  27170. +cleanup_module(void)
  27171. +{
  27172. +    int i;
  27173. +
  27174. +    for (i=0; i < 3; i++) {
  27175. +        if (dev_plip[i].priv) {
  27176. +            unregister_netdev(&dev_plip[i]);
  27177. +            release_region(PAR_DATA(&dev_plip[i]), (PAR_DATA(&dev_plip[i]) == 0x3bc)? 3 : 8);
  27178. +            kfree_s(dev_plip[i].priv, sizeof(struct net_local));
  27179. +            dev_plip[i].priv = NULL;
  27180. +        }
  27181. +    }
  27182. +}
  27183. +#endif /* MODULE */
  27184. +
  27185. +/*
  27186. + * Local variables:
  27187. + * compile-command: "gcc -DMODULE -DCONFIG_MODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c plip.c"
  27188. + * End:
  27189. + */
  27190. diff -urNwbB linux/arch/arm/drivers/net/ppp.c linux.arm/arch/arm/drivers/net/ppp.c
  27191. --- linux/arch/arm/drivers/net/ppp.c    Thu Jan  1 01:00:00 1970
  27192. +++ linux.arm/arch/arm/drivers/net/ppp.c    Sat Feb 24 09:36:53 1996
  27193. @@ -0,0 +1,3634 @@
  27194. +/*  PPP for Linux
  27195. + *
  27196. + *  Michael Callahan <callahan@maths.ox.ac.uk>
  27197. + *  Al Longyear <longyear@netcom.com>
  27198. + *
  27199. + *  Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
  27200. + *  ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
  27201. + *
  27202. + *  ==FILEVERSION 7==
  27203. + *
  27204. + *  NOTE TO MAINTAINERS:
  27205. + *     If you modify this file at all, increment the number above.
  27206. + *     ppp.c is shipped with a PPP distribution as well as with the kernel;
  27207. + *     if everyone increases the FILEVERSION number above, then scripts
  27208. + *     can do the right thing when deciding whether to install a new ppp.c
  27209. + *     file.  Don't change the format of that line otherwise, so the
  27210. + *     installation script can recognize it.
  27211. + */
  27212. +
  27213. +/*
  27214. +   Sources:
  27215. +
  27216. +   slip.c
  27217. +
  27218. +   RFC1331: The Point-to-Point Protocol (PPP) for the Transmission of
  27219. +   Multi-protocol Datagrams over Point-to-Point Links
  27220. +
  27221. +   RFC1332: IPCP
  27222. +
  27223. +   ppp-2.0
  27224. +
  27225. +   Flags for this module (any combination is acceptable for testing.):
  27226. +
  27227. +   OPTIMIZE_FLAG_TIME - Number of jiffies to force sending of leading flag
  27228. +            character. This is normally set to ((HZ * 3) / 2).
  27229. +            This is 1.5 seconds. If zero then the leading
  27230. +            flag is always sent.
  27231. +
  27232. +   CHECK_CHARACTERS   - Enable the checking on all received characters for
  27233. +            8 data bits, no parity. This adds a small amount of
  27234. +            processing for each received character.
  27235. +            
  27236. +   NEW_SKBUFF          - Use NET3.020 sk_buff's
  27237. +*/
  27238. +
  27239. +/* #define NEW_SKBUFF        1 */
  27240. +#define OPTIMIZE_FLAG_TIME    ((HZ * 3)/2)
  27241. +
  27242. +#define CHECK_CHARACTERS    1
  27243. +#define PPP_COMPRESS        1
  27244. +#define USE_SKB_PROTOCOL 1  /* Set by the installation program! */
  27245. +
  27246. +#ifdef  NEW_SKBUFF
  27247. +#undef  USE_SKB_PROTOCOL
  27248. +#define USE_SKB_PROTOCOL 2
  27249. +#endif
  27250. +
  27251. +#ifndef PPP_MAX_DEV
  27252. +#define PPP_MAX_DEV    256
  27253. +#endif
  27254. +
  27255. +/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp $
  27256. + * Added dynamic allocation of channels to eliminate
  27257. + *   compiled-in limits on the number of channels.
  27258. + *
  27259. + * Dynamic channel allocation code Copyright 1995 Caldera, Inc.,
  27260. + *   released under the GNU General Public License Version 2.
  27261. + */
  27262. +
  27263. +#include <linux/autoconf.h>
  27264. +#include <linux/module.h>
  27265. +
  27266. +#include <endian.h>
  27267. +#include <linux/kernel.h>
  27268. +#include <linux/sched.h>
  27269. +#include <linux/types.h>
  27270. +#include <linux/fcntl.h>
  27271. +#include <linux/interrupt.h>
  27272. +#include <linux/ptrace.h>
  27273. +#include <linux/ioport.h>
  27274. +#include <linux/in.h>
  27275. +#include <linux/malloc.h>
  27276. +#include <linux/tty.h>
  27277. +#include <linux/errno.h>
  27278. +#include <linux/sched.h>    /* to get the struct task_struct */
  27279. +#include <linux/string.h>    /* used in new tty drivers */
  27280. +#include <linux/signal.h>    /* used in new tty drivers */
  27281. +#include <asm/system.h>
  27282. +#include <asm/bitops.h>
  27283. +#include <asm/segment.h>
  27284. +#include <net/if.h>
  27285. +#include <linux/if_ether.h>
  27286. +#include <linux/netdevice.h>
  27287. +#include <linux/skbuff.h>
  27288. +#include <linux/inet.h>
  27289. +#include <linux/ioctl.h>
  27290. +
  27291. +#ifdef NEW_SKBUFF
  27292. +#include <linux/netprotocol.h>
  27293. +#else
  27294. +typedef struct sk_buff         sk_buff;
  27295. +#define skb_data(skb)         ((unsigned char *) (skb)->data)
  27296. +#endif
  27297. +
  27298. +#include <netinet/ip.h>
  27299. +#include <netinet/tcp.h>
  27300. +#include <linux/if_arp.h>
  27301. +#include "slhc.h"
  27302. +#include <linux/ppp_defs.h>
  27303. +#include <linux/socket.h>
  27304. +#include <linux/if_ppp.h>
  27305. +#include <linux/if_pppvar.h>
  27306. +
  27307. +#undef   PACKETPTR
  27308. +#define  PACKETPTR 1
  27309. +#include <linux/ppp-comp.h>
  27310. +#undef   PACKETPTR
  27311. +
  27312. +#define bsd_decompress    (*ppp->sc_rcomp->decompress)
  27313. +#define bsd_compress    (*ppp->sc_xcomp->compress)
  27314. +
  27315. +#ifndef PPP_IPX
  27316. +#define PPP_IPX 0x2b  /* IPX protocol over PPP */
  27317. +#endif
  27318. +
  27319. +#ifndef PPP_LQR
  27320. +#define PPP_LQR 0xc025  /* Link Quality Reporting Protocol */
  27321. +#endif
  27322. +
  27323. +static int ppp_register_compressor (struct compressor *cp);
  27324. +static void ppp_unregister_compressor (struct compressor *cp);
  27325. +
  27326. +/*
  27327. + * Local functions
  27328. + */
  27329. +
  27330. +static struct compressor *find_compressor (int type);
  27331. +static void ppp_init_ctrl_blk (register struct ppp *);
  27332. +static void ppp_kick_tty (struct ppp *, struct ppp_buffer *bfr);
  27333. +static int ppp_doframe (struct ppp *);
  27334. +static struct ppp *ppp_alloc (void);
  27335. +static void ppp_print_buffer (const u_char *, const u_char *, int);
  27336. +extern inline void ppp_stuff_char (struct ppp *ppp,
  27337. +                   register struct ppp_buffer *buf,
  27338. +                   register u_char chr);
  27339. +extern inline int lock_buffer (register struct ppp_buffer *buf);
  27340. +
  27341. +static int rcv_proto_ip         (struct ppp *, u_short, u_char *, int);
  27342. +static int rcv_proto_ipx        (struct ppp *, u_short, u_char *, int);
  27343. +static int rcv_proto_vjc_comp   (struct ppp *, u_short, u_char *, int);
  27344. +static int rcv_proto_vjc_uncomp (struct ppp *, u_short, u_char *, int);
  27345. +static int rcv_proto_unknown    (struct ppp *, u_short, u_char *, int);
  27346. +static int rcv_proto_lqr        (struct ppp *, u_short, u_char *, int);
  27347. +static void ppp_doframe_lower   (struct ppp *, u_char *, int);
  27348. +static int ppp_doframe          (struct ppp *);
  27349. +
  27350. +extern int  ppp_bsd_compressor_init(void);
  27351. +static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd);
  27352. +static int  rcv_proto_ccp (struct ppp *, u_short, u_char *, int);
  27353. +
  27354. +#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c))
  27355. +
  27356. +#ifndef OPTIMIZE_FLAG_TIME
  27357. +#define OPTIMIZE_FLAG_TIME    0
  27358. +#endif
  27359. +
  27360. +#ifndef PPP_MAX_DEV
  27361. +#define PPP_MAX_DEV 256
  27362. +#endif
  27363. +
  27364. +/*
  27365. + * Parameters which may be changed via insmod.
  27366. + */
  27367. +
  27368. +static int  flag_time = OPTIMIZE_FLAG_TIME;
  27369. +static int  max_dev   = PPP_MAX_DEV;
  27370. +
  27371. +/*
  27372. + * The "main" procedure to the ppp device
  27373. + */
  27374. +
  27375. +int ppp_init (struct device *);
  27376. +
  27377. +/*
  27378. + * Network device driver callback routines
  27379. + */
  27380. +
  27381. +static int ppp_dev_open (struct device *);
  27382. +static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd);
  27383. +static int ppp_dev_close (struct device *);
  27384. +static int ppp_dev_xmit (sk_buff *, struct device *);
  27385. +static struct enet_statistics *ppp_dev_stats (struct device *);
  27386. +
  27387. +#if USE_SKB_PROTOCOL == 0  /* The 1.2.x kernel is here */
  27388. +#define dev_alloc_skb(count)        alloc_skb(count, GFP_ATOMIC)
  27389. +#define skb_put(skb,count)          skb_data(skb)
  27390. +#define get_long_user(addr)        get_user_long((void *) addr)
  27391. +#define get_int_user(addr)        ((int) get_user_long((void *) addr))
  27392. +#define put_byte_user(val,addr)        put_fs_byte(val,((u_char *) (addr)))
  27393. +#define put_long_user(val,addr)        put_fs_long((val),((void *) (addr)))
  27394. +
  27395. +static unsigned short ppp_dev_type (sk_buff *, struct device *);
  27396. +static int ppp_dev_header (unsigned char *buff, struct device *dev,
  27397. +               unsigned short type, void *daddr, void *saddr,
  27398. +               unsigned len, struct sk_buff *skb);
  27399. +
  27400. +#else /* The 1.3.x kernel is here */
  27401. +#define get_long_user(addr)        get_user(((int *) addr))
  27402. +#define get_int_user(addr)        ((int) get_user(((int *) addr)))
  27403. +#define put_byte_user(val,addr)        put_user((val),((u_char *) (addr)))
  27404. +#define put_long_user(val,addr)        put_user((val),((int *) (addr)))
  27405. +
  27406. +static int ppp_dev_header (sk_buff *, struct device *, unsigned short,
  27407. +               void *, void *, unsigned);
  27408. +#endif
  27409. +
  27410. +#ifdef NEW_SKBUFF
  27411. +static int ppp_dev_input (struct protocol *self, struct protocol *lower,
  27412. +              sk_buff *skb, void *saddr, void *daddr);
  27413. +static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type,
  27414. +               int subid, void *saddr, void *daddr, void *opt);
  27415. +static int ppp_dev_getkey(int protocol, int subid, unsigned char *key);
  27416. +#else
  27417. +static int ppp_dev_rebuild (void *, struct device *, unsigned long,
  27418. +                sk_buff *);
  27419. +#endif
  27420. +
  27421. +/*
  27422. + * TTY callbacks
  27423. + */
  27424. +
  27425. +static int ppp_tty_read (struct tty_struct *, struct file *, u_char *,
  27426. +             unsigned int);
  27427. +static int ppp_tty_write (struct tty_struct *, struct file *, const u_char *,
  27428. +              unsigned int);
  27429. +static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
  27430. +              unsigned long);
  27431. +static int ppp_tty_select (struct tty_struct *tty, struct inode *inode,
  27432. +              struct file *filp, int sel_type, select_table * wait);
  27433. +static int ppp_tty_open (struct tty_struct *);
  27434. +static void ppp_tty_close (struct tty_struct *);
  27435. +static int ppp_tty_room (struct tty_struct *tty);
  27436. +static void ppp_tty_receive (struct tty_struct *tty, const u_char * cp,
  27437. +                 char *fp, int count);
  27438. +static void ppp_tty_wakeup (struct tty_struct *tty);
  27439. +
  27440. +#define CHECK_PPP(a)  if (!ppp->inuse) { printk (ppp_warning, __LINE__); return a;}
  27441. +#define CHECK_PPP_VOID()  if (!ppp->inuse) { printk (ppp_warning, __LINE__); return;}
  27442. +
  27443. +#define in_xmap(ppp,c)    (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
  27444. +#define in_rmap(ppp,c)    ((((unsigned int) (u_char) (c)) < 0x20) && \
  27445. +            ppp->recv_async_map & (1 << (c)))
  27446. +
  27447. +#define bset(p,b)    ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
  27448. +
  27449. +#define tty2ppp(tty)    ((struct ppp *) (tty->disc_data))
  27450. +#define dev2ppp(dev)    ((struct ppp *) (dev->priv))
  27451. +#define ppp2tty(ppp)    ((struct tty_struct *) ppp->tty)
  27452. +#define ppp2dev(ppp)    ((struct device *) ppp->dev)
  27453. +
  27454. +struct ppp_hdr {
  27455. +    unsigned char address;
  27456. +    unsigned char control;
  27457. +    unsigned char protocol[2];
  27458. +};
  27459. +
  27460. +#define PPP_HARD_HDR_LEN    (sizeof (struct ppp_hdr))
  27461. +
  27462. +typedef struct  ppp_ctrl {
  27463. +    struct ppp_ctrl *next;        /* Next structure in the list    */
  27464. +    char            name [8];    /* Name of the device        */
  27465. +    struct ppp      ppp;        /* PPP control table        */
  27466. +    struct device   dev;        /* Device information table    */
  27467. +} ppp_ctrl_t;
  27468. +
  27469. +static ppp_ctrl_t *ppp_list = NULL;
  27470. +
  27471. +#define ctl2ppp(ctl) (struct ppp *)    &ctl->ppp
  27472. +#define ctl2dev(ctl) (struct device *) &ctl->dev
  27473. +#undef  PPP_NRUNIT
  27474. +
  27475. +/* Buffer types */
  27476. +#define BUFFER_TYPE_DEV_RD    0  /* ppp read buffer       */
  27477. +#define BUFFER_TYPE_TTY_WR    1  /* tty write buffer      */
  27478. +#define BUFFER_TYPE_DEV_WR    2  /* ppp write buffer      */
  27479. +#define BUFFER_TYPE_TTY_RD    3  /* tty read buffer       */
  27480. +#define BUFFER_TYPE_VJ        4  /* vj compression buffer */
  27481. +
  27482. +/* Define this string only once for all macro envocations */
  27483. +static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
  27484. +
  27485. +static char szVersion[]         = PPP_VERSION;
  27486. +#ifdef NEW_SKBUFF
  27487. +static struct protocol proto_ppp;
  27488. +#endif
  27489. +
  27490. +/*
  27491. + * Information for the protocol decoder
  27492. + */
  27493. +
  27494. +typedef int (*pfn_proto)  (struct ppp *, u_short, u_char *, int);
  27495. +
  27496. +typedef struct ppp_proto_struct {
  27497. +    int        proto;
  27498. +    pfn_proto    func;
  27499. +} ppp_proto_type;
  27500. +
  27501. +static
  27502. +ppp_proto_type proto_list[] = {
  27503. +    { PPP_IP,         rcv_proto_ip         },
  27504. +    { PPP_IPX,        rcv_proto_ipx        },
  27505. +    { PPP_VJC_COMP,   rcv_proto_vjc_comp   },
  27506. +    { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp },
  27507. +    { PPP_LQR,        rcv_proto_lqr        },
  27508. +    { PPP_CCP,        rcv_proto_ccp        },
  27509. +    { 0,              rcv_proto_unknown    }  /* !!! MUST BE LAST !!! */
  27510. +};
  27511. +
  27512. +/*
  27513. + * Values for FCS calculations.
  27514. + */
  27515. +
  27516. +#define PPP_INITFCS    0xffff    /* Initial FCS value */
  27517. +#define PPP_GOODFCS    0xf0b8    /* Good final FCS value */
  27518. +#define PPP_FCS(fcs, c)    (((fcs) >> 8) ^ ppp_crc16_table[((fcs) ^ (c)) & 0xff])
  27519. +
  27520. +unsigned short ppp_crc16_table[256] =
  27521. +{
  27522. +    0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
  27523. +    0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
  27524. +    0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
  27525. +    0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
  27526. +    0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
  27527. +    0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
  27528. +    0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
  27529. +    0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
  27530. +    0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
  27531. +    0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
  27532. +    0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
  27533. +    0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
  27534. +    0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
  27535. +    0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
  27536. +    0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
  27537. +    0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
  27538. +    0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
  27539. +    0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
  27540. +    0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
  27541. +    0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
  27542. +    0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
  27543. +    0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
  27544. +    0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
  27545. +    0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
  27546. +    0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
  27547. +    0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
  27548. +    0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
  27549. +    0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
  27550. +    0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
  27551. +    0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
  27552. +    0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
  27553. +    0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
  27554. +};
  27555. +
  27556. +#ifdef CHECK_CHARACTERS
  27557. +static unsigned paritytab[8] =
  27558. +{
  27559. +    0x96696996, 0x69969669, 0x69969669, 0x96696996,
  27560. +    0x69969669, 0x96696996, 0x96696996, 0x69969669
  27561. +};
  27562. +#endif
  27563. +
  27564. +/* local function to store a value into the LQR frame */
  27565. +extern inline u_char * store_long (register u_char *p, register int value) {
  27566. +    *p++ = (u_char) (value >> 24);
  27567. +    *p++ = (u_char) (value >> 16);
  27568. +    *p++ = (u_char) (value >>  8);
  27569. +    *p++ = (u_char) value;
  27570. +    return p;
  27571. +}
  27572. +
  27573. +/*************************************************************
  27574. + * INITIALIZATION
  27575. + *************************************************************/
  27576. +
  27577. +/* This procedure is called once and once only to define who we are to
  27578. + * the operating system and the various procedures that it may use in
  27579. + * accessing the ppp protocol.
  27580. + */
  27581. +
  27582. +static int
  27583. +ppp_first_time (void)
  27584. +{
  27585. +    static struct tty_ldisc    ppp_ldisc;
  27586. +    int    status;
  27587. +
  27588. +    printk (KERN_INFO
  27589. +        "PPP: version %s (dynamic channel allocation)"
  27590. +#ifdef NEW_SKBUFF
  27591. +        " NEW_SKBUFF"
  27592. +#endif
  27593. +        "\n", szVersion);
  27594. +
  27595. +#ifndef MODULE /* slhc module logic has its own copyright announcment */
  27596. +    printk (KERN_INFO
  27597. +        "TCP compression code copyright 1989 Regents of the "
  27598. +        "University of California\n");
  27599. +#endif
  27600. +    
  27601. +    printk (KERN_INFO
  27602. +        "PPP Dynamic channel allocation code copyright 1995 "
  27603. +        "Caldera, Inc.\n");
  27604. +/*
  27605. + * Register the protocol for the device
  27606. + */
  27607. +
  27608. +#ifdef NEW_SKBUFF  
  27609. +    memset (&proto_ppp, 0, sizeof (proto_ppp));
  27610. +
  27611. +    proto_ppp.name          = "PPP";
  27612. +    proto_ppp.output        = ppp_dev_output;
  27613. +    proto_ppp.input         = ppp_dev_input;
  27614. +    proto_ppp.bh_input      = ppp_dev_input;
  27615. +    proto_ppp.control_event = default_protocol_control;
  27616. +    proto_ppp.get_binding   = ppp_dev_getkey;
  27617. +    proto_ppp.header_space  = 0; /* PPP_HARD_HDR_LEN; */
  27618. +
  27619. +    protocol_register(&proto_ppp);
  27620. +#endif
  27621. +
  27622. +/*
  27623. + * Register the tty dicipline
  27624. + */    
  27625. +    (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
  27626. +    ppp_ldisc.magic        = TTY_LDISC_MAGIC;
  27627. +    ppp_ldisc.open        = ppp_tty_open;
  27628. +    ppp_ldisc.close        = ppp_tty_close;
  27629. +    ppp_ldisc.read        = ppp_tty_read;
  27630. +    ppp_ldisc.write        = ppp_tty_write;
  27631. +    ppp_ldisc.ioctl        = ppp_tty_ioctl;
  27632. +    ppp_ldisc.select    = ppp_tty_select;
  27633. +    ppp_ldisc.receive_room    = ppp_tty_room;
  27634. +    ppp_ldisc.receive_buf    = ppp_tty_receive;
  27635. +    ppp_ldisc.write_wakeup    = ppp_tty_wakeup;
  27636. +    
  27637. +    status = tty_register_ldisc (N_PPP, &ppp_ldisc);
  27638. +    if (status == 0)
  27639. +        printk (KERN_INFO "PPP line discipline registered.\n");
  27640. +    else
  27641. +        printk (KERN_ERR "error registering line discipline: %d\n",
  27642. +            status);
  27643. +    return status;
  27644. +}
  27645. +
  27646. +/*************************************************************
  27647. + * INITIALIZATION
  27648. + *************************************************************/
  27649. +
  27650. +/* called when the device is actually created */
  27651. +
  27652. +static int
  27653. +ppp_init_dev (struct device *dev)
  27654. +{
  27655. +    int    indx;
  27656. +#ifdef NEW_SKBUFF  
  27657. +    dev->default_protocol = &proto_ppp;    /* Our protocol layer is PPP */
  27658. +#else
  27659. +    dev->hard_header      = ppp_dev_header;
  27660. +#if USE_SKB_PROTOCOL == 0
  27661. +    dev->type_trans       = ppp_dev_type;
  27662. +#endif
  27663. +    dev->rebuild_header   = ppp_dev_rebuild;
  27664. +    dev->hard_header_len  = 0; /* PPP_HARD_HDR_LEN; */
  27665. +#endif
  27666. +
  27667. +    /* device INFO */
  27668. +    dev->mtu              = PPP_MTU;
  27669. +    dev->hard_start_xmit  = ppp_dev_xmit;
  27670. +    dev->open             = ppp_dev_open;
  27671. +    dev->stop             = ppp_dev_close;
  27672. +    dev->get_stats        = ppp_dev_stats;
  27673. +    dev->do_ioctl         = ppp_dev_ioctl;
  27674. +    dev->addr_len         = 0;
  27675. +    dev->type             = ARPHRD_PPP;
  27676. +
  27677. +    for (indx = 0; indx < DEV_NUMBUFFS; indx++)
  27678. +        skb_queue_head_init (&dev->buffs[indx]);
  27679. +
  27680. +    /* New-style flags */
  27681. +    dev->flags      = IFF_POINTOPOINT;
  27682. +    dev->family     = AF_INET;
  27683. +    dev->pa_addr    = 0;
  27684. +    dev->pa_brdaddr = 0;
  27685. +    dev->pa_mask    = 0;
  27686. +    dev->pa_alen    = 4; /* sizeof (unsigned long) */
  27687. +
  27688. +    return 0;
  27689. +}
  27690. +
  27691. +/*
  27692. + * Local procedure to initialize the ppp structure
  27693. + */
  27694. +
  27695. +static void
  27696. +ppp_init_ctrl_blk (register struct ppp *ppp)
  27697. +{
  27698. +    ppp->magic  = PPP_MAGIC;
  27699. +    ppp->toss   = 0xE0;
  27700. +    ppp->escape = 0;
  27701. +
  27702. +    ppp->flags  = 0;
  27703. +    ppp->mtu    = PPP_MTU;
  27704. +    ppp->mru    = PPP_MRU;
  27705. +
  27706. +    memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map));
  27707. +    ppp->xmit_async_map[0] = 0xffffffff;
  27708. +    ppp->xmit_async_map[3] = 0x60000000;
  27709. +    ppp->recv_async_map    = 0x00000000;
  27710. +
  27711. +    ppp->rbuf       = NULL;
  27712. +    ppp->wbuf       = NULL;
  27713. +    ppp->ubuf       = NULL;
  27714. +    ppp->cbuf       = NULL;
  27715. +    ppp->slcomp     = NULL;
  27716. +    ppp->read_wait  = NULL;
  27717. +    ppp->write_wait = NULL;
  27718. +    ppp->last_xmit  = jiffies - flag_time;
  27719. +
  27720. +    /* clear statistics */
  27721. +    memset (&ppp->stats, '\0', sizeof (struct pppstat));
  27722. +
  27723. +    /* Reset the demand dial information */
  27724. +    ppp->ddinfo.xmit_idle=         /* time since last NP packet sent */
  27725. +    ppp->ddinfo.recv_idle=jiffies; /* time since last NP packet received */
  27726. +
  27727. +    /* PPP compression data */
  27728. +    ppp->sc_xc_state =
  27729. +    ppp->sc_rc_state = NULL;
  27730. +}
  27731. +
  27732. +static struct symbol_table ppp_syms = {
  27733. +#include <linux/symtab_begin.h>
  27734. +    X(ppp_register_compressor),
  27735. +    X(ppp_unregister_compressor),
  27736. +    X(ppp_crc16_table),
  27737. +#include <linux/symtab_end.h>
  27738. +};
  27739. +
  27740. +/* called at boot/load time for each ppp device defined in the kernel */
  27741. +
  27742. +#ifndef MODULE
  27743. +int
  27744. +ppp_init (struct device *dev)
  27745. +{
  27746. +    static int first_time = 1;
  27747. +    int    answer = 0;
  27748. +
  27749. +    if (first_time) {
  27750. +        first_time = 0;
  27751. +        answer     = ppp_first_time();
  27752. +        if (answer == 0)
  27753. +            (void) register_symtab (&ppp_syms);
  27754. +    }
  27755. +    if (answer)
  27756. +        return answer;
  27757. +    /*
  27758. +     * Return "not found", so that dev_init() will unlink
  27759. +     * the placeholder device entry for us.
  27760. +     */
  27761. +    return ENODEV;
  27762. +
  27763. +}
  27764. +#endif
  27765. +
  27766. +/*
  27767. + * Routine to allocate a buffer for later use by the driver.
  27768. + */
  27769. +
  27770. +static struct ppp_buffer *
  27771. +ppp_alloc_buf (int size, int type)
  27772. +{
  27773. +    struct ppp_buffer *buf;
  27774. +
  27775. +    buf = (struct ppp_buffer *) kmalloc (size + sizeof (struct ppp_buffer),
  27776. +                         GFP_ATOMIC);
  27777. +
  27778. +    if (buf != NULL) {
  27779. +        buf->size   = size - 1;    /* Mask for the buffer size */
  27780. +        buf->type   = type;
  27781. +        buf->locked = 0;
  27782. +        buf->count  = 0;
  27783. +        buf->head   = 0;
  27784. +        buf->tail   = 0;
  27785. +        buf->fcs    = PPP_INITFCS;
  27786. +    }
  27787. +    return (buf);
  27788. +}
  27789. +
  27790. +/*
  27791. + * Routine to release the allocated buffer.
  27792. + */
  27793. +
  27794. +static void
  27795. +ppp_free_buf (struct ppp_buffer *ptr)
  27796. +{
  27797. +    if (ptr != NULL)
  27798. +        kfree (ptr);
  27799. +}
  27800. +
  27801. +/*
  27802. + * Lock the indicated transmit buffer
  27803. + */
  27804. +
  27805. +extern inline int
  27806. +lock_buffer (register struct ppp_buffer *buf)
  27807. +{
  27808. +    register int state;
  27809. +    int flags;
  27810. +/*
  27811. + * Save the current state and if free then set it to the "busy" state
  27812. + */
  27813. +    save_flags (flags);
  27814. +    cli ();
  27815. +    state = buf->locked;
  27816. +    if (state == 0)
  27817. +        buf->locked = 2;
  27818. +/*
  27819. + * Restore the flags and return the previous state. 0 implies success.
  27820. + */
  27821. +    restore_flags (flags);
  27822. +    return (state);
  27823. +}
  27824. +
  27825. +/*
  27826. + * MTU has been changed by the IP layer. Unfortunately we are not told
  27827. + * about this, but we spot it ourselves and fix things up. We could be
  27828. + * in an upcall from the tty driver, or in an ip packet queue.
  27829. + */
  27830. +
  27831. +static int
  27832. +ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
  27833. +{
  27834. +    struct device *dev;
  27835. +
  27836. +    struct ppp_buffer *new_rbuf;
  27837. +    struct ppp_buffer *new_wbuf;
  27838. +    struct ppp_buffer *new_cbuf;
  27839. +    struct ppp_buffer *new_tbuf;
  27840. +
  27841. +    struct ppp_buffer *old_rbuf;
  27842. +    struct ppp_buffer *old_wbuf;
  27843. +    struct ppp_buffer *old_cbuf;
  27844. +    struct ppp_buffer *old_tbuf;
  27845. +
  27846. +    int mtu, mru;
  27847. +/*
  27848. + *  Allocate the buffer from the kernel for the data
  27849. + */
  27850. +    dev = ppp2dev (ppp);
  27851. +    mru = new_mru;
  27852. +    /* allow for possible escapement of every character */
  27853. +    mtu = (new_mtu * 2) + 20;
  27854. +
  27855. +    /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
  27856. +    if (mru < PPP_MRU)
  27857. +        mru = PPP_MRU;
  27858. +
  27859. +    mru += 10;
  27860. +    
  27861. +    if (ppp->flags & SC_DEBUG)
  27862. +        printk (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
  27863. +            dev->name, new_mtu, new_mru);
  27864. +
  27865. +    new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN,    BUFFER_TYPE_DEV_WR);
  27866. +    new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24,    BUFFER_TYPE_TTY_WR);
  27867. +    new_rbuf = ppp_alloc_buf (mru + 84,        BUFFER_TYPE_DEV_RD);
  27868. +    new_cbuf = ppp_alloc_buf (mru+PPP_HARD_HDR_LEN,    BUFFER_TYPE_VJ);
  27869. +/*
  27870. + *  If the buffers failed to allocate then complain and release the partial
  27871. + *  allocations.
  27872. + */
  27873. +    if (new_wbuf == NULL || new_tbuf == NULL ||
  27874. +        new_rbuf == NULL || new_cbuf == NULL) {
  27875. +        if (ppp->flags & SC_DEBUG)
  27876. +            printk (KERN_ERR
  27877. +                "ppp: failed to allocate new buffers\n");
  27878. +
  27879. +        ppp_free_buf (new_wbuf);
  27880. +        ppp_free_buf (new_tbuf);
  27881. +        ppp_free_buf (new_rbuf);
  27882. +        ppp_free_buf (new_cbuf);
  27883. +        return 0;
  27884. +    }
  27885. +/*
  27886. + *  Update the pointers to the new buffer structures.
  27887. + */
  27888. +    cli ();
  27889. +    old_wbuf = ppp->wbuf;
  27890. +    old_rbuf = ppp->rbuf;
  27891. +    old_cbuf = ppp->cbuf;
  27892. +    old_tbuf = ppp->tbuf;
  27893. +
  27894. +    ppp->wbuf = new_wbuf;
  27895. +    ppp->rbuf = new_rbuf;
  27896. +    ppp->cbuf = new_cbuf;
  27897. +    ppp->tbuf = new_tbuf;
  27898. +
  27899. +    ppp->rbuf->size -= 80;  /* reserve space for vj header expansion */
  27900. +
  27901. +    dev->mem_start  = (unsigned long) buf_base (new_wbuf);
  27902. +    dev->mem_end    = (unsigned long) (dev->mem_start + mtu);
  27903. +    dev->rmem_start = (unsigned long) buf_base (new_rbuf);
  27904. +    dev->rmem_end   = (unsigned long) (dev->rmem_start + mru);
  27905. +/*
  27906. + *  Update the parameters for the new buffer sizes
  27907. + */
  27908. +    ppp->toss   = 0xE0;    /* To ignore characters until new FLAG */
  27909. +    ppp->escape = 0;    /* No pending escape character */
  27910. +
  27911. +    dev->mtu    =
  27912. +    ppp->mtu    = new_mtu;
  27913. +    ppp->mru    = new_mru;
  27914. +
  27915. +    ppp->s1buf  = NULL;
  27916. +    ppp->s2buf  = NULL;
  27917. +    ppp->xbuf   = NULL;
  27918. +
  27919. +    ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
  27920. +    ppp->flags      &= ~SC_XMIT_BUSY;
  27921. +
  27922. +    sti ();
  27923. +/*
  27924. + *  Release old buffer pointers
  27925. + */
  27926. +    ppp_free_buf (old_rbuf);
  27927. +    ppp_free_buf (old_wbuf);
  27928. +    ppp_free_buf (old_cbuf);
  27929. +    ppp_free_buf (old_tbuf);
  27930. +    return 1;
  27931. +}
  27932. +
  27933. +/*
  27934. + * CCP is down; free (de)compressor state if necessary.
  27935. + */
  27936. +
  27937. +static void
  27938. +ppp_ccp_closed (struct ppp *ppp)
  27939. +{
  27940. +    if (ppp->sc_xc_state) {
  27941. +        (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);
  27942. +        ppp->sc_xc_state = NULL;
  27943. +    }
  27944. +
  27945. +    if (ppp->sc_rc_state) {
  27946. +        (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);
  27947. +        ppp->sc_rc_state = NULL;
  27948. +    }
  27949. +}
  27950. +
  27951. +/*
  27952. + * Called to release all of the information in the current PPP structure.
  27953. + *
  27954. + * It is called when the ppp device goes down or if it is unable to go
  27955. + * up.
  27956. + */
  27957. +
  27958. +static void
  27959. +ppp_release (struct ppp *ppp)
  27960. +{
  27961. +    struct tty_struct *tty;
  27962. +    struct device *dev;
  27963. +
  27964. +    tty = ppp2tty (ppp);
  27965. +    dev = ppp2dev (ppp);
  27966. +
  27967. +    ppp_ccp_closed (ppp);
  27968. +
  27969. +    if (tty != NULL && tty->disc_data == ppp)
  27970. +        tty->disc_data = NULL;    /* Break the tty->ppp link */
  27971. +
  27972. +    if (dev && dev->flags & IFF_UP) {
  27973. +        dev_close (dev); /* close the device properly */
  27974. +        dev->flags = 0;  /* prevent recursion */
  27975. +    }
  27976. +
  27977. +    ppp_free_buf (ppp->rbuf);
  27978. +    ppp_free_buf (ppp->wbuf);
  27979. +    ppp_free_buf (ppp->cbuf);
  27980. +    ppp_free_buf (ppp->ubuf);
  27981. +    ppp_free_buf (ppp->tbuf);
  27982. +
  27983. +    ppp->rbuf  =
  27984. +    ppp->wbuf  =
  27985. +    ppp->cbuf  =
  27986. +    ppp->tbuf  =
  27987. +    ppp->xbuf  =
  27988. +    ppp->s1buf =
  27989. +    ppp->s2buf =
  27990. +    ppp->ubuf  = NULL;
  27991. +
  27992. +    if (ppp->slcomp) {
  27993. +        slhc_free (ppp->slcomp);
  27994. +        ppp->slcomp = NULL;
  27995. +    }
  27996. +
  27997. +    ppp->inuse = 0;
  27998. +    ppp->tty   = NULL;
  27999. +}
  28000. +
  28001. +/*
  28002. + * Device callback.
  28003. + *
  28004. + * Called when the PPP device goes down in response to an ifconfig request.
  28005. + */
  28006. +
  28007. +static void
  28008. +ppp_tty_close (struct tty_struct *tty)
  28009. +{
  28010. +    struct ppp *ppp = tty2ppp (tty);
  28011. +
  28012. +    if (ppp != NULL) {
  28013. +        if (ppp->magic != PPP_MAGIC) {
  28014. +            if (ppp->flags & SC_DEBUG)
  28015. +                printk (KERN_WARNING
  28016. +                       "ppp: trying to close unopened tty!\n");
  28017. +        } else {
  28018. +            CHECK_PPP_VOID();
  28019. +            if (ppp->flags & SC_DEBUG)
  28020. +                printk (KERN_INFO "ppp: channel %s closing.\n",
  28021. +                    ppp2dev(ppp) -> name);
  28022. +            ppp_release (ppp);
  28023. +            MOD_DEC_USE_COUNT;
  28024. +        }
  28025. +    }
  28026. +}
  28027. +
  28028. +/*
  28029. + * TTY callback.
  28030. + *
  28031. + * Called when the tty discipline is switched to PPP.
  28032. + */
  28033. +
  28034. +static int
  28035. +ppp_tty_open (struct tty_struct *tty)
  28036. +{
  28037. +    struct ppp *ppp = tty2ppp (tty);
  28038. +/*
  28039. + * There should not be an existing table for this slot.
  28040. + */
  28041. +    if (ppp) {
  28042. +        if (ppp->flags & SC_DEBUG)
  28043. +            printk (KERN_ERR
  28044. +            "ppp_tty_open: gack! tty already associated to %s!\n",
  28045. +            ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name
  28046. +                        : "unknown");
  28047. +        return -EEXIST;
  28048. +    }
  28049. +/*
  28050. + * Allocate the structure from the system
  28051. + */
  28052. +    ppp = ppp_alloc();
  28053. +    if (ppp == NULL) {
  28054. +        if (ppp->flags & SC_DEBUG)
  28055. +            printk (KERN_ERR
  28056. +            "ppp_tty_open: couldn't allocate ppp channel\n");
  28057. +        return -ENFILE;
  28058. +    }
  28059. +/*
  28060. + * Initialize the control block
  28061. + */
  28062. +    ppp_init_ctrl_blk (ppp);
  28063. +    ppp->tty       = tty;
  28064. +    tty->disc_data = ppp;
  28065. +/*
  28066. + * Flush any pending characters in the driver and discipline.
  28067. + */
  28068. +    if (tty->ldisc.flush_buffer)
  28069. +        tty->ldisc.flush_buffer (tty);
  28070. +
  28071. +    if (tty->driver.flush_buffer)
  28072. +        tty->driver.flush_buffer (tty);
  28073. +/*
  28074. + * Allocate space for the default VJ header compression slots
  28075. + */
  28076. +    ppp->slcomp = slhc_init (16, 16);
  28077. +    if (ppp->slcomp == NULL) {
  28078. +        if (ppp->flags & SC_DEBUG)
  28079. +            printk (KERN_ERR
  28080. +            "ppp_tty_open: no space for compression buffers!\n");
  28081. +        ppp_release (ppp);
  28082. +        return -ENOMEM;
  28083. +    }
  28084. +/*
  28085. + * Allocate space for the MTU and MRU buffers
  28086. + */
  28087. +    if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
  28088. +        ppp_release (ppp);
  28089. +        return -ENOMEM;
  28090. +    }
  28091. +/*
  28092. + * Allocate space for a user level buffer
  28093. + */
  28094. +    ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
  28095. +    if (ppp->ubuf == NULL) {
  28096. +        if (ppp->flags & SC_DEBUG)
  28097. +            printk (KERN_ERR
  28098. +               "ppp_tty_open: no space for user receive buffer\n");
  28099. +        ppp_release (ppp);
  28100. +        return -ENOMEM;
  28101. +    }
  28102. +
  28103. +    if (ppp->flags & SC_DEBUG)
  28104. +        printk (KERN_INFO "ppp: channel %s open\n",
  28105. +            ppp2dev(ppp)->name);
  28106. +
  28107. +    MOD_INC_USE_COUNT;
  28108. +    return (ppp->line);
  28109. +}
  28110. +
  28111. +/*
  28112. + * Local function to send the next portion of the buffer.
  28113. + *
  28114. + * Called by the tty driver's tty_wakeup function should it be entered
  28115. + * because the partial buffer was transmitted.
  28116. + *
  28117. + * Called by kick_tty to send the initial portion of the buffer.
  28118. + *
  28119. + * Completion processing of the buffer transmission is handled here.
  28120. + */
  28121. +
  28122. +static void
  28123. +ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
  28124. +             struct ppp_buffer *xbuf)
  28125. +{
  28126. +    register int count, actual;
  28127. +/*
  28128. + * Prevent re-entrancy by ensuring that this routine is called only once.
  28129. + */
  28130. +    cli ();
  28131. +    if (ppp->flags & SC_XMIT_BUSY) {
  28132. +        sti ();
  28133. +        return;
  28134. +    }
  28135. +    ppp->flags |= SC_XMIT_BUSY;
  28136. +    sti ();
  28137. +/*
  28138. + * Send the next block of data to the modem
  28139. + */
  28140. +    count = xbuf->count - xbuf->tail;
  28141. +    actual = tty->driver.write (tty, 0,
  28142. +                    buf_base (xbuf) + xbuf->tail, count);
  28143. +/*
  28144. + * Terminate transmission of any block which may have an error.
  28145. + * This could occur should the carrier drop.
  28146. + */
  28147. +    if (actual < 0) {
  28148. +            ppp->stats.ppp_oerrors++;
  28149. +        actual = count;
  28150. +    } else
  28151. +        ppp->bytes_sent += actual;
  28152. +/*
  28153. + * If the buffer has been transmitted then clear the indicators.
  28154. + */
  28155. +    xbuf->tail += actual;
  28156. +    if (actual == count) {
  28157. +        xbuf = NULL;
  28158. +        ppp->flags &= ~SC_XMIT_BUSY;
  28159. +/*
  28160. + * Complete the transmission on the current buffer.
  28161. + */
  28162. +        xbuf = ppp->xbuf;
  28163. +        if (xbuf != NULL) {
  28164. +            tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
  28165. +            xbuf->locked = 0;
  28166. +            ppp->xbuf    = NULL;
  28167. +/*
  28168. + * If the completed buffer came from the device write, then complete the
  28169. + * transmission block.
  28170. + */
  28171. +            if (ppp2dev (ppp) -> flags & IFF_UP) {
  28172. +                if (xbuf->type == BUFFER_TYPE_DEV_WR)
  28173. +                        ppp2dev (ppp)->tbusy = 0;
  28174. +                mark_bh (NET_BH);
  28175. +            }
  28176. +/*
  28177. + * Wake up the transmission queue for all completion events.
  28178. + */
  28179. +            wake_up_interruptible (&ppp->write_wait);
  28180. +/*
  28181. + * Look at the priorities. Choose a daemon write over the device driver.
  28182. + */
  28183. +            cli();
  28184. +            xbuf = ppp->s1buf;
  28185. +            ppp->s1buf = NULL;
  28186. +            if (xbuf == NULL) {
  28187. +                xbuf = ppp->s2buf;
  28188. +                ppp->s2buf = NULL;
  28189. +            }
  28190. +            sti();
  28191. +/*
  28192. + * If there is a pending buffer then transmit it now.
  28193. + */
  28194. +            if (xbuf != NULL) {
  28195. +                ppp->flags &= ~SC_XMIT_BUSY;
  28196. +                ppp_kick_tty (ppp, xbuf);
  28197. +                return;
  28198. +            }
  28199. +        }
  28200. +    }
  28201. +/*
  28202. + * Clear the re-entry flag
  28203. + */
  28204. +    ppp->flags &= ~SC_XMIT_BUSY;
  28205. +}
  28206. +
  28207. +/*
  28208. + * This function is called by the tty driver when the transmit buffer has
  28209. + * additional space. It is used by the ppp code to continue to transmit
  28210. + * the current buffer should the buffer have been partially sent.
  28211. + *
  28212. + * In addition, it is used to send the first part of the buffer since the
  28213. + * logic and the inter-locking would be identical.
  28214. + */
  28215. +
  28216. +static void
  28217. +ppp_tty_wakeup (struct tty_struct *tty)
  28218. +{
  28219. +    struct ppp_buffer *xbuf;
  28220. +    struct ppp *ppp = tty2ppp (tty);
  28221. +
  28222. +    if (!ppp)
  28223. +        return;
  28224. +
  28225. +    if (ppp->magic != PPP_MAGIC)
  28226. +        return;
  28227. +/*
  28228. + * Ensure that there is a transmission pending. Clear the re-entry flag if
  28229. + * there is no pending buffer. Otherwise, send the buffer.
  28230. + */
  28231. +    xbuf = ppp->xbuf;
  28232. +    if (xbuf == NULL)
  28233. +        tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
  28234. +    else
  28235. +        ppp_tty_wakeup_code (ppp, tty, xbuf);
  28236. +}
  28237. +
  28238. +/*
  28239. + * This function is called to transmit a buffer to the remote. The buffer
  28240. + * is placed on the pending queue if there is presently a buffer being
  28241. + * sent or it is transmitted with the aid of ppp_tty_wakeup.
  28242. + */
  28243. +
  28244. +static void
  28245. +ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
  28246. +{
  28247. +    register int flags;
  28248. +/*
  28249. + * Hold interrupts.
  28250. + */
  28251. +    save_flags (flags);
  28252. +    cli ();
  28253. +/*
  28254. + * Control the flags which are best performed with the interrupts masked.
  28255. + */
  28256. +    xbuf->locked     = 1;
  28257. +    xbuf->tail       = 0;
  28258. +/*
  28259. + * If the transmitter is busy then place the buffer on the appropriate
  28260. + * priority queue.
  28261. + */
  28262. +    if (ppp->xbuf != NULL) {
  28263. +        if (xbuf->type == BUFFER_TYPE_TTY_WR)
  28264. +            ppp->s1buf = xbuf;
  28265. +        else
  28266. +            ppp->s2buf = xbuf;
  28267. +        restore_flags (flags);
  28268. +        return;
  28269. +    }
  28270. +/*
  28271. + * If the transmitter is not busy then this is the highest priority frame
  28272. + */
  28273. +    ppp->flags      &= ~SC_XMIT_BUSY;
  28274. +    ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
  28275. +    ppp->xbuf        = xbuf;
  28276. +    restore_flags (flags);
  28277. +/*
  28278. + * Do the "tty wakeup_code" to actually send this buffer.
  28279. + */
  28280. +    ppp_tty_wakeup_code (ppp, ppp2tty (ppp), xbuf);
  28281. +}
  28282. +
  28283. +/*************************************************************
  28284. + * TTY INPUT
  28285. + *    The following functions handle input that arrives from
  28286. + *    the TTY.    It recognizes PPP frames and either hands them
  28287. + *    to the network layer or queues them for delivery to a
  28288. + *    user process reading this TTY.
  28289. + *************************************************************/
  28290. +
  28291. +/*
  28292. + * Callback function from tty driver. Return the amount of space left
  28293. + * in the receiver's buffer to decide if remote transmitter is to be
  28294. + * throttled.
  28295. + */
  28296. +
  28297. +static int
  28298. +ppp_tty_room (struct tty_struct *tty)
  28299. +{
  28300. +    return 65536;        /* We can handle an infinite amount of data. :-) */
  28301. +}
  28302. +
  28303. +/*
  28304. + * Callback function when data is available at the tty driver.
  28305. + */
  28306. +
  28307. +static void
  28308. +ppp_tty_receive (struct tty_struct *tty, const u_char * data,
  28309. +         char *flags, int count)
  28310. +{
  28311. +    register struct ppp *ppp = tty2ppp (tty);
  28312. +    register struct ppp_buffer *buf = NULL;
  28313. +    u_char chr;
  28314. +/*
  28315. + * Fetch the pointer to the buffer. Be careful about race conditions.
  28316. + */
  28317. +    if (ppp != NULL)
  28318. +        buf = ppp->rbuf;
  28319. +
  28320. +    if (buf == NULL)
  28321. +        return;
  28322. +/*
  28323. + * Verify the table pointer and ensure that the line is
  28324. + * still in PPP discipline.
  28325. + */
  28326. +    if (ppp->magic != PPP_MAGIC) {
  28327. +        if (ppp->flags & SC_DEBUG)
  28328. +            printk (KERN_DEBUG
  28329. +                "PPP: handler called but couldn't find "
  28330. +                "PPP struct.\n");
  28331. +        return;
  28332. +    }
  28333. +    CHECK_PPP_VOID ();
  28334. +/*
  28335. + * Print the buffer if desired
  28336. + */
  28337. +    if (ppp->flags & SC_LOG_RAWIN)
  28338. +        ppp_print_buffer ("receive buffer", data, count);
  28339. +/*
  28340. + * Collect the character and error condition for the character. Set the toss
  28341. + * flag for the first character error.
  28342. + */
  28343. +    while (count-- > 0) {
  28344. +        ppp->bytes_rcvd++;
  28345. +        chr = *data++;
  28346. +        if (flags) {
  28347. +            if (*flags && ppp->toss == 0)
  28348. +                ppp->toss = *flags;
  28349. +            ++flags;
  28350. +        }
  28351. +/*
  28352. + * Set the flags for 8 data bits and no parity.
  28353. + *
  28354. + * Actually, it sets the flags for d7 being 0/1 and parity being even/odd
  28355. + * so that the normal processing would have all flags set at the end of the
  28356. + * session. A missing flag bit would denote an error condition.
  28357. + */
  28358. +
  28359. +#ifdef CHECK_CHARACTERS
  28360. +        if (chr & 0x80)
  28361. +            ppp->flags |= SC_RCV_B7_1;
  28362. +        else
  28363. +            ppp->flags |= SC_RCV_B7_0;
  28364. +
  28365. +        if (paritytab[chr >> 5] & (1 << (chr & 0x1F)))
  28366. +            ppp->flags |= SC_RCV_ODDP;
  28367. +        else
  28368. +            ppp->flags |= SC_RCV_EVNP;
  28369. +#endif
  28370. +/*
  28371. + * Branch on the character. Process the escape character. The sequence ESC ESC
  28372. + * is defined to be ESC.
  28373. + */
  28374. +        switch (chr) {
  28375. +        case PPP_ESCAPE: /* PPP_ESCAPE: invert bit in next character */
  28376. +            ppp->escape = PPP_TRANS;
  28377. +            break;
  28378. +/*
  28379. + * FLAG. This is the end of the block. If the block terminated by ESC FLAG,
  28380. + * then the block is to be ignored. In addition, characters before the very
  28381. + * first FLAG are also tossed by this procedure.
  28382. + */
  28383. +        case PPP_FLAG:    /* PPP_FLAG: end of frame */
  28384. +            ppp->stats.ppp_ibytes += ppp->rbuf->count;
  28385. +            if (ppp->escape)
  28386. +                ppp->toss |= 0x80;
  28387. +/*
  28388. + * Process frames which are not to be ignored. If the processing failed,
  28389. + * then clean up the VJ tables.
  28390. + */
  28391. +            if ((ppp->toss & 0x80) != 0 ||
  28392. +                ppp_doframe (ppp) == 0) {
  28393. +                slhc_toss (ppp->slcomp);
  28394. +            }
  28395. +/*
  28396. + * Reset all indicators for the new frame to follow.
  28397. + */
  28398. +            buf->count  = 0;
  28399. +            buf->fcs    = PPP_INITFCS;
  28400. +            ppp->escape = 0;
  28401. +            ppp->toss   = 0;
  28402. +            break;
  28403. +/*
  28404. + * All other characters in the data come here. If the character is in the
  28405. + * receive mask then ignore the character.
  28406. + */
  28407. +        default:
  28408. +            if (in_rmap (ppp, chr))
  28409. +                break;
  28410. +/*
  28411. + * Adjust the character and if the frame is to be discarded then simply
  28412. + * ignore the character until the ending FLAG is received.
  28413. + */
  28414. +            chr ^= ppp->escape;
  28415. +            ppp->escape = 0;
  28416. +
  28417. +            if (ppp->toss != 0)
  28418. +                break;
  28419. +/*
  28420. + * If the count sent is within reason then store the character, bump the
  28421. + * count, and update the FCS for the character.
  28422. + */
  28423. +            if (buf->count < buf->size) {
  28424. +                buf_base (buf)[buf->count++] = chr;
  28425. +                buf->fcs = PPP_FCS (buf->fcs, chr);
  28426. +                break;
  28427. +            }
  28428. +/*
  28429. + * The peer sent too much data. Set the flags to discard the current frame
  28430. + * and wait for the re-synchronization FLAG to be sent.
  28431. + */
  28432. +            ppp->stats.ppp_ierrors++;
  28433. +            ppp->toss |= 0xC0;
  28434. +            break;
  28435. +        }
  28436. +    }
  28437. +}
  28438. +
  28439. +/*
  28440. + * Put the input frame into the networking system for the indicated protocol
  28441. + */
  28442. +
  28443. +static int
  28444. +ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
  28445. +{
  28446. +    sk_buff *skb = dev_alloc_skb (count);
  28447. +/*
  28448. + * Generate a skb buffer for the new frame.
  28449. + */
  28450. +    if (skb == NULL) {
  28451. +        if (ppp->flags & SC_DEBUG)
  28452. +            printk (KERN_ERR
  28453. +             "ppp_do_ip: packet dropped on %s (no memory)!\n",
  28454. +             ppp2dev (ppp)->name);
  28455. +        return 0;
  28456. +    }
  28457. +/*
  28458. + * Move the received data from the input buffer to the skb buffer.
  28459. + */
  28460. +    skb->dev = ppp2dev (ppp);    /* We are the device */
  28461. +#if USE_SKB_PROTOCOL == 0
  28462. +    skb->len = count;
  28463. +#else
  28464. +    skb->protocol = proto;
  28465. +    skb->mac.raw  = skb_data(skb);
  28466. +#endif
  28467. +    memcpy (skb_put(skb,count), data, count);    /* move data */
  28468. +/*
  28469. + * Tag the frame and kick it to the proper receive routine
  28470. + */
  28471. +    skb->free = 1;
  28472. +    ppp->ddinfo.recv_idle = jiffies;
  28473. +    netif_rx (skb);
  28474. +    return 1;
  28475. +}
  28476. +
  28477. +/*
  28478. + * Process the receipt of an IP frame
  28479. + */
  28480. +
  28481. +static int
  28482. +rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count)
  28483. +{
  28484. +    if (ppp2dev (ppp)->flags & IFF_UP) {
  28485. +        if (count > 0)
  28486. +            return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count);
  28487. +    }
  28488. +    return 0;
  28489. +}
  28490. +
  28491. +/*
  28492. + * Process the receipt of an IPX frame
  28493. + */
  28494. +
  28495. +static int
  28496. +rcv_proto_ipx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
  28497. +{
  28498. +#ifdef NEW_SKBUFF
  28499. +    if (ppp2dev (ppp)->flags & IFF_UP) {
  28500. +        if (count > 0)
  28501. +            return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
  28502. +    } else
  28503. +#endif
  28504. +    return 0;
  28505. +}
  28506. +
  28507. +/*
  28508. + * Process the receipt of an VJ Compressed frame
  28509. + */
  28510. +
  28511. +static int
  28512. +rcv_proto_vjc_comp (struct ppp *ppp, unsigned short proto,
  28513. +            u_char *data, int count)
  28514. +{
  28515. +    if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
  28516. +        int new_count = slhc_uncompress (ppp->slcomp, data, count);
  28517. +        if (new_count >= 0) {
  28518. +            return rcv_proto_ip (ppp, PPP_IP, data, new_count);
  28519. +        }
  28520. +        if (ppp->flags & SC_DEBUG)
  28521. +            printk (KERN_NOTICE
  28522. +                "ppp: error in VJ decompression\n");
  28523. +    }
  28524. +    return 0;
  28525. +}
  28526. +
  28527. +/*
  28528. + * Process the receipt of an VJ Un-compressed frame
  28529. + */
  28530. +
  28531. +static int
  28532. +rcv_proto_vjc_uncomp (struct ppp *ppp, unsigned short proto,
  28533. +              u_char *data, int count)
  28534. +{
  28535. +    if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
  28536. +        if (slhc_remember (ppp->slcomp, data, count) > 0) {
  28537. +            return rcv_proto_ip (ppp, PPP_IP, data, count);
  28538. +        }
  28539. +        if (ppp->flags & SC_DEBUG)
  28540. +            printk (KERN_NOTICE
  28541. +                "ppp: error in VJ memorizing\n");
  28542. +    }
  28543. +    return 0;
  28544. +}
  28545. +
  28546. +/*
  28547. + * Receive all unclassified protocols.
  28548. + */
  28549. +
  28550. +static int
  28551. +rcv_proto_unknown (struct ppp *ppp, unsigned short proto,
  28552. +           u_char *data, int len)
  28553. +{
  28554. +    int totlen;
  28555. +    register int current_idx;
  28556. +
  28557. +#define PUTC(c)                         \
  28558. +{                             \
  28559. +    buf_base (ppp->ubuf) [current_idx++] = (u_char) (c); \
  28560. +    current_idx &= ppp->ubuf->size;             \
  28561. +    if (current_idx == ppp->ubuf->tail)             \
  28562. +        goto failure;                 \
  28563. +}
  28564. +
  28565. +/*
  28566. + * The total length includes the protocol data.
  28567. + * Lock the user information buffer.
  28568. + */
  28569. +    if (set_bit (0, &ppp->ubuf->locked)) {
  28570. +        if (ppp->flags & SC_DEBUG)
  28571. +            printk (KERN_DEBUG
  28572. +                "ppp_us_queue: can't get lock\n");
  28573. +    } else {
  28574. +        current_idx = ppp->ubuf->head;
  28575. +/*
  28576. + * Insert the buffer length (not counted), the protocol, and the data
  28577. + */
  28578. +        totlen = len + 2;
  28579. +        PUTC (totlen >> 8);
  28580. +        PUTC (totlen);
  28581. +
  28582. +        PUTC (proto >> 8);
  28583. +        PUTC (proto);
  28584. +
  28585. +        totlen -= 2;
  28586. +        while (totlen-- > 0) {
  28587. +            PUTC (*data++);
  28588. +        }
  28589. +#undef PUTC
  28590. +/*
  28591. + * The frame is complete. Update the head pointer and wakeup the pppd
  28592. + * process.
  28593. + */
  28594. +        ppp->ubuf->head = current_idx;
  28595. +
  28596. +        clear_bit (0, &ppp->ubuf->locked);
  28597. +        wake_up_interruptible (&ppp->read_wait);
  28598. +        if (ppp->tty->fasync != NULL)
  28599. +            kill_fasync (ppp->tty->fasync, SIGIO);
  28600. +
  28601. +        if (ppp->flags & SC_DEBUG)
  28602. +            printk (KERN_INFO
  28603. +                "ppp: successfully queued %d bytes, flags = %x\n",
  28604. +                len + 2, ppp->flags);
  28605. +
  28606. +        return 1;
  28607. +/*
  28608. + * The buffer is full. Unlock the header
  28609. + */
  28610. +failure:
  28611. +        clear_bit (0, &ppp->ubuf->locked);
  28612. +        if (ppp->flags & SC_DEBUG)
  28613. +            printk (KERN_INFO
  28614. +                "ppp_us_queue: ran out of buffer space.\n");
  28615. +    }
  28616. +/*
  28617. + * Discard the frame. There are no takers for this protocol.
  28618. + */
  28619. +    if (ppp->flags & SC_DEBUG)
  28620. +        printk (KERN_WARNING
  28621. +            "ppp: dropping packet on the floor.\n");
  28622. +    slhc_toss (ppp->slcomp);
  28623. +    return 0;
  28624. +}
  28625. +
  28626. +/*
  28627. + * Handle a CCP packet.
  28628. + *
  28629. + * The CCP packet is passed along to the pppd process just like any
  28630. + * other PPP frame. The difference is that some processing needs to be
  28631. + * immediate or the compressors will become confused on the peer.
  28632. + */
  28633. +
  28634. +static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd)
  28635. +{
  28636. +    int slen    = CCP_LENGTH(dp);
  28637. +    u_char *opt = dp   + CCP_HDRLEN;
  28638. +    int opt_len = slen - CCP_HDRLEN;
  28639. +
  28640. +    if (slen > len)
  28641. +        return;
  28642. +
  28643. +    switch (CCP_CODE(dp)) {
  28644. +    case CCP_CONFREQ:
  28645. +    case CCP_TERMREQ:
  28646. +    case CCP_TERMACK:
  28647. +/*
  28648. + * CCP must be going down - disable compression
  28649. + */
  28650. +        if (ppp->flags & SC_CCP_UP) {
  28651. +            ppp->flags &= ~(SC_CCP_UP   |
  28652. +                    SC_COMP_RUN |
  28653. +                    SC_DECOMP_RUN);
  28654. +        }
  28655. +        break;
  28656. +
  28657. +    case CCP_CONFACK:
  28658. +        if ((ppp->flags & SC_CCP_OPEN) == 0)
  28659. +            break;
  28660. +        if (ppp->flags & SC_CCP_UP)
  28661. +            break;
  28662. +        if (slen < (CCP_HDRLEN + CCP_OPT_MINLEN))
  28663. +            break;
  28664. +        if (slen < (CCP_OPT_LENGTH (opt) + CCP_HDRLEN))
  28665. +            break;
  28666. +/*
  28667. + * we're agreeing to send compressed packets.
  28668. + */
  28669. +        if (!rcvd) {
  28670. +            if (ppp->sc_xc_state == NULL)
  28671. +                break;
  28672. +
  28673. +            if ((*ppp->sc_xcomp->comp_init)
  28674. +                (ppp->sc_xc_state,
  28675. +                 opt,
  28676. +                 opt_len,
  28677. +                 ppp2dev (ppp)->base_addr,
  28678. +                 0,
  28679. +                 ppp->flags & SC_DEBUG))
  28680. +                ppp->flags |= SC_COMP_RUN;
  28681. +            break;
  28682. +        }
  28683. +/*
  28684. + * peer is agreeing to send compressed packets.
  28685. + */
  28686. +        if (ppp->sc_rc_state == NULL)
  28687. +            break;
  28688. +
  28689. +        if ((*ppp->sc_rcomp->decomp_init)
  28690. +            (ppp->sc_rc_state,
  28691. +             opt,
  28692. +             opt_len,
  28693. +             ppp2dev (ppp)->base_addr,
  28694. +             0,
  28695. +             ppp->mru,
  28696. +             ppp->flags & SC_DEBUG)) {
  28697. +            ppp->flags |= SC_DECOMP_RUN;
  28698. +            ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
  28699. +        }
  28700. +        break;
  28701. +/*
  28702. + * The protocol sequence is complete at this end
  28703. + */
  28704. +    case CCP_RESETACK:
  28705. +        if ((ppp->flags & SC_CCP_UP) == 0)
  28706. +            break;
  28707. +
  28708. +        if (!rcvd) {
  28709. +            if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN))
  28710. +                (*ppp->sc_xcomp->comp_reset)(ppp->sc_xc_state);
  28711. +        } else {
  28712. +            if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) {
  28713. +                  (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state);
  28714. +                ppp->flags &= ~SC_DC_ERROR;
  28715. +            }
  28716. +        }
  28717. +        break;
  28718. +    }
  28719. +}
  28720. +
  28721. +static int
  28722. +rcv_proto_ccp (struct ppp *ppp, unsigned short proto, u_char *dp, int len)
  28723. +{
  28724. +    ppp_proto_ccp (ppp, dp, len, 1);
  28725. +    return rcv_proto_unknown (ppp, proto, dp, len);
  28726. +}
  28727. +
  28728. +/*
  28729. + * Handle a LQR packet.
  28730. + *
  28731. + * The LQR packet is passed along to the pppd process just like any
  28732. + * other PPP frame. The difference is that some processing needs to be
  28733. + * performed to append the current data to the end of the frame.
  28734. + */
  28735. +
  28736. +static int
  28737. +rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len)
  28738. +{
  28739. +#if 0 /* until support is in the pppd process don't corrupt the reject. */
  28740. +    register u_char *p;
  28741. +    if (len > 8) {
  28742. +        if (len < 48)
  28743. +            memset (&data [len], '\0', 48 - len);
  28744. +/*
  28745. + * Fill in the fields from the driver data
  28746. + */
  28747. +        p = &data [48];
  28748. +        p = store_long (p, ++ppp->stats.ppp_ilqrs);
  28749. +        p = store_long (p, ppp->stats.ppp_ipackets);
  28750. +        p = store_long (p, ppp->stats.ppp_discards);
  28751. +        p = store_long (p, ppp->stats.ppp_ierrors);
  28752. +        p = store_long (p, ppp->stats.ppp_ioctects + len);
  28753. +
  28754. +        len = 68;
  28755. +    }
  28756. +#endif
  28757. +/*
  28758. + * Pass the frame to the pppd daemon.
  28759. + */
  28760. +    return rcv_proto_unknown (ppp, proto, data, len);
  28761. +}
  28762. +
  28763. +/* on entry, a received frame is in ppp->rbuf.bufr
  28764. +   check it and dispose as appropriate */
  28765. +
  28766. +static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int count)
  28767. +{
  28768. +    u_short        proto = PPP_PROTOCOL (data);
  28769. +    ppp_proto_type  *proto_ptr;
  28770. +/*
  28771. + * Ignore empty frames
  28772. + */
  28773. +    if (count <= 4)
  28774. +        return;
  28775. +/*
  28776. + * Count the frame and print it
  28777. + */
  28778. +    ++ppp->stats.ppp_ipackets;
  28779. +    if (ppp->flags & SC_LOG_INPKT)
  28780. +        ppp_print_buffer ("receive frame", data, count);
  28781. +/*
  28782. + * Find the procedure to handle this protocol. The last one is marked
  28783. + * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon.
  28784. + */
  28785. +    proto_ptr = proto_list;
  28786. +    while (proto_ptr->proto != 0 && proto_ptr->proto != proto)
  28787. +        ++proto_ptr;
  28788. +/*
  28789. + * Update the appropriate statistic counter.
  28790. + */
  28791. +    if ((*proto_ptr->func) (ppp, proto,
  28792. +                &data[PPP_HARD_HDR_LEN],
  28793. +                count - PPP_HARD_HDR_LEN))
  28794. +        ppp->stats.ppp_ioctects += count;
  28795. +    else
  28796. +        ++ppp->stats.ppp_discards;
  28797. +}
  28798. +
  28799. +/* on entry, a received frame is in ppp->rbuf.bufr
  28800. +   check it and dispose as appropriate */
  28801. +
  28802. +static int
  28803. +ppp_doframe (struct ppp *ppp)
  28804. +{
  28805. +    u_char    *data = buf_base (ppp->rbuf);
  28806. +    int    count = ppp->rbuf->count;
  28807. +    int    addr, ctrl, proto;
  28808. +    int    new_count;
  28809. +    u_char *new_data;
  28810. +#ifndef NO_RMK_TEMP_FIX
  28811. +    int    malloced_data;
  28812. +#endif
  28813. +/*
  28814. + * If there is a pending error from the receiver then log it and discard
  28815. + * the damaged frame.
  28816. + */
  28817. +    if (ppp->toss) {
  28818. +        if (ppp->flags & SC_DEBUG)
  28819. +            printk (KERN_WARNING
  28820. +                "ppp_toss: tossing frame, reason = %d\n",
  28821. +                ppp->toss);
  28822. +        ppp->stats.ppp_ierrors++;
  28823. +        return 0;
  28824. +    }
  28825. +/*
  28826. + * An empty frame is ignored. This occurs if the FLAG sequence precedes and
  28827. + * follows each frame.
  28828. + */
  28829. +    if (count == 0)
  28830. +        return 1;
  28831. +/*
  28832. + * Generate an error if the frame is too small.
  28833. + */
  28834. +    if (count < PPP_HARD_HDR_LEN) {
  28835. +        if (ppp->flags & SC_DEBUG)
  28836. +            printk (KERN_WARNING
  28837. +                "ppp: got runt ppp frame, %d chars\n", count);
  28838. +        slhc_toss (ppp->slcomp);
  28839. +        ppp->stats.ppp_ierrors++;
  28840. +        return 1;
  28841. +    }
  28842. +/*
  28843. + * Verify the CRC of the frame and discard the CRC characters from the
  28844. + * end of the buffer.
  28845. + */
  28846. +    if (ppp->rbuf->fcs != PPP_GOODFCS) {
  28847. +        if (ppp->flags & SC_DEBUG)
  28848. +            printk (KERN_WARNING
  28849. +                "ppp: frame with bad fcs, excess = %x\n",
  28850. +                ppp->rbuf->fcs ^ PPP_GOODFCS);
  28851. +        ppp->stats.ppp_ierrors++;
  28852. +        return 0;
  28853. +    }
  28854. +    count -= 2;        /* ignore the fcs characters */
  28855. +/*
  28856. + * Ignore the leading ADDRESS and CONTROL fields in the frame.
  28857. + */
  28858. +    addr   = PPP_ALLSTATIONS;
  28859. +    ctrl   = PPP_UI;
  28860. +
  28861. +    if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
  28862. +        data  += 2;
  28863. +        count -= 2;
  28864. +    }
  28865. +/*
  28866. + * Obtain the protocol from the frame
  28867. + */
  28868. +    proto = (u_short) *data++;
  28869. +    if ((proto & 1) == 0) {
  28870. +        proto = (proto << 8) | (u_short) *data++;
  28871. +        --count;
  28872. +    }
  28873. +/*
  28874. + * Rewrite the header with the full information. This may encroach upon
  28875. + * the 'filler' area in the buffer header. This is the purpose for the
  28876. + * filler.
  28877. + */
  28878. +    *(--data) = proto;
  28879. +    *(--data) = proto >> 8;
  28880. +    *(--data) = ctrl;
  28881. +    *(--data) = addr;
  28882. +    count    += 3;
  28883. +#ifndef NO_RMK_TEMP_FIX
  28884. +    /*
  28885. +     * rmk: should make sure that the packet received is on a word boundary.
  28886. +     * this is a temporary fix!!!
  28887. +     */
  28888. +    if ((int)data & 3) {
  28889. +        new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC); /* would like to have 'count' here */
  28890. +        memcpy (new_data, data, count);
  28891. +        data = new_data;
  28892. +        malloced_data = 1;
  28893. +    } else
  28894. +        malloced_data = 0;
  28895. +#endif
  28896. +/*
  28897. + * Process the active decompressor.
  28898. + */
  28899. +    if ((ppp->sc_rc_state != (void *) 0) &&
  28900. +        (ppp->flags & SC_DECOMP_RUN)     &&
  28901. +        ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {
  28902. +        if (proto == PPP_COMP) {
  28903. +/*
  28904. + * If the frame is compressed then decompress it.
  28905. + */
  28906. +            new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC);
  28907. +            if (new_data == NULL) {
  28908. +                if (ppp->flags & SC_DEBUG)
  28909. +                    printk (KERN_ERR
  28910. +                        "ppp_doframe: no memory\n");
  28911. +                slhc_toss (ppp->slcomp);
  28912. +                (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
  28913. +                              data,
  28914. +                              count);
  28915. +#ifndef NO_RMK_TEMP_FIX
  28916. +                if (malloced_data) kfree (data);
  28917. +#endif                              
  28918. +                return 1;
  28919. +            }
  28920. +/*
  28921. + * Decompress the frame
  28922. + */
  28923. +            new_count = bsd_decompress (ppp->sc_rc_state,
  28924. +                            data,
  28925. +                            count,
  28926. +                            new_data,
  28927. +                            ppp->mru + 4);
  28928. +            switch (new_count) {
  28929. +            default:
  28930. +                ppp_doframe_lower (ppp, new_data, new_count);
  28931. +                kfree (new_data);
  28932. +#ifndef NO_RMK_TEMP_FIX
  28933. +                if (malloced_data) kfree (data);
  28934. +#endif
  28935. +                return 1;
  28936. +
  28937. +            case DECOMP_OK:
  28938. +                break;
  28939. +
  28940. +            case DECOMP_ERROR:
  28941. +                ppp->flags |= SC_DC_ERROR;
  28942. +                break;
  28943. +
  28944. +            case DECOMP_FATALERROR:
  28945. +                ppp->flags |= SC_DC_FERROR;
  28946. +                break;
  28947. +            }
  28948. +/*
  28949. + * Log the error condition and discard the frame.
  28950. + */
  28951. +            if (ppp->flags & SC_DEBUG)
  28952. +                printk (KERN_ERR
  28953. +                    "ppp_proto_comp: "
  28954. +                    "decompress err %d\n", new_count);
  28955. +            kfree (new_data);
  28956. +            slhc_toss (ppp->slcomp);
  28957. +#ifndef NO_RMK_TEMP_FIX
  28958. +            if (malloced_data) kfree (data);
  28959. +#endif                              
  28960. +            return 1;
  28961. +        }
  28962. +/*
  28963. + * The frame is not special. Pass it through the compressor without
  28964. + * actually compressing the data
  28965. + */
  28966. +        (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
  28967. +                      data,
  28968. +                      count);
  28969. +    }
  28970. +/*
  28971. + * Process the uncompressed frame.
  28972. + */
  28973. +    ppp_doframe_lower (ppp, data, count);
  28974. +#ifndef NO_RMK_TEMP_FIX
  28975. +    if (malloced_data) kfree (data);
  28976. +#endif                              
  28977. +    return 1;
  28978. +}
  28979. +
  28980. +/*************************************************************
  28981. + * LINE DISCIPLINE SUPPORT
  28982. + *    The following functions form support user programs
  28983. + *    which read and write data on a TTY with the PPP line
  28984. + *    discipline.  Reading is done from a circular queue,
  28985. + *    filled by the lower TTY levels.
  28986. + *************************************************************/
  28987. +
  28988. +/* read a PPP frame from the us_rbuff circular buffer,
  28989. +   waiting if necessary
  28990. +*/
  28991. +
  28992. +static int
  28993. +ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
  28994. +          unsigned int nr)
  28995. +{
  28996. +    struct ppp *ppp = tty2ppp (tty);
  28997. +    u_char c;
  28998. +    int len, indx;
  28999. +
  29000. +#define GETC(c)                        \
  29001. +{                            \
  29002. +    c = buf_base (ppp->ubuf) [ppp->ubuf->tail++];    \
  29003. +    ppp->ubuf->tail &= ppp->ubuf->size;        \
  29004. +}
  29005. +
  29006. +/*
  29007. + * Validate the pointer to the PPP structure
  29008. + */
  29009. +    if (!ppp)
  29010. +        return -EIO;
  29011. +
  29012. +    if (ppp->magic != PPP_MAGIC)
  29013. +        return -EIO;
  29014. +
  29015. +    CHECK_PPP (-ENXIO);
  29016. +
  29017. +    if (ppp->flags & SC_DEBUG)
  29018. +        printk (KERN_DEBUG
  29019. +            "ppp_tty_read: called buf=%p nr=%u\n",
  29020. +            buf, nr);
  29021. +/*
  29022. + * Acquire the read lock.
  29023. + */
  29024. +    for (;;) {
  29025. +        ppp = tty2ppp (tty);
  29026. +        if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
  29027. +            return 0;
  29028. +
  29029. +        if (set_bit (0, &ppp->ubuf->locked) != 0) {
  29030. +            if (ppp->flags & SC_DEBUG)
  29031. +                printk (KERN_DEBUG
  29032. +                     "ppp_tty_read: sleeping(ubuf)\n");
  29033. +
  29034. +            current->timeout = 0;
  29035. +            current->state   = TASK_INTERRUPTIBLE;
  29036. +            schedule ();
  29037. +
  29038. +            if (current->signal & ~current->blocked)
  29039. +                return -EINTR;
  29040. +            continue;
  29041. +        }
  29042. +/*
  29043. + * Before we attempt to write the frame to the user, ensure that the
  29044. + * user has access to the pages for the total buffer length.
  29045. + */
  29046. +        indx = verify_area (VERIFY_WRITE, buf, nr);
  29047. +        if (indx != 0)
  29048. +            return (indx);
  29049. +/*
  29050. + * Fetch the length of the buffer from the first two bytes.
  29051. + */
  29052. +        if (ppp->ubuf->head == ppp->ubuf->tail)
  29053. +            len = 0;
  29054. +        else {
  29055. +            GETC (c);
  29056. +            len = c << 8;
  29057. +            GETC (c);
  29058. +            len += c;
  29059. +        }
  29060. +/*
  29061. + * If there is no length then wait for the data to arrive.
  29062. + */
  29063. +        if (len == 0) {
  29064. +            /* no data */
  29065. +            clear_bit (0, &ppp->ubuf->locked);
  29066. +            if (file->f_flags & O_NONBLOCK) {
  29067. +                if (ppp->flags & SC_DEBUG)
  29068. +                    printk (KERN_DEBUG
  29069. +                        "ppp_tty_read: no data "
  29070. +                        "(EAGAIN)\n");
  29071. +                return -EAGAIN;
  29072. +            }
  29073. +            current->timeout = 0;
  29074. +
  29075. +            if (ppp->flags & SC_DEBUG)
  29076. +                printk (KERN_DEBUG
  29077. +                    "ppp_tty_read: sleeping(read_wait)\n");
  29078. +
  29079. +            interruptible_sleep_on (&ppp->read_wait);
  29080. +            if (current->signal & ~current->blocked)
  29081. +                return -EINTR;
  29082. +            continue;
  29083. +        }
  29084. +/*
  29085. + * Reset the time of the last read operation.
  29086. + */
  29087. +        if (ppp->flags & SC_DEBUG)
  29088. +            printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len);
  29089. +/*
  29090. + * Ensure that the frame will fit within the caller's buffer. If not, then
  29091. + * discard the frame from the input buffer and return an error to the caller.
  29092. + */
  29093. +        if (len + 2 > nr) {
  29094. +            /* Can't copy it, update us_rbuff_head */
  29095. +
  29096. +            if (ppp->flags & SC_DEBUG)
  29097. +                printk (KERN_DEBUG
  29098. +                "ppp: read of %u bytes too small for %d "
  29099. +                "frame\n", nr, len + 2);
  29100. +            ppp->ubuf->tail += len;
  29101. +            ppp->ubuf->tail &= ppp->ubuf->size;
  29102. +            clear_bit (0, &ppp->ubuf->locked);
  29103. +            ppp->stats.ppp_ierrors++;
  29104. +            return -EOVERFLOW;
  29105. +        }
  29106. +/*
  29107. + * Before we attempt to write the frame to the user, ensure that the
  29108. + * page tables are proper.
  29109. + */
  29110. +        indx = verify_area (VERIFY_WRITE, buf, len + 2);
  29111. +        if (indx != 0) {
  29112. +            ppp->ubuf->tail += len;
  29113. +            ppp->ubuf->tail &= ppp->ubuf->size;
  29114. +            clear_bit (0, &ppp->ubuf->locked);
  29115. +            return (indx);
  29116. +        }
  29117. +/*
  29118. + * Fake the insertion of the ADDRESS and CONTROL information because these
  29119. + * were not saved in the buffer.
  29120. + */
  29121. +        put_byte_user (PPP_ALLSTATIONS, buf++);
  29122. +        put_byte_user (PPP_UI,          buf++);
  29123. +
  29124. +        indx = len;
  29125. +/*
  29126. + * Copy the received data from the buffer to the caller's area.
  29127. + */
  29128. +        while (indx-- > 0) {
  29129. +            GETC (c);
  29130. +            put_byte_user (c, buf);
  29131. +            ++buf;
  29132. +        }
  29133. +/*
  29134. + * Release the lock and return the character count in the buffer area.
  29135. + */
  29136. +        clear_bit (0, &ppp->ubuf->locked);
  29137. +        len += 2; /* Account for ADDRESS and CONTROL bytes */
  29138. +        if (ppp->flags & SC_DEBUG)
  29139. +            printk (KERN_DEBUG
  29140. +                "ppp_tty_read: passing %d bytes up\n", len);
  29141. +        return len;
  29142. +    }
  29143. +#undef GETC
  29144. +}
  29145. +
  29146. +/* stuff a character into the transmit buffer, using PPP's way of escaping
  29147. +   special characters.
  29148. +   also, update fcs to take account of new character */
  29149. +
  29150. +extern inline void
  29151. +ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
  29152. +        register u_char chr)
  29153. +{
  29154. +/*
  29155. + * The buffer should not be full.
  29156. + */
  29157. +    if (ppp->flags & SC_DEBUG) {
  29158. +        if ((buf->count < 0) || (buf->count > 3000))
  29159. +            printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
  29160. +                (unsigned int) buf->count,
  29161. +                (unsigned int) chr);
  29162. +    }
  29163. +/*
  29164. + * Update the FCS and if the character needs to be escaped, do it.
  29165. + */
  29166. +    buf->fcs = PPP_FCS (buf->fcs, chr);
  29167. +    if (in_xmap (ppp, chr)) {
  29168. +        chr ^= PPP_TRANS;
  29169. +        ins_char (buf, PPP_ESCAPE);
  29170. +    }
  29171. +/*
  29172. + * Add the character to the buffer.
  29173. + */
  29174. +    ins_char (buf, chr);
  29175. +}
  29176. +
  29177. +/*
  29178. + * Procedure to encode the data with the proper escapement and send the
  29179. + * data to the remote system.
  29180. + */
  29181. +
  29182. +static void
  29183. +ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
  29184. +            u_char *data, int count, int non_ip)
  29185. +{
  29186. +    unsigned short int write_fcs;
  29187. +    int     address, control;
  29188. +    int    proto;
  29189. +/*
  29190. + * Insert the leading FLAG character
  29191. + */
  29192. +    buf->count = 0;
  29193. +
  29194. +    if (non_ip || flag_time == 0)
  29195. +        ins_char (buf, PPP_FLAG);
  29196. +    else {
  29197. +        if (jiffies - ppp->last_xmit > flag_time)
  29198. +            ins_char (buf, PPP_FLAG);
  29199. +    }
  29200. +    ppp->last_xmit = jiffies;
  29201. +    buf->fcs       = PPP_INITFCS;
  29202. +/*
  29203. + * Emit the address/control information if needed
  29204. + */
  29205. +    address = PPP_ADDRESS  (data);
  29206. +    control = PPP_CONTROL  (data);
  29207. +    proto   = PPP_PROTOCOL (data);
  29208. +
  29209. +    if (address != PPP_ALLSTATIONS ||
  29210. +        control != PPP_UI ||
  29211. +        (ppp->flags & SC_COMP_AC) == 0) {
  29212. +        ppp_stuff_char (ppp, buf, address);
  29213. +        ppp_stuff_char (ppp, buf, control);
  29214. +    }
  29215. +/*
  29216. + * Emit the protocol (compressed if possible)
  29217. + */
  29218. +    if ((ppp->flags & SC_COMP_PROT) == 0 || (proto & 0xFF00))
  29219. +        ppp_stuff_char (ppp, buf, proto >> 8);
  29220. +
  29221. +    ppp_stuff_char (ppp, buf, proto);
  29222. +/*
  29223. + * Insert the data
  29224. + */
  29225. +    data  += 4;
  29226. +    count -= 4;
  29227. +
  29228. +    while (count-- > 0)
  29229. +        ppp_stuff_char (ppp, buf, *data++);
  29230. +/*
  29231. + * Add the trailing CRC and the final flag character
  29232. + */
  29233. +    write_fcs = buf->fcs ^ 0xFFFF;
  29234. +    ppp_stuff_char (ppp, buf, write_fcs);
  29235. +    ppp_stuff_char (ppp, buf, write_fcs >> 8);
  29236. +
  29237. +    if (ppp->flags & SC_DEBUG)
  29238. +        printk (KERN_DEBUG "ppp_dev_xmit_lower: fcs is %hx\n",
  29239. +            write_fcs);
  29240. +/*
  29241. + * Add the trailing flag character
  29242. + */
  29243. +    ins_char (buf, PPP_FLAG);
  29244. +/*
  29245. + * Print the buffer
  29246. + */
  29247. +    if (ppp->flags & SC_LOG_FLUSH)
  29248. +        ppp_print_buffer ("ppp flush", buf_base (buf),
  29249. +                  buf->count);
  29250. +    else {
  29251. +        if (ppp->flags & SC_DEBUG)
  29252. +            printk (KERN_DEBUG
  29253. +                "ppp_dev_xmit: writing %d chars\n",
  29254. +                buf->count);
  29255. +    }
  29256. +/*
  29257. + * Send the block to the tty driver.
  29258. + */
  29259. +    ppp->stats.ppp_obytes += buf->count;
  29260. +    ppp_kick_tty (ppp, buf);
  29261. +}
  29262. +
  29263. +/*
  29264. + * Send an frame to the remote with the proper bsd compression.
  29265. + *
  29266. + * Return 0 if frame was queued for transmission.
  29267. + *        1 if frame must be re-queued for later driver support.
  29268. + */
  29269. +
  29270. +static int
  29271. +ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
  29272. +            u_char *data, int count)
  29273. +{
  29274. +    int    proto;
  29275. +    int     address, control;
  29276. +    u_char *new_data;
  29277. +    int     new_count;
  29278. +/*
  29279. + * Print the buffer
  29280. + */
  29281. +    if (ppp->flags & SC_LOG_OUTPKT)
  29282. +        ppp_print_buffer ("write frame", data, count);
  29283. +/*
  29284. + * Determine if the frame may be compressed. Attempt to compress the
  29285. + * frame if possible.
  29286. + */
  29287. +    proto   = PPP_PROTOCOL (data);
  29288. +    address = PPP_ADDRESS  (data);
  29289. +    control = PPP_CONTROL  (data);
  29290. +
  29291. +    if (((ppp->flags & SC_COMP_RUN) != 0)    &&
  29292. +        (ppp->sc_xc_state != (void *) 0)    &&
  29293. +        (address == PPP_ALLSTATIONS)    &&
  29294. +        (control == PPP_UI)            &&
  29295. +        (proto != PPP_LCP)            &&
  29296. +        (proto != PPP_CCP)) {
  29297. +        new_data = kmalloc (count, GFP_ATOMIC);
  29298. +        if (new_data == NULL) {
  29299. +            if (ppp->flags & SC_DEBUG)
  29300. +                printk (KERN_ERR
  29301. +                    "ppp_dev_xmit_frame: no memory\n");
  29302. +            return 1;
  29303. +        }
  29304. +
  29305. +        new_count = bsd_compress (ppp->sc_xc_state,
  29306. +                      data,
  29307. +                      new_data,
  29308. +                      count,
  29309. +                      count);
  29310. +
  29311. +        if (new_count > 0) {
  29312. +            ++ppp->stats.ppp_opackets;
  29313. +            ppp->stats.ppp_ooctects += new_count;
  29314. +
  29315. +            ppp_dev_xmit_lower (ppp, buf, new_data,
  29316. +                        new_count, 0);
  29317. +            kfree (new_data);
  29318. +            return 0;
  29319. +        }
  29320. +/*
  29321. + * The frame could not be compressed.
  29322. + */
  29323. +        kfree (new_data);
  29324. +    }
  29325. +/*
  29326. + * The frame may not be compressed. Update the statistics before the
  29327. + * count field is destroyed. The frame will be transmitted.
  29328. + */
  29329. +    ++ppp->stats.ppp_opackets;
  29330. +    ppp->stats.ppp_ooctects += count;
  29331. +/*
  29332. + * Go to the escape encoding
  29333. + */
  29334. +    ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00));
  29335. +    return 0;
  29336. +}
  29337. +
  29338. +/*
  29339. + * Revise the tty frame for specific protocols.
  29340. + */
  29341. +
  29342. +static int
  29343. +send_revise_frame (register struct ppp *ppp, u_char *data, int len)
  29344. +{
  29345. +    u_char *p;
  29346. +
  29347. +    switch (PPP_PROTOCOL (data)) {
  29348. +/*
  29349. + * Update the LQR frame with the current MIB information. This saves having
  29350. + * the daemon read old MIB data from the driver.
  29351. + */
  29352. +    case PPP_LQR:
  29353. +        len = 48;            /* total size of this frame */
  29354. +        p   = (u_char *) &data [40];    /* Point to last two items. */
  29355. +        p   = store_long (p, ppp->stats.ppp_opackets + 1);
  29356. +        p   = store_long (p, ppp->stats.ppp_ooctects + len);
  29357. +        break;
  29358. +/*
  29359. + * Outbound compression frames
  29360. + */
  29361. +    case PPP_CCP:
  29362. +        ppp_proto_ccp (ppp,
  29363. +                   data + PPP_HARD_HDR_LEN,
  29364. +                   len  - PPP_HARD_HDR_LEN,
  29365. +                   0);
  29366. +        break;
  29367. +/*
  29368. + * All other frame types
  29369. + */
  29370. +    default:
  29371. +        break;
  29372. +    }
  29373. +
  29374. +    return len;
  29375. +}
  29376. +
  29377. +/*
  29378. + * write a frame with NR chars from BUF to TTY
  29379. + * we have to put the FCS field on ourselves
  29380. + */
  29381. +
  29382. +static int
  29383. +ppp_tty_write (struct tty_struct *tty, struct file *file, const u_char * data,
  29384. +           unsigned int count)
  29385. +{
  29386. +    struct ppp *ppp = tty2ppp (tty);
  29387. +    u_char *new_data;
  29388. +    int status;
  29389. +/*
  29390. + * Verify the pointer to the PPP data and that the tty is still in PPP mode.
  29391. + */
  29392. +    if (!ppp)
  29393. +        return -EIO;
  29394. +
  29395. +    if (ppp->magic != PPP_MAGIC)
  29396. +        return -EIO;
  29397. +
  29398. +    CHECK_PPP (-ENXIO);
  29399. +/*
  29400. + * Ensure that the caller does not wish to send too much.
  29401. + */
  29402. +    if (count > PPP_MTU) {
  29403. +        if (ppp->flags & SC_DEBUG)
  29404. +            printk (KERN_WARNING
  29405. +                "ppp_tty_write: truncating user packet "
  29406. +                "from %u to mtu %d\n", count, PPP_MTU);
  29407. +        count = PPP_MTU;
  29408. +    }
  29409. +/*
  29410. + * Allocate a buffer for the data and fetch it from the user space.
  29411. + */
  29412. +    new_data = kmalloc (count, GFP_KERNEL);
  29413. +    if (new_data == NULL) {
  29414. +        if (ppp->flags & SC_DEBUG)
  29415. +            printk (KERN_ERR
  29416. +                "ppp_tty_write: no memory\n");
  29417. +        return 0;
  29418. +    }
  29419. +/*
  29420. + * lock this PPP unit so we will be the only writer;
  29421. + * sleep if necessary
  29422. + */
  29423. +    while (lock_buffer (ppp->tbuf) != 0) {
  29424. +        current->timeout = 0;
  29425. +        if (ppp->flags & SC_DEBUG)
  29426. +            printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
  29427. +        interruptible_sleep_on (&ppp->write_wait);
  29428. +
  29429. +        ppp = tty2ppp (tty);
  29430. +        if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) {
  29431. +            kfree (new_data);
  29432. +            return 0;
  29433. +        }
  29434. +
  29435. +        if (current->signal & ~current->blocked) {
  29436. +            kfree (new_data);
  29437. +            return -EINTR;
  29438. +        }
  29439. +    }
  29440. +/*
  29441. + * Ensure that the caller's buffer is valid.
  29442. + */
  29443. +    status = verify_area (VERIFY_READ, data, count);
  29444. +    if (status != 0) {
  29445. +        kfree (new_data);
  29446. +        ppp->tbuf->locked = 0;
  29447. +        return status;
  29448. +    }
  29449. +
  29450. +    memcpy_fromfs (new_data, data, count);
  29451. +/*
  29452. + * Change the LQR frame
  29453. + */
  29454. +    count = send_revise_frame (ppp, new_data, count);
  29455. +/*
  29456. + * Send the data
  29457. + */
  29458. +    ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count);
  29459. +    kfree (new_data);
  29460. +    return (int) count;
  29461. +}
  29462. +
  29463. +/*
  29464. + * Process the BSD compression IOCTL event for the tty device.
  29465. + */
  29466. +
  29467. +static int
  29468. +ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
  29469. +{
  29470. +    struct compressor *cp;
  29471. +    struct ppp_option_data data;
  29472. +    int error;
  29473. +    int nb;
  29474. +    u_char *ptr;
  29475. +    u_char ccp_option[CCP_MAX_OPTION_LENGTH];
  29476. +/*
  29477. + * Fetch the compression parameters
  29478. + */
  29479. +    error = verify_area (VERIFY_READ, odp, sizeof (data));
  29480. +    if (error == 0) {
  29481. +        memcpy_fromfs (&data, odp, sizeof (data));
  29482. +        nb  = data.length;
  29483. +        ptr = data.ptr;
  29484. +        if ((unsigned long) nb >= (unsigned long)CCP_MAX_OPTION_LENGTH)
  29485. +            nb = CCP_MAX_OPTION_LENGTH;
  29486. +    
  29487. +        error = verify_area (VERIFY_READ, ptr, nb);
  29488. +    }
  29489. +
  29490. +    if (error != 0)
  29491. +        return error;
  29492. +
  29493. +    memcpy_fromfs (ccp_option, ptr, nb);
  29494. +
  29495. +    if (ccp_option[1] < 2)    /* preliminary check on the length byte */
  29496. +        return (-EINVAL);
  29497. +
  29498. +    cp = find_compressor ((int) (unsigned) (unsigned char) ccp_option[0]);
  29499. +    if (cp != (struct compressor *) 0) {
  29500. +        /*
  29501. +         * Found a handler for the protocol - try to allocate
  29502. +         * a compressor or decompressor.
  29503. +         */
  29504. +        error = 0;
  29505. +        if (data.transmit) {
  29506. +            if (ppp->sc_xc_state != NULL)
  29507. +                (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
  29508. +
  29509. +            ppp->sc_xcomp    = cp;
  29510. +            ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
  29511. +
  29512. +            if (ppp->sc_xc_state == NULL) {
  29513. +                if (ppp->flags & SC_DEBUG)
  29514. +                    printk("ppp%ld: comp_alloc failed\n",
  29515. +                           ppp2dev (ppp)->base_addr);
  29516. +                error = -ENOBUFS;
  29517. +            }
  29518. +            ppp->flags &= ~SC_COMP_RUN;
  29519. +        } else {
  29520. +            if (ppp->sc_rc_state != NULL)
  29521. +                (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
  29522. +            ppp->sc_rcomp    = cp;
  29523. +            ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
  29524. +            if (ppp->sc_rc_state == NULL) {
  29525. +                if (ppp->flags & SC_DEBUG)
  29526. +                    printk("ppp%ld: decomp_alloc failed\n",
  29527. +                           ppp2dev (ppp)->base_addr);
  29528. +                error = ENOBUFS;
  29529. +            }
  29530. +            ppp->flags &= ~SC_DECOMP_RUN;
  29531. +        }
  29532. +        return (error);
  29533. +    }
  29534. +
  29535. +    if (ppp->flags & SC_DEBUG)
  29536. +        printk(KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n",
  29537. +               ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1],
  29538. +               ccp_option[2], nb);
  29539. +    return (-EINVAL);    /* no handler found */
  29540. +}
  29541. +
  29542. +/*
  29543. + * Process the IOCTL event for the tty device.
  29544. + */
  29545. +
  29546. +static int
  29547. +ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
  29548. +           unsigned long param3)
  29549. +{
  29550. +    struct ppp *ppp = tty2ppp (tty);
  29551. +    register int temp_i = 0;
  29552. +    int error;
  29553. +/*
  29554. + * Verify the status of the PPP device.
  29555. + */
  29556. +    if (!ppp)
  29557. +        return -EBADF;
  29558. +
  29559. +    if (ppp->magic != PPP_MAGIC)
  29560. +        return -EBADF;
  29561. +
  29562. +    CHECK_PPP (-ENXIO);
  29563. +/*
  29564. + * The user must have an euid of root to do these requests.
  29565. + */
  29566. +    if (!suser ())
  29567. +        return -EPERM;
  29568. +/*
  29569. + * Set the MRU value
  29570. + */
  29571. +    switch (param2) {
  29572. +    case PPPIOCSMRU:
  29573. +        error = verify_area (VERIFY_READ, (void *) param3,
  29574. +                     sizeof (temp_i));
  29575. +        if (error == 0) {
  29576. +            temp_i = get_int_user ((int *) param3);
  29577. +            if (ppp->flags & SC_DEBUG)
  29578. +                printk (KERN_INFO
  29579. +                 "ppp_tty_ioctl: set mru to %x\n", temp_i);
  29580. +
  29581. +            if (ppp->mru != temp_i)
  29582. +                ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i);
  29583. +        }
  29584. +        break;
  29585. +/*
  29586. + * Fetch the flags
  29587. + */
  29588. +    case PPPIOCGFLAGS:
  29589. +        error = verify_area (VERIFY_WRITE, (void *) param3,
  29590. +                     sizeof (temp_i));
  29591. +        if (error == 0) {
  29592. +            temp_i = (ppp->flags & SC_MASK);
  29593. +#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
  29594. +            temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
  29595. +                  SC_RCV_ODDP | SC_RCV_EVNP;
  29596. +#endif
  29597. +            put_long_user ((long) temp_i, param3);
  29598. +            if (ppp->flags & SC_DEBUG)
  29599. +                printk (KERN_DEBUG
  29600. +                "ppp_tty_ioctl: get flags: addr %lx flags "
  29601. +                "%x\n", param3, temp_i);
  29602. +        }
  29603. +        break;
  29604. +/*
  29605. + * Set the flags for the various options
  29606. + */
  29607. +    case PPPIOCSFLAGS:
  29608. +        error = verify_area (VERIFY_READ, (void *) param3,
  29609. +                     sizeof (temp_i));
  29610. +        if (error == 0) {
  29611. +            temp_i  = get_int_user (param3) & SC_MASK;
  29612. +            temp_i |= (ppp->flags & ~SC_MASK);
  29613. +
  29614. +            if ((ppp->flags & SC_CCP_OPEN) &&
  29615. +                (temp_i & SC_CCP_OPEN) == 0)
  29616. +                ppp_ccp_closed (ppp);
  29617. +
  29618. +            if ((ppp->flags | temp_i) & SC_DEBUG)
  29619. +                printk (KERN_INFO
  29620. +                   "ppp_tty_ioctl: set flags to %x\n", temp_i);
  29621. +            ppp->flags = temp_i;
  29622. +        }
  29623. +        break;
  29624. +/*
  29625. + * Set the compression mode
  29626. + */
  29627. +    case PPPIOCSCOMPRESS:
  29628. +        error = ppp_set_compression (ppp,
  29629. +                        (struct ppp_option_data *) param3);
  29630. +        break;
  29631. +/*
  29632. + * Retrieve the transmit async map
  29633. + */
  29634. +    case PPPIOCGASYNCMAP:
  29635. +        error = verify_area (VERIFY_WRITE, (void *) param3,
  29636. +                     sizeof (temp_i));
  29637. +        if (error == 0) {
  29638. +            put_long_user (ppp->xmit_async_map[0], param3);
  29639. +            if (ppp->flags & SC_DEBUG)
  29640. +                printk (KERN_INFO
  29641. +                     "ppp_tty_ioctl: get asyncmap: addr "
  29642. +                     "%lx asyncmap %lx\n",
  29643. +                     param3,
  29644. +                     (unsigned long) ppp->xmit_async_map[0]);
  29645. +        }
  29646. +        break;
  29647. +/*
  29648. + * Set the transmit async map
  29649. + */
  29650. +    case PPPIOCSASYNCMAP:
  29651. +        error = verify_area (VERIFY_READ, (void *) param3,
  29652. +                     sizeof (temp_i));
  29653. +        if (error == 0) {
  29654. +            ppp->xmit_async_map[0] = get_long_user (param3);
  29655. +            if (ppp->flags & SC_DEBUG)
  29656. +                printk (KERN_INFO
  29657. +                     "ppp_tty_ioctl: set xmit asyncmap %lx\n",
  29658. +                     (unsigned long) ppp->xmit_async_map[0]);
  29659. +        }
  29660. +        break;
  29661. +/*
  29662. + * Set the receive async map
  29663. + */
  29664. +    case PPPIOCSRASYNCMAP:
  29665. +        error = verify_area (VERIFY_READ, (void *) param3,
  29666. +                     sizeof (temp_i));
  29667. +        if (error == 0) {
  29668. +            ppp->recv_async_map = get_long_user (param3);
  29669. +            if (ppp->flags & SC_DEBUG)
  29670. +                printk (KERN_INFO
  29671. +                     "ppp_tty_ioctl: set rcv asyncmap %lx\n",
  29672. +                     (unsigned long) ppp->recv_async_map);
  29673. +        }
  29674. +        break;
  29675. +/*
  29676. + * Obtain the unit number for this device.
  29677. + */
  29678. +    case PPPIOCGUNIT:
  29679. +        error = verify_area (VERIFY_WRITE, (void *) param3,
  29680. +                     sizeof (temp_i));
  29681. +        if (error == 0) {
  29682. +            put_long_user (ppp2dev (ppp)->base_addr, param3);
  29683. +            if (ppp->flags & SC_DEBUG)
  29684. +                printk (KERN_INFO
  29685. +                    "ppp_tty_ioctl: get unit: %ld",
  29686. +                    ppp2dev (ppp)->base_addr);
  29687. +        }
  29688. +        break;
  29689. +/*
  29690. + * Set the debug level
  29691. + */
  29692. +    case PPPIOCSDEBUG:
  29693. +        error = verify_area (VERIFY_READ, (void *) param3,
  29694. +                     sizeof (temp_i));
  29695. +        if (error == 0) {
  29696. +            temp_i  = (get_int_user (param3) & 0x1F) << 16;
  29697. +            temp_i |= (ppp->flags & ~0x1F0000);
  29698. +
  29699. +            if ((ppp->flags | temp_i) & SC_DEBUG)
  29700. +                printk (KERN_INFO
  29701. +                   "ppp_tty_ioctl: set flags to %x\n", temp_i);
  29702. +            ppp->flags = temp_i;
  29703. +        }
  29704. +        break;
  29705. +/*
  29706. + * Get the debug level
  29707. + */
  29708. +    case PPPIOCGDEBUG:
  29709. +        error = verify_area (VERIFY_WRITE, (void *) param3,
  29710. +                     sizeof (temp_i));
  29711. +        if (error == 0) {
  29712. +            temp_i = (ppp->flags >> 16) & 0x1F;
  29713. +            put_long_user ((long) temp_i, param3);
  29714. +
  29715. +            if (ppp->flags & SC_DEBUG)
  29716. +                printk (KERN_INFO
  29717. +                    "ppp_tty_ioctl: get debug level %d\n",
  29718. +                    temp_i);
  29719. +              }
  29720. +        break;
  29721. +/*
  29722. + * Get the times since the last send/receive frame operation
  29723. + */
  29724. +    case PPPIOCGIDLE:
  29725. +        error = verify_area (VERIFY_WRITE, (void *) param3,
  29726. +                     sizeof (struct ppp_idle));
  29727. +        if (error == 0) {
  29728. +            struct ppp_idle cur_ddinfo;
  29729. +            unsigned long cur_jiffies = jiffies;
  29730. +
  29731. +            /* change absolute times to relative times. */
  29732. +            cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ;
  29733. +            cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ;
  29734. +            memcpy_tofs ((void *) param3, &cur_ddinfo,
  29735. +                     sizeof (cur_ddinfo));
  29736. +            if (ppp->flags & SC_DEBUG)
  29737. +                printk (KERN_INFO
  29738. +                "ppp_tty_ioctl: read demand dial info\n");
  29739. +        }
  29740. +        break;
  29741. +/*
  29742. + * Retrieve the extended async map
  29743. + */
  29744. +    case PPPIOCGXASYNCMAP:
  29745. +        error = verify_area (VERIFY_WRITE,
  29746. +                     (void *) param3,
  29747. +                     sizeof (ppp->xmit_async_map));
  29748. +        if (error == 0) {
  29749. +            memcpy_tofs ((void *) param3,
  29750. +                     ppp->xmit_async_map,
  29751. +                     sizeof (ppp->xmit_async_map));
  29752. +
  29753. +            if (ppp->flags & SC_DEBUG)
  29754. +                printk (KERN_INFO
  29755. +                "ppp_tty_ioctl: get xasyncmap: addr %lx\n",
  29756. +                param3);
  29757. +        }
  29758. +        break;
  29759. +/*
  29760. + * Set the async extended map
  29761. + */
  29762. +    case PPPIOCSXASYNCMAP:
  29763. +        error = verify_area (VERIFY_READ, (void *) param3,
  29764. +                     sizeof (ppp->xmit_async_map));
  29765. +        if (error == 0) {
  29766. +            __u32 temp_tbl[8];
  29767. +
  29768. +            memcpy_fromfs (temp_tbl, (void *) param3,
  29769. +                       sizeof (ppp->xmit_async_map));
  29770. +            temp_tbl[1]  =  0x00000000;
  29771. +            temp_tbl[2] &= ~0x40000000;
  29772. +            temp_tbl[3] |=  0x60000000;
  29773. +
  29774. +            if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
  29775. +                (temp_tbl[4] & temp_tbl[5]) != 0 ||
  29776. +                (temp_tbl[6] & temp_tbl[7]) != 0)
  29777. +                error = -EINVAL;
  29778. +            else {
  29779. +                memcpy (ppp->xmit_async_map, temp_tbl,
  29780. +                    sizeof (ppp->xmit_async_map));
  29781. +
  29782. +                if (ppp->flags & SC_DEBUG)
  29783. +                    printk (KERN_INFO
  29784. +                    "ppp_tty_ioctl: set xasyncmap\n");
  29785. +            }
  29786. +        }
  29787. +        break;
  29788. +/*
  29789. + * Set the maximum VJ header compression slot number.
  29790. + */
  29791. +    case PPPIOCSMAXCID:
  29792. +        error = verify_area (VERIFY_READ, (void *) param3,
  29793. +                     sizeof (temp_i));
  29794. +        if (error == 0) {
  29795. +            temp_i = get_int_user (param3) + 1;
  29796. +            if (ppp->flags & SC_DEBUG)
  29797. +                printk (KERN_INFO
  29798. +                     "ppp_tty_ioctl: set maxcid to %d\n",
  29799. +                     temp_i);
  29800. +            if (ppp->slcomp != NULL)
  29801. +                slhc_free (ppp->slcomp);
  29802. +            ppp->slcomp = slhc_init (16, temp_i);
  29803. +
  29804. +            if (ppp->slcomp == NULL) {
  29805. +                if (ppp->flags & SC_DEBUG)
  29806. +                    printk (KERN_ERR
  29807. +                    "ppp: no space for compression buffers!\n");
  29808. +                ppp_release (ppp);
  29809. +                error = -ENOMEM;
  29810. +            }
  29811. +        }
  29812. +        break;
  29813. +/*
  29814. + * Allow users to read, but not set, the serial port parameters
  29815. + */
  29816. +    case TCGETS:
  29817. +    case TCGETA:
  29818. +        error = n_tty_ioctl (tty, file, param2, param3);
  29819. +        break;
  29820. +/*
  29821. + *  All other ioctl() events will come here.
  29822. + */
  29823. +    default:
  29824. +        if (ppp->flags & SC_DEBUG)
  29825. +            printk (KERN_ERR
  29826. +                "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n",
  29827. +                param2,
  29828. +                param3);
  29829. +
  29830. +        error = -ENOIOCTLCMD;
  29831. +        break;
  29832. +    }
  29833. +    return error;
  29834. +}
  29835. +
  29836. +/*
  29837. + * TTY callback.
  29838. + *
  29839. + * Process the select() statement for the PPP device.
  29840. + */
  29841. +
  29842. +static int
  29843. +ppp_tty_select (struct tty_struct *tty, struct inode *inode,
  29844. +        struct file *filp, int sel_type, select_table * wait)
  29845. +{
  29846. +    struct ppp *ppp = tty2ppp (tty);
  29847. +    int result = 1;
  29848. +/*
  29849. + * Verify the status of the PPP device.
  29850. + */
  29851. +    if (!ppp)
  29852. +        return -EBADF;
  29853. +
  29854. +    if (ppp->magic != PPP_MAGIC)
  29855. +        return -EBADF;
  29856. +
  29857. +    CHECK_PPP (0);
  29858. +/*
  29859. + * Branch on the type of select mode. A read request must lock the user
  29860. + * buffer area.
  29861. + */
  29862. +    switch (sel_type) {
  29863. +    case SEL_IN:
  29864. +        if (set_bit (0, &ppp->ubuf->locked) == 0) {
  29865. +            /* Test for the presence of data in the queue */
  29866. +            if (ppp->ubuf->head != ppp->ubuf->tail) {
  29867. +                clear_bit (0, &ppp->ubuf->locked);
  29868. +                break;
  29869. +            }
  29870. +            clear_bit (0, &ppp->ubuf->locked);
  29871. +        }        /* fall through */
  29872. +        /*
  29873. + * Exceptions or read errors.
  29874. + */
  29875. +    case SEL_EX:
  29876. +        /* Is this a pty link and the remote disconnected? */
  29877. +        if (tty->flags & (1 << TTY_SLAVE_CLOSED))
  29878. +            break;
  29879. +
  29880. +        /* Is this a local link and the modem disconnected? */
  29881. +        if (tty_hung_up_p (filp))
  29882. +            break;
  29883. +
  29884. +        select_wait (&ppp->read_wait, wait);
  29885. +        result = 0;
  29886. +        break;
  29887. +/*
  29888. + * Write mode. A write is allowed if there is no current transmission.
  29889. + */
  29890. +    case SEL_OUT:
  29891. +        if (ppp->tbuf->locked != 0) {
  29892. +            select_wait (&ppp->write_wait, wait);
  29893. +            result = 0;
  29894. +        }
  29895. +        break;
  29896. +    }
  29897. +    return result;
  29898. +}
  29899. +
  29900. +/*************************************************************
  29901. + * NETWORK OUTPUT
  29902. + *    This routine accepts requests from the network layer
  29903. + *    and attempts to deliver the packets.
  29904. + *    It also includes various routines we are compelled to
  29905. + *    have to make the network layer work (arp, etc...).
  29906. + *************************************************************/
  29907. +
  29908. +/*
  29909. + * Callback from the network layer when the device goes up.
  29910. + */
  29911. +
  29912. +static int
  29913. +ppp_dev_open (struct device *dev)
  29914. +{
  29915. +    struct ppp *ppp = dev2ppp (dev);
  29916. +
  29917. +    /* reset POINTOPOINT every time, since dev_close zaps it! */
  29918. +    dev->flags |= IFF_POINTOPOINT;
  29919. +
  29920. +    if (ppp2tty (ppp) == NULL) {
  29921. +        if (ppp->flags & SC_DEBUG)
  29922. +            printk (KERN_ERR
  29923. +            "ppp: %s not connected to a TTY! can't go open!\n",
  29924. +            dev->name);
  29925. +        return -ENXIO;
  29926. +    }
  29927. +
  29928. +    if (ppp->flags & SC_DEBUG)
  29929. +        printk (KERN_INFO
  29930. +            "ppp: channel %s going up for IP packets!\n",
  29931. +            dev->name);
  29932. +
  29933. +    CHECK_PPP (-ENXIO);
  29934. +    return 0;
  29935. +}
  29936. +
  29937. +/*
  29938. + * Callback from the network layer when the ppp device goes down.
  29939. + */
  29940. +
  29941. +static int
  29942. +ppp_dev_close (struct device *dev)
  29943. +{
  29944. +    struct ppp *ppp = dev2ppp (dev);
  29945. +
  29946. +    if (ppp2tty (ppp) == NULL) {
  29947. +        if (ppp->flags & SC_DEBUG)
  29948. +            printk (KERN_ERR
  29949. +            "ppp: %s not connected to a TTY! can't go down!\n",
  29950. +            dev->name);
  29951. +        return -ENXIO;
  29952. +    }
  29953. +/*
  29954. + * We don't do anything about the device going down. It is not important
  29955. + * for us.
  29956. + */
  29957. +    if (ppp->flags & SC_DEBUG)
  29958. +        printk (KERN_INFO
  29959. +            "ppp: channel %s going down for IP packets!\n",
  29960. +            dev->name);
  29961. +    CHECK_PPP (-ENXIO);
  29962. +    return 0;
  29963. +}
  29964. +
  29965. +/*
  29966. + * IOCTL operation to read the version of the driver.
  29967. + */
  29968. +
  29969. +static int
  29970. +ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr)
  29971. +{
  29972. +        int error;
  29973. +    int len;
  29974. +    char *result;
  29975. +/*
  29976. + * Must have write access to the buffer.
  29977. + */
  29978. +    result = (char *) ifr->ifr_ifru.ifru_data;
  29979. +    len    = strlen (szVersion) + 1;
  29980. +    error  = verify_area (VERIFY_WRITE, result, len);
  29981. +/*
  29982. + * Move the version data
  29983. + */
  29984. +    if (error == 0)
  29985. +        memcpy_tofs (result, szVersion, len);
  29986. +
  29987. +    return error;
  29988. +}
  29989. +
  29990. +/*
  29991. + * IOCTL to read the statistics for the pppstats program.
  29992. + */
  29993. +
  29994. +static int
  29995. +ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
  29996. +{
  29997. +    struct ppp_stats *result, temp;
  29998. +    int    error;
  29999. +/*
  30000. + * Must have write access to the buffer.
  30001. + */
  30002. +    result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
  30003. +    error = verify_area (VERIFY_WRITE,
  30004. +                 result,
  30005. +                 sizeof (temp));
  30006. +/*
  30007. + * Supply the information for the caller. First move the version data
  30008. + * then move the ppp stats; and finally the vj stats.
  30009. + */
  30010. +    memset (&temp, 0, sizeof(temp));
  30011. +    if (error == 0 && dev->flags & IFF_UP) {
  30012. +        memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
  30013. +        if (ppp->slcomp != NULL) {
  30014. +            temp.vj.vjs_packets    = ppp->slcomp->sls_o_compressed+
  30015. +                         ppp->slcomp->sls_o_uncompressed;
  30016. +            temp.vj.vjs_compressed = ppp->slcomp->sls_o_compressed;
  30017. +            temp.vj.vjs_searches   = ppp->slcomp->sls_o_searches;
  30018. +            temp.vj.vjs_misses     = ppp->slcomp->sls_o_misses;
  30019. +            temp.vj.vjs_errorin    = ppp->slcomp->sls_i_error;
  30020. +            temp.vj.vjs_tossed     = ppp->slcomp->sls_i_tossed;
  30021. +            temp.vj.vjs_uncompressedin = ppp->slcomp->sls_i_uncompressed;
  30022. +            temp.vj.vjs_compressedin   = ppp->slcomp->sls_i_compressed;
  30023. +        }
  30024. +    }
  30025. +/*
  30026. + * Move the data to the caller's buffer
  30027. + */
  30028. +    if (error == 0)
  30029. +        memcpy_tofs (result, &temp, sizeof (temp));
  30030. +    return error;
  30031. +}
  30032. +
  30033. +/*
  30034. + * IOCTL to read the compression statistics for the pppstats program.
  30035. + */
  30036. +
  30037. +static int
  30038. +ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
  30039. +{
  30040. +    struct ppp_comp_stats *result, temp;
  30041. +    int    error;
  30042. +/*
  30043. + * Must have write access to the buffer.
  30044. + */
  30045. +    result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
  30046. +    error = verify_area (VERIFY_WRITE,
  30047. +                 result,
  30048. +                 sizeof (temp));
  30049. +/*
  30050. + * Supply the information for the caller.
  30051. + */
  30052. +    memset (&temp, 0, sizeof(temp));
  30053. +    if (error == 0 && dev->flags & IFF_UP) {
  30054. +        if (ppp->sc_xc_state != NULL)
  30055. +            (*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state,
  30056. +                             &temp.c);
  30057. +
  30058. +        if (ppp->sc_rc_state != NULL)
  30059. +            (*ppp->sc_rcomp->decomp_stat) (ppp->sc_rc_state,
  30060. +                               &temp.d);
  30061. +    }
  30062. +/*
  30063. + * Move the data to the caller's buffer
  30064. + */
  30065. +    if (error == 0)
  30066. +        memcpy_tofs (result, &temp, sizeof (temp));
  30067. +    return error;
  30068. +}
  30069. +
  30070. +/*
  30071. + * Callback from the network layer to process the sockioctl functions.
  30072. + */
  30073. +
  30074. +static int
  30075. +ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
  30076. +{
  30077. +    struct ppp *ppp = dev2ppp (dev);
  30078. +    int error;
  30079. +/*
  30080. + * Process the requests
  30081. + */
  30082. +    switch (cmd) {
  30083. +    case SIOCGPPPSTATS:
  30084. +        error = ppp_dev_ioctl_stats (ppp, ifr, dev);
  30085. +        break;
  30086. +
  30087. +    case SIOCGPPPCSTATS:
  30088. +        error = ppp_dev_ioctl_comp_stats (ppp, ifr, dev);
  30089. +        break;
  30090. +
  30091. +    case SIOCGPPPVER:
  30092. +        error = ppp_dev_ioctl_version (ppp, ifr);
  30093. +        break;
  30094. +
  30095. +    default:
  30096. +        error = -EINVAL;
  30097. +        break;
  30098. +    }
  30099. +    return error;
  30100. +}
  30101. +
  30102. +/*
  30103. + * Send an IP frame to the remote with vj header compression.
  30104. + *
  30105. + * Return 0 if frame was queued for transmission.
  30106. + *        1 if frame must be re-queued for later driver support.
  30107. + */
  30108. +
  30109. +static int
  30110. +ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data)
  30111. +{
  30112. +    int      proto = PPP_IP;
  30113. +    int     len;
  30114. +    struct ppp_hdr    *hdr;
  30115. +    struct tty_struct *tty = ppp2tty (ppp);
  30116. +/*
  30117. + * Obtain the length from the IP header.
  30118. + */
  30119. +    len = ((struct iphdr *)data) -> tot_len;
  30120. +    len = ntohs (len);
  30121. +/*
  30122. + * Validate the tty interface
  30123. + */
  30124. +    if (tty == NULL) {
  30125. +        if (ppp->flags & SC_DEBUG)
  30126. +            printk (KERN_ERR
  30127. +                "ppp_dev_xmit: %s not connected to a TTY!\n",
  30128. +                dev->name);
  30129. +        return 0;
  30130. +    }
  30131. +/*
  30132. + * Ensure that the PPP device is still up
  30133. + */
  30134. +    if (!(dev->flags & IFF_UP)) {
  30135. +        if (ppp->flags & SC_DEBUG)
  30136. +            printk (KERN_WARNING
  30137. +                "ppp_dev_xmit: packet sent on interface %s,"
  30138. +                " which is down for IP\n",
  30139. +                dev->name);
  30140. +        return 0;
  30141. +    }
  30142. +/*
  30143. + * Detect a change in the transfer size
  30144. + */
  30145. +    if (ppp->mtu != ppp2dev (ppp)->mtu) {
  30146. +        ppp_changedmtu (ppp,
  30147. +                ppp2dev (ppp)->mtu,
  30148. +                ppp->mru);
  30149. +    }
  30150. +/*
  30151. + * Acquire the lock on the transmission buffer. If the buffer was busy then
  30152. + * mark the device as busy and return "failure to send, try back later" error.
  30153. + */
  30154. +    if (lock_buffer (ppp->wbuf) != 0) {
  30155. +        dev->tbusy = 1;
  30156. +        return 1;
  30157. +    }
  30158. +/*
  30159. + * Print the frame being sent
  30160. + */
  30161. +    if (ppp->flags & SC_LOG_OUTPKT)
  30162. +        ppp_print_buffer ("ppp outpkt", data, len);
  30163. +/*
  30164. + * At this point, the buffer will be transmitted. There is no other exit.
  30165. + *
  30166. + * Try to compress the header.
  30167. + */
  30168. +    if (ppp->flags & SC_COMP_TCP) {
  30169. +        len = slhc_compress (ppp->slcomp, data, len,
  30170. +                     buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN,
  30171. +                     &data,
  30172. +                     (ppp->flags & SC_NO_TCP_CCID) == 0);
  30173. +
  30174. +        if (data[0] & SL_TYPE_COMPRESSED_TCP) {
  30175. +            proto    = PPP_VJC_COMP;
  30176. +            data[0] ^= SL_TYPE_COMPRESSED_TCP;
  30177. +        } else {
  30178. +            if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
  30179. +                proto = PPP_VJC_UNCOMP;
  30180. +            data[0] = (data[0] & 0x0f) | 0x40;
  30181. +        }
  30182. +    }
  30183. +/*
  30184. + * Send the frame
  30185. + */
  30186. +    len  += PPP_HARD_HDR_LEN;
  30187. +    hdr   = &((struct ppp_hdr *) data)[-1];
  30188. +
  30189. +    hdr->address     = PPP_ALLSTATIONS;
  30190. +    hdr->control     = PPP_UI;
  30191. +    hdr->protocol[0] = 0;
  30192. +    hdr->protocol[1] = proto;
  30193. +
  30194. +    return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len);
  30195. +}
  30196. +
  30197. +/*
  30198. + * This is just an interum solution until the 1.3 kernel's networking is
  30199. + * available. The 1.2 kernel has problems with device headers before the
  30200. + * buffers.
  30201. + *
  30202. + * This routine should be deleted, and the ppp_dev_xmit_ip1 routine called
  30203. + * by this name.
  30204. + */
  30205. +
  30206. +static int
  30207. +ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data)
  30208. +{
  30209. +    struct ppp_hdr *hdr;
  30210. +    int     len;
  30211. +    int     answer;
  30212. +
  30213. +    len = ((struct iphdr *)data) -> tot_len;
  30214. +    len = ntohs (len);
  30215. +
  30216. +    hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr),
  30217. +                      GFP_ATOMIC);
  30218. +
  30219. +    if (hdr == NULL)
  30220. +        answer = 1;
  30221. +    else {
  30222. +        memcpy (&hdr[1], data, len);
  30223. +        answer = ppp_dev_xmit_ip1 (dev, ppp, (u_char *) &hdr[1]);
  30224. +        kfree (hdr);
  30225. +    }
  30226. +
  30227. +    return answer;
  30228. +}
  30229. +
  30230. +/*
  30231. + * Send an IPX (or any other non-IP) frame to the remote.
  30232. + *
  30233. + * Return 0 if frame was queued for transmission.
  30234. + *        1 if frame must be re-queued for later driver support.
  30235. + */
  30236. +
  30237. +#ifdef NEW_SKBUFF
  30238. +static int
  30239. +ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp,
  30240. +          u_char *data, int len, int proto)
  30241. +{
  30242. +    struct tty_struct *tty = ppp2tty (ppp);
  30243. +    struct ppp_hdr    *hdr;
  30244. +/*
  30245. + * Validate the tty interface
  30246. + */
  30247. +    if (tty == NULL) {
  30248. +        if (ppp->flags & SC_DEBUG)
  30249. +            printk (KERN_ERR
  30250. +                "ppp_dev_xmit: %s not connected to a TTY!\n",
  30251. +                dev->name);
  30252. +        return 0;
  30253. +    }
  30254. +/*
  30255. + * Ensure that the PPP device is still up
  30256. + */
  30257. +    if (!(dev->flags & IFF_UP)) {
  30258. +        if (ppp->flags & SC_DEBUG)
  30259. +            printk (KERN_WARNING
  30260. +                "ppp_dev_xmit: packet sent on interface %s,"
  30261. +                " which is down\n",
  30262. +                dev->name);
  30263. +        return 0;
  30264. +    }
  30265. +/*
  30266. + * Detect a change in the transfer size
  30267. + */
  30268. +    if (ppp->mtu != ppp2dev (ppp)->mtu) {
  30269. +        ppp_changedmtu (ppp,
  30270. +                ppp2dev (ppp)->mtu,
  30271. +                ppp->mru);
  30272. +    }
  30273. +/*
  30274. + * Acquire the lock on the transmission buffer. If the buffer was busy then
  30275. + * mark the device as busy and return "failure to send, try back later" error.
  30276. + */
  30277. +    if (lock_buffer (ppp->wbuf) != 0) {
  30278. +        dev->tbusy = 1;
  30279. +        return 1;
  30280. +    }
  30281. +/*
  30282. + * Print the frame being sent
  30283. + */
  30284. +    if (ppp->flags & SC_LOG_OUTPKT)
  30285. +        ppp_print_buffer ("ppp outpkt", data, len);
  30286. +/*
  30287. + * Send the frame
  30288. + */
  30289. +    len  += PPP_HARD_HDR_LEN;
  30290. +    hdr   = &((struct ppp_hdr *) data)[-1];
  30291. +
  30292. +    hdr->address     = PPP_ALLSTATIONS;
  30293. +    hdr->control     = PPP_UI;
  30294. +    hdr->protocol[0] = proto >> 8;
  30295. +    hdr->protocol[1] = proto;
  30296. +
  30297. +    return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len);
  30298. +}
  30299. +
  30300. +/*
  30301. + * This is just an interum solution until the 1.3 kernel's networking is
  30302. + * available. The 1.2 kernel has problems with device headers before the
  30303. + * buffers.
  30304. + *
  30305. + * This routine should be deleted, and the ppp_dev_xmit_ipx1 routine called
  30306. + * by this name.
  30307. + */
  30308. +
  30309. +static int
  30310. +ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
  30311. +          u_char *data, int len, int proto)
  30312. +{
  30313. +    struct ppp_hdr    *hdr;
  30314. +    int     answer;
  30315. +
  30316. +    hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr),
  30317. +                      GFP_ATOMIC);
  30318. +    if (hdr == NULL)
  30319. +        answer = 1;
  30320. +    else {
  30321. +        memcpy (&hdr[1], data, len);
  30322. +        answer = ppp_dev_xmit_ipx1 (dev, ppp, (u_char *) &hdr[1],
  30323. +                        len, proto);
  30324. +        kfree (hdr);
  30325. +    }
  30326. +
  30327. +    return answer;
  30328. +}
  30329. +#endif
  30330. +
  30331. +/*
  30332. + * Send a frame to the remote.
  30333. + */
  30334. +
  30335. +static int
  30336. +ppp_dev_xmit (sk_buff *skb, struct device *dev)
  30337. +{
  30338. +    int answer, len;
  30339. +    u_char *data;
  30340. +    struct ppp        *ppp = dev2ppp (dev);
  30341. +    struct tty_struct *tty = ppp2tty (ppp);
  30342. +/*
  30343. + * just a little sanity check.
  30344. + */
  30345. +    if (skb == NULL) {
  30346. +        if (ppp->flags & SC_DEBUG)
  30347. +            printk (KERN_WARNING "ppp_dev_xmit: null packet!\n");
  30348. +        return 0;
  30349. +    }
  30350. +/*
  30351. + * Avoid timing problem should tty hangup while data is queued to be sent
  30352. + */
  30353. +    if (!ppp->inuse) {
  30354. +        dev_kfree_skb (skb, FREE_WRITE);
  30355. +        dev_close (dev);
  30356. +        return 0;
  30357. +    }
  30358. +/*
  30359. + * Validate the tty linkage
  30360. + */
  30361. +    if (ppp->flags & SC_DEBUG)
  30362. +        printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %p\n",
  30363. +            dev->name, skb);
  30364. +/*
  30365. + * Validate the tty interface
  30366. + */
  30367. +    if (tty == NULL) {
  30368. +        if (ppp->flags & SC_DEBUG)
  30369. +            printk (KERN_ERR
  30370. +                "ppp_dev_xmit: %s not connected to a TTY!\n",
  30371. +                dev->name);
  30372. +        dev_kfree_skb (skb, FREE_WRITE);
  30373. +        return 0;
  30374. +    }
  30375. +/*
  30376. + * Fetch the pointer to the data
  30377. + */
  30378. +    len   = skb->len;
  30379. +    data  = skb_data(skb);
  30380. +/*
  30381. + * Look at the protocol in the skb to determine the difference between
  30382. + * an IP frame and an IPX frame.
  30383. + */
  30384. +
  30385. +#ifdef NEW_SKBUFF
  30386. +    switch (skb->protocol) {
  30387. +    case htons (ETH_P_IPX):
  30388. +        answer = ppp_dev_xmit_ipx (dev, ppp, data, len, PPP_IPX);
  30389. +        break;
  30390. +
  30391. +    case htons (ETH_P_IP):
  30392. +        answer = ppp_dev_xmit_ip (dev, ppp, data);
  30393. +        break;
  30394. +
  30395. +    default: /* All others have no support at this time. */
  30396. +        dev_kfree_skb (skb, FREE_WRITE);
  30397. +        return 0;
  30398. +    }
  30399. +#else
  30400. +    answer = ppp_dev_xmit_ip (dev, ppp, data);
  30401. +#endif
  30402. +
  30403. +/*
  30404. + * This is the end of the transmission. Release the buffer if it was sent.
  30405. + */
  30406. +    if (answer == 0) {
  30407. +        dev_kfree_skb (skb, FREE_WRITE);
  30408. +        ppp->ddinfo.xmit_idle = jiffies;
  30409. +    }
  30410. +    return answer;
  30411. +}
  30412. +
  30413. +/*
  30414. + * Generate the statistic information for the /proc/net/dev listing.
  30415. + */
  30416. +
  30417. +static struct enet_statistics *
  30418. +ppp_dev_stats (struct device *dev)
  30419. +{
  30420. +    struct ppp *ppp = dev2ppp (dev);
  30421. +    static struct enet_statistics ppp_stats;
  30422. +
  30423. +    ppp_stats.rx_packets          = ppp->stats.ppp_ipackets;
  30424. +    ppp_stats.rx_errors           = ppp->stats.ppp_ierrors;
  30425. +    ppp_stats.rx_dropped          = ppp->stats.ppp_ierrors;
  30426. +    ppp_stats.rx_fifo_errors      = 0;
  30427. +    ppp_stats.rx_length_errors    = 0;
  30428. +    ppp_stats.rx_over_errors      = 0;
  30429. +    ppp_stats.rx_crc_errors       = 0;
  30430. +    ppp_stats.rx_frame_errors     = 0;
  30431. +    ppp_stats.tx_packets          = ppp->stats.ppp_opackets;
  30432. +    ppp_stats.tx_errors           = ppp->stats.ppp_oerrors;
  30433. +    ppp_stats.tx_dropped          = 0;
  30434. +    ppp_stats.tx_fifo_errors      = 0;
  30435. +    ppp_stats.collisions          = 0;
  30436. +    ppp_stats.tx_carrier_errors   = 0;
  30437. +    ppp_stats.tx_aborted_errors   = 0;
  30438. +    ppp_stats.tx_window_errors    = 0;
  30439. +    ppp_stats.tx_heartbeat_errors = 0;
  30440. +
  30441. +    if (ppp->flags & SC_DEBUG)
  30442. +        printk (KERN_INFO "ppp_dev_stats called");
  30443. +    return &ppp_stats;
  30444. +}
  30445. +
  30446. +#ifdef NEW_SKBUFF
  30447. +/*
  30448. + *    The PPP protocol is currently pure IP (no IPX yet). This defines
  30449. + *      the protocol layer which is blank since the driver does all the
  30450. + *      cooking.
  30451. + */
  30452. +
  30453. +static int ppp_dev_input (struct protocol *self, struct protocol *lower,
  30454. +              sk_buff *skb, void *saddr, void *daddr)
  30455. +{
  30456. +    return protocol_pass_demultiplex(self, NULL, skb, NULL, NULL);
  30457. +}
  30458. +
  30459. +static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type,
  30460. +               int subid, void *saddr, void *daddr, void *opt)
  30461. +{
  30462. +    if(skb->dev==NULL)
  30463. +    {
  30464. +        printk("ppp_dev_output: No device.\n");
  30465. +        kfree_skb(skb, FREE_WRITE);
  30466. +        return -1;
  30467. +    }
  30468. +    dev_queue_xmit(skb, skb->dev, skb->priority);
  30469. +    return 0;
  30470. +}
  30471. +
  30472. +static int ppp_dev_getkey(int protocol, int subid, unsigned char *key)
  30473. +{
  30474. +    switch (protocol)
  30475. +    {
  30476. +    case htons (ETH_P_IP):
  30477. +    case htons (ETH_P_IPX):
  30478. +        return 0;
  30479. +
  30480. +    default:
  30481. +        break;
  30482. +    }
  30483. +
  30484. +    return -EAFNOSUPPORT;
  30485. +}
  30486. +
  30487. +#else
  30488. +
  30489. +#if USE_SKB_PROTOCOL == 0
  30490. +/*
  30491. + * Called to enquire about the type of the frame in the buffer. Return
  30492. + * ETH_P_IP for an IP frame, ETH_P_IPX for an IPX frame.
  30493. + */
  30494. +
  30495. +static unsigned short
  30496. +ppp_dev_type (sk_buff *skb, struct device *dev)
  30497. +{
  30498. +    return (htons (ETH_P_IP));
  30499. +}
  30500. +#endif
  30501. +
  30502. +#if USE_SKB_PROTOCOL == 0
  30503. +static int ppp_dev_header (unsigned char *buff, struct device *dev,
  30504. +               unsigned short type, void *daddr, void *saddr,
  30505. +               unsigned len, struct sk_buff *skb)
  30506. +#else
  30507. +static int ppp_dev_header (sk_buff *skb, struct device *dev,
  30508. +               unsigned short type, void *daddr,
  30509. +               void *saddr, unsigned len)
  30510. +#endif
  30511. +{
  30512. +    return (0);
  30513. +}
  30514. +
  30515. +static int
  30516. +ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr,
  30517. +         sk_buff *skb)
  30518. +{
  30519. +    return (0);
  30520. +}
  30521. +#endif
  30522. +
  30523. +/*************************************************************
  30524. + * UTILITIES
  30525. + *    Miscellany called by various functions above.
  30526. + *************************************************************/
  30527. +
  30528. +/* allocate or create a PPP channel */
  30529. +static struct ppp *
  30530. +ppp_alloc (void)
  30531. +{
  30532. +    int        if_num;
  30533. +    int        status;
  30534. +    ppp_ctrl_t    *ctl;
  30535. +    struct device    *dev;
  30536. +    struct ppp    *ppp;
  30537. +
  30538. +    /* try to find an free device */
  30539. +    ctl      = ppp_list;
  30540. +    if_num   = 0;
  30541. +  
  30542. +    while (ctl) {
  30543. +        ppp = ctl2ppp (ctl);
  30544. +        if (!set_bit(0, &ppp->inuse))
  30545. +            return (ppp);
  30546. +        ctl = ctl->next;
  30547. +        if (++if_num == max_dev)
  30548. +            return (NULL);
  30549. +    }
  30550. +/*
  30551. + * There are no available items. Allocate a device from the system pool
  30552. + */
  30553. +    ctl = (ppp_ctrl_t *) kmalloc (sizeof(ppp_ctrl_t), GFP_KERNEL);
  30554. +    if (ctl) {
  30555. +        (void) memset(ctl, 0, sizeof(ppp_ctrl_t));
  30556. +        ppp = ctl2ppp (ctl);
  30557. +        dev = ctl2dev (ctl);
  30558. +
  30559. +        /* initialize channel control data */
  30560. +        set_bit(0, &ppp->inuse);
  30561. +
  30562. +        ppp->line      = if_num;
  30563. +        ppp->tty       = NULL;
  30564. +        ppp->dev       = dev;
  30565. +    
  30566. +        dev->next      = NULL;
  30567. +        dev->init      = ppp_init_dev;
  30568. +        dev->name      = ctl->name;
  30569. +        dev->base_addr = (unsigned long) if_num;
  30570. +        dev->priv      = (void *) ppp;
  30571. +
  30572. +        sprintf (dev->name, "ppp%d", if_num);
  30573. +    
  30574. +        /* link in the new channel */
  30575. +        ctl->next      = ppp_list;
  30576. +        ppp_list       = ctl;
  30577. +
  30578. +/* register device so that we can be ifconfig'd */
  30579. +/* ppp_init_dev() will be called as a side-effect */
  30580. +
  30581. +        status = register_netdev (dev);
  30582. +        if (status == 0) {
  30583. +            printk (KERN_INFO "registered device %s\n", dev->name);
  30584. +            return (ppp);
  30585. +        }
  30586. +
  30587. +        printk (KERN_ERR
  30588. +               "ppp_alloc - register_netdev(%s) = %d failure.\n",
  30589. +            dev->name, status);
  30590. +        /* This one will forever be busy as it is not initialized */
  30591. +    }
  30592. +    return (NULL);
  30593. +}
  30594. +
  30595. +/*
  30596. + * Utility procedures to print a buffer in hex/ascii
  30597. + */
  30598. +
  30599. +static void
  30600. +ppp_print_hex (register u_char * out, const u_char * in, int count)
  30601. +{
  30602. +    register u_char next_ch;
  30603. +    static char hex[] = "0123456789ABCDEF";
  30604. +
  30605. +    while (count-- > 0) {
  30606. +        next_ch = *in++;
  30607. +        *out++ = hex[(next_ch >> 4) & 0x0F];
  30608. +        *out++ = hex[next_ch & 0x0F];
  30609. +        ++out;
  30610. +    }
  30611. +}
  30612. +
  30613. +static void
  30614. +ppp_print_char (register u_char * out, const u_char * in, int count)
  30615. +{
  30616. +    register u_char next_ch;
  30617. +
  30618. +    while (count-- > 0) {
  30619. +        next_ch = *in++;
  30620. +
  30621. +        if (next_ch < 0x20 || next_ch > 0x7e)
  30622. +            *out++ = '.';
  30623. +        else {
  30624. +            *out++ = next_ch;
  30625. +            if (next_ch == '%')   /* printk/syslogd has a bug !! */
  30626. +                *out++ = '%';
  30627. +        }
  30628. +    }
  30629. +    *out = '\0';
  30630. +}
  30631. +
  30632. +static void
  30633. +ppp_print_buffer (const u_char * name, const u_char * buf, int count)
  30634. +{
  30635. +    u_char line[44];
  30636. +
  30637. +    if (name != (u_char *) NULL)
  30638. +        printk (KERN_DEBUG "ppp: %s, count = %d\n", name, count);
  30639. +
  30640. +    while (count > 8) {
  30641. +        memset (line, 32, 44);
  30642. +        ppp_print_hex (line, buf, 8);
  30643. +        ppp_print_char (&line[8 * 3], buf, 8);
  30644. +        printk (KERN_DEBUG "%s\n", line);
  30645. +        count -= 8;
  30646. +        buf += 8;
  30647. +    }
  30648. +
  30649. +    if (count > 0) {
  30650. +        memset (line, 32, 44);
  30651. +        ppp_print_hex (line, buf, count);
  30652. +        ppp_print_char (&line[8 * 3], buf, count);
  30653. +        printk (KERN_DEBUG "%s\n", line);
  30654. +    }
  30655. +}
  30656. +
  30657. +/*************************************************************
  30658. + * Compressor module interface
  30659. + *************************************************************/
  30660. +
  30661. +struct compressor_link {
  30662. +    struct compressor_link    *next;
  30663. +    struct compressor    *comp;
  30664. +};
  30665. +
  30666. +static struct compressor_link *ppp_compressors = (struct compressor_link *) 0;
  30667. +
  30668. +static struct compressor *find_compressor (int type)
  30669. +{
  30670. +    struct compressor_link *lnk;
  30671. +    unsigned long flags;
  30672. +
  30673. +    save_flags(flags);
  30674. +    cli();
  30675. +
  30676. +    lnk = ppp_compressors;
  30677. +    while (lnk != (struct compressor_link *) 0) {
  30678. +        if ((int) (unsigned char) lnk->comp->compress_proto == type) {
  30679. +            restore_flags(flags);
  30680. +            return lnk->comp;
  30681. +        }
  30682. +        lnk = lnk->next;
  30683. +    }
  30684. +
  30685. +    restore_flags(flags);
  30686. +    return (struct compressor *) 0;
  30687. +}
  30688. +
  30689. +static int ppp_register_compressor (struct compressor *cp)
  30690. +{
  30691. +    struct compressor_link *new;
  30692. +    unsigned long flags;
  30693. +
  30694. +    new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL);
  30695. +
  30696. +    if (new == (struct compressor_link *) 0)
  30697. +          return 1;
  30698. +
  30699. +    save_flags(flags);
  30700. +    cli();
  30701. +
  30702. +    if (find_compressor (cp->compress_proto)) {
  30703. +        restore_flags(flags);
  30704. +          kfree (new);
  30705. +        return 0;
  30706. +    }
  30707. +
  30708. +    new->next    = ppp_compressors;
  30709. +    new->comp    = cp;
  30710. +    ppp_compressors = new;
  30711. +
  30712. +    restore_flags(flags);
  30713. +    return 0;
  30714. +}
  30715. +
  30716. +static void ppp_unregister_compressor (struct compressor *cp)
  30717. +{
  30718. +    struct compressor_link *prev = (struct compressor_link *) 0;
  30719. +    struct compressor_link *lnk;
  30720. +    unsigned long flags;
  30721. +
  30722. +    save_flags(flags);
  30723. +    cli();
  30724. +
  30725. +    lnk  = ppp_compressors;
  30726. +    while (lnk != (struct compressor_link *) 0) {
  30727. +        if (lnk->comp == cp) {
  30728. +              if (prev)
  30729. +                prev->next = lnk->next;
  30730. +            else
  30731. +                ppp_compressors = lnk->next;
  30732. +            kfree (lnk);
  30733. +            break;
  30734. +        }
  30735. +        prev = lnk;
  30736. +        lnk  = lnk->next;
  30737. +    }
  30738. +    restore_flags(flags);
  30739. +}
  30740. +
  30741. +/*************************************************************
  30742. + * Module support routines
  30743. + *************************************************************/
  30744. +
  30745. +#ifdef MODULE
  30746. +
  30747. +int
  30748. +init_module(void)
  30749. +{
  30750. +    int status;
  30751. +
  30752. +    /* register our line disciplines */
  30753. +    status = ppp_first_time();
  30754. +    if (status != 0)
  30755. +        printk (KERN_INFO
  30756. +               "PPP: ppp_init() failure %d\n", status);
  30757. +    else
  30758. +        (void) register_symtab (&ppp_syms);
  30759. +    return (status);
  30760. +}
  30761. +
  30762. +void
  30763. +cleanup_module(void)
  30764. +{
  30765. +    int status;
  30766. +    ppp_ctrl_t *ctl, *next_ctl;
  30767. +    struct device *dev;
  30768. +    struct ppp *ppp;
  30769. +    int busy_flag = 0;
  30770. +/*
  30771. + * Ensure that the devices are not in operation.
  30772. + */
  30773. +    ctl = ppp_list;
  30774. +    while (ctl) {
  30775. +        ppp = ctl2ppp (ctl);
  30776. +        if (ppp->inuse && ppp->tty != NULL) {
  30777. +            busy_flag = 1;
  30778. +            break;
  30779. +        }
  30780. +
  30781. +        dev = ctl2dev (ctl);
  30782. +        if (dev->start || dev->flags & IFF_UP) {
  30783. +            busy_flag = 1;
  30784. +            break;
  30785. +        }
  30786. +        ctl = ctl->next;
  30787. +    }
  30788. +/*
  30789. + * Ensure that there are no compressor modules registered
  30790. + */
  30791. +    if (busy_flag == 0 && ppp_compressors != NULL)
  30792. +        busy_flag = 1;
  30793. +
  30794. +    if (busy_flag) {
  30795. +        printk (KERN_INFO
  30796. +            "PPP: device busy, remove delayed\n");
  30797. +        return;
  30798. +    }
  30799. +/*
  30800. + * Release the tty registration of the line dicipline so that no new entries
  30801. + * may be created.
  30802. + */
  30803. +    status = tty_register_ldisc (N_PPP, NULL);
  30804. +    if (status != 0)
  30805. +        printk (KERN_INFO
  30806. +            "PPP: Unable to unregister ppp line discipline "
  30807. +            "(err = %d)\n", status);
  30808. +    else
  30809. +        printk (KERN_INFO
  30810. +               "PPP: ppp line discipline successfully unregistered\n");
  30811. +/*
  30812. + * De-register the devices so that there is no problem with them
  30813. + */    
  30814. +    next_ctl = ppp_list;
  30815. +    while (next_ctl) {
  30816. +        ctl      = next_ctl;
  30817. +        next_ctl = ctl->next;
  30818. +        ppp      = ctl2ppp (ctl);
  30819. +        dev      = ctl2dev (ctl);
  30820. +
  30821. +        ppp_release       (ppp);
  30822. +        unregister_netdev (dev);
  30823. +        kfree (ctl);
  30824. +    }
  30825. +}
  30826. +#endif
  30827. diff -urNwbB linux/arch/arm/drivers/scsi/Makefile linux.arm/arch/arm/drivers/scsi/Makefile
  30828. --- linux/arch/arm/drivers/scsi/Makefile    Thu Jan  1 01:00:00 1970
  30829. +++ linux.arm/arch/arm/drivers/scsi/Makefile    Sat Feb 24 13:17:59 1996
  30830. @@ -0,0 +1,147 @@
  30831. +
  30832. +# Makefile for kernel/blk_drv/scsi
  30833. +#
  30834. +# Note! Dependencies are done automagically by 'make dep', which also
  30835. +# removes any old dependencies. DON'T put your own dependencies here
  30836. +# unless it's something special (ie not a .c file).
  30837. +#
  30838. +
  30839. +all: links first_rule
  30840. +
  30841. +L_TARGET := scsi.a
  30842. +L_OBJS   :=
  30843. +M_OBJS   :=
  30844. +MOD_LIST_NAME := SCSI_MODULES
  30845. +SCSI_SRCS := $(wildcard $(L_OBJS:%.o=%.c))
  30846. +
  30847. +ifeq (${CFLAGS},)
  30848. +CFLAGS = -D__KERNEL__ \
  30849. +    -Wall -Wstrict-prototypes -I. -I../../../../include \
  30850. +    -O2 -fomit-frame-pointer
  30851. +
  30852. +include ../../../../.config
  30853. +
  30854. +TOPDIR = ../../../..
  30855. +endif
  30856. +
  30857. +ifeq ($(CONFIG_SCSI),y)
  30858. +L_OBJS += hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
  30859. +else
  30860. +  ifeq ($(CONFIG_SCSI),m)
  30861. +    ifdef CONFIG_MODVERSIONS
  30862. +      # Create this before we build anything else.
  30863. +      SCSI_MODULE_VER := scsi_syms.ver
  30864. +      SYMTAB_OBJS := scsi_syms.o
  30865. +    endif
  30866. +    M_OBJS += scsi_mod.o
  30867. +  endif
  30868. +endif
  30869. +
  30870. +ifeq ($(CONFIG_CHR_DEV_ST),y)
  30871. +L_OBJS += st.o
  30872. +else
  30873. +  ifeq ($(CONFIG_CHR_DEV_ST),m)
  30874. +  M_OBJS += st.o
  30875. +  endif
  30876. +endif
  30877. +
  30878. +ifeq ($(CONFIG_BLK_DEV_SD),y)
  30879. +L_OBJS += sd.o sd_ioctl.o
  30880. +else
  30881. +  ifeq ($(CONFIG_BLK_DEV_SD),m)
  30882. +  M_OBJS += sd_mod.o
  30883. +  endif
  30884. +endif
  30885. +
  30886. +ifeq ($(CONFIG_BLK_DEV_SR),y)
  30887. +L_OBJS += sr.o sr_ioctl.o
  30888. +else
  30889. +  ifeq ($(CONFIG_BLK_DEV_SR),m)
  30890. +  M_OBJS += sr_mod.o
  30891. +  endif
  30892. +endif
  30893. +
  30894. +ifeq ($(CONFIG_CHR_DEV_SG),y)
  30895. +L_OBJS += sg.o
  30896. +else
  30897. +  ifeq ($(CONFIG_CHR_DEV_SG),m)
  30898. +  M_OBJS += sg.o
  30899. +  endif
  30900. +endif
  30901. +
  30902. +ifeq ($(CONFIG_SCSI_CUMANA_1),y)
  30903. +L_OBJS += cumana_1.o
  30904. +else
  30905. +  ifeq ($(CONFIG_SCSI_CUMANA_1),m)
  30906. +  M_OBJS += cumana_1.o
  30907. +  endif
  30908. +endif
  30909. +
  30910. +ifeq ($(CONFIG_SCSI_ECOSCSI),y)
  30911. +L_OBJS += ecoscsi.o
  30912. +else
  30913. +  ifeq ($(CONFIG_SCSI_ECOSCSI),m)
  30914. +  M_OBJS += ecoscsi.o
  30915. +  endif
  30916. +endif
  30917. +
  30918. +ifeq ($(CONFIG_SCSI_OAK1),y)
  30919. +L_OBJS += oak.o
  30920. +else
  30921. +  ifeq ($(CONFIG_SCSI_OAK1),m)
  30922. +  M_OBJS += oak_mod.o
  30923. +  endif
  30924. +endif
  30925. +
  30926. +ifeq ($(CONFIG_SCSI_ACORNSCSI_3),y)
  30927. +L_OBJS += acornscsi.o acornscsi-io.o
  30928. +else
  30929. +  ifeq ($(CONFIG_SCSI_ACORNSCSI_3),m)
  30930. +  M_OBJS += acornscsi_mod.o
  30931. +  endif
  30932. +endif
  30933. +
  30934. +include $(TOPDIR)/Rules.make
  30935. +
  30936. +ifeq ($(CONFIG_SCSI),m)
  30937. +  ifdef CONFIG_MODVERSIONS
  30938. +    include ../../../../versions.mk
  30939. +  endif
  30940. +endif
  30941. +
  30942. +fastdep: links
  30943. +
  30944. +scsi_mod.o: $(SCSI_MODULE_VER) hosts.o scsi.o scsi_ioctl.o constants.o \
  30945. +        scsicam.o scsi_proc.o $(SYMTAB_OBJS)
  30946. +    $(LD) $(LD_RFLAG) -r -o $@ hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o $(SYMTAB_OBJS)
  30947. +
  30948. +sr_mod.o: $(SCSI_MODULE_VER) sr.o sr_ioctl.o
  30949. +    $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o
  30950. +
  30951. +sd_mod.o: $(SCSI_MODULE_VER) sd.o sd_ioctl.o
  30952. +    $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o
  30953. +
  30954. +oak_mod.o: oak.o
  30955. +    $(LD) $(LD_RFLAG) -r -o oak_mod.o oak.o `gcc --print-libgcc-file-name`
  30956. +
  30957. +acornscsi_mod.o: acornscsi.o acornscsi-io.o
  30958. +    $(LD) $(LD_RFLAG) -r -o acornscsi_mod.o acornscsi.o acornscsi-io.o `gcc --print-libgcc-file-name`
  30959. +
  30960. +$(SYMTAB_OBJS): $(SYMTAB_OBJS:.o=.c)
  30961. +
  30962. +modules: $(SCSI_MODULE_VER)
  30963. +
  30964. +LK = constants.c constants.h hosts.h scsi.h scsi_ioctl.c scsi_ioctl.h scsi_proc.c scsi_syms.c \
  30965. +    scsicam.c sd.c sd.h sd_ioctl.c sg.c sg.h sr.c sr.h sr_ioctl.c st.c st.h st_options.h
  30966. +
  30967. +links:
  30968. +    -@for f in $(LK); do \
  30969. +        ln -s ../../../../drivers/scsi/$$f .; \
  30970. +    done
  30971. +    touch links
  30972. +
  30973. +LINKCLEAN:
  30974. +    -@for f in $(LK); do \
  30975. +        if [ -L $$f ]; then rm -f $$f; fi; \
  30976. +    done
  30977. +    rm -f links
  30978. diff -urNwbB linux/arch/arm/drivers/scsi/NCR5380.c linux.arm/arch/arm/drivers/scsi/NCR5380.c
  30979. --- linux/arch/arm/drivers/scsi/NCR5380.c    Thu Jan  1 01:00:00 1970
  30980. +++ linux.arm/arch/arm/drivers/scsi/NCR5380.c    Sat Feb 24 09:36:54 1996
  30981. @@ -0,0 +1,2786 @@
  30982. +#define NDEBUG (NDEBUG_RESTART_SELECT)
  30983. +/* 
  30984. + * NCR 5380 generic driver routines.  These should make it *trivial*
  30985. + *     to implement 5380 SCSI drivers under Linux with a non-trantor
  30986. + *    architecture.
  30987. + *
  30988. + *    Note that these routines also work with NR53c400 family chips.
  30989. + *
  30990. + * Copyright 1993, Drew Eckhardt
  30991. + *    Visionary Computing 
  30992. + *    (Unix and Linux consulting and custom programming)
  30993. + *     drew@colorado.edu
  30994. + *    +1 (303) 666-5836
  30995. + *
  30996. + * DISTRIBUTION RELEASE 6. 
  30997. + *
  30998. + * For more information, please consult 
  30999. + *
  31000. + * NCR 5380 Family
  31001. + * SCSI Protocol Controller
  31002. + * Databook
  31003. + *
  31004. + * NCR Microelectronics
  31005. + * 1635 Aeroplaza Drive
  31006. + * Colorado Springs, CO 80916
  31007. + * 1+ (719) 578-3400
  31008. + * 1+ (800) 334-5454
  31009. + */
  31010. +
  31011. +/*
  31012. + * $Log: NCR5380.c,v $
  31013. + * Revision 1.5  1994/01/19  09:14:57  drew
  31014. + * Fixed udelay() hack that was being used on DATAOUT phases
  31015. + * instead of a proper wait for the final handshake.
  31016. + *
  31017. + * Revision 1.4  1994/01/19  06:44:25  drew
  31018. + * *** empty log message ***
  31019. + *
  31020. + * Revision 1.3  1994/01/19  05:24:40  drew
  31021. + * Added support for TCR LAST_BYTE_SENT bit.
  31022. + *
  31023. + * Revision 1.2  1994/01/15  06:14:11  drew
  31024. + * REAL DMA support, bug fixes.
  31025. + *
  31026. + * Revision 1.1  1994/01/15  06:00:54  drew
  31027. + * Initial revision
  31028. + *
  31029. + */
  31030. +
  31031. +/*
  31032. + * Further development / testing that should be done : 
  31033. + * 1.  Cleanup the NCR5380_transfer_dma function and DMA operation complete
  31034. + *     code so that everything does the same thing that's done at the 
  31035. + *     end of a pseudo-DMA read operation.
  31036. + *
  31037. + * 2.  Fix REAL_DMA (interrupt driven, polled works fine) -
  31038. + *     basically, transfer size needs to be reduced by one 
  31039. + *     and the last byte read as is done with PSEUDO_DMA.
  31040. + * 
  31041. + * 3.  Test USLEEP code 
  31042. + *
  31043. + * 4.  Test SCSI-II tagged queueing (I have no devices which support 
  31044. + *    tagged queueing)
  31045. + *
  31046. + * 5.  Test linked command handling code after Eric is ready with 
  31047. + *      the high level code.
  31048. + */
  31049. +
  31050. +#ifndef notyet
  31051. +#undef LINKED
  31052. +#undef USLEEP
  31053. +#undef REAL_DMA
  31054. +#endif
  31055. +
  31056. +#ifdef REAL_DMA_POLL
  31057. +#undef READ_OVERRUNS
  31058. +#define READ_OVERRUNS
  31059. +#endif
  31060. +
  31061. +/*
  31062. + * Design
  31063. + * Issues :
  31064. + *
  31065. + * The other Linux SCSI drivers were written when Linux was Intel PC-only,
  31066. + * and specifically for each board rather than each chip.  This makes their
  31067. + * adaptation to platforms like the Mac (Some of which use NCR5380's)
  31068. + * more difficult than it has to be.
  31069. + *
  31070. + * Also, many of the SCSI drivers were written before the command queuing
  31071. + * routines were implemented, meaning their implementations of queued 
  31072. + * commands were hacked on rather than designed in from the start.
  31073. + *
  31074. + * When I designed the Linux SCSI drivers I figured that 
  31075. + * while having two different SCSI boards in a system might be useful
  31076. + * for debugging things, two of the same type wouldn't be used.
  31077. + * Well, I was wrong and a number of users have mailed me about running
  31078. + * multiple high-performance SCSI boards in a server.
  31079. + *
  31080. + * Finally, when I get questions from users, I have no idea what 
  31081. + * revision of my driver they are running.
  31082. + *
  31083. + * This driver attempts to address these problems :
  31084. + * This is a generic 5380 driver.  To use it on a different platform, 
  31085. + * one simply writes appropriate system specific macros (ie, data
  31086. + * transfer - some PC's will use the I/O bus, 68K's must use 
  31087. + * memory mapped) and drops this file in their 'C' wrapper.
  31088. + *
  31089. + * As far as command queueing, two queues are maintained for 
  31090. + * each 5380 in the system - commands that haven't been issued yet,
  31091. + * and commands that are currently executing.  This means that an 
  31092. + * unlimited number of commands may be queued, letting 
  31093. + * more commands propagate from the higher driver levels giving higher 
  31094. + * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported, 
  31095. + * allowing multiple commands to propagate all the way to a SCSI-II device 
  31096. + * while a command is already executing.
  31097. + *
  31098. + * To solve the multiple-boards-in-the-same-system problem, 
  31099. + * there is a separate instance structure for each instance
  31100. + * of a 5380 in the system.  So, multiple NCR5380 drivers will
  31101. + * be able to coexist with appropriate changes to the high level
  31102. + * SCSI code.  
  31103. + *
  31104. + * A NCR5380_PUBLIC_REVISION macro is provided, with the release
  31105. + * number (updated for each public release) printed by the 
  31106. + * NCR5380_print_options command, which should be called from the 
  31107. + * wrapper detect function, so that I know what release of the driver
  31108. + * users are using.
  31109. + *
  31110. + * Issues specific to the NCR5380 : 
  31111. + *
  31112. + * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 
  31113. + * piece of hardware that requires you to sit in a loop polling for 
  31114. + * the REQ signal as long as you are connected.  Some devices are 
  31115. + * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 
  31116. + * while doing long seek operations.
  31117. + * 
  31118. + * The workaround for this is to keep track of devices that have
  31119. + * disconnected.  If the device hasn't disconnected, for commands that
  31120. + * should disconnect, we do something like 
  31121. + *
  31122. + * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
  31123. + * 
  31124. + * Some tweaking of N and M needs to be done.  An algorithm based 
  31125. + * on "time to data" would give the best results as long as short time
  31126. + * to datas (ie, on the same track) were considered, however these 
  31127. + * broken devices are the exception rather than the rule and I'd rather
  31128. + * spend my time optimizing for the normal case.
  31129. + *
  31130. + * Architecture :
  31131. + *
  31132. + * At the heart of the design is a coroutine, NCR5380_main,
  31133. + * which is started when not running by the interrupt handler,
  31134. + * timer, and queue command function.  It attempts to establish
  31135. + * I_T_L or I_T_L_Q nexuses by removing the commands from the 
  31136. + * issue queue and calling NCR5380_select() if a nexus 
  31137. + * is not established. 
  31138. + *
  31139. + * Once a nexus is established, the NCR5380_information_transfer()
  31140. + * phase goes through the various phases as instructed by the target.
  31141. + * if the target goes into MSG IN and sends a DISCONNECT message,
  31142. + * the command structure is placed into the per instance disconnected
  31143. + * queue, and NCR5380_main tries to find more work.  If USLEEP
  31144. + * was defined, and the target is idle for too long, the system
  31145. + * will try to sleep.
  31146. + *
  31147. + * If a command has disconnected, eventually an interrupt will trigger,
  31148. + * calling NCR5380_intr()  which will in turn call NCR5380_reselect
  31149. + * to reestablish a nexus.  This will run main if necessary.
  31150. + *
  31151. + * On command termination, the done function will be called as 
  31152. + * appropriate.
  31153. + *
  31154. + * SCSI pointers are maintained in the SCp field of SCSI command 
  31155. + * structures, being initialized after the command is connected
  31156. + * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
  31157. + * Note that in violation of the standard, an implicit SAVE POINTERS operation
  31158. + * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
  31159. + */
  31160. +
  31161. +/*
  31162. + * Using this file :
  31163. + * This file a skeleton Linux SCSI driver for the NCR 5380 series
  31164. + * of chips.  To use it, you write a architecture specific functions 
  31165. + * and macros and include this file in your driver.
  31166. + *
  31167. + * These macros control options : 
  31168. + * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be 
  31169. + *    defined.
  31170. + * 
  31171. + * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
  31172. + *    for commands that return with a CHECK CONDITION status. 
  31173. + *
  31174. + * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
  31175. + *     transceivers. 
  31176. + *
  31177. + * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
  31178. + *    bytes at a time.  Since interrupts are disabled by default during
  31179. + *    these transfers, we might need this to give reasonable interrupt
  31180. + *    service time if the transfer size gets too large.
  31181. + *
  31182. + * LINKED - if defined, linked commands are supported.
  31183. + *
  31184. + * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
  31185. + *
  31186. + * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
  31187. + *
  31188. + * REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't
  31189. + *     rely on phase mismatch and EOP interrupts to determine end 
  31190. + *    of phase.
  31191. + *
  31192. + * SCSI2 - if defined, SCSI-2 tagged queuing is used where possible
  31193. + *
  31194. + * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  You
  31195. + *        only really want to use this if you're having a problem with
  31196. + *        dropped characters during high speed communications, and even
  31197. + *        then, you're going to be better off twiddling with transfersize
  31198. + *        in the high level code.
  31199. + *
  31200. + * USLEEP - if defined, on devices that aren't disconnecting from the 
  31201. + *    bus, we will go to sleep so that the CPU can get real work done 
  31202. + *    when we run a command that won't complete immediately.
  31203. + *
  31204. + * Note that if USLEEP is defined, NCR5380_TIMER *must* also be
  31205. + * defined.
  31206. + *
  31207. + * Defaults for these will be provided if USLEEP is defined, although
  31208. + * the user may want to adjust these to allocate CPU resources to 
  31209. + * the SCSI driver or "real" code.
  31210. + * 
  31211. + * USLEEP_SLEEP - amount of time, in jiffies, to sleep
  31212. + *
  31213. + * USLEEP_POLL - amount of time, in jiffies, to poll
  31214. + *
  31215. + * These macros MUST be defined :
  31216. + * NCR5380_local_declare() - declare any local variables needed for your transfer
  31217. + *    routines.
  31218. + *
  31219. + * NCR5380_setup(instance) - initialize any local variables needed from a given
  31220. + *    instance of the host adapter for NCR5380_{read,write,pread,pwrite}
  31221. + * 
  31222. + * NCR5380_read(register)  - read from the specified register
  31223. + *
  31224. + * NCR5380_write(register, value) - write to the specific register 
  31225. + *
  31226. + * NCR5380_implementation_fields  - additional fields needed for this 
  31227. + *    specific implementation of the NCR5380
  31228. + *
  31229. + * Either real DMA *or* pseudo DMA may be implemented
  31230. + * REAL functions : 
  31231. + * NCR5380_REAL_DMA should be defined if real DMA is to be used.
  31232. + * Note that the DMA setup functions should return the number of bytes 
  31233. + *    that they were able to program the controller for.
  31234. + *
  31235. + * Also note that generic i386/PC versions of these macros are 
  31236. + *    available as NCR5380_i386_dma_write_setup,
  31237. + *    NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
  31238. + *
  31239. + * NCR5380_dma_write_setup(instance, src, count) - initialize
  31240. + * NCR5380_dma_read_setup(instance, dst, count) - initialize
  31241. + * NCR5380_dma_residual(instance); - residual count
  31242. + *
  31243. + * PSEUDO functions :
  31244. + * NCR5380_pwrite(instance, src, count)
  31245. + * NCR5380_pread(instance, dst, count);
  31246. + *
  31247. + * If nothing specific to this implementation needs doing (ie, with external
  31248. + * hardware), you must also define 
  31249. + *  
  31250. + * NCR5380_queue_command
  31251. + * NCR5380_reset
  31252. + * NCR5380_abort
  31253. + *
  31254. + * to be the global entry points into the specific driver, ie 
  31255. + * #define NCR5380_queue_command t128_queue_command.
  31256. + *
  31257. + * If this is not done, the routines will be defined as static functions
  31258. + * with the NCR5380* names and the user must provide a globally
  31259. + * accessible wrapper function.
  31260. + *
  31261. + * The generic driver is initialized by calling NCR5380_init(instance),
  31262. + * after setting the appropriate host specific fields and ID.  If the 
  31263. + * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
  31264. + * possible) function may be used.  Before the specific driver initialization
  31265. + * code finishes, NCR5380_print_options should be called.
  31266. + */
  31267. +
  31268. +static struct Scsi_Host *first_instance = NULL;
  31269. +static Scsi_Host_Template *the_template = NULL;
  31270. +
  31271. +/*
  31272. + * Function : void initialize_SCp(Scsi_Cmnd *cmd)
  31273. + *
  31274. + * Purpose : initialize the saved data pointers for cmd to point to the 
  31275. + *    start of the buffer.
  31276. + *
  31277. + * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
  31278. + */
  31279. +
  31280. +static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) {
  31281. +    /* 
  31282. +     * Initialize the Scsi Pointer field so that all of the commands in the 
  31283. +     * various queues are valid.
  31284. +     */
  31285. +
  31286. +    if (cmd->use_sg) {
  31287. +    cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
  31288. +    cmd->SCp.buffers_residual = cmd->use_sg - 1;
  31289. +    cmd->SCp.ptr = (char *) cmd->SCp.buffer->address;
  31290. +    cmd->SCp.this_residual = cmd->SCp.buffer->length;
  31291. +    } else {
  31292. +    cmd->SCp.buffer = NULL;
  31293. +    cmd->SCp.buffers_residual = 0;
  31294. +    cmd->SCp.ptr = (char *) cmd->request_buffer;
  31295. +    cmd->SCp.this_residual = cmd->request_bufflen;
  31296. +    }
  31297. +}
  31298. +
  31299. +#include <linux/delay.h>
  31300. +
  31301. +#ifdef NDEBUG
  31302. +static struct {
  31303. +    unsigned char mask;
  31304. +    char * name;} 
  31305. +signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, 
  31306. +    { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD,  "CD" }, { SR_IO, "IO" }, 
  31307. +    { SR_SEL, "SEL" }, {0, NULL}}, 
  31308. +basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
  31309. +icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
  31310. +    {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, 
  31311. +    {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, 
  31312. +    {0, NULL}},
  31313. +mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, 
  31314. +    {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, 
  31315. +    "MODE PARITY INTR"}, {MR_MONITOR_BSY, "MODE MONITOR BSY"},
  31316. +    {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, 
  31317. +    {0, NULL}};
  31318. +
  31319. +/*
  31320. + * Function : void NCR5380_print(struct Scsi_Host *instance)
  31321. + *
  31322. + * Purpose : print the SCSI bus signals for debugging purposes
  31323. + *
  31324. + * Input : instance - which NCR5380
  31325. + */
  31326. +
  31327. +static void NCR5380_print(struct Scsi_Host *instance) {
  31328. +    NCR5380_local_declare();
  31329. +    unsigned char status, data, basr, mr, icr, i;
  31330. +    NCR5380_setup(instance);
  31331. +    cli();
  31332. +    data = NCR5380_read(CURRENT_SCSI_DATA_REG);
  31333. +    status = NCR5380_read(STATUS_REG);
  31334. +    mr = NCR5380_read(MODE_REG);
  31335. +    icr = NCR5380_read(INITIATOR_COMMAND_REG);
  31336. +    basr = NCR5380_read(BUS_AND_STATUS_REG);
  31337. +    sti();
  31338. +    for (i = 0; signals[i].mask ; ++i) 
  31339. +    if (status & signals[i].mask)
  31340. +        printk(" %s", signals[i].name);
  31341. +    for (i = 0; basrs[i].mask ; ++i) 
  31342. +    if (basr & basrs[i].mask)
  31343. +        printk(" %s", basrs[i].name);
  31344. +    for (i = 0; icrs[i].mask; ++i) 
  31345. +    if (icr & icrs[i].mask)
  31346. +        printk(" %s", icrs[i].name);
  31347. +    for (i = 0; mrs[i].mask; ++i) 
  31348. +    if (mr & mrs[i].mask)
  31349. +        printk(" %s", mrs[i].name);
  31350. +    printk("\n");
  31351. +}
  31352. +
  31353. +static struct {
  31354. +    unsigned char value;
  31355. +    char *name;
  31356. +} phases[] = {
  31357. +{PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
  31358. +{PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
  31359. +{PHASE_UNKNOWN, "UNKNOWN"}};
  31360. +
  31361. +/* 
  31362. + * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
  31363. + *
  31364. + * Purpose : print the current SCSI phase for debugging purposes
  31365. + *
  31366. + * Input : instance - which NCR5380
  31367. + */
  31368. +
  31369. +static void NCR5380_print_phase(struct Scsi_Host *instance) {
  31370. +    NCR5380_local_declare();
  31371. +    unsigned char status;
  31372. +    int i;
  31373. +    NCR5380_setup(instance);
  31374. +
  31375. +    status = NCR5380_read(STATUS_REG);
  31376. +    if (!(status & SR_REQ)) 
  31377. +    printk("scsi%d: REQ not asserted, phase unknown.\n", 
  31378. +        instance->host_no);
  31379. +    else {
  31380. +    for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 
  31381. +        (phases[i].value != (status & PHASE_MASK)); ++i); 
  31382. +    printk("scsi%d: phase %s\n", instance->host_no, phases[i].name);
  31383. +    }
  31384. +}
  31385. +#endif
  31386. +
  31387. +/*
  31388. + * We need to have our coroutine active given these constraints : 
  31389. + * 1.  The mutex flag, main_running, can only be set when the main 
  31390. + *     routine can actually process data, otherwise SCSI commands
  31391. + *     will never get issued.
  31392. + *
  31393. + * 2.  NCR5380_main() shouldn't be called before it has exited, because
  31394. + *     other drivers have had kernel stack overflows in similar
  31395. + *     situations.
  31396. + *
  31397. + * 3.  We don't want to inline NCR5380_main() because of space concerns,
  31398. + *     even though it is only called in two places.
  31399. + *
  31400. + * So, the solution is to set the mutex in an inline wrapper for the 
  31401. + * main coroutine, and have the main coroutine exit with interrupts 
  31402. + * disabled after the final search through the queues so that no race 
  31403. + * conditions are possible.
  31404. + */
  31405. +
  31406. +static volatile int main_running = 0;
  31407. +
  31408. +/* 
  31409. + * Function : run_main(void)
  31410. + * 
  31411. + * Purpose : insure that the coroutine is running and will process our 
  31412. + *     request.  main_running is checked/set here (in an inline function)
  31413. + *    rather than in NCR5380_main itself to reduce the chances of stack
  31414. + *    overflow.
  31415. + *
  31416. + */
  31417. +
  31418. +static __inline__ void run_main(void) {
  31419. +    cli();
  31420. +    if (!main_running) {
  31421. +    main_running = 1;
  31422. +        NCR5380_main();
  31423. +    /* 
  31424. +         * main_running is cleared in NCR5380_main once it can't do 
  31425. +     * more work, and NCR5380_main exits with interrupts disabled.
  31426. +     */
  31427. +    sti();
  31428. +    } else 
  31429. +    sti();
  31430. +}
  31431. +
  31432. +#ifdef USLEEP
  31433. +#ifndef NCR5380_TIMER
  31434. +#error "NCR5380_TIMER must be defined so that this type of NCR5380 driver gets a unique timer."
  31435. +#endif
  31436. +
  31437. +/*
  31438. + * These need tweaking, and would probably work best as per-device 
  31439. + * flags initialized differently for disk, tape, cd, etc devices.
  31440. + * People with broken devices are free to experiment as to what gives
  31441. + * the best results for them.
  31442. + *
  31443. + * USLEEP_SLEEP should be a minimum seek time.
  31444. + *
  31445. + * USLEEP_POLL should be a maximum rotational latency.
  31446. + */
  31447. +#ifndef USLEEP_SLEEP
  31448. +/* 20 ms (reasonable hard disk speed) */
  31449. +#define USLEEP_SLEEP 2
  31450. +#endif
  31451. +/* 300 RPM (floppy speed) */
  31452. +#ifndef USLEEP_POLL
  31453. +#define USLEEP_POLL 20
  31454. +#endif
  31455. +
  31456. +static struct Scsi_Host * expires_first = NULL;
  31457. +
  31458. +/* 
  31459. + * Function : int should_disconnect (unsigned char cmd)
  31460. + *
  31461. + * Purpose : decide weather a command would normally disconnect or 
  31462. + *    not, since if it won't disconnect we should go to sleep.
  31463. + *
  31464. + * Input : cmd - opcode of SCSI command
  31465. + *
  31466. + * Returns : DISCONNECT_LONG if we should disconnect for a really long 
  31467. + *     time (ie always, sleep, look for REQ active, sleep), 
  31468. + *    DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal
  31469. + *     time-to-data delay, DISCONNECT_NONE if this command would return
  31470. + *     immediately.
  31471. + *
  31472. + *      Future sleep algorithms based on time to data can exploit 
  31473. + *      something like this so they can differentiate between "normal" 
  31474. + *    (ie, read, write, seek) and unusual commands (ie, * format).
  31475. + *
  31476. + * Note : We don't deal with commands that handle an immediate disconnect,
  31477. + *        
  31478. + */
  31479. +
  31480. +static int should_disconnect (unsigned char cmd) {
  31481. +    switch (cmd) {
  31482. +    case READ_6:
  31483. +    case WRITE_6:
  31484. +    case SEEK_6:
  31485. +    case READ_10:
  31486. +    case WRITE_10:
  31487. +    case SEEK_10:
  31488. +    return DISCONNECT_TIME_TO_DATA;
  31489. +    case FORMAT_UNIT:
  31490. +    case SEARCH_HIGH:
  31491. +    case SEARCH_LOW:
  31492. +    case SEARCH_EQUAL:
  31493. +    return DISCONNECT_LONG;
  31494. +    default:
  31495. +    return DISCONNECT_NONE;
  31496. +    }
  31497. +}
  31498. +
  31499. +/*
  31500. + * Assumes instance->time_expires has been set in higher level code.
  31501. + */
  31502. +
  31503. +static int NCR5380_set_timer (struct Scsi_Host *instance) {
  31504. +    struct Scsi_Host *tmp, **prev;
  31505. +    
  31506. +    cli();
  31507. +    if (((struct NCR5380_hostdata *) (instance->host_data))->next_timer) {
  31508. +    sti();
  31509. +    return -1;
  31510. +    }
  31511. +
  31512. +    for (prev = &expires_first, tmp = expires_first; tmp; 
  31513. +    prev = &(((struct NCR5380_hostdata *) tmp->host_data)->next_timer), 
  31514. +    tmp = ((struct NCR5380_hostdata *) tmp->host_data)->next_timer)
  31515. +    if (instance->time_expires < tmp->time_expires) 
  31516. +        break;
  31517. +       
  31518. +    instance->next_timer = tmp;
  31519. +    *prev = instance;
  31520. +    timer_table[NCR5380_TIMER].expires = expires_first->time_expires;
  31521. +    timer_active |= 1 << NCR5380_TIMER;
  31522. +    sti();
  31523. +    return 0;
  31524. +}    
  31525. +
  31526. +/* Doing something about unwanted reentrancy here might be useful */
  31527. +void NCR5380_timer_fn(void) {
  31528. +    struct Scsi_Host *instance;
  31529. +    cli();
  31530. +    for (; expires_first && expires_first->time_expires >= jiffies; ) {
  31531. +    instance = ((NCR5380_hostdata *) expires_first->host_data)->
  31532. +        expires_next;
  31533. +    ((NCR5380_hostdata *) expires_first->host_data)->expires_next = 
  31534. +        NULL;
  31535. +    ((NCR5380_hostdata *) expires_first->host_data)->time_expires = 
  31536. +        0;
  31537. +    expires_first = instance;
  31538. +    }
  31539. +
  31540. +    if (expires_first) {
  31541. +    timer_table[NCR5380_TIMER].expires = ((NCR5380_hostdata *) 
  31542. +        expires_first->host_data)->time_expires;
  31543. +    timer_active |= (1 << NCR5380_TIMER);
  31544. +    } else {
  31545. +    timer_table[NCR5380_TIMER].expires = 0;
  31546. +    timer_active &= ~(1 << MCR5380_TIMER);
  31547. +    }
  31548. +    sti();
  31549. +
  31550. +    run_main();
  31551. +}
  31552. +#endif /* def USLEEP */
  31553. +
  31554. +static void NCR5380_all_init (void) {
  31555. +    static int done = 0;
  31556. +    if (!done) {
  31557. +#if (NDEBUG & NDEBUG_INIT)
  31558. +    printk("scsi : NCR5380_all_init()\n");
  31559. +#endif
  31560. +    done = 1;
  31561. +#ifdef USLEEP
  31562. +    timer_table[NCR5380_TIMER].expires = 0;
  31563. +    timer_table[NCR5380_TIMER].fn = NCR5380_timer_fn;
  31564. +#endif
  31565. +    }
  31566. +}
  31567. +
  31568. +#ifdef AUTOPROBE_IRQ
  31569. +/*
  31570. + * Function : int NCR5380_probe_irq (struct Scsi_Host *instance, int possible)
  31571. + * 
  31572. + * Purpose : autoprobe for the IRQ line used by the NCR5380.  
  31573. + *
  31574. + * Inputs : instance - pointer to this instance of the NCR5380 driver,
  31575. + *          possible - bitmask of permissible interrupts.
  31576. + *
  31577. + * Returns : number of the IRQ selected, IRQ_NONE if no interrupt fired.
  31578. + * 
  31579. + * XXX no effort is made to deal with spurious interrupts. 
  31580. + */
  31581. +
  31582. +
  31583. +static int probe_irq;
  31584. +static void probe_intr (int irq, struct pt_regs * regs) {
  31585. +    probe_irq = irq;
  31586. +};
  31587. +
  31588. +static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible) {
  31589. +    NCR5380_local_declare();
  31590. +    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
  31591. +     instance->hostdata;
  31592. +    unsigned long timeout;
  31593. +    int trying_irqs, i, mask;
  31594. +    NCR5380_setup(instance);
  31595. +
  31596. +    for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1) 
  31597. +    if ((mask & possible) &&  (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe") 
  31598. +        == 0)) 
  31599. +        trying_irqs |= mask;
  31600. +
  31601. +    timeout = jiffies + 25;
  31602. +    probe_irq = IRQ_NONE;
  31603. +
  31604. +/*
  31605. + * A interrupt is triggered whenever BSY = false, SEL = true
  31606. + * and a bit set in the SELECT_ENABLE_REG is asserted on the 
  31607. + * SCSI bus.
  31608. + *
  31609. + * Note that the bus is only driven when the phase control signals
  31610. + * (I/O, C/D, and MSG) match those in the TCR, so we must reset that
  31611. + * to zero.
  31612. + */
  31613. +
  31614. +    NCR5380_write(TARGET_COMMAND_REG, 0);
  31615. +    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
  31616. +    NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
  31617. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | 
  31618. +    ICR_ASSERT_SEL);
  31619. +
  31620. +    while (probe_irq == IRQ_NONE && jiffies < timeout);
  31621. +
  31622. +    NCR5380_write(SELECT_ENABLE_REG, 0);
  31623. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  31624. +
  31625. +    for (i = 0, mask = 1; i < 16; ++i, mask <<= 1)
  31626. +    if (trying_irqs & mask) 
  31627. +        free_irq(i);
  31628. +
  31629. +    return probe_irq;
  31630. +}
  31631. +#endif /* AUTOPROBE_IRQ */
  31632. +/*
  31633. + * Function : void NCR58380_print_options (struct Scsi_Host *instance)
  31634. + *
  31635. + * Purpose : called by probe code indicating the NCR5380 driver
  31636. + *         options that were selected.
  31637. + *
  31638. + * Inputs : instance, pointer to this instance.  Unused.
  31639. + */
  31640. +
  31641. +static void NCR5380_print_options (struct Scsi_Host *instance) {
  31642. +    printk(" generic options"
  31643. +#ifdef AUTOPROBE_IRQ
  31644. +    " AUTOPROBE_IRQ"
  31645. +#endif
  31646. +#ifdef AUTOSENSE 
  31647. +    " AUTOSENSE"
  31648. +#endif
  31649. +#ifdef DIFFERENTIAL
  31650. +    " DIFFERENTIAL"
  31651. +#endif
  31652. +#ifdef REAL_DMA
  31653. +    " REAL DMA"
  31654. +#endif
  31655. +#ifdef REAL_DMA_POLL
  31656. +    " REAL DMA POLL"
  31657. +#endif
  31658. +#ifdef PARITY
  31659. +    " PARITY"
  31660. +#endif
  31661. +#ifdef PSEUDO_DMA
  31662. +    " PSEUDO DMA"
  31663. +#endif
  31664. +#ifdef SCSI2
  31665. +    " SCSI-2"
  31666. +#endif
  31667. +#ifdef UNSAFE
  31668. +    " UNSAFE "
  31669. +#endif
  31670. +    );
  31671. +#ifdef USLEEP
  31672. +    printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP);
  31673. +#endif
  31674. +    printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
  31675. +#ifdef NCR53C400
  31676. +    if (hostdata->flags & FLAG_NCR53C400) {
  31677. +    printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE);
  31678. +    }
  31679. +#endif
  31680. +}
  31681. +
  31682. +/*
  31683. + * Function : void NCR5380_print_status (struct Scsi_Host *instance)
  31684. + *
  31685. + * Purpose : print commands in the various queues, called from
  31686. + *    NCR5380_abort and NCR5380_debug to aid debugging.
  31687. + *
  31688. + * Inputs : instance, pointer to this instance.  
  31689. + */
  31690. +
  31691. +static void NCR5380_print_status (struct Scsi_Host *instance) {
  31692. +    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) 
  31693. +    instance->hostdata;
  31694. +    Scsi_Cmnd *ptr;
  31695. +
  31696. +
  31697. +    printk("NCR5380 : coroutine is%s running.\n",
  31698. +    main_running ? "" : "n't");
  31699. +    
  31700. +#ifdef NDEBUG
  31701. +    NCR5380_print (instance);
  31702. +    NCR5380_print_phase (instance);
  31703. +#endif
  31704. +
  31705. +    cli();
  31706. +    if (!hostdata->connected) {
  31707. +    printk ("scsi%d: no currently connected command\n",
  31708. +        instance->host_no);
  31709. +    } else {
  31710. +    print_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected);
  31711. +    }
  31712. +
  31713. +    printk ("scsi%d: issue_queue\n", instance->host_no);
  31714. +
  31715. +    for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; 
  31716. +    ptr = (Scsi_Cmnd *) ptr->host_scribble) 
  31717. +    print_Scsi_Cmnd (ptr);
  31718. +
  31719. +    printk ("scsi%d: disconnected_queue\n", instance->host_no);
  31720. +
  31721. +    for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; 
  31722. +    ptr = (Scsi_Cmnd *) ptr->host_scribble) 
  31723. +    print_Scsi_Cmnd (ptr);
  31724. +    
  31725. +    sti();
  31726. +}
  31727. +
  31728. +
  31729. +/* 
  31730. + * Function : void NCR5380_init (struct Scsi_Host *instance, flags)
  31731. + *
  31732. + * Purpose : initializes *instance and corresponding 5380 chip,
  31733. + *    with flags OR'd into the initial flags value.
  31734. + *
  31735. + * Inputs : instance - instantiation of the 5380 driver.  
  31736. + *
  31737. + * Notes : I assume that the host, hostno, and id bits have been
  31738. + *     set correctly.  I don't care about the irq and other fields. 
  31739. + * 
  31740. + */
  31741. +
  31742. +static void NCR5380_init (struct Scsi_Host *instance, int flags) {
  31743. +    NCR5380_local_declare();
  31744. +    int i;
  31745. +    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) 
  31746. +    instance->hostdata;
  31747. +
  31748. +    /* 
  31749. +     * On NCR53C400 boards, NCR5380 registers are mapped 8 past 
  31750. +     * the base address.
  31751. +     */
  31752. +
  31753. +    if (flags & FLAG_NCR53C400)
  31754. +    instance->io_port += 8;
  31755. +
  31756. +    NCR5380_setup(instance);
  31757. +
  31758. +    NCR5380_all_init();
  31759. +
  31760. +    hostdata->aborted = 0;
  31761. +    hostdata->id_mask = 1 << instance->this_id;
  31762. +    for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
  31763. +    if (i > hostdata->id_mask)
  31764. +        hostdata->id_higher_mask |= i;
  31765. +    for (i = 0; i < 8; ++i)
  31766. +    hostdata->busy[i] = 0;
  31767. +#ifdef REAL_DMA
  31768. +    hostdata->dmalen = 0;
  31769. +#endif
  31770. +    hostdata->targets_present = 0;
  31771. +    hostdata->connected = NULL;
  31772. +    hostdata->issue_queue = NULL;
  31773. +    hostdata->disconnected_queue = NULL;
  31774. +    hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags;
  31775. +
  31776. +    if (!the_template) {
  31777. +    the_template = instance->hostt;
  31778. +    first_instance = instance;
  31779. +    }
  31780. +    
  31781. +
  31782. +#ifdef USLEEP
  31783. +    hostdata->time_expires = 0;
  31784. +    hostdata->next_timer = NULL;
  31785. +#endif
  31786. +
  31787. +#ifndef AUTOSENSE
  31788. +    if ((instance->cmd_per_lun > 1) || instance->can_queue > 1)) 
  31789. +     printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
  31790. +            "        without AUTOSENSE option, contingent allegiance conditions may\n"
  31791. +            "        be incorrectly cleared.\n", instance->host_no);
  31792. +#endif /* def AUTOSENSE */
  31793. +
  31794. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  31795. +    NCR5380_write(MODE_REG, MR_BASE);
  31796. +    NCR5380_write(TARGET_COMMAND_REG, 0);
  31797. +    NCR5380_write(SELECT_ENABLE_REG, 0);
  31798. +#ifdef NCR53C400
  31799. +    if (hostdata->flags & FLAG_NCR53C400) {
  31800. +    NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
  31801. +    }
  31802. +#endif
  31803. +}
  31804. +
  31805. +/* 
  31806. + * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, 
  31807. + *    void (*done)(Scsi_Cmnd *)) 
  31808. + *
  31809. + * Purpose :  enqueues a SCSI command
  31810. + *
  31811. + * Inputs : cmd - SCSI command, done - function called on completion, with
  31812. + *    a pointer to the command descriptor.
  31813. + * 
  31814. + * Returns : 0
  31815. + *
  31816. + * Side effects : 
  31817. + *      cmd is added to the per instance issue_queue, with minor 
  31818. + *    twiddling done to the host specific fields of cmd.  If the 
  31819. + *    main coroutine is not running, it is restarted.
  31820. + *
  31821. + */
  31822. +
  31823. +/* Only make static if a wrapper function is used */
  31824. +#ifndef NCR5380_queue_command
  31825. +static
  31826. +#endif
  31827. +int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) {
  31828. +    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
  31829. +    cmd->host->hostdata;
  31830. +    Scsi_Cmnd *tmp;
  31831. +
  31832. +#if (NDEBUG & NDEBUG_NO_WRITE)
  31833. +    switch (cmd->cmnd[0]) {
  31834. +    case WRITE:
  31835. +    case WRITE_10:
  31836. +    printk("scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
  31837. +        instance->host_no);
  31838. +    cmd->result = (DID_ERROR << 16);
  31839. +    done(cmd);
  31840. +    return 0;
  31841. +    }
  31842. +#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
  31843. +
  31844. +
  31845. +    /* 
  31846. +     * We use the host_scribble field as a pointer to the next command  
  31847. +     * in a queue 
  31848. +     */
  31849. +
  31850. +    cmd->host_scribble = NULL;
  31851. +    cmd->scsi_done = done;
  31852. +
  31853. +    cmd->result = 0;
  31854. +
  31855. +
  31856. +    /* 
  31857. +     * Insert the cmd into the issue queue. Note that REQUEST SENSE 
  31858. +     * commands are added to the head of the queue since any command will
  31859. +     * clear the contingent allegiance condition that exists and the 
  31860. +     * sense data is only guaranteed to be valid while the condition exists.
  31861. +     */
  31862. +
  31863. +    cli();
  31864. +    if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
  31865. +    cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
  31866. +    hostdata->issue_queue = cmd;
  31867. +    } else {
  31868. +    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; 
  31869. +        tmp = (Scsi_Cmnd *) tmp->host_scribble);
  31870. +    tmp->host_scribble = (unsigned char *) cmd;
  31871. +    }
  31872. +#if (NDEBUG & NDEBUG_QUEUES)
  31873. +    printk("scsi%d: command added to %s of queue\n", instance->host_no,
  31874. +    (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
  31875. +#endif
  31876. +
  31877. +/* Run the coroutine if it isn't already running. */
  31878. +    run_main();
  31879. +    return 0;
  31880. +}
  31881. +
  31882. +/*
  31883. + * Function : NCR5380_main (void) 
  31884. + *
  31885. + * Purpose : NCR5380_main is a coroutine that runs as long as more work can 
  31886. + *    be done on the NCR5380 host adapters in a system.  Both 
  31887. + *    NCR5380_queue_command() and NCR5380_intr() will try to start it 
  31888. + *    in case it is not running.
  31889. + * 
  31890. + * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should 
  31891. + *  reenable them.  This prevents reentrancy and kernel stack overflow.
  31892. + */     
  31893. +    
  31894. +static void NCR5380_main (void) {
  31895. +    Scsi_Cmnd *tmp, *prev;
  31896. +    struct Scsi_Host *instance;
  31897. +    struct NCR5380_hostdata *hostdata;
  31898. +    int done;
  31899. +
  31900. +    /*
  31901. +     * We run (with interrupts disabled) until we're sure that none of 
  31902. +     * the host adapters have anything that can be done, at which point 
  31903. +     * we set main_running to 0 and exit.
  31904. +     *
  31905. +     * Interrupts are enabled before doing various other internal 
  31906. +     * instructions, after we've decided that we need to run through
  31907. +     * the loop again.
  31908. +     *
  31909. +     * this should prevent any race conditions.
  31910. +     */
  31911. +
  31912. +    do {
  31913. +    cli(); /* Freeze request queues */
  31914. +    done = 1;
  31915. +    for (instance = first_instance; instance && 
  31916. +        instance->hostt == the_template; instance=instance->next) {
  31917. +        hostdata = (struct NCR5380_hostdata *) instance->hostdata;
  31918. +        cli();
  31919. +        if (!hostdata->connected) {
  31920. +#if (NDEBUG & NDEBUG_MAIN)
  31921. +        printk("scsi%d: not connected\n", instance->host_no);
  31922. +#endif
  31923. +        /*
  31924. +         * Search through the issue_queue for a command destined
  31925. +         * for a target that's not busy.
  31926. +         */
  31927. +        for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, 
  31928. +            prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) 
  31929. +            tmp->host_scribble) 
  31930. +
  31931. +            /*  When we find one, remove it from the issue queue. */
  31932. +            if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) {
  31933. +                if (prev)
  31934. +                prev->host_scribble = tmp->host_scribble;
  31935. +                else
  31936. +                hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble;
  31937. +            tmp->host_scribble = NULL;
  31938. +
  31939. +            /* reenable interrupts after finding one */
  31940. +            sti();
  31941. +
  31942. +            /* 
  31943. +             * Attempt to establish an I_T_L nexus here. 
  31944. +             * On success, instance->hostdata->connected is set.
  31945. +             * On failure, we must add the command back to the
  31946. +             *   issue queue so we can keep trying.    
  31947. +             */
  31948. +#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
  31949. +            printk("scsi%d: main() : command for target %d lun %d removed from issue_queue\n",
  31950. +                instance->host_no, tmp->target, tmp->lun);
  31951. +#endif
  31952. +                /* 
  31953. +                 * REQUEST SENSE commands are issued without tagged
  31954. +                 * queueing, even on SCSI-II devices because the 
  31955. +                 * contingent allegiance condition exists for the 
  31956. +                 * entire unit.
  31957. +                 */
  31958. +                
  31959. +            if (!NCR5380_select(instance, tmp, 
  31960. +                (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : 
  31961. +                TAG_NEXT)) {
  31962. +                break;
  31963. +            } else {
  31964. +                cli();
  31965. +                tmp->host_scribble = (unsigned char *) 
  31966. +                hostdata->issue_queue;
  31967. +                hostdata->issue_queue = tmp;
  31968. +                sti();
  31969. +#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
  31970. +            printk("scsi%d: main(): select() failed, returned to issue_queue\n",
  31971. +                instance->host_no);
  31972. +#endif
  31973. +            }
  31974. +            } /* if target/lun is not busy */
  31975. +        } /* if (!hostdata->connected) */
  31976. +        
  31977. +        if (hostdata->connected 
  31978. +#ifdef REAL_DMA
  31979. +        && !hostdata->dmalen
  31980. +#endif
  31981. +#ifdef USLEEP
  31982. +        && (!hostdata->time_expires || hostdata->time_expires >= jiffies)
  31983. +#endif
  31984. +        ) {
  31985. +        sti();
  31986. +#if (NDEBUG & NDEBUG_MAIN)
  31987. +        printk("scsi%d: main() : performing information transfer\n",
  31988. +            instance->host_no);
  31989. +#endif
  31990. +        NCR5380_information_transfer(instance);
  31991. +#if (NDEBUG & NDEBUG_MAIN)
  31992. +        printk("scsi%d: main() : done set false\n", instance->host_no);
  31993. +#endif
  31994. +        done = 0;
  31995. +        } else 
  31996. +        break;
  31997. +    } /* for instance */
  31998. +    } while (!done);
  31999. +    main_running = 0;
  32000. +}
  32001. +
  32002. +/*
  32003. + * Function : void NCR5380_intr (int irq)
  32004. + * 
  32005. + * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
  32006. + *    from the disconnected queue, and restarting NCR5380_main() 
  32007. + *    as required.
  32008. + *
  32009. + * Inputs : int irq, irq that caused this interrupt.
  32010. + *
  32011. + */
  32012. +
  32013. +static void NCR5380_intr (int irq, struct pt_regs * regs) {
  32014. +    NCR5380_local_declare(); 
  32015. +    struct Scsi_Host *instance;
  32016. +    int done;
  32017. +    unsigned char basr;
  32018. +#if (NDEBUG & NDEBUG_INTR)
  32019. +    printk("scsi : NCR5380 irq %d triggered\n", irq);
  32020. +#endif
  32021. +    do {
  32022. +    done = 1;
  32023. +    for (instance = first_instance; instance && (instance->hostt == 
  32024. +        the_template); instance = instance->next)
  32025. +        if (instance->irq == irq) {
  32026. +        
  32027. +        /* Look for pending interrupts */
  32028. +        NCR5380_setup(instance);
  32029. +        basr = NCR5380_read(BUS_AND_STATUS_REG);
  32030. +        /* XXX dispatch to appropriate routine if found and done=0 */
  32031. +        if (basr & BASR_IRQ) {
  32032. +#if (NDEBUG & NDEBUG_INTR)
  32033. +            NCR5380_print(instance);
  32034. +#endif
  32035. +            if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == 
  32036. +            (SR_SEL | SR_IO)) {
  32037. +            done = 0;
  32038. +            sti();
  32039. +#if (NDEBUG & NDEBUG_INTR)
  32040. +            printk("scsi%d: SEL interrupt\n", instance->host_no);
  32041. +#endif
  32042. +            NCR5380_reselect(instance);
  32043. +            (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
  32044. +            } else if (basr & BASR_PARITY_ERROR) {
  32045. +#if (NDEBUG & NDEBUG_INTR)
  32046. +            printk("scsi%d: PARITY interrupt\n", instance->host_no);
  32047. +#endif
  32048. +            (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
  32049. +             } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
  32050. +#if (NDEBUG & NDEBUG_INTR)
  32051. +             printk("scsi%d: RESET interrupt\n", instance->host_no);
  32052. +#endif
  32053. +            (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
  32054. +            } else {
  32055. +/*  
  32056. + * XXX the rest of the interrupt conditions should *only* occur during a 
  32057. + * DMA transfer, which I haven't gotten around to fixing yet.
  32058. + */
  32059. +
  32060. +#if defined(REAL_DMA)
  32061. +            /*
  32062. +             * We should only get PHASE MISMATCH and EOP interrupts
  32063. +             * if we have DMA enabled, so do a sanity check based on
  32064. +             * the current setting of the MODE register.
  32065. +             */
  32066. +
  32067. +            if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & 
  32068. +                BASR_END_DMA_TRANSFER) || 
  32069. +                !(basr & BASR_PHASE_MATCH))) {
  32070. +                int transfered;
  32071. +
  32072. +                if (!hostdata->connected) 
  32073. +                panic("scsi%d: received end of DMA interrupt with no connected cmd\n",
  32074. +                    instance->hostno);
  32075. +
  32076. +                transfered = (hostdata->dmalen - NCR5380_dma_residual(instance));
  32077. +                hostdata->connected->SCp.this_residual -= transferred;
  32078. +                hostdata->connected->SCp.ptr += transferred;
  32079. +                hostdata->dmalen = 0;
  32080. +
  32081. +                (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
  32082. +#if NCR_TIMEOUT
  32083. +                {
  32084. +                  unsigned long timeout = jiffies + NCR_TIMEOUT;
  32085. +
  32086. +                  while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK
  32087. +                     && jiffies < timeout)
  32088. +                ;
  32089. +                  if (jiffies >= timeout)
  32090. +                    printk("scsi: timeout at %d\n", __LINE__);
  32091. +                }
  32092. +#else /* NCR_TIMEOUT */
  32093. +                while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);
  32094. +#endif
  32095. +
  32096. +                NCR5380_write(MODE_REG, MR_BASE);
  32097. +                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  32098. +            }
  32099. +#else
  32100. +#if (NDEBUG & NDEBUG_INTR)
  32101. +            printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
  32102. +#endif
  32103. +            (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
  32104. +#endif
  32105. +            } 
  32106. +        } /* if BASR_IRQ */
  32107. +        if (!done) 
  32108. +            run_main();
  32109. +        } /* if (instance->irq == irq) */
  32110. +    } while (!done);
  32111. +}
  32112. +
  32113. +/* 
  32114. + * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, 
  32115. + *    int tag);
  32116. + *
  32117. + * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
  32118. + *    including ARBITRATION, SELECTION, and initial message out for 
  32119. + *    IDENTIFY and queue messages. 
  32120. + *
  32121. + * Inputs : instance - instantiation of the 5380 driver on which this 
  32122. + *     target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for 
  32123. + *    new tag, TAG_NONE for untagged queueing, otherwise set to the tag for 
  32124. + *    the command that is presently connected.
  32125. + * 
  32126. + * Returns : -1 if selection could not execute for some reason,
  32127. + *    0 if selection succeeded or failed because the target 
  32128. + *     did not respond.
  32129. + *
  32130. + * Side effects : 
  32131. + *     If bus busy, arbitration failed, etc, NCR5380_select() will exit 
  32132. + *        with registers as they should have been on entry - ie
  32133. + *        SELECT_ENABLE will be set appropriately, the NCR5380
  32134. + *        will cease to drive any SCSI bus signals.
  32135. + *
  32136. + *    If successful : I_T_L or I_T_L_Q nexus will be established, 
  32137. + *        instance->connected will be set to cmd.  
  32138. + *         SELECT interrupt will be disabled.
  32139. + *
  32140. + *    If failed (no target) : cmd->scsi_done() will be called, and the 
  32141. + *        cmd->result host byte set to DID_BAD_TARGET.
  32142. + */
  32143. +
  32144. +static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
  32145. +    int tag) {
  32146. +    NCR5380_local_declare();
  32147. +    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata*) 
  32148. +    instance->hostdata;
  32149. +    unsigned char tmp[3], phase;
  32150. +    unsigned char *data;
  32151. +    int len;
  32152. +    unsigned long timeout;
  32153. +    NCR5380_setup(instance);
  32154. +
  32155. +    hostdata->restart_select = 0;
  32156. +#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) 
  32157. +    NCR5380_print(instance);
  32158. +    printk("scsi%d: starting arbitration, id = %d\n", instance->host_no,
  32159. +    instance->this_id);
  32160. +#endif
  32161. +    cli(); 
  32162. +
  32163. +    /* 
  32164. +     * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
  32165. +     * data bus during SELECTION.
  32166. +     */
  32167. +
  32168. +    NCR5380_write(TARGET_COMMAND_REG, 0);
  32169. +
  32170. +
  32171. +    /* 
  32172. +     * Start arbitration.
  32173. +     */
  32174. +    
  32175. +    NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
  32176. +    NCR5380_write(MODE_REG, MR_ARBITRATE);
  32177. +
  32178. +    sti();
  32179. +
  32180. +    /* Wait for arbitration logic to complete */
  32181. +#if NCR_TIMEOUT
  32182. +    {
  32183. +      unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
  32184. +
  32185. +      while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
  32186. +       && jiffies < timeout)
  32187. +    ;
  32188. +      if (jiffies >= timeout)
  32189. +      {
  32190. +    printk("scsi: arbitration timeout at %d\n", __LINE__);
  32191. +    NCR5380_write(MODE_REG, MR_BASE);
  32192. +    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
  32193. +    return -1;
  32194. +      }
  32195. +    }
  32196. +#else /* NCR_TIMEOUT */
  32197. +    while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS));
  32198. +#endif
  32199. +
  32200. +#if (NDEBUG & NDEBUG_ARBITRATION) 
  32201. +    printk("scsi%d: arbitration complete\n", instance->host_no);
  32202. +/* Avoid GCC 2.4.5 asm needs to many reloads error */
  32203. +    __asm__("nop");
  32204. +#endif
  32205. +
  32206. +    /* 
  32207. +     * The arbitration delay is 2.2us, but this is a minimum and there is 
  32208. +     * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
  32209. +     * the integral nature of udelay().
  32210. +     *
  32211. +     */
  32212. +
  32213. +    udelay(3);
  32214. +
  32215. +    /* Check for lost arbitration */
  32216. +    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
  32217. +    (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
  32218. +    (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
  32219. +    NCR5380_write(MODE_REG, MR_BASE); 
  32220. +#if (NDEBUG & NDEBUG_ARBITRATION)
  32221. +    printk("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", 
  32222. +    instance->host_no);
  32223. +#endif
  32224. +    return -1;
  32225. +    }
  32226. +
  32227. +
  32228. +
  32229. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);
  32230. +    
  32231. +    if (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) {
  32232. +    NCR5380_write(MODE_REG, MR_BASE);
  32233. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  32234. +#if (NDEBUG & NDEBUG_ARBITRATION)
  32235. +    printk("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", 
  32236. +    instance->host_no);
  32237. +#endif
  32238. +    return -1;
  32239. +    }
  32240. +
  32241. +    /* 
  32242. +     * Again, bus clear + bus settle time is 1.2us, however, this is 
  32243. +     * a minimum so we'll udelay ceil(1.2)
  32244. +     */
  32245. +
  32246. +    udelay(2);    
  32247. +
  32248. +#if (NDEBUG & NDEBUG_ARBITRATION)
  32249. +    printk("scsi%d: won arbitration\n", instance->host_no);
  32250. +#endif
  32251. +
  32252. +
  32253. +    /* 
  32254. +     * Now that we have won arbitration, start Selection process, asserting 
  32255. +     * the host and target ID's on the SCSI bus.
  32256. +     */
  32257. +
  32258. +    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
  32259. +
  32260. +    /* 
  32261. +     * Raise ATN while SEL is true before BSY goes false from arbitration,
  32262. +     * since this is the only way to guarantee that we'll get a MESSAGE OUT
  32263. +     * phase immediately after selection.
  32264. +     */
  32265. +
  32266. +    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | 
  32267. +    ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
  32268. +    NCR5380_write(MODE_REG, MR_BASE);
  32269. +
  32270. +    /* 
  32271. +     * Reselect interrupts must be turned off prior to the dropping of BSY,
  32272. +     * otherwise we will trigger an interrupt.
  32273. +     */
  32274. +    NCR5380_write(SELECT_ENABLE_REG, 0);
  32275. +
  32276. +    /* Reset BSY */
  32277. +    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | 
  32278. +    ICR_ASSERT_ATN | ICR_ASSERT_SEL));
  32279. +
  32280. +    /* 
  32281. +     * Something weird happens when we cease to drive BSY - looks
  32282. +     * like the board/chip is letting us do another read before the 
  32283. +     * appropriate propagation delay has expired, and we're confusing
  32284. +     * a BSY signal from ourselves as the target's response to SELECTION.
  32285. +     *
  32286. +     * A small delay (the 'C++' frontend breaks the pipeline with an
  32287. +     * unnecessary jump, making it work on my 386-33/Trantor T128, the
  32288. +     * tighter 'C' code breaks and requires this) solves the problem - 
  32289. +     * the 1 us delay is arbitrary, and only used because this delay will 
  32290. +     * be the same on other platforms and since it works here, it should 
  32291. +     * work there.
  32292. +     */
  32293. +
  32294. +    udelay(1);
  32295. +
  32296. +#if (NDEBUG & NDEBUG_SELECTION)
  32297. +    printk("scsi%d: selecting target %d\n", instance->host_no, cmd->target);
  32298. +#endif
  32299. +
  32300. +    /* 
  32301. +     * The SCSI specification calls for a 250 ms timeout for the actual 
  32302. +     * selection.
  32303. +     */
  32304. +
  32305. +    timeout = jiffies + 25; 
  32306. +
  32307. +    /* 
  32308. +     * XXX very interesting - we're seeing a bounce where the BSY we 
  32309. +     * asserted is being reflected / still asserted (propagation delay?)
  32310. +     * and it's detecting as true.  Sigh.
  32311. +     */
  32312. +
  32313. +    while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & 
  32314. +    (SR_BSY | SR_IO)));
  32315. +
  32316. +    if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == 
  32317. +        (SR_SEL | SR_IO)) {
  32318. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  32319. +        NCR5380_reselect(instance);
  32320. +        printk ("scsi%d: reselection after won arbitration?\n",
  32321. +        instance->host_no);
  32322. +        NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
  32323. +        return -1;
  32324. +    }
  32325. +
  32326. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
  32327. +
  32328. +    if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
  32329. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  32330. +    if (hostdata->targets_present & (1 << cmd->target)) {
  32331. +        printk("scsi%d: weirdness\n", instance->host_no);
  32332. +        if (hostdata->restart_select)
  32333. +        printk("\trestart select\n");
  32334. +#ifdef NDEBUG
  32335. +        NCR5380_print (instance);
  32336. +#endif
  32337. +        NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
  32338. +        return -1;
  32339. +    }
  32340. +    cmd->result = DID_BAD_TARGET << 16;
  32341. +    cmd->scsi_done(cmd);
  32342. +    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
  32343. +#if (NDEBUG & NDEBUG_SELECTION)
  32344. +    printk("scsi%d: target did not respond within 250ms\n", 
  32345. +        instance->host_no);
  32346. +#endif
  32347. +    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
  32348. +    return 0;
  32349. +    } 
  32350. +
  32351. +    hostdata->targets_present |= (1 << cmd->target);
  32352. +
  32353. +    /*
  32354. +     * Since we followed the SCSI spec, and raised ATN while SEL 
  32355. +     * was true but before BSY was false during selection, the information
  32356. +     * transfer phase should be a MESSAGE OUT phase so that we can send the
  32357. +     * IDENTIFY message.
  32358. +     * 
  32359. +     * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
  32360. +     * message (2 bytes) with a tag ID that we increment with every command
  32361. +     * until it wraps back to 0.
  32362. +     *
  32363. +     * XXX - it turns out that there are some broken SCSI-II devices,
  32364. +     *         which claim to support tagged queuing but fail when more than
  32365. +     *         some number of commands are issued at once.
  32366. +     */
  32367. +
  32368. +    /* Wait for start of REQ/ACK handshake */
  32369. +    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
  32370. +
  32371. +#if (NDEBUG & NDEBUG_SELECTION)
  32372. +    printk("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
  32373. +    instance->host_no, cmd->target);
  32374. +#endif
  32375. +    tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun);
  32376. +#ifdef SCSI2
  32377. +    if (cmd->device->tagged_queue && (tag != TAG_NONE)) {
  32378. +    tmp[1] = SIMPLE_QUEUE_TAG;
  32379. +    if (tag == TAG_NEXT) {
  32380. +        /* 0 is TAG_NONE, used to imply no tag for this command */
  32381. +        if (cmd->device->current_tag == 0)
  32382. +        cmd->device->current_tag = 1;
  32383. +
  32384. +        cmd->tag = cmd->device->current_tag;
  32385. +        cmd->device->current_tag++;
  32386. +    } else  
  32387. +        cmd->tag = (unsigned char) tag;
  32388. +
  32389. +    tmp[2] = cmd->tag;
  32390. +    hostdata->last_message = SIMPLE_QUEUE_TAG;
  32391. +    len = 3;
  32392. +    } else 
  32393. +#endif /* def SCSI2 */
  32394. +    {
  32395. +    len = 1;
  32396. +    cmd->tag=0;
  32397. +    }
  32398. +
  32399. +    /* Send message(s) */
  32400. +    data = tmp;
  32401. +    phase = PHASE_MSGOUT;
  32402. +    NCR5380_transfer_pio(instance, &phase, &len, &data);
  32403. +#if (NDEBUG & NDEBUG_SELECTION)
  32404. +    printk("scsi%d: nexus established.\n", instance->host_no);
  32405. +#endif
  32406. +    /* XXX need to handle errors here */
  32407. +    hostdata->connected = cmd;
  32408. +#ifdef SCSI2
  32409. +    if (!cmd->device->tagged_queue)
  32410. +#endif    
  32411. +    hostdata->busy[cmd->target] |= (1 << cmd->lun);
  32412. +
  32413. +    initialize_SCp(cmd);
  32414. +
  32415. +
  32416. +    return 0;
  32417. +}
  32418. +
  32419. +/* 
  32420. + * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 
  32421. + *      unsigned char *phase, int *count, unsigned char **data)
  32422. + *
  32423. + * Purpose : transfers data in given phase using polled I/O
  32424. + *
  32425. + * Inputs : instance - instance of driver, *phase - pointer to 
  32426. + *    what phase is expected, *count - pointer to number of 
  32427. + *    bytes to transfer, **data - pointer to data pointer.
  32428. + * 
  32429. + * Returns : -1 when different phase is entered without transferring
  32430. + *    maximum number of bytes, 0 if all bytes or transfered or exit
  32431. + *    is in same phase.
  32432. + *
  32433. + *     Also, *phase, *count, *data are modified in place.
  32434. + *
  32435. + * XXX Note : handling for bus free may be useful.
  32436. + */
  32437. +
  32438. +/*
  32439. + * Note : this code is not as quick as it could be, however it 
  32440. + * IS 100% reliable, and for the actual data transfer where speed
  32441. + * counts, we will always do a pseudo DMA or DMA transfer.
  32442. + */
  32443. +
  32444. +static int NCR5380_transfer_pio (struct Scsi_Host *instance, 
  32445. +    unsigned char *phase, int *count, unsigned char **data) {
  32446. +    NCR5380_local_declare();
  32447. +    register unsigned char p = *phase, tmp;
  32448. +    register int c = *count;
  32449. +    register unsigned char *d = *data;
  32450. +    NCR5380_setup(instance);
  32451. +
  32452. +    /* 
  32453. +     * The NCR5380 chip will only drive the SCSI bus when the 
  32454. +     * phase specified in the appropriate bits of the TARGET COMMAND
  32455. +     * REGISTER match the STATUS REGISTER
  32456. +     */
  32457. +
  32458. +    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
  32459. +
  32460. +    do {
  32461. +    /* 
  32462. +     * Wait for assertion of REQ, after which the phase bits will be 
  32463. +     * valid 
  32464. +     */
  32465. +    while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
  32466. +
  32467. +#if (NDEBUG & NDEBUG_HANDSHAKE)
  32468. +    printk("scsi%d: REQ detected\n", instance->host_no);
  32469. +#endif
  32470. +
  32471. +    /* Check for phase mismatch */    
  32472. +    if ((tmp & PHASE_MASK) != p) {
  32473. +#if (NDEBUG & NDEBUG_PIO)
  32474. +        printk("scsi%d: phase mismatch\n", instance->host_no);
  32475. +        NCR5380_print_phase(instance);
  32476. +#endif
  32477. +        break;
  32478. +    }
  32479. +
  32480. +    /* Do actual transfer from SCSI bus to / from memory */
  32481. +    if (!(p & SR_IO)) 
  32482. +        NCR5380_write(OUTPUT_DATA_REG, *d);
  32483. +    else 
  32484. +        *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
  32485. +
  32486. +    ++d;
  32487. +
  32488. +    /* 
  32489. +     * The SCSI standard suggests that in MSGOUT phase, the initiator
  32490. +     * should drop ATN on the last byte of the message phase
  32491. +     * after REQ has been asserted for the handshake but before
  32492. +     * the initiator raises ACK.
  32493. +     */
  32494. +
  32495. +    if (!(p & SR_IO)) {
  32496. +        if (!((p & SR_MSG) && c > 1)) {
  32497. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
  32498. +            ICR_ASSERT_DATA);
  32499. +#if (NDEBUG & NDEBUG_PIO)
  32500. +    NCR5380_print(instance);
  32501. +#endif
  32502. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
  32503. +            ICR_ASSERT_DATA | ICR_ASSERT_ACK);
  32504. +        } else {
  32505. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
  32506. +            ICR_ASSERT_DATA | ICR_ASSERT_ATN);
  32507. +#if (NDEBUG & NDEBUG_PIO)
  32508. +    NCR5380_print(instance);
  32509. +#endif
  32510. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
  32511. +            ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
  32512. +        }
  32513. +    } else {
  32514. +#if (NDEBUG & NDEBUG_PIO)
  32515. +    NCR5380_print(instance);
  32516. +#endif
  32517. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
  32518. +    }
  32519. +
  32520. +    while (NCR5380_read(STATUS_REG) & SR_REQ);
  32521. +
  32522. +#if (NDEBUG & NDEBUG_HANDSHAKE)
  32523. +        printk("scsi%d: req false, handshake complete\n", instance->host_no);
  32524. +#endif
  32525. +
  32526. +/*
  32527. + * We have several special cases to consider during REQ/ACK handshaking : 
  32528. + * 1.  We were in MSGOUT phase, and we are on the last byte of the 
  32529. + *    message.  ATN must be dropped as ACK is dropped.
  32530. + *
  32531. + * 2.  We are in a MSGIN phase, and we are on the last byte of the  
  32532. + *    message.  We must exit with ACK asserted, so that the calling
  32533. + *    code may raise ATN before dropping ACK to reject the message.
  32534. + *
  32535. + * 3.  ACK and ATN are clear and the target may proceed as normal.
  32536. + */
  32537. +    if (!(p == PHASE_MSGIN && c == 1)) {  
  32538. +        if (p == PHASE_MSGOUT && c > 1)
  32539. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
  32540. +        else
  32541. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  32542. +    } 
  32543. +    } while (--c);
  32544. +
  32545. +#if (NDEBUG & NDEBUG_PIO) 
  32546. +    printk("scsi%d: residual %d\n", instance->host_no, c);
  32547. +#endif
  32548. +
  32549. +    *count = c;
  32550. +    *data = d;
  32551. +    tmp = NCR5380_read(STATUS_REG);
  32552. +    if (tmp & SR_REQ)
  32553. +    *phase = tmp & PHASE_MASK;
  32554. +    else 
  32555. +    *phase = PHASE_UNKNOWN;
  32556. +
  32557. +    if (!c || (*phase == p))
  32558. +    return 0;
  32559. +    else 
  32560. +    return -1;
  32561. +}
  32562. +
  32563. +#if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL)
  32564. +/* 
  32565. + * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 
  32566. + *      unsigned char *phase, int *count, unsigned char **data)
  32567. + *
  32568. + * Purpose : transfers data in given phase using either real
  32569. + *    or pseudo DMA.
  32570. + *
  32571. + * Inputs : instance - instance of driver, *phase - pointer to 
  32572. + *    what phase is expected, *count - pointer to number of 
  32573. + *    bytes to transfer, **data - pointer to data pointer.
  32574. + * 
  32575. + * Returns : -1 when different phase is entered without transferring
  32576. + *    maximum number of bytes, 0 if all bytes or transfered or exit
  32577. + *    is in same phase.
  32578. + *
  32579. + *     Also, *phase, *count, *data are modified in place.
  32580. + *
  32581. + */
  32582. +
  32583. +
  32584. +static int NCR5380_transfer_dma (struct Scsi_Host *instance, 
  32585. +    unsigned char *phase, int *count, unsigned char **data) {
  32586. +    NCR5380_local_declare();
  32587. +    register int c = *count;
  32588. +    register unsigned char p = *phase;
  32589. +    register unsigned char *d = *data;
  32590. +    unsigned char tmp;
  32591. +    int foo;
  32592. +#if defined(REAL_DMA_POLL)
  32593. +    int cnt, toPIO;
  32594. +    unsigned char saved_data = 0, overrun = 0, residue;
  32595. +#endif
  32596. +
  32597. +    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) 
  32598. +    instance->hostdata;
  32599. +
  32600. +    NCR5380_setup(instance);
  32601. +
  32602. +    if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
  32603. +        *phase = tmp;
  32604. +        return -1;
  32605. +    }
  32606. +#if defined(REAL_DMA) || defined(REAL_DMA_POLL) 
  32607. +#ifdef READ_OVERRUNS
  32608. +     if (p & SR_IO) {
  32609. +       c -= 2;
  32610. +     }
  32611. +#endif
  32612. +#if (NDEBUG & NDEBUG_DMA)
  32613. +    printk("scsi%d: initializing DMA channel %d for %s, %d bytes %s %0x\n",
  32614. +    instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" :
  32615. +    "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);
  32616. +#endif
  32617. +    hostdata->dma_len = (p & SR_IO) ?
  32618. +    NCR5380_dma_read_setup(instance, d, c) : 
  32619. +    NCR5380_dma_write_setup(instance, d, c);
  32620. +#endif
  32621. +
  32622. +    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
  32623. +
  32624. +#ifdef REAL_DMA
  32625. +    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
  32626. +#elif defined(REAL_DMA_POLL)
  32627. +    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
  32628. +#else
  32629. +    /*
  32630. +     * Note : on my sample board, watch-dog timeouts occurred when interrupts
  32631. +     * were not disabled for the duration of a single DMA transfer, from 
  32632. +     * before the setting of DMA mode to after transfer of the last byte.
  32633. +     */
  32634. +
  32635. +#if defined(PSEUDO_DMA) && !defined(UNSAFE)
  32636. +    cli();
  32637. +#endif
  32638. +    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
  32639. +#endif /* def REAL_DMA */
  32640. +
  32641. +#if (NDEBUG & NDEBUG_DMA) & 0
  32642. +    printk("scsi%d: mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG));
  32643. +#endif
  32644. +
  32645. +/* 
  32646. + * FOO stuff. For some UNAPPARENT reason, I'm getting 
  32647. + * watchdog timers fired on bootup for NO APPARENT REASON, meaning it's
  32648. + * probably a timing problem.
  32649. + *
  32650. + * Since this is the only place I have back-to-back writes, perhaps this 
  32651. + * is the problem?
  32652. + */
  32653. +
  32654. +    if (p & SR_IO) {
  32655. +#ifndef FOO
  32656. +    udelay(1);
  32657. +#endif
  32658. +    NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
  32659. +    } else {
  32660. +#ifndef FOO
  32661. +    udelay(1);
  32662. +#endif
  32663. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
  32664. +#ifndef FOO
  32665. +    udelay(1);
  32666. +#endif
  32667. +    NCR5380_write(START_DMA_SEND_REG, 0);
  32668. +#ifndef FOO
  32669. +    udelay(1);
  32670. +#endif
  32671. +    }
  32672. +
  32673. +#if defined(REAL_DMA_POLL)
  32674. +    do {
  32675. +    tmp = NCR5380_read(BUS_AND_STATUS_REG);
  32676. +    } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | 
  32677. +    BASR_END_DMA_TRANSFER)));
  32678. +
  32679. +/*
  32680. +  At this point, either we've completed DMA, or we have a phase mismatch,
  32681. +  or we've unexpectedly lost BUSY (which is a real error).
  32682. +
  32683. +  For write DMAs, we want to wait until the last byte has been
  32684. +  transferred out over the bus before we turn off DMA mode.  Alas, there
  32685. +  seems to be no terribly good way of doing this on a 5380 under all
  32686. +  conditions.  For non-scatter-gather operations, we can wait until REQ
  32687. +  and ACK both go false, or until a phase mismatch occurs.  Gather-writes
  32688. +  are nastier, since the device will be expecting more data than we
  32689. +  are prepared to send it, and REQ will remain asserted.  On a 53C8[01] we
  32690. +  could test LAST BIT SENT to assure transfer (I imagine this is precisely
  32691. +  why this signal was added to the newer chips) but on the older 538[01]
  32692. +  this signal does not exist.  The workaround for this lack is a watchdog;
  32693. +  we bail out of the wait-loop after a modest amount of wait-time if
  32694. +  the usual exit conditions are not met.  Not a terribly clean or
  32695. +  correct solution :-%
  32696. +
  32697. +  Reads are equally tricky due to a nasty characteristic of the NCR5380.
  32698. +  If the chip is in DMA mode for an READ, it will respond to a target's
  32699. +  REQ by latching the SCSI data into the INPUT DATA register and asserting
  32700. +  ACK, even if it has _already_ been notified by the DMA controller that
  32701. +  the current DMA transfer has completed!  If the NCR5380 is then taken
  32702. +  out of DMA mode, this already-acknowledged byte is lost.
  32703. +
  32704. +  This is not a problem for "one DMA transfer per command" reads, because
  32705. +  the situation will never arise... either all of the data is DMA'ed
  32706. +  properly, or the target switches to MESSAGE IN phase to signal a
  32707. +  disconnection (either operation bringing the DMA to a clean halt).
  32708. +  However, in order to handle scatter-reads, we must work around the
  32709. +  problem.  The chosen fix is to DMA N-2 bytes, then check for the
  32710. +  condition before taking the NCR5380 out of DMA mode.  One or two extra
  32711. +  bytes are transferred via PIO as necessary to fill out the original
  32712. +  request.
  32713. +*/
  32714. +
  32715. +    if (p & SR_IO) {
  32716. +#ifdef READ_OVERRUNS
  32717. +      udelay(10);
  32718. +      if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH|BASR_ACK)) ==
  32719. +           (BASR_PHASE_MATCH | BASR_ACK))) {
  32720. +        saved_data = NCR5380_read(INPUT_DATA_REGISTER);
  32721. +        overrun = 1;
  32722. +      }
  32723. +#endif
  32724. +    } else {
  32725. +      int limit = 100;
  32726. +      while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) ||
  32727. +            (NCR5380_read(STATUS_REG) & SR_REQ)) {
  32728. +        if (!(tmp & BASR_PHASE_MATCH)) break;
  32729. +        if (--limit < 0) break;
  32730. +      }
  32731. +    }
  32732. +
  32733. +
  32734. +#if (NDEBUG & NDEBUG_DMA)
  32735. +    printk("scsi%d: polled DMA transfer complete, basr 0x%X, sr 0x%X\n",
  32736. +       instance->host_no, tmp, NCR5380_read(STATUS_REG));
  32737. +#endif
  32738. +
  32739. +    NCR5380_write(MODE_REG, MR_BASE);
  32740. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  32741. +
  32742. +    residue = NCR5380_dma_residual(instance);
  32743. +    c -= residue;
  32744. +    *count -= c;
  32745. +    *data += c;
  32746. +    *phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
  32747. +
  32748. +#ifdef READ_OVERRUNS
  32749. +    if (*phase == p && (p & SR_IO) && residue == 0) {
  32750. +      if (overrun) {
  32751. +#if (NDEBUG & NDEBUG_DMA)
  32752. +        printk("Got an input overrun, using saved byte\n");
  32753. +#endif
  32754. +        **data = saved_data;
  32755. +        *data += 1;
  32756. +        *count -= 1;
  32757. +        cnt = toPIO = 1;
  32758. +      } else {
  32759. +        printk("No overrun??\n");
  32760. +        cnt = toPIO = 2;
  32761. +      }
  32762. +#if (NDEBUG & NDEBUG_DMA)
  32763. +      printk("Doing %d-byte PIO to 0x%X\n", cnt, *data);
  32764. +#endif
  32765. +      NCR5380_transfer_pio(instance, phase, &cnt, data);
  32766. +      *count -= toPIO - cnt;
  32767. +    }
  32768. +#endif        
  32769. +
  32770. +#if (NDEBUG & NDEBUG_DMA)
  32771. +     printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n",
  32772. +        *data, *count, *(*data+*count-1), *(*data+*count));
  32773. +#endif
  32774. +     return 0;
  32775. +     
  32776. +#elif defined(REAL_DMA)
  32777. +    return 0;
  32778. +#else /* defined(REAL_DMA_POLL) */
  32779. +    if (p & SR_IO) {
  32780. +#if 0
  32781. +    if (!(foo = NCR5380_pread(instance, d, c - 1))) {
  32782. +        /*
  32783. +         * We can't disable DMA mode after successfully transferring 
  32784. +         * what we plan to be the last byte, since that would open up
  32785. +         * a race condition where if the target asserted REQ before 
  32786. +         * we got the DMA mode reset, the NCR5380 would have latched
  32787. +         * an additional byte into the INPUT DATA register and we'd
  32788. +         * have dropped it.
  32789. +         * 
  32790. +         * The workaround was to transfer one fewer bytes than we 
  32791. +         * intended to with the pseudo-DMA read function, wait for 
  32792. +         * the chip to latch the last byte, read it, and then disable
  32793. +         * pseudo-DMA mode.
  32794. +         * 
  32795. +         * After REQ is asserted, the NCR5380 asserts DRQ and ACK.
  32796. +         * REQ is deasserted when ACK is asserted, and not reasserted
  32797. +         * until ACK goes false.  Since the NCR5380 won't lower ACK
  32798. +         * until DACK is asserted, which won't happen unless we twiddle
  32799. +         * the DMA port or we take the NCR5380 out of DMA mode, we 
  32800. +         * can guarantee that we won't handshake another extra 
  32801. +         * byte.
  32802. +             */
  32803. +
  32804. +        while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
  32805. +        /* Wait for clean handshake */
  32806. +        while (NCR5380_read(STATUS_REG) & SR_REQ);
  32807. +        d[c - 1] = NCR5380_read(INPUT_DATA_REG);
  32808. +    }
  32809. +#else
  32810. +    if (!(foo = NCR5380_pread(instance, d, c - 2))) {
  32811. +        while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
  32812. +        while (NCR5380_read(STATUS_REG) & SR_REQ);
  32813. +        d[c - 2] = NCR5380_read(INPUT_DATA_REG);
  32814. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
  32815. +        while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
  32816. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ACK);
  32817. +        while (NCR5380_read(STATUS_REG) & SR_REQ);
  32818. +        d[c - 2] = NCR5380_read(INPUT_DATA_REG);
  32819. +    }
  32820. +#endif
  32821. +    } else {
  32822. +    int timeout;
  32823. +    if (!(foo = NCR5380_pwrite(instance, d, c))) {
  32824. +        /*
  32825. +         * Wait for the last byte to be sent.  If REQ is being asserted for 
  32826. +         * the byte we're interested, we'll ACK it and it will go false.  
  32827. +         */
  32828. +        if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) {
  32829. +        timeout = 20000;
  32830. +#if 1
  32831. +#if 1
  32832. +        while (!(NCR5380_read(BUS_AND_STATUS_REG) & 
  32833. +            BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) &
  32834. +                BASR_PHASE_MATCH));
  32835. +#else
  32836. +        if (NCR5380_read(STATUS_REG) & SR_REQ) {
  32837. +            for (; timeout && 
  32838. +            !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); 
  32839. +            --timeout);
  32840. +            for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ);
  32841. +            --timeout);
  32842. +        } 
  32843. +#endif
  32844. +    
  32845. +
  32846. +#if (NDEBUG & NDEBUG_LAST_BYTE_SENT)
  32847. +        if (!timeout) 
  32848. +            printk("scsi%d: timed out on last byte\n",
  32849. +                instance->host_no);
  32850. +#endif
  32851. +
  32852. +
  32853. +        if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) {
  32854. +            hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT;
  32855. +            if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) {
  32856. +            hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;
  32857. +#if (NDEBUG & NDEBUG_LAST_BYTE_SENT)
  32858. +            printk("scsi%d: last bit sent works\n", 
  32859. +                instance->host_no);
  32860. +#endif
  32861. +            }
  32862. +        }
  32863. +        } else 
  32864. +        while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT));
  32865. +#else
  32866. +        udelay (5);
  32867. +#endif
  32868. +    }
  32869. +    }
  32870. +
  32871. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  32872. +    NCR5380_write(MODE_REG, MR_BASE);
  32873. +
  32874. +    *data = d + c;
  32875. +    *count = 0;
  32876. +    *phase = (NCR5380_read(STATUS_REG & PHASE_MASK));
  32877. +#if defined(PSEUDO_DMA) && !defined(UNSAFE)
  32878. +    sti();
  32879. +#endif /* defined(REAL_DMA_POLL) */
  32880. +    return foo;
  32881. +#endif /* def REAL_DMA */
  32882. +}
  32883. +#endif /* defined(REAL_DMA) | defined(PSEUDO_DMA) */
  32884. +
  32885. +/*
  32886. + * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
  32887. + *
  32888. + * Purpose : run through the various SCSI phases and do as the target 
  32889. + *     directs us to.  Operates on the currently connected command, 
  32890. + *    instance->connected.
  32891. + *
  32892. + * Inputs : instance, instance for which we are doing commands
  32893. + *
  32894. + * Side effects : SCSI things happen, the disconnected queue will be 
  32895. + *    modified if a command disconnects, *instance->connected will
  32896. + *    change.
  32897. + *
  32898. + * XXX Note : we need to watch for bus free or a reset condition here 
  32899. + *     to recover from an unexpected bus free condition.
  32900. + */
  32901. +static void NCR5380_information_transfer (struct Scsi_Host *instance) {
  32902. +    NCR5380_local_declare();
  32903. +    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) 
  32904. +    instance->hostdata;
  32905. +    unsigned char msgout = NOP;
  32906. +    int sink = 0;
  32907. +    int len;
  32908. +#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
  32909. +    int transfersize;
  32910. +#endif
  32911. +    unsigned char *data;
  32912. +    unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
  32913. +    Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
  32914. +    NCR5380_setup(instance);
  32915. +
  32916. +    while (1) {
  32917. +    tmp = NCR5380_read(STATUS_REG);
  32918. +    /* We only have a valid SCSI phase when REQ is asserted */
  32919. +    if (tmp & SR_REQ) {
  32920. +        phase = (tmp & PHASE_MASK); 
  32921. +        if (phase != old_phase) {
  32922. +        old_phase = phase;
  32923. +#if (NDEBUG & NDEBUG_INFORMATION)
  32924. +        NCR5380_print_phase(instance);
  32925. +#endif
  32926. +        }
  32927. +        
  32928. +        if (sink && (phase != PHASE_MSGOUT)) {
  32929. +        NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
  32930. +
  32931. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
  32932. +            ICR_ASSERT_ACK);
  32933. +        while (NCR5380_read(STATUS_REG) & SR_REQ);
  32934. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
  32935. +            ICR_ASSERT_ATN);
  32936. +        sink = 0;
  32937. +        continue;
  32938. +        }
  32939. +
  32940. +        switch (phase) {
  32941. +        case PHASE_DATAIN:
  32942. +        case PHASE_DATAOUT:
  32943. +#if (NDEBUG & NDEBUG_NO_DATAOUT)
  32944. +        printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n",
  32945. +            instance->host_no);
  32946. +        sink = 1;
  32947. +        msgout = ABORT;
  32948. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
  32949. +        break;
  32950. +#endif
  32951. +        /* 
  32952. +         * If there is no room left in the current buffer in the
  32953. +         * scatter-gather list, move onto the next one.
  32954. +         */
  32955. +
  32956. +        if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
  32957. +            ++cmd->SCp.buffer;
  32958. +            --cmd->SCp.buffers_residual;
  32959. +            cmd->SCp.this_residual = cmd->SCp.buffer->length;
  32960. +            cmd->SCp.ptr = cmd->SCp.buffer->address;
  32961. +#if (NDEBUG & NDEBUG_INFORMATION)
  32962. +            printk("scsi%d: %d bytes and %d buffers left\n",
  32963. +            instance->host_no, cmd->SCp.this_residual,
  32964. +            cmd->SCp.buffers_residual);
  32965. +#endif
  32966. +        }
  32967. +
  32968. +        /*
  32969. +         * The preferred transfer method is going to be 
  32970. +         * PSEUDO-DMA for systems that are strictly PIO,
  32971. +         * since we can let the hardware do the handshaking.
  32972. +         *
  32973. +         * For this to work, we need to know the transfersize
  32974. +         * ahead of time, since the pseudo-DMA code will sit
  32975. +         * in an unconditional loop.
  32976. +         */
  32977. +
  32978. +#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
  32979. +#ifdef NCR5380_dma_xfer_len
  32980. +        if (!cmd->device->borken &&
  32981. +            (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
  32982. +#else
  32983. +                transfersize = cmd->transfersize;
  32984. +
  32985. +#ifdef LIMIT_TRANSFERSIZE  /* If we have problems with interrupt service */
  32986. +                if( transfersize > 512 )
  32987. +                    transfersize = 512;
  32988. +#endif  /* LIMIT_TRANSFERSIZE */
  32989. +
  32990. +                if (!cmd->device->borken && transfersize && 
  32991. +                    cmd->SCp.this_residual && !(cmd->SCp.this_residual % 
  32992. +                    transfersize)) {
  32993. +#endif
  32994. +            len = transfersize;
  32995. +            if (NCR5380_transfer_dma(instance, &phase,
  32996. +            &len, (unsigned char **) &cmd->SCp.ptr)) {
  32997. +            /*
  32998. +             * If the watchdog timer fires, all future accesses to this
  32999. +             * device will use the polled-IO.
  33000. +             */ 
  33001. +            printk("scsi%d: switching target %d lun %d to slow handshake\n",
  33002. +                instance->host_no, cmd->target, cmd->lun);
  33003. +            cmd->device->borken = 1;
  33004. +            NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
  33005. +                ICR_ASSERT_ATN);
  33006. +            sink = 1;
  33007. +            msgout = ABORT;
  33008. +            /* XXX - need to source or sink data here, as appropriate */
  33009. +            } else
  33010. +            cmd->SCp.this_residual -= transfersize - len;
  33011. +        } else
  33012. +#endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */
  33013. +          NCR5380_transfer_pio(instance, &phase, 
  33014. +            (int *) &cmd->SCp.this_residual, (unsigned char **)
  33015. +            &cmd->SCp.ptr);
  33016. +        break;
  33017. +        case PHASE_MSGIN:
  33018. +        len = 1;
  33019. +        data = &tmp;
  33020. +        NCR5380_transfer_pio(instance, &phase, &len, &data);
  33021. +        cmd->SCp.Message = tmp;
  33022. +
  33023. +        switch (tmp) {
  33024. +        /*
  33025. +         * Linking lets us reduce the time required to get the 
  33026. +         * next command out to the device, hopefully this will
  33027. +         * mean we don't waste another revolution due to the delays
  33028. +         * required by ARBITRATION and another SELECTION.
  33029. +         *
  33030. +         * In the current implementation proposal, low level drivers
  33031. +         * merely have to start the next command, pointed to by 
  33032. +         * next_link, done() is called as with unlinked commands.
  33033. +         */
  33034. +#ifdef LINKED
  33035. +        case LINKED_CMD_COMPLETE:
  33036. +        case LINKED_FLG_CMD_COMPLETE:
  33037. +            /* Accept message by clearing ACK */
  33038. +            NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33039. +            
  33040. +#if (NDEBUG & NDEBUG_LINKED) 
  33041. +            printk("scsi%d: target %d lun %d linked command complete.\n",
  33042. +            instance->host_no, cmd->target, cmd->lun);
  33043. +#endif
  33044. +            /* 
  33045. +             * Sanity check : A linked command should only terminate with
  33046. +             * one of these messages if there are more linked commands
  33047. +             * available.
  33048. +             */
  33049. +
  33050. +            if (!cmd->next_link) {
  33051. +             printk("scsi%d: target %d lun %d linked command complete, no next_link\n"
  33052. +                instance->host_no, cmd->target, cmd->lun);
  33053. +                sink = 1;
  33054. +                msgout = ABORT;
  33055. +                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
  33056. +                ICR_ASSERT_ATN);
  33057. +                break;
  33058. +            }
  33059. +
  33060. +            initialize_SCp(cmd->next_link);
  33061. +            /* The next command is still part of this process */
  33062. +            cmd->next_link->tag = cmd->tag;
  33063. +            cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
  33064. +#if (NDEBUG & NDEBUG_LINKED) 
  33065. +            printk("scsi%d: target %d lun %d linked request done, calling scsi_done().\n",
  33066. +            instance->host_no, cmd->target, cmd->lun);
  33067. +#endif
  33068. +            cmd->scsi_done(cmd);
  33069. +            cmd = hostdata->connected;
  33070. +            break;
  33071. +#endif /* def LINKED */
  33072. +        case ABORT:
  33073. +        case COMMAND_COMPLETE: 
  33074. +            /* Accept message by clearing ACK */
  33075. +            NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33076. +            hostdata->connected = NULL;
  33077. +#if (NDEBUG & NDEBUG_QUEUES)
  33078. +            printk("scsi%d: command for target %d, lun %d completed\n",
  33079. +            instance->host_no, cmd->target, cmd->lun);
  33080. +#endif
  33081. +            hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
  33082. +
  33083. +            /* 
  33084. +             * I'm not sure what the correct thing to do here is : 
  33085. +             * 
  33086. +             * If the command that just executed is NOT a request 
  33087. +             * sense, the obvious thing to do is to set the result
  33088. +             * code to the values of the stored parameters.
  33089. +             * 
  33090. +             * If it was a REQUEST SENSE command, we need some way 
  33091. +             * to differentiate between the failure code of the original
  33092. +             * and the failure code of the REQUEST sense - the obvious
  33093. +             * case is success, where we fall through and leave the result
  33094. +             * code unchanged.
  33095. +             * 
  33096. +             * The non-obvious place is where the REQUEST SENSE failed 
  33097. +             */
  33098. +
  33099. +            if (cmd->cmnd[0] != REQUEST_SENSE) 
  33100. +            cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
  33101. +            else if (cmd->SCp.Status != GOOD)
  33102. +            cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
  33103. +            
  33104. +#ifdef AUTOSENSE
  33105. +            if ((cmd->cmnd[0] != REQUEST_SENSE) && 
  33106. +            (cmd->SCp.Status == CHECK_CONDITION)) {
  33107. +#if (NDEBUG & NDEBUG_AUTOSENSE) 
  33108. +            printk("scsi%d: performing request sense\n", 
  33109. +                instance->host_no);
  33110. +#endif
  33111. +            cmd->cmnd[0] = REQUEST_SENSE;
  33112. +            cmd->cmnd[1] &= 0xe0;
  33113. +            cmd->cmnd[2] = 0;
  33114. +            cmd->cmnd[3] = 0;
  33115. +            cmd->cmnd[4] = sizeof(cmd->sense_buffer);
  33116. +            cmd->cmnd[5] = 0;
  33117. +
  33118. +            cmd->SCp.buffer = NULL;
  33119. +            cmd->SCp.buffers_residual = 0;
  33120. +            cmd->SCp.ptr = (char *) cmd->sense_buffer;
  33121. +            cmd->SCp.this_residual = sizeof(cmd->sense_buffer);
  33122. +
  33123. +            cli();
  33124. +            cmd->host_scribble = (unsigned char *) 
  33125. +                hostdata->issue_queue;
  33126. +                hostdata->issue_queue = (Scsi_Cmnd *) cmd;
  33127. +                sti();
  33128. +#if (NDEBUG & NDEBUG_QUEUES)
  33129. +            printk("scsi%d: REQUEST SENSE added to head of issue queue\n");
  33130. +#endif
  33131. +           } else
  33132. +#endif /* def AUTOSENSE */
  33133. +            cmd->scsi_done(cmd);
  33134. +
  33135. +            NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
  33136. +            /* 
  33137. +             * Restore phase bits to 0 so an interrupted selection, 
  33138. +             * arbitration can resume.
  33139. +             */
  33140. +            NCR5380_write(TARGET_COMMAND_REG, 0);
  33141. +            
  33142. +            while ((NCR5380_read(STATUS_REG) & SR_BSY) && 
  33143. +            !hostdata->connected);
  33144. +            return;
  33145. +        case MESSAGE_REJECT:
  33146. +            /* Accept message by clearing ACK */
  33147. +            NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33148. +            switch (hostdata->last_message) {
  33149. +            case HEAD_OF_QUEUE_TAG:
  33150. +            case ORDERED_QUEUE_TAG:
  33151. +            case SIMPLE_QUEUE_TAG:
  33152. +            cmd->device->tagged_queue = 0;
  33153. +            hostdata->busy[cmd->target] |= (1 << cmd->lun);
  33154. +            break;
  33155. +            default:
  33156. +            break;
  33157. +            }
  33158. +        case DISCONNECT:
  33159. +            /* Accept message by clearing ACK */
  33160. +            NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33161. +            cmd->device->disconnect = 1;
  33162. +            cli();
  33163. +            cmd->host_scribble = (unsigned char *) 
  33164. +            hostdata->disconnected_queue;
  33165. +            hostdata->connected = NULL;
  33166. +            hostdata->disconnected_queue = cmd;
  33167. +            sti();
  33168. +#if (NDEBUG & NDEBUG_QUEUES)
  33169. +            printk("scsi%d: command for target %d lun %d was moved from connected to"
  33170. +                   "  the disconnected_queue\n", instance->host_no, 
  33171. +                cmd->target, cmd->lun);
  33172. +#endif
  33173. +            /* 
  33174. +             * Restore phase bits to 0 so an interrupted selection, 
  33175. +             * arbitration can resume.
  33176. +             */
  33177. +            NCR5380_write(TARGET_COMMAND_REG, 0);
  33178. +            /* Enable reselect interrupts */
  33179. +            NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
  33180. +            /* Wait for bus free to avoid nasty timeouts */
  33181. +            while ((NCR5380_read(STATUS_REG) & SR_BSY) && 
  33182. +            !hostdata->connected);
  33183. +            return;
  33184. +        /* 
  33185. +         * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
  33186. +         * operation, in violation of the SCSI spec so we can safely 
  33187. +         * ignore SAVE/RESTORE pointers calls.
  33188. +         *
  33189. +         * Unfortunately, some disks violate the SCSI spec and 
  33190. +         * don't issue the required SAVE_POINTERS message before
  33191. +         * disconnecting, and we have to break spec to remain 
  33192. +         * compatible.
  33193. +         */
  33194. +        case SAVE_POINTERS:
  33195. +        case RESTORE_POINTERS:
  33196. +            /* Accept message by clearing ACK */
  33197. +            NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33198. +            break;
  33199. +        case EXTENDED_MESSAGE:
  33200. +/* 
  33201. + * Extended messages are sent in the following format :
  33202. + * Byte     
  33203. + * 0        EXTENDED_MESSAGE == 1
  33204. + * 1        length (includes one byte for code, doesn't 
  33205. + *        include first two bytes)
  33206. + * 2         code
  33207. + * 3..length+1    arguments
  33208. + *
  33209. + * Start the extended message buffer with the EXTENDED_MESSAGE
  33210. + * byte, since print_msg() wants the whole thing.  
  33211. + */
  33212. +            extended_msg[0] = EXTENDED_MESSAGE;
  33213. +            /* Accept first byte by clearing ACK */
  33214. +            NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33215. +
  33216. +#if (NDEBUG & NDEBUG_EXTENDED)
  33217. +            printk("scsi%d: receiving extended message\n",
  33218. +            instance->host_no);
  33219. +#endif
  33220. +
  33221. +            len = 2;
  33222. +            data = extended_msg + 1;
  33223. +            phase = PHASE_MSGIN;
  33224. +            NCR5380_transfer_pio(instance, &phase, &len, &data);
  33225. +
  33226. +#if (NDEBUG & NDEBUG_EXTENDED)
  33227. +            printk("scsi%d: length=%d, code=0x%02x\n", 
  33228. +            instance->host_no, (int) extended_msg[1],
  33229. +            (int) extended_msg[2]);
  33230. +#endif
  33231. +
  33232. +            if (!len && extended_msg[1] <= 
  33233. +            (sizeof (extended_msg) - 1)) {
  33234. +            /* Accept third byte by clearing ACK */
  33235. +            NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33236. +            len = extended_msg[1] - 1;
  33237. +            data = extended_msg + 3;
  33238. +            phase = PHASE_MSGIN;
  33239. +
  33240. +            NCR5380_transfer_pio(instance, &phase, &len, &data);
  33241. +
  33242. +#if (NDEBUG & NDEBUG_EXTENDED)
  33243. +            printk("scsi%d: message received, residual %d\n",
  33244. +            instance->host_no, len);
  33245. +#endif
  33246. +
  33247. +            switch (extended_msg[2]) {
  33248. +            case EXTENDED_SDTR:
  33249. +            case EXTENDED_WDTR:
  33250. +            case EXTENDED_MODIFY_DATA_POINTER:
  33251. +            case EXTENDED_EXTENDED_IDENTIFY:
  33252. +                tmp = 0;
  33253. +            }
  33254. +            } else if (len) {
  33255. +            printk("scsi%d: error receiving extended message\n",
  33256. +                instance->host_no);
  33257. +            tmp = 0;
  33258. +            } else {
  33259. +            printk("scsi%d: extended message code %02x length %d is too long\n",
  33260. +                instance->host_no, extended_msg[2], extended_msg[1]);
  33261. +            tmp = 0;
  33262. +            }
  33263. +        /* Fall through to reject message */
  33264. +            
  33265. +        /* 
  33266. +           * If we get something weird that we aren't expecting, 
  33267. +          * reject it.
  33268. +         */
  33269. +        default:
  33270. +            if (!tmp) {
  33271. +            printk("scsi%d: rejecting message ", instance->host_no);
  33272. +            print_msg (extended_msg);
  33273. +            printk("\n");
  33274. +            } else if (tmp != EXTENDED_MESSAGE)
  33275. +            printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n",
  33276. +                instance->host_no, tmp, cmd->target, cmd->lun);
  33277. +            else
  33278. +            printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n",
  33279. +                instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun);
  33280. +   
  33281. +            msgout = MESSAGE_REJECT;
  33282. +            NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
  33283. +            ICR_ASSERT_ATN);
  33284. +            break;
  33285. +        } /* switch (tmp) */
  33286. +        break;
  33287. +        case PHASE_MSGOUT:
  33288. +        len = 1;
  33289. +        data = &msgout;
  33290. +        hostdata->last_message = msgout;
  33291. +        NCR5380_transfer_pio(instance, &phase, &len, &data);
  33292. +        if (msgout == ABORT) {
  33293. +            hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
  33294. +            hostdata->connected = NULL;
  33295. +            cmd->result = DID_ERROR << 16;
  33296. +            cmd->scsi_done(cmd);
  33297. +            NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
  33298. +            return;
  33299. +        }
  33300. +        msgout = NOP;
  33301. +        break;
  33302. +        case PHASE_CMDOUT:
  33303. +        len = cmd->cmd_len;
  33304. +        data = cmd->cmnd;
  33305. +        /* 
  33306. +         * XXX for performance reasons, on machines with a 
  33307. +         * PSEUDO-DMA architecture we should probably 
  33308. +         * use the dma transfer function.  
  33309. +         */
  33310. +        NCR5380_transfer_pio(instance, &phase, &len, 
  33311. +            &data);
  33312. +#ifdef USLEEP
  33313. +        if (!disconnect && should_disconnect(cmd->cmnd[0])) {
  33314. +            hostdata->time_expires = jiffies + USLEEP_SLEEP;
  33315. +#if (NDEBUG & NDEBUG_USLEEP)
  33316. +        printk("scsi%d: issued command, sleeping until %ul\n", instance->host_no,
  33317. +            hostdata->time_expires);
  33318. +#endif
  33319. +            NCR5380_set_timer (instance);
  33320. +            return;
  33321. +        }
  33322. +#endif /* def USLEEP */
  33323. +        break;
  33324. +        case PHASE_STATIN:
  33325. +        len = 1;
  33326. +        data = &tmp;
  33327. +        NCR5380_transfer_pio(instance, &phase, &len, &data);
  33328. +        cmd->SCp.Status = tmp;
  33329. +        break;
  33330. +        default:
  33331. +        printk("scsi%d: unknown phase\n", instance->host_no);
  33332. +#ifdef NDEBUG
  33333. +        NCR5380_print(instance);
  33334. +#endif
  33335. +        } /* switch(phase) */
  33336. +    } /* if (tmp * SR_REQ) */ 
  33337. +#ifdef USLEEP
  33338. +    else {
  33339. +        if (!disconnect && hostdata->time_expires && jiffies > 
  33340. +        hostdata->time_expires) {
  33341. +        hostdata->time_expires = jiffies + USLEEP_SLEEP;
  33342. +#if (NDEBUG & NDEBUG_USLEEP)
  33343. +        printk("scsi%d: poll timed out, sleeping until %ul\n", instance->host_no,
  33344. +            hostdata->time_expires);
  33345. +#endif
  33346. +        NCR5380_set_timer (instance);
  33347. +        return;
  33348. +        }
  33349. +    }
  33350. +#endif
  33351. +    } /* while (1) */
  33352. +}
  33353. +
  33354. +/*
  33355. + * Function : void NCR5380_reselect (struct Scsi_Host *instance)
  33356. + *
  33357. + * Purpose : does reselection, initializing the instance->connected 
  33358. + *    field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q 
  33359. + *    nexus has been reestablished,
  33360. + *    
  33361. + * Inputs : instance - this instance of the NCR5380.
  33362. + *
  33363. + */
  33364. +
  33365. +
  33366. +static void NCR5380_reselect (struct Scsi_Host *instance) {
  33367. +    NCR5380_local_declare();
  33368. +    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
  33369. +    instance->hostdata;
  33370. +    unsigned char target_mask;
  33371. +    unsigned char lun, phase;
  33372. +    int len;
  33373. +#ifdef SCSI2
  33374. +    unsigned char tag;
  33375. +#endif
  33376. +    unsigned char msg[3];
  33377. +    unsigned char *data;
  33378. +    Scsi_Cmnd *tmp = NULL, *prev;
  33379. +    int abort = 0;
  33380. +    NCR5380_setup(instance);
  33381. +
  33382. +    /*
  33383. +     * Disable arbitration, etc. since the host adapter obviously
  33384. +     * lost, and tell an interrupted NCR5380_select() to restart.
  33385. +     */
  33386. +
  33387. +    NCR5380_write(MODE_REG, MR_BASE);
  33388. +    hostdata->restart_select = 1;
  33389. +
  33390. +    target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
  33391. +
  33392. +#if (NDEBUG & NDEBUG_RESELECTION)
  33393. +    printk("scsi%d: reselect\n", instance->host_no);
  33394. +#endif
  33395. +
  33396. +    /* 
  33397. +     * At this point, we have detected that our SCSI ID is on the bus,
  33398. +     * SEL is true and BSY was false for at least one bus settle delay
  33399. +     * (400 ns).
  33400. +     *
  33401. +     * We must assert BSY ourselves, until the target drops the SEL
  33402. +     * signal.
  33403. +     */
  33404. +
  33405. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
  33406. +    
  33407. +    while (NCR5380_read(STATUS_REG) & SR_SEL);
  33408. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33409. +
  33410. +    /*
  33411. +     * Wait for target to go into MSGIN.
  33412. +     */
  33413. +
  33414. +    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
  33415. +
  33416. +    len = 1;
  33417. +    data = msg;
  33418. +    phase = PHASE_MSGIN;
  33419. +    NCR5380_transfer_pio(instance, &phase, &len, &data);
  33420. +
  33421. +
  33422. +    if (!msg[0] & 0x80) {
  33423. +    printk("scsi%d: expecting IDENTIFY message, got ",
  33424. +        instance->host_no);
  33425. +    print_msg(msg);
  33426. +    abort = 1;
  33427. +    } else {
  33428. +    /* Accept message by clearing ACK */
  33429. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33430. +    lun = (msg[0] & 0x07);
  33431. +
  33432. +    /* 
  33433. +     * We need to add code for SCSI-II to track which devices have
  33434. +     * I_T_L_Q nexuses established, and which have simple I_T_L
  33435. +     * nexuses so we can chose to do additional data transfer.
  33436. +      */
  33437. +
  33438. +#ifdef SCSI2
  33439. +#error "SCSI-II tagged queueing is not supported yet"
  33440. +#endif
  33441. +
  33442. +    /* 
  33443. +     * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we 
  33444. +     * just reestablished, and remove it from the disconnected queue.
  33445. +     */
  33446. +
  33447. +
  33448. +    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; 
  33449. +        tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) 
  33450. +        if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
  33451. +#ifdef SCSI2
  33452. +        && (tag == tmp->tag) 
  33453. +#endif
  33454. +) {
  33455. +        if (prev)
  33456. +        prev->host_scribble = tmp->host_scribble;
  33457. +        else
  33458. +        hostdata->disconnected_queue = (Scsi_Cmnd *) tmp->host_scribble;
  33459. +        tmp->host_scribble = NULL;
  33460. +        break;
  33461. +    }
  33462. +
  33463. +    if (!tmp) {
  33464. +#ifdef SCSI2
  33465. +        printk("scsi%d: warning : target bitmask %02x lun %d tag %d not in disconnect_queue.\n",
  33466. +            instance->host_no, target_mask, lun, tag);
  33467. +#else
  33468. +        printk("scsi%d: warning : target bitmask %02x lun %d not in disconnect_queue.\n",
  33469. +            instance->host_no, target_mask, lun);
  33470. +#endif
  33471. +    /* 
  33472. +     * Since we have an established nexus that we can't do anything with,
  33473. +     * we must abort it.  
  33474. +     */
  33475. +    abort = 1;
  33476. +    }
  33477. +    }
  33478. +
  33479. +    if (abort) {
  33480. +    msg[0] = ABORT;
  33481. +    len = 1;
  33482. +    data = msg;
  33483. +    phase = PHASE_MSGOUT;
  33484. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
  33485. +    NCR5380_transfer_pio(instance, &phase, &len, &data);
  33486. +    } else {
  33487. +    hostdata->connected = tmp;
  33488. +#if (NDEBUG & NDEBUG_RESELECTION)
  33489. +    printk"scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
  33490. +        instance->host_no, tmp->target, tmp->lun, tmp->tag);
  33491. +#endif
  33492. +    }
  33493. +}
  33494. +
  33495. +/*
  33496. + * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
  33497. + *
  33498. + * Purpose : called by interrupt handler when DMA finishes or a phase
  33499. + *    mismatch occurs (which would finish the DMA transfer).  
  33500. + *
  33501. + * Inputs : instance - this instance of the NCR5380.
  33502. + *
  33503. + * Returns : pointer to the Scsi_Cmnd structure for which the I_T_L
  33504. + *     nexus has been reestablished, on failure NULL is returned.
  33505. + */
  33506. +
  33507. +#ifdef REAL_DMA
  33508. +static void NCR5380_dma_complete (NCR5380_instance *instance) {
  33509. +    NCR5380_local_declare();
  33510. +    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *
  33511. +    instance->hostdata);
  33512. +    int transferred;
  33513. +    NCR5380_setup(instance);
  33514. +    
  33515. +    /*
  33516. +     * XXX this might not be right.
  33517. +     *
  33518. +     * Wait for final byte to transfer, ie wait for ACK to go false.
  33519. +     *
  33520. +     * We should use the Last Byte Sent bit, unfortunately this is 
  33521. +     * not available on the 5380/5381 (only the various CMOS chips)
  33522. +     */
  33523. +
  33524. +    while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);
  33525. +
  33526. +    NCR5380_write(MODE_REG, MR_BASE);
  33527. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33528. +
  33529. +    /*
  33530. +     * The only places we should see a phase mismatch and have to send
  33531. +     * data from the same set of pointers will be the data transfer
  33532. +     * phases.  So, residual, requested length are only important here.
  33533. +     */
  33534. +
  33535. +    if (!(hostdata->connected->SCp.phase & SR_CD)) {
  33536. +    transferred = instance->dmalen - NCR5380_dma_residual();
  33537. +    hostdata->connected->SCp.this_residual -= transferred;
  33538. +    hostdata->connected->SCp.ptr += transferred;
  33539. +    }
  33540. +}
  33541. +#endif /* def REAL_DMA */
  33542. +
  33543. +/*
  33544. + * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
  33545. + *
  33546. + * Purpose : abort a command
  33547. + *
  33548. + * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the 
  33549. + *     host byte of the result field to, if zero DID_ABORTED is 
  33550. + *    used.
  33551. + *
  33552. + * Returns : 0 - success, -1 on failure.
  33553. + *
  33554. + * XXX - there is no way to abort the command that is currently 
  33555. + *      connected, you have to wait for it to complete.  If this is 
  33556. + *     a problem, we could implement longjmp() / setjmp(), setjmp()
  33557. + *      called where the loop started in NCR5380_main().
  33558. + */
  33559. +
  33560. +#ifndef NCR5380_abort
  33561. +static
  33562. +#endif
  33563. +int NCR5380_abort (Scsi_Cmnd *cmd) {
  33564. +    NCR5380_local_declare();
  33565. +    struct Scsi_Host *instance = cmd->host;
  33566. +    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
  33567. +    instance->hostdata;
  33568. +    Scsi_Cmnd *tmp, **prev;
  33569. +    unsigned char msg, phase, *msgptr;
  33570. +    int len;
  33571. +
  33572. +    printk("scsi%d: aborting command\n", instance->host_no);
  33573. +    print_Scsi_Cmnd (cmd);
  33574. +
  33575. +    NCR5380_print_status (instance);
  33576. +
  33577. +    cli();
  33578. +    NCR5380_setup(instance);
  33579. +    
  33580. +#if (NDEBUG & NDEBUG_ABORT)
  33581. +    printk("scsi%d: abort called\n", instance->host_no);
  33582. +    printk("        basr 0x%X, sr 0x%X\n", 
  33583. +       NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG));
  33584. +#endif
  33585. +
  33586. +#if 0
  33587. +/*
  33588. + * Case 1 : If the command is the currently executing command, 
  33589. + * we'll set the aborted flag and return control so that 
  33590. + * information transfer routine can exit cleanly.
  33591. + */
  33592. +
  33593. +    if (hostdata->connected == cmd) {
  33594. +#if (NDEBUG & NDEBUG_ABORT)
  33595. +    printk("scsi%d: aborting connected command\n", instance->host_no);
  33596. +#endif
  33597. +    hostdata->aborted = 1;
  33598. +/*
  33599. + * We should perform BSY checking, and make sure we haven't slipped
  33600. + * into BUS FREE.
  33601. + */
  33602. +
  33603. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN);
  33604. +/* 
  33605. + * Since we can't change phases until we've completed the current 
  33606. + * handshake, we have to source or sink a byte of data if the current
  33607. + * phase is not MSGOUT.
  33608. + */
  33609. +
  33610. +/* 
  33611. + * Return control to the executing NCR drive so we can clear the
  33612. + * aborted flag and get back into our main loop.
  33613. + */ 
  33614. +    return 0;
  33615. +    }
  33616. +#endif
  33617. +
  33618. +/* 
  33619. + * Case 2 : If the command hasn't been issued yet, we simply remove it 
  33620. + *         from the issue queue.
  33621. + */
  33622. +    for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), 
  33623. +    tmp = (Scsi_Cmnd *) hostdata->issue_queue;
  33624. +    tmp; prev = (Scsi_Cmnd **) &(tmp->host_scribble), tmp = 
  33625. +    (Scsi_Cmnd *) tmp->host_scribble) 
  33626. +    if (cmd == tmp) {
  33627. +        (*prev) = (Scsi_Cmnd *) tmp->host_scribble;
  33628. +        tmp->host_scribble = NULL;
  33629. +        tmp->result = DID_ABORT << 16;
  33630. +        sti();
  33631. +#if (NDEBUG & NDEBUG_ABORT)
  33632. +    printk("scsi%d: abort removed command from issue queue.\n", 
  33633. +    instance->host_no);
  33634. +#endif
  33635. +        tmp->done(tmp);
  33636. +        return SCSI_ABORT_SUCCESS;
  33637. +    }
  33638. +
  33639. +/* 
  33640. + * Case 3 : If any commands are connected, we're going to fail the abort
  33641. + *        and let the high level SCSI driver retry at a later time or 
  33642. + *        issue a reset.
  33643. + *
  33644. + *        Timeouts, and therefore aborted commands, will be highly unlikely
  33645. + *          and handling them cleanly in this situation would make the common
  33646. + *        case of noresets less efficient, and would pollute our code.  So,
  33647. + *        we fail.
  33648. + */
  33649. +
  33650. +    if (hostdata->connected) {
  33651. +    sti();
  33652. +#if (NDEBUG & NDEBUG_ABORT)
  33653. +    printk("scsi%d: abort failed, command connected.\n", instance->host_no);
  33654. +#endif
  33655. +        return SCSI_ABORT_NOT_RUNNING;
  33656. +    }
  33657. +
  33658. +/*
  33659. + * Case 4: If the command is currently disconnected from the bus, and 
  33660. + *     there are no connected commands, we reconnect the I_T_L or 
  33661. + *    I_T_L_Q nexus associated with it, go into message out, and send 
  33662. + *      an abort message.
  33663. + *
  33664. + * This case is especially ugly. In order to reestablish the nexus, we
  33665. + * need to call NCR5380_select().  The easiest way to implement this 
  33666. + * function was to abort if the bus was busy, and let the interrupt
  33667. + * handler triggered on the SEL for reselect take care of lost arbitrations
  33668. + * where necessary, meaning interrupts need to be enabled.
  33669. + *
  33670. + * When interrupts are enabled, the queues may change - so we 
  33671. + * can't remove it from the disconnected queue before selecting it
  33672. + * because that could cause a failure in hashing the nexus if that 
  33673. + * device reselected.
  33674. + * 
  33675. + * Since the queues may change, we can't use the pointers from when we
  33676. + * first locate it.
  33677. + *
  33678. + * So, we must first locate the command, and if NCR5380_select()
  33679. + * succeeds, then issue the abort, relocate the command and remove
  33680. + * it from the disconnected queue.
  33681. + */
  33682. +
  33683. +    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; 
  33684. +    tmp = (Scsi_Cmnd *) tmp->host_scribble) 
  33685. +        if (cmd == tmp) {
  33686. +            sti(); 
  33687. +#if (NDEBUG & NDEBUG_ABORT)
  33688. +    printk("scsi%d: aborting disconnected command.\n", instance->host_no);
  33689. +#endif
  33690. +  
  33691. +            if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
  33692. +        return SCSI_ABORT_BUSY;
  33693. +
  33694. +#if (NDEBUG & NDEBUG_ABORT)
  33695. +    printk("scsi%d: nexus reestablished.\n", instance->host_no);
  33696. +#endif
  33697. +
  33698. +        msg = ABORT;
  33699. +        msgptr = &msg;
  33700. +        len = 1;
  33701. +        phase = PHASE_MSGOUT;
  33702. +        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
  33703. +        NCR5380_transfer_pio (instance, &phase, &len, &msgptr);
  33704. +
  33705. +        cli();
  33706. +        for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), 
  33707. +        tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
  33708. +        tmp; prev = (Scsi_Cmnd **) &(tmp->host_scribble), tmp = 
  33709. +        (Scsi_Cmnd *) tmp->host_scribble) 
  33710. +            if (cmd == tmp) {
  33711. +            *prev = (Scsi_Cmnd *) tmp->host_scribble;
  33712. +            tmp->host_scribble = NULL;
  33713. +            tmp->result = DID_ABORT << 16;
  33714. +            sti();
  33715. +            tmp->done(tmp);
  33716. +            return SCSI_ABORT_SUCCESS;
  33717. +        }
  33718. +    }
  33719. +
  33720. +/*
  33721. + * Case 5 : If we reached this point, the command was not found in any of 
  33722. + *        the queues.
  33723. + *
  33724. + * We probably reached this point because of an unlikely race condition
  33725. + * between the command completing successfully and the abortion code,
  33726. + * so we won't panic, but we will notify the user in case something really
  33727. + * broke.
  33728. + */
  33729. +
  33730. +    sti();
  33731. +    printk("scsi%d: warning : SCSI command probably completed successfully\n"
  33732. +           "        before abortion\n", instance->host_no); 
  33733. +    return SCSI_ABORT_NOT_RUNNING;
  33734. +}
  33735. +
  33736. +
  33737. +/* 
  33738. + * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
  33739. + * 
  33740. + * Purpose : reset the SCSI bus.
  33741. + *
  33742. + * Returns : SCSI_RESET_WAKEUP
  33743. + *
  33744. + */ 
  33745. +
  33746. +#ifndef NCR5380_reset
  33747. +static
  33748. +#endif
  33749. +int NCR5380_reset (Scsi_Cmnd *cmd) {
  33750. +    NCR5380_local_declare();
  33751. +    NCR5380_setup(cmd->host);
  33752. +
  33753. +    NCR5380_print_status (cmd->host);
  33754. +
  33755. +    cli();
  33756. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
  33757. +    udelay(25);
  33758. +    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
  33759. +    sti();
  33760. +
  33761. +    return SCSI_RESET_WAKEUP;
  33762. +}
  33763. +
  33764. diff -urNwbB linux/arch/arm/drivers/scsi/NCR5380.h linux.arm/arch/arm/drivers/scsi/NCR5380.h
  33765. --- linux/arch/arm/drivers/scsi/NCR5380.h    Thu Jan  1 01:00:00 1970
  33766. +++ linux.arm/arch/arm/drivers/scsi/NCR5380.h    Sat Feb 24 09:36:54 1996
  33767. @@ -0,0 +1,352 @@
  33768. +/* 
  33769. + * NCR 5380 defines
  33770. + *
  33771. + * Copyright 1993, Drew Eckhardt
  33772. + *    Visionary Computing
  33773. + *    (Unix consulting and custom programming)
  33774. + *     drew@colorado.edu
  33775. + *      +1 (303) 666-5836
  33776. + *
  33777. + * DISTRIBUTION RELEASE 6
  33778. + *
  33779. + * For more information, please consult 
  33780. + *
  33781. + * NCR 5380 Family
  33782. + * SCSI Protocol Controller
  33783. + * Databook
  33784. + * NCR Microelectronics
  33785. + * 1635 Aeroplaza Drive
  33786. + * Colorado Springs, CO 80916
  33787. + * 1+ (719) 578-3400
  33788. + * 1+ (800) 334-5454
  33789. + */
  33790. +
  33791. +/*
  33792. + * $Log: NCR5380.h,v $
  33793. + */
  33794. +
  33795. +#ifndef NCR5380_H
  33796. +#define NCR5380_H
  33797. +
  33798. +#define NCR5380_PUBLIC_RELEASE 6
  33799. +#ifdef NCR53C400
  33800. +#define NCR53C400_PUBLIC_RELEASE 1
  33801. +#endif
  33802. +
  33803. +#define NDEBUG_ARBITRATION    0x1
  33804. +#define NDEBUG_AUTOSENSE    0x2
  33805. +#define NDEBUG_DMA        0x4
  33806. +#define NDEBUG_HANDSHAKE    0x8
  33807. +#define NDEBUG_INFORMATION    0x10
  33808. +#define NDEBUG_INIT        0x20
  33809. +#define NDEBUG_INTR        0x40
  33810. +#define NDEBUG_LINKED        0x80
  33811. +#define NDEBUG_MAIN        0x100
  33812. +#define NDEBUG_NO_DATAOUT    0x200
  33813. +#define NDEBUG_NO_WRITE        0x400
  33814. +#define NDEBUG_PIO        0x800
  33815. +#define NDEBUG_PSEUDO_DMA    0x1000
  33816. +#define NDEBUG_QUEUES        0x2000
  33817. +#define NDEBUG_RESELECTION    0x4000
  33818. +#define NDEBUG_SELECTION    0x8000
  33819. +#define NDEBUG_USLEEP        0x10000
  33820. +#define NDEBUG_LAST_BYTE_SENT    0x20000
  33821. +#define NDEBUG_RESTART_SELECT    0x40000
  33822. +#define NDEBUG_EXTENDED        0x80000
  33823. +
  33824. +/* 
  33825. + * The contents of the OUTPUT DATA register are asserted on the bus when
  33826. + * either arbitration is occurring or the phase-indicating signals (
  33827. + * IO, CD, MSG) in the TARGET COMMAND register and the ASSERT DATA
  33828. + * bit in the INITIATOR COMMAND register is set.
  33829. + */
  33830. +
  33831. +#define OUTPUT_DATA_REG         0       /* wo DATA lines on SCSI bus */
  33832. +#define CURRENT_SCSI_DATA_REG   0       /* ro same */
  33833. +
  33834. +#define INITIATOR_COMMAND_REG    1    /* rw */
  33835. +#define ICR_ASSERT_RST        0x80    /* rw Set to assert RST  */
  33836. +#define ICR_ARBITRATION_PROGRESS 0x40    /* ro Indicates arbitration complete */
  33837. +#define ICR_TRI_STATE        0x40    /* wo Set to tri-state drivers */
  33838. +#define ICR_ARBITRATION_LOST    0x20    /* ro Indicates arbitration lost */
  33839. +#define ICR_DIFF_ENABLE        0x20    /* wo Set to enable diff. drivers */
  33840. +#define ICR_ASSERT_ACK        0x10    /* rw ini Set to assert ACK */
  33841. +#define ICR_ASSERT_BSY        0x08    /* rw Set to assert BSY */
  33842. +#define ICR_ASSERT_SEL         0x04    /* rw Set to assert SEL */
  33843. +#define ICR_ASSERT_ATN        0x02    /* rw Set to assert ATN */
  33844. +#define ICR_ASSERT_DATA        0x01    /* rw SCSI_DATA_REG is asserted */
  33845. +
  33846. +#ifdef DIFFERENTIAL
  33847. +#define ICR_BASE        ICR_DIFF_ENABLE
  33848. +#else
  33849. +#define ICR_BASE        0
  33850. +#endif
  33851. +
  33852. +#define MODE_REG        2
  33853. +/*
  33854. + * Note : BLOCK_DMA code will keep DRQ asserted for the duration of the 
  33855. + * transfer, causing the chip to hog the bus.  You probably don't want 
  33856. + * this.
  33857. + */
  33858. +#define MR_BLOCK_DMA_MODE    0x80    /* rw block mode DMA */
  33859. +#define MR_TARGET        0x40    /* rw target mode */
  33860. +#define MR_ENABLE_PAR_CHECK   0x20    /* rw enable parity checking */
  33861. +#define MR_ENABLE_PAR_INTR    0x10    /* rw enable bad parity interrupt */
  33862. +#define MR_ENABLE_EOP_INTR    0x08    /* rw enable eop interrupt */
  33863. +#define MR_MONITOR_BSY    0x04    /* rw enable int on unexpected bsy fail */
  33864. +#define MR_DMA_MODE        0x02    /* rw DMA / pseudo DMA mode */
  33865. +#define MR_ARBITRATE        0x01    /* rw start arbitration */
  33866. +
  33867. +#ifdef PARITY
  33868. +#define MR_BASE            MR_ENABLE_PAR_CHECK
  33869. +#else
  33870. +#define MR_BASE            0
  33871. +#endif
  33872. +
  33873. +#define TARGET_COMMAND_REG    3
  33874. +#define TCR_LAST_BYTE_SENT    0x80    /* ro DMA done */
  33875. +#define TCR_ASSERT_REQ        0x08    /* tgt rw assert REQ */
  33876. +#define TCR_ASSERT_MSG        0x04    /* tgt rw assert MSG */
  33877. +#define TCR_ASSERT_CD        0x02    /* tgt rw assert CD */
  33878. +#define TCR_ASSERT_IO        0x01    /* tgt rw assert IO */
  33879. +
  33880. +#define STATUS_REG        4    /* ro */
  33881. +/*
  33882. + * Note : a set bit indicates an active signal, driven by us or another 
  33883. + * device.
  33884. + */
  33885. +#define SR_RST            0x80    
  33886. +#define SR_BSY            0x40
  33887. +#define SR_REQ            0x20
  33888. +#define SR_MSG            0x10
  33889. +#define SR_CD            0x08
  33890. +#define SR_IO            0x04
  33891. +#define SR_SEL            0x02
  33892. +#define SR_DBP            0x01
  33893. +
  33894. +/*
  33895. + * Setting a bit in this register will cause an interrupt to be generated when 
  33896. + * BSY is false and SEL true and this bit is asserted  on the bus.
  33897. + */
  33898. +#define SELECT_ENABLE_REG    4    /* wo */
  33899. +
  33900. +#define BUS_AND_STATUS_REG    5    /* ro */
  33901. +#define BASR_END_DMA_TRANSFER    0x80    /* ro set on end of transfer */
  33902. +#define BASR_DRQ        0x40    /* ro mirror of DRQ pin */
  33903. +#define BASR_PARITY_ERROR    0x20    /* ro parity error detected */
  33904. +#define BASR_IRQ        0x10    /* ro mirror of IRQ pin */
  33905. +#define BASR_PHASE_MATCH    0x08    /* ro Set when MSG CD IO match TCR */
  33906. +#define BASR_BUSY_ERROR        0x04    /* ro Unexpected change to inactive state */
  33907. +#define BASR_ATN         0x02    /* ro BUS status */
  33908. +#define BASR_ACK        0x01    /* ro BUS status */
  33909. +
  33910. +/* Write any value to this register to start a DMA send */
  33911. +#define START_DMA_SEND_REG    5    /* wo */
  33912. +
  33913. +/* 
  33914. + * Used in DMA transfer mode, data is latched from the SCSI bus on
  33915. + * the falling edge of REQ (ini) or ACK (tgt)
  33916. + */
  33917. +#define INPUT_DATA_REG            6    /* ro */
  33918. +
  33919. +/* Write any value to this register to start a DMA receive */
  33920. +#define START_DMA_TARGET_RECEIVE_REG    6    /* wo */
  33921. +
  33922. +/* Read this register to clear interrupt conditions */
  33923. +#define RESET_PARITY_INTERRUPT_REG    7    /* ro */
  33924. +
  33925. +/* Write any value to this register to start an ini mode DMA receive */
  33926. +#define START_DMA_INITIATOR_RECEIVE_REG 7    /* wo */
  33927. +
  33928. +#ifdef NCR53C400
  33929. +#define C400_CONTROL_STATUS_REG                -8      /* rw */
  33930. +
  33931. +#define CSR_RESET              0x80    /* wo  Resets 53c400 */
  33932. +#define CSR_53C80_REG          0x80    /* ro  5380 registers busy */
  33933. +#define CSR_TRANS_DIR          0x40    /* rw  Data transfer direction */
  33934. +#define CSR_SCSI_BUFF_INTR     0x20    /* rw  Enable int on transfer ready */
  33935. +#define CSR_53C80_INTR         0x10    /* rw  Enable 53c80 interrupts */
  33936. +#define CSR_SHARED_INTR                0x08    /* rw  Interrupt sharing */
  33937. +#define CSR_HOST_BUF_NOT_RDY   0x04    /* ro  Is Host buffer ready */
  33938. +#define CSR_SCSI_BUF_RDY       0x02    /* ro  SCSI buffer read */
  33939. +#define CSR_GATED_53C80_IRQ    0x01    /* ro  Last block xferred */
  33940. +
  33941. +#define CSR_BASE CSR_SCSI_BUFF_INTR | CSR_53C80_INTR
  33942. +
  33943. +/* Number of 128-byte blocks to be transferred */
  33944. +#define C400_CLOCK_COUNTER_REG         -7      /* rw */
  33945. +
  33946. +/* Resume transfer after disconnect */
  33947. +#define C400_RESUME_TRANSFER_REG       -6      /* wo */
  33948. +
  33949. +/* Access to host buffer stack */
  33950. +#define C400_HOST_BUFFER                       -4      /* rw */
  33951. +
  33952. +#endif /* NCR53C400 */
  33953. +
  33954. +
  33955. +/* Note : PHASE_* macros are based on the values of the STATUS register */
  33956. +#define PHASE_MASK     (SR_MSG | SR_CD | SR_IO)
  33957. +
  33958. +#define PHASE_DATAOUT        0
  33959. +#define PHASE_DATAIN        SR_IO
  33960. +#define PHASE_CMDOUT        SR_CD
  33961. +#define PHASE_STATIN        (SR_CD | SR_IO)
  33962. +#define PHASE_MSGOUT        (SR_MSG | SR_CD)
  33963. +#define PHASE_MSGIN        (SR_MSG | SR_CD | SR_IO)
  33964. +#define PHASE_UNKNOWN        0xff
  33965. +
  33966. +/* 
  33967. + * Convert status register phase to something we can use to set phase in 
  33968. + * the target register so we can get phase mismatch interrupts on DMA 
  33969. + * transfers.
  33970. + */
  33971. +#define PHASE_SR_TO_TCR(phase) ((phase) >> 2)    
  33972. +
  33973. +/*
  33974. + * The internal should_disconnect() function returns these based on the 
  33975. + * expected length of a disconnect if a device supports disconnect/
  33976. + * reconnect.
  33977. + */
  33978. +
  33979. +#define DISCONNECT_NONE        0
  33980. +#define DISCONNECT_TIME_TO_DATA    1
  33981. +#define DISCONNECT_LONG        2
  33982. +
  33983. +/* 
  33984. + * These are "special" values for the tag parameter passed to NCR5380_select.
  33985. + */
  33986. +
  33987. +#define TAG_NEXT    -1     /* Use next free tag */
  33988. +#define TAG_NONE    -2    /* 
  33989. +                 * Establish I_T_L nexus instead of I_T_L_Q
  33990. +                 * even on SCSI-II devices.
  33991. +                 */
  33992. +
  33993. +/*
  33994. + * These are "special" values for the irq and dma_channel fields of the 
  33995. + * Scsi_Host structure
  33996. + */
  33997. +
  33998. +#define IRQ_NONE    255
  33999. +#define DMA_NONE    255
  34000. +#define IRQ_AUTO    254
  34001. +#define DMA_AUTO    254
  34002. +
  34003. +#define FLAG_HAS_LAST_BYTE_SENT        1    /* NCR53c81 or better */
  34004. +#define FLAG_CHECK_LAST_BYTE_SENT    2    /* Only test once */
  34005. +#define FLAG_NCR53C400            4    /* NCR53c400 */
  34006. +
  34007. +#ifndef ASM
  34008. +struct NCR5380_hostdata {
  34009. +    NCR5380_implementation_fields;        /* implementation specific */
  34010. +    unsigned char id_mask, id_higher_mask;    /* 1 << id, all bits greater */
  34011. +    unsigned char targets_present;        /* targets we have connected
  34012. +                           to, so we can call a select
  34013. +                           failure a retryable condition */
  34014. +    volatile unsigned char busy[8];        /* index = target, bit = lun */
  34015. +#if defined(REAL_DMA) || defined(REAL_DMA_POLL)
  34016. +    volatile int dma_len;            /* requested length of DMA */
  34017. +#endif
  34018. +    volatile unsigned char last_message;    /* last message OUT */
  34019. +    volatile Scsi_Cmnd *connected;        /* currently connected command */
  34020. +    volatile Scsi_Cmnd *issue_queue;        /* waiting to be issued */
  34021. +    volatile Scsi_Cmnd *disconnected_queue;    /* waiting for reconnect */
  34022. +    volatile int restart_select;        /* we have disconnected,
  34023. +                           used to restart 
  34024. +                           NCR5380_select() */
  34025. +    volatile unsigned aborted:1;        /* flag, says aborted */
  34026. +    int flags;
  34027. +#ifdef USLEEP
  34028. +    unsigned long time_expires;            /* in jiffies, set prior to sleeping */
  34029. +    struct Scsi_Host *next_timer;
  34030. +#endif
  34031. +};
  34032. +
  34033. +#ifdef __KERNEL__
  34034. +static struct Scsi_Host *first_instance;        /* linked list of 5380's */
  34035. +
  34036. +#if defined(AUTOPROBE_IRQ)
  34037. +static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible);
  34038. +#endif
  34039. +static void NCR5380_init (struct Scsi_Host *instance, int flags);
  34040. +static void NCR5380_information_transfer (struct Scsi_Host *instance);
  34041. +static void NCR5380_intr (int irq, struct pt_regs * regs);
  34042. +static void NCR5380_main (void);
  34043. +static void NCR5380_print_options (struct Scsi_Host *instance);
  34044. +#ifndef NCR5380_abort
  34045. +static
  34046. +#endif
  34047. +int NCR5380_abort (Scsi_Cmnd *cmd);
  34048. +#ifndef NCR5380_reset
  34049. +static
  34050. +#endif
  34051. +int NCR5380_reset (Scsi_Cmnd *cmd);
  34052. +#ifndef NCR5380_queue_command
  34053. +static 
  34054. +#endif
  34055. +int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
  34056. +
  34057. +
  34058. +static void NCR5380_reselect (struct Scsi_Host *instance);
  34059. +static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag);
  34060. +#if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
  34061. +static int NCR5380_transfer_dma (struct Scsi_Host *instance,
  34062. +        unsigned char *phase, int *count, unsigned char **data);
  34063. +#endif
  34064. +static int NCR5380_transfer_pio (struct Scsi_Host *instance,
  34065. +        unsigned char *phase, int *count, unsigned char **data);
  34066. +
  34067. +#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) && defined(i386)
  34068. +static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
  34069. +    unsigned char *ptr, unsigned int count, unsigned char mode) {
  34070. +    unsigned limit;
  34071. +
  34072. +    if (instance->dma_channel <=3) {
  34073. +    if (count > 65536)
  34074. +        count = 65536;
  34075. +    limit = 65536 - (((unsigned) ptr) & 0xFFFF);
  34076. +    } else {
  34077. +    if (count > 65536 * 2) 
  34078. +        count = 65536 * 2;
  34079. +    limit = 65536* 2 - (((unsigned) ptr) & 0x1FFFF);
  34080. +    }
  34081. +
  34082. +    if (count > limit) count = limit;
  34083. +
  34084. +    if ((count & 1) || (((unsigned) ptr) & 1))
  34085. +    panic ("scsi%d : attempted unaligned DMA transfer\n", instance->host_no);
  34086. +    cli();
  34087. +    disable_dma(instance->dma_channel);
  34088. +    clear_dma_ff(instance->dma_channel);
  34089. +    set_dma_addr(instance->dma_channel, (unsigned int) ptr);
  34090. +    set_dma_count(instance->dma_channel, count);
  34091. +    set_dma_mode(instance->dma_channel, mode);
  34092. +    enable_dma(instance->dma_channel);
  34093. +    sti();
  34094. +    return count;
  34095. +}
  34096. +
  34097. +static __inline__ int NCR5380_i386_dma_write_setup (struct Scsi_Host *instance,
  34098. +    unsigned char *src, unsigned int count) {
  34099. +    return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_WRITE);
  34100. +}
  34101. +
  34102. +static __inline__ int NCR5380_i386_dma_read_setup (struct Scsi_Host *instance,
  34103. +    unsigned char *src, unsigned int count) {
  34104. +    return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_READ);
  34105. +}
  34106. +
  34107. +static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) {
  34108. +    register int tmp;
  34109. +    cli();
  34110. +    clear_dma_ff(instance->dma_channel);
  34111. +    tmp = get_dma_residue(instance->dma_channel);
  34112. +    sti();
  34113. +    return tmp;
  34114. +}
  34115. +#endif /* defined(REAL_DMA) && defined(i386)  */
  34116. +#endif __KERNEL_
  34117. +#endif /* ndef ASM */
  34118. +#endif /* NCR5380_H */
  34119. diff -urNwbB linux/arch/arm/drivers/scsi/acornscsi-io.S linux.arm/arch/arm/drivers/scsi/acornscsi-io.S
  34120. --- linux/arch/arm/drivers/scsi/acornscsi-io.S    Thu Jan  1 01:00:00 1970
  34121. +++ linux.arm/arch/arm/drivers/scsi/acornscsi-io.S    Sun Feb 11 09:32:30 1996
  34122. @@ -0,0 +1,253 @@
  34123. +@  linux/arch/arm/drivers/scsi/acornscsi-io.S: Acorn SCSI card IO
  34124. +@
  34125. +@ There is a reason for not using LDMs in this file - it kills the
  34126. +@ floppy drive and the serial port!  In order to keep those running
  34127. +@ error free, we use single word operations.
  34128. +@
  34129. +
  34130. +@ Purpose: transfer a block of data from the acorn scsi card to memory
  34131. +@ Proto  : void acornscsi_in(int portstrt, char *buffer, int length)
  34132. +@ Returns: nothing
  34133. +
  34134. +        .align
  34135. +        .global    ___acornscsi_in
  34136. +___acornscsi_in:
  34137. +        mov    ip, sp
  34138. +        stmfd    sp!, {r4 - r10, fp, ip, lr, pc}
  34139. +        sub    fp, ip, #4
  34140. +        cmp    r0,#0x00C00000
  34141. +        movge    r3, #0
  34142. +        movlt    r3, #0x03000000
  34143. +        orrlt    r3, r3, #0x00010000
  34144. +        add    r0, r3, r0, lsl #2
  34145. +        mov    ip, #0xff
  34146. +        orr    ip, ip, ip, lsl #8
  34147. +acornscsi_in1lp:
  34148. +        subs    r2, r2, #32
  34149. +        bmi    acornscsi_in16
  34150. +        ldr    r3, [r0], #4
  34151. +        and    r3, r3, ip
  34152. +        ldr    r4, [r0], #4
  34153. +        orr    r3, r3, r4, lsl #16
  34154. +        ldr    r5, [r0], #4
  34155. +        and     r4, r5, ip
  34156. +        ldr    r6, [r0], #4
  34157. +        orr    r4, r4, r6, lsl #16
  34158. +        ldr    r7, [r0], #4
  34159. +        and    r5, r7, ip
  34160. +        ldr    r8, [r0], #4
  34161. +        orr    r5, r5, r8, lsl #16
  34162. +        ldr    r9, [r0], #4
  34163. +        and    r6, r9, ip
  34164. +        ldr    r10, [r0], #4
  34165. +        orr    r6, r6, r10, lsl #16
  34166. +        stmia    r1!, {r3 - r6}
  34167. +        ldr    r3, [r0], #4
  34168. +        and    r3, r3, ip
  34169. +        ldr    r4, [r0], #4
  34170. +        orr    r3, r3, r4, lsl #16
  34171. +        ldr    r5, [r0], #4
  34172. +        and     r4, r5, ip
  34173. +        ldr    r6, [r0], #4
  34174. +        orr    r4, r4, r6, lsl #16
  34175. +        ldr    r7, [r0], #4
  34176. +        and    r5, r7, ip
  34177. +        ldr    r8, [r0], #4
  34178. +        orr    r5, r5, r8, lsl #16
  34179. +        ldr    r9, [r0], #4
  34180. +        and    r6, r9, ip
  34181. +        ldr    r10, [r0], #4
  34182. +        orr    r6, r6, r10, lsl #16
  34183. +        stmia    r1!, {r3 - r6}
  34184. +        bne    acornscsi_in1lp
  34185. +        ldmea    fp, {r4 - r10, fp, sp, pc}^
  34186. +acornscsi_in16:    adds    r2, r2, #16
  34187. +        bmi    acornscsi_in8
  34188. +acornscsi_in16lp:
  34189. +        ldr    r3, [r0], #4
  34190. +        and    r3, r3, ip
  34191. +        ldr    r4, [r0], #4
  34192. +        orr    r3, r3, r4, lsl #16
  34193. +        ldr    r5, [r0], #4
  34194. +        and     r4, r5, ip
  34195. +        ldr    r6, [r0], #4
  34196. +        orr    r4, r4, r6, lsl #16
  34197. +        ldr    r7, [r0], #4
  34198. +        and    r5, r7, ip
  34199. +        ldr    r8, [r0], #4
  34200. +        orr    r5, r5, r8, lsl #16
  34201. +        ldr    r9, [r0], #4
  34202. +        and    r6, r9, ip
  34203. +        ldr    r10, [r0], #4
  34204. +        orr    r6, r6, r10, lsl #16
  34205. +        stmia    r1!, {r3 - r6}
  34206. +        ldmeqea    fp, {r4 - r10, fp, sp, pc}^
  34207. +        sub    r2, r2, #16
  34208. +acornscsi_in8:    adds    r2, r2, #8
  34209. +        bmi    acornscsi_in4
  34210. +        ldr    r3, [r0], #4
  34211. +        and    r3, r3, ip
  34212. +        ldr    r4, [r0], #4
  34213. +        orr    r3, r3, r4, lsl #16
  34214. +        ldr    r5, [r0], #4
  34215. +        and    r4, r5, ip
  34216. +        ldr    r6, [r0], #4
  34217. +        orr    r4, r4, r6, lsl #16
  34218. +        stmia    r1!, {r3 - r4}
  34219. +        ldmeqea    fp, {r4 - r10, fp, sp, pc}^
  34220. +        sub    r2, r2, #8
  34221. +acornscsi_in4:    adds    r2, r2, #4
  34222. +        bmi    acornscsi_in2
  34223. +        ldr    r3, [r0], #4
  34224. +        and    r3, r3, ip
  34225. +        ldr    r4, [r0], #4
  34226. +        orr    r3, r3, r4, lsl #16
  34227. +        str    r3, [r1], #4
  34228. +        ldmeqea    fp, {r4 - r10, fp, sp, pc}^
  34229. +        sub    r2, r2, #4
  34230. +acornscsi_in2:    adds    r2, r2, #2
  34231. +        ldr    r3, [r0], #4
  34232. +        and    r3, r3, ip
  34233. +        strb    r3, [r1], #1
  34234. +        mov    r3, r3, lsr #8
  34235. +        strplb    r3, [r1], #1
  34236. +        ldmea    fp, {r4 - r10, fp, sp, pc}^
  34237. +
  34238. +@ Purpose: transfer a block of data from memory to the acorn scsi card
  34239. +@ Proto  : void acornscsi_in(int portstrt, char *buffer, int length)
  34240. +@ Returns: nothing
  34241. +
  34242. +        .global    ___acornscsi_out
  34243. +___acornscsi_out:
  34244. +        mov    ip, sp
  34245. +        stmfd    sp!, {r4 - r10, fp, ip, lr, pc}
  34246. +        sub    fp, ip, #4
  34247. +        cmp    r0,#0x00C00000
  34248. +        movge    r3, #0
  34249. +        movlt    r3, #0x03000000
  34250. +        orrlt    r3, r3, #0x00010000
  34251. +        add    r0, r3, r0, lsl #2
  34252. +        mov    ip, #0xff
  34253. +        orr    ip, ip, ip, lsl #8
  34254. +acornscsi_out1lp:
  34255. +        subs    r2, r2, #32
  34256. +        bmi    acornscsi_out16
  34257. +        ldmia    r1!, {r7 - r10}
  34258. +        mov    r3, r7, lsl #16
  34259. +        orr    r3, r3, r3, lsr #16
  34260. +        str    r3, [r0], #4
  34261. +        mov    r4, r7, lsr #16
  34262. +        orr    r4, r4, r4, lsl #16
  34263. +        str    r4, [r0], #4
  34264. +        mov    r5, r8, lsl #16
  34265. +        orr    r5, r5, r5, lsr #16
  34266. +        str    r5, [r0], #4
  34267. +        mov    r6, r8, lsr #16
  34268. +        orr    r6, r6, r6, lsl #16
  34269. +        str    r6, [r0], #4
  34270. +        mov    r7, r9, lsl #16
  34271. +        orr    r7, r7, r7, lsr #16
  34272. +        str    r7, [r0], #4
  34273. +        mov    r8, r9, lsr #16
  34274. +        orr    r8, r8, r8, lsl #16
  34275. +        str    r8, [r0], #4
  34276. +        mov    r9, r10, lsl #16
  34277. +        orr    r9, r9, r9, lsr #16
  34278. +        str    r9, [r0], #4
  34279. +        mov    r10, r10, lsr #16
  34280. +        orr    r10, r10, r10, lsl #16
  34281. +        str    r10, [r0], #4
  34282. +        ldmia    r1!, {r7 - r10}
  34283. +        mov    r3, r7, lsl #16
  34284. +        orr    r3, r3, r3, lsr #16
  34285. +        str    r3, [r0], #4
  34286. +        mov    r4, r7, lsr #16
  34287. +        orr    r4, r4, r4, lsl #16
  34288. +        str    r4, [r0], #4
  34289. +        mov    r5, r8, lsl #16
  34290. +        orr    r5, r5, r5, lsr #16
  34291. +        str    r5, [r0], #4
  34292. +        mov    r6, r8, lsr #16
  34293. +        orr    r6, r6, r6, lsl #16
  34294. +        str    r6, [r0], #4
  34295. +        mov    r7, r9, lsl #16
  34296. +        orr    r7, r7, r7, lsr #16
  34297. +        str    r7, [r0], #4
  34298. +        mov    r8, r9, lsr #16
  34299. +        orr    r8, r8, r8, lsl #16
  34300. +        str    r8, [r0], #4
  34301. +        mov    r9, r10, lsl #16
  34302. +        orr    r9, r9, r9, lsr #16
  34303. +        str    r9, [r0], #4
  34304. +        mov    r10, r10, lsr #16
  34305. +        orr    r10, r10, r10, lsl #16
  34306. +        str    r10, [r0], #4
  34307. +        bne    acornscsi_out1lp
  34308. +        ldmea    fp, {r4 - r10, fp, sp, pc}^
  34309. +acornscsi_out16:
  34310. +        adds    r2, r2, #16
  34311. +        bmi    acornscsi_out8
  34312. +acornscsi_out16lp:
  34313. +        ldmia    r1!, {r7 - r10}
  34314. +        mov    r3, r7, lsl #16
  34315. +        orr    r3, r3, r3, lsr #16
  34316. +        str    r3, [r0], #4
  34317. +        mov    r4, r7, lsr #16
  34318. +        orr    r4, r4, r4, lsl #16
  34319. +        str    r4, [r0], #4
  34320. +        mov    r5, r8, lsl #16
  34321. +        orr    r5, r5, r5, lsr #16
  34322. +        str    r5, [r0], #4
  34323. +        mov    r6, r8, lsr #16
  34324. +        orr    r6, r6, r6, lsl #16
  34325. +        str    r6, [r0], #4
  34326. +        mov    r7, r9, lsl #16
  34327. +        orr    r7, r7, r7, lsr #16
  34328. +        str    r7, [r0], #4
  34329. +        mov    r8, r9, lsr #16
  34330. +        orr    r8, r8, r8, lsl #16
  34331. +        str    r8, [r0], #4
  34332. +        mov    r9, r10, lsl #16
  34333. +        orr    r9, r9, r9, lsr #16
  34334. +        str    r9, [r0], #4
  34335. +        mov    r10, r10, lsr #16
  34336. +        orr    r10, r10, r10, lsl #16
  34337. +        str    r10, [r0], #4
  34338. +        ldmeqea    fp, {r4 - r10, fp, sp, pc}^
  34339. +        sub    r2, r2, #16
  34340. +acornscsi_out8:    adds    r2, r2, #8
  34341. +        bmi    acornscsi_out4
  34342. +        ldmia    r1!, {r5 - r6}
  34343. +        mov    r3, r5, lsl #16
  34344. +        orr    r3, r3, r3, lsr #16
  34345. +        str    r3, [r0], #4
  34346. +        mov    r4, r5, lsr #16
  34347. +        orr    r4, r4, r4, lsl #16
  34348. +        str    r4, [r0], #4
  34349. +        mov    r5, r6, lsl #16
  34350. +        orr    r5, r5, r5, lsr #16
  34351. +        str    r5, [r0], #4
  34352. +        mov    r6, r6, lsr #16
  34353. +        orr    r6, r6, r6, lsl #16
  34354. +        str    r6, [r0], #4
  34355. +        ldmeqea    fp, {r4 - r10, fp, sp, pc}^
  34356. +        sub    r2, r2, #8
  34357. +acornscsi_out4:    adds    r2, r2, #4
  34358. +        bmi    acornscsi_out2
  34359. +        ldr    r4, [r1], #4
  34360. +        mov    r3, r4, lsl #16
  34361. +        orr    r3, r3, r3, lsr #16
  34362. +        str    r3, [r0], #4
  34363. +        mov    r4, r4, lsr #16
  34364. +        orr    r4, r4, r4, lsl #16
  34365. +        str    r4, [r0], #4
  34366. +        ldmeqea    fp, {r4 - r10, fp, sp, pc}^
  34367. +        sub    r2, r2, #4
  34368. +acornscsi_out2:    adds    r2, r2, #2
  34369. +        ldr    r3, [r1], #2
  34370. +        and    r3, r3, ip
  34371. +        strb    r3, [r0], #1
  34372. +        mov    r3, r3, lsr #8
  34373. +        strplb    r3, [r0], #1
  34374. +        ldmea    fp, {r4 - r10, fp, sp, pc}^
  34375. +
  34376. diff -urNwbB linux/arch/arm/drivers/scsi/acornscsi.c linux.arm/arch/arm/drivers/scsi/acornscsi.c
  34377. --- linux/arch/arm/drivers/scsi/acornscsi.c    Thu Jan  1 01:00:00 1970
  34378. +++ linux.arm/arch/arm/drivers/scsi/acornscsi.c    Sun Feb 11 09:32:31 1996
  34379. @@ -0,0 +1,1967 @@
  34380. +/*
  34381. + * linux/arch/arm/drivers/scsi/acornscsi.c
  34382. + *
  34383. + *  Acorn scsi SP3 driver
  34384. + *
  34385. + *  By R.M.King, using SP3 info supplied by Acorn.
  34386. + *
  34387. + * Abandoned using the Select and Transfer command since there were
  34388. + * some nasty races between our software and the target devices that
  34389. + * were not easy to solve, and the device specs said that there were
  34390. + * some nasty bugs in that command...
  34391. + *
  34392. + */
  34393. +
  34394. +#ifdef MODULE
  34395. +#include <linux/module.h>
  34396. +#include <linux/config.h>
  34397. +#endif
  34398. +
  34399. +#include <linux/kernel.h>
  34400. +#include <linux/sched.h>
  34401. +#include <linux/string.h>
  34402. +#include <linux/signal.h>
  34403. +#include <linux/errno.h>
  34404. +#include <linux/proc_fs.h>
  34405. +#include <linux/stat.h>
  34406. +#include <asm/bitops.h>
  34407. +#include <asm/system.h>
  34408. +#include <asm/io.h>
  34409. +#include <asm/ecard.h>
  34410. +#include "../block/blk.h"
  34411. +#include "scsi.h"
  34412. +#include "hosts.h"
  34413. +#include "acornscsi.h"
  34414. +#include "constants.h"
  34415. +
  34416. +#define DEBUG_NO_WRITE    1
  34417. +#define DEBUG_QUEUES    2
  34418. +#define DEBUG_DMA    4
  34419. +#define DEBUG_ABORT    8
  34420. +#define DEBUG_DISCON    16
  34421. +#define DEBUG_CONNECT    32
  34422. +#define DEBUG_PHASES    64
  34423. +#define DEBUG_WRITE    128
  34424. +#define DEBUG_LINK    256
  34425. +
  34426. +/*
  34427. + *====================================================================================
  34428. + *
  34429. + * Driver Configuration
  34430. + *
  34431. + *
  34432. + *
  34433. + * SCSI-II Tagged queue support.
  34434. + *
  34435. + * I don't have any SCSI devices that support it, so it is totally untested (except to
  34436. + * make sure that it doesn't interfere with any non-tagging devices).  It is not fully
  34437. + * implemented either - what happens when a tagging device reconnects???
  34438. + */
  34439. +#undef SCSI2_TAG
  34440. +
  34441. +/*
  34442. + * SCSI-II Linked command support.
  34443. + *
  34444. + * The higher level code doesn't support linked commands yet.
  34445. + */
  34446. +#undef SCSI2_LINK
  34447. +
  34448. +/*
  34449. + * Debugging information
  34450. + *
  34451. + * Please see debug list above
  34452. + */
  34453. +#define DEBUG (DEBUG_ABORT)
  34454. +
  34455. +/*
  34456. + * List of devices that the driver will recognise
  34457. + *
  34458. + * PRODS is the list of product numbers
  34459. + * MANUS is the list of manufacturer numbers
  34460. + *
  34461. + * NOTE: this is used as a pair of numbers.  If you add a number in the middle of
  34462. + *       one, then you must add a number in at the same place in the other.
  34463. + */
  34464. +#define PRODS 0x0002
  34465. +#define MANUS 0x0000
  34466. +/*
  34467. + *====================================================================================
  34468. + */
  34469. +
  34470. +#define VER_MAJOR 1
  34471. +#define VER_MINOR 4
  34472. +
  34473. +#if 0
  34474. +/*
  34475. + * This is as per acorns spec.
  34476. + */
  34477. +#define INIT_DEVCON0 (DEVCON0_RQL | DEVCON0_EXW)
  34478. +#define INIT_DEVCON1 (DEVCON1_BHLD)
  34479. +#define INIT_SBICDMA (CTRL_DMABURST)
  34480. +#define DMAC_READ    (MODECON_READ)
  34481. +#define DMAC_WRITE   (MODECON_WRITE)
  34482. +#else
  34483. +/*
  34484. + * Hopefully this will improve performance with floppy disk + serial port
  34485. + */
  34486. +#define INIT_DEVCON0 (DEVCON0_RQL | DEVCON0_EXW)
  34487. +#define INIT_DEVCON1 (0)
  34488. +#define INIT_SBICDMA (CTRL_DMAMODE)
  34489. +#define DMAC_READ    (MODECON_READ|MODECON_SINGLE)
  34490. +#define DMAC_WRITE   (MODECON_WRITE|MODECON_SINGLE)
  34491. +#endif
  34492. +
  34493. +#define POD_SPACE(x) ((x) + 0xd0000)
  34494. +#define SCpdirection SCp.phase
  34495. +#define MASK_ON (MASKREG_M3|MASKREG_M2|MASKREG_M1|MASKREG_M0)
  34496. +#define MASK_OFF (MASKREG_M3|MASKREG_M2|MASKREG_M1)
  34497. +#define RESET_STATUS(x) ({ status_ptr = 0; })
  34498. +#define ADD_STATUS(x) ({ status_array[status_ptr] = (x); status_ptr = (status_ptr + 1) & 63; })
  34499. +
  34500. +static unsigned char status_array[64];
  34501. +static unsigned int status_ptr = 0;
  34502. +
  34503. +static struct Scsi_Host *first_instance = NULL;
  34504. +static Scsi_Host_Template *the_template = NULL;
  34505. +
  34506. +/*
  34507. + * Todo:
  34508. + *     Complete abort processing code when command is disconnected [waiting for one to happen]
  34509. + */
  34510. +
  34511. +static struct proc_dir_entry proc_scsi_acornscsi = {
  34512. +    PROC_SCSI_EATA, 9, "acornscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2
  34513. +};
  34514. +
  34515. +static inline void sbic_write (struct Scsi_Host *instance, int reg, int value)
  34516. +{
  34517. +    outb(reg, instance->io_port + 0x800);
  34518. +    outw(value, instance->io_port + 0x801);
  34519. +}
  34520. +
  34521. +static inline int sbic_read (struct Scsi_Host *instance, int reg)
  34522. +{
  34523. +    if(reg == ASR)
  34524. +           return inw(instance->io_port + 0x800) & 0xff;
  34525. +    outb(reg, instance->io_port + 0x800);
  34526. +    return inw(instance->io_port + 0x801) & 0xff;
  34527. +}
  34528. +
  34529. +static inline void page_write (struct Scsi_Host *instance, int value)
  34530. +{
  34531. +    outb(value, POD_SPACE(instance->io_port) + 0xc00);
  34532. +}
  34533. +
  34534. +static inline int dmac_read (struct Scsi_Host *instance, int reg)
  34535. +{
  34536. +    return inb (instance->io_port + 0xc00 + reg);
  34537. +}
  34538. +
  34539. +static inline void dmac_write (struct Scsi_Host *instance, int reg, int value)
  34540. +{
  34541. +    outb (value, instance->io_port + 0xc00 + reg);
  34542. +}
  34543. +
  34544. +static inline void dmac_clearintr (struct Scsi_Host *instance)
  34545. +{
  34546. +    outb (0, POD_SPACE(instance->io_port) + 0x800);
  34547. +}
  34548. +
  34549. +static inline int read_irqstat (struct Scsi_Host *instance)
  34550. +{
  34551. +    return inb (POD_SPACE(instance->io_port) + 0x800);
  34552. +}
  34553. +
  34554. +static inline void sbic_reset (struct Scsi_Host *instance)
  34555. +{
  34556. +    sbic_write (instance, OWNID, OWNID_EAF | instance->this_id);
  34557. +    sbic_write (instance, CMND, CMND_RESET);
  34558. +}
  34559. +
  34560. +/*=============================================================================================
  34561. + * utility routines
  34562. + */
  34563. +static void print_sbic_status (int asr, int ssr, int cmdphase)
  34564. +{
  34565. +    printk("sbic status: %s %s %s %s %s %s ",
  34566. +        asr & ASR_INT ? "INT" : "int",
  34567. +        asr & ASR_LCI ? "LCI" : "lci",
  34568. +        asr & ASR_BSY ? "BSY" : "bsy",
  34569. +        asr & ASR_CIP ? "CIP" : "cip",
  34570. +        asr & ASR_PE  ? "PE"  : "pe",
  34571. +        asr & ASR_DBR ? "DBR" : "dbr");
  34572. +    printk("scsi status: %X:%X phase %02X\n",
  34573. +        (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase);
  34574. +}
  34575. +
  34576. +static void acornscsi_printstatus (struct Scsi_Host *instance)
  34577. +{
  34578. +    int statptr;
  34579. +    printk ("IRQs: ");
  34580. +    statptr = status_ptr - 20;
  34581. +    if (statptr < 0)
  34582. +    statptr += 64;
  34583. +    for (; statptr != status_ptr; statptr = (statptr + 2) & 63) {
  34584. +        printk ("[%02X:%02X] ", status_array[statptr], status_array[statptr+1]);
  34585. +    }
  34586. +    printk ("\n");
  34587. +}
  34588. +
  34589. +static inline int acornscsi_cmdtype (int command)
  34590. +{
  34591. +    switch (command) {
  34592. +        case WRITE_6:
  34593. +        case WRITE_10:
  34594. +        case WRITE_12:
  34595. +            return CMD_WRITE;
  34596. +        case READ_6:
  34597. +        case READ_10:
  34598. +        case READ_12:
  34599. +            return CMD_READ;
  34600. +        default:
  34601. +            return CMD_MISC;
  34602. +    }
  34603. +}
  34604. +
  34605. +static int acornscsi_writedirection (int command)
  34606. +{
  34607. +    switch (command) {
  34608. +    case CHANGE_DEFINITION:
  34609. +    case COMPARE:
  34610. +    case COPY:
  34611. +    case COPY_VERIFY:
  34612. +    case LOG_SELECT:
  34613. +    case MODE_SELECT:
  34614. +    case MODE_SELECT_10:
  34615. +    case SEND_DIAGNOSTIC:
  34616. +    case WRITE_BUFFER:
  34617. +    case FORMAT_UNIT:
  34618. +    case REASSIGN_BLOCKS:
  34619. +    case RESERVE:
  34620. +    case SEARCH_EQUAL:
  34621. +    case SEARCH_HIGH:
  34622. +    case SEARCH_LOW:
  34623. +    case WRITE_6:
  34624. +    case WRITE_10:
  34625. +    case WRITE_VERIFY:
  34626. +    case UPDATE_BLOCK:
  34627. +    case WRITE_LONG:
  34628. +    case WRITE_SAME:
  34629. +    case SEARCH_HIGH_12:
  34630. +    case SEARCH_EQUAL_12:
  34631. +    case SEARCH_LOW_12:
  34632. +    case WRITE_12:
  34633. +    case WRITE_VERIFY_12:
  34634. +    case SET_WINDOW:
  34635. +    case MEDIUM_SCAN:
  34636. +    case SEND_VOLUME_TAG:
  34637. +    case 0xea:
  34638. +        return 1;
  34639. +    case TEST_UNIT_READY:
  34640. +    default:
  34641. +        return 0;
  34642. +    }
  34643. +}
  34644. +
  34645. +static inline void acornscsi_setupdmac(struct Scsi_Host *instance, int mode,
  34646. +        unsigned long address, int length)
  34647. +{
  34648. +    dmac_write (instance, MASKREG, MASK_ON);
  34649. +    if (length) {
  34650. +    length -= 1;
  34651. +    dmac_write (instance, TXCNTLO, length);
  34652. +    dmac_write (instance, TXCNTHI, length >> 8);
  34653. +    dmac_write (instance, TXADRLO, address);
  34654. +    dmac_write (instance, TXADRMD, address >> 8);
  34655. +    dmac_write (instance, TXADRHI, address >> 16);
  34656. +    dmac_write (instance, MODECON, mode);
  34657. +    dmac_write (instance, MASKREG, MASK_OFF);
  34658. +    } else {
  34659. +    dmac_write (instance, TXCNTLO, 0);
  34660. +    dmac_write (instance, TXCNTHI, 0);
  34661. +    }
  34662. +}
  34663. +
  34664. +/*
  34665. + * Function : acornscsi_initialisebuffer (Scsi_Cmnd *cmd)
  34666. + *
  34667. + * Purpose  : Initialise the buffer pointers
  34668. + *
  34669. + * Params   : cmd - command structure
  34670. + *
  34671. + */
  34672. +static inline void acornscsi_initialisebuffer (Scsi_Cmnd *cmd)
  34673. +{
  34674. +    if (cmd->use_sg) {
  34675. +    cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
  34676. +    cmd->SCp.buffers_residual = cmd->use_sg - 1;
  34677. +    cmd->SCp.ptr = (char *) cmd->SCp.buffer->address;
  34678. +    cmd->SCp.this_residual = cmd->SCp.buffer->length;
  34679. +    } else {
  34680. +    cmd->SCp.buffer = NULL;
  34681. +    cmd->SCp.buffers_residual = 0;
  34682. +    cmd->SCp.ptr = (char *) cmd->request_buffer;
  34683. +    cmd->SCp.this_residual = cmd->request_bufflen;
  34684. +    }
  34685. +}
  34686. +
  34687. +/*
  34688. + * Function : acornscsi_nextbuffer (Scsi_Cmnd *cmd)
  34689. + *
  34690. + * Purpose  : If the current buffer is empty, move onto the next buffer
  34691. + *
  34692. + * Params   : cmd - command structure containing the buffers.
  34693. + *
  34694. + * Returns  : zero if no more buffers, else non-zero
  34695. + */
  34696. +static inline int acornscsi_nextbuffer (Scsi_Cmnd *cmd)
  34697. +{
  34698. +    if (cmd->SCp.this_residual == 0)
  34699. +    if (cmd->SCp.buffers_residual) {
  34700. +        cmd->SCp.buffer++;
  34701. +        cmd->SCp.buffers_residual--;
  34702. +        cmd->SCp.ptr = (char *) cmd->SCp.buffer->address;
  34703. +        cmd->SCp.this_residual = cmd->SCp.buffer->length;
  34704. +        return 1;
  34705. +    } else {
  34706. +        cmd->SCp.ptr = NULL;
  34707. +        cmd->SCp.this_residual = 0;
  34708. +        return 0;
  34709. +    }
  34710. +}
  34711. +
  34712. +/*
  34713. + * Function : acornscsi_readbuffer (struct Scsi_Host *instance, char *buffer,
  34714. + *            unsigned long boardaddr, int len)
  34715. + *
  34716. + * Purpose  : transfer a block of data from the scsi card to memory
  34717. + *
  34718. + * Params   : instance  - host specific data
  34719. + *          : buffer    - address to put data
  34720. + *          : boardaddr - address of data on scsi card
  34721. + *          : len       - length of data to transfer
  34722. + *
  34723. + */
  34724. +static void acornscsi_readtobh (struct Scsi_Host *instance, struct acornscsi_hostdata *hostdata,
  34725. +            struct as_cmnd *ascmd, short residual)
  34726. +{
  34727. +    unsigned long buffer_length;
  34728. +    unsigned int page, offset;
  34729. +    Scsi_Cmnd *SCpnt;
  34730. +    extern void __acornscsi_in (int port, char *buffer, int transfer);
  34731. +
  34732. +    SCpnt = ascmd->cmd;
  34733. +
  34734. +    if (ascmd->buffer) {
  34735. +        page = (ascmd->buf1addr >> 12) & 0x3f;
  34736. +        offset = ascmd->buf1addr & 4095;
  34737. +    buffer_length = ascmd->buf1len - residual;
  34738. +    } else {
  34739. +        page = (ascmd->buf0addr >> 12) & 0x3f;
  34740. +        offset = ascmd->buf0addr & 4095;
  34741. +    buffer_length = ascmd->buf0len - residual;
  34742. +    }
  34743. +
  34744. +    page_write (instance, hostdata->page_reg | page);
  34745. +
  34746. +#if (DEBUG & DEBUG_DMA)
  34747. +    printk ("scsi%d :  debug : readtobh: (%04lX %04lX)\n        ", instance->host_no, (page << 12) | offset,
  34748. +    buffer_length);
  34749. +#endif
  34750. +
  34751. +    while (buffer_length > 0) {
  34752. +        int this_length;
  34753. +
  34754. +    if (SCpnt->SCp.this_residual > buffer_length)
  34755. +        this_length = buffer_length;
  34756. +    else
  34757. +        this_length = SCpnt->SCp.this_residual;
  34758. +
  34759. +    SCpnt->SCp.this_residual -= this_length;
  34760. +    buffer_length  -= this_length;
  34761. +
  34762. +#if (DEBUG & DEBUG_DMA)
  34763. +    printk ("[%p %04lX %04X] ", SCpnt->SCp.ptr, (page << 12) | offset, this_length);
  34764. +#endif
  34765. +
  34766. +    while (this_length > 0) {
  34767. +        int this_trans;
  34768. +
  34769. +        this_trans = 4096 - offset;
  34770. +        if (this_trans > this_length)
  34771. +        this_trans = this_length;
  34772. +
  34773. +        __acornscsi_in (instance->io_port + (offset >> 1), SCpnt->SCp.ptr, this_trans);
  34774. +
  34775. +        SCpnt->SCp.ptr += this_trans;
  34776. +        offset         += this_trans;
  34777. +        this_length    -= this_trans;
  34778. +
  34779. +        if (offset > 4095) {
  34780. +            offset -= 4096;
  34781. +            page    = (page + 1) & 0x3f;
  34782. +            page_write (instance, hostdata->page_reg | page);
  34783. +        }
  34784. +    }
  34785. +
  34786. +    if (acornscsi_nextbuffer (SCpnt) == 0)
  34787. +        break;
  34788. +    }
  34789. +#if (DEBUG & DEBUG_DMA)
  34790. +    printk ("\n");
  34791. +#endif
  34792. +}
  34793. +
  34794. +/*
  34795. + * Function : acornscsi_writebuffer (struct Scsi_Host *instance, char *buffer,
  34796. + *            unsigned long boardaddr, int len)
  34797. + *
  34798. + * Purpose  : transfer a block of data from memory to the scsi card
  34799. + *
  34800. + * Params   : instance  - host specific data
  34801. + *          : buffer    - address to put data
  34802. + *          : boardaddr - address of data on scsi card
  34803. + *          : len       - length of data to transfer
  34804. + *
  34805. + */
  34806. +static inline void acornscsi_writebuffer (struct Scsi_Host *instance, char *buffer,
  34807. +            unsigned long boardaddr, int len)
  34808. +{
  34809. +    extern void __acornscsi_out (int port, char *buffer, int transfer);
  34810. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *)instance->hostdata;
  34811. +    unsigned int page, offset;
  34812. +
  34813. +    page = (boardaddr >> 12) & 0x3f;
  34814. +    offset = boardaddr & 4095;
  34815. +
  34816. +    page_write (instance, hostdata->page_reg | page);
  34817. +
  34818. +    while (len > 0) {
  34819. +    int this_trans;
  34820. +
  34821. +    this_trans = 4096 - offset;
  34822. +    if (len < this_trans)
  34823. +        this_trans = len;
  34824. +
  34825. +    __acornscsi_out (instance->io_port + (offset >> 1), buffer, this_trans);
  34826. +
  34827. +    buffer += this_trans;
  34828. +    offset += this_trans;
  34829. +    len    -= this_trans;
  34830. +
  34831. +    if (offset > 4095) {
  34832. +        offset -= 4096;
  34833. +        page    = (page + 1) & 0x3f;
  34834. +        page_write (instance, hostdata->page_reg | page);
  34835. +    }
  34836. +    }
  34837. +}
  34838. +
  34839. +static unsigned long acornscsi_writefrombh (struct Scsi_Host *instance,    struct as_cmnd *ascmd,
  34840. +                    int buffer)
  34841. +{
  34842. +    Scsi_Cmnd *SCpnt;
  34843. +    unsigned long buffer_address, buffer_offset;
  34844. +    SCpnt = ascmd->cmd;
  34845. +
  34846. +    if (buffer)
  34847. +    buffer_address = ascmd->buf1addr;
  34848. +    else
  34849. +    buffer_address = ascmd->buf0addr;
  34850. +
  34851. +#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
  34852. +    printk ("scsi%d :  debug : writefrombh: (%04lX)\n        ", instance->host_no, buffer_address);
  34853. +#endif
  34854. +
  34855. +    buffer_offset = 0;
  34856. +
  34857. +    do {
  34858. +    int this_length;
  34859. +    
  34860. +    if (buffer_offset + SCpnt->SCp.this_residual >= 4096)
  34861. +        this_length = 4096 - buffer_offset;
  34862. +    else
  34863. +        this_length = SCpnt->SCp.this_residual;
  34864. +
  34865. +#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
  34866. +    printk ("[%p %04lX %04X] ", SCpnt->SCp.ptr, buffer_address + buffer_offset, this_length);
  34867. +#endif
  34868. +
  34869. +    acornscsi_writebuffer (instance, SCpnt->SCp.ptr, buffer_address + buffer_offset, this_length);
  34870. +
  34871. +    SCpnt->SCp.this_residual -= this_length;
  34872. +    SCpnt->SCp.ptr += this_length;
  34873. +    buffer_offset += this_length;
  34874. +
  34875. +    if (acornscsi_nextbuffer (SCpnt) == 0)
  34876. +        break;
  34877. +    } while (buffer_offset < 4096);
  34878. +
  34879. +#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
  34880. +    printk ("\n");
  34881. +#endif
  34882. +    if (buffer)
  34883. +    ascmd->buf1len = buffer_offset;
  34884. +    else
  34885. +    ascmd->buf0len = buffer_offset;
  34886. +
  34887. +    return buffer_offset;
  34888. +}    
  34889. +/*
  34890. + * Function : acornscsi_handletransfer (struct Scsi_Host *instance);
  34891. + *
  34892. + * Purpose  : transfers a block of data from the on-board buffer
  34893. + *            to the scatter list or buffer and updates the dmac
  34894. + *
  34895. + * Params   : instance - the device to handle
  34896. + *
  34897. + */
  34898. +static inline int acornscsi_handletransfer (struct Scsi_Host *instance)
  34899. +{
  34900. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *)instance->hostdata;
  34901. +    struct as_cmnd *ascmd = hostdata->connected;
  34902. +    
  34903. +    if (!ascmd) {
  34904. +        printk("scsi%d : warning: dmac interrupt with no connected command\n", instance->host_no);
  34905. +        return 0;
  34906. +    }
  34907. +
  34908. +    dmac_write (instance, MASKREG, MASK_ON);
  34909. +    dmac_clearintr (instance);
  34910. +
  34911. +#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
  34912. +    printk ("htrans: ");
  34913. +#endif
  34914. +    switch (hostdata->phase) {
  34915. +    case PHASE_COMMANDSENT:
  34916. +    printk ("\n");
  34917. +    return 0;
  34918. +
  34919. +    case PHASE_DATAIN:
  34920. +    if (ascmd->buffer) {
  34921. +        ascmd->totallen -= ascmd->buf1len;
  34922. +        if (ascmd->totallen > 4096)
  34923. +        ascmd->buf0len = 4096;
  34924. +        else
  34925. +        ascmd->buf0len = ascmd->totallen;
  34926. +
  34927. +        acornscsi_setupdmac (instance, DMAC_READ, ascmd->buf0addr, ascmd->buf0len);
  34928. +    } else {
  34929. +        ascmd->totallen -= ascmd->buf0len;
  34930. +        if (ascmd->totallen > 4096)
  34931. +        ascmd->buf1len = 4096;
  34932. +        else
  34933. +        ascmd->buf1len = ascmd->totallen;
  34934. +
  34935. +        acornscsi_setupdmac (instance, DMAC_READ, ascmd->buf1addr, ascmd->buf1len);
  34936. +    }
  34937. +    acornscsi_readtobh (instance, hostdata, ascmd, 0);
  34938. +    ascmd->buffer ^= 1;
  34939. +    if (ascmd->totallen == 0)
  34940. +        return 0;
  34941. +    return 1;
  34942. +
  34943. +    case PHASE_DATAOUT:
  34944. +    if (ascmd->buffer) {
  34945. +        ascmd->totallen -= ascmd->buf1len;
  34946. +
  34947. +        acornscsi_setupdmac (instance, DMAC_WRITE, ascmd->buf0addr, ascmd->buf0len);
  34948. +        ascmd->buffer = 0;
  34949. +
  34950. +        acornscsi_writefrombh (instance, ascmd, 1);
  34951. +    } else {
  34952. +        ascmd->totallen -= ascmd->buf0len;
  34953. +
  34954. +        acornscsi_setupdmac (instance, DMAC_WRITE, ascmd->buf1addr, ascmd->buf1len);
  34955. +        ascmd->buffer = 1;
  34956. +
  34957. +        acornscsi_writefrombh (instance, ascmd, 0);
  34958. +    }
  34959. +
  34960. +    if (ascmd->totallen == 0)
  34961. +        return 0;
  34962. +    return 1;
  34963. +    }
  34964. +    return 0;
  34965. +}
  34966. +
  34967. +static void acornscsi_sendcommand (struct Scsi_Host *instance,
  34968. +            struct acornscsi_hostdata *hostdata)
  34969. +{
  34970. +    struct as_dev *dev;
  34971. +    struct as_cmnd *asprev, *ascmd;
  34972. +    int i;
  34973. +
  34974. +    cli ();
  34975. +    if (hostdata->connected)
  34976. +    goto not_busy;
  34977. +
  34978. +    if (hostdata->aborting) {
  34979. +    if (!(sbic_read (instance, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
  34980. +        hostdata->phase = PHASE_CONNECTING_FOR_ABORT;
  34981. +        sbic_write (instance, DESTID, hostdata->aborting->cmd->target);
  34982. +        sbic_write (instance, CMND, CMND_SELWITHATN);
  34983. +#if (DEBUG & (DEBUG_QUEUES|DEBUG_ABORT|DEBUG_CONNECT))
  34984. +        printk ("scsi%d : restarting abortion of id %d\n", instance->host_no,
  34985. +                hostdata->aborting->cmd->target);
  34986. +#endif
  34987. +    }
  34988. +    goto not_busy;
  34989. +    }
  34990. +
  34991. +    if (hostdata->connecting) {
  34992. +    if (!(sbic_read (instance, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
  34993. +        hostdata->phase = PHASE_CONNECTING;
  34994. +        sbic_write (instance, DESTID, hostdata->connecting->cmd->target);
  34995. +        sbic_write (instance, CMND, CMND_SELWITHATN);
  34996. +#if (DEBUG & (DEBUG_QUEUES|DEBUG_CONNECT))
  34997. +        printk ("scsi%d : restarting selection of id %d\n", instance->host_no,
  34998. +                hostdata->connecting->cmd->target);
  34999. +#endif
  35000. +    }
  35001. +    goto not_busy;
  35002. +    }
  35003. +
  35004. +    for (i = 0, dev = hostdata->dev; i < 8; i++, dev++) {
  35005. +    for (ascmd = dev->issue_head, asprev = NULL; ascmd; asprev = ascmd, ascmd = ascmd->next) {
  35006. +        if (!ascmd->used || !ascmd->cmd || !ascmd->cmd->scsi_done) {
  35007. +            printk ("scsi%d : warning: invalid %s found in issue queue\n",
  35008. +            instance->host_no, ascmd->used ? ascmd->cmd ? "scsi_done" : "cmd" : "used");
  35009. +        if (asprev)
  35010. +            asprev = ascmd->next;
  35011. +        else
  35012. +            dev->issue_head = ascmd->next;
  35013. +        if (ascmd == dev->issue_tail)
  35014. +            dev->issue_tail = asprev;
  35015. +        continue;
  35016. +        }
  35017. +
  35018. +        if (ascmd->cmd->device->tagged_queue == 0) {
  35019. +        if (set_bit (ascmd->cmd->lun, &dev->busy))
  35020. +            continue;
  35021. +        }
  35022. +#ifdef SCSI2_TAG
  35023. +        else {
  35024. +        /*
  35025. +         * SCSI-II Tagged support.  If the command is not a request sense, then
  35026. +         * we allocate a tag to it.
  35027. +         */
  35028. +        if (ascmd->cmd->cmnd[0] != REQUEST_SENSE) {
  35029. +            if (ascmd->cmd->device->current_tag == 0) {
  35030. +            printk ("scsi%d : Enabling tagged queueing for target %d.\n",
  35031. +                ascmd->cmd->host->host_no, ascmd->cmd->target);
  35032. +            ascmd->cmd->device->current_tag = 1; /* enable tagging */
  35033. +            }
  35034. +            ascmd->cmd->tag = ascmd->cmd->device->current_tag++;
  35035. +            if (ascmd->cmd->device->current_tag == 0) /* MUST not become zero */
  35036. +            ascmd->cmd->device->current_tag += 1;
  35037. +        }
  35038. +        }
  35039. +#endif
  35040. +
  35041. +        hostdata->connecting = ascmd;
  35042. +
  35043. +        if (asprev)
  35044. +            asprev->next = ascmd->next;
  35045. +        else
  35046. +            dev->issue_head = ascmd->next;
  35047. +
  35048. +        if (ascmd == dev->issue_tail)
  35049. +            dev->issue_tail = asprev;
  35050. +
  35051. +        hostdata->stats.removes += 1;
  35052. +
  35053. +        if (!(sbic_read (instance, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
  35054. +        sti ();
  35055. +            hostdata->phase = PHASE_CONNECTING;
  35056. +        sbic_write (instance, DESTID, hostdata->connecting->cmd->target);
  35057. +        sbic_write (instance, CMND, CMND_SELWITHATN);
  35058. +#if (DEBUG & (DEBUG_QUEUES|DEBUG_CONNECT))
  35059. +        printk ("scsi%d :  debug : starting selection of id %d\n", instance->host_no,
  35060. +                hostdata->connecting->cmd->target);
  35061. +#endif
  35062. +        }
  35063. +
  35064. +        sti ();
  35065. +
  35066. +        switch (acornscsi_cmdtype (ascmd->cmd->cmnd[0])) {
  35067. +        case CMD_WRITE:
  35068. +        hostdata->stats.writes += 1;
  35069. +        break;
  35070. +        case CMD_READ:
  35071. +            hostdata->stats.reads += 1;
  35072. +            break;
  35073. +        case CMD_MISC:
  35074. +            hostdata->stats.miscs += 1;
  35075. +            break;
  35076. +        }
  35077. +        return;
  35078. +    }
  35079. +    }
  35080. +
  35081. +not_busy:
  35082. +    sti ();
  35083. +}
  35084. +
  35085. +static inline void acornscsi_startsendcommand (struct Scsi_Host *instance)
  35086. +{
  35087. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *)instance->hostdata;
  35088. +
  35089. +    if (set_bit (0, (void *)&hostdata->busy) == 0)
  35090. +    acornscsi_sendcommand (instance, hostdata);
  35091. +    hostdata->busy = 0;
  35092. +}
  35093. +
  35094. +static void acornscsi_done (struct Scsi_Host *instance, struct as_cmnd *ascmd)
  35095. +{
  35096. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *)instance->hostdata;
  35097. +    Scsi_Cmnd *SCpnt;
  35098. +
  35099. +    sbic_write (instance, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
  35100. +
  35101. +    SCpnt = ascmd->cmd;
  35102. +
  35103. +    if (!SCpnt)
  35104. +    panic ("scsi%d :  fatal : null command in acornscsi_done\n", instance->host_no);
  35105. +#if 0
  35106. +    printk ("scsi%d : target %d connected in %d, finished %d, transferred %d\n",
  35107. +        instance->host_no, SCpnt->target, ascmd->connect_jiffies - ascmd->queued_jiffies,
  35108. +             finished_jiffies - ascmd->queued_jiffies, SCpnt->request_bufflen);
  35109. +#endif
  35110. +    ascmd->cmd     = NULL;
  35111. +    ascmd->next    = NULL;
  35112. +    ascmd->buf0len = 0;
  35113. +    ascmd->buf1len = 0;
  35114. +    ascmd->used    = 0;
  35115. +
  35116. +    hostdata->dev[SCpnt->target].busy &= ~(1 << SCpnt->lun);
  35117. +
  35118. +    if (!SCpnt->scsi_done)
  35119. +    panic ("scsi%d :  fatal : null scsi_done function in acornscsi_done\n", instance->host_no);
  35120. +
  35121. +    SCpnt->scsi_done (SCpnt);
  35122. +}
  35123. +
  35124. +static inline void acornscsi_savepointers (struct Scsi_Host *instance,
  35125. +                struct acornscsi_hostdata *hostdata)
  35126. +{
  35127. +    struct as_cmnd *ascmd = hostdata->connected;
  35128. +
  35129. +    dmac_write (instance, MASKREG, MASK_ON);
  35130. +    
  35131. +    ascmd->saved_sbic_transcnt = hostdata->tmpsbiclen;
  35132. +    ascmd->saved_dmac_address  = (dmac_read (instance, TXADRHI) << 16) |
  35133. +                     (dmac_read (instance, TXADRMD) << 8) |
  35134. +                      dmac_read (instance, TXADRLO);
  35135. +    ascmd->saved_dmac_transcnt = (dmac_read (instance, TXCNTHI) << 8) |
  35136. +                      dmac_read (instance, TXCNTLO);
  35137. +    ascmd->saved = 1;
  35138. +#if (DEBUG & DEBUG_DISCON)
  35139. +    printk ("scsi%d :  debug : discon: sl %06lX da %06lX dl %04lX\n", instance->host_no,
  35140. +        ascmd->saved_sbic_transcnt, ascmd->saved_dmac_address,
  35141. +        ascmd->saved_dmac_transcnt);
  35142. +#endif
  35143. +}
  35144. +
  35145. +/*
  35146. + * Function : acornscsi_disconnect (struct Scsi_Host *instance)
  35147. + *
  35148. + * Purpose  : disconnect the current command & put onto disconnected queue
  35149. + *
  35150. + * Params   : instance - host data
  35151. + *
  35152. + * Notes:
  35153. + * We appear to have a race condition between this exiting, sending the next command,
  35154. + * and a device on the bus reselecting us...
  35155. + */
  35156. +static inline void acornscsi_disconnect (struct Scsi_Host *instance)
  35157. +{
  35158. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *)instance->hostdata;
  35159. +    struct as_dev *dev;
  35160. +    struct as_cmnd *ascmd;
  35161. +    unsigned long flags;
  35162. +
  35163. +    dev = &hostdata->dev[hostdata->connected->cmd->target];
  35164. +
  35165. +    dmac_write (instance, MASKREG, MASK_ON);
  35166. +
  35167. +    save_flags (flags);
  35168. +    cli ();
  35169. +    ascmd = hostdata->connected;
  35170. +    hostdata->connected = NULL;
  35171. +
  35172. +    ascmd->next = dev->disconnected;
  35173. +    dev->disconnected = ascmd;
  35174. +    restore_flags (flags);
  35175. +
  35176. +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
  35177. +    printk("scsi%d : command for target %d lun %d tag %d moved to disconnected queue\n",
  35178. +    instance->host_no, ascmd->cmd->target, ascmd->cmd->lun, ascmd->cmd->tag);
  35179. +#endif
  35180. +}
  35181. +
  35182. +/*
  35183. + * Function : acornscsi_reconnect (struct Scsi_Host *instance)
  35184. + *
  35185. + * Purpose  : restore a previously saved command state
  35186. + *
  35187. + * Params   : instance - host data
  35188. + */
  35189. +static inline int acornscsi_reconnect (struct Scsi_Host *instance)
  35190. +{
  35191. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *)instance->hostdata;
  35192. +    struct as_dev *dev;
  35193. +    struct as_cmnd *ascmd, **asprev;
  35194. +    int sourceid, sourcelun, sourcetag = 0;
  35195. +
  35196. +    sourceid = sbic_read (instance, SOURCEID);
  35197. +
  35198. +    if (hostdata->connected) {
  35199. +    printk ("scsi%d : warning: reconnecting while connected to target %d\n",
  35200. +        instance->host_no, hostdata->connected->cmd->target);
  35201. +    hostdata->connected = NULL;
  35202. +    }
  35203. +
  35204. +    if (!(sourceid & 8)) {
  35205. +    printk ("scsi%d : warning: invalid source id after reselection - chip/device fault?\n",
  35206. +        instance->host_no);
  35207. +    return 0;
  35208. +    }
  35209. +
  35210. +    sourceid &= 7;
  35211. +    sourcelun = sbic_read (instance, DATA); /* should this be target lun or data? */
  35212. +    sourcelun &= 7;
  35213. +
  35214. +    dev = &hostdata->dev[sourceid];
  35215. +
  35216. +    for (asprev = &dev->disconnected; *asprev; asprev = &(*asprev)->next) {
  35217. +        ascmd = *asprev;
  35218. +    if (ascmd->cmd->target != sourceid) {
  35219. +        printk ("scsi%d : warning: command on wrong disconnected queue %d instead of %d\n",
  35220. +        instance->host_no, ascmd->cmd->target, sourceid);
  35221. +    }
  35222. +    if (ascmd->cmd->lun == sourcelun && ascmd->cmd->tag == sourcetag) {
  35223. +        *asprev = ascmd->next;
  35224. +        ascmd->next = NULL;
  35225. +        hostdata->connected = ascmd;
  35226. +#if (DEBUG & DEBUG_QUEUES)
  35227. +        printk ("scsi%d :  debug : command for target %d lun %d tag %d reconnected\n",
  35228. +        instance->host_no, ascmd->cmd->target, ascmd->cmd->lun, ascmd->cmd->tag);
  35229. +#endif
  35230. +        return 1;
  35231. +    }
  35232. +    }
  35233. +    printk("scsi%d : warning: target %d lun %d tag %d not in disconnect_queue.\n",
  35234. +    instance->host_no, sourceid, sourcelun, sourcetag);
  35235. +    return 0;
  35236. +}
  35237. +
  35238. +/*
  35239. + * Function : acornscsi_forcedisconnect (struct Scsi_Host *instance)
  35240. + *
  35241. + * Purpose  : force a disconnect from the bus
  35242. + *
  35243. + * Params   : instance - hostdata
  35244. + */
  35245. +static inline void acornscsi_forcedisconnect (struct Scsi_Host *instance)
  35246. +{
  35247. +}
  35248. +
  35249. +/*
  35250. + * Function : acornscsi_startabort (struct Scsi_Host *instance)
  35251. + *
  35252. + * Purpose  : start aborting a connected command
  35253. + *
  35254. + * Params   : instance - hostdata
  35255. + */
  35256. +static inline void acornscsi_startabort (struct Scsi_Host *instance)
  35257. +{
  35258. +    acornscsi_printstatus (instance);
  35259. +}
  35260. +
  35261. +/* ==========================================================================================
  35262. + * Interrupt routines.
  35263. + */
  35264. +static int acornscsi_sbicintr (struct Scsi_Host *instance)
  35265. +{
  35266. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *)instance->hostdata;
  35267. +    struct as_cmnd *ascmd;
  35268. +    int asr, ssr;
  35269. +
  35270. +    asr = sbic_read (instance, ASR);
  35271. +    if (!(asr & ASR_INT))
  35272. +    return INTR_CONTINUE;
  35273. +
  35274. +    ssr = sbic_read (instance, SSR);
  35275. +#if (DEBUG & (DEBUG_DMA|DEBUG_RECON|DEBUG_PHASES|DEBUG_WRITE))
  35276. +    print_sbic_status(asr, ssr, sbic_read (instance, CMNDPHASE));
  35277. +#endif
  35278. +    ADD_STATUS(ssr);
  35279. +    ADD_STATUS(hostdata->phase);
  35280. +
  35281. +    ascmd = hostdata->connected;
  35282. +
  35283. +    /*
  35284. +     * This is just one big switch statement
  35285. +     */
  35286. +
  35287. +    switch (ssr) {
  35288. +
  35289. +/* ---------------------- Reset -------------------------------------------------------- */
  35290. +    
  35291. +    case 0x00: /* reset state - not advanced */
  35292. +    printk ("scsi%d : reset in standard mode but wanted advanced mode.\n",
  35293. +        instance->host_no);
  35294. +    case 0x01: /* reset state - advanced */
  35295. +    sbic_write (instance, CTRL, INIT_SBICDMA | CTRL_IDI);
  35296. +    sbic_write (instance, TIMEOUT, 10);
  35297. +    sbic_write (instance, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
  35298. +    return INTR_CONTINUE;
  35299. +
  35300. +/* ---------------------- Select ------------------------------------------------------- */
  35301. +    
  35302. +    case 0x11: /* select command ok */
  35303. +        switch (hostdata->phase) {
  35304. +    case PHASE_CONNECTING:
  35305. +        if (!hostdata->connecting) {
  35306. +        printk ("scsi%d : warning: select ok but no connecting command\n",
  35307. +            instance->host_no);
  35308. +        goto abort_connect;
  35309. +        }
  35310. +        hostdata->connected = hostdata->connecting;
  35311. +        hostdata->connecting = NULL;
  35312. +        hostdata->phase = PHASE_CONNECTED;
  35313. +        hostdata->connected->buffer = 2;
  35314. +        hostdata->msgout = NOP;
  35315. +        hostdata->last_message = NOP;
  35316. +        hostdata->connected->connect_jiffies = jiffies;
  35317. +#if (DEBUG & (DEBUG_QUEUES|DEBUG_CONNECT))
  35318. +        printk ("scsi%d :  debug : command connected to target %d\n",
  35319. +            instance->host_no, hostdata->connected->cmd->target);
  35320. +#endif
  35321. +        return INTR_CONNECTED;
  35322. +
  35323. +    case PHASE_CONNECTING_FOR_ABORT:
  35324. +        if (!hostdata->aborting) {
  35325. +        printk ("scsi%d : warning: select ok but no connecting aborting command\n",
  35326. +            instance->host_no);
  35327. +        goto abort_connect;
  35328. +        }
  35329. +        hostdata->connected = hostdata->aborting;
  35330. +        hostdata->aborting = NULL;
  35331. +        hostdata->phase = PHASE_CONNECTED_FOR_ABORT;
  35332. +        hostdata->msgout = ABORT;
  35333. +        hostdata->last_message = NOP;
  35334. +        hostdata->connected->buffer = 2;
  35335. +#if (DEBUG & (DEBUG_QUEUES|DEBUG_CONNECT))
  35336. +        printk ("scsi%d :  debug : abort command connected to target %d\n",
  35337. +            instance->host_no, hostdata->connected->cmd->target);
  35338. +#endif
  35339. +        return INTR_CONNECTED;
  35340. +
  35341. +    default:
  35342. +        printk ("scsi%d : warning: select connected to target with invalid phase (%X)\n",
  35343. +        instance->host_no, hostdata->phase);
  35344. +    abort_connect:
  35345. +        /* At this point we have lost the command totally (and hence can't return an
  35346. +         * error until the upper code causes an abort.
  35347. +         */
  35348. +        acornscsi_printstatus (instance);
  35349. +        acornscsi_forcedisconnect (instance);
  35350. +        return INTR_NOTCONNECTED;
  35351. +    }
  35352. +
  35353. +    case 0x42:        /* select timeout */
  35354. +    switch (hostdata->phase) {
  35355. +    case PHASE_CONNECTING:
  35356. +        ascmd = hostdata->connecting;
  35357. +        hostdata->connecting = NULL;
  35358. +        ascmd->cmd->result = DID_BAD_TARGET << 16;
  35359. +        hostdata->phase = PHASE_IDLE;
  35360. +        acornscsi_done (instance, ascmd);
  35361. +        return INTR_NOTCONNECTED;
  35362. +
  35363. +    case PHASE_CONNECTING_FOR_ABORT:
  35364. +        ascmd = hostdata->aborting;
  35365. +        hostdata->aborting = NULL;
  35366. +        ascmd->cmd->result = DID_BAD_TARGET << 16;
  35367. +        hostdata->phase = PHASE_IDLE;
  35368. +        acornscsi_done (instance, ascmd);
  35369. +        return INTR_NOTCONNECTED;
  35370. +
  35371. +    default:
  35372. +        printk ("scsi%d : warning: select timeout for target %d in wrong phase\n",
  35373. +            instance->host_no, hostdata->connecting->cmd->target);
  35374. +        acornscsi_printstatus (instance);
  35375. +        return INTR_NOTCONNECTED;
  35376. +    }
  35377. +
  35378. +    case 0x81: /* reselection occurred */
  35379. +    /* for this, we need to add extra code to allow us to keep track of whether this
  35380. +     * is SCSI 2 tagged or not.  I am not sure how this part is supposed to work.
  35381. +     *
  35382. +     * For the moment, I will assume that it works the same way that we tell the
  35383. +     * device, ie. SELECT->MESSAGE(IDENTIFY)->MESSAGE(SIMPLE_TAG)->MESSAGE(TAGID)
  35384. +     */
  35385. +    if (acornscsi_reconnect (instance)) {
  35386. +        sbic_write (instance, CMND, CMND_NEGATEACK);
  35387. +        hostdata->phase = PHASE_RECONNECTED;
  35388. +    }
  35389. +    return INTR_CONNECTED;
  35390. +    
  35391. +    case 0x41:        /* unexpected disconnect aborted command */
  35392. +    if (!ascmd) {
  35393. +        printk ("scsi%d : warning: unexpected disconnect without connected command\n",
  35394. +        instance->host_no);
  35395. +        return INTR_NOTCONNECTED;
  35396. +    }
  35397. +    hostdata->connected = NULL;
  35398. +    ascmd->cmd->result = DID_ABORT << 16;
  35399. +    acornscsi_done (instance, ascmd);
  35400. +    hostdata->phase = PHASE_IDLE;
  35401. +    return INTR_NOTCONNECTED;
  35402. +
  35403. +    case 0x85: /* disconnection occurred */
  35404. +    if (ascmd == NULL) {
  35405. +        printk ("scsi%d : warning: disconnect with no connected command\n",
  35406. +            instance->host_no);
  35407. +        return INTR_NOTCONNECTED;
  35408. +    }
  35409. +    switch (hostdata->phase) {
  35410. +    case PHASE_FINISHED:
  35411. +        hostdata->connected = NULL;
  35412. +        hostdata->stats.fins += 1;
  35413. +        ascmd->cmd->result = ascmd->cmd->SCp.Status | (ascmd->cmd->SCp.Message << 8);
  35414. +        hostdata->phase = PHASE_IDLE;
  35415. +        acornscsi_done (instance, ascmd);
  35416. +        return INTR_NOTCONNECTED;
  35417. +
  35418. +    case PHASE_DISCONNECTING:
  35419. +        acornscsi_disconnect (instance);
  35420. +        hostdata->phase = PHASE_IDLE;
  35421. +        return INTR_NOTCONNECTED;
  35422. +
  35423. +    default:
  35424. +        printk ("scsi%d : warning: invalid phase in disconnect (%X)\n",
  35425. +        instance->host_no, hostdata->phase);
  35426. +        acornscsi_printstatus (instance);
  35427. +    }
  35428. +        return INTR_NOTCONNECTED;
  35429. +
  35430. +/* ---------------------- data out ----------------------------------------------------- */
  35431. +
  35432. +    case 0x88: /* connect - data out [only after reconnection] */
  35433. +    if (hostdata->phase != PHASE_RECONNECTED) {
  35434. +        printk ("scsi%d : warning: invalid phase for reconnected data out (%X)\n",
  35435. +        instance->host_no, hostdata->phase);
  35436. +        return INTR_CONNECTED;
  35437. +    }
  35438. +
  35439. +#if (DEBUG & (DEBUG_DISCON|DEBUG_WRITE))
  35440. +        printk ("scsi%d :  debug : recon: buffer %d ",
  35441. +        instance->host_no, ascmd->buffer);
  35442. +#endif
  35443. +    if (ascmd->buffer == 0 || ascmd->buffer == 1) {
  35444. +        if (!ascmd->saved) {
  35445. +        printk ("scsi%d : warning: no saved data for reconnected command\n",
  35446. +            instance->host_no);
  35447. +        return INTR_CONNECTED;
  35448. +        }
  35449. +        ascmd->saved = 0;
  35450. +
  35451. +        dmac_write (instance, MASKREG, MASK_ON);
  35452. +        dmac_write (instance, TXCNTLO, ascmd->saved_dmac_transcnt);
  35453. +        dmac_write (instance, TXCNTHI, ascmd->saved_dmac_transcnt >> 8);
  35454. +        dmac_write (instance, TXADRLO, ascmd->saved_dmac_address);
  35455. +        dmac_write (instance, TXADRMD, ascmd->saved_dmac_address >> 8);
  35456. +        dmac_write (instance, TXADRHI, ascmd->saved_dmac_address >> 16);
  35457. +        dmac_write (instance, MODECON, DMAC_WRITE);
  35458. +        dmac_write (instance, MASKREG, MASK_OFF);
  35459. +        sbic_write (instance, TRANSCNTL, ascmd->saved_sbic_transcnt);
  35460. +        sbic_write (instance, TRANSCNTM, ascmd->saved_sbic_transcnt >> 8);
  35461. +        sbic_write (instance, TRANSCNTH, ascmd->saved_sbic_transcnt >> 16);
  35462. +#if (DEBUG & (DEBUG_DISCON|DEBUG_WRITE))
  35463. +        printk ("sl %06lX da %06lX dl %04lX\n", ascmd->saved_sbic_transcnt,
  35464. +        ascmd->saved_dmac_address, ascmd->saved_dmac_transcnt);
  35465. +#endif
  35466. +        sbic_write (instance, CMND, CMND_XFERINFO);
  35467. +        hostdata->phase = PHASE_DATAOUT;
  35468. +        return INTR_CONNECTED;
  35469. +    }
  35470. +    ascmd->saved = 0;
  35471. +    goto data_out_common;
  35472. +
  35473. +    case 0x18: /* transfer completed - data out */
  35474. +    if (hostdata->phase != PHASE_COMMANDSENT) {
  35475. +        printk ("scsi%d : warning: invalid phase for data out (%X)\n",
  35476. +        instance->host_no, hostdata->phase);
  35477. +        acornscsi_startabort (instance);
  35478. +        return INTR_CONNECTED;
  35479. +    }
  35480. +    data_out_common:
  35481. +    ascmd->buffer = 0;
  35482. +    acornscsi_writefrombh (instance, ascmd, 0);
  35483. +    acornscsi_setupdmac (instance, DMAC_WRITE, ascmd->buf0addr, ascmd->buf0len);
  35484. +    sbic_write (instance, TRANSCNTL, ascmd->totallen);
  35485. +    sbic_write (instance, TRANSCNTM, ascmd->totallen >> 8);
  35486. +    sbic_write (instance, TRANSCNTH, ascmd->totallen >> 16);
  35487. +    sbic_write (instance, CMND, CMND_XFERINFO);
  35488. +    hostdata->phase = PHASE_DATAOUT;
  35489. +    acornscsi_writefrombh (instance, ascmd, 1);
  35490. +#if (DEBUG & (DEBUG_DISCON|DEBUG_WRITE))
  35491. +    printk ("sl %06lX da %06lX dl %04lX\n", ascmd->totallen, ascmd->buf0addr,
  35492. +        ascmd->buf0len);
  35493. +#endif
  35494. +    return INTR_CONNECTED;
  35495. +
  35496. +/* ---------------------- data in ------------------------------------------------------ */
  35497. +
  35498. +    case 0x89: /* connect - data in [only after reconnection] */
  35499. +    if (hostdata->phase != PHASE_RECONNECTED) {
  35500. +        printk ("scsi%d : warning: invalid phase for reconnected data in (%X)\n",
  35501. +        instance->host_no, hostdata->phase);
  35502. +        return INTR_CONNECTED;
  35503. +    }
  35504. +
  35505. +#if (DEBUG & DEBUG_DISCON)
  35506. +    printk ("scsi%d :  debug : recon: buffer %d ",
  35507. +        instance->host_no, ascmd->buffer);
  35508. +#endif
  35509. +    if (ascmd->buffer == 0 || ascmd->buffer == 1) {
  35510. +        if (!ascmd->saved) {
  35511. +        printk ("scsi%d : warning: no saved data for reconnected command\n",
  35512. +            instance->host_no);
  35513. +        return INTR_CONNECTED;
  35514. +        }
  35515. +        ascmd->saved = 0;
  35516. +
  35517. +        dmac_write (instance, MASKREG, MASK_ON);
  35518. +        dmac_write (instance, TXCNTLO, ascmd->saved_dmac_transcnt);
  35519. +        dmac_write (instance, TXCNTHI, ascmd->saved_dmac_transcnt >> 8);
  35520. +        dmac_write (instance, TXADRLO, ascmd->saved_dmac_address);
  35521. +        dmac_write (instance, TXADRMD, ascmd->saved_dmac_address >> 8);
  35522. +        dmac_write (instance, TXADRHI, ascmd->saved_dmac_address >> 16);
  35523. +        dmac_write (instance, MODECON, DMAC_READ);
  35524. +        dmac_write (instance, MASKREG, MASK_OFF);
  35525. +        sbic_write (instance, TRANSCNTL, ascmd->saved_sbic_transcnt);
  35526. +        sbic_write (instance, TRANSCNTM, ascmd->saved_sbic_transcnt >> 8);
  35527. +        sbic_write (instance, TRANSCNTH, ascmd->saved_sbic_transcnt >> 16);
  35528. +#if (DEBUG & DEBUG_DISCON)
  35529. +        printk ("sl %06lX da %06lX dl %04lX\n", ascmd->saved_sbic_transcnt,
  35530. +        ascmd->saved_dmac_address, ascmd->saved_dmac_transcnt);
  35531. +#endif
  35532. +        sbic_write (instance, CMND, CMND_XFERINFO);
  35533. +        hostdata->phase = PHASE_DATAIN;
  35534. +        return INTR_CONNECTED;
  35535. +    }
  35536. +    ascmd->saved = 0;
  35537. +    goto data_in_common;
  35538. +
  35539. +    case 0x19: /* transfer completed - data in */
  35540. +    if (hostdata->phase != PHASE_COMMANDSENT) {
  35541. +        printk ("scsi%d : warning: invalid phase for data in (%X)\n",
  35542. +        instance->host_no, hostdata->phase);
  35543. +        acornscsi_startabort (instance);
  35544. +        return INTR_CONNECTED;
  35545. +    }
  35546. +    data_in_common:
  35547. +    ascmd->buffer = 0;
  35548. +
  35549. +    if (ascmd->totallen > 4096)
  35550. +        ascmd->buf0len = 4096;
  35551. +    else
  35552. +        ascmd->buf0len = ascmd->totallen;
  35553. +
  35554. +    acornscsi_setupdmac (instance, DMAC_READ, ascmd->buf0addr, ascmd->buf0len);
  35555. +
  35556. +    sbic_write (instance, TRANSCNTL, ascmd->totallen);
  35557. +    sbic_write (instance, TRANSCNTM, ascmd->totallen >> 8);
  35558. +    sbic_write (instance, TRANSCNTH, ascmd->totallen >> 16);
  35559. +#if (DEBUG & DEBUG_DISCON)
  35560. +    printk ("sl %06lX da %06lX dl %04X\n", ascmd->totallen, ascmd->buf0addr,
  35561. +        ascmd->buf0len);
  35562. +#endif
  35563. +    sbic_write (instance, CMND, CMND_XFERINFO);
  35564. +    hostdata->phase = PHASE_DATAIN;
  35565. +    return INTR_CONNECTED;
  35566. +
  35567. +/* ---------------------- command out -------------------------------------------------- */
  35568. +
  35569. +    case 0x1a: /* transfer completed - command info next */
  35570. +    case 0x8a: {/* connection - command phase out */
  35571. +    Scsi_Cmnd *SCpnt;
  35572. +    int i;
  35573. +    
  35574. +    if (hostdata->phase != PHASE_COMMAND) {
  35575. +        printk ("scsi%d : warning: invalid phase for command (%X)\n",
  35576. +        instance->host_no, hostdata->phase);
  35577. +        acornscsi_startabort (instance);
  35578. +        return INTR_CONNECTED;
  35579. +    }
  35580. +    SCpnt = hostdata->connected->cmd;
  35581. +
  35582. +    sbic_write (instance, TRANSCNTL, SCpnt->cmd_len);
  35583. +    sbic_write (instance, TRANSCNTM, 0);
  35584. +    sbic_write (instance, TRANSCNTH, 0);
  35585. +    sbic_write (instance, CMND, CMND_XFERINFO);
  35586. +
  35587. +    for (i = 0; i < SCpnt->cmd_len; i++) {
  35588. +        int asr;
  35589. +        do {
  35590. +        asr = sbic_read (instance, ASR) & (ASR_INT | ASR_BSY | ASR_DBR);
  35591. +        } while (asr == ASR_BSY);
  35592. +        if (!(asr & ASR_DBR)) {
  35593. +        printk ("scsi%d : warning: interrupt while sending command\n",
  35594. +            instance->host_no);
  35595. +        return INTR_CONNECTED;
  35596. +        }
  35597. +        sbic_write (instance, DATA, SCpnt->cmnd[i]);
  35598. +    }
  35599. +    hostdata->phase = PHASE_COMMANDSENT;
  35600. +        
  35601. +    return INTR_CONNECTED;
  35602. +    }
  35603. +
  35604. +/* ---------------------- status in ---------------------------------------------------- */
  35605. +
  35606. +    case 0x1b: /* transfer completed - status phase in */
  35607. +    case 0x8b: /* connection - status phase in [only after reconnection] */
  35608. +    switch (hostdata->phase) {
  35609. +    case PHASE_RECONNECTED:
  35610. +        if (ssr == 0x8b)
  35611. +        break;
  35612. +        goto complain_status_in;
  35613. +
  35614. +    case PHASE_COMMANDSENT:
  35615. +    case PHASE_DATAIN:
  35616. +    case PHASE_DATAOUT:
  35617. +        if (ssr == 0x1b)
  35618. +        break;
  35619. +
  35620. +    complain_status_in:
  35621. +    default:
  35622. +        printk ("scsi%d : warning: invalid phase (%02X) in status in (%02X)\n",
  35623. +        instance->host_no, hostdata->phase, ssr);
  35624. +        acornscsi_printstatus (instance);
  35625. +        acornscsi_startabort (instance);
  35626. +        return INTR_CONNECTED;
  35627. +    }
  35628. +    sbic_write (instance, CMND, CMND_XFERINFO|CMND_SBT);
  35629. +    while ((sbic_read (instance, ASR) & ASR_DBR) == 0);
  35630. +    hostdata->connected->cmd->SCp.Status = sbic_read (instance, DATA);
  35631. +    hostdata->phase = PHASE_STATUSIN;
  35632. +    return INTR_CONNECTED;
  35633. +
  35634. +    case 0x4b: { /* unexpected status info */
  35635. +    short residual;
  35636. +
  35637. +    dmac_write (instance, MASKREG, MASK_ON);
  35638. +    residual = ((dmac_read (instance, TXCNTHI) << 8) | dmac_read (instance, TXCNTLO)) + 1;
  35639. +
  35640. +    sbic_write (instance, TRANSCNTH, 0);
  35641. +    sbic_write (instance, TRANSCNTM, 0);
  35642. +    sbic_write (instance, TRANSCNTL, 0);
  35643. +
  35644. +    switch (hostdata->phase) {
  35645. +    case PHASE_DATAIN:
  35646. +        acornscsi_readtobh (instance, hostdata, ascmd, residual);
  35647. +        break;
  35648. +
  35649. +    case PHASE_DATAOUT:
  35650. +    case PHASE_COMMAND:
  35651. +    case PHASE_COMMANDSENT:
  35652. +        break;
  35653. +
  35654. +    default:
  35655. +        printk ("scsi%d : warning: invalid phase in unexpected status in (%X)\n",
  35656. +        instance->host_no, hostdata->phase);
  35657. +        acornscsi_printstatus (instance);
  35658. +        return INTR_CONNECTED;
  35659. +    }
  35660. +
  35661. +    sbic_write (instance, CMND, CMND_XFERINFO|CMND_SBT);
  35662. +    while ((sbic_read (instance, ASR) & ASR_DBR) == 0);
  35663. +    hostdata->connected->cmd->SCp.Status = sbic_read (instance, DATA);
  35664. +    hostdata->phase = PHASE_STATUSIN;
  35665. +
  35666. +    return INTR_CONNECTED;
  35667. +    }
  35668. +
  35669. +/* ---------------------- message out -------------------------------------------------- */
  35670. +
  35671. +    case 0x8e: /* connection - message out phase [only after reconnection] */
  35672. +    switch (hostdata->phase) {
  35673. +    case PHASE_CONNECTED:
  35674. +#ifdef SCSI2_TAG
  35675. +        if (ascmd->cmd->device->tagged_queue) {
  35676. +        int i;
  35677. +        sbic_write (instance, TRANSCNTL, 3);
  35678. +        sbic_write (instance, TRANSCNTM, 0);
  35679. +        sbic_write (instance, TRANSCNTH, 0);
  35680. +        sbic_write (instance, CMND, CMND_XFERINFO);
  35681. +        if (ascmd->cmd->device->tagged_queue)
  35682. +            hostdata->last_message = SIMPLE_QUEUE_TAG;
  35683. +        for (i = 0; i < 3; i++) {
  35684. +            do {
  35685. +            asr = sbic_read (instance, ASR) & (ASR_INT | ASR_BSY | ASR_DBR);
  35686. +            } while (asr == ASR_BSY);
  35687. +            if (!(asr & ASR_DBR)) {
  35688. +            printk ("scsi%d : warning: interrupt while sending tag\n",
  35689. +                instance->host_no);
  35690. +            return INTR_CONNECTED;
  35691. +            }
  35692. +            switch (i) {
  35693. +            case 0:
  35694. +            sbic_write (instance, DATA, IDENTIFY(1, hostdata->connected->cmd->lun));
  35695. +            break;
  35696. +            case 1:
  35697. +            sbic_write (instance, DATA, SIMPLE_QUEUE_TAG);
  35698. +            break;
  35699. +            case 2:
  35700. +            sbic_write (instance, DATA, hostdata->connected->cmd->tag);
  35701. +            break;
  35702. +            }
  35703. +        }
  35704. +        } else
  35705. +#endif
  35706. +        {
  35707. +        sbic_write (instance, CMND, CMND_XFERINFO|CMND_SBT);
  35708. +        while ((sbic_read (instance, ASR) & ASR_DBR) == 0);
  35709. +        sbic_write (instance, DATA, IDENTIFY(1, hostdata->connected->cmd->lun));
  35710. +        }
  35711. +        hostdata->phase = PHASE_COMMAND;
  35712. +        return INTR_CONNECTED;
  35713. +
  35714. +    case PHASE_CONNECTED_FOR_ABORT:
  35715. +        sbic_write (instance, CMND, CMND_XFERINFO|CMND_SBT);
  35716. +        while ((sbic_read (instance, ASR) & ASR_DBR) == 0);
  35717. +        sbic_write (instance, DATA, ABORT);
  35718. +        hostdata->last_message = ABORT;
  35719. +        return INTR_CONNECTED;
  35720. +
  35721. +    default:
  35722. +        printk ("scsi%d : warning: invalid phase in message out (%X)\n",
  35723. +        instance->host_no, hostdata->phase);
  35724. +        acornscsi_printstatus (instance);
  35725. +        return INTR_CONNECTED;
  35726. +    }
  35727. +
  35728. +/* ---------------------- message in --------------------------------------------------- */
  35729. +
  35730. +    case 0x1f: /* transfer completed - message in phase */
  35731. +    case 0x4f: /* transfer terminated - message in phase */
  35732. +    case 0x8f: /* connection - message in phase [only after reconnection] [???] */
  35733. +    hostdata->tmpsbiclen = sbic_read (instance, TRANSCNTL) |
  35734. +                  (sbic_read (instance, TRANSCNTM) << 8) |
  35735. +                  (sbic_read (instance, TRANSCNTH) << 16);
  35736. +    switch (hostdata->phase) {
  35737. +    case PHASE_STATUSIN:
  35738. +    case PHASE_DATAIN:
  35739. +    case PHASE_DATAOUT:
  35740. +        break;
  35741. +
  35742. +    case PHASE_COMMANDSENT:
  35743. +        if (ssr == 0x1f || ssr == 0x4f)
  35744. +        break;
  35745. +        goto complain_msg_in;
  35746. +
  35747. +    case PHASE_RECONNECTED:
  35748. +        if (ssr == 0x8f)
  35749. +            break;
  35750. +
  35751. +    default:
  35752. +    complain_msg_in:
  35753. +        /* just complain - accept message in anyway otherwise host will hang until reset */
  35754. +        printk ("scsi%d : warning: invalid phase (%02X) in message in (%02X)\n",
  35755. +        instance->host_no, hostdata->phase, ssr);
  35756. +        acornscsi_printstatus (instance);
  35757. +    }
  35758. +    sbic_write (instance, CMND, CMND_XFERINFO|CMND_SBT);
  35759. +    while ((sbic_read (instance, ASR) & ASR_DBR) == 0);
  35760. +    hostdata->connected->cmd->SCp.Message = sbic_read (instance, DATA);
  35761. +    return INTR_CONNECTED;
  35762. +
  35763. +    case 0x20: {/* message in transfer paused */
  35764. +    int message = hostdata->connected->cmd->SCp.Message;
  35765. +#if 0
  35766. +printk ("scsi%d :  debug : message received:", instance->host_no);
  35767. +print_msg ((unsigned char *)&hostdata->connected->cmd->SCp.Message);
  35768. +printk ("\n");
  35769. +#endif
  35770. +    switch (message) {
  35771. +    case COMMAND_COMPLETE:
  35772. +        sbic_write (instance, CMND, CMND_NEGATEACK);
  35773. +        hostdata->phase = PHASE_FINISHED;
  35774. +        return INTR_CONNECTED;
  35775. +
  35776. +    case SAVE_POINTERS:
  35777. +        sbic_write (instance, CMND, CMND_NEGATEACK);
  35778. +        acornscsi_savepointers (instance, hostdata);
  35779. +        break;
  35780. +
  35781. +    case RESTORE_POINTERS:
  35782. +        sbic_write (instance, CMND, CMND_NEGATEACK);
  35783. +        break;
  35784. +
  35785. +    case DISCONNECT:
  35786. +        sbic_write (instance, CMND, CMND_NEGATEACK);
  35787. +        /* If the device has not issued a 'save pointers' message, do it. */
  35788. +        if (!hostdata->connected->saved)
  35789. +        acornscsi_savepointers (instance, hostdata);
  35790. +        hostdata->phase = PHASE_DISCONNECTING;
  35791. +        return INTR_CONNECTED;
  35792. +
  35793. +    case LINKED_CMD_COMPLETE:
  35794. +    case LINKED_FLG_CMD_COMPLETE:
  35795. +#ifdef SCSI2_LINK
  35796. +        /*
  35797. +         * We don't support linked commands yet
  35798. +         */
  35799. +        if (0) {
  35800. +#if (DEBUG & DEBUG_LINKED)
  35801. +        printk ("scsi%d : target %d lun %d tag %d linked command complete\n",
  35802. +            instance->host_no, ascmd->connected->target, ascmd->connected->tag);
  35803. +#endif
  35804. +        /*
  35805. +         * A linked command should only terminate with one of these messages
  35806. +         * if there are more linked commands available.
  35807. +         */
  35808. +        if (!ascmd->cmd->next_link) {
  35809. +            printk ("scsi%d : warning: target %d lun %d tag %d linked command complete, but no next_link\n",
  35810. +            instance->host_no, ascmd->connected->target, ascmd->connected->tag);
  35811. +            hostdata->msgout = ABORT;
  35812. +            goto go_msg_out;
  35813. +        }
  35814. +        sbic_write (instance, CMND, CMND_NEGATEACK);
  35815. +
  35816. +        ascmd->cmd->next_link->tag = ascmd->cmd->tag;
  35817. +        /* scsi_done */
  35818. +        hostdata->connected->cmd = ascmd->cmd->next_link;
  35819. +        break;
  35820. +        }
  35821. +#endif
  35822. +        goto reject;
  35823. +
  35824. +    case MESSAGE_REJECT:
  35825. +        sbic_write (instance, CMND, CMND_NEGATEACK);
  35826. +        switch (hostdata->last_message) {
  35827. +#ifdef SCSI2_TAG
  35828. +        case HEAD_OF_QUEUE_TAG:
  35829. +        case ORDERED_QUEUE_TAG:
  35830. +        case SIMPLE_QUEUE_TAG:
  35831. +        ascmd->cmd->device->tagged_queue = 0;
  35832. +        set_bit (ascmd->cmd->lun, &hostdata->dev[ascmd->cmd->target].busy);
  35833. +        printk ("scsi%d : disabling tagged queueing for target %d\n",
  35834. +            instance->host_no, ascmd->cmd->target);
  35835. +        break;
  35836. +#endif
  35837. +        default:
  35838. +            break;
  35839. +        }
  35840. +
  35841. +    default: /* reject message */
  35842. +    reject:
  35843. +        hostdata->msgout = MESSAGE_REJECT;
  35844. +        sbic_write (instance, CMND, CMND_ASSERTATN);
  35845. +        while (sbic_read (instance, ASR) & ASR_BSY);
  35846. +        if (!(sbic_read (instance, ASR) & ASR_INT)) {
  35847. +        sbic_write (instance, CMND, CMND_NEGATEACK);
  35848. +        }
  35849. +        break;
  35850. +    }
  35851. +    }
  35852. +    return INTR_CONNECTED;
  35853. +
  35854. +    default:
  35855. +    printk ("scsi%d : unknown interrupt number %02X\n", instance->host_no, ssr);
  35856. +    acornscsi_printstatus (instance);
  35857. +    return INTR_CONTINUE;
  35858. +    }
  35859. +}
  35860. +
  35861. +static void acornscsi_intr(int irq, struct pt_regs *regs)
  35862. +{
  35863. +    struct Scsi_Host *instance;
  35864. +    int need_command, need_command_done;
  35865. +
  35866. +    do {
  35867. +        need_command_done = 0;
  35868. +    for (instance = first_instance; instance && (instance->hostt == the_template);
  35869. +        instance = instance->next) {
  35870. +        if (instance->irq != irq)
  35871. +            continue;
  35872. +
  35873. +        need_command = 0;
  35874. +
  35875. +        if (read_irqstat(instance) & 2)
  35876. +        /* setup for next buffer & transfer current buffer */
  35877. +        if (acornscsi_handletransfer(instance))
  35878. +            continue;
  35879. +
  35880. +        if (read_irqstat(instance) & 8)
  35881. +            switch (acornscsi_sbicintr (instance)) {
  35882. +        case INTR_NOTCONNECTED:
  35883. +            need_command = 1;
  35884. +            break;
  35885. +        case INTR_CONNECTED:
  35886. +            need_command_done = 1;
  35887. +            break;
  35888. +        }
  35889. +        if (need_command) {
  35890. +            acornscsi_startsendcommand (instance);
  35891. +            need_command_done = 1;
  35892. +        }
  35893. +    }
  35894. +    }
  35895. +    while(need_command_done);
  35896. +}
  35897. +
  35898. +/*=============================================================================================
  35899. + * Interfaces between interrupt handler and rest of scsi code
  35900. + */
  35901. +
  35902. +/*
  35903. + * Function : acornscsi_queuecmd (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
  35904. + *
  35905. + * Purpose  : queues a SCSI command
  35906. + *
  35907. + * Params   : cmd  - SCSI command
  35908. + *            done - function called on completion, with pointer to command descriptor
  35909. + *
  35910. + * Returns  : 0
  35911. + *
  35912. + */
  35913. +int acornscsi_queuecmd (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
  35914. +{
  35915. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *)cmd->host->hostdata;
  35916. +    struct as_cmnd *as_cmd;
  35917. +    int i;
  35918. +#if (DEBUG & DEBUG_QUEUES)
  35919. +    const char *where;
  35920. +#endif
  35921. +
  35922. +    if (!done) {
  35923. +        /* there should be some way of rejecting errors like this without panicing... */
  35924. +    panic ("scsi%d :  fatal : queuecommand called with NULL done function [cmd=%p]\n",
  35925. +        cmd->host->host_no, cmd);
  35926. +    return -EINVAL;
  35927. +    }
  35928. +
  35929. +#if (DEBUG & DEBUG_NO_WRITE)
  35930. +    if (acornscsi_cmdtype (cmd->cmnd[0]) == CMD_WRITE) {
  35931. +    printk ("scsi%d : id %d: WRITE attempted with NO_WRITE flag set\n",
  35932. +        cmd->host->host_no, cmd->target);
  35933. +    cmd->result = DID_ERROR << 16;
  35934. +    done (cmd);
  35935. +    return 0;
  35936. +    }
  35937. +#endif
  35938. +
  35939. +    cmd->host_scribble = NULL;
  35940. +    cmd->scsi_done = done;
  35941. +    cmd->result = 0;
  35942. +    cmd->SCpdirection = acornscsi_writedirection (cmd->cmnd[0]);
  35943. +
  35944. +    acornscsi_initialisebuffer (cmd);
  35945. +
  35946. +    cmd->tag = 0;
  35947. +
  35948. +    for (i = 0, as_cmd = hostdata->queuedcommands; i < CAN_QUEUE; i++, as_cmd ++) {
  35949. +    if (set_bit (0, (void *)&as_cmd->used) == 0) {
  35950. +        if (as_cmd->cmd) {
  35951. +        printk ("scsi%d : warning: free command found wasn't free\n",
  35952. +            cmd->host->host_no);
  35953. +        continue;
  35954. +        }
  35955. +        as_cmd->cmd = cmd;
  35956. +
  35957. +        if (cmd->cmnd[0] == REQUEST_SENSE) {
  35958. +        cli ();
  35959. +        as_cmd->next = hostdata->dev[cmd->target].issue_head;
  35960. +        hostdata->dev[cmd->target].issue_head = as_cmd;
  35961. +        sti ();
  35962. +#if (DEBUG & DEBUG_QUEUES)
  35963. +        where = "head";
  35964. +#endif
  35965. +        } else {
  35966. +        cli ();
  35967. +        as_cmd->next = NULL;
  35968. +        if (hostdata->dev[cmd->target].issue_head == NULL)
  35969. +            hostdata->dev[cmd->target].issue_head = as_cmd;
  35970. +        if (hostdata->dev[cmd->target].issue_tail)
  35971. +            hostdata->dev[cmd->target].issue_tail->next = as_cmd;
  35972. +        hostdata->dev[cmd->target].issue_tail = as_cmd;
  35973. +        sti ();
  35974. +#if (DEBUG & DEBUG_QUEUES)
  35975. +        where = "tail";
  35976. +#endif
  35977. +        }
  35978. +        hostdata->stats.queues += 1;
  35979. +#if (DEBUG & DEBUG_QUEUES)
  35980. +        printk ("scsi%d :  debug : command put on %s of queue for target %d\n",
  35981. +            cmd->host->host_no, where, cmd->target);
  35982. +#endif
  35983. +        as_cmd->buffer = 2;
  35984. +        as_cmd->totallen = cmd->request_bufflen;
  35985. +        as_cmd->queued_jiffies = jiffies;
  35986. +        acornscsi_startsendcommand (cmd->host);
  35987. +        return 0;
  35988. +    }
  35989. +    }
  35990. +
  35991. +    printk ("scsi%d :  error : could not find a free slot for command?\n", cmd->host->host_no);
  35992. +
  35993. +    cmd->result = DID_ERROR << 16;
  35994. +    done (cmd);
  35995. +    return -1;
  35996. +}
  35997. +
  35998. +int acornscsi_abort(Scsi_Cmnd * cmd)
  35999. +{
  36000. +    struct Scsi_Host *instance = cmd->host;
  36001. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *) instance->hostdata;
  36002. +    struct as_cmnd *ascmd, *asprev;
  36003. +
  36004. +    hostdata->stats.aborts += 1;
  36005. +
  36006. +    printk("acornscsi_abort: ");
  36007. +    print_sbic_status(sbic_read (instance, ASR), sbic_read (instance, SSR),
  36008. +            sbic_read (instance, CMNDPHASE));
  36009. +
  36010. +    /*
  36011. +     * Check to see if the command hasn't been issued.  If so, just remove it from the queue.
  36012. +     */
  36013. +    for (ascmd = hostdata->dev[cmd->target].issue_head, asprev = NULL; ascmd;
  36014. +        asprev = ascmd, ascmd = ascmd->next) {
  36015. +
  36016. +    if (ascmd->cmd == cmd) {
  36017. +        if (ascmd == hostdata->dev[cmd->target].issue_tail)
  36018. +        hostdata->dev[cmd->target].issue_tail = asprev;
  36019. +        if (asprev)
  36020. +            asprev->next = ascmd->next;
  36021. +        else
  36022. +            hostdata->dev[cmd->target].issue_head = ascmd->next;
  36023. +            ascmd->next = NULL;
  36024. +        sti();
  36025. +
  36026. +        ascmd->cmd->result = DID_ABORT << 16;
  36027. +#if (DEBUG & DEBUG_ABORT)
  36028. +        printk("scsi%d : abort removed command from issue queue\n", instance->host_no);
  36029. +#endif
  36030. +        acornscsi_done (instance, ascmd);
  36031. +        return SCSI_ABORT_SUCCESS;
  36032. +    }
  36033. +    }
  36034. +
  36035. +    /*
  36036. +     * If the command is connected, try to abort it
  36037. +     */
  36038. +    if (hostdata->connected && hostdata->connected->cmd == cmd) {
  36039. +    sti();
  36040. +#if (DEBUG & DEBUG_ABORT)
  36041. +    printk("scsi%d : aborting connected command\n", instance->host_no);
  36042. +#endif
  36043. +    hostdata->connected->cmd->result = DID_ABORT << 16; /* Hmm... doesn't seem to work.. */
  36044. +    sbic_write (instance, CMND, CMND_ASSERTATN); /* DISCONNECT? */
  36045. +    return SCSI_ABORT_PENDING;
  36046. +    }
  36047. +
  36048. +#if 0 /* we can now schedule an abort of a command while one is executing */
  36049. +    /*
  36050. +     * If a command is connected, we can't do anything to abort it at the moment.
  36051. +     */
  36052. +    if (hostdata->connected) {
  36053. +    sti();
  36054. +#if (DEBUG & DEBUG_ABORT)
  36055. +    printk("scsi%d : abort failed, command connected\n", instance->host_no);
  36056. +#endif
  36057. +    return SCSI_ABORT_BUSY;
  36058. +    }
  36059. +#endif
  36060. +
  36061. +    /*
  36062. +     * If the command is disconnected, and there are no connected commands, reconnect
  36063. +     * and send abort message
  36064. +     */
  36065. +    for (ascmd = hostdata->dev[cmd->target].disconnected, asprev = NULL; asprev;
  36066. +        asprev = ascmd, ascmd = ascmd->next) {
  36067. +    if (ascmd->cmd == cmd) {
  36068. +#if (DEBUG & DEBUG_ABORT)
  36069. +        printk("scsi%d : aborting disconnected command\n", instance->host_no);
  36070. +#endif
  36071. +        if (asprev)
  36072. +        asprev->next = ascmd->next;
  36073. +        else
  36074. +            hostdata->dev[cmd->target].disconnected = ascmd->next;
  36075. +        ascmd->next = NULL;
  36076. +
  36077. +        hostdata->aborting = ascmd;
  36078. +        sti ();
  36079. +
  36080. +        acornscsi_startsendcommand (instance);
  36081. +        return SCSI_ABORT_PENDING;
  36082. +    }
  36083. +    }
  36084. +
  36085. +    sti();
  36086. +    printk ("scsi%d : warning: SCSI command probably completed successfully before abortion\n",
  36087. +            instance->host_no);
  36088. +while (1);
  36089. +    return SCSI_ABORT_NOT_RUNNING;
  36090. +}
  36091. +
  36092. +int acornscsi_reset(Scsi_Cmnd * cmd)
  36093. +{
  36094. +    struct Scsi_Host *instance = cmd->host;
  36095. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *)instance->hostdata;
  36096. +    
  36097. +    hostdata->stats.resets += 1;
  36098. +
  36099. +    printk("acornscsi_reset:\n");
  36100. +    print_sbic_status(sbic_read (instance, ASR), sbic_read (instance, SSR), sbic_read (instance, CMNDPHASE));
  36101. +    hostdata->connected = NULL;
  36102. +    sbic_reset(instance);
  36103. +#if 0
  36104. +    cmd->result = DID_RESET << 16;
  36105. +    acornscsi_done (instance, cmd);
  36106. +#endif
  36107. +    return SCSI_RESET_SUCCESS;
  36108. +}
  36109. +
  36110. +/*==============================================================================================
  36111. + * initialisation & miscellaneous support
  36112. + */
  36113. +static struct expansion_card *ecs[4];
  36114. +
  36115. +static void acornscsi_init (struct Scsi_Host *instance)
  36116. +{
  36117. +    struct acornscsi_hostdata *hostdata = (struct acornscsi_hostdata *) instance->hostdata;
  36118. +    int i;
  36119. +
  36120. +    hostdata->busy = 0;
  36121. +    hostdata->phase = 0;
  36122. +    hostdata->page_reg = 0x40;
  36123. +    hostdata->connecting = NULL;
  36124. +    hostdata->aborting = NULL;
  36125. +    hostdata->connected = NULL;
  36126. +
  36127. +    for (i = 0; i < CAN_QUEUE; i++) {
  36128. +    hostdata->queuedcommands[i].used     = 0;
  36129. +    hostdata->queuedcommands[i].cmd      = NULL;
  36130. +    hostdata->queuedcommands[i].next     = NULL;
  36131. +    hostdata->queuedcommands[i].buf0addr = i * 0x2000;
  36132. +    hostdata->queuedcommands[i].buf1addr = i * 0x2000 + 0x1000;
  36133. +    hostdata->queuedcommands[i].buf0len  = 0;
  36134. +    hostdata->queuedcommands[i].buf1len  = 0;
  36135. +    }
  36136. +
  36137. +    for (i = 0; i < 8; i++) {
  36138. +        hostdata->dev[i].issue_head   = NULL;
  36139. +        hostdata->dev[i].issue_tail   = NULL;
  36140. +        hostdata->dev[i].disconnected = NULL;
  36141. +        hostdata->dev[i].busy = 0;
  36142. +    }
  36143. +
  36144. +    hostdata->stats.queues = 0;
  36145. +    hostdata->stats.removes= 0;
  36146. +    hostdata->stats.fins   = 0;
  36147. +    hostdata->stats.reads  = 0;
  36148. +    hostdata->stats.writes = 0;
  36149. +    hostdata->stats.aborts = 0;
  36150. +    hostdata->stats.resets = 0;
  36151. +    hostdata->stats.disconnects = 0;
  36152. +
  36153. +    page_write(instance, 0x40);
  36154. +
  36155. +    if (!the_template)
  36156. +    {
  36157. +    the_template = instance->hostt;
  36158. +    first_instance = instance;
  36159. +    }
  36160. +
  36161. +    /* setup sbic - WD33C93A */
  36162. +    sbic_reset(instance);
  36163. +
  36164. +    /* setup dmac - uPC71071 */
  36165. +    dmac_write (instance, INIT, 0);
  36166. +    dmac_write (instance, INIT, INIT_8BIT);
  36167. +    dmac_write (instance, CHANNEL, CHANNEL_0);
  36168. +    dmac_write (instance, DEVCON0, INIT_DEVCON0);
  36169. +    dmac_write (instance, DEVCON1, INIT_DEVCON1);
  36170. +}
  36171. +
  36172. +int acornscsi_detect(Scsi_Host_Template * tpnt)
  36173. +{
  36174. +    static int acornscsi_prods[] = { PRODS };
  36175. +    static int acornscsi_manus[] = { MANUS };
  36176. +    int i, count = 0;
  36177. +    struct Scsi_Host *instance;
  36178. +
  36179. +    tpnt->proc_dir = &proc_scsi_acornscsi;
  36180. +
  36181. +    for (i = 0; i < 4; i++)
  36182. +        ecs[i] = NULL;
  36183. +
  36184. +    while(1) {
  36185. +    ecs[count] = ecard_find(0, sizeof(acornscsi_prods), acornscsi_prods, acornscsi_manus);
  36186. +    if(!ecs[count])
  36187. +        break;
  36188. +
  36189. +    instance = scsi_register (tpnt, sizeof(struct acornscsi_hostdata));
  36190. +    instance->io_port = ((int)ecs[count]->r_podaddr & ~0x003C0000) >> 2;
  36191. +    instance->irq = ecs[count]->irq;
  36192. +
  36193. +    if (instance->irq != 0xff) {
  36194. +        if (request_irq(instance->irq, acornscsi_intr, SA_INTERRUPT, "acorn scsi"))
  36195. +        {
  36196. +        printk("scsi%d : IRQ%d not free, interrupts disabled\n",
  36197. +            instance->host_no, instance->irq);
  36198. +        instance->irq = 0xff;
  36199. +        }
  36200. +    }
  36201. +    if (instance->irq == 0xff) {
  36202. +        printk("scsi%d : interrupts not enabled. For better interactive performance,\n",
  36203. +        instance->host_no);
  36204. +        printk("scsi%d : please find out why I cannot get the interrupt.\n",
  36205. +        instance->host_no);
  36206. +    }
  36207. +
  36208. +    ecard_claim(ecs[count]); /* Must claim here - card produces irq on reset */
  36209. +    acornscsi_init(instance);
  36210. +
  36211. +    ++count;
  36212. +    }
  36213. +    return count;
  36214. +}
  36215. +
  36216. +const char *acornscsi_info(struct Scsi_Host *host)
  36217. +{
  36218. +    static char string[100], *p;
  36219. +
  36220. +    p = string;
  36221. +    
  36222. +    p += sprintf (string, "%s at port %X irq", host->hostt->name, host->io_port);
  36223. +    if (host->irq == 0xff)
  36224. +    p += sprintf (p, "s disabled");
  36225. +    else
  36226. +    p += sprintf (p, " %d", host->irq);
  36227. +    sprintf (p, " version %d.%02d", VER_MAJOR, VER_MINOR);
  36228. +
  36229. +    return string;
  36230. +}
  36231. +
  36232. +int acornscsi_proc_info(char *buffer, char **start, off_t offset,
  36233. +            int length, int host_no, int inout)
  36234. +{
  36235. +    int len, pos, begin, first;
  36236. +    struct Scsi_Host *host = scsi_hostlist;
  36237. +    struct acornscsi_hostdata *hostdata;
  36238. +    Scsi_Device *scd;
  36239. +
  36240. +    while (host) {
  36241. +    if (host->host_no == host_no)
  36242. +        break;
  36243. +    host = host->next;
  36244. +    }
  36245. +
  36246. +    hostdata  = (struct acornscsi_hostdata *) host->hostdata;
  36247. +    
  36248. +    if (inout == 1)
  36249. +    return -EINVAL;
  36250. +
  36251. +    begin = 0;
  36252. +    pos = sprintf(buffer,
  36253. +            "Acorn SCSI driver version %d.%02d\n", VER_MAJOR, VER_MINOR);
  36254. +
  36255. +    len = sprintf(buffer+pos,
  36256. +                "Address: %08X          IRQ : %d\n"
  36257. +                "SBIC   : WD33C93           DMAC: uPC71071\n\n"
  36258. +            "Statistics:\n", host->io_port, host->irq);
  36259. +    pos += len;
  36260. +    
  36261. +    len = sprintf(buffer+pos,
  36262. +            "Queued commands: %ld\n"
  36263. +            "Issued commands: %ld\n"
  36264. +            "Done commands  : %ld\n"
  36265. +            "Reads          : %ld\n"
  36266. +            "Writes         : %ld\n"
  36267. +            "Others         : %ld\n"
  36268. +            "Disconnects    : %ld\n"
  36269. +            "Aborts         : %ld\n"
  36270. +            "Resets         : %ld\n",
  36271. +                hostdata->stats.queues,
  36272. +                hostdata->stats.removes,
  36273. +                hostdata->stats.fins,
  36274. +                hostdata->stats.reads,
  36275. +                hostdata->stats.writes,
  36276. +                hostdata->stats.miscs,
  36277. +                hostdata->stats.disconnects,
  36278. +                hostdata->stats.aborts,
  36279. +                hostdata->stats.resets);
  36280. +    pos += len;
  36281. +
  36282. +    scd = scsi_devices;
  36283. +
  36284. +    first = 1;
  36285. +    
  36286. +    while (scd) {
  36287. +    if (scd->host == host) {
  36288. +            if (first) {
  36289. +        len = sprintf(buffer+pos,
  36290. +                "\nAttached devices:\n");
  36291. +        pos += len;
  36292. +        first = 0;
  36293. +        }
  36294. +
  36295. +        proc_print_scsidevice(scd, buffer, &len, pos);
  36296. +        pos += len;
  36297. +        pos += sprintf (buffer+pos, "Extensions: ");
  36298. +        if (scd->tagged_supported)
  36299. +        pos += sprintf (buffer+pos, "TAG %sabled [%d] ",
  36300. +            scd->tagged_queue ? "en" : "dis", scd->current_tag);
  36301. +        pos += sprintf (buffer+pos, "\n");
  36302. +
  36303. +        if (pos + begin < offset) {
  36304. +            begin += pos;
  36305. +            pos = 0;
  36306. +        }
  36307. +        if (pos + begin > offset + length)
  36308. +            break;
  36309. +    }
  36310. +    scd = scd->next;
  36311. +    }
  36312. +
  36313. +    if (first) {
  36314. +    len = sprintf(buffer+pos,
  36315. +             "Attached devices: none\n");
  36316. +     pos += len;
  36317. +    }
  36318. +    
  36319. +    *start = buffer + (offset - begin);
  36320. +    pos -= offset - begin;
  36321. +    if (pos > length)
  36322. +    pos = length;
  36323. +
  36324. +    return pos;
  36325. +}
  36326. +
  36327. +#include "sd.h"
  36328. +#include "scsi_ioctl.h"
  36329. +
  36330. +int acornscsi_biosparam (Scsi_Disk *disk, kdev_t dev, int info_array[])
  36331. +{
  36332. +    info_array[0] = 16;
  36333. +    info_array[1] = 63;
  36334. +    info_array[2] = 2112;
  36335. +
  36336. +    return 0;
  36337. +}
  36338. +#ifdef MODULE
  36339. +
  36340. +Scsi_Host_Template driver_template = ACORNSCSI_3;
  36341. +
  36342. +#define SCSI_CLEANUP \
  36343. +    { int i; for (i = 0; i<4; i++) if (ecs[i]) ecard_release(ecs[i]); }
  36344. +
  36345. +#include "scsi_module.c"
  36346. +#endif
  36347. diff -urNwbB linux/arch/arm/drivers/scsi/acornscsi.h linux.arm/arch/arm/drivers/scsi/acornscsi.h
  36348. --- linux/arch/arm/drivers/scsi/acornscsi.h    Thu Jan  1 01:00:00 1970
  36349. +++ linux.arm/arch/arm/drivers/scsi/acornscsi.h    Sun Feb 25 13:45:55 1996
  36350. @@ -0,0 +1,306 @@
  36351. +#ifndef ACORNSCSI_H
  36352. +#define ACORNSCSI_H
  36353. +
  36354. +#ifndef ASM
  36355. +extern int acornscsi_detect (Scsi_Host_Template *);
  36356. +extern const char *acornscsi_info (struct Scsi_Host *);
  36357. +extern int acornscsi_queuecmd (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
  36358. +extern int acornscsi_abort (Scsi_Cmnd *);
  36359. +extern int acornscsi_reset (Scsi_Cmnd *);
  36360. +extern int acornscsi_proc_info (char *, char **, off_t, int, int, int);
  36361. +extern int acornscsi_biosparam (Disk *, kdev_t, int []);
  36362. +
  36363. +#ifndef NULL
  36364. +#define NULL 0
  36365. +#endif
  36366. +
  36367. +#ifndef CMD_PER_LUN
  36368. +#define CMD_PER_LUN 2
  36369. +#endif
  36370. +
  36371. +#ifndef CAN_QUEUE
  36372. +#define CAN_QUEUE 16
  36373. +#endif
  36374. +
  36375. +#ifndef PROC_SCSI_AKA30
  36376. +#include "linux/proc_fs.h"
  36377. +#define PROC_SCSI_AKA30 PROC_SCSI_EATA
  36378. +#endif
  36379. +
  36380. +#define ACORNSCSI_3 \
  36381. +    { \
  36382. +    NULL, \
  36383. +    NULL, \
  36384. +    NULL, \
  36385. +    acornscsi_proc_info, \
  36386. +    "Acorn 16-bit SCSI", \
  36387. +    acornscsi_detect, \
  36388. +    NULL, \
  36389. +    acornscsi_info, \
  36390. +    NULL, \
  36391. +    acornscsi_queuecmd, \
  36392. +    acornscsi_abort, \
  36393. +    acornscsi_reset, \
  36394. +    NULL, \
  36395. +    acornscsi_biosparam, \
  36396. +    CAN_QUEUE, \
  36397. +    7, \
  36398. +    SG_ALL, \
  36399. +    CMD_PER_LUN, \
  36400. +    0, \
  36401. +    0, \
  36402. +    DISABLE_CLUSTERING \
  36403. +    }
  36404. +
  36405. +#ifndef HOSTS_C
  36406. +
  36407. +/* SBIC registers */
  36408. +#define OWNID            0
  36409. +#define OWNID_FS1        (1<<7)
  36410. +#define OWNID_FS2        (1<<6)
  36411. +#define OWNID_EHP        (1<<4)
  36412. +#define OWNID_EAF        (1<<3)
  36413. +
  36414. +#define CTRL            1
  36415. +#define CTRL_DMAMODE        (1<<7)
  36416. +#define CTRL_DMADBAMODE        (1<<6)
  36417. +#define CTRL_DMABURST        (1<<5)
  36418. +#define CTRL_DMAPOLLED        0
  36419. +#define CTRL_HHP        (1<<4)
  36420. +#define CTRL_EDI        (1<<3)
  36421. +#define CTRL_IDI        (1<<2)
  36422. +#define CTRL_HA            (1<<1)
  36423. +#define CTRL_HSP        (1<<0)
  36424. +
  36425. +#define TIMEOUT            2
  36426. +#define TOTSECTS        3
  36427. +#define TOTHEADS        4
  36428. +#define TOTCYLH            5
  36429. +#define TOTCYLL            6
  36430. +#define LOGADDRH        7
  36431. +#define LOGADDRM2        8
  36432. +#define LOGADDRM1        9
  36433. +#define LOGADDRL        10
  36434. +#define SECTORNUM        11
  36435. +#define HEADNUM            12
  36436. +#define CYLH            13
  36437. +#define CYLL            14
  36438. +#define TARGETLUN        15
  36439. +#define TARGETLUN_TLV        (1<<7)
  36440. +#define TARGETLUN_DOK        (1<<6)
  36441. +
  36442. +#define CMNDPHASE        16
  36443. +#define SYNCHTRANSFER        17
  36444. +#define SYNCHTRANSFER_OF0    0x00
  36445. +#define SYNCHTRANSFER_OF1    0x01
  36446. +#define SYNCHTRANSFER_OF2    0x02
  36447. +#define SYNCHTRANSFER_OF3    0x03
  36448. +#define SYNCHTRANSFER_OF4    0x04
  36449. +#define SYNCHTRANSFER_OF5    0x05
  36450. +#define SYNCHTRANSFER_OF6    0x06
  36451. +#define SYNCHTRANSFER_OF7    0x07
  36452. +#define SYNCHTRANSFER_OF8    0x08
  36453. +#define SYNCHTRANSFER_OF9    0x09
  36454. +#define SYNCHTRANSFER_OF10    0x0A
  36455. +#define SYNCHTRANSFER_OF11    0x0B
  36456. +#define SYNCHTRANSFER_OF12    0x0C
  36457. +#define SYNCHTRANSFER_8DBA    0x00
  36458. +#define SYNCHTRANSFER_2DBA    0x20
  36459. +#define SYNCHTRANSFER_3DBA    0x30
  36460. +#define SYNCHTRANSFER_4DBA    0x40
  36461. +#define SYNCHTRANSFER_5DBA    0x50
  36462. +#define SYNCHTRANSFER_6DBA    0x60
  36463. +#define SYNCHTRANSFER_7DBA    0x70
  36464. +
  36465. +#define TRANSCNTH        18
  36466. +#define TRANSCNTM        19
  36467. +#define TRANSCNTL        20
  36468. +#define DESTID            21
  36469. +#define DESTID_SCC        (1<<7)
  36470. +#define DESTID_DPD        (1<<6)
  36471. +
  36472. +#define SOURCEID        22
  36473. +#define SOURCEID_ER        (1<<7)
  36474. +#define SOURCEID_ES        (1<<6)
  36475. +#define SOURCEID_DSP        (1<<5)
  36476. +#define SOURCEID_SIV        (1<<4)
  36477. +
  36478. +#define SSR            23
  36479. +#define CMND            24
  36480. +#define CMND_RESET        0x00
  36481. +#define CMND_ABORT        0x01
  36482. +#define CMND_ASSERTATN        0x02
  36483. +#define CMND_NEGATEACK        0x03
  36484. +#define CMND_DISCONNECT        0x04
  36485. +#define CMND_RESELECT        0x05
  36486. +#define CMND_SELWITHATN        0x06
  36487. +#define CMND_SELECT        0x07
  36488. +#define CMND_SELECTATNTRANSFER    0x08
  36489. +#define CMND_SELECTTRANSFER    0x09
  36490. +#define CMND_RESELECTRXDATA    0x0A
  36491. +#define CMND_RESELECTTXDATA    0x0B
  36492. +#define CMND_WAITFORSELRECV    0x0C
  36493. +#define CMND_SENDSTATCMD    0x0D
  36494. +#define CMND_SENDDISCONNECT    0x0E
  36495. +#define CMND_SETIDI        0x0F
  36496. +#define CMND_RECEIVECMD        0x10
  36497. +#define CMND_RECEIVEDTA        0x11
  36498. +#define CMND_RECEIVEMSG        0x12
  36499. +#define CMND_RECEIVEUSP        0x13
  36500. +#define CMND_SENDCMD        0x14
  36501. +#define CMND_SENDDATA        0x15
  36502. +#define CMND_SENDMSG        0x16
  36503. +#define CMND_SENDUSP        0x17
  36504. +#define CMND_TRANSLATEADDR    0x18
  36505. +#define CMND_XFERINFO        0x20
  36506. +#define CMND_SBT        (1<<7)
  36507. +
  36508. +#define DATA            25
  36509. +#define ASR            26
  36510. +#define ASR_INT            (1<<7)
  36511. +#define ASR_LCI            (1<<6)
  36512. +#define ASR_BSY            (1<<5)
  36513. +#define ASR_CIP            (1<<4)
  36514. +#define ASR_PE            (1<<1)
  36515. +#define ASR_DBR            (1<<0)
  36516. +
  36517. +/* DMAC registers */
  36518. +#define INIT            0x00
  36519. +#define INIT_8BIT        (1)
  36520. +
  36521. +#define CHANNEL            0x80
  36522. +#define CHANNEL_0        0x00
  36523. +#define CHANNEL_1        0x01
  36524. +#define CHANNEL_2        0x02
  36525. +#define CHANNEL_3        0x03
  36526. +
  36527. +#define TXCNTLO            0x01
  36528. +#define TXCNTHI            0x81
  36529. +#define TXADRLO            0x02
  36530. +#define TXADRMD            0x82
  36531. +#define TXADRHI            0x03
  36532. +
  36533. +#define DEVCON0            0x04
  36534. +#define DEVCON0_AKL        (1<<7)
  36535. +#define DEVCON0_RQL        (1<<6)
  36536. +#define DEVCON0_EXW        (1<<5)
  36537. +#define DEVCON0_ROT        (1<<4)
  36538. +#define DEVCON0_CMP        (1<<3)
  36539. +#define DEVCON0_DDMA        (1<<2)
  36540. +#define DEVCON0_AHLD        (1<<1)
  36541. +#define DEVCON0_MTM        (1<<0)
  36542. +
  36543. +#define DEVCON1            0x84
  36544. +#define DEVCON1_WEV        (1<<1)
  36545. +#define DEVCON1_BHLD        (1<<0)
  36546. +
  36547. +#define MODECON            0x05
  36548. +#define MODECON_WOED        0x01
  36549. +#define MODECON_VERIFY        0x00
  36550. +#define MODECON_READ        0x04
  36551. +#define MODECON_WRITE        0x08
  36552. +#define MODECON_AUTOINIT    0x10
  36553. +#define MODECON_ADDRDIR        0x20
  36554. +#define MODECON_DEMAND        0x00
  36555. +#define MODECON_SINGLE        0x40
  36556. +#define MODECON_BLOCK        0x80
  36557. +#define MODECON_CASCADE        0xC0
  36558. +
  36559. +#define STATUS            0x85
  36560. +#define TEMPLO            0x06
  36561. +#define TEMPHI            0x86
  36562. +#define REQREG            0x07
  36563. +#define MASKREG            0x87
  36564. +#define MASKREG_M0        0x01
  36565. +#define MASKREG_M1        0x02
  36566. +#define MASKREG_M2        0x04
  36567. +#define MASKREG_M3        0x08
  36568. +
  36569. +/* miscellaneous internal variables */
  36570. +
  36571. +#define CMD_READ        0
  36572. +#define CMD_WRITE        1
  36573. +#define CMD_MISC        2
  36574. +
  36575. +#define PHASE_IDLE            0x00
  36576. +#define PHASE_CONNECTING        0x41
  36577. +#define PHASE_CONNECTED            0x42
  36578. +#define PHASE_COMMAND            0x43
  36579. +#define PHASE_COMMANDSENT        0x44
  36580. +
  36581. +#define PHASE_DATAIN            0x46
  36582. +#define PHASE_DATAOUT            0x47
  36583. +
  36584. +#define PHASE_STATUSIN            0x4c
  36585. +#define PHASE_FINISHED            0x4d
  36586. +#define PHASE_DISCONNECTING        0x4f
  36587. +#define PHASE_RECONNECTED        0x50
  36588. +
  36589. +#define PHASE_CONNECTING_FOR_ABORT    0x80
  36590. +#define PHASE_CONNECTED_FOR_ABORT    0x81
  36591. +
  36592. +#define INTR_CONNECTED        0
  36593. +#define INTR_NOTCONNECTED    1
  36594. +#define INTR_CONTINUE        2
  36595. +
  36596. +struct as_stats {
  36597. +    unsigned long queues;
  36598. +    unsigned long removes;
  36599. +    unsigned long fins;
  36600. +    unsigned long reads;
  36601. +    unsigned long writes;
  36602. +    unsigned long miscs;
  36603. +    unsigned long aborts;
  36604. +    unsigned long resets;
  36605. +    unsigned long disconnects;
  36606. +};
  36607. +
  36608. +struct as_cmnd {
  36609. +    Scsi_Cmnd *cmd;
  36610. +    struct as_cmnd *next;                /* next command in queue         */
  36611. +    int used;                        /* block in use                 */
  36612. +    unsigned long queued_jiffies;
  36613. +    unsigned long connect_jiffies;
  36614. +    unsigned long totallen;
  36615. +    unsigned long buf0addr;
  36616. +    unsigned long buf1addr;
  36617. +    unsigned long saved_dmac_address;
  36618. +    unsigned long saved_dmac_transcnt;
  36619. +    unsigned long saved_sbic_transcnt;
  36620. +    unsigned short buf0len;
  36621. +    unsigned short buf1len;
  36622. +    unsigned char buffer;
  36623. +    unsigned char saved;
  36624. +};
  36625. +
  36626. +struct as_dev {
  36627. +    struct as_cmnd *issue_head;
  36628. +    struct as_cmnd *issue_tail;
  36629. +    struct as_cmnd *disconnected;            /* commands disconnected         */
  36630. +    unsigned char busy;                    /* luns on device that are busy         */
  36631. +};
  36632. +    
  36633. +struct acornscsi_hostdata {
  36634. +    int busy;                        /* in process of connecting         */
  36635. +    int page_reg;                    /* current page register value         */
  36636. +
  36637. +    /* data for the connected command */
  36638. +    int phase;                        /* phase of command             */
  36639. +    int last_message;                    /* last message sent             */
  36640. +    int msgout;                        /* message to be sent out         */
  36641. +    unsigned long tmpsbiclen;
  36642. +
  36643. +    struct as_cmnd *connecting;                /* command that is connecting         */
  36644. +    struct as_cmnd *aborting;                /* command that is aborting         */
  36645. +    struct as_cmnd *connected;                /* command that is connected         */
  36646. +
  36647. +    struct as_cmnd queuedcommands[CAN_QUEUE];        /* commands                  */
  36648. +
  36649. +    struct as_dev dev[8];
  36650. +    struct as_stats stats;
  36651. +};
  36652. +
  36653. +#endif
  36654. +
  36655. +#endif /* ndef ASM */
  36656. +#endif /* ACORNSCSI_H */
  36657. diff -urNwbB linux/arch/arm/drivers/scsi/cumana_1.c linux.arm/arch/arm/drivers/scsi/cumana_1.c
  36658. --- linux/arch/arm/drivers/scsi/cumana_1.c    Thu Jan  1 01:00:00 1970
  36659. +++ linux.arm/arch/arm/drivers/scsi/cumana_1.c    Sat Feb 24 09:36:55 1996
  36660. @@ -0,0 +1,318 @@
  36661. +#define AUTOSENSE
  36662. +#define PSEUDO_DMA
  36663. +
  36664. +/*
  36665. + * Generic Generic NCR5380 driver
  36666. + *
  36667. + * Copyright 1995, Russell King
  36668. + *
  36669. + * ALPHA RELEASE 1.
  36670. + *
  36671. + * For more information, please consult
  36672. + *
  36673. + * NCR 5380 Family
  36674. + * SCSI Protocol Controller
  36675. + * Databook
  36676. + *
  36677. + * NCR Microelectronics
  36678. + * 1635 Aeroplaza Drive
  36679. + * Colorado Springs, CO 80916
  36680. + * 1+ (719) 578-3400
  36681. + * 1+ (800) 334-5454
  36682. + */
  36683. +
  36684. +
  36685. +/*
  36686. + * Options :
  36687. + *
  36688. + * PARITY - enable parity checking.  Not supported.
  36689. + *
  36690. + * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
  36691. + *
  36692. + * USLEEP - enable support for devices that don't disconnect.  Untested.
  36693. + */
  36694. +
  36695. +/*
  36696. + * $Log: cumana_NCR5380.c,v $
  36697. + */
  36698. +
  36699. +#include <asm/system.h>
  36700. +#include <asm/io.h>
  36701. +#include <linux/signal.h>
  36702. +#include <linux/sched.h>
  36703. +#include "../block/blk.h"
  36704. +#include "scsi.h"
  36705. +#include "hosts.h"
  36706. +#include "cumana_1.h"
  36707. +#include "NCR5380.h"
  36708. +#include "constants.h"
  36709. +
  36710. +#include <asm/ecard.h>
  36711. +
  36712. +static unsigned int cumana_1_prods[] = { 0x00a0 };
  36713. +static unsigned int cumana_1_manus[] = { 0x003a };
  36714. +
  36715. +/*
  36716. + * Function : cumana_NCR5380_setup(char *str, int *ints)
  36717. + *
  36718. + * Purpose : LILO command line initialization of the overrides array,
  36719. + *
  36720. + * Inputs : str - unused, ints - array of integer parameters with ints[0]
  36721. + *    equal to the number of ints.
  36722. + *
  36723. + */
  36724. +
  36725. +void cumana_NCR5380_setup(char *str, int *ints) {
  36726. +}
  36727. +
  36728. +/*
  36729. + * Function : int cumana_NCR5380_detect(Scsi_Host_Template * tpnt)
  36730. + *
  36731. + * Purpose : initializes cumana NCR5380 driver based on the
  36732. + *    command line / compile time port and irq definitions.
  36733. + *
  36734. + * Inputs : tpnt - template for this SCSI adapter.
  36735. + *
  36736. + * Returns : 1 if a host adapter was found, 0 if not.
  36737. + *
  36738. + */
  36739. +
  36740. +int cumana_NCR5380_detect(Scsi_Host_Template * tpnt) {
  36741. +    struct expansion_card *ec;
  36742. +    int count = 0;
  36743. +    struct Scsi_Host *instance;
  36744. +
  36745. +    while(1) {
  36746. +        if((ec = ecard_find(0, sizeof(cumana_1_prods), cumana_1_prods, cumana_1_manus)) == NULL)
  36747. +            break;
  36748. +
  36749. +        instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
  36750. +        instance->io_port = (((int)ec->r_podaddr & ~0x003c0000UL) | 0x00242000UL) >> 2;
  36751. +
  36752. +    NCR5380_init(instance, 0);
  36753. +
  36754. +    instance->irq = ec->irq;
  36755. +        ((struct NCR5380_hostdata *)instance->hostdata)->ctrl=0;
  36756. +        outb(0x00, instance->io_port - 577);
  36757. +
  36758. +    if (instance->irq != IRQ_NONE)
  36759. +        if (request_irq(instance->irq, cumana_NCR5380_intr, SA_INTERRUPT, "Cumana SCSI 1 card")) {
  36760. +        printk("scsi%d: IRQ%d not free, interrupts disabled\n",
  36761. +            instance->host_no, instance->irq);
  36762. +        instance->irq = IRQ_NONE;
  36763. +        }
  36764. +
  36765. +    if (instance->irq == IRQ_NONE) {
  36766. +        printk("scsi%d: interrupts not enabled. for better interactive performance,\n", instance->host_no);
  36767. +        printk("scsi%d: please jumper the board for a free IRQ.\n", instance->host_no);
  36768. +    }
  36769. +
  36770. +    printk("scsi%d: at port %X irq", instance->host_no, instance->io_port);
  36771. +    if (instance->irq == IRQ_NONE)
  36772. +        printk ("s disabled");
  36773. +    else
  36774. +        printk (" %d", instance->irq);
  36775. +    printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
  36776. +        CAN_QUEUE, CMD_PER_LUN, CUMANA_NCR5380_PUBLIC_RELEASE);
  36777. +    printk("\nscsi%d:", instance->host_no);
  36778. +    NCR5380_print_options(instance);
  36779. +    printk("\n");
  36780. +
  36781. +    ecard_claim(ec);
  36782. +    ++count;
  36783. +    }
  36784. +    return count;
  36785. +}
  36786. +
  36787. +const char * cumana_NCR5380_info (struct Scsi_Host *spnt) {
  36788. +    return "";
  36789. +}
  36790. +
  36791. +#ifdef NOT_EFFICIENT
  36792. +#define CTRL(p,v)     outb(*ctrl = (v), (p) - 577)
  36793. +#define STAT(p)       inb((p)+1)
  36794. +#define IN(p)         inb((p))
  36795. +#define OUT(v,p)      outb((v), (p))
  36796. +#else
  36797. +#define CTRL(p,v)    (p[-2308] = (*ctrl = (v)))
  36798. +#define STAT(p)        (p[4])
  36799. +#define IN(p)        (*(p))
  36800. +#define IN2(p)        ((unsigned short)(*(volatile unsigned long *)(p)))
  36801. +#define OUT(v,p)    (*(p) = (v))
  36802. +#define OUT2(v,p)    (*((volatile unsigned long *)(p)) = (v))
  36803. +#endif
  36804. +#define L(v)        (((v)<<16)|((v) & 0x0000ffff))
  36805. +#define H(v)        (((v)>>16)|((v) & 0xffff0000))
  36806. +
  36807. +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
  36808. +              int len)
  36809. +{
  36810. +  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
  36811. +  int oldctrl = *ctrl;
  36812. +  unsigned long *laddr;
  36813. +#ifdef NOT_EFFICIENT
  36814. +  int ioaddr = instance->io_port;
  36815. +  int dma_io = ioaddr & ~(0x3C0000>>2);
  36816. +#else
  36817. +  volatile unsigned char *ioaddr = (unsigned char *)(instance->io_port<<2);
  36818. +  volatile unsigned char *dma_io = (unsigned char *)((int)ioaddr & ~0x3C0000);
  36819. +#endif
  36820. +
  36821. +  if(!len) return 0;
  36822. +
  36823. +  CTRL(ioaddr, 0x02);
  36824. +  laddr = (unsigned long *)addr;
  36825. +  while(len >= 32)
  36826. +  {
  36827. +    int status;
  36828. +    unsigned long v;
  36829. +    status = STAT(ioaddr);
  36830. +    if(status & 0x80)
  36831. +      goto end;
  36832. +    if(!(status & 0x40))
  36833. +      continue;
  36834. +    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
  36835. +    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
  36836. +    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
  36837. +    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
  36838. +    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
  36839. +    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
  36840. +    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
  36841. +    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
  36842. +    len -= 32;
  36843. +    if(len == 0)
  36844. +      break;
  36845. +  }
  36846. +
  36847. +  addr = (unsigned char *)laddr;
  36848. +  CTRL(ioaddr, 0x12);
  36849. +  while(len > 0)
  36850. +  {
  36851. +    int status;
  36852. +    status = STAT(ioaddr);
  36853. +    if(status & 0x80)
  36854. +      goto end;
  36855. +    if(status & 0x40)
  36856. +    {
  36857. +      OUT(*addr++, dma_io);
  36858. +      if(--len == 0)
  36859. +        break;
  36860. +    }
  36861. +
  36862. +    status = STAT(ioaddr);
  36863. +    if(status & 0x80)
  36864. +      goto end;
  36865. +    if(status & 0x40)
  36866. +    {
  36867. +      OUT(*addr++, dma_io);
  36868. +      if(--len == 0)
  36869. +        break;
  36870. +    }
  36871. +  }
  36872. +end:
  36873. +  CTRL(ioaddr, oldctrl|0x40);
  36874. +  return len;
  36875. +}
  36876. +
  36877. +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
  36878. +              int len)
  36879. +{
  36880. +  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
  36881. +  int oldctrl = *ctrl;
  36882. +  unsigned long *laddr;
  36883. +#ifdef NOT_EFFICIENT
  36884. +  int ioaddr = instance->io_port;
  36885. +  int dma_io = ioaddr & ~(0x3C0000>>2);
  36886. +#else
  36887. +  volatile unsigned char *ioaddr = (unsigned char *)(instance->io_port<<2);
  36888. +  volatile unsigned char *dma_io = (unsigned char *)((int)ioaddr & ~0x3C0000);
  36889. +#endif
  36890. +
  36891. +  if(!len) return 0;
  36892. +
  36893. +  CTRL(ioaddr, 0x00);
  36894. +  laddr = (unsigned long *)addr;
  36895. +  while(len >= 32)
  36896. +  {
  36897. +    int status;
  36898. +    status = STAT(ioaddr);
  36899. +    if(status & 0x80)
  36900. +      goto end;
  36901. +    if(!(status & 0x40))
  36902. +      continue;
  36903. +    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
  36904. +    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
  36905. +    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
  36906. +    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
  36907. +    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
  36908. +    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
  36909. +    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
  36910. +    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
  36911. +    len -= 32;
  36912. +    if(len == 0)
  36913. +      break;
  36914. +  }
  36915. +
  36916. +  addr = (unsigned char *)laddr;
  36917. +  CTRL(ioaddr, 0x10);
  36918. +  while(len > 0)
  36919. +  {
  36920. +    int status;
  36921. +    status = STAT(ioaddr);
  36922. +    if(status & 0x80)
  36923. +      goto end;
  36924. +    if(status & 0x40)
  36925. +    {
  36926. +      *addr++ = IN(dma_io);
  36927. +      if(--len == 0)
  36928. +        break;
  36929. +    }
  36930. +
  36931. +    status = STAT(ioaddr);
  36932. +    if(status & 0x80)
  36933. +      goto end;
  36934. +    if(status & 0x40)
  36935. +    {
  36936. +      *addr++ = IN(dma_io);
  36937. +      if(--len == 0)
  36938. +        break;
  36939. +    }
  36940. +  }
  36941. +end:
  36942. +  CTRL(ioaddr, oldctrl|0x40);
  36943. +  return len;
  36944. +}
  36945. +
  36946. +#undef STAT
  36947. +#undef CTRL
  36948. +#undef IN
  36949. +#undef OUT
  36950. +
  36951. +#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
  36952. +
  36953. +static char cumana_NCR5380_read(struct Scsi_Host *instance, int reg)
  36954. +{
  36955. +  int ioaddr = instance->io_port;
  36956. +  int i;
  36957. +  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
  36958. +
  36959. +  CTRL(ioaddr, 0);
  36960. +  i = inb(ioaddr + 64 + reg);
  36961. +  CTRL(ioaddr, 0x40);
  36962. +
  36963. +  return i;
  36964. +}
  36965. +
  36966. +static void cumana_NCR5380_write(struct Scsi_Host *instance, int reg, int value)
  36967. +{
  36968. +  int ioaddr = instance->io_port;
  36969. +  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
  36970. +
  36971. +  CTRL(ioaddr, 0);
  36972. +  outb(value, ioaddr + 64 + reg);
  36973. +  CTRL(ioaddr, 0x40);
  36974. +}
  36975. +
  36976. +#undef CTRL
  36977. +
  36978. +#include "NCR5380.c"
  36979. diff -urNwbB linux/arch/arm/drivers/scsi/cumana_1.h linux.arm/arch/arm/drivers/scsi/cumana_1.h
  36980. --- linux/arch/arm/drivers/scsi/cumana_1.h    Thu Jan  1 01:00:00 1970
  36981. +++ linux.arm/arch/arm/drivers/scsi/cumana_1.h    Sat Feb 24 09:36:55 1996
  36982. @@ -0,0 +1,88 @@
  36983. +/*
  36984. + * Cumana Generic NCR5380 driver defines
  36985. + *
  36986. + * Copyright 1993, Drew Eckhardt
  36987. + *    Visionary Computing
  36988. + *    (Unix and Linux consulting and custom programming)
  36989. + *    drew@colorado.edu
  36990. + *      +1 (303) 440-4894
  36991. + *
  36992. + * ALPHA RELEASE 1.
  36993. + *
  36994. + * For more information, please consult
  36995. + *
  36996. + * NCR 5380 Family
  36997. + * SCSI Protocol Controller
  36998. + * Databook
  36999. + *
  37000. + * NCR Microelectronics
  37001. + * 1635 Aeroplaza Drive
  37002. + * Colorado Springs, CO 80916
  37003. + * 1+ (719) 578-3400
  37004. + * 1+ (800) 334-5454
  37005. + */
  37006. +
  37007. +/*
  37008. + * $Log: cumana_NCR5380.h,v $
  37009. + */
  37010. +
  37011. +#ifndef CUMANA_NCR5380_H
  37012. +#define CUMANA_NCR5380_H
  37013. +
  37014. +#define CUMANA_NCR5380_PUBLIC_RELEASE 1
  37015. +
  37016. +
  37017. +#ifndef ASM
  37018. +int cumana_NCR5380_abort(Scsi_Cmnd *);
  37019. +int cumana_NCR5380_detect(Scsi_Host_Template *);
  37020. +const char *cumana_NCR5380_info(struct Scsi_Host *);
  37021. +int cumana_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
  37022. +int cumana_NCR5380_reset(Scsi_Cmnd *);
  37023. +
  37024. +
  37025. +#ifndef NULL
  37026. +#define NULL 0
  37027. +#endif
  37028. +
  37029. +#ifndef CMD_PER_LUN
  37030. +#define CMD_PER_LUN 2
  37031. +#endif
  37032. +
  37033. +#ifndef CAN_QUEUE
  37034. +#define CAN_QUEUE 16
  37035. +#endif
  37036. +
  37037. +#ifdef HOSTS_C
  37038. +
  37039. +#define CUMANA_NCR5380 {NULL, NULL, "Cumana 16-bit SCSI",        \
  37040. +    cumana_NCR5380_detect, NULL, cumana_NCR5380_info, NULL,     \
  37041. +    cumana_NCR5380_queue_command, cumana_NCR5380_abort,         \
  37042. +    cumana_NCR5380_reset, NULL,                     \
  37043. +    NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,        \
  37044. +    /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
  37045. +
  37046. +#else
  37047. +#define NCR5380_implementation_fields \
  37048. +    int port, ctrl
  37049. +
  37050. +#define NCR5380_local_declare() \
  37051. +        struct Scsi_Host *_instance
  37052. +
  37053. +#define NCR5380_setup(instance) \
  37054. +        _instance = instance
  37055. +
  37056. +#define NCR5380_read(reg) cumana_NCR5380_read(_instance, reg)
  37057. +#define NCR5380_write(reg, value) cumana_NCR5380_write(_instance, reg, value)
  37058. +
  37059. +#define NCR5380_intr cumana_NCR5380_intr
  37060. +#define NCR5380_queue_command cumana_NCR5380_queue_command
  37061. +#define NCR5380_abort cumana_NCR5380_abort
  37062. +#define NCR5380_reset cumana_NCR5380_reset
  37063. +
  37064. +#define BOARD_NORMAL    0
  37065. +#define BOARD_NCR53C400    1
  37066. +
  37067. +#endif /* else def HOSTS_C */
  37068. +#endif /* ndef ASM */
  37069. +#endif /* CUMANA_NCR5380_H */
  37070. +
  37071. diff -urNwbB linux/arch/arm/drivers/scsi/ecoscsi.c linux.arm/arch/arm/drivers/scsi/ecoscsi.c
  37072. --- linux/arch/arm/drivers/scsi/ecoscsi.c    Thu Jan  1 01:00:00 1970
  37073. +++ linux.arm/arch/arm/drivers/scsi/ecoscsi.c    Sat Feb 24 09:36:55 1996
  37074. @@ -0,0 +1,207 @@
  37075. +#define AUTOSENSE
  37076. +/* #define PSEUDO_DMA */
  37077. +
  37078. +/*
  37079. + * EcoSCSI Generic NCR5380 driver
  37080. + *
  37081. + * Copyright 1995, Russell King
  37082. + *
  37083. + * ALPHA RELEASE 1.
  37084. + *
  37085. + * For more information, please consult
  37086. + *
  37087. + * NCR 5380 Family
  37088. + * SCSI Protocol Controller
  37089. + * Databook
  37090. + *
  37091. + * NCR Microelectronics
  37092. + * 1635 Aeroplaza Drive
  37093. + * Colorado Springs, CO 80916
  37094. + * 1+ (719) 578-3400
  37095. + * 1+ (800) 334-5454
  37096. + */
  37097. +
  37098. +/*
  37099. + * Options :
  37100. + *
  37101. + * PARITY - enable parity checking.  Not supported.
  37102. + *
  37103. + * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
  37104. + *
  37105. + * USLEEP - enable support for devices that don't disconnect.  Untested.
  37106. + */
  37107. +
  37108. +/*
  37109. + * $Log: ecoscsi_NCR5380.c,v $
  37110. + */
  37111. +
  37112. +#include <asm/system.h>
  37113. +#include <asm/io.h>
  37114. +#include <linux/signal.h>
  37115. +#include <linux/sched.h>
  37116. +#include "../block/blk.h"
  37117. +#include "scsi.h"
  37118. +#include "hosts.h"
  37119. +#include "ecoscsi.h"
  37120. +#include "NCR5380.h"
  37121. +#include "constants.h"
  37122. +
  37123. +static char ecoscsi_NCR5380_read(struct Scsi_Host *instance, int reg)
  37124. +{
  37125. +  int ioaddr = instance->io_port;
  37126. +  outb(reg | 8, ioaddr);
  37127. +  return inb(ioaddr + 1);
  37128. +}
  37129. +
  37130. +static void ecoscsi_NCR5380_write(struct Scsi_Host *instance, int reg, int value)
  37131. +{
  37132. +  int ioaddr = instance->io_port;
  37133. +  outb(reg | 8, ioaddr);
  37134. +  outb(value, ioaddr + 1);
  37135. +}
  37136. +
  37137. +/*
  37138. + * Function : ecoscsi_NCR5380_setup(char *str, int *ints)
  37139. + *
  37140. + * Purpose : LILO command line initialization of the overrides array,
  37141. + *
  37142. + * Inputs : str - unused, ints - array of integer parameters with ints[0]
  37143. + *    equal to the number of ints.
  37144. + *
  37145. + */
  37146. +
  37147. +void ecoscsi_NCR5380_setup(char *str, int *ints) {
  37148. +}
  37149. +
  37150. +/*
  37151. + * Function : int ecoscsi_NCR5380_detect(Scsi_Host_Template * tpnt)
  37152. + *
  37153. + * Purpose : initializes ecoscsi NCR5380 driver based on the
  37154. + *    command line / compile time port and irq definitions.
  37155. + *
  37156. + * Inputs : tpnt - template for this SCSI adapter.
  37157. + *
  37158. + * Returns : 1 if a host adapter was found, 0 if not.
  37159. + *
  37160. + */
  37161. +
  37162. +int ecoscsi_NCR5380_detect(Scsi_Host_Template * tpnt) {
  37163. +    struct Scsi_Host *instance;
  37164. +
  37165. +    instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
  37166. +    instance->io_port = 0x033A0000 >> 2;
  37167. +
  37168. +    ecoscsi_NCR5380_write (instance, MODE_REG, 0x20);        /* Is it really SCSI? */
  37169. +    if (ecoscsi_NCR5380_read (instance, MODE_REG) != 0x20)    /* Write to a reg.    */
  37170. +    {
  37171. +        scsi_unregister(instance);
  37172. +        return 0;                        /* and try to read    */
  37173. +    }
  37174. +    ecoscsi_NCR5380_write( instance, MODE_REG, 0x00 );        /* it back.          */
  37175. +    if (ecoscsi_NCR5380_read (instance, MODE_REG) != 0x00)
  37176. +    {
  37177. +        scsi_unregister(instance);
  37178. +        return 0;
  37179. +    }
  37180. +
  37181. +    NCR5380_init(instance, 0);
  37182. +
  37183. +    instance->irq = IRQ_NONE;
  37184. +
  37185. +    if (instance->irq != IRQ_NONE)
  37186. +    if (request_irq(instance->irq, ecoscsi_NCR5380_intr, SA_INTERRUPT, "NCR5380")) {
  37187. +        printk("scsi%d: IRQ%d not free, interrupts disabled\n",
  37188. +        instance->host_no, instance->irq);
  37189. +        instance->irq = IRQ_NONE;
  37190. +    }
  37191. +
  37192. +    if (instance->irq != IRQ_NONE) {
  37193. +      printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no);
  37194. +    printk("scsi%d: that the board had an interrupt!\n", instance->host_no);
  37195. +    }
  37196. +
  37197. +    printk("scsi%d: at port %X irq", instance->host_no, instance->io_port);
  37198. +    if (instance->irq == IRQ_NONE)
  37199. +    printk ("s disabled");
  37200. +    else
  37201. +        printk (" %d", instance->irq);
  37202. +    printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
  37203. +        CAN_QUEUE, CMD_PER_LUN, ECOSCSI_NCR5380_PUBLIC_RELEASE);
  37204. +    printk("\nscsi%d:", instance->host_no);
  37205. +    NCR5380_print_options(instance);
  37206. +    printk("\n");
  37207. +    return 1;
  37208. +}
  37209. +
  37210. +const char * ecoscsi_NCR5380_info (struct Scsi_Host *spnt) {
  37211. +    return "";
  37212. +}
  37213. +
  37214. +#if 0
  37215. +#define STAT(p) inw(p + 144)
  37216. +
  37217. +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
  37218. +              int len)
  37219. +{
  37220. +  int ioaddr = instance->io_port;
  37221. +printk("writing %p len %d\n",addr, len);
  37222. +  if(!len) return -1;
  37223. +
  37224. +  while(1)
  37225. +  {
  37226. +    int status;
  37227. +    while(((status = STAT(ioaddr)) & 0x100)==0);
  37228. +  }
  37229. +}
  37230. +
  37231. +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
  37232. +              int len)
  37233. +{
  37234. +  int ioaddr = instance->io_port;
  37235. +  int ioaddr2= instance->io_port + 0x100;
  37236. +  unsigned char *start = addr;
  37237. +  int s;
  37238. +printk("reading %p len %d\n",addr, len);
  37239. +  outb(inb(ioaddr + 128), ioaddr + 135);
  37240. +  while(len > 0)
  37241. +  {
  37242. +    int status,b,i, timeout;
  37243. +    timeout = 0x07FFFFFF;
  37244. +    while(((status = STAT(ioaddr)) & 0x100)==0)
  37245. +    {
  37246. +      timeout--;
  37247. +      if(status & 0x200 || !timeout)
  37248. +      {
  37249. +        printk("status = %p\n",status);
  37250. +        outb(0, ioaddr + 135);
  37251. +        return 1;
  37252. +      }
  37253. +    }
  37254. +    if(len >= 128)
  37255. +    {
  37256. +      for(i=0; i<64; i++)
  37257. +      {
  37258. +        b = inw(ioaddr + 136);
  37259. +        *addr++ = b;
  37260. +        *addr++ = b>>8;
  37261. +      }
  37262. +      len -= 128;
  37263. +    }
  37264. +    else
  37265. +    {
  37266. +      b = inw(ioaddr + 136);
  37267. +      *addr ++ = b;
  37268. +      len -= 1;
  37269. +      if(len)
  37270. +        *addr ++ = b>>8;
  37271. +      len -= 1;
  37272. +    }
  37273. +  }
  37274. +  outb(0, ioaddr + 135);
  37275. +  printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]);
  37276. +  return 1;
  37277. +}
  37278. +#endif
  37279. +#undef STAT
  37280. +
  37281. +#include "NCR5380.c"
  37282. diff -urNwbB linux/arch/arm/drivers/scsi/ecoscsi.h linux.arm/arch/arm/drivers/scsi/ecoscsi.h
  37283. --- linux/arch/arm/drivers/scsi/ecoscsi.h    Thu Jan  1 01:00:00 1970
  37284. +++ linux.arm/arch/arm/drivers/scsi/ecoscsi.h    Sat Feb 24 09:36:55 1996
  37285. @@ -0,0 +1,84 @@
  37286. +/*
  37287. + * Cumana Generic NCR5380 driver defines
  37288. + *
  37289. + * Copyright 1995, Russell King
  37290. + *
  37291. + * ALPHA RELEASE 1.
  37292. + *
  37293. + * For more information, please consult
  37294. + *
  37295. + * NCR 5380 Family
  37296. + * SCSI Protocol Controller
  37297. + * Databook
  37298. + *
  37299. + * NCR Microelectronics
  37300. + * 1635 Aeroplaza Drive
  37301. + * Colorado Springs, CO 80916
  37302. + * 1+ (719) 578-3400
  37303. + * 1+ (800) 334-5454
  37304. + */
  37305. +
  37306. +/*
  37307. + * $Log: ecoscsi_NCR5380.h,v $
  37308. + */
  37309. +
  37310. +#ifndef ECOSCSI_NCR5380_H
  37311. +#define ECOSCSI_NCR5380_H
  37312. +
  37313. +#define ECOSCSI_NCR5380_PUBLIC_RELEASE 1
  37314. +
  37315. +
  37316. +#ifndef ASM
  37317. +int ecoscsi_NCR5380_abort(Scsi_Cmnd *);
  37318. +int ecoscsi_NCR5380_detect(Scsi_Host_Template *);
  37319. +const char *ecoscsi_NCR5380_info(struct Scsi_Host *);
  37320. +int ecoscsi_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
  37321. +int ecoscsi_NCR5380_reset(Scsi_Cmnd *);
  37322. +
  37323. +
  37324. +#ifndef NULL
  37325. +#define NULL 0
  37326. +#endif
  37327. +
  37328. +#ifndef CMD_PER_LUN
  37329. +#define CMD_PER_LUN 2
  37330. +#endif
  37331. +
  37332. +#ifndef CAN_QUEUE
  37333. +#define CAN_QUEUE 16
  37334. +#endif
  37335. +
  37336. +#ifdef HOSTS_C
  37337. +
  37338. +#define ECOSCSI_NCR5380 {NULL, NULL, "Serial Port EcoSCSI NCR5380",    \
  37339. +    ecoscsi_NCR5380_detect, NULL, ecoscsi_NCR5380_info, NULL,     \
  37340. +    ecoscsi_NCR5380_queue_command, ecoscsi_NCR5380_abort,         \
  37341. +    ecoscsi_NCR5380_reset, NULL,                     \
  37342. +    NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,        \
  37343. +    /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
  37344. +
  37345. +#else
  37346. +#define NCR5380_implementation_fields \
  37347. +    int port, ctrl
  37348. +
  37349. +#define NCR5380_local_declare() \
  37350. +        struct Scsi_Host *_instance
  37351. +
  37352. +#define NCR5380_setup(instance) \
  37353. +        _instance = instance
  37354. +
  37355. +#define NCR5380_read(reg) ecoscsi_NCR5380_read(_instance, reg)
  37356. +#define NCR5380_write(reg, value) ecoscsi_NCR5380_write(_instance, reg, value)
  37357. +
  37358. +#define NCR5380_intr ecoscsi_NCR5380_intr
  37359. +#define NCR5380_queue_command ecoscsi_NCR5380_queue_command
  37360. +#define NCR5380_abort ecoscsi_NCR5380_abort
  37361. +#define NCR5380_reset ecoscsi_NCR5380_reset
  37362. +
  37363. +#define BOARD_NORMAL    0
  37364. +#define BOARD_NCR53C400    1
  37365. +
  37366. +#endif /* else def HOSTS_C */
  37367. +#endif /* ndef ASM */
  37368. +#endif /* ECOSCSI_NCR5380_H */
  37369. +
  37370. diff -urNwbB linux/arch/arm/drivers/scsi/hosts.c linux.arm/arch/arm/drivers/scsi/hosts.c
  37371. --- linux/arch/arm/drivers/scsi/hosts.c    Thu Jan  1 01:00:00 1970
  37372. +++ linux.arm/arch/arm/drivers/scsi/hosts.c    Sat Feb 24 09:36:56 1996
  37373. @@ -0,0 +1,339 @@
  37374. +/*
  37375. + *  hosts.c Copyright (C) 1992 Drew Eckhardt
  37376. + *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
  37377. + *
  37378. + *  mid to lowlevel SCSI driver interface
  37379. + *      Initial versions: Drew Eckhardt
  37380. + *      Subsequent revisions: Eric Youngdale
  37381. + *
  37382. + *  <drew@colorado.edu>
  37383. + */
  37384. +
  37385. +
  37386. +/*
  37387. + *  This file contains the medium level SCSI
  37388. + *  host interface initialization, as well as the scsi_hosts array of SCSI
  37389. + *  hosts currently present in the system.
  37390. + */
  37391. +
  37392. +#ifdef MODULE
  37393. +/*
  37394. + * Don't import our own symbols, as this would severely mess up our
  37395. + * symbol tables.
  37396. + */
  37397. +#define _SCSI_SYMS_VER_
  37398. +#include <linux/autoconf.h>
  37399. +#include <linux/module.h>
  37400. +#include <linux/version.h>
  37401. +#else
  37402. +#define MOD_INC_USE_COUNT
  37403. +#define MOD_DEC_USE_COUNT
  37404. +#endif
  37405. +
  37406. +#include <linux/config.h>
  37407. +#include "../block/blk.h"
  37408. +#include <linux/kernel.h>
  37409. +#include <linux/string.h>
  37410. +#include <linux/mm.h>
  37411. +#include <linux/proc_fs.h>
  37412. +
  37413. +#include "scsi.h"
  37414. +
  37415. +#ifndef NULL
  37416. +#define NULL 0L
  37417. +#endif
  37418. +
  37419. +#define HOSTS_C
  37420. +
  37421. +#include "hosts.h"
  37422. +
  37423. +#ifdef CONFIG_SCSI_ACORNSCSI_3
  37424. +#include "acornscsi.h"
  37425. +#endif
  37426. +
  37427. +#ifdef CONFIG_SCSI_CUMANA_1
  37428. +#include "cumana_1.h"
  37429. +#endif
  37430. +
  37431. +#ifdef CONFIG_SCSI_OAK1
  37432. +#include "oak.h"
  37433. +#endif
  37434. +
  37435. +#ifdef CONFIG_SCSI_ECOSCSI
  37436. +#include "ecoscsi.h"
  37437. +#endif
  37438. +
  37439. +#ifdef CONFIG_SCSI_DEBUG
  37440. +#include "scsi_debug.h"
  37441. +#endif
  37442. +
  37443. +/*
  37444. +static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.c,v 1.3 1993/09/24 12:21:00 drew Exp drew $";
  37445. +*/
  37446. +
  37447. +/*
  37448. + *  The scsi host entries should be in the order you wish the
  37449. + *  cards to be detected.  A driver may appear more than once IFF
  37450. + *  it can deal with being detected (and therefore initialized)
  37451. + *  with more than one simultaneous host number, can handle being
  37452. + *  reentrant, etc.
  37453. + *
  37454. + *  They may appear in any order, as each SCSI host is told which host 
  37455. + *  number it is during detection.
  37456. + */
  37457. +
  37458. +/* This is a placeholder for controllers that are not configured into
  37459. + * the system - we do this to ensure that the controller numbering is
  37460. + * always consistent, no matter how the kernel is configured. */
  37461. +
  37462. +#define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
  37463. +               NULL, NULL, 0, 0, 0, 0, 0, 0}
  37464. +
  37465. +/*
  37466. + *  When figure is run, we don't want to link to any object code.  Since
  37467. + *  the macro for each host will contain function pointers, we cannot
  37468. + *  use it and instead must use a "blank" that does no such
  37469. + *  idiocy.
  37470. + */
  37471. +
  37472. +Scsi_Host_Template * scsi_hosts = NULL;
  37473. +
  37474. +static Scsi_Host_Template builtin_scsi_hosts[] =
  37475. +{
  37476. +#ifdef CONFIG_SCSI_ACORNSCSI_3
  37477. +    ACORNSCSI_3,
  37478. +#endif
  37479. +#ifdef CONFIG_SCSI_CUMANA_1
  37480. +    CUMANA_NCR5380,
  37481. +#endif
  37482. +#ifdef CONFIG_SCSI_OAK1
  37483. +    OAK_NCR5380,
  37484. +#endif
  37485. +#ifdef CONFIG_SCSI_ECOSCSI
  37486. +    ECOSCSI_NCR5380,
  37487. +#endif
  37488. +#ifdef CONFIG_SCSI_DEBUG
  37489. +    SCSI_DEBUG,
  37490. +#endif
  37491. +};
  37492. +
  37493. +#define MAX_SCSI_HOSTS (sizeof(builtin_scsi_hosts) / sizeof(Scsi_Host_Template))
  37494. +
  37495. +
  37496. +/*
  37497. + *  Our semaphores and timeout counters, where size depends on 
  37498. + *      MAX_SCSI_HOSTS here.
  37499. + */
  37500. +
  37501. +struct Scsi_Host * scsi_hostlist = NULL;
  37502. +struct Scsi_Device_Template * scsi_devicelist = NULL;
  37503. +
  37504. +int max_scsi_hosts = 0;
  37505. +int next_scsi_host = 0;
  37506. +
  37507. +void
  37508. +scsi_unregister(struct Scsi_Host * sh){
  37509. +    struct Scsi_Host * shpnt;
  37510. +    
  37511. +    if(scsi_hostlist == sh)
  37512. +    scsi_hostlist = sh->next;
  37513. +    else {
  37514. +    shpnt = scsi_hostlist;
  37515. +    while(shpnt->next != sh) shpnt = shpnt->next;
  37516. +    shpnt->next = shpnt->next->next;
  37517. +    }
  37518. +    
  37519. +    /* If we are removing the last host registered, it is safe to reuse
  37520. +     * its host number (this avoids "holes" at boot time) (DB) 
  37521. +     */
  37522. +    if (max_scsi_hosts == next_scsi_host && !scsi_loadable_module_flag)
  37523. +    max_scsi_hosts--;
  37524. +    
  37525. +    next_scsi_host--;
  37526. +    scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + sh->extra_bytes);
  37527. +}
  37528. +
  37529. +/* We call this when we come across a new host adapter. We only do this
  37530. + * once we are 100% sure that we want to use this host adapter -  it is a
  37531. + * pain to reverse this, so we try and avoid it 
  37532. + */
  37533. +
  37534. +struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
  37535. +    struct Scsi_Host * retval, *shpnt;
  37536. +    retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j,
  37537. +                          (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
  37538. +    retval->host_busy = 0;
  37539. +    retval->block = NULL;
  37540. +    retval->wish_block = 0;
  37541. +    if(j > 0xffff) panic("Too many extra bytes requested\n");
  37542. +    retval->extra_bytes = j;
  37543. +    retval->loaded_as_module = scsi_loadable_module_flag;
  37544. +    retval->host_no = max_scsi_hosts++; /* never reuse host_no (DB) */
  37545. +    next_scsi_host++;
  37546. +    retval->host_queue = NULL;
  37547. +    retval->host_wait = NULL;
  37548. +    retval->last_reset = 0;
  37549. +    retval->irq = 0;
  37550. +    retval->dma_channel = 0xff;
  37551. +
  37552. +    /* These three are default values which can be overridden */
  37553. +    retval->max_channel = 0; 
  37554. +    retval->max_id = 8;      
  37555. +    retval->max_lun = 8;
  37556. +
  37557. +    retval->unique_id = 0;
  37558. +    retval->io_port = 0;
  37559. +    retval->forbidden_addr = 0;
  37560. +    retval->forbidden_size = 0;
  37561. +    retval->hostt = tpnt;
  37562. +    retval->next = NULL;
  37563. +#ifdef DEBUG
  37564. +    printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
  37565. +#endif
  37566. +
  37567. +    /* The next six are the default values which can be overridden
  37568. +     * if need be */
  37569. +    retval->this_id = tpnt->this_id;
  37570. +    retval->can_queue = tpnt->can_queue;
  37571. +    retval->sg_tablesize = tpnt->sg_tablesize;
  37572. +    retval->cmd_per_lun = tpnt->cmd_per_lun;
  37573. +    retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
  37574. +    retval->use_clustering = tpnt->use_clustering;   
  37575. +    if(!scsi_hostlist)
  37576. +    scsi_hostlist = retval;
  37577. +    else
  37578. +    {
  37579. +    shpnt = scsi_hostlist;
  37580. +    while(shpnt->next) shpnt = shpnt->next;
  37581. +    shpnt->next = retval;
  37582. +    }
  37583. +    
  37584. +    return retval;
  37585. +}
  37586. +
  37587. +int
  37588. +scsi_register_device(struct Scsi_Device_Template * sdpnt)
  37589. +{
  37590. +    if(sdpnt->next) panic("Device already registered");
  37591. +    sdpnt->next = scsi_devicelist;
  37592. +    scsi_devicelist = sdpnt;
  37593. +    return 0;
  37594. +}
  37595. +
  37596. +unsigned int scsi_init()
  37597. +{
  37598. +    static int called = 0;
  37599. +    int i, pcount;
  37600. +    Scsi_Host_Template * tpnt;
  37601. +    struct Scsi_Host * shpnt;
  37602. +    const char * name;
  37603. +    
  37604. +    if(called) return 0;
  37605. +
  37606. +    called = 1;
  37607. +    for (tpnt = &builtin_scsi_hosts[0], i = 0; i < MAX_SCSI_HOSTS; ++i, tpnt++)
  37608. +    {
  37609. +    /*
  37610. +     * Initialize our semaphores.  -1 is interpreted to mean
  37611. +     * "inactive" - where as 0 will indicate a time out condition.
  37612. +     */
  37613. +    
  37614. +    pcount = next_scsi_host;
  37615. +    if ((tpnt->detect) &&
  37616. +        (tpnt->present =
  37617. +         tpnt->detect(tpnt)))
  37618. +    {
  37619. +        /* The only time this should come up is when people use
  37620. +         * some kind of patched driver of some kind or another. */
  37621. +        if(pcount == next_scsi_host) {
  37622. +        if(tpnt->present > 1)
  37623. +            panic("Failure to register low-level scsi driver");
  37624. +        /* The low-level driver failed to register a driver.  We
  37625. +         * can do this now. */
  37626. +        scsi_register(tpnt,0);
  37627. +        }
  37628. +        tpnt->next = scsi_hosts;
  37629. +        scsi_hosts = tpnt;
  37630. +
  37631. +         /* Add the driver to /proc/scsi */
  37632. +#if CONFIG_PROC_FS 
  37633. +         build_proc_dir_entries(tpnt);
  37634. +#endif
  37635. +    }
  37636. +    }
  37637. +        
  37638. +    for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
  37639. +    {
  37640. +    if(shpnt->hostt->info)
  37641. +        name = shpnt->hostt->info(shpnt);
  37642. +    else
  37643. +        name = shpnt->hostt->name;
  37644. +    printk ("scsi%d : %s\n", /* And print a little message */
  37645. +        shpnt->host_no, name);
  37646. +    }
  37647. +    
  37648. +    printk ("scsi : %d host%s.\n", next_scsi_host,
  37649. +        (next_scsi_host == 1) ? "" : "s");
  37650. +    
  37651. +    scsi_make_blocked_list();
  37652. +    
  37653. +    /* Now attach the high level drivers */
  37654. +#ifdef CONFIG_BLK_DEV_SD
  37655. +    scsi_register_device(&sd_template);
  37656. +#endif
  37657. +#ifdef CONFIG_BLK_DEV_SR
  37658. +    scsi_register_device(&sr_template);
  37659. +#endif
  37660. +#ifdef CONFIG_CHR_DEV_ST
  37661. +    scsi_register_device(&st_template);
  37662. +#endif
  37663. +#ifdef CONFIG_CHR_DEV_SG
  37664. +    scsi_register_device(&sg_template);
  37665. +#endif
  37666. +
  37667. +#if 0      
  37668. +    max_scsi_hosts = next_scsi_host;
  37669. +#endif
  37670. +    return 0;
  37671. +}
  37672. +
  37673. +
  37674. +void scsi_mem_init(unsigned long memory_end)
  37675. +{
  37676. +    struct Scsi_Host *Host;
  37677. +    long High8, Low24;
  37678. +    for (Host = scsi_hostlist; Host != NULL; Host = Host->next) {
  37679. +    if (Host->forbidden_addr > 0 && Host->forbidden_size > 0) {
  37680. +        for (High8 = 1<<24; High8 < memory_end; High8 += 1<<24) {
  37681. +        for (Low24 = Host->forbidden_addr;
  37682. +             Low24 < Host->forbidden_addr + Host->forbidden_size;
  37683. +             Low24 += PAGE_SIZE) {
  37684. +            unsigned long ForbiddenAddress = High8 + Low24;
  37685. +            if (ForbiddenAddress >= memory_end) goto next_host;
  37686. +            mem_map[MAP_NR(ForbiddenAddress)].reserved = 1;
  37687. +        }
  37688. +        }
  37689. +    }
  37690. +    next_host:
  37691. +    continue;
  37692. +    }
  37693. +}
  37694. +
  37695. +/*
  37696. + * Overrides for Emacs so that we follow Linus's tabbing style.
  37697. + * Emacs will notice this stuff at the end of the file and automatically
  37698. + * adjust the settings for this buffer only.  This must remain at the end
  37699. + * of the file.
  37700. + * ---------------------------------------------------------------------------
  37701. + * Local variables:
  37702. + * c-indent-level: 4
  37703. + * c-brace-imaginary-offset: 0
  37704. + * c-brace-offset: -4
  37705. + * c-argdecl-indent: 4
  37706. + * c-label-offset: -4
  37707. + * c-continued-statement-offset: 4
  37708. + * c-continued-brace-offset: 0
  37709. + * indent-tabs-mode: nil
  37710. + * tab-width: 8
  37711. + * End:
  37712. + */
  37713. diff -urNwbB linux/arch/arm/drivers/scsi/oak.c linux.arm/arch/arm/drivers/scsi/oak.c
  37714. --- linux/arch/arm/drivers/scsi/oak.c    Thu Jan  1 01:00:00 1970
  37715. +++ linux.arm/arch/arm/drivers/scsi/oak.c    Sat Feb 24 09:36:56 1996
  37716. @@ -0,0 +1,209 @@
  37717. +#define AUTOSENSE
  37718. +/*#define PSEUDO_DMA*/
  37719. +
  37720. +/*
  37721. + * Oak Generic NCR5380 driver
  37722. + *
  37723. + * Copyright 1995, Russell King
  37724. + *
  37725. + * ALPHA RELEASE 1.
  37726. + *
  37727. + * For more information, please consult
  37728. + *
  37729. + * NCR 5380 Family
  37730. + * SCSI Protocol Controller
  37731. + * Databook
  37732. + *
  37733. + * NCR Microelectronics
  37734. + * 1635 Aeroplaza Drive
  37735. + * Colorado Springs, CO 80916
  37736. + * 1+ (719) 578-3400
  37737. + * 1+ (800) 334-5454
  37738. + */
  37739. +
  37740. +/*
  37741. + * Options :
  37742. + *
  37743. + * PARITY - enable parity checking.  Not supported.
  37744. + *
  37745. + * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
  37746. + *
  37747. + * USLEEP - enable support for devices that don't disconnect.  Untested.
  37748. + */
  37749. +
  37750. +/*
  37751. + * $Log: oak.c,v $
  37752. + */
  37753. +
  37754. +#ifdef MODULE
  37755. +#include <linux/module.h>
  37756. +#include <linux/config.h>
  37757. +#endif
  37758. +
  37759. +#include <asm/system.h>
  37760. +#include <asm/io.h>
  37761. +#include <linux/signal.h>
  37762. +#include <linux/sched.h>
  37763. +#include "../block/blk.h"
  37764. +#include "scsi.h"
  37765. +#include "hosts.h"
  37766. +#include "oak.h"
  37767. +#include "NCR5380.h"
  37768. +#include "constants.h"
  37769. +
  37770. +#undef START_DMA_INITIATOR_RECEIVE_REG
  37771. +#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
  37772. +
  37773. +#include <asm/ecard.h>
  37774. +
  37775. +static int oak_prods[] = { 0x0058 };
  37776. +static int oak_manus[] = { 0x0021 };
  37777. +
  37778. +/*
  37779. + * Function : int oak_NCR5380_detect(Scsi_Host_Template * tpnt)
  37780. + *
  37781. + * Purpose : initializes oak NCR5380 driver based on the
  37782. + *    command line / compile time port and irq definitions.
  37783. + *
  37784. + * Inputs : tpnt - template for this SCSI adapter.
  37785. + *
  37786. + * Returns : 1 if a host adapter was found, 0 if not.
  37787. + *
  37788. + */
  37789. +
  37790. +static struct expansion_card *ecs[4];
  37791. +
  37792. +int oak_NCR5380_detect(Scsi_Host_Template * tpnt) {
  37793. +    int count = 0, i;
  37794. +    struct Scsi_Host *instance;
  37795. +
  37796. +    while(1) {
  37797. +        if ((ecs[count] = ecard_find(0, sizeof(oak_prods), oak_prods, oak_manus)) == NULL)
  37798. +            break;
  37799. +
  37800. +        instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
  37801. +        instance->io_port = ((int)ecs[count]->r_podaddr & ~0x003c0000)>>2;
  37802. +
  37803. +    NCR5380_init(instance, 0);
  37804. +
  37805. +    instance->irq = 255;
  37806. +
  37807. +    if (instance->irq != IRQ_NONE)
  37808. +        if (request_irq(instance->irq, oak_NCR5380_intr, SA_INTERRUPT, "Oak SCSI")) {
  37809. +        printk("scsi%d: IRQ%d not free, interrupts disabled\n",
  37810. +            instance->host_no, instance->irq);
  37811. +        instance->irq = IRQ_NONE;
  37812. +        }
  37813. +
  37814. +    if (instance->irq != IRQ_NONE) {
  37815. +        printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no);
  37816. +        printk("scsi%d: that the board had an interrupt!\n", instance->host_no);
  37817. +    }
  37818. +
  37819. +    printk("scsi%d: at port %X irq", instance->host_no, instance->io_port);
  37820. +    if (instance->irq == IRQ_NONE)
  37821. +        printk ("s disabled");
  37822. +    else
  37823. +        printk (" %d", instance->irq);
  37824. +    printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
  37825. +        CAN_QUEUE, CMD_PER_LUN, OAK_NCR5380_PUBLIC_RELEASE);
  37826. +    printk("\nscsi%d:", instance->host_no);
  37827. +    NCR5380_print_options(instance);
  37828. +    printk("\n");
  37829. +
  37830. +    ecard_claim(ecs[count]);
  37831. +    ++count;
  37832. +    }
  37833. +    for(i=0; i<count; i++)
  37834. +        ecard_release(ecs[i]);
  37835. +#ifdef MODULE
  37836. +    if(count == 0)
  37837. +        printk("No oak scsi devices found\n");
  37838. +#endif
  37839. +    return count;
  37840. +}
  37841. +
  37842. +const char * oak_NCR5380_info (struct Scsi_Host *spnt) {
  37843. +    return "";
  37844. +}
  37845. +
  37846. +#define STAT(p)   inw(p + 144)
  37847. +extern void inswb(int from, void *to, int len);
  37848. +
  37849. +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
  37850. +              int len)
  37851. +{
  37852. +  int ioaddr = instance->io_port;
  37853. +printk("writing %p len %d\n",addr, len);
  37854. +  if(!len) return -1;
  37855. +
  37856. +  while(1)
  37857. +  {
  37858. +    int status;
  37859. +    while(((status = STAT(ioaddr)) & 0x100)==0);
  37860. +  }
  37861. +}
  37862. +
  37863. +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
  37864. +              int len)
  37865. +{
  37866. +  int ioaddr = instance->io_port;
  37867. +printk("reading %p len %d\n", addr, len);
  37868. +  while(len > 0)
  37869. +  {
  37870. +    int status, timeout;
  37871. +    unsigned long b;
  37872. +    
  37873. +    timeout = 0x01FFFFFF;
  37874. +    
  37875. +    while(((status = STAT(ioaddr)) & 0x100)==0)
  37876. +    {
  37877. +      timeout--;
  37878. +      if(status & 0x200 || !timeout)
  37879. +      {
  37880. +        printk("status = %08lX\n",status);
  37881. +        return 1;
  37882. +      }
  37883. +    }
  37884. +    if(len >= 128)
  37885. +    {
  37886. +      inswb(ioaddr + 136, addr, 128);
  37887. +      addr += 128;
  37888. +      len -= 128;
  37889. +    }
  37890. +    else
  37891. +    {
  37892. +      b = (unsigned long) inw(ioaddr + 136);
  37893. +      *addr ++ = b;
  37894. +      len -= 1;
  37895. +      if(len)
  37896. +        *addr ++ = b>>8;
  37897. +      len -= 1;
  37898. +    }
  37899. +  }
  37900. +  return 0;
  37901. +}
  37902. +
  37903. +static char oak_NCR5380_read(struct Scsi_Host *instance, int reg)
  37904. +{
  37905. +  int ioaddr = instance->io_port;
  37906. +  return inb(ioaddr + reg);
  37907. +}
  37908. +
  37909. +static void oak_NCR5380_write(struct Scsi_Host *instance, int reg, int value)
  37910. +{
  37911. +  int ioaddr = instance->io_port;
  37912. +  outb(value, ioaddr + reg);
  37913. +}
  37914. +
  37915. +#undef STAT
  37916. +
  37917. +#include "NCR5380.c"
  37918. +
  37919. +#ifdef MODULE
  37920. +
  37921. +Scsi_Host_Template driver_template = OAK_NCR5380;
  37922. +
  37923. +#include "scsi_module.c"
  37924. +#endif
  37925. +
  37926. diff -urNwbB linux/arch/arm/drivers/scsi/oak.h linux.arm/arch/arm/drivers/scsi/oak.h
  37927. --- linux/arch/arm/drivers/scsi/oak.h    Thu Jan  1 01:00:00 1970
  37928. +++ linux.arm/arch/arm/drivers/scsi/oak.h    Sat Feb 24 09:36:56 1996
  37929. @@ -0,0 +1,86 @@
  37930. +/*
  37931. + * Cumana Generic NCR5380 driver defines
  37932. + *
  37933. + * Copyright 1993, Drew Eckhardt
  37934. + *    Visionary Computing
  37935. + *    (Unix and Linux consulting and custom programming)
  37936. + *    drew@colorado.edu
  37937. + *      +1 (303) 440-4894
  37938. + *
  37939. + * ALPHA RELEASE 1.
  37940. + *
  37941. + * For more information, please consult
  37942. + *
  37943. + * NCR 5380 Family
  37944. + * SCSI Protocol Controller
  37945. + * Databook
  37946. + *
  37947. + * NCR Microelectronics
  37948. + * 1635 Aeroplaza Drive
  37949. + * Colorado Springs, CO 80916
  37950. + * 1+ (719) 578-3400
  37951. + * 1+ (800) 334-5454
  37952. + */
  37953. +
  37954. +/*
  37955. + * $Log: oak_NCR5380.h,v $
  37956. + */
  37957. +
  37958. +#ifndef OAK_NCR5380_H
  37959. +#define OAK_NCR5380_H
  37960. +
  37961. +#define OAK_NCR5380_PUBLIC_RELEASE 1
  37962. +
  37963. +
  37964. +#ifndef ASM
  37965. +int oak_NCR5380_abort(Scsi_Cmnd *);
  37966. +int oak_NCR5380_detect(Scsi_Host_Template *);
  37967. +const char *oak_NCR5380_info(struct Scsi_Host *);
  37968. +int oak_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
  37969. +int oak_NCR5380_reset(Scsi_Cmnd *);
  37970. +
  37971. +
  37972. +#ifndef NULL
  37973. +#define NULL 0
  37974. +#endif
  37975. +
  37976. +#ifndef CMD_PER_LUN
  37977. +#define CMD_PER_LUN 2
  37978. +#endif
  37979. +
  37980. +#ifndef CAN_QUEUE
  37981. +#define CAN_QUEUE 16
  37982. +#endif
  37983. +
  37984. +#define OAK_NCR5380 {NULL, NULL, "Oak 16-bit SCSI",            \
  37985. +    oak_NCR5380_detect, NULL, oak_NCR5380_info, NULL,        \
  37986. +    oak_NCR5380_queue_command, oak_NCR5380_abort,             \
  37987. +    oak_NCR5380_reset, NULL,                     \
  37988. +    NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,        \
  37989. +    /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
  37990. +
  37991. +#ifndef HOSTS_C
  37992. +#define NCR5380_implementation_fields \
  37993. +    int port, ctrl
  37994. +
  37995. +#define NCR5380_local_declare() \
  37996. +        struct Scsi_Host *_instance
  37997. +
  37998. +#define NCR5380_setup(instance) \
  37999. +        _instance = instance
  38000. +
  38001. +#define NCR5380_read(reg) oak_NCR5380_read(_instance, reg)
  38002. +#define NCR5380_write(reg, value) oak_NCR5380_write(_instance, reg, value)
  38003. +
  38004. +#define NCR5380_intr oak_NCR5380_intr
  38005. +#define NCR5380_queue_command oak_NCR5380_queue_command
  38006. +#define NCR5380_abort oak_NCR5380_abort
  38007. +#define NCR5380_reset oak_NCR5380_reset
  38008. +
  38009. +#define BOARD_NORMAL    0
  38010. +#define BOARD_NCR53C400    1
  38011. +
  38012. +#endif /* else def HOSTS_C */
  38013. +#endif /* ndef ASM */
  38014. +#endif /* OAK_NCR5380_H */
  38015. +
  38016. diff -urNwbB linux/arch/arm/drivers/scsi/scsi.c linux.arm/arch/arm/drivers/scsi/scsi.c
  38017. --- linux/arch/arm/drivers/scsi/scsi.c    Thu Jan  1 01:00:00 1970
  38018. +++ linux.arm/arch/arm/drivers/scsi/scsi.c    Sat Feb 24 09:36:57 1996
  38019. @@ -0,0 +1,3148 @@
  38020. +/*
  38021. + *  scsi.c Copyright (C) 1992 Drew Eckhardt
  38022. + *         Copyright (C) 1993, 1994, 1995 Eric Youngdale
  38023. + *
  38024. + *  generic mid-level SCSI driver
  38025. + *      Initial versions: Drew Eckhardt
  38026. + *      Subsequent revisions: Eric Youngdale
  38027. + *
  38028. + *  <drew@colorado.edu>
  38029. + *
  38030. + *  Bug correction thanks go to :
  38031. + *      Rik Faith <faith@cs.unc.edu>
  38032. + *      Tommy Thorn <tthorn>
  38033. + *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
  38034. + *
  38035. + *  Modified by Eric Youngdale eric@aib.com to
  38036. + *  add scatter-gather, multiple outstanding request, and other
  38037. + *  enhancements.
  38038. + *
  38039. + *  Native multichannel and wide scsi support added 
  38040. + *  by Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
  38041. + */
  38042. +#ifdef MODULE
  38043. +/*
  38044. + * Don't import our own symbols, as this would severely mess up our
  38045. + * symbol tables.
  38046. + */
  38047. +#define _SCSI_SYMS_VER_
  38048. +#include <linux/autoconf.h>
  38049. +#include <linux/module.h>
  38050. +#include <linux/version.h>
  38051. +#else
  38052. +#define MOD_INC_USE_COUNT
  38053. +#define MOD_DEC_USE_COUNT
  38054. +#endif
  38055. +
  38056. +#include <asm/system.h>
  38057. +#include <linux/sched.h>
  38058. +#include <linux/timer.h>
  38059. +#include <linux/string.h>
  38060. +#include <linux/malloc.h>
  38061. +#include <asm/irq.h>
  38062. +#include <asm/dma.h>
  38063. +#include <linux/ioport.h>
  38064. +#include <linux/kernel.h>
  38065. +#include<linux/stat.h>
  38066. +
  38067. +#include "../block/blk.h"
  38068. +#include "scsi.h"
  38069. +#include "hosts.h"
  38070. +#include "constants.h"
  38071. +
  38072. +
  38073. +#undef USE_STATIC_SCSI_MEMORY
  38074. +
  38075. +/*
  38076. +static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.5 1993/09/24 12:45:18 drew Exp drew $";
  38077. +*/
  38078. +
  38079. +
  38080. +/* Command groups 3 and 4 are reserved and should never be used.  */
  38081. +const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };
  38082. +
  38083. +#define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
  38084. +
  38085. +static void scsi_done (Scsi_Cmnd *SCpnt);
  38086. +static int update_timeout (Scsi_Cmnd *, int);
  38087. +static void print_inquiry(unsigned char *data);
  38088. +static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid);
  38089. +
  38090. +static unsigned char * dma_malloc_freelist = NULL;
  38091. +static int scsi_need_isa_bounce_buffers;
  38092. +static unsigned int dma_sectors = 0;
  38093. +unsigned int dma_free_sectors = 0;
  38094. +unsigned int need_isa_buffer = 0;
  38095. +static unsigned char ** dma_malloc_pages = NULL;
  38096. +
  38097. +static int time_start;
  38098. +static int time_elapsed;
  38099. +static volatile struct Scsi_Host * host_active = NULL;
  38100. +#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
  38101. +              || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
  38102. +
  38103. +#define MAX_SCSI_DEVICE_CODE 10
  38104. +const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
  38105. +{
  38106. +    "Direct-Access    ",
  38107. +    "Sequential-Access",
  38108. +    "Printer          ",
  38109. +    "Processor        ",
  38110. +    "WORM             ",
  38111. +    "CD-ROM           ",
  38112. +    "Scanner          ",
  38113. +    "Optical Device   ",
  38114. +    "Medium Changer   ",
  38115. +    "Communications   "
  38116. +};
  38117. +
  38118. +
  38119. +/*
  38120. + * global variables :
  38121. + * scsi_devices an array of these specifying the address for each
  38122. + * (host, id, LUN)
  38123. + */
  38124. +
  38125. +Scsi_Device * scsi_devices = NULL;
  38126. +
  38127. +/* Process ID of SCSI commands */
  38128. +unsigned long scsi_pid = 0;
  38129. +
  38130. +static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
  38131. +static void resize_dma_pool(void);
  38132. +
  38133. +/* This variable is merely a hook so that we can debug the kernel with gdb. */
  38134. +Scsi_Cmnd * last_cmnd = NULL;
  38135. +
  38136. +/* This is the pointer to the /proc/scsi code. 
  38137. + * It is only initialized to !=0 if the scsi code is present 
  38138. + */ 
  38139. +extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start, 
  38140. +                      off_t offset, int length, int inout); 
  38141. +extern int dispatch_scsi_info(int ino, char *buffer, char **start, 
  38142. +                  off_t offset, int length, int inout); 
  38143. +
  38144. +struct proc_dir_entry proc_scsi_scsi = {
  38145. +    PROC_SCSI_SCSI, 4, "scsi",
  38146. +    S_IFREG | S_IRUGO | S_IWUSR, 2, 0, 0, 0, 
  38147. +    NULL,
  38148. +    NULL, NULL,
  38149. +    NULL, NULL, NULL
  38150. +};
  38151. +
  38152. +
  38153. +/*
  38154. + *  As the scsi do command functions are intelligent, and may need to
  38155. + *  redo a command, we need to keep track of the last command
  38156. + *  executed on each one.
  38157. + */
  38158. +
  38159. +#define WAS_RESET       0x01
  38160. +#define WAS_TIMEDOUT    0x02
  38161. +#define WAS_SENSE       0x04
  38162. +#define IS_RESETTING    0x08
  38163. +#define IS_ABORTING     0x10
  38164. +#define ASKED_FOR_SENSE 0x20
  38165. +
  38166. +/*
  38167. + *  This is the number  of clock ticks we should wait before we time out
  38168. + *  and abort the command.  This is for  where the scsi.c module generates
  38169. + *  the command, not where it originates from a higher level, in which
  38170. + *  case the timeout is specified there.
  38171. + *
  38172. + *  ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
  38173. + *  respectively.
  38174. + */
  38175. +
  38176. +#ifdef DEBUG_TIMEOUT
  38177. +static void scsi_dump_status(void);
  38178. +#endif
  38179. +
  38180. +
  38181. +#ifdef DEBUG
  38182. +    #define SCSI_TIMEOUT (5*HZ)
  38183. +#else
  38184. +    #define SCSI_TIMEOUT (1*HZ)
  38185. +#endif
  38186. +
  38187. +#ifdef DEBUG
  38188. +    #define SENSE_TIMEOUT SCSI_TIMEOUT
  38189. +    #define ABORT_TIMEOUT SCSI_TIMEOUT
  38190. +    #define RESET_TIMEOUT SCSI_TIMEOUT
  38191. +#else
  38192. +    #define SENSE_TIMEOUT (5*HZ/10)
  38193. +    #define RESET_TIMEOUT (5*HZ/10)
  38194. +    #define ABORT_TIMEOUT (5*HZ/10)
  38195. +#endif
  38196. +
  38197. +#define MIN_RESET_DELAY (1*HZ)
  38198. +
  38199. +/* Do not call reset on error if we just did a reset within 10 sec. */
  38200. +#define MIN_RESET_PERIOD (10*HZ)
  38201. +
  38202. +/* The following devices are known not to tolerate a lun != 0 scan for
  38203. + * one reason or another.  Some will respond to all luns, others will
  38204. + * lock up. 
  38205. + */
  38206. +
  38207. +#define BLIST_NOLUN     0x01
  38208. +#define BLIST_FORCELUN  0x02
  38209. +#define BLIST_BORKEN    0x04
  38210. +#define BLIST_KEY       0x08
  38211. +#define BLIST_SINGLELUN 0x10
  38212. +
  38213. +struct dev_info{
  38214. +    const char * vendor;
  38215. +    const char * model;
  38216. +    const char * revision; /* Latest revision known to be bad.  Not used yet */
  38217. +    unsigned flags;
  38218. +};
  38219. +
  38220. +/*
  38221. + * This is what was previously known as the blacklist.  The concept
  38222. + * has been expanded so that we can specify other types of things we
  38223. + * need to be aware of.
  38224. + */
  38225. +static struct dev_info device_list[] =
  38226. +{
  38227. +{"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
  38228. +{"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
  38229. +{"DENON","DRD-25X","V", BLIST_NOLUN},           /* Locks up if probed for lun != 0 */
  38230. +{"HITACHI","DK312C","CM81", BLIST_NOLUN},       /* Responds to all lun - dtg */
  38231. +{"HITACHI","DK314C","CR21" , BLIST_NOLUN},      /* responds to all lun */
  38232. +{"IMS", "CDD521/10","2.06", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
  38233. +{"MAXTOR","XT-3280","PR02", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
  38234. +{"MAXTOR","XT-4380S","B3C", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
  38235. +{"MAXTOR","MXT-1240S","I1.2", BLIST_NOLUN},     /* Locks up when LUN>0 polled */
  38236. +{"MAXTOR","XT-4170S","B5A", BLIST_NOLUN},       /* Locks-up sometimes when LUN>0 polled. */
  38237. +{"MAXTOR","XT-8760S","B7B", BLIST_NOLUN},       /* guess what? */
  38238. +{"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
  38239. +{"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
  38240. +{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},   /* causes failed REQUEST SENSE on lun 1 
  38241. +                         * for aha152x controller, which causes 
  38242. +                         * SCSI code to reset bus.*/
  38243. +{"SEAGATE", "ST296","921", BLIST_NOLUN},        /* Responds to all lun */
  38244. +{"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN},
  38245. +{"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN},
  38246. +{"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN},
  38247. +{"TANDBERG","TDC 3600","U07", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */
  38248. +{"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1 
  38249. +                         * for seagate controller, which causes 
  38250. +                         * SCSI code to reset bus.*/
  38251. +{"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1 
  38252. +                         * for seagate controller, which causes 
  38253. +                         * SCSI code to reset bus.*/
  38254. +{"QUANTUM","LPS525S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
  38255. +{"QUANTUM","PD1225S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
  38256. +{"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN},   /* Locks up if polled for lun != 0 */
  38257. +{"SANKYO", "CP525","6.64", BLIST_NOLUN},        /* causes failed REQ SENSE, extra reset */
  38258. +{"HP", "C1750A", "3226", BLIST_NOLUN},          /* scanjet iic */
  38259. +{"HP", "C1790A", "", BLIST_NOLUN},              /* scanjet iip */
  38260. +{"HP", "C2500A", "", BLIST_NOLUN},              /* scanjet iicx */
  38261. +
  38262. +/*
  38263. + * Other types of devices that have special flags.
  38264. + */
  38265. +{"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN},
  38266. +{"TEXEL","CD-ROM","1.06", BLIST_BORKEN},
  38267. +{"INSITE","Floptical   F*8I","*", BLIST_KEY},
  38268. +{"INSITE","I325VM","*", BLIST_KEY},
  38269. +{"PIONEER","CD-ROMDRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
  38270. +{"PIONEER","CD-ROMDRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
  38271. +/*
  38272. + * Must be at end of list...
  38273. + */
  38274. +{NULL, NULL, NULL}
  38275. +};
  38276. +
  38277. +static int get_device_flags(unsigned char * response_data){
  38278. +    int i = 0;
  38279. +    unsigned char * pnt;
  38280. +    for(i=0; 1; i++){
  38281. +    if(device_list[i].vendor == NULL) return 0;
  38282. +    pnt = &response_data[8];
  38283. +    while(*pnt && *pnt == ' ') pnt++;
  38284. +    if(memcmp(device_list[i].vendor, pnt,
  38285. +          strlen(device_list[i].vendor))) continue;
  38286. +    pnt = &response_data[16];
  38287. +    while(*pnt && *pnt == ' ') pnt++;
  38288. +    if(memcmp(device_list[i].model, pnt,
  38289. +          strlen(device_list[i].model))) continue;
  38290. +    return device_list[i].flags;
  38291. +    }
  38292. +    return 0;
  38293. +}
  38294. +
  38295. +/*
  38296. + *  As the actual SCSI command runs in the background, we must set up a
  38297. + *  flag that tells scan_scsis() when the result it has is valid.
  38298. + *  scan_scsis can set the_result to -1, and watch for it to become the
  38299. + *  actual return code for that call.  the scan_scsis_done function() is
  38300. + *  our user specified completion function that is passed on to the
  38301. + *  scsi_do_cmd() function.
  38302. + */
  38303. +
  38304. +volatile int in_scan_scsis = 0;
  38305. +static int the_result;
  38306. +
  38307. +void scsi_make_blocked_list(void)  {
  38308. +    int block_count = 0, index;
  38309. +    unsigned int flags;
  38310. +    struct Scsi_Host * sh[128], * shpnt;
  38311. +    
  38312. +    /*
  38313. +     * Create a circular linked list from the scsi hosts which have
  38314. +     * the "wish_block" field in the Scsi_Host structure set.
  38315. +     * The blocked list should include all the scsi hosts using ISA DMA.
  38316. +     * In some systems, using two dma channels simultaneously causes
  38317. +     * unpredictable results.
  38318. +     * Among the scsi hosts in the blocked list, only one host at a time
  38319. +     * is allowed to have active commands queued. The transition from
  38320. +     * one active host to the next one is allowed only when host_busy == 0
  38321. +     * for the active host (which implies host_busy == 0 for all the hosts
  38322. +     * in the list). Moreover for block devices the transition to a new
  38323. +     * active host is allowed only when a request is completed, since a
  38324. +     * block device request can be divided into multiple scsi commands
  38325. +     * (when there are few sg lists or clustering is disabled).
  38326. +     *
  38327. +     * (DB, 4 Feb 1995)
  38328. +     */
  38329. +    
  38330. +    save_flags(flags);
  38331. +    cli();
  38332. +    host_active = NULL;
  38333. +    
  38334. +    for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
  38335. +    
  38336. +#if 0
  38337. +    /*
  38338. +     * Is this is a candidate for the blocked list?
  38339. +     * Useful to put into the blocked list all the hosts whose driver
  38340. +     * does not know about the host->block feature.
  38341. +     */
  38342. +    if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1;
  38343. +#endif
  38344. +    
  38345. +    if (shpnt->wish_block) sh[block_count++] = shpnt;
  38346. +    }
  38347. +    
  38348. +    if (block_count == 1) sh[0]->block = NULL;
  38349. +    
  38350. +    else if (block_count > 1) {
  38351. +    
  38352. +    for(index = 0; index < block_count - 1; index++) {
  38353. +        sh[index]->block = sh[index + 1];
  38354. +        printk("scsi%d : added to blocked host list.\n",
  38355. +           sh[index]->host_no);
  38356. +    }
  38357. +    
  38358. +    sh[block_count - 1]->block = sh[0];
  38359. +    printk("scsi%d : added to blocked host list.\n",
  38360. +           sh[index]->host_no);
  38361. +    }
  38362. +    
  38363. +    restore_flags(flags);
  38364. +}
  38365. +
  38366. +static void scan_scsis_done (Scsi_Cmnd * SCpnt)
  38367. +{
  38368. +    
  38369. +#ifdef DEBUG
  38370. +    printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);
  38371. +#endif
  38372. +    SCpnt->request.rq_status = RQ_SCSI_DONE;
  38373. +    
  38374. +    if (SCpnt->request.sem != NULL)
  38375. +    up(SCpnt->request.sem);
  38376. +}
  38377. +
  38378. +#ifdef CONFIG_SCSI_MULTI_LUN
  38379. +static int max_scsi_luns = 8;
  38380. +#else
  38381. +static int max_scsi_luns = 1;
  38382. +#endif
  38383. +
  38384. +void scsi_luns_setup(char *str, int *ints) {
  38385. +    if (ints[0] != 1)
  38386. +    printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
  38387. +    else
  38388. +    max_scsi_luns = ints[1];
  38389. +}
  38390. +
  38391. +/*
  38392. + *  Detecting SCSI devices :
  38393. + *  We scan all present host adapter's busses,  from ID 0 to ID (max_id).
  38394. + *  We use the INQUIRY command, determine device type, and pass the ID /
  38395. + *  lun address of all sequential devices to the tape driver, all random
  38396. + *  devices to the disk driver.
  38397. + */
  38398. +static
  38399. +void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, 
  38400. +         unchar hchannel, unchar hid, unchar hlun)
  38401. +{
  38402. +    int dev, lun, type, channel;
  38403. +    unsigned char scsi_cmd [12];
  38404. +    unsigned char scsi_result0 [256];
  38405. +    unsigned char * scsi_result;
  38406. +    Scsi_Device * SDpnt, *SDtail;
  38407. +    struct Scsi_Device_Template * sdtpnt;
  38408. +    int                 bflags;
  38409. +    int                 max_dev_lun = 0;
  38410. +    Scsi_Cmnd  *SCpnt;
  38411. +    
  38412. +    ++in_scan_scsis;
  38413. +    lun = 0;
  38414. +    type = -1;
  38415. +    SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC|GFP_DMA);
  38416. +    SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
  38417. +    SDtail = scsi_devices;
  38418. +    
  38419. +    if(scsi_devices) while(SDtail->next) SDtail = SDtail->next;
  38420. +    
  38421. +    /* Make sure we have something that is valid for DMA purposes */
  38422. +    scsi_result = ((!dma_malloc_freelist  || !shpnt->unchecked_isa_dma)
  38423. +           ?  &scsi_result0[0] : scsi_malloc(512));
  38424. +    
  38425. +    if(scsi_result == NULL) {
  38426. +    printk("Unable to obtain scsi_result buffer\n");
  38427. +    goto leave;
  38428. +    }
  38429. +    
  38430. +    shpnt->host_queue = SCpnt; /* We need this so that commands can time out */
  38431. +
  38432. +    if(hardcoded == 1) {
  38433. +    channel = hchannel;
  38434. +    dev = hid;
  38435. +    lun = hlun;
  38436. +    goto crude; /* Anyone remember good ol' BASIC ?  :-) */
  38437. +    }
  38438. +
  38439. +    for (channel = 0; channel <= shpnt->max_channel; channel++)
  38440. +    {
  38441. +    for (dev = 0; dev < shpnt->max_id; ++dev) {
  38442. +        if (shpnt->this_id != dev) {
  38443. +        
  38444. +        /*
  38445. +         * We need the for so our continue, etc. work fine.
  38446. +         * We put this in a variable so that we can override
  38447. +         * it during the scan if we detect a device *KNOWN*
  38448. +         * to have multiple logical units.
  38449. +         */
  38450. +        max_dev_lun = (max_scsi_luns < shpnt->max_lun ? 
  38451. +                   max_scsi_luns : shpnt->max_lun);
  38452. +
  38453. +        for (lun = 0; lun < max_dev_lun; ++lun)
  38454. +        {
  38455. +        crude:
  38456. +            memset(SDpnt, 0, sizeof(Scsi_Device));
  38457. +            SDpnt->host = shpnt;
  38458. +            SDpnt->id = dev;
  38459. +            SDpnt->lun = lun;
  38460. +            SDpnt->channel = channel;
  38461. +
  38462. +            /* Some low level driver could use device->type (DB) */
  38463. +            SDpnt->type = -1;
  38464. +            /*
  38465. +             * Assume that the device will have handshaking problems, 
  38466. +             * and then fix this field later if it turns out it doesn't
  38467. +             */
  38468. +            SDpnt->borken = 1;
  38469. +                    SDpnt->was_reset = 0;
  38470. +                    SDpnt->expecting_cc_ua = 0;
  38471. +            
  38472. +            scsi_cmd[0] = TEST_UNIT_READY;
  38473. +            scsi_cmd[1] = lun << 5;
  38474. +            scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
  38475. +            
  38476. +            memset(SCpnt, 0,  sizeof(Scsi_Cmnd));
  38477. +            SCpnt->host = SDpnt->host;
  38478. +            SCpnt->device = SDpnt;
  38479. +            SCpnt->target = SDpnt->id;
  38480. +            SCpnt->lun = SDpnt->lun;
  38481. +            SCpnt->channel = SDpnt->channel;
  38482. +
  38483. +            {
  38484. +            /*
  38485. +             * Do the actual command, and wait for it to finish
  38486. +             */
  38487. +            struct semaphore sem = MUTEX_LOCKED;
  38488. +            SCpnt->request.sem = &sem;
  38489. +            SCpnt->request.rq_status = RQ_SCSI_BUSY;
  38490. +            scsi_do_cmd (SCpnt, (void *)  scsi_cmd, 
  38491. +                     (void *) scsi_result,
  38492. +                     256,  scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
  38493. +            down(&sem);
  38494. +            }
  38495. +
  38496. +#if defined(DEBUG) || defined(DEBUG_INIT)
  38497. +            printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
  38498. +            printk("scsi: return code %08x\n", SCpnt->result);
  38499. +#endif
  38500. +
  38501. +            if(SCpnt->result) {
  38502. +            if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
  38503. +                 (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
  38504. +                ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
  38505. +                if (SCpnt->sense_buffer[2] &0xe0)
  38506. +                continue; /* No devices here... */
  38507. +                if(((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
  38508. +                   ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION))
  38509. +                continue;
  38510. +            }
  38511. +            else
  38512. +                break;
  38513. +            }
  38514. +            
  38515. +#if defined (DEBUG) || defined(DEBUG_INIT)
  38516. +            printk("scsi: performing INQUIRY\n");
  38517. +#endif
  38518. +
  38519. +            /*
  38520. +             * Build an INQUIRY command block.
  38521. +             */
  38522. +            scsi_cmd[0] = INQUIRY;
  38523. +            scsi_cmd[1] = (lun << 5) & 0xe0;
  38524. +            scsi_cmd[2] = 0;
  38525. +            scsi_cmd[3] = 0;
  38526. +            scsi_cmd[4] = 255;
  38527. +            scsi_cmd[5] = 0;
  38528. +            
  38529. +            SCpnt->cmd_len = 0;
  38530. +
  38531. +            {
  38532. +            struct semaphore sem = MUTEX_LOCKED;
  38533. +            SCpnt->request.sem = &sem;
  38534. +            SCpnt->request.rq_status = RQ_SCSI_BUSY;
  38535. +            scsi_do_cmd (SCpnt, (void *)  scsi_cmd, 
  38536. +                 (void *) scsi_result,
  38537. +                 256,  scan_scsis_done, SCSI_TIMEOUT, 3);
  38538. +            down(&sem);
  38539. +            }
  38540. +            
  38541. +            the_result = SCpnt->result;
  38542. +            
  38543. +#if defined(DEBUG) || defined(DEBUG_INIT)
  38544. +            if (!the_result)
  38545. +            printk("scsi: INQUIRY successful\n");
  38546. +            else
  38547. +            printk("scsi: INQUIRY failed with code %08x\n", the_result);
  38548. +#endif
  38549. +            
  38550. +            if(the_result) break;
  38551. +            
  38552. +            /* skip other luns on this device */
  38553. +            
  38554. +            if (!the_result)
  38555. +            {
  38556. +            /* It would seem some TOSHIBA CDROM 
  38557. +             * gets things wrong 
  38558. +             */
  38559. +            if (!strncmp(scsi_result+8,"TOSHIBA",7) &&
  38560. +                !strncmp(scsi_result+16,"CD-ROM",6) &&
  38561. +                scsi_result[0] == TYPE_DISK) {
  38562. +                scsi_result[0] = TYPE_ROM;
  38563. +                scsi_result[1] |= 0x80;  /* removable */
  38564. +            }
  38565. +            
  38566. +            if (!strncmp(scsi_result+8,"NEC",3)) {
  38567. +                if (!strncmp(scsi_result+16,"CD-ROM DRIVE:84 ",16) || 
  38568. +                !strncmp(scsi_result+16,"CD-ROM DRIVE:25",15))
  38569. +                SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR;
  38570. +                else
  38571. +                SDpnt->manufacturer = SCSI_MAN_NEC;
  38572. +            } else if (!strncmp(scsi_result+8,"TOSHIBA",7))
  38573. +                SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
  38574. +            else if (!strncmp(scsi_result+8,"SONY",4))
  38575. +                SDpnt->manufacturer = SCSI_MAN_SONY;
  38576. +                        else if (!strncmp(scsi_result+8, "PIONEER", 7))
  38577. +                            SDpnt->manufacturer = SCSI_MAN_PIONEER;
  38578. +            else
  38579. +                SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
  38580. +            
  38581. +            memcpy(SDpnt->vendor, scsi_result+8, 8);
  38582. +            memcpy(SDpnt->model, scsi_result+16, 16);
  38583. +            memcpy(SDpnt->rev, scsi_result+32, 4);
  38584. +            SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
  38585. +            SDpnt->lockable = SDpnt->removable;
  38586. +            SDpnt->changed = 0;
  38587. +            SDpnt->access_count = 0;
  38588. +            SDpnt->busy = 0;
  38589. +            SDpnt->has_cmdblocks = 0;
  38590. +            /*
  38591. +             * Currently, all sequential devices are assumed to be
  38592. +             * tapes, all random devices disk, with the appropriate
  38593. +             * read only flags set for ROM / WORM treated as RO.
  38594. +             */
  38595. +            
  38596. +            switch (type = (scsi_result[0] & 0x1f))
  38597. +            {
  38598. +            case TYPE_TAPE :
  38599. +            case TYPE_DISK :
  38600. +            case TYPE_MOD :
  38601. +            case TYPE_PROCESSOR :