diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/Changes linux-2.5/Documentation/Changes --- linux-2.5.20/Documentation/Changes Mon Jun 3 02:44:53 2002 +++ linux-2.5/Documentation/Changes Tue Jun 4 00:29:15 2002 @@ -77,11 +77,13 @@ have not received much testing for Linux kernel compilation, and there are almost certainly bugs (mainly, but not exclusively, in the kernel) that will need to be fixed in order to use these compilers. In any case, using -pgcc instead of plain gcc is just asking for trouble. +pgcc instead of egcs or plain gcc is just asking for trouble. -Note that gcc 2.7.2.3 and gcc 2.91.66 (egcs-1.1.2) are no longer supported -kernel compilers. The kernel no longer works around bugs in these versions, -and, in fact, will refuse to be compiled with it. +Note that gcc 2.7.2.3 is no longer a supported kernel compiler. The kernel +no longer works around bugs in gcc 2.7.2.3 and, in fact, will refuse to +be compiled with it. egcs-1.1.2 has register allocation problems in very +obscure cases. We have ensured the kernel does not trip these in any known +situation. The 2.5 tree is likely to drop egcs-1.1.2 workarounds. The Red Hat gcc 2.96 compiler subtree can also be used to build this tree. You should ensure you use gcc-2.96-74 or later. gcc-2.96-54 will not build @@ -273,6 +275,10 @@ Kernel compilation ****************** +egcs 1.1.2 (gcc 2.91.66) +------------------------ +o + gcc 2.95.3 ---------- o @@ -314,7 +320,7 @@ Reiserfsprogs ------------- -o +o LVM toolset ----------- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/DocBook/Makefile linux-2.5/Documentation/DocBook/Makefile --- linux-2.5.20/Documentation/DocBook/Makefile Mon Jun 3 02:44:49 2002 +++ linux-2.5/Documentation/DocBook/Makefile Mon Jun 3 17:10:18 2002 @@ -20,7 +20,7 @@ @$(MAKE) -C $(TOPDIR)/scripts doc-progs $(BOOKS): $(TOPDIR)/scripts/docgen $(TOPDIR)/scripts/gen-all-syms \ - $(TOPDIR)/scripts/kernel-doc $(TOPDIR)/scripts/docproc + $(TOPDIR)/scripts/kernel-doc $(TOPDIR)/scripts/docproc .PHONY: sgmldocs psdocs pdfdocs htmldocs clean mrproper @@ -31,6 +31,8 @@ pdfdocs: $(PDF) htmldocs: $(HTML) + +man: kernel-api-man %.eps: %.fig fig2dev -Leps $< $@ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/DocBook/kernel-api.tmpl linux-2.5/Documentation/DocBook/kernel-api.tmpl --- linux-2.5.20/Documentation/DocBook/kernel-api.tmpl Mon Jun 3 02:44:37 2002 +++ linux-2.5/Documentation/DocBook/kernel-api.tmpl Mon Jun 3 17:10:18 2002 @@ -48,6 +48,12 @@ Delaying, scheduling, and timer routines !Ekernel/sched.c +!Ekernel/context.c +!Ekernel/timer.c + + + Misc functions +!Ekernel/exit.c diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/arm/README linux-2.5/Documentation/arm/README --- linux-2.5.20/Documentation/arm/README Mon Jun 3 02:44:46 2002 +++ linux-2.5/Documentation/arm/README Wed May 8 14:50:36 2002 @@ -7,8 +7,8 @@ --------------------- In order to compile ARM Linux, you will need a compiler capable of - generating ARM ELF code with GNU extensions. GCC 2.95.1 and EGCS 1.1.2 - are good compilers. + generating ARM ELF code with GNU extensions. GCC 2.95.3 is a good + compiler. To build ARM Linux natively, you shouldn't have to alter the ARCH = line in the top level Makefile. However, if you don't have the ARM Linux ELF diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/isdn/README.HiSax linux-2.5/Documentation/isdn/README.HiSax --- linux-2.5.20/Documentation/isdn/README.HiSax Mon Jun 3 02:44:42 2002 +++ linux-2.5/Documentation/isdn/README.HiSax Fri May 3 03:49:06 2002 @@ -52,6 +52,7 @@ Sedlbauer Speed Star/Speed Star2 (PCMCIA) Sedlbauer ISDN-Controller PC/104 USR Sportster internal TA (compatible Stollmann tina-pp V3) +USR internal TA PCI ith Kommunikationstechnik GmbH MIC 16 ISA card Traverse Technologie NETjet PCI S0 card and NETspider U card Ovislink ISDN sc100-p card (NETjet driver) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/kernel-doc-nano-HOWTO.txt linux-2.5/Documentation/kernel-doc-nano-HOWTO.txt --- linux-2.5.20/Documentation/kernel-doc-nano-HOWTO.txt Mon Jun 3 02:44:49 2002 +++ linux-2.5/Documentation/kernel-doc-nano-HOWTO.txt Fri May 3 03:49:06 2002 @@ -73,10 +73,10 @@ mkdir $ARGV[0],0777; $state = 0; while () { - if (/^\.TH \"[^\"]*\" 4 \"([^\"]*)\"/) { + if (/^\.TH \"[^\"]*\" (\d) \"([^\"]*)\"/) { if ($state == 1) { close OUT } $state = 1; - $fn = "$ARGV[0]/$1.4"; + $fn = "$ARGV[0]/$2.$1"; print STDERR "Creating $fn\n"; open OUT, ">$fn" or die "can't open $fn: $!\n"; print OUT $_; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/kernel-parameters.txt linux-2.5/Documentation/kernel-parameters.txt --- linux-2.5.20/Documentation/kernel-parameters.txt Mon Jun 3 02:44:50 2002 +++ linux-2.5/Documentation/kernel-parameters.txt Sat Jun 1 00:34:32 2002 @@ -127,7 +127,7 @@ BusLogic= [HW,SCSI] - cachesize= [BUGS=ix86] Override level 2 CPU cache size detection. + cachesize= [BUGS=IA-32] Override level 2 CPU cache size detection. Sometimes CPU hardware bugs make them report the cache size incorrectly. The kernel will attempt work arounds to fix known problems, but for some CPUs it is not @@ -319,8 +319,6 @@ max_scsi_luns= [SCSI] - mca-pentium [BUGS=ix86] - mcd= [HW,CD] mcdx= [HW,CD] @@ -339,6 +337,9 @@ memfrac= [KNL] + mem=nopentium [BUGS=IA-32] Disable usage of 4MB pages for kernel + memory. + mga= [HW,DRM] mpu401= [HW,SOUND] @@ -365,9 +366,9 @@ nfsroot= [NFS] nfs root filesystem for disk-less boxes. - nmi_watchdog= [KNL,BUGS=ix86] debugging features for SMP kernels. + nmi_watchdog= [KNL,BUGS=IA-32] debugging features for SMP kernels. - no387 [BUGS=ix86] Tells the kernel to use the 387 maths + no387 [BUGS=IA-32] Tells the kernel to use the 387 maths emulation library even if a 387 maths coprocessor is present. @@ -385,7 +386,9 @@ nohlt [BUGS=ARM] - no-hlt [BUGS=ix86] + no-hlt [BUGS=IA-32] + + noht [SMP,IA-32] Disables P4 Xeon(tm) HyperThreading. noisapnp [ISAPNP] Disables ISA PnP code. @@ -402,7 +405,7 @@ nosync [HW, M68K] Disables sync negotiation for all devices. - notsc [BUGS=ix86] Disable Time Stamp Counter + notsc [BUGS=IA-32] Disable Time Stamp Counter nowb [ARM] @@ -518,7 +521,7 @@ ramdisk_start= [RAM] Starting block of RAM disk image (so you can place it after the kernel image on a boot floppy). - reboot= [BUGS=ix86] + reboot= [BUGS=IA-32] reserve= [KNL,BUGS] force the kernel to ignore some iomem area. @@ -607,7 +610,7 @@ video= [FB] frame buffer configuration. - vga= [BOOT] on ix386, select a particular video mode + vga= [BOOT] on IA-32, select a particular video mode (use vga=ask for menu). This is actually a boot loader parameter; the value is passed to the kernel using a special protocol. See diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/networking/pktgen.txt linux-2.5/Documentation/networking/pktgen.txt --- linux-2.5.20/Documentation/networking/pktgen.txt Thu Jan 1 01:00:00 1970 +++ linux-2.5/Documentation/networking/pktgen.txt Wed Mar 27 13:07:16 2002 @@ -0,0 +1,50 @@ +How to use the Linux packet generator module. + +1. Enable CONFIG_NET_PKTGEN to compile and build pktgen.o, install it + in the place where insmod may find it. +2. Cut script "ipg" (see below). +3. Edit script to set preferred device and destination IP address. +4. Run in shell: ". ipg" +5. After this two commands are defined: + A. "pg" to start generator and to get results. + B. "pgset" to change generator parameters. F.e. + pgset "multiskb 1" use multiple SKBs for packet generation + pgset "multiskb 0" use single SKB for all transmits + pgset "pkt_size 9014" sets packet size to 9014 + pgset "frags 5" packet will consist of 5 fragments + pgset "count 200000" sets number of packets to send + pgset "ipg 5000" sets artificial gap inserted between packets + to 5000 nanoseconds + pgset "dst 10.0.0.1" sets IP destination address + (BEWARE! This generator is very aggressive!) + pgset "dstmac 00:00:00:00:00:00" sets MAC destination address + pgset stop aborts injection + + Also, ^C aborts generator. + +---- cut here + +#! /bin/sh + +modprobe pktgen.o + +function pgset() { + local result + + echo $1 > /proc/net/pg + + result=`cat /proc/net/pg | fgrep "Result: OK:"` + if [ "$result" = "" ]; then + cat /proc/net/pg | fgrep Result: + fi +} + +function pg() { + echo inject > /proc/net/pg + cat /proc/net/pg +} + +pgset "odev eth0" +pgset "dst 0.0.0.0" + +---- cut here diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/s390/Debugging390.txt linux-2.5/Documentation/s390/Debugging390.txt --- linux-2.5.20/Documentation/s390/Debugging390.txt Mon Jun 3 02:44:43 2002 +++ linux-2.5/Documentation/s390/Debugging390.txt Thu Dec 27 16:32:30 2001 @@ -237,9 +237,10 @@ On 390 our limitations & strengths make us slightly different. -For backward compatibility we are only allowed use 31 bits (2GB) -of our 32 bit addresses,however, we use entirely separate address -spaces for the user & kernel. +For backward compatibility ( because of the psw address hi bit which +indicates whether we are in 31 or 64 bit mode ) we are only allowed +use 31 bits (2GB) of our 32 bit addresses. However, +we use entirely separate address spaces for the user & kernel. This means we can support 2GB of non Extended RAM on s/390, & more with the Extended memory managment swap device & @@ -2123,6 +2124,12 @@ now do p/x (*(**$sp+56))&0x7fffffff & so on. + +Another good trick to look at addresses on the stack if you've somehow lost +the backchain is. +x/500xa $sp +This displays anything the name of any known functions above the stack pointer +for 500 bytes. Disassembling instructions without debug info --------------------------------------------- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/sound/rme96xx linux-2.5/Documentation/sound/rme96xx --- linux-2.5.20/Documentation/sound/rme96xx Thu Jan 1 01:00:00 1970 +++ linux-2.5/Documentation/sound/rme96xx Fri Apr 19 20:41:31 2002 @@ -0,0 +1,767 @@ +Beta release of the rme96xx (driver for RME 96XX cards like the +"Hammerfall" and the "Hammerfall light") + +Important: The driver module has to be installed on a freshly rebooted system, +otherwise the driver might not be able to acquire its buffers. + +features: + + - OSS programming interface (i.e. runs with standard OSS soundsoftware) + - OSS/Multichannel interface (OSS multichannel is done by just aquiring + more than 2 channels). The driver does not use more than one device + ( yet .. this feature may be implemented later ) + - more than one RME card supported + +The driver uses a specific multichannel interface, which I will document +when the driver gets stable. (take a look at the defines in rme96xx.h, +which adds blocked multichannel formats i.e instead of +lrlrlrlr --> llllrrrr etc. + +Use the "rmectrl" programm to look at the status of the card .. +or use xrmectrl, a GUI interface for the ctrl program. + +What you can do with the rmectrl program is to set the stereo device for +OSS emulation (e.g. if you use SPDIF out). + +You do: + +./ctrl offset 24 24 + +which makes the stereo device use channels 25 and 26. + +Guenter Geiger + +copy the first part of the attached source code into rmectrl.c +and the second part into xrmectrl (or get the program from +http://gige.xdv.org/pages/soft/pages/rme) + +to compile: gcc -o rmectrl rmectrl.c +------------------------------ snip ------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rme96xx.h" + +/* + remctrl.c + (C) 2000 Guenter Geiger + HP20020201 - Heiko Purnhagen +*/ + +/* # define DEVICE_NAME "/dev/mixer" */ +# define DEVICE_NAME "/dev/mixer1" + + +void usage(void) +{ + fprintf(stderr,"usage: rmectrl [/dev/mixer] [command [options]]\n\n"); + fprintf(stderr,"where command is one of:\n"); + fprintf(stderr," help show this help\n"); + fprintf(stderr," status show status bits\n"); + fprintf(stderr," control show control bits\n"); + fprintf(stderr," mix show mixer/offset status\n"); + fprintf(stderr," master set sync master\n"); + fprintf(stderr," pro set spdif out pro\n"); + fprintf(stderr," emphasis set spdif out emphasis\n"); + fprintf(stderr," dolby set spdif out no audio\n"); + fprintf(stderr," optout set spdif out optical\n"); + fprintf(stderr," wordclock set sync wordclock\n"); + fprintf(stderr," spdifin set spdif in (0=optical,1=coax,2=intern)\n"); + fprintf(stderr," syncref set sync source (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n"); + fprintf(stderr," adat1cd set ADAT1 on internal CD\n"); + fprintf(stderr," offset set dev (0..3) offset (0..25)\n"); + exit(-1); +} + + +int main(int argc, char* argv[]) +{ + int cards; + int ret; + int i; + double ft; + int fd, fdwr; + int param,orig; + rme_status_t stat; + rme_ctrl_t ctrl; + char *device; + int argidx; + + if (argc < 2) + usage(); + + if (*argv[1]=='/') { + device = argv[1]; + argidx = 2; + } + else { + device = DEVICE_NAME; + argidx = 1; + } + + fprintf(stdout,"mixer device %s\n",device); + if ((fd = open(device,O_RDONLY)) < 0) { + fprintf(stdout,"opening device failed\n"); + exit(-1); + } + + if ((fdwr = open(device,O_WRONLY)) < 0) { + fprintf(stdout,"opening device failed\n"); + exit(-1); + } + + if (argc < argidx+1) + usage(); + + if (!strcmp(argv[argidx],"help")) + usage(); + if (!strcmp(argv[argidx],"-h")) + usage(); + if (!strcmp(argv[argidx],"--help")) + usage(); + + if (!strcmp(argv[argidx],"status")) { + ioctl(fd,SOUND_MIXER_PRIVATE2,&stat); + fprintf(stdout,"stat.irq %d\n",stat.irq); + fprintf(stdout,"stat.lockmask %d\n",stat.lockmask); + fprintf(stdout,"stat.sr48 %d\n",stat.sr48); + fprintf(stdout,"stat.wclock %d\n",stat.wclock); + fprintf(stdout,"stat.bufpoint %d\n",stat.bufpoint); + fprintf(stdout,"stat.syncmask %d\n",stat.syncmask); + fprintf(stdout,"stat.doublespeed %d\n",stat.doublespeed); + fprintf(stdout,"stat.tc_busy %d\n",stat.tc_busy); + fprintf(stdout,"stat.tc_out %d\n",stat.tc_out); + fprintf(stdout,"stat.crystalrate %d (0=64k 3=96k 4=88.2k 5=48k 6=44.1k 7=32k)\n",stat.crystalrate); + fprintf(stdout,"stat.spdif_error %d\n",stat.spdif_error); + fprintf(stdout,"stat.bufid %d\n",stat.bufid); + fprintf(stdout,"stat.tc_valid %d\n",stat.tc_valid); + exit (0); + } + + if (!strcmp(argv[argidx],"control")) { + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + fprintf(stdout,"ctrl.start %d\n",ctrl.start); + fprintf(stdout,"ctrl.latency %d (0=64 .. 7=8192)\n",ctrl.latency); + fprintf(stdout,"ctrl.master %d\n",ctrl.master); + fprintf(stdout,"ctrl.ie %d\n",ctrl.ie); + fprintf(stdout,"ctrl.sr48 %d\n",ctrl.sr48); + fprintf(stdout,"ctrl.spare %d\n",ctrl.spare); + fprintf(stdout,"ctrl.doublespeed %d\n",ctrl.doublespeed); + fprintf(stdout,"ctrl.pro %d\n",ctrl.pro); + fprintf(stdout,"ctrl.emphasis %d\n",ctrl.emphasis); + fprintf(stdout,"ctrl.dolby %d\n",ctrl.dolby); + fprintf(stdout,"ctrl.opt_out %d\n",ctrl.opt_out); + fprintf(stdout,"ctrl.wordclock %d\n",ctrl.wordclock); + fprintf(stdout,"ctrl.spdif_in %d (0=optical,1=coax,2=intern)\n",ctrl.spdif_in); + fprintf(stdout,"ctrl.sync_ref %d (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n",ctrl.sync_ref); + fprintf(stdout,"ctrl.spdif_reset %d\n",ctrl.spdif_reset); + fprintf(stdout,"ctrl.spdif_select %d\n",ctrl.spdif_select); + fprintf(stdout,"ctrl.spdif_clock %d\n",ctrl.spdif_clock); + fprintf(stdout,"ctrl.spdif_write %d\n",ctrl.spdif_write); + fprintf(stdout,"ctrl.adat1_cd %d\n",ctrl.adat1_cd); + exit (0); + } + + if (!strcmp(argv[argidx],"mix")) { + rme_mixer mix; + int i; + + for (i=0; i<4; i++) { + mix.devnr = i; + ioctl(fd,SOUND_MIXER_PRIVATE1,&mix); + if (mix.devnr == i) { + fprintf(stdout,"devnr %d\n",mix.devnr); + fprintf(stdout,"mix.i_offset %2d (0-25)\n",mix.i_offset); + fprintf(stdout,"mix.o_offset %2d (0-25)\n",mix.o_offset); + } + } + exit (0); + } + +/* the control flags */ + + if (argc < argidx+2) + usage(); + + if (!strcmp(argv[argidx],"master")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("master = %d\n",val); + ctrl.master = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"pro")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("pro = %d\n",val); + ctrl.pro = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"emphasis")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("emphasis = %d\n",val); + ctrl.emphasis = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"dolby")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("dolby = %d\n",val); + ctrl.dolby = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"optout")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("optout = %d\n",val); + ctrl.opt_out = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"wordclock")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("wordclock = %d\n",val); + ctrl.wordclock = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"spdifin")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("spdifin = %d\n",val); + ctrl.spdif_in = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"syncref")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("syncref = %d\n",val); + ctrl.sync_ref = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"adat1cd")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("adat1cd = %d\n",val); + ctrl.adat1_cd = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + +/* setting offset */ + + if (argc < argidx+4) + usage(); + + if (!strcmp(argv[argidx],"offset")) { + rme_mixer mix; + + mix.devnr = atoi(argv[argidx+1]); + + mix.i_offset = atoi(argv[argidx+2]); + mix.o_offset = atoi(argv[argidx+3]); + ioctl(fdwr,SOUND_MIXER_PRIVATE1,&mix); + fprintf(stdout,"devnr %d\n",mix.devnr); + fprintf(stdout,"mix.i_offset to %d\n",mix.i_offset); + fprintf(stdout,"mix.o_offset to %d\n",mix.o_offset); + exit (0); + } + + usage(); + exit (0); /* to avoid warning */ +} + + +---------------------------- -------------------------------- +#!/usr/bin/wish + +# xrmectrl +# (C) 2000 Guenter Geiger +# HP20020201 - Heiko Purnhagen + +#set defaults "-relief ridged" +set CTRLPROG "./rmectrl" +if {$argc} { + set CTRLPROG "$CTRLPROG $argv" +} +puts "CTRLPROG $CTRLPROG" + +frame .butts +button .butts.exit -text "Exit" -command "exit" -relief ridge +#button .butts.state -text "State" -command "get_all" + +pack .butts.exit -side left +pack .butts -side bottom + + +# +# STATUS +# + +frame .status + +# Sampling Rate + +frame .status.sr +label .status.sr.text -text "Sampling Rate" -justify left +radiobutton .status.sr.441 -selectcolor red -text "44.1 kHz" -width 10 -anchor nw -variable srate -value 44100 -font times +radiobutton .status.sr.480 -selectcolor red -text "48 kHz" -width 10 -anchor nw -variable srate -value 48000 -font times +radiobutton .status.sr.882 -selectcolor red -text "88.2 kHz" -width 10 -anchor nw -variable srate -value 88200 -font times +radiobutton .status.sr.960 -selectcolor red -text "96 kHz" -width 10 -anchor nw -variable srate -value 96000 -font times + +pack .status.sr.text .status.sr.441 .status.sr.480 .status.sr.882 .status.sr.960 -side top -padx 3 + +# Lock + +frame .status.lock +label .status.lock.text -text "Lock" -justify left +checkbutton .status.lock.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatlock1 -font times +checkbutton .status.lock.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatlock2 -font times +checkbutton .status.lock.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatlock3 -font times + +pack .status.lock.text .status.lock.adat1 .status.lock.adat2 .status.lock.adat3 -side top -padx 3 + +# Sync + +frame .status.sync +label .status.sync.text -text "Sync" -justify left +checkbutton .status.sync.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatsync1 -font times +checkbutton .status.sync.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatsync2 -font times +checkbutton .status.sync.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatsync3 -font times + +pack .status.sync.text .status.sync.adat1 .status.sync.adat2 .status.sync.adat3 -side top -padx 3 + +# Timecode + +frame .status.tc +label .status.tc.text -text "Timecode" -justify left +checkbutton .status.tc.busy -selectcolor red -text "busy" -anchor nw -width 10 -variable tcbusy -font times +checkbutton .status.tc.out -selectcolor red -text "out" -anchor nw -width 10 -variable tcout -font times +checkbutton .status.tc.valid -selectcolor red -text "valid" -anchor nw -width 10 -variable tcvalid -font times + +pack .status.tc.text .status.tc.busy .status.tc.out .status.tc.valid -side top -padx 3 + +# SPDIF In + +frame .status.spdif +label .status.spdif.text -text "SPDIF In" -justify left +label .status.spdif.sr -text "--.- kHz" -anchor n -width 10 -font times +checkbutton .status.spdif.error -selectcolor red -text "Input Lock" -anchor nw -width 10 -variable spdiferr -font times + +pack .status.spdif.text .status.spdif.sr .status.spdif.error -side top -padx 3 + +pack .status.sr .status.lock .status.sync .status.tc .status.spdif -side left -fill x -anchor n -expand 1 + + +# +# CONTROL +# + +proc setprof {} { + global CTRLPROG + global spprof + exec $CTRLPROG pro $spprof +} + +proc setemph {} { + global CTRLPROG + global spemph + exec $CTRLPROG emphasis $spemph +} + +proc setnoaud {} { + global CTRLPROG + global spnoaud + exec $CTRLPROG dolby $spnoaud +} + +proc setoptical {} { + global CTRLPROG + global spoptical + exec $CTRLPROG optout $spoptical +} + +proc setspdifin {} { + global CTRLPROG + global spdifin + exec $CTRLPROG spdifin [expr $spdifin - 1] +} + +proc setsyncsource {} { + global CTRLPROG + global syncsource + exec $CTRLPROG syncref [expr $syncsource -1] +} + + +proc setmaster {} { + global CTRLPROG + global master + exec $CTRLPROG master $master +} + +proc setwordclock {} { + global CTRLPROG + global wordclock + exec $CTRLPROG wordclock $wordclock +} + +proc setadat1cd {} { + global CTRLPROG + global adat1cd + exec $CTRLPROG adat1cd $adat1cd +} + + +frame .control + +# SPDIF In & SPDIF Out + + +frame .control.spdif + +frame .control.spdif.in +label .control.spdif.in.text -text "SPDIF In" -justify left +radiobutton .control.spdif.in.input1 -text "Optical" -anchor nw -width 13 -variable spdifin -value 1 -command setspdifin -selectcolor blue -font times +radiobutton .control.spdif.in.input2 -text "Coaxial" -anchor nw -width 13 -variable spdifin -value 2 -command setspdifin -selectcolor blue -font times +radiobutton .control.spdif.in.input3 -text "Intern " -anchor nw -width 13 -variable spdifin -command setspdifin -value 3 -selectcolor blue -font times + +checkbutton .control.spdif.in.adat1cd -text "ADAT1 Intern" -anchor nw -width 13 -variable adat1cd -command setadat1cd -selectcolor blue -font times + +pack .control.spdif.in.text .control.spdif.in.input1 .control.spdif.in.input2 .control.spdif.in.input3 .control.spdif.in.adat1cd + +label .control.spdif.space + +frame .control.spdif.out +label .control.spdif.out.text -text "SPDIF Out" -justify left +checkbutton .control.spdif.out.pro -text "Professional" -anchor nw -width 13 -variable spprof -command setprof -selectcolor blue -font times +checkbutton .control.spdif.out.emphasis -text "Emphasis" -anchor nw -width 13 -variable spemph -command setemph -selectcolor blue -font times +checkbutton .control.spdif.out.dolby -text "NoAudio" -anchor nw -width 13 -variable spnoaud -command setnoaud -selectcolor blue -font times +checkbutton .control.spdif.out.optout -text "Optical Out" -anchor nw -width 13 -variable spoptical -command setoptical -selectcolor blue -font times + +pack .control.spdif.out.optout .control.spdif.out.dolby .control.spdif.out.emphasis .control.spdif.out.pro .control.spdif.out.text -side bottom + +pack .control.spdif.in .control.spdif.space .control.spdif.out -side top -fill y -padx 3 -expand 1 + +# Sync Mode & Sync Source + +frame .control.sync +frame .control.sync.mode +label .control.sync.mode.text -text "Sync Mode" -justify left +checkbutton .control.sync.mode.master -text "Master" -anchor nw -width 13 -variable master -command setmaster -selectcolor blue -font times +checkbutton .control.sync.mode.wc -text "Wordclock" -anchor nw -width 13 -variable wordclock -command setwordclock -selectcolor blue -font times + +pack .control.sync.mode.text .control.sync.mode.master .control.sync.mode.wc + +label .control.sync.space + +frame .control.sync.src +label .control.sync.src.text -text "Sync Source" -justify left +radiobutton .control.sync.src.input1 -text "ADAT1" -anchor nw -width 13 -variable syncsource -value 1 -command setsyncsource -selectcolor blue -font times +radiobutton .control.sync.src.input2 -text "ADAT2" -anchor nw -width 13 -variable syncsource -value 2 -command setsyncsource -selectcolor blue -font times +radiobutton .control.sync.src.input3 -text "ADAT3" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 3 -selectcolor blue -font times +radiobutton .control.sync.src.input4 -text "SPDIF" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 4 -selectcolor blue -font times + +pack .control.sync.src.input4 .control.sync.src.input3 .control.sync.src.input2 .control.sync.src.input1 .control.sync.src.text -side bottom + +pack .control.sync.mode .control.sync.space .control.sync.src -side top -fill y -padx 3 -expand 1 + +label .control.space -text "" -width 10 + +# Buffer Size + +frame .control.buf +label .control.buf.text -text "Buffer Size (Latency)" -justify left +radiobutton .control.buf.b1 -selectcolor red -text "64 (1.5 ms)" -width 13 -anchor nw -variable ssrate -value 1 -font times +radiobutton .control.buf.b2 -selectcolor red -text "128 (3 ms)" -width 13 -anchor nw -variable ssrate -value 2 -font times +radiobutton .control.buf.b3 -selectcolor red -text "256 (6 ms)" -width 13 -anchor nw -variable ssrate -value 3 -font times +radiobutton .control.buf.b4 -selectcolor red -text "512 (12 ms)" -width 13 -anchor nw -variable ssrate -value 4 -font times +radiobutton .control.buf.b5 -selectcolor red -text "1024 (23 ms)" -width 13 -anchor nw -variable ssrate -value 5 -font times +radiobutton .control.buf.b6 -selectcolor red -text "2048 (46 ms)" -width 13 -anchor nw -variable ssrate -value 6 -font times +radiobutton .control.buf.b7 -selectcolor red -text "4096 (93 ms)" -width 13 -anchor nw -variable ssrate -value 7 -font times +radiobutton .control.buf.b8 -selectcolor red -text "8192 (186 ms)" -width 13 -anchor nw -variable ssrate -value 8 -font times + +pack .control.buf.text .control.buf.b1 .control.buf.b2 .control.buf.b3 .control.buf.b4 .control.buf.b5 .control.buf.b6 .control.buf.b7 .control.buf.b8 -side top -padx 3 + +# Offset + +frame .control.offset + +frame .control.offset.in +label .control.offset.in.text -text "Offset In" -justify left +label .control.offset.in.off0 -text "dev\#0: -" -anchor nw -width 10 -font times +label .control.offset.in.off1 -text "dev\#1: -" -anchor nw -width 10 -font times +label .control.offset.in.off2 -text "dev\#2: -" -anchor nw -width 10 -font times +label .control.offset.in.off3 -text "dev\#3: -" -anchor nw -width 10 -font times + +pack .control.offset.in.text .control.offset.in.off0 .control.offset.in.off1 .control.offset.in.off2 .control.offset.in.off3 + +label .control.offset.space + +frame .control.offset.out +label .control.offset.out.text -text "Offset Out" -justify left +label .control.offset.out.off0 -text "dev\#0: -" -anchor nw -width 10 -font times +label .control.offset.out.off1 -text "dev\#1: -" -anchor nw -width 10 -font times +label .control.offset.out.off2 -text "dev\#2: -" -anchor nw -width 10 -font times +label .control.offset.out.off3 -text "dev\#3: -" -anchor nw -width 10 -font times + +pack .control.offset.out.off3 .control.offset.out.off2 .control.offset.out.off1 .control.offset.out.off0 .control.offset.out.text -side bottom + +pack .control.offset.in .control.offset.space .control.offset.out -side top -fill y -padx 3 -expand 1 + + +pack .control.spdif .control.sync .control.space .control.buf .control.offset -side left -fill both -anchor n -expand 1 + + +label .statustext -text Status -justify center -relief ridge +label .controltext -text Control -justify center -relief ridge + +label .statusspace +label .controlspace + +pack .statustext .status .statusspace .controltext .control .controlspace -side top -anchor nw -fill both -expand 1 + + +proc get_bit {output sstr} { + set idx1 [string last [concat $sstr 1] $output] + set idx1 [expr $idx1 != -1] + return $idx1 +} + +proc get_val {output sstr} { + set val [string wordend $output [string last $sstr $output]] + set val [string range $output $val [expr $val+1]] + return $val +} + +proc get_val2 {output sstr} { + set val [string wordend $output [string first $sstr $output]] + set val [string range $output $val [expr $val+2]] + return $val +} + +proc get_control {} { + global spprof + global spemph + global spnoaud + global spoptical + global spdifin + global ssrate + global master + global wordclock + global syncsource + global CTRLPROG + + set f [open "| $CTRLPROG control" r+] + set ooo [read $f 1000] + close $f +# puts $ooo + + set spprof [ get_bit $ooo "pro"] + set spemph [ get_bit $ooo "emphasis"] + set spnoaud [ get_bit $ooo "dolby"] + set spoptical [ get_bit $ooo "opt_out"] + set spdifin [ expr [ get_val $ooo "spdif_in"] + 1] + set ssrate [ expr [ get_val $ooo "latency"] + 1] + set master [ expr [ get_val $ooo "master"]] + set wordclock [ expr [ get_val $ooo "wordclock"]] + set syncsource [ expr [ get_val $ooo "sync_ref"] + 1] +} + +proc get_status {} { + global srate + global ctrlcom + + global adatlock1 + global adatlock2 + global adatlock3 + + global adatsync1 + global adatsync2 + global adatsync3 + + global tcbusy + global tcout + global tcvalid + + global spdiferr + global crystal + global .status.spdif.text + global CTRLPROG + + + set f [open "| $CTRLPROG status" r+] + set ooo [read $f 1000] + close $f +# puts $ooo + +# samplerate + + set idx1 [string last "sr48 1" $ooo] + set idx2 [string last "doublespeed 1" $ooo] + if {$idx1 >= 0} { + set fact1 48000 + } else { + set fact1 44100 + } + + if {$idx2 >= 0} { + set fact2 2 + } else { + set fact2 1 + } + set srate [expr $fact1 * $fact2] +# ADAT lock + + set val [get_val $ooo lockmask] + set adatlock1 0 + set adatlock2 0 + set adatlock3 0 + if {[expr $val & 1]} { + set adatlock3 1 + } + if {[expr $val & 2]} { + set adatlock2 1 + } + if {[expr $val & 4]} { + set adatlock1 1 + } + +# ADAT sync + set val [get_val $ooo syncmask] + set adatsync1 0 + set adatsync2 0 + set adatsync3 0 + + if {[expr $val & 1]} { + set adatsync3 1 + } + if {[expr $val & 2]} { + set adatsync2 1 + } + if {[expr $val & 4]} { + set adatsync1 1 + } + +# TC busy + + set tcbusy [get_bit $ooo "busy"] + set tcout [get_bit $ooo "out"] + set tcvalid [get_bit $ooo "valid"] + set spdiferr [expr [get_bit $ooo "spdif_error"] == 0] + +# 000=64kHz, 100=88.2kHz, 011=96kHz +# 111=32kHz, 110=44.1kHz, 101=48kHz + + set val [get_val $ooo crystalrate] + + set crystal "--.- kHz" + if {$val == 0} { + set crystal "64 kHz" + } + if {$val == 4} { + set crystal "88.2 kHz" + } + if {$val == 3} { + set crystal "96 kHz" + } + if {$val == 7} { + set crystal "32 kHz" + } + if {$val == 6} { + set crystal "44.1 kHz" + } + if {$val == 5} { + set crystal "48 kHz" + } + .status.spdif.sr configure -text $crystal +} + +proc get_offset {} { + global inoffset + global outoffset + global CTRLPROG + + set f [open "| $CTRLPROG mix" r+] + set ooo [read $f 1000] + close $f +# puts $ooo + + if { [string match "*devnr*" $ooo] } { + set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] + set val [get_val2 $ooo i_offset] + .control.offset.in.off0 configure -text "dev\#0: $val" + set val [get_val2 $ooo o_offset] + .control.offset.out.off0 configure -text "dev\#0: $val" + } else { + .control.offset.in.off0 configure -text "dev\#0: -" + .control.offset.out.off0 configure -text "dev\#0: -" + } + if { [string match "*devnr*" $ooo] } { + set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] + set val [get_val2 $ooo i_offset] + .control.offset.in.off1 configure -text "dev\#1: $val" + set val [get_val2 $ooo o_offset] + .control.offset.out.off1 configure -text "dev\#1: $val" + } else { + .control.offset.in.off1 configure -text "dev\#1: -" + .control.offset.out.off1 configure -text "dev\#1: -" + } + if { [string match "*devnr*" $ooo] } { + set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] + set val [get_val2 $ooo i_offset] + .control.offset.in.off2 configure -text "dev\#2: $val" + set val [get_val2 $ooo o_offset] + .control.offset.out.off2 configure -text "dev\#2: $val" + } else { + .control.offset.in.off2 configure -text "dev\#2: -" + .control.offset.out.off2 configure -text "dev\#2: -" + } + if { [string match "*devnr*" $ooo] } { + set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] + set val [get_val2 $ooo i_offset] + .control.offset.in.off3 configure -text "dev\#3: $val" + set val [get_val2 $ooo o_offset] + .control.offset.out.off3 configure -text "dev\#3: $val" + } else { + .control.offset.in.off3 configure -text "dev\#3: -" + .control.offset.out.off3 configure -text "dev\#3: -" + } +} + + +proc get_all {} { +get_status +get_control +get_offset +} + +# main +while {1} { + after 200 + get_all + update +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Documentation/sysctl/vm.txt linux-2.5/Documentation/sysctl/vm.txt --- linux-2.5.20/Documentation/sysctl/vm.txt Mon Jun 3 02:44:52 2002 +++ linux-2.5/Documentation/sysctl/vm.txt Sun Mar 3 17:54:35 2002 @@ -21,6 +21,7 @@ - buffermem - freepages - kswapd +- max_map_count - overcommit_memory - page-cluster - pagecache @@ -167,6 +168,19 @@ and don't use much of it. Look at: mm/mmap.c::vm_enough_memory() for more information. + +============================================================== + +max_map_count: + +This file contains the maximum number of memory map areas a +process may have. Memory map areas are used as a side-effect +of calling malloc, directly by mmap and mprotect, and also +when loading shared libraries. + +While most applications need less than a thousand maps, +certain programs, particularly malloc debuggers, may consume +lots of them, e.g. up to one or two maps per allocation. ============================================================== diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/MAINTAINERS linux-2.5/MAINTAINERS --- linux-2.5.20/MAINTAINERS Mon Jun 3 02:44:40 2002 +++ linux-2.5/MAINTAINERS Mon Jun 3 17:10:18 2002 @@ -550,14 +550,12 @@ S: Maintained EXT2 FILE SYSTEM -P: Remy Card -M: Remy.Card@linux.org -L: linux-kernel@vger.kernel.org +L: ext2-devel@lists.sourceforge.net S: Maintained EXT3 FILE SYSTEM -P: Remy Card, Stephen Tweedie -M: sct@redhat.com, akpm@zip.com.au, adilger@turbolinux.com +P: Stephen Tweedie, Andrew Morton +M: sct@redhat.com, akpm@zip.com.au, adilger@clusterfs.com L: ext3-users@redhat.com S: Maintained @@ -714,7 +712,7 @@ S: Maintained IBM ServeRAID RAID DRIVER -P: Jack Hammer +P: Jack Hammer P: Dave Jeffrey M: ipslinux@us.ibm.com W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html @@ -1204,6 +1202,12 @@ W: http://www.ozlabs.org/people/dgibson/dldwd S: Maintained +ORINOCO DRIVER +P: David Gibson +M: hermes@gibson.dropbear.id.au +W: http://www.ozlabs.org/people/dgibson/dldwd +S: Maintained + PARALLEL PORT SUPPORT P: Phil Blundell M: Philip.Blundell@pobox.com @@ -1274,6 +1278,20 @@ L: linux-net@vger.kernel.org S: Maintained +PERMEDIA 3 FRAMEBUFFER DRIVER +P: Romain Dolbeau +M: dolbeau@irisa.fr +L: linux-fbdev-devel@lists.sourceforge.net +W: http://www.irisa.fr/prive/dolbeau/pm3fb/pm3fb.html +S: Maintained + +PHILIPS NINO PALM PC +P: Steven Hill +M: sjhill@realitydiluted.com +L: linux-mips@oss.sgi.com +W: http://www.realitydiluted.com/projects/nino +S: Maintained + PNP SUPPORT P: Tom Lees M: tom@lpsg.demon.co.uk @@ -1361,6 +1379,12 @@ L: linux-kernel@vger.kernel.org S: Maintained +RME96XX MULTICHANNEL SOUND DRIVER +P: Guenter Geiger +M: geiger@epy.co.at +L: linux-kernel@vger.kernel.org +S: Maintained + RTLINUX REALTIME LINUX P: Victor Yodaiken M: yodaiken@fsmlabs.com @@ -1388,6 +1412,11 @@ L: linux-kernel@vger.kernel.org S: Maintained +SC1200 WDT DRIVER +P: Zwane Mwaikambo +M: zwane@commfireservices.com +S: Maintained + SCSI CDROM DRIVER P: Jens Axboe M: axboe@suse.de @@ -1676,6 +1705,12 @@ L: linux-usb-devel@lists.sourceforge.net S: Maintained +USB EHCI DRIVER +P: David Brownell +M: dbrownell@users.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained + USB HID/HIDBP/INPUT DRIVERS P: Vojtech Pavlik M: vojtech@suse.cz @@ -1752,6 +1787,13 @@ W: http://www.beattie-home.net/linux S: Maintained +USB RTL8150 DRIVER +P: Petko Manolov +M: petkan@users.sourceforge.net +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained + USB SE401 DRIVER P: Jeroen Vreeken M: pe1rxq@amsat.org @@ -1854,7 +1896,6 @@ VIDEO FOR LINUX P: Gerd Knorr M: kraxel@bytesex.org -W: http://roadrunner.swansea.linux.org.uk/v4l.shtml S: Maintained WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Makefile linux-2.5/Makefile --- linux-2.5.20/Makefile Mon Jun 3 02:44:41 2002 +++ linux-2.5/Makefile Mon Jun 3 17:10:18 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 20 -EXTRAVERSION = +EXTRAVERSION =-dj1 # We are using a recursive build, so we need to do a little thinking # to get the ordering right. @@ -30,7 +30,7 @@ TOPDIR := $(CURDIR) HPATH = $(TOPDIR)/include -FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net +FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu HOSTCC = gcc HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer @@ -107,7 +107,10 @@ CPPFLAGS := -D__KERNEL__ -I$(HPATH) CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ - -fomit-frame-pointer -fno-strict-aliasing -fno-common + -fno-strict-aliasing -fno-common +ifndef CONFIG_FRAME_POINTER +CFLAGS += -fomit-frame-pointer +endif AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) ifdef CONFIG_MODULES @@ -121,7 +124,7 @@ LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =init kernel lib drivers mm fs net ipc sound -DRIVERS-y = drivers/built-in.o +DRIVERS-y = drivers/built-in.o DRIVERS-$(CONFIG_SOUND) += sound/sound.o DRIVERS := $(DRIVERS-y) @@ -129,6 +132,16 @@ include arch/$(ARCH)/Makefile +# Extra cflags for kbuild 2.4. The default is to forbid includes by kernel code +# from user space headers. Some UML code requires user space headers, in the +# UML Makefiles add 'kbuild_2_4_nostdinc :=' before include Rules.make. No +# other kernel code should include user space headers, if you need +# 'kbuild_2_4_nostdinc :=' or -I/usr/include for kernel code and you are not UML +# then your code is broken! KAO. + +kbuild_2_4_nostdinc := -nostdinc $(shell $(CC) -print-search-dirs | sed -ne 's/install: \(.*\)/-I \1include/gp') +export kbuild_2_4_nostdinc + export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS # boot target @@ -140,12 +153,12 @@ # Build vmlinux # --------------------------------------------------------------------------- -# This is a bit tricky: If we need to relink vmlinux, we want -# the version number incremented, which means recompile init/version.o -# and relink init/init.o. However, we cannot do this during the +# This is a bit tricky: If we need to relink vmlinux, we want +# the version number incremented, which means recompile init/version.o +# and relink init/init.o. However, we cannot do this during the # normal descending-into-subdirs phase, since at that time # we cannot yet know if we will need to relink vmlinux. -# So we descend into init/ inside the rule for vmlinux again. +# So we descend into init/ inside the rule for vmlinux again. vmlinux-objs := $(HEAD) $(INIT) $(CORE_FILES) $(LIBS) $(DRIVERS) $(NETWORKS) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/README linux-2.5/README --- linux-2.5.20/README Mon Jun 3 02:44:46 2002 +++ linux-2.5/README Tue Jun 4 00:29:15 2002 @@ -153,9 +153,8 @@ COMPILING the kernel: - - Make sure you have gcc 2.95.3 available. - gcc 2.91.66 (egcs-1.1.2), and gcc 2.7.2.3 are known to miscompile - some parts of the kernel, and are *no longer supported*. + - Make sure you have gcc 2.95.3 available. gcc 2.91.66 (egcs-1.1.2) may + also work but is not as safe, and *gcc 2.7.2.3 is no longer supported*. Also remember to upgrade your binutils package (for as/ld/nm and company) if necessary. For more information, refer to ./Documentation/Changes. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/Rules.make linux-2.5/Rules.make --- linux-2.5.20/Rules.make Mon Jun 3 02:44:47 2002 +++ linux-2.5/Rules.make Mon Jun 3 17:10:18 2002 @@ -21,6 +21,7 @@ RELDIR := $(subst $(TOPDIR)/,,$(CURDIR)) TOPDIR_REL := $(subst $(space),,$(foreach d,$(subst /, ,$(RELDIR)),../)) endif +EXTRA_CFLAGS_nostdinc := $(EXTRA_CFLAGS) $(kbuild_2_4_nostdinc) # Figure out what we need to build from the various variables # =========================================================================== @@ -211,7 +212,7 @@ cmd_link_multi = $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $($(basename $@)-objs),$^) # We would rather have a list of rules like -# foo.o: $(foo-objs) +# foo.o: $(foo-objs) # but that's not so easy, so we rather make all composite objects depend # on the set of all their parts $(multi-used-y) : %.o: $(multi-objs-y) FORCE @@ -224,7 +225,7 @@ # This make dependencies quickly # fastdep: FORCE - $(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS) -- $(wildcard *.[chS]) > .depend + $(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -- $(wildcard *.[chS]) > .depend ifdef ALL_SUB_DIRS $(MAKE) $(patsubst %,_sfdep_%,$(ALL_SUB_DIRS)) _FASTDEP_ALL_SUB_DIRS="$(ALL_SUB_DIRS)" endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/alpha/Config.help linux-2.5/arch/alpha/Config.help --- linux-2.5.20/arch/alpha/Config.help Mon Jun 3 02:44:41 2002 +++ linux-2.5/arch/alpha/Config.help Tue Mar 26 11:45:21 2002 @@ -251,6 +251,10 @@ CONFIG_ALPHA_GAMMA Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx. +CONFIG_ALPHA_EV67 + Is this a machine based on the EV67 core? If in doubt, select N here + and the machine will be treated as an EV6. + CONFIG_ALPHA_SRM There are two different types of booting firmware on Alphas: SRM, which is command line driven, and ARC, which uses menus and arrow @@ -592,4 +596,15 @@ and certain other kinds of spinlock errors commonly made. This is best used in conjunction with the NMI watchdog so that spinlock deadlocks are also debuggable. + +CONFIG_DEBUG_RWLOCK + If you say Y here then read-write lock processing will count how many + times it has tried to get the lock and issue an error message after + too many attempts. If you suspect a rwlock problem or a kernel + hacker asks for this option then say Y. Otherwise say N. + +CONFIG_DEBUG_SEMAPHORE + If you say Y here then semaphore processing will issue lots of + verbose debugging messages. If you suspect a semaphore problem or a + kernel hacker asks for this option then say Y. Otherwise say N. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/alpha/kernel/alpha_ksyms.c linux-2.5/arch/alpha/kernel/alpha_ksyms.c --- linux-2.5.20/arch/alpha/kernel/alpha_ksyms.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/arch/alpha/kernel/alpha_ksyms.c Sat Jun 1 00:34:32 2002 @@ -214,6 +214,7 @@ EXPORT_SYMBOL(smp_imb); EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(__cpu_number_map); +EXPORT_SYMBOL(__cpu_logical_map); EXPORT_SYMBOL(smp_num_cpus); EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_call_function_on_cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/alpha/kernel/pci_iommu.c linux-2.5/arch/alpha/kernel/pci_iommu.c --- linux-2.5.20/arch/alpha/kernel/pci_iommu.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/arch/alpha/kernel/pci_iommu.c Mon Feb 25 22:20:45 2002 @@ -30,6 +30,10 @@ #define DEBUG_NODIRECT 0 #define DEBUG_FORCEDAC 0 +/* Most Alphas support 32-bit ISA DMA. Exceptions are XL, Ruffian and + Nautilus (see asm/dma.h for details). */ +#define ISA_DMA_MASK (MAX_DMA_ADDRESS - IDENT_ADDR - 1 < 0xffffffff ? \ + MAX_DMA_ADDRESS - IDENT_ADDR - 1 : 0xffffffff) static inline unsigned long mk_iommu_pte(unsigned long paddr) @@ -181,7 +185,7 @@ int dac_allowed) { struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose; - dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + dma_addr_t max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK; struct pci_iommu_arena *arena; long npages, dma_ofs, i; unsigned long paddr; @@ -213,18 +217,15 @@ } /* If the machine doesn't define a pci_tbi routine, we have to - assume it doesn't support sg mapping. */ + assume it doesn't support sg mapping, and, since we tried to + use direct_map above, it now must be considered an error. */ if (! alpha_mv.mv_pci_tbi) { - static int been_here = 0; + static int been_here = 0; /* Only print the message once. */ if (!been_here) { - printk(KERN_WARNING "pci_map_single: no hw sg, using " - "direct map when possible\n"); + printk(KERN_WARNING "pci_map_single: no HW sg\n"); been_here = 1; } - if (paddr + size <= __direct_map_size) - return (paddr + __direct_map_base); - else - return 0; + return 0; } arena = hose->sg_pci; @@ -588,7 +589,7 @@ /* Second, figure out where we're going to map things. */ if (alpha_mv.mv_pci_tbi) { hose = pdev ? pdev->sysdata : pci_isa_hose; - max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK; arena = hose->sg_pci; if (!arena || arena->dma_base + arena->size - 1 > max_dma) arena = hose->sg_isa; @@ -651,7 +652,7 @@ return; hose = pdev ? pdev->sysdata : pci_isa_hose; - max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK; arena = hose->sg_pci; if (!arena || arena->dma_base + arena->size - 1 > max_dma) arena = hose->sg_isa; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/alpha/kernel/proto.h linux-2.5/arch/alpha/kernel/proto.h --- linux-2.5.20/arch/alpha/kernel/proto.h Mon Jun 3 02:44:43 2002 +++ linux-2.5/arch/alpha/kernel/proto.h Tue Feb 26 21:24:48 2002 @@ -106,7 +106,7 @@ extern void SMC93x_Init(void); /* smc37c669.c */ -extern void SMC669_Init(int); +extern int SMC669_Init(int); /* es1888.c */ extern void es1888_init(void); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/alpha/kernel/smc37c669.c linux-2.5/arch/alpha/kernel/smc37c669.c --- linux-2.5.20/arch/alpha/kernel/smc37c669.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/arch/alpha/kernel/smc37c669.c Wed Jan 16 18:27:10 2002 @@ -2528,7 +2528,7 @@ * * RETURNS: * - * Nothing + * 1 if the chip found, 0 otherwise * * ARGUMENTS: * @@ -2539,7 +2539,7 @@ * None * */ -void __init SMC669_Init ( int index ) +int __init SMC669_Init ( int index ) { SMC37c669_CONFIG_REGS *SMC_base; unsigned long flags; @@ -2602,11 +2602,13 @@ __restore_flags(flags); printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n", (unsigned long) SMC_base ); + return 1; } else { __restore_flags(flags); #if SMC_DEBUG printk( "No SMC37c669 Super I/O Controller found\n" ); #endif + return 0; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/alpha/kernel/smp.c linux-2.5/arch/alpha/kernel/smp.c --- linux-2.5.20/arch/alpha/kernel/smp.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/arch/alpha/kernel/smp.c Fri May 17 00:17:52 2002 @@ -181,9 +181,23 @@ calibrate_delay. */ wait_boot_cpu_to_stop(cpuid); mb(); +try_again: calibrate_delay(); smp_store_cpu_info(cpuid); + + { +#define LPJ(c) ((long)cpu_data[c].loops_per_jiffy) + static int tries = 3; + long diff = LPJ(boot_cpuid) - LPJ(cpuid); + if (diff < 0) diff = -diff; + + if (diff > LPJ(boot_cpuid)/10 && --tries) { + printk("Bogus BogoMIPS for cpu %d - retrying...\n", cpuid); + goto try_again; + } + } + /* Allow master to continue only after we written loops_per_jiffy. */ wmb(); smp_secondary_alive = 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/alpha/kernel/sys_miata.c linux-2.5/arch/alpha/kernel/sys_miata.c --- linux-2.5.20/arch/alpha/kernel/sys_miata.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/arch/alpha/kernel/sys_miata.c Sun Apr 14 17:12:07 2002 @@ -231,7 +231,15 @@ miata_init_pci(void) { cia_init_pci(); - SMC669_Init(0); /* it might be a GL (fails harmlessly if not) */ + /* The PYXIS has data corruption problem with scatter/gather + burst DMA reads crossing 8K boundary. It had been fixed + with off-chip logic on all PYXIS systems except first + MIATAs, so disable SG DMA on such machines. */ + if (!SMC669_Init(0)) { /* MIATA GL has SMC37c669 Super I/O */ + alpha_mv.mv_pci_tbi = NULL; + printk(KERN_INFO "pci: pyxis 8K boundary dma bug - " + "sg dma disabled\n"); + } es1888_init(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/arm/config.in linux-2.5/arch/arm/config.in --- linux-2.5.20/arch/arm/config.in Mon Jun 3 02:44:43 2002 +++ linux-2.5/arch/arm/config.in Mon Jun 3 17:10:18 2002 @@ -563,9 +563,6 @@ source drivers/isdn/Config.in -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in source drivers/char/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/arm/mach-footbridge/netwinder-hw.c linux-2.5/arch/arm/mach-footbridge/netwinder-hw.c --- linux-2.5.20/arch/arm/mach-footbridge/netwinder-hw.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/arch/arm/mach-footbridge/netwinder-hw.c Sat Apr 27 13:13:18 2002 @@ -328,7 +328,10 @@ */ static void __init wb977_init(void) { - request_region(0x370, 2, "W83977AF configuration"); + if (!request_region(0x370, 2, "W83977AF configuration")) { + printk(KERN_WARNING"Unable to request region 0x370\n"); + return; + } /* * Open up the SuperIO chip diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/arm/mach-shark/leds.c linux-2.5/arch/arm/mach-shark/leds.c --- linux-2.5.20/arch/arm/mach-shark/leds.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/arch/arm/mach-shark/leds.c Sat Apr 27 13:13:42 2002 @@ -152,7 +152,10 @@ leds_event = sequoia_leds_event; /* Make LEDs independent of power-state */ - request_region(0x24,4,"sequoia"); + if (!request_region(0x24,4,"sequoia")) { + printk(KERN_WARNING"arm: Unable to request region 0x24\n"); + return -EIO; + } temp = sequoia_read(0x09); temp |= 1<<10; sequoia_write(temp,0x09); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/arm/tools/getconstants.c linux-2.5/arch/arm/tools/getconstants.c --- linux-2.5.20/arch/arm/tools/getconstants.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/arch/arm/tools/getconstants.c Wed May 8 14:50:36 2002 @@ -23,9 +23,6 @@ #if defined(__APCS_26__) && defined(CONFIG_CPU_32) #error Sorry, your compiler targets APCS-26 but this kernel requires APCS-32 #endif -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95) -#error Sorry, your compiler is known to miscompile kernels. Only use gcc 2.95.3 and later. -#endif #if __GNUC__ == 2 && __GNUC_MINOR__ == 95 /* shame we can't detect the .1 or .2 releases */ #warning GCC 2.95.2 and earlier miscompiles kernels. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/cris/boot/Makefile linux-2.5/arch/cris/boot/Makefile --- linux-2.5.20/arch/cris/boot/Makefile Mon Jun 3 02:44:49 2002 +++ linux-2.5/arch/cris/boot/Makefile Fri Feb 8 03:15:29 2002 @@ -8,6 +8,8 @@ @$(MAKE) -C compressed vmlinuz dep: + @$(MAKE) -C compressed depend + @$(MAKE) -C rescue depend clean: rm -f zImage tools/build compressed/vmlinux.out diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/cris/boot/compressed/Makefile linux-2.5/arch/cris/boot/compressed/Makefile --- linux-2.5.20/arch/cris/boot/compressed/Makefile Mon Jun 3 02:44:39 2002 +++ linux-2.5/arch/cris/boot/compressed/Makefile Fri Feb 8 03:15:29 2002 @@ -4,6 +4,13 @@ # create a compressed vmlinux image from the original vmlinux files and romfs # +ifndef TOPDIR +TOPDIR = ../../../.. +HPATH = $(TOPDIR)/include +export HPATH +endif + + CC = gcc-cris -melf -I $(TOPDIR)/include CFLAGS = -O2 LD = ld-cris @@ -37,4 +44,10 @@ clean: rm -f piggy.img vmlinuz vmlinuz.o + +depend: + $(CC) -M *.S *.c > .depend + +-include .depend + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/cris/boot/rescue/Makefile linux-2.5/arch/cris/boot/rescue/Makefile --- linux-2.5.20/arch/cris/boot/rescue/Makefile Mon Jun 3 02:44:48 2002 +++ linux-2.5/arch/cris/boot/rescue/Makefile Tue May 21 22:53:42 2002 @@ -3,6 +3,8 @@ # ifndef TOPDIR TOPDIR = ../../../.. +HPATH = $(TOPDIR)/include +export HPATH endif CC = gcc-cris -mlinux -I $(TOPDIR)/include CFLAGS = -O2 @@ -52,3 +54,8 @@ modules: modules-install: + +depend: + $(CC) -M *.S > .depend + +-include .depend diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/cris/config.in linux-2.5/arch/cris/config.in --- linux-2.5.20/arch/cris/config.in Mon Jun 3 02:44:50 2002 +++ linux-2.5/arch/cris/config.in Mon May 6 14:18:19 2002 @@ -196,9 +196,6 @@ fi endmenu -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in source drivers/char/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/cris/drivers/ethernet.c linux-2.5/arch/cris/drivers/ethernet.c --- linux-2.5.20/arch/cris/drivers/ethernet.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/arch/cris/drivers/ethernet.c Thu Apr 4 14:06:00 2002 @@ -530,6 +530,15 @@ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, enable, on); + *R_NETWORK_TR_CTRL = + IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr) | + IO_STATE(R_NETWORK_TR_CTRL, delay, none) | + IO_STATE(R_NETWORK_TR_CTRL, cancel, dont) | + IO_STATE(R_NETWORK_TR_CTRL, cd, enable) | + IO_STATE(R_NETWORK_TR_CTRL, retry, enable) | + IO_STATE(R_NETWORK_TR_CTRL, pad, enable) | + IO_STATE(R_NETWORK_TR_CTRL, crc, enable); + save_flags(flags); cli(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/cris/drivers/serial.c linux-2.5/arch/cris/drivers/serial.c --- linux-2.5.20/arch/cris/drivers/serial.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/arch/cris/drivers/serial.c Fri Feb 8 03:15:29 2002 @@ -363,8 +363,7 @@ #define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10) -#define SERIAL_RECV_SIZE 4096 -#define SERIAL_DESCR_BUF_SIZE 512 +#define SERIAL_DESCR_BUF_SIZE 256 /* Add an x here to log a lot of timer stuff */ #define TIMERD(x) @@ -1260,15 +1259,56 @@ #define START_FLUSH_FAST_TIMER(info, string) #endif +static struct etrax_recv_buffer * +alloc_recv_buffer(unsigned int size) +{ + struct etrax_recv_buffer *buffer; + + if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) + return NULL; + + buffer->next = NULL; + buffer->length = 0; + buffer->error = TTY_NORMAL; + + return buffer; +} + +static void +append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + if (!info->first_recv_buffer) + info->first_recv_buffer = buffer; + else + info->last_recv_buffer->next = buffer; + + info->last_recv_buffer = buffer; + + info->recv_cnt += buffer->length; + if (info->recv_cnt > info->max_recv_cnt) + info->max_recv_cnt = info->recv_cnt; + + restore_flags(flags); +} + static int add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag) { - if (!CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE)) + struct etrax_recv_buffer *buffer; + + if (!(buffer = alloc_recv_buffer(4))) return 0; - info->recv.buf[info->recv.head] = data; - info->flag_buf[info->recv.head] = flag; - info->recv.head = (info->recv.head + 1) & (SERIAL_RECV_SIZE - 1); + buffer->length = 1; + buffer->error = flag; + buffer->buffer[0] = data; + + append_recv_buffer(info, buffer); info->icount.rx++; @@ -1276,33 +1316,33 @@ } static _INLINE_ unsigned int -copy_descr_data(struct e100_serial *info, unsigned int recvl, unsigned char *buf) +handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl) { - unsigned int count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); - unsigned int length = 0; - - while (length < recvl && count) { - if (length + count > recvl) - count = recvl - length; - - memcpy(info->recv.buf + info->recv.head, buf + length, count); - memset(info->flag_buf + info->recv.head, '\0', count); - info->recv.head = (info->recv.head + count) & (SERIAL_RECV_SIZE - 1); - length += count; + struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer; - count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); + if (info->recv_cnt + recvl > 65536) { + printk(__FUNCTION__ ": Too much pending incoming serial data! Dropping %u bytes.\n", recvl); + return 0; } - if (length != recvl) { - printk(__FUNCTION__ ": Buffer overflow! %d byte(s) did not fit.\n", recvl - length); - PROCSTAT(ser_stat[info->line].overrun_cnt += recvl - length); - } + buffer->length = recvl; + + if (info->errorcode == ERRCODE_SET_BREAK) + buffer->error = TTY_BREAK; + info->errorcode = 0; - return length; + append_recv_buffer(info, buffer); + + if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + panic(__FUNCTION__ ": Failed to allocate memory for receive buffer!\n"); + + descr->buf = virt_to_phys(buffer->buffer); + + return recvl; } static _INLINE_ unsigned int -copy_all_descr_data(struct e100_serial *info) +handle_all_descr_data(struct e100_serial *info) { struct etrax_dma_descr *descr; unsigned int recvl; @@ -1336,7 +1376,7 @@ /* update stats */ info->icount.rx += recvl; - ret += copy_descr_data(info, recvl, phys_to_virt(descr->buf)); + ret += handle_descr_data(info, descr, recvl); } return ret; @@ -1347,7 +1387,6 @@ { struct tty_struct *tty; unsigned char rstat; - unsigned int old_head; #ifdef CONFIG_SVINTO_SIM /* No receive in the simulator. Will probably be when the rest of @@ -1372,12 +1411,7 @@ if (info->errorcode == ERRCODE_INSERT_BREAK) add_char_and_flag(info, '\0', TTY_BREAK); - old_head = info->recv.head; - - if (copy_all_descr_data(info) && info->errorcode == ERRCODE_SET_BREAK) - info->flag_buf[old_head] = TTY_BREAK; - - info->errorcode = 0; + handle_all_descr_data(info); /* Read the status register to detect errors */ rstat = info->port[REG_STATUS]; @@ -1400,10 +1434,6 @@ add_char_and_flag(info, data, TTY_FRAME); } - if (!E100_RTS_GET(info) && - CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) < TTY_THROTTLE_LIMIT) - info->tty->driver.throttle(info->tty); - START_FLUSH_FAST_TIMER(info, "receive_chars"); /* Restart the receiving DMA */ @@ -1414,19 +1444,20 @@ start_recv_dma(struct e100_serial *info) { struct etrax_dma_descr *descr = info->rec_descr; - unsigned char *buf = info->recv.buf + 2*SERIAL_RECV_SIZE; + struct etrax_recv_buffer *buffer; int i; /* Set up the receiving descriptors */ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { + if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + panic(__FUNCTION__ ": Failed to allocate memory for receive buffer!\n"); + descr[i].ctrl = d_int; - descr[i].buf = virt_to_phys(buf); + descr[i].buf = virt_to_phys(buffer->buffer); descr[i].sw_len = SERIAL_DESCR_BUF_SIZE; descr[i].hw_len = 0; descr[i].status = 0; descr[i].next = virt_to_phys(&descr[i+1]); - - buf += SERIAL_DESCR_BUF_SIZE; } /* Link the last descriptor to the first */ @@ -1618,11 +1649,11 @@ flush_to_flip_buffer(struct e100_serial *info) { struct tty_struct *tty = info->tty; - unsigned int count = CIRC_CNT_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); + struct etrax_recv_buffer *buffer; unsigned int length; unsigned long flags; - if (!count) + if (!info->first_recv_buffer) return; save_flags(flags); @@ -1630,19 +1661,31 @@ length = tty->flip.count; - do { + while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) { + unsigned int count = buffer->length; + if (length + count > TTY_FLIPBUF_SIZE) count = TTY_FLIPBUF_SIZE - length; - memcpy(tty->flip.char_buf_ptr + length, info->recv.buf + info->recv.tail, count); - memcpy(tty->flip.flag_buf_ptr + length, info->flag_buf + info->recv.tail, count); - info->recv.tail = ((info->recv.tail + count) & (SERIAL_RECV_SIZE-1)); + memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count); + memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count); + tty->flip.flag_buf_ptr[length] = buffer->error; + length += count; - - count = CIRC_CNT_TO_END(info->recv.head, - info->recv.tail, - SERIAL_RECV_SIZE); - } while (length < TTY_FLIPBUF_SIZE && count); + info->recv_cnt -= count; + + if (count == buffer->length) { + info->first_recv_buffer = buffer->next; + kfree(buffer); + } else { + buffer->length -= count; + memmove(buffer->buffer, buffer->buffer + count, buffer->length); + buffer->error = TTY_NORMAL; + } + } + + if (!info->first_recv_buffer) + info->last_recv_buffer = NULL; tty->flip.count = length; @@ -1654,11 +1697,6 @@ #else queue_task_irq_off(&tty->flip.tqueue, &tq_timer); #endif - - /* unthrottle if we have throttled */ - if (E100_RTS_GET(info) && - CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) > TTY_THROTTLE_LIMIT) - tty->driver.unthrottle(info->tty); } static _INLINE_ void @@ -1668,7 +1706,7 @@ flush_to_flip_buffer(info); - if (CIRC_CNT(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE)) + if (info->first_recv_buffer) START_FLUSH_FAST_TIMER(info, "flip"); } @@ -2005,18 +2043,12 @@ { unsigned long flags; unsigned long xmit_page; - unsigned char *recv_page; + int i; xmit_page = get_zeroed_page(GFP_KERNEL); if (!xmit_page) return -ENOMEM; - recv_page = kmalloc(2 * SERIAL_RECV_SIZE + SERIAL_RECV_DESCRIPTORS * SERIAL_DESCR_BUF_SIZE, GFP_KERNEL); - if (!recv_page) { - free_page(xmit_page); - return -ENOMEM; - } - save_flags(flags); cli(); /* if it was already initialized, skip this */ @@ -2024,7 +2056,6 @@ if (info->flags & ASYNC_INITIALIZED) { restore_flags(flags); free_page(xmit_page); - kfree(recv_page); return 0; } @@ -2033,13 +2064,6 @@ else info->xmit.buf = (unsigned char *) xmit_page; - if (info->recv.buf) - kfree(recv_page); - else { - info->recv.buf = (unsigned char *) recv_page; - info->flag_buf = info->recv.buf + SERIAL_RECV_SIZE; - } - #ifdef SERIAL_DEBUG_OPEN printk("starting up ttyS%d (xmit_buf 0x%p, recv_buf 0x%p)...\n", info->line, info->xmit.buf, info->recv.buf); #endif @@ -2050,8 +2074,13 @@ right? */ if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit.head = info->xmit.tail = 0; - info->recv.head = info->recv.tail = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + info->rec_descr[i].buf = NULL; /* No real action in the simulator, but may set info important to ioctl. */ @@ -2090,8 +2119,12 @@ clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit.head = info->xmit.tail = 0; - info->recv.head = info->recv.tail = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + info->rec_descr[i].buf = 0; + /* * and set the speed and other flags of the serial port * this will start the rx/tx as well @@ -2143,6 +2176,9 @@ shutdown(struct e100_serial * info) { unsigned long flags; + struct etrax_dma_descr *descr = info->rec_descr; + struct etrax_recv_buffer *buffer; + int i; #ifndef CONFIG_SVINTO_SIM /* shut down the transmitter and receiver */ @@ -2179,11 +2215,12 @@ info->xmit.buf = NULL; } - if (info->recv.buf) { - kfree(info->recv.buf); - info->recv.buf = NULL; - info->flag_buf = NULL; - } + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + if (descr[i].buf) { + buffer = phys_to_virt(descr[i].buf) - sizeof *buffer; + kfree(buffer); + descr[i].buf = 0; + } if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { /* hang up DTR and RTS if HUPCL is enabled */ @@ -3413,6 +3450,10 @@ (unsigned long)info->icount.tx, (unsigned long)info->icount.rx); + ret += sprintf(buf+ret, " rx_pend:%lu/%lu", + (unsigned long)info->recv_cnt, + (unsigned long)info->max_recv_cnt); + if (info->icount.frame) ret += sprintf(buf+ret, " fe:%lu", (unsigned long)info->icount.frame); @@ -3581,9 +3622,8 @@ init_waitqueue_head(&info->close_wait); info->xmit.buf = NULL; info->xmit.tail = info->xmit.head = 0; - info->recv.buf = NULL; - info->recv.tail = info->recv.head = 0; - info->flag_buf = NULL; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; info->last_tx_active_usec = 0; info->last_tx_active = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/cris/drivers/serial.h linux-2.5/arch/cris/drivers/serial.h --- linux-2.5.20/arch/cris/drivers/serial.h Mon Jun 3 02:44:46 2002 +++ linux-2.5/arch/cris/drivers/serial.h Fri Feb 8 03:15:29 2002 @@ -25,6 +25,15 @@ #define SERIAL_RECV_DESCRIPTORS 8 +struct etrax_recv_buffer { + struct etrax_recv_buffer *next; + unsigned short length; + unsigned char error; + unsigned char pad; + + unsigned char buffer[0]; +}; + struct e100_serial { int baud; volatile u8 *port; /* R_SERIALx_CTRL */ @@ -81,8 +90,10 @@ long session; /* Session of opening process */ long pgrp; /* pgrp of opening process */ struct circ_buf xmit; - struct circ_buf recv; - unsigned char *flag_buf; + struct etrax_recv_buffer *first_recv_buffer; + struct etrax_recv_buffer *last_recv_buffer; + unsigned int recv_cnt; + unsigned int max_recv_cnt; struct tq_struct tqueue; struct async_icount icount; /* error-statistics etc.*/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/Config.help linux-2.5/arch/i386/Config.help --- linux-2.5.20/arch/i386/Config.help Mon Jun 3 02:44:41 2002 +++ linux-2.5/arch/i386/Config.help Sat May 25 19:51:58 2002 @@ -416,7 +416,7 @@ - "Winchip-C6" for original IDT Winchip. - "Winchip-2" for IDT Winchip 2. - "Winchip-2A" for IDT Winchips with 3dNow! capabilities. - - "CyrixIII" for VIA Cyrix III or VIA C3. + - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3. If you don't know what to do, choose "386". @@ -635,6 +635,18 @@ just add about 9 KB to your kernel. See for more information. + +CONFIG_IKCONFIG + This option enables the complete Linux kernel ".config" file contents + to be saved in the kernel (zipped) image file. It provides + documentation of which kernel options are used in a running kernel or + in an on-disk kernel. It can be extracted from the kernel image file + with a script and used as input to rebuild the current kernel or to + build another kernel. Since the kernel image is zipped, using this + option adds approximately 8 KB to a kernel image file. + This option is not available as a module. If you want a separate + file to save the kernel's .config contents, use 'installkernel' or 'cp' + or a similar tool, or just save it in '/lib/modules/'. CONFIG_PM "Power Management" means that parts of your computer are shut diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/boot/compressed/misc.c linux-2.5/arch/i386/boot/compressed/misc.c --- linux-2.5.20/arch/i386/boot/compressed/misc.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/arch/i386/boot/compressed/misc.c Wed May 8 15:05:39 2002 @@ -202,10 +202,10 @@ SCREEN_INFO.orig_y = y; pos = (x + cols * y) * 2; /* Update cursor position */ - outb_p(14, vidport); - outb_p(0xff & (pos >> 9), vidport+1); - outb_p(15, vidport); - outb_p(0xff & (pos >> 1), vidport+1); + outb_local_p(14, vidport); + outb_local_p(0xff & (pos >> 9), vidport+1); + outb_local_p(15, vidport); + outb_local_p(0xff & (pos >> 1), vidport+1); } static void* memset(void* s, int c, size_t n) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/config.in linux-2.5/arch/i386/config.in --- linux-2.5.20/arch/i386/config.in Mon Jun 3 02:44:46 2002 +++ linux-2.5/arch/i386/config.in Wed May 29 17:17:38 2002 @@ -30,7 +30,7 @@ Winchip-C6 CONFIG_MWINCHIPC6 \ Winchip-2 CONFIG_MWINCHIP2 \ Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \ - CyrixIII/C3 CONFIG_MCYRIXIII" Pentium-Pro + CyrixIII/VIA-C3 CONFIG_MCYRIXIII" Pentium-Pro # # Define implied options from the CPU selection here # @@ -155,7 +155,7 @@ bool 'Machine Check Exception' CONFIG_X86_MCE dep_bool 'Check for non-fatal errors on Athlon/Duron' CONFIG_X86_MCE_NONFATAL $CONFIG_X86_MCE -dep_bool 'check for P4 thermal throttling interrupt.' CONFIG_X86_MCE_P4THERMAL $CONFIG_X86_MCE $CONFIG_X86_LOCAL_APIC +dep_bool 'Check for P4 thermal throttling interrupt.' CONFIG_X86_MCE_P4THERMAL $CONFIG_X86_MCE $CONFIG_X86_LOCAL_APIC tristate 'Toshiba Laptop support' CONFIG_TOSHIBA @@ -269,6 +269,8 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +bool 'Kernel .config support' CONFIG_IKCONFIG + bool 'Power Management support' CONFIG_PM dep_tristate ' Advanced Power Management BIOS support' CONFIG_APM $CONFIG_PM @@ -357,10 +359,8 @@ fi endmenu -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in + source drivers/char/Config.in #source drivers/misc/Config.in @@ -402,13 +402,16 @@ bool 'Kernel debugging' CONFIG_DEBUG_KERNEL if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then + bool ' Disable obsolete code' CONFIG_DEBUG_OBSOLETE bool ' Debug memory allocations' CONFIG_DEBUG_SLAB bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK + bool ' Debug 486 string copies' CONFIG_DEBUG_486_STRING if [ "$CONFIG_HIGHMEM" = "y" ]; then bool ' Highmem debugging' CONFIG_DEBUG_HIGHMEM fi + bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER fi endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/defconfig linux-2.5/arch/i386/defconfig --- linux-2.5.20/arch/i386/defconfig Mon Jun 3 02:44:42 2002 +++ linux-2.5/arch/i386/defconfig Sat May 25 19:51:58 2002 @@ -117,6 +117,7 @@ CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y +CONFIG_IKCONFIG=n CONFIG_PM=y # CONFIG_APM is not set # CONFIG_SOFTWARE_SUSPEND is not set @@ -493,10 +494,10 @@ # CONFIG_PCMCIA_3C574 is not set # CONFIG_PCMCIA_FMVJ18X is not set CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set # CONFIG_PCMCIA_NMCLAN is not set # CONFIG_PCMCIA_SMC91C92 is not set # CONFIG_PCMCIA_XIRC2PS is not set -# CONFIG_PCMCIA_AXNET is not set # CONFIG_ARCNET_COM20020_CS is not set # CONFIG_PCMCIA_IBMTR is not set CONFIG_NET_PCMCIA_RADIO=y @@ -526,21 +527,61 @@ # # Input device support # -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=y +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set # CONFIG_GAMEPORT is not set CONFIG_SOUND_GAMEPORT=y # CONFIG_GAMEPORT_NS558 is not set # CONFIG_GAMEPORT_L4 is not set # CONFIG_INPUT_EMU10K1 is not set -# CONFIG_GAMEPORT_PCIGAME is not set # CONFIG_GAMEPORT_FM801 is not set # CONFIG_GAMEPORT_CS461x is not set -# CONFIG_SERIO is not set -# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_PS2SERKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=y +# CONFIG_MOUSE_GUNZE is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE_USB is not set +# CONFIG_JOYSTICK_IFORCE_232 is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDDLER is not set +# CONFIG_JOYSTICK_DB9 is not set +# CONFIG_JOYSTICK_GAMECON is not set +# CONFIG_JOYSTICK_TURBOGRAFX is not set # # Character devices @@ -561,15 +602,6 @@ # I2C support # # CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -CONFIG_MOUSE=y -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set # CONFIG_QIC02_TAPE is not set # @@ -602,6 +634,7 @@ CONFIG_DRM_RADEON=y # CONFIG_DRM_I810 is not set # CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set # # PCMCIA character devices @@ -840,13 +873,9 @@ # # USB Human Interface Devices (HID) # -# CONFIG_USB_HID is not set - -# -# Input core support is needed for USB HID input layer or HIDBP support -# -# CONFIG_USB_HIDINPUT is not set +CONFIG_USB_HID=y # CONFIG_USB_HIDDEV is not set +# CONFIG_USB_WACOM is not set # CONFIG_USB_KBD is not set # CONFIG_USB_MOUSE is not set # CONFIG_USB_WACOM is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/Makefile linux-2.5/arch/i386/kernel/Makefile --- linux-2.5.20/arch/i386/kernel/Makefile Mon Jun 3 02:44:43 2002 +++ linux-2.5/arch/i386/kernel/Makefile Fri May 31 02:06:42 2002 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -EXTRA_TARGETS := head.o init_task.o +EXTRA_TARGETS := first_rule kernel.o head.o init_task.o O_TARGET := kernel.o @@ -14,6 +14,7 @@ bootflag.o obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_EISA) += eisa.o obj-$(CONFIG_MTRR) += mtrr.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o @@ -29,6 +30,10 @@ obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o endif -EXTRA_AFLAGS := -traditional +EXTRA_AFLAGS := -traditional + +kernel-subdir-y := cpu +subdir-y := $(kernel-subdir-y) +obj-y += $(foreach dir,$(kernel-subdir-y),$(dir)/$(dir).o) include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/apic.c linux-2.5/arch/i386/kernel/apic.c --- linux-2.5.20/arch/i386/kernel/apic.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/arch/i386/kernel/apic.c Sun May 26 01:40:46 2002 @@ -700,7 +700,15 @@ for (i = 0; i < nr_ioapics; i++) { if (smp_found_config) { ioapic_phys = mp_ioapics[i].mpc_apicaddr; + if (!ioapic_phys) { + printk(KERN_ERR "WARNING: bogus zero IO-APIC address found in MPTABLE, disabling IO/APIC support!\n"); + + smp_found_config = 0; + skip_ioapic_setup = 1; + goto fake_ioapic_page; + } } else { +fake_ioapic_page: ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); ioapic_phys = __pa(ioapic_phys); } @@ -1063,7 +1071,6 @@ * [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ -unsigned int apic_timer_irqs [NR_CPUS]; void smp_apic_timer_interrupt(struct pt_regs regs) { @@ -1072,7 +1079,7 @@ /* * the NMI deadlock-detector uses this. */ - apic_timer_irqs[cpu]++; + irq_stat[cpu].apic_timer_irqs++; /* * NOTE! We'd better ACK the irq immediately, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/apm.c linux-2.5/arch/i386/kernel/apm.c --- linux-2.5.20/arch/i386/kernel/apm.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/arch/i386/kernel/apm.c Mon Jun 3 17:10:19 2002 @@ -921,9 +921,9 @@ * callback we use. */ -void handle_poweroff (int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { - apm_power_off(); +void handle_poweroff (int key, struct pt_regs *pt_regs, struct tty_struct *tty) +{ + apm_power_off(); } struct sysrq_key_op sysrq_poweroff_op = { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/bluesmoke.c linux-2.5/arch/i386/kernel/bluesmoke.c --- linux-2.5.20/arch/i386/kernel/bluesmoke.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/arch/i386/kernel/bluesmoke.c Sat May 25 19:51:58 2002 @@ -18,8 +18,24 @@ #ifdef CONFIG_X86_MCE +/* as supported by the P4/Xeon family */ +struct intel_mce_extended_msrs { + u32 eax; + u32 ebx; + u32 ecx; + u32 edx; + u32 esi; + u32 edi; + u32 ebp; + u32 esp; + u32 eflags; + u32 eip; + /* u32 *reserved[]; */ +}; + static int mce_disabled __initdata = 0; +static int mce_num_extended_msrs = 0; static int banks; @@ -75,47 +91,73 @@ if (!cpu_has(c, X86_FEATURE_ACC)) return; /* -ENODEV */ - rdmsr(MSR_IA32_MISC_ENABLE, l, h); /* first check if its enabled already, in which case there might * be some SMM goo which handles it, so we can't even put a handler * since it might be delivered via SMI already -zwanem. */ - - if (l & (1<<3)) { - printk(KERN_DEBUG "CPU#%d: Thermal monitoring already enabled\n", cpu); - } else { - wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h); - printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu); + rdmsr(MSR_IA32_MISC_ENABLE, l, h); + h = apic_read(APIC_LVTTHMR); + if ((l & (1<<3)) && (h & APIC_DM_SMI)) { + printk(KERN_DEBUG "CPU#%d: Thermal monitoring handled by SMI\n", cpu); + return; /* -EBUSY */ } - /* check whether a vector already exists */ - l = apic_read(APIC_LVTTHMR); - if (l & 0xff) { - printk(KERN_DEBUG "CPU#%d: Thermal LVT already handled\n", cpu); + /* check whether a vector already exists, temporarily masked? */ + if (h & APIC_VECTOR_MASK) { + printk(KERN_DEBUG "CPU#%d: Thermal LVT vector (%#x) already installed\n", + cpu, (h & APIC_VECTOR_MASK)); return; /* -EBUSY */ } - wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h); - printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu); - /* The temperature transition interrupt handler setup */ - l = THERMAL_APIC_VECTOR; /* our delivery vector */ - l |= (APIC_DM_FIXED | APIC_LVT_MASKED); /* we'll mask till we're ready */ - apic_write_around(APIC_LVTTHMR, l); + h = THERMAL_APIC_VECTOR; /* our delivery vector */ + h |= (APIC_DM_FIXED | APIC_LVT_MASKED); /* we'll mask till we're ready */ + apic_write_around(APIC_LVTTHMR, h); rdmsr(MSR_IA32_THERM_INTERRUPT, l, h); - wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x3 , h); + wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03 , h); /* ok we're good to go... */ vendor_thermal_interrupt = intel_thermal_interrupt; + + rdmsr(MSR_IA32_MISC_ENABLE, l, h); + wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h); + l = apic_read(APIC_LVTTHMR); apic_write_around(APIC_LVTTHMR, l & ~APIC_LVT_MASKED); - + printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu); return; } #endif /* CONFIG_X86_MCE_P4THERMAL */ +/* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */ + +static int inline intel_get_extended_msrs(struct intel_mce_extended_msrs *r) +{ + u32 h; + + if (mce_num_extended_msrs == 0) + goto done; + + rdmsr(MSR_IA32_MCG_EAX, r->eax, h); + rdmsr(MSR_IA32_MCG_EBX, r->ebx, h); + rdmsr(MSR_IA32_MCG_ECX, r->ecx, h); + rdmsr(MSR_IA32_MCG_EDX, r->edx, h); + rdmsr(MSR_IA32_MCG_ESI, r->esi, h); + rdmsr(MSR_IA32_MCG_EDI, r->edi, h); + rdmsr(MSR_IA32_MCG_EBP, r->ebp, h); + rdmsr(MSR_IA32_MCG_ESP, r->esp, h); + rdmsr(MSR_IA32_MCG_EFLAGS, r->eflags, h); + rdmsr(MSR_IA32_MCG_EIP, r->eip, h); + + /* can we rely on kmalloc to do a dynamic + * allocation for the reserved registers? + */ +done: + return mce_num_extended_msrs; +} + /* * Machine Check Handler For PII/PIII */ @@ -126,6 +168,7 @@ u32 alow, ahigh, high, low; u32 mcgstl, mcgsth; int i; + struct intel_mce_extended_msrs dbg; rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); if(mcgstl&(1<<0)) /* Recoverable ? */ @@ -133,6 +176,15 @@ printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl); + if (intel_get_extended_msrs(&dbg)) { + printk(KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n", + smp_processor_id(), dbg.eip, dbg.eflags); + printk(KERN_DEBUG "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n", + dbg.eax, dbg.ebx, dbg.ecx, dbg.edx); + printk(KERN_DEBUG "\tesi: %08x edi: %08x ebp: %08x esp: %08x\n", + dbg.esi, dbg.edi, dbg.ebp, dbg.esp); + } + for (i=0;ix86_vendor == X86_VENDOR_INTEL && c->x86 == 15) { + /* Check for P4/Xeon extended MCE MSRs */ + rdmsr(MSR_IA32_MCG_CAP, l, h); + if (l & (1<<9)) {/* MCG_EXT_P */ + mce_num_extended_msrs = (l >> 16) & 0xff; + printk(KERN_INFO "CPU#%d: Intel P4/Xeon Extended MCE MSRs (%d) available\n", + smp_processor_id(), mce_num_extended_msrs); + } + #ifdef CONFIG_X86_MCE_P4THERMAL - /* Only enable thermal throttling warning on Pentium 4. */ - if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 15) + /* Check for P4/Xeon Thermal monitor */ intel_init_thermal(c); #endif + } done=1; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/Makefile linux-2.5/arch/i386/kernel/cpu/Makefile --- linux-2.5.20/arch/i386/kernel/cpu/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/Makefile Wed May 8 15:11:31 2002 @@ -0,0 +1,15 @@ +O_TARGET := cpu.o + +obj-y += amd.o +obj-y += cyrix.o +obj-y += centaur.o +obj-y += transmeta.o +obj-y += intel.o +obj-y += rise.o +obj-y += nexgen.o +obj-y += umc.o + +obj-y += common.o +obj-y += proc.o + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/amd.c linux-2.5/arch/i386/kernel/cpu/amd.c --- linux-2.5.20/arch/i386/kernel/cpu/amd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/amd.c Sat May 25 18:23:37 2002 @@ -0,0 +1,216 @@ +#include +#include +#include +#include + +#include "cpu.h" + +/* + * B step AMD K6 before B 9730xxxx have hardware bugs that can cause + * misexecution of code under Linux. Owners of such processors should + * contact AMD for precise details and a CPU swap. + * + * See http://www.multimania.com/poulot/k6bug.html + * http://www.amd.com/K6/k6docs/revgd.html + * + * The following test is erm.. interesting. AMD neglected to up + * the chip setting when fixing the bug but they also tweaked some + * performance at the same time.. + */ + +extern void vide(void); +__asm__(".align 4\nvide: ret"); + +static void __init init_amd(struct cpuinfo_x86 *c) +{ + u32 l, h; + int mbytes = max_mapnr >> (20-PAGE_SHIFT); + int r; + + /* + * FIXME: We should handle the K5 here. Set up the write + * range and also turn on MSR 83 bits 4 and 31 (write alloc, + * no bus pipeline) + */ + + /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; + 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ + clear_bit(0*32+31, c->x86_capability); + + r = get_model_name(c); + + switch(c->x86) + { + case 5: + if( c->x86_model < 6 ) + { + /* Based on AMD doc 20734R - June 2000 */ + if ( c->x86_model == 0 ) { + clear_bit(X86_FEATURE_APIC, c->x86_capability); + set_bit(X86_FEATURE_PGE, c->x86_capability); + } + break; + } + + if ( c->x86_model == 6 && c->x86_mask == 1 ) { + const int K6_BUG_LOOP = 1000000; + int n; + void (*f_vide)(void); + unsigned long d, d2; + + printk(KERN_INFO "AMD K6 stepping B detected - "); + + /* + * It looks like AMD fixed the 2.6.2 bug and improved indirect + * calls at the same time. + */ + + n = K6_BUG_LOOP; + f_vide = vide; + rdtscl(d); + while (n--) + f_vide(); + rdtscl(d2); + d = d2-d; + + /* Knock these two lines out if it debugs out ok */ + printk(KERN_INFO "K6 BUG %ld %d (Report these if test report is incorrect)\n", d, 20*K6_BUG_LOOP); + printk(KERN_INFO "AMD K6 stepping B detected - "); + /* -- cut here -- */ + if (d > 20*K6_BUG_LOOP) + printk("system stability may be impaired when more than 32 MB are used.\n"); + else + printk("probably OK (after B9730xxxx).\n"); + printk(KERN_INFO "Please see http://www.mygale.com/~poulot/k6bug.html\n"); + } + + /* K6 with old style WHCR */ + if (c->x86_model < 8 || + (c->x86_model== 8 && c->x86_mask < 8)) { + /* We can only write allocate on the low 508Mb */ + if(mbytes>508) + mbytes=508; + + rdmsr(MSR_K6_WHCR, l, h); + if ((l&0x0000FFFF)==0) { + unsigned long flags; + l=(1<<0)|((mbytes/4)<<1); + local_irq_save(flags); + wbinvd(); + wrmsr(MSR_K6_WHCR, l, h); + local_irq_restore(flags); + printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n", + mbytes); + } + break; + } + + if ((c->x86_model == 8 && c->x86_mask >7) || + c->x86_model == 9 || c->x86_model == 13) { + /* The more serious chips .. */ + + if(mbytes>4092) + mbytes=4092; + + rdmsr(MSR_K6_WHCR, l, h); + if ((l&0xFFFF0000)==0) { + unsigned long flags; + l=((mbytes>>2)<<22)|(1<<16); + local_irq_save(flags); + wbinvd(); + wrmsr(MSR_K6_WHCR, l, h); + local_irq_restore(flags); + printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n", + mbytes); + } + + /* Set MTRR capability flag if appropriate */ + if (c->x86_model == 13 || c->x86_model == 9 || + (c->x86_model == 8 && c->x86_mask >= 8)) + set_bit(X86_FEATURE_K6_MTRR, c->x86_capability); + break; + } + break; + + case 6: /* An Athlon/Duron */ + + /* Bit 15 of Athlon specific MSR 15, needs to be 0 + * to enable SSE on Palomino/Morgan CPU's. + * If the BIOS didn't enable it already, enable it + * here. + */ + if (c->x86_model == 6 || c->x86_model == 7) { + if (!cpu_has(c, X86_FEATURE_XMM)) { + printk(KERN_INFO "Enabling disabled K7/SSE Support.\n"); + rdmsr(MSR_K7_HWCR, l, h); + l &= ~0x00008000; + wrmsr(MSR_K7_HWCR, l, h); + set_bit(X86_FEATURE_XMM, c->x86_capability); + } + } + break; + + } + + display_cacheinfo(c); +// return r; +} + +static void amd_identify(struct cpuinfo_x86 * c) +{ + u32 xlvl; + + if (have_cpuid_p()) { + generic_identify(c); + + /* AMD-defined flags: level 0x80000001 */ + xlvl = cpuid_eax(0x80000000); + if ( (xlvl & 0xffff0000) == 0x80000000 ) { + if ( xlvl >= 0x80000001 ) + c->x86_capability[1] = cpuid_edx(0x80000001); + if ( xlvl >= 0x80000004 ) + get_model_name(c); /* Default name */ + } + } +} + +static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size) +{ + /* AMD errata T13 (order #21922) */ + if ((c->x86 == 6)) { + if (c->x86_model == 3 && c->x86_mask == 0) /* Duron Rev A0 */ + size = 64; + if (c->x86_model == 4 && + (c->x86_mask==0 || c->x86_mask==1)) /* Tbird rev A1/A2 */ + size = 256; + } + return size; +} + +static struct cpu_dev amd_cpu_dev __initdata = { + c_vendor: "AMD", + c_ident: { "AuthenticAMD" }, + c_models: { + { X86_VENDOR_AMD, 4, + { + [3] "486 DX/2", + [7] "486 DX/2-WB", + [8] "486 DX/4", + [9] "486 DX/4-WB", + [14] "Am5x86-WT", + [15] "Am5x86-WB" + } + }, + }, + c_init: init_amd, + c_identify: amd_identify, + c_size_cache: amd_size_cache, +}; + +int __init amd_init_cpu(void) +{ + cpu_devs[X86_VENDOR_AMD] = &amd_cpu_dev; + return 0; +} + +//early_arch_initcall(amd_init_cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/centaur.c linux-2.5/arch/i386/kernel/cpu/centaur.c --- linux-2.5.20/arch/i386/kernel/cpu/centaur.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/centaur.c Wed May 8 15:11:31 2002 @@ -0,0 +1,426 @@ +#include +#include +#include +#include +#include +#include "cpu.h" + +#ifdef CONFIG_X86_OOSTORE + +static u32 __init power2(u32 x) +{ + u32 s=1; + while(s<=x) + s<<=1; + return s>>=1; +} + + +/* + * Set up an actual MCR + */ + +static void __init centaur_mcr_insert(int reg, u32 base, u32 size, int key) +{ + u32 lo, hi; + + hi = base & ~0xFFF; + lo = ~(size-1); /* Size is a power of 2 so this makes a mask */ + lo &= ~0xFFF; /* Remove the ctrl value bits */ + lo |= key; /* Attribute we wish to set */ + wrmsr(reg+MSR_IDT_MCR0, lo, hi); + mtrr_centaur_report_mcr(reg, lo, hi); /* Tell the mtrr driver */ +} + +/* + * Figure what we can cover with MCR's + * + * Shortcut: We know you can't put 4Gig of RAM on a winchip + */ + +static u32 __init ramtop(void) /* 16388 */ +{ + int i; + u32 top = 0; + u32 clip = 0xFFFFFFFFUL; + + for (i = 0; i < e820.nr_map; i++) { + unsigned long start, end; + + if (e820.map[i].addr > 0xFFFFFFFFUL) + continue; + /* + * Don't MCR over reserved space. Ignore the ISA hole + * we frob around that catastrophy already + */ + + if (e820.map[i].type == E820_RESERVED) + { + if(e820.map[i].addr >= 0x100000UL && e820.map[i].addr < clip) + clip = e820.map[i].addr; + continue; + } + start = e820.map[i].addr; + end = e820.map[i].addr + e820.map[i].size; + if (start >= end) + continue; + if (end > top) + top = end; + } + /* Everything below 'top' should be RAM except for the ISA hole. + Because of the limited MCR's we want to map NV/ACPI into our + MCR range for gunk in RAM + + Clip might cause us to MCR insufficient RAM but that is an + acceptable failure mode and should only bite obscure boxes with + a VESA hole at 15Mb + + The second case Clip sometimes kicks in is when the EBDA is marked + as reserved. Again we fail safe with reasonable results + */ + + if(top>clip) + top=clip; + + return top; +} + +/* + * Compute a set of MCR's to give maximum coverage + */ + +static int __init centaur_mcr_compute(int nr, int key) +{ + u32 mem = ramtop(); + u32 root = power2(mem); + u32 base = root; + u32 top = root; + u32 floor = 0; + int ct = 0; + + while(ct high && fspace > low) + { + centaur_mcr_insert(ct, floor, fspace, key); + floor += fspace; + } + else if(high > low) + { + centaur_mcr_insert(ct, top, high, key); + top += high; + } + else if(low > 0) + { + base -= low; + centaur_mcr_insert(ct, base, low, key); + } + else break; + ct++; + } + /* + * We loaded ct values. We now need to set the mask. The caller + * must do this bit. + */ + + return ct; +} + +static void __init centaur_create_optimal_mcr(void) +{ + int i; + /* + * Allocate up to 6 mcrs to mark as much of ram as possible + * as write combining and weak write ordered. + * + * To experiment with: Linux never uses stack operations for + * mmio spaces so we could globally enable stack operation wc + * + * Load the registers with type 31 - full write combining, all + * writes weakly ordered. + */ + int used = centaur_mcr_compute(6, 31); + + /* + * Wipe unused MCRs + */ + + for(i=used;i<8;i++) + wrmsr(MSR_IDT_MCR0+i, 0, 0); +} + +static void __init winchip2_create_optimal_mcr(void) +{ + u32 lo, hi; + int i; + + /* + * Allocate up to 6 mcrs to mark as much of ram as possible + * as write combining, weak store ordered. + * + * Load the registers with type 25 + * 8 - weak write ordering + * 16 - weak read ordering + * 1 - write combining + */ + + int used = centaur_mcr_compute(6, 25); + + /* + * Mark the registers we are using. + */ + + rdmsr(MSR_IDT_MCR_CTRL, lo, hi); + for(i=0;i>17) & 7; + lo |= key<<6; /* replace with unlock key */ + wrmsr(MSR_IDT_MCR_CTRL, lo, hi); +} + +static void __init winchip2_protect_mcr(void) +{ + u32 lo, hi; + + rdmsr(MSR_IDT_MCR_CTRL, lo, hi); + lo&=~0x1C0; /* blank bits 8-6 */ + wrmsr(MSR_IDT_MCR_CTRL, lo, hi); +} +#endif + +static void __init init_centaur(struct cpuinfo_x86 *c) +{ + enum { + ECX8=1<<1, + EIERRINT=1<<2, + DPM=1<<3, + DMCE=1<<4, + DSTPCLK=1<<5, + ELINEAR=1<<6, + DSMC=1<<7, + DTLOCK=1<<8, + EDCTLB=1<<8, + EMMX=1<<9, + DPDC=1<<11, + EBRPRED=1<<12, + DIC=1<<13, + DDC=1<<14, + DNA=1<<15, + ERETSTK=1<<16, + E2MMX=1<<19, + EAMD3D=1<<20, + }; + + char *name; + u32 fcr_set=0; + u32 fcr_clr=0; + u32 lo,hi,newlo; + u32 aa,bb,cc,dd; + + /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; + 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ + clear_bit(0*32+31, c->x86_capability); + + switch (c->x86) { + + case 5: + switch(c->x86_model) { + case 4: + name="C6"; + fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK; + fcr_clr=DPDC; + printk(KERN_NOTICE "Disabling bugged TSC.\n"); + clear_bit(X86_FEATURE_TSC, c->x86_capability); +#ifdef CONFIG_X86_OOSTORE + centaur_create_optimal_mcr(); + /* Enable + write combining on non-stack, non-string + write combining on string, all types + weak write ordering + + The C6 original lacks weak read order + + Note 0x120 is write only on Winchip 1 */ + + wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); +#endif + break; + case 8: + switch(c->x86_mask) { + default: + name="2"; + break; + case 7 ... 9: + name="2A"; + break; + case 10 ... 15: + name="2B"; + break; + } + fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; + fcr_clr=DPDC; +#ifdef CONFIG_X86_OOSTORE + winchip2_unprotect_mcr(); + winchip2_create_optimal_mcr(); + rdmsr(MSR_IDT_MCR_CTRL, lo, hi); + /* Enable + write combining on non-stack, non-string + write combining on string, all types + weak write ordering + */ + lo|=31; + wrmsr(MSR_IDT_MCR_CTRL, lo, hi); + winchip2_protect_mcr(); +#endif + break; + case 9: + name="3"; + fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; + fcr_clr=DPDC; +#ifdef CONFIG_X86_OOSTORE + winchip2_unprotect_mcr(); + winchip2_create_optimal_mcr(); + rdmsr(MSR_IDT_MCR_CTRL, lo, hi); + /* Enable + write combining on non-stack, non-string + write combining on string, all types + weak write ordering + */ + lo|=31; + wrmsr(MSR_IDT_MCR_CTRL, lo, hi); + winchip2_protect_mcr(); +#endif + break; + case 10: + name="4"; + /* no info on the WC4 yet */ + break; + default: + name="??"; + } + + rdmsr(MSR_IDT_FCR1, lo, hi); + newlo=(lo|fcr_set) & (~fcr_clr); + + if (newlo!=lo) { + printk(KERN_INFO "Centaur FCR was 0x%X now 0x%X\n", lo, newlo ); + wrmsr(MSR_IDT_FCR1, newlo, hi ); + } else { + printk(KERN_INFO "Centaur FCR is 0x%X\n",lo); + } + /* Emulate MTRRs using Centaur's MCR. */ + set_bit(X86_FEATURE_CENTAUR_MCR, c->x86_capability); + /* Report CX8 */ + set_bit(X86_FEATURE_CX8, c->x86_capability); + /* Set 3DNow! on Winchip 2 and above. */ + if (c->x86_model >=8) + set_bit(X86_FEATURE_3DNOW, c->x86_capability); + /* See if we can find out some more. */ + if ( cpuid_eax(0x80000000) >= 0x80000005 ) { + /* Yes, we can. */ + cpuid(0x80000005,&aa,&bb,&cc,&dd); + /* Add L1 data and code cache sizes. */ + c->x86_cache_size = (cc>>24)+(dd>>24); + } + sprintf( c->x86_model_id, "WinChip %s", name ); + break; + + case 6: + switch (c->x86_model) { + case 6 ... 8: /* Cyrix III family */ + rdmsr (MSR_VIA_FCR, lo, hi); + lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */ + wrmsr (MSR_VIA_FCR, lo, hi); + + set_bit(X86_FEATURE_CX8, c->x86_capability); + set_bit(X86_FEATURE_3DNOW, c->x86_capability); + + get_model_name(c); + display_cacheinfo(c); + break; + } + break; + } +} + +static unsigned int centaur_size_cache(struct cpuinfo_x86 * c, unsigned int size) +{ + /* VIA C3 CPUs (670-68F) need further shifting. */ + if ((c->x86 == 6) && ((c->x86_model == 7) || (c->x86_model == 8))) + size >>= 8; + return size; +} + +static struct cpu_dev centaur_cpu_dev __initdata = { + c_vendor: "Centaur", + c_ident: { "CentaurHauls" }, + c_init: init_centaur, + c_size_cache: centaur_size_cache, +}; + +int __init centaur_init_cpu(void) +{ + cpu_devs[X86_VENDOR_CENTAUR] = ¢aur_cpu_dev; + return 0; +} + +//early_arch_initcall(centaur_init_cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/changelog linux-2.5/arch/i386/kernel/cpu/changelog --- linux-2.5.20/arch/i386/kernel/cpu/changelog Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/changelog Fri May 10 03:27:37 2002 @@ -0,0 +1,63 @@ +/* + * Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean + * and Martin Mares, November 1997. + * + * Force Cyrix 6x86(MX) and M II processors to report MTRR capability + * and Cyrix "coma bug" recognition by + * Zoltán Böszörményi February 1999. + * + * Force Centaur C6 processors to report MTRR capability. + * Bart Hartgers , May 1999. + * + * Intel Mobile Pentium II detection fix. Sean Gilley, June 1999. + * + * IDT Winchip tweaks, misc clean ups. + * Dave Jones , August 1999 + * + * Better detection of Centaur/IDT WinChip models. + * Bart Hartgers , August 1999. + * + * Cleaned up cache-detection code + * Dave Jones , October 1999 + * + * Added proper L2 cache detection for Coppermine + * Dragan Stancevic , October 1999 + * + * Added the original array for capability flags but forgot to credit + * myself :) (~1998) Fixed/cleaned up some cpu_model_info and other stuff + * Jauder Ho , January 2000 + * + * Detection for Celeron coppermine, identify_cpu() overhauled, + * and a few other clean ups. + * Dave Jones , April 2000 + * + * Pentium III FXSR, SSE support + * General FPU state handling cleanups + * Gareth Hughes , May 2000 + * + * Added proper Cascades CPU and L2 cache detection for Cascades + * and 8-way type cache happy bunch from Intel:^) + * Dragan Stancevic , May 2000 + * + * Forward port AMD Duron errata T13 from 2.2.17pre + * Dave Jones , August 2000 + * + * Forward port lots of fixes/improvements from 2.2.18pre + * Cyrix III, Pentium IV support. + * Dave Jones , October 2000 + * + * Massive cleanup of CPU detection and bug handling; + * Transmeta CPU detection, + * H. Peter Anvin , November 2000 + * + * VIA C3 Support. + * Dave Jones , March 2001 + * + * AMD Athlon/Duron/Thunderbird bluesmoke support. + * Dave Jones , April 2001. + * + * CacheSize bug workaround updates for AMD, Intel & VIA Cyrix. + * Dave Jones , September, October 2001. + * + */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/common.c linux-2.5/arch/i386/kernel/cpu/common.c --- linux-2.5.20/arch/i386/kernel/cpu/common.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/common.c Fri May 10 16:06:30 2002 @@ -0,0 +1,486 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" + +static int cachesize_override __initdata = -1; +static int disable_x86_fxsr __initdata = 0; + +struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {}; + +static struct cpu_dev default_cpu; +static struct cpu_dev * this_cpu = &default_cpu; + +extern void mcheck_init(struct cpuinfo_x86 *c); + +static void default_init(struct cpuinfo_x86 * c) +{ + /* Not much we can do here... */ + /* Check if at least it has cpuid */ + if (c->cpuid_level == -1) { + /* No cpuid. It must be an ancient CPU */ + if (c->x86 == 4) + strcpy(c->x86_model_id, "486"); + else if (c->x86 == 3) + strcpy(c->x86_model_id, "386"); + } +} + +static struct cpu_dev default_cpu = { + c_init: default_init, +}; + +static int __init cachesize_setup(char *str) +{ + get_option (&str, &cachesize_override); + return 1; +} +__setup("cachesize=", cachesize_setup); + +#ifndef CONFIG_X86_TSC +static int tsc_disable __initdata = 0; + +static int __init tsc_setup(char *str) +{ + tsc_disable = 1; + return 1; +} + +__setup("notsc", tsc_setup); +#endif + +int __init get_model_name(struct cpuinfo_x86 *c) +{ + unsigned int *v; + char *p, *q; + + if (cpuid_eax(0x80000000) < 0x80000004) + return 0; + + v = (unsigned int *) c->x86_model_id; + cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); + cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); + cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); + c->x86_model_id[48] = 0; + + /* Intel chips right-justify this string for some dumb reason; + undo that brain damage */ + p = q = &c->x86_model_id[0]; + while ( *p == ' ' ) + p++; + if ( p != q ) { + while ( *p ) + *q++ = *p++; + while ( q <= &c->x86_model_id[48] ) + *q++ = '\0'; /* Zero-pad the rest */ + } + + return 1; +} + + +void __init display_cacheinfo(struct cpuinfo_x86 *c) +{ + unsigned int n, dummy, ecx, edx, l2size; + + n = cpuid_eax(0x80000000); + + if (n >= 0x80000005) { + cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); + printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n", + edx>>24, edx&0xFF, ecx>>24, ecx&0xFF); + c->x86_cache_size=(ecx>>24)+(edx>>24); + } + + if (n < 0x80000006) /* Some chips just has a large L1. */ + return; + + ecx = cpuid_ecx(0x80000006); + l2size = ecx >> 16; + + /* do processor-specific cache resizing */ + if (this_cpu->c_size_cache) + l2size = this_cpu->c_size_cache(c,l2size); + + /* Allow user to override all this if necessary. */ + if (cachesize_override != -1) + l2size = cachesize_override; + + if ( l2size == 0 ) + return; /* Again, no L2 cache is possible */ + + c->x86_cache_size = l2size; + + printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n", + l2size, ecx & 0xFF); +} + +/* Naming convention should be: [()] */ +/* This table only is used unless init_() below doesn't set it; */ +/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */ + +/* Look up CPU names by table lookup. */ +static char __init *table_lookup_model(struct cpuinfo_x86 *c) +{ + struct cpu_model_info *info; + + if ( c->x86_model >= 16 ) + return NULL; /* Range check */ + + if (!this_cpu) + return NULL; + + info = this_cpu->c_models; + + while (info && info->family) { + if (info->family == c->x86) + return info->model_names[c->x86_model]; + info++; + } + return NULL; /* Not found */ +} + + + +void __init get_cpu_vendor(struct cpuinfo_x86 *c) +{ + char *v = c->x86_vendor_id; + int i; + + for (i = 0; i < X86_VENDOR_NUM; i++) { + if (cpu_devs[i]) { + if (!strcmp(v,cpu_devs[i]->c_ident[0]) || + (cpu_devs[i]->c_ident[1] && + !strcmp(v,cpu_devs[i]->c_ident[1]))) { + c->x86_vendor = i; + this_cpu = cpu_devs[i]; + break; + } + } + } +} + + +static int __init x86_fxsr_setup(char * s) +{ + disable_x86_fxsr = 1; + return 1; +} +__setup("nofxsr", x86_fxsr_setup); + + +/* Standard macro to see if a specific flag is changeable */ +static inline int flag_is_changeable_p(u32 flag) +{ + u32 f1, f2; + + asm("pushfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "movl %0,%1\n\t" + "xorl %2,%0\n\t" + "pushl %0\n\t" + "popfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "popfl\n\t" + : "=&r" (f1), "=&r" (f2) + : "ir" (flag)); + + return ((f1^f2) & flag) != 0; +} + + +/* Probe for the CPUID instruction */ +int __init have_cpuid_p(void) +{ + return flag_is_changeable_p(X86_EFLAGS_ID); +} + +void __init generic_identify(struct cpuinfo_x86 * c) +{ + u32 tfms; + int junk; + + if (have_cpuid_p()) { + /* Get vendor name */ + cpuid(0x00000000, &c->cpuid_level, + (int *)&c->x86_vendor_id[0], + (int *)&c->x86_vendor_id[8], + (int *)&c->x86_vendor_id[4]); + + get_cpu_vendor(c); + /* Initialize the standard set of capabilities */ + /* Note that the vendor-specific code below might override */ + + /* Intel-defined flags: level 0x00000001 */ + if ( c->cpuid_level >= 0x00000001 ) { + u32 capability; + cpuid(0x00000001, &tfms, &junk, &junk, &capability); + c->x86_capability[0] = capability; + c->x86 = (tfms >> 8) & 15; + c->x86_model = (tfms >> 4) & 15; + c->x86_mask = tfms & 15; + } else { + /* Have CPUID level 0 only - unheard of */ + c->x86 = 4; + } + } +} + +/* + * This does the hard work of actually picking apart the CPU stuff... + */ +void __init identify_cpu(struct cpuinfo_x86 *c) +{ + int i; + + c->loops_per_jiffy = loops_per_jiffy; + c->x86_cache_size = -1; + c->x86_vendor = X86_VENDOR_UNKNOWN; + c->cpuid_level = -1; /* CPUID not detected */ + c->x86_model = c->x86_mask = 0; /* So far unknown... */ + c->x86_vendor_id[0] = '\0'; /* Unset */ + c->x86_model_id[0] = '\0'; /* Unset */ + memset(&c->x86_capability, 0, sizeof c->x86_capability); + + if (!have_cpuid_p()) { + /* First of all, decide if this is a 486 or higher */ + /* It's a 486 if we can modify the AC flag */ + if ( flag_is_changeable_p(X86_EFLAGS_AC) ) + c->x86 = 4; + else + c->x86 = 3; + } + + if (this_cpu->c_identify) + this_cpu->c_identify(c); + else + generic_identify(c); + + printk(KERN_DEBUG "CPU: Before vendor init, caps: %08lx %08lx %08lx, vendor = %d\n", + c->x86_capability[0], + c->x86_capability[1], + c->x86_capability[2], + c->x86_vendor); + + /* + * Vendor-specific initialization. In this section we + * canonicalize the feature flags, meaning if there are + * features a certain CPU supports which CPUID doesn't + * tell us, CPUID claiming incorrect flags, or other bugs, + * we handle them here. + * + * At the end of this section, c->x86_capability better + * indicate the features this CPU genuinely supports! + */ + if (this_cpu->c_init) + this_cpu->c_init(c); + + printk(KERN_DEBUG "CPU: After vendor init, caps: %08lx %08lx %08lx %08lx\n", + c->x86_capability[0], + c->x86_capability[1], + c->x86_capability[2], + c->x86_capability[3]); + + /* + * The vendor-specific functions might have changed features. Now + * we do "generic changes." + */ + + /* TSC disabled? */ +#ifndef CONFIG_X86_TSC + if ( tsc_disable ) + clear_bit(X86_FEATURE_TSC, c->x86_capability); +#endif + + /* FXSR disabled? */ + if (disable_x86_fxsr) { + clear_bit(X86_FEATURE_FXSR, c->x86_capability); + clear_bit(X86_FEATURE_XMM, c->x86_capability); + } + + /* Init Machine Check Exception if available. */ + mcheck_init(c); + + /* If the model name is still unset, do table lookup. */ + if ( !c->x86_model_id[0] ) { + char *p; + p = table_lookup_model(c); + if ( p ) + strcpy(c->x86_model_id, p); + else + /* Last resort... */ + sprintf(c->x86_model_id, "%02x/%02x", + c->x86_vendor, c->x86_model); + } + + /* Now the feature flags better reflect actual CPU features! */ + + printk(KERN_DEBUG "CPU: After generic, caps: %08lx %08lx %08lx %08lx\n", + c->x86_capability[0], + c->x86_capability[1], + c->x86_capability[2], + c->x86_capability[3]); + + /* + * On SMP, boot_cpu_data holds the common feature set between + * all CPUs; so make sure that we indicate which features are + * common between the CPUs. The first time this routine gets + * executed, c == &boot_cpu_data. + */ + if ( c != &boot_cpu_data ) { + /* AND the already accumulated flags with these */ + for ( i = 0 ; i < NCAPINTS ; i++ ) + boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; + } + + printk(KERN_DEBUG "CPU: Common caps: %08lx %08lx %08lx %08lx\n", + boot_cpu_data.x86_capability[0], + boot_cpu_data.x86_capability[1], + boot_cpu_data.x86_capability[2], + boot_cpu_data.x86_capability[3]); +} +/* + * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c + */ + +void __init dodgy_tsc(void) +{ + get_cpu_vendor(&boot_cpu_data); + if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) || + ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC )) + cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data); +} + +void __init print_cpu_info(struct cpuinfo_x86 *c) +{ + char *vendor = NULL; + + if (c->x86_vendor < X86_VENDOR_NUM) + vendor = this_cpu->c_vendor; + else if (c->cpuid_level >= 0) + vendor = c->x86_vendor_id; + + if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor))) + printk("%s ", vendor); + + if (!c->x86_model_id[0]) + printk("%d86", c->x86); + else + printk("%s", c->x86_model_id); + + if (c->x86_mask || c->cpuid_level >= 0) + printk(" stepping %02x\n", c->x86_mask); + else + printk("\n"); +} + +unsigned long cpu_initialized __initdata = 0; + +/* This is hacky. :) + * We're emulating future behavior. + * In the future, the cpu-specific init functions will be called implicitly + * via the magic of initcalls. + * They will insert themselves into the cpu_devs structure. + * Then, when cpu_init() is called, we can just iterate over that array. + */ + +extern int intel_cpu_init(void); +extern int cyrix_init_cpu(void); +extern int nsc_init_cpu(void); +extern int amd_init_cpu(void); +extern int centaur_init_cpu(void); +extern int transmeta_init_cpu(void); +extern int rise_init_cpu(void); +extern int nexgen_init_cpu(void); +extern int umc_init_cpu(void); + +void __init early_cpu_init(void) +{ + intel_cpu_init(); + cyrix_init_cpu(); + nsc_init_cpu(); + amd_init_cpu(); + centaur_init_cpu(); + transmeta_init_cpu(); + rise_init_cpu(); + nexgen_init_cpu(); + umc_init_cpu(); +} +/* + * cpu_init() initializes state that is per-CPU. Some data is already + * initialized (naturally) in the bootstrap process, such as the GDT + * and IDT. We reload them nevertheless, this function acts as a + * 'CPU state barrier', nothing should get across. + */ +void __init cpu_init (void) +{ + int nr = smp_processor_id(); + struct tss_struct * t = &init_tss[nr]; + + if (test_and_set_bit(nr, &cpu_initialized)) { + printk(KERN_WARNING "CPU#%d already initialized!\n", nr); + for (;;) __sti(); + } + printk(KERN_INFO "Initializing CPU#%d\n", nr); + + if (cpu_has_vme || cpu_has_tsc || cpu_has_de) + clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); +#ifndef CONFIG_X86_TSC + if (tsc_disable && cpu_has_tsc) { + printk(KERN_NOTICE "Disabling TSC...\n"); + /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/ + clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability); + set_in_cr4(X86_CR4_TSD); + } +#endif + + __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); + __asm__ __volatile__("lidt %0": "=m" (idt_descr)); + + /* + * Delete NT + */ + __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); + + /* + * set up and load the per-CPU TSS and LDT + */ + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + if(current->mm) + BUG(); + enter_lazy_tlb(&init_mm, current, nr); + + t->esp0 = current->thread.esp0; + set_tss_desc(nr,t); + gdt_table[__TSS(nr)].b &= 0xfffffdff; + load_TR(nr); + load_LDT(&init_mm.context); + + /* Clear %fs and %gs. */ + asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); + + /* Clear all 6 debug registers: */ + +#define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) ); + + CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7); + +#undef CD + + /* + * Force FPU initialization: + */ + clear_thread_flag(TIF_USEDFPU); + current->used_math = 0; + stts(); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/cpu.h linux-2.5/arch/i386/kernel/cpu/cpu.h --- linux-2.5.20/arch/i386/kernel/cpu/cpu.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/cpu.h Wed May 8 15:11:31 2002 @@ -0,0 +1,28 @@ + +struct cpu_model_info { + int vendor; + int family; + char *model_names[16]; +}; + +/* attempt to consolidate cpu attributes */ +struct cpu_dev { + char * c_vendor; + + /* some have two possibilities for cpuid string */ + char * c_ident[2]; + + struct cpu_model_info c_models[4]; + + void (*c_init)(struct cpuinfo_x86 * c); + void (*c_identify)(struct cpuinfo_x86 * c); + unsigned int (*c_size_cache)(struct cpuinfo_x86 * c, unsigned int size); +}; + +extern struct cpu_dev * cpu_devs [X86_VENDOR_NUM]; + +extern int get_model_name(struct cpuinfo_x86 *c); +extern void display_cacheinfo(struct cpuinfo_x86 *c); + +extern void generic_identify(struct cpuinfo_x86 * c); +extern int have_cpuid_p(void); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/cyrix.c linux-2.5/arch/i386/kernel/cpu/cyrix.c --- linux-2.5.20/arch/i386/kernel/cpu/cyrix.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/cyrix.c Wed May 8 15:11:31 2002 @@ -0,0 +1,350 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" + +/* + * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU + */ +void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) +{ + unsigned char ccr2, ccr3; + unsigned long flags; + + /* we test for DEVID by checking whether CCR3 is writable */ + local_irq_save(flags); + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, ccr3 ^ 0x80); + getCx86(0xc0); /* dummy to change bus */ + + if (getCx86(CX86_CCR3) == ccr3) { /* no DEVID regs. */ + ccr2 = getCx86(CX86_CCR2); + setCx86(CX86_CCR2, ccr2 ^ 0x04); + getCx86(0xc0); /* dummy */ + + if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */ + *dir0 = 0xfd; + else { /* Cx486S A step */ + setCx86(CX86_CCR2, ccr2); + *dir0 = 0xfe; + } + } + else { + setCx86(CX86_CCR3, ccr3); /* restore CCR3 */ + + /* read DIR0 and DIR1 CPU registers */ + *dir0 = getCx86(CX86_DIR0); + *dir1 = getCx86(CX86_DIR1); + } + local_irq_restore(flags); +} + +/* + * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in + * order to identify the Cyrix CPU model after we're out of setup.c + * + * Actually since bugs.h doesnt even reference this perhaps someone should + * fix the documentation ??? + */ +static unsigned char Cx86_dir0_msb __initdata = 0; + +static char Cx86_model[][9] __initdata = { + "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ", + "M II ", "Unknown" +}; +static char Cx486_name[][5] __initdata = { + "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx", + "SRx2", "DRx2" +}; +static char Cx486S_name[][4] __initdata = { + "S", "S2", "Se", "S2e" +}; +static char Cx486D_name[][4] __initdata = { + "DX", "DX2", "?", "?", "?", "DX4" +}; +static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock"; +static char cyrix_model_mult1[] __initdata = "12??43"; +static char cyrix_model_mult2[] __initdata = "12233445"; + +/* + * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old + * BIOSes for compatability with DOS games. This makes the udelay loop + * work correctly, and improves performance. + * + * FIXME: our newer udelay uses the tsc. We dont need to frob with SLOP + */ + +extern void calibrate_delay(void) __init; + +static void __init check_cx686_slop(struct cpuinfo_x86 *c) +{ + unsigned long flags; + + if (Cx86_dir0_msb == 3) { + unsigned char ccr3, ccr5; + + local_irq_save(flags); + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ + ccr5 = getCx86(CX86_CCR5); + if (ccr5 & 2) + setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */ + setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ + local_irq_restore(flags); + + if (ccr5 & 2) { /* possible wrong calibration done */ + printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n"); + calibrate_delay(); + c->loops_per_jiffy = loops_per_jiffy; + } + } +} + +static void __init init_cyrix(struct cpuinfo_x86 *c) +{ + unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; + char *buf = c->x86_model_id; + const char *p = NULL; + + /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; + 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ + clear_bit(0*32+31, c->x86_capability); + + /* Cyrix used bit 24 in extended (AMD) CPUID for Cyrix MMX extensions */ + if ( test_bit(1*32+24, c->x86_capability) ) { + clear_bit(1*32+24, c->x86_capability); + set_bit(X86_FEATURE_CXMMX, c->x86_capability); + } + + do_cyrix_devid(&dir0, &dir1); + + check_cx686_slop(c); + + Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family" */ + dir0_lsn = dir0 & 0xf; /* model or clock multiplier */ + + /* common case step number/rev -- exceptions handled below */ + c->x86_model = (dir1 >> 4) + 1; + c->x86_mask = dir1 & 0xf; + + /* Now cook; the original recipe is by Channing Corn, from Cyrix. + * We do the same thing for each generation: we work out + * the model, multiplier and stepping. Black magic included, + * to make the silicon step/rev numbers match the printed ones. + */ + + switch (dir0_msn) { + unsigned char tmp; + + case 0: /* Cx486SLC/DLC/SRx/DRx */ + p = Cx486_name[dir0_lsn & 7]; + break; + + case 1: /* Cx486S/DX/DX2/DX4 */ + p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5] + : Cx486S_name[dir0_lsn & 3]; + break; + + case 2: /* 5x86 */ + Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5]; + p = Cx86_cb+2; + break; + + case 3: /* 6x86/6x86L */ + Cx86_cb[1] = ' '; + Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5]; + if (dir1 > 0x21) { /* 686L */ + Cx86_cb[0] = 'L'; + p = Cx86_cb; + (c->x86_model)++; + } else /* 686 */ + p = Cx86_cb+1; + /* Emulate MTRRs using Cyrix's ARRs. */ + set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability); + /* 6x86's contain this bug */ + c->coma_bug = 1; + break; + + case 4: /* MediaGX/GXm */ +#ifdef CONFIG_PCI + /* It isn't really a PCI quirk directly, but the cure is the + same. The MediaGX has deep magic SMM stuff that handles the + SB emulation. It thows away the fifo on disable_dma() which + is wrong and ruins the audio. + + Bug2: VSA1 has a wrap bug so that using maximum sized DMA + causes bad things. According to NatSemi VSA2 has another + bug to do with 'hlt'. I've not seen any boards using VSA2 + and X doesn't seem to support it either so who cares 8). + VSA1 we work around however. + */ + + printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bugs.\n"); + isa_dma_bridge_buggy = 2; +#endif + c->x86_cache_size=16; /* Yep 16K integrated cache thats it */ + + /* GXm supports extended cpuid levels 'ala' AMD */ + if (c->cpuid_level == 2) { + /* Enable Natsemi MMX extensions */ + setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1); + + get_model_name(c); /* get CPU marketing name */ + /* + * The 5510/5520 companion chips have a funky PIT + * that breaks the TSC synchronizing, so turn it off + */ + if(pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) || + pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL)) + clear_bit(X86_FEATURE_TSC, c->x86_capability); + return; + } + else { /* MediaGX */ + Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4'; + p = Cx86_cb+2; + c->x86_model = (dir1 & 0x20) ? 1 : 2; +#ifndef CONFIG_CS5520 + clear_bit(X86_FEATURE_TSC, c->x86_capability); +#endif + } + break; + + case 5: /* 6x86MX/M II */ + if (dir1 > 7) + { + dir0_msn++; /* M II */ + /* Enable MMX extensions (App note 108) */ + setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1); + } + else + { + c->coma_bug = 1; /* 6x86MX, it has the bug. */ + } + tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0; + Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7]; + p = Cx86_cb+tmp; + if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20)) + (c->x86_model)++; + /* Emulate MTRRs using Cyrix's ARRs. */ + set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability); + break; + + case 0xf: /* Cyrix 486 without DEVID registers */ + switch (dir0_lsn) { + case 0xd: /* either a 486SLC or DLC w/o DEVID */ + dir0_msn = 0; + p = Cx486_name[(c->hard_math) ? 1 : 0]; + break; + + case 0xe: /* a 486S A step */ + dir0_msn = 0; + p = Cx486S_name[0]; + break; + } + break; + + default: /* unknown (shouldn't happen, we know everyone ;-) */ + dir0_msn = 7; + break; + } + strcpy(buf, Cx86_model[dir0_msn & 7]); + if (p) strcat(buf, p); + return; +} + +/* + * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected + * by the fact that they preserve the flags across the division of 5/2. + * PII and PPro exhibit this behavior too, but they have cpuid available. + */ + +/* + * Perform the Cyrix 5/2 test. A Cyrix won't change + * the flags, while other 486 chips will. + */ +static inline int test_cyrix_52div(void) +{ + unsigned int test; + + __asm__ __volatile__( + "sahf\n\t" /* clear flags (%eax = 0x0005) */ + "div %b2\n\t" /* divide 5 by 2 */ + "lahf" /* store flags into %ah */ + : "=a" (test) + : "0" (5), "q" (2) + : "cc"); + + /* AH is 0x02 on Cyrix after the divide.. */ + return (unsigned char) (test >> 8) == 0x02; +} + +static void cyrix_identify(struct cpuinfo_x86 * c) +{ + /* Detect Cyrix with disabled CPUID */ + if ( c->x86 == 4 && test_cyrix_52div() ) { + unsigned char dir0, dir1; + + strcpy(c->x86_vendor_id, "CyrixInstead"); + c->x86_vendor = X86_VENDOR_CYRIX; + + /* Actually enable cpuid on the older cyrix */ + + /* Retrieve CPU revisions */ + + do_cyrix_devid(&dir0, &dir1); + + dir0>>=4; + + /* Check it is an affected model */ + + if (dir0 == 5 || dir0 == 3) + { + unsigned char ccr3, ccr4; + unsigned long flags; + printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n"); + local_irq_save(flags); + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ + ccr4 = getCx86(CX86_CCR4); + setCx86(CX86_CCR4, ccr4 | 0x80); /* enable cpuid */ + setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ + local_irq_restore(flags); + } + } + generic_identify(c); +} + +static struct cpu_dev cyrix_cpu_dev __initdata = { + c_vendor: "Cyrix", + c_ident: { "CyrixInstead" }, + c_init: init_cyrix, + c_identify: cyrix_identify, +}; + +int __init cyrix_init_cpu(void) +{ + cpu_devs[X86_VENDOR_CYRIX] = &cyrix_cpu_dev; + return 0; +} + +//early_arch_initcall(cyrix_init_cpu); + +static struct cpu_dev nsc_cpu_dev __initdata = { + c_vendor: "NSC", + c_ident: { "Geode by NSC" }, + c_init: init_cyrix, + c_identify: generic_identify, +}; + +int __init nsc_init_cpu(void) +{ + cpu_devs[X86_VENDOR_NSC] = &nsc_cpu_dev; + return 0; +} + +//early_arch_initcall(nsc_init_cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/intel.c linux-2.5/arch/i386/kernel/cpu/intel.c --- linux-2.5.20/arch/i386/kernel/cpu/intel.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/intel.c Sun May 26 00:32:46 2002 @@ -0,0 +1,401 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" + +static int disable_x86_serial_nr __initdata = 1; +static int disable_P4_HT __initdata = 0; +extern int trap_init_f00f_bug(void); + +/* + * Early probe support logic for ppro memory erratum #50 + * + * This is called before we do cpu ident work + */ + +int __init ppro_with_ram_bug(void) +{ + char vendor_id[16]; + int ident; + + /* Must have CPUID */ + if(!have_cpuid_p()) + return 0; + if(cpuid_eax(0)<1) + return 0; + + /* Must be Intel */ + cpuid(0, &ident, + (int *)&vendor_id[0], + (int *)&vendor_id[8], + (int *)&vendor_id[4]); + + if(memcmp(vendor_id, "IntelInside", 12)) + return 0; + + ident = cpuid_eax(1); + + /* Model 6 */ + + if(((ident>>8)&15)!=6) + return 0; + + /* Pentium Pro */ + + if(((ident>>4)&15)!=1) + return 0; + + if((ident&15) < 8) + { + printk(KERN_INFO "Pentium Pro with Errata#50 detected. Taking evasive action.\n"); + return 1; + } + printk(KERN_INFO "Your Pentium Pro seems ok.\n"); + return 0; +} + +static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c) +{ + if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) { + /* Disable processor serial number */ + unsigned long lo,hi; + rdmsr(MSR_IA32_BBL_CR_CTL,lo,hi); + lo |= 0x200000; + wrmsr(MSR_IA32_BBL_CR_CTL,lo,hi); + printk(KERN_NOTICE "CPU serial number disabled.\n"); + clear_bit(X86_FEATURE_PN, c->x86_capability); + + /* Disabling the serial number may affect the cpuid level */ + c->cpuid_level = cpuid_eax(0); + } +} + +static int __init x86_serial_nr_setup(char *s) +{ + disable_x86_serial_nr = 0; + return 1; +} +__setup("serialnumber", x86_serial_nr_setup); + +static int __init P4_disable_ht(char *s) +{ + disable_P4_HT = 1; + return 1; +} +__setup("noht", P4_disable_ht); + + +/* + * P4 Xeon errata 037 workaround. + * Hardware prefetcher may cause stale data to be loaded into the cache. + */ +static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c) +{ + unsigned long lo, hi; + + if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) { + rdmsr (MSR_IA32_MISC_ENABLE, lo, hi); + if ((lo & (1<<9)) == 0) { + printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n"); + printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n"); + lo |= (1<<9); /* Disable hw prefetching */ + wrmsr (MSR_IA32_MISC_ENABLE, lo, hi); + } + } +} + + +static void __init init_intel(struct cpuinfo_x86 *c) +{ + char *p = NULL; + unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ + +#ifdef CONFIG_X86_F00F_BUG + /* + * All current models of Pentium and Pentium with MMX technology CPUs + * have the F0 0F bug, which lets nonpriviledged users lock up the system. + * Note that the workaround only should be initialized once... + */ + c->f00f_bug = 0; + if ( c->x86 == 5 ) { + static int f00f_workaround_enabled = 0; + + c->f00f_bug = 1; + if ( !f00f_workaround_enabled ) { + trap_init_f00f_bug(); + printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); + f00f_workaround_enabled = 1; + } + } +#endif + + + if (c->cpuid_level > 1) { + /* supports eax=2 call */ + int i, j, n; + int regs[4]; + unsigned char *dp = (unsigned char *)regs; + + /* Number of times to iterate */ + n = cpuid_eax(2) & 0xFF; + + for ( i = 0 ; i < n ; i++ ) { + cpuid(2, ®s[0], ®s[1], ®s[2], ®s[3]); + + /* If bit 31 is set, this is an unknown format */ + for ( j = 0 ; j < 3 ; j++ ) { + if ( regs[j] < 0 ) regs[j] = 0; + } + + /* Byte 0 is level count, not a descriptor */ + for ( j = 1 ; j < 16 ; j++ ) { + unsigned char des = dp[j]; + unsigned char dl, dh; + unsigned int cs; + + dh = des >> 4; + dl = des & 0x0F; + + /* Black magic... */ + + switch ( dh ) + { + case 0: + switch ( dl ) { + case 6: + /* L1 I cache */ + l1i += 8; + break; + case 8: + /* L1 I cache */ + l1i += 16; + break; + case 10: + /* L1 D cache */ + l1d += 8; + break; + case 12: + /* L1 D cache */ + l1d += 16; + break; + default:; + /* TLB, or unknown */ + } + break; + case 2: + if ( dl ) { + /* L3 cache */ + cs = (dl-1) << 9; + l3 += cs; + } + break; + case 4: + if ( c->x86 > 6 && dl ) { + /* P4 family */ + /* L3 cache */ + cs = 128 << (dl-1); + l3 += cs; + break; + } + /* else same as 8 - fall through */ + case 8: + if ( dl ) { + /* L2 cache */ + cs = 128 << (dl-1); + l2 += cs; + } + break; + case 6: + if (dl > 5) { + /* L1 D cache */ + cs = 8<<(dl-6); + l1d += cs; + } + break; + case 7: + if ( dl >= 8 ) + { + /* L2 cache */ + cs = 64<<(dl-8); + l2 += cs; + } else { + /* L0 I cache, count as L1 */ + cs = dl ? (16 << (dl-1)) : 12; + l1i += cs; + } + break; + default: + /* TLB, or something else we don't know about */ + break; + } + } + } + if ( l1i || l1d ) + printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n", + l1i, l1d); + if ( l2 ) + printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); + if ( l3 ) + printk(KERN_INFO "CPU: L3 cache: %dK\n", l3); + + /* + * This assumes the L3 cache is shared; it typically lives in + * the northbridge. The L1 caches are included by the L2 + * cache, and so should not be included for the purpose of + * SMP switching weights. + */ + c->x86_cache_size = l2 ? l2 : (l1i+l1d); + } + + /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it */ + if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 ) + clear_bit(X86_FEATURE_SEP, c->x86_capability); + + /* Names for the Pentium II/Celeron processors + detectable only by also checking the cache size. + Dixon is NOT a Celeron. */ + if (c->x86 == 6) { + switch (c->x86_model) { + case 5: + if (l2 == 0) + p = "Celeron (Covington)"; + if (l2 == 256) + p = "Mobile Pentium II (Dixon)"; + break; + + case 6: + if (l2 == 128) + p = "Celeron (Mendocino)"; + break; + + case 8: + if (l2 == 128) + p = "Celeron (Coppermine)"; + break; + } + } + + if ( p ) + strcpy(c->x86_model_id, p); + +#ifdef CONFIG_SMP + if (cpu_has(c, X86_FEATURE_HT)) { + extern int phys_proc_id[NR_CPUS]; + + u32 eax, ebx, ecx, edx; + int index_lsb, index_msb, tmp; + int initial_apic_id; + int cpu = smp_processor_id(); + + cpuid(1, &eax, &ebx, &ecx, &edx); + smp_num_siblings = (ebx & 0xff0000) >> 16; + + if (smp_num_siblings == 1) { + printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); + } else if (smp_num_siblings > 1 ) { + index_lsb = 0; + index_msb = 31; + /* + * At this point we only support two siblings per + * processor package. + */ +#define NR_SIBLINGS 2 + if (smp_num_siblings != NR_SIBLINGS) { + printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings); + smp_num_siblings = 1; + goto too_many_siblings; + } + tmp = smp_num_siblings; + while ((tmp & 1) == 0) { + tmp >>=1 ; + index_lsb++; + } + tmp = smp_num_siblings; + while ((tmp & 0x80000000 ) == 0) { + tmp <<=1 ; + index_msb--; + } + if (index_lsb != index_msb ) + index_msb++; + initial_apic_id = ebx >> 24 & 0xff; + phys_proc_id[cpu] = initial_apic_id >> index_msb; + + printk(KERN_INFO "CPU: Physical Processor ID: %d\n", + phys_proc_id[cpu]); + } + + } +too_many_siblings: + + if (disable_P4_HT) + clear_bit(X86_FEATURE_HT, &c->x86_capability); +#endif + + /* Disable the PN if appropriate */ + squash_the_stupid_serial_number(c); + + /* Work around errata */ + Intel_errata_workarounds(c); +} + + +static unsigned int intel_size_cache(struct cpuinfo_x86 * c, unsigned int size) +{ + /* Intel PIII Tualatin. This comes in two flavours. + * One has 256kb of cache, the other 512. We have no way + * to determine which, so we use a boottime override + * for the 512kb model, and assume 256 otherwise. + */ + if ((c->x86 == 6) && (c->x86_model == 11) && (size == 0)) + size = 256; + return size; +} + +static struct cpu_dev intel_cpu_dev __initdata = { + c_vendor: "Intel", + c_ident: { "GenuineIntel" }, + c_models: { + { X86_VENDOR_INTEL, 4, + { + [0] "486 DX-25/33", + [1] "486 DX-50", + [2] "486 SX", + [3] "486 DX/2", + [4] "486 SL", + [5] "486 SX/2", + [7] "486 DX/2-WB", + [8] "486 DX/4", + [9] "486 DX/4-WB" + } + }, + { X86_VENDOR_INTEL, 5, + { + [0] "Pentium 60/66 A-step", + [1] "Pentium 60/66", + [2] "Pentium 75 - 200", + [3] "OverDrive PODP5V83", + [4] "Pentium MMX", + [7] "Mobile Pentium 75 - 200", + [8] "Mobile Pentium MMX" + } + }, + }, + c_init: init_intel, + c_identify: generic_identify, + c_size_cache: intel_size_cache, +}; + +__init int intel_cpu_init(void) +{ + cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev; + return 0; +} + +// arch_initcall(intel_cpu_init); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/nexgen.c linux-2.5/arch/i386/kernel/cpu/nexgen.c --- linux-2.5.20/arch/i386/kernel/cpu/nexgen.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/nexgen.c Wed May 8 15:11:31 2002 @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +#include "cpu.h" + +/* + * Detect a NexGen CPU running without BIOS hypercode new enough + * to have CPUID. (Thanks to Herbert Oppmann) + */ + +static int __init deep_magic_nexgen_probe(void) +{ + int ret; + + __asm__ __volatile__ ( + " movw $0x5555, %%ax\n" + " xorw %%dx,%%dx\n" + " movw $2, %%cx\n" + " divw %%cx\n" + " movl $0, %%eax\n" + " jnz 1f\n" + " movl $1, %%eax\n" + "1:\n" + : "=a" (ret) : : "cx", "dx" ); + return ret; +} + +static void __init init_nexgen(struct cpuinfo_x86 * c) +{ + c->x86_cache_size = 256; /* A few had 1 MB... */ +} + +static void nexgen_identify(struct cpuinfo_x86 * c) +{ + /* Detect NexGen with old hypercode */ + if ( deep_magic_nexgen_probe() ) { + strcpy(c->x86_vendor_id, "NexGenDriven"); + } + generic_identify(c); +} + +static struct cpu_dev nexgen_cpu_dev __initdata = { + c_vendor: "Nexgen", + c_ident: { "NexGenDriven" }, + c_models: { + { X86_VENDOR_NEXGEN,5, { [1] "Nx586" } }, + }, + c_init: init_nexgen, + c_identify: nexgen_identify, +}; + +int __init nexgen_init_cpu(void) +{ + cpu_devs[X86_VENDOR_NEXGEN] = &nexgen_cpu_dev; + return 0; +} + +//early_arch_initcall(nexgen_init_cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/proc.c linux-2.5/arch/i386/kernel/cpu/proc.c --- linux-2.5.20/arch/i386/kernel/cpu/proc.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/proc.c Sat May 25 18:25:00 2002 @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include + +/* + * Get CPU information for use by the procfs. + */ +static int show_cpuinfo(struct seq_file *m, void *v) +{ + /* + * These flag bits must match the definitions in . + * NULL means this bit is undefined or reserved; either way it doesn't + * have meaning as far as Linux is concerned. Note that it's important + * to realize there is a difference between this table and CPUID -- if + * applications want to get the raw CPUID data, they should access + * /dev/cpu//cpuid instead. + */ + static char *x86_cap_flags[] = { + /* Intel-defined */ + "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", + "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", + "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", + "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL, + + /* AMD-defined */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, "mp", NULL, NULL, "mmxext", NULL, + NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow", + + /* Transmeta-defined */ + "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* Other (Linux-defined) */ + "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }; + struct cpuinfo_x86 *c = v; + int i, n = c - cpu_data; + int fpu_exception; + +#ifdef CONFIG_SMP + if (!(cpu_online_map & (1<x86_vendor_id[0] ? c->x86_vendor_id : "unknown", + c->x86, + c->x86_model, + c->x86_model_id[0] ? c->x86_model_id : "unknown"); + + if (c->x86_mask || c->cpuid_level >= 0) + seq_printf(m, "stepping\t: %d\n", c->x86_mask); + else + seq_printf(m, "stepping\t: unknown\n"); + + if ( cpu_has(c, X86_FEATURE_TSC) ) { + seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n", + cpu_khz / 1000, (cpu_khz % 1000)); + } + + /* Cache size */ + if (c->x86_cache_size >= 0) + seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); + + /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ + fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu); + seq_printf(m, "fdiv_bug\t: %s\n" + "hlt_bug\t\t: %s\n" + "f00f_bug\t: %s\n" + "coma_bug\t: %s\n" + "fpu\t\t: %s\n" + "fpu_exception\t: %s\n" + "cpuid level\t: %d\n" + "wp\t\t: %s\n" + "flags\t\t:", + c->fdiv_bug ? "yes" : "no", + c->hlt_works_ok ? "no" : "yes", + c->f00f_bug ? "yes" : "no", + c->coma_bug ? "yes" : "no", + c->hard_math ? "yes" : "no", + fpu_exception ? "yes" : "no", + c->cpuid_level, + c->wp_works_ok ? "yes" : "no"); + + for ( i = 0 ; i < 32*NCAPINTS ; i++ ) + if ( test_bit(i, &c->x86_capability) && + x86_cap_flags[i] != NULL ) + seq_printf(m, " %s", x86_cap_flags[i]); + + seq_printf(m, "\nbogomips\t: %lu.%02lu\n\n", + c->loops_per_jiffy/(500000/HZ), + (c->loops_per_jiffy/(5000/HZ)) % 100); + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < NR_CPUS ? cpu_data + *pos : NULL; +} +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} +static void c_stop(struct seq_file *m, void *v) +{ +} +struct seq_operations cpuinfo_op = { + start: c_start, + next: c_next, + stop: c_stop, + show: show_cpuinfo, +}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/rise.c linux-2.5/arch/i386/kernel/cpu/rise.c --- linux-2.5.20/arch/i386/kernel/cpu/rise.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/rise.c Wed May 8 15:11:31 2002 @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +#include "cpu.h" + +static void __init init_rise(struct cpuinfo_x86 *c) +{ + printk("CPU: Rise iDragon"); + if (c->x86_model > 2) + printk(" II"); + printk("\n"); + + /* Unhide possibly hidden capability flags + The mp6 iDragon family don't have MSRs. + We switch on extra features with this cpuid weirdness: */ + __asm__ ( + "movl $0x6363452a, %%eax\n\t" + "movl $0x3231206c, %%ecx\n\t" + "movl $0x2a32313a, %%edx\n\t" + "cpuid\n\t" + "movl $0x63634523, %%eax\n\t" + "movl $0x32315f6c, %%ecx\n\t" + "movl $0x2333313a, %%edx\n\t" + "cpuid\n\t" : : : "eax", "ebx", "ecx", "edx" + ); + set_bit(X86_FEATURE_CX8, c->x86_capability); +} + +static struct cpu_dev rise_cpu_dev __initdata = { + c_vendor: "Rise", + c_ident: { "RiseRiseRise" }, + c_models: { + { X86_VENDOR_RISE, 5, + { + [0] "iDragon", + [2] "iDragon", + [8] "iDragon II", + [9] "iDragon II" + } + }, + }, + c_init: init_rise, +}; + +int __init rise_init_cpu(void) +{ + cpu_devs[X86_VENDOR_RISE] = &rise_cpu_dev; + return 0; +} + +//early_arch_initcall(rise_init_cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/transmeta.c linux-2.5/arch/i386/kernel/cpu/transmeta.c --- linux-2.5.20/arch/i386/kernel/cpu/transmeta.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/transmeta.c Wed May 8 15:11:31 2002 @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include "cpu.h" + +static void __init init_transmeta(struct cpuinfo_x86 *c) +{ + unsigned int cap_mask, uk, max, dummy; + unsigned int cms_rev1, cms_rev2; + unsigned int cpu_rev, cpu_freq, cpu_flags; + char cpu_info[65]; + + get_model_name(c); /* Same as AMD/Cyrix */ + display_cacheinfo(c); + + /* Print CMS and CPU revision */ + max = cpuid_eax(0x80860000); + if ( max >= 0x80860001 ) { + cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags); + printk(KERN_INFO "CPU: Processor revision %u.%u.%u.%u, %u MHz\n", + (cpu_rev >> 24) & 0xff, + (cpu_rev >> 16) & 0xff, + (cpu_rev >> 8) & 0xff, + cpu_rev & 0xff, + cpu_freq); + } + if ( max >= 0x80860002 ) { + cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy); + printk(KERN_INFO "CPU: Code Morphing Software revision %u.%u.%u-%u-%u\n", + (cms_rev1 >> 24) & 0xff, + (cms_rev1 >> 16) & 0xff, + (cms_rev1 >> 8) & 0xff, + cms_rev1 & 0xff, + cms_rev2); + } + if ( max >= 0x80860006 ) { + cpuid(0x80860003, + (void *)&cpu_info[0], + (void *)&cpu_info[4], + (void *)&cpu_info[8], + (void *)&cpu_info[12]); + cpuid(0x80860004, + (void *)&cpu_info[16], + (void *)&cpu_info[20], + (void *)&cpu_info[24], + (void *)&cpu_info[28]); + cpuid(0x80860005, + (void *)&cpu_info[32], + (void *)&cpu_info[36], + (void *)&cpu_info[40], + (void *)&cpu_info[44]); + cpuid(0x80860006, + (void *)&cpu_info[48], + (void *)&cpu_info[52], + (void *)&cpu_info[56], + (void *)&cpu_info[60]); + cpu_info[64] = '\0'; + printk(KERN_INFO "CPU: %s\n", cpu_info); + } + + /* Unhide possibly hidden capability flags */ + rdmsr(0x80860004, cap_mask, uk); + wrmsr(0x80860004, ~0, uk); + c->x86_capability[0] = cpuid_edx(0x00000001); + wrmsr(0x80860004, cap_mask, uk); +} + +static void transmeta_identify(struct cpuinfo_x86 * c) +{ + u32 xlvl; + generic_identify(c); + + /* Transmeta-defined flags: level 0x80860001 */ + xlvl = cpuid_eax(0x80860000); + if ( (xlvl & 0xffff0000) == 0x80860000 ) { + if ( xlvl >= 0x80860001 ) + c->x86_capability[2] = cpuid_edx(0x80860001); + } +} + +static struct cpu_dev transmeta_cpu_dev __initdata = { + c_vendor: "Transmeta", + c_ident: { "GenuineTMx86", "TransmetaCPU" }, + c_init: init_transmeta, + c_identify: transmeta_identify, +}; + +int __init transmeta_init_cpu(void) +{ + cpu_devs[X86_VENDOR_TRANSMETA] = &transmeta_cpu_dev; + return 0; +} + +//early_arch_initcall(transmeta_init_cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/cpu/umc.c linux-2.5/arch/i386/kernel/cpu/umc.c --- linux-2.5.20/arch/i386/kernel/cpu/umc.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/cpu/umc.c Wed May 8 15:11:31 2002 @@ -0,0 +1,33 @@ +#include +#include +#include +#include "cpu.h" + +/* UMC chips appear to be only either 386 or 486, so no special init takes place. + */ +static void __init init_umc(struct cpuinfo_x86 * c) +{ + +} + +static struct cpu_dev umc_cpu_dev __initdata = { + c_vendor: "UMC", + c_ident: { "UMC UMC UMC" }, + c_models: { + { X86_VENDOR_UMC, 4, + { + [1] "U5D", + [2] "U5S", + } + }, + }, + c_init: init_umc, +}; + +int __init umc_init_cpu(void) +{ + cpu_devs[X86_VENDOR_UMC] = &umc_cpu_dev; + return 0; +} + +//early_arch_initcall(umc_init_cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/dmi_scan.c linux-2.5/arch/i386/kernel/dmi_scan.c --- linux-2.5.20/arch/i386/kernel/dmi_scan.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/arch/i386/kernel/dmi_scan.c Wed May 8 14:47:54 2002 @@ -296,6 +296,62 @@ } /* + * Some machines, usually laptops, can't handle an enabled local APIC. + * The symptoms include hangs or reboots when suspending or resuming, + * attaching or detaching the power cord, or entering BIOS setup screens + * through magic key sequences. + */ +static int __init local_apic_kills_bios(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_enable_local_apic; + if (!dont_enable_local_apic) { + dont_enable_local_apic = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "Refusing to enable the local APIC.\n", + d->ident); + } +#endif + return 0; +} + +/* + * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after + * resumes, and also at what appears to be asynchronous APM events, + * if the local APIC is enabled. + */ +static int __init apm_kills_local_apic(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_enable_local_apic; + if (apm_info.bios.version && !dont_enable_local_apic) { + dont_enable_local_apic = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "Refusing to enable the local APIC.\n", + d->ident); + } +#endif + return 0; +} + +/* + * The Intel AL440LX mainboard will hang randomly if the local APIC + * timer is running and the APM BIOS hasn't been disabled. + */ +static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_use_local_apic_timer; + if (apm_info.bios.version && !dont_use_local_apic_timer) { + dont_use_local_apic_timer = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "The local APIC timer will not be used.\n", + d->ident); + } +#endif + return 0; +} +/* * Work around broken HP Pavilion Notebooks which assign USB to * IRQ 9 even though it is actually wired to IRQ 11 */ @@ -372,6 +428,7 @@ * The MP1.4 table is right however and so SMP kernels tend to work. */ +extern int skip_ioapic_setup; static __init int broken_pirq(struct dmi_blacklist *d) { printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n"); @@ -379,6 +436,9 @@ printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n"); printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n"); printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n"); +#ifdef CONFIG_X86_IO_APIC + skip_ioapic_setup = 0; +#endif return 0; } @@ -433,62 +493,6 @@ return 0; } -/* - * Some machines, usually laptops, can't handle an enabled local APIC. - * The symptoms include hangs or reboots when suspending or resuming, - * attaching or detaching the power cord, or entering BIOS setup screens - * through magic key sequences. - */ -static int __init local_apic_kills_bios(struct dmi_blacklist *d) -{ -#ifdef CONFIG_X86_LOCAL_APIC - extern int dont_enable_local_apic; - if (!dont_enable_local_apic) { - dont_enable_local_apic = 1; - printk(KERN_WARNING "%s with broken BIOS detected. " - "Refusing to enable the local APIC.\n", - d->ident); - } -#endif - return 0; -} - -/* - * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after - * resumes, and also at what appears to be asynchronous APM events, - * if the local APIC is enabled. - */ -static int __init apm_kills_local_apic(struct dmi_blacklist *d) -{ -#ifdef CONFIG_X86_LOCAL_APIC - extern int dont_enable_local_apic; - if (apm_info.bios.version && !dont_enable_local_apic) { - dont_enable_local_apic = 1; - printk(KERN_WARNING "%s with broken BIOS detected. " - "Refusing to enable the local APIC.\n", - d->ident); - } -#endif - return 0; -} - -/* - * The Intel AL440LX mainboard will hang randomly if the local APIC - * timer is running and the APM BIOS hasn't been disabled. - */ -static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d) -{ -#ifdef CONFIG_X86_LOCAL_APIC - extern int dont_use_local_apic_timer; - if (apm_info.bios.version && !dont_use_local_apic_timer) { - dont_use_local_apic_timer = 1; - printk(KERN_WARNING "%s with broken BIOS detected. " - "The local APIC timer will not be used.\n", - d->ident); - } -#endif - return 0; -} /* * Simple "print if true" callback diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/eisa.c linux-2.5/arch/i386/kernel/eisa.c --- linux-2.5.20/arch/i386/kernel/eisa.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/arch/i386/kernel/eisa.c Wed Feb 20 23:18:38 2002 @@ -0,0 +1,55 @@ +/* + * linux/arch/i386/kernel/eisa.c + * + * Copyright (C) 2002 Dave Jones + * + */ + +#include +#include +#include + +struct device *eisa_iobus; + +void __init init_eisa(void) +{ + struct device *eisa_dev; + int eisa_addr=0; + int id, id2; + + return; /* this is currently broken, I'll fix it later.*/ + + if (EISA_bus==0) + return; + + eisa_iobus = kmalloc(sizeof(*(eisa_iobus)),GFP_KERNEL); + memset (eisa_iobus, 0, sizeof(*(eisa_iobus))); + sprintf (eisa_iobus->bus_id, "eisa"); + sprintf (eisa_iobus->name, "EISA bus"); + device_register(eisa_iobus); + + while (eisa_addr < 0x9000) { + + id = inw(eisa_addr+0xC80); + if (id!=0xffff) { + id2 = inw(eisa_addr+0xC81); + + eisa_dev = kmalloc (sizeof (struct device), GFP_KERNEL); + if (eisa_dev == NULL) + return; + + memset (eisa_dev, 0, sizeof(struct device)); + + /* FIXME: This should export *3* 5-bit numbers. Euch. */ + sprintf (eisa_dev->name, "EISA device %x%x", id, id2); + sprintf (eisa_dev->bus_id, "%d", eisa_addr/0x1000); + eisa_dev->parent = eisa_iobus; + device_register(eisa_dev); + } + + eisa_addr += 0x1000; + } +} + +subsys_initcall(init_eisa); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/head.S linux-2.5/arch/i386/kernel/head.S --- linux-2.5.20/arch/i386/kernel/head.S Mon Jun 3 02:44:41 2002 +++ linux-2.5/arch/i386/kernel/head.S Sun May 26 01:42:04 2002 @@ -82,7 +82,7 @@ * Initialize page tables */ movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */ - movl $007,%eax /* "007" doesn't mean with right to kill, but + movl $007,%eax /* "007" doesn't mean with license to kill, but PRESENT+RW+USER */ 2: stosl add $0x1000,%eax diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/i386_ksyms.c linux-2.5/arch/i386/kernel/i386_ksyms.c --- linux-2.5.20/arch/i386/kernel/i386_ksyms.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/arch/i386/kernel/i386_ksyms.c Sat Jun 1 02:10:27 2002 @@ -33,7 +33,7 @@ extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; -#if defined(CONFIG_APM_MODULE) +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) extern void machine_real_restart(unsigned char *, int); EXPORT_SYMBOL(machine_real_restart); extern void default_idle(void); @@ -54,9 +54,7 @@ /* platform dependent support */ EXPORT_SYMBOL(boot_cpu_data); -#ifdef CONFIG_EISA EXPORT_SYMBOL(EISA_bus); -#endif EXPORT_SYMBOL(MCA_bus); EXPORT_SYMBOL(__verify_write); EXPORT_SYMBOL(dump_thread); @@ -74,6 +72,7 @@ EXPORT_SYMBOL(get_cmos_time); EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); +EXPORT_SYMBOL(empty_zero_page); #ifdef CONFIG_DEBUG_IOVIRT EXPORT_SYMBOL(__io_virt_debug); @@ -126,7 +125,7 @@ #ifdef CONFIG_SMP EXPORT_SYMBOL(cpu_data); -EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(kernel_flag_cacheline); EXPORT_SYMBOL(smp_num_cpus); EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL_NOVERS(__write_lock_failed); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/io_apic.c linux-2.5/arch/i386/kernel/io_apic.c --- linux-2.5.20/arch/i386/kernel/io_apic.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/arch/i386/kernel/io_apic.c Mon Jun 3 17:10:19 2002 @@ -274,15 +274,27 @@ #define MAX_PIRQS 8 int pirq_entries [MAX_PIRQS]; int pirqs_enabled; -int skip_ioapic_setup; +#ifdef CONFIG_X86_UP_APIC +int skip_ioapic_setup=1; +#else +int skip_ioapic_setup=0; +#endif -static int __init ioapic_setup(char *str) +static int __init noioapic_setup(char *str) { skip_ioapic_setup = 1; return 1; } -__setup("noapic", ioapic_setup); +__setup("noapic", noioapic_setup); + +static int __init ioapic_setup(char *str) +{ + skip_ioapic_setup = 0; + return 1; +} + +__setup("apic", ioapic_setup); static int __init ioapic_pirq_setup(char *str) { @@ -724,7 +736,14 @@ } irq = pin_2_irq(idx, apic, pin); - add_pin_to_irq(irq, apic, pin); + /* + * skip adding the timer int on secondary nodes, which causes + * a small but painful rift in the time-space continuum + */ + if (clustered_apic_mode && (apic != 0) && (irq == 0)) + continue; + else + add_pin_to_irq(irq, apic, pin); if (!apic && !IO_APIC_IRQ(irq)) continue; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/irq.c linux-2.5/arch/i386/kernel/irq.c --- linux-2.5.20/arch/i386/kernel/irq.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/arch/i386/kernel/irq.c Sun May 26 01:40:46 2002 @@ -168,7 +168,8 @@ #if CONFIG_X86_LOCAL_APIC seq_printf(p, "LOC: "); for (j = 0; j < smp_num_cpus; j++) - seq_printf(p, "%10u ", apic_timer_irqs[cpu_logical_map(j)]); + seq_printf(p, "%10u ", + irq_stat[cpu_logical_map(j)].apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/nmi.c linux-2.5/arch/i386/kernel/nmi.c --- linux-2.5.20/arch/i386/kernel/nmi.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/arch/i386/kernel/nmi.c Sun May 26 01:40:46 2002 @@ -344,7 +344,7 @@ */ int sum, cpu = smp_processor_id(); - sum = apic_timer_irqs[cpu]; + sum = irq_stat[cpu].apic_timer_irqs; if (last_irq_sums[cpu] == sum) { /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/process.c linux-2.5/arch/i386/kernel/process.c --- linux-2.5.20/arch/i386/kernel/process.c Mon Jun 3 02:44:37 2002 +++ linux-2.5/arch/i386/kernel/process.c Tue May 21 22:20:44 2002 @@ -42,6 +42,7 @@ #include #include #include +#include #include #ifdef CONFIG_MATH_EMULATION #include @@ -55,14 +56,6 @@ int hlt_counter; /* - * Return saved PC of a blocked thread. - */ -unsigned long thread_saved_pc(struct task_struct *tsk) -{ - return ((unsigned long *)tsk->thread.esp)[3]; -} - -/* * Powermanagement idle function, if any.. */ void (*pm_idle)(void); @@ -263,7 +256,7 @@ 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ 0x74, 0x02, /* jz f */ - 0x0f, 0x08, /* invd */ + 0x0f, 0x09, /* wbinvd */ 0x24, 0x10, /* f: andb $0x10,al */ 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ }; @@ -536,6 +529,8 @@ BUG(); } } + + release_x86_irqs(dead_task); } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/semaphore.c linux-2.5/arch/i386/kernel/semaphore.c --- linux-2.5.20/arch/i386/kernel/semaphore.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/arch/i386/kernel/semaphore.c Sat Apr 13 17:42:54 2002 @@ -183,6 +183,10 @@ ".align 4\n" ".globl __down_failed\n" "__down_failed:\n\t" +#if defined(CONFIG_FRAME_POINTER) + "pushl %ebp\n\t" + "movl %esp,%ebp\n\t" +#endif "pushl %eax\n\t" "pushl %edx\n\t" "pushl %ecx\n\t" @@ -190,6 +194,10 @@ "popl %ecx\n\t" "popl %edx\n\t" "popl %eax\n\t" +#if defined(CONFIG_FRAME_POINTER) + "movl %ebp,%esp\n\t" + "popl %ebp\n\t" +#endif "ret" ); @@ -198,11 +206,19 @@ ".align 4\n" ".globl __down_failed_interruptible\n" "__down_failed_interruptible:\n\t" +#if defined(CONFIG_FRAME_POINTER) + "pushl %ebp\n\t" + "movl %esp,%ebp\n\t" +#endif "pushl %edx\n\t" "pushl %ecx\n\t" "call __down_interruptible\n\t" "popl %ecx\n\t" "popl %edx\n\t" +#if defined(CONFIG_FRAME_POINTER) + "movl %ebp,%esp\n\t" + "popl %ebp\n\t" +#endif "ret" ); @@ -211,11 +227,19 @@ ".align 4\n" ".globl __down_failed_trylock\n" "__down_failed_trylock:\n\t" +#if defined(CONFIG_FRAME_POINTER) + "pushl %ebp\n\t" + "movl %esp,%ebp\n\t" +#endif "pushl %edx\n\t" "pushl %ecx\n\t" "call __down_trylock\n\t" "popl %ecx\n\t" "popl %edx\n\t" +#if defined(CONFIG_FRAME_POINTER) + "movl %ebp,%esp\n\t" + "popl %ebp\n\t" +#endif "ret" ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/setup.c linux-2.5/arch/i386/kernel/setup.c --- linux-2.5.20/arch/i386/kernel/setup.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/arch/i386/kernel/setup.c Mon Jun 3 17:10:19 2002 @@ -3,73 +3,16 @@ * * Copyright (C) 1995 Linus Torvalds * - * Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean - * and Martin Mares, November 1997. - * - * Force Cyrix 6x86(MX) and M II processors to report MTRR capability - * and Cyrix "coma bug" recognition by - * Zoltán Böszörményi February 1999. - * - * Force Centaur C6 processors to report MTRR capability. - * Bart Hartgers , May 1999. - * - * Intel Mobile Pentium II detection fix. Sean Gilley, June 1999. - * - * IDT Winchip tweaks, misc clean ups. - * Dave Jones , August 1999 - * * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 * - * Better detection of Centaur/IDT WinChip models. - * Bart Hartgers , August 1999. - * * Memory region support * David Parsons , July-August 1999 * - * Cleaned up cache-detection code - * Dave Jones , October 1999 - * - * Added proper L2 cache detection for Coppermine - * Dragan Stancevic , October 1999 - * - * Added the original array for capability flags but forgot to credit - * myself :) (~1998) Fixed/cleaned up some cpu_model_info and other stuff - * Jauder Ho , January 2000 - * - * Detection for Celeron coppermine, identify_cpu() overhauled, - * and a few other clean ups. - * Dave Jones , April 2000 - * - * Pentium III FXSR, SSE support - * General FPU state handling cleanups - * Gareth Hughes , May 2000 - * - * Added proper Cascades CPU and L2 cache detection for Cascades - * and 8-way type cache happy bunch from Intel:^) - * Dragan Stancevic , May 2000 - * - * Forward port AMD Duron errata T13 from 2.2.17pre - * Dave Jones , August 2000 - * - * Forward port lots of fixes/improvements from 2.2.18pre - * Cyrix III, Pentium IV support. - * Dave Jones , October 2000 - * - * Massive cleanup of CPU detection and bug handling; - * Transmeta CPU detection, - * H. Peter Anvin , November 2000 - * * Added E820 sanitization routine (removes overlapping memory regions); * Brian Moyle , February 2001 * - * VIA C3 Support. - * Dave Jones , March 2001 - * - * AMD Athlon/Duron/Thunderbird bluesmoke support. - * Dave Jones , April 2001. - * - * CacheSize bug workaround updates for AMD, Intel & VIA Cyrix. - * Dave Jones , September, October 2001. + * Moved CPU detection code to cpu/${cpu}.c + * Patrick Mochel , March 2002 * */ @@ -77,45 +20,21 @@ * This file handles the architecture-dependent parts of initialization */ -#include #include -#include #include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include #include #include #ifdef CONFIG_BLK_DEV_RAM #include #endif -#include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include #include -#include /* * Machine setup.. @@ -126,11 +45,7 @@ unsigned long mmu_cr4_features; -/* - * Bus types .. - */ int MCA_bus; - /* for MCA, but anyone else can use it if they want */ unsigned int machine_id; unsigned int machine_submodel_id; @@ -158,20 +73,15 @@ unsigned char aux_device_present; -extern void mcheck_init(struct cpuinfo_x86 *c); +extern void early_cpu_init(void); extern void dmi_scan_machine(void); extern int root_mountflags; extern char _text, _etext, _edata, _end; extern int blk_nohighio; void __init visws_get_board_type_and_rev(void); -static int disable_x86_serial_nr __initdata = 1; -static int disable_x86_fxsr __initdata = 0; - unsigned long saved_videomode; -extern unsigned long saved_videomode; - /* * This is set up by the setup-routine at boot-time */ @@ -297,6 +207,22 @@ } } +static void __init limit_regions (unsigned long long size) +{ + int i; + unsigned long long current_size = 0; + + for (i = 0; i < e820.nr_map; i++) { + if (e820.map[i].type == E820_RAM) { + current_size += e820.map[i].size; + if (current_size >= size) { + e820.map[i].size -= current_size-size; + e820.nr_map = i + 1; + return; + } + } + } +} static void __init add_memory_region(unsigned long long start, unsigned long long size, int type) { @@ -598,7 +524,7 @@ { char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; - int usermem = 0; + int userdef = 0; /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); @@ -621,32 +547,24 @@ } else if (!memcmp(from+4, "exactmap", 8)) { from += 8+4; e820.nr_map = 0; - usermem = 1; + userdef = 1; } else { /* If the user specifies memory size, we - * blow away any automatically generated - * size + * limit the BIOS-provided memory map to + * that size. exactmap can be used to specify + * the exact map. mem=number can be used to + * trim the existing memory map. */ unsigned long long start_at, mem_size; - if (usermem == 0) { - /* first time in: zap the whitelist - * and reinitialize it with the - * standard low-memory region. - */ - e820.nr_map = 0; - usermem = 1; - add_memory_region(0, LOWMEMSIZE(), E820_RAM); - } mem_size = memparse(from+4, &from); - if (*from == '@') + if (*from == '@') { start_at = memparse(from+1, &from); - else { - start_at = HIGH_MEMORY; - mem_size -= HIGH_MEMORY; - usermem=0; + add_memory_region(start_at, mem_size, E820_RAM); + } else { + limit_regions(mem_size); + userdef=1; } - add_memory_region(start_at, mem_size, E820_RAM); } } /* @@ -666,7 +584,7 @@ } *to = '\0'; *cmdline_p = command_line; - if (usermem) { + if (userdef) { printk(KERN_INFO "user-defined physical RAM map:\n"); print_memory_map("user"); } @@ -678,6 +596,8 @@ unsigned long start_pfn, max_low_pfn; int i; + early_cpu_init(); + #ifdef CONFIG_VISWS visws_get_board_type_and_rev(); #endif @@ -977,27 +897,6 @@ dmi_scan_machine(); } -static int cachesize_override __initdata = -1; -static int __init cachesize_setup(char *str) -{ - get_option (&str, &cachesize_override); - return 1; -} -__setup("cachesize=", cachesize_setup); - - -#ifndef CONFIG_X86_TSC -static int tsc_disable __initdata = 0; - -static int __init tsc_setup(char *str) -{ - tsc_disable = 1; - return 1; -} - -__setup("notsc", tsc_setup); -#endif - static int __init highio_setup(char *str) { printk("i386: disabling HIGHMEM block I/O\n"); @@ -1006,1938 +905,6 @@ } __setup("nohighio", highio_setup); -static int __init get_model_name(struct cpuinfo_x86 *c) -{ - unsigned int *v; - char *p, *q; - - if (cpuid_eax(0x80000000) < 0x80000004) - return 0; - - v = (unsigned int *) c->x86_model_id; - cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); - cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); - cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); - c->x86_model_id[48] = 0; - - /* Intel chips right-justify this string for some dumb reason; - undo that brain damage */ - p = q = &c->x86_model_id[0]; - while ( *p == ' ' ) - p++; - if ( p != q ) { - while ( *p ) - *q++ = *p++; - while ( q <= &c->x86_model_id[48] ) - *q++ = '\0'; /* Zero-pad the rest */ - } - - return 1; -} - - -static void __init display_cacheinfo(struct cpuinfo_x86 *c) -{ - unsigned int n, dummy, ecx, edx, l2size; - - n = cpuid_eax(0x80000000); - - if (n >= 0x80000005) { - cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); - printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n", - edx>>24, edx&0xFF, ecx>>24, ecx&0xFF); - c->x86_cache_size=(ecx>>24)+(edx>>24); - } - - if (n < 0x80000006) /* Some chips just has a large L1. */ - return; - - ecx = cpuid_ecx(0x80000006); - l2size = ecx >> 16; - - /* AMD errata T13 (order #21922) */ - if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) { - if (c->x86_model == 3 && c->x86_mask == 0) /* Duron Rev A0 */ - l2size = 64; - if (c->x86_model == 4 && - (c->x86_mask==0 || c->x86_mask==1)) /* Tbird rev A1/A2 */ - l2size = 256; - } - - /* Intel PIII Tualatin. This comes in two flavours. - * One has 256kb of cache, the other 512. We have no way - * to determine which, so we use a boottime override - * for the 512kb model, and assume 256 otherwise. - */ - if ((c->x86_vendor == X86_VENDOR_INTEL) && (c->x86 == 6) && - (c->x86_model == 11) && (l2size == 0)) - l2size = 256; - - /* VIA C3 CPUs (670-68F) need further shifting. */ - if (c->x86_vendor == X86_VENDOR_CENTAUR && (c->x86 == 6) && - ((c->x86_model == 7) || (c->x86_model == 8))) { - l2size = l2size >> 8; - } - - /* Allow user to override all this if necessary. */ - if (cachesize_override != -1) - l2size = cachesize_override; - - if ( l2size == 0 ) - return; /* Again, no L2 cache is possible */ - - c->x86_cache_size = l2size; - - printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n", - l2size, ecx & 0xFF); -} - -/* - * B step AMD K6 before B 9730xxxx have hardware bugs that can cause - * misexecution of code under Linux. Owners of such processors should - * contact AMD for precise details and a CPU swap. - * - * See http://www.multimania.com/poulot/k6bug.html - * http://www.amd.com/K6/k6docs/revgd.html - * - * The following test is erm.. interesting. AMD neglected to up - * the chip setting when fixing the bug but they also tweaked some - * performance at the same time.. - */ - -extern void vide(void); -__asm__(".align 4\nvide: ret"); - -static int __init init_amd(struct cpuinfo_x86 *c) -{ - u32 l, h; - int mbytes = max_mapnr >> (20-PAGE_SHIFT); - int r; - - /* - * FIXME: We should handle the K5 here. Set up the write - * range and also turn on MSR 83 bits 4 and 31 (write alloc, - * no bus pipeline) - */ - - /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; - 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ - clear_bit(0*32+31, c->x86_capability); - - r = get_model_name(c); - - switch(c->x86) - { - case 5: - if( c->x86_model < 6 ) - { - /* Based on AMD doc 20734R - June 2000 */ - if ( c->x86_model == 0 ) { - clear_bit(X86_FEATURE_APIC, c->x86_capability); - set_bit(X86_FEATURE_PGE, c->x86_capability); - } - break; - } - - if ( c->x86_model == 6 && c->x86_mask == 1 ) { - const int K6_BUG_LOOP = 1000000; - int n; - void (*f_vide)(void); - unsigned long d, d2; - - printk(KERN_INFO "AMD K6 stepping B detected - "); - - /* - * It looks like AMD fixed the 2.6.2 bug and improved indirect - * calls at the same time. - */ - - n = K6_BUG_LOOP; - f_vide = vide; - rdtscl(d); - while (n--) - f_vide(); - rdtscl(d2); - d = d2-d; - - /* Knock these two lines out if it debugs out ok */ - printk(KERN_INFO "K6 BUG %ld %d (Report these if test report is incorrect)\n", d, 20*K6_BUG_LOOP); - printk(KERN_INFO "AMD K6 stepping B detected - "); - /* -- cut here -- */ - if (d > 20*K6_BUG_LOOP) - printk("system stability may be impaired when more than 32 MB are used.\n"); - else - printk("probably OK (after B9730xxxx).\n"); - printk(KERN_INFO "Please see http://www.mygale.com/~poulot/k6bug.html\n"); - } - - /* K6 with old style WHCR */ - if (c->x86_model < 8 || - (c->x86_model== 8 && c->x86_mask < 8)) { - /* We can only write allocate on the low 508Mb */ - if(mbytes>508) - mbytes=508; - - rdmsr(MSR_K6_WHCR, l, h); - if ((l&0x0000FFFF)==0) { - unsigned long flags; - l=(1<<0)|((mbytes/4)<<1); - local_irq_save(flags); - wbinvd(); - wrmsr(MSR_K6_WHCR, l, h); - local_irq_restore(flags); - printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n", - mbytes); - } - break; - } - - if ((c->x86_model == 8 && c->x86_mask >7) || - c->x86_model == 9 || c->x86_model == 13) { - /* The more serious chips .. */ - - if(mbytes>4092) - mbytes=4092; - - rdmsr(MSR_K6_WHCR, l, h); - if ((l&0xFFFF0000)==0) { - unsigned long flags; - l=((mbytes>>2)<<22)|(1<<16); - local_irq_save(flags); - wbinvd(); - wrmsr(MSR_K6_WHCR, l, h); - local_irq_restore(flags); - printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n", - mbytes); - } - - /* Set MTRR capability flag if appropriate */ - if (c->x86_model == 13 || c->x86_model == 9 || - (c->x86_model == 8 && c->x86_mask >= 8)) - set_bit(X86_FEATURE_K6_MTRR, c->x86_capability); - break; - } - break; - - case 6: /* An Athlon/Duron */ - - /* Bit 15 of Athlon specific MSR 15, needs to be 0 - * to enable SSE on Palomino/Morgan CPU's. - * If the BIOS didn't enable it already, enable it - * here. - */ - if (c->x86_model == 6 || c->x86_model == 7) { - if (!cpu_has(c, X86_FEATURE_XMM)) { - printk(KERN_INFO "Enabling disabled K7/SSE Support.\n"); - rdmsr(MSR_K7_HWCR, l, h); - l &= ~0x00008000; - wrmsr(MSR_K7_HWCR, l, h); - set_bit(X86_FEATURE_XMM, c->x86_capability); - } - } - break; - - } - - display_cacheinfo(c); - return r; -} - -/* - * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU - */ -static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) -{ - unsigned char ccr2, ccr3; - unsigned long flags; - - /* we test for DEVID by checking whether CCR3 is writable */ - local_irq_save(flags); - ccr3 = getCx86(CX86_CCR3); - setCx86(CX86_CCR3, ccr3 ^ 0x80); - getCx86(0xc0); /* dummy to change bus */ - - if (getCx86(CX86_CCR3) == ccr3) { /* no DEVID regs. */ - ccr2 = getCx86(CX86_CCR2); - setCx86(CX86_CCR2, ccr2 ^ 0x04); - getCx86(0xc0); /* dummy */ - - if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */ - *dir0 = 0xfd; - else { /* Cx486S A step */ - setCx86(CX86_CCR2, ccr2); - *dir0 = 0xfe; - } - } - else { - setCx86(CX86_CCR3, ccr3); /* restore CCR3 */ - - /* read DIR0 and DIR1 CPU registers */ - *dir0 = getCx86(CX86_DIR0); - *dir1 = getCx86(CX86_DIR1); - } - local_irq_restore(flags); -} - -/* - * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in - * order to identify the Cyrix CPU model after we're out of setup.c - * - * Actually since bugs.h doesnt even reference this perhaps someone should - * fix the documentation ??? - */ -static unsigned char Cx86_dir0_msb __initdata = 0; - -static char Cx86_model[][9] __initdata = { - "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ", - "M II ", "Unknown" -}; -static char Cx486_name[][5] __initdata = { - "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx", - "SRx2", "DRx2" -}; -static char Cx486S_name[][4] __initdata = { - "S", "S2", "Se", "S2e" -}; -static char Cx486D_name[][4] __initdata = { - "DX", "DX2", "?", "?", "?", "DX4" -}; -static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock"; -static char cyrix_model_mult1[] __initdata = "12??43"; -static char cyrix_model_mult2[] __initdata = "12233445"; - -/* - * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old - * BIOSes for compatability with DOS games. This makes the udelay loop - * work correctly, and improves performance. - * - * FIXME: our newer udelay uses the tsc. We dont need to frob with SLOP - */ - -extern void calibrate_delay(void) __init; - -static void __init check_cx686_slop(struct cpuinfo_x86 *c) -{ - unsigned long flags; - - if (Cx86_dir0_msb == 3) { - unsigned char ccr3, ccr5; - - local_irq_save(flags); - ccr3 = getCx86(CX86_CCR3); - setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ - ccr5 = getCx86(CX86_CCR5); - if (ccr5 & 2) - setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */ - setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ - local_irq_restore(flags); - - if (ccr5 & 2) { /* possible wrong calibration done */ - printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n"); - calibrate_delay(); - c->loops_per_jiffy = loops_per_jiffy; - } - } -} - - -static void __init init_cyrix(struct cpuinfo_x86 *c) -{ - unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; - char *buf = c->x86_model_id; - const char *p = NULL; - - /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; - 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ - clear_bit(0*32+31, c->x86_capability); - - /* Cyrix used bit 24 in extended (AMD) CPUID for Cyrix MMX extensions */ - if ( test_bit(1*32+24, c->x86_capability) ) { - clear_bit(1*32+24, c->x86_capability); - set_bit(X86_FEATURE_CXMMX, c->x86_capability); - } - - do_cyrix_devid(&dir0, &dir1); - - check_cx686_slop(c); - - Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family" */ - dir0_lsn = dir0 & 0xf; /* model or clock multiplier */ - - /* common case step number/rev -- exceptions handled below */ - c->x86_model = (dir1 >> 4) + 1; - c->x86_mask = dir1 & 0xf; - - /* Now cook; the original recipe is by Channing Corn, from Cyrix. - * We do the same thing for each generation: we work out - * the model, multiplier and stepping. Black magic included, - * to make the silicon step/rev numbers match the printed ones. - */ - - switch (dir0_msn) { - unsigned char tmp; - - case 0: /* Cx486SLC/DLC/SRx/DRx */ - p = Cx486_name[dir0_lsn & 7]; - break; - - case 1: /* Cx486S/DX/DX2/DX4 */ - p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5] - : Cx486S_name[dir0_lsn & 3]; - break; - - case 2: /* 5x86 */ - Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5]; - p = Cx86_cb+2; - break; - - case 3: /* 6x86/6x86L */ - Cx86_cb[1] = ' '; - Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5]; - if (dir1 > 0x21) { /* 686L */ - Cx86_cb[0] = 'L'; - p = Cx86_cb; - (c->x86_model)++; - } else /* 686 */ - p = Cx86_cb+1; - /* Emulate MTRRs using Cyrix's ARRs. */ - set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability); - /* 6x86's contain this bug */ - c->coma_bug = 1; - break; - - case 4: /* MediaGX/GXm */ -#ifdef CONFIG_PCI - /* It isn't really a PCI quirk directly, but the cure is the - same. The MediaGX has deep magic SMM stuff that handles the - SB emulation. It thows away the fifo on disable_dma() which - is wrong and ruins the audio. - - Bug2: VSA1 has a wrap bug so that using maximum sized DMA - causes bad things. According to NatSemi VSA2 has another - bug to do with 'hlt'. I've not seen any boards using VSA2 - and X doesn't seem to support it either so who cares 8). - VSA1 we work around however. - */ - - printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bugs.\n"); - isa_dma_bridge_buggy = 2; -#endif - c->x86_cache_size=16; /* Yep 16K integrated cache thats it */ - - /* GXm supports extended cpuid levels 'ala' AMD */ - if (c->cpuid_level == 2) { - /* Enable Natsemi MMX extensions */ - setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1); - - get_model_name(c); /* get CPU marketing name */ - /* - * The 5510/5520 companion chips have a funky PIT - * that breaks the TSC synchronizing, so turn it off - */ - if(pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) || - pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL)) - clear_bit(X86_FEATURE_TSC, c->x86_capability); - return; - } - else { /* MediaGX */ - Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4'; - p = Cx86_cb+2; - c->x86_model = (dir1 & 0x20) ? 1 : 2; -#ifndef CONFIG_CS5520 - clear_bit(X86_FEATURE_TSC, c->x86_capability); -#endif - } - break; - - case 5: /* 6x86MX/M II */ - if (dir1 > 7) - { - dir0_msn++; /* M II */ - /* Enable MMX extensions (App note 108) */ - setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1); - } - else - { - c->coma_bug = 1; /* 6x86MX, it has the bug. */ - } - tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0; - Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7]; - p = Cx86_cb+tmp; - if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20)) - (c->x86_model)++; - /* Emulate MTRRs using Cyrix's ARRs. */ - set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability); - break; - - case 0xf: /* Cyrix 486 without DEVID registers */ - switch (dir0_lsn) { - case 0xd: /* either a 486SLC or DLC w/o DEVID */ - dir0_msn = 0; - p = Cx486_name[(c->hard_math) ? 1 : 0]; - break; - - case 0xe: /* a 486S A step */ - dir0_msn = 0; - p = Cx486S_name[0]; - break; - } - break; - - default: /* unknown (shouldn't happen, we know everyone ;-) */ - dir0_msn = 7; - break; - } - strcpy(buf, Cx86_model[dir0_msn & 7]); - if (p) strcat(buf, p); - return; -} - -#ifdef CONFIG_X86_OOSTORE - -static u32 __init power2(u32 x) -{ - u32 s=1; - while(s<=x) - s<<=1; - return s>>=1; -} - -/* - * Set up an actual MCR - */ - -static void __init winchip_mcr_insert(int reg, u32 base, u32 size, int key) -{ - u32 lo, hi; - - hi = base & ~0xFFF; - lo = ~(size-1); /* Size is a power of 2 so this makes a mask */ - lo &= ~0xFFF; /* Remove the ctrl value bits */ - lo |= key; /* Attribute we wish to set */ - wrmsr(reg+MSR_IDT_MCR0, lo, hi); - mtrr_centaur_report_mcr(reg, lo, hi); /* Tell the mtrr driver */ -} - -/* - * Figure what we can cover with MCR's - * - * Shortcut: We know you can't put 4Gig of RAM on a winchip - */ - -static u32 __init ramtop(void) /* 16388 */ -{ - int i; - u32 top = 0; - u32 clip = 0xFFFFFFFFUL; - - for (i = 0; i < e820.nr_map; i++) { - unsigned long start, end; - - if (e820.map[i].addr > 0xFFFFFFFFUL) - continue; - /* - * Don't MCR over reserved space. Ignore the ISA hole - * we frob around that catastrophy already - */ - - if (e820.map[i].type == E820_RESERVED) - { - if(e820.map[i].addr >= 0x100000UL && e820.map[i].addr < clip) - clip = e820.map[i].addr; - continue; - } - start = e820.map[i].addr; - end = e820.map[i].addr + e820.map[i].size; - if (start >= end) - continue; - if (end > top) - top = end; - } - /* Everything below 'top' should be RAM except for the ISA hole. - Because of the limited MCR's we want to map NV/ACPI into our - MCR range for gunk in RAM - - Clip might cause us to MCR insufficient RAM but that is an - acceptable failure mode and should only bite obscure boxes with - a VESA hole at 15Mb - - The second case Clip sometimes kicks in is when the EBDA is marked - as reserved. Again we fail safe with reasonable results - */ - - if(top>clip) - top=clip; - - return top; -} - -/* - * Compute a set of MCR's to give maximum coverage - */ - -static int __init winchip_mcr_compute(int nr, int key) -{ - u32 mem = ramtop(); - u32 root = power2(mem); - u32 base = root; - u32 top = root; - u32 floor = 0; - int ct = 0; - - while(ct high && fspace > low) - { - winchip_mcr_insert(ct, floor, fspace, key); - floor += fspace; - } - else if(high > low) - { - winchip_mcr_insert(ct, top, high, key); - top += high; - } - else if(low > 0) - { - base -= low; - winchip_mcr_insert(ct, base, low, key); - } - else break; - ct++; - } - /* - * We loaded ct values. We now need to set the mask. The caller - * must do this bit. - */ - - return ct; -} - -static void __init winchip_create_optimal_mcr(void) -{ - int i; - /* - * Allocate up to 6 mcrs to mark as much of ram as possible - * as write combining and weak write ordered. - * - * To experiment with: Linux never uses stack operations for - * mmio spaces so we could globally enable stack operation wc - * - * Load the registers with type 31 - full write combining, all - * writes weakly ordered. - */ - int used = winchip_mcr_compute(6, 31); - - /* - * Wipe unused MCRs - */ - - for(i=used;i<8;i++) - wrmsr(MSR_IDT_MCR0+i, 0, 0); -} - -static void __init winchip2_create_optimal_mcr(void) -{ - u32 lo, hi; - int i; - - /* - * Allocate up to 6 mcrs to mark as much of ram as possible - * as write combining, weak store ordered. - * - * Load the registers with type 25 - * 8 - weak write ordering - * 16 - weak read ordering - * 1 - write combining - */ - - int used = winchip_mcr_compute(6, 25); - - /* - * Mark the registers we are using. - */ - - rdmsr(MSR_IDT_MCR_CTRL, lo, hi); - for(i=0;i>17) & 7; - lo |= key<<6; /* replace with unlock key */ - wrmsr(MSR_IDT_MCR_CTRL, lo, hi); -} - -static void __init winchip2_protect_mcr(void) -{ - u32 lo, hi; - - rdmsr(MSR_IDT_MCR_CTRL, lo, hi); - lo&=~0x1C0; /* blank bits 8-6 */ - wrmsr(MSR_IDT_MCR_CTRL, lo, hi); -} - -#endif - -static void __init init_centaur(struct cpuinfo_x86 *c) -{ - enum { - ECX8=1<<1, - EIERRINT=1<<2, - DPM=1<<3, - DMCE=1<<4, - DSTPCLK=1<<5, - ELINEAR=1<<6, - DSMC=1<<7, - DTLOCK=1<<8, - EDCTLB=1<<8, - EMMX=1<<9, - DPDC=1<<11, - EBRPRED=1<<12, - DIC=1<<13, - DDC=1<<14, - DNA=1<<15, - ERETSTK=1<<16, - E2MMX=1<<19, - EAMD3D=1<<20, - }; - - char *name; - u32 fcr_set=0; - u32 fcr_clr=0; - u32 lo,hi,newlo; - u32 aa,bb,cc,dd; - - /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; - 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ - clear_bit(0*32+31, c->x86_capability); - - switch (c->x86) { - - case 5: - switch(c->x86_model) { - case 4: - name="C6"; - fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK; - fcr_clr=DPDC; - printk(KERN_NOTICE "Disabling bugged TSC.\n"); - clear_bit(X86_FEATURE_TSC, c->x86_capability); -#ifdef CONFIG_X86_OOSTORE - winchip_create_optimal_mcr(); - /* Enable - write combining on non-stack, non-string - write combining on string, all types - weak write ordering - - The C6 original lacks weak read order - - Note 0x120 is write only on Winchip 1 */ - - wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); -#endif - break; - case 8: - switch(c->x86_mask) { - default: - name="2"; - break; - case 7 ... 9: - name="2A"; - break; - case 10 ... 15: - name="2B"; - break; - } - fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; - fcr_clr=DPDC; -#ifdef CONFIG_X86_OOSTORE - winchip2_unprotect_mcr(); - winchip2_create_optimal_mcr(); - rdmsr(MSR_IDT_MCR_CTRL, lo, hi); - /* Enable - write combining on non-stack, non-string - write combining on string, all types - weak write ordering - */ - lo|=31; - wrmsr(MSR_IDT_MCR_CTRL, lo, hi); - winchip2_protect_mcr(); -#endif - break; - case 9: - name="3"; - fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; - fcr_clr=DPDC; -#ifdef CONFIG_X86_OOSTORE - winchip2_unprotect_mcr(); - winchip2_create_optimal_mcr(); - rdmsr(MSR_IDT_MCR_CTRL, lo, hi); - /* Enable - write combining on non-stack, non-string - write combining on string, all types - weak write ordering - */ - lo|=31; - wrmsr(MSR_IDT_MCR_CTRL, lo, hi); - winchip2_protect_mcr(); -#endif - break; - case 10: - name="4"; - /* no info on the WC4 yet */ - break; - default: - name="??"; - } - - rdmsr(MSR_IDT_FCR1, lo, hi); - newlo=(lo|fcr_set) & (~fcr_clr); - - if (newlo!=lo) { - printk(KERN_INFO "Centaur FCR was 0x%X now 0x%X\n", lo, newlo ); - wrmsr(MSR_IDT_FCR1, newlo, hi ); - } else { - printk(KERN_INFO "Centaur FCR is 0x%X\n",lo); - } - /* Emulate MTRRs using Centaur's MCR. */ - set_bit(X86_FEATURE_CENTAUR_MCR, c->x86_capability); - /* Report CX8 */ - set_bit(X86_FEATURE_CX8, c->x86_capability); - /* Set 3DNow! on Winchip 2 and above. */ - if (c->x86_model >=8) - set_bit(X86_FEATURE_3DNOW, c->x86_capability); - /* See if we can find out some more. */ - if ( cpuid_eax(0x80000000) >= 0x80000005 ) { - /* Yes, we can. */ - cpuid(0x80000005,&aa,&bb,&cc,&dd); - /* Add L1 data and code cache sizes. */ - c->x86_cache_size = (cc>>24)+(dd>>24); - } - sprintf( c->x86_model_id, "WinChip %s", name ); - break; - - case 6: - switch (c->x86_model) { - case 6 ... 8: /* Cyrix III family */ - rdmsr (MSR_VIA_FCR, lo, hi); - lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */ - wrmsr (MSR_VIA_FCR, lo, hi); - - set_bit(X86_FEATURE_CX8, c->x86_capability); - set_bit(X86_FEATURE_3DNOW, c->x86_capability); - - get_model_name(c); - display_cacheinfo(c); - break; - } - break; - } -} - - -static void __init init_transmeta(struct cpuinfo_x86 *c) -{ - unsigned int cap_mask, uk, max, dummy; - unsigned int cms_rev1, cms_rev2; - unsigned int cpu_rev, cpu_freq, cpu_flags; - char cpu_info[65]; - - get_model_name(c); /* Same as AMD/Cyrix */ - display_cacheinfo(c); - - /* Print CMS and CPU revision */ - max = cpuid_eax(0x80860000); - if ( max >= 0x80860001 ) { - cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags); - printk(KERN_INFO "CPU: Processor revision %u.%u.%u.%u, %u MHz\n", - (cpu_rev >> 24) & 0xff, - (cpu_rev >> 16) & 0xff, - (cpu_rev >> 8) & 0xff, - cpu_rev & 0xff, - cpu_freq); - } - if ( max >= 0x80860002 ) { - cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy); - printk(KERN_INFO "CPU: Code Morphing Software revision %u.%u.%u-%u-%u\n", - (cms_rev1 >> 24) & 0xff, - (cms_rev1 >> 16) & 0xff, - (cms_rev1 >> 8) & 0xff, - cms_rev1 & 0xff, - cms_rev2); - } - if ( max >= 0x80860006 ) { - cpuid(0x80860003, - (void *)&cpu_info[0], - (void *)&cpu_info[4], - (void *)&cpu_info[8], - (void *)&cpu_info[12]); - cpuid(0x80860004, - (void *)&cpu_info[16], - (void *)&cpu_info[20], - (void *)&cpu_info[24], - (void *)&cpu_info[28]); - cpuid(0x80860005, - (void *)&cpu_info[32], - (void *)&cpu_info[36], - (void *)&cpu_info[40], - (void *)&cpu_info[44]); - cpuid(0x80860006, - (void *)&cpu_info[48], - (void *)&cpu_info[52], - (void *)&cpu_info[56], - (void *)&cpu_info[60]); - cpu_info[64] = '\0'; - printk(KERN_INFO "CPU: %s\n", cpu_info); - } - - /* Unhide possibly hidden capability flags */ - rdmsr(0x80860004, cap_mask, uk); - wrmsr(0x80860004, ~0, uk); - c->x86_capability[0] = cpuid_edx(0x00000001); - wrmsr(0x80860004, cap_mask, uk); -} - - -static void __init init_rise(struct cpuinfo_x86 *c) -{ - printk("CPU: Rise iDragon"); - if (c->x86_model > 2) - printk(" II"); - printk("\n"); - - /* Unhide possibly hidden capability flags - The mp6 iDragon family don't have MSRs. - We switch on extra features with this cpuid weirdness: */ - __asm__ ( - "movl $0x6363452a, %%eax\n\t" - "movl $0x3231206c, %%ecx\n\t" - "movl $0x2a32313a, %%edx\n\t" - "cpuid\n\t" - "movl $0x63634523, %%eax\n\t" - "movl $0x32315f6c, %%ecx\n\t" - "movl $0x2333313a, %%edx\n\t" - "cpuid\n\t" : : : "eax", "ebx", "ecx", "edx" - ); - set_bit(X86_FEATURE_CX8, c->x86_capability); -} - - -extern void trap_init_f00f_bug(void); - -static void __init init_intel(struct cpuinfo_x86 *c) -{ - char *p = NULL; - unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ - -#ifdef CONFIG_X86_F00F_BUG - /* - * All current models of Pentium and Pentium with MMX technology CPUs - * have the F0 0F bug, which lets nonpriviledged users lock up the system. - * Note that the workaround only should be initialized once... - */ - c->f00f_bug = 0; - if ( c->x86 == 5 ) { - static int f00f_workaround_enabled = 0; - - c->f00f_bug = 1; - if ( !f00f_workaround_enabled ) { - trap_init_f00f_bug(); - printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); - f00f_workaround_enabled = 1; - } - } -#endif - - - if (c->cpuid_level > 1) { - /* supports eax=2 call */ - int i, j, n; - int regs[4]; - unsigned char *dp = (unsigned char *)regs; - - /* Number of times to iterate */ - n = cpuid_eax(2) & 0xFF; - - for ( i = 0 ; i < n ; i++ ) { - cpuid(2, ®s[0], ®s[1], ®s[2], ®s[3]); - - /* If bit 31 is set, this is an unknown format */ - for ( j = 0 ; j < 3 ; j++ ) { - if ( regs[j] < 0 ) regs[j] = 0; - } - - /* Byte 0 is level count, not a descriptor */ - for ( j = 1 ; j < 16 ; j++ ) { - unsigned char des = dp[j]; - unsigned char dl, dh; - unsigned int cs; - - dh = des >> 4; - dl = des & 0x0F; - - /* Black magic... */ - - switch ( dh ) - { - case 0: - switch ( dl ) { - case 6: - /* L1 I cache */ - l1i += 8; - break; - case 8: - /* L1 I cache */ - l1i += 16; - break; - case 10: - /* L1 D cache */ - l1d += 8; - break; - case 12: - /* L1 D cache */ - l1d += 16; - break; - default:; - /* TLB, or unknown */ - } - break; - case 2: - if ( dl ) { - /* L3 cache */ - cs = (dl-1) << 9; - l3 += cs; - } - break; - case 4: - if ( c->x86 > 6 && dl ) { - /* P4 family */ - /* L3 cache */ - cs = 128 << (dl-1); - l3 += cs; - break; - } - /* else same as 8 - fall through */ - case 8: - if ( dl ) { - /* L2 cache */ - cs = 128 << (dl-1); - l2 += cs; - } - break; - case 6: - if (dl > 5) { - /* L1 D cache */ - cs = 8<<(dl-6); - l1d += cs; - } - break; - case 7: - if ( dl >= 8 ) - { - /* L2 cache */ - cs = 64<<(dl-8); - l2 += cs; - } else { - /* L0 I cache, count as L1 */ - cs = dl ? (16 << (dl-1)) : 12; - l1i += cs; - } - break; - default: - /* TLB, or something else we don't know about */ - break; - } - } - } - if ( l1i || l1d ) - printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n", - l1i, l1d); - if ( l2 ) - printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); - if ( l3 ) - printk(KERN_INFO "CPU: L3 cache: %dK\n", l3); - - /* - * This assumes the L3 cache is shared; it typically lives in - * the northbridge. The L1 caches are included by the L2 - * cache, and so should not be included for the purpose of - * SMP switching weights. - */ - c->x86_cache_size = l2 ? l2 : (l1i+l1d); - } - - /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it */ - if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 ) - clear_bit(X86_FEATURE_SEP, c->x86_capability); - - /* Names for the Pentium II/Celeron processors - detectable only by also checking the cache size. - Dixon is NOT a Celeron. */ - if (c->x86 == 6) { - switch (c->x86_model) { - case 5: - if (l2 == 0) - p = "Celeron (Covington)"; - if (l2 == 256) - p = "Mobile Pentium II (Dixon)"; - break; - - case 6: - if (l2 == 128) - p = "Celeron (Mendocino)"; - break; - - case 8: - if (l2 == 128) - p = "Celeron (Coppermine)"; - break; - } - } - - if ( p ) - strcpy(c->x86_model_id, p); - -#ifdef CONFIG_SMP - if (cpu_has(c, X86_FEATURE_HT)) { - extern int phys_proc_id[NR_CPUS]; - - u32 eax, ebx, ecx, edx; - int index_lsb, index_msb, tmp; - int initial_apic_id; - int cpu = smp_processor_id(); - - cpuid(1, &eax, &ebx, &ecx, &edx); - smp_num_siblings = (ebx & 0xff0000) >> 16; - - if (smp_num_siblings == 1) { - printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); - } else if (smp_num_siblings > 1 ) { - index_lsb = 0; - index_msb = 31; - /* - * At this point we only support two siblings per - * processor package. - */ -#define NR_SIBLINGS 2 - if (smp_num_siblings != NR_SIBLINGS) { - printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings); - smp_num_siblings = 1; - goto too_many_siblings; - } - tmp = smp_num_siblings; - while ((tmp & 1) == 0) { - tmp >>=1 ; - index_lsb++; - } - tmp = smp_num_siblings; - while ((tmp & 0x80000000 ) == 0) { - tmp <<=1 ; - index_msb--; - } - if (index_lsb != index_msb ) - index_msb++; - initial_apic_id = ebx >> 24 & 0xff; - phys_proc_id[cpu] = initial_apic_id >> index_msb; - - printk(KERN_INFO "CPU: Physical Processor ID: %d\n", - phys_proc_id[cpu]); - } - - } -too_many_siblings: -#endif -} - -void __init get_cpu_vendor(struct cpuinfo_x86 *c) -{ - char *v = c->x86_vendor_id; - - if (!strcmp(v, "GenuineIntel")) - c->x86_vendor = X86_VENDOR_INTEL; - else if (!strcmp(v, "AuthenticAMD")) - c->x86_vendor = X86_VENDOR_AMD; - else if (!strcmp(v, "CyrixInstead")) - c->x86_vendor = X86_VENDOR_CYRIX; - else if (!strcmp(v, "Geode by NSC")) - c->x86_vendor = X86_VENDOR_NSC; - else if (!strcmp(v, "UMC UMC UMC ")) - c->x86_vendor = X86_VENDOR_UMC; - else if (!strcmp(v, "CentaurHauls")) - c->x86_vendor = X86_VENDOR_CENTAUR; - else if (!strcmp(v, "NexGenDriven")) - c->x86_vendor = X86_VENDOR_NEXGEN; - else if (!strcmp(v, "RiseRiseRise")) - c->x86_vendor = X86_VENDOR_RISE; - else if (!strcmp(v, "GenuineTMx86") || - !strcmp(v, "TransmetaCPU")) - c->x86_vendor = X86_VENDOR_TRANSMETA; - else - c->x86_vendor = X86_VENDOR_UNKNOWN; -} - -struct cpu_model_info { - int vendor; - int family; - char *model_names[16]; -}; - -/* Naming convention should be: [()] */ -/* This table only is used unless init_() below doesn't set it; */ -/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */ -static struct cpu_model_info cpu_models[] __initdata = { - { X86_VENDOR_INTEL, 4, - { "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL", - "486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, - NULL, NULL, NULL, NULL, NULL }}, - { X86_VENDOR_INTEL, 5, - { "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75 - 200", - "OverDrive PODP5V83", "Pentium MMX", NULL, NULL, - "Mobile Pentium 75 - 200", "Mobile Pentium MMX", NULL, NULL, NULL, - NULL, NULL, NULL, NULL }}, - { X86_VENDOR_INTEL, 6, - { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", - NULL, "Pentium II (Deschutes)", "Mobile Pentium II", - "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, - "Pentium III (Cascades)", NULL, NULL, NULL, NULL }}, - { X86_VENDOR_AMD, 4, - { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB", - "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", - "Am5x86-WB" }}, - { X86_VENDOR_AMD, 5, /* Is this this really necessary?? */ - { "K5/SSA5", "K5", - "K5", "K5", NULL, NULL, - "K6", "K6", "K6-2", - "K6-3", NULL, NULL, NULL, NULL, NULL, NULL }}, - { X86_VENDOR_AMD, 6, /* Is this this really necessary?? */ - { "Athlon", "Athlon", - "Athlon", NULL, "Athlon", NULL, - NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, - { X86_VENDOR_UMC, 4, - { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL }}, - { X86_VENDOR_NEXGEN, 5, - { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, - { X86_VENDOR_RISE, 5, - { "iDragon", NULL, "iDragon", NULL, NULL, NULL, NULL, - NULL, "iDragon II", "iDragon II", NULL, NULL, NULL, NULL, NULL, NULL }}, -}; - -/* Look up CPU names by table lookup. */ -static char __init *table_lookup_model(struct cpuinfo_x86 *c) -{ - struct cpu_model_info *info = cpu_models; - int i; - - if ( c->x86_model >= 16 ) - return NULL; /* Range check */ - - for ( i = 0 ; i < sizeof(cpu_models)/sizeof(struct cpu_model_info) ; i++ ) { - if ( info->vendor == c->x86_vendor && - info->family == c->x86 ) { - return info->model_names[c->x86_model]; - } - info++; - } - return NULL; /* Not found */ -} - -/* - * Detect a NexGen CPU running without BIOS hypercode new enough - * to have CPUID. (Thanks to Herbert Oppmann) - */ - -static int __init deep_magic_nexgen_probe(void) -{ - int ret; - - __asm__ __volatile__ ( - " movw $0x5555, %%ax\n" - " xorw %%dx,%%dx\n" - " movw $2, %%cx\n" - " divw %%cx\n" - " movl $0, %%eax\n" - " jnz 1f\n" - " movl $1, %%eax\n" - "1:\n" - : "=a" (ret) : : "cx", "dx" ); - return ret; -} - -static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c) -{ - if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) { - /* Disable processor serial number */ - unsigned long lo,hi; - rdmsr(MSR_IA32_BBL_CR_CTL,lo,hi); - lo |= 0x200000; - wrmsr(MSR_IA32_BBL_CR_CTL,lo,hi); - printk(KERN_NOTICE "CPU serial number disabled.\n"); - clear_bit(X86_FEATURE_PN, c->x86_capability); - - /* Disabling the serial number may affect the cpuid level */ - c->cpuid_level = cpuid_eax(0); - } -} - - -static int __init x86_serial_nr_setup(char *s) -{ - disable_x86_serial_nr = 0; - return 1; -} -__setup("serialnumber", x86_serial_nr_setup); - -static int __init x86_fxsr_setup(char * s) -{ - disable_x86_fxsr = 1; - return 1; -} -__setup("nofxsr", x86_fxsr_setup); - - -/* Standard macro to see if a specific flag is changeable */ -static inline int flag_is_changeable_p(u32 flag) -{ - u32 f1, f2; - - asm("pushfl\n\t" - "pushfl\n\t" - "popl %0\n\t" - "movl %0,%1\n\t" - "xorl %2,%0\n\t" - "pushl %0\n\t" - "popfl\n\t" - "pushfl\n\t" - "popl %0\n\t" - "popfl\n\t" - : "=&r" (f1), "=&r" (f2) - : "ir" (flag)); - - return ((f1^f2) & flag) != 0; -} - - -/* Probe for the CPUID instruction */ -static int __init have_cpuid_p(void) -{ - return flag_is_changeable_p(X86_EFLAGS_ID); -} - -/* - * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected - * by the fact that they preserve the flags across the division of 5/2. - * PII and PPro exhibit this behavior too, but they have cpuid available. - */ - -/* - * Perform the Cyrix 5/2 test. A Cyrix won't change - * the flags, while other 486 chips will. - */ -static inline int test_cyrix_52div(void) -{ - unsigned int test; - - __asm__ __volatile__( - "sahf\n\t" /* clear flags (%eax = 0x0005) */ - "div %b2\n\t" /* divide 5 by 2 */ - "lahf" /* store flags into %ah */ - : "=a" (test) - : "0" (5), "q" (2) - : "cc"); - - /* AH is 0x02 on Cyrix after the divide.. */ - return (unsigned char) (test >> 8) == 0x02; -} - -/* Try to detect a CPU with disabled CPUID, and if so, enable. This routine - may also be used to detect non-CPUID processors and fill in some of - the information manually. */ -static int __init id_and_try_enable_cpuid(struct cpuinfo_x86 *c) -{ - /* First of all, decide if this is a 486 or higher */ - /* It's a 486 if we can modify the AC flag */ - if ( flag_is_changeable_p(X86_EFLAGS_AC) ) - c->x86 = 4; - else - c->x86 = 3; - - /* Detect Cyrix with disabled CPUID */ - if ( c->x86 == 4 && test_cyrix_52div() ) { - unsigned char dir0, dir1; - - strcpy(c->x86_vendor_id, "CyrixInstead"); - c->x86_vendor = X86_VENDOR_CYRIX; - - /* Actually enable cpuid on the older cyrix */ - - /* Retrieve CPU revisions */ - - do_cyrix_devid(&dir0, &dir1); - - dir0>>=4; - - /* Check it is an affected model */ - - if (dir0 == 5 || dir0 == 3) - { - unsigned char ccr3, ccr4; - unsigned long flags; - printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n"); - local_irq_save(flags); - ccr3 = getCx86(CX86_CCR3); - setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ - ccr4 = getCx86(CX86_CCR4); - setCx86(CX86_CCR4, ccr4 | 0x80); /* enable cpuid */ - setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ - local_irq_restore(flags); - } - } else - - /* Detect NexGen with old hypercode */ - if ( deep_magic_nexgen_probe() ) { - strcpy(c->x86_vendor_id, "NexGenDriven"); - } - - return have_cpuid_p(); /* Check to see if CPUID now enabled? */ -} - -/* - * This does the hard work of actually picking apart the CPU stuff... - */ -void __init identify_cpu(struct cpuinfo_x86 *c) -{ - int junk, i; - u32 xlvl, tfms; - - c->loops_per_jiffy = loops_per_jiffy; - c->x86_cache_size = -1; - c->x86_vendor = X86_VENDOR_UNKNOWN; - c->cpuid_level = -1; /* CPUID not detected */ - c->x86_model = c->x86_mask = 0; /* So far unknown... */ - c->x86_vendor_id[0] = '\0'; /* Unset */ - c->x86_model_id[0] = '\0'; /* Unset */ - memset(&c->x86_capability, 0, sizeof c->x86_capability); - - if ( !have_cpuid_p() && !id_and_try_enable_cpuid(c) ) { - /* CPU doesn't have CPUID */ - - /* If there are any capabilities, they're vendor-specific */ - /* enable_cpuid() would have set c->x86 for us. */ - } else { - /* CPU does have CPUID */ - - /* Get vendor name */ - cpuid(0x00000000, &c->cpuid_level, - (int *)&c->x86_vendor_id[0], - (int *)&c->x86_vendor_id[8], - (int *)&c->x86_vendor_id[4]); - - get_cpu_vendor(c); - /* Initialize the standard set of capabilities */ - /* Note that the vendor-specific code below might override */ - - /* Intel-defined flags: level 0x00000001 */ - if ( c->cpuid_level >= 0x00000001 ) { - u32 capability; - cpuid(0x00000001, &tfms, &junk, &junk, &capability); - c->x86_capability[0] = capability; - c->x86 = (tfms >> 8) & 15; - c->x86_model = (tfms >> 4) & 15; - c->x86_mask = tfms & 15; - } else { - /* Have CPUID level 0 only - unheard of */ - c->x86 = 4; - } - - /* AMD-defined flags: level 0x80000001 */ - xlvl = cpuid_eax(0x80000000); - if ( (xlvl & 0xffff0000) == 0x80000000 ) { - if ( xlvl >= 0x80000001 ) - c->x86_capability[1] = cpuid_edx(0x80000001); - if ( xlvl >= 0x80000004 ) - get_model_name(c); /* Default name */ - } - - /* Transmeta-defined flags: level 0x80860001 */ - xlvl = cpuid_eax(0x80860000); - if ( (xlvl & 0xffff0000) == 0x80860000 ) { - if ( xlvl >= 0x80860001 ) - c->x86_capability[2] = cpuid_edx(0x80860001); - } - } - - printk(KERN_DEBUG "CPU: Before vendor init, caps: %08lx %08lx %08lx, vendor = %d\n", - c->x86_capability[0], - c->x86_capability[1], - c->x86_capability[2], - c->x86_vendor); - - /* - * Vendor-specific initialization. In this section we - * canonicalize the feature flags, meaning if there are - * features a certain CPU supports which CPUID doesn't - * tell us, CPUID claiming incorrect flags, or other bugs, - * we handle them here. - * - * At the end of this section, c->x86_capability better - * indicate the features this CPU genuinely supports! - */ - switch ( c->x86_vendor ) { - case X86_VENDOR_AMD: - init_amd(c); - break; - - case X86_VENDOR_CENTAUR: - init_centaur(c); - break; - - case X86_VENDOR_CYRIX: - init_cyrix(c); - break; - - case X86_VENDOR_INTEL: - init_intel(c); - break; - - case X86_VENDOR_NEXGEN: - c->x86_cache_size = 256; /* A few had 1 MB... */ - break; - - case X86_VENDOR_NSC: - init_cyrix(c); - break; - - case X86_VENDOR_RISE: - init_rise(c); - break; - - case X86_VENDOR_TRANSMETA: - init_transmeta(c); - break; - - case X86_VENDOR_UNKNOWN: - default: - /* Not much we can do here... */ - /* Check if at least it has cpuid */ - if (c->cpuid_level == -1) - { - /* No cpuid. It must be an ancient CPU */ - if (c->x86 == 4) - strcpy(c->x86_model_id, "486"); - else if (c->x86 == 3) - strcpy(c->x86_model_id, "386"); - } - break; - - } - - printk(KERN_DEBUG "CPU: After vendor init, caps: %08lx %08lx %08lx %08lx\n", - c->x86_capability[0], - c->x86_capability[1], - c->x86_capability[2], - c->x86_capability[3]); - - /* - * The vendor-specific functions might have changed features. Now - * we do "generic changes." - */ - - /* TSC disabled? */ -#ifndef CONFIG_X86_TSC - if ( tsc_disable ) - clear_bit(X86_FEATURE_TSC, c->x86_capability); -#endif - - /* FXSR disabled? */ - if (disable_x86_fxsr) { - clear_bit(X86_FEATURE_FXSR, c->x86_capability); - clear_bit(X86_FEATURE_XMM, c->x86_capability); - } - - /* Disable the PN if appropriate */ - squash_the_stupid_serial_number(c); - - /* Init Machine Check Exception if available. */ - mcheck_init(c); - - /* If the model name is still unset, do table lookup. */ - if ( !c->x86_model_id[0] ) { - char *p; - p = table_lookup_model(c); - if ( p ) - strcpy(c->x86_model_id, p); - else - /* Last resort... */ - sprintf(c->x86_model_id, "%02x/%02x", - c->x86_vendor, c->x86_model); - } - - /* Now the feature flags better reflect actual CPU features! */ - - printk(KERN_DEBUG "CPU: After generic, caps: %08lx %08lx %08lx %08lx\n", - c->x86_capability[0], - c->x86_capability[1], - c->x86_capability[2], - c->x86_capability[3]); - - /* - * On SMP, boot_cpu_data holds the common feature set between - * all CPUs; so make sure that we indicate which features are - * common between the CPUs. The first time this routine gets - * executed, c == &boot_cpu_data. - */ - if ( c != &boot_cpu_data ) { - /* AND the already accumulated flags with these */ - for ( i = 0 ; i < NCAPINTS ; i++ ) - boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; - } - - printk(KERN_DEBUG "CPU: Common caps: %08lx %08lx %08lx %08lx\n", - boot_cpu_data.x86_capability[0], - boot_cpu_data.x86_capability[1], - boot_cpu_data.x86_capability[2], - boot_cpu_data.x86_capability[3]); -} -/* - * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c - */ - -void __init dodgy_tsc(void) -{ - get_cpu_vendor(&boot_cpu_data); - - if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) || - ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC )) - init_cyrix(&boot_cpu_data); -} - - -/* These need to match */ -static char *cpu_vendor_names[] __initdata = { - "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta", "NSC" }; - - -void __init print_cpu_info(struct cpuinfo_x86 *c) -{ - char *vendor = NULL; - - if (c->x86_vendor < sizeof(cpu_vendor_names)/sizeof(char *)) - vendor = cpu_vendor_names[c->x86_vendor]; - else if (c->cpuid_level >= 0) - vendor = c->x86_vendor_id; - - if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor))) - printk("%s ", vendor); - - if (!c->x86_model_id[0]) - printk("%d86", c->x86); - else - printk("%s", c->x86_model_id); - - if (c->x86_mask || c->cpuid_level >= 0) - printk(" stepping %02x\n", c->x86_mask); - else - printk("\n"); -} - -/* - * Get CPU information for use by the procfs. - */ -static int show_cpuinfo(struct seq_file *m, void *v) -{ - /* - * These flag bits must match the definitions in . - * NULL means this bit is undefined or reserved; either way it doesn't - * have meaning as far as Linux is concerned. Note that it's important - * to realize there is a difference between this table and CPUID -- if - * applications want to get the raw CPUID data, they should access - * /dev/cpu//cpuid instead. - */ - static char *x86_cap_flags[] = { - /* Intel-defined */ - "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", - "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", - "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", - "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL, - - /* AMD-defined */ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, - NULL, NULL, NULL, "mp", NULL, NULL, "mmxext", NULL, - NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow", - - /* Transmeta-defined */ - "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - - /* Other (Linux-defined) */ - "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - }; - struct cpuinfo_x86 *c = v; - int i, n = c - cpu_data; - int fpu_exception; - -#ifdef CONFIG_SMP - if (!(cpu_online_map & (1<x86_vendor_id[0] ? c->x86_vendor_id : "unknown", - c->x86, - c->x86_model, - c->x86_model_id[0] ? c->x86_model_id : "unknown"); - - if (c->x86_mask || c->cpuid_level >= 0) - seq_printf(m, "stepping\t: %d\n", c->x86_mask); - else - seq_printf(m, "stepping\t: unknown\n"); - - if ( cpu_has(c, X86_FEATURE_TSC) ) { - seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n", - cpu_khz / 1000, (cpu_khz % 1000)); - } - - /* Cache size */ - if (c->x86_cache_size >= 0) - seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); - - /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ - fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu); - seq_printf(m, "fdiv_bug\t: %s\n" - "hlt_bug\t\t: %s\n" - "f00f_bug\t: %s\n" - "coma_bug\t: %s\n" - "fpu\t\t: %s\n" - "fpu_exception\t: %s\n" - "cpuid level\t: %d\n" - "wp\t\t: %s\n" - "flags\t\t:", - c->fdiv_bug ? "yes" : "no", - c->hlt_works_ok ? "no" : "yes", - c->f00f_bug ? "yes" : "no", - c->coma_bug ? "yes" : "no", - c->hard_math ? "yes" : "no", - fpu_exception ? "yes" : "no", - c->cpuid_level, - c->wp_works_ok ? "yes" : "no"); - - for ( i = 0 ; i < 32*NCAPINTS ; i++ ) - if ( test_bit(i, c->x86_capability) && - x86_cap_flags[i] != NULL ) - seq_printf(m, " %s", x86_cap_flags[i]); - - seq_printf(m, "\nbogomips\t: %lu.%02lu\n\n", - c->loops_per_jiffy/(500000/HZ), - (c->loops_per_jiffy/(5000/HZ)) % 100); - return 0; -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - return *pos < NR_CPUS ? cpu_data + *pos : NULL; -} -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} -static void c_stop(struct seq_file *m, void *v) -{ -} -struct seq_operations cpuinfo_op = { - start: c_start, - next: c_next, - stop: c_stop, - show: show_cpuinfo, -}; - -unsigned long cpu_initialized __initdata = 0; - -/* - * cpu_init() initializes state that is per-CPU. Some data is already - * initialized (naturally) in the bootstrap process, such as the GDT - * and IDT. We reload them nevertheless, this function acts as a - * 'CPU state barrier', nothing should get across. - */ -void __init cpu_init (void) -{ - int nr = smp_processor_id(); - struct tss_struct * t = &init_tss[nr]; - - if (test_and_set_bit(nr, &cpu_initialized)) { - printk(KERN_WARNING "CPU#%d already initialized!\n", nr); - for (;;) __sti(); - } - printk(KERN_INFO "Initializing CPU#%d\n", nr); - - if (cpu_has_vme || cpu_has_tsc || cpu_has_de) - clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); -#ifndef CONFIG_X86_TSC - if (tsc_disable && cpu_has_tsc) { - printk(KERN_NOTICE "Disabling TSC...\n"); - /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/ - clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability); - set_in_cr4(X86_CR4_TSD); - } -#endif - - __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); - __asm__ __volatile__("lidt %0": "=m" (idt_descr)); - - /* - * Delete NT - */ - __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); - - /* - * set up and load the per-CPU TSS and LDT - */ - atomic_inc(&init_mm.mm_count); - current->active_mm = &init_mm; - if(current->mm) - BUG(); - enter_lazy_tlb(&init_mm, current, nr); - - t->esp0 = current->thread.esp0; - set_tss_desc(nr,t); - gdt_table[__TSS(nr)].b &= 0xfffffdff; - load_TR(nr); - load_LDT(&init_mm.context); - - /* Clear %fs and %gs. */ - asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); - - /* Clear all 6 debug registers: */ - -#define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) ); - - CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7); - -#undef CD - - /* - * Force FPU initialization: - */ - clear_thread_flag(TIF_USEDFPU); - current->used_math = 0; - stts(); -} - -/* - * Early probe support logic for ppro memory erratum #50 - * - * This is called before we do cpu ident work - */ - -int __init ppro_with_ram_bug(void) -{ - char vendor_id[16]; - int ident; - - /* Must have CPUID */ - if(!have_cpuid_p()) - return 0; - if(cpuid_eax(0)<1) - return 0; - - /* Must be Intel */ - cpuid(0, &ident, - (int *)&vendor_id[0], - (int *)&vendor_id[8], - (int *)&vendor_id[4]); - - if(memcmp(vendor_id, "IntelInside", 12)) - return 0; - - ident = cpuid_eax(1); - - /* Model 6 */ - - if(((ident>>8)&15)!=6) - return 0; - - /* Pentium Pro */ - - if(((ident>>4)&15)!=1) - return 0; - - if((ident&15) < 8) - { - printk(KERN_INFO "Pentium Pro with Errata#50 detected. Taking evasive action.\n"); - return 1; - } - printk(KERN_INFO "Your Pentium Pro seems ok.\n"); - return 0; -} - /* * Local Variables: * mode:c diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/smp.c linux-2.5/arch/i386/kernel/smp.c --- linux-2.5.20/arch/i386/kernel/smp.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/arch/i386/kernel/smp.c Tue May 21 20:53:06 2002 @@ -104,7 +104,7 @@ */ /* The 'big kernel lock' */ -spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +spinlock_cacheline_t kernel_flag_cacheline = {SPIN_LOCK_UNLOCKED}; struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0, }}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/time.c linux-2.5/arch/i386/kernel/time.c --- linux-2.5.20/arch/i386/kernel/time.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/arch/i386/kernel/time.c Sat May 25 19:51:58 2002 @@ -28,6 +28,9 @@ * 1998-12-24 Copyright (C) 1998 Andrea Arcangeli * Fixed a xtime SMP race (we need the xtime_lock rw spinlock to * serialize accesses to xtime/lost_ticks). + * 2001-02-20 Hiroshi Miura + * Work around for Cyrix/IBM/NSC MediaGX/GXm, NSC Geode southbridge + * PIT bug. (NSC Cx5510/5520) */ #include @@ -471,6 +474,10 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int count; +#ifdef CONFIG_CS5520 + int count1, count2, count3; + int n1, n2, n3; +#endif /* * Here we are in the timer irq handler. We just have irqs locally @@ -499,6 +506,7 @@ rdtscl(last_tsc_low); +#ifndef CONFIG_CS5520 spin_lock(&i8253_lock); outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -511,6 +519,59 @@ } do_timer_interrupt(irq, NULL, regs); +#else + spin_lock(&i8253_lock); + outb_p(0x00, 0x43); /* latch the count ASAP */ +/* this codes comes from FreeBSD */ + count1 = inb_p(0x40); + count1 |= inb(0x40) << 8; + count2 = inb_p(0x40); + count2 = inb(0x40) << 8; + count3 = inb_p(0x40); + count3 = inb(0x40) << 8; + spin_unlock(&i8253_lock); + + if (count1 >= count2 && count2 >= count3 && count1 - count2 < 0x200) + count = count2; + else { + +#define _swap_val(a, b) do { \ + int c = a;\ + a = b; \ + b = c; \ +} while(0) + /* sort values */ + if (count1 < count2) + _swap_val(count1, count2); + if (count2 < count3) + _swap_val(count2, count3); + if (count1 < count2) + _swap_val(count1, count2); + + /* compare the middle value */ + if (count1 - count3 < 0x200) + count = count2; + else + { + n1 = count2 - count3; + n2 = count3 - count1 + LATCH; + n3 = count1 - count2; + count = count3; + if (n1 >= n2) { + if (n1 >= n3) + count = count1; + } else { + if (n2 >= n3) + count = count2; + } + } + } + count = ((LATCH-1) - count) * TICK_SIZE; + delay_at_last_interrupt = (count + LATCH/2) / LATCH; + } + + do_timer_interrupt(irq, NULL, regs); +#endif write_unlock(&xtime_lock); @@ -685,6 +746,10 @@ if (cpu_has_tsc) { unsigned long tsc_quotient = calibrate_tsc(); +#ifdef CONFIG_CS5520 + if (!tsc_quotient) + tsc_quotient = calibrate_tsc(); +#endif if (tsc_quotient) { fast_gettimeoffset_quotient = tsc_quotient; use_tsc = 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/traps.c linux-2.5/arch/i386/kernel/traps.c --- linux-2.5.20/arch/i386/kernel/traps.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/arch/i386/kernel/traps.c Sat May 25 19:51:58 2002 @@ -955,8 +955,8 @@ } #endif -#ifdef CONFIG_EISA int EISA_bus; +#ifdef CONFIG_EISA static struct resource eisa_id = { "EISA ID", 0xc80, 0xc83, IORESOURCE_BUSY }; #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/kernel/vm86.c linux-2.5/arch/i386/kernel/vm86.c --- linux-2.5.20/arch/i386/kernel/vm86.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/arch/i386/kernel/vm86.c Sun May 26 01:38:09 2002 @@ -18,6 +18,7 @@ #include #include #include +#include /* * Known problems: @@ -98,23 +99,24 @@ pte_t *pte, *mapped; int i; + preempt_disable(); + spin_lock(&tsk->mm->page_table_lock); pgd = pgd_offset(tsk->mm, 0xA0000); if (pgd_none(*pgd)) - return; + goto out; if (pgd_bad(*pgd)) { pgd_ERROR(*pgd); pgd_clear(pgd); - return; + goto out; } pmd = pmd_offset(pgd, 0xA0000); if (pmd_none(*pmd)) - return; + goto out; if (pmd_bad(*pmd)) { pmd_ERROR(*pmd); pmd_clear(pmd); - return; + goto out; } - preempt_disable(); pte = mapped = pte_offset_map(pmd, 0xA0000); for (i = 0; i < 32; i++) { if (pte_present(*pte)) @@ -122,6 +124,8 @@ pte++; } pte_unmap(mapped); +out: + spin_unlock(&tsk->mm->page_table_lock); preempt_enable(); flush_tlb(); } @@ -331,74 +335,176 @@ * Boy are these ugly, but we need to do the correct 16-bit arithmetic. * Gcc makes a mess of it, so we do it inline and use non-obvious calling * conventions.. + * FIXME: is VM86_UNKNOWN really the correct return code? */ -#define pushb(base, ptr, val) \ -__asm__ __volatile__( \ - "decw %w0\n\t" \ - "movb %2,0(%1,%0)" \ - : "=r" (ptr) \ - : "r" (base), "q" (val), "0" (ptr)) - -#define pushw(base, ptr, val) \ -__asm__ __volatile__( \ - "decw %w0\n\t" \ - "movb %h2,0(%1,%0)\n\t" \ - "decw %w0\n\t" \ - "movb %b2,0(%1,%0)" \ - : "=r" (ptr) \ - : "r" (base), "q" (val), "0" (ptr)) - -#define pushl(base, ptr, val) \ -__asm__ __volatile__( \ - "decw %w0\n\t" \ - "rorl $16,%2\n\t" \ - "movb %h2,0(%1,%0)\n\t" \ - "decw %w0\n\t" \ - "movb %b2,0(%1,%0)\n\t" \ - "decw %w0\n\t" \ - "rorl $16,%2\n\t" \ - "movb %h2,0(%1,%0)\n\t" \ - "decw %w0\n\t" \ - "movb %b2,0(%1,%0)" \ - : "=r" (ptr) \ - : "r" (base), "q" (val), "0" (ptr)) - -#define popb(base, ptr) \ -({ unsigned long __res; \ -__asm__ __volatile__( \ - "movb 0(%1,%0),%b2\n\t" \ - "incw %w0" \ - : "=r" (ptr), "=r" (base), "=q" (__res) \ - : "0" (ptr), "1" (base), "2" (0)); \ -__res; }) - -#define popw(base, ptr) \ -({ unsigned long __res; \ -__asm__ __volatile__( \ - "movb 0(%1,%0),%b2\n\t" \ - "incw %w0\n\t" \ - "movb 0(%1,%0),%h2\n\t" \ - "incw %w0" \ - : "=r" (ptr), "=r" (base), "=q" (__res) \ - : "0" (ptr), "1" (base), "2" (0)); \ -__res; }) - -#define popl(base, ptr) \ -({ unsigned long __res; \ -__asm__ __volatile__( \ - "movb 0(%1,%0),%b2\n\t" \ - "incw %w0\n\t" \ - "movb 0(%1,%0),%h2\n\t" \ - "incw %w0\n\t" \ - "rorl $16,%2\n\t" \ - "movb 0(%1,%0),%b2\n\t" \ - "incw %w0\n\t" \ - "movb 0(%1,%0),%h2\n\t" \ - "incw %w0\n\t" \ - "rorl $16,%2" \ - : "=r" (ptr), "=r" (base), "=q" (__res) \ - : "0" (ptr), "1" (base)); \ -__res; }) +#define pushb(base, ptr, val, regs) \ + do { \ + int err; \ + __asm__ __volatile__( \ + "decw %w0\n\t" \ + "1: movb %3,0(%2,%0)\n\t" \ + "xor %1,%1\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "3: movl $1,%1\n\t" \ + " jmp 2b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,3b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (err) \ + : "r" (base), "q" (val), "0" (ptr)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + } while(0) + +#define pushw(base, ptr, val, regs) \ + do { \ + int err; \ + __asm__ __volatile__( \ + "decw %w0\n\t" \ + "1: movb %h3,0(%2,%0)\n\t" \ + "decw %w0\n\t" \ + "2: movb %b3,0(%2,%0)\n\t" \ + "xor %1,%1\n\t" \ + "3:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "4: movl $1,%1\n\t" \ + " jmp 3b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,4b\n" \ + " .long 2b,4b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (err) \ + : "r" (base), "q" (val), "0" (ptr)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + } while(0) + +#define pushl(base, ptr, val, regs) \ + do { \ + int err; \ + __asm__ __volatile__( \ + "decw %w0\n\t" \ + "rorl $16,%3\n\t" \ + "1: movb %h3,0(%2,%0)\n\t" \ + "decw %w0\n\t" \ + "2: movb %b3,0(%2,%0)\n\t" \ + "decw %w0\n\t" \ + "rorl $16,%3\n\t" \ + "3: movb %h3,0(%2,%0)\n\t" \ + "decw %w0\n\t" \ + "4: movb %b3,0(%2,%0)\n\t" \ + "xor %1,%1\n\t" \ + "5:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "6: movl $1,%1\n\t" \ + " jmp 5b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,6b\n" \ + " .long 2b,6b\n" \ + " .long 3b,6b\n" \ + " .long 4b,6b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (err) \ + : "r" (base), "q" (val), "0" (ptr)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + } while(0) + +#define popb(base, ptr, regs) \ + ({ \ + unsigned long __res; \ + unsigned int err; \ + __asm__ __volatile__( \ + "1:movb 0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "xor %3,%3\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "3: movl $1,%3\n\t" \ + " jmp 2b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,3b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (base), "=q" (__res), \ + "=r" (err) \ + : "0" (ptr), "1" (base), "2" (0)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + __res; \ + }) + +#define popw(base, ptr, regs) \ + ({ \ + unsigned long __res; \ + unsigned int err; \ + __asm__ __volatile__( \ + "1:movb 0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "2:movb 0(%1,%0),%h2\n\t" \ + "incw %w0\n\t" \ + "xor %3,%3\n\t" \ + "3:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "4: movl $1,%3\n\t" \ + " jmp 3b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,4b\n" \ + " .long 2b,4b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (base), "=q" (__res), \ + "=r" (err) \ + : "0" (ptr), "1" (base), "2" (0)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + __res; \ + }) + +#define popl(base, ptr, regs) \ + ({ \ + unsigned long __res; \ + unsigned int err; \ + __asm__ __volatile__( \ + "1:movb 0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "2:movb 0(%1,%0),%h2\n\t" \ + "incw %w0\n\t" \ + "rorl $16,%2\n\t" \ + "3:movb 0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "4:movb 0(%1,%0),%h2\n\t" \ + "incw %w0\n\t" \ + "rorl $16,%2\n\t" \ + "xor %3,%3\n\t" \ + "5:\n" \ + ".section .fixup,\"ax\"\n\t" \ + "6: movl $1,%3\n\t" \ + " jmp 5b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,6b\n" \ + " .long 2b,6b\n" \ + " .long 3b,6b\n" \ + " .long 4b,6b\n" \ + ".previous" \ + : "=r" (ptr), "=r" (base), "=q" (__res), \ + "=r" (err) \ + : "0" (ptr), "1" (base), "2" (0)); \ + if (err) \ + return_to_32bit(regs, VM86_UNKNOWN); \ + __res; \ + }) static void do_int(struct kernel_vm86_regs *regs, int i, unsigned char * ssp, unsigned long sp) { @@ -415,9 +521,9 @@ goto cannot_handle; if ((segoffs >> 16) == BIOSSEG) goto cannot_handle; - pushw(ssp, sp, get_vflags(regs)); - pushw(ssp, sp, regs->cs); - pushw(ssp, sp, IP(regs)); + pushw(ssp, sp, get_vflags(regs), regs); + pushw(ssp, sp, regs->cs, regs); + pushw(ssp, sp, IP(regs), regs); regs->cs = segoffs >> 16; SP(regs) -= 6; IP(regs) = segoffs & 0xffff; @@ -459,7 +565,7 @@ #define CHECK_IF_IN_TRAP \ if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \ - pushw(ssp,sp,popw(ssp,sp) | TF_MASK); + pushw(ssp,sp,popw(ssp,sp, regs) | TF_MASK, regs); #define VM86_FAULT_RETURN \ if (VMPI.force_return_for_pic && (VEFLAGS & (IF_MASK | VIF_MASK))) \ return_to_32bit(regs, VM86_PICRETURN); \ @@ -470,17 +576,17 @@ sp = SP(regs); ip = IP(regs); - switch (popb(csp, ip)) { + switch (popb(csp, ip, regs)) { /* operand size override */ case 0x66: - switch (popb(csp, ip)) { + switch (popb(csp, ip, regs)) { /* pushfd */ case 0x9c: SP(regs) -= 4; IP(regs) += 2; - pushl(ssp, sp, get_vflags(regs)); + pushl(ssp, sp, get_vflags(regs), regs); VM86_FAULT_RETURN; /* popfd */ @@ -488,16 +594,16 @@ SP(regs) += 4; IP(regs) += 2; CHECK_IF_IN_TRAP - set_vflags_long(popl(ssp, sp), regs); + set_vflags_long(popl(ssp, sp, regs), regs); VM86_FAULT_RETURN; /* iretd */ case 0xcf: SP(regs) += 12; - IP(regs) = (unsigned short)popl(ssp, sp); - regs->cs = (unsigned short)popl(ssp, sp); + IP(regs) = (unsigned short)popl(ssp, sp, regs); + regs->cs = (unsigned short)popl(ssp, sp, regs); CHECK_IF_IN_TRAP - set_vflags_long(popl(ssp, sp), regs); + set_vflags_long(popl(ssp, sp, regs), regs); VM86_FAULT_RETURN; /* need this to avoid a fallthrough */ default: @@ -508,7 +614,7 @@ case 0x9c: SP(regs) -= 2; IP(regs)++; - pushw(ssp, sp, get_vflags(regs)); + pushw(ssp, sp, get_vflags(regs), regs); VM86_FAULT_RETURN; /* popf */ @@ -516,12 +622,12 @@ SP(regs) += 2; IP(regs)++; CHECK_IF_IN_TRAP - set_vflags_short(popw(ssp, sp), regs); + set_vflags_short(popw(ssp, sp, regs), regs); VM86_FAULT_RETURN; /* int xx */ case 0xcd: { - int intno=popb(csp, ip); + int intno=popb(csp, ip, regs); IP(regs) += 2; if (VMPI.vm86dbg_active) { if ( (1 << (intno &7)) & VMPI.vm86dbg_intxxtab[intno >> 3] ) @@ -534,10 +640,10 @@ /* iret */ case 0xcf: SP(regs) += 6; - IP(regs) = popw(ssp, sp); - regs->cs = popw(ssp, sp); + IP(regs) = popw(ssp, sp, regs); + regs->cs = popw(ssp, sp, regs); CHECK_IF_IN_TRAP - set_vflags_short(popw(ssp, sp), regs); + set_vflags_short(popw(ssp, sp, regs), regs); VM86_FAULT_RETURN; /* cli */ @@ -615,6 +721,14 @@ } read_unlock(&tasklist_lock); return ret; +} + +void release_x86_irqs(struct task_struct *task) +{ + int i; + for (i=3; i<16; i++) + if (vm86_irqs[i].tsk == task) + free_vm86_irq(i); } static inline void handle_irq_zombies(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/math-emu/fpu_system.h linux-2.5/arch/i386/math-emu/fpu_system.h --- linux-2.5.20/arch/i386/math-emu/fpu_system.h Mon Jun 3 02:44:46 2002 +++ linux-2.5/arch/i386/math-emu/fpu_system.h Mon Apr 15 02:24:50 2002 @@ -20,6 +20,8 @@ of the stack frame of math_emulate() */ #define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg +/* s is always from a cpu register, and the cpu does bounds checking + * during register load --> no further bounds checks needed */ #define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3]) #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/math-emu/reg_add_sub.c linux-2.5/arch/i386/math-emu/reg_add_sub.c --- linux-2.5.20/arch/i386/math-emu/reg_add_sub.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/arch/i386/math-emu/reg_add_sub.c Sun Mar 3 17:54:35 2002 @@ -140,7 +140,7 @@ FPU_REG const *a, *b; FPU_REG *dest; u_char taga, tagb, signa, signb, saved_sign, sign; - int diff, tag, expa, expb, deststnr; + int diff, tag = 0, expa, expb, deststnr; a = &st(0); taga = FPU_gettag0(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/math-emu/reg_compare.c linux-2.5/arch/i386/math-emu/reg_compare.c --- linux-2.5.20/arch/i386/math-emu/reg_compare.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/arch/i386/math-emu/reg_compare.c Sun Mar 3 17:54:35 2002 @@ -174,7 +174,7 @@ /* This function requires that st(0) is not empty */ int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag) { - int f, c; + int f = 0, c; c = compare(loaded_data, loaded_tag); @@ -216,7 +216,7 @@ static int compare_st_st(int nr) { - int f, c; + int f = 0, c; FPU_REG *st_ptr; if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) @@ -268,7 +268,7 @@ static int compare_u_st_st(int nr) { - int f, c; + int f = 0, c; FPU_REG *st_ptr; if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/math-emu/reg_divide.c linux-2.5/arch/i386/math-emu/reg_divide.c --- linux-2.5.20/arch/i386/math-emu/reg_divide.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/arch/i386/math-emu/reg_divide.c Sun Mar 3 17:54:35 2002 @@ -203,4 +203,5 @@ } #endif /* PARANOID */ + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/math-emu/reg_ld_str.c linux-2.5/arch/i386/math-emu/reg_ld_str.c --- linux-2.5.20/arch/i386/math-emu/reg_ld_str.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/arch/i386/math-emu/reg_ld_str.c Sun Mar 3 17:54:35 2002 @@ -632,7 +632,7 @@ /* Put a float into user memory */ int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single) { - long templ; + long templ = 0; unsigned long increment = 0; /* avoid gcc warnings */ int precision_loss; int exp; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/math-emu/reg_mul.c linux-2.5/arch/i386/math-emu/reg_mul.c --- linux-2.5.20/arch/i386/math-emu/reg_mul.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/arch/i386/math-emu/reg_mul.c Sun Mar 3 17:54:35 2002 @@ -128,4 +128,5 @@ } #endif /* PARANOID */ + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/mm/fault.c linux-2.5/arch/i386/mm/fault.c --- linux-2.5.20/arch/i386/mm/fault.c Mon Jun 3 02:44:38 2002 +++ linux-2.5/arch/i386/mm/fault.c Sat Mar 23 22:48:55 2002 @@ -27,8 +27,6 @@ extern void die(const char *,struct pt_regs *,long); -extern int console_loglevel; - /* * Ugly, ugly, but the goto's result in better assembly.. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/i386/mm/init.c linux-2.5/arch/i386/mm/init.c --- linux-2.5.20/arch/i386/mm/init.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/arch/i386/mm/init.c Fri May 31 02:30:36 2002 @@ -405,21 +405,26 @@ void __init mem_init(void) { +#ifdef CONFIG_HIGHMEM +# ifdef CONFIG_M686 extern int ppro_with_ram_bug(void); + int bad_ppro = ppro_with_ram_bug(); +# else + int bad_ppro = 0; +# endif +#endif int codesize, reservedpages, datasize, initsize; int tmp; - int bad_ppro; if (!mem_map) BUG(); - bad_ppro = ppro_with_ram_bug(); - #ifdef CONFIG_HIGHMEM highmem_start_page = mem_map + highstart_pfn; max_mapnr = num_physpages = highend_pfn; + num_mappedpages = max_low_pfn; #else - max_mapnr = num_physpages = max_low_pfn; + max_mapnr = num_mappedpages = num_physpages = max_low_pfn; #endif high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); @@ -461,7 +466,7 @@ datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", + printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), codesize >> 10, @@ -525,14 +530,14 @@ free_page(addr); totalram_pages++; } - printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); + printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { if (start < end) - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ia64/config.in linux-2.5/arch/ia64/config.in --- linux-2.5.20/arch/ia64/config.in Mon Jun 3 02:44:50 2002 +++ linux-2.5/arch/ia64/config.in Sat Jun 1 00:34:32 2002 @@ -195,9 +195,6 @@ fi # !HP_SIM -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in source drivers/char/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ia64/ia32/sys_ia32.c linux-2.5/arch/ia64/ia32/sys_ia32.c --- linux-2.5.20/arch/ia64/ia32/sys_ia32.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/arch/ia64/ia32/sys_ia32.c Sat Jun 1 00:34:32 2002 @@ -3796,12 +3796,15 @@ struct smb_mount_data *s = (struct smb_mount_data *)raw_data; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; + if (s32->version != SMB_MOUNT_OLDVERSION) + goto out; s->version = s32->version; s->mounted_uid = s32->mounted_uid; s->uid = s32->uid; s->gid = s32->gid; s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; +out: return raw_data; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ia64/kernel/irq.c linux-2.5/arch/ia64/kernel/irq.c --- linux-2.5.20/arch/ia64/kernel/irq.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/arch/ia64/kernel/irq.c Sat Jun 1 00:34:32 2002 @@ -189,7 +189,7 @@ seq_puts(p, "LOC: "); for (j = 0; j < smp_num_cpus; j++) seq_printf(p, "%10u ", - apic_timer_irqs[cpu_logical_map(j)]); + irq_stat[cpu_logical_map(j)].apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/m68k/amiga/config.c linux-2.5/arch/m68k/amiga/config.c --- linux-2.5.20/arch/m68k/amiga/config.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/arch/m68k/amiga/config.c Fri May 10 02:05:24 2002 @@ -70,11 +70,13 @@ extern char m68k_debug_device[]; static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); +#ifndef CONFIG_KEYBOARD_AMIGA /* amiga specific keyboard functions */ extern int amiga_keyb_init(void); extern int amiga_kbdrate (struct kbd_repeat *); extern int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode); +#endif /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); @@ -389,9 +391,11 @@ request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); mach_sched_init = amiga_sched_init; +#ifndef CONFIG_KEYBOARD_AMIGA mach_keyb_init = amiga_keyb_init; mach_kbdrate = amiga_kbdrate; mach_kbd_translate = amiga_kbd_translate; +#endif SYSRQ_KEY = 0xff; mach_init_IRQ = amiga_init_IRQ; mach_default_handler = &amiga_default_handler; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/mips/Config.help linux-2.5/arch/mips/Config.help --- linux-2.5.20/arch/mips/Config.help Mon Jun 3 02:44:50 2002 +++ linux-2.5/arch/mips/Config.help Tue Mar 26 11:45:21 2002 @@ -809,6 +809,24 @@ either a NEC Vr5432 or QED RM5231. Say Y here if you wish to build a kernel for this platform. +CONFIG_IT8172_REVC + Say Y here to support the older, Revision C version of the Integrated + Technology Express, Inc. ITE8172 SBC. Vendor page at + ; picture of the + board at . + +CONFIG_IT8172_SCR0 + Say Y here to support smart-card reader 0 (SCR0) on the Integrated + Technology Express, Inc. ITE8172 SBC. Vendor page at + ; picture of the + board at . + +CONFIG_IT8172_SCR1 + Say Y here to support smart-card reader 1 (SCR1) on the Integrated + Technology Express, Inc. ITE8172 SBC. Vendor page at + ; picture of the + board at . + CONFIG_MIPS_IVR This is an evaluation board built by Globespan to showcase thir iVR (Internet Video Recorder) design. It utilizes a QED RM5231 @@ -875,4 +893,10 @@ If you are using GDB for remote debugging over a serial port and would like kernel messages to be formatted into GDB $O packets so that GDB prints them as program output, say 'Y'. + +CONFIG_ARC_CONSOLE + Support for the PROM-based console on MIPS machines built according + to the Advanced Risc Computing specification, which is now (2001) + dead. These included boxes from Deskstation, Acer, Olivetti and + NEC. There is a history at . diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/mips/au1000/common/serial.c linux-2.5/arch/mips/au1000/common/serial.c --- linux-2.5.20/arch/mips/au1000/common/serial.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/arch/mips/au1000/common/serial.c Sun Mar 3 23:50:41 2002 @@ -433,7 +433,7 @@ if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); break_pressed = 0; goto ignore_char; } @@ -2606,7 +2606,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_AU1000_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/mips/baget/vacserial.c linux-2.5/arch/mips/baget/vacserial.c --- linux-2.5.20/arch/mips/baget/vacserial.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/arch/mips/baget/vacserial.c Sun Dec 30 13:55:22 2001 @@ -2373,7 +2373,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/mips/config.in linux-2.5/arch/mips/config.in --- linux-2.5.20/arch/mips/config.in Mon Jun 3 02:44:51 2002 +++ linux-2.5/arch/mips/config.in Tue Apr 23 10:31:37 2002 @@ -399,6 +399,8 @@ fi endmenu +source drivers/input/Config.in + source drivers/char/Config.in source drivers/media/Config.in @@ -484,7 +486,6 @@ fi source drivers/usb/Config.in -source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/mips/jazz/setup.c linux-2.5/arch/mips/jazz/setup.c --- linux-2.5.20/arch/mips/jazz/setup.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/arch/mips/jazz/setup.c Mon Apr 15 01:34:04 2002 @@ -62,6 +62,13 @@ static void __init jazz_irq_setup(void) { + if (!request_region(0x20, 0x20, "pic1")) + return; + if (!request_region(0xa0, 0x20, "pic2")) + { + release_region(0x20, 0x20); + return; + } set_except_vector(0, jazz_handle_int); r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, JAZZ_IE_ETHERNET | @@ -75,13 +82,33 @@ change_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1); /* set the clock to 100 Hz */ r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); - request_region(0x20, 0x20, "pic1"); - request_region(0xa0, 0x20, "pic2"); + i8259_setup_irq(2, &irq2); } void __init jazz_setup(void) { + if (!request_region(0x00,0x20,"dma1")) + return; + if (!request_region(0x40,0x20,"timer")) + { + release_region(0x00, 0x20); + return; + } + if (!request_region(0x80,0x10,"dma page reg")) + { + release_region(0x00, 0x20); + release_region(0x40, 0x20); + return; + } + if (!request_region(0xc0,0x20,"dma2")) + { + release_region(0x00, 0x20); + release_region(0x40, 0x20); + release_region(0x80, 0x10); + return; + } + add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K); add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M); add_wired_entry (0x01800017, 0x01000017, 0xe4000000, PM_4M); @@ -91,10 +118,7 @@ if (mips_machtype == MACH_MIPS_MAGNUM_4000) EISA_bus = 1; isa_slot_offset = 0xe3000000; - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); + board_time_init = jazz_time_init; /* The RTC is outside the port address space */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/mips64/Config.help linux-2.5/arch/mips64/Config.help --- linux-2.5.20/arch/mips64/Config.help Mon Jun 3 02:44:45 2002 +++ linux-2.5/arch/mips64/Config.help Sat Mar 23 22:50:27 2002 @@ -414,3 +414,9 @@ This allows you to run 32-bit Linux/ELF binaries on your Ultra. Everybody wants this; say Y. +CONFIG_ARC_CONSOLE + Support for the PROM-based console on MIPS machines built according + to the Advanced Risc Computing specification, which is now (2001) + dead. These included boxes from Deskstation, Acer, Olivetti and + NEC. There is a history at . + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/mips64/config.in linux-2.5/arch/mips64/config.in --- linux-2.5.20/arch/mips64/config.in Mon Jun 3 02:44:42 2002 +++ linux-2.5/arch/mips64/config.in Tue Apr 23 10:31:37 2002 @@ -192,6 +192,8 @@ fi endmenu +source drivers/input/Config.in + source drivers/char/Config.in #source drivers/misc/Config.in @@ -233,7 +235,6 @@ fi source drivers/usb/Config.in -source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/mips64/kernel/ioctl32.c linux-2.5/arch/mips64/kernel/ioctl32.c --- linux-2.5.20/arch/mips64/kernel/ioctl32.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/arch/mips64/kernel/ioctl32.c Wed May 1 14:33:38 2002 @@ -732,12 +732,15 @@ IOCTL32_HANDLER(HDIO_GETGEO, hdio_getgeo), /* hdreg.h ioctls */ IOCTL32_HANDLER(HDIO_GET_UNMASKINTR, hdio_ioctl_trans), IOCTL32_HANDLER(HDIO_GET_MULTCOUNT, hdio_ioctl_trans), + // HDIO_OBSOLETE_IDENTITY IOCTL32_HANDLER(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans), IOCTL32_HANDLER(HDIO_GET_32BIT, hdio_ioctl_trans), IOCTL32_HANDLER(HDIO_GET_NOWERR, hdio_ioctl_trans), IOCTL32_HANDLER(HDIO_GET_DMA, hdio_ioctl_trans), IOCTL32_HANDLER(HDIO_GET_NICE, hdio_ioctl_trans), IOCTL32_DEFAULT(HDIO_GET_IDENTITY), + // HDIO_TRISTATE_HWIF /* not implemented */ + // HDIO_DRIVE_TASK /* To do, need specs */ IOCTL32_DEFAULT(HDIO_DRIVE_CMD), IOCTL32_DEFAULT(HDIO_SET_MULTCOUNT), IOCTL32_DEFAULT(HDIO_SET_UNMASKINTR), diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/parisc/config.in linux-2.5/arch/parisc/config.in --- linux-2.5.20/arch/parisc/config.in Mon Jun 3 02:44:53 2002 +++ linux-2.5/arch/parisc/config.in Thu Feb 14 02:57:57 2002 @@ -162,6 +162,7 @@ endmenu fi +source drivers/input/Config.in source drivers/char/Config.in source fs/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/parisc/kernel/pdc_cons.c linux-2.5/arch/parisc/kernel/pdc_cons.c --- linux-2.5.20/arch/parisc/kernel/pdc_cons.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/arch/parisc/kernel/pdc_cons.c Mon Feb 25 18:54:26 2002 @@ -137,9 +137,8 @@ --pdc_console_initialized; #ifdef CONFIG_VT_CONSOLE - schedule_console_callback(); + schedule_task(&vt_cons->vt_tq); #endif - unregister_console(&pdc_cons); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/parisc/kernel/traps.c linux-2.5/arch/parisc/kernel/traps.c --- linux-2.5.20/arch/parisc/kernel/traps.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/arch/parisc/kernel/traps.c Thu Dec 27 16:32:30 2001 @@ -43,7 +43,6 @@ static inline void console_verbose(void) { - extern int console_loglevel; console_loglevel = 15; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ppc/4xx_io/serial_sicc.c linux-2.5/arch/ppc/4xx_io/serial_sicc.c --- linux-2.5.20/arch/ppc/4xx_io/serial_sicc.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/arch/ppc/4xx_io/serial_sicc.c Sun Mar 3 23:50:41 2002 @@ -462,7 +462,7 @@ #ifdef SUPPORT_SYSRQ if (info->sysrq) { if (ch && time_before(jiffies, info->sysrq)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); info->sysrq = 0; goto ignore_char; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ppc/8260_io/uart.c linux-2.5/arch/ppc/8260_io/uart.c --- linux-2.5.20/arch/ppc/8260_io/uart.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/arch/ppc/8260_io/uart.c Sat Jun 1 00:34:33 2002 @@ -2534,7 +2534,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_8xx_open; serial_driver.close = rs_8xx_close; serial_driver.write = rs_8xx_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ppc/8xx_io/uart.c linux-2.5/arch/ppc/8xx_io/uart.c --- linux-2.5.20/arch/ppc/8xx_io/uart.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/arch/ppc/8xx_io/uart.c Sat Jun 1 00:34:33 2002 @@ -481,7 +481,7 @@ if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); break_pressed = 0; goto ignore_char; } else @@ -2582,7 +2582,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_8xx_open; serial_driver.close = rs_8xx_close; serial_driver.write = rs_8xx_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ppc/Config.help linux-2.5/arch/ppc/Config.help --- linux-2.5.20/arch/ppc/Config.help Mon Jun 3 02:44:44 2002 +++ linux-2.5/arch/ppc/Config.help Sat Jun 1 00:34:33 2002 @@ -247,6 +247,31 @@ includes a server that supports the frame buffer device directly (XF68_FBDev). +CONFIG_VIODASD + If you are running on an iSeries system and you want to use + virtual disks created and managed by OS/400, say Y. + +CONFIG_VIODASD_IDE + This causes the iSeries virtual disks to look like IDE disks. + If you have programs or utilities that only support certain + kinds of disks, this option will cause iSeries virtual disks + to pretend to be IDE disks, which may satisfy the program. + +CONFIG_VIOCD + If you are running Linux on an IBM iSeries system and you want to + read a CD drive owned by OS/400, say Y here. + +CONFIG_VIOTAPE + If you are running Linux on an iSeries system and you want Linux + to read and/or write a tape drive owned by OS/400, say Y here. + +CONFIG_PMAC_APM_EMU + This driver provides an emulated /dev/apm_bios and /proc/apm. The + first one is mostly intended for XFree to sleep & wakeup properly, + the second one provides some battery information to allow existing + APM utilities to work. It provides less useful information than + tools specifically designed for PowerBooks or /proc/pmu/battery_x. + CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or any other SCSI device under Linux, say Y and make sure that you know diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ppc/amiga/config.c linux-2.5/arch/ppc/amiga/config.c --- linux-2.5.20/arch/ppc/amiga/config.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/arch/ppc/amiga/config.c Thu Feb 14 02:57:57 2002 @@ -76,9 +76,11 @@ extern char m68k_debug_device[]; static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); +#ifndef CONFIG_KEYBOARD_AMIGA /* amiga specific keyboard functions */ extern int amiga_keyb_init(void); extern int amiga_kbdrate (struct kbd_repeat *); +#endif /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); @@ -407,8 +409,10 @@ request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); mach_sched_init = amiga_sched_init; +#ifndef CONFIG_KEYBOARD_AMIGA mach_keyb_init = amiga_keyb_init; mach_kbdrate = amiga_kbdrate; +#endif mach_init_IRQ = amiga_init_IRQ; #ifndef CONFIG_APUS mach_default_handler = &amiga_default_handler; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ppc/xmon/start.c linux-2.5/arch/ppc/xmon/start.c --- linux-2.5.20/arch/ppc/xmon/start.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/arch/ppc/xmon/start.c Fri May 10 02:05:25 2002 @@ -98,7 +98,7 @@ #ifdef CONFIG_MAGIC_SYSRQ static void sysrq_handle_xmon(int key, struct pt_regs *regs, - struct kbd_struct *kbd, struct tty_struct *tty) + struct tty_struct *tty) { xmon(regs); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ppc64/kernel/chrp_setup.c linux-2.5/arch/ppc64/kernel/chrp_setup.c --- linux-2.5.20/arch/ppc64/kernel/chrp_setup.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/arch/ppc64/kernel/chrp_setup.c Fri May 3 12:57:29 2002 @@ -121,12 +121,19 @@ } void __init chrp_request_regions(void) { - request_region(0x20,0x20,"pic1"); - request_region(0xa0,0x20,"pic2"); - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); + if (!request_region(0x20,0x20,"pic1")) + panic("chrp: Unable to request region 0x20\n"); + if (!request_region(0xa0,0x20,"pic2")) + panic("chrp: Unable to request region 0xa0\n"); + if (!request_region(0x00,0x20,"dma1")) + panic("chrp: Unable to request region 0x00\n"); + if (!request_region(0x40,0x20,"timer")) + panic("chrp: Unable to request region 0x40\n"); + if (!request_region(0x80,0x10,"dma page reg")) + panic("chrp: Unable to request region 0x80\n"); + if (!request_region(0xc0,0x20,"dma2")) + panic("chrp: Unable to request region 0xc0\n"); + return; } void __init diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ppc64/kernel/ioctl32.c linux-2.5/arch/ppc64/kernel/ioctl32.c --- linux-2.5.20/arch/ppc64/kernel/ioctl32.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/arch/ppc64/kernel/ioctl32.c Mon Jun 3 17:10:19 2002 @@ -1794,6 +1794,8 @@ static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) { + struct tty_struct *tty = (struct tty_struct *) file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct consolefontdesc cfdarg; struct console_font_op op; int i, perm; @@ -1816,7 +1818,7 @@ op.height = cfdarg.charheight; op.charcount = cfdarg.charcount; op.data = cfdarg.chardata; - return con_font_op(fg_console, &op); + return con_font_op(vc->display_fg->vc_cons[fg_console], &op); case GIO_FONTX: if (!cfdarg.chardata) return 0; @@ -1826,7 +1828,7 @@ op.height = cfdarg.charheight; op.charcount = cfdarg.charcount; op.data = cfdarg.chardata; - i = con_font_op(fg_console, &op); + i = con_font_op(vc->display_fg->vc_cons[fg_console], &op); if (i) return i; cfdarg.charheight = op.height; @@ -1849,9 +1851,10 @@ static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) { + struct tty_struct *tty = (struct tty_struct *) file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct console_font_op op; int perm = vt_check(file), i; - struct vt_struct *vt; if (perm < 0) return perm; @@ -1861,8 +1864,7 @@ return -EPERM; op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data); op.flags |= KD_FONT_FLAG_OLD; - vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data; - i = con_font_op(vt->vc_num, &op); + i = con_font_op(vc, &op); if (i) return i; ((struct console_font_op32 *)&op)->data = (unsigned long)op.data; if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32))) @@ -1870,6 +1872,33 @@ return 0; } +struct unimapdesc32 { + unsigned short entry_ct; + u32 entries; +}; + +static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) +{ + struct tty_struct *tty = (struct tty_struct *) file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; + struct unimapdesc32 tmp; + int perm = vt_check(file); + + if (perm < 0) return perm; + if (copy_from_user(&tmp, user_ud, sizeof tmp)) + return -EFAULT; + switch (cmd) { + case PIO_UNIMAP: + if (!perm) return -EPERM; + return con_set_unimap(vc->display_fg->vc_cons[fg_console], tmp.entry_ct, (struct unipair *)A(tmp.entries)); + case GIO_UNIMAP: + return con_get_unimap(vc->display_fg->vc_cons[fg_console], tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); + } + return 0; +} +#endif /* CONFIG_VT */ + +#ifdef CONFIG_FB struct fb_fix_screeninfo32 { char id[16]; /* identification string eg "TT Builtin" */ unsigned int smem_start; /* Start of frame buffer mem */ @@ -1994,29 +2023,8 @@ return err; } -struct unimapdesc32 { - unsigned short entry_ct; - u32 entries; -}; +#endif /* CONFIG_FB */ -static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) -{ - struct unimapdesc32 tmp; - int perm = vt_check(file); - - if (perm < 0) return perm; - if (copy_from_user(&tmp, user_ud, sizeof tmp)) - return -EFAULT; - switch (cmd) { - case PIO_UNIMAP: - if (!perm) return -EPERM; - return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries)); - case GIO_UNIMAP: - return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); - } - return 0; -} -#endif /* CONFIG_VT */ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); @@ -4465,6 +4473,8 @@ HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl), HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl), HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl), +#endif +#ifdef CONFIG_FB HANDLE_IOCTL(FBIOGET_FSCREENINFO, do_fbioget_fscreeninfo_ioctl), HANDLE_IOCTL(FBIOGETCMAP, do_fbiogetcmap_ioctl), HANDLE_IOCTL(FBIOPUTCMAP, do_fbioputcmap_ioctl), diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ppc64/kernel/sys_ppc32.c linux-2.5/arch/ppc64/kernel/sys_ppc32.c --- linux-2.5.20/arch/ppc64/kernel/sys_ppc32.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/arch/ppc64/kernel/sys_ppc32.c Mon Jun 3 17:10:19 2002 @@ -398,12 +398,15 @@ struct smb_mount_data *s = (struct smb_mount_data *)raw_data; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; + if (s32->version != SMB_MOUNT_OLDVERSION) + goto out; s->version = s32->version; s->mounted_uid = s32->mounted_uid; s->uid = s32->uid; s->gid = s32->gid; s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; +out: return raw_data; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/ppc64/xmon/start.c linux-2.5/arch/ppc64/xmon/start.c --- linux-2.5.20/arch/ppc64/xmon/start.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/arch/ppc64/xmon/start.c Sun Apr 14 17:12:08 2002 @@ -52,7 +52,7 @@ } #endif -static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, struct kbd_struct *kbd, struct tty_struct *tty) +static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { xmon(pt_regs); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/s390/Config.help linux-2.5/arch/s390/Config.help --- linux-2.5.20/arch/s390/Config.help Mon Jun 3 02:44:42 2002 +++ linux-2.5/arch/s390/Config.help Sat Apr 27 00:11:03 2002 @@ -155,7 +155,10 @@ IPL device. CONFIG_IPL_TAPE - Select this option if you want to IPL the image from a Tape. + Select "tape" if you want to IPL the image from a Tape. + + Select "vm_reader" if you are running under VM/ESA and want + to IPL the image from the emulated card reader. CONFIG_FAST_IRQ Select this option in order to get the interrupts processed faster @@ -168,4 +171,21 @@ Say Y to print all process fault locations to the console. This is a debugging option; you probably do not want to set it unless you are an S390 port maintainer. + +CONFIG_PFAULT + Select this option, if you want to use PFAULT pseudo page fault + handling under VM. If running native or in LPAR, this option + has no effect. If your VM does not support PFAULT, PAGEEX + pseudo page fault handling will be used. + Note that VM 4.2 supports PFAULT but has a bug in its + implementation that causes some problems. + Everybody who wants to run Linux under VM != VM4.2 should select + this option. + +CONFIG_SHARED_KERNEL + Select this option, if you want to share the text segment of the + Linux kernel between different VM guests. This reduces memory + usage with lots of guests but greatly increases kernel size. + You should only select this option if you know what you are + doing and want to exploit this feature. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/s390x/kernel/linux32.c linux-2.5/arch/s390x/kernel/linux32.c --- linux-2.5.20/arch/s390x/kernel/linux32.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/arch/s390x/kernel/linux32.c Sat Jun 1 00:34:33 2002 @@ -1524,12 +1524,15 @@ struct smb_mount_data *s = (struct smb_mount_data *)raw_data; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; + if (s32->version != SMB_MOUNT_OLDVERSION) + goto out; s->version = s32->version; s->mounted_uid = low2highuid(s32->mounted_uid); s->uid = low2highuid(s32->uid); s->gid = low2highgid(s32->gid); s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; +out: return raw_data; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sh/config.in linux-2.5/arch/sh/config.in --- linux-2.5.20/arch/sh/config.in Mon Jun 3 02:44:50 2002 +++ linux-2.5/arch/sh/config.in Sat Mar 23 22:50:31 2002 @@ -257,15 +257,12 @@ fi endmenu -# -# input before char - char/joystick depends on it. As does USB. -# -source drivers/input/Config.in - if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then source drivers/maple/Config.in fi +source drivers/input/Config.in + mainmenu_option next_comment comment 'Character devices' @@ -294,20 +291,6 @@ "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then bool 'Heartbeat LED' CONFIG_HEARTBEAT fi - -if [ "$CONFIG_SH_DREAMCAST" = "y" -a "$CONFIG_MAPLE" != "n" ]; then - mainmenu_option next_comment - comment 'Maple Bus input peripherals' - if [ "$CONFIG_INPUT" != "n" ]; then - dep_tristate ' Maple Bus keyboard support' CONFIG_MAPLE_KEYBOARD $CONFIG_INPUT - dep_tristate ' Maple Bus mouse support' CONFIG_MAPLE_MOUSE $CONFIG_INPUT - else - comment 'Input core support is required for Maple input peripherals' - fi - endmenu -fi - -source drivers/char/joystick/Config.in if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sh/kernel/hd64465_gpio.c linux-2.5/arch/sh/kernel/hd64465_gpio.c --- linux-2.5.20/arch/sh/kernel/hd64465_gpio.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/arch/sh/kernel/hd64465_gpio.c Mon Apr 15 01:34:04 2002 @@ -165,10 +165,18 @@ static int __init hd64465_gpio_init(void) { - /* TODO: check return values */ - request_region(HD64465_REG_GPACR, 0x1000, MODNAME); - request_irq(HD64465_IRQ_GPIO, hd64465_gpio_interrupt, + int err; + + if (!request_region(HD64465_REG_GPACR, 0x1000, MODNAME)) + return -EIO; + err=request_irq(HD64465_IRQ_GPIO, hd64465_gpio_interrupt, SA_INTERRUPT, MODNAME, 0); + if (err) + { + printk(KERN_ERR"HD64465: Unable to get irq %d.\n", HD64465_IRQ_GPIO); + release_region(HD64465_REG_GPACR, 0x1000); + return err; + } printk("HD64465 GPIO layer on irq %d\n", HD64465_IRQ_GPIO); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sh/kernel/pci-sh7751.c linux-2.5/arch/sh/kernel/pci-sh7751.c --- linux-2.5.20/arch/sh/kernel/pci-sh7751.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/arch/sh/kernel/pci-sh7751.c Mon Apr 15 01:34:04 2002 @@ -216,7 +216,8 @@ if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) { outl (tmp, PCI_REG(SH7751_PCIPAR)); printk(KERN_INFO "PCI: Using configuration type 1\n"); - request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1"); + if (!request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1")) + return NULL; return &pci_direct_conf1; } outl (tmp, PCI_REG(SH7751_PCIPAR)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc/defconfig linux-2.5/arch/sparc/defconfig --- linux-2.5.20/arch/sparc/defconfig Mon Jun 3 02:44:52 2002 +++ linux-2.5/arch/sparc/defconfig Fri May 3 12:57:29 2002 @@ -378,6 +378,7 @@ # CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_874 is not set # CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc/kernel/sunos_ioctl.c linux-2.5/arch/sparc/kernel/sunos_ioctl.c --- linux-2.5.20/arch/sparc/kernel/sunos_ioctl.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/arch/sparc/kernel/sunos_ioctl.c Mon Jan 14 22:39:45 2002 @@ -39,8 +39,12 @@ { int ret = -EBADF; - if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) + read_lock(¤t->files->file_lock); + if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) { + read_unlock(¤t->files->file_lock); goto out; + } + read_unlock(¤t->files->file_lock); /* First handle an easy compat. case for tty ldisc. */ if(cmd == TIOCSETD) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc64/config.in linux-2.5/arch/sparc64/config.in --- linux-2.5.20/arch/sparc64/config.in Mon Jun 3 02:44:45 2002 +++ linux-2.5/arch/sparc64/config.in Wed May 1 20:36:25 2002 @@ -292,5 +292,3 @@ fi endmenu - -source lib/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc64/defconfig linux-2.5/arch/sparc64/defconfig --- linux-2.5.20/arch/sparc64/defconfig Mon Jun 3 02:44:46 2002 +++ linux-2.5/arch/sparc64/defconfig Sat May 25 19:51:59 2002 @@ -288,8 +288,6 @@ CONFIG_IDEDMA_PCI_AUTO=y CONFIG_IDEDMA_ONLYDISK=y CONFIG_BLK_DEV_IDEDMA=y -# CONFIG_BLK_DEV_IDE_TCQ is not set -# CONFIG_BLK_DEV_IDE_TCQ_DEFAULT is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_AEC62XX_TUNING is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc64/kernel/ioctl32.c linux-2.5/arch/sparc64/kernel/ioctl32.c --- linux-2.5.20/arch/sparc64/kernel/ioctl32.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/arch/sparc64/kernel/ioctl32.c Fri May 10 02:05:25 2002 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.136 2002/01/14 09:49:52 davem Exp $ +/* $Id: ioctl32.c,v 1.2 2002/03/22 20:13:58 jsimmons Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -872,6 +872,7 @@ return err ? -EFAULT : 0; } +#ifdef CONFIG_FB struct fbcmap32 { int index; /* first element (0 origin) */ int count; @@ -1111,6 +1112,7 @@ if (cmap.transp) kfree(cmap.transp); return err; } +#endif /* CONFIG_FB */ static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { @@ -2040,6 +2042,7 @@ return err; } +#ifdef CONFIG_VT extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int vt_check(struct file *file) @@ -2074,6 +2077,8 @@ static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) { + struct tty_struct *tty = (struct tty_struct *)file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct consolefontdesc cfdarg; struct console_font_op op; int i, perm; @@ -2096,7 +2101,7 @@ op.height = cfdarg.charheight; op.charcount = cfdarg.charcount; op.data = cfdarg.chardata; - return con_font_op(fg_console, &op); + return con_font_op(vc->display_fg->vc_cons[fg_console].d, &op); case GIO_FONTX: if (!cfdarg.chardata) return 0; @@ -2106,7 +2111,7 @@ op.height = cfdarg.charheight; op.charcount = cfdarg.charcount; op.data = cfdarg.chardata; - i = con_font_op(fg_console, &op); + i = con_font_op(vc->display_fg->vc_cons[fg_console], &op); if (i) return i; cfdarg.charheight = op.height; @@ -2129,6 +2134,8 @@ static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) { + struct tty_struct *tty = (struct tty_struct *)file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct console_font_op op; int perm = vt_check(file), i; struct vt_struct *vt; @@ -2141,8 +2148,7 @@ return -EPERM; op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data); op.flags |= KD_FONT_FLAG_OLD; - vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data; - i = con_font_op(vt->vc_num, &op); + i = con_font_op(vc, &op); if (i) return i; ((struct console_font_op32 *)&op)->data = (unsigned long)op.data; if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32))) @@ -2157,6 +2163,8 @@ static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) { + struct tty_struct *tty = (struct tty_struct *)file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct unimapdesc32 tmp; int perm = vt_check(file); @@ -2166,12 +2174,13 @@ switch (cmd) { case PIO_UNIMAP: if (!perm) return -EPERM; - return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries)); + return con_set_unimap(vc->display_fg->vc_cons[fg_console], tmp.entry_ct, (struct unipair *)A(tmp.entries)); case GIO_UNIMAP: - return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); + return con_get_unimap(vc->display_fg->vc_cons[fg_console], tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); } return 0; } +#endif /* CONFIG_VT */ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc64/kernel/irq.c linux-2.5/arch/sparc64/kernel/irq.c --- linux-2.5.20/arch/sparc64/kernel/irq.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/arch/sparc64/kernel/irq.c Thu Apr 4 05:19:50 2002 @@ -830,6 +830,11 @@ kbd_pt_regs = regs; #endif +#ifdef CONFIG_PCI + if (irq == 9) + kbd_pt_regs = regs; +#endif + /* Sliiiick... */ #ifndef CONFIG_SMP bp = ((irq != 0) ? diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc64/kernel/pci_common.c linux-2.5/arch/sparc64/kernel/pci_common.c --- linux-2.5.20/arch/sparc64/kernel/pci_common.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/arch/sparc64/kernel/pci_common.c Thu Apr 4 05:19:50 2002 @@ -718,6 +718,20 @@ return; } + /* If this is an empty EBUS device, sometimes OBP fails to + * give it a valid fully specified interrupts property. + * The EBUS hooked up to SunHME on PCI I/O boards of + * Ex000 systems is one such case. + * + * The interrupt is not important so just ignore it. + */ + if (pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_EBUS && + !prom_getchild(prom_node)) { + pdev->irq = 0; + return; + } + err = prom_getproperty(prom_node, "interrupts", (char *)&prom_irq, sizeof(prom_irq)); if (err == 0 || err == -1) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc64/kernel/rtrap.S linux-2.5/arch/sparc64/kernel/rtrap.S --- linux-2.5.20/arch/sparc64/kernel/rtrap.S Mon Jun 3 02:44:49 2002 +++ linux-2.5/arch/sparc64/kernel/rtrap.S Fri May 3 12:57:29 2002 @@ -41,7 +41,8 @@ __handle_user_windows: call fault_in_user_windows wrpr %g0, RTRAP_PSTATE, %pstate - wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate + ba,pt %xcc, __handle_user_windows_continue + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate /* Redo sched+sig checks */ ldx [%g6 + TI_FLAGS], %l0 andcc %l0, _TIF_NEED_RESCHED, %g0 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc64/kernel/smp.c linux-2.5/arch/sparc64/kernel/smp.c --- linux-2.5.20/arch/sparc64/kernel/smp.c Mon Jun 3 02:44:37 2002 +++ linux-2.5/arch/sparc64/kernel/smp.c Fri May 17 00:17:52 2002 @@ -696,14 +696,14 @@ if (page->mapping != NULL) data0 |= ((u64)1 << 32); spitfire_xcall_deliver(data0, - __pa(page->virtual), - (u64) page->virtual, - mask); + __pa(page->virtual), + (u64) page->virtual, + mask); } else { data0 = ((u64)&xcall_flush_dcache_page_cheetah); cheetah_xcall_deliver(data0, - __pa(page->virtual), - 0, mask); + __pa(page->virtual), + 0, mask); } #ifdef CONFIG_DEBUG_DCFLUSH atomic_inc(&dcpage_flushes_xcall); @@ -831,23 +831,25 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - u32 ctx = CTX_HWBITS(mm->context); - int cpu = smp_processor_id(); + { + u32 ctx = CTX_HWBITS(mm->context); + int cpu = smp_processor_id(); - start &= PAGE_MASK; - end = PAGE_ALIGN(end); + start &= PAGE_MASK; + end = PAGE_ALIGN(end); - if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) { - mm->cpu_vm_mask = (1UL << cpu); - goto local_flush_and_out; - } + if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) { + mm->cpu_vm_mask = (1UL << cpu); + goto local_flush_and_out; + } - smp_cross_call_masked(&xcall_flush_tlb_range, - ctx, start, end, - mm->cpu_vm_mask); + smp_cross_call_masked(&xcall_flush_tlb_range, + ctx, start, end, + mm->cpu_vm_mask); - local_flush_and_out: - __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start)); + local_flush_and_out: + __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start)); + } } void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc64/kernel/sunos_ioctl32.c linux-2.5/arch/sparc64/kernel/sunos_ioctl32.c --- linux-2.5.20/arch/sparc64/kernel/sunos_ioctl32.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/arch/sparc64/kernel/sunos_ioctl32.c Mon Jan 14 22:39:45 2002 @@ -100,8 +100,12 @@ if(fd >= SUNOS_NR_OPEN) goto out; - if(!fcheck(fd)) + read_lock(¤t->files->file_lock); + if(!fcheck(fd)) { + read_unlock(¤t->files->file_lock); goto out; + } + read_unlock(¤t->files->file_lock); if(cmd == TIOCSETD) { mm_segment_t old_fs = get_fs(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc64/kernel/sys_sparc32.c linux-2.5/arch/sparc64/kernel/sys_sparc32.c --- linux-2.5.20/arch/sparc64/kernel/sys_sparc32.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/arch/sparc64/kernel/sys_sparc32.c Sat Jun 1 00:34:33 2002 @@ -1527,6 +1527,8 @@ struct smb_mount_data news, *s = &news; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; + if (s32->version != SMB_MOUNT_OLDVERSION) + goto out; s->version = s32->version; s->mounted_uid = low2highuid(s32->mounted_uid); s->uid = low2highuid(s32->uid); @@ -1534,6 +1536,7 @@ s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; memcpy(raw_data, s, sizeof(struct smb_mount_data)); +out: return raw_data; } @@ -3904,27 +3907,6 @@ set_fs(old_fs); if (offset && put_user(of, offset)) - return -EFAULT; - - return ret; -} - -extern asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count); - -asmlinkage int sys32_sendfile64(int out_fd, int in_fd, __kernel_loff_t32 *offset, s32 count) -{ - mm_segment_t old_fs = get_fs(); - int ret; - loff_t lof; - - if (offset && get_user(lof, offset)) - return -EFAULT; - - set_fs(KERNEL_DS); - ret = sys_sendfile64(out_fd, in_fd, offset ? &lof : NULL, count); - set_fs(old_fs); - - if (offset && put_user(lof, offset)) return -EFAULT; return ret; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/sparc64/solaris/timod.c linux-2.5/arch/sparc64/solaris/timod.c --- linux-2.5.20/arch/sparc64/solaris/timod.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/arch/sparc64/solaris/timod.c Thu Apr 4 05:19:50 2002 @@ -149,7 +149,9 @@ struct socket *sock; SOLD("wakeing socket"); + read_lock(¤t->files->file_lock); sock = SOCKET_I(current->files->fd[fd]->f_dentry->d_inode); + read_unlock(¤t->files->file_lock); wake_up_interruptible(&sock->wait); read_lock(&sock->sk->callback_lock); if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) @@ -163,7 +165,9 @@ struct sol_socket_struct *sock; SOLD("queuing primsg"); + read_lock(¤t->files->file_lock); sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + read_unlock(¤t->files->file_lock); it->next = sock->pfirst; sock->pfirst = it; if (!sock->plast) @@ -177,7 +181,9 @@ struct sol_socket_struct *sock; SOLD("queuing primsg at end"); + read_lock(¤t->files->file_lock); sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + read_unlock(¤t->files->file_lock); it->next = NULL; if (sock->plast) sock->plast->next = it; @@ -355,7 +361,11 @@ (int (*)(int, unsigned long *))SYS(socketcall); int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) = (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto); - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (!filp) + return -EBADF; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLD("entry"); @@ -636,7 +646,11 @@ SOLD("entry"); SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p)); - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (!filp) + return -EBADF; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL)); @@ -847,7 +861,9 @@ lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); if(!filp) goto out; ino = filp->f_dentry->d_inode; @@ -914,7 +930,9 @@ lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); if(!filp) goto out; ino = filp->f_dentry->d_inode; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/x86_64/ia32/ia32_ioctl.c linux-2.5/arch/x86_64/ia32/ia32_ioctl.c --- linux-2.5.20/arch/x86_64/ia32/ia32_ioctl.c Mon Jun 3 02:44:37 2002 +++ linux-2.5/arch/x86_64/ia32/ia32_ioctl.c Fri May 10 00:31:48 2002 @@ -1629,6 +1629,7 @@ return err; } +#ifdef CONFIG_VT extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int vt_check(struct file *file) @@ -1663,6 +1664,8 @@ static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) { + struct tty_struct *tty = (struct tty_struct *)file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct consolefontdesc cfdarg; struct console_font_op op; int i, perm; @@ -1685,7 +1688,7 @@ op.height = cfdarg.charheight; op.charcount = cfdarg.charcount; op.data = cfdarg.chardata; - return con_font_op(fg_console, &op); + return con_font_op(vc->display_fg->vc_cons[fg_console], &op); case GIO_FONTX: if (!cfdarg.chardata) return 0; @@ -1695,7 +1698,7 @@ op.height = cfdarg.charheight; op.charcount = cfdarg.charcount; op.data = cfdarg.chardata; - i = con_font_op(fg_console, &op); + i = con_font_op(vc->display_fg->vc_cons[fg_console], &op); if (i) return i; cfdarg.charheight = op.height; @@ -1718,9 +1721,10 @@ static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) { + struct tty_struct *tty = (struct tty_struct *)file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct console_font_op op; int perm = vt_check(file), i; - struct vt_struct *vt; if (perm < 0) return perm; @@ -1730,8 +1734,7 @@ return -EPERM; op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data); op.flags |= KD_FONT_FLAG_OLD; - vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data; - i = con_font_op(vt->vc_num, &op); + i = con_font_op(vc, &op); if (i) return i; ((struct console_font_op32 *)&op)->data = (unsigned long)op.data; if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32))) @@ -1746,6 +1749,8 @@ static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) { + struct tty_struct *tty = (struct tty_struct *)file->private_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; struct unimapdesc32 tmp; int perm = vt_check(file); @@ -1755,12 +1760,13 @@ switch (cmd) { case PIO_UNIMAP: if (!perm) return -EPERM; - return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries)); + return con_set_unimap(vc->display_fg->vc_cons[fg_console], tmp.entry_ct, (struct unipair *)A(tmp.entries)); case GIO_UNIMAP: - return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); + return con_get_unimap(vc->display_fg->vc_cons[fg_console], tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); } return 0; } +#endif /* CONFIG_VT */ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/x86_64/kernel/apic.c linux-2.5/arch/x86_64/kernel/apic.c --- linux-2.5.20/arch/x86_64/kernel/apic.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/arch/x86_64/kernel/apic.c Sun May 26 01:40:46 2002 @@ -1044,7 +1044,6 @@ * [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ -unsigned int apic_timer_irqs [NR_CPUS]; void smp_apic_timer_interrupt(struct pt_regs *regs) { @@ -1053,7 +1052,7 @@ /* * the NMI deadlock-detector uses this. */ - apic_timer_irqs[cpu]++; + cpu_pda[cpu].apic_timer_irqs++; /* * NOTE! We'd better ACK the irq immediately, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/x86_64/kernel/irq.c linux-2.5/arch/x86_64/kernel/irq.c --- linux-2.5.20/arch/x86_64/kernel/irq.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/arch/x86_64/kernel/irq.c Sun May 26 01:40:46 2002 @@ -168,7 +168,7 @@ #if CONFIG_X86_LOCAL_APIC seq_printf(p, "LOC: "); for (j = 0; j < smp_num_cpus; j++) - seq_printf(p, "%10u ", apic_timer_irqs[cpu_logical_map(j)]); + seq_printf(p, "%10u ", cpu_pda[cpu_logical_map(j)].apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/x86_64/kernel/mtrr.c linux-2.5/arch/x86_64/kernel/mtrr.c --- linux-2.5.20/arch/x86_64/kernel/mtrr.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/arch/x86_64/kernel/mtrr.c Tue May 21 20:05:55 2002 @@ -1,28 +1,31 @@ /* x86-64 MTRR (Memory Type Range Register) driver. Based largely upon arch/i386/kernel/mtrr.c - Copyright (C) 1997-2000 Richard Gooch + Copyright (C) 1997-2000 Richard Gooch Copyright (C) 2002 Dave Jones. - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. (For earlier history, see arch/i386/kernel/mtrr.c) September 2001 Dave Jones Initial rewrite for x86-64. - + 64-bit fixes. + Removal of non-Intel style MTRR code. + Removal of redundant abstraction layer. */ + #include #include #include @@ -60,7 +63,7 @@ #include #include -#define MTRR_VERSION "2.00 (20020207)" +#define MTRR_VERSION "2.00 (20020521)" #define TRUE 1 #define FALSE 0 @@ -85,95 +88,89 @@ #define MTRRfix4K_F8000_MSR 0x26f #ifdef CONFIG_SMP -#define MTRR_CHANGE_MASK_FIXED 0x01 -#define MTRR_CHANGE_MASK_VARIABLE 0x02 -#define MTRR_CHANGE_MASK_DEFTYPE 0x04 +#define MTRR_CHANGE_MASK_FIXED 0x01 +#define MTRR_CHANGE_MASK_VARIABLE 0x02 +#define MTRR_CHANGE_MASK_DEFTYPE 0x04 #endif typedef u8 mtrr_type; -#define LINE_SIZE 80 +#define LINE_SIZE 80 #ifdef CONFIG_SMP #define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type) #else -#define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \ - TRUE) +#define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type, TRUE) #endif #if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS) #define USERSPACE_INTERFACE #endif -#ifndef USERSPACE_INTERFACE -#define compute_ascii() while (0) -#endif - #ifdef USERSPACE_INTERFACE static char *ascii_buffer; static unsigned int ascii_buf_bytes; +static void compute_ascii (void); +#else +#define compute_ascii() while (0) #endif + static unsigned int *usage_table; static DECLARE_MUTEX (main_lock); -/* Private functions */ -#ifdef USERSPACE_INTERFACE -static void compute_ascii (void); -#endif - struct set_mtrr_context { - unsigned long flags; - unsigned long deftype_lo; - unsigned long deftype_hi; - unsigned long cr4val; + u32 deftype_lo; + u32 deftype_hi; + u64 flags; + u64 cr4val; }; /* Put the processor into a state where MTRRs can be safely set */ static void set_mtrr_prepare (struct set_mtrr_context *ctxt) { - unsigned long cr0; + u64 cr0; /* Disable interrupts locally */ __save_flags(ctxt->flags); __cli(); - /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if (test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability)) { - ctxt->cr4val = read_cr4(); + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability)) { + ctxt->cr4val = read_cr4(); write_cr4(ctxt->cr4val & ~(1UL << 7)); - } + } - /* Disable and flush caches. Note that wbinvd flushes the TLBs as - a side-effect */ + /* Disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect */ cr0 = read_cr0() | 0x40000000; - wbinvd(); + wbinvd(); write_cr0(cr0); - wbinvd(); + wbinvd(); - /* Disable MTRRs, and set the default type to uncached */ + /* Disable MTRRs, and set the default type to uncached */ rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); } -/* Restore the processor after a set_mtrr_prepare */ +/* Restore the processor after a set_mtrr_prepare */ static void set_mtrr_done (struct set_mtrr_context *ctxt) { - /* Flush caches and TLBs */ - wbinvd(); + /* Flush caches and TLBs */ + wbinvd(); - /* Restore MTRRdefType */ + /* Restore MTRRdefType */ wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); - /* Enable caches */ + /* Enable caches */ write_cr0(read_cr0() & 0xbfffffff); - /* Restore value of CR4 */ - if (test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability)) + /* Restore value of CR4 */ + if (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability)) write_cr4 (ctxt->cr4val); - /* Re-enable interrupts locally (if enabled previously) */ + /* Re-enable interrupts locally (if enabled previously) */ __restore_flags(ctxt->flags); } @@ -181,7 +178,7 @@ /* This function returns the number of variable MTRRs */ static unsigned int get_num_var_ranges (void) { - unsigned long config, dummy; + u32 config, dummy; rdmsr (MTRRcap_MSR, config, dummy); return (config & 0xff); @@ -191,71 +188,71 @@ /* Returns non-zero if we have the write-combining memory type */ static int have_wrcomb (void) { - unsigned long config, dummy; + u32 config, dummy; rdmsr (MTRRcap_MSR, config, dummy); return (config & (1 << 10)); } -static u32 size_or_mask, size_and_mask; +static u64 size_or_mask, size_and_mask; -static void get_mtrr (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type * type) +static void get_mtrr (unsigned int reg, u64 *base, u64 *size, mtrr_type * type) { - unsigned long mask_lo, mask_hi, base_lo, base_hi; + u32 mask_lo, mask_hi, base_lo, base_hi; + u64 newsize; rdmsr (MTRRphysMask_MSR (reg), mask_lo, mask_hi); if ((mask_lo & 0x800) == 0) { - /* Invalid (i.e. free) range */ - *base = 0; - *size = 0; - *type = 0; - return; - } + /* Invalid (i.e. free) range */ + *base = 0; + *size = 0; + *type = 0; + return; + } rdmsr (MTRRphysBase_MSR (reg), base_lo, base_hi); - /* Work out the shifted address mask. */ - mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT) - | mask_lo >> PAGE_SHIFT; - - /* This works correctly if size is a power of two, i.e. a - contiguous range. */ - *size = -mask_lo; - *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT; - *type = base_lo & 0xff; + /* Work out the shifted address mask. */ + newsize = (u64) size_or_mask | mask_hi << (32 - PAGE_SHIFT) + | mask_lo >> PAGE_SHIFT; + + /* This works correctly if size is a power of two, i.e. a + contiguous range. */ + *size = -newsize; + *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT; + *type = base_lo & 0xff; } -static void set_mtrr_up (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type, int do_safe) -/* [SUMMARY] Set variable MTRR register on the local CPU. - The register to set. - The base address of the region. - The size of the region. If this is 0 the region is disabled. - The type of the region. - If TRUE, do the change safely. If FALSE, safety measures should - be done externally. - [RETURNS] Nothing. -*/ +/* + * Set variable MTRR register on the local CPU. + * The register to set. + * The base address of the region. + * The size of the region. If this is 0 the region is disabled. + * The type of the region. + * If TRUE, do the change safely. If FALSE, safety measures should + * be done externally. + */ +static void set_mtrr_up (unsigned int reg, u64 base, + u64 size, mtrr_type type, int do_safe) { - struct set_mtrr_context ctxt; + struct set_mtrr_context ctxt; if (do_safe) set_mtrr_prepare (&ctxt); if (size == 0) { - /* The invalid bit is kept in the mask, so we simply clear the - relevant mask register to disable a range. */ - wrmsr (MTRRphysMask_MSR (reg), 0, 0); + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ + wrmsr (MTRRphysMask_MSR (reg), 0, 0); } else { - wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type, - (base & size_and_mask) >> (32 - PAGE_SHIFT)); - wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800, - (-size & size_and_mask) >> (32 - PAGE_SHIFT)); - } + wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type, + (base & size_and_mask) >> (32 - PAGE_SHIFT)); + wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800, + (-size & size_and_mask) >> (32 - PAGE_SHIFT)); + } if (do_safe) set_mtrr_done (&ctxt); } @@ -264,124 +261,129 @@ #ifdef CONFIG_SMP struct mtrr_var_range { - unsigned long base_lo; - unsigned long base_hi; - unsigned long mask_lo; - unsigned long mask_hi; + u32 base_lo; + u32 base_hi; + u32 mask_lo; + u32 mask_hi; }; /* Get the MSR pair relating to a var range */ static void __init get_mtrr_var_range (unsigned int index, - struct mtrr_var_range *vr) + struct mtrr_var_range *vr) { - rdmsr (MTRRphysBase_MSR (index), vr->base_lo, vr->base_hi); - rdmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi); + rdmsr (MTRRphysBase_MSR (index), vr->base_lo, vr->base_hi); + rdmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi); } /* Set the MSR pair relating to a var range. Returns TRUE if changes are made */ -static int __init -set_mtrr_var_range_testing (unsigned int index, struct mtrr_var_range *vr) +static int __init set_mtrr_var_range_testing (unsigned int index, + struct mtrr_var_range *vr) { - unsigned int lo, hi; - int changed = FALSE; + u32 lo, hi; + int changed = FALSE; rdmsr (MTRRphysBase_MSR (index), lo, hi); if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) - || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { + || (vr->base_hi & 0x000fffffUL) != (hi & 0x000fffffUL)) { wrmsr (MTRRphysBase_MSR (index), vr->base_lo, vr->base_hi); - changed = TRUE; - } + changed = TRUE; + } rdmsr (MTRRphysMask_MSR (index), lo, hi); if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) - || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) { + || (vr->mask_hi & 0x000fffffUL) != (hi & 0x000fffffUL)) { wrmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi); - changed = TRUE; - } - return changed; + changed = TRUE; + } + return changed; } static void __init get_fixed_ranges (mtrr_type * frs) { - unsigned long *p = (unsigned long *) frs; - int i; + u32 *p = (u32 *) frs; + int i; rdmsr (MTRRfix64K_00000_MSR, p[0], p[1]); - for (i = 0; i < 2; i++) + for (i = 0; i < 2; i++) rdmsr (MTRRfix16K_80000_MSR + i, p[2 + i * 2], p[3 + i * 2]); - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) rdmsr (MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]); } static int __init set_fixed_ranges_testing (mtrr_type * frs) { - unsigned long *p = (unsigned long *) frs; - int changed = FALSE; - int i; - unsigned long lo, hi; + u32 *p = (u32 *) frs; + int changed = FALSE; + int i; + u32 lo, hi; + printk (KERN_INFO "mtrr: rdmsr 64K_00000\n"); rdmsr (MTRRfix64K_00000_MSR, lo, hi); if (p[0] != lo || p[1] != hi) { - wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]); - changed = TRUE; - } + printk (KERN_INFO "mtrr: Writing %x:%x to 64K MSR. lohi were %x:%x\n", p[0], p[1], lo, hi); + wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]); + changed = TRUE; + } + printk (KERN_INFO "mtrr: rdmsr 16K_80000\n"); for (i = 0; i < 2; i++) { - rdmsr (MTRRfix16K_80000_MSR + i, lo, hi); + rdmsr (MTRRfix16K_80000_MSR + i, lo, hi); if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) { - wrmsr (MTRRfix16K_80000_MSR + i, p[2 + i * 2], - p[3 + i * 2]); - changed = TRUE; + printk (KERN_INFO "mtrr: Writing %x:%x to 16K MSR%d. lohi were %x:%x\n", p[2 + i * 2], p[3 + i * 2], i, lo, hi ); + wrmsr (MTRRfix16K_80000_MSR + i, p[2 + i * 2], p[3 + i * 2]); + changed = TRUE; + } } - } + printk (KERN_INFO "mtrr: rdmsr 4K_C0000\n"); for (i = 0; i < 8; i++) { - rdmsr (MTRRfix4K_C0000_MSR + i, lo, hi); + rdmsr (MTRRfix4K_C0000_MSR + i, lo, hi); + printk (KERN_INFO "mtrr: MTRRfix4K_C0000_MSR+%d = %x:%x\n", i, lo, hi); if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) { - wrmsr (MTRRfix4K_C0000_MSR + i, p[6 + i * 2], - p[7 + i * 2]); - changed = TRUE; + printk (KERN_INFO "mtrr: Writing %x:%x to 4K MSR%d. lohi were %x:%x\n", p[6 + i * 2], p[7 + i * 2], i, lo, hi); + wrmsr (MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]); + changed = TRUE; + } } - } - return changed; + return changed; } struct mtrr_state { - unsigned int num_var_ranges; - struct mtrr_var_range *var_ranges; - mtrr_type fixed_ranges[NUM_FIXED_RANGES]; - unsigned char enabled; - mtrr_type def_type; + unsigned int num_var_ranges; + struct mtrr_var_range *var_ranges; + mtrr_type fixed_ranges[NUM_FIXED_RANGES]; + mtrr_type def_type; + unsigned char enabled; }; /* Grab all of the MTRR state for this CPU into *state */ static void __init get_mtrr_state (struct mtrr_state *state) { - unsigned int nvrs, i; - struct mtrr_var_range *vrs; - unsigned long lo, dummy; - - nvrs = state->num_var_ranges = get_num_var_ranges (); - vrs = state->var_ranges - = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); - if (vrs == NULL) - nvrs = state->num_var_ranges = 0; - - for (i = 0; i < nvrs; i++) - get_mtrr_var_range (i, &vrs[i]); - get_fixed_ranges (state->fixed_ranges); - - rdmsr (MTRRdefType_MSR, lo, dummy); - state->def_type = (lo & 0xff); - state->enabled = (lo & 0xc00) >> 10; + unsigned int nvrs, i; + struct mtrr_var_range *vrs; + u32 lo, dummy; + + nvrs = state->num_var_ranges = get_num_var_ranges(); + vrs = state->var_ranges + = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); + if (vrs == NULL) + nvrs = state->num_var_ranges = 0; + + for (i = 0; i < nvrs; i++) + get_mtrr_var_range (i, &vrs[i]); + get_fixed_ranges (state->fixed_ranges); + + rdmsr (MTRRdefType_MSR, lo, dummy); + state->def_type = (lo & 0xff); + state->enabled = (lo & 0xc00) >> 10; } @@ -393,33 +395,34 @@ } -static unsigned long __init set_mtrr_state (struct mtrr_state *state, - struct set_mtrr_context *ctxt) -/* [SUMMARY] Set the MTRR state for this CPU. - The MTRR state information to read. - Some relevant CPU context. - [NOTE] The CPU must already be in a safe state for MTRR changes. - [RETURNS] 0 if no changes made, else a mask indication what was changed. -*/ +/* + * Set the MTRR state for this CPU. + * The MTRR state information to read. + * Some relevant CPU context. + * [NOTE] The CPU must already be in a safe state for MTRR changes. + * [RETURNS] 0 if no changes made, else a mask indication what was changed. + */ +static u64 __init set_mtrr_state (struct mtrr_state *state, + struct set_mtrr_context *ctxt) { - unsigned int i; - unsigned long change_mask = 0; + unsigned int i; + u64 change_mask = 0; - for (i = 0; i < state->num_var_ranges; i++) + for (i = 0; i < state->num_var_ranges; i++) if (set_mtrr_var_range_testing (i, &state->var_ranges[i])) - change_mask |= MTRR_CHANGE_MASK_VARIABLE; + change_mask |= MTRR_CHANGE_MASK_VARIABLE; if (set_fixed_ranges_testing (state->fixed_ranges)) - change_mask |= MTRR_CHANGE_MASK_FIXED; - /* Set_mtrr_restore restores the old value of MTRRdefType, - so to set it we fiddle with the saved value */ + change_mask |= MTRR_CHANGE_MASK_FIXED; + /* Set_mtrr_restore restores the old value of MTRRdefType, + so to set it we fiddle with the saved value */ if ((ctxt->deftype_lo & 0xff) != state->def_type || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) { - ctxt->deftype_lo |= (state->def_type | state->enabled << 10); - change_mask |= MTRR_CHANGE_MASK_DEFTYPE; - } + ctxt->deftype_lo |= (state->def_type | state->enabled << 10); + change_mask |= MTRR_CHANGE_MASK_DEFTYPE; + } - return change_mask; + return change_mask; } @@ -428,167 +431,162 @@ static volatile int wait_barrier_cache_enable = FALSE; struct set_mtrr_data { - unsigned long smp_base; - unsigned long smp_size; - unsigned int smp_reg; - mtrr_type smp_type; + u64 smp_base; + u64 smp_size; + unsigned int smp_reg; + mtrr_type smp_type; }; +/* + * Synchronisation handler. Executed by "other" CPUs. + */ static void ipi_handler (void *info) -/* [SUMMARY] Synchronisation handler. Executed by "other" CPUs. - [RETURNS] Nothing. -*/ { - struct set_mtrr_data *data = info; - struct set_mtrr_context ctxt; + struct set_mtrr_data *data = info; + struct set_mtrr_context ctxt; set_mtrr_prepare (&ctxt); - /* Notify master that I've flushed and disabled my cache */ - atomic_dec (&undone_count); + /* Notify master that I've flushed and disabled my cache */ + atomic_dec (&undone_count); while (wait_barrier_execute) barrier (); - /* The master has cleared me to execute */ - (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size, - data->smp_type, FALSE); + /* The master has cleared me to execute */ + set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, + data->smp_type, FALSE); - /* Notify master CPU that I've executed the function */ - atomic_dec (&undone_count); + /* Notify master CPU that I've executed the function */ + atomic_dec (&undone_count); - /* Wait for master to clear me to enable cache and return */ + /* Wait for master to clear me to enable cache and return */ while (wait_barrier_cache_enable) barrier (); - set_mtrr_done (&ctxt); + set_mtrr_done (&ctxt); } -static void set_mtrr_smp (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type) +static void set_mtrr_smp (unsigned int reg, u64 base, u64 size, mtrr_type type) { - struct set_mtrr_data data; - struct set_mtrr_context ctxt; + struct set_mtrr_data data; + struct set_mtrr_context ctxt; - data.smp_reg = reg; - data.smp_base = base; - data.smp_size = size; - data.smp_type = type; - wait_barrier_execute = TRUE; - wait_barrier_cache_enable = TRUE; - atomic_set (&undone_count, smp_num_cpus - 1); + data.smp_reg = reg; + data.smp_base = base; + data.smp_size = size; + data.smp_type = type; + wait_barrier_execute = TRUE; + wait_barrier_cache_enable = TRUE; + atomic_set (&undone_count, smp_num_cpus - 1); - /* Start the ball rolling on other CPUs */ - if (smp_call_function (ipi_handler, &data, 1, 0) != 0) - panic ("mtrr: timed out waiting for other CPUs\n"); + /* Start the ball rolling on other CPUs */ + if (smp_call_function (ipi_handler, &data, 1, 0) != 0) + panic ("mtrr: timed out waiting for other CPUs\n"); - /* Flush and disable the local CPU's cache */ + /* Flush and disable the local CPU's cache */ set_mtrr_prepare (&ctxt); - /* Wait for all other CPUs to flush and disable their caches */ + /* Wait for all other CPUs to flush and disable their caches */ while (atomic_read (&undone_count) > 0) barrier (); /* Set up for completion wait and then release other CPUs to change MTRRs */ - atomic_set (&undone_count, smp_num_cpus - 1); - wait_barrier_execute = FALSE; - (*set_mtrr_up) (reg, base, size, type, FALSE); + atomic_set (&undone_count, smp_num_cpus - 1); + wait_barrier_execute = FALSE; + set_mtrr_up (reg, base, size, type, FALSE); - /* Now wait for other CPUs to complete the function */ + /* Now wait for other CPUs to complete the function */ while (atomic_read (&undone_count) > 0) barrier (); - /* Now all CPUs should have finished the function. Release the barrier to - allow them to re-enable their caches and return from their interrupt, - then enable the local cache and return */ - wait_barrier_cache_enable = FALSE; - set_mtrr_done (&ctxt); + /* Now all CPUs should have finished the function. Release the barrier to + allow them to re-enable their caches and return from their interrupt, + then enable the local cache and return */ + wait_barrier_cache_enable = FALSE; + set_mtrr_done (&ctxt); } /* Some BIOS's are fucked and don't set all MTRRs the same! */ -static void __init mtrr_state_warn (unsigned long mask) +static void __init mtrr_state_warn (u32 mask) { if (!mask) return; - if (mask & MTRR_CHANGE_MASK_FIXED) - printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); - if (mask & MTRR_CHANGE_MASK_VARIABLE) - printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); - if (mask & MTRR_CHANGE_MASK_DEFTYPE) - printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); - printk ("mtrr: probably your BIOS does not setup all CPUs\n"); + if (mask & MTRR_CHANGE_MASK_FIXED) + printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_VARIABLE) + printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_DEFTYPE) + printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); + printk ("mtrr: probably your BIOS does not setup all CPUs\n"); } -#endif /* CONFIG_SMP */ +#endif /* CONFIG_SMP */ -static char inline * attrib_to_str (int x) +static inline char * attrib_to_str (int x) { - return (x <= 6) ? mtrr_strings[x] : "?"; + return (x <= 6) ? mtrr_strings[x] : "?"; } static void __init init_table (void) { - int i, max; + int i, max; - max = get_num_var_ranges (); + max = get_num_var_ranges (); if ((usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL))==NULL) { - printk ("mtrr: could not allocate\n"); - return; - } + printk ("mtrr: could not allocate\n"); + return; + } for (i = 0; i < max; i++) usage_table[i] = 1; #ifdef USERSPACE_INTERFACE if ((ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL)) == NULL) { - printk ("mtrr: could not allocate\n"); - return; - } - ascii_buf_bytes = 0; - compute_ascii (); + printk ("mtrr: could not allocate\n"); + return; + } + ascii_buf_bytes = 0; + compute_ascii (); #endif } -static int generic_get_free_region (unsigned long base, - unsigned long size) -/* [SUMMARY] Get a free MTRR. - The starting (base) address of the region. - The size (in bytes) of the region. - [RETURNS] The index of the region on success, else -1 on error. +/* + * Get a free MTRR. + * returns the index of the region on success, else -1 on error. */ +static int get_free_region(void) { - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize; + int i, max; + mtrr_type ltype; + u64 lbase; + u64 lsize; - max = get_num_var_ranges (); + max = get_num_var_ranges (); for (i = 0; i < max; ++i) { - (*get_mtrr) (i, &lbase, &lsize, <ype); + get_mtrr (i, &lbase, &lsize, <ype); if (lsize == 0) return i; - } - return -ENOSPC; + } + return -ENOSPC; } -static int (*get_free_region) (unsigned long base, - unsigned long size) = generic_get_free_region; - /** * mtrr_add_page - Add a memory type region * @base: Physical base address of region in pages (4 KB) * @size: Physical size of region in pages (4 KB) * @type: Type of MTRR desired * @increment: If this is true do usage counting on the region + * Returns The MTRR register on success, else a negative number + * indicating the error code. * - * Memory type region registers control the caching on newer Intel and - * non Intel processors. This function allows drivers to request an - * MTRR is added. The details and hardware specifics of each processor's - * implementation are hidden from the caller, but nevertheless the - * caller should expect to need to provide a power of two size on an - * equivalent power of two boundary. + * Memory type region registers control the caching on newer + * processors. This function allows drivers to request an MTRR is added. + * The caller should expect to need to provide a power of two size on + * an equivalent power of two boundary. * * If the region cannot be added either because all regions are in use * or the CPU cannot support it a negative value is returned. On success @@ -596,48 +594,33 @@ * as a cookie only. * * On a multiprocessor machine the changes are made to all processors. - * This is required on x86 by the Intel processors. * * The available types are * * %MTRR_TYPE_UNCACHABLE - No caching - * * %MTRR_TYPE_WRBACK - Write data back in bursts whenever - * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts - * * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes * * BUGS: Needs a quiet flag for the cases where drivers do not mind * failures and do not wish system log messages to be sent. */ -int mtrr_add_page (unsigned long base, unsigned long size, - unsigned int type, char increment) +int mtrr_add_page (u64 base, u64 size, unsigned int type, char increment) { -/* [SUMMARY] Add an MTRR entry. - The starting (base, in pages) address of the region. - The size of the region. (in pages) - The type of the new region. - If true and the region already exists, the usage count will be - incremented. - [RETURNS] The MTRR register on success, else a negative number indicating - the error code. - [NOTE] This routine uses a spinlock. -*/ - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize, last; + int i, max; + mtrr_type ltype; + u64 lbase, last, lsize; if (base + size < 0x100) { printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n", - base, size); - return -EINVAL; + base, size); + return -EINVAL; } /* Check upper bits of base and last are equal and lower bits are 0 - for base and 1 for last */ + for base and 1 for last */ last = base + size - 1; for (lbase = base; !(lbase & 1) && (last & 1); lbase = lbase >> 1, last = last >> 1) ; @@ -646,75 +629,75 @@ printk (KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n", base, size); - return -EINVAL; - } + return -EINVAL; + } if (type >= MTRR_NUM_TYPES) { - printk ("mtrr: type: %u illegal\n", type); - return -EINVAL; - } + printk ("mtrr: type: %u illegal\n", type); + return -EINVAL; + } - /* If the type is WC, check that this processor supports it */ + /* If the type is WC, check that this processor supports it */ if ((type == MTRR_TYPE_WRCOMB) && !have_wrcomb ()) { printk (KERN_WARNING "mtrr: your processor doesn't support write-combining\n"); - return -ENOSYS; - } + return -ENOSYS; + } if (base & size_or_mask || size & size_or_mask) { - printk ("mtrr: base or size exceeds the MTRR width\n"); - return -EINVAL; - } + printk ("mtrr: base or size exceeds the MTRR width\n"); + return -EINVAL; + } - increment = increment ? 1 : 0; - max = get_num_var_ranges (); - /* Search for existing MTRR */ + increment = increment ? 1 : 0; + max = get_num_var_ranges (); + /* Search for existing MTRR */ down (&main_lock); for (i = 0; i < max; ++i) { - (*get_mtrr) (i, &lbase, &lsize, <ype); + get_mtrr (i, &lbase, &lsize, <ype); if (base >= lbase + lsize) continue; if ((base < lbase) && (base + size <= lbase)) continue; - /* At this point we know there is some kind of overlap/enclosure */ + /* At this point we know there is some kind of overlap/enclosure */ if ((base < lbase) || (base + size > lbase + lsize)) { up (&main_lock); printk (KERN_WARNING "mtrr: 0x%lx000,0x%lx000 overlaps existing" - " 0x%lx000,0x%lx000\n", base, size, lbase, - lsize); - return -EINVAL; - } - /* New region is enclosed by an existing region */ + " 0x%lx000,0x%lx000\n", base, size, lbase, lsize); + return -EINVAL; + } + /* New region is enclosed by an existing region */ if (ltype != type) { if (type == MTRR_TYPE_UNCACHABLE) continue; up (&main_lock); printk ("mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", - base, size, attrib_to_str (ltype), + base, size, + attrib_to_str (ltype), attrib_to_str (type)); - return -EINVAL; - } + return -EINVAL; + } if (increment) ++usage_table[i]; - compute_ascii (); + compute_ascii (); up (&main_lock); - return i; - } - /* Search for an empty MTRR */ - i = (*get_free_region) (base, size); + return i; + } + /* Search for an empty MTRR */ + i = get_free_region(); if (i < 0) { up (&main_lock); - printk ("mtrr: no more MTRRs available\n"); - return i; - } - set_mtrr (i, base, size, type); - usage_table[i] = 1; - compute_ascii (); + printk ("mtrr: no more MTRRs available\n"); + return i; + } + set_mtrr (i, base, size, type); + usage_table[i] = 1; + compute_ascii (); up (&main_lock); - return i; + return i; } @@ -724,13 +707,13 @@ * @size: Physical size of region * @type: Type of MTRR desired * @increment: If this is true do usage counting on the region + * Return the MTRR register on success, else a negative numbe + * indicating the error code. * - * Memory type region registers control the caching on newer Intel and - * non Intel processors. This function allows drivers to request an - * MTRR is added. The details and hardware specifics of each processor's - * implementation are hidden from the caller, but nevertheless the - * caller should expect to need to provide a power of two size on an - * equivalent power of two boundary. + * Memory type region registers control the caching on newer processors. + * This function allows drivers to request an MTRR is added. + * The caller should expect to need to provide a power of two size on + * an equivalent power of two boundary. * * If the region cannot be added either because all regions are in use * or the CPU cannot support it a negative value is returned. On success @@ -743,35 +726,21 @@ * The available types are * * %MTRR_TYPE_UNCACHABLE - No caching - * * %MTRR_TYPE_WRBACK - Write data back in bursts whenever - * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts - * * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes * * BUGS: Needs a quiet flag for the cases where drivers do not mind * failures and do not wish system log messages to be sent. */ -int mtrr_add (unsigned long base, unsigned long size, unsigned int type, - char increment) +int mtrr_add (u64 base, u64 size, unsigned int type, char increment) { -/* [SUMMARY] Add an MTRR entry. - The starting (base) address of the region. - The size (in bytes) of the region. - The type of the new region. - If true and the region already exists, the usage count will be - incremented. - [RETURNS] The MTRR register on success, else a negative number indicating - the error code. -*/ - if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); - return -EINVAL; - } + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } return mtrr_add_page (base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment); } @@ -791,65 +760,57 @@ * On success the register is returned, on failure a negative error * code. */ - -int mtrr_del_page (int reg, unsigned long base, unsigned long size) -/* [SUMMARY] Delete MTRR/decrement usage count. - The register. If this is less than 0 then <> and <> must - be supplied. - The base address of the region. This is ignored if <> is >= 0. - The size of the region. This is ignored if <> is >= 0. - [RETURNS] The register on success, else a negative number indicating - the error code. - [NOTE] This routine uses a spinlock. -*/ + +int mtrr_del_page (int reg, u64 base, u64 size) { - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize; + int i, max; + mtrr_type ltype; + u64 lbase; + u64 lsize; - max = get_num_var_ranges (); - down (&main_lock); + max = get_num_var_ranges (); + down (&main_lock); if (reg < 0) { - /* Search for existing MTRR */ + /* Search for existing MTRR */ for (i = 0; i < max; ++i) { - (*get_mtrr) (i, &lbase, &lsize, <ype); + get_mtrr (i, &lbase, &lsize, <ype); if (lbase == base && lsize == size) { - reg = i; - break; - } - } + reg = i; + break; + } + } if (reg < 0) { up (&main_lock); printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size); - return -EINVAL; + return -EINVAL; + } } - } if (reg >= max) { - up (&main_lock); - printk ("mtrr: register: %d too big\n", reg); - return -EINVAL; - } - (*get_mtrr) (reg, &lbase, &lsize, <ype); + up (&main_lock); + printk ("mtrr: register: %d too big\n", reg); + return -EINVAL; + } + get_mtrr (reg, &lbase, &lsize, <ype); if (lsize < 1) { - up (&main_lock); - printk ("mtrr: MTRR %d not used\n", reg); - return -EINVAL; - } + up (&main_lock); + printk ("mtrr: MTRR %d not used\n", reg); + return -EINVAL; + } if (usage_table[reg] < 1) { - up (&main_lock); - printk ("mtrr: reg: %d has count=0\n", reg); - return -EINVAL; - } + up (&main_lock); + printk ("mtrr: reg: %d has count=0\n", reg); + return -EINVAL; + } if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0); - compute_ascii (); - up (&main_lock); - return reg; + compute_ascii (); + up (&main_lock); + return reg; } @@ -867,89 +828,81 @@ * On success the register is returned, on failure a negative error * code. */ - -int mtrr_del (int reg, unsigned long base, unsigned long size) -/* [SUMMARY] Delete MTRR/decrement usage count. - The register. If this is less than 0 then <> and <> must - be supplied. - The base address of the region. This is ignored if <> is >= 0. - The size of the region. This is ignored if <> is >= 0. - [RETURNS] The register on success, else a negative number indicating - the error code. -*/ + +int mtrr_del (int reg, u64 base, u64 size) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); - return -EINVAL; - } + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } return mtrr_del_page (reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); } #ifdef USERSPACE_INTERFACE -static int mtrr_file_add (unsigned long base, unsigned long size, - unsigned int type, char increment, struct file *file, int page) +static int mtrr_file_add (u64 base, u64 size, unsigned int type, + struct file *file, int page) { - int reg, max; - unsigned int *fcount = file->private_data; + int reg, max; + unsigned int *fcount = file->private_data; - max = get_num_var_ranges (); + max = get_num_var_ranges (); if (fcount == NULL) { if ((fcount = kmalloc (max * sizeof *fcount, GFP_KERNEL)) == NULL) { - printk ("mtrr: could not allocate\n"); - return -ENOMEM; + printk ("mtrr: could not allocate\n"); + return -ENOMEM; + } + memset (fcount, 0, max * sizeof *fcount); + file->private_data = fcount; } - memset (fcount, 0, max * sizeof *fcount); - file->private_data = fcount; - } - if (!page) { + if (!page) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); - return -EINVAL; + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; } - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - } - reg = mtrr_add_page (base, size, type, 1); + reg = mtrr_add_page (base, size, type, 1); if (reg >= 0) ++fcount[reg]; - return reg; + return reg; } -static int mtrr_file_del (unsigned long base, unsigned long size, - struct file *file, int page) +static int mtrr_file_del (u64 base, u64 size, + struct file *file, int page) { - int reg; - unsigned int *fcount = file->private_data; + int reg; + unsigned int *fcount = file->private_data; - if (!page) { + if (!page) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); - return -EINVAL; + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; } - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - } - reg = mtrr_del_page (-1, base, size); + reg = mtrr_del_page (-1, base, size); if (reg < 0) return reg; if (fcount == NULL) return reg; if (fcount[reg] < 1) return -EINVAL; - --fcount[reg]; - return reg; + --fcount[reg]; + return reg; } @@ -965,8 +918,8 @@ if (copy_to_user (buf, ascii_buffer + *ppos, len)) return -EFAULT; - *ppos += len; - return len; + *ppos += len; + return len; } @@ -977,249 +930,247 @@ "disable=%d" */ { - int i, err; - unsigned long reg; - unsigned long long base, size; - char *ptr; - char line[LINE_SIZE]; + int i, err, reg; + u64 base; + u64 size; + char *ptr; + char line[LINE_SIZE]; - if (!capable (CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; - /* Can't seek (pwrite) on this device */ + /* Can't seek (pwrite) on this device */ if (ppos != &file->f_pos) return -ESPIPE; - memset (line, 0, LINE_SIZE); + memset (line, 0, LINE_SIZE); if (len > LINE_SIZE) len = LINE_SIZE; if (copy_from_user (line, buf, len - 1)) return -EFAULT; - ptr = line + strlen (line) - 1; + ptr = line + strlen (line) - 1; if (*ptr == '\n') *ptr = '\0'; if (!strncmp (line, "disable=", 8)) { - reg = simple_strtoul (line + 8, &ptr, 0); - err = mtrr_del_page (reg, 0, 0); + reg = simple_strtoul (line + 8, &ptr, 0); + err = mtrr_del_page (reg, 0, 0); if (err < 0) return err; - return len; - } + return len; + } if (strncmp (line, "base=", 5)) { - printk ("mtrr: no \"base=\" in line: \"%s\"\n", line); - return -EINVAL; - } + printk ("mtrr: no \"base=\" in line: \"%s\"\n", line); + return -EINVAL; + } - base = simple_strtoull (line + 5, &ptr, 0); + base = simple_strtoull (line + 5, &ptr, 0); for (; isspace (*ptr); ++ptr) ; if (strncmp (ptr, "size=", 5)) { - printk ("mtrr: no \"size=\" in line: \"%s\"\n", line); - return -EINVAL; - } + printk ("mtrr: no \"size=\" in line: \"%s\"\n", line); + return -EINVAL; + } - size = simple_strtoull (ptr + 5, &ptr, 0); + size = simple_strtoull (ptr + 5, &ptr, 0); if ((base & 0xfff) || (size & 0xfff)) { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%Lx base: 0x%Lx\n", size, base); - return -EINVAL; - } + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } for (; isspace (*ptr); ++ptr) ; if (strncmp (ptr, "type=", 5)) { - printk ("mtrr: no \"type=\" in line: \"%s\"\n", line); - return -EINVAL; - } - ptr += 5; + printk ("mtrr: no \"type=\" in line: \"%s\"\n", line); + return -EINVAL; + } + ptr += 5; for (; isspace (*ptr); ++ptr) ; for (i = 0; i < MTRR_NUM_TYPES; ++i) { if (strcmp (ptr, mtrr_strings[i])) continue; - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - err = - mtrr_add_page ((unsigned long) base, (unsigned long) size, - i, 1); + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; + err = mtrr_add_page ((u64) base, (u64) size, i, 1); if (err < 0) return err; - return len; - } - printk ("mtrr: illegal type: \"%s\"\n", ptr); - return -EINVAL; + return len; + } + printk ("mtrr: illegal type: \"%s\"\n", ptr); + return -EINVAL; } static int mtrr_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - int err; - mtrr_type type; - struct mtrr_sentry sentry; - struct mtrr_gentry gentry; + int err; + mtrr_type type; + struct mtrr_sentry sentry; + struct mtrr_gentry gentry; switch (cmd) { - default: - return -ENOIOCTLCMD; + default: + return -ENOIOCTLCMD; - case MTRRIOC_ADD_ENTRY: - if (!capable (CAP_SYS_ADMIN)) + case MTRRIOC_ADD_ENTRY: + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; + return -EFAULT; err = - mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, + mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_SET_ENTRY: - if (!capable (CAP_SYS_ADMIN)) + case MTRRIOC_SET_ENTRY: + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); + return -EFAULT; + err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_DEL_ENTRY: - if (!capable (CAP_SYS_ADMIN)) + case MTRRIOC_DEL_ENTRY: + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_file_del (sentry.base, sentry.size, file, 0); + return -EFAULT; + err = mtrr_file_del (sentry.base, sentry.size, file, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_KILL_ENTRY: - if (!capable (CAP_SYS_ADMIN)) + case MTRRIOC_KILL_ENTRY: + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_del (-1, sentry.base, sentry.size); + return -EFAULT; + err = mtrr_del (-1, sentry.base, sentry.size); if (err < 0) return err; - break; + break; - case MTRRIOC_GET_ENTRY: + case MTRRIOC_GET_ENTRY: if (copy_from_user (&gentry, (void *) arg, sizeof gentry)) - return -EFAULT; + return -EFAULT; if (gentry.regnum >= get_num_var_ranges ()) return -EINVAL; - (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); + get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type); - /* Hide entries that go above 4GB */ + /* Hide entries that go above 4GB */ if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000) - gentry.base = gentry.size = gentry.type = 0; - else { - gentry.base <<= PAGE_SHIFT; - gentry.size <<= PAGE_SHIFT; - gentry.type = type; - } + gentry.base = gentry.size = gentry.type = 0; + else { + gentry.base <<= PAGE_SHIFT; + gentry.size <<= PAGE_SHIFT; + gentry.type = type; + } if (copy_to_user ((void *) arg, &gentry, sizeof gentry)) - return -EFAULT; - break; + return -EFAULT; + break; - case MTRRIOC_ADD_PAGE_ENTRY: - if (!capable (CAP_SYS_ADMIN)) + case MTRRIOC_ADD_PAGE_ENTRY: + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; + return -EFAULT; err = - mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, + mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 1); if (err < 0) return err; - break; + break; - case MTRRIOC_SET_PAGE_ENTRY: - if (!capable (CAP_SYS_ADMIN)) + case MTRRIOC_SET_PAGE_ENTRY: + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); + return -EFAULT; + err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; - break; + break; - case MTRRIOC_DEL_PAGE_ENTRY: - if (!capable (CAP_SYS_ADMIN)) + case MTRRIOC_DEL_PAGE_ENTRY: + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_file_del (sentry.base, sentry.size, file, 1); + return -EFAULT; + err = mtrr_file_del (sentry.base, sentry.size, file, 1); if (err < 0) return err; - break; + break; - case MTRRIOC_KILL_PAGE_ENTRY: - if (!capable (CAP_SYS_ADMIN)) + case MTRRIOC_KILL_PAGE_ENTRY: + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) - return -EFAULT; - err = mtrr_del_page (-1, sentry.base, sentry.size); + return -EFAULT; + err = mtrr_del_page (-1, sentry.base, sentry.size); if (err < 0) return err; - break; + break; - case MTRRIOC_GET_PAGE_ENTRY: + case MTRRIOC_GET_PAGE_ENTRY: if (copy_from_user (&gentry, (void *) arg, sizeof gentry)) - return -EFAULT; + return -EFAULT; if (gentry.regnum >= get_num_var_ranges ()) return -EINVAL; - (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); - gentry.type = type; + get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type); + gentry.type = type; if (copy_to_user ((void *) arg, &gentry, sizeof gentry)) - return -EFAULT; - break; - } - return 0; + return -EFAULT; + break; + } + return 0; } static int mtrr_close (struct inode *ino, struct file *file) { - int i, max; - unsigned int *fcount = file->private_data; + int i, max; + unsigned int *fcount = file->private_data; if (fcount == NULL) return 0; lock_kernel (); - max = get_num_var_ranges (); + max = get_num_var_ranges (); for (i = 0; i < max; ++i) { while (fcount[i] > 0) { if (mtrr_del (i, 0, 0) < 0) printk ("mtrr: reg %d not used\n", i); - --fcount[i]; + --fcount[i]; + } } - } unlock_kernel (); - kfree (fcount); - file->private_data = NULL; - return 0; + kfree (fcount); + file->private_data = NULL; + return 0; } static struct file_operations mtrr_fops = { - owner: THIS_MODULE, - read: mtrr_read, - write: mtrr_write, - ioctl: mtrr_ioctl, + owner: THIS_MODULE, + read: mtrr_read, + write: mtrr_write, + ioctl: mtrr_ioctl, release:mtrr_close, }; @@ -1231,39 +1182,39 @@ static void compute_ascii (void) { - char factor; - int i, max; - mtrr_type type; - unsigned long base, size; + char factor; + int i, max; + mtrr_type type; + u64 base; + u64 size; - ascii_buf_bytes = 0; - max = get_num_var_ranges (); + ascii_buf_bytes = 0; + max = get_num_var_ranges (); for (i = 0; i < max; i++) { - (*get_mtrr) (i, &base, &size, &type); + get_mtrr (i, &base, &size, &type); if (size == 0) usage_table[i] = 0; else { if (size < (0x100000 >> PAGE_SHIFT)) { - /* less than 1MB */ - factor = 'K'; - size <<= PAGE_SHIFT - 10; + /* less than 1MB */ + factor = 'K'; + size <<= PAGE_SHIFT - 10; } else { - factor = 'M'; - size >>= 20 - PAGE_SHIFT; - } - sprintf - (ascii_buffer + ascii_buf_bytes, - "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n", - i, base, base >> (20 - PAGE_SHIFT), size, factor, - attrib_to_str (type), usage_table[i]); - ascii_buf_bytes += - strlen (ascii_buffer + ascii_buf_bytes); + factor = 'M'; + size >>= 20 - PAGE_SHIFT; + } + sprintf + (ascii_buffer + ascii_buf_bytes, + "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n", + i, base, base >> (20 - PAGE_SHIFT), size, factor, + attrib_to_str (type), usage_table[i]); + ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes); + } } - } - devfs_set_file_size (devfs_handle, ascii_buf_bytes); + devfs_set_file_size (devfs_handle, ascii_buf_bytes); #ifdef CONFIG_PROC_FS - if (proc_root_mtrr) - proc_root_mtrr->size = ascii_buf_bytes; + if (proc_root_mtrr) + proc_root_mtrr->size = ascii_buf_bytes; #endif } @@ -1272,33 +1223,27 @@ EXPORT_SYMBOL (mtrr_add); EXPORT_SYMBOL (mtrr_del); - + static void __init mtrr_setup (void) { printk ("mtrr: v%s)\n", MTRR_VERSION); - if (test_bit (X86_FEATURE_MTRR, &boot_cpu_data.x86_capability)) { + if (test_bit (X86_FEATURE_MTRR, boot_cpu_data.x86_capability)) { /* Query the width (in bits) of the physical addressable memory on the Hammer family. */ if ((cpuid_eax (0x80000000) >= 0x80000008)) { - u32 phys_addr; + u32 phys_addr; phys_addr = cpuid_eax (0x80000008) & 0xff; - size_or_mask = - ~((1 << (phys_addr - PAGE_SHIFT)) - 1); - size_and_mask = ~size_or_mask & 0xfff00000; - } else { - /* FIXME: This is to make it work on Athlon during debugging. */ - size_or_mask = 0xff000000; /* 36 bits */ - size_and_mask = 0x00f00000; - } - + size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1); + size_and_mask = ~size_or_mask & 0xfffffffffff00000; + } printk ("mtrr: detected mtrr type: x86-64\n"); - } + } } #ifdef CONFIG_SMP -static volatile unsigned long smp_changes_mask __initdata = 0; +static volatile u32 smp_changes_mask __initdata = 0; static struct mtrr_state smp_mtrr_state __initdata = { 0, 0 }; void __init mtrr_init_boot_cpu (void) @@ -1310,31 +1255,32 @@ void __init mtrr_init_secondary_cpu (void) { - unsigned long mask, count; - struct set_mtrr_context ctxt; - - /* Note that this is not ideal, since the cache is only flushed/disabled - for this CPU while the MTRRs are changed, but changing this requires - more invasive changes to the way the kernel boots */ + u64 mask; + int count; + struct set_mtrr_context ctxt; + + /* Note that this is not ideal, since the cache is only flushed/disabled + for this CPU while the MTRRs are changed, but changing this requires + more invasive changes to the way the kernel boots */ set_mtrr_prepare (&ctxt); - mask = set_mtrr_state (&smp_mtrr_state, &ctxt); - set_mtrr_done (&ctxt); + mask = set_mtrr_state (&smp_mtrr_state, &ctxt); + set_mtrr_done (&ctxt); - /* Use the atomic bitops to update the global mask */ + /* Use the atomic bitops to update the global mask */ for (count = 0; count < sizeof mask * 8; ++count) { if (mask & 0x01) set_bit (count, &smp_changes_mask); - mask >>= 1; - } + mask >>= 1; + } } -#endif /* CONFIG_SMP */ +#endif /* CONFIG_SMP */ int __init mtrr_init (void) { #ifdef CONFIG_SMP - /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */ + /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */ finalize_mtrr_state (&smp_mtrr_state); mtrr_state_warn (smp_changes_mask); @@ -1343,18 +1289,17 @@ #endif #ifdef CONFIG_PROC_FS - proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); - if (proc_root_mtrr) { - proc_root_mtrr->owner = THIS_MODULE; - proc_root_mtrr->proc_fops = &mtrr_fops; - } + proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); + if (proc_root_mtrr) { + proc_root_mtrr->owner = THIS_MODULE; + proc_root_mtrr->proc_fops = &mtrr_fops; + } #endif #ifdef CONFIG_DEVFS_FS - devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, - S_IFREG | S_IRUGO | S_IWUSR, - &mtrr_fops, NULL); + devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, + S_IFREG | S_IRUGO | S_IWUSR, + &mtrr_fops, NULL); #endif - init_table (); - return 0; + init_table (); + return 0; } - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/x86_64/kernel/nmi.c linux-2.5/arch/x86_64/kernel/nmi.c --- linux-2.5.20/arch/x86_64/kernel/nmi.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/arch/x86_64/kernel/nmi.c Sun May 26 01:40:46 2002 @@ -240,7 +240,7 @@ */ int sum, cpu = smp_processor_id(); - sum = apic_timer_irqs[cpu]; + sum = cpu_pda[cpu].apic_timer_irqs; if (last_irq_sums[cpu] == sum) { /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/x86_64/kernel/pci-pc.c linux-2.5/arch/x86_64/kernel/pci-pc.c --- linux-2.5.20/arch/x86_64/kernel/pci-pc.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/arch/x86_64/kernel/pci-pc.c Mon Apr 22 02:24:21 2002 @@ -215,7 +215,8 @@ outl (tmp, 0xCF8); __restore_flags(flags); printk("PCI: Using configuration type 1\n"); - request_region(0xCF8, 8, "PCI conf1"); + if (!request_region(0xCF8, 8, "PCI conf1")) + return NULL; return &pci_direct_conf1; } outl (tmp, 0xCF8); @@ -232,7 +233,8 @@ pci_sanity_check(&pci_direct_conf2)) { __restore_flags(flags); printk("PCI: Using configuration type 2\n"); - request_region(0xCF8, 4, "PCI conf2"); + if (!request_region(0xCF8, 4, "PCI conf2")) + return NULL; return &pci_direct_conf2; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/x86_64/kernel/setup.c linux-2.5/arch/x86_64/kernel/setup.c --- linux-2.5.20/arch/x86_64/kernel/setup.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/arch/x86_64/kernel/setup.c Mon Apr 22 02:24:21 2002 @@ -1021,7 +1021,7 @@ void __init print_cpu_info(struct cpuinfo_x86 *c) { if (c->x86_model_id[0]) - printk("AMD %s", c->x86_model_id); + printk("%s", c->x86_model_id); if (c->x86_mask || c->cpuid_level >= 0) printk(" stepping %02x\n", c->x86_mask); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/arch/x86_64/lib/mmx.c linux-2.5/arch/x86_64/lib/mmx.c --- linux-2.5.20/arch/x86_64/lib/mmx.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/arch/x86_64/lib/mmx.c Mon May 6 14:24:26 2002 @@ -62,7 +62,7 @@ "\n" : : "r" (from) ); - for(; i>5; i--) + for (; i>5; i--) { __asm__ __volatile__ ( " prefetch 320(%0)\n" @@ -231,10 +231,11 @@ void mmx_clear_page(void * page) { -#if 1 +#if 0 __builtin_memset(page,0,PAGE_SIZE); #else /* AK: these in_interrupt checks should not be needed. */ + /* DJ: Only because of the slower defines in on x86-64 */ if(unlikely(in_interrupt())) __builtin_memset(page,0,PAGE_SIZE); else @@ -244,7 +245,7 @@ void mmx_copy_page(void *to, void *from) { -#if 1 +#if 0 __builtin_memcpy(to,from,PAGE_SIZE); #else /* AK: these in_interrupt checks should not be needed. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/Makefile linux-2.5/drivers/Makefile --- linux-2.5.20/drivers/Makefile Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/Makefile Fri May 31 02:35:46 2002 @@ -29,7 +29,7 @@ obj-$(CONFIG_DIO) += dio/ obj-$(CONFIG_SBUS) += sbus/ obj-$(CONFIG_ZORRO) += zorro/ -obj-$(CONFIG_ALL_PPC) += macintosh/ +obj-$(CONFIG_PPC) += macintosh/ obj-$(CONFIG_MAC) += macintosh/ obj-$(CONFIG_PNP) += pnp/ obj-$(CONFIG_SGI) += sgi/ @@ -46,6 +46,6 @@ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BLUEZ) += bluetooth/ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ -obj-$(CONFIG_ISDN) += isdn/ +obj-$(CONFIG_ISDN_BOOL) += isdn/ include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/ac.c linux-2.5/drivers/acpi/ac.c --- linux-2.5.20/drivers/acpi/ac.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/acpi/ac.c Mon Jun 3 17:26:20 2002 @@ -1,5 +1,5 @@ /* - * acpi_ac.c - ACPI AC Adapter Driver ($Revision: 26 $) + * acpi_ac.c - ACPI AC Adapter Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/battery.c linux-2.5/drivers/acpi/battery.c --- linux-2.5.20/drivers/acpi/battery.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/acpi/battery.c Mon Jun 3 17:26:20 2002 @@ -1,5 +1,5 @@ /* - * acpi_battery.c - ACPI Battery Driver ($Revision: 35 $) + * acpi_battery.c - ACPI Battery Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/bus.c linux-2.5/drivers/acpi/bus.c --- linux-2.5.20/drivers/acpi/bus.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/acpi/bus.c Mon Jun 3 17:26:21 2002 @@ -1,5 +1,5 @@ /* - * acpi_bus.c - ACPI Bus Driver ($Revision: 77 $) + * acpi_bus.c - ACPI Bus Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Paul Diefenbaugh * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/button.c linux-2.5/drivers/acpi/button.c --- linux-2.5.20/drivers/acpi/button.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/acpi/button.c Mon Jun 3 17:26:21 2002 @@ -1,5 +1,5 @@ /* - * acpi_button.c - ACPI Button Driver ($Revision: 29 $) + * acpi_button.c - ACPI Button Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/ec.c linux-2.5/drivers/acpi/ec.c --- linux-2.5.20/drivers/acpi/ec.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/acpi/ec.c Mon Jun 3 17:26:21 2002 @@ -1,5 +1,5 @@ /* - * acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 31 $) + * acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/fan.c linux-2.5/drivers/acpi/fan.c --- linux-2.5.20/drivers/acpi/fan.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/acpi/fan.c Mon Jun 3 17:26:21 2002 @@ -1,5 +1,5 @@ /* - * acpi_fan.c - ACPI Fan Driver ($Revision: 28 $) + * acpi_fan.c - ACPI Fan Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/osl.c linux-2.5/drivers/acpi/osl.c --- linux-2.5.20/drivers/acpi/osl.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/acpi/osl.c Mon Jun 3 17:26:21 2002 @@ -1,5 +1,5 @@ /* - * acpi_osl.c - OS-dependent functions ($Revision: 78 $) + * acpi_osl.c - OS-dependent functions ($Revision: 1.1 $) * * Copyright (C) 2000 Andrew Henroid * Copyright (C) 2001, 2002 Andy Grover diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/pci_bind.c linux-2.5/drivers/acpi/pci_bind.c --- linux-2.5.20/drivers/acpi/pci_bind.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/acpi/pci_bind.c Mon Jun 3 17:26:21 2002 @@ -1,5 +1,5 @@ /* - * pci_bind.c - ACPI PCI Device Binding ($Revision: 2 $) + * pci_bind.c - ACPI PCI Device Binding ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/pci_irq.c linux-2.5/drivers/acpi/pci_irq.c --- linux-2.5.20/drivers/acpi/pci_irq.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/acpi/pci_irq.c Mon Jun 3 17:26:21 2002 @@ -1,5 +1,5 @@ /* - * pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 7 $) + * pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/pci_link.c linux-2.5/drivers/acpi/pci_link.c --- linux-2.5.20/drivers/acpi/pci_link.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/acpi/pci_link.c Mon Jun 3 17:26:22 2002 @@ -1,5 +1,5 @@ /* - * pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 31 $) + * pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/pci_root.c linux-2.5/drivers/acpi/pci_root.c --- linux-2.5.20/drivers/acpi/pci_root.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/acpi/pci_root.c Mon Jun 3 17:26:22 2002 @@ -1,5 +1,5 @@ /* - * pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 37 $) + * pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/power.c linux-2.5/drivers/acpi/power.c --- linux-2.5.20/drivers/acpi/power.c Mon Jun 3 02:44:37 2002 +++ linux-2.5/drivers/acpi/power.c Mon Jun 3 17:26:22 2002 @@ -1,5 +1,5 @@ /* - * acpi_power.c - ACPI Bus Power Management ($Revision: 37 $) + * acpi_power.c - ACPI Bus Power Management ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/processor.c linux-2.5/drivers/acpi/processor.c --- linux-2.5.20/drivers/acpi/processor.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/acpi/processor.c Mon Jun 3 17:26:22 2002 @@ -1,5 +1,5 @@ /* - * acpi_processor.c - ACPI Processor Driver ($Revision: 66 $) + * acpi_processor.c - ACPI Processor Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/system.c linux-2.5/drivers/acpi/system.c --- linux-2.5.20/drivers/acpi/system.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/acpi/system.c Mon Jun 3 17:26:22 2002 @@ -1,5 +1,5 @@ /* - * acpi_system.c - ACPI System Driver ($Revision: 57 $) + * acpi_system.c - ACPI System Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/thermal.c linux-2.5/drivers/acpi/thermal.c --- linux-2.5.20/drivers/acpi/thermal.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/acpi/thermal.c Mon Jun 3 17:26:23 2002 @@ -1,5 +1,5 @@ /* - * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 39 $) + * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/acpi/utils.c linux-2.5/drivers/acpi/utils.c --- linux-2.5.20/drivers/acpi/utils.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/acpi/utils.c Mon Jun 3 17:26:32 2002 @@ -1,5 +1,5 @@ /* - * acpi_utils.c - ACPI Utility Functions ($Revision: 5 $) + * acpi_utils.c - ACPI Utility Functions ($Revision: 1.1 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/atm/Config.help linux-2.5/drivers/atm/Config.help --- linux-2.5.20/drivers/atm/Config.help Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/atm/Config.help Mon Feb 25 18:58:39 2002 @@ -2,6 +2,12 @@ ATM over TCP driver. Useful mainly for development and for experiments. If unsure, say N. +CONFIG_ATM_LANAI + Supports ATM cards based on the Efficient Networks "Lanai" + chipset such as the Speedstream 3010 and the ENI-25p. The + Speedstream 3060 is currently not supported since we don't + have the code to drive the on-board Alcatel DSL chipset (yet). + CONFIG_ATM_ENI Driver for the Efficient Networks ENI155p series and SMC ATM Power155 155 Mbps ATM adapters. Both, the versions with 512KB and diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/DAC960.c linux-2.5/drivers/block/DAC960.c --- linux-2.5.20/drivers/block/DAC960.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/block/DAC960.c Tue May 21 22:20:44 2002 @@ -1944,7 +1944,7 @@ Initialize the I/O Request Queue. */ RequestQueue = BLK_DEFAULT_QUEUE(MajorNumber); - blk_init_queue(RequestQueue, DAC960_RequestFunction); + blk_init_queue(RequestQueue, DAC960_RequestFunction, &Controller->lock); RequestQueue->queuedata = Controller; blk_queue_max_hw_segments(RequestQueue, Controller->DriverScatterGatherLimit); @@ -2261,6 +2261,7 @@ Controller->Bus = Bus; Controller->Device = Device; Controller->Function = Function; + Controller->lock = SPIN_LOCK_UNLOCKED; /* Map the Controller Register Window. */ @@ -2404,8 +2405,12 @@ DAC960_V1_QueueReadWriteCommand; break; case DAC960_PD_Controller: - request_region(Controller->IO_Address, 0x80, - Controller->FullModelName); + if (!request_region(Controller->IO_Address, 0x80, + Controller->FullModelName)) + { + DAC960_Error("Unable request region at 0x%x\n", Controller->IO_Address); + goto Failure; + } DAC960_PD_DisableInterrupts(BaseAddress); DAC960_PD_AcknowledgeStatus(BaseAddress); udelay(1000); @@ -2430,8 +2435,12 @@ DAC960_V1_QueueReadWriteCommand; break; case DAC960_P_Controller: - request_region(Controller->IO_Address, 0x80, - Controller->FullModelName); + if (!request_region(Controller->IO_Address, 0x80, + Controller->FullModelName)) + { + DAC960_Error("Unable request region at 0x%x\n", Controller->IO_Address); + goto Failure; + } DAC960_PD_DisableInterrupts(BaseAddress); DAC960_PD_AcknowledgeStatus(BaseAddress); udelay(1000); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/DAC960.h linux-2.5/drivers/block/DAC960.h --- linux-2.5.20/drivers/block/DAC960.h Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/block/DAC960.h Fri May 3 12:57:30 2002 @@ -2476,6 +2476,7 @@ int PartitionSizes[DAC960_MinorCount]; unsigned char ProgressBuffer[DAC960_ProgressBufferSize]; unsigned char UserStatusBuffer[DAC960_UserMessageSize]; + spinlock_t lock; } DAC960_Controller_T; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/floppy.c linux-2.5/drivers/block/floppy.c --- linux-2.5.20/drivers/block/floppy.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/block/floppy.c Mon Jun 3 17:10:21 2002 @@ -4257,9 +4257,12 @@ CLEARSTRUCT(FDCS); FDCS->dtr = -1; FDCS->dor = 0x4; -#ifdef __sparc__ - /*sparcs don't have a DOR reset which we can fall back on to*/ - FDCS->version = FDC_82072A; +#if defined(__sparc__) || defined(__mc68000__) + /*sparcs/sun3x don't have a DOR reset which we can fall back on to*/ +#ifdef __mc68000__ + if(MACH_IS_SUN3X) +#endif + FDCS->version = FDC_82072A; #endif } @@ -4558,3 +4561,5 @@ __setup ("floppy=", floppy_setup); module_init(floppy_init) #endif + +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/genhd.c linux-2.5/drivers/block/genhd.c --- linux-2.5.20/drivers/block/genhd.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/block/genhd.c Fri May 10 02:05:26 2002 @@ -31,6 +31,7 @@ * Global kernel list of partitioning information. */ static struct gendisk *gendisk_head; +static struct gendisk *gendisk_array[MAX_BLKDEV]; /** * add_gendisk - add partitioning information to kernel list @@ -60,6 +61,7 @@ goto out; } } + gendisk_array[gp->major] = gp; gp->next = gendisk_head; gendisk_head = gp; out: @@ -82,6 +84,7 @@ struct gendisk **gpp; write_lock(&gendisk_lock); + gendisk_array[gp->major] = NULL; for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next)) if (*gpp == gp) break; @@ -107,11 +110,15 @@ int maj = major(dev); read_lock(&gendisk_lock); + if ((gp = gendisk_array[maj])) + goto out; + + /* This is needed for early 2.4 source compatiblity. --hch */ for (gp = gendisk_head; gp; gp = gp->next) if (gp->major == maj) break; +out: read_unlock(&gendisk_lock); - return gp; } @@ -206,7 +213,6 @@ extern int soc_probe(void); extern int atmdev_init(void); extern int i2o_init(void); -extern int cpqarray_init(void); int __init device_init(void) { @@ -222,9 +228,6 @@ #ifdef CONFIG_FC4_SOC /* This has to be done before scsi_dev_init */ soc_probe(); -#endif -#ifdef CONFIG_BLK_CPQ_DA - cpqarray_init(); #endif #ifdef CONFIG_NET net_dev_init(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/ida_ioctl.h linux-2.5/drivers/block/ida_ioctl.h --- linux-2.5.20/drivers/block/ida_ioctl.h Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/block/ida_ioctl.h Mon May 6 16:41:36 2002 @@ -31,6 +31,9 @@ #define IDAREVALIDATEVOLS 0x30303131 #define IDADRIVERVERSION 0x31313232 #define IDAGETPCIINFO 0x32323333 +#define IDADEREGDISK 0x33333434 +#define IDAREGNEWDISK 0x34343535 +#define IDAGETLOGINFO 0x35353636 typedef struct _ida_pci_info_struct { @@ -38,6 +41,13 @@ unsigned char dev_fn; __u32 board_id; } ida_pci_info_struct; + +typedef struct _idaLogvolInfo_struct{ +int LogVolID; +int num_opens; /* number of opens on the logical volume */ +int num_parts; /* number of partitions configured on logvol */ +} idaLogvolInfo_struct; + /* * Normally, the ioctl determines the logical unit for this command by * the major,minor number of the fd passed to ioctl. If you need to send diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/paride/bpck6.c linux-2.5/drivers/block/paride/bpck6.c --- linux-2.5.20/drivers/block/paride/bpck6.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/block/paride/bpck6.c Fri May 10 16:02:58 2002 @@ -17,13 +17,15 @@ Version 2.0.0 is the first to have source released Version 2.0.1 is the "Cox-ified" source code Version 2.0.2 - fixed version string usage, and made ppc functions static + Version 2.0.2ac - additional cleanup (privptr now not private to fix 64bit + platforms), use memset, rename clashing PPC define. */ /* PARAMETERS */ int verbose=0; /* set this to 1 to see debugging messages and whatnot */ -#define BACKPACK_VERSION "2.0.2" +#define BACKPACK_VERSION "2.0.2ac" #include #include @@ -40,7 +42,7 @@ -#define PPCSTRUCT(pi) ((PPC *)(pi->private)) +#define PPCSTRUCT(pi) ((PPC_STORAGE *)(pi->privptr)) /****************************************************************/ /* @@ -223,12 +225,10 @@ static void bpck6_init_proto(PIA *pi) { - int i; - /* allocate a state structure for this item */ - pi->private=(int)kmalloc(sizeof(PPC),GFP_KERNEL); + pi->privptr=kmalloc(sizeof(PPC_STORAGE),GFP_KERNEL); - if(pi->private==(int)NULL) + if(pi->privptr==NULL) { printk(KERN_ERR "%s: ERROR COULDN'T ALLOCATE MEMORY\n",pi->device); return; @@ -238,10 +238,7 @@ MOD_INC_USE_COUNT; } - for(i=0;iprivate))[i]=0; - } + memset(pi->privptr, 0, sizeof(PPC_STORAGE)); } static void bpck6_release_proto(PIA *pi) @@ -249,7 +246,7 @@ MOD_DEC_USE_COUNT; /* free after use count decremented so that we aren't using it when it is decremented */ - kfree((void *)(pi->private)); + kfree(pi->privptr); } struct pi_protocol bpck6 = { "bpck6", /* name for proto*/ @@ -290,7 +287,7 @@ #ifdef MODULE /*module information*/ -static int init_module(void) +int init_module(void) { printk(KERN_INFO "bpck6: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n"); printk(KERN_INFO "bpck6: Copyright 2001 by Micro Solutions, Inc., DeKalb IL. USA\n"); @@ -303,7 +300,7 @@ return pi_register(&bpck6) - 1; } -void cleanup_module(void) +void cleanup_module(void) { pi_unregister(&bpck6); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/paride/paride.h linux-2.5/drivers/block/paride/paride.h --- linux-2.5.20/drivers/block/paride/paride.h Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/block/paride/paride.h Fri May 3 03:49:06 2002 @@ -13,9 +13,10 @@ /* Changes: 1.01 GRG 1998.05.05 init_proto, release_proto + 1.01ac AGC 2002.04.03 added privptr */ -#define PARIDE_H_VERSION "1.01" +#define PARIDE_H_VERSION "1.01ac" /* Some adapters need to know what kind of device they are in @@ -46,7 +47,9 @@ int saved_r2; /* saved port state */ int reserved; /* number of ports reserved */ int private; /* for protocol module */ - + void *privptr; /* private pointer for protocol module */ + /* For 2.5 just make private a ulong but + for 2.4 fixups thats a bit risky.. */ wait_queue_head_t parq; /* semaphore for parport sharing */ void *pardev; /* pointer to pardevice */ char *parname; /* parport name */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/paride/pcd.c linux-2.5/drivers/block/paride/pcd.c --- linux-2.5.20/drivers/block/paride/pcd.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/block/paride/pcd.c Sat May 25 19:52:00 2002 @@ -330,7 +330,7 @@ int pcd_init (void) /* preliminary initialisation */ -{ int i, unit; +{ int unit; if (disable) return -1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/paride/pd.c linux-2.5/drivers/block/paride/pd.c --- linux-2.5.20/drivers/block/paride/pd.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/block/paride/pd.c Sat Jun 1 00:34:34 2002 @@ -382,7 +382,7 @@ int pd_init (void) -{ int i; +{ request_queue_t * q; if (disable) return -1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/paride/ppc6lnx.c linux-2.5/drivers/block/paride/ppc6lnx.c --- linux-2.5.20/drivers/block/paride/ppc6lnx.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/block/paride/ppc6lnx.c Fri May 3 03:49:06 2002 @@ -79,7 +79,7 @@ u8 org_data; // original LPT data port contents u8 org_ctrl; // original LPT control port contents u8 cur_ctrl; // current control port contents -} PPC; +} PPC_STORAGE; //*************************************************************************** @@ -101,25 +101,25 @@ //*************************************************************************** -static int ppc6_select(PPC *ppc); -static void ppc6_deselect(PPC *ppc); -static void ppc6_send_cmd(PPC *ppc, u8 cmd); -static void ppc6_wr_data_byte(PPC *ppc, u8 data); -static u8 ppc6_rd_data_byte(PPC *ppc); -static u8 ppc6_rd_port(PPC *ppc, u8 port); -static void ppc6_wr_port(PPC *ppc, u8 port, u8 data); -static void ppc6_rd_data_blk(PPC *ppc, u8 *data, long count); -static void ppc6_wait_for_fifo(PPC *ppc); -static void ppc6_wr_data_blk(PPC *ppc, u8 *data, long count); -static void ppc6_rd_port16_blk(PPC *ppc, u8 port, u8 *data, long length); -static void ppc6_wr_port16_blk(PPC *ppc, u8 port, u8 *data, long length); -static void ppc6_wr_extout(PPC *ppc, u8 regdata); -static int ppc6_open(PPC *ppc); -static void ppc6_close(PPC *ppc); +static int ppc6_select(PPC_STORAGE *ppc); +static void ppc6_deselect(PPC_STORAGE *ppc); +static void ppc6_send_cmd(PPC_STORAGE *ppc, u8 cmd); +static void ppc6_wr_data_byte(PPC_STORAGE *ppc, u8 data); +static u8 ppc6_rd_data_byte(PPC_STORAGE *ppc); +static u8 ppc6_rd_port(PPC_STORAGE *ppc, u8 port); +static void ppc6_wr_port(PPC_STORAGE *ppc, u8 port, u8 data); +static void ppc6_rd_data_blk(PPC_STORAGE *ppc, u8 *data, long count); +static void ppc6_wait_for_fifo(PPC_STORAGE *ppc); +static void ppc6_wr_data_blk(PPC_STORAGE *ppc, u8 *data, long count); +static void ppc6_rd_port16_blk(PPC_STORAGE *ppc, u8 port, u8 *data, long length); +static void ppc6_wr_port16_blk(PPC_STORAGE *ppc, u8 port, u8 *data, long length); +static void ppc6_wr_extout(PPC_STORAGE *ppc, u8 regdata); +static int ppc6_open(PPC_STORAGE *ppc); +static void ppc6_close(PPC_STORAGE *ppc); //*************************************************************************** -static int ppc6_select(PPC *ppc) +static int ppc6_select(PPC_STORAGE *ppc) { u8 i, j, k; @@ -205,7 +205,7 @@ //*************************************************************************** -static void ppc6_deselect(PPC *ppc) +static void ppc6_deselect(PPC_STORAGE *ppc) { if (ppc->mode & 4) // EPP ppc->cur_ctrl |= port_init; @@ -223,7 +223,7 @@ //*************************************************************************** -static void ppc6_send_cmd(PPC *ppc, u8 cmd) +static void ppc6_send_cmd(PPC_STORAGE *ppc, u8 cmd) { switch(ppc->mode) { @@ -254,7 +254,7 @@ //*************************************************************************** -static void ppc6_wr_data_byte(PPC *ppc, u8 data) +static void ppc6_wr_data_byte(PPC_STORAGE *ppc, u8 data) { switch(ppc->mode) { @@ -285,7 +285,7 @@ //*************************************************************************** -static u8 ppc6_rd_data_byte(PPC *ppc) +static u8 ppc6_rd_data_byte(PPC_STORAGE *ppc) { u8 data = 0; @@ -358,7 +358,7 @@ //*************************************************************************** -static u8 ppc6_rd_port(PPC *ppc, u8 port) +static u8 ppc6_rd_port(PPC_STORAGE *ppc, u8 port) { ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_READ)); @@ -367,7 +367,7 @@ //*************************************************************************** -static void ppc6_wr_port(PPC *ppc, u8 port, u8 data) +static void ppc6_wr_port(PPC_STORAGE *ppc, u8 port, u8 data) { ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_WRITE)); @@ -376,7 +376,7 @@ //*************************************************************************** -static void ppc6_rd_data_blk(PPC *ppc, u8 *data, long count) +static void ppc6_rd_data_blk(PPC_STORAGE *ppc, u8 *data, long count) { switch(ppc->mode) { @@ -512,7 +512,7 @@ //*************************************************************************** -static void ppc6_wait_for_fifo(PPC *ppc) +static void ppc6_wait_for_fifo(PPC_STORAGE *ppc) { int i; @@ -525,7 +525,7 @@ //*************************************************************************** -static void ppc6_wr_data_blk(PPC *ppc, u8 *data, long count) +static void ppc6_wr_data_blk(PPC_STORAGE *ppc, u8 *data, long count) { switch(ppc->mode) { @@ -644,7 +644,7 @@ //*************************************************************************** -static void ppc6_rd_port16_blk(PPC *ppc, u8 port, u8 *data, long length) +static void ppc6_rd_port16_blk(PPC_STORAGE *ppc, u8 port, u8 *data, long length) { length = length << 1; @@ -664,7 +664,7 @@ //*************************************************************************** -static void ppc6_wr_port16_blk(PPC *ppc, u8 port, u8 *data, long length) +static void ppc6_wr_port16_blk(PPC_STORAGE *ppc, u8 port, u8 *data, long length) { length = length << 1; @@ -684,7 +684,7 @@ //*************************************************************************** -static void ppc6_wr_extout(PPC *ppc, u8 regdata) +static void ppc6_wr_extout(PPC_STORAGE *ppc, u8 regdata) { ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_WRITE)); @@ -693,7 +693,7 @@ //*************************************************************************** -static int ppc6_open(PPC *ppc) +static int ppc6_open(PPC_STORAGE *ppc) { int ret; @@ -717,7 +717,7 @@ //*************************************************************************** -static void ppc6_close(PPC *ppc) +static void ppc6_close(PPC_STORAGE *ppc) { ppc6_deselect(ppc); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/rd.c linux-2.5/drivers/block/rd.c --- linux-2.5.20/drivers/block/rd.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/block/rd.c Sat Jun 1 00:34:34 2002 @@ -86,7 +86,7 @@ */ int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */ /* - * It would be very desiderable to have a soft-blocksize (that in the case + * It would be very desirable to have a soft-blocksize (that in the case * of the ramdisk driver is also the hardblocksize ;) of PAGE_SIZE because * doing that we'll achieve a far better MM footprint. Using a rd_blocksize of * BLOCK_SIZE in the worst case we'll make PAGE_SIZE/BLOCK_SIZE buffer-pages @@ -103,26 +103,48 @@ * 2000 Transmeta Corp. * aops copied from ramfs. */ -static int ramdisk_readpage(struct file *file, struct page * page) +static void ramdisk_updatepage(struct page * page, int need_kmap) { - if (!PageUptodate(page)) { - memset(kmap(page), 0, PAGE_CACHE_SIZE); + struct buffer_head *bh = NULL; + void * address; + + if (PageUptodate(page)) + return; + + if (page_has_buffers(page)) + bh = page_buffers(page); + if (need_kmap) + kmap(page); + address = page_address(page); + if (bh) { + struct buffer_head *tmp = bh; + do { + if (!buffer_uptodate(tmp)) { + memset(address, 0, tmp->b_size); + set_buffer_uptodate(tmp); + } + address += tmp->b_size; + tmp = tmp->b_this_page; + } while (tmp != bh); + } else + memset(address, 0, PAGE_CACHE_SIZE); + if (need_kmap) kunmap(page); - flush_dcache_page(page); - SetPageUptodate(page); - } + flush_dcache_page(page); + SetPageUptodate(page); +} + + +static int ramdisk_readpage(struct file *file, struct page * page) +{ + ramdisk_updatepage(page, 1); unlock_page(page); return 0; } static int ramdisk_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { - if (!PageUptodate(page)) { - void *addr = page_address(page); - memset(addr, 0, PAGE_CACHE_SIZE); - flush_dcache_page(page); - SetPageUptodate(page); - } + ramdisk_updatepage(page, 0); SetPageDirty(page); return 0; } @@ -157,30 +179,20 @@ int count; struct page * page; char * src, * dst; - int unlock = 0; count = PAGE_CACHE_SIZE - offset; if (count > size) count = size; size -= count; - page = find_get_page(mapping, index); + page = grab_cache_page(mapping, index); if (!page) { - page = grab_cache_page(mapping, index); err = -ENOMEM; - if (!page) - goto out; - err = 0; - - if (!PageUptodate(page)) { - memset(kmap(page), 0, PAGE_CACHE_SIZE); - kunmap(page); - SetPageUptodate(page); - } - - unlock = 1; + goto out; } + ramdisk_updatepage(page, 1); + index++; if (rw == READ) { @@ -204,8 +216,7 @@ } else { SetPageDirty(page); } - if (unlock) - unlock_page(page); + unlock_page(page); __free_page(page); } while (size); @@ -296,9 +307,10 @@ error = 0; } up(&inode->i_bdev->bd_sem); + invalidate_buffers(inode->i_rdev); break; - case BLKGETSIZE: - case BLKGETSIZE64: + case BLKGETSIZE: + case BLKGETSIZE64: case BLKROSET: case BLKROGET: case BLKSSZGET: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/block/z2ram.c linux-2.5/drivers/block/z2ram.c --- linux-2.5.20/drivers/block/z2ram.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/block/z2ram.c Sat May 25 19:52:00 2002 @@ -86,16 +86,16 @@ if ( ( start + len ) > z2ram_size ) { - printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n", + printk( KERN_ERR DEVICE_NAME ": bad access: block=%ld, count=%ld\n", CURRENT->sector, CURRENT->current_nr_sectors); end_request( FALSE ); continue; } - if ( ( rq_data_dir(CURRENT) != READ ) && ( rq_data_dir(CURRENT) != WRITE ) ) + if ( ( CURRENT->cmd != READ ) && ( CURRENT->cmd != WRITE ) ) { - printk( KERN_ERR DEVICE_NAME ": bad command: %ld\n", rq_data_dir(CURRENT) ); + printk( KERN_ERR DEVICE_NAME ": bad command: %d\n", CURRENT->cmd ); end_request( FALSE ); continue; } @@ -109,7 +109,7 @@ addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ]; - if ( rq_data_dir(CURRENT) == READ ) + if ( CURRENT->cmd == READ ) memcpy( CURRENT->buffer, (char *)addr, size ); else memcpy( (char *)addr, CURRENT->buffer, size ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/bluetooth/bluecard_cs.c linux-2.5/drivers/bluetooth/bluecard_cs.c --- linux-2.5.20/drivers/bluetooth/bluecard_cs.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/bluetooth/bluecard_cs.c Sat May 25 19:52:00 2002 @@ -98,7 +98,7 @@ dev_link_t *bluecard_attach(void); void bluecard_detach(dev_link_t *); -dev_link_t *dev_list = NULL; +static dev_link_t *dev_list = NULL; /* Default baud rate: 57600, 115200, 230400 or 460800 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/bluetooth/hci_uart.c linux-2.5/drivers/bluetooth/hci_uart.c --- linux-2.5.20/drivers/bluetooth/hci_uart.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/bluetooth/hci_uart.c Wed May 1 21:12:18 2002 @@ -0,0 +1,580 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * BlueZ HCI UART driver. + * + * $Id: hci_uart.c,v 1.5 2001/07/05 18:42:44 maxk Exp $ + */ +#define VERSION "1.0" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef HCI_UART_DEBUG +#undef DBG +#define DBG( A... ) +#undef DMP +#define DMP( A... ) +#endif + +/* ------- Interface to HCI layer ------ */ +/* Initialize device */ +int n_hci_open(struct hci_dev *hdev) +{ + DBG("%s %p", hdev->name, hdev); + + /* Nothing to do for UART driver */ + + hdev->flags |= HCI_RUNNING; + + return 0; +} + +/* Reset device */ +int n_hci_flush(struct hci_dev *hdev) +{ + struct n_hci *n_hci = (struct n_hci *) hdev->driver_data; + struct tty_struct *tty = n_hci->tty; + + DBG("hdev %p tty %p", hdev, tty); + + /* Drop TX queue */ + skb_queue_purge(&n_hci->txq); + + /* Flush any pending characters in the driver and discipline. */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + return 0; +} + +/* Close device */ +int n_hci_close(struct hci_dev *hdev) +{ + DBG("hdev %p", hdev); + + hdev->flags &= ~HCI_RUNNING; + + n_hci_flush(hdev); + + return 0; +} + +int n_hci_tx_wakeup(struct n_hci *n_hci) +{ + register struct tty_struct *tty = n_hci->tty; + + if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) { + set_bit(TRANS_WAKEUP, &n_hci->tx_state); + return 0; + } + + DBG(""); + do { + register struct sk_buff *skb; + register int len; + + clear_bit(TRANS_WAKEUP, &n_hci->tx_state); + + if (!(skb = skb_dequeue(&n_hci->txq))) + break; + + DMP(skb->data, skb->len); + + /* Send frame to TTY driver */ + tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + len = tty->driver.write(tty, 0, skb->data, skb->len); + + n_hci->hdev.stat.byte_tx += len; + + DBG("sent %d", len); + + if (len == skb->len) { + /* Full frame was sent */ + kfree_skb(skb); + } else { + /* Subtract sent part and requeue */ + skb_pull(skb, len); + skb_queue_head(&n_hci->txq, skb); + } + } while (test_bit(TRANS_WAKEUP, &n_hci->tx_state)); + clear_bit(TRANS_SENDING, &n_hci->tx_state); + + return 0; +} + +/* Send frames from HCI layer */ +int n_hci_send_frame(struct sk_buff *skb) +{ + struct hci_dev* hdev = (struct hci_dev *) skb->dev; + struct tty_struct *tty; + struct n_hci *n_hci; + + if (!hdev) { + ERR("Frame for uknown device (hdev=NULL)"); + return -ENODEV; + } + + if (!(hdev->flags & HCI_RUNNING)) + return -EBUSY; + + n_hci = (struct n_hci *) hdev->driver_data; + tty = n_hci2tty(n_hci); + + DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + + case HCI_SCODATA_PKT: + hdev->stat.cmd_tx++; + break; + }; + + /* Prepend skb with frame type and queue */ + memcpy(skb_push(skb, 1), &skb->pkt_type, 1); + skb_queue_tail(&n_hci->txq, skb); + + n_hci_tx_wakeup(n_hci); + + return 0; +} + +/* ------ LDISC part ------ */ + +/* n_hci_tty_open + * + * Called when line discipline changed to N_HCI. + * + * Arguments: + * tty pointer to tty info structure + * Return Value: + * 0 if success, otherwise error code + */ +static int n_hci_tty_open(struct tty_struct *tty) +{ + struct n_hci *n_hci = tty2n_hci(tty); + struct hci_dev *hdev; + + DBG("tty %p", tty); + + if (n_hci) + return -EEXIST; + + if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) { + ERR("Can't allocate controll structure"); + return -ENFILE; + } + memset(n_hci, 0, sizeof(struct n_hci)); + + /* Initialize and register HCI device */ + hdev = &n_hci->hdev; + + hdev->type = HCI_UART; + hdev->driver_data = n_hci; + + hdev->open = n_hci_open; + hdev->close = n_hci_close; + hdev->flush = n_hci_flush; + hdev->send = n_hci_send_frame; + + if (hci_register_dev(hdev) < 0) { + ERR("Can't register HCI device %s", hdev->name); + kfree(n_hci); + return -ENODEV; + } + + tty->disc_data = n_hci; + n_hci->tty = tty; + + spin_lock_init(&n_hci->rx_lock); + n_hci->rx_state = WAIT_PACKET_TYPE; + + skb_queue_head_init(&n_hci->txq); + + MOD_INC_USE_COUNT; + + /* Flush any pending characters in the driver and discipline. */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + return 0; +} + +/* n_hci_tty_close() + * + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. + */ +static void n_hci_tty_close(struct tty_struct *tty) +{ + struct n_hci *n_hci = tty2n_hci(tty); + struct hci_dev *hdev = &n_hci->hdev; + + DBG("tty %p hdev %p", tty, hdev); + + if (n_hci != NULL) { + n_hci_close(hdev); + + if (hci_unregister_dev(hdev) < 0) { + ERR("Can't unregister HCI device %s",hdev->name); + } + + hdev->driver_data = NULL; + tty->disc_data = NULL; + kfree(n_hci); + + MOD_DEC_USE_COUNT; + } +} + +/* n_hci_tty_wakeup() + * + * Callback for transmit wakeup. Called when low level + * device driver can accept more send data. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: None + */ +static void n_hci_tty_wakeup( struct tty_struct *tty ) +{ + struct n_hci *n_hci = tty2n_hci(tty); + + DBG(""); + + if (!n_hci) + return; + + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + + if (tty != n_hci->tty) + return; + + n_hci_tx_wakeup(n_hci); +} + +/* n_hci_tty_room() + * + * Callback function from tty driver. Return the amount of + * space left in the receiver's buffer to decide if remote + * transmitter is to be throttled. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: number of bytes left in receive buffer + */ +static int n_hci_tty_room (struct tty_struct *tty) +{ + return 65536; +} + +static inline int n_hci_check_data_len(struct n_hci *n_hci, int len) +{ + register int room = skb_tailroom(n_hci->rx_skb); + + DBG("len %d room %d", len, room); + if (!len) { + DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); + hci_recv_frame(n_hci->rx_skb); + } else if (len > room) { + ERR("Data length is to large"); + kfree_skb(n_hci->rx_skb); + n_hci->hdev.stat.err_rx++; + } else { + n_hci->rx_state = WAIT_DATA; + n_hci->rx_count = len; + return len; + } + + n_hci->rx_state = WAIT_PACKET_TYPE; + n_hci->rx_skb = NULL; + n_hci->rx_count = 0; + return 0; +} + +static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count) +{ + register const char *ptr; + hci_event_hdr *eh; + hci_acl_hdr *ah; + hci_sco_hdr *sh; + register int len, type, dlen; + + DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count); + + n_hci->hdev.stat.byte_rx += count; + + ptr = data; + while (count) { + if (n_hci->rx_count) { + len = MIN(n_hci->rx_count, count); + memcpy(skb_put(n_hci->rx_skb, len), ptr, len); + n_hci->rx_count -= len; count -= len; ptr += len; + + if (n_hci->rx_count) + continue; + + switch (n_hci->rx_state) { + case WAIT_DATA: + DBG("Complete data"); + + DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); + + hci_recv_frame(n_hci->rx_skb); + + n_hci->rx_state = WAIT_PACKET_TYPE; + n_hci->rx_skb = NULL; + continue; + + case WAIT_EVENT_HDR: + eh = (hci_event_hdr *) n_hci->rx_skb->data; + + DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); + + n_hci_check_data_len(n_hci, eh->plen); + continue; + + case WAIT_ACL_HDR: + ah = (hci_acl_hdr *) n_hci->rx_skb->data; + dlen = __le16_to_cpu(ah->dlen); + + DBG("ACL header: dlen %d", dlen); + + n_hci_check_data_len(n_hci, dlen); + continue; + + case WAIT_SCO_HDR: + sh = (hci_sco_hdr *) n_hci->rx_skb->data; + + DBG("SCO header: dlen %d", sh->dlen); + + n_hci_check_data_len(n_hci, sh->dlen); + continue; + }; + } + + /* WAIT_PACKET_TYPE */ + switch (*ptr) { + case HCI_EVENT_PKT: + DBG("Event packet"); + n_hci->rx_state = WAIT_EVENT_HDR; + n_hci->rx_count = HCI_EVENT_HDR_SIZE; + type = HCI_EVENT_PKT; + break; + + case HCI_ACLDATA_PKT: + DBG("ACL packet"); + n_hci->rx_state = WAIT_ACL_HDR; + n_hci->rx_count = HCI_ACL_HDR_SIZE; + type = HCI_ACLDATA_PKT; + break; + + case HCI_SCODATA_PKT: + DBG("SCO packet"); + n_hci->rx_state = WAIT_SCO_HDR; + n_hci->rx_count = HCI_SCO_HDR_SIZE; + type = HCI_SCODATA_PKT; + break; + + default: + ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); + n_hci->hdev.stat.err_rx++; + ptr++; count--; + continue; + }; + ptr++; count--; + + /* Allocate packet */ + if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + ERR("Can't allocate mem for new packet"); + + n_hci->rx_state = WAIT_PACKET_TYPE; + n_hci->rx_count = 0; + return; + } + n_hci->rx_skb->dev = (void *) &n_hci->hdev; + n_hci->rx_skb->pkt_type = type; + } +} + +/* n_hci_tty_receive() + * + * Called by tty low level driver when receive data is + * available. + * + * Arguments: tty pointer to tty isntance data + * data pointer to received data + * flags pointer to flags for data + * count count of received data in bytes + * + * Return Value: None + */ +static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count) +{ + struct n_hci *n_hci = tty2n_hci(tty); + + if (!n_hci || tty != n_hci->tty) + return; + + spin_lock(&n_hci->rx_lock); + n_hci_rx(n_hci, data, flags, count); + spin_unlock(&n_hci->rx_lock); + + if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) + tty->driver.unthrottle(tty); +} + +/* n_hci_tty_ioctl() + * + * Process IOCTL system call for the tty device. + * + * Arguments: + * + * tty pointer to tty instance data + * file pointer to open file object for device + * cmd IOCTL command code + * arg argument for IOCTL call (cmd dependent) + * + * Return Value: Command dependent + */ +static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct n_hci *n_hci = tty2n_hci(tty); + int error = 0; + + DBG(""); + + /* Verify the status of the device */ + if (!n_hci) + return -EBADF; + + switch (cmd) { + default: + error = n_tty_ioctl(tty, file, cmd, arg); + break; + }; + + return error; +} + +/* + * We don't provide read/write/poll interface for user space. + */ +static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) +{ + return 0; +} +static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) +{ + return 0; +} +static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) +{ + return 0; +} + +int __init n_hci_init(void) +{ + static struct tty_ldisc n_hci_ldisc; + int err; + + INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); + INF("Written 2000,2001 by Maxim Krasnyansky "); + + /* Register the tty discipline */ + + memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc)); + n_hci_ldisc.magic = TTY_LDISC_MAGIC; + n_hci_ldisc.name = "n_hci"; + n_hci_ldisc.open = n_hci_tty_open; + n_hci_ldisc.close = n_hci_tty_close; + n_hci_ldisc.read = n_hci_tty_read; + n_hci_ldisc.write = n_hci_tty_write; + n_hci_ldisc.ioctl = n_hci_tty_ioctl; + n_hci_ldisc.poll = n_hci_tty_poll; + n_hci_ldisc.receive_room= n_hci_tty_room; + n_hci_ldisc.receive_buf = n_hci_tty_receive; + n_hci_ldisc.write_wakeup= n_hci_tty_wakeup; + + if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) { + ERR("Can't register HCI line discipline (%d)", err); + return err; + } + + return 0; +} + +void n_hci_cleanup(void) +{ + int err; + + /* Release tty registration of line discipline */ + if ((err = tty_register_ldisc(N_HCI, NULL))) + ERR("Can't unregister HCI line discipline (%d)", err); +} + +module_init(n_hci_init); +module_exit(n_hci_cleanup); + +MODULE_AUTHOR("Maxim Krasnyansky "); +MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/cdrom/cdrom.c linux-2.5/drivers/cdrom/cdrom.c --- linux-2.5.20/drivers/cdrom/cdrom.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/cdrom/cdrom.c Fri May 3 03:49:06 2002 @@ -761,6 +761,7 @@ cgc.cmd[0] = GPCMD_LOAD_UNLOAD; cgc.cmd[4] = 2 + (slot >= 0); cgc.cmd[8] = slot; + cgc.timeout = 60 * HZ; /* The Sanyo 3 CD changer uses byte 7 of the GPCMD_TEST_UNIT_READY to command to switch CDs instead of diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/cdrom/gscd.c linux-2.5/drivers/cdrom/gscd.c --- linux-2.5.20/drivers/cdrom/gscd.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/cdrom/gscd.c Sat Jun 1 00:34:34 2002 @@ -292,7 +292,7 @@ goto out; if (CURRENT->cmd != READ) { - printk("GSCD: bad cmd %p\n", CURRENT->cmd); + printk("GSCD: bad cmd %d\n", CURRENT->cmd); end_request(0); goto repeat; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/cdrom/sbpcd.c linux-2.5/drivers/cdrom/sbpcd.c --- linux-2.5.20/drivers/cdrom/sbpcd.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/cdrom/sbpcd.c Mon Jun 3 17:10:21 2002 @@ -346,7 +346,7 @@ * * Thu May 30 14:14:47 CEST 2002: * - * I have presumably found the reson for the above - there was a bogous + * have presumably found the reson for the above - there was a bogous * end_request substitute, which was manipulating the request queues * incorrectly. If someone has access to the actual hardware, and it's * still operations - well please free to test it. @@ -354,6 +354,13 @@ * Marcin Dalecki */ +/* + * Add bio/kdev_t changes for 2.5.x required to make it work again. + * Still room for improvement in the request handling here if anyone + * actually cares. Bring your own chainsaw. Paul G. 02/2002 + */ + + #include #include @@ -463,6 +470,8 @@ #define NUM_PROBE (sizeof(sbpcd) / sizeof(int)) +static spinlock_t sbpcd_lock = SPIN_LOCK_UNLOCKED; + /*==========================================================================*/ #define INLINE inline @@ -4857,23 +4866,21 @@ printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n", xnr, CURRENT, CURRENT->sector, CURRENT->nr_sectors, current->pid, jiffies); #endif - if (blk_queue_empty(QUEUE)) { CLEAR_INTR; return; } - req = CURRENT; /* take out our request so no other */ - blkdev_dequeue_request(req); /* task can fuck it up GTL */ + req = CURRENT; if (req -> sector == -1) end_request(0); spin_unlock_irq(q->queue_lock); down(&ioctl_read_sem); - if (req->cmd != READ) + if (rq_data_dir(CURRENT) != READ) { - msg(DBG_INF, "bad cmd %d\n", req->cmd); + msg(DBG_INF, "bad cmd %d\n", req->cmd[0]); goto err_done; } i = minor(req->rq_dev); @@ -5764,6 +5771,12 @@ i=SetSpeed(); if (i>=0) D_S[j].CD_changed=1; } + + if (!request_region(CDo_command,4,major_name)) + { + printk(KERN_WARNING "sbpcd: Unable to request region 0x%x\n", CDo_command); + return -EIO; + } /* * Turn on the CD audio channels. @@ -5785,9 +5798,8 @@ } blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_sbpcd_request, &sbpcd_lock); - request_region(CDo_command,4,major_name); - devfs_handle = devfs_mk_dir (NULL, "sbp", NULL); + for (j=0;j. +CONFIG_INDYDOG + Hardware driver for the Indy's/I2's watchdog. This is a + watchdog timer that will reboot the machine after a 60 second + timer expired and no process has written to /dev/watchdog during + that time. + CONFIG_60XX_WDT This driver can be used with the watchdog timer found on some single board computers, namely the 6010 PII based computer. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/Config.in linux-2.5/drivers/char/Config.in --- linux-2.5.20/drivers/char/Config.in Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/char/Config.in Mon Jun 3 17:10:21 2002 @@ -7,6 +7,9 @@ bool 'Virtual terminal' CONFIG_VT if [ "$CONFIG_VT" = "y" ]; then bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE + if [ "$CONFIG_IA64" = "y" ]; then + bool 'Support for serial console port described by EFI HCDP table' CONFIG_SERIAL_HCDP + fi fi tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL if [ "$CONFIG_SERIAL" = "y" ]; then @@ -16,9 +19,6 @@ tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL fi fi -if [ "$CONFIG_ACPI" = "y" -a "$CONFIG_IA64" = "y" ]; then - bool ' Support for serial ports defined by ACPI tables' CONFIG_SERIAL_ACPI -fi dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS @@ -64,6 +64,41 @@ tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION fi if [ "$CONFIG_MIPS" = "y" ]; then + bool ' TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912 + dep_bool ' Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912 + bool ' Enable Au1000 UART Support' CONFIG_AU1000_UART + if [ "$CONFIG_AU1000_UART" = "y" ]; then + bool ' Enable Au1000 serial console' CONFIG_AU1000_SERIAL_CONSOLE + fi + bool 'TXx927 SIO support' CONFIG_TXX927_SERIAL + if [ "$CONFIG_TXX927_SERIAL" = "y" ]; then + bool 'TXx927 SIO Console support' CONFIG_TXX927_SERIAL_CONSOLE + fi + if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then + bool ' Support for sb1250 onchip DUART' CONFIG_SIBYTE_SB1250_DUART + if [ "$CONFIG_SIBYTE_SB1250_DUART" = "y" ]; then + bool ' Console on SB1250 DUART' CONFIG_SIBYTE_SB1250_DUART_CONSOLE + if [ "$CONFIG_SIBYTE_SB1250_DUART_CONSOLE" = "y" ]; then + define_bool CONFIG_SERIAL_CONSOLE y + fi + int ' Output buffers size (in bytes)' CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE 1024 + bool ' Leave port 1 alone (for kgdb or audio)' CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 + fi + fi + fi +fi +if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then + tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 +fi +if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then + bool 'DC21285 serial port support' CONFIG_SERIAL_21285 + if [ "$CONFIG_SERIAL_21285" = "y" ]; then + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD + fi + bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE + fi + if [ "$CONFIG_MIPS" = "y" ]; then bool ' TMPTX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912 dep_bool ' Console on TMPTX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912 bool ' Enable Au1000 UART Support' CONFIG_AU1000_UART @@ -72,7 +107,7 @@ fi fi fi -if [ "$CONFIG_IT8712" = "y" ]; then +if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then define_bool CONFIG_IT8172_CIR y @@ -82,17 +117,12 @@ bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 bool 'Enable Smart Card Reader 1 Support ' CONFIG_IT8172_SCR1 fi -if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then - tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 -fi -if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'DC21285 serial port support' CONFIG_SERIAL_21285 - if [ "$CONFIG_SERIAL_21285" = "y" ]; then - if [ "$CONFIG_OBSOLETE" = "y" ]; then - bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD - fi - bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE +if [ "$CONFIG_MIPS_IVR" = "y" ]; then + bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD + if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then + define_bool CONFIG_IT8172_CIR y fi + bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then @@ -111,26 +141,6 @@ source drivers/i2c/Config.in -mainmenu_option next_comment -comment 'Mice' -tristate 'Bus Mouse Support' CONFIG_BUSMOUSE -if [ "$CONFIG_BUSMOUSE" != "n" ]; then - dep_tristate ' ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE - dep_tristate ' Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE - dep_tristate ' Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE - if [ "$CONFIG_ADB" = "y" -a "$CONFIG_ADB_KEYBOARD" = "y" ]; then - dep_tristate ' Apple Desktop Bus mouse support (old driver)' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE - fi -fi - -tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE -if [ "$CONFIG_MOUSE" != "n" ]; then - bool ' PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE - tristate ' C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE - tristate ' PC110 digitizer pad support' CONFIG_PC110_PAD -fi -endmenu - tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE if [ "$CONFIG_QIC02_TAPE" != "n" ]; then bool ' Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF @@ -148,18 +158,11 @@ bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT - tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG - tristate ' WDT Watchdog timer' CONFIG_WDT - tristate ' WDT PCI Watchdog timer' CONFIG_WDTPCI - if [ "$CONFIG_WDT" != "n" ]; then - bool ' WDT501 features' CONFIG_WDT_501 - if [ "$CONFIG_WDT_501" = "y" ]; then - bool ' Fan Tachometer' CONFIG_WDT_501_FAN - fi - fi - tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT + tristate ' ALi M7101 PMU Watchdog Timer' CONFIG_ALIM7101_WDT + tristate ' AMD "Elan" SC520 Watchdog Timer' CONFIG_SC520_WDT + tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then @@ -171,8 +174,12 @@ tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT + tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG tristate ' W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT + if [ "$CONFIG_MIPS" = "y" ]; then + dep_tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22 + fi fi endmenu @@ -185,7 +192,12 @@ tristate 'NetWinder flash support' CONFIG_NWFLASH fi -dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI +if [ "$CONFIG_X86" = "y" -o "$CONFIG_X86_64" = "y" ]; then + dep_tristate 'AMD 768 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI +fi +if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then + dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI +fi tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC if [ "$CONFIG_IA64" = "y" ]; then @@ -229,6 +241,13 @@ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then source drivers/char/pcmcia/Config.in +fi +if [ "$CONFIG_MIPS_AU1000" = "y" ]; then + tristate ' Alchemy Au1000 GPIO device support' CONFIG_AU1000_GPIO + tristate ' Au1000/ADS7846 touchscreen support' CONFIG_TS_AU1000_ADS7846 +fi +if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then + tristate ' ITE GPIO' CONFIG_ITE_GPIO fi if [ "$CONFIG_X86" = "y" ]; then diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/Makefile linux-2.5/drivers/char/Makefile --- linux-2.5.20/drivers/char/Makefile Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/char/Makefile Mon Jun 3 16:17:43 2002 @@ -12,22 +12,20 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := busmouse.o console.o keyboard.o sysrq.o \ +export-objs := busmouse.o vt.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o \ sonypi.o tty_io.o tty_ioctl.o generic_serial.o rtc.o \ - ip2main.o + ip2main.o au1000_gpio.o mod-subdirs := ftape drm pcmcia KEYMAP =defkeymap.o KEYBD =pc_keyb.o -CONSOLE =console.o SERIAL =serial.o ifeq ($(ARCH),s390) KEYMAP = KEYBD = - CONSOLE = SERIAL = endif @@ -40,7 +38,6 @@ ifeq ($(ARCH),s390x) KEYMAP = KEYBD = - CONSOLE = SERIAL = endif @@ -48,11 +45,18 @@ ifdef CONFIG_AMIGA KEYBD = amikeyb.o else - KEYBD = + ifndef CONFIG_MAC + KEYBD = + endif endif SERIAL = endif +ifdef CONFIG_Q40 + KEYBD += q40_keyb.o + SERIAL = serial.o +endif + ifeq ($(ARCH),arm) ifneq ($(CONFIG_PC_KEYMAP),y) KEYMAP = @@ -65,28 +69,23 @@ ifeq ($(ARCH),sh) KEYMAP = KEYBD = - CONSOLE = ifeq ($(CONFIG_SH_HP600),y) KEYMAP = defkeymap.o KEYBD = scan_keyb.o hp600_keyb.o - CONSOLE = console.o endif ifeq ($(CONFIG_SH_DMIDA),y) # DMIDA does not connect the HD64465 PS/2 keyboard port # but we allow for USB keyboards to be plugged in. KEYMAP = defkeymap.o KEYBD = # hd64465_keyb.o pc_keyb.o - CONSOLE = console.o endif ifeq ($(CONFIG_SH_EC3104),y) KEYMAP = defkeymap.o KEYBD = ec3104_keyb.o - CONSOLE = console.o endif ifeq ($(CONFIG_SH_DREAMCAST),y) KEYMAP = defkeymap.o KEYBD = - CONSOLE = console.o endif endif @@ -114,12 +113,17 @@ KEYMAP = qtronixmap.o endif -obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o +ifeq ($(CONFIG_DUMMY_KEYB),y) + KEYBD = dummy_keyb.o +endif + +obj-$(CONFIG_VT) += vt.o vt_ioctl.o decvte.o vc_screen.o consolemap.o consolemap_deftbl.o selection.o obj-$(CONFIG_SERIAL) += $(SERIAL) -obj-$(CONFIG_SERIAL_ACPI) += acpi_serial.o +obj-$(CONFIG_SERIAL_ACPI) += hcdp_serial.o obj-$(CONFIG_SERIAL_21285) += serial_21285.o obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o +obj-$(CONFIG_TS_AU1000_ADS7846) += au1000_ts.o ifndef CONFIG_SUN_KEYBOARD obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD) @@ -137,6 +141,7 @@ obj-$(CONFIG_CYCLADES) += cyclades.o obj-$(CONFIG_STALLION) += stallion.o obj-$(CONFIG_ISTALLION) += istallion.o +obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o obj-$(CONFIG_RISCOM8) += riscom8.o obj-$(CONFIG_ISI) += isicom.o @@ -156,9 +161,8 @@ obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o +obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o -obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o -obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_BUSMOUSE) += busmouse.o @@ -166,12 +170,7 @@ obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_APPLICOM) += applicom.o obj-$(CONFIG_SONYPI) += sonypi.o -obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o -obj-$(CONFIG_82C710_MOUSE) += qpmouse.o -obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o obj-$(CONFIG_ATARIMOUSE) += atarimouse.o -obj-$(CONFIG_ADBMOUSE) += adbmouse.o -obj-$(CONFIG_PC110_PAD) += pc110pad.o obj-$(CONFIG_RTC) += rtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o ifeq ($(CONFIG_PPC),) @@ -181,6 +180,12 @@ obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o +obj-$(CONFIG_AMD_RNG) += amd768_rng.o + +obj-$(CONFIG_ITE_GPIO) += ite_gpio.o +obj-$(CONFIG_AU1000_GPIO) += au1000_gpio.o +obj-$(CONFIG_COBALT_LCD) += lcd.o + obj-$(CONFIG_QIC02_TAPE) += tpqic02.o obj-$(CONFIG_FTAPE) += ftape/ obj-$(CONFIG_H8) += h8.o @@ -200,6 +205,8 @@ obj-$(CONFIG_IB700_WDT) += ib700wdt.o obj-$(CONFIG_MIXCOMWD) += mixcomwd.o obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o +obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o +obj-$(CONFIG_SC520_WDT) += sc520_wdt.o obj-$(CONFIG_WDT) += wdt.o obj-$(CONFIG_WDTPCI) += wdt_pci.o obj-$(CONFIG_21285_WATCHDOG) += wdt285.o @@ -208,6 +215,10 @@ obj-$(CONFIG_MACHZ_WDT) += machzwd.o obj-$(CONFIG_SH_WDT) += shwdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o +obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o +obj-$(CONFIG_INDYDOG) += indydog.o +obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o +obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o obj-$(CONFIG_MWAVE) += mwave/ obj-$(CONFIG_AGP) += agp/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/adbmouse.c linux-2.5/drivers/char/adbmouse.c --- linux-2.5.20/drivers/char/adbmouse.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/char/adbmouse.c Thu Jan 1 01:00:00 1970 @@ -1,209 +0,0 @@ -/* - * Macintosh ADB Mouse driver for Linux - * - * 27 Oct 1997 Michael Schmitz - * logitech fixes by anthony tong - * further hacking by Paul Mackerras - * - * Apple mouse protocol according to: - * - * Device code shamelessly stolen from: - */ -/* - * Atari Mouse Driver for Linux - * by Robert de Vries (robert@and.nl) 19Jul93 - * - * 16 Nov 1994 Andreas Schwab - * Compatibility with busmouse - * Support for three button mouse (shamelessly stolen from MiNT) - * third button wired to one of the joystick directions on joystick 1 - * - * 1996/02/11 Andreas Schwab - * Module support - * Allow multiple open's - * - * Converted to use new generic busmouse code. 11 July 1998 - * Russell King - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __powerpc__ -#include -#endif -#if defined(__mc68000__) || defined(MODULE) -#include -#endif - -#include "busmouse.h" - -static int msedev; -static unsigned char adb_mouse_buttons[16]; - -extern void (*adb_mouse_interrupt_hook)(unsigned char *, int); -extern int adb_emulate_buttons; -extern int adb_button2_keycode; -extern int adb_button3_keycode; - -/* - * XXX: need to figure out what ADB mouse packets mean ... - * This is the stuff stolen from the Atari driver ... - */ -static void adb_mouse_interrupt(unsigned char *buf, int nb) -{ - int buttons, id; - char dx, dy; - - /* - Handler 1 -- 100cpi original Apple mouse protocol. - Handler 2 -- 200cpi original Apple mouse protocol. - - For Apple's standard one-button mouse protocol the data array will - contain the following values: - - BITS COMMENTS - data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. - data[1] = bxxx xxxx First button and x-axis motion. - data[2] = byyy yyyy Second button and y-axis motion. - - Handler 4 -- Apple Extended mouse protocol. - - For Apple's 3-button mouse protocol the data array will contain the - following values: - - BITS COMMENTS - data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. - data[1] = bxxx xxxx Left button and x-axis motion. - data[2] = byyy yyyy Second button and y-axis motion. - data[3] = byyy bxxx Third button and fourth button. - Y is additiona. high bits of y-axis motion. - X is additional high bits of x-axis motion. - - 'buttons' here means 'button down' states! - Button 1 (left) : bit 2, busmouse button 3 - Button 2 (right) : bit 0, busmouse button 1 - Button 3 (middle): bit 1, busmouse button 2 - */ - - /* x/y and buttons swapped */ - - id = (buf[0] >> 4) & 0xf; - - buttons = adb_mouse_buttons[id]; - - /* button 1 (left, bit 2) */ - buttons = (buttons & 3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */ - - /* button 2 (middle) */ - buttons = (buttons & 5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */ - - /* button 3 (right) present? - * on a logitech mouseman, the right and mid buttons sometimes behave - * strangely until they both have been pressed after booting. */ - /* data valid only if extended mouse format ! */ - if (nb >= 4) - buttons = (buttons & 6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */ - - adb_mouse_buttons[id] = buttons; - - /* a button is down if it is down on any mouse */ - for (id = 0; id < 16; ++id) - buttons &= adb_mouse_buttons[id]; - - dx = ((buf[2] & 0x7f) < 64 ? (buf[2] & 0x7f) : (buf[2] & 0x7f) - 128); - dy = ((buf[1] & 0x7f) < 64 ? (buf[1] & 0x7f) : (buf[1] & 0x7f) - 128); - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); - - if (console_loglevel >= 8) - printk(" %X %X %X dx %d dy %d \n", - buf[1], buf[2], buf[3], dx, dy); -} - -static int release_mouse(struct inode *inode, struct file *file) -{ - adb_mouse_interrupt_hook = NULL; - /* - * FIXME?: adb_mouse_interrupt_hook may still be executing - * on another CPU. - */ - return 0; -} - -static int open_mouse(struct inode *inode, struct file *file) -{ - adb_mouse_interrupt_hook = adb_mouse_interrupt; - return 0; -} - -static struct busmouse adb_mouse = -{ - ADB_MOUSE_MINOR, "adbmouse", THIS_MODULE, open_mouse, release_mouse, 7 -}; - -static int __init adb_mouse_init(void) -{ -#ifdef __powerpc__ - if ((_machine != _MACH_chrp) && (_machine != _MACH_Pmac)) - return -ENODEV; -#endif -#ifdef __mc68000__ - if (!MACH_IS_MAC) - return -ENODEV; -#endif - /* all buttons up */ - memset(adb_mouse_buttons, 7, sizeof(adb_mouse_buttons)); - - msedev = register_busmouse(&adb_mouse); - if (msedev < 0) - printk(KERN_WARNING "Unable to register ADB mouse driver.\n"); - else - printk(KERN_INFO "Macintosh ADB mouse driver installed.\n"); - - return msedev < 0 ? msedev : 0; -} - -#ifndef MODULE - -/* - * XXX this function is misnamed. - * It is called if the kernel is booted with the adb_buttons=xxx - * option, which is about using ADB keyboard buttons to emulate - * mouse buttons. -- paulus - */ -static int __init adb_mouse_setup(char *str) -{ - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - if (ints[0] >= 1) { - adb_emulate_buttons = ints[1]; - if (ints[0] >= 2) - adb_button2_keycode = ints[2]; - if (ints[0] >= 3) - adb_button3_keycode = ints[3]; - } - return 1; -} - -__setup("adb_buttons=", adb_mouse_setup); - -#endif /* !MODULE */ - -static void __exit adb_mouse_cleanup(void) -{ - unregister_busmouse(msedev); -} - -module_init(adb_mouse_init); -module_exit(adb_mouse_cleanup); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/alim7101_wdt.c linux-2.5/drivers/char/alim7101_wdt.c --- linux-2.5.20/drivers/char/alim7101_wdt.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/alim7101_wdt.c Sat Apr 13 15:42:55 2002 @@ -0,0 +1,335 @@ +/* + * ALi M7101 PMU Computer Watchdog Timer driver for Linux 2.4.x + * + * Based on w83877f_wdt.c by Scott Jennings + * and the Cobalt kernel WDT timer driver by Tim Hockin + * + * + * (c)2002 Steve Hill + * + * Theory of operation: + * A Watchdog Timer (WDT) is a hardware circuit that can + * reset the computer system in case of a software fault. + * You probably knew that already. + * + * Usually a userspace daemon will notify the kernel WDT driver + * via the /proc/watchdog special device file that userspace is + * still alive, at regular intervals. When such a notification + * occurs, the driver will usually tell the hardware watchdog + * that everything is in order, and that the watchdog should wait + * for yet another little while to reset the system. + * If userspace fails (RAM error, kernel bug, whatever), the + * notifications cease to occur, and the hardware watchdog will + * reset the system (causing a reboot) after the timeout occurs. + * + * This WDT driver is different from most other Linux WDT + * drivers in that the driver will ping the watchdog by itself, + * because this particular WDT has a very short timeout (1.6 + * seconds) and it would be insane to count on any userspace + * daemon always getting scheduled within that time frame. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OUR_NAME "alim7101_wdt" + +#define WDT_ENABLE 0x9C +#define WDT_DISABLE 0x8C + +#define ALI_7101_WDT 0x92 +#define ALI_WDT_ARM 0x01 + +/* + * We're going to use a 1 second timeout. + * If we reset the watchdog every ~250ms we should be safe. */ + +#define WDT_INTERVAL (HZ/4+1) + +/* + * We must not require too good response from the userspace daemon. + * Here we require the userspace daemon to send us a heartbeat + * char to /dev/watchdog every 30 seconds. + */ + +#define WDT_HEARTBEAT (HZ * 30) + +static void wdt_timer_ping(unsigned long); +static struct timer_list timer; +static unsigned long next_heartbeat; +static unsigned long wdt_is_open; +static int wdt_expect_close; +static struct pci_dev *alim7101_pmu; + +/* + * Whack the dog + */ + +static void wdt_timer_ping(unsigned long data) +{ + /* If we got a heartbeat pulse within the WDT_US_INTERVAL + * we agree to ping the WDT + */ + char tmp; + + if(time_before(jiffies, next_heartbeat)) + { + /* Ping the WDT (this is actually a disarm/arm sequence) */ + pci_read_config_byte(alim7101_pmu, 0x92, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); + pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); + } else { + printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + } + /* Re-set the timer interval */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); +} + +/* + * Utility routines + */ + +static void wdt_change(int writeval) +{ + char tmp; + + pci_read_config_byte(alim7101_pmu, 0x92, &tmp); + if (writeval == WDT_ENABLE) + pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); + else + pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); +} + +static void wdt_startup(void) +{ + next_heartbeat = jiffies + WDT_HEARTBEAT; + + /* We must enable before we kick off the timer in case the timer + occurs as we ping it */ + + wdt_change(WDT_ENABLE); + + /* Start the timer */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + + + printk(OUR_NAME ": Watchdog timer is now enabled.\n"); +} + +static void wdt_turnoff(void) +{ + /* Stop the timer */ + del_timer_sync(&timer); + wdt_change(WDT_DISABLE); + printk(OUR_NAME ": Watchdog timer is now disabled...\n"); +} + +/* + * /dev/watchdog handling + */ + +static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +{ + /* We can't seek */ + if(ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count) + { + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++) + if(buf[ofs] == 'V') + wdt_expect_close = 1; + + /* someone wrote to us, we should restart timer */ + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 1; + }; + return 0; +} + +static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos) +{ + /* No can do */ + return -EINVAL; +} + +static int fop_open(struct inode * inode, struct file * file) +{ + /* Just in case we're already talking to someone... */ + if(test_and_set_bit(0, &wdt_is_open)) + return -EBUSY; + /* Good, fire up the show */ + wdt_startup(); + return 0; +} + +static int fop_close(struct inode * inode, struct file * file) +{ +#ifdef CONFIG_WDT_NOWAYOUT + if(wdt_expect_close) + wdt_turnoff(); + else { + printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); + } +#else + wdt_turnoff(); +#endif + clear_bit(0, &wdt_is_open); + return 0; +} + +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident= + { + 0, + 1, + "ALiM7101" + }; + + switch(cmd) + { + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 0; + default: + return -ENOTTY; + } +} + +static struct file_operations wdt_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + read: fop_read, + write: fop_write, + open: fop_open, + release: fop_close, + ioctl: fop_ioctl +}; + +static struct miscdevice wdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wdt_fops +}; + +/* + * Notifier for system down + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +{ + if (code==SYS_DOWN || code==SYS_HALT) wdt_turnoff(); + if (code==SYS_RESTART) { + /* + * Cobalt devices have no way of rebooting themselves other than + * getting the watchdog to pull reset, so we restart the watchdog on + * reboot with no heartbeat + */ + wdt_change(WDT_ENABLE); + printk(OUR_NAME ": Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n"); + }; + return NOTIFY_DONE; +} + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier= +{ + wdt_notify_sys, + 0, + 0 +}; + +static void __exit alim7101_wdt_unload(void) +{ + wdt_turnoff(); + /* Deregister */ + misc_deregister(&wdt_miscdev); + unregister_reboot_notifier(&wdt_notifier); +} + +static int __init alim7101_wdt_init(void) +{ + int rc = -EBUSY; + struct pci_dev *ali1543_south; + char tmp; + + printk(KERN_INFO OUR_NAME ": Steve Hill .\n"); + alim7101_pmu = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,NULL); + if (!alim7101_pmu) { + printk(KERN_INFO OUR_NAME ": ALi M7101 PMU not present - WDT not set\n"); + return -EBUSY; + }; + + /* Set the WDT in the PMU to 1 second */ + pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02); + + ali1543_south = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); + if (!ali1543_south) { + printk(KERN_INFO OUR_NAME ": ALi 1543 South-Bridge not present - WDT not set\n"); + return -EBUSY; + }; + pci_read_config_byte(ali1543_south, 0x5e, &tmp); + if ((tmp & 0x1e) != 0x12) { + printk(KERN_INFO OUR_NAME ": ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n"); + return -EBUSY; + }; + + init_timer(&timer); + timer.function = wdt_timer_ping; + timer.data = 1; + + rc = misc_register(&wdt_miscdev); + if (rc) + return rc; + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) { + misc_deregister(&wdt_miscdev); + return rc; + }; + + printk(KERN_INFO OUR_NAME ": WDT driver for ALi M7101 initialised.\n"); + return 0; +} + +module_init(alim7101_wdt_init); +module_exit(alim7101_wdt_unload); + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Steve Hill"); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/amd768_rng.c linux-2.5/drivers/char/amd768_rng.c --- linux-2.5.20/drivers/char/amd768_rng.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/amd768_rng.c Sun Apr 14 21:43:55 2002 @@ -0,0 +1,295 @@ +/* + Hardware driver for the AMD 768 Random Number Generator (RNG) + (c) Copyright 2001 Red Hat Inc + + derived from + + Hardware driver for Intel i810 Random Number Generator (RNG) + Copyright 2000,2001 Jeff Garzik + Copyright 2000,2001 Philipp Rumpf + + Please read Documentation/i810_rng.txt for details on use. + + ---------------------------------------------------------- + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * core module and version information + */ +#define RNG_VERSION "0.1.0" +#define RNG_MODULE_NAME "amd768_rng" +#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION +#define PFX RNG_MODULE_NAME ": " + + +/* + * debugging macros + */ +#undef RNG_DEBUG /* define to enable copious debugging info */ + +#ifdef RNG_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#undef RNG_NDEBUG /* define to disable lightweight runtime checks */ +#ifdef RNG_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + +#define RNG_MISCDEV_MINOR 183 /* official */ + +/* + * various RNG status variables. they are globals + * as we only support a single RNG device + */ + +static u32 pmbase; /* PMxx I/O base */ +static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */ + + +/* + * inlined helper functions for accessing RNG registers + */ + +static inline int rng_data_present (void) +{ + return inl(pmbase+0xF4) & 1; +} + + +static inline int rng_data_read (void) +{ + return inl(pmbase+0xF0); +} + +static int rng_dev_open (struct inode *inode, struct file *filp) +{ + if ((filp->f_mode & FMODE_READ) == 0) + return -EINVAL; + if (filp->f_mode & FMODE_WRITE) + return -EINVAL; + + /* wait for device to become free */ + if (filp->f_flags & O_NONBLOCK) { + if (down_trylock (&rng_open_sem)) + return -EAGAIN; + } else { + if (down_interruptible (&rng_open_sem)) + return -ERESTARTSYS; + } + return 0; +} + + +static int rng_dev_release (struct inode *inode, struct file *filp) +{ + up(&rng_open_sem); + return 0; +} + + +static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size, + loff_t * offp) +{ + static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; + int have_data; + u32 data = 0; + ssize_t ret = 0; + + while (size) { + spin_lock(&rng_lock); + + have_data = 0; + if (rng_data_present()) { + data = rng_data_read(); + have_data = 4; + } + + spin_unlock (&rng_lock); + + while (have_data > 0) { + if (put_user((u8)data, buf++)) { + ret = ret ? : -EFAULT; + break; + } + size--; + ret++; + have_data--; + data>>=8; + } + + if (filp->f_flags & O_NONBLOCK) + return ret ? : -EAGAIN; + + if(need_resched()) + { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + else + udelay(200); /* FIXME: We could poll for 250uS ?? */ + + if (signal_pending (current)) + return ret ? : -ERESTARTSYS; + } + return ret; +} + + +static struct file_operations rng_chrdev_ops = { + owner: THIS_MODULE, + open: rng_dev_open, + release: rng_dev_release, + read: rng_dev_read, +}; + + +static struct miscdevice rng_miscdev = { + RNG_MISCDEV_MINOR, + RNG_MODULE_NAME, + &rng_chrdev_ops, +}; + + +/* + * rng_init_one - look for and attempt to init a single RNG + */ +static int __init rng_init_one (struct pci_dev *dev) +{ + int rc; + u8 rnen; + + DPRINTK ("ENTER\n"); + + rc = misc_register (&rng_miscdev); + if (rc) { + printk (KERN_ERR PFX "cannot register misc device\n"); + DPRINTK ("EXIT, returning %d\n", rc); + goto err_out; + } + + pci_read_config_dword(dev, 0x58, &pmbase); + + pmbase&=0x0000FF00; + + if(pmbase == 0) + { + printk (KERN_ERR PFX "power management base not set\n"); + DPRINTK ("EXIT, returning %d\n", rc); + goto err_out_free_miscdev; + } + + pci_read_config_byte(dev, 0x40, &rnen); + rnen|=(1<<7); /* RNG on */ + pci_write_config_byte(dev, 0x40, rnen); + + pci_read_config_byte(dev, 0x41, &rnen); + rnen|=(1<<7); /* PMIO enable */ + pci_write_config_byte(dev, 0x41, rnen); + + printk(KERN_INFO PFX "AMD768 system management I/O registers at 0x%X.\n", pmbase); + DPRINTK ("EXIT, returning 0\n"); + return 0; + +err_out_free_miscdev: + misc_deregister (&rng_miscdev); +err_out: + return rc; +} + + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ +static struct pci_device_id rng_pci_tbl[] __initdata = { + { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; +MODULE_DEVICE_TABLE (pci, rng_pci_tbl); + + +MODULE_AUTHOR("Alan Cox, Jeff Garzik, Philipp Rumpf, Matt Sottek"); +MODULE_DESCRIPTION("AMD 768 Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL"); + + +/* + * rng_init - initialize RNG module + */ +static int __init rng_init (void) +{ + int rc; + struct pci_dev *pdev; + + DPRINTK ("ENTER\n"); + + init_MUTEX (&rng_open_sem); + + pci_for_each_dev(pdev) { + if (pci_match_device (rng_pci_tbl, pdev) != NULL) + goto match; + } + + DPRINTK ("EXIT, returning -ENODEV\n"); + return -ENODEV; + +match: + rc = rng_init_one (pdev); + if (rc) + return rc; + + printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * rng_init - shutdown RNG module + */ +static void __exit rng_cleanup (void) +{ + DPRINTK ("ENTER\n"); + misc_deregister (&rng_miscdev); + DPRINTK ("EXIT\n"); +} + + +module_init (rng_init); +module_exit (rng_cleanup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/amigamouse.c linux-2.5/drivers/char/amigamouse.c --- linux-2.5.20/drivers/char/amigamouse.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/char/amigamouse.c Thu Jan 1 01:00:00 1970 @@ -1,213 +0,0 @@ -/* - * Amiga Mouse Driver for Linux 68k by Michael Rausch - * based upon: - * - * Logitech Bus Mouse Driver for Linux - * by James Banks - * - * Mods by Matthew Dillon - * calls verify_area() - * tracks better when X is busy or paging - * - * Heavily modified by David Giller - * changed from queue- to counter- driven - * hacked out a (probably incorrect) mouse_poll - * - * Modified again by Nathan Laredo to interface with - * 0.96c-pl1 IRQ handling changes (13JUL92) - * didn't bother touching poll code. - * - * Modified the poll() code blindly to conform to the VFS - * requirements. 92.07.14 - Linus. Somebody should test it out. - * - * Modified by Johan Myreen to make room for other mice (9AUG92) - * removed assignment chr_fops[10] = &mouse_fops; see mouse.c - * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public. - * renamed this file mouse.c => busmouse.c - * - * Modified for use in the 1.3 kernels by Jes Sorensen. - * - * Moved the isr-allocation to the mouse_{open,close} calls, as there - * is no reason to service the mouse in the vertical blank isr if - * the mouse is not in use. Jes Sorensen - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "busmouse.h" - -#if AMIGA_OLD_INT -#define AMI_MSE_INT_ON() mouseint_allowed = 1 -#define AMI_MSE_INT_OFF() mouseint_allowed = 0 -static int mouseint_allowed; -#endif - -static int msedev; - -static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp) -{ - static int lastx=0, lasty=0; - int dx, dy; - int nx, ny; - unsigned char buttons; - - unsigned short joy0dat, potgor; - -#if AMIGA_OLD_INT - if(!mouseint_allowed) - return; - AMI_MSE_INT_OFF(); -#endif - - /* - * This routine assumes, just like Kickstart, that the mouse - * has not moved more than 127 ticks since last VBL. - */ - - joy0dat = custom.joy0dat; - - nx = joy0dat & 0xff; - ny = joy0dat >> 8; - - dx = nx - lastx; - if (dx < - 127) - dx = (256 + nx) - lastx; - - if (dx > 127) - dx = (nx - 256) - lastx; - - dy = ny - lasty; - if (dy < - 127) - dy = (256 + ny) - lasty; - - if (dy > 127) - dy = (ny - 256) - lasty; - - lastx = nx; - lasty = ny; - -#if 0 - dx = -lastdx; - dx += (lastdx = joy0dat & 0xff); - if (dx < -127) - dx = -255-dx; /* underrun */ - else - if (dx > 127) - dx = 255-dx; /* overflow */ - - dy = -lastdy; - dy += (lastdy = joy0dat >> 8); - if (dy < -127) - dy = -255-dy; - else - if (dy > 127) - dy = 255-dy; -#endif - - - potgor = custom.potgor; - buttons = (ciaa.pra & 0x40 ? 4 : 0) | /* left button; note that the bits are low-active, as are the expected results -> double negation */ -#if 1 - (potgor & 0x0100 ? 2 : 0) | /* middle button; emulation goes here */ -#endif - (potgor & 0x0400 ? 1 : 0); /* right button */ - - - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); -#if AMIGA_OLD_INT - AMI_MSE_INT_ON(); -#endif -} - -/* - * close access to the mouse - */ - -static int release_mouse(struct inode * inode, struct file * file) -{ - free_irq(IRQ_AMIGA_VERTB, mouse_interrupt); -#if AMIGA_OLD_INT - AMI_MSE_INT_OFF(); -#endif - return 0; -} - -/* - * open access to the mouse, currently only one open is - * allowed. - */ - -static int open_mouse(struct inode * inode, struct file * file) -{ - /* - * use VBL to poll mouse deltas - */ - - if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0, - "Amiga mouse", mouse_interrupt)) { - printk(KERN_INFO "Installing Amiga mouse failed.\n"); - return -EIO; - } - -#if AMIGA_OLD_INT - AMI_MSE_INT_ON(); -#endif - return 0; -} - -static struct busmouse amigamouse = { - AMIGAMOUSE_MINOR, "amigamouse", THIS_MODULE, open_mouse, release_mouse, 7 -}; - -static int __init amiga_mouse_init(void) -{ - if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE)) - return -ENODEV; - if (!request_mem_region(CUSTOM_PHYSADDR+10, 2, "amigamouse [Denise]")) - return -EBUSY; - - custom.joytest = 0; /* reset counters */ -#if AMIGA_OLD_INT - AMI_MSE_INT_OFF(); -#endif - msedev = register_busmouse(&amigamouse); - if (msedev < 0) - printk(KERN_WARNING "Unable to install Amiga mouse driver.\n"); - else - printk(KERN_INFO "Amiga mouse installed.\n"); - return msedev < 0 ? msedev : 0; -} - -static void __exit amiga_mouse_exit(void) -{ - unregister_busmouse(msedev); - release_mem_region(CUSTOM_PHYSADDR+10, 2); -} - -module_init(amiga_mouse_init); -module_exit(amiga_mouse_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/amiserial.c linux-2.5/drivers/char/amiserial.c --- linux-2.5.20/drivers/char/amiserial.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/char/amiserial.c Wed Mar 27 13:07:16 2002 @@ -2143,7 +2143,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/atixlmouse.c linux-2.5/drivers/char/atixlmouse.c --- linux-2.5.20/drivers/char/atixlmouse.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/char/atixlmouse.c Thu Jan 1 01:00:00 1970 @@ -1,151 +0,0 @@ -/* - * ATI XL Bus Mouse Driver for Linux - * by Bob Harris (rth@sparta.com) - * - * Uses VFS interface for linux 0.98 (01OCT92) - * - * Modified by Chris Colohan (colohan@eecg.toronto.edu) - * Modularised 8-Sep-95 Philip Blundell - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - * - * version 0.3a - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "busmouse.h" - -#define ATIXL_MOUSE_IRQ 5 /* H/W interrupt # set up on ATIXL board */ -#define ATIXL_BUSMOUSE 3 /* Minor device # (mknod c 10 3 /dev/bm) */ - -/* ATI XL Inport Busmouse Definitions */ - -#define ATIXL_MSE_DATA_PORT 0x23d -#define ATIXL_MSE_SIGNATURE_PORT 0x23e -#define ATIXL_MSE_CONTROL_PORT 0x23c - -#define ATIXL_MSE_READ_BUTTONS 0x00 -#define ATIXL_MSE_READ_X 0x01 -#define ATIXL_MSE_READ_Y 0x02 - -/* Some nice ATI XL macros */ - -/* Select IR7, HOLD UPDATES (INT ENABLED), save X,Y */ -#define ATIXL_MSE_DISABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ - outb( (0x20 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } - -/* Select IR7, Enable updates (INT ENABLED) */ -#define ATIXL_MSE_ENABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ - outb( (0xdf & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } - -/* Select IR7 - Mode Register, NO INTERRUPTS */ -#define ATIXL_MSE_INT_OFF() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ - outb( (0xe7 & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } - -/* Select IR7 - Mode Register, DATA INTERRUPTS ENABLED */ -#define ATIXL_MSE_INT_ON() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ - outb( (0x08 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } - -/* Same general mouse structure */ - -static int msedev; - -static void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - char dx, dy, buttons; - - ATIXL_MSE_DISABLE_UPDATE(); /* Note that interrupts are still enabled */ - outb(ATIXL_MSE_READ_X, ATIXL_MSE_CONTROL_PORT); /* Select IR1 - X movement */ - dx = inb( ATIXL_MSE_DATA_PORT); - outb(ATIXL_MSE_READ_Y, ATIXL_MSE_CONTROL_PORT); /* Select IR2 - Y movement */ - dy = inb( ATIXL_MSE_DATA_PORT); - outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */ - buttons = inb( ATIXL_MSE_DATA_PORT); - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); - ATIXL_MSE_ENABLE_UPDATE(); -} - -static int release_mouse(struct inode * inode, struct file * file) -{ - ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */ - free_irq(ATIXL_MOUSE_IRQ, NULL); - return 0; -} - -static int open_mouse(struct inode * inode, struct file * file) -{ - if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL)) - return -EBUSY; - ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */ - return 0; -} - -static struct busmouse atixlmouse = { - ATIXL_BUSMOUSE, "atixl", THIS_MODULE, open_mouse, release_mouse, 0 -}; - -static int __init atixl_busmouse_init(void) -{ - unsigned char a,b,c; - - /* - * We must request the resource and claim it atomically - * nowdays. We can throw it away on error. Otherwise we - * may race another module load of the same I/O - */ - - if (!request_region(ATIXL_MSE_DATA_PORT, 3, "atixlmouse")) - return -EIO; - - a = inb( ATIXL_MSE_SIGNATURE_PORT ); /* Get signature */ - b = inb( ATIXL_MSE_SIGNATURE_PORT ); - c = inb( ATIXL_MSE_SIGNATURE_PORT ); - if (( a != b ) && ( a == c )) - printk(KERN_INFO "\nATI Inport "); - else - { - release_region(ATIXL_MSE_DATA_PORT,3); - return -EIO; - } - outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */ - outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */ - outb(0x0a, ATIXL_MSE_DATA_PORT); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */ - - msedev = register_busmouse(&atixlmouse); - if (msedev < 0) - { - printk("Bus mouse initialisation error.\n"); - release_region(ATIXL_MSE_DATA_PORT,3); /* Was missing */ - } - else - printk("Bus mouse detected and installed.\n"); - return msedev < 0 ? msedev : 0; -} - -static void __exit atixl_cleanup (void) -{ - release_region(ATIXL_MSE_DATA_PORT, 3); - unregister_busmouse(msedev); -} - -module_init(atixl_busmouse_init); -module_exit(atixl_cleanup); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/au1000_gpio.c linux-2.5/drivers/char/au1000_gpio.c --- linux-2.5.20/drivers/char/au1000_gpio.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/au1000_gpio.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,270 @@ +/* + * FILE NAME au1000_gpio.c + * + * BRIEF MODULE DESCRIPTION + * Driver for Alchemy Au1000 GPIO. + * + * Author: MontaVista Software, Inc. + * Steve Longerbeam + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "0.01" + +static const struct { + u32 active_hi; + u32 avail_mask; +} pinfunc_to_avail[15] = { + {1, 0x7<<16}, // 0 = SSI0 / GPIO[18:16] + {-1, 0}, // 1 = AC97 / SSI1 + {1, 1<<19}, // 2 = IRDA / GPIO19 + {1, 1<<20}, // 3 = UART0 / GPIO20 + {1, 0x1f<<24}, // 4 = NIC2 / GPIO[28:24] + {1, 0x7<<29}, // 5 = I2S / GPIO[31:29] + {0, 1<<8}, // 6 = I2SDI / GPIO8 + {0, 0x3f<<9}, // 7 = UART3 / GPIO[14:9] + {0, 1<<15}, // 8 = IRFIRSEL / GPIO15 + {0, 1<<2}, // 9 = EXTCLK0 or OSC / GPIO2 + {0, 1<<3}, // 10 = EXTCLK1 / GPIO3 + {0, 1<<6}, // 11 = SMROMCKE / GPIO6 + {1, 1<<21}, // 12 = UART1 / GPIO21 + {1, 1<<22}, // 13 = UART2 / GPIO22 + {1, 1<<23} // 14 = UART3 / GPIO23 +}; + + +u32 get_au1000_avail_gpio_mask(void) +{ + int i; + u32 pinfunc = inl(SYS_PINFUNC); + u32 avail_mask = 0; // start with no gpio available + + // first, check for GPIO's reprogrammed as peripheral pins + for (i=0; i<15; i++) { + if (pinfunc_to_avail[i].active_hi < 0) + continue; + if (!(pinfunc_to_avail[i].active_hi ^ + ((pinfunc & (1< +#include + +#include +#include +#include +#include +#include +#include /* request_region */ +#include /* mark_bh */ +#include /* get_user,copy_to_user */ +#include +#include + +#define TS_NAME "au1000-ts" +#define TS_MAJOR 11 + +#define PFX TS_NAME +#define AU1000_TS_DEBUG 1 + +#ifdef AU1000_TS_DEBUG +#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) + + +// SSI Status register bit defines +#define SSISTAT_BF (1<<4) +#define SSISTAT_OF (1<<3) +#define SSISTAT_UF (1<<2) +#define SSISTAT_DONE (1<<1) +#define SSISTAT_BUSY (1<<0) + +// SSI Interrupt Pending and Enable register bit defines +#define SSIINT_OI (1<<3) +#define SSIINT_UI (1<<2) +#define SSIINT_DI (1<<1) + +// SSI Address/Data register bit defines +#define SSIADAT_D (1<<24) +#define SSIADAT_ADDR_BIT 16 +#define SSIADAT_ADDR_MASK (0xff<pressure_eqn == PRESSURE_EQN_2) { + Rt = (ts->x_plate_ohms * ts->x_raw * + (4096 - ts->z1_raw)) / ts->z1_raw; + Rt -= (ts->y_plate_ohms * ts->y_raw); + Rt = (Rt + 2048) >> 12; // round up to nearest ohm + } else { + Rt = (ts->x_plate_ohms * ts->x_raw * + (ts->z2_raw - ts->z1_raw)) / ts->z1_raw; + Rt = (Rt + 2048) >> 12; // round up to nearest ohm + } + + // hysteresis + if (!ts->pendown && Rt > ts->pendown_thresh_ohms) + ts->pendown = 1; + else if (ts->pendown && Rt < ts->penup_thresh_ohms) + ts->pendown = 0; + + if (ts->pendown) { + // Pen is down + // Calculate calibrated X,Y + Xcal = ((ts->cal.xscale * ts->x_raw) >> 8) + ts->cal.xtrans; + Ycal = ((ts->cal.yscale * ts->y_raw) >> 8) + ts->cal.ytrans; + + event.x = (unsigned short)Xcal; + event.y = (unsigned short)Ycal; + event.pressure = (unsigned short)Rt; + + // add this event to the event queue + spin_lock_irqsave(&ts->lock, flags); + ts->event_buf[ts->nextIn++] = event; + if (ts->nextIn == EVENT_BUFSIZE) + ts->nextIn = 0; + if (ts->event_count < EVENT_BUFSIZE) { + ts->event_count++; + } else { + // throw out the oldest event + if (++ts->nextOut == EVENT_BUFSIZE) + ts->nextOut = 0; + } + spin_unlock_irqrestore(&ts->lock, flags); + + // async notify + if (ts->fasync) + kill_fasync(&ts->fasync, SIGIO, POLL_IN); + // wake up any read call + if (waitqueue_active(&ts->wait)) + wake_up_interruptible(&ts->wait); + } +} + + +/* + * Raw X,Y,pressure acquisition timer function. This triggers + * the start of a new acquisition. Its duration between calls + * is the touch screen polling rate. + */ +static void +au1000_acq_timer(unsigned long data) +{ + au1000_ts_t* ts = (au1000_ts_t*)data; + unsigned long flags; + + spin_lock_irqsave(&ts->lock, flags); + + // start acquisition with X coordinate + ts->acq_state = ACQ_X; + // start me up + outl(SSIADAT_D | (MEASURE_12BIT_X << SSIADAT_ADDR_BIT), SSI0_ADATA); + + // schedule next acquire + ts->acq_timer.expires = jiffies + HZ / 100; + add_timer(&ts->acq_timer); + + spin_unlock_irqrestore(&ts->lock, flags); +} + +static void +ssi0_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + au1000_ts_t *ts = (au1000_ts_t*)dev_id; + u32 stat, int_stat, data; + + spin_lock(&ts->lock); + + stat = inl(SSI0_STATUS); + // clear sticky status bits + outl(stat & (SSISTAT_OF|SSISTAT_UF|SSISTAT_DONE), SSI0_STATUS); + + int_stat = inl(SSI0_INT); + // clear sticky intr status bits + outl(int_stat & (SSIINT_OI|SSIINT_UI|SSIINT_DI), SSI0_INT); + + if ((int_stat & (SSIINT_OI|SSIINT_UI|SSIINT_DI)) != SSIINT_DI) { + if (int_stat & SSIINT_OI) + err("overflow"); + if (int_stat & SSIINT_UI) + err("underflow"); + spin_unlock(&ts->lock); + return; + } + + data = inl(SSI0_ADATA) & SSIADAT_DATA_MASK; + + switch (ts->acq_state) { + case IDLE: + break; + case ACQ_X: + ts->x_raw = data; + ts->acq_state = ACQ_Y; + // trigger Y acq + outl(SSIADAT_D | (MEASURE_12BIT_Y << SSIADAT_ADDR_BIT), + SSI0_ADATA); + break; + case ACQ_Y: + ts->y_raw = data; + ts->acq_state = ACQ_Z1; + // trigger Z1 acq + outl(SSIADAT_D | (MEASURE_12BIT_Z1 << SSIADAT_ADDR_BIT), + SSI0_ADATA); + break; + case ACQ_Z1: + ts->z1_raw = data; + if (ts->pressure_eqn == PRESSURE_EQN_2) { + // don't acq Z2, using 2nd eqn for touch pressure + ts->acq_state = IDLE; + // got the raw stuff, now mark BH + queue_task(&ts->chug_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } else { + ts->acq_state = ACQ_Z2; + // trigger Z2 acq + outl(SSIADAT_D | (MEASURE_12BIT_Z2<z2_raw = data; + ts->acq_state = IDLE; + // got the raw stuff, now mark BH + queue_task(&ts->chug_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + break; + } + + spin_unlock(&ts->lock); +} + + +/* +++++++++++++ File operations ++++++++++++++*/ + +static int +au1000_fasync(int fd, struct file *filp, int mode) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + return fasync_helper(fd, filp, mode, &ts->fasync); +} + +static int +au1000_ioctl(struct inode * inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + + switch(cmd) { + case TS_GET_RATE: /* TODO: what is this? */ + break; + case TS_SET_RATE: /* TODO: what is this? */ + break; + case TS_GET_CAL: + copy_to_user((char *)arg, (char *)&ts->cal, sizeof(TS_CAL)); + break; + case TS_SET_CAL: + copy_from_user((char *)&ts->cal, (char *)arg, sizeof(TS_CAL)); + break; + default: + err("unknown cmd %04x", cmd); + return -EINVAL; + } + + return 0; +} + +static unsigned int +au1000_poll(struct file * filp, poll_table * wait) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + poll_wait(filp, &ts->wait, wait); + if (ts->event_count) + return POLLIN | POLLRDNORM; + return 0; +} + +static ssize_t +au1000_read(struct file * filp, char * buf, size_t count, loff_t * l) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + unsigned long flags; + TS_EVENT event; + int i; + + if (ts->event_count == 0) { + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&ts->wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + for (i = count; + i >= sizeof(TS_EVENT); + i -= sizeof(TS_EVENT), buf += sizeof(TS_EVENT)) { + if (ts->event_count == 0) + break; + spin_lock_irqsave(&ts->lock, flags); + event = ts->event_buf[ts->nextOut++]; + if (ts->nextOut == EVENT_BUFSIZE) + ts->nextOut = 0; + if (ts->event_count) + ts->event_count--; + spin_unlock_irqrestore(&ts->lock, flags); + copy_to_user(buf, &event, sizeof(TS_EVENT)); + } + + return count - i; +} + + +static int +au1000_open(struct inode * inode, struct file * filp) +{ + au1000_ts_t* ts; + unsigned long flags; + + filp->private_data = ts = &au1000_ts; + + spin_lock_irqsave(&ts->lock, flags); + + // setup SSI0 config + outl(DEFAULT_SSI_CONFIG, SSI0_CONFIG); + + // clear out SSI0 status bits + outl(SSISTAT_OF|SSISTAT_UF|SSISTAT_DONE, SSI0_STATUS); + // clear out SSI0 interrupt pending bits + outl(SSIINT_OI|SSIINT_UI|SSIINT_DI, SSI0_INT); + + // enable SSI0 interrupts + outl(SSIINT_OI|SSIINT_UI|SSIINT_DI, SSI0_INT_ENABLE); + + /* + * init bh handler that chugs the raw data (calibrates and + * calculates touch pressure). + */ + ts->chug_tq.routine = chug_raw_data; + ts->chug_tq.data = ts; + ts->pendown = 0; // pen up + + // flush event queue + ts->nextIn = ts->nextOut = ts->event_count = 0; + + // Start acquisition timer function + init_timer(&ts->acq_timer); + ts->acq_timer.function = au1000_acq_timer; + ts->acq_timer.data = (unsigned long)ts; + ts->acq_timer.expires = jiffies + HZ / 100; + add_timer(&ts->acq_timer); + + spin_unlock_irqrestore(&ts->lock, flags); + MOD_INC_USE_COUNT; + return 0; +} + +static int +au1000_release(struct inode * inode, struct file * filp) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + unsigned long flags; + + au1000_fasync(-1, filp, 0); + del_timer_sync(&ts->acq_timer); + + spin_lock_irqsave(&ts->lock, flags); + // disable SSI0 interrupts + outl(0, SSI0_INT_ENABLE); + spin_unlock_irqrestore(&ts->lock, flags); + + MOD_DEC_USE_COUNT; + return 0; +} + + +static struct file_operations ts_fops = { + read: au1000_read, + poll: au1000_poll, + ioctl: au1000_ioctl, + fasync: au1000_fasync, + open: au1000_open, + release: au1000_release, +}; + +/* +++++++++++++ End File operations ++++++++++++++*/ + + +int __init +au1000ts_init_module(void) +{ + au1000_ts_t* ts = &au1000_ts; + int ret; + + /* register our character device */ + if ((ret = register_chrdev(TS_MAJOR, TS_NAME, &ts_fops)) < 0) { + err("can't get major number"); + return ret; + } + info("registered"); + + memset(ts, 0, sizeof(au1000_ts_t)); + init_waitqueue_head(&ts->wait); + spin_lock_init(&ts->lock); + + if (!request_region(virt_to_phys((void*)SSI0_STATUS), 0x100, TS_NAME)) { + err("SSI0 ports in use"); + return -ENXIO; + } + + if ((ret = request_irq(AU1000_SSI0_INT, ssi0_interrupt, + SA_SHIRQ | SA_INTERRUPT, TS_NAME, ts))) { + err("could not get IRQ"); + return ret; + } + + // initial calibration values + ts->cal.xscale = -93; + ts->cal.xtrans = 346; + ts->cal.yscale = -64; + ts->cal.ytrans = 251; + + // init pen up/down hysteresis points + ts->pendown_thresh_ohms = DEFAULT_PENDOWN_THRESH_OHMS; + ts->penup_thresh_ohms = DEFAULT_PENUP_THRESH_OHMS; + ts->pressure_eqn = PRESSURE_EQN_2; + // init X and Y plate resistances + ts->x_plate_ohms = DEFAULT_X_PLATE_OHMS; + ts->y_plate_ohms = DEFAULT_Y_PLATE_OHMS; + + // set GPIO to SSI0 function + outl(inl(PIN_FUNCTION) & ~1, PIN_FUNCTION); + + // enable SSI0 clock and bring SSI0 out of reset + outl(0, SSI0_CONTROL); + udelay(1000); + outl(SSIEN_E, SSI0_CONTROL); + udelay(100); + + // FIXME: is this a working baudrate? + ts->clkdiv = 0; + ts->baudrate = calc_baudrate(ts->clkdiv); + outl(ts->clkdiv, SSI0_CLKDIV); + + info("baudrate = %d Hz", ts->baudrate); + + return 0; +} + +void +au1000ts_cleanup_module(void) +{ + // disable clocks and hold in reset + outl(SSIEN_CD, SSI0_CONTROL); + free_irq(AU1000_SSI0_INT, &au1000_ts); + release_region(virt_to_phys((void*)SSI0_STATUS), 0x100); + unregister_chrdev(TS_MAJOR, TS_NAME); +} + +/* Module information */ +MODULE_AUTHOR("Steve Longerbeam, stevel@mvista.com, www.mvista.com"); +MODULE_DESCRIPTION("Au1000/ADS7846 Touch Screen Driver"); + +module_init(au1000ts_init_module); +module_exit(au1000ts_cleanup_module); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/busmouse.c linux-2.5/drivers/char/busmouse.c --- linux-2.5.20/drivers/char/busmouse.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/char/busmouse.c Mon May 6 16:17:50 2002 @@ -157,9 +157,12 @@ struct busmouse_data *mse = (struct busmouse_data *)filp->private_data; int retval; + lock_kernel(); retval = fasync_helper(fd, filp, on, &mse->fasyncptr); if (retval < 0) + unlock_kernel(); return retval; + unlock_kernel(); return 0; } @@ -168,7 +171,6 @@ struct busmouse_data *mse = (struct busmouse_data *)file->private_data; int ret = 0; - lock_kernel(); busmouse_fasync(-1, file, 0); down(&mouse_sem); /* to protect mse->active */ @@ -179,7 +181,6 @@ __MOD_DEC_USE_COUNT(mse->ops->owner); mse->ready = 0; } - unlock_kernel(); up( &mouse_sem); return ret; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/console.c linux-2.5/drivers/char/console.c --- linux-2.5.20/drivers/char/console.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/char/console.c Thu Jan 1 01:00:00 1970 @@ -1,3022 +0,0 @@ -/* - * linux/drivers/char/console.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * Hopefully this will be a rather complete VT102 implementation. - * - * Beeping thanks to John T Kohl. - * - * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics - * Chars, and VT100 enhancements by Peter MacDonald. - * - * Copy and paste function by Andrew Haylett, - * some enhancements by Alessandro Rubini. - * - * Code to check for different video-cards mostly by Galen Hunt, - * - * - * Rudimentary ISO 10646/Unicode/UTF-8 character set support by - * Markus Kuhn, . - * - * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 - * Resizing of consoles, aeb, 940926 - * - * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 - * - * - * User-defined bell sound, new setterm control sequences and printk - * redirection by Martin Mares 19-Nov-95 - * - * APM screenblank bug fixed Takashi Manabe - * - * Merge with the abstract console driver by Geert Uytterhoeven - * , Jan 1997. - * - * Original m68k console driver modifications by - * - * - Arno Griffioen - * - David Carter - * - * Note that the abstract console driver allows all consoles to be of - * potentially different sizes, so the following variables depend on the - * current console (currcons): - * - * - video_num_columns - * - video_num_lines - * - video_size_row - * - can_do_color - * - * The abstract console driver provides a generic interface for a text - * console. It supports VGA text mode, frame buffer based graphical consoles - * and special graphics processors that are only accessible through some - * registers (e.g. a TMS340x0 GSP). - * - * The interface to the hardware is specified using a special structure - * (struct consw) which contains function pointers to console operations - * (see for more information). - * - * Support for changeable cursor shape - * by Pavel Machek , August 1997 - * - * Ported to i386 and con_scrolldelta fixed - * by Emmanuel Marty , April 1998 - * - * Resurrected character buffers in videoram plus lots of other trickery - * by Martin Mares , July 1998 - * - * Removed old-style timers, introduced console_timer, made timer - * deletion SMP-safe. 17Jun00, Andrew Morton - * - * Removed console_lock, enabled interrupts across all console operations - * 13 March 2001, Andrew Morton - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "console_macros.h" - - -const struct consw *conswitchp; - -/* A bitmap for codes <32. A bit of 1 indicates that the code - * corresponding to that bit number invokes some special action - * (such as cursor movement) and should not be displayed as a - * glyph unless the disp_ctrl mode is explicitly enabled. - */ -#define CTRL_ACTION 0x0d00ff81 -#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ - -/* - * Here is the default bell parameters: 750HZ, 1/8th of a second - */ -#define DEFAULT_BELL_PITCH 750 -#define DEFAULT_BELL_DURATION (HZ/8) - -extern void vcs_make_devfs (unsigned int index, int unregister); - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -static struct tty_struct *console_table[MAX_NR_CONSOLES]; -static struct termios *console_termios[MAX_NR_CONSOLES]; -static struct termios *console_termios_locked[MAX_NR_CONSOLES]; -struct vc vc_cons [MAX_NR_CONSOLES]; - -#ifndef VT_SINGLE_DRIVER -static const struct consw *con_driver_map[MAX_NR_CONSOLES]; -#endif - -static int con_open(struct tty_struct *, struct file *); -static void vc_init(unsigned int console, unsigned int rows, - unsigned int cols, int do_clear); -static void blank_screen(unsigned long dummy); -static void gotoxy(int currcons, int new_x, int new_y); -static void save_cur(int currcons); -static void reset_terminal(int currcons, int do_clear); -static void con_flush_chars(struct tty_struct *tty); -static void set_vesa_blanking(unsigned long arg); -static void set_cursor(int currcons); -static void hide_cursor(int currcons); -static void unblank_screen_t(unsigned long dummy); -static void console_callback(void *ignored); - -static int printable; /* Is console ready for printing? */ - -int do_poke_blanked_console; -int console_blanked; - -static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ -static int blankinterval = 10*60*HZ; -static int vesa_off_interval; - -static struct tq_struct console_callback_tq = { - routine: console_callback, -}; - -/* - * fg_console is the current virtual console, - * last_console is the last used one, - * want_console is the console we want to switch to, - * kmsg_redirect is the console for kernel messages, - */ -int fg_console; -int last_console; -int want_console = -1; -int kmsg_redirect; - -/* - * For each existing display, we have a pointer to console currently visible - * on that display, allowing consoles other than fg_console to be refreshed - * appropriately. Unless the low-level driver supplies its own display_fg - * variable, we use this one for the "master display". - */ -static struct vc_data *master_display_fg; - -/* - * Unfortunately, we need to delay tty echo when we're currently writing to the - * console since the code is (and always was) not re-entrant, so we schedule - * all flip requests to process context with schedule-task() and run it from - * console_callback(). - */ - -/* - * For the same reason, we defer scrollback to the console callback. - */ -static int scrollback_delta; - -/* - * Hook so that the power management routines can (un)blank - * the console on our behalf. - */ -int (*console_blank_hook)(int); - -static struct timer_list console_timer; - -/* - * Low-Level Functions - */ - -#define IS_FG (currcons == fg_console) -#define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d) - -#ifdef VT_BUF_VRAM_ONLY -#define DO_UPDATE 0 -#else -#define DO_UPDATE IS_VISIBLE -#endif - -static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data); -static struct pm_dev *pm_con; - -static inline unsigned short *screenpos(int currcons, int offset, int viewed) -{ - unsigned short *p; - - if (!viewed) - p = (unsigned short *)(origin + offset); - else if (!sw->con_screen_pos) - p = (unsigned short *)(visible_origin + offset); - else - p = sw->con_screen_pos(vc_cons[currcons].d, offset); - return p; -} - -static inline void scrolldelta(int lines) -{ - scrollback_delta += lines; - schedule_console_callback(); -} - -void schedule_console_callback(void) -{ - schedule_task(&console_callback_tq); -} - -static void scrup(int currcons, unsigned int t, unsigned int b, int nr) -{ - unsigned short *d, *s; - - if (t+nr >= b) - nr = b - t - 1; - if (b > video_num_lines || t >= b || nr < 1) - return; - if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr)) - return; - d = (unsigned short *) (origin+video_size_row*t); - s = (unsigned short *) (origin+video_size_row*(t+nr)); - scr_memcpyw(d, s, (b-t-nr) * video_size_row); - scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr); -} - -static void -scrdown(int currcons, unsigned int t, unsigned int b, int nr) -{ - unsigned short *s; - unsigned int step; - - if (t+nr >= b) - nr = b - t - 1; - if (b > video_num_lines || t >= b || nr < 1) - return; - if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr)) - return; - s = (unsigned short *) (origin+video_size_row*t); - step = video_num_columns * nr; - scr_memmovew(s + step, s, (b-t-nr)*video_size_row); - scr_memsetw(s, video_erase_char, 2*step); -} - -static void do_update_region(int currcons, unsigned long start, int count) -{ -#ifndef VT_BUF_VRAM_ONLY - unsigned int xx, yy, offset; - u16 *p; - - p = (u16 *) start; - if (!sw->con_getxy) { - offset = (start - origin) / 2; - xx = offset % video_num_columns; - yy = offset / video_num_columns; - } else { - int nxx, nyy; - start = sw->con_getxy(vc_cons[currcons].d, start, &nxx, &nyy); - xx = nxx; yy = nyy; - } - for(;;) { - u16 attrib = scr_readw(p) & 0xff00; - int startx = xx; - u16 *q = p; - while (xx < video_num_columns && count) { - if (attrib != (scr_readw(p) & 0xff00)) { - if (p > q) - sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx); - startx = xx; - q = p; - attrib = scr_readw(p) & 0xff00; - } - p++; - xx++; - count--; - } - if (p > q) - sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx); - if (!count) - break; - xx = 0; - yy++; - if (sw->con_getxy) { - p = (u16 *)start; - start = sw->con_getxy(vc_cons[currcons].d, start, NULL, NULL); - } - } -#endif -} - -void update_region(int currcons, unsigned long start, int count) -{ - if (DO_UPDATE) { - hide_cursor(currcons); - do_update_region(currcons, start, count); - set_cursor(currcons); - } -} - -/* Structure of attributes is hardware-dependent */ - -static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) -{ - if (sw->con_build_attr) - return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse); - -#ifndef VT_BUF_VRAM_ONLY -/* - * ++roman: I completely changed the attribute format for monochrome - * mode (!can_do_color). The formerly used MDA (monochrome display - * adapter) format didn't allow the combination of certain effects. - * Now the attribute is just a bit vector: - * Bit 0..1: intensity (0..2) - * Bit 2 : underline - * Bit 3 : reverse - * Bit 7 : blink - */ - { - u8 a = color; - if (!can_do_color) - return _intensity | - (_underline ? 4 : 0) | - (_reverse ? 8 : 0) | - (_blink ? 0x80 : 0); - if (_underline) - a = (a & 0xf0) | ulcolor; - else if (_intensity == 0) - a = (a & 0xf0) | halfcolor; - if (_reverse) - a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77); - if (_blink) - a ^= 0x80; - if (_intensity == 2) - a ^= 0x08; - if (hi_font_mask == 0x100) - a <<= 1; - return a; - } -#else - return 0; -#endif -} - -static void update_attr(int currcons) -{ - attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm); - video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) << 8) | ' '; -} - -/* Note: inverting the screen twice should revert to the original state */ - -void invert_screen(int currcons, int offset, int count, int viewed) -{ - unsigned short *p; - - count /= 2; - p = screenpos(currcons, offset, viewed); - if (sw->con_invert_region) - sw->con_invert_region(vc_cons[currcons].d, p, count); -#ifndef VT_BUF_VRAM_ONLY - else { - u16 *q = p; - int cnt = count; - u16 a; - - if (!can_do_color) { - while (cnt--) { - a = scr_readw(q); - a ^= 0x0800; - scr_writew(a, q); - q++; - } - } else if (hi_font_mask == 0x100) { - while (cnt--) { - a = scr_readw(q); - a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); - scr_writew(a, q); - q++; - } - } else { - while (cnt--) { - a = scr_readw(q); - a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); - scr_writew(a, q); - q++; - } - } - } -#endif - if (DO_UPDATE) - do_update_region(currcons, (unsigned long) p, count); -} - -/* used by selection: complement pointer position */ -void complement_pos(int currcons, int offset) -{ - static unsigned short *p; - static unsigned short old; - static unsigned short oldx, oldy; - - if (p) { - scr_writew(old, p); - if (DO_UPDATE) - sw->con_putc(vc_cons[currcons].d, old, oldy, oldx); - } - if (offset == -1) - p = NULL; - else { - unsigned short new; - p = screenpos(currcons, offset, 1); - old = scr_readw(p); - new = old ^ complement_mask; - scr_writew(new, p); - if (DO_UPDATE) { - oldx = (offset >> 1) % video_num_columns; - oldy = (offset >> 1) / video_num_columns; - sw->con_putc(vc_cons[currcons].d, new, oldy, oldx); - } - } -} - -static void insert_char(int currcons, unsigned int nr) -{ - unsigned short *p, *q = (unsigned short *) pos; - - p = q + video_num_columns - nr - x; - while (--p >= q) - scr_writew(scr_readw(p), p + nr); - scr_memsetw(q, video_erase_char, nr*2); - need_wrap = 0; - if (DO_UPDATE) { - unsigned short oldattr = attr; - sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1, - video_num_columns-x-nr); - attr = video_erase_char >> 8; - while (nr--) - sw->con_putc(vc_cons[currcons].d, - video_erase_char,y,x+nr); - attr = oldattr; - } -} - -static void delete_char(int currcons, unsigned int nr) -{ - unsigned int i = x; - unsigned short *p = (unsigned short *) pos; - - while (++i <= video_num_columns - nr) { - scr_writew(scr_readw(p+nr), p); - p++; - } - scr_memsetw(p, video_erase_char, nr*2); - need_wrap = 0; - if (DO_UPDATE) { - unsigned short oldattr = attr; - sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1, - video_num_columns-x-nr); - attr = video_erase_char >> 8; - while (nr--) - sw->con_putc(vc_cons[currcons].d, - video_erase_char, y, - video_num_columns-1-nr); - attr = oldattr; - } -} - -static int softcursor_original; - -static void add_softcursor(int currcons) -{ - int i = scr_readw((u16 *) pos); - u32 type = cursor_type; - - if (! (type & 0x10)) return; - if (softcursor_original != -1) return; - softcursor_original = i; - i |= ((type >> 8) & 0xff00 ); - i ^= ((type) & 0xff00 ); - if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; - if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; - scr_writew(i, (u16 *) pos); - if (DO_UPDATE) - sw->con_putc(vc_cons[currcons].d, i, y, x); -} - -static void hide_cursor(int currcons) -{ - if (currcons == sel_cons) - clear_selection(); - if (softcursor_original != -1) { - scr_writew(softcursor_original,(u16 *) pos); - if (DO_UPDATE) - sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x); - softcursor_original = -1; - } - sw->con_cursor(vc_cons[currcons].d,CM_ERASE); -} - -static void set_cursor(int currcons) -{ - if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS) - return; - if (deccm) { - if (currcons == sel_cons) - clear_selection(); - add_softcursor(currcons); - if ((cursor_type & 0x0f) != 1) - sw->con_cursor(vc_cons[currcons].d,CM_DRAW); - } else - hide_cursor(currcons); -} - -static void set_origin(int currcons) -{ - if (!IS_VISIBLE || - !sw->con_set_origin || - !sw->con_set_origin(vc_cons[currcons].d)) - origin = (unsigned long) screenbuf; - visible_origin = origin; - scr_end = origin + screenbuf_size; - pos = origin + video_size_row*y + 2*x; -} - -static inline void save_screen(int currcons) -{ - if (sw->con_save_screen) - sw->con_save_screen(vc_cons[currcons].d); -} - -/* - * Redrawing of screen - */ - -void redraw_screen(int new_console, int is_switch) -{ - int redraw = 1; - int currcons, old_console; - - if (!vc_cons_allocated(new_console)) { - /* strange ... */ - /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */ - return; - } - - if (is_switch) { - currcons = fg_console; - hide_cursor(currcons); - if (fg_console != new_console) { - struct vc_data **display = vc_cons[new_console].d->vc_display_fg; - old_console = (*display) ? (*display)->vc_num : fg_console; - *display = vc_cons[new_console].d; - fg_console = new_console; - currcons = old_console; - if (!IS_VISIBLE) { - save_screen(currcons); - set_origin(currcons); - } - currcons = new_console; - if (old_console == new_console) - redraw = 0; - } - } else { - currcons = new_console; - hide_cursor(currcons); - } - - if (redraw) { - int update; - set_origin(currcons); - update = sw->con_switch(vc_cons[currcons].d); - set_palette(currcons); - if (update && vcmode != KD_GRAPHICS) - do_update_region(currcons, origin, screenbuf_size/2); - } - set_cursor(currcons); - if (is_switch) { - set_leds(); - compute_shiftstate(); - } -} - -/* - * Allocation, freeing and resizing of VTs. - */ - -int vc_cons_allocated(unsigned int i) -{ - return (i < MAX_NR_CONSOLES && vc_cons[i].d); -} - -static void visual_init(int currcons, int init) -{ - /* ++Geert: sw->con_init determines console size */ - sw = conswitchp; -#ifndef VT_SINGLE_DRIVER - if (con_driver_map[currcons]) - sw = con_driver_map[currcons]; -#endif - cons_num = currcons; - display_fg = &master_display_fg; - vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir; - vc_cons[currcons].d->vc_uni_pagedir = 0; - hi_font_mask = 0; - complement_mask = 0; - can_do_color = 0; - sw->con_init(vc_cons[currcons].d, init); - if (!complement_mask) - complement_mask = can_do_color ? 0x7700 : 0x0800; - s_complement_mask = complement_mask; - video_size_row = video_num_columns<<1; - screenbuf_size = video_num_lines*video_size_row; -} - -int vc_allocate(unsigned int currcons) /* return 0 on success */ -{ - if (currcons >= MAX_NR_CONSOLES) - return -ENXIO; - if (!vc_cons[currcons].d) { - long p, q; - - /* prevent users from taking too much memory */ - if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - /* due to the granularity of kmalloc, we waste some memory here */ - /* the alloc is done in two steps, to optimize the common situation - of a 25x80 console (structsize=216, screenbuf_size=4000) */ - /* although the numbers above are not valid since long ago, the - point is still up-to-date and the comment still has its value - even if only as a historical artifact. --mj, July 1998 */ - p = (long) kmalloc(structsize, GFP_KERNEL); - if (!p) - return -ENOMEM; - memset((void *)p, 0, structsize); - vc_cons[currcons].d = (struct vc_data *)p; - vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data)); - visual_init(currcons, 1); - if (!*vc_cons[currcons].d->vc_uni_pagedir_loc) - con_set_default_unimap(currcons); - q = (long)kmalloc(screenbuf_size, GFP_KERNEL); - if (!q) { - kfree((char *) p); - vc_cons[currcons].d = NULL; - vt_cons[currcons] = NULL; - return -ENOMEM; - } - screenbuf = (unsigned short *) q; - kmalloced = 1; - vc_init(currcons, video_num_lines, video_num_columns, 1); - - if (!pm_con) { - pm_con = pm_register(PM_SYS_DEV, - PM_SYS_VGA, - pm_con_request); - } - } - return 0; -} - -/* - * Change # of rows and columns (0 means unchanged/the size of fg_console) - * [this is to be used together with some user program - * like resize that changes the hardware videomode] - */ -int vc_resize(unsigned int lines, unsigned int cols, - unsigned int first, unsigned int last) -{ - unsigned int cc, ll, ss, sr, todo = 0; - unsigned int currcons = fg_console, i; - unsigned short *newscreens[MAX_NR_CONSOLES]; - - cc = (cols ? cols : video_num_columns); - ll = (lines ? lines : video_num_lines); - sr = cc << 1; - ss = sr * ll; - - for (currcons = first; currcons <= last; currcons++) { - if (!vc_cons_allocated(currcons) || - (cc == video_num_columns && ll == video_num_lines)) - newscreens[currcons] = NULL; - else { - unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER); - if (!p) { - for (i = first; i < currcons; i++) - if (newscreens[i]) - kfree(newscreens[i]); - return -ENOMEM; - } - newscreens[currcons] = p; - todo++; - } - } - if (!todo) - return 0; - - for (currcons = first; currcons <= last; currcons++) { - unsigned int occ, oll, oss, osr; - unsigned long ol, nl, nlend, rlth, rrem; - if (!newscreens[currcons] || !vc_cons_allocated(currcons)) - continue; - - oll = video_num_lines; - occ = video_num_columns; - osr = video_size_row; - oss = screenbuf_size; - - video_num_lines = ll; - video_num_columns = cc; - video_size_row = sr; - screenbuf_size = ss; - - rlth = MIN(osr, sr); - rrem = sr - rlth; - ol = origin; - nl = (long) newscreens[currcons]; - nlend = nl + ss; - if (ll < oll) - ol += (oll - ll) * osr; - - update_attr(currcons); - - while (ol < scr_end) { - scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); - if (rrem) - scr_memsetw((void *)(nl + rlth), video_erase_char, rrem); - ol += osr; - nl += sr; - } - if (nlend > nl) - scr_memsetw((void *) nl, video_erase_char, nlend - nl); - if (kmalloced) - kfree(screenbuf); - screenbuf = newscreens[currcons]; - kmalloced = 1; - screenbuf_size = ss; - set_origin(currcons); - - /* do part of a reset_terminal() */ - top = 0; - bottom = video_num_lines; - gotoxy(currcons, x, y); - save_cur(currcons); - - if (console_table[currcons]) { - struct winsize ws, *cws = &console_table[currcons]->winsize; - memset(&ws, 0, sizeof(ws)); - ws.ws_row = video_num_lines; - ws.ws_col = video_num_columns; - if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && - console_table[currcons]->pgrp > 0) - kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1); - *cws = ws; - } - - if (IS_VISIBLE) - update_screen(currcons); - } - - return 0; -} - - -void vc_disallocate(unsigned int currcons) -{ - acquire_console_sem(); - if (vc_cons_allocated(currcons)) { - sw->con_deinit(vc_cons[currcons].d); - if (kmalloced) - kfree(screenbuf); - if (currcons >= MIN_NR_CONSOLES) - kfree(vc_cons[currcons].d); - vc_cons[currcons].d = NULL; - } - release_console_sem(); -} - -/* - * VT102 emulator - */ - -#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x) -#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x) -#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x) - -#define decarm VC_REPEAT -#define decckm VC_CKMODE -#define kbdapplic VC_APPLIC -#define lnm VC_CRLF - -/* - * this is what the terminal answers to a ESC-Z or csi0c query. - */ -#define VT100ID "\033[?1;2c" -#define VT102ID "\033[?6c" - -unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, - 8,12,10,14, 9,13,11,15 }; - -/* the default colour table, for VGA+ colour systems */ -int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, - 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; -int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, - 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; -int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, - 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; - -/* - * gotoxy() must verify all boundaries, because the arguments - * might also be negative. If the given position is out of - * bounds, the cursor is placed at the nearest margin. - */ -static void gotoxy(int currcons, int new_x, int new_y) -{ - int min_y, max_y; - - if (new_x < 0) - x = 0; - else - if (new_x >= video_num_columns) - x = video_num_columns - 1; - else - x = new_x; - if (decom) { - min_y = top; - max_y = bottom; - } else { - min_y = 0; - max_y = video_num_lines; - } - if (new_y < min_y) - y = min_y; - else if (new_y >= max_y) - y = max_y - 1; - else - y = new_y; - pos = origin + y*video_size_row + (x<<1); - need_wrap = 0; -} - -/* for absolute user moves, when decom is set */ -static void gotoxay(int currcons, int new_x, int new_y) -{ - gotoxy(currcons, new_x, decom ? (top+new_y) : new_y); -} - -void scrollback(int lines) -{ - int currcons = fg_console; - - if (!lines) - lines = video_num_lines/2; - scrolldelta(-lines); -} - -void scrollfront(int lines) -{ - int currcons = fg_console; - - if (!lines) - lines = video_num_lines/2; - scrolldelta(lines); -} - -static void lf(int currcons) -{ - /* don't scroll if above bottom of scrolling region, or - * if below scrolling region - */ - if (y+1 == bottom) - scrup(currcons,top,bottom,1); - else if (y < video_num_lines-1) { - y++; - pos += video_size_row; - } - need_wrap = 0; -} - -static void ri(int currcons) -{ - /* don't scroll if below top of scrolling region, or - * if above scrolling region - */ - if (y == top) - scrdown(currcons,top,bottom,1); - else if (y > 0) { - y--; - pos -= video_size_row; - } - need_wrap = 0; -} - -static inline void cr(int currcons) -{ - pos -= x<<1; - need_wrap = x = 0; -} - -static inline void bs(int currcons) -{ - if (x) { - pos -= 2; - x--; - need_wrap = 0; - } -} - -static inline void del(int currcons) -{ - /* ignored */ -} - -static void csi_J(int currcons, int vpar) -{ - unsigned int count; - unsigned short * start; - - switch (vpar) { - case 0: /* erase from cursor to end of display */ - count = (scr_end-pos)>>1; - start = (unsigned short *) pos; - if (DO_UPDATE) { - /* do in two stages */ - sw->con_clear(vc_cons[currcons].d, y, x, 1, - video_num_columns-x); - sw->con_clear(vc_cons[currcons].d, y+1, 0, - video_num_lines-y-1, - video_num_columns); - } - break; - case 1: /* erase from start to cursor */ - count = ((pos-origin)>>1)+1; - start = (unsigned short *) origin; - if (DO_UPDATE) { - /* do in two stages */ - sw->con_clear(vc_cons[currcons].d, 0, 0, y, - video_num_columns); - sw->con_clear(vc_cons[currcons].d, y, 0, 1, - x + 1); - } - break; - case 2: /* erase whole display */ - count = video_num_columns * video_num_lines; - start = (unsigned short *) origin; - if (DO_UPDATE) - sw->con_clear(vc_cons[currcons].d, 0, 0, - video_num_lines, - video_num_columns); - break; - default: - return; - } - scr_memsetw(start, video_erase_char, 2*count); - need_wrap = 0; -} - -static void csi_K(int currcons, int vpar) -{ - unsigned int count; - unsigned short * start; - - switch (vpar) { - case 0: /* erase from cursor to end of line */ - count = video_num_columns-x; - start = (unsigned short *) pos; - if (DO_UPDATE) - sw->con_clear(vc_cons[currcons].d, y, x, 1, - video_num_columns-x); - break; - case 1: /* erase from start of line to cursor */ - start = (unsigned short *) (pos - (x<<1)); - count = x+1; - if (DO_UPDATE) - sw->con_clear(vc_cons[currcons].d, y, 0, 1, - x + 1); - break; - case 2: /* erase whole line */ - start = (unsigned short *) (pos - (x<<1)); - count = video_num_columns; - if (DO_UPDATE) - sw->con_clear(vc_cons[currcons].d, y, 0, 1, - video_num_columns); - break; - default: - return; - } - scr_memsetw(start, video_erase_char, 2 * count); - need_wrap = 0; -} - -static void csi_X(int currcons, int vpar) /* erase the following vpar positions */ -{ /* not vt100? */ - int count; - - if (!vpar) - vpar++; - count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar; - - scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count); - if (DO_UPDATE) - sw->con_clear(vc_cons[currcons].d, y, x, 1, count); - need_wrap = 0; -} - -static void default_attr(int currcons) -{ - intensity = 1; - underline = 0; - reverse = 0; - blink = 0; - color = def_color; -} - -/* console_sem is held */ -static void csi_m(int currcons) -{ - int i; - - for (i=0;i<=npar;i++) - switch (par[i]) { - case 0: /* all attributes off */ - default_attr(currcons); - break; - case 1: - intensity = 2; - break; - case 2: - intensity = 0; - break; - case 4: - underline = 1; - break; - case 5: - blink = 1; - break; - case 7: - reverse = 1; - break; - case 10: /* ANSI X3.64-1979 (SCO-ish?) - * Select primary font, don't display - * control chars if defined, don't set - * bit 8 on output. - */ - translate = set_translate(charset == 0 - ? G0_charset - : G1_charset,currcons); - disp_ctrl = 0; - toggle_meta = 0; - break; - case 11: /* ANSI X3.64-1979 (SCO-ish?) - * Select first alternate font, lets - * chars < 32 be displayed as ROM chars. - */ - translate = set_translate(IBMPC_MAP,currcons); - disp_ctrl = 1; - toggle_meta = 0; - break; - case 12: /* ANSI X3.64-1979 (SCO-ish?) - * Select second alternate font, toggle - * high bit before displaying as ROM char. - */ - translate = set_translate(IBMPC_MAP,currcons); - disp_ctrl = 1; - toggle_meta = 1; - break; - case 21: - case 22: - intensity = 1; - break; - case 24: - underline = 0; - break; - case 25: - blink = 0; - break; - case 27: - reverse = 0; - break; - case 38: /* ANSI X3.64-1979 (SCO-ish?) - * Enables underscore, white foreground - * with white underscore (Linux - use - * default foreground). - */ - color = (def_color & 0x0f) | background; - underline = 1; - break; - case 39: /* ANSI X3.64-1979 (SCO-ish?) - * Disable underline option. - * Reset colour to default? It did this - * before... - */ - color = (def_color & 0x0f) | background; - underline = 0; - break; - case 49: - color = (def_color & 0xf0) | foreground; - break; - default: - if (par[i] >= 30 && par[i] <= 37) - color = color_table[par[i]-30] - | background; - else if (par[i] >= 40 && par[i] <= 47) - color = (color_table[par[i]-40]<<4) - | foreground; - break; - } - update_attr(currcons); -} - -static void respond_string(const char * p, struct tty_struct * tty) -{ - while (*p) { - tty_insert_flip_char(tty, *p, 0); - p++; - } - con_schedule_flip(tty); -} - -static void cursor_report(int currcons, struct tty_struct * tty) -{ - char buf[40]; - - sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1); - respond_string(buf, tty); -} - -static inline void status_report(struct tty_struct * tty) -{ - respond_string("\033[0n", tty); /* Terminal ok */ -} - -static inline void respond_ID(struct tty_struct * tty) -{ - respond_string(VT102ID, tty); -} - -void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) -{ - char buf[8]; - - sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), - (char)('!' + mry)); - respond_string(buf, tty); -} - -/* invoked via ioctl(TIOCLINUX) and through set_selection */ -int mouse_reporting(void) -{ - int currcons = fg_console; - - return report_mouse; -} - -/* console_sem is held */ -static void set_mode(int currcons, int on_off) -{ - int i; - - for (i=0; i<=npar; i++) - if (ques) switch(par[i]) { /* DEC private modes set/reset */ - case 1: /* Cursor keys send ^[Ox/^[[x */ - if (on_off) - set_kbd(decckm); - else - clr_kbd(decckm); - break; - case 3: /* 80/132 mode switch unimplemented */ - deccolm = on_off; -#if 0 - (void) vc_resize(video_num_lines, deccolm ? 132 : 80); - /* this alone does not suffice; some user mode - utility has to change the hardware regs */ -#endif - break; - case 5: /* Inverted screen on/off */ - if (decscnm != on_off) { - decscnm = on_off; - invert_screen(currcons, 0, screenbuf_size, 0); - update_attr(currcons); - } - break; - case 6: /* Origin relative/absolute */ - decom = on_off; - gotoxay(currcons,0,0); - break; - case 7: /* Autowrap on/off */ - decawm = on_off; - break; - case 8: /* Autorepeat on/off */ - if (on_off) - set_kbd(decarm); - else - clr_kbd(decarm); - break; - case 9: - report_mouse = on_off ? 1 : 0; - break; - case 25: /* Cursor on/off */ - deccm = on_off; - break; - case 1000: - report_mouse = on_off ? 2 : 0; - break; - } else switch(par[i]) { /* ANSI modes set/reset */ - case 3: /* Monitor (display ctrls) */ - disp_ctrl = on_off; - break; - case 4: /* Insert Mode on/off */ - decim = on_off; - break; - case 20: /* Lf, Enter == CrLf/Lf */ - if (on_off) - set_kbd(lnm); - else - clr_kbd(lnm); - break; - } -} - -/* console_sem is held */ -static void setterm_command(int currcons) -{ - switch(par[0]) { - case 1: /* set color for underline mode */ - if (can_do_color && par[1] < 16) { - ulcolor = color_table[par[1]]; - if (underline) - update_attr(currcons); - } - break; - case 2: /* set color for half intensity mode */ - if (can_do_color && par[1] < 16) { - halfcolor = color_table[par[1]]; - if (intensity == 0) - update_attr(currcons); - } - break; - case 8: /* store colors as defaults */ - def_color = attr; - if (hi_font_mask == 0x100) - def_color >>= 1; - default_attr(currcons); - update_attr(currcons); - break; - case 9: /* set blanking interval */ - blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; - poke_blanked_console(); - break; - case 10: /* set bell frequency in Hz */ - if (npar >= 1) - bell_pitch = par[1]; - else - bell_pitch = DEFAULT_BELL_PITCH; - break; - case 11: /* set bell duration in msec */ - if (npar >= 1) - bell_duration = (par[1] < 2000) ? - par[1]*HZ/1000 : 0; - else - bell_duration = DEFAULT_BELL_DURATION; - break; - case 12: /* bring specified console to the front */ - if (par[1] >= 1 && vc_cons_allocated(par[1]-1)) - set_console(par[1] - 1); - break; - case 13: /* unblank the screen */ - poke_blanked_console(); - break; - case 14: /* set vesa powerdown interval */ - vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; - break; - } -} - -/* console_sem is held */ -static void csi_at(int currcons, unsigned int nr) -{ - if (nr > video_num_columns - x) - nr = video_num_columns - x; - else if (!nr) - nr = 1; - insert_char(currcons, nr); -} - -/* console_sem is held */ -static void csi_L(int currcons, unsigned int nr) -{ - if (nr > video_num_lines - y) - nr = video_num_lines - y; - else if (!nr) - nr = 1; - scrdown(currcons,y,bottom,nr); - need_wrap = 0; -} - -/* console_sem is held */ -static void csi_P(int currcons, unsigned int nr) -{ - if (nr > video_num_columns - x) - nr = video_num_columns - x; - else if (!nr) - nr = 1; - delete_char(currcons, nr); -} - -/* console_sem is held */ -static void csi_M(int currcons, unsigned int nr) -{ - if (nr > video_num_lines - y) - nr = video_num_lines - y; - else if (!nr) - nr=1; - scrup(currcons,y,bottom,nr); - need_wrap = 0; -} - -/* console_sem is held (except via vc_init->reset_terminal */ -static void save_cur(int currcons) -{ - saved_x = x; - saved_y = y; - s_intensity = intensity; - s_underline = underline; - s_blink = blink; - s_reverse = reverse; - s_charset = charset; - s_color = color; - saved_G0 = G0_charset; - saved_G1 = G1_charset; -} - -/* console_sem is held */ -static void restore_cur(int currcons) -{ - gotoxy(currcons,saved_x,saved_y); - intensity = s_intensity; - underline = s_underline; - blink = s_blink; - reverse = s_reverse; - charset = s_charset; - color = s_color; - G0_charset = saved_G0; - G1_charset = saved_G1; - translate = set_translate(charset ? G1_charset : G0_charset,currcons); - update_attr(currcons); - need_wrap = 0; -} - -enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, - EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, - ESpalette }; - -/* console_sem is held (except via vc_init()) */ -static void reset_terminal(int currcons, int do_clear) -{ - top = 0; - bottom = video_num_lines; - vc_state = ESnormal; - ques = 0; - translate = set_translate(LAT1_MAP,currcons); - G0_charset = LAT1_MAP; - G1_charset = GRAF_MAP; - charset = 0; - need_wrap = 0; - report_mouse = 0; - utf = 0; - utf_count = 0; - - disp_ctrl = 0; - toggle_meta = 0; - - decscnm = 0; - decom = 0; - decawm = 1; - deccm = 1; - decim = 0; - - set_kbd(decarm); - clr_kbd(decckm); - clr_kbd(kbdapplic); - clr_kbd(lnm); - kbd_table[currcons].lockstate = 0; - kbd_table[currcons].slockstate = 0; - kbd_table[currcons].ledmode = LED_SHOW_FLAGS; - kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate; - /* do not do set_leds here because this causes an endless tasklet loop - when the keyboard hasn't been initialized yet */ - - cursor_type = CUR_DEFAULT; - complement_mask = s_complement_mask; - - default_attr(currcons); - update_attr(currcons); - - tab_stop[0] = 0x01010100; - tab_stop[1] = - tab_stop[2] = - tab_stop[3] = - tab_stop[4] = 0x01010101; - - bell_pitch = DEFAULT_BELL_PITCH; - bell_duration = DEFAULT_BELL_DURATION; - - gotoxy(currcons,0,0); - save_cur(currcons); - if (do_clear) - csi_J(currcons,2); -} - -/* console_sem is held */ -static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c) -{ - /* - * Control characters can be used in the _middle_ - * of an escape sequence. - */ - switch (c) { - case 0: - return; - case 7: - if (bell_duration) - kd_mksound(bell_pitch, bell_duration); - return; - case 8: - bs(currcons); - return; - case 9: - pos -= (x << 1); - while (x < video_num_columns - 1) { - x++; - if (tab_stop[x >> 5] & (1 << (x & 31))) - break; - } - pos += (x << 1); - return; - case 10: case 11: case 12: - lf(currcons); - if (!is_kbd(lnm)) - return; - case 13: - cr(currcons); - return; - case 14: - charset = 1; - translate = set_translate(G1_charset,currcons); - disp_ctrl = 1; - return; - case 15: - charset = 0; - translate = set_translate(G0_charset,currcons); - disp_ctrl = 0; - return; - case 24: case 26: - vc_state = ESnormal; - return; - case 27: - vc_state = ESesc; - return; - case 127: - del(currcons); - return; - case 128+27: - vc_state = ESsquare; - return; - } - switch(vc_state) { - case ESesc: - vc_state = ESnormal; - switch (c) { - case '[': - vc_state = ESsquare; - return; - case ']': - vc_state = ESnonstd; - return; - case '%': - vc_state = ESpercent; - return; - case 'E': - cr(currcons); - lf(currcons); - return; - case 'M': - ri(currcons); - return; - case 'D': - lf(currcons); - return; - case 'H': - tab_stop[x >> 5] |= (1 << (x & 31)); - return; - case 'Z': - respond_ID(tty); - return; - case '7': - save_cur(currcons); - return; - case '8': - restore_cur(currcons); - return; - case '(': - vc_state = ESsetG0; - return; - case ')': - vc_state = ESsetG1; - return; - case '#': - vc_state = EShash; - return; - case 'c': - reset_terminal(currcons,1); - return; - case '>': /* Numeric keypad */ - clr_kbd(kbdapplic); - return; - case '=': /* Appl. keypad */ - set_kbd(kbdapplic); - return; - } - return; - case ESnonstd: - if (c=='P') { /* palette escape sequence */ - for (npar=0; npar='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { - par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; - if (npar==7) { - int i = par[0]*3, j = 1; - palette[i] = 16*par[j++]; - palette[i++] += par[j++]; - palette[i] = 16*par[j++]; - palette[i++] += par[j++]; - palette[i] = 16*par[j++]; - palette[i] += par[j]; - set_palette(currcons); - vc_state = ESnormal; - } - } else - vc_state = ESnormal; - return; - case ESsquare: - for(npar = 0 ; npar < NPAR ; npar++) - par[npar] = 0; - npar = 0; - vc_state = ESgetpars; - if (c == '[') { /* Function key */ - vc_state=ESfunckey; - return; - } - ques = (c=='?'); - if (ques) - return; - case ESgetpars: - if (c==';' && npar='0' && c<='9') { - par[npar] *= 10; - par[npar] += c-'0'; - return; - } else vc_state=ESgotpars; - case ESgotpars: - vc_state = ESnormal; - switch(c) { - case 'h': - set_mode(currcons,1); - return; - case 'l': - set_mode(currcons,0); - return; - case 'c': - if (ques) { - if (par[0]) - cursor_type = par[0] | (par[1]<<8) | (par[2]<<16); - else - cursor_type = CUR_DEFAULT; - return; - } - break; - case 'm': - if (ques) { - clear_selection(); - if (par[0]) - complement_mask = par[0]<<8 | par[1]; - else - complement_mask = s_complement_mask; - return; - } - break; - case 'n': - if (!ques) { - if (par[0] == 5) - status_report(tty); - else if (par[0] == 6) - cursor_report(currcons,tty); - } - return; - } - if (ques) { - ques = 0; - return; - } - switch(c) { - case 'G': case '`': - if (par[0]) par[0]--; - gotoxy(currcons,par[0],y); - return; - case 'A': - if (!par[0]) par[0]++; - gotoxy(currcons,x,y-par[0]); - return; - case 'B': case 'e': - if (!par[0]) par[0]++; - gotoxy(currcons,x,y+par[0]); - return; - case 'C': case 'a': - if (!par[0]) par[0]++; - gotoxy(currcons,x+par[0],y); - return; - case 'D': - if (!par[0]) par[0]++; - gotoxy(currcons,x-par[0],y); - return; - case 'E': - if (!par[0]) par[0]++; - gotoxy(currcons,0,y+par[0]); - return; - case 'F': - if (!par[0]) par[0]++; - gotoxy(currcons,0,y-par[0]); - return; - case 'd': - if (par[0]) par[0]--; - gotoxay(currcons,x,par[0]); - return; - case 'H': case 'f': - if (par[0]) par[0]--; - if (par[1]) par[1]--; - gotoxay(currcons,par[1],par[0]); - return; - case 'J': - csi_J(currcons,par[0]); - return; - case 'K': - csi_K(currcons,par[0]); - return; - case 'L': - csi_L(currcons,par[0]); - return; - case 'M': - csi_M(currcons,par[0]); - return; - case 'P': - csi_P(currcons,par[0]); - return; - case 'c': - if (!par[0]) - respond_ID(tty); - return; - case 'g': - if (!par[0]) - tab_stop[x >> 5] &= ~(1 << (x & 31)); - else if (par[0] == 3) { - tab_stop[0] = - tab_stop[1] = - tab_stop[2] = - tab_stop[3] = - tab_stop[4] = 0; - } - return; - case 'm': - csi_m(currcons); - return; - case 'q': /* DECLL - but only 3 leds */ - /* map 0,1,2,3 to 0,1,2,4 */ - if (par[0] < 4) - setledstate(kbd_table + currcons, - (par[0] < 3) ? par[0] : 4); - return; - case 'r': - if (!par[0]) - par[0]++; - if (!par[1]) - par[1] = video_num_lines; - /* Minimum allowed region is 2 lines */ - if (par[0] < par[1] && - par[1] <= video_num_lines) { - top=par[0]-1; - bottom=par[1]; - gotoxay(currcons,0,0); - } - return; - case 's': - save_cur(currcons); - return; - case 'u': - restore_cur(currcons); - return; - case 'X': - csi_X(currcons, par[0]); - return; - case '@': - csi_at(currcons,par[0]); - return; - case ']': /* setterm functions */ - setterm_command(currcons); - return; - } - return; - case ESpercent: - vc_state = ESnormal; - switch (c) { - case '@': /* defined in ISO 2022 */ - utf = 0; - return; - case 'G': /* prelim official escape code */ - case '8': /* retained for compatibility */ - utf = 1; - return; - } - return; - case ESfunckey: - vc_state = ESnormal; - return; - case EShash: - vc_state = ESnormal; - if (c == '8') { - /* DEC screen alignment test. kludge :-) */ - video_erase_char = - (video_erase_char & 0xff00) | 'E'; - csi_J(currcons, 2); - video_erase_char = - (video_erase_char & 0xff00) | ' '; - do_update_region(currcons, origin, screenbuf_size/2); - } - return; - case ESsetG0: - if (c == '0') - G0_charset = GRAF_MAP; - else if (c == 'B') - G0_charset = LAT1_MAP; - else if (c == 'U') - G0_charset = IBMPC_MAP; - else if (c == 'K') - G0_charset = USER_MAP; - if (charset == 0) - translate = set_translate(G0_charset,currcons); - vc_state = ESnormal; - return; - case ESsetG1: - if (c == '0') - G1_charset = GRAF_MAP; - else if (c == 'B') - G1_charset = LAT1_MAP; - else if (c == 'U') - G1_charset = IBMPC_MAP; - else if (c == 'K') - G1_charset = USER_MAP; - if (charset == 1) - translate = set_translate(G1_charset,currcons); - vc_state = ESnormal; - return; - default: - vc_state = ESnormal; - } -} - -/* This is a temporary buffer used to prepare a tty console write - * so that we can easily avoid touching user space while holding the - * console spinlock. It is allocated in con_init and is shared by - * this code and the vc_screen read/write tty calls. - * - * We have to allocate this statically in the kernel data section - * since console_init (and thus con_init) are called before any - * kernel memory allocation is available. - */ -char con_buf[PAGE_SIZE]; -#define CON_BUF_SIZE PAGE_SIZE -DECLARE_MUTEX(con_buf_sem); - -/* acquires console_sem */ -static int do_con_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ -#ifdef VT_BUF_VRAM_ONLY -#define FLUSH do { } while(0); -#else -#define FLUSH if (draw_x >= 0) { \ - sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \ - draw_x = -1; \ - } -#endif - - int c, tc, ok, n = 0, draw_x = -1; - unsigned int currcons; - unsigned long draw_from = 0, draw_to = 0; - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; - u16 himask, charmask; - const unsigned char *orig_buf = NULL; - int orig_count; - - if (in_interrupt()) - return count; - - currcons = vt->vc_num; - if (!vc_cons_allocated(currcons)) { - /* could this happen? */ - static int error = 0; - if (!error) { - error = 1; - printk("con_write: tty %d not allocated\n", currcons+1); - } - return 0; - } - - orig_buf = buf; - orig_count = count; - - if (from_user) { - down(&con_buf_sem); - -again: - if (count > CON_BUF_SIZE) - count = CON_BUF_SIZE; - console_conditional_schedule(); - if (copy_from_user(con_buf, buf, count)) { - n = 0; /* ?? are error codes legal here ?? */ - goto out; - } - - buf = con_buf; - } - - /* At this point 'buf' is guarenteed to be a kernel buffer - * and therefore no access to userspace (and therefore sleeping) - * will be needed. The con_buf_sem serializes all tty based - * console rendering and vcs write/read operations. We hold - * the console spinlock during the entire write. - */ - - acquire_console_sem(); - - himask = hi_font_mask; - charmask = himask ? 0x1ff : 0xff; - - /* undraw cursor first */ - if (IS_FG) - hide_cursor(currcons); - - while (!tty->stopped && count) { - c = *buf; - buf++; - n++; - count--; - - if (utf) { - /* Combine UTF-8 into Unicode */ - /* Incomplete characters silently ignored */ - if(c > 0x7f) { - if (utf_count > 0 && (c & 0xc0) == 0x80) { - utf_char = (utf_char << 6) | (c & 0x3f); - utf_count--; - if (utf_count == 0) - tc = c = utf_char; - else continue; - } else { - if ((c & 0xe0) == 0xc0) { - utf_count = 1; - utf_char = (c & 0x1f); - } else if ((c & 0xf0) == 0xe0) { - utf_count = 2; - utf_char = (c & 0x0f); - } else if ((c & 0xf8) == 0xf0) { - utf_count = 3; - utf_char = (c & 0x07); - } else if ((c & 0xfc) == 0xf8) { - utf_count = 4; - utf_char = (c & 0x03); - } else if ((c & 0xfe) == 0xfc) { - utf_count = 5; - utf_char = (c & 0x01); - } else - utf_count = 0; - continue; - } - } else { - tc = c; - utf_count = 0; - } - } else { /* no utf */ - tc = translate[toggle_meta ? (c|0x80) : c]; - } - - /* If the original code was a control character we - * only allow a glyph to be displayed if the code is - * not normally used (such as for cursor movement) or - * if the disp_ctrl mode has been explicitly enabled. - * Certain characters (as given by the CTRL_ALWAYS - * bitmap) are always displayed as control characters, - * as the console would be pretty useless without - * them; to display an arbitrary font position use the - * direct-to-font zone in UTF-8 mode. - */ - ok = tc && (c >= 32 || - (!utf && !(((disp_ctrl ? CTRL_ALWAYS - : CTRL_ACTION) >> c) & 1))) - && (c != 127 || disp_ctrl) - && (c != 128+27); - - if (vc_state == ESnormal && ok) { - /* Now try to find out how to display it */ - tc = conv_uni_to_pc(vc_cons[currcons].d, tc); - if ( tc == -4 ) { - /* If we got -4 (not found) then see if we have - defined a replacement character (U+FFFD) */ - tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd); - - /* One reason for the -4 can be that we just - did a clear_unimap(); - try at least to show something. */ - if (tc == -4) - tc = c; - } else if ( tc == -3 ) { - /* Bad hash table -- hope for the best */ - tc = c; - } - if (tc & ~charmask) - continue; /* Conversion failed */ - - if (need_wrap || decim) - FLUSH - if (need_wrap) { - cr(currcons); - lf(currcons); - } - if (decim) - insert_char(currcons, 1); - scr_writew(himask ? - ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : - (attr << 8) + tc, - (u16 *) pos); - if (DO_UPDATE && draw_x < 0) { - draw_x = x; - draw_from = pos; - } - if (x == video_num_columns - 1) { - need_wrap = decawm; - draw_to = pos+2; - } else { - x++; - draw_to = (pos+=2); - } - continue; - } - FLUSH - do_con_trol(tty, currcons, c); - } - FLUSH - console_conditional_schedule(); - release_console_sem(); - -out: - if (from_user) { - /* If the user requested something larger than - * the CON_BUF_SIZE, and the tty is not stopped, - * keep going. - */ - if ((orig_count > CON_BUF_SIZE) && !tty->stopped) { - orig_count -= CON_BUF_SIZE; - orig_buf += CON_BUF_SIZE; - count = orig_count; - buf = orig_buf; - goto again; - } - - up(&con_buf_sem); - } - - return n; -#undef FLUSH -} - -/* - * This is the console switching callback. - * - * Doing console switching in a process context allows - * us to do the switches asynchronously (needed when we want - * to switch due to a keyboard interrupt). Synchronization - * with other console code and prevention of re-entrancy is - * ensured with console_sem. - */ -static void console_callback(void *ignored) -{ - acquire_console_sem(); - - if (want_console >= 0) { - if (want_console != fg_console && vc_cons_allocated(want_console)) { - hide_cursor(fg_console); - change_console(want_console); - /* we only changed when the console had already - been allocated - a new console is not created - in an interrupt routine */ - } - want_console = -1; - } - if (do_poke_blanked_console) { /* do not unblank for a LED change */ - do_poke_blanked_console = 0; - poke_blanked_console(); - } - if (scrollback_delta) { - int currcons = fg_console; - clear_selection(); - if (vcmode == KD_TEXT) - sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta); - scrollback_delta = 0; - } - - release_console_sem(); -} - -void set_console(int nr) -{ - want_console = nr; - schedule_console_callback(); -} - -#ifdef CONFIG_VT_CONSOLE - -/* - * Console on virtual terminal - * - * The console must be locked when we get here. - */ - -void vt_console_print(struct console *co, const char * b, unsigned count) -{ - int currcons = fg_console; - unsigned char c; - static unsigned long printing; - const ushort *start; - ushort cnt = 0; - ushort myx; - - /* console busy or not yet initialized */ - if (!printable || test_and_set_bit(0, &printing)) - return; - - pm_access(pm_con); - - if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) - currcons = kmsg_redirect - 1; - - /* read `x' only after setting currecons properly (otherwise - the `x' macro will read the x of the foreground console). */ - myx = x; - - if (!vc_cons_allocated(currcons)) { - /* impossible */ - /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ - goto quit; - } - - if (vcmode != KD_TEXT) - goto quit; - - /* undraw cursor first */ - if (IS_FG) - hide_cursor(currcons); - - start = (ushort *)pos; - - /* Contrived structure to try to emulate original need_wrap behaviour - * Problems caused when we have need_wrap set on '\n' character */ - while (count--) { - c = *b++; - if (c == 10 || c == 13 || c == 8 || need_wrap) { - if (cnt > 0) { - if (IS_VISIBLE) - sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); - x += cnt; - if (need_wrap) - x--; - cnt = 0; - } - if (c == 8) { /* backspace */ - bs(currcons); - start = (ushort *)pos; - myx = x; - continue; - } - if (c != 13) - lf(currcons); - cr(currcons); - start = (ushort *)pos; - myx = x; - if (c == 10 || c == 13) - continue; - } - scr_writew((attr << 8) + c, (unsigned short *) pos); - cnt++; - if (myx == video_num_columns - 1) { - need_wrap = 1; - continue; - } - pos+=2; - myx++; - } - if (cnt > 0) { - if (IS_VISIBLE) - sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); - x += cnt; - if (x == video_num_columns) { - x--; - need_wrap = 1; - } - } - set_cursor(currcons); - - if (!oops_in_progress) - poke_blanked_console(); - -quit: - clear_bit(0, &printing); -} - -static kdev_t vt_console_device(struct console *c) -{ - return mk_kdev(TTY_MAJOR, c->index ? c->index : fg_console + 1); -} - -struct console vt_console_driver = { - name: "tty", - write: vt_console_print, - device: vt_console_device, - unblank: unblank_screen, - flags: CON_PRINTBUFFER, - index: -1, -}; -#endif - -/* - * Handling of Linux-specific VC ioctls - */ - -/* - * Generally a bit racy with respect to console_sem(). - * - * There are some functions which don't need it. - * - * There are some functions which can sleep for arbitrary periods (paste_selection) - * but we don't need the lock there anyway. - * - * set_selection has locking, and definitely needs it - */ - -int tioclinux(struct tty_struct *tty, unsigned long arg) -{ - char type, data; - int ret; - - if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) - return -EINVAL; - if (current->tty != tty && !capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(type, (char *)arg)) - return -EFAULT; - ret = 0; - switch (type) - { - case 2: - acquire_console_sem(); - ret = set_selection(arg, tty, 1); - release_console_sem(); - break; - case 3: - ret = paste_selection(tty); - break; - case 4: - unblank_screen(); - break; - case 5: - ret = sel_loadlut(arg); - break; - case 6: - - /* - * Make it possible to react to Shift+Mousebutton. - * Note that 'shift_state' is an undocumented - * kernel-internal variable; programs not closely - * related to the kernel should not use this. - */ - data = shift_state; - ret = __put_user(data, (char *) arg); - break; - case 7: - data = mouse_reporting(); - ret = __put_user(data, (char *) arg); - break; - case 10: - set_vesa_blanking(arg); - break;; - case 11: /* set kmsg redirect */ - if (!capable(CAP_SYS_ADMIN)) { - ret = -EPERM; - } else { - if (get_user(data, (char *)arg+1)) - ret = -EFAULT; - else - kmsg_redirect = data; - } - break; - case 12: /* get fg_console */ - ret = fg_console; - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -/* - * /dev/ttyN handling - */ - -static int con_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - int retval; - - pm_access(pm_con); - retval = do_con_write(tty, from_user, buf, count); - con_flush_chars(tty); - - return retval; -} - -static void con_put_char(struct tty_struct *tty, unsigned char ch) -{ - if (in_interrupt()) - return; /* n_r3964 calls put_char() from interrupt context */ - pm_access(pm_con); - do_con_write(tty, 0, &ch, 1); -} - -static int con_write_room(struct tty_struct *tty) -{ - if (tty->stopped) - return 0; - return 4096; /* No limit, really; we're not buffering */ -} - -static int con_chars_in_buffer(struct tty_struct *tty) -{ - return 0; /* we're not buffering */ -} - -/* - * con_throttle and con_unthrottle are only used for - * paste_selection(), which has to stuff in a large number of - * characters... - */ -static void con_throttle(struct tty_struct *tty) -{ -} - -static void con_unthrottle(struct tty_struct *tty) -{ - struct vt_struct *vt = (struct vt_struct *) tty->driver_data; - - wake_up_interruptible(&vt->paste_wait); -} - -/* - * Turn the Scroll-Lock LED on when the tty is stopped - */ -static void con_stop(struct tty_struct *tty) -{ - int console_num; - if (!tty) - return; - console_num = minor(tty->device) - (tty->driver.minor_start); - if (!vc_cons_allocated(console_num)) - return; - set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); -} - -/* - * Turn the Scroll-Lock LED off when the console is started - */ -static void con_start(struct tty_struct *tty) -{ - int console_num; - if (!tty) - return; - console_num = minor(tty->device) - (tty->driver.minor_start); - if (!vc_cons_allocated(console_num)) - return; - clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); -} - -static void con_flush_chars(struct tty_struct *tty) -{ - struct vt_struct *vt; - - if (in_interrupt()) /* from flush_to_ldisc */ - return; - - pm_access(pm_con); - - /* if we race with con_close(), vt may be null */ - acquire_console_sem(); - vt = (struct vt_struct *)tty->driver_data; - if (vt) - set_cursor(vt->vc_num); - release_console_sem(); -} - -/* - * Allocate the console screen memory. - */ -static int con_open(struct tty_struct *tty, struct file * filp) -{ - unsigned int currcons; - int i; - - currcons = minor(tty->device) - tty->driver.minor_start; - - i = vc_allocate(currcons); - if (i) - return i; - - vt_cons[currcons]->vc_num = currcons; - tty->driver_data = vt_cons[currcons]; - - if (!tty->winsize.ws_row && !tty->winsize.ws_col) { - tty->winsize.ws_row = video_num_lines; - tty->winsize.ws_col = video_num_columns; - } - if (tty->count == 1) - vcs_make_devfs (currcons, 0); - return 0; -} - -static void con_close(struct tty_struct *tty, struct file * filp) -{ - if (!tty) - return; - if (tty->count != 1) return; - vcs_make_devfs (minor(tty->device) - tty->driver.minor_start, 1); - tty->driver_data = 0; -} - -static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear) -{ - int j, k ; - - video_num_columns = cols; - video_num_lines = rows; - video_size_row = cols<<1; - screenbuf_size = video_num_lines * video_size_row; - - set_origin(currcons); - pos = origin; - reset_vc(currcons); - for (j=k=0; j<16; j++) { - vc_cons[currcons].d->vc_palette[k++] = default_red[j] ; - vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ; - vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ; - } - def_color = 0x07; /* white */ - ulcolor = 0x0f; /* bold white */ - halfcolor = 0x08; /* grey */ - init_waitqueue_head(&vt_cons[currcons]->paste_wait); - reset_terminal(currcons, do_clear); -} - -/* - * This routine initializes console interrupts, and does nothing - * else. If you want the screen to clear, call tty_write with - * the appropriate escape-sequence. - */ - -struct tty_driver console_driver; -static int console_refcount; - -void __init con_init(void) -{ - const char *display_desc = NULL; - unsigned int currcons = 0; - - if (conswitchp) - display_desc = conswitchp->con_startup(); - if (!display_desc) { - fg_console = 0; - return; - } - - memset(&console_driver, 0, sizeof(struct tty_driver)); - console_driver.magic = TTY_DRIVER_MAGIC; - console_driver.name = "vc/%d"; - console_driver.name_base = 1; - console_driver.major = TTY_MAJOR; - console_driver.minor_start = 1; - console_driver.num = MAX_NR_CONSOLES; - console_driver.type = TTY_DRIVER_TYPE_CONSOLE; - console_driver.init_termios = tty_std_termios; - console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - /* Tell tty_register_driver() to skip consoles because they are - * registered before kmalloc() is ready. We'll patch them in later. - * See comments at console_init(); see also con_init_devfs(). - */ - console_driver.flags |= TTY_DRIVER_NO_DEVFS; - console_driver.refcount = &console_refcount; - console_driver.table = console_table; - console_driver.termios = console_termios; - console_driver.termios_locked = console_termios_locked; - - console_driver.open = con_open; - console_driver.close = con_close; - console_driver.write = con_write; - console_driver.write_room = con_write_room; - console_driver.put_char = con_put_char; - console_driver.flush_chars = con_flush_chars; - console_driver.chars_in_buffer = con_chars_in_buffer; - console_driver.ioctl = vt_ioctl; - console_driver.stop = con_stop; - console_driver.start = con_start; - console_driver.throttle = con_throttle; - console_driver.unthrottle = con_unthrottle; - - if (tty_register_driver(&console_driver)) - panic("Couldn't register console driver\n"); - - init_timer(&console_timer); - console_timer.function = blank_screen; - if (blankinterval) { - mod_timer(&console_timer, jiffies + blankinterval); - } - - /* - * kmalloc is not running yet - we use the bootmem allocator. - */ - for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { - vc_cons[currcons].d = (struct vc_data *) - alloc_bootmem(sizeof(struct vc_data)); - vt_cons[currcons] = (struct vt_struct *) - alloc_bootmem(sizeof(struct vt_struct)); - visual_init(currcons, 1); - screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size); - kmalloced = 0; - vc_init(currcons, video_num_lines, video_num_columns, - currcons || !sw->con_save_screen); - } - currcons = fg_console = 0; - master_display_fg = vc_cons[currcons].d; - set_origin(currcons); - save_screen(currcons); - gotoxy(currcons,x,y); - csi_J(currcons, 0); - update_screen(fg_console); - printk("Console: %s %s %dx%d", - can_do_color ? "colour" : "mono", - display_desc, video_num_columns, video_num_lines); - printable = 1; - printk("\n"); - -#ifdef CONFIG_VT_CONSOLE - register_console(&vt_console_driver); -#endif -} - -#ifndef VT_SINGLE_DRIVER - -static void clear_buffer_attributes(int currcons) -{ - unsigned short *p = (unsigned short *) origin; - int count = screenbuf_size/2; - int mask = hi_font_mask | 0xff; - - for (; count > 0; count--, p++) { - scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); - } -} - -/* - * If we support more console drivers, this function is used - * when a driver wants to take over some existing consoles - * and become default driver for newly opened ones. - */ - -void take_over_console(const struct consw *csw, int first, int last, int deflt) -{ - int i, j = -1; - const char *desc; - - desc = csw->con_startup(); - if (!desc) return; - if (deflt) - conswitchp = csw; - - for (i = first; i <= last; i++) { - int old_was_color; - int currcons = i; - - con_driver_map[i] = csw; - - if (!vc_cons[i].d || !vc_cons[i].d->vc_sw) - continue; - - j = i; - if (IS_VISIBLE) - save_screen(i); - old_was_color = vc_cons[i].d->vc_can_do_color; - vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d); - visual_init(i, 0); - update_attr(i); - - /* If the console changed between mono <-> color, then - * the attributes in the screenbuf will be wrong. The - * following resets all attributes to something sane. - */ - if (old_was_color != vc_cons[i].d->vc_can_do_color) - clear_buffer_attributes(i); - - if (IS_VISIBLE) - update_screen(i); - } - printk("Console: switching "); - if (!deflt) - printk("consoles %d-%d ", first+1, last+1); - if (j >= 0) - printk("to %s %s %dx%d\n", - vc_cons[j].d->vc_can_do_color ? "colour" : "mono", - desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows); - else - printk("to %s\n", desc); -} - -void give_up_console(const struct consw *csw) -{ - int i; - - for(i = 0; i < MAX_NR_CONSOLES; i++) - if (con_driver_map[i] == csw) - con_driver_map[i] = NULL; -} - -#endif - -/* - * Screen blanking - */ - -static void set_vesa_blanking(unsigned long arg) -{ - char *argp = (char *)arg + 1; - unsigned int mode; - get_user(mode, argp); - vesa_blank_mode = (mode < 4) ? mode : 0; -} - -/* We can't register the console with devfs during con_init(), because it - * is called before kmalloc() works. This function is called later to - * do the registration. - */ -void __init con_init_devfs (void) -{ - int i; - - for (i = 0; i < console_driver.num; i++) - tty_register_devfs (&console_driver, DEVFS_FL_AOPEN_NOTIFY, - console_driver.minor_start + i); -} - -/* - * This is called by a timer handler - */ -static void vesa_powerdown(void) -{ - struct vc_data *c = vc_cons[fg_console].d; - /* - * Power down if currently suspended (1 or 2), - * suspend if currently blanked (0), - * else do nothing (i.e. already powered down (3)). - * Called only if powerdown features are allowed. - */ - switch (vesa_blank_mode) { - case VESA_NO_BLANKING: - c->vc_sw->con_blank(c, VESA_VSYNC_SUSPEND+1); - break; - case VESA_VSYNC_SUSPEND: - case VESA_HSYNC_SUSPEND: - c->vc_sw->con_blank(c, VESA_POWERDOWN+1); - break; - } -} - -/* - * This is a timer handler - */ -static void vesa_powerdown_screen(unsigned long dummy) -{ - console_timer.function = unblank_screen_t; - - vesa_powerdown(); -} - -static void timer_do_blank_screen(int entering_gfx, int from_timer_handler) -{ - int currcons = fg_console; - int i; - - if (console_blanked) - return; - - /* entering graphics mode? */ - if (entering_gfx) { - hide_cursor(currcons); - save_screen(currcons); - sw->con_blank(vc_cons[currcons].d, -1); - console_blanked = fg_console + 1; - set_origin(currcons); - return; - } - - /* don't blank graphics */ - if (vcmode != KD_TEXT) { - console_blanked = fg_console + 1; - return; - } - - hide_cursor(currcons); - if (!from_timer_handler) - del_timer_sync(&console_timer); - if (vesa_off_interval) { - console_timer.function = vesa_powerdown_screen; - mod_timer(&console_timer, jiffies + vesa_off_interval); - } else { - if (!from_timer_handler) - del_timer_sync(&console_timer); - console_timer.function = unblank_screen_t; - } - - save_screen(currcons); - /* In case we need to reset origin, blanking hook returns 1 */ - i = sw->con_blank(vc_cons[currcons].d, 1); - console_blanked = fg_console + 1; - if (i) - set_origin(currcons); - - if (console_blank_hook && console_blank_hook(1)) - return; - if (vesa_blank_mode) - sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1); -} - -void do_blank_screen(int entering_gfx) -{ - timer_do_blank_screen(entering_gfx, 0); -} - -/* - * This is a timer handler - */ -static void unblank_screen_t(unsigned long dummy) -{ - unblank_screen(); -} - -/* - * Called by timer as well as from vt_console_driver - */ -void unblank_screen(void) -{ - int currcons; - - if (!console_blanked) - return; - if (!vc_cons_allocated(fg_console)) { - /* impossible */ - printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); - return; - } - currcons = fg_console; - if (vcmode != KD_TEXT) - return; /* but leave console_blanked != 0 */ - - console_timer.function = blank_screen; - if (blankinterval) { - mod_timer(&console_timer, jiffies + blankinterval); - } - - console_blanked = 0; - if (console_blank_hook) - console_blank_hook(0); - set_palette(currcons); - if (sw->con_blank(vc_cons[currcons].d, 0)) - /* Low-level driver cannot restore -> do it ourselves */ - update_screen(fg_console); - set_cursor(fg_console); -} - -/* - * This is both a user-level callable and a timer handler - */ -static void blank_screen(unsigned long dummy) -{ - timer_do_blank_screen(0, 1); -} - -void poke_blanked_console(void) -{ - del_timer(&console_timer); - if (!vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS) - return; - if (console_blanked) { - console_timer.function = unblank_screen_t; - mod_timer(&console_timer, jiffies); /* Now */ - } else if (blankinterval) { - mod_timer(&console_timer, jiffies + blankinterval); - } -} - -/* - * Palettes - */ - -void set_palette(int currcons) -{ - if (vcmode != KD_GRAPHICS) - sw->con_set_palette(vc_cons[currcons].d, color_table); -} - -static int set_get_cmap(unsigned char *arg, int set) -{ - int i, j, k; - - for (i = 0; i < 16; i++) - if (set) { - get_user(default_red[i], arg++); - get_user(default_grn[i], arg++); - get_user(default_blu[i], arg++); - } else { - put_user(default_red[i], arg++); - put_user(default_grn[i], arg++); - put_user(default_blu[i], arg++); - } - if (set) { - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i)) { - for (j = k = 0; j < 16; j++) { - vc_cons[i].d->vc_palette[k++] = default_red[j]; - vc_cons[i].d->vc_palette[k++] = default_grn[j]; - vc_cons[i].d->vc_palette[k++] = default_blu[j]; - } - set_palette(i); - } - } - return 0; -} - -/* - * Load palette into the DAC registers. arg points to a colour - * map, 3 bytes per colour, 16 colours, range from 0 to 255. - */ - -int con_set_cmap(unsigned char *arg) -{ - return set_get_cmap (arg,1); -} - -int con_get_cmap(unsigned char *arg) -{ - return set_get_cmap (arg,0); -} - -void reset_palette(int currcons) -{ - int j, k; - for (j=k=0; j<16; j++) { - palette[k++] = default_red[j]; - palette[k++] = default_grn[j]; - palette[k++] = default_blu[j]; - } - set_palette(currcons); -} - -/* - * Font switching - * - * Currently we only support fonts up to 32 pixels wide, at a maximum height - * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, - * depending on width) reserved for each character which is kinda wasty, but - * this is done in order to maintain compatibility with the EGA/VGA fonts. It - * is upto the actual low-level console-driver convert data into its favorite - * format (maybe we should add a `fontoffset' field to the `display' - * structure so we wont have to convert the fontdata all the time. - * /Jes - */ - -#define max_font_size 65536 - -int con_font_op(int currcons, struct console_font_op *op) -{ - int rc = -EINVAL; - int size = max_font_size, set; - u8 *temp = NULL; - struct console_font_op old_op; - - if (vt_cons[currcons]->vc_mode != KD_TEXT) - goto quit; - memcpy(&old_op, op, sizeof(old_op)); - if (op->op == KD_FONT_OP_SET) { - if (!op->data) - return -EINVAL; - if (op->charcount > 512) - goto quit; - if (!op->height) { /* Need to guess font height [compat] */ - int h, i; - u8 *charmap = op->data, tmp; - - /* If from KDFONTOP ioctl, don't allow things which can be done in userland, - so that we can get rid of this soon */ - if (!(op->flags & KD_FONT_FLAG_OLD)) - goto quit; - rc = -EFAULT; - for (h = 32; h > 0; h--) - for (i = 0; i < op->charcount; i++) { - if (get_user(tmp, &charmap[32*i+h-1])) - goto quit; - if (tmp) - goto nonzero; - } - rc = -EINVAL; - goto quit; - nonzero: - rc = -EINVAL; - op->height = h; - } - if (op->width > 32 || op->height > 32) - goto quit; - size = (op->width+7)/8 * 32 * op->charcount; - if (size > max_font_size) - return -ENOSPC; - set = 1; - } else if (op->op == KD_FONT_OP_GET) - set = 0; - else - return sw->con_font_op(vc_cons[currcons].d, op); - if (op->data) { - temp = kmalloc(size, GFP_KERNEL); - if (!temp) - return -ENOMEM; - if (set && copy_from_user(temp, op->data, size)) { - rc = -EFAULT; - goto quit; - } - op->data = temp; - } - - acquire_console_sem(); - rc = sw->con_font_op(vc_cons[currcons].d, op); - release_console_sem(); - - op->data = old_op.data; - if (!rc && !set) { - int c = (op->width+7)/8 * 32 * op->charcount; - - if (op->data && op->charcount > old_op.charcount) - rc = -ENOSPC; - if (!(op->flags & KD_FONT_FLAG_OLD)) { - if (op->width > old_op.width || - op->height > old_op.height) - rc = -ENOSPC; - } else { - if (op->width != 8) - rc = -EIO; - else if ((old_op.height && op->height > old_op.height) || - op->height > 32) - rc = -ENOSPC; - } - if (!rc && op->data && copy_to_user(op->data, temp, c)) - rc = -EFAULT; - } -quit: if (temp) - kfree(temp); - return rc; -} - -/* - * Interface exported to selection and vcs. - */ - -/* used by selection */ -u16 screen_glyph(int currcons, int offset) -{ - u16 w = scr_readw(screenpos(currcons, offset, 1)); - u16 c = w & 0xff; - - if (w & hi_font_mask) - c |= 0x100; - return c; -} - -/* used by vcs - note the word offset */ -unsigned short *screen_pos(int currcons, int w_offset, int viewed) -{ - return screenpos(currcons, 2 * w_offset, viewed); -} - -void getconsxy(int currcons, char *p) -{ - p[0] = x; - p[1] = y; -} - -void putconsxy(int currcons, char *p) -{ - gotoxy(currcons, p[0], p[1]); - set_cursor(currcons); -} - -u16 vcs_scr_readw(int currcons, const u16 *org) -{ - if ((unsigned long)org == pos && softcursor_original != -1) - return softcursor_original; - return scr_readw(org); -} - -void vcs_scr_writew(int currcons, u16 val, u16 *org) -{ - scr_writew(val, org); - if ((unsigned long)org == pos) { - softcursor_original = -1; - add_softcursor(currcons); - } -} - -static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data) -{ - switch (rqst) - { - case PM_RESUME: - unblank_screen(); - break; - case PM_SUSPEND: - do_blank_screen(0); - break; - } - return 0; -} - -/* - * Visible symbols for modules - */ - -EXPORT_SYMBOL(color_table); -EXPORT_SYMBOL(default_red); -EXPORT_SYMBOL(default_grn); -EXPORT_SYMBOL(default_blu); -EXPORT_SYMBOL(video_font_height); -EXPORT_SYMBOL(video_scan_lines); -EXPORT_SYMBOL(vc_resize); -EXPORT_SYMBOL(fg_console); -EXPORT_SYMBOL(console_blank_hook); -#ifdef CONFIG_VT -EXPORT_SYMBOL(vt_cons); -#endif -#ifndef VT_SINGLE_DRIVER -EXPORT_SYMBOL(take_over_console); -EXPORT_SYMBOL(give_up_console); -#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/console_macros.h linux-2.5/drivers/char/console_macros.h --- linux-2.5.20/drivers/char/console_macros.h Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/char/console_macros.h Sun Mar 3 23:50:41 2002 @@ -1,70 +1,99 @@ -#define cons_num (vc_cons[currcons].d->vc_num) -#define sw (vc_cons[currcons].d->vc_sw) -#define screenbuf (vc_cons[currcons].d->vc_screenbuf) -#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size) -#define origin (vc_cons[currcons].d->vc_origin) -#define scr_top (vc_cons[currcons].d->vc_scr_top) -#define visible_origin (vc_cons[currcons].d->vc_visible_origin) -#define scr_end (vc_cons[currcons].d->vc_scr_end) -#define pos (vc_cons[currcons].d->vc_pos) -#define top (vc_cons[currcons].d->vc_top) -#define bottom (vc_cons[currcons].d->vc_bottom) -#define x (vc_cons[currcons].d->vc_x) -#define y (vc_cons[currcons].d->vc_y) -#define vc_state (vc_cons[currcons].d->vc_state) -#define npar (vc_cons[currcons].d->vc_npar) -#define par (vc_cons[currcons].d->vc_par) -#define ques (vc_cons[currcons].d->vc_ques) -#define attr (vc_cons[currcons].d->vc_attr) -#define saved_x (vc_cons[currcons].d->vc_saved_x) -#define saved_y (vc_cons[currcons].d->vc_saved_y) -#define translate (vc_cons[currcons].d->vc_translate) -#define G0_charset (vc_cons[currcons].d->vc_G0_charset) -#define G1_charset (vc_cons[currcons].d->vc_G1_charset) -#define saved_G0 (vc_cons[currcons].d->vc_saved_G0) -#define saved_G1 (vc_cons[currcons].d->vc_saved_G1) -#define utf (vc_cons[currcons].d->vc_utf) -#define utf_count (vc_cons[currcons].d->vc_utf_count) -#define utf_char (vc_cons[currcons].d->vc_utf_char) -#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char) -#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl) -#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta) -#define decscnm (vc_cons[currcons].d->vc_decscnm) -#define decom (vc_cons[currcons].d->vc_decom) -#define decawm (vc_cons[currcons].d->vc_decawm) -#define deccm (vc_cons[currcons].d->vc_deccm) -#define decim (vc_cons[currcons].d->vc_decim) -#define deccolm (vc_cons[currcons].d->vc_deccolm) -#define need_wrap (vc_cons[currcons].d->vc_need_wrap) -#define kmalloced (vc_cons[currcons].d->vc_kmalloced) -#define report_mouse (vc_cons[currcons].d->vc_report_mouse) -#define color (vc_cons[currcons].d->vc_color) -#define s_color (vc_cons[currcons].d->vc_s_color) -#define def_color (vc_cons[currcons].d->vc_def_color) +#define cons_num (vc->vc_num) +#define video_num_columns (vc->vc_cols) +#define video_num_lines (vc->vc_rows) +#define video_size_row (vc->vc_size_row) +#define vcmode (vc->vc_mode) +#define can_do_color (vc->vc_can_do_color) +#define screenbuf (vc->vc_screenbuf) +#define screenbuf_size (vc->vc_screenbuf_size) +#define origin (vc->vc_origin) +#define scr_top (vc->vc_scr_top) +#define visible_origin (vc->vc_visible_origin) +#define scr_end (vc->vc_scr_end) +#define pos (vc->vc_pos) +#define top (vc->vc_top) +#define bottom (vc->vc_bottom) +#define x (vc->vc_x) +#define y (vc->vc_y) +#define vc_state (vc->vc_state) +#define npar (vc->vc_npar) +#define par (vc->vc_par) +#define ques (vc->vc_ques) +#define attr (vc->vc_attr) +#define saved_x (vc->vc_saved_x) +#define saved_y (vc->vc_saved_y) +#define translate (vc->vc_translate) +#define G0_charset (vc->vc_G0_charset) +#define G1_charset (vc->vc_G1_charset) +#define saved_G0 (vc->vc_saved_G0) +#define saved_G1 (vc->vc_saved_G1) +#define utf (vc->vc_utf) +#define utf_count (vc->vc_utf_count) +#define utf_char (vc->vc_utf_char) +#define video_erase_char (vc->vc_video_erase_char) +#define disp_ctrl (vc->vc_disp_ctrl) +#define toggle_meta (vc->vc_toggle_meta) +#define decscnm (vc->vc_decscnm) +#define decom (vc->vc_decom) +#define decawm (vc->vc_decawm) +#define deccm (vc->vc_deccm) +#define decim (vc->vc_decim) +#define deccolm (vc->vc_deccolm) +#define need_wrap (vc->vc_need_wrap) +#define kmalloced (vc->vc_kmalloced) +#define report_mouse (vc->vc_report_mouse) +#define color (vc->vc_color) +#define s_color (vc->vc_s_color) +#define def_color (vc->vc_def_color) #define foreground (color & 0x0f) #define background (color & 0xf0) -#define charset (vc_cons[currcons].d->vc_charset) -#define s_charset (vc_cons[currcons].d->vc_s_charset) -#define intensity (vc_cons[currcons].d->vc_intensity) -#define underline (vc_cons[currcons].d->vc_underline) -#define blink (vc_cons[currcons].d->vc_blink) -#define reverse (vc_cons[currcons].d->vc_reverse) -#define s_intensity (vc_cons[currcons].d->vc_s_intensity) -#define s_underline (vc_cons[currcons].d->vc_s_underline) -#define s_blink (vc_cons[currcons].d->vc_s_blink) -#define s_reverse (vc_cons[currcons].d->vc_s_reverse) -#define ulcolor (vc_cons[currcons].d->vc_ulcolor) -#define halfcolor (vc_cons[currcons].d->vc_halfcolor) -#define tab_stop (vc_cons[currcons].d->vc_tab_stop) -#define palette (vc_cons[currcons].d->vc_palette) -#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch) -#define bell_duration (vc_cons[currcons].d->vc_bell_duration) -#define cursor_type (vc_cons[currcons].d->vc_cursor_type) -#define display_fg (vc_cons[currcons].d->vc_display_fg) -#define complement_mask (vc_cons[currcons].d->vc_complement_mask) -#define s_complement_mask (vc_cons[currcons].d->vc_s_complement_mask) -#define hi_font_mask (vc_cons[currcons].d->vc_hi_font_mask) +#define charset (vc->vc_charset) +#define s_charset (vc->vc_s_charset) +#define intensity (vc->vc_intensity) +#define underline (vc->vc_underline) +#define blink (vc->vc_blink) +#define reverse (vc->vc_reverse) +#define s_intensity (vc->vc_s_intensity) +#define s_underline (vc->vc_s_underline) +#define s_blink (vc->vc_s_blink) +#define s_reverse (vc->vc_s_reverse) +#define ulcolor (vc->vc_ulcolor) +#define halfcolor (vc->vc_halfcolor) +#define tab_stop (vc->vc_tab_stop) +#define palette (vc->vc_palette) +#define bell_pitch (vc->vc_bell_pitch) +#define bell_duration (vc->vc_bell_duration) +#define cursor_type (vc->vc_cursor_type) +#define complement_mask (vc->vc_complement_mask) +#define s_complement_mask (vc->vc_s_complement_mask) +#define hi_font_mask (vc->vc_hi_font_mask) -#define vcmode (vt_cons[currcons]->vc_mode) +#define dectcem (vc->vc_dectcem) +#define decscl (vc->vc_decscl) +#define c8bit (vc->vc_c8bit) +#define d8bit (vc->vc_d8bit) +#define shift (vc->vc_shift) +#define priv1 (vc->vc_priv1) +#define priv2 (vc->vc_priv2) +#define priv3 (vc->vc_priv3) +#define priv4 (vc->vc_priv4) +#define decckm (vc->vc_decckm) +#define decsclm (vc->vc_decsclm) +#define decarm (vc->vc_decarm) +#define decnrcm (vc->vc_decnrcm) +#define decnkm (vc->vc_decnkm) +#define kam (vc->vc_kam) +#define crm (vc->vc_crm) +#define lnm (vc->vc_lnm) +#define irm (vc->vc_irm) +#define GL_charset (vc->vc_GL_charset) +#define GR_charset (vc->vc_GR_charset) +#define G2_charset (vc->vc_G2_charset) +#define G3_charset (vc->vc_G3_charset) +#define GS_charset (vc->vc_GS_charset) +#define saved_G2 (vc->vc_saved_G2) +#define saved_G3 (vc->vc_saved_G3) +#define saved_GS (vc->vc_saved_GS) -#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct)) +#define sw (vc->display_fg->vt_sw) +#define softcursor_original (vc->display_fg->cursor_original) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/consolemap.c linux-2.5/drivers/char/consolemap.c --- linux-2.5.20/drivers/char/consolemap.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/char/consolemap.c Sun Mar 3 23:50:41 2002 @@ -19,7 +19,6 @@ #include #include #include -#include #include static unsigned short translations[][256] = { @@ -182,7 +181,7 @@ static struct uni_pagedir *dflt; -static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i) +static void set_inverse_transl(struct vc_data *vc, struct uni_pagedir *p, int i) { int j, glyph; unsigned short *t = translations[i]; @@ -199,7 +198,7 @@ memset(q, 0, MAX_GLYPH); for (j = 0; j < E_TABSZ; j++) { - glyph = conv_uni_to_pc(conp, t[j]); + glyph = conv_uni_to_pc(vc, t[j]); if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) { /* prefer '-' above SHY etc. */ q[glyph] = j; @@ -207,10 +206,10 @@ } } -unsigned short *set_translate(int m,int currcons) +void set_translate(struct vc_data *vc, int m) { - inv_translate[currcons] = m; - return translations[m]; + inv_translate[vc->vc_num] = m; + vc->vc_translate = translations[m]; } /* @@ -220,29 +219,32 @@ * was active, or using Unicode. * Still, it is now possible to a certain extent to cut and paste non-ASCII. */ -unsigned char inverse_translate(struct vc_data *conp, int glyph) +unsigned char inverse_translate(struct vc_data *vc, int glyph) { struct uni_pagedir *p; if (glyph < 0 || glyph >= MAX_GLYPH) return 0; - else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) || - !p->inverse_translations[inv_translate[conp->vc_num]]) + else if (!(p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc) || + !p->inverse_translations[inv_translate[vc->vc_num]]) return glyph; else - return p->inverse_translations[inv_translate[conp->vc_num]][glyph]; + return p->inverse_translations[inv_translate[vc->vc_num]][glyph]; } static void update_user_maps(void) { - int i; struct uni_pagedir *p, *q = NULL; + struct vc_data *vc; + int i; for (i = 0; i < MAX_NR_CONSOLES; i++) { - if (!vc_cons_allocated(i)) + vc = vt_cons->vc_cons[i]; + + if (!vc) continue; - p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p && p != q) { - set_inverse_transl(vc_cons[i].d, p, USER_MAP); + set_inverse_transl(vc, p, USER_MAP); q = p; } } @@ -286,7 +288,7 @@ for (i=0; ivc_cons[fg_console], p[i]); __put_user((ch & ~0xff) ? 0 : ch, arg+i); } return 0; @@ -363,28 +365,29 @@ } } -void con_free_unimap(int con) +void con_free_unimap(struct vc_data *vc) { struct uni_pagedir *p; - struct vc_data *conp = vc_cons[con].d; - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (!p) return; - *conp->vc_uni_pagedir_loc = 0; + *vc->vc_uni_pagedir_loc = 0; if (--p->refcount) return; con_release_unimap(p); kfree(p); } -static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p) +static int con_unify_unimap(struct vc_data *vc, struct uni_pagedir *p) { int i, j, k; struct uni_pagedir *q; for (i = 0; i < MAX_NR_CONSOLES; i++) { - if (!vc_cons_allocated(i)) + struct vc_data *tmp = vc->display_fg->vc_cons[i]; + + if (!tmp) continue; - q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; + q = (struct uni_pagedir *)*tmp->vc_uni_pagedir_loc; if (!q || q == p || q->sum != p->sum) continue; for (j = 0; j < 32; j++) { @@ -407,7 +410,7 @@ } if (j == 32) { q->refcount++; - *conp->vc_uni_pagedir_loc = (unsigned long)q; + *vc->vc_uni_pagedir_loc = (unsigned long)q; con_release_unimap(p); kfree(p); return 1; @@ -443,12 +446,11 @@ } /* ui is a leftover from using a hashtable, but might be used again */ -int con_clear_unimap(int con, struct unimapinit *ui) +int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) { struct uni_pagedir *p, *q; - struct vc_data *conp = vc_cons[con].d; - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p && p->readonly) return -EIO; if (!p || --p->refcount) { q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL); @@ -458,7 +460,7 @@ } memset(q, 0, sizeof(*q)); q->refcount=1; - *conp->vc_uni_pagedir_loc = (unsigned long)q; + *vc->vc_uni_pagedir_loc = (unsigned long)q; } else { if (p == dflt) dflt = NULL; p->refcount++; @@ -469,13 +471,12 @@ } int -con_set_unimap(int con, ushort ct, struct unipair *list) +con_set_unimap(struct vc_data *vc, ushort ct, struct unipair *list) { - int err = 0, err1, i; struct uni_pagedir *p, *q; - struct vc_data *conp = vc_cons[con].d; - - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + int err = 0, err1, i; + + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p->readonly) return -EIO; if (!ct) return 0; @@ -484,10 +485,10 @@ int j, k; u16 **p1, *p2, l; - err1 = con_clear_unimap(con, NULL); + err1 = con_clear_unimap(vc, NULL); if (err1) return err1; - q = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; for (i = 0, l = 0; i < 32; i++) if ((p1 = p->uni_pgdir[i])) for (j = 0; j < 32; j++) @@ -497,7 +498,7 @@ err1 = con_insert_unipair(q, l, p2[k]); if (err1) { p->refcount++; - *conp->vc_uni_pagedir_loc = (unsigned long)p; + *vc->vc_uni_pagedir_loc = (unsigned long)p; con_release_unimap(q); kfree(q); return err1; @@ -516,12 +517,11 @@ list++; } - if (con_unify_unimap(conp, p)) + if (con_unify_unimap(vc, p)) return err; for (i = 0; i <= 3; i++) - set_inverse_transl(conp, p, i); /* Update all inverse translations */ - + set_inverse_transl(vc, p, i); /* Update all inverse translations */ return err; } @@ -531,19 +531,18 @@ PIO_FONTRESET ioctl is called. */ int -con_set_default_unimap(int con) +con_set_default_unimap(struct vc_data *vc) { int i, j, err = 0, err1; u16 *q; struct uni_pagedir *p; - struct vc_data *conp = vc_cons[con].d; if (dflt) { - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p == dflt) return 0; dflt->refcount++; - *conp->vc_uni_pagedir_loc = (unsigned long)dflt; + *vc->vc_uni_pagedir_loc = (unsigned long)dflt; if (p && --p->refcount) { con_release_unimap(p); kfree(p); @@ -552,11 +551,10 @@ } /* The default font is always 256 characters */ - - err = con_clear_unimap(con,NULL); + err = con_clear_unimap(vc, NULL); if (err) return err; - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; q = dfont_unitable; for (i = 0; i < 256; i++) @@ -566,29 +564,27 @@ err = err1; } - if (con_unify_unimap(conp, p)) { - dflt = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + if (con_unify_unimap(vc, p)) { + dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; return err; } for (i = 0; i <= 3; i++) - set_inverse_transl(conp, p, i); /* Update all inverse translations */ + set_inverse_transl(vc, p, i); /* Update all inverse translations */ dflt = p; return err; } int -con_copy_unimap(int dstcon, int srccon) +con_copy_unimap(struct vc_data *dconp, struct vc_data *sconp) { - struct vc_data *sconp = vc_cons[srccon].d; - struct vc_data *dconp = vc_cons[dstcon].d; struct uni_pagedir *q; - if (!vc_cons_allocated(srccon) || !*sconp->vc_uni_pagedir_loc) + if (!sconp || !*sconp->vc_uni_pagedir_loc) return -EINVAL; if (*dconp->vc_uni_pagedir_loc == *sconp->vc_uni_pagedir_loc) return 0; - con_free_unimap(dstcon); + con_free_unimap(dconp); q = (struct uni_pagedir *)*sconp->vc_uni_pagedir_loc; q->refcount++; *dconp->vc_uni_pagedir_loc = (long)q; @@ -596,16 +592,15 @@ } int -con_get_unimap(int con, ushort ct, ushort *uct, struct unipair *list) +con_get_unimap(struct vc_data *vc, ushort ct, ushort *uct, struct unipair *list) { int i, j, k, ect; u16 **p1, *p2; struct uni_pagedir *p; - struct vc_data *conp = vc_cons[con].d; ect = 0; - if (*conp->vc_uni_pagedir_loc) { - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + if (*vc->vc_uni_pagedir_loc) { + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; for (i = 0; i < 32; i++) if ((p1 = p->uni_pgdir[i])) for (j = 0; j < 32; j++) @@ -625,16 +620,16 @@ return ((ect <= ct) ? 0 : -ENOMEM); } -void con_protect_unimap(int con, int rdonly) +void con_protect_unimap(struct vc_data *vc, int rdonly) { struct uni_pagedir *p = (struct uni_pagedir *) - *vc_cons[con].d->vc_uni_pagedir_loc; + *vc->vc_uni_pagedir_loc; if (p) p->readonly = rdonly; } int -conv_uni_to_pc(struct vc_data *conp, long ucs) +conv_uni_to_pc(struct vc_data *vc, long ucs) { int h; u16 **p1, *p2; @@ -655,10 +650,10 @@ else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE) return ucs & UNI_DIRECT_MASK; - if (!*conp->vc_uni_pagedir_loc) + if (!*vc->vc_uni_pagedir_loc) return -3; - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if ((p1 = p->uni_pgdir[ucs >> 11]) && (p2 = p1[(ucs >> 6) & 0x1f]) && (h = p2[ucs & 0x3f]) < MAX_GLYPH) @@ -677,7 +672,10 @@ { int i; - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc) - con_set_default_unimap(i); + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *vc = vt_cons->vc_cons[i]; + + if (vc && !*vc->vc_uni_pagedir_loc) + con_set_default_unimap(vc); + } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/decvte.c linux-2.5/drivers/char/decvte.c --- linux-2.5.20/drivers/char/decvte.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/decvte.c Sun Mar 3 23:50:41 2002 @@ -0,0 +1,2029 @@ +/* + * decvte.c - DEC VT terminal emulation code. + * Copyright (C) 2000 James Simmons + * + * I moved all the VT emulation code out of console.c to here. It makes life + * much easier and the code smaller. It also allows other devices to emulate + * a TTY besides the video system. People can also change the makefile to + * support a different emulation if they wanted. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "console_macros.h" + +/* + * DEC VT emulator + */ + +/* Different states of the emulator */ +enum { ESinit, + /* ESC substates */ + ESesc, ESacs, ESscf, ESgzd4, ESg1d4, ESg2d4, + ESg3d4, ESg1d6, ESg2d6, ESg3d6, ESdocs, + /* CSI substates */ + EScsi, EScsi_getpars, EScsi_gotpars, EScsi_space, + EScsi_exclam, EScsi_dquote, EScsi_dollar, EScsi_and, + EScsi_squote, EScsi_star, EScsi_plus, + /* OSC substates */ + ESosc, ESpalette, + /* Misc. states */ + ESfunckey, ESignore, +}; + +#define __VTE_CSI (c8bit == 0 ? "\033[" : "\233") +#define __VTE_DCS (c8bit == 0 ? "\033P" : "\220") +#define __VTE_ST (c8bit == 0 ? "\033\\" : "\234") +#define __VTE_APC (c8bit == 0 ? "\033_" : "\237") + +/* + * this is what the terminal answers to a ESC-Z or csi0c query. + */ +#define VT100ID "\033[?1;2c" +#define VT102ID "\033[?6c" + +/* + * Here is the default bell parameters: 750HZ, 1/8th of a second + */ +#define DEFAULT_BELL_PITCH 750 +#define DEFAULT_BELL_DURATION (HZ/8) + +/* + * LINE FEED (LF) + */ +void vte_lf(struct vc_data *vc) +{ + /* don't scroll if above bottom of scrolling region, or + * if below scrolling region + */ + if (y+1 == bottom) + scrup(vc, top, bottom, 1); + else if (y < video_num_lines-1) { + y++; + pos += video_size_row; + } + need_wrap = 0; +} + +/* + * REVERSE LINE FEED (RI) + */ +static void vte_ri(struct vc_data *vc) +{ + /* don't scroll if below top of scrolling region, or + * if above scrolling region + */ + if (y == top) + scrdown(vc, top, bottom, 1); + else if (y > 0) { + y--; + pos -= video_size_row; + } + need_wrap = 0; +} + +/* + * CARRIAGE RETURN (CR) + */ +inline void vte_cr(struct vc_data *vc) +{ + pos -= x<<1; + need_wrap = x = 0; +} + +/* + * BACK SPACE (BS) + */ +inline void vte_bs(struct vc_data *vc) +{ + if (x) { + pos -= 2; + x--; + need_wrap = 0; + } +} + +/* + * CURSOR LINE TABULATION (CVT) + * + * NOTE: + * In accordance with our interpretation of VT as LF we will treat CVT as + * (par[0] * LF). Not very creative, but at least consequent. + */ +static void vte_cvt(struct vc_data *vc, int vpar) +{ + int i; + + for (i = 0; i < vpar; i++) { + vte_lf(vc); + } +} + +/* + * CURSOR BACKWARD TABULATION (CBT) + */ +static void vte_cbt(struct vc_data *vc, int vpar) +{ + int i; + + for (i = 0; i < vpar; i++) { + pos -= (x << 1); + while (x > 0) { + x--; + if (tab_stop[x >> 5] & (1 << (x & 31))) + break; + } + pos += (x << 1); + } +} + +/* + * CURSOR FORWARD TABULATION (CHT) + */ +static void vte_cht(struct vc_data *vc, int vpar) +{ + int i; + + for (i = 0; i < vpar; i++) { + pos -= (x << 1); + while (x < video_num_columns - 1) { + x++; + if (tab_stop[x >> 5] & (1 << (x & 31))) + break; + } + pos += (x << 1); + } +} + +/* + * ERASE IN PAGE (ED) + */ +void vte_ed(struct vc_data *vc, int vpar) +{ + unsigned short *start; + unsigned int count; + + switch (vpar) { + case 0: /* erase from cursor to end of display */ + count = (scr_end-pos)>>1; + start = (unsigned short *) pos; + /* do in two stages */ + clear_region(vc, x, y, video_num_columns-x, 1); + clear_region(vc, 0, y+1, video_num_columns, + video_num_lines-y-1); + break; + case 1: /* erase from start to cursor */ + count = ((pos-origin)>>1)+1; + start = (unsigned short *) origin; + /* do in two stages */ + clear_region(vc, 0, 0, video_num_columns, y); + clear_region(vc, 0, y, x + 1, 1); + break; + case 2: /* erase whole display */ + count = video_num_columns * video_num_lines; + start = (unsigned short *) origin; + clear_region(vc, 0, 0, video_num_columns, + video_num_lines); + break; + default: + return; + } + scr_memsetw(start, video_erase_char, 2*count); + need_wrap = 0; +} + +/* + * ERASE IN LINE (EL) + */ +static void vte_el(struct vc_data *vc, int vpar) +{ + unsigned int count; + unsigned short * start; + + switch (vpar) { + case 0: /* erase from cursor to end of line */ + count = video_num_columns-x; + start = (unsigned short *) pos; + clear_region(vc, x, y, video_num_columns-x, 1); + break; + case 1: /* erase from start of line to cursor */ + start = (unsigned short *) (pos - (x<<1)); + count = x+1; + clear_region(vc, 0, y, x + 1, 1); + break; + case 2: /* erase whole line */ + start = (unsigned short *) (pos - (x<<1)); + count = video_num_columns; + clear_region(vc, 0, y, video_num_columns, 1); + break; + default: + return; + } + scr_memsetw(start, video_erase_char, 2 * count); + need_wrap = 0; +} + +/* + * Erase character (ECH) + * + * NOTE: This function is not available in DEC VT1xx terminals. + */ +static void vte_ech(struct vc_data *vc, int vpar) +{ + int count; + + if (!vpar) + vpar++; + count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar; + + scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count); + clear_region(vc, x, y, count, 1); + need_wrap = 0; +} + +/* + * SELECT GRAPHIC RENDITION (SGR) + * + * NOTE: The DEC vt1xx series only implements attribute values 0,1,4,5 and 7. + */ +static void vte_sgr(struct vc_data *vc) +{ + int i; + + for (i=0;i<=npar;i++) + switch (par[i]) { + case 0: /* all attributes off */ + default_attr(vc); + break; + case 1: /* bold or increased intensity */ + intensity = 2; + break; + case 2: /* faint or decreased intensity */ + intensity = 0; + break; + case 4: /* singly underlined. */ + underline = 1; + break; + case 5: /* slowly blinking (< 2.5 Hz) */ + case 6: /* rapidly blinking (>= 2.5 Hz) */ + blink = 1; + break; + case 7: /* negative image */ + reverse = 1; + break; + case 10:/* primary (default) font + * ANSI X3.64-1979 (SCO-ish?) + * Select primary font, don't display + * control chars if defined, don't set + * bit 8 on output. + */ + set_translate(vc, charset == 0 ? + G0_charset : G1_charset); + disp_ctrl = 0; + toggle_meta = 0; + break; + case 11:/* first alternative font + * ANSI X3.64-1979 (SCO-ish?) + * Select first alternate font, lets + * chars < 32 be displayed as ROM chars. + */ + set_translate(vc, IBMPC_MAP); + disp_ctrl = 1; + toggle_meta = 0; + break; + case 12:/* second alternative font + * Select second alternate font, toggle + * high bit before displaying as ROM char. + */ + set_translate(vc, IBMPC_MAP); + disp_ctrl = 1; + toggle_meta = 1; + break; + case 21:/* normal intensity */ + case 22:/* normal intensity */ + intensity = 1; + break; + case 24:/* not underlined (neither singly nor doubly) */ + underline = 0; + break; + case 25:/* steady (not blinking) */ + blink = 0; + break; + case 27:/* positive image */ + reverse = 0; + break; + case 38:/* foreground color (ISO 8613-6/ITU T.416) + * Enables underscore, white foreground + * with white underscore (Linux - use + * default foreground). + */ + color = (def_color & 0x0f) | background; + underline = 1; + break; + case 39:/* default display color */ + color = (def_color & 0x0f) | background; + underline = 0; + break; + case 49:/* default background color */ + color = (def_color & 0xf0) | foreground; + break; + default: + if (par[i] >= 30 && par[i] <= 37) + color = color_table[par[i]-30] + | background; + else if (par[i] >= 40 && par[i] <= 47) + color = (color_table[par[i]-40]<<4) + | foreground; + break; + } + update_attr(vc); +} + +/* + * Fake a DEC DSR for non-implemented features + */ +static void vte_fake_dec_dsr(struct tty_struct *tty, char *reply) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "%s?%sn", __VTE_CSI, reply); + respond_string(buf, tty); +} + +/* + * CURSOR POSITION REPORT (CPR) + * DEC EXTENDED CURSOR POSITION REPORT (DECXCPR) + */ +static void vte_cpr(struct tty_struct *tty, int ext) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + if (ext) { + /* + * NOTE: Since we do not (yet?) implement any form of page + * memory, we will always return the cursor position in page 1. + */ + sprintf(buf, "%s?%d;%d;1R", __VTE_CSI, + y + (decom ? top + 1 : 1), x+1); + } else { + sprintf(buf, "%s%d;%dR", __VTE_CSI, + y + (decom ? top + 1 : 1), x+1); + } + respond_string(buf, tty); +} + +/* + * DEVICE STATUS REPORT (DSR) + */ +static inline void vte_dsr(struct tty_struct * tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "%s0n", __VTE_CSI); + respond_string(buf, tty); +} + +/* + * ANSWERBACK MESSAGE + */ +static inline void vte_answerback(struct tty_struct *tty) +{ + respond_string("l i n u x", tty); +} + +/* + * DA - DEVICE ATTRIBUTE + */ +static inline void vte_da(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + /* We claim VT220 compatibility... */ + sprintf(buf, "%s?62;1;2;6;7;8;9c", __VTE_CSI); + respond_string(buf, tty); +} + +#define VTE_VERSION 211 +/* + * DA - SECONDARY DEVICE ATTRIBUTE [VT220 and up] + * + * Reply parameters: + * 1 = Model (1=vt220, 18=vt330, 19=vt340, 41=vt420) + * 2 = Firmware version (nn = n.n) + * 3 = Installed options (0 = none) + */ +static void vte_dec_da2(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "%s>%d;%d;0c", __VTE_CSI, 1, VTE_VERSION / 10); + respond_string(buf, tty); +} + +/* + * DA - TERTIARY DEVICE ATTRIBUTE [VT220 and up] + * + * Reply: unit ID (we report "0") + */ +static void vte_dec_da3(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "%s!|%s%s", __VTE_DCS, "0", __VTE_ST); + respond_string(buf, tty); +} + +/* + * DECREPTPARM - DEC REPORT TERMINAL PARAMETERS [VT1xx/VT2xx/VT320] + */ +static void vte_decreptparm(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "\033[%d;1;1;120;120;1;0x", par[0] + 2); + respond_string(buf, tty); +} + +/* + * SM - SET MODE / + * RM - RESET MODE + */ +static void set_mode(struct vc_data *vc, int on_off) +{ + int i; + + for (i=0; i<=npar; i++) + /* DEC private modes set/reset */ + if (priv4) switch(par[i]) { + case 1: /* DECCKM - Cursor keys mode */ + if (on_off) + set_kbd_mode(&vc->kbd_table, VC_CKMODE); + else + clr_kbd_mode(&vc->kbd_table, VC_CKMODE); + break; + case 2: /* DECANM - ANSI mode */ + break; + case 3: /* DECCOLM - Column mode */ +#if 0 + deccolm = on_off; + (void) vc_resize(video_num_lines, deccolm ? 132 +: 80); + /* this alone does not suffice; some user mode + utility has to change the hardware regs */ +#endif + break; + case 4: /* DECSCLM - Scrolling mode */ + break; + case 5: /* DECSCNM - Screen mode */ + if (decscnm != on_off) { + decscnm = on_off; + invert_screen(vc, 0, screenbuf_size, 0); + update_attr(vc); + } + break; + case 6: /* DECOM - Origin mode */ + decom = on_off; + gotoxay(vc, 0, 0); + break; + case 7: /* DECAWM - Autowrap mode */ + decawm = on_off; + break; + case 8: /* DECARM - Autorepeat mode */ + decarm = on_off; + if (on_off) + set_kbd_mode(&vc->kbd_table, VC_REPEAT); + else + clr_kbd_mode(&vc->kbd_table, VC_REPEAT); + break; + case 9: + report_mouse = on_off ? 1 : 0; + break; + case 25: /* DECTCEM - Text cursor enable mode */ + dectcem = on_off; + break; + case 42: /* DECNCRS - National character set replacement mode */ + break; + case 60: /* DECHCCM - Horizontal cursor coupling mode */ break; + case 61: /* DECVCCM - Vertical cursor coupling mode */ + break; + case 64: /* DECPCCM - Page cursor coupling mode */ + break; + case 66: /* DECNKM - Numeric keybad mode */ + decnkm = on_off; + if (on_off) + set_kbd_mode(&vc->kbd_table, VC_APPLIC); + else + clr_kbd_mode(&vc->kbd_table, VC_APPLIC); + break; + case 67: /* DECBKM - Backarrow key mode */ + break; + case 68: /* DECKBUM - Keyboard usage mode */ + break; + case 69: /* DECVSSM - Vertical split screen mode +*/ + break; + case 73: /* DECXRLM - Transfer rate limiting mode */ + break; + case 81: /* DECKPM - Keyboard position mode */ + break; + case 1000: + report_mouse = on_off ? 2 : 0; + break; + } else switch(par[i]) { /* ANSI modes set/reset */ + case 3: /* Monitor (display ctrls) */ + disp_ctrl = on_off; + break; + case 4: /* Insert Mode on/off */ + irm = on_off; + break; + case 20: /* Lf, Enter == CrLf/Lf */ + if (on_off) + set_kbd_mode(&vc->kbd_table, VC_CRLF); + else + clr_kbd_mode(&vc->kbd_table, VC_CRLF); + break; + } +} + +/* + * DECCIR - Cursor information report + */ +static void vte_deccir(struct tty_struct *tty) +{ + /* not yet implemented */ +} + +/* + * DECMSR - Macro space report + */ +static void vte_decmsr(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "%s%d*{", __VTE_CSI, 0); /* No space left */ + respond_string(buf, tty); +} + +/* + * DECRPM - Report mode + */ +static void vte_decrpm(struct tty_struct *tty, int priv, int mode, int status) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + if (status == 0) { + status = 2; + } else { + if (status == 2) { + status = 0; + } + } + + if (priv) + sprintf(buf, "%s?%d;%d$y", __VTE_CSI, mode, status); + else + sprintf(buf, "%s%d;%d$y", __VTE_CSI, mode, status); + respond_string(buf, tty); +} + +/* + * DECRQM - Request mode + * + * Reply codes: + * 0 = reset + * 1 = set + * 2 = unknown + * 3 = premanently set + * 4 = permanently reset + */ +static void vte_decrqm(struct tty_struct *tty, int priv) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + + if (priv) { + switch (par[0]) { + case 1: /* DECCKM - Cursor keys mode */ + vte_decrpm(tty, priv, par[0], decckm); + break; + case 2: /* DECANM */ + case 3: /* DECCOLM */ + case 4: /* DECSCLM */ + vte_decrpm(tty, priv, par[0], 4); + break; + case 5: /* DECSCNM */ + vte_decrpm(tty, priv, par[0], decscnm); + break; + case 6: /* DECOM */ + vte_decrpm(tty, priv, par[0], decom); + break; + case 7: /* DECAWM */ + vte_decrpm(tty, priv, par[0], decawm); + break; + case 8: /* DECARM */ + vte_decrpm(tty, priv, par[0], decarm); + break; + case 25: /* DECTCEM */ + vte_decrpm(tty, priv, par[0], dectcem); + break; + case 42: /* DECNCRM */ + case 60: /* DECHCCM */ + case 61: /* DECVCCM */ + case 64: /* DECPCCM */ + vte_decrpm(tty, priv, par[0], 4); + break; + case 66: /* DECNKM */ + vte_decrpm(tty, priv, par[0], decnkm); + break; + case 67: /* DECBKM */ + case 68: /* DECKBUM */ + case 69: /* DECVSSM */ + case 73: /* DECXRLM */ + case 81: /* DECKPM */ + vte_decrpm(tty, priv, par[0], 4); + break; + default: + vte_decrpm(tty, priv, par[0], 2); + } + } else { + switch (par[0]) { + case 1: /* GATM */ + vte_decrpm(tty, priv, par[0], 4); + break; + case 2: /* KAM */ + vte_decrpm(tty, priv, par[0], kam); + break; + case 3: /* CRM */ + vte_decrpm(tty, priv, par[0], 4); + break; + case 4: /* IRM */ + vte_decrpm(tty, priv, par[0], irm); + break; + case 5: /* SRTM */ + case 6: /* ERM */ + case 7: /* VEM */ + case 8: /* BDSM */ + case 9: /* DCSM */ + case 10: /* HEM */ + case 11: /* PUM */ + case 12: /* SRM */ + case 13: /* FEAM */ + case 14: /* FETM */ + case 15: /* MATM */ + case 16: /* TTM */ + case 17: /* SATM */ + case 18: /* TSM */ + case 19: /* EBM */ + vte_decrpm(tty, priv, par[0], 4); + break; + case 20: /* LNM */ + vte_decrpm(tty, priv, par[0], lnm); + break; + case 21: /* GRCM */ + case 22: /* ZDM */ + vte_decrpm(tty, priv, par[0], 4); + break; + default: + vte_decrpm(tty, priv, par[0], 2); + } + } +} + +/* + * DECSCL - Set operating level + */ +static void vte_decscl(struct vc_data *vc) +{ + switch (par[0]) { + case 61: /* VT100 mode */ + if (npar == 1) { + decscl = 1; + c8bit = 0; + } + break; + case 62: /* VT200 mode */ + case 63: /* VT300 mode */ + case 64: /* VT400 mode */ + if (npar <= 2) { + decscl = 4; + if (par[1] == 1) + c8bit = 0; + else + c8bit = 1; + } + break; + } + return; +} + +/* + * DECTABSR - Tabulation stop report + */ +void vte_dectabsr(struct tty_struct *tty) +{ + /* not yet implemented */ +} + +/* + * DECTSR - Terminal state report + */ +void vte_dectsr(struct tty_struct *tty) +{ + /* not yet implemented */ +} + +static void setterm_command(struct vc_data *vc) +{ + switch(par[0]) { + case 1: /* set color for underline mode */ + if (can_do_color && par[1] < 16) { + ulcolor = color_table[par[1]]; + if (underline) + update_attr(vc); + } + break; + case 2: /* set color for half intensity mode */ + if (can_do_color && par[1] < 16) { + halfcolor = color_table[par[1]]; + if (intensity == 0) + update_attr(vc); + } + break; + case 8: /* store colors as defaults */ + def_color = attr; + if (hi_font_mask == 0x100) + def_color >>= 1; + default_attr(vc); + update_attr(vc); + break; + case 9: /* set blanking interval */ + vc->display_fg->blank_interval = + ((par[1] < 60) ? par[1] : 60) * 60 * HZ; + poke_blanked_console(vc->display_fg); + break; + case 10: /* set bell frequency in Hz */ + if (npar >= 1) + bell_pitch = par[1]; + else + bell_pitch = DEFAULT_BELL_PITCH; + break; + case 11: /* set bell duration in msec */ + if (npar >= 1) + bell_duration = (par[1] < 2000) ? + par[1]*HZ/1000 : 0; + else + bell_duration = DEFAULT_BELL_DURATION; + break; + case 12: /* bring specified console to the front */ + if (par[1] >= 1 && vc_cons_allocated(par[1]-1)) + set_console(par[1] - 1); + break; + case 13: /* unblank the screen */ + poke_blanked_console(vc->display_fg); + break; + case 14: /* set vesa powerdown interval */ + vc->display_fg->off_interval = + ((par[1] < 60) ? par[1] : 60) * 60 * HZ; + break; + } +} + +/* + * ICH - INSERT CHARACTER [VT220] + */ +static void vte_ich(struct vc_data *vc, unsigned int nr) +{ + if (nr > video_num_columns - x) + nr = video_num_columns - x; + else if (!nr) + nr = 1; + insert_char(vc, nr); +} + +/* + * IL - INSERT LINE + */ +static void vte_il(struct vc_data *vc, unsigned int nr) +{ + if (nr > video_num_lines - y) + nr = video_num_lines - y; + else if (!nr) + nr = 1; + insert_line(vc, nr); +} + +/* + * DCH - DELETE CHARACTER + */ +static void vte_dch(struct vc_data *vc, unsigned int nr) +{ + if (nr > video_num_columns - x) + nr = video_num_columns - x; + else if (!nr) + nr = 1; + delete_char(vc, nr); +} + +/* + * DL - DELETE LINE + */ +static void vte_dl(struct vc_data *vc, unsigned int nr) +{ + if (nr > video_num_lines - y) + nr = video_num_lines - y; + else if (!nr) + nr=1; + delete_line(vc, nr); +} + +/* + * DECSC - SAVE CURSOR + * + * This saves the following states: + * - cursor position + * - graphic rendition + * - character set shift state + * - state of wrap flag + * - state of origin mode + * - state of selective erase (not implemented) + */ +void vte_decsc(struct vc_data *vc) +{ + saved_x = x; + saved_y = y; + s_intensity = intensity; + s_underline = underline; + s_blink = blink; + s_reverse = reverse; + s_charset = charset; + s_color = color; + saved_G0 = G0_charset; + saved_G1 = G1_charset; + saved_G2 = G2_charset; + saved_G3 = G3_charset; +} + +/* + * DECRC - RESTORE CURSOR + */ +static void vte_decrc(struct vc_data *vc) +{ + gotoxy(vc, saved_x, saved_y); + intensity = s_intensity; + underline = s_underline; + blink = s_blink; + reverse = s_reverse; + charset = s_charset; + color = s_color; + G0_charset = saved_G0; + G1_charset = saved_G1; + G2_charset = saved_G2; + G3_charset = saved_G3; + set_translate(vc, charset ? G1_charset : G0_charset); + update_attr(vc); + need_wrap = 0; +} + +/* + * RIS - RESET TO INITIAL STATE + * + * On DEC terminals this causes the following: + * - all set-up parameters are replaced by power-up defaults + * - all communications lines are disconnected (should we send SIGHUP to + * controlling process?) + * - all user-defined keys are cleared (not implemented) + * - the screen is cleared + * - cursor is place to upper-left corner + * - SGR state is set to normal + * - selective erase attribute write state is set to "non-selective erase" + * (not implemented) + * - all character sets are set to default (not implemented) + */ +void vte_ris(struct vc_data *vc, int do_clear) +{ + top = 0; + bottom = video_num_lines; + vc_state = ESinit; + priv1 = 0; + priv2 = 0; + priv3 = 0; + priv4 = 0; + set_translate(vc, LAT1_MAP); + G0_charset = LAT1_MAP; + G1_charset = GRAF_MAP; + charset = 0; + need_wrap = 0; + report_mouse = 0; + utf = 0; + utf_count = 0; + + disp_ctrl = 0; + toggle_meta = 0; + + c8bit = 0; /* disable 8-bit controls */ + decckm = 0; /* cursor key sequences */ + decsclm = 0; /* jump scroll */ + decscnm = 0; /* normal screen */ + decom = 0; /* absolute adressing */ + decawm = 1; /* autowrap disabled */ + decarm = 1; /* autorepeat enabled */ + dectcem = 1; /* text cursor enabled */ + + kam = 0; /* keyboard enabled */ + crm = 0; /* execute control functions */ + irm = 0; /* replace */ + lnm = 0; /* line feed */ + + set_kbd_mode(&vc->kbd_table, VC_REPEAT); + clr_kbd_mode(&vc->kbd_table, VC_CKMODE); + clr_kbd_mode(&vc->kbd_table, VC_APPLIC); + clr_kbd_mode(&vc->kbd_table, VC_CRLF); + vc->kbd_table.lockstate = KBD_DEFLOCK; + vc->kbd_table.slockstate = 0; + vc->kbd_table.ledmode = LED_SHOW_FLAGS; + vc->kbd_table.ledflagstate = + vc->kbd_table.default_ledflagstate = KBD_DEFLEDS; + vc->kbd_table.modeflags = KBD_DEFMODE; + vc->kbd_table.kbdmode = VC_XLATE; + set_leds(); + + cursor_type = CUR_DEFAULT; + complement_mask = s_complement_mask; + + default_attr(vc); + update_attr(vc); + + tab_stop[0] = 0x01010100; + tab_stop[1] = + tab_stop[2] = + tab_stop[3] = + tab_stop[4] = 0x01010101; + + bell_pitch = DEFAULT_BELL_PITCH; + bell_duration = DEFAULT_BELL_DURATION; + + gotoxy(vc, 0, 0); + vte_decsc(vc); + if (do_clear) + vte_ed(vc, 2); +} + +/* + * TABULATION CLEAR (TBC) + * + * NOTE: + * In case of parameters 0 and 2 the number of lines affected depends on the + * setting of the Tabulation Stop Mode (TSM). Since we don't implement TSM, + * this is silently ignored. + * + * Parameters 1 and 4 are similiar to 0 and 3, but affect only line tabulation + * stops, which are not implemented. + * + * Parameter 2 may only be interpreted, when we implement a tabulation stop map + * per display line. + */ +static void vte_tbc(struct vc_data *vc, int vpar) +{ + switch (vpar) { + case 0: + /* + * The character tabulation stop at the active + * presentation position is cleared. + */ + tab_stop[x >> 5] &= ~(1 << (x & 31)); + return; + case 2: + /* + * All character tabulation stops in the active + * line are cleared. + */ + case 3: + /* + * All character tabulation stops are cleared. + */ + case 5: + /* + * All tabulation stops are cleared. + */ + tab_stop[0] = tab_stop[1] = tab_stop[2] = tab_stop[3] = + tab_stop[4] = 0; + } +} + +void terminal_emulation(struct tty_struct *tty, int c) +{ + /* + * C0 CONTROL CHARACTERS + * + * NOTE: Control characters can be used in the _middle_ + * of an escape sequence. (XXX: Really? Test!) + */ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + + switch (c) { + case 0x00: /* NUL - Null */ + case 0x01: /* SOH - Start of header */ + case 0x02: /* STX - */ + case 0x03: /* ETX - */ + case 0x04: /* EOT - End of transmission */ + return; + case 0x05: /* ENQ - Enquiry */ + vte_answerback(tty); + return; + case 0x06: /* ACK - Acknowledge */ + return; + case 0x07: /* BEL - Bell */ + if (bell_duration) + kd_mksound(bell_pitch, bell_duration); + return; + case 0x08: /* BS - Back space */ + vte_bs(vc); + return; + case 0x09: /* HT - Character tabulation */ + pos -= (x << 1); + while (x < video_num_columns - 1) { + x++; + if (tab_stop[x >> 5] & (1 << (x & 31))) + break; + } + pos += (x << 1); + return; + case 0x0a: /* LF - Line feed */ + case 0x0b: /* VT - Line tabulation */ + /* + * Since line tabulation is not implemented in the DEC VT + * series (except VT131 ?), the DEC VT series treats any + * VT as LF. + */ + case 0x0c: /* FF - Form feed */ + /* + * DEC VT series processes FF as LF. + */ + vte_lf(vc); + if (!get_kbd_mode(&vc->kbd_table, VC_CRLF)) + return; + case 0x0d: /* CR - Carriage return */ + vte_cr(vc); + return; + case 0x0e: /* SO - Shift out / LS1 - Locking shift 1 */ + charset = 1; + set_translate(vc, G1_charset); + disp_ctrl = 1; + return; + case 0x0f: /* SI - Shift in / LS0 - Locking shift 0 */ + charset = 0; + set_translate(vc, G0_charset); + disp_ctrl = 0; + return; + case 0x10: /* DLE - */ + case 0x11: /* DC1 - Device control 1 */ + case 0x12: /* DC2 - Device control 1 */ + case 0x13: /* DC3 - Device control 1 */ + case 0x14: /* DC4 - Device control 1 */ + case 0x15: /* NAK - Negative acknowledge */ + case 0x16: /* SYN - Synchronize */ + case 0x17: /* ETB - */ + return; + case 0x18: /* CAN - Cancel */ + vc_state = ESinit; + return; + case 0x19: /* EM - */ + return; + case 0x1a: /* SUB - Substitute */ + vc_state = ESinit; + return; + case 0x1b: /* ESC - Escape */ + vc_state = ESesc; + return; + case 0x1c: /* IS4 - */ + case 0x1d: /* IS3 - */ + case 0x1e: /* IS2 - */ + case 0x1f: /* IS1 - */ + return; + case 0x7f: /* DEL - Delete */ + /* + * This character is ignored, unless a 96-set has been mapped, + * but this is not supported at the moment. + */ + return; + } + + if (c8bit == 1) + /* + * C1 control functions (8-bit mode). + */ + switch (c) { + case 0x80: /* unused */ + case 0x81: /* unused */ + case 0x82: /* BPH - Break permitted here */ + case 0x83: /* NBH - No break here */ + return; + case 0x84: /* IND - Line feed (DEC only) */ +#ifndef VTE_STRICT_ISO + vte_lf(vc); +#endif /* ndef VTE_STRICT_ISO */ + return; + case 0x85: /* NEL - Next line */ + vte_lf(vc); + vte_cr(vc); + return; + case 0x86: /* SSA - Start of selected area */ + case 0x87: /* ESA - End of selected area */ + return; + case 0x88: /* HTS - Character tabulation set */ + tab_stop[x >> 5] |= (1 << (x & 31)); + return; + case 0x89: /* HTJ - Character tabulation with justify */ + case 0x8a: /* VTS - Line tabulation set */ + case 0x8b: /* PLD - Partial line down */ + case 0x8c: /* PLU - Partial line up */ + return; + case 0x8d: /* RI - Reverse line feed */ + vte_ri(vc); + return; +#if 0 + case 0x8e: /* SS2 - Single shift 2 */ + need_shift = 1; + GS_charset = G2_charset; /* G2 -> GS */ + return; + case 0x8f: /* SS3 - Single shift 3 */ + need_shift = 1; + GS_charset = G3_charset; /* G3 -> GS */ + return; +#endif + case 0x90: /* DCS - Device control string */ + return; + case 0x91: /* PU1 - Private use 1 */ + case 0x92: /* PU2 - Private use 2 */ + case 0x93: /* STS - Set transmit state*/ + case 0x94: /* CCH - Cancel character */ + case 0x95: /* MW - Message waiting */ + case 0x96: /* SPA - Start of guarded area */ + case 0x97: /* EPA - End of guarded area */ + case 0x98: /* SOS - Start of string */ + case 0x99: /* unused */ + return; + case 0x9a: /* SCI - Single character introducer */ +#ifndef VTE_STRICT_ISO + vte_da(tty); +#endif /* ndef VTE_STRICT_ISO */ + return; + case 0x9b: /* CSI - Control sequence introducer */ + vc_state = EScsi; + return; + case 0x9c: /* ST - String Terminator */ + case 0x9d: /* OSC - Operating system command */ + case 0x9e: /* PM - Privacy message */ + case 0x9f: /* APC - Application program command */ + return; + } + + switch(vc_state) { + case ESesc: + vc_state = ESinit; + switch (c) { + + case ' ': /* ACS - Announce code structure */ + vc_state = ESacs; + return; + case '#': /* SCF - Single control functions */ + vc_state = ESscf; + return; + case '%': /* DOCS - Designate other coding system */ + vc_state = ESdocs; + return; +#ifdef CONFIG_VT_HP + case '&': /* HP terminal emulation */ + vc_state = ESesc_and; + return; +#endif /* def CONFIG_VT_HP */ + case '(': /* GZD4 - G0-designate 94-set */ + vc_state = ESgzd4; + return; + case ')': /* G1D4 - G1-designate 94-set */ + vc_state = ESg1d4; + return; +#if 0 + case '*': /* G2D4 - G2-designate 94-set */ + vc_state = ESg2d4; + return; + case '+': /* G3D4 - G3-designate 94-set */ + vc_state = ESg3d4; + return; + case '-': /* G1D6 - G1-designate 96-set */ + vc_state = ESg1d6; + return; + case '.': /* G2D6 - G2-designate 96-set */ + vc_state = ESg2d6; + return; + case '/': /* G3D6 - G3-designate 96-set */ + vc_state = ESg3d6; + return; +#endif + /* ===== Private control functions ===== */ + + case '6': /* DECBI - Back index */ + return; + case '7': /* DECSC - Save cursor */ + vte_decsc(vc); + return; + case '8': /* DECRC - Restore cursor */ + vte_decrc(vc); + return; + case '9': /* DECFI - Forward index */ + return; + case '=': /* DECKPAM - Keypad application mode */ + decnkm = 1; + set_kbd_mode(&vc->kbd_table, VC_APPLIC); + return; + case '>': /* DECKPNM - Keypad numeric mode */ + decnkm = 0; + clr_kbd_mode(&vc->kbd_table, VC_APPLIC); + return; + + /* ===== C1 control functions ===== */ + case '@': /* unallocated */ + case 'A': /* unallocated */ + case 'B': /* BPH - Break permitted here */ + case 'C': /* NBH - No break here */ + case 'D': /* IND - Line feed (DEC only) */ +#ifndef VTE_STRICT_ISO + vte_lf(vc); +#endif /* ndef VTE_STRICT_ISO */ + return; + case 'E': /* NEL - Next line */ + vte_cr(vc); + vte_lf(vc); + return; + case 'F': /* SSA - Start of selected area */ + case 'G': /* ESA - End of selected area */ + return; + case 'H': /* HTS - Character tabulation set */ + tab_stop[x >> 5] |= (1 << (x & 31)); + return; + case 'I': /* HTJ - Character tabulation with justify */ + case 'J': /* VTS - Line tabulation set */ + case 'K': /* PLD - Partial line down */ + case 'L': /* PLU - Partial line up */ + return; + case 'M': /* RI - Reverse line feed */ + vte_ri(vc); + return; + case 'N': /* SS2 - Single shift 2 */ + shift = 1; + GS_charset = G2_charset; /* G2 -> GS */ + return; + case 'O': /* SS3 - Single shift 3 */ + shift = 1; + GS_charset = G3_charset; + return; + case 'P': /* DCS - Device control string */ + return; + case 'Q': /* PU1 - Private use 1 */ + case 'R': /* PU2 - Private use 2 */ + case 'S': /* STS - Set transmit state */ + case 'T': /* CCH - Cancel character */ + case 'U': /* MW - Message waiting */ + case 'V': /* SPA - Start of guarded area */ + case 'W': /* EPA - End of guarded area */ + case 'X': /* SOS - Start of string */ + case 'Y': /* unallocated */ + return; + case 'Z': /* SCI - Single character introducer */ +#ifndef VTE_STRICT_ISO + vte_da(tty); +#endif /* ndef VTE_STRICT_ISO */ + return; + case '[': /* CSI - Control sequence introducer */ + vc_state = EScsi; + return; + case '\\': /* ST - String Terminator */ + return; + case ']': /* OSC - Operating system command */ + /* XXX: Fixme! Wrong sequence and format! */ + vc_state = ESosc; + return; + case '^': /* PM - Privacy Message */ + case '_': /* APC - Application Program Command */ + return; + + /* ===== Single control functions ===== */ + case '`': /* DMI - Disable manual input */ + kam = 0; + return; + case 'b': /* EMI - Enable manual input */ + kam = 1; + return; + case 'c': /* RIS - Reset ti initial state */ + vte_ris(vc, 1); + return; + case 'd': /* CMD - Coding Method Delimiter */ + return; +#if 0 + case 'n': /* LS2 - Locking shift G2 */ + GL_charset = G2_charset; /* (G2 -> GL) */ + return; + case 'o': /* LS3 - Locking shift G3 */ + GL_charset = G3_charset; /* (G3 -> GL) */ + return; + case '|': /* LS3R - Locking shift G3 right */ + GR_charset = G3_charset; /* G3 -> GR */ + return; + case '}': /* LS2R - Locking shift G2 right */ + GR_charset = G2_charset; /* G2 -> GR */ + return; + case '~': /* LS1R - Locking shift G1 right */ + GR_charset = G1_charset; /* G1 -> GR */ + return; +#endif + } + return; + case ESacs: + vc_state = ESinit; + switch (c) { + case 'F': /* Select 7-bit C1 control transmission */ + if (decscl != 1) /* Ignore if in VT100 mode */ + c8bit = 0; + return; + case 'G': /* Select 8-Bit C1 control transmission */ + if (decscl != 1) /* Ignore if in VT100 mode */ + c8bit = 1; + return; + case 'L': /* ANSI conformance level 1 */ + case 'M': /* ANSI conformance level 2 */ + case 'N': /* ANSI conformance level 3 */ + /* Not yet implemented. */ + return; + } + return; + case ESosc: + vc_state = ESinit; + switch (c) { + case 'P': /* palette escape sequence */ + for (npar = 0; npar < NPAR; npar++) + par[npar] = 0; + npar = 0; + vc_state = ESpalette; + return; + case 'R': /* reset palette */ + reset_palette(vc); + vc_state = ESinit; + return; + } + return; + case ESpalette: + if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) +{ + par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; + if (npar==7) { + int i = par[0]*3, j = 1; + palette[i] = 16*par[j++]; + palette[i++] += par[j++]; + palette[i] = 16*par[j++]; + palette[i++] += par[j++]; + palette[i] = 16*par[j++]; + palette[i] += par[j]; + set_palette(vc); + vc_state = ESinit; + } + } else + vc_state = ESinit; + return; + case EScsi: + for(npar = 0 ; npar < NPAR ; npar++) + par[npar] = 0; + npar = 0; + vc_state = EScsi_getpars; + if (c == '[') { + /* Function key */ + vc_state = ESfunckey; + return; + } + priv1 = (c == '<'); + priv2 = (c == '='); + priv3 = (c == '>'); + priv4 = (c == '?'); + if (priv1) { + vc_state = ESinit; + return; + } + if (priv2 || priv3 || priv4) { + return; + } + case EScsi_getpars: + if (c==';' && npar='0' && c<='9') { + par[npar] *= 10; + par[npar] += c-'0'; + return; + } else vc_state=EScsi_gotpars; + case EScsi_gotpars: + vc_state = ESinit; + /* + * Process control functions with private parameter flag. + */ + switch(c) { + case '$': + if (priv4) { + vc_state = EScsi_dollar; + return; + } + break; + case 'J': + if (priv4) { + /* DECSED - Selective erase in display */ + return; + } + break; + case 'K': + if (priv4) { + /* DECSEL - Selective erase in display */ + return; + } + break; + case 'h': /* SM - Set Mode */ + set_mode(vc, 1); + return; + case 'l': /* RM - Reset Mode */ + set_mode(vc, 0); + return; + case 'c': + if (priv2) { + if (!par[0]) + vte_dec_da3(tty); + priv2 = 0; + return; + } + if (priv3) { + if (!par[0]) + vte_dec_da2(tty); + priv3 = 0; + return; + } + if (priv4) { + if (par[0]) + cursor_type = par[0] | (par[1]<<8) | (par[2]<<16); + else + cursor_type = CUR_DEFAULT; + priv4 = 0; + return; + } + break; + case 'm': + if (priv4) { + clear_selection(); + if (par[0]) + complement_mask = par[0]<<8 | par[1]; + else + complement_mask = s_complement_mask; + priv4 = 0; + return; + } + break; + case 'n': + if (priv4) { + switch (par[0]) { + case 6: /* DECXCPR - Extended CPR */ + vte_cpr(tty, 1); + break; + case 15: /* DEC printer status */ + vte_fake_dec_dsr(tty, "13"); + break; + case 25: /* DEC UDK status */ + vte_fake_dec_dsr(tty, "21"); + break; + case 26: /* DEC keyboard status */ + vte_fake_dec_dsr(tty, "27;1;0;1"); + break; + case 53: /* DEC locator status */ + vte_fake_dec_dsr(tty, "53"); + break; + case 62: /* DEC macro space */ + vte_decmsr(tty); + break; + case 75: /* DEC data integrity */ + vte_fake_dec_dsr(tty, "70"); + break; + case 85: /* DEC multiple session status */ vte_fake_dec_dsr(tty, "83"); + break; + } + } else + switch (par[0]) { + case 5: /* DSR - Device status report */ + vte_dsr(tty); + break; + case 6: /* CPR - Cursor position report */ + vte_cpr(tty, 0); + break; + } + priv4 = 0; + return; + } + if (priv1 || priv2 || priv3 || priv4) { + priv1 = + priv2 = + priv3 = + priv4 = 0; + return; + } + /* + * Process control functions with standard parameter strings. + */ + switch(c) { + + /* ===== Control functions w/ intermediate byte ===== */ + case ' ': /* Intermediate byte: SP (ISO 6429) */ + vc_state = EScsi_space; + return; + case '!': /* Intermediate byte: ! (DEC VT series) */ + vc_state = EScsi_exclam; + return; + case '"': /* Intermediate byte: " (DEC VT series) */ + vc_state = EScsi_dquote; + return; + case '$': /* Intermediate byte: $ (DEC VT series) */ + vc_state = EScsi_dollar; + return; + case '&': /* Intermediate byte: & (DEC VT series) */ + vc_state = EScsi_and; + return; + case '*': /* Intermediate byte: * (DEC VT series) */ + vc_state = EScsi_star; + return; + case '+': /* Intermediate byte: + (DEC VT series) */ + vc_state = EScsi_plus; + return; + /* ==== Control functions w/o intermediate byte ==== */ + case '@': /* ICH - Insert character */ + vte_ich(vc, par[0]); + return; + case 'A': /* CUU - Cursor up */ + case 'k': /* VPB - Line position backward */ + if (!par[0]) par[0]++; + gotoxy(vc, x, y-par[0]); + return; + case 'B': /* CUD - Cursor down */ + case 'e': /* VPR - Line position forward */ + if (!par[0]) par[0]++; + gotoxy(vc, x, y+par[0]); + return; + case 'C': /* CUF - Cursor right */ + case 'a': /* HPR - Character position forward */ + if (!par[0]) par[0]++; + gotoxy(vc, x+par[0], y); + return; + case 'D': /* CUB - Cursor left */ + case 'j': /* HPB - Character position backward */ + if (!par[0]) par[0]++; + gotoxy(vc, x-par[0], y); + return; + case 'E': /* CNL - Cursor next line */ + if (!par[0]) par[0]++; + gotoxy(vc, 0, y+par[0]); + return; + case 'F': /* CPL - Cursor preceeding line */ + if (!par[0]) par[0]++; + gotoxy(vc, 0, y-par[0]); + return; + case 'G': /* CHA - Cursor character absolute */ + case '`': /* HPA - Character position absolute */ + if (par[0]) par[0]--; + gotoxy(vc, par[0], y); + return; + case 'H': /* CUP - Cursor position */ + case 'f': /* HVP - Horizontal and vertical position */ + if (par[0]) par[0]--; + if (par[1]) par[1]--; + gotoxay(vc, par[1], par[0]); + return; + case 'I': /* CHT - Cursor forward tabulation */ + if (!par[0]) + par[0]++; + vte_cht(vc, par[0]); + return; + case 'J': /* ED - Erase in page */ + vte_ed(vc, par[0]); + return; + case 'K': /* EL - Erase in line */ + vte_el(vc, par[0]); + return; + case 'L': /* IL - Insert line */ + vte_il(vc, par[0]); + return; + case 'M': /* DL - Delete line */ + vte_dl(vc, par[0]); + return; + case 'P': /* DCH - Delete character */ + vte_dch(vc, par[0]); + return; + case 'U': /* NP - Next page */ + case 'V': /* PP - Preceeding page */ + return; + case 'W': /* CTC - Cursor tabulation control */ + switch (par[0]) { + case 0: /* Set character tab stop at current position */ tab_stop[x >> 5] |= (1 << (x & 31)); + return; + case 2: /* Clear character tab stop at curr. position */ vte_tbc(vc, 0); + return; + case 5: /* All character tab stops are cleared. */ + vte_tbc(vc, 5); + return; + } + return; + case 'X': /* ECH - Erase character */ + vte_ech(vc, par[0]); + return; + case 'Y': /* CVT - Cursor line tabulation */ + if (!par[0]) + par[0]++; + vte_cvt(vc, par[0]); + return; + case 'Z': /* CBT - Cursor backward tabulation */ + vte_cbt(vc, par[0]); + return; + case ']': +#ifndef VT_STRICT_ISO + setterm_command(vc); +#endif /* def VT_STRICT_ISO */ + return; + case 'c': /* DA - Device attribute */ + if (!par[0]) + vte_da(tty); + return; + case 'd': /* VPA - Line position absolute */ + if (par[0]) par[0]--; + gotoxay(vc, x, par[0]); + return; + case 'g': /* TBC - Tabulation clear */ + vte_tbc(vc, par[0]); + return; + case 'm': /* SGR - Select graphics rendition */ + vte_sgr(vc); + return; + + /* ===== Private control sequences ===== */ + + case 'q': /* DECLL - but only 3 leds */ + switch (par[0]) { + case 0: /* all LEDs off */ + case 1: /* LED 1 on */ + case 2: /* LED 2 on */ + case 3: /* LED 3 on */ + setledstate(&vc->kbd_table, + (par[0] < 3) ? par[0] : 4); + case 4: /* LED 4 on */ + ; + } + return; + case 'r': /* DECSTBM - Set top and bottom margin */ + if (!par[0]) + par[0]++; + if (!par[1]) + par[1] = video_num_lines; + /* Minimum allowed region is 2 lines */ + if (par[0] < par[1] && + par[1] <= video_num_lines) { + top=par[0]-1; + bottom=par[1]; + gotoxay(vc, 0, 0); + } + return; + case 's': /* DECSLRM - Set left and right margin */ + return; + case 't': /* DECSLPP - Set lines per page */ + return; + case 'x': /* DECREQTPARM - Request terminal parameters */ + vte_decreptparm(tty); + return; + case 'y': + if (par[0] == 4) { + /* DECTST - Invoke confidence test */ + return; + } + } + return; + case EScsi_space: + vc_state = ESinit; + switch (c) { + /* + * Note: All codes betweem 0x40 and 0x6f are subject to + * standardisation by the ISO. The codes netweem 0x70 + * and 0x7f are free for private use. + */ + case '@': /* SL - Scroll left */ + case 'A': /* SR - Scroll right */ + return; + case 'P': /* PPA - Page position absolute */ + case 'Q': /* PPR - Page position forward */ + case 'R': /* PPB - Page position backward */ + return; + } + return; + case EScsi_exclam: + vc_state = ESinit; + switch (c) { + case 'p': /* DECSTR - Soft terminal reset */ + /* + * Note: On a true DEC VT there are differences + * between RIS and DECSTR. Right now we ignore + * this... -dbk + */ + vte_ris(vc, 1); + return; + } + return; + case EScsi_dquote: + vc_state = ESinit; + switch (c) { + case 'p': /* DECSCL - Set operating level */ + vte_decscl(vc); + return; + case 'q': /* DECSCA - Select character protection +attribute */ + return; + case 'v': /* DECRQDE - Request window report */ + ; + } + return; + case EScsi_dollar: + vc_state = ESinit; + switch (c) { + case 'p': /* DECRQM - Request mode */ + vte_decrqm(tty, priv4); + return; + case 'r': /* DECCARA - Change attributes in rectangular area */ + return; + case 't': /* DECRARA - Reverse attributes in rectangular area */ + return; + case 'u': /* DECRQTSR - Request terminal state */ + if (par[0] == 1) + vte_dectsr(tty); + return; + case 'v': /* DECCRA - Copy rectangular area */ + return; + case 'w': /* DECRQPSR - Request presentation status */ + switch (par[0]) { + case 1: + vte_deccir(tty); + break; + case 2: + vte_dectabsr(tty); + break; + } + return; + case 'x': /* DECFRA - Fill rectangular area */ + return; + case 'z': /* DECERA - Erase rectangular area */ + return; + case '{': /* DECSERA - Selective erase rectangular area */ + return; + case '|': /* DECSCPP - Set columns per page */ + return; + case '}': /* DECSASD - Select active status display */ + return; + case '~': /* DECSSDT - Select status display type +*/ + return; + } + return; + case EScsi_and: + vc_state = ESinit; + switch (c) { + case 'u': /* DECRQUPSS - Request user-preferred supplemental set */ + return; + case 'x': /* Enable Session Command */ + return; + } + return; + case EScsi_squote: + vc_state = ESinit; + switch (c) { + case '}': /* DECIC - Insert column */ + return; + case '~': /* DECDC - Delete column */ + return; + } + case EScsi_star: + vc_state = ESinit; + switch (c) { + case 'x': /* DECSACE - Select attribute change extent */ + return; + case 'y': /* DECRQCRA - Request checksum on rectangular area */ + return; + case 'z': /* DECINVM - Invoke macro */ + return; + case '|': /* DECSNLS - Select number of lines */ + return; + case '}': /* DECLFKC - Local function key control +*/ + return; + } + return; + case EScsi_plus: + vc_state = ESinit; + switch (c) { + case 'p': /* DECSR - Secure reset */ + return; + } + return; + case ESdocs: + vc_state = ESinit; + switch (c) { + case '@': /* defined in ISO 2022 */ + utf = 0; + return; + case 'G': /* prelim official escape code */ + case '8': /* retained for compatibility */ + utf = 1; + return; + } + return; +#ifdef CONFIG_VT_HP + case ESesc_and: + vc_state = ESinit; + switch (c) { + case 'f': /* Set function key label */ + return; + case 'j': /* Display function key labels */ + return; + } + return; +#endif + case ESfunckey: + vc_state = ESinit; + return; + case ESscf: + vc_state = ESinit; + if (c == '8') { + /* DEC screen alignment test. kludge :-) */ + video_erase_char = + (video_erase_char & 0xff00) | 'E'; + vte_ed(vc, 2); + video_erase_char = + (video_erase_char & 0xff00) | ' '; + do_update_region(vc, origin, screenbuf_size/2); + } + return; + case ESgzd4: + switch (c) { + case '0': /* DEC Special graphics */ + G0_charset = GRAF_MAP; + break; +#if 0 + case '>': /* DEC Technical */ + G0_charset = DEC_TECH_MAP; + break; +#endif + case 'A': /* ISO Latin-1 supplemental */ + G0_charset = LAT1_MAP; + break; + case 'B': /* ASCII */ + G0_charset = LAT1_MAP; + break; + case 'U': + G0_charset = IBMPC_MAP; + break; + case 'K': + G0_charset = USER_MAP; + break; + } + if (charset == 0) + set_translate(vc, G0_charset); + vc_state = ESinit; + return; + case ESg1d4: + switch (c) { + case '0': /* DEC Special graphics */ + G1_charset = GRAF_MAP; + break; +#if 0 + case '>': /* DEC Technical */ + G1_charset = DEC_TECH_MAP; + break; +#endif + case 'A': /* ISO Latin-1 supplemental */ + G1_charset = LAT1_MAP; + break; + case 'B': /* ASCII */ + G1_charset = LAT1_MAP; + break; + case 'U': + G1_charset = IBMPC_MAP; + break; + case 'K': + G1_charset = USER_MAP; + break; + } + if (charset == 1) + set_translate(vc, G1_charset); + vc_state = ESinit; + return; + case ESg2d4: + switch (c) { + case '0': /* DEC Special graphics */ + G2_charset = GRAF_MAP; + break; +#if 0 + case '>': /* DEC Technical */ + G2_charset = DEC_TECH_MAP; + break; +#endif + case 'A': /* ISO Latin-1 supplemental */ + G2_charset = LAT1_MAP; + break; + case 'B': /* ASCII */ + G2_charset = LAT1_MAP; + break; + case 'U': + G2_charset = IBMPC_MAP; + break; + case 'K': + G2_charset = USER_MAP; + break; + } + if (charset == 1) + set_translate(vc, G2_charset); + vc_state = ESinit; + return; + case ESg3d4: + switch (c) { + case '0': /* DEC Special graphics */ + G3_charset = GRAF_MAP; + break; +#if 0 + case '>': /* DEC Technical */ + G3_charset = DEC_TECH_MAP; + break; +#endif + case 'A': /* ISO Latin-1 supplemental */ + G3_charset = LAT1_MAP; + break; + case 'B': /* ASCII */ + G3_charset = LAT1_MAP; + break; + case 'U': + G3_charset = IBMPC_MAP; + break; + case 'K': + G3_charset = USER_MAP; + break; + } + if (charset == 1) + set_translate(vc, G3_charset); + vc_state = ESinit; + return; + default: + vc_state = ESinit; + } +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/drm/Config.help linux-2.5/drivers/char/drm/Config.help --- linux-2.5.20/drivers/char/drm/Config.help Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/char/drm/Config.help Mon Feb 25 18:58:39 2002 @@ -37,3 +37,7 @@ card. If M is selected, the module will be called mga.o. AGP support is required for this driver to work. +CONFIG_DRM_SIS + Choose this option if you have a SIS graphics card. AGP support is + required for this driver to work. + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/drm/Config.in linux-2.5/drivers/char/drm/Config.in --- linux-2.5.20/drivers/char/drm/Config.in Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/char/drm/Config.in Sat May 25 19:52:00 2002 @@ -12,6 +12,7 @@ tristate ' ATI Rage 128' CONFIG_DRM_R128 dep_tristate ' ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP dep_tristate ' Intel I810' CONFIG_DRM_I810 $CONFIG_AGP - dep_tristate ' Intel 830M' CONFIG_DRM_I830 $CONFIG_AGP + dep_tristate ' Intel 830M' CONFIG_DRM_I830 $CONFIG_AGP dep_tristate ' Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP + dep_tristate ' SiS' CONFIG_DRM_SIS $CONFIG_AGP fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/dummy_keyb.c linux-2.5/drivers/char/dummy_keyb.c --- linux-2.5.20/drivers/char/dummy_keyb.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/dummy_keyb.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,60 @@ +/* + * linux/drivers/char/dummy_keyb.c + * + * Allows CONFIG_VT on hardware without keyboards. + * + * Copyright (C) 1999, 2001 Bradley D. LaRonde + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * What is this for? + * + * Not all systems have keyboards. Some don't even have a keyboard + * port. However, some of those systems have video support and can + * use the virtual terminal support for display. However, the virtual + * terminal code expects a keyboard of some kind. This driver keeps + * the virtual terminal code happy by providing it a "keyboard", albeit + * a very quiet one. + * + * If you want to use the virtual terminal support but your system + * does not support a keyboard, define CONFIG_DUMMY_KEYB along with + * CONFIG_VT. + * + */ +#include +#include +#include + +void kbd_leds(unsigned char leds) +{ +} + +int kbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + return (scancode == keycode) ? 0 : -EINVAL; +} + +int kbd_getkeycode(unsigned int scancode) +{ + return scancode; +} + +int kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + *keycode = scancode; + + return 1; +} + +char kbd_unexpected_up(unsigned char keycode) +{ + return 0x80; +} + +void __init kbd_init_hw(void) +{ + printk("Dummy keyboard driver installed.\n"); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/dz.h linux-2.5/drivers/char/dz.h --- linux-2.5.20/drivers/char/dz.h Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/char/dz.h Sun Mar 3 17:54:35 2002 @@ -10,6 +10,8 @@ #ifndef DZ_SERIAL_H #define DZ_SERIAL_H +#define SERIAL_MAGIC 0x5301 + /* * Definitions for the Control and Status Received. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/ftape/lowlevel/fdc-io.c linux-2.5/drivers/char/ftape/lowlevel/fdc-io.c --- linux-2.5.20/drivers/char/ftape/lowlevel/fdc-io.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/char/ftape/lowlevel/fdc-io.c Mon Apr 15 01:34:05 2002 @@ -926,7 +926,7 @@ disable_dma(fdc.dma); clear_dma_ff(fdc.dma); set_dma_mode(fdc.dma, mode); - set_dma_addr(fdc.dma, virt_to_bus((void*)addr)); + set_dma_addr(fdc.dma, isa_virt_to_bus((void*)addr)); set_dma_count(fdc.dma, count); enable_dma(fdc.dma); } @@ -945,7 +945,7 @@ /* Program the DMA controller. */ TRACE(ft_t_fdc_dma, - "phys. addr. = %lx", virt_to_bus((void*) buff->ptr)); + "phys. addr. = %lx", isa_virt_to_bus((void*) buff->ptr)); save_flags(flags); cli(); /* could be called from ISR ! */ fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4); @@ -997,7 +997,7 @@ TRACE_ABORT(-EIO, ft_t_bug, "bug: illegal operation parameter"); } - TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr)); + TRACE(ft_t_fdc_dma, "phys. addr. = %lx", isa_virt_to_bus((void*)buff->ptr)); save_flags(flags); cli(); /* could be called from ISR ! */ if (operation != FDC_VERIFY) { @@ -1209,27 +1209,35 @@ TRACE_FUN(ft_t_flow); if (ft_mach2 || ft_probe_fc10) { - if (check_region(fdc.sra, 8) < 0) { + if (!request_region(fdc.sra, 8, "fdc (ft)")) + { #ifndef BROKEN_FLOPPY_DRIVER TRACE_EXIT -EBUSY; #else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); + TRACE(ft_t_warn, "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); #endif - } - request_region(fdc.sra, 8, "fdc (ft)"); - } else { - if (check_region(fdc.sra, 6) < 0 || - check_region(fdc.dir, 1) < 0) { + } + + if (!request_region(fdc.sra, 6, "fdc (ft)")) + { + release_region(fdc.sra, 8); #ifndef BROKEN_FLOPPY_DRIVER TRACE_EXIT -EBUSY; #else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); + TRACE(ft_t_warn, "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); #endif - } - request_region(fdc.sra, 6, "fdc (ft)"); - request_region(fdc.sra + 7, 1, "fdc (ft)"); + } + + if (!request_region(fdc.sra+7, 1, "fdc (ft)")) + { + release_region(fdc.sra, 8); + release_region(fdc.sra, 6); +#ifndef BROKEN_FLOPPY_DRIVER + TRACE_EXIT -EBUSY; +#else + TRACE(ft_t_warn, "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); +#endif + } } TRACE_EXIT 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/ftape/zftape/zftape-init.c linux-2.5/drivers/char/ftape/zftape/zftape-init.c --- linux-2.5.20/drivers/char/ftape/zftape/zftape-init.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/char/ftape/zftape/zftape-init.c Fri May 10 16:35:15 2002 @@ -28,6 +28,7 @@ #include #include #include +#include #include #ifdef CONFIG_KMOD #include @@ -67,7 +68,7 @@ /* Local vars. */ -static int busy_flag; +static unsigned long busy_flag; static sigset_t orig_sigmask; @@ -203,6 +204,7 @@ static struct vm_operations_struct dummy = { NULL, }; vma->vm_ops = &dummy; #endif + vma->vm_flags &= ~VM_IO; } current->blocked = old_sigmask; /* restore mask */ TRACE_EXIT result; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/generic_serial.c linux-2.5/drivers/char/generic_serial.c --- linux-2.5.20/drivers/char/generic_serial.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/char/generic_serial.c Wed Jan 30 17:03:50 2002 @@ -219,8 +219,13 @@ while (1) { c = count; - /* This is safe because we "OWN" the "head". Noone else can - change the "head": we own the port_write_sem. */ + /* Note: This part can be done without + * interrupt routine protection since + * the interrupt routines may only modify + * shared variables in safe ways, in the worst + * case causing us to loop twice in the code + * below. See comments below. */ + /* Don't overrun the end of the buffer */ t = SERIAL_XMIT_SIZE - port->xmit_head; if (t < c) c = t; @@ -511,7 +516,7 @@ void gs_shutdown_port (struct gs_port *port) { - long flags; + unsigned long flags; func_enter(); @@ -594,6 +599,7 @@ int do_clocal = 0; int CD; struct tty_struct *tty; + unsigned long flags; func_enter (); @@ -673,10 +679,11 @@ add_wait_queue(&port->open_wait, &wait); gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); + save_flags(flags); cli(); if (!tty_hung_up_p(filp)) port->count--; - sti(); + restore_flags(flags); port->blocked_open++; while (1) { CD = port->rd->get_CD (port); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/hcdp_serial.c linux-2.5/drivers/char/hcdp_serial.c --- linux-2.5.20/drivers/char/hcdp_serial.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/hcdp_serial.c Fri May 3 03:49:06 2002 @@ -0,0 +1,221 @@ +/* + * linux/arch/ia64/kernel/hcdp_serial.c + * + * Copyright (C) 2002 Hewlett-Packard Co. + * Copyright (C) 2002 Khalid Aziz + * + * Parse the EFI HCDP table to locate serial console and debug ports + * and initialize them + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef SERIAL_DEBUG_HCDP + +extern struct serial_state rs_table[]; +extern int serial_nr_ports; + +/* + * Parse the HCDP table to find descriptions for headless console and + * debug serial ports and add them to rs_table[]. A pointer to HCDP + * table is passed as parameter. This function should be called + * before serial_console_init() is called to make sure the HCDP serial + * console will be available for use. IA-64 kernel calls this function + * from setup_arch() after the EFI and ACPI tables have been parsed. + */ +void __init setup_serial_hcdp(void *tablep) +{ + hcdp_t hcdp; + hcdp_dev_t *hcdp_dev; + struct serial_struct serial_req; + unsigned long iobase; + int global_sys_irq; + int i, nr; + int shift_once = 1; + +#ifdef SERIAL_DEBUG_HCDP + printk("Entering setup_serial_hcdp()\n"); +#endif + + /* Verify we have a valid table pointer */ + if (tablep == NULL) { + return; + } + + /* + * We do not trust firmware to give us a table starting at an + * aligned address. Make a local copy of the HCDP table with + * aligned structures. + */ + memcpy(&hcdp, tablep, sizeof(hcdp)); + + /* + * Perform a sanity check on the table. Table should have a + * signature of "HCDP" and it should be atleast 82 bytes + * long to have any useful information. + */ + if ((strncmp(hcdp.signature, HCDP_SIGNATURE, + HCDP_SIG_LEN) != 0)) { + return; + } + if (hcdp.len < 82) { + return; + } + +#ifdef SERIAL_DEBUG_HCDP + printk("setup_serial_hcdp(): table pointer = 0x%p\n", tablep); + printk(" sig = '%c%c%c%c'\n", + hcdp.signature[0], + hcdp.signature[1], + hcdp.signature[2], + hcdp.signature[3]); + printk(" length = %d\n", hcdp.len); + printk(" Rev = %d\n", hcdp.rev); + printk(" OEM ID = %c%c%c%c%c%c\n", + hcdp.oemid[0], hcdp.oemid[1], hcdp.oemid[2], + hcdp.oemid[3], hcdp.oemid[4], hcdp.oemid[5]); + printk(" Number of entries = %d\n", hcdp.num_entries); +#endif + + /* + * Parse each device entry + */ + for (nr=0; nrtype != HCDP_DEV_CONSOLE) + continue; + + iobase = (u64)(hcdp_dev->base_addr.addrhi)<<32 | hcdp_dev->base_addr.addrlo; + global_sys_irq = hcdp_dev->global_int; +#ifdef SERIAL_DEBUG_HCDP + printk(" type = %s\n", + ((hcdp_dev->type == HCDP_DEV_CONSOLE)?"Headless Console":((hcdp_dev->type == HCDP_DEV_DEBUG)?"Debug port":"Huh????"))); + printk(" Base address space = %s\n", ((hcdp_dev->base_addr.space_id == ACPI_MEM_SPACE)?"Memory Space":((hcdp_dev->base_addr.space_id == ACPI_IO_SPACE)?"I/O space":"PCI space"))); + printk(" Base address = 0x%p\n", iobase); + printk(" Global System Int = %d\n", global_sys_irq); + printk(" Baud rate = %d\n", hcdp_dev->baud); + printk(" Bits = %d\n", hcdp_dev->bits); + printk(" Clock rate = %d\n", hcdp_dev->clock_rate); + if (hcdp_dev->base_addr.space_id == ACPI_PCICONF_SPACE) { + printk(" PCI serial port:\n"); + printk(" Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n", + hcdp_dev->pci_bus, hcdp_dev->pci_dev, + hcdp_dev->pci_vendor_id, hcdp_dev->pci_dev_id); + } +#endif + + + /* + * Now build a serial_req structure to update the entry in + * rs_table for the headless console port. + */ + if (hcdp_dev->clock_rate) + serial_req.baud_base = hcdp_dev->clock_rate; + else + serial_req.baud_base = DEFAULT_BAUD_BASE; + /* + * Check if this is an I/O mapped address or a memory mapped address + */ + if (hcdp_dev->base_addr.space_id == ACPI_MEM_SPACE) { + serial_req.port = 0; + serial_req.port_high = 0; + serial_req.iomem_base = (void *)ioremap(iobase, 64); + serial_req.io_type = SERIAL_IO_MEM; + } + else if (hcdp_dev->base_addr.space_id == ACPI_IO_SPACE) { + serial_req.port = (unsigned long) iobase & 0xffffffff; + serial_req.port_high = (unsigned long)(((u64)iobase) >> 32); + serial_req.iomem_base = NULL; + serial_req.io_type = SERIAL_IO_PORT; + } + else if (hcdp_dev->base_addr.space_id == ACPI_PCICONF_SPACE) { + printk("WARNING: No support for PCI serial console\n"); + return; + } + + /* + * Check if HCDP defines a port already in rs_table + */ + for (i = 0; i < serial_nr_ports; i++) { + if ((rs_table[i].port == serial_req.port) && + (rs_table[i].iomem_base==serial_req.iomem_base)) + break; + } + if (i == serial_nr_ports) { + /* + * We have reserved a slot for HCDP defined console + * port at HCDP_SERIAL_CONSOLE_PORT in rs_table + * which is not 0. This means using this slot would + * put the console at a device other than ttyS0. + * Users expect to see the console at ttyS0. Now + * that we have determined HCDP does describe a + * serial console and it is not one of the compiled + * in ports, let us move the entries in rs_table + * up by a slot towards HCDP_SERIAL_CONSOLE_PORT to + * make room for the HCDP console at ttyS0. We may go + * through this loop more than once if + * early_serial_setup() fails. Make sure we shift the + * entries in rs_table only once. + */ + if (shift_once) { + int j; + + for (j=HCDP_SERIAL_CONSOLE_PORT; j>0; j--) + memcpy(rs_table+j, rs_table+j-1, + sizeof(struct serial_state)); + shift_once = 0; + } + serial_req.line = 0; + } + else + serial_req.line = i; + + /* + * If the table does not have IRQ information, use 0 for IRQ. + * This will force rs_init() to probe for IRQ. + */ + serial_req.irq = global_sys_irq; + if (global_sys_irq == 0) { + serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF; + } + else { + serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF| + ASYNC_AUTO_IRQ; + } + + serial_req.xmit_fifo_size = serial_req.custom_divisor = 0; + serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0; + serial_req.iomem_reg_shift = 0; + if (early_serial_setup(&serial_req) < 0) { + printk("setup_serial_hcdp(): early_serial_setup() for HCDP serial console port failed. Will try any additional consoles in HCDP.\n"); + continue; + } + else + if (hcdp_dev->type == HCDP_DEV_CONSOLE) + break; +#ifdef SERIAL_DEBUG_HCDP + printk("\n"); +#endif + } + +#ifdef SERIAL_DEBUG_HCDP + printk("Leaving setup_serial_hcdp()\n"); +#endif +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/indydog.c linux-2.5/drivers/char/indydog.c --- linux-2.5.20/drivers/char/indydog.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/indydog.c Wed Mar 27 23:55:15 2002 @@ -0,0 +1,155 @@ +/* + * IndyDog 0.2 A Hardware Watchdog Device for SGI IP22 + * + * (c) Copyright 2002 Guido Guenther , All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * based on softdog.c by Alan Cox + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long indydog_alive; +static struct sgimc_misc_ctrl *mcmisc_regs; + +static void indydog_ping() +{ + mcmisc_regs->watchdogt = 0; +} + + +/* + * Allow only one person to hold it open + */ + +static int indydog_open(struct inode *inode, struct file *file) +{ + u32 mc_ctrl0; + + if( test_and_set_bit(0,&indydog_alive) ) + return -EBUSY; +#ifdef CONFIG_WATCHDOG_NOWAYOUT + MOD_INC_USE_COUNT; +#endif + /* + * Activate timer + */ + mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000); + + mc_ctrl0 = mcmisc_regs->cpuctrl0 | SGIMC_CCTRL0_WDOG; + mcmisc_regs->cpuctrl0 = mc_ctrl0; + indydog_ping(); + + printk("Started watchdog timer.\n"); + return 0; +} + +static int indydog_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we defined ...NOWAYOUT + */ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + { + u32 mc_ctrl0 = mcmisc_regs->cpuctrl0; + mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG; + mcmisc_regs->cpuctrl0 = mc_ctrl0; + printk("Stopped watchdog timer.\n"); + } +#endif + clear_bit(0,&indydog_alive); + return 0; +} + +static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if(len) { + indydog_ping(); + return 1; + } + return 0; +} + +static int indydog_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident = { + identity: "Hardware Watchdog for SGI IP22", + }; + switch (cmd) { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0,(int *)arg); + case WDIOC_KEEPALIVE: + indydog_ping(); + return 0; + } +} + +static struct file_operations indydog_fops = { + owner: THIS_MODULE, + write: indydog_write, + ioctl: indydog_ioctl, + open: indydog_open, + release: indydog_release, +}; + +static struct miscdevice indydog_miscdev = { + minor: WATCHDOG_MINOR, + name: "watchdog", + fops: &indydog_fops, +}; + +static const char banner[] __initdata = KERN_INFO "Hardware Watchdog Timer for SGI IP22: 0.2\n"; + +static int __init watchdog_init(void) +{ + int ret; + + ret = misc_register(&indydog_miscdev); + + if (ret) + return ret; + + printk(banner); + + return 0; +} + +static void __exit watchdog_exit(void) +{ + misc_deregister(&indydog_miscdev); +} + +module_init(watchdog_init); +module_exit(watchdog_exit); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/ip2/i2cmd.c linux-2.5/drivers/char/ip2/i2cmd.c --- linux-2.5.20/drivers/char/ip2/i2cmd.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/char/ip2/i2cmd.c Thu Dec 13 16:32:35 2001 @@ -139,7 +139,7 @@ //static UCHAR ct86[]={ 2, BTH, 0x56,0 }; // RCV_ENABLE static UCHAR ct87[] = { 1, BYP, 0x57 }; // HW_TEST //static UCHAR ct88[]={ 3, BTH, 0x58,0,0 }; // RCV_THRESHOLD -static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW +//static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW //static UCHAR ct90[]={ 3, BYP, 0x5A,0,0 }; // Set SILO //static UCHAR ct91[]={ 2, BYP, 0x5B,0 }; // timed break diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/ip2.c linux-2.5/drivers/char/ip2.c --- linux-2.5.20/drivers/char/ip2.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/char/ip2.c Thu Dec 13 16:32:35 2001 @@ -33,9 +33,10 @@ */ static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 }; static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; -static int poll_only = 0; #ifdef MODULE + +static int poll_only = 0; # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) MODULE_AUTHOR("Doug McNash"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/keyboard.c linux-2.5/drivers/char/keyboard.c --- linux-2.5.20/drivers/char/keyboard.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/char/keyboard.c Sun Mar 3 23:50:41 2002 @@ -43,298 +43,129 @@ #include #include -#define SIZE(x) (sizeof(x)/sizeof((x)[0])) +extern void ctrl_alt_del(void); -#ifndef KBD_DEFMODE -#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) -#endif +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) -#ifndef KBD_DEFLEDS /* - * Some laptops take the 789uiojklm,. keys as number pad when NumLock - * is on. This seems a good reason to start with NumLock off. + * Exported functions/variables */ -#define KBD_DEFLEDS 0 -#endif - -#ifndef KBD_DEFLOCK -#define KBD_DEFLOCK 0 -#endif void (*kbd_ledfunc)(unsigned int led); EXPORT_SYMBOL(handle_scancode); EXPORT_SYMBOL(kbd_ledfunc); - -extern void ctrl_alt_del(void); - -struct console; +/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ +struct pt_regs *kbd_pt_regs; +void compute_shiftstate(void); /* - * global state includes the following, and various static variables - * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next. - * (last_console is now a global variable) + * Handler Tables. */ -/* shift state counters.. */ -static unsigned char k_down[NR_SHIFT]; -/* keyboard key bitmap */ -static unsigned long key_down[256/BITS_PER_LONG]; - -static int dead_key_next; -/* - * In order to retrieve the shift_state (for the mouse server), either - * the variable must be global, or a new procedure must be created to - * return the value. I chose the former way. - */ -int shift_state; -static int npadch = -1; /* -1 or number assembled on pad */ -static unsigned char diacr; -static char rep; /* flag telling character repeat */ -struct kbd_struct kbd_table[MAX_NR_CONSOLES]; -static struct tty_struct **ttytab; -static struct kbd_struct * kbd = kbd_table; -static struct tty_struct * tty; - -void compute_shiftstate(void); - -typedef void (*k_hand)(unsigned char value, char up_flag); -typedef void (k_handfn)(unsigned char value, char up_flag); - -static k_handfn - do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, - do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, - do_ignore; - -static k_hand key_handler[16] = { - do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, - do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, - do_ignore, do_ignore -}; - /* Key types processed even in raw modes */ #define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT)) +#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK)) -typedef void (*void_fnp)(void); -typedef void (void_fn)(void); - -static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, - num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, - SAK, decr_console, incr_console, spawn_console, bare_num; - -static void_fnp spec_fn_table[] = { - do_null, enter, show_ptregs, show_mem, - show_state, send_intr, lastcons, caps_toggle, - num, hold, scroll_forw, scroll_back, - boot_it, caps_on, compose, SAK, - decr_console, incr_console, spawn_console, bare_num -}; +#define K_HANDLERS\ + k_self, k_fn, k_spec, k_pad,\ + k_dead, k_cons, k_cur, k_shift,\ + k_meta, k_ascii, k_lock, k_lowercase,\ + k_slock, k_dead2, k_ignore, k_ignore + +typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, + char up_flag); +static k_handler_fn K_HANDLERS; +static k_handler_fn *k_handler[16] = { K_HANDLERS }; + +#define FN_HANDLERS\ + fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ + fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ + fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ + fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ + fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num + +typedef void (fn_handler_fn)(struct vc_data *vc); +static fn_handler_fn FN_HANDLERS; +static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; -#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK)) +/* + * Variables/functions exported for vt_ioctl.c + */ /* maximum values each key_handler can handle */ const int max_vals[] = { - 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, - NR_DEAD - 1, 255, 3, NR_SHIFT - 1, - 255, NR_ASCII - 1, NR_LOCK - 1, 255, - NR_LOCK - 1, 255 + 255, SIZE(func_table) - 1, SIZE(fn_handler) - 1, NR_PAD - 1, + NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, + 255, NR_LOCK - 1, 255 }; - const int NR_TYPES = SIZE(max_vals); -/* N.B. drivers/macintosh/mac_keyb.c needs to call put_queue */ -void put_queue(int); -static unsigned char handle_diacr(unsigned char); - -/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ -struct pt_regs * kbd_pt_regs; - -#ifdef CONFIG_MAGIC_SYSRQ -static int sysrq_pressed; -#endif - -static struct pm_dev *pm_kbd; - -/* - * Many other routines do put_queue, but I think either - * they produce ASCII, or they produce some user-assigned - * string, and in both cases we might assume that it is - * in utf-8 already. - */ -void to_utf8(ushort c) { - if (c < 0x80) - put_queue(c); /* 0******* */ - else if (c < 0x800) { - put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */ - put_queue(0x80 | (c & 0x3f)); - } else { - put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */ - put_queue(0x80 | ((c >> 6) & 0x3f)); - put_queue(0x80 | (c & 0x3f)); - } - /* UTF-8 is defined for words of up to 31 bits, - but we need only 16 bits here */ -} +int spawnpid, spawnsig; /* * Translation of escaped scancodes to keycodes. * This is now user-settable (for machines were it makes sense). */ - -int setkeycode(unsigned int scancode, unsigned int keycode) -{ - return kbd_setkeycode(scancode, keycode); -} - int getkeycode(unsigned int scancode) { return kbd_getkeycode(scancode); } -void handle_scancode(unsigned char scancode, int down) +int setkeycode(unsigned int scancode, unsigned int keycode) { - unsigned char keycode; - char up_flag = down ? 0 : 0200; - char raw_mode; - - pm_access(pm_kbd); - add_keyboard_randomness(scancode | up_flag); - - tty = ttytab? ttytab[fg_console]: NULL; - if (tty && (!tty->driver_data)) { - /* - * We touch the tty structure via the ttytab array - * without knowing whether or not tty is open, which - * is inherently dangerous. We currently rely on that - * fact that console_open sets tty->driver_data when - * it opens it, and clears it when it closes it. - */ - tty = NULL; - } - kbd = kbd_table + fg_console; - if ((raw_mode = (kbd->kbdmode == VC_RAW))) { - put_queue(scancode | up_flag); - /* we do not return yet, because we want to maintain - the key_down array, so that we have the correct - values when finishing RAW mode or when changing VT's */ - } - - /* - * Convert scancode to keycode - */ - if (!kbd_translate(scancode, &keycode, raw_mode)) - goto out; - - /* - * At this point the variable `keycode' contains the keycode. - * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid). - * We keep track of the up/down status of the key, and - * return the keycode if in MEDIUMRAW mode. - */ - - if (up_flag) { - rep = 0; - if(!test_and_clear_bit(keycode, key_down)) - up_flag = kbd_unexpected_up(keycode); - } else - rep = test_and_set_bit(keycode, key_down); - -#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ - if (keycode == SYSRQ_KEY) { - sysrq_pressed = !up_flag; - goto out; - } else if (sysrq_pressed) { - if (!up_flag) { - handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty); - goto out; - } - } -#endif + return kbd_setkeycode(scancode, keycode); +} - if (kbd->kbdmode == VC_MEDIUMRAW) { - /* soon keycodes will require more than one byte */ - put_queue(keycode + up_flag); - raw_mode = 1; /* Most key classes will be ignored */ - } +/* + * Variables/function exported for vt.c + */ +int shift_state = 0; - /* - * Small change in philosophy: earlier we defined repetition by - * rep = keycode == prev_keycode; - * prev_keycode = keycode; - * but now by the fact that the depressed key was down already. - * Does this ever make a difference? Yes. - */ +/* + * Internal Data. + */ - /* - * Repeat a key only if the input buffers are empty or the - * characters get echoed locally. This makes key repeat usable - * with slow applications and under heavy loads. - */ - if (!rep || - (vc_kbd_mode(kbd,VC_REPEAT) && tty && - (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { - u_short keysym; - u_char type; +static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */ +static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ +static int dead_key_next; +static int npadch = -1; /* -1 or number assembled on pad */ +static unsigned char diacr; +static char rep; /* flag telling character repeat */ +pm_callback pm_kbd_request_override = NULL; +typedef void (pm_kbd_func) (void); +static struct pm_dev *pm_kbd; - /* the XOR below used to be an OR */ - int shift_final = (shift_state | kbd->slockstate) ^ - kbd->lockstate; - ushort *key_map = key_maps[shift_final]; +static unsigned char ledstate = 0xff; /* undefined */ +static unsigned char ledioctl; - if (key_map != NULL) { - keysym = key_map[keycode]; - type = KTYP(keysym); +static struct ledptr { + unsigned int *addr; + unsigned int mask; + unsigned char valid:1; +} ledptrs[3]; - if (type >= 0xf0) { - type -= 0xf0; - if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) - goto out; - if (type == KT_LETTER) { - type = KT_LATIN; - if (vc_kbd_led(kbd, VC_CAPSLOCK)) { - key_map = key_maps[shift_final ^ (1<slockstate = 0; - } else { - /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ - if (!up_flag && !raw_mode) - to_utf8(keysym); - } - } else { - /* maybe beep? */ - /* we have at least to update shift_state */ -#if 1 /* how? two almost equivalent choices follow */ - compute_shiftstate(); - kbd->slockstate = 0; /* play it safe */ -#else - keysym = U(plain_map[keycode]); - type = KTYP(keysym); - if (type == KT_SHIFT) - (*key_handler[type])(keysym & 0xff, up_flag); +#ifdef CONFIG_MAGIC_SYSRQ +static int sysrq_pressed; #endif - } - } -out: - do_poke_blanked_console = 1; - schedule_console_callback(); -} - -void put_queue(int ch) +/* + * Helper Functions. + */ +static void put_queue(struct vc_data *vc, int ch) { + struct tty_struct *tty = vc->vc_tty; + if (tty) { tty_insert_flip_char(tty, ch, 0); con_schedule_flip(tty); } } -static void puts_queue(char *cp) +static void puts_queue(struct vc_data *vc, char *cp) { + struct tty_struct *tty = vc->vc_tty; + if (!tty) return; @@ -345,48 +176,172 @@ con_schedule_flip(tty); } -static void applkey(int key, char mode) +static void applkey(struct vc_data *vc, int key, char mode) { static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; buf[1] = (mode ? 'O' : '['); buf[2] = key; - puts_queue(buf); + puts_queue(vc, buf); +} + +/* + * A note on character conversion: + * + * A keymap maps keycodes to keysyms, which, at present, are 16-bit + * values. If a keysym is < 0xf000 then it specifies a 16-bit Unicode + * character to be queued. If a keysym is >= 0xf000, then 0xf000 is + * subtracted to give a pair of octets, extracted by KTYP and KVAL. + * The KTYP is used as an index into key_handler[] to give a function + * which handles the KVAL. The "normal" key_handler is k_self, which + * treats the KVAL as an 8-bit character to be queued. + * + * When a 16-bit Unicode character is queued it is converted to UTF-8 + * if the keyboard is in Unicode mode; otherwise it is converted to an + * 8-bit character using the current ACM (see consolemap.c). An 8-bit + * character is assumed to be in the character set defined by the + * current ACM, so it is queued unchanged if the keyboard is in 8-bit + * mode; otherwise it is converted using the inverse ACM. + * + * The handling of diacritics uses 8-bit characters, which are + * converted using the inverse ACM, when in Unicode mode. The strings + * bound to function keys are not converted, so they may already + * contain UTF-8. Codes entered using do_ascii() treated as 16-bit and + * converted to UTF-8 in Unicode mode; otherwise they are treated as + * 8-bit and queued unchanged. + * + * Since KTYP is not used in the case of Unicode keysyms, it is not + * possible to use KT_LETTER to implement CapsLock. Either use 8-bit + * keysyms with an appropriate ACM or use the work-around proposed in + * k_lock(). + */ + +/* + * Many other routines do put_queue, but I think either + * they produce ASCII, or they produce some user-assigned + * string, and in both cases we might assume that it is + * in utf-8 already. UTF-8 is defined for words of up to 31 bits, + * but we need only 16 bits here + */ +void to_utf8(struct vc_data *vc, ushort c) +{ + if (c < 0x80) + /* 0******* */ + put_queue(vc, c); + else if (c < 0x800) { + /* 110***** 10****** */ + put_queue(vc, 0xc0 | (c >> 6)); + put_queue(vc, 0x80 | (c & 0x3f)); + } else { + /* 1110**** 10****** 10****** */ + put_queue(vc, 0xe0 | (c >> 12)); + put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); + put_queue(vc, 0x80 | (c & 0x3f)); + } +} + +/* + * called after returning from RAW mode or when changing consoles - + * recompute shift_down[] and shift_state from key_down[] + * maybe called when keymap is undefined, so that shiftkey release is seen + */ +void compute_shiftstate(void) +{ + int i, j, k, sym, val; + + shift_state = 0; + memset(shift_down, 0, sizeof(shift_down)); + + for (i = 0; i < SIZE(key_down); i++) { + + if (!key_down[i]) + continue; + + k = i*BITS_PER_LONG; + + for (j = 0; j < BITS_PER_LONG; j++, k++) { + + if (!test_bit(k, key_down)) + continue; + + sym = U(plain_map[k]); + if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) + continue; + + val = KVAL(sym); + if (val == KVAL(K_CAPSSHIFT)) + val = KVAL(K_SHIFT); + + shift_down[val]++; + shift_state |= (1 << val); + } + } +} + +/* + * We have a combining character DIACR here, followed by the character CH. + * If the combination occurs in the table, return the corresponding value. + * Otherwise, if CH is a space or equals DIACR, return DIACR. + * Otherwise, conclude that DIACR was not combining after all, + * queue it and return CH. + */ +unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) +{ + int d = diacr; + int i; + + diacr = 0; + + for (i = 0; i < accent_table_size; i++) { + if (accent_table[i].diacr == d && accent_table[i].base == ch) + return accent_table[i].result; + } + + if (ch == ' ' || ch == d) + return d; + + put_queue(vc, d); + return ch; } -static void enter(void) +/* + * Special function handlers + */ +static void fn_enter(struct vc_data *vc) { if (diacr) { - put_queue(diacr); + put_queue(vc, diacr); diacr = 0; } - put_queue(13); - if (vc_kbd_mode(kbd,VC_CRLF)) - put_queue(10); + put_queue(vc, 13); + if (get_kbd_mode(&vc->kbd_table, VC_CRLF)) + put_queue(vc, 10); } -static void caps_toggle(void) +static void fn_caps_toggle(struct vc_data *vc) { if (rep) return; - chg_vc_kbd_led(kbd, VC_CAPSLOCK); + chg_kbd_led(&vc->kbd_table, VC_CAPSLOCK); } -static void caps_on(void) +static void fn_caps_on(struct vc_data *vc) { if (rep) return; - set_vc_kbd_led(kbd, VC_CAPSLOCK); + set_kbd_led(&vc->kbd_table, VC_CAPSLOCK); } -static void show_ptregs(void) +static void fn_show_ptregs(struct vc_data *vc) { if (kbd_pt_regs) show_regs(kbd_pt_regs); } -static void hold(void) +static void fn_hold(struct vc_data *vc) { + struct tty_struct *tty = vc->vc_tty; + if (rep || !tty) return; @@ -401,12 +356,12 @@ stop_tty(tty); } -static void num(void) +static void fn_num(struct vc_data *vc) { - if (vc_kbd_mode(kbd,VC_APPLIC)) - applkey('P', 1); + if (get_kbd_mode(&vc->kbd_table, VC_APPLIC)) + applkey(vc, 'P', 1); else - bare_num(); + fn_bare_num(vc); } /* @@ -415,19 +370,19 @@ * Bind this to NumLock if you prefer that the NumLock key always * changes the NumLock flag. */ -static void bare_num(void) +static void fn_bare_num(struct vc_data *vc) { if (!rep) - chg_vc_kbd_led(kbd,VC_NUMLOCK); + chg_kbd_led(&vc->kbd_table, VC_NUMLOCK); } -static void lastcons(void) +static void fn_lastcons(struct vc_data *vc) { /* switch to the last used console, ChN */ - set_console(last_console); + set_console(vc->display_fg->last_console->vc_num); } -static void decr_console(void) +static void fn_dec_console(struct vc_data *vc) { int i; @@ -440,7 +395,7 @@ set_console(i); } -static void incr_console(void) +static void fn_inc_console(struct vc_data *vc) { int i; @@ -453,114 +408,114 @@ set_console(i); } -static void send_intr(void) +static void fn_send_intr(struct vc_data *vc) { + struct tty_struct *tty = vc->vc_tty; + if (!tty) return; tty_insert_flip_char(tty, 0, TTY_BREAK); con_schedule_flip(tty); } -static void scroll_forw(void) +static void fn_scroll_forw(struct vc_data *vc) +{ + scrollfront(vc, 0); +} + +static void fn_scroll_back(struct vc_data *vc) +{ + scrollback(vc, 0); +} + +static void fn_show_mem(struct vc_data *vc) { - scrollfront(0); + show_mem(); } -static void scroll_back(void) +static void fn_show_state(struct vc_data *vc) { - scrollback(0); + show_state(); } -static void boot_it(void) +static void fn_boot_it(struct vc_data *vc) { ctrl_alt_del(); } -static void compose(void) +static void fn_compose(struct vc_data *vc) { + /* ???? */ dead_key_next = 1; } -int spawnpid, spawnsig; - -static void spawn_console(void) +static void fn_spawn_con(struct vc_data *vc) { - if (spawnpid) - if(kill_proc(spawnpid, spawnsig, 1)) - spawnpid = 0; + if (spawnpid) + if (kill_proc(spawnpid, spawnsig, 1)) + spawnpid = 0; } -static void SAK(void) +static void fn_SAK(struct vc_data *vc) { + struct tty_struct *tty = vc->vc_tty; + /* * SAK should also work in all raw modes and reset * them properly. */ - - do_SAK(tty); - reset_vc(fg_console); + if (tty) + do_SAK(tty); + reset_vc(vc); #if 0 do_unblank_screen(); /* not in interrupt routine? */ #endif } -static void do_ignore(unsigned char value, char up_flag) +static void fn_null(struct vc_data *vc) { + compute_shiftstate(); } -static void do_null() +/* + * Special key handlers + */ +static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag) { - compute_shiftstate(); } -static void do_spec(unsigned char value, char up_flag) +static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; - if (value >= SIZE(spec_fn_table)) + if (value >= SIZE(fn_handler)) return; - if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) && - !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value))) + if ((vc->kbd_table.kbdmode == VC_RAW || + vc->kbd_table.kbdmode == VC_MEDIUMRAW) && + !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value))) return; - spec_fn_table[value](); + fn_handler[value](vc); } -static void do_lowercase(unsigned char value, char up_flag) +static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) { - printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n"); + printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); } -static void do_self(unsigned char value, char up_flag) +static void k_self(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; /* no action, if this is a key release */ if (diacr) - value = handle_diacr(value); + value = handle_diacr(vc, value); if (dead_key_next) { dead_key_next = 0; diacr = value; return; } - - put_queue(value); -} - -#define A_GRAVE '`' -#define A_ACUTE '\'' -#define A_CFLEX '^' -#define A_TILDE '~' -#define A_DIAER '"' -#define A_CEDIL ',' -static unsigned char ret_diacr[NR_DEAD] = - {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL }; - -/* Obsolete - for backwards compatibility only */ -static void do_dead(unsigned char value, char up_flag) -{ - value = ret_diacr[value]; - do_dead2(value,up_flag); + put_queue(vc, value); } /* @@ -568,60 +523,51 @@ * dead keys modifying the same character. Very useful * for Vietnamese. */ -static void do_dead2(unsigned char value, char up_flag) +static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; - - diacr = (diacr ? handle_diacr(value) : value); + diacr = (diacr ? handle_diacr(vc, value) : value); } - /* - * We have a combining character DIACR here, followed by the character CH. - * If the combination occurs in the table, return the corresponding value. - * Otherwise, if CH is a space or equals DIACR, return DIACR. - * Otherwise, conclude that DIACR was not combining after all, - * queue it and return CH. + * Obsolete - for backwards compatibility only */ -unsigned char handle_diacr(unsigned char ch) +static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) { - int d = diacr; - int i; - - diacr = 0; - - for (i = 0; i < accent_table_size; i++) { - if (accent_table[i].diacr == d && accent_table[i].base == ch) - return accent_table[i].result; - } - - if (ch == ' ' || ch == d) - return d; - - put_queue(d); - return ch; + static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; + value = ret_diacr[value]; + k_dead2(vc, value, up_flag); } -static void do_cons(unsigned char value, char up_flag) +static void k_cons(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; set_console(value); } -static void do_fn(unsigned char value, char up_flag) +static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; if (value < SIZE(func_table)) { if (func_table[value]) - puts_queue(func_table[value]); + puts_queue(vc, func_table[value]); } else - printk(KERN_ERR "do_fn called with value=%d\n", value); + printk(KERN_ERR "k_fn called with value=%d\n", value); } -static void do_pad(unsigned char value, char up_flag) +static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) +{ + static const char *cur_chars = "BDCA"; + + if (up_flag) + return; + applkey(vc, cur_chars[value], get_kbd_mode(&vc->kbd_table, VC_CKMODE)); +} + +static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) { static const char *pad_chars = "0123456789+-*/\015,.?()"; static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; @@ -630,178 +576,162 @@ return; /* no action, if this is a key release */ /* kludge... shift forces cursor/number keys */ - if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) { - applkey(app_map[value], 1); + if (get_kbd_mode(&vc->kbd_table, VC_APPLIC) && !shift_down[KG_SHIFT]) { + applkey(vc, app_map[value], 1); return; } - if (!vc_kbd_led(kbd,VC_NUMLOCK)) + if (!get_kbd_led(&vc->kbd_table, VC_NUMLOCK)) switch (value) { case KVAL(K_PCOMMA): case KVAL(K_PDOT): - do_fn(KVAL(K_REMOVE), 0); + k_fn(vc, KVAL(K_REMOVE), 0); return; case KVAL(K_P0): - do_fn(KVAL(K_INSERT), 0); + k_fn(vc, KVAL(K_INSERT), 0); return; case KVAL(K_P1): - do_fn(KVAL(K_SELECT), 0); + k_fn(vc, KVAL(K_SELECT), 0); return; case KVAL(K_P2): - do_cur(KVAL(K_DOWN), 0); + k_cur(vc, KVAL(K_DOWN), 0); return; case KVAL(K_P3): - do_fn(KVAL(K_PGDN), 0); + k_fn(vc, KVAL(K_PGDN), 0); return; case KVAL(K_P4): - do_cur(KVAL(K_LEFT), 0); + k_cur(vc, KVAL(K_LEFT), 0); return; case KVAL(K_P6): - do_cur(KVAL(K_RIGHT), 0); + k_cur(vc, KVAL(K_RIGHT), 0); return; case KVAL(K_P7): - do_fn(KVAL(K_FIND), 0); + k_fn(vc, KVAL(K_FIND), 0); return; case KVAL(K_P8): - do_cur(KVAL(K_UP), 0); + k_cur(vc, KVAL(K_UP), 0); return; case KVAL(K_P9): - do_fn(KVAL(K_PGUP), 0); + k_fn(vc, KVAL(K_PGUP), 0); return; case KVAL(K_P5): - applkey('G', vc_kbd_mode(kbd, VC_APPLIC)); + applkey(vc, 'G', get_kbd_mode(&vc->kbd_table, + VC_APPLIC)); return; } - put_queue(pad_chars[value]); - if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) - put_queue(10); + put_queue(vc, pad_chars[value]); + if (value == KVAL(K_PENTER) && get_kbd_mode(&vc->kbd_table, VC_CRLF)) + put_queue(vc, 10); } -static void do_cur(unsigned char value, char up_flag) -{ - static const char *cur_chars = "BDCA"; - if (up_flag) - return; - - applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE)); -} - -static void do_shift(unsigned char value, char up_flag) +static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) { int old_state = shift_state; if (rep) return; - - /* Mimic typewriter: - a CapsShift key acts like Shift but undoes CapsLock */ + /* + * Mimic typewriter: + * a CapsShift key acts like Shift but undoes CapsLock + */ if (value == KVAL(K_CAPSSHIFT)) { value = KVAL(K_SHIFT); if (!up_flag) - clr_vc_kbd_led(kbd, VC_CAPSLOCK); + clr_kbd_led(&vc->kbd_table, VC_CAPSLOCK); } if (up_flag) { - /* handle the case that two shift or control - keys are depressed simultaneously */ - if (k_down[value]) - k_down[value]--; + /* + * handle the case that two shift or control + * keys are depressed simultaneously + */ + if (shift_down[value]) + shift_down[value]--; } else - k_down[value]++; + shift_down[value]++; - if (k_down[value]) + if (shift_down[value]) shift_state |= (1 << value); else - shift_state &= ~ (1 << value); + shift_state &= ~(1 << value); /* kludge */ if (up_flag && shift_state != old_state && npadch != -1) { - if (kbd->kbdmode == VC_UNICODE) - to_utf8(npadch & 0xffff); + if (vc->kbd_table.kbdmode == VC_UNICODE) + to_utf8(vc, npadch & 0xffff); else - put_queue(npadch & 0xff); + put_queue(vc, npadch & 0xff); npadch = -1; } } -/* called after returning from RAW mode or when changing consoles - - recompute k_down[] and shift_state from key_down[] */ -/* maybe called when keymap is undefined, so that shiftkey release is seen */ -void compute_shiftstate(void) -{ - int i, j, k, sym, val; - - shift_state = 0; - for(i=0; i < SIZE(k_down); i++) - k_down[i] = 0; - - for(i=0; i < SIZE(key_down); i++) - if(key_down[i]) { /* skip this word if not a single bit on */ - k = i*BITS_PER_LONG; - for(j=0; jkbd_table, VC_META)) { + put_queue(vc, '\033'); + put_queue(vc, value); } else - put_queue(value | 0x80); + put_queue(vc, value | 0x80); } -static void do_ascii(unsigned char value, char up_flag) +static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) { int base; if (up_flag) return; - if (value < 10) /* decimal input of code, while Alt depressed */ - base = 10; - else { /* hexadecimal input of code, while AltGr depressed */ - value -= 10; - base = 16; + if (value < 10) { + /* decimal input of code, while Alt depressed */ + base = 10; + } else { + /* hexadecimal input of code, while AltGr depressed */ + value -= 10; + base = 16; } if (npadch == -1) - npadch = value; + npadch = value; else - npadch = npadch * base + value; + npadch = npadch * base + value; } -static void do_lock(unsigned char value, char up_flag) +static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag || rep) return; - chg_vc_kbd_lock(kbd, value); + if (value >= NR_LOCK) { + /* + * Change the lock state and + * set the CapsLock LED to the new state + */ + unsigned char mask; + + mask = 1 << (value -= NR_LOCK); + if ((vc->kbd_table.lockstate ^= mask) & mask) + set_kbd_led(&vc->kbd_table, VC_CAPSLOCK); + else + clr_kbd_led(&vc->kbd_table, VC_CAPSLOCK); + } else { + /* Just change the lock state */ + chg_kbd_lock(&vc->kbd_table, value); + } } -static void do_slock(unsigned char value, char up_flag) +static void k_slock(struct vc_data *vc, unsigned char value, char up_flag) { - do_shift(value,up_flag); + k_shift(vc, value, up_flag); if (up_flag || rep) return; - chg_vc_kbd_slock(kbd, value); + chg_kbd_slock(&vc->kbd_table, value); /* try to make Alt, oops, AltGr and such work */ - if (!key_maps[kbd->lockstate ^ kbd->slockstate]) { - kbd->slockstate = 0; - chg_vc_kbd_slock(kbd, value); + if (!key_maps[vc->kbd_table.lockstate ^ vc->kbd_table.slockstate]) { + vc->kbd_table.slockstate = 0; + chg_kbd_slock(&vc->kbd_table, value); } } @@ -810,69 +740,58 @@ * or (ii) whatever pattern of lights people want to show using KDSETLED, * or (iii) specified bits of specified words in kernel memory. */ +unsigned char getledstate(void) +{ + return ledstate; +} -static unsigned char ledstate = 0xff; /* undefined */ -static unsigned char ledioctl; - -unsigned char getledstate(void) { - return ledstate; +void setledstate(struct kbd_struct *kbd, unsigned int led) +{ + if (!(led & ~7)) { + ledioctl = led; + kbd->ledmode = LED_SHOW_IOCTL; + } else + kbd->ledmode = LED_SHOW_FLAGS; + set_leds(); } -void setledstate(struct kbd_struct *kbd, unsigned int led) { - if (!(led & ~7)) { - ledioctl = led; - kbd->ledmode = LED_SHOW_IOCTL; - } else - kbd->ledmode = LED_SHOW_FLAGS; - set_leds(); +void register_leds(struct kbd_struct *kbd, unsigned int led, + unsigned int *addr, unsigned int mask) +{ + if (led < 3) { + ledptrs[led].addr = addr; + ledptrs[led].mask = mask; + ledptrs[led].valid = 1; + kbd->ledmode = LED_SHOW_MEM; + } else + kbd->ledmode = LED_SHOW_FLAGS; } -static struct ledptr { - unsigned int *addr; - unsigned int mask; - unsigned char valid:1; -} ledptrs[3]; +static inline unsigned char getleds(struct vt_struct *vt) +{ + struct vc_data *vc = vt->vc_cons[fg_console]; + struct kbd_struct *kbd = NULL; + unsigned char leds; + int i; + + if (vc) + kbd = &vc->kbd_table; -void register_leds(int console, unsigned int led, - unsigned int *addr, unsigned int mask) { - struct kbd_struct *kbd = kbd_table + console; - if (led < 3) { - ledptrs[led].addr = addr; - ledptrs[led].mask = mask; - ledptrs[led].valid = 1; - kbd->ledmode = LED_SHOW_MEM; - } else - kbd->ledmode = LED_SHOW_FLAGS; -} - -static inline unsigned char getleds(void){ - struct kbd_struct *kbd = kbd_table + fg_console; - unsigned char leds; - - if (kbd->ledmode == LED_SHOW_IOCTL) - return ledioctl; - leds = kbd->ledflagstate; - if (kbd->ledmode == LED_SHOW_MEM) { - if (ledptrs[0].valid) { - if (*ledptrs[0].addr & ledptrs[0].mask) - leds |= 1; - else - leds &= ~1; - } - if (ledptrs[1].valid) { - if (*ledptrs[1].addr & ledptrs[1].mask) - leds |= 2; - else - leds &= ~2; - } - if (ledptrs[2].valid) { - if (*ledptrs[2].addr & ledptrs[2].mask) - leds |= 4; - else - leds &= ~4; + if (kbd->ledmode == LED_SHOW_IOCTL) + return ledioctl; + + leds = kbd->ledflagstate; + + if (kbd->ledmode == LED_SHOW_MEM) { + for (i = 0; i < 3; i++) + if (ledptrs[i].valid) { + if (*ledptrs[i].addr & ledptrs[i].mask) + leds |= (1 << i); + else + leds &= ~(1 << i); + } } - } - return leds; + return leds; } /* @@ -888,9 +807,10 @@ * used, but this allows for easy and efficient race-condition * prevention later on. */ + static void kbd_bh(unsigned long dummy) { - unsigned char leds = getleds(); + unsigned char leds = getleds(vt_cons); if (leds != ledstate) { ledstate = leds; @@ -902,28 +822,144 @@ EXPORT_SYMBOL(keyboard_tasklet); DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); -typedef void (pm_kbd_func) (void); +void handle_scancode(unsigned char scancode, int down) +{ + struct vc_data *vc = vt_cons->vc_cons[fg_console]; + char up_flag = down ? 0 : 0200; + struct tty_struct *tty; + unsigned char keycode; + char raw_mode; -pm_callback pm_kbd_request_override = NULL; + pm_access(pm_kbd); + add_keyboard_randomness(scancode | up_flag); -int __init kbd_init(void) -{ - int i; - struct kbd_struct kbd0; - extern struct tty_driver console_driver; + tty = vc->vc_tty; - kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; - kbd0.ledmode = LED_SHOW_FLAGS; - kbd0.lockstate = KBD_DEFLOCK; - kbd0.slockstate = 0; - kbd0.modeflags = KBD_DEFMODE; - kbd0.kbdmode = VC_XLATE; - - for (i = 0 ; i < MAX_NR_CONSOLES ; i++) - kbd_table[i] = kbd0; + if (tty && (!tty->driver_data)) { + /* + * We touch the tty structure via the ttytab array + * without knowing whether or not tty is open, which + * is inherently dangerous. We currently rely on that + * fact that console_open sets tty->driver_data when + * it opens it, and clears it when it closes it. + */ + tty = NULL; + } + + if ((raw_mode = (vc->kbd_table.kbdmode == VC_RAW))) { + put_queue(vc, scancode | up_flag); + /* we do not return yet, because we want to maintain + the key_down array, so that we have the correct + values when finishing RAW mode or when changing VT's */ + } + + /* + * Convert scancode to keycode + */ + if (!kbd_translate(scancode, &keycode, raw_mode)) + goto out; + + /* + * At this point the variable `keycode' contains the keycode. + * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid). + * We keep track of the up/down status of the key, and + * return the keycode if in MEDIUMRAW mode. + */ + + if (up_flag) { + rep = 0; + if(!test_and_clear_bit(keycode, key_down)) + up_flag = kbd_unexpected_up(keycode); + } else + rep = test_and_set_bit(keycode, key_down); + +#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ + if (keycode == SYSRQ_KEY) { + sysrq_pressed = !up_flag; + goto out; + } else if (sysrq_pressed) { + if (!up_flag) { + handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, tty); + goto out; + } + } +#endif + + if (vc->kbd_table.kbdmode == VC_MEDIUMRAW) { + /* soon keycodes will require more than one byte */ + put_queue(vc, keycode + up_flag); + raw_mode = 1; /* Most key classes will be ignored */ + } + + /* + * Small change in philosophy: earlier we defined repetition by + * rep = keycode == prev_keycode; + * prev_keycode = keycode; + * but now by the fact that the depressed key was down already. + * Does this ever make a difference? Yes. + */ - ttytab = console_driver.table; + /* + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and under heavy loads. + */ + if (!rep || + (get_kbd_mode(&vc->kbd_table, VC_REPEAT) && tty && + (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { + u_short keysym; + u_char type; + + /* the XOR below used to be an OR */ + int shift_final = (shift_state | vc->kbd_table.slockstate) ^ + vc->kbd_table.lockstate; + ushort *key_map = key_maps[shift_final]; + + if (key_map != NULL) { + keysym = key_map[keycode]; + type = KTYP(keysym); + if (type >= 0xf0) { + type -= 0xf0; + if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) + goto out; + if (type == KT_LETTER) { + type = KT_LATIN; + if (get_kbd_led(&vc->kbd_table, VC_CAPSLOCK)) { + key_map = key_maps[shift_final ^ (1<kbd_table.slockstate = 0; + } else { + /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ + if (!up_flag && !raw_mode) + to_utf8(vc, keysym); + } + } else { + /* maybe beep? */ + /* we have at least to update shift_state */ +#if 1 /* how? two almost equivalent choices follow */ + compute_shiftstate(); + vc->kbd_table.slockstate = 0; /* play it safe */ +#else + keysym = U(plain_map[keycode]); + type = KTYP(keysym); + if (type == KT_SHIFT) + (*key_handler[type])(keysym & 0xff, up_flag); +#endif + } + } +out: + do_poke_blanked_console = 1; + schedule_task(&vc->display_fg->vt_tq); +} + +int __init kbd_init(void) +{ kbd_init_hw(); tasklet_enable(&keyboard_tasklet); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/lcd.c linux-2.5/drivers/char/lcd.c --- linux-2.5.20/drivers/char/lcd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/lcd.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,632 @@ +/* + * LCD, LED and Button interface for Cobalt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996, 1997 by Andrew Bose + * + * Linux kernel version history: + * March 2001: Ported from 2.0.34 by Liam Davies + * + */ + +#define RTC_IO_EXTENT 0x10 /*Only really two ports, but... */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "lcd.h" + +static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg); + +static int lcd_present = 1; + +int led_state = 0; + +#if defined(CONFIG_TULIP) && 0 + +#define MAX_INTERFACES 8 +static linkcheck_func_t linkcheck_callbacks[MAX_INTERFACES]; +static void *linkcheck_cookies[MAX_INTERFACES]; + +int lcd_register_linkcheck_func(int iface_num, void *func, void *cookie) +{ + if (iface_num < 0 || + iface_num >= MAX_INTERFACES || + linkcheck_callbacks[iface_num] != NULL) + return -1; + linkcheck_callbacks[iface_num] = (linkcheck_func_t) func; + linkcheck_cookies[iface_num] = cookie; + return 0; +} +#endif + +static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct lcd_display button_display; + unsigned long address, a; + int index; + + switch (cmd) { + case LCD_On: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0F); + break; + + case LCD_Off: + udelay(150); + BusyCheck(); + LCDWriteInst(0x08); + break; + + case LCD_Reset: + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x01); + udelay(150); + LCDWriteInst(0x06); + break; + + case LCD_Clear: + udelay(150); + BusyCheck(); + LCDWriteInst(0x01); + break; + + case LCD_Cursor_Left: + udelay(150); + BusyCheck(); + LCDWriteInst(0x10); + break; + + case LCD_Cursor_Right: + udelay(150); + BusyCheck(); + LCDWriteInst(0x14); + break; + + case LCD_Cursor_Off: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0C); + break; + + case LCD_Cursor_On: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0F); + break; + + case LCD_Blink_Off: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0E); + break; + + case LCD_Get_Cursor_Pos:{ + struct lcd_display display; + + udelay(150); + BusyCheck(); + display.cursor_address = ( LCDReadInst ); + display.cursor_address = ( display.cursor_address & 0x07F ); + if(copy_to_user((struct lcd_display*)arg, &display, sizeof(struct lcd_display))) + return -EFAULT; + + break; + } + + + case LCD_Set_Cursor_Pos: { + struct lcd_display display; + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + + a = (display.cursor_address | kLCD_Addr ); + + udelay(150); + BusyCheck(); + LCDWriteInst( a ); + + break; + } + + case LCD_Get_Cursor: { + struct lcd_display display; + + udelay(150); + BusyCheck(); + display.character = LCDReadData; + + if(copy_to_user((struct lcd_display*)arg, &display, sizeof(struct lcd_display))) + return -EFAULT; + udelay(150); + BusyCheck(); + LCDWriteInst(0x10); + + break; + } + + case LCD_Set_Cursor:{ + struct lcd_display display; + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + + udelay(150); + BusyCheck(); + LCDWriteData( display.character ); + udelay(150); + BusyCheck(); + LCDWriteInst(0x10); + + break; + } + + + case LCD_Disp_Left: + udelay(150); + BusyCheck(); + LCDWriteInst(0x18); + break; + + case LCD_Disp_Right: + udelay(150); + BusyCheck(); + LCDWriteInst(0x1C); + break; + + case LCD_Home: + udelay(150); + BusyCheck(); + LCDWriteInst(0x02); + break; + + case LCD_Write: { + struct lcd_display display; + + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + + udelay(150); + BusyCheck(); + LCDWriteInst(0x80); + udelay(150); + BusyCheck(); + + for (index = 0; index < (display.size1); index++) { + udelay(150); + BusyCheck(); + LCDWriteData( display.line1[index]); + BusyCheck(); + } + + udelay(150); + BusyCheck(); + LCDWriteInst(0xC0); + udelay(150); + BusyCheck(); + for (index = 0; index < (display.size2); index++) { + udelay(150); + BusyCheck(); + LCDWriteData( display.line2[index]); + } + + break; + } + + case LCD_Read: { + struct lcd_display display; + + BusyCheck(); + for (address = kDD_R00; address <= kDD_R01; address++) { + a = (address | kLCD_Addr ); + + udelay(150); + BusyCheck(); + LCDWriteInst( a ); + udelay(150); + BusyCheck(); + display.line1[address] = LCDReadData; + } + + display.line1[ 0x27 ] = '\0'; + + for (address = kDD_R10; address <= kDD_R11; address++) { + a = (address | kLCD_Addr ); + + udelay(150); + BusyCheck(); + LCDWriteInst( a ); + + udelay(150); + BusyCheck(); + display.line2[address - 0x40 ] = LCDReadData; + } + + display.line2[ 0x27 ] = '\0'; + + if(copy_to_user((struct lcd_display*)arg, &display, + sizeof(struct lcd_display))) + return -EFAULT; + break; + } + +// set all GPIO leds to led_display.leds + + case LED_Set: { + struct lcd_display led_display; + + + if(copy_from_user(&led_display, (struct lcd_display*)arg, + sizeof(struct lcd_display))) + return -EFAULT; + + led_state = led_display.leds; + LEDSet(led_state); + + break; + } + + +// set only bit led_display.leds + + case LED_Bit_Set: { + int i; + int bit=1; + struct lcd_display led_display; + + + if(copy_from_user(&led_display, (struct lcd_display*)arg, + sizeof(struct lcd_display))) + return -EFAULT; + + for (i=0;i<(int)led_display.leds;i++) + { + bit = 2*bit; + } + + led_state = led_state | bit; + LEDSet(led_state); + break; + } + +// clear only bit led_display.leds + + case LED_Bit_Clear: { + int i; + int bit=1; + struct lcd_display led_display; + + + if(copy_from_user(&led_display, (struct lcd_display*)arg, + sizeof(struct lcd_display))) + return -EFAULT; + + for (i=0;i<(int)led_display.leds;i++) + { + bit = 2*bit; + } + + led_state = led_state & ~bit; + LEDSet(led_state); + break; + } + + + case BUTTON_Read: { + button_display.buttons = GPIRead; + if(copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display))) + return -EFAULT; + break; + } + + case LINK_Check: { + button_display.buttons = *((volatile unsigned long *) (0xB0100060) ); + if(copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display))) + return -EFAULT; + break; + } + + case LINK_Check_2: { + int iface_num; + + /* panel-utils should pass in the desired interface status is wanted for + * in "buttons" of the structure. We will set this to non-zero if the + * link is in fact up for the requested interface. --DaveM + */ + if(copy_from_user(&button_display, (struct lcd_display *)arg, sizeof(button_display))) + return -EFAULT; + iface_num = button_display.buttons; +#if defined(CONFIG_TULIP) && 0 + if (iface_num >= 0 && + iface_num < MAX_INTERFACES && + linkcheck_callbacks[iface_num] != NULL) { + button_display.buttons = + linkcheck_callbacks[iface_num](linkcheck_cookies[iface_num]); + } else +#endif + button_display.buttons = 0; + + if(__copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display))) + return -EFAULT; + break; + } + +// Erase the flash + + case FLASH_Erase: { + + int ctr=0; + + // Chip Erase Sequence + WRITE_FLASH( kFlash_Addr1, kFlash_Data1 ); + WRITE_FLASH( kFlash_Addr2, kFlash_Data2 ); + WRITE_FLASH( kFlash_Addr1, kFlash_Erase3 ); + WRITE_FLASH( kFlash_Addr1, kFlash_Data1 ); + WRITE_FLASH( kFlash_Addr2, kFlash_Data2 ); + WRITE_FLASH( kFlash_Addr1, kFlash_Erase6 ); + + printk( "Erasing Flash.\n"); + + while ( (!dqpoll(0x00000000,0xFF)) && (!timeout(0x00000000)) ) { + ctr++; + } + + printk("\n"); + printk("\n"); + printk("\n"); + + if (READ_FLASH(0x07FFF0)==0xFF) { printk("Erase Successful\r\n"); } + else if (timeout) { printk("Erase Timed Out\r\n"); } + + break; + } + +// burn the flash + + case FLASH_Burn: { + + volatile unsigned long burn_addr; + unsigned long flags; + int i; + unsigned char *rom; + + + struct lcd_display display; + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + rom = (unsigned char *) kmalloc((128),GFP_ATOMIC); + if ( rom == NULL ) { + printk ("broken\n"); + return 1; + } + + printk("Churning and Burning -"); + save_flags(flags); + for (i=0; iRomImage[0]); + + if(!access_ok(VERIFY_WRITE, user_bytes, FLASH_SIZE)) + return -EFAULT; + + printk("Reading Flash"); + for (i=0; i 0) + return -EINVAL; + + lcd_waiters++; + while(((buttons_now = (long)button_pressed()) == 0) && + !(signal_pending(current))) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2 * HZ); + } + lcd_waiters--; + + if(signal_pending(current)) + return -ERESTARTSYS; + return buttons_now; +} + +/* + * The various file operations we support. + */ + +static struct file_operations lcd_fops = { + read: lcd_read, + ioctl: lcd_ioctl, + open: lcd_open, +}; + +static struct miscdevice lcd_dev= +{ + LCD_MINOR, + "lcd", + &lcd_fops +}; + +int lcd_init(void) +{ +unsigned long data; + + printk("%s\n", LCD_DRIVER); + misc_register(&lcd_dev); + + /* Check region? Naaah! Just snarf it up. */ +/* request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/ + + udelay(150); + data = LCDReadData; + if ( (data & 0x000000FF) == (0x00) ) { + lcd_present = 0; + printk("LCD Not Present\n"); + } + else { + lcd_present = 1; + WRITE_GAL( kGal_DevBank2PReg, kGal_DevBank2Cfg ); + WRITE_GAL( kGal_DevBank3PReg, kGal_DevBank3Cfg ); + } + + return 0; +} + + +// +// Function: dqpoll +// +// Description: Polls the data lines to see if the flash is busy +// +// In: address, byte data +// +// Out: 0 = busy, 1 = write or erase complete +// +// + +int dqpoll( volatile unsigned long address, volatile unsigned char data ) { + +volatile unsigned char dq7; + +dq7 = data & 0x80; + +return ( (READ_FLASH(address) & 0x80) == dq7 ); + +} + + +// +// Function: timeout +// +// Description: Checks to see if erase or write has timed out +// By polling dq5 +// +// In: address +// +// +// Out: 0 = not timed out, 1 = timed out + +int timeout( volatile unsigned long address ) { + + +return ( (READ_FLASH(address) & 0x20) == 0x20 ); + +} + + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/lcd.h linux-2.5/drivers/char/lcd.h --- linux-2.5.20/drivers/char/lcd.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/lcd.h Sun Mar 3 17:54:35 2002 @@ -0,0 +1,184 @@ +/* + * LED, LCD and Button panel driver for Cobalt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996, 1997 by Andrew Bose + * + * Linux kernel version history: + * March 2001: Ported from 2.0.34 by Liam Davies + * + */ + +// function headers + +int dqpoll( volatile unsigned long, volatile unsigned char ); +int timeout( volatile unsigned long ); + +#define LCD_CHARS_PER_LINE 40 +#define FLASH_SIZE 524288 +#define MAX_IDLE_TIME 120 + +struct lcd_display { + unsigned long buttons; + int size1; + int size2; + unsigned char line1[LCD_CHARS_PER_LINE]; + unsigned char line2[LCD_CHARS_PER_LINE]; + unsigned char cursor_address; + unsigned char character; + unsigned char leds; + unsigned char *RomImage; +}; + + + +#define LCD_DRIVER "Cobalt LCD Driver v2.10" + +#define kLCD_IR 0xBF000000 +#define kLCD_DR 0xBF000010 +#define kGPI 0xBD000000 +#define kLED 0xBC000000 + +#define kDD_R00 0x00 +#define kDD_R01 0x27 +#define kDD_R10 0x40 +#define kDD_R11 0x67 + +#define kLCD_Addr 0x00000080 + +#define LCDTimeoutValue 0xfff + + +// Flash definitions AMD 29F040 +#define kFlashBase 0xBFC00000 + +#define kFlash_Addr1 0x5555 +#define kFlash_Addr2 0x2AAA +#define kFlash_Data1 0xAA +#define kFlash_Data2 0x55 +#define kFlash_Prog 0xA0 +#define kFlash_Erase3 0x80 +#define kFlash_Erase6 0x10 +#define kFlash_Read 0xF0 + +#define kFlash_ID 0x90 +#define kFlash_VenAddr 0x00 +#define kFlash_DevAddr 0x01 +#define kFlash_VenID 0x01 +#define kFlash_DevID 0xA4 // 29F040 +//#define kFlash_DevID 0xAD // 29F016 + + +// Macros + +#define LCDWriteData(x) (*(volatile unsigned long *) kLCD_DR) = (x << 24) +#define LCDWriteInst(x) (*(volatile unsigned long *) kLCD_IR) = (x << 24) + +#define LCDReadData (((*(volatile unsigned long *) kLCD_DR) >> 24)) +#define LCDReadInst (((*(volatile unsigned long *) kLCD_IR) >> 24)) + +#define GPIRead (( (*(volatile unsigned long *) kGPI) >> 24)) + +#define LEDSet(x) (*(volatile unsigned char *) kLED) = ((char)x) + +#define WRITE_GAL(x,y) (*((volatile unsigned long *) (0xB4000000 | (x)) ) =y) +#define BusyCheck() while ((LCDReadInst & 0x80) == 0x80) + +#define WRITE_FLASH(x,y) (*((volatile unsigned char *) (kFlashBase | (x)) ) = y) +#define READ_FLASH(x) *((volatile unsigned char *) (kFlashBase | (x)) ) + + + +/* + * Function command codes for io_ctl. + */ +#define LCD_On 1 +#define LCD_Off 2 +#define LCD_Clear 3 +#define LCD_Reset 4 +#define LCD_Cursor_Left 5 +#define LCD_Cursor_Right 6 +#define LCD_Disp_Left 7 +#define LCD_Disp_Right 8 +#define LCD_Get_Cursor 9 +#define LCD_Set_Cursor 10 +#define LCD_Home 11 +#define LCD_Read 12 +#define LCD_Write 13 +#define LCD_Cursor_Off 14 +#define LCD_Cursor_On 15 +#define LCD_Get_Cursor_Pos 16 +#define LCD_Set_Cursor_Pos 17 +#define LCD_Blink_Off 18 + +#define LED_Set 40 +#define LED_Bit_Set 41 +#define LED_Bit_Clear 42 + + +// Button defs +#define BUTTON_Read 50 + +// Flash command codes +#define FLASH_Erase 60 +#define FLASH_Burn 61 +#define FLASH_Read 62 + + +// Ethernet LINK check hackaroo +#define LINK_Check 90 +#define LINK_Check_2 91 + +// Button patterns _B - single layer lcd boards + +#define BUTTON_NONE 0x3F +#define BUTTON_NONE_B 0xFE + +#define BUTTON_Left 0x3B +#define BUTTON_Left_B 0xFA + +#define BUTTON_Right 0x37 +#define BUTTON_Right_B 0xDE + +#define BUTTON_Up 0x2F +#define BUTTON_Up_B 0xF6 + +#define BUTTON_Down 0x1F +#define BUTTON_Down_B 0xEE + +#define BUTTON_Next 0x3D +#define BUTTON_Next_B 0x7E + +#define BUTTON_Enter 0x3E +#define BUTTON_Enter_B 0xBE + +#define BUTTON_Reset_B 0xFC + + +// debounce constants + +#define BUTTON_SENSE 160000 +#define BUTTON_DEBOUNCE 5000 + + +// Galileo register stuff + +#define kGal_DevBank2Cfg 0x1466DB33 +#define kGal_DevBank2PReg 0x464 +#define kGal_DevBank3Cfg 0x146FDFFB +#define kGal_DevBank3PReg 0x468 + +// Network + +#define kIPADDR 1 +#define kNETMASK 2 +#define kGATEWAY 3 +#define kDNS 4 + +#define kClassA 5 +#define kClassB 6 +#define kClassC 7 + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/logibusmouse.c linux-2.5/drivers/char/logibusmouse.c --- linux-2.5.20/drivers/char/logibusmouse.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/char/logibusmouse.c Thu Jan 1 01:00:00 1970 @@ -1,165 +0,0 @@ -/* - * Logitech Bus Mouse Driver for Linux - * by James Banks - * - * Mods by Matthew Dillon - * calls verify_area() - * tracks better when X is busy or paging - * - * Heavily modified by David Giller - * changed from queue- to counter- driven - * hacked out a (probably incorrect) mouse_select - * - * Modified again by Nathan Laredo to interface with - * 0.96c-pl1 IRQ handling changes (13JUL92) - * didn't bother touching select code. - * - * Modified the select() code blindly to conform to the VFS - * requirements. 92.07.14 - Linus. Somebody should test it out. - * - * Modified by Johan Myreen to make room for other mice (9AUG92) - * removed assignment chr_fops[10] = &mouse_fops; see mouse.c - * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public. - * renamed this file mouse.c => busmouse.c - * - * Minor addition by Cliff Matthews - * added fasync support - * - * Modularised 6-Sep-95 Philip Blundell - * - * Replaced dumb busy loop with udelay() 16 Nov 95 - * Nathan Laredo - * - * Track I/O ports with request_region(). 12 Dec 95 Philip Blundell - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "busmouse.h" - -static int msedev; -static int mouse_irq = MOUSE_IRQ; - -MODULE_PARM(mouse_irq, "i"); - -#ifndef MODULE - -static int __init bmouse_setup(char *str) -{ - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - mouse_irq=ints[1]; - - return 1; -} - -__setup("logi_busmouse=", bmouse_setup); - -#endif /* !MODULE */ - -static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - char dx, dy; - unsigned char buttons; - - outb(MSE_READ_X_LOW, MSE_CONTROL_PORT); - dx = (inb(MSE_DATA_PORT) & 0xf); - outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT); - dx |= (inb(MSE_DATA_PORT) & 0xf) << 4; - outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT ); - dy = (inb(MSE_DATA_PORT) & 0xf); - outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT); - buttons = inb(MSE_DATA_PORT); - dy |= (buttons & 0xf) << 4; - buttons = ((buttons >> 5) & 0x07); - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); - MSE_INT_ON(); -} - -/* - * close access to the mouse - */ -static int close_mouse(struct inode * inode, struct file * file) -{ - MSE_INT_OFF(); - free_irq(mouse_irq, NULL); - return 0; -} - -/* - * open access to the mouse - */ - -static int open_mouse(struct inode * inode, struct file * file) -{ - if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL)) - return -EBUSY; - MSE_INT_ON(); - return 0; -} - -static struct busmouse busmouse = { - LOGITECH_BUSMOUSE, "busmouse", THIS_MODULE, open_mouse, close_mouse, 7 -}; - -static int __init logi_busmouse_init(void) -{ - if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse")) - return -EIO; - - outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT); - outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT); - udelay(100L); /* wait for reply from mouse */ - if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) { - release_region(LOGIBM_BASE, LOGIBM_EXTENT); - return -EIO; - } - - outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT); - MSE_INT_OFF(); - - msedev = register_busmouse(&busmouse); - if (msedev < 0) { - release_region(LOGIBM_BASE, LOGIBM_EXTENT); - printk(KERN_WARNING "Unable to register busmouse driver.\n"); - } - else - printk(KERN_INFO "Logitech busmouse installed.\n"); - - return msedev < 0 ? msedev : 0; -} - -static void __exit logi_busmouse_cleanup (void) -{ - unregister_busmouse(msedev); - release_region(LOGIBM_BASE, LOGIBM_EXTENT); -} - -module_init(logi_busmouse_init); -module_exit(logi_busmouse_cleanup); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/mem.c linux-2.5/drivers/char/mem.c --- linux-2.5.20/drivers/char/mem.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/char/mem.c Sun Apr 14 17:12:08 2002 @@ -199,10 +199,10 @@ vma->vm_flags |= VM_RESERVED; /* - * Don't dump addresses that are not real memory to a core file. + * Dump addresses that are real memory to a core file. */ - if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) - vma->vm_flags |= VM_IO; + if (offset < __pa(high_memory) && !(file->f_flags & O_SYNC)) + vma->vm_flags &= ~VM_IO; if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start, vma->vm_page_prot)) @@ -324,7 +324,7 @@ return virtr + wrote; } -#if !defined(__mc68000__) +#if defined(CONFIG_ISA) || !defined(__mc68000__) static ssize_t read_port(struct file * file, char * buf, size_t count, loff_t *ppos) { @@ -473,6 +473,7 @@ return shmem_zero_setup(vma); if (zeromap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; + vma->vm_flags &= ~VM_IO; return 0; } @@ -557,7 +558,7 @@ write: write_null, }; -#if !defined(__mc68000__) +#if defined(CONFIG_ISA) || !defined(__mc68000__) static struct file_operations port_fops = { llseek: memory_lseek, read: read_port, @@ -591,7 +592,7 @@ case 3: filp->f_op = &null_fops; break; -#if !defined(__mc68000__) +#if defined(CONFIG_ISA) || !defined(__mc68000__) case 4: filp->f_op = &port_fops; break; @@ -628,7 +629,9 @@ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, {3, "null", S_IRUGO | S_IWUGO, &null_fops}, +#if defined(CONFIG_ISA) || !defined(__mc68000__) {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, +#endif {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, {7, "full", S_IRUGO | S_IWUGO, &full_fops}, {8, "random", S_IRUGO | S_IWUSR, &random_fops}, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/misc.c linux-2.5/drivers/char/misc.c --- linux-2.5.20/drivers/char/misc.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/char/misc.c Fri May 3 03:49:06 2002 @@ -48,7 +48,6 @@ #include #include -#include #include #include "busmouse.h" @@ -76,6 +75,7 @@ extern int pmu_device_init(void); extern int tosh_init(void); extern int i8k_init(void); +extern int lcd_init(void); static int misc_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private) @@ -277,6 +277,9 @@ #endif #ifdef CONFIG_TOSHIBA tosh_init(); +#endif +#ifdef CONFIG_COBALT_LCD + lcd_init(); #endif #ifdef CONFIG_I8K i8k_init(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/mk712.c linux-2.5/drivers/char/mk712.c --- linux-2.5.20/drivers/char/mk712.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/mk712.c Sat Apr 13 15:42:55 2002 @@ -0,0 +1,505 @@ +/* -*- c -*- --------------------------------------------------------- * + * + * linux/drivers/char/mk712.c + * + * Copyright 1999-2002 Transmeta Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver supports the MK712 touch screen. + * based on busmouse.c, pc_keyb.c, and other mouse drivers + * + * 1999-12-18: original version, Daniel Quinlan + * 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll + * to use queue_empty, Nathan Laredo + * 1999-12-20: improved random point rejection, Nathan Laredo + * 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed + * queue code, added module options, other fixes, Daniel Quinlan + * 2002-03-15: Clean up for kernel merge + * Fixed multi open race, fixed memory checks, fixed resource + * allocation, fixed close/powerdown bug, switched to new init + * + * ------------------------------------------------------------------------- */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DEBUG(x) x +#define SQUARE(x) ((x)*(x)) + +#define MK712_DEFAULT_IO 0x260 /* demo board: 0x200, 0x208, 0x300 */ +#define MK712_DEFAULT_IRQ 10 /* demo board: 10, 12, 14 or 15 */ + +/* eight 8-bit registers */ +#define MK712_STATUS_LOW 0 /* READ */ +#define MK712_STATUS_HIGH 1 /* READ */ +#define MK712_X_LOW 2 /* READ */ +#define MK712_X_HIGH 3 /* READ */ +#define MK712_Y_LOW 4 /* READ */ +#define MK712_Y_HIGH 5 /* READ */ +#define MK712_CONTROL 6 /* R/W */ +#define MK712_RATE 7 /* R/W */ + +/* status */ +#define MK712_STATUS_TOUCH 0x10 +#define MK712_CONVERSION_COMPLETE 0x80 + +#define MK712_ENABLE_INT 0x01 /* enable interrupts */ +#define MK712_INT_ON_CONVERSION_COMPLETE 0x02 /* if bit 0 = 1 */ +#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS_A 0x04 /* if bit 0 = 1 */ +#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS_B 0x08 /* if bit 0 = 1 */ +#define MK712_ENABLE_PERIODIC_CONVERSIONS 0x10 +#define MK712_READ_ONE_POINT 0x20 +#define MK712_POWERDOWN_A 0x40 +#define MK712_POWERDOWN_B 0x80 + +#define MK712_BUF_SIZE 256 /* a page */ + +struct mk712_packet { + unsigned int header; + unsigned int x; + unsigned int y; + unsigned int reserved; +}; + +struct mk712_queue { + unsigned long head; + unsigned long tail; + wait_queue_head_t proc_list; + struct fasync_struct *fasync; + struct mk712_packet buf[256]; +}; + +#ifdef MODULE +static int io = 0; +static int irq = 0; +#endif +static int mk712_io = MK712_DEFAULT_IO; +static int mk712_irq = MK712_DEFAULT_IRQ; +static int mk712_users = 0; +static spinlock_t mk712_lock = SPIN_LOCK_UNLOCKED; +static struct mk712_queue *queue; /* mouse data buffer */ + +static struct mk712_packet get_from_queue(void) +{ + struct mk712_packet result; + unsigned long flags; + + spin_lock_irqsave(&mk712_lock, flags); + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (MK712_BUF_SIZE-1); + spin_unlock_irqrestore(&mk712_lock, flags); + return result; +} + +static inline int queue_empty(void) +{ + return queue->head == queue->tail; +} + +static int mk712_fasync(int fd, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper(fd, filp, on, &queue->fasync); + if (retval < 0) + return retval; + return 0; +} + +static void mk712_output_packet(struct mk712_packet data) +{ + int head = queue->head; + + queue->buf[head] = data; + head = (head + 1) & (MK712_BUF_SIZE-1); + if (head != queue->tail) { + queue->head = head; + kill_fasync(&queue->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&queue->proc_list); + } +} + +static int points = 0; /* number of stored points */ +static int output_point = 0; /* did I output a point since last release? */ + +static void mk712_output_point(int x, int y) +{ + struct mk712_packet t; + + t.header = 0; + t.x = x; + t.y = y; + t.reserved = 0; + + mk712_output_packet(t); + output_point = 1; +} + +static void mk712_store_point(int x_new, int y_new) +{ + static int x[3], y[3]; + int x_out, y_out; + + x[points] = x_new; + y[points] = y_new; + + if (points == 1 && abs(x[0] - x[1]) < 88 && abs(y[0] - y[1]) < 88) + { + x_out = (x[0] + x[1]) >> 1; + y_out = (y[0] + y[1]) >> 1; + mk712_output_point(x_out, y_out); + } + + if (points == 2) { + if ((abs(x[1] - x[2]) < 88 && abs(y[1] - y[2]) < 88) && + (abs(x[0] - x[1]) < 88 && abs(y[0] - y[1]) < 88)) + { + x_out = (x[0] + x[1] + x[2]) / 3; + y_out = (y[0] + y[1] + y[2]) / 3; + mk712_output_point(x_out, y_out); + } + else if (abs(x[1] - x[2]) < 88 && abs(y[1] - y[2]) < 88) + { + x_out = (x[1] + x[2]) >> 1; + y_out = (y[1] + y[2]) >> 1; + mk712_output_point(x_out, y_out); + } + else + { + int x_avg, y_avg, d0, d1, d2; + + x_avg = (x[0] + x[1] + x[2]) / 3; + y_avg = (y[0] + y[1] + y[2]) / 3; + + d0 = SQUARE(x[0] - x_avg) + SQUARE(y[0] - y_avg); + d1 = SQUARE(x[1] - x_avg) + SQUARE(y[1] - y_avg); + d2 = SQUARE(x[2] - x_avg) + SQUARE(y[2] - y_avg); + + if (d2 > d1 && d2 > d0) + { + x_out = (x[0] + x[1]) >> 1; + y_out = (y[0] + y[1]) >> 1; + } + if (d1 > d0 && d1 > d2) + { + x_out = (x[0] + x[2]) >> 1; + y_out = (y[0] + y[2]) >> 1; + } + else + { + x_out = (x[1] + x[2]) >> 1; + y_out = (y[1] + y[2]) >> 1; + } + + mk712_output_point(x_out, y_out); + + x[0] = x[1]; + x[1] = x[2]; + y[0] = y[1]; + y[1] = y[2]; + } + } + else + { + points++; + } +} + +static void mk712_release_event(void) +{ + struct mk712_packet t; + + if (!output_point) { + points = 0; + return; + } + output_point = 0; + + t.header = 1; + t.x = t.y = t.reserved = 0; + + mk712_output_packet(t); + points = 0; +} + +#define MK712_FILTER +static void mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned short x; + unsigned short y; + unsigned char status; + unsigned long flags; +#ifdef MK712_FILTER + static int drop_next = 1; +#endif + + spin_lock_irqsave(&mk712_lock, flags); + + status = inb(mk712_io + MK712_STATUS_LOW); + + if (!(status & MK712_CONVERSION_COMPLETE)) { +#ifdef MK712_FILTER + drop_next = 1; +#endif + return; + } + if (!(status & MK712_STATUS_TOUCH)) /* release event */ + { +#ifdef MK712_FILTER + drop_next = 1; +#endif + mk712_release_event(); + + spin_unlock_irqrestore(&mk712_lock, flags); + wake_up_interruptible(&queue->proc_list); + + return; + } + + x = inw(mk712_io + MK712_X_LOW) & 0x0fff; + y = inw(mk712_io + MK712_Y_LOW) & 0x0fff; + +#ifdef MK712_FILTER + if (drop_next) + { + drop_next = 0; + + spin_unlock_irqrestore(&mk712_lock, flags); + wake_up_interruptible(&queue->proc_list); + + return; + } +#endif + + x = inw(mk712_io + MK712_X_LOW) & 0x0fff; + y = inw(mk712_io + MK712_Y_LOW) & 0x0fff; + + mk712_store_point(x, y); + + spin_unlock_irqrestore(&mk712_lock, flags); + wake_up_interruptible(&queue->proc_list); +} + +static int mk712_open(struct inode *inode, struct file *file) +{ + unsigned char control; + unsigned long flags; + + control = 0; + + spin_lock_irqsave(&mk712_lock, flags); + if(!mk712_users++) + { + outb(0, mk712_io + MK712_CONTROL); + + control |= (MK712_ENABLE_INT | + MK712_INT_ON_CONVERSION_COMPLETE | + MK712_INT_ON_CHANGE_IN_TOUCH_STATUS_B | + MK712_ENABLE_PERIODIC_CONVERSIONS | + MK712_POWERDOWN_A); + outb(control, mk712_io + MK712_CONTROL); + + outb(10, mk712_io + MK712_RATE); /* default count = 10 */ + + queue->head = queue->tail = 0; /* Flush input queue */ + } + spin_unlock_irqrestore(&mk712_lock, flags); + return 0; +} + +static int mk712_close(struct inode * inode, struct file * file) { + /* power down controller */ + unsigned long flags; + spin_lock_irqsave(&mk712_lock, flags); + if(--mk712_users==0) + outb(0, mk712_io + MK712_CONTROL); + spin_unlock_irqrestore(&mk712_lock, flags); + return 0; +} + +static unsigned int mk712_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &queue->proc_list, wait); + if(!queue_empty()) + return POLLIN | POLLRDNORM; + return 0; +} + +static int mk712_ioctl(struct inode *inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + if (!inode) + BUG(); + return -ENOTTY; +} + + +static ssize_t mk712_read(struct file *file, char *buffer, + size_t count, loff_t *pos) +{ + DECLARE_WAITQUEUE(wait, current); + ssize_t bytes_read = 0; + struct mk712_packet p; + + /* wait for an event */ + if (queue_empty()) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&queue->proc_list, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&queue->proc_list, &wait); + } + + while (bytes_read < count && !queue_empty()) { + p = get_from_queue(); + if (copy_to_user (buffer+bytes_read, (void *) &p, sizeof(p))) + { + bytes_read = -EFAULT; + break; + } + bytes_read += sizeof(p); + } + + if (bytes_read > 0) + { + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + return bytes_read; + } + + if (signal_pending(current)) + return -ERESTARTSYS; + + return bytes_read; +} + +static ssize_t mk712_write(struct file *file, const char *buffer, size_t count, + loff_t *ppos) +{ + return -EINVAL; +} + +struct file_operations mk712_fops = { + owner: THIS_MODULE, + read: mk712_read, + write: mk712_write, + poll: mk712_poll, + ioctl: mk712_ioctl, + open: mk712_open, + release: mk712_close, + fasync: mk712_fasync, +}; + +static struct miscdevice mk712_touchscreen = { + MK712_MINOR, "mk712_touchscreen", &mk712_fops +}; + +int __init mk712_init(void) +{ +#ifdef MODULE + if (io) + mk712_io = io; + if (irq) + mk712_irq = irq; +#endif + + if(request_region(mk712_io, 8, "mk712_touchscreen")) + { + printk("mk712: unable to get IO region\n"); + return -ENODEV; + } + + /* set up wait queue */ + queue = (struct mk712_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if(queue == NULL) + { + release_region(mk712_io, 8); + return -ENOMEM; + } + memset(queue, 0, sizeof(*queue)); + queue->head = queue->tail = 0; + init_waitqueue_head(&queue->proc_list); + + /* The MK712 is ISA and hard-coded to a particular IRQ, so the + driver should keep the IRQ as long as it is loaded. */ + if(request_irq(mk712_irq, mk712_interrupt, 0, "mk712_touchscreen", + queue)) + { + printk("mk712: unable to get IRQ\n"); + release_region(mk712_io, 8); + kfree(queue); + return -EBUSY; + } + + /* register misc device */ + if(misc_register(&mk712_touchscreen)<0) + { + release_region(mk712_io, 8); + kfree(queue); + free_irq(mk712_irq, queue); + return -ENODEV; + } + return 0; +} + +static void __exit mk712_exit(void) +{ + misc_deregister(&mk712_touchscreen); + release_region(mk712_io, 8); + free_irq(mk712_irq, queue); + kfree(queue); + printk(KERN_INFO "mk712 touchscreen uninstalled\n"); +} + +MODULE_AUTHOR("Daniel Quinlan"); +MODULE_DESCRIPTION("MK712 touch screen driver"); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O base address of MK712 touch screen controller"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "IRQ of MK712 touch screen controller"); +MODULE_LICENSE("GPL"); + +module_init(mk712_init); +module_exit(mk712_exit); + +/* + * Local variables: + * c-file-style: "linux" + * End: + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/msbusmouse.c linux-2.5/drivers/char/msbusmouse.c --- linux-2.5.20/drivers/char/msbusmouse.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/char/msbusmouse.c Thu Jan 1 01:00:00 1970 @@ -1,175 +0,0 @@ -/* - * Microsoft busmouse driver based on Logitech driver (see busmouse.c) - * - * Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92) - * - * Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net) - * 8/28/92 - * - * Microsoft Bus Mouse support folded into 0.97pl4 code - * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) - * Changes: Logitech and Microsoft support in the same kernel. - * Defined new constants in busmouse.h for MS mice. - * Added int mse_busmouse_type to distinguish busmouse types - * Added a couple of new functions to handle differences in using - * MS vs. Logitech (where the int variable wasn't appropriate). - * - * Modified by Peter Cervasio (address above) (26SEP92) - * Changes: Included code to (properly?) detect when a Microsoft mouse is - * really attached to the machine. Don't know what this does to - * Logitech bus mice, but all it does is read ports. - * - * Modified by Christoph Niemann (niemann@rubdv15.etdv.ruhr-uni-bochum.de) - * Changes: Better interrupt-handler (like in busmouse.c). - * Some changes to reduce code-size. - * Changed detection code to use inb_p() instead of doing empty - * loops to delay i/o. - * - * Modularised 8-Sep-95 Philip Blundell - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - * - * version 0.3b - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "busmouse.h" - -static int msedev; -static int mouse_irq = MOUSE_IRQ; - -MODULE_PARM(mouse_irq, "i"); - -#ifndef MODULE - -static int __init msmouse_setup(char *str) -{ - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - mouse_irq=ints[1]; - - return 1; -} - -__setup("msmouse=",msmouse_setup); - -#endif /* !MODULE */ - -static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - char dx, dy; - unsigned char buttons; - - outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); - outb((inb(MS_MSE_DATA_PORT) | 0x20), MS_MSE_DATA_PORT); - - outb(MS_MSE_READ_X, MS_MSE_CONTROL_PORT); - dx = inb(MS_MSE_DATA_PORT); - - outb(MS_MSE_READ_Y, MS_MSE_CONTROL_PORT); - dy = inb(MS_MSE_DATA_PORT); - - outb(MS_MSE_READ_BUTTONS, MS_MSE_CONTROL_PORT); - buttons = ~(inb(MS_MSE_DATA_PORT)) & 0x07; - - outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); - outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT); - - /* why did the original have: - * if (dx != 0 || dy != 0 || buttons != mouse.buttons || - * ((~buttons) & 0x07)) - * ^^^^^^^^^^^^^^^^^^^ this? - */ - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); -} - -static int release_mouse(struct inode * inode, struct file * file) -{ - MS_MSE_INT_OFF(); - free_irq(mouse_irq, NULL); - return 0; -} - -static int open_mouse(struct inode * inode, struct file * file) -{ - if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL)) - return -EBUSY; - - outb(MS_MSE_START, MS_MSE_CONTROL_PORT); - MS_MSE_INT_ON(); - return 0; -} - -static struct busmouse msbusmouse = { - MICROSOFT_BUSMOUSE, "msbusmouse", THIS_MODULE, open_mouse, release_mouse, 0 -}; - -static int __init ms_bus_mouse_init(void) -{ - int present = 0; - int mse_byte, i; - - if (check_region(MS_MSE_CONTROL_PORT, 0x04)) - return -ENODEV; - - if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) { - - mse_byte = inb_p(MS_MSE_SIGNATURE_PORT); - - for (i = 0; i < 4; i++) { - if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) { - if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte) - present = 1; - else - present = 0; - } else - present = 0; - } - } - if (present == 0) - return -EIO; - if (!request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse")) - return -EIO; - - MS_MSE_INT_OFF(); - msedev = register_busmouse(&msbusmouse); - if (msedev < 0) { - printk(KERN_WARNING "Unable to register msbusmouse driver.\n"); - release_region(MS_MSE_CONTROL_PORT, 0x04); - } - else - printk(KERN_INFO "Microsoft BusMouse detected and installed.\n"); - return msedev < 0 ? msedev : 0; -} - -static void __exit ms_bus_mouse_exit(void) -{ - unregister_busmouse(msedev); - release_region(MS_MSE_CONTROL_PORT, 0x04); -} - -module_init(ms_bus_mouse_init) -module_exit(ms_bus_mouse_exit) - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/nvram.c linux-2.5/drivers/char/nvram.c --- linux-2.5.20/drivers/char/nvram.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/char/nvram.c Sat May 25 19:52:01 2002 @@ -214,7 +214,7 @@ * The are the file operation function for user access to /dev/nvram */ -static long long nvram_llseek(struct file *file,loff_t offset, int origin ) +static loff_t nvram_llseek(struct file *file,loff_t offset, int origin ) { lock_kernel(); switch( origin ) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/nwflash.c linux-2.5/drivers/char/nwflash.c --- linux-2.5.20/drivers/char/nwflash.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/char/nwflash.c Sat May 25 19:52:01 2002 @@ -47,7 +47,7 @@ static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg); static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos); static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos); -static long long flash_llseek(struct file *file, long long offset, int orig); +static loff_t flash_llseek(struct file *file, loff_t offset, int orig); #define KFLASH_SIZE 1024*1024 //1 Meg #define KFLASH_SIZE4 4*1024*1024 //4 Meg @@ -301,9 +301,9 @@ * also note that seeking relative to the "end of file" isn't supported: * it has no meaning, so it returns -EINVAL. */ -static long long flash_llseek(struct file *file, long long offset, int orig) +static loff_t flash_llseek(struct file *file, loff_t offset, int orig) { - long long ret; + loff_t ret; lock_kernel(); if (flashdebug) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/pc110pad.c linux-2.5/drivers/char/pc110pad.c --- linux-2.5.20/drivers/char/pc110pad.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/char/pc110pad.c Thu Jan 1 01:00:00 1970 @@ -1,851 +0,0 @@ -/* - * Linux driver for the PC110 pad - */ - -/** - * DOC: PC110 Digitizer Hardware - * - * The pad provides triples of data. The first byte has - * 0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down - * The second byte is bits 0-6 X - * The third is bits 0-6 Y - * - * This is read internally and used to synthesize a stream of - * triples in the form expected from a PS/2 device. Specialist - * applications can choose to obtain the pad data in other formats - * including a debugging mode. - * - * It would be good to add a joystick driver mode to this pad so - * that doom and other game playing are better. One possible approach - * would be to deactive the mouse mode while the joystick port is opened. - */ - -/* - * History - * - * 0.0 1997-05-16 Alan Cox - Pad reader - * 0.1 1997-05-19 Robin O'Leary - PS/2 emulation - * 0.2 1997-06-03 Robin O'Leary - tap gesture - * 0.3 1997-06-27 Alan Cox - 2.1 commit - * 0.4 1997-11-09 Alan Cox - Single Unix VFS API changes - * 0.5 2000-02-10 Alan Cox - 2.3.x cleanup, documentation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "pc110pad.h" - - -static struct pc110pad_params default_params = { - mode: PC110PAD_PS2, - bounce_interval: 50 MS, - tap_interval: 200 MS, - irq: 10, - io: 0x15E0, -}; - -static struct pc110pad_params current_params; - - -/* driver/filesystem interface management */ -static wait_queue_head_t queue; -static struct fasync_struct *asyncptr; -static int active_count = 0; /* number of concurrent open()s */ -static spinlock_t pc110_lock = SPIN_LOCK_UNLOCKED; -/* this lock should be held when referencing active_count */ -static struct semaphore reader_lock; - -/** - * wake_readers: - * - * Take care of letting any waiting processes know that - * now would be a good time to do a read(). Called - * whenever a state transition occurs, real or synthetic. Also - * issue any SIGIO's to programs that use SIGIO on mice (eg - * Executor) - */ - -static void wake_readers(void) -{ - wake_up_interruptible(&queue); - kill_fasync(&asyncptr, SIGIO, POLL_IN); -} - - -/*****************************************************************************/ -/* - * Deal with the messy business of synthesizing button tap and drag - * events. - * - * Exports: - * notify_pad_up_down() - * Must be called whenever debounced pad up/down state changes. - * button_pending - * Flag is set whenever read_button() has new values - * to return. - * read_button() - * Obtains the current synthetic mouse button state. - */ - -/* - * These keep track of up/down transitions needed to generate the - * synthetic mouse button events. While recent_transition is set, - * up/down events cause transition_count to increment. tap_timer - * turns off the recent_transition flag and may cause some synthetic - * up/down mouse events to be created by incrementing synthesize_tap. - */ - -static int button_pending; -static int recent_transition; -static int transition_count; -static int synthesize_tap; -static void tap_timeout(unsigned long data); -static struct timer_list tap_timer = { function: tap_timeout }; - - -/** - * tap_timeout: - * @data: Unused - * - * This callback goes off a short time after an up/down transition; - * before it goes off, transitions will be considered part of a - * single PS/2 event and counted in transition_count. Once the - * timeout occurs the recent_transition flag is cleared and - * any synthetic mouse up/down events are generated. - */ - -static void tap_timeout(unsigned long data) -{ - if(!recent_transition) - { - printk(KERN_ERR "pc110pad: tap_timeout but no recent transition!\n"); - } - if( transition_count==2 || transition_count==4 || transition_count==6 ) - { - synthesize_tap+=transition_count; - button_pending = 1; - wake_readers(); - } - recent_transition=0; -} - - -/** - * notify_pad_up_down: - * - * Called by the raw pad read routines when a (debounced) up/down - * transition is detected. - */ - -void notify_pad_up_down(void) -{ - if(recent_transition) - { - transition_count++; - } - else - { - transition_count=1; - recent_transition=1; - } - mod_timer(&tap_timer, jiffies + current_params.tap_interval); - - /* changes to transition_count can cause reported button to change */ - button_pending = 1; - wake_readers(); -} - -/** - * read_button: - * @b: pointer to the button status. - * - * The actual button state depends on what we are seeing. We have to check - * for the tap gesture and also for dragging. - */ - -static void read_button(int *b) -{ - if(synthesize_tap) - { - *b=--synthesize_tap & 1; - } - else - { - *b=(!recent_transition && transition_count==3); /* drag */ - } - button_pending=(synthesize_tap>0); -} - - -/*****************************************************************************/ -/* - * Read pad absolute co-ordinates and debounced up/down state. - * - * Exports: - * pad_irq() - * Function to be called whenever the pad signals - * that it has new data available. - * read_raw_pad() - * Returns the most current pad state. - * xy_pending - * Flag is set whenever read_raw_pad() has new values - * to return. - * Imports: - * wake_readers() - * Called when movement occurs. - * notify_pad_up_down() - * Called when debounced up/down status changes. - */ - -/* - * These are up/down state and absolute co-ords read directly from pad - */ - -static int raw_data[3]; -static int raw_data_count; -static int raw_x, raw_y; /* most recent absolute co-ords read */ -static int raw_down; /* raw up/down state */ -static int debounced_down; /* up/down state after debounce processing */ -static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE; - /* set just after an up/down transition */ -static int xy_pending; /* set if new data have not yet been read */ - -/* - * Timer goes off a short while after an up/down transition and copies - * the value of raw_down to debounced_down. - */ - -static void bounce_timeout(unsigned long data); -static struct timer_list bounce_timer = { function: bounce_timeout }; - - - -/** - * bounce_timeout: - * @data: Unused - * - * No further up/down transitions happened within the - * bounce period, so treat this as a genuine transition. - */ - -static void bounce_timeout(unsigned long data) -{ - switch(bounce) - { - case NO_BOUNCE: - { - /* - * Strange; the timer callback should only go off if - * we were expecting to do bounce processing! - */ - printk(KERN_WARNING "pc110pad, bounce_timeout: bounce flag not set!\n"); - break; - } - case JUST_GONE_UP: - { - /* - * The last up we spotted really was an up, so set - * debounced state the same as raw state. - */ - bounce=NO_BOUNCE; - if(debounced_down==raw_down) - { - printk(KERN_WARNING "pc110pad, bounce_timeout: raw already debounced!\n"); - } - debounced_down=raw_down; - - notify_pad_up_down(); - break; - } - case JUST_GONE_DOWN: - { - /* - * We don't debounce down events, but we still time - * out soon after one occurs so we can avoid the (x,y) - * skittering that sometimes happens. - */ - bounce=NO_BOUNCE; - break; - } - } -} - - -/** - * pad_irq: - * @irq: Interrupt number - * @ptr: Unused - * @regs: Unused - * - * Callback when pad's irq goes off; copies values in to raw_* globals; - * initiates debounce processing. This isn't SMP safe however there are - * no SMP machines with a PC110 touchpad on them. - */ - -static void pad_irq(int irq, void *ptr, struct pt_regs *regs) -{ - - /* Obtain byte from pad and prime for next byte */ - { - int value=inb_p(current_params.io); - int handshake=inb_p(current_params.io+2); - outb_p(handshake | 1, current_params.io+2); - outb_p(handshake &~1, current_params.io+2); - inb_p(0x64); - - raw_data[raw_data_count++]=value; - } - - if(raw_data_count==3) - { - int new_down=raw_data[0]&0x01; - int new_x=raw_data[1]; - int new_y=raw_data[2]; - if(raw_data[0]&0x10) new_x+=128; - if(raw_data[0]&0x80) new_x+=256; - if(raw_data[0]&0x08) new_y+=128; - - if( (raw_x!=new_x) || (raw_y!=new_y) ) - { - raw_x=new_x; - raw_y=new_y; - xy_pending=1; - } - - if(new_down != raw_down) - { - /* Down state has changed. raw_down always holds - * the most recently observed state. - */ - raw_down=new_down; - - /* Forget any earlier bounce processing */ - if(bounce) - { - del_timer(&bounce_timer); - bounce=NO_BOUNCE; - } - - if(new_down) - { - if(debounced_down) - { - /* pad gone down, but we were reporting - * it down anyway because we suspected - * (correctly) that the last up was just - * a bounce - */ - } - else - { - bounce=JUST_GONE_DOWN; - mod_timer(&bounce_timer, - jiffies+current_params.bounce_interval); - /* start new stroke/tap */ - debounced_down=new_down; - notify_pad_up_down(); - } - } - else /* just gone up */ - { - if(recent_transition) - { - /* early bounces are probably part of - * a multi-tap gesture, so process - * immediately - */ - debounced_down=new_down; - notify_pad_up_down(); - } - else - { - /* don't trust it yet */ - bounce=JUST_GONE_UP; - mod_timer(&bounce_timer, - jiffies+current_params.bounce_interval); - } - } - } - wake_readers(); - raw_data_count=0; - } -} - -/** - * read_raw_pad: - * @down: set if the pen is down - * @debounced: set if the debounced pen position is down - * @x: X position - * @y: Y position - * - * Retrieve the data saved by the interrupt handler and indicate we - * have no more pending XY to do. - * - * FIXME: We should switch to a spinlock for this. - */ - -static void read_raw_pad(int *down, int *debounced, int *x, int *y) -{ - disable_irq(current_params.irq); - { - *down=raw_down; - *debounced=debounced_down; - *x=raw_x; - *y=raw_y; - xy_pending = 0; - } - enable_irq(current_params.irq); -} - -/*****************************************************************************/ -/* - * Filesystem interface - */ - -/* - * Read returns byte triples, so we need to keep track of - * how much of a triple has been read. This is shared across - * all processes which have this device open---not that anything - * will make much sense in that case. - */ -static int read_bytes[3]; -static int read_byte_count; - -/** - * sample_raw: - * @d: sample buffer - * - * Retrieve a triple of sample data. - */ - - -static void sample_raw(int d[3]) -{ - d[0]=raw_data[0]; - d[1]=raw_data[1]; - d[2]=raw_data[2]; -} - -/** - * sample_rare: - * @d: sample buffer - * - * Retrieve a triple of sample data and sanitize it. We do the needed - * scaling and masking to get the current status. - */ - - -static void sample_rare(int d[3]) -{ - int thisd, thisdd, thisx, thisy; - - read_raw_pad(&thisd, &thisdd, &thisx, &thisy); - - d[0]=(thisd?0x80:0) - | (thisx/256)<<4 - | (thisdd?0x08:0) - | (thisy/256) - ; - d[1]=thisx%256; - d[2]=thisy%256; -} - -/** - * sample_debug: - * @d: sample buffer - * - * Retrieve a triple of sample data and mix it up with the state - * information in the gesture parser. Not useful for normal users but - * handy when debugging - */ - -static void sample_debug(int d[3]) -{ - int thisd, thisdd, thisx, thisy; - int b; - unsigned long flags; - - spin_lock_irqsave(&pc110_lock, flags); - read_raw_pad(&thisd, &thisdd, &thisx, &thisy); - d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce; - d[1]=(recent_transition?0x80:0)+transition_count; - read_button(&b); - d[2]=(synthesize_tap<<4) | (b?0x01:0); - spin_unlock_irqrestore(&pc110_lock, flags); -} - -/** - * sample_ps2: - * @d: sample buffer - * - * Retrieve a triple of sample data and turn the debounced tap and - * stroke information into what appears to be a PS/2 mouse. This means - * the PC110 pad needs no funny application side support. - */ - - -static void sample_ps2(int d[3]) -{ - static int lastx, lasty, lastd; - - int thisd, thisdd, thisx, thisy; - int dx, dy, b; - - /* - * Obtain the current mouse parameters and limit as appropriate for - * the return data format. Interrupts are only disabled while - * obtaining the parameters, NOT during the puts_fs_byte() calls, - * so paging in put_user() does not affect mouse tracking. - */ - read_raw_pad(&thisd, &thisdd, &thisx, &thisy); - read_button(&b); - - /* Now compare with previous readings. Note that we use the - * raw down flag rather than the debounced one. - */ - if( (thisd && !lastd) /* new stroke */ - || (bounce!=NO_BOUNCE) ) - { - dx=0; - dy=0; - } - else - { - dx = (thisx-lastx); - dy = -(thisy-lasty); - } - lastx=thisx; - lasty=thisy; - lastd=thisd; - -/* - d[0]= ((dy<0)?0x20:0) - | ((dx<0)?0x10:0) - | 0x08 - | (b? 0x01:0x00) - ; -*/ - d[0]= ((dy<0)?0x20:0) - | ((dx<0)?0x10:0) - | (b? 0x00:0x08) - ; - d[1]=dx; - d[2]=dy; -} - - -/** - * fasync_pad: - * @fd: file number for the file - * @filp: file handle - * @on: 1 to add, 0 to remove a notifier - * - * Update the queue of asynchronous event notifiers. We can use the - * same helper the mice do and that does almost everything we need. - */ - -static int fasync_pad(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &asyncptr); - if (retval < 0) - return retval; - return 0; -} - - -/** - * close_pad: - * @inode: inode of pad - * @file: file handle to pad - * - * Close access to the pad. We turn the pad power off if this is the - * last user of the pad. I've not actually measured the power draw but - * the DOS driver is careful to do this so we follow suit. - */ - -static int close_pad(struct inode * inode, struct file * file) -{ - unsigned long flags; - fasync_pad(-1, file, 0); - spin_lock_irqsave(&pc110_lock, flags); - if (!--active_count) - outb(0x30, current_params.io+2); /* switch off digitiser */ - spin_unlock_irqrestore(&pc110_lock, flags); - return 0; -} - - -/** - * open_pad: - * @inode: inode of pad - * @file: file handle to pad - * - * Open access to the pad. We turn the pad off first (we turned it off - * on close but if this is the first open after a crash the state is - * indeterminate). The device has a small fifo so we empty that before - * we kick it back into action. - */ - -static int open_pad(struct inode * inode, struct file * file) -{ - unsigned long flags; - - spin_lock_irqsave(&pc110_lock, flags); - if (active_count++) - { - spin_unlock_irqrestore(&pc110_lock, flags); - return 0; - } - - outb(0x30, current_params.io+2); /* switch off digitiser */ - pad_irq(0,0,0); /* read to flush any pending bytes */ - pad_irq(0,0,0); /* read to flush any pending bytes */ - pad_irq(0,0,0); /* read to flush any pending bytes */ - outb(0x38, current_params.io+2); /* switch on digitiser */ - current_params = default_params; - raw_data_count=0; /* re-sync input byte counter */ - read_byte_count=0; /* re-sync output byte counter */ - button_pending=0; - recent_transition=0; - transition_count=0; - synthesize_tap=0; - del_timer(&bounce_timer); - del_timer(&tap_timer); - spin_unlock_irqrestore(&pc110_lock, flags); - - return 0; -} - - -/** - * write_pad: - * @file: File handle to the pad - * @buffer: Unused - * @count: Unused - * @ppos: Unused - * - * Writes are disallowed. A true PS/2 mouse lets you write stuff. Everyone - * seems happy with this and not faking the write modes. - */ - -static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - - -/* - * new_sample: - * @d: sample buffer - * - * Fetch a new sample according the current mouse mode the pad is - * using. - */ - -void new_sample(int d[3]) -{ - switch(current_params.mode) - { - case PC110PAD_RAW: sample_raw(d); break; - case PC110PAD_RARE: sample_rare(d); break; - case PC110PAD_DEBUG: sample_debug(d); break; - case PC110PAD_PS2: sample_ps2(d); break; - } -} - - -/** - * read_pad: - * @file: File handle to pad - * @buffer: Target for the mouse data - * @count: Buffer length - * @ppos: Offset (unused) - * - * Read data from the pad. We use the reader_lock to avoid mess when there are - * two readers. This shouldnt be happening anyway but we play safe. - */ - -static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos) -{ - int r; - - down(&reader_lock); - for(r=0; rPC110PAD_PS2) - || (new.bounce_interval<0) - || (new.tap_interval<0) - ) - return -EINVAL; - - current_params.mode = new.mode; - current_params.bounce_interval = new.bounce_interval; - current_params.tap_interval = new.tap_interval; - return 0; - } - return -ENOTTY; -} - - -static struct file_operations pad_fops = { - owner: THIS_MODULE, - read: read_pad, - write: write_pad, - poll: pad_poll, - ioctl: pad_ioctl, - open: open_pad, - release: close_pad, - fasync: fasync_pad, -}; - - -static struct miscdevice pc110_pad = { - minor: PC110PAD_MINOR, - name: "pc110 pad", - fops: &pad_fops, -}; - - -/** - * pc110pad_init_driver: - * - * We configure the pad with the default parameters (that is PS/2 - * emulation mode. We then claim the needed I/O and interrupt resources. - * Finally as a matter of paranoia we turn the pad off until we are - * asked to open it by an application. - */ - -static char banner[] __initdata = KERN_INFO "PC110 digitizer pad at 0x%X, irq %d.\n"; - -static int __init pc110pad_init_driver(void) -{ - init_MUTEX(&reader_lock); - current_params = default_params; - - if (request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0)) { - printk(KERN_ERR "pc110pad: Unable to get IRQ.\n"); - return -EBUSY; - } - if (!request_region(current_params.io, 4, "pc110pad")) { - printk(KERN_ERR "pc110pad: I/O area in use.\n"); - free_irq(current_params.irq,0); - return -EBUSY; - } - init_waitqueue_head(&queue); - printk(banner, current_params.io, current_params.irq); - misc_register(&pc110_pad); - outb(0x30, current_params.io+2); /* switch off digitiser */ - return 0; -} - -/* - * pc110pad_exit_driver: - * - * Free the resources we acquired when the module was loaded. We also - * turn the pad off to be sure we don't leave it using power. - */ - -static void __exit pc110pad_exit_driver(void) -{ - outb(0x30, current_params.io+2); /* switch off digitiser */ - if (current_params.irq) - free_irq(current_params.irq, 0); - current_params.irq = 0; - release_region(current_params.io, 4); - misc_deregister(&pc110_pad); -} - -module_init(pc110pad_init_driver); -module_exit(pc110pad_exit_driver); - -MODULE_AUTHOR("Alan Cox, Robin O'Leary"); -MODULE_DESCRIPTION("Driver for the touchpad on the IBM PC110 palmtop"); -MODULE_LICENSE("GPL"); - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/pc110pad.h linux-2.5/drivers/char/pc110pad.h --- linux-2.5.20/drivers/char/pc110pad.h Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/char/pc110pad.h Thu Jan 1 01:00:00 1970 @@ -1,31 +0,0 @@ -#ifndef _PC110PAD_H -#define _PC110PAD_H - -#include - -enum pc110pad_mode { - PC110PAD_RAW, /* bytes as they come out of the hardware */ - PC110PAD_RARE, /* debounced up/down and absolute x,y */ - PC110PAD_DEBUG, /* up/down, debounced, transitions, button */ - PC110PAD_PS2, /* ps2 relative (default) */ -}; - - -struct pc110pad_params { - enum pc110pad_mode mode; - int bounce_interval; - int tap_interval; - int irq; - int io; -}; - -#define MS *HZ/1000 - -/* Appears as device major=10 (MISC), minor=PC110_PAD */ - -#define PC110PAD_IOCTL_TYPE 0x9a - -#define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params) -#define PC110PADIOCSETP _IOW(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params) - -#endif /* _PC110PAD_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/pc_keyb.c linux-2.5/drivers/char/pc_keyb.c --- linux-2.5.20/drivers/char/pc_keyb.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/char/pc_keyb.c Sun Jan 20 17:11:45 2002 @@ -61,79 +61,6 @@ "\r\000/"; /* 0x60 - 0x6f */ #endif -static void kbd_write_command_w(int data); -static void kbd_write_output_w(int data); -#ifdef CONFIG_PSMOUSE -static void aux_write_ack(int val); -static void __aux_write_ack(int val); -static int aux_reconnect = 0; -#endif - -static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; -static unsigned char handle_kbd_event(void); - -/* used only by send_data - set by keyboard_interrupt */ -static volatile unsigned char reply_expected; -static volatile unsigned char acknowledge; -static volatile unsigned char resend; - - -#if defined CONFIG_PSMOUSE -/* - * PS/2 Auxiliary Device - */ - -static int __init psaux_init(void); - -#define AUX_RECONNECT1 0xaa /* scancode1 when ps2 device is plugged (back) in */ -#define AUX_RECONNECT2 0x00 /* scancode2 when ps2 device is plugged (back) in */ - -static struct aux_queue *queue; /* Mouse data buffer. */ -static int aux_count; -static spinlock_t aux_count_lock = SPIN_LOCK_UNLOCKED; -/* used when we send commands to the mouse that expect an ACK. */ -static unsigned char mouse_reply_expected; - -#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) -#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) - -#define MAX_RETRIES 60 /* some aux operations take long time*/ -#endif /* CONFIG_PSMOUSE */ - -/* - * Wait for keyboard controller input buffer to drain. - * - * Don't use 'jiffies' so that we don't depend on - * interrupts.. - * - * Quote from PS/2 System Reference Manual: - * - * "Address hex 0060 and address hex 0064 should be written only when - * the input-buffer-full bit and output-buffer-full bit in the - * Controller Status register are set 0." - */ - -static void kb_wait(void) -{ - unsigned long timeout = KBC_TIMEOUT; - - do { - /* - * "handle_kbd_event()" will handle any incoming events - * while we wait - keypresses or mouse movement. - */ - unsigned char status = handle_kbd_event(); - - if (! (status & KBD_STAT_IBF)) - return; - mdelay(1); - timeout--; - } while (timeout); -#ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "Keyboard timed out[1]\n"); -#endif -} - /* * Translation of escaped scancodes to keycodes. * This is now user-settable. @@ -268,32 +195,6 @@ e0_keys[scancode - 128]; } -static int do_acknowledge(unsigned char scancode) -{ - if (reply_expected) { - /* Unfortunately, we must recognise these codes only if we know they - * are known to be valid (i.e., after sending a command), because there - * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have - * keys with such codes :( - */ - if (scancode == KBD_REPLY_ACK) { - acknowledge = 1; - reply_expected = 0; - return 0; - } else if (scancode == KBD_REPLY_RESEND) { - resend = 1; - reply_expected = 0; - return 0; - } - /* Should not happen... */ -#if 0 - printk(KERN_DEBUG "keyboard reply expected - got %02x\n", - scancode); -#endif - } - return 1; -} - int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode) { @@ -401,848 +302,8 @@ int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data) { -#if defined CONFIG_PSMOUSE - unsigned long flags; - - if (rqst == PM_RESUME) { - if (queue) { /* Aux port detected */ - spin_lock_irqsave(&aux_count_lock, flags); - if ( aux_count == 0) { /* Mouse not in use */ - spin_lock(&kbd_controller_lock); - /* - * Dell Lat. C600 A06 enables mouse after resume. - * When user touches the pad, it posts IRQ 12 - * (which we do not process), thus holding keyboard. - */ - kbd_write_command(KBD_CCMD_MOUSE_DISABLE); - /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MODE); - kb_wait(); - kbd_write_output(AUX_INTS_OFF); - spin_unlock(&kbd_controller_lock); - } - spin_unlock_irqrestore(&aux_count_lock, flags); - } - } -#endif return 0; } - -static inline void handle_mouse_event(unsigned char scancode) -{ -#ifdef CONFIG_PSMOUSE - unsigned long flags; - static unsigned char prev_code; - if (mouse_reply_expected) { - if (scancode == AUX_ACK) { - mouse_reply_expected--; - return; - } - mouse_reply_expected = 0; - } - else if(scancode == AUX_RECONNECT2 && prev_code == AUX_RECONNECT1 - && aux_reconnect) { - printk (KERN_INFO "PS/2 mouse reconnect detected\n"); - queue->head = queue->tail = 0; /* Flush input queue */ - __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ - return; - } - - prev_code = scancode; - add_mouse_randomness(scancode); - spin_lock_irqsave(&aux_count_lock, flags); - if ( aux_count ) { - int head = queue->head; - - queue->buf[head] = scancode; - head = (head + 1) & (AUX_BUF_SIZE-1); - if (head != queue->tail) { - queue->head = head; - kill_fasync(&queue->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&queue->proc_list); - } - } - spin_unlock_irqrestore(&aux_count_lock, flags); -#endif -} - -static unsigned char kbd_exists = 1; - -static inline void handle_keyboard_event(unsigned char scancode) -{ -#ifdef CONFIG_VT - kbd_exists = 1; - if (do_acknowledge(scancode)) - handle_scancode(scancode, !(scancode & 0x80)); -#endif - tasklet_schedule(&keyboard_tasklet); -} - -/* - * This reads the keyboard status port, and does the - * appropriate action. - * - * It requires that we hold the keyboard controller - * spinlock. - */ -static unsigned char handle_kbd_event(void) -{ - unsigned char status = kbd_read_status(); - unsigned int work = 10000; - - while ((--work > 0) && (status & KBD_STAT_OBF)) { - unsigned char scancode; - - scancode = kbd_read_input(); - - /* Error bytes must be ignored to make the - Synaptics touchpads compaq use work */ -#if 1 - /* Ignore error bytes */ - if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) -#endif - { - if (status & KBD_STAT_MOUSE_OBF) - handle_mouse_event(scancode); - else - handle_keyboard_event(scancode); - } - - status = kbd_read_status(); - } - - if (!work) - printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", status); - - return status; -} - - -static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ -#ifdef CONFIG_VT - kbd_pt_regs = regs; -#endif - - spin_lock_irq(&kbd_controller_lock); - handle_kbd_event(); - spin_unlock_irq(&kbd_controller_lock); -} - -/* - * send_data sends a character to the keyboard and waits - * for an acknowledge, possibly retrying if asked to. Returns - * the success status. - * - * Don't use 'jiffies', so that we don't depend on interrupts - */ -static int send_data(unsigned char data) -{ - int retries = 3; - - do { - unsigned long timeout = KBD_TIMEOUT; - - acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */ - resend = 0; - reply_expected = 1; - kbd_write_output_w(data); - for (;;) { - if (acknowledge) - return 1; - if (resend) - break; - mdelay(1); - if (!--timeout) { -#ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?(%02x)\n", data); -#endif - return 0; - } - } - } while (retries-- > 0); -#ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n"); -#endif - return 0; -} - -void pckbd_leds(unsigned char leds) -{ - if (kbd_exists && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) { - send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ - kbd_exists = 0; - } -} - -#define DEFAULT_KEYB_REP_DELAY 250 -#define DEFAULT_KEYB_REP_RATE 30 /* cps */ - -static struct kbd_repeat kbdrate={ - DEFAULT_KEYB_REP_DELAY, - DEFAULT_KEYB_REP_RATE -}; - -static unsigned char parse_kbd_rate(struct kbd_repeat *r) -{ - static struct r2v{ - int rate; - unsigned char val; - } kbd_rates[]={ {5,0x14}, - {7,0x10}, - {10,0x0c}, - {15,0x08}, - {20,0x04}, - {25,0x02}, - {30,0x00} - }; - static struct d2v{ - int delay; - unsigned char val; - } kbd_delays[]={{250,0}, - {500,1}, - {750,2}, - {1000,3} - }; - int rate=0,delay=0; - if (r != NULL){ - int i,new_rate=30,new_delay=250; - if (r->rate <= 0) - r->rate=kbdrate.rate; - if (r->delay <= 0) - r->delay=kbdrate.delay; - for (i=0; i < sizeof(kbd_rates)/sizeof(struct r2v); i++) - if (kbd_rates[i].rate == r->rate){ - new_rate=kbd_rates[i].rate; - rate=kbd_rates[i].val; - break; - } - for (i=0; i < sizeof(kbd_delays)/sizeof(struct d2v); i++) - if (kbd_delays[i].delay == r->delay){ - new_delay=kbd_delays[i].delay; - delay=kbd_delays[i].val; - break; - } - r->rate=new_rate; - r->delay=new_delay; - } - return (delay << 5) | rate; -} - -static int write_kbd_rate(unsigned char r) -{ - if (!send_data(KBD_CMD_SET_RATE) || !send_data(r)){ - send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ - return 0; - }else - return 1; -} - -static int pckbd_rate(struct kbd_repeat *rep) -{ - if (rep == NULL) - return -EINVAL; - else{ - unsigned char r=parse_kbd_rate(rep); - struct kbd_repeat old_rep; - memcpy(&old_rep,&kbdrate,sizeof(struct kbd_repeat)); - if (write_kbd_rate(r)){ - memcpy(&kbdrate,rep,sizeof(struct kbd_repeat)); - memcpy(rep,&old_rep,sizeof(struct kbd_repeat)); - return 0; - } - } - return -EIO; -} - -/* - * In case we run on a non-x86 hardware we need to initialize both the - * keyboard controller and the keyboard. On a x86, the BIOS will - * already have initialized them. - * - * Some x86 BIOSes do not correctly initialize the keyboard, so the - * "kbd-reset" command line options can be given to force a reset. - * [Ranger] - */ -#ifdef __i386__ - int kbd_startup_reset __initdata = 0; -#else - int kbd_startup_reset __initdata = 1; -#endif - -/* for "kbd-reset" cmdline param */ -static int __init kbd_reset_setup(char *str) -{ - kbd_startup_reset = 1; - return 1; -} - -__setup("kbd-reset", kbd_reset_setup); - -#define KBD_NO_DATA (-1) /* No data */ -#define KBD_BAD_DATA (-2) /* Parity or other error */ - -static int __init kbd_read_data(void) -{ - int retval = KBD_NO_DATA; - unsigned char status; - - status = kbd_read_status(); - if (status & KBD_STAT_OBF) { - unsigned char data = kbd_read_input(); - - retval = data; - if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) - retval = KBD_BAD_DATA; - } - return retval; -} - -static void __init kbd_clear_input(void) -{ - int maxread = 100; /* Random number */ - - do { - if (kbd_read_data() == KBD_NO_DATA) - break; - } while (--maxread); -} - -static int __init kbd_wait_for_input(void) -{ - long timeout = KBD_INIT_TIMEOUT; - - do { - int retval = kbd_read_data(); - if (retval >= 0) - return retval; - mdelay(1); - } while (--timeout); - return -1; -} - -static void kbd_write_command_w(int data) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(data); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -static void kbd_write_output_w(int data) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_output(data); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -#if defined(__alpha__) -/* - * Some Alphas cannot mask some/all interrupts, so we have to - * make sure not to allow interrupts AT ALL when polling for - * specific return values from the keyboard. - * - * I think this should work on any architecture, but for now, only Alpha. - */ -static int kbd_write_command_w_and_wait(int data) -{ - unsigned long flags; - int input; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(data); - input = kbd_wait_for_input(); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - return input; -} - -static int kbd_write_output_w_and_wait(int data) -{ - unsigned long flags; - int input; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_output(data); - input = kbd_wait_for_input(); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - return input; -} -#else -static int kbd_write_command_w_and_wait(int data) -{ - kbd_write_command_w(data); - return kbd_wait_for_input(); -} - -static int kbd_write_output_w_and_wait(int data) -{ - kbd_write_output_w(data); - return kbd_wait_for_input(); -} -#endif /* __alpha__ */ - -#if defined CONFIG_PSMOUSE -static void kbd_write_cmd(int cmd) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MODE); - kb_wait(); - kbd_write_output(cmd); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} -#endif /* CONFIG_PSMOUSE */ - -static char * __init initialize_kbd(void) -{ - int status; - -#ifdef CONFIG_IA64 - /* - * This is not really IA-64 specific. Probably ought to be done on all platforms - * that are (potentially) legacy-free. - */ - if (kbd_read_status() == 0xff && kbd_read_input() == 0xff) { - kbd_exists = 0; - return "No keyboard controller preset"; - } -#endif - - /* - * Test the keyboard interface. - * This seems to be the only way to get it going. - * If the test is successful a x55 is placed in the input buffer. - */ - kbd_write_command_w(KBD_CCMD_SELF_TEST); - if (kbd_wait_for_input() != 0x55) - return "Keyboard failed self test"; - - /* - * Perform a keyboard interface test. This causes the controller - * to test the keyboard clock and data lines. The results of the - * test are placed in the input buffer. - */ - kbd_write_command_w(KBD_CCMD_KBD_TEST); - if (kbd_wait_for_input() != 0x00) - return "Keyboard interface failed self test"; - - /* - * Enable the keyboard by allowing the keyboard clock to run. - */ - kbd_write_command_w(KBD_CCMD_KBD_ENABLE); - - /* - * Reset keyboard. If the read times out - * then the assumption is that no keyboard is - * plugged into the machine. - * This defaults the keyboard to scan-code set 2. - * - * Set up to try again if the keyboard asks for RESEND. - */ - do { - kbd_write_output_w(KBD_CMD_RESET); - status = kbd_wait_for_input(); - if (status == KBD_REPLY_ACK) - break; - if (status != KBD_REPLY_RESEND) - return "Keyboard reset failed, no ACK"; - } while (1); - - if (kbd_wait_for_input() != KBD_REPLY_POR) - return "Keyboard reset failed, no POR"; - - /* - * Set keyboard controller mode. During this, the keyboard should be - * in the disabled state. - * - * Set up to try again if the keyboard asks for RESEND. - */ - do { - kbd_write_output_w(KBD_CMD_DISABLE); - status = kbd_wait_for_input(); - if (status == KBD_REPLY_ACK) - break; - if (status != KBD_REPLY_RESEND) - return "Disable keyboard: no ACK"; - } while (1); - - kbd_write_command_w(KBD_CCMD_WRITE_MODE); - kbd_write_output_w(KBD_MODE_KBD_INT - | KBD_MODE_SYS - | KBD_MODE_DISABLE_MOUSE - | KBD_MODE_KCC); - - /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ - if (!(kbd_write_command_w_and_wait(KBD_CCMD_READ_MODE) & KBD_MODE_KCC)) - { - /* - * If the controller does not support conversion, - * Set the keyboard to scan-code set 1. - */ - kbd_write_output_w(0xF0); - kbd_wait_for_input(); - kbd_write_output_w(0x01); - kbd_wait_for_input(); - } - - if (kbd_write_output_w_and_wait(KBD_CMD_ENABLE) != KBD_REPLY_ACK) - return "Enable keyboard: no ACK"; - - /* - * Finally, set the typematic rate to maximum. - */ - if (kbd_write_output_w_and_wait(KBD_CMD_SET_RATE) != KBD_REPLY_ACK) - return "Set rate: no ACK"; - if (kbd_write_output_w_and_wait(0x00) != KBD_REPLY_ACK) - return "Set rate: no 2nd ACK"; - - return NULL; -} - -void __init pckbd_init_hw(void) -{ - kbd_request_region(); - - /* Flush any pending input. */ - kbd_clear_input(); - - if (kbd_startup_reset) { - char *msg = initialize_kbd(); - if (msg) - printk(KERN_WARNING "initialize_kbd: %s\n", msg); -#ifdef CONFIG_IA64 - if (!kbd_exists) - return; -#endif - } - -#if defined CONFIG_PSMOUSE - psaux_init(); -#endif - - kbd_rate = pckbd_rate; - - /* Ok, finally allocate the IRQ, and off we go.. */ - kbd_request_irq(keyboard_interrupt); -} - -#if defined CONFIG_PSMOUSE - -static int __init aux_reconnect_setup (char *str) -{ - aux_reconnect = 1; - return 1; -} - -__setup("psaux-reconnect", aux_reconnect_setup); - -/* - * Check if this is a dual port controller. - */ -static int __init detect_auxiliary_port(void) -{ - unsigned long flags; - int loops = 10; - int retval = 0; - - /* Check if the BIOS detected a device on the auxiliary port. */ - if (aux_device_present == 0xaa) - return 1; - - spin_lock_irqsave(&kbd_controller_lock, flags); - - /* Put the value 0x5A in the output buffer using the "Write - * Auxiliary Device Output Buffer" command (0xD3). Poll the - * Status Register for a while to see if the value really - * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF - * bit is also set to 1 in the Status Register, we assume this - * controller has an Auxiliary Port (a.k.a. Mouse Port). - */ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); - - kb_wait(); - kbd_write_output(0x5a); /* 0x5a is a random dummy value. */ - - do { - unsigned char status = kbd_read_status(); - - if (status & KBD_STAT_OBF) { - (void) kbd_read_input(); - if (status & KBD_STAT_MOUSE_OBF) { - printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); - retval = 1; - } - break; - } - mdelay(1); - } while (--loops); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - - return retval; -} - -/* - * Send a byte to the mouse. - */ -static void aux_write_dev(int val) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MOUSE); - kb_wait(); - kbd_write_output(val); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -/* - * Send a byte to the mouse & handle returned ack - */ -static void __aux_write_ack(int val) -{ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MOUSE); - kb_wait(); - kbd_write_output(val); - /* we expect an ACK in response. */ - mouse_reply_expected++; - kb_wait(); -} - -static void aux_write_ack(int val) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - __aux_write_ack(val); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -static unsigned char get_from_queue(void) -{ - unsigned char result; - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - return result; -} - - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - -static int fasync_aux(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &queue->fasync); - if (retval < 0) - return retval; - return 0; -} - - -/* - * Random magic cookie for the aux device - */ -#define AUX_DEV ((void *)queue) - -static int release_aux(struct inode * inode, struct file * file) -{ - unsigned long flags; - fasync_aux(-1, file, 0); - spin_lock_irqsave(&aux_count_lock, flags); - if ( --aux_count ) { - spin_unlock_irqrestore(&aux_count_lock, flags); - return 0; - } - spin_unlock_irqrestore(&aux_count_lock, flags); - kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ - kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); - aux_free_irq(AUX_DEV); - return 0; -} - -/* - * Install interrupt handler. - * Enable auxiliary device. - */ - -static int open_aux(struct inode * inode, struct file * file) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&aux_count_lock, flags); - if ( aux_count++ ) { - spin_unlock_irqrestore(&aux_count_lock, flags); - return 0; - } - queue->head = queue->tail = 0; /* Flush input queue */ - spin_unlock_irqrestore(&aux_count_lock, flags); - ret = aux_request_irq(keyboard_interrupt, AUX_DEV); - spin_lock_irqsave(&aux_count_lock, flags); - if (ret) { - aux_count--; - spin_unlock_irqrestore(&aux_count_lock, flags); - return -EBUSY; - } - spin_unlock_irqrestore(&aux_count_lock, flags); - kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the - auxiliary port on - controller. */ - aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ - kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ - - mdelay(2); /* Ensure we follow the kbc access delay rules.. */ - - send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */ - return 0; -} - -/* - * Put bytes from input queue to buffer. - */ - -static ssize_t read_aux(struct file * file, char * buffer, - size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - ssize_t i = count; - unsigned char c; - - if (queue_empty()) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&queue->proc_list, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (queue_empty() && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&queue->proc_list, &wait); - } - while (i > 0 && !queue_empty()) { - c = get_from_queue(); - put_user(c, buffer++); - i--; - } - if (count-i) { - file->f_dentry->d_inode->i_atime = CURRENT_TIME; - return count-i; - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* - * Write to the aux device. - */ - -static ssize_t write_aux(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - ssize_t retval = 0; - - if (count) { - ssize_t written = 0; - - if (count > 32) - count = 32; /* Limit to 32 bytes. */ - do { - char c; - get_user(c, buffer++); - aux_write_dev(c); - written++; - } while (--count); - retval = -EIO; - if (written) { - retval = written; - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; - } - } - - return retval; -} - -/* No kernel lock held - fine */ -static unsigned int aux_poll(struct file *file, poll_table * wait) -{ - poll_wait(file, &queue->proc_list, wait); - if (!queue_empty()) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations psaux_fops = { - read: read_aux, - write: write_aux, - poll: aux_poll, - open: open_aux, - release: release_aux, - fasync: fasync_aux, -}; - -/* - * Initialize driver. - */ -static struct miscdevice psaux_mouse = { - PSMOUSE_MINOR, "psaux", &psaux_fops -}; - -static int __init psaux_init(void) -{ - int retval; - - if (!detect_auxiliary_port()) - return -EIO; - - if ((retval = misc_register(&psaux_mouse))) - return retval; - - queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - if (queue == NULL) { - printk(KERN_ERR "psaux_init(): out of memory\n"); - misc_deregister(&psaux_mouse); - return -ENOMEM; - } - memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - init_waitqueue_head(&queue->proc_list); - -#ifdef INITIALIZE_MOUSE - kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ - aux_write_ack(AUX_SET_SAMPLE); - aux_write_ack(100); /* 100 samples/sec */ - aux_write_ack(AUX_SET_RES); - aux_write_ack(3); /* 8 counts per mm */ - aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ -#endif /* INITIALIZE_MOUSE */ - kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ - kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ - - return 0; -} - -#endif /* CONFIG_PSMOUSE */ +void pckbd_leds(unsigned char leds) { } +void __init pckbd_init_hw(void) { } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/pcmcia/serial_cs.c linux-2.5/drivers/char/pcmcia/serial_cs.c --- linux-2.5.20/drivers/char/pcmcia/serial_cs.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/char/pcmcia/serial_cs.c Thu Dec 13 16:32:35 2001 @@ -2,7 +2,7 @@ A driver for PCMCIA serial devices - serial_cs.c 1.123 2000/08/24 18:46:38 + serial_cs.c 1.128 2001/10/18 12:18:35 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -53,30 +54,32 @@ #include #include -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("PCMCIA serial card driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); /* Enable the speaker? */ -static int do_sound = 1; +INT_MODULE_PARM(do_sound, 1); -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(do_sound, "i"); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -93,6 +96,8 @@ { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 }, { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 }, { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 }, { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 }, { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 }, { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 } @@ -357,7 +362,6 @@ found_port: if (i != CS_SUCCESS) { - printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); cs_error(link->handle, RequestIO, i); return -1; } @@ -437,7 +441,6 @@ i = CardServices(RequestIRQ, link->handle, &link->irq); if (i != CS_SUCCESS) { - printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } @@ -663,5 +666,3 @@ module_init(init_serial_cs); module_exit(exit_serial_cs); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/pcwd.c linux-2.5/drivers/char/pcwd.c --- linux-2.5.20/drivers/char/pcwd.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/char/pcwd.c Sat May 25 19:52:01 2002 @@ -40,6 +40,8 @@ * fairly useless proc entry. * 990610 removed said useless proc code for the merge * 000403 Removed last traces of proc code. + * 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default */ #include @@ -76,7 +78,7 @@ */ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; -#define WD_VER "1.10 (06/05/99)" +#define WD_VER "1.12 (12/14/2001)" /* * It should be noted that PCWD_REVISION_B was removed because A and B @@ -88,7 +90,22 @@ #define PCWD_REVISION_A 1 #define PCWD_REVISION_C 2 -#define WD_TIMEOUT 3 /* 1 1/2 seconds for a timeout */ +#define WD_TIMEOUT 4 /* 2 seconds for a timeout */ +static int timeout_val = WD_TIMEOUT; +static int timeout = 2; + +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=2)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * These are the defines for the PC Watchdog card, revision A. @@ -121,7 +138,7 @@ if (prev_card_dat == 0xFF) return 0; - while(count < WD_TIMEOUT) { + while(count < timeout_val) { /* Read the raw card data from the port, and strip off the first 4 bits */ @@ -450,16 +467,16 @@ { if (minor(ino->i_rdev)==WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - /* Disable the board */ - if (revision == PCWD_REVISION_C) { - spin_lock(&io_lock); - outb_p(0xA5, current_readport + 3); - outb_p(0xA5, current_readport + 3); - spin_unlock(&io_lock); + if (!nowayout) { + /* Disable the board */ + if (revision == PCWD_REVISION_C) { + spin_lock(&io_lock); + outb_p(0xA5, current_readport + 3); + outb_p(0xA5, current_readport + 3); + spin_unlock(&io_lock); + } + atomic_inc( &open_allowed ); } - atomic_inc( &open_allowed ); -#endif } return 0; } @@ -559,10 +576,16 @@ "temperature", &pcwd_fops }; + +static void __init pcwd_validate_timeout(void) +{ + timeout_val = timeout * 2; +} static int __init pcwatchdog_init(void) { int i, found = 0; + pcwd_validate_timeout(); spin_lock_init(&io_lock); revision = PCWD_REVISION_A; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/q40_keyb.c linux-2.5/drivers/char/q40_keyb.c --- linux-2.5.20/drivers/char/q40_keyb.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/char/q40_keyb.c Fri May 3 03:49:06 2002 @@ -31,9 +31,6 @@ #include #include -/* Some configuration switches are present in the include file... */ - -#define KBD_REPORT_ERR /* Simple translation table for the SysRq keys */ @@ -215,7 +212,6 @@ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ }; -static unsigned int prev_scancode = 0; /* remember E0, E1 */ int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode) { @@ -246,10 +242,21 @@ int q40kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode) { - if (scancode == 0xe0 || scancode == 0xe1) { + static int prev_scancode; + + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { prev_scancode = scancode; return 0; - } + } + + /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; + return 0; + } + + scancode &= 0x7f; if (prev_scancode) { /* @@ -347,7 +354,7 @@ spin_lock(&kbd_controller_lock); kbd_pt_regs = regs; - status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG); + status = Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG); if (status ) { unsigned char scancode,qcode; @@ -398,7 +405,7 @@ int retval = KBD_NO_DATA; unsigned char status; - status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG); + status = Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG); if (status) { unsigned char data = master_inb(KEYCODE_REG); @@ -408,8 +415,6 @@ return retval; } -extern void q40kbd_leds(unsigned char leds) -{ /* nothing can be done */ } static void __init kbd_clear_input(void) { @@ -424,10 +429,7 @@ void __init q40kbd_init_hw(void) { -#if 0 - /* Get the keyboard controller registers (incomplete decode) */ - request_region(0x60, 16, "keyboard"); -#endif + /* Flush any pending input. */ kbd_clear_input(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/qpmouse.c linux-2.5/drivers/char/qpmouse.c --- linux-2.5.20/drivers/char/qpmouse.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/char/qpmouse.c Thu Jan 1 01:00:00 1970 @@ -1,381 +0,0 @@ -/* - * linux/drivers/char/qpmouse.c - * - * Driver for a 82C710 C&T mouse interface chip. - * - * Based on the PS/2 driver by Johan Myreen. - * - * Corrections in device setup for some laptop mice & trackballs. - * 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca) - * - * Modified by Johan Myreen (jem@iki.fi) 04Aug93 - * to include support for QuickPort mouse. - * - * Changed references to "QuickPort" with "82C710" since "QuickPort" - * is not what this driver is all about -- QuickPort is just a - * connector type, and this driver is for the mouse port on the Chips - * & Technologies 82C710 interface chip. 15Nov93 jem@iki.fi - * - * Added support for SIGIO. 28Jul95 jem@iki.fi - * - * Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com - * - * Modularised 8-Sep-95 Philip Blundell - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include /* mouse enable command.. */ - - -/* - * We use the same minor number as the PS/2 mouse for (bad) historical - * reasons.. - */ -#define PSMOUSE_MINOR 1 /* Minor device # for this mouse */ -#define QP_BUF_SIZE 2048 - -struct qp_queue { - unsigned long head; - unsigned long tail; - wait_queue_head_t proc_list; - struct fasync_struct *fasync; - unsigned char buf[QP_BUF_SIZE]; -}; - -static struct qp_queue *queue; - -static unsigned int get_from_queue(void) -{ - unsigned int result; - unsigned long flags; - - save_flags(flags); - cli(); - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (QP_BUF_SIZE-1); - restore_flags(flags); - return result; -} - - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - -static int fasync_qp(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &queue->fasync); - if (retval < 0) - return retval; - return 0; -} - -/* - * 82C710 Interface - */ - -#define QP_DATA 0x310 /* Data Port I/O Address */ -#define QP_STATUS 0x311 /* Status Port I/O Address */ - -#define QP_DEV_IDLE 0x01 /* Device Idle */ -#define QP_RX_FULL 0x02 /* Device Char received */ -#define QP_TX_IDLE 0x04 /* Device XMIT Idle */ -#define QP_RESET 0x08 /* Device Reset */ -#define QP_INTS_ON 0x10 /* Device Interrupt On */ -#define QP_ERROR_FLAG 0x20 /* Device Error */ -#define QP_CLEAR 0x40 /* Device Clear */ -#define QP_ENABLE 0x80 /* Device Enable */ - -#define QP_IRQ 12 - -static int qp_present; -static int qp_count; -static spinlock_t qp_count_lock = SPIN_LOCK_UNLOCKED; -static int qp_data = QP_DATA; -static int qp_status = QP_STATUS; - -static int poll_qp_status(void); -static int probe_qp(void); - -/* - * Interrupt handler for the 82C710 mouse port. A character - * is waiting in the 82C710. - */ - -static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs) -{ - int head = queue->head; - int maxhead = (queue->tail-1) & (QP_BUF_SIZE-1); - - add_mouse_randomness(queue->buf[head] = inb(qp_data)); - if (head != maxhead) { - head++; - head &= QP_BUF_SIZE-1; - } - queue->head = head; - kill_fasync(&queue->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&queue->proc_list); -} - -static int release_qp(struct inode * inode, struct file * file) -{ - unsigned char status; - - fasync_qp(-1, file, 0); - spin_lock( &qp_count_lock ); - if (!--qp_count) { - if (!poll_qp_status()) - printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n"); - status = inb_p(qp_status); - outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status); - if (!poll_qp_status()) - printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n"); - free_irq(QP_IRQ, NULL); - } - spin_unlock( &qp_count_lock ); - return 0; -} - -/* - * Install interrupt handler. - * Enable the device, enable interrupts. - */ - -static int open_qp(struct inode * inode, struct file * file) -{ - unsigned char status; - - if (!qp_present) - return -EINVAL; - - spin_lock( &qp_count_lock ); - if (qp_count++) - { - spin_unlock( &qp_count_lock ); - return 0; - } - spin_unlock( &qp_count_lock ); - - if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse", NULL)) { - qp_count--; - return -EBUSY; - } - - status = inb_p(qp_status); - status |= (QP_ENABLE|QP_RESET); - outb_p(status, qp_status); - status &= ~(QP_RESET); - outb_p(status, qp_status); - - queue->head = queue->tail = 0; /* Flush input queue */ - status |= QP_INTS_ON; - outb_p(status, qp_status); /* Enable interrupts */ - - while (!poll_qp_status()) { - printk(KERN_ERR "Error: Mouse device busy in open_qp()\n"); - qp_count--; - status &= ~(QP_ENABLE|QP_INTS_ON); - outb_p(status, qp_status); - free_irq(QP_IRQ, NULL); - return -EBUSY; - } - - outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */ - return 0; -} - -/* - * Write to the 82C710 mouse device. - */ - -static ssize_t write_qp(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - ssize_t i = count; - - while (i--) { - char c; - if (!poll_qp_status()) - return -EIO; - get_user(c, buffer++); - outb_p(c, qp_data); - } - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; - return count; -} - -static unsigned int poll_qp(struct file *file, poll_table * wait) -{ - poll_wait(file, &queue->proc_list, wait); - if (!queue_empty()) - return POLLIN | POLLRDNORM; - return 0; -} - -/* - * Wait for device to send output char and flush any input char. - */ - -#define MAX_RETRIES (60) - -static int poll_qp_status(void) -{ - int retries=0; - - while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE)) - != (QP_DEV_IDLE|QP_TX_IDLE) - && retries < MAX_RETRIES) { - - if (inb_p(qp_status)&(QP_RX_FULL)) - inb_p(qp_data); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((5*HZ + 99) / 100); - retries++; - } - return !(retries==MAX_RETRIES); -} - -/* - * Put bytes from input queue to buffer. - */ - -static ssize_t read_qp(struct file * file, char * buffer, - size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - ssize_t i = count; - unsigned char c; - - if (queue_empty()) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&queue->proc_list, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (queue_empty() && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&queue->proc_list, &wait); - } - while (i > 0 && !queue_empty()) { - c = get_from_queue(); - put_user(c, buffer++); - i--; - } - if (count-i) { - file->f_dentry->d_inode->i_atime = CURRENT_TIME; - return count-i; - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -struct file_operations qp_fops = { - owner: THIS_MODULE, - read: read_qp, - write: write_qp, - poll: poll_qp, - open: open_qp, - release: release_qp, - fasync: fasync_qp, -}; - -/* - * Initialize driver. - */ -static struct miscdevice qp_mouse = { - minor: PSMOUSE_MINOR, - name: "QPmouse", - fops: &qp_fops, -}; - -/* - * Function to read register in 82C710. - */ - -static inline unsigned char read_710(unsigned char index) -{ - outb_p(index, 0x390); /* Write index */ - return inb_p(0x391); /* Read the data */ -} - - -/* - * See if we can find a 82C710 device. Read mouse address. - */ - -static int __init probe_qp(void) -{ - outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ - outb_p(0xaa, 0x3fa); /* Inverse of 55 */ - outb_p(0x36, 0x3fa); /* Address the chip */ - outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ - outb_p(0x1b, 0x2fa); /* Inverse of e4 */ - if (read_710(0x0f) != 0xe4) /* Config address found? */ - return 0; /* No: no 82C710 here */ - qp_data = read_710(0x0d)*4; /* Get mouse I/O address */ - qp_status = qp_data+1; - outb_p(0x0f, 0x390); - outb_p(0x0f, 0x391); /* Close config mode */ - return 1; -} - -static char msg_banner[] __initdata = KERN_INFO "82C710 type pointing device detected -- driver installed.\n"; -static char msg_nomem[] __initdata = KERN_ERR "qpmouse: no queue memory.\n"; - -static int __init qpmouse_init_driver(void) -{ - if (!probe_qp()) - return -EIO; - - printk(msg_banner); - -/* printk("82C710 address = %x (should be 0x310)\n", qp_data); */ - queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - if (queue == NULL) { - printk(msg_nomem); - return -ENOMEM; - } - qp_present = 1; - misc_register(&qp_mouse); - memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - init_waitqueue_head(&queue->proc_list); - return 0; -} - -static void __exit qpmouse_exit_driver(void) -{ - misc_deregister(&qp_mouse); - kfree(queue); -} - -module_init(qpmouse_init_driver); -module_exit(qpmouse_exit_driver); - - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/qtronix.c linux-2.5/drivers/char/qtronix.c --- linux-2.5.20/drivers/char/qtronix.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/char/qtronix.c Sun Mar 3 17:54:35 2002 @@ -51,6 +51,7 @@ #ifdef CONFIG_QTRONIX_KEYBOARD +#include #include #include #include @@ -121,7 +122,7 @@ }; -void init_qtronix_990P_kbd(void) +void __init init_qtronix_990P_kbd(void) { int retval; @@ -592,4 +593,5 @@ return 0; } +module_init(init_qtronix_990P_kbd); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/rocket.c linux-2.5/drivers/char/rocket.c --- linux-2.5.20/drivers/char/rocket.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/char/rocket.c Tue Apr 16 03:44:35 2002 @@ -454,11 +454,9 @@ continue; ctlp= sCtlNumToCtlPtr(ctrl); -#ifdef CONFIG_PCI if(ctlp->BusType == isPCI) CtlMask= sPCIGetControllerIntStatus(ctlp); else -#endif CtlMask= sGetControllerIntStatus(ctlp); for (aiop=0; CtlMask; CtlMask >>= 1, aiop++) { if (CtlMask & 1) { @@ -1330,7 +1328,7 @@ { if (tty) sprintf(buf, "%s%d", tty->driver.name, - MINOR(tty->device) - tty->driver.minor_start + + minor(tty->device) - tty->driver.minor_start + tty->driver.name_base); else strcpy(buf, "NULL tty"); @@ -1794,6 +1792,10 @@ str = "8-port Modem"; max_num_aiops = 1; break; + case 0x8: + str = "mysterious 8 port"; + max_num_aiops = 1; + break; default: str = "(unknown/unsupported)"; max_num_aiops = 0; @@ -1872,6 +1874,10 @@ PCI_DEVICE_ID_RP8M, i, &bus, &device_fn)) if(register_PCI(count+boards_found, bus, device_fn)) count++; + if(!pcibios_find_device(PCI_VENDOR_ID_RP, + 0x8, i, &bus, &device_fn)) + if(register_PCI(count+boards_found, bus, device_fn)) + count++; } return(count); } @@ -1916,11 +1922,13 @@ num_aiops); if (rcktpt_io_addr[i] + 0x40 == controller) { *reserved_controller = 1; - request_region(rcktpt_io_addr[i], 68, - "Comtrol Rocketport"); + if (!request_region(rcktpt_io_addr[i], 68, + "Comtrol Rocketport")) + return 0; } else { - request_region(rcktpt_io_addr[i], 64, - "Comtrol Rocketport"); + if (!request_region(rcktpt_io_addr[i], 64, + "Comtrol Rocketport")) + return 0; } return(1); } @@ -2008,7 +2016,11 @@ } if (reserved_controller == 0) - request_region(controller, 4, "Comtrol Rocketport"); + if (!request_region(controller, 4, "Comtrol Rocketport")) + { + rocket_timer.function = 0; + return -EIO; + } /* * Set up the tty driver structure and then register this @@ -2071,6 +2083,7 @@ if (retval < 0) { printk("Couldn't install Rocketport callout driver " "(error %d)\n", -retval); + release_region(controller, 4); return -1; } @@ -2078,6 +2091,7 @@ if (retval < 0) { printk("Couldn't install tty Rocketport driver " "(error %d)\n", -retval); + release_region(controller, 4); return -1; } #ifdef ROCKET_DEBUG_OPEN diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/sc1200wdt.c linux-2.5/drivers/char/sc1200wdt.c --- linux-2.5.20/drivers/char/sc1200wdt.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/sc1200wdt.c Sat Apr 13 15:42:55 2002 @@ -0,0 +1,432 @@ +/* + * National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver + * (c) Copyright 2002 Zwane Mwaikambo , + * All Rights Reserved. + * Based on wdt.c and wdt977.c by Alan Cox and Woody Suwalski respectively. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The author(s) of this software shall not be held liable for damages + * of any nature resulting due to the use of this software. This + * software is provided AS-IS with no warranties. + * + * Changelog: + * 20020220 Zwane Mwaikambo Code based on datasheet, no hardware. + * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik and Alan Cox. + * 20020222 Zwane Mwaikambo Added probing. + * 20020225 Zwane Mwaikambo Added ISAPNP support. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SC1200_MODULE_VER "build 20020303" +#define SC1200_MODULE_NAME "sc1200wdt" +#define PFX SC1200_MODULE_NAME ": " + +#define MAX_TIMEOUT 255 /* 255 minutes */ +#define PMIR (io) /* Power Management Index Register */ +#define PMDR (io+1) /* Power Management Data Register */ + +/* Data Register indexes */ +#define FER1 0x00 /* Function enable register 1 */ +#define FER2 0x01 /* Function enable register 2 */ +#define PMC1 0x02 /* Power Management Ctrl 1 */ +#define PMC2 0x03 /* Power Management Ctrl 2 */ +#define PMC3 0x04 /* Power Management Ctrl 3 */ +#define WDTO 0x05 /* Watchdog timeout register */ +#define WDCF 0x06 /* Watchdog config register */ +#define WDST 0x07 /* Watchdog status register */ + +/* WDO Status */ +#define WDO_ENABLED 0x00 +#define WDO_DISABLED 0x01 + +/* WDCF bitfields - which devices assert WDO */ +#define KBC_IRQ 0x01 /* Keyboard Controller */ +#define MSE_IRQ 0x02 /* Mouse */ +#define UART1_IRQ 0x03 /* Serial0 */ +#define UART2_IRQ 0x04 /* Serial1 */ +/* 5 -7 are reserved */ + +static char banner[] __initdata = KERN_INFO PFX SC1200_MODULE_VER; +static int timeout = 1; +static int io = -1; +static int io_len = 2; /* for non plug and play */ +struct semaphore open_sem; +static int expect_close = 0; +spinlock_t sc1200wdt_lock; /* io port access serialisation */ + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +static int isapnp = 1; +static struct pci_dev *wdt_dev; +#endif + +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "io port"); +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1"); + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +MODULE_PARM(isapnp, "i"); +MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled"); +#endif + + +/* Read from Data Register */ +static inline void sc1200wdt_read_data(unsigned char index, unsigned char *data) +{ + spin_lock(&sc1200wdt_lock); + outb_p(index, PMIR); + *data = inb(PMDR); + spin_unlock(&sc1200wdt_lock); +} + + +/* Write to Data Register */ +static inline void sc1200wdt_write_data(unsigned char index, unsigned char data) +{ + spin_lock(&sc1200wdt_lock); + outb_p(index, PMIR); + outb(data, PMDR); + spin_unlock(&sc1200wdt_lock); +} + + +/* This returns the status of the WDO signal, inactive high. + * returns WDO_ENABLED or WDO_DISABLED + */ +static inline int sc1200wdt_status(void) +{ + unsigned char ret; + + sc1200wdt_read_data(WDST, &ret); + return (ret & 0x01); /* bits 1 - 7 are undefined */ +} + + +static int sc1200wdt_open(struct inode *inode, struct file *file) +{ + unsigned char reg; + + /* allow one at a time */ + if (down_trylock(&open_sem)) + return -EBUSY; + +#ifdef CONFIG_WATCHDOG_NOWAYOUT + MOD_INC_USE_COUNT; +#endif + + if (timeout > MAX_TIMEOUT) + timeout = MAX_TIMEOUT; + + sc1200wdt_read_data(WDCF, ®); + /* assert WDO when any of the following interrupts are triggered too */ + reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ); + sc1200wdt_write_data(WDCF, reg); + /* set the timeout and get the ball rolling */ + sc1200wdt_write_data(WDTO, timeout); + printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout); + + return 0; +} + + +static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int new_timeout; + static struct watchdog_info ident = { + options: WDIOF_SETTIMEOUT, + identity: "PC87307/PC97307" + }; + + switch (cmd) { + default: + return -ENOTTY; /* Keep Pavel Machek amused ;) */ + + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof ident)) + return -EFAULT; + return 0; + + case WDIOC_GETSTATUS: + return put_user(sc1200wdt_status(), (int *)arg); + + case WDIOC_KEEPALIVE: + sc1200wdt_write_data(WDTO, timeout); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, (int *)arg)) + return -EFAULT; + + /* the API states this is given in secs */ + new_timeout /= 60; + if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) + return -EINVAL; + + timeout = new_timeout; + sc1200wdt_write_data(WDTO, timeout); + /* fall through and return the new timeout */ + + case WDIOC_GETTIMEOUT: + return put_user(timeout * 60, (int *)arg); + } +} + + +static int sc1200wdt_release(struct inode *inode, struct file *file) +{ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + if (expect_close) { + sc1200wdt_write_data(WDTO, 0); + printk(KERN_INFO PFX "Watchdog disabled\n"); + } else { + sc1200wdt_write_data(WDTO, timeout); + printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout); + } +#endif + up(&open_sem); + + return 0; +} + + +static ssize_t sc1200wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (len) { +#ifndef CONFIG_WATCHDOG_NOWAYOUT + size_t i; + + expect_close = 0; + + for (i = 0; i != len; i++) + { + if (data[i] == 'V') + expect_close = 1; + } +#endif + sc1200wdt_write_data(WDTO, timeout); + return len; + } + + return 0; +} + + +static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + sc1200wdt_write_data(WDTO, 0); + + return NOTIFY_DONE; +} + + +static struct notifier_block sc1200wdt_notifier = +{ + notifier_call: sc1200wdt_notify_sys +}; + +static struct file_operations sc1200wdt_fops = +{ + owner: THIS_MODULE, + write: sc1200wdt_write, + ioctl: sc1200wdt_ioctl, + open: sc1200wdt_open, + release: sc1200wdt_release +}; + +static struct miscdevice sc1200wdt_miscdev = +{ + minor: WATCHDOG_MINOR, + name: "watchdog", + fops: &sc1200wdt_fops +}; + + +static int __init sc1200wdt_probe(void) +{ + /* The probe works by reading the PMC3 register's default value of 0x0e + * there is one caveat, if the device disables the parallel port or any + * of the UARTs we won't be able to detect it. + * Nb. This could be done with accuracy by reading the SID registers, but + * we don't have access to those io regions. + */ + + unsigned char reg; + + sc1200wdt_read_data(PMC3, ®); + reg &= 0x0f; /* we don't want the UART busy bits */ + return (reg == 0x0e) ? 0 : -ENODEV; +} + + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + +static int __init sc1200wdt_isapnp_probe(void) +{ + int ret; + + /* The WDT is logical device 8 on the main device */ + wdt_dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('N','S','C'), ISAPNP_FUNCTION(0x08), NULL); + if (!wdt_dev) + return -ENODEV; + + if (wdt_dev->prepare(wdt_dev) < 0) { + printk(KERN_ERR PFX "ISA PnP found device that could not be autoconfigured\n"); + return -EAGAIN; + } + + if (!(pci_resource_flags(wdt_dev, 0) & IORESOURCE_IO)) { + printk(KERN_ERR PFX "ISA PnP could not find io ports\n"); + return -ENODEV; + } + + ret = wdt_dev->activate(wdt_dev); + if (ret && (ret != -EBUSY)) + return -ENOMEM; + + /* io port resource overriding support? */ + io = pci_resource_start(wdt_dev, 0); + io_len = pci_resource_len(wdt_dev, 0); + + printk(KERN_DEBUG PFX "ISA PnP found device at io port %#x/%d\n", io, io_len); + return 0; +} + +#endif /* CONFIG_ISAPNP */ + + +static int __init sc1200wdt_init(void) +{ + int ret; + + printk(banner); + + spin_lock_init(&sc1200wdt_lock); + sema_init(&open_sem, 1); + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if (isapnp) { + ret = sc1200wdt_isapnp_probe(); + if (ret) + goto out_clean; + } +#endif + + if (io == -1) { + printk(KERN_ERR PFX "io parameter must be specified\n"); + ret = -EINVAL; + goto out_clean; + } + + if (!request_region(io, io_len, SC1200_MODULE_NAME)) { + printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); + ret = -EBUSY; + goto out_pnp; + } + + ret = sc1200wdt_probe(); + if (ret) + goto out_io; + + ret = register_reboot_notifier(&sc1200wdt_notifier); + if (ret) { + printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret); + goto out_io; + } + + ret = misc_register(&sc1200wdt_miscdev); + if (ret) { + printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); + goto out_rbt; + } + + /* ret = 0 */ + +out_clean: + return ret; + +out_rbt: + unregister_reboot_notifier(&sc1200wdt_notifier); + +out_io: + release_region(io, io_len); + +out_pnp: +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if (isapnp && wdt_dev) + wdt_dev->deactivate(wdt_dev); +#endif + goto out_clean; +} + + +static void __exit sc1200wdt_exit(void) +{ + misc_deregister(&sc1200wdt_miscdev); + unregister_reboot_notifier(&sc1200wdt_notifier); + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if(isapnp && wdt_dev) + wdt_dev->deactivate(wdt_dev); +#endif + + release_region(io, io_len); +} + + +#ifndef MODULE +static int __init sc1200wdt_setup(char *str) +{ + int ints[4]; + + str = get_options (str, ARRAY_SIZE(ints), ints); + + if (ints[0] > 0) { + io = ints[1]; + if (ints[0] > 1) + timeout = ints[2]; + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if (ints[0] > 2) + isapnp = ints[3]; +#endif + } + + return 1; +} + +__setup("sc1200wdt=", sc1200wdt_setup); +#endif /* MODULE */ + + +module_init(sc1200wdt_init); +module_exit(sc1200wdt_exit); + +MODULE_AUTHOR("Zwane Mwaikambo "); +MODULE_DESCRIPTION("Driver for National Semiconductor PC87307/PC97307 watchdog component"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/sc520_wdt.c linux-2.5/drivers/char/sc520_wdt.c --- linux-2.5.20/drivers/char/sc520_wdt.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/sc520_wdt.c Sun Apr 14 22:02:59 2002 @@ -0,0 +1,381 @@ +/* + * AMD Elan SC520 processor Watchdog Timer driver for Linux 2.4.x + * + * Based on acquirewdt.c by Alan Cox, + * and sbc60xxwdt.c by Jakob Oestergaard + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The authors do NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * (c) Copyright 2001 Scott Jennings + * 9/27 - 2001 [Initial release] + * + * Additional fixes Alan Cox + * - Fixed formatting + * - Removed debug printks + * - Fixed SMP built kernel deadlock + * - Switched to private locks not lock_kernel + * - Used ioremap/writew/readw + * - Added NOWAYOUT support + * + * Theory of operation: + * A Watchdog Timer (WDT) is a hardware circuit that can + * reset the computer system in case of a software fault. + * You probably knew that already. + * + * Usually a userspace daemon will notify the kernel WDT driver + * via the /proc/watchdog special device file that userspace is + * still alive, at regular intervals. When such a notification + * occurs, the driver will usually tell the hardware watchdog + * that everything is in order, and that the watchdog should wait + * for yet another little while to reset the system. + * If userspace fails (RAM error, kernel bug, whatever), the + * notifications cease to occur, and the hardware watchdog will + * reset the system (causing a reboot) after the timeout occurs. + * + * This WDT driver is different from most other Linux WDT + * drivers in that the driver will ping the watchdog by itself, + * because this particular WDT has a very short timeout (1.6 + * seconds) and it would be insane to count on any userspace + * daemon always getting scheduled within that time frame. + * + * This driver uses memory mapped IO, and spinlock. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The SC520 can timeout anywhere from 492us to 32.21s. + * If we reset the watchdog every ~250ms we should be safe. + */ + +#define WDT_INTERVAL (HZ/4+1) + +/* + * We must not require too good response from the userspace daemon. + * Here we require the userspace daemon to send us a heartbeat + * char to /dev/watchdog every 30 seconds. + */ + +#define WDT_HEARTBEAT (HZ * 30) + +/* + * AMD Elan SC520 timeout value is 492us times a power of 2 (0-7) + * + * 0: 492us 2: 1.01s 4: 4.03s 6: 16.22s + * 1: 503ms 3: 2.01s 5: 8.05s 7: 32.21s + */ + +#define TIMEOUT_EXPONENT ( 1 << 3 ) /* 0x08 = 2.01s */ + +/* #define MMCR_BASE_DEFAULT 0xfffef000 */ +#define MMCR_BASE_DEFAULT ((__u16 *)0xffffe) +#define OFFS_WDTMRCTL ((unsigned int)0xcb0) +#define WDT_ENB 0x8000 /* [15] Watchdog Timer Enable */ +#define WDT_WRST_ENB 0x4000 /* [14] Watchdog Timer Reset Enable */ + +#define OUR_NAME "sc520_wdt" + +#define WRT_DOG(data) *wdtmrctl=data + +static __u16 *wdtmrctl; + +static void wdt_timer_ping(unsigned long); +static struct timer_list timer; +static unsigned long next_heartbeat; +static unsigned long wdt_is_open; +static int wdt_expect_close; + +static spinlock_t wdt_spinlock; +/* + * Whack the dog + */ + +static void wdt_timer_ping(unsigned long data) +{ + /* If we got a heartbeat pulse within the WDT_US_INTERVAL + * we agree to ping the WDT + */ + if(time_before(jiffies, next_heartbeat)) + { + /* Ping the WDT */ + spin_lock(&wdt_spinlock); + writew(0xAAAA, wdtmrctl); + writew(0x5555, wdtmrctl); + spin_unlock(&wdt_spinlock); + + /* Re-set the timer interval */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + } else { + printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + } +} + +/* + * Utility routines + */ + +static void wdt_config(int writeval) +{ + __u16 dummy; + unsigned long flags; + + /* buy some time (ping) */ + spin_lock_irqsave(&wdt_spinlock, flags); + dummy=readw(wdtmrctl); /* ensure write synchronization */ + writew(0xAAAA, wdtmrctl); + writew(0x5555, wdtmrctl); + /* make WDT configuration register writable one time */ + writew(0x3333, wdtmrctl); + writew(0xCCCC, wdtmrctl); + /* write WDT configuration register */ + writew(writeval, wdtmrctl); + spin_unlock_irqrestore(&wdt_spinlock, flags); +} + +static void wdt_startup(void) +{ + next_heartbeat = jiffies + WDT_HEARTBEAT; + + /* Start the timer */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + + wdt_config(WDT_ENB | WDT_WRST_ENB | TIMEOUT_EXPONENT); + printk(OUR_NAME ": Watchdog timer is now enabled.\n"); +} + +static void wdt_turnoff(void) +{ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + /* Stop the timer */ + del_timer(&timer); + wdt_config(0); + printk(OUR_NAME ": Watchdog timer is now disabled...\n"); +#endif +} + + +/* + * /dev/watchdog handling + */ + +static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +{ + /* We can't seek */ + if(ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count) + { + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++) + if(buf[ofs] == 'V') + wdt_expect_close = 1; + + /* Well, anyhow someone wrote to us, we should return that favour */ + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 1; + } + return 0; +} + +static int fop_open(struct inode * inode, struct file * file) +{ + switch(minor(inode->i_rdev)) + { + case WATCHDOG_MINOR: + /* Just in case we're already talking to someone... */ + if(test_and_set_bit(0, &wdt_is_open)) + return -EBUSY; + /* Good, fire up the show */ + wdt_startup(); +#ifdef CONFIG_WATCHDOG_NOWAYOUT + MOD_INC_USE_COUNT; +#endif + return 0; + default: + return -ENODEV; + } +} + +static int fop_close(struct inode * inode, struct file * file) +{ + if(minor(inode->i_rdev) == WATCHDOG_MINOR) + { + if(wdt_expect_close) + wdt_turnoff(); + else { + del_timer(&timer); + printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); + } + } + clear_bit(0, &wdt_is_open); + return 0; +} + +static long long fop_llseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + 0, + 1, + "SC520" + }; + + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 0; + } +} + +static struct file_operations wdt_fops = { + owner: THIS_MODULE, + llseek: fop_llseek, + write: fop_write, + open: fop_open, + release: fop_close, + ioctl: fop_ioctl +}; + +static struct miscdevice wdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wdt_fops +}; + +/* + * Notifier for system down + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + wdt_turnoff(); + return NOTIFY_DONE; +} + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier= +{ + wdt_notify_sys, + 0, + 0 +}; + +static void __exit sc520_wdt_unload(void) +{ + wdt_turnoff(); + + /* Deregister */ + misc_deregister(&wdt_miscdev); + iounmap(wdtmrctl); + unregister_reboot_notifier(&wdt_notifier); +} + +static int __init sc520_wdt_init(void) +{ + int rc = -EBUSY; + unsigned long cbar; + + spin_lock_init(&wdt_spinlock); + + init_timer(&timer); + timer.function = wdt_timer_ping; + timer.data = 0; + + rc = misc_register(&wdt_miscdev); + if (rc) + goto err_out_region2; + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) + goto err_out_miscdev; + + /* get the Base Address Register */ + cbar = inl_p(0xfffc); + printk(OUR_NAME ": CBAR: 0x%08lx\n", cbar); + /* check if MMCR aliasing bit is set */ + if (cbar & 0x80000000) { + printk(OUR_NAME ": MMCR Aliasing enabled.\n"); + wdtmrctl = (__u16 *)(cbar & 0x3fffffff); + } else { + printk(OUR_NAME "!!! WARNING !!!\n" + "\t MMCR Aliasing found NOT enabled!\n" + "\t Using default value of: %p\n" + "\t This has not been tested!\n" + "\t Please email Scott Jennings \n" + "\t and Bill Jennings if it works!\n" + , MMCR_BASE_DEFAULT + ); + wdtmrctl = MMCR_BASE_DEFAULT; + } + + wdtmrctl = (__u16 *)((char *)wdtmrctl + OFFS_WDTMRCTL); + wdtmrctl = ioremap((unsigned long)wdtmrctl, 2); + printk(KERN_INFO OUR_NAME ": WDT driver for SC520 initialised.\n"); + + return 0; + +err_out_miscdev: + misc_deregister(&wdt_miscdev); +err_out_region2: + return rc; +} + +module_init(sc520_wdt_init); +module_exit(sc520_wdt_unload); + +MODULE_AUTHOR("Scott and Bill Jennings"); +MODULE_DESCRIPTION("Driver for watchdog timer in AMD \"Elan\" SC520 uProcessor"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/selection.c linux-2.5/drivers/char/selection.c --- linux-2.5.20/drivers/char/selection.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/char/selection.c Mon Feb 25 18:54:26 2002 @@ -22,7 +22,6 @@ #include #include -#include #include #ifndef MIN @@ -32,8 +31,6 @@ /* Don't take this from : 011-015 on the screen aren't spaces */ #define isspace(c) ((c) == ' ') -extern void poke_blanked_console(void); - /* Variables for selection control. */ /* Use a dynamic buffer, instead of static (Dec 1994) */ int sel_cons; /* must not be disallocated */ @@ -48,19 +45,31 @@ /* set reverse video on characters s-e of console with selection. */ inline static void highlight(const int s, const int e) { - invert_screen(sel_cons, s, e-s+2, 1); + invert_screen(vt_cons->vc_cons[sel_cons], s, e-s+2, 1); } /* use complementary color to show the pointer */ inline static void highlight_pointer(const int where) { - complement_pos(sel_cons, where); + complement_pos(vt_cons->vc_cons[sel_cons], where); +} + +u16 screen_glyph(struct vc_data *vc, int offset) +{ + u16 w = scr_readw(screenpos(vc, offset, 1)); + u16 c = w & 0xff; + + if (w & vc->vc_hi_font_mask) + c |= 0x100; + return c; } static unsigned char sel_pos(int n) { - return inverse_translate(vc_cons[sel_cons].d, screen_glyph(sel_cons, n)); + struct vc_data *vc = vt_cons->vc_cons[sel_cons]; + + return inverse_translate(vc, screen_glyph(vc, n)); } /* remove the current selection highlight, if any, @@ -114,13 +123,13 @@ /* set the current selection. Invoked by ioctl() or by kernel code. */ int set_selection(const unsigned long arg, struct tty_struct *tty, int user) { + struct vc_data *vc = vt_cons->vc_cons[fg_console]; int sel_mode, new_sel_start, new_sel_end, spc; char *bp, *obp; int i, ps, pe; - unsigned int currcons = fg_console; unblank_screen(); - poke_blanked_console(); + poke_blanked_console(vc->display_fg); { unsigned short *args, xs, ys, xe, ye; @@ -141,12 +150,12 @@ sel_mode = *args; } xs--; ys--; xe--; ye--; - xs = limit(xs, video_num_columns - 1); - ys = limit(ys, video_num_lines - 1); - xe = limit(xe, video_num_columns - 1); - ye = limit(ye, video_num_lines - 1); - ps = ys * video_size_row + (xs << 1); - pe = ye * video_size_row + (xe << 1); + xs = limit(xs, vc->vc_cols - 1); + ys = limit(ys, vc->vc_rows - 1); + xe = limit(xe, vc->vc_cols - 1); + ye = limit(ye, vc->vc_rows - 1); + ps = ys * vc->vc_size_row + (xs << 1); + pe = ye * vc->vc_size_row + (xe << 1); if (sel_mode == 4) { /* useful for screendump without selection highlights */ @@ -154,7 +163,7 @@ return 0; } - if (mouse_reporting() && (sel_mode & 16)) { + if (mouse_reporting(vc) && (sel_mode & 16)) { mouse_report(tty, sel_mode & 15, xs, ys); return 0; } @@ -186,7 +195,7 @@ (!spc && !inword(sel_pos(ps)))) break; new_sel_start = ps; - if (!(ps % video_size_row)) + if (!(ps % vc->vc_size_row)) break; } spc = isspace(sel_pos(pe)); @@ -196,14 +205,14 @@ (!spc && !inword(sel_pos(pe)))) break; new_sel_end = pe; - if (!((pe + 2) % video_size_row)) + if (!((pe + 2) % vc->vc_size_row)) break; } break; case 2: /* line-by-line selection */ - new_sel_start = ps - ps % video_size_row; - new_sel_end = pe + video_size_row - - pe % video_size_row - 2; + new_sel_start = ps - ps % vc->vc_size_row; + new_sel_end = pe + vc->vc_size_row + - pe % vc->vc_size_row - 2; break; case 3: highlight_pointer(pe); @@ -217,11 +226,11 @@ /* select to end of line if on trailing space */ if (new_sel_end > new_sel_start && - !atedge(new_sel_end, video_size_row) && + !atedge(new_sel_end, vc->vc_size_row) && isspace(sel_pos(new_sel_end))) { for (pe = new_sel_end + 2; ; pe += 2) if (!isspace(sel_pos(pe)) || - atedge(pe, video_size_row)) + atedge(pe, vc->vc_size_row)) break; if (isspace(sel_pos(pe))) new_sel_end = pe; @@ -268,7 +277,7 @@ *bp = sel_pos(i); if (!isspace(*bp++)) obp = bp; - if (! ((i + 2) % video_size_row)) { + if (! ((i + 2) % vc->vc_size_row)) { /* strip trailing blanks from line and add newline, unless non-space at end of line. */ if (obp != bp) { @@ -288,12 +297,12 @@ */ int paste_selection(struct tty_struct *tty) { - struct vt_struct *vt = (struct vt_struct *) tty->driver_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; int pasted = 0, count; DECLARE_WAITQUEUE(wait, current); - poke_blanked_console(); - add_wait_queue(&vt->paste_wait, &wait); + poke_blanked_console(vc->display_fg); + add_wait_queue(&vc->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); if (test_bit(TTY_THROTTLED, &tty->flags)) { @@ -305,7 +314,7 @@ tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count); pasted += count; } - remove_wait_queue(&vt->paste_wait, &wait); + remove_wait_queue(&vc->paste_wait, &wait); current->state = TASK_RUNNING; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/serial.c linux-2.5/drivers/char/serial.c --- linux-2.5.20/drivers/char/serial.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/char/serial.c Fri May 17 01:07:34 2002 @@ -57,6 +57,11 @@ * 10/00: add in optional software flow control for serial console. * Kanoj Sarcar (Modified by Theodore Ts'o) * + * 02/02: Fix for AMD Elan bug in transmit irq routine, by + * Christer Weinigel , + * Robert Schwebel , + * Juergen Beisert , + * Theodore Ts'o */ static char *serial_version = "5.05c"; @@ -193,6 +198,7 @@ #include #include #include +#include #if (LINUX_VERSION_CODE >= 131343) #include #endif @@ -231,8 +237,8 @@ #include #include -#ifdef CONFIG_MAC_SERIAL -#define SERIAL_DEV_OFFSET 2 +#if defined(CONFIG_MAC_SERIAL) +#define SERIAL_DEV_OFFSET ((_machine == _MACH_prep || _machine == _MACH_chrp) ? 0 : 2) #else #define SERIAL_DEV_OFFSET 0 #endif @@ -321,11 +327,12 @@ MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA"); #endif /* CONFIG_SERIAL_RSA */ -static struct serial_state rs_table[RS_TABLE_SIZE] = { +struct serial_state rs_table[RS_TABLE_SIZE] = { SERIAL_PORT_DFNS /* Defined in serial.h */ }; #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) +int serial_nr_ports = NR_PORTS; #if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)) #define NR_PCI_BOARDS 8 @@ -645,7 +652,7 @@ if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); break_pressed = 0; goto ignore_char; } @@ -801,7 +808,7 @@ */ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - int status; + int status, iir; struct async_struct * info; int pass_counter = 0; struct async_struct *end_mark = 0; @@ -826,7 +833,7 @@ do { if (!info->tty || - (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { + ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) { if (!end_mark) end_mark = info; goto next; @@ -845,7 +852,9 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if (status & UART_LSR_THRE) + if ((status & UART_LSR_THRE) || + /* for buggy ELAN processors */ + ((iir & UART_IIR_ID) == UART_IIR_THRI)) transmit_chars(info, 0); next: @@ -879,7 +888,7 @@ */ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { - int status; + int status, iir; int pass_counter = 0; struct async_struct * info; #ifdef CONFIG_SERIAL_MULTIPORT @@ -901,6 +910,7 @@ first_multi = inb(multi->port_monitor); #endif + iir = serial_in(info, UART_IIR); do { status = serial_inp(info, UART_LSR); #ifdef SERIAL_DEBUG_INTR @@ -909,18 +919,21 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if (status & UART_LSR_THRE) + if ((status & UART_LSR_THRE) || + /* For buggy ELAN processors */ + ((iir & UART_IIR_ID) == UART_IIR_THRI)) transmit_chars(info, 0); if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 0 +#if SERIAL_DEBUG_INTR printk("rs_single loop break.\n"); #endif break; } + iir = serial_in(info, UART_IIR); #ifdef SERIAL_DEBUG_INTR - printk("IIR = %x...", serial_in(info, UART_IIR)); + printk("IIR = %x...", iir); #endif - } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); + } while ((iir & UART_IIR_NO_INT) == 0); info->last_active = jiffies; #ifdef CONFIG_SERIAL_MULTIPORT if (multi->port_monitor) @@ -1210,7 +1223,7 @@ if (!page) return -ENOMEM; - save_flags(flags); cli(); + spin_lock_irqsave( &info->irq_spinlock, flags); if (info->flags & ASYNC_INITIALIZED) { free_page(page); @@ -1448,11 +1461,11 @@ change_speed(info, 0); info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return 0; errout: - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return retval; } @@ -1476,7 +1489,7 @@ state->irq); #endif - save_flags(flags); cli(); /* Disable interrupts */ + spin_lock_irqsave( &info->irq_spinlock, flags); /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq @@ -1484,41 +1497,6 @@ */ wake_up_interruptible(&info->delta_msr_wait); - /* - * First unlink the serial port from the IRQ chain... - */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[state->irq] = info->next_port; - figure_IRQ_timeout(state->irq); - - /* - * Free the IRQ, if necessary - */ - if (state->irq && (!IRQ_ports[state->irq] || - !IRQ_ports[state->irq]->next_port)) { - if (IRQ_ports[state->irq]) { - free_irq(state->irq, &IRQ_ports[state->irq]); - retval = request_irq(state->irq, rs_interrupt_single, - SA_SHIRQ, "serial", - &IRQ_ports[state->irq]); - - if (retval) - printk("serial shutdown: request_irq: error %d" - " Couldn't reacquire IRQ.\n", retval); - } else - free_irq(state->irq, &IRQ_ports[state->irq]); - } - - if (info->xmit.buf) { - unsigned long pg = (unsigned long) info->xmit.buf; - info->xmit.buf = 0; - free_page(pg); - } - info->IER = 0; serial_outp(info, UART_IER, 0x00); /* disable all intrs */ #ifdef CONFIG_SERIAL_MANY_PORTS @@ -1575,7 +1553,43 @@ serial_outp(info, UART_IER, UART_IERX_SLEEP); } info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, &IRQ_ports[state->irq]); + retval = request_irq(state->irq, rs_interrupt_single, + SA_SHIRQ, "serial", + &IRQ_ports[state->irq]); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, &IRQ_ports[state->irq]); + } + + if (info->xmit.buf) { + unsigned long pg = (unsigned long) info->xmit.buf; + info->xmit.buf = 0; + free_page(pg); + } + + spin_unlock_irqrestore( &info->irq_spinlock, flags); } #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ @@ -2186,11 +2200,15 @@ if ((state->type != PORT_UNKNOWN) && state->port) { #ifdef CONFIG_SERIAL_RSA if (state->type == PORT_RSA) - request_region(state->port + UART_RSA_BASE, - 16, "serial_rsa(set)"); + { + if (!request_region(state->port + UART_RSA_BASE, + 16, "serial_rsa(set)")) + return -EIO; + } else #endif - request_region(state->port,8,"serial(set)"); + if (!request_region(state->port,8,"serial(set)")) + return -EIO; } @@ -3119,6 +3137,7 @@ info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; info->state = sstate; + spin_lock_init(&info->irq_spinlock); info->line = line; info->iomem_base = sstate->iomem_base; info->iomem_reg_shift = sstate->iomem_reg_shift; @@ -3149,6 +3168,10 @@ * enables interrupts for a serial port, linking in its async structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. + * + * Note that on failure, we don't decrement the module use count - the tty + * later will call rs_close, which will decrement it for us as long as + * tty->driver_data is set non-NULL. --rmk */ static int rs_open(struct tty_struct *tty, struct file * filp) { @@ -3169,10 +3192,8 @@ } tty->driver_data = info; info->tty = tty; - if (serial_paranoia_check(info, tty->device, "rs_open")) { - MOD_DEC_USE_COUNT; + if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV; - } #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, @@ -3187,10 +3208,8 @@ */ if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); - if (!page) { - MOD_DEC_USE_COUNT; + if (!page) return -ENOMEM; - } if (tmp_buf) free_page(page); else @@ -3204,7 +3223,6 @@ (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); - MOD_DEC_USE_COUNT; #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); @@ -3217,10 +3235,8 @@ * Start up serial port */ retval = startup(info); - if (retval) { - MOD_DEC_USE_COUNT; + if (retval) return retval; - } retval = block_til_ready(tty, filp, info); if (retval) { @@ -3228,7 +3244,6 @@ printk("rs_open returning after block_til_ready with %d\n", retval); #endif - MOD_DEC_USE_COUNT; return retval; } @@ -3267,14 +3282,17 @@ int ret; unsigned long flags; + /* + * Return zero characters for ports not claimed by driver. + */ + if (state->type == PORT_UNKNOWN) { + return 0; /* ignore unused ports */ + } + ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", state->line, uart_config[state->type].name, - state->port, state->irq); - - if (!state->port || (state->type == PORT_UNKNOWN)) { - ret += sprintf(buf+ret, "\n"); - return ret; - } + (state->port ? state->port : (long)state->iomem_base), + state->irq); /* * Figure out the current RS-232 lines @@ -3663,6 +3681,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; save_flags(flags); cli(); @@ -3915,7 +3934,14 @@ case 6: /* BAR 4*/ case 7: base_idx=idx-2; /* BAR 5*/ } - + + /* AFAVLAB uses a different mixture of BARs and offsets */ + /* Not that ugly ;) -- HW */ + if (dev->vendor == PCI_VENDOR_ID_AFAVLAB && idx >= 4) { + base_idx = 4; + offset = (idx - 4) * 8; + } + /* Some Titan cards are also a little weird */ if (dev->vendor == PCI_VENDOR_ID_TITAN && (dev->device == PCI_DEVICE_ID_TITAN_400L || @@ -4101,12 +4127,14 @@ * interface chip and different configuration methods: * - 10x cards have control registers in IO and/or memory space; * - 20x cards have control registers in standard PCI configuration space. + * + * SIIG initialization functions exported for use by parport_serial.c module. */ #define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) #define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) -static int __devinit +int __devinit pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable) { u16 data, *p; @@ -4131,11 +4159,12 @@ iounmap(p); return 0; } +EXPORT_SYMBOL(pci_siig10x_fn); #define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) #define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) -static int __devinit +int __devinit pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable) { u8 data; @@ -4154,6 +4183,7 @@ } return 0; } +EXPORT_SYMBOL(pci_siig20x_fn); /* Added for EKF Intel i960 serial boards */ static int __devinit @@ -4262,8 +4292,10 @@ pbn_b0_bt_1_115200, pbn_b0_bt_2_115200, + pbn_b0_bt_8_115200, pbn_b0_bt_1_460800, pbn_b0_bt_2_460800, + pbn_b0_bt_4_460800, pbn_b1_1_115200, pbn_b1_2_115200, @@ -4340,8 +4372,10 @@ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 8, 115200 }, /* pbn_b0_bt_8_115200 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 460800 }, /* pbn_b0_bt_4_460800 */ { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */ { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */ @@ -4467,6 +4501,12 @@ return 1; } +static inline int serial_is_redundant(const struct pci_board *board) +{ + return !((board->num_ports > 1) || (board->base_baud != 115200) || + (board->init_fn) || (board->first_uart_offset)); +} + static int __devinit serial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { @@ -4481,7 +4521,8 @@ if (ent->driver_data == pbn_default && serial_pci_guess_board(dev, board)) return -ENODEV; - else if (serial_pci_guess_board(dev, &tmp) == 0) { + else if ((serial_pci_guess_board(dev, &tmp) == 0) && + (serial_is_redundant(board))) { printk(KERN_INFO "Redundant entry in serial pci_table. " "Please send the output of\n" "lspci -vv, this message (%04x,%04x,%04x,%04x)\n" @@ -4724,15 +4765,6 @@ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig10x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_1 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_1 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_1 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig10x_2 }, @@ -4742,15 +4774,6 @@ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig10x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig10x_4 }, @@ -4769,24 +4792,6 @@ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig20x_2 }, @@ -4796,15 +4801,6 @@ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig20x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig20x_4 }, @@ -4849,6 +4845,12 @@ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_460800 }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_1_115200 }, @@ -4861,6 +4863,11 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_2_115200 }, + /* AFAVLAB serial card, from Harald Welte */ + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_115200 }, + /* EKF addition for i960 Boards form EKF with serial port */ { PCI_VENDOR_ID_INTEL, 0x1960, 0xE4BF, PCI_ANY_ID, 0, 0, @@ -5414,6 +5421,7 @@ #endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; + serial_driver.name_base = SERIAL_DEV_OFFSET; serial_driver.num = NR_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; @@ -5425,7 +5433,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -5639,6 +5649,7 @@ info->io_type = req->io_type; info->iomem_base = req->iomem_base; info->iomem_reg_shift = req->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; } autoconfig(state); if (state->type == PORT_UNKNOWN) { @@ -5946,6 +5957,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; quot = state->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); #if defined(__powerpc__) || defined(__alpha__) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/serial167.c linux-2.5/drivers/char/serial167.c --- linux-2.5.20/drivers/char/serial167.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/char/serial167.c Mon Apr 15 02:54:27 2002 @@ -102,6 +102,7 @@ DECLARE_TASK_QUEUE(tq_cyclades); struct tty_driver cy_serial_driver, cy_callout_driver; +static struct console sercons; extern int serial_console; static struct cyclades_port *serial_console_info = NULL; static unsigned int serial_console_cflag = 0; @@ -1261,7 +1262,7 @@ break; } - cli(); + save_flags(flags); cli(); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); @@ -1276,7 +1277,7 @@ up(&tmp_buf_sem); } else { while (1) { - cli(); + save_flags(flags); cli(); c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { @@ -1376,7 +1377,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); printk("cy_throttle ttyS%d\n", info->line); #endif @@ -1412,7 +1413,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); printk("cy_unthrottle ttyS%d\n", info->line); #endif @@ -2394,7 +2395,11 @@ memset(&cy_serial_driver, 0, sizeof(struct tty_driver)); cy_serial_driver.magic = TTY_DRIVER_MAGIC; +#ifdef CONFIG_DEVFS_FS + cy_serial_driver.name = "tts/%d"; +#else cy_serial_driver.name = "ttyS"; +#endif cy_serial_driver.major = TTY_MAJOR; cy_serial_driver.minor_start = 64; cy_serial_driver.num = NR_PORTS; @@ -2408,6 +2413,7 @@ cy_serial_driver.table = serial_table; cy_serial_driver.termios = serial_termios; cy_serial_driver.termios_locked = serial_termios_locked; + cy_serial_driver.console = &sercons; cy_serial_driver.open = cy_open; cy_serial_driver.close = cy_close; cy_serial_driver.write = cy_write; @@ -2429,7 +2435,11 @@ * major number and the subtype code. */ cy_callout_driver = cy_serial_driver; +#ifdef CONFIG_DEVFS_FS + cy_callout_driver.name = "cua/%d"; +#else cy_callout_driver.name = "cua"; +#endif cy_callout_driver.major = TTYAUX_MAJOR; cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/serial_21285.c linux-2.5/drivers/char/serial_21285.c --- linux-2.5.20/drivers/char/serial_21285.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/char/serial_21285.c Sat May 25 19:52:01 2002 @@ -45,6 +45,7 @@ static struct termios *rs285_termios[1]; static struct termios *rs285_termios_locked[1]; +static struct console rs285_cons; static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char; static struct tty_struct *rs285_tty; @@ -312,7 +313,9 @@ rs285_driver.table = rs285_table; rs285_driver.termios = rs285_termios; rs285_driver.termios_locked = rs285_termios_locked; - +#ifdef CONFIG_SERIAL_21285_CONSOLE + rs285_driver.console = &rs285_cons; +#endif rs285_driver.open = rs285_open; rs285_driver.close = rs285_close; rs285_driver.write = rs285_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/serial_amba.c linux-2.5/drivers/char/serial_amba.c --- linux-2.5.20/drivers/char/serial_amba.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/char/serial_amba.c Sat May 25 19:52:01 2002 @@ -356,7 +356,7 @@ #ifdef SUPPORT_SYSRQ if (info->sysrq) { if (ch && time_before(jiffies, info->sysrq)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); info->sysrq = 0; goto ignore_char; } @@ -1789,7 +1789,9 @@ ambanormal_driver.table = ambauart_table; ambanormal_driver.termios = ambauart_termios; ambanormal_driver.termios_locked = ambauart_termios_locked; - +#ifdef CONFIG_SERIAL_AMBA_CONSOLE + ambanormal_driver.console = &ambauart_cons; +#endif ambanormal_driver.open = ambauart_open; ambanormal_driver.close = ambauart_close; ambanormal_driver.write = ambauart_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/serial_tx3912.c linux-2.5/drivers/char/serial_tx3912.c --- linux-2.5.20/drivers/char/serial_tx3912.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/char/serial_tx3912.c Fri Mar 1 18:58:13 2002 @@ -1,8 +1,6 @@ /* * drivers/char/serial_tx3912.c * - * Copyright (C) 1999 Harald Koerfgen - * Copyright (C) 2000 Jim Pick * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) * * This program is free software; you can redistribute it and/or modify @@ -15,19 +13,13 @@ #include #include #include -#include -#include #include -#include -#include #include #include -#include -#include +#include #include #include #include -#include #include #include "serial_tx3912.h" @@ -62,35 +54,19 @@ }; /* - * Structures and such for TTY sessions and usage counts + * Structures and usage counts */ static struct tty_driver rs_driver, rs_callout_driver; -static struct tty_struct * rs_table[TX3912_UART_NPORTS] = { NULL, }; -static struct termios ** rs_termios; -static struct termios ** rs_termios_locked; -struct rs_port *rs_ports; -int rs_refcount; -int rs_initialized = 0; - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- +static struct tty_struct **rs_tty; +static struct termios **rs_termios; +static struct termios **rs_termios_locked; +static struct rs_port *rs_port; +static int rs_refcount; +static int rs_initialized; + + +/* + * Receive a character */ static inline void receive_char_pio(struct rs_port *port) { @@ -98,83 +74,34 @@ unsigned char ch; int counter = 2048; - /* While there are characters, get them ... */ - while (counter>0) { - if (!(inl(port->base + TX3912_UART_CTRL1) & UART_RX_HOLD_FULL)) + /* While there are characters */ + while (counter > 0) { + if (!(inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_RXHOLDFULL)) break; - ch = inb(port->base + TX3912_UART_DATA); + ch = inb(TX3912_UARTA_DATA); if (tty->flip.count < TTY_FLIPBUF_SIZE) { *tty->flip.char_buf_ptr++ = ch; *tty->flip.flag_buf_ptr++ = 0; tty->flip.count++; } - udelay(1); /* Allow things to happen - it take a while */ + udelay(1); counter--; } - if (!counter) - printk( "Ugh, looped in receive_char_pio!\n" ); tty_flip_buffer_push(tty); - -#if 0 - /* Now handle error conditions */ - if (*status & (INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_PARITYERR_INT) | - INTTYPE(UART_BREAK_INT))) { - - /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. - */ - if (*status & port->ignore_status_mask) { - goto ignore_char; - } - *status &= port->read_status_mask; - - if (*status & INTTYPE(UART_BREAK_INT)) { - rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "handling break...."); - *tty->flip.flag_buf_ptr = TTY_BREAK; - } - else if (*status & INTTYPE(UART_PARITYERR_INT)) { - *tty->flip.flag_buf_ptr = TTY_PARITY; - } - else if (*status & INTTYPE(UART_FRAMEERR_INT)) { - *tty->flip.flag_buf_ptr = TTY_FRAME; - } - if (*status & INTTYPE(UART_RXOVERRUN_INT)) { - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } - } - } - - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; - -ignore_char: - tty_flip_buffer_push(tty); -#endif } +/* + * Transmit a character + */ static inline void transmit_char_pio(struct rs_port *port) { - /* While I'm able to transmit ... */ + /* TX while bytes available */ for (;;) { - if (!(inl(port->base + TX3912_UART_CTRL1) & UART_TX_EMPTY)) + if (!(inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_EMPTY)) break; else if (port->x_char) { - outb(port->x_char, port->base + TX3912_UART_DATA); + outb(port->x_char, TX3912_UARTA_DATA); port->icount.tx++; port->x_char = 0; } @@ -184,14 +111,14 @@ } else { outb(port->gs.xmit_buf[port->gs.xmit_tail++], - port->base + TX3912_UART_DATA); + TX3912_UARTA_DATA); port->icount.tx++; port->gs.xmit_tail &= SERIAL_XMIT_SIZE-1; if (--port->gs.xmit_cnt <= 0) { break; } } - udelay(10); /* Allow things to happen - it take a while */ + udelay(10); } if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped || @@ -203,519 +130,418 @@ if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup) (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); - rs_dprintk (TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", + rs_dprintk(TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", port->gs.wakeup_chars); wake_up_interruptible(&port->gs.tty->write_wait); } } - - +/* + * We don't have MSR + */ static inline void check_modem_status(struct rs_port *port) { - /* We don't have a carrier detect line - but just respond - like we had one anyways so that open() becomes unblocked */ wake_up_interruptible(&port->gs.open_wait); } -int count = 0; - /* - * This is the serial driver's interrupt routine (inlined, because - * there are two different versions of this, one for each serial port, - * differing only by the bits used in interrupt status 2 register) + * RX interrupt handler */ - -static inline void rs_rx_interrupt(int irq, void *dev_id, - struct pt_regs * regs, int intshift) +static inline void rs_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct rs_port * port; - unsigned long int2status; - unsigned long flags; - unsigned long ints; + unsigned long flags, status; save_and_cli(flags); - port = (struct rs_port *)dev_id; - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift); - - /* Get the interrrupts we have enabled */ - int2status = IntStatus2 & IntEnable2; + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "rs_rx_interrupt..."); - /* Get interrupts in easy to use form */ - ints = int2status >> intshift; + /* Get the interrupts */ + status = inl(TX3912_INT2_STATUS); /* Clear any interrupts we might be about to handle */ - IntClear2 = int2status & ( - (INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT) | - INTTYPE(UART_RX_INT)) << intshift); + outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR); - if (!port || !port->gs.tty) { + if(!rs_port || !rs_port->gs.tty) { restore_flags(flags); return; } /* RX Receiver Holding Register Overrun */ - if (ints & INTTYPE(UART_RXOVERRUN_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "overrun"); - port->icount.overrun++; + if(status & TX3912_INT2_UARTATXOVERRUNINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "overrun"); + rs_port->icount.overrun++; } /* RX Frame Error */ - if (ints & INTTYPE(UART_FRAMEERR_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "frame error"); - port->icount.frame++; + if(status & TX3912_INT2_UARTAFRAMEERRINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "frame error"); + rs_port->icount.frame++; } /* Break signal received */ - if (ints & INTTYPE(UART_BREAK_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "break"); - port->icount.brk++; + if(status & TX3912_INT2_UARTABREAKINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "break"); + rs_port->icount.brk++; } /* RX Parity Error */ - if (ints & INTTYPE(UART_PARITYERR_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "parity error"); - port->icount.parity++; + if(status & TX3912_INT2_UARTAPARITYINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "parity error"); + rs_port->icount.parity++; } - /* Receive byte (non-DMA) */ - if (ints & INTTYPE(UART_RX_INT)) { - receive_char_pio(port); + /* Byte received */ + if(status & TX3912_INT2_UARTARXINT) { + receive_char_pio(rs_port); } restore_flags(flags); - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); } -static inline void rs_tx_interrupt(int irq, void *dev_id, - struct pt_regs * regs, int intshift) +/* + * TX interrupt handler + */ +static inline void rs_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct rs_port * port; - unsigned long int2status; - unsigned long flags; - unsigned long ints; + unsigned long flags, status; save_and_cli(flags); - port = (struct rs_port *)dev_id; - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift); + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "rs_tx_interrupt..."); - /* Get the interrrupts we have enabled */ - int2status = IntStatus2 & IntEnable2; + /* Get the interrupts */ + status = inl(TX3912_INT2_STATUS); - if (!port || !port->gs.tty) { + if(!rs_port || !rs_port->gs.tty) { restore_flags(flags); return; } - /* Get interrupts in easy to use form */ - ints = int2status >> intshift; + /* Clear interrupts */ + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); - /* Clear any interrupts we might be about to handle */ - IntClear2 = int2status & ( - (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << intshift); - - /* TX holding register empty, so transmit byte (non-DMA) */ - if (ints & (INTTYPE(UART_TX_INT) | INTTYPE(UART_EMPTY_INT))) { - transmit_char_pio(port); + /* TX holding register empty - transmit a byte */ + if(status & TX3912_INT2_UARTAEMPTYINT) { + transmit_char_pio(rs_port); } /* TX Transmit Holding Register Overrun (shouldn't happen) */ - if (ints & INTTYPE(UART_TXOVERRUN_INT)) { - printk ( "rs: TX overrun\n"); + if(status & TX3912_INT2_UARTATXOVERRUNINT) { + printk( "rs_tx_interrupt: TX overrun\n"); } - /* - check_modem_status(); - */ - restore_flags(flags); - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); -} - -static void rs_rx_interrupt_uarta(int irq, void *dev_id, - struct pt_regs * regs) -{ - rs_rx_interrupt(irq, dev_id, regs, UARTA_SHIFT); -} - -static void rs_tx_interrupt_uarta(int irq, void *dev_id, - struct pt_regs * regs) -{ - rs_tx_interrupt(irq, dev_id, regs, UARTA_SHIFT); + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); } /* - *********************************************************************** - * Here are the routines that actually * - * interface with the generic_serial driver * - *********************************************************************** + * Here are the routines that actually interface with the generic driver */ static void rs_disable_tx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - port->gs.flags &= ~GS_TX_INTEN; - IntEnable2 &= ~((INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift); - - IntClear2 = (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift; + outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_ENABLE); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); restore_flags(flags); } static void rs_enable_tx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - IntClear2 = (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift; - - IntEnable2 |= (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift; - - /* Send a char to start TX interrupts happening */ - transmit_char_pio(port); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); + outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_ENABLE); + transmit_char_pio(rs_port); restore_flags(flags); } static void rs_disable_rx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - IntEnable2 &= ~((INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift); - - IntClear2 = (INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift; + outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_RX_BITS, + TX3912_INT2_ENABLE); + outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR); restore_flags(flags); } static void rs_enable_rx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - IntEnable2 |= (INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift; - - /* Empty the input buffer - apparently this is *vital* */ - while (inl(port->base + TX3912_UART_CTRL1) & UART_RX_HOLD_FULL) { - inb(port->base + TX3912_UART_DATA); - } - - IntClear2 = (INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift; + outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_RX_BITS, + TX3912_INT2_ENABLE); + while (inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_RXHOLDFULL) + inb(TX3912_UARTA_DATA); + outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR); restore_flags(flags); } - +/* + * We have no CD + */ static int rs_get_CD (void * ptr) { - /* No Carried Detect in Hardware - just return true */ - func_exit(); - return (1); + return 1; } +/* + * Shut down the port + */ static void rs_shutdown_port (void * ptr) { - struct rs_port *port = ptr; - func_enter(); - - port->gs.flags &= ~GS_ACTIVE; - + rs_port->gs.flags &= ~GS_ACTIVE; func_exit(); } static int rs_set_real_termios (void *ptr) { - struct rs_port *port = ptr; - int t; + unsigned int ctrl1 = 0; + unsigned int ctrl2 = 0; - switch (port->gs.baud) { - /* Save some typing work... */ -#define e(x) case x:t= TX3912_UART_CTRL2_B ## x ; break - e(300);e(600);e(1200);e(2400);e(4800);e(9600); - e(19200);e(38400);e(57600);e(76800);e(115200);e(230400); - case 0 :t = -1; - break; - default: - /* Can I return "invalid"? */ - t = TX3912_UART_CTRL2_B9600; - printk (KERN_INFO "rs: unsupported baud rate: %d.\n", port->gs.baud); - break; - } -#undef e - if (t >= 0) { - /* Jim: Set Hardware Baud rate - there is some good - code in drivers/char/serial.c */ - - /* Program hardware for parity, data bits, stop bits (note: these are hardcoded to 8N1 */ - UartA_Ctrl1 &= 0xf000000f; - UartA_Ctrl1 &= ~(UART_DIS_TXD | SER_SEVEN_BIT | SER_EVEN_PARITY | SER_TWO_STOP); - -#define CFLAG port->gs.tty->termios->c_cflag - if (C_PARENB(port->gs.tty)) { - if (!C_PARODD(port->gs.tty)) - UartA_Ctrl1 |= SER_EVEN_PARITY; - else - UartA_Ctrl1 |= SER_ODD_PARITY; - } - if ((CFLAG & CSIZE)==CS6) - printk(KERN_ERR "6 bits not supported\n"); - if ((CFLAG & CSIZE)==CS5) - printk(KERN_ERR "5 bits not supported\n"); - if ((CFLAG & CSIZE)==CS7) - UartA_Ctrl1 |= SER_SEVEN_BIT; - if (C_CSTOPB(port->gs.tty)) - UartA_Ctrl1 |= SER_TWO_STOP; - - outl(t, port->base + TX3912_UART_CTRL2); - outl(0, port->base + TX3912_UART_DMA_CTRL1); - outl(0, port->base + TX3912_UART_DMA_CTRL2); - UartA_Ctrl1 |= TX3912_UART_CTRL1_UARTON; + /* Set baud rate */ + switch (rs_port->gs.baud) { + case 0: + goto done; + case 1200: + ctrl2 = TX3912_UART_CTRL2_B1200; + break; + case 2400: + ctrl2 = TX3912_UART_CTRL2_B2400; + break; + case 4800: + ctrl2 = TX3912_UART_CTRL2_B4800; + break; + case 9600: + ctrl2 = TX3912_UART_CTRL2_B9600; + break; + case 19200: + ctrl2 = TX3912_UART_CTRL2_B19200; + break; + case 38400: + ctrl2 = TX3912_UART_CTRL2_B38400; + break; + case 57600: + ctrl2 = TX3912_UART_CTRL2_B57600; + break; + case 115200: + default: + ctrl2 = TX3912_UART_CTRL2_B115200; + break; + } + + /* Clear current UARTA settings */ + ctrl1 = inl(TX3912_UARTA_CTRL1) & 0xf000000f; - /* wait until UARTA is stable */ - while (~UartA_Ctrl1 & TX3912_UART_CTRL1_UARTON); + /* Set parity */ + if(C_PARENB(rs_port->gs.tty)) { + if (!C_PARODD(rs_port->gs.tty)) + ctrl1 |= (TX3912_UART_CTRL1_ENPARITY | + TX3912_UART_CTRL1_EVENPARITY); + else + ctrl1 |= TX3912_UART_CTRL1_ENPARITY; } - func_exit (); - return 0; + /* Set data size */ + switch(rs_port->gs.tty->termios->c_cflag & CSIZE) { + case CS7: + ctrl1 |= TX3912_UART_CTRL1_BIT_7; + break; + case CS5: + case CS6: + printk(KERN_ERR "Data byte size unsupported. Defaulting to CS8\n"); + case CS8: + default: + ctrl1 &= ~TX3912_UART_CTRL1_BIT_7; + } + + /* Set stop bits */ + if(C_CSTOPB(rs_port->gs.tty)) + ctrl1 |= TX3912_UART_CTRL1_TWOSTOP; + + /* Write the control registers */ + outl(ctrl2, TX3912_UARTA_CTRL2); + outl(0, TX3912_UARTA_DMA_CTRL1); + outl(0, TX3912_UARTA_DMA_CTRL2); + outl(ctrl1, TX3912_UARTA_CTRL1); + + /* Loop until the UART is on */ + while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON); + +done: + func_exit(); + return 0; } +/* + * Anyone in the buffer? + */ static int rs_chars_in_buffer (void * ptr) { - struct rs_port *port = ptr; - int scratch; - - scratch = inl(port->base + TX3912_UART_CTRL1); - - return ((scratch & UART_TX_EMPTY) ? 0 : 1); + return ((inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_EMPTY) ? 0 : 1); } -/* ********************************************************************** * - * Here are the routines that actually * - * interface with the rest of the system * - * ********************************************************************** */ -static int rs_open (struct tty_struct * tty, struct file * filp) +/* + * Open the serial port + */ +static int rs_open(struct tty_struct * tty, struct file * filp) { - struct rs_port *port; - int retval, line; + int retval; func_enter(); - if (!rs_initialized) { + if(!rs_initialized) { return -EIO; } - line = minor(tty->device) - tty->driver.minor_start; - rs_dprintk (TX3912_UART_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p)\n", - (int) current->pid, line, tty, current->tty); - - if ((line < 0) || (line >= TX3912_UART_NPORTS)) + if(minor(tty->device) - tty->driver.minor_start) { return -ENODEV; + } - /* Pre-initialized already */ - port = & rs_ports[line]; - - rs_dprintk (TX3912_UART_DEBUG_OPEN, "port = %p\n", port); - - tty->driver_data = port; - port->gs.tty = tty; - port->gs.count++; + rs_dprintk(TX3912_UART_DEBUG_OPEN, "Serial opening...\n"); - rs_dprintk (TX3912_UART_DEBUG_OPEN, "starting port\n"); + tty->driver_data = rs_port; + rs_port->gs.tty = tty; + rs_port->gs.count++; /* * Start up serial port */ - retval = gs_init_port(&port->gs); - rs_dprintk (TX3912_UART_DEBUG_OPEN, "done gs_init\n"); - if (retval) { - port->gs.count--; + retval = gs_init_port(&rs_port->gs); + rs_dprintk(TX3912_UART_DEBUG_OPEN, "Finished gs_init...\n"); + if(retval) { + rs_port->gs.count--; return retval; } - port->gs.flags |= GS_ACTIVE; - - rs_dprintk (TX3912_UART_DEBUG_OPEN, "before inc_use_count (count=%d.\n", - port->gs.count); - if (port->gs.count == 1) { + rs_port->gs.flags |= GS_ACTIVE; + if(rs_port->gs.count == 1) { MOD_INC_USE_COUNT; } - rs_dprintk (TX3912_UART_DEBUG_OPEN, "after inc_use_count\n"); - - /* Jim: Initialize port hardware here */ - - /* Enable high-priority interrupts for UARTA */ - IntEnable6 |= INT6_UARTARXINT; - rs_enable_rx_interrupts(&rs_ports[0]); - retval = gs_block_til_ready(&port->gs, filp); - rs_dprintk (TX3912_UART_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", - retval, port->gs.count); + rs_enable_rx_interrupts(rs_port); + rs_enable_tx_interrupts(rs_port); - if (retval) { + retval = gs_block_til_ready(&rs_port->gs, filp); + if(retval) { MOD_DEC_USE_COUNT; - port->gs.count--; + rs_port->gs.count--; return retval; } - /* tty->low_latency = 1; */ - if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { + if((rs_port->gs.count == 1) && + (rs_port->gs.flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) - *tty->termios = port->gs.normal_termios; + *tty->termios = rs_port->gs.normal_termios; else - *tty->termios = port->gs.callout_termios; - rs_set_real_termios (port); + *tty->termios = rs_port->gs.callout_termios; + rs_set_real_termios(rs_port); } - port->gs.session = current->session; - port->gs.pgrp = current->pgrp; + rs_port->gs.session = current->session; + rs_port->gs.pgrp = current->pgrp; func_exit(); - /* Jim */ -/* cli(); */ - return 0; - } - - -static void rs_close (void *ptr) +/* + * Close the serial port + */ +static void rs_close(void *ptr) { - func_enter (); - - /* Anything to do here? */ - + func_enter(); MOD_DEC_USE_COUNT; - func_exit (); + func_exit(); } - -/* I haven't the foggiest why the decrement use count has to happen - here. The whole linux serial drivers stuff needs to be redesigned. - My guess is that this is a hack to minimize the impact of a bug - elsewhere. Thinking about it some more. (try it sometime) Try - running minicom on a serial port that is driven by a modularized - driver. Have the modem hangup. Then remove the driver module. Then - exit minicom. I expect an "oops". -- REW */ -static void rs_hungup (void *ptr) +/* + * Hang up the serial port + */ +static void rs_hungup(void *ptr) { - func_enter (); + func_enter(); MOD_DEC_USE_COUNT; - func_exit (); + func_exit(); } -static int rs_ioctl (struct tty_struct * tty, struct file * filp, +/* + * Serial ioctl call + */ +static int rs_ioctl(struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { - int rc; - struct rs_port *port = tty->driver_data; - int ival; + int ival, rc; rc = 0; switch (cmd) { - case TIOCGSOFTCAR: - rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + case TIOCGSOFTCAR: + rc = put_user((tty->termios->c_cflag & CLOCAL) ? 1 : 0, (unsigned int *) arg); - break; - case TIOCSSOFTCAR: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(int))) == 0) { - get_user(ival, (unsigned int *) arg); - tty->termios->c_cflag = - (tty->termios->c_cflag & ~CLOCAL) | - (ival ? CLOCAL : 0); - } - break; - case TIOCGSERIAL: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct))) == 0) - rc = gs_getserial(&port->gs, (struct serial_struct *) arg); - break; - case TIOCSSERIAL: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(struct serial_struct))) == 0) - rc = gs_setserial(&port->gs, (struct serial_struct *) arg); - break; - default: - rc = -ENOIOCTLCMD; - break; + break; + case TIOCSSOFTCAR: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(int))) == 0) { + get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCGSERIAL: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_getserial(&rs_port->gs, (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_setserial(&rs_port->gs, (struct serial_struct *) arg); + break; + default: + rc = -ENOIOCTLCMD; + break; } - /* func_exit(); */ return rc; } - /* - * This function is used to send a high-priority XON/XOFF character to - * the device + * Send xchar */ static void rs_send_xchar(struct tty_struct * tty, char ch) { - struct rs_port *port = (struct rs_port *)tty->driver_data; - func_enter (); + func_enter(); - port->x_char = ch; + rs_port->x_char = ch; if (ch) { - /* Make sure transmit interrupts are on */ rs_enable_tx_interrupts(tty); } func_exit(); } - /* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ + * Throttle characters as directed by upper tty layer */ static void rs_throttle(struct tty_struct * tty) { @@ -726,17 +552,19 @@ tty->ldisc.chars_in_buffer(tty)); #endif - func_enter (); + func_enter(); if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); - func_exit (); + func_exit(); } +/* + * Un-throttle characters as directed by upper tty layer + */ static void rs_unthrottle(struct tty_struct * tty) { - struct rs_port *port = (struct rs_port *)tty->driver_data; #ifdef TX3912_UART_DEBUG_THROTTLE char buf[64]; @@ -747,8 +575,8 @@ func_enter(); if (I_IXOFF(tty)) { - if (port->x_char) - port->x_char = 0; + if (rs_port->x_char) + rs_port->x_char = 0; else rs_send_xchar(tty, START_CHAR(tty)); } @@ -756,105 +584,75 @@ func_exit(); } - - - - -/* ********************************************************************** * - * Here are the initialization routines. * - * ********************************************************************** */ - -void * ckmalloc (int size) -{ - void *p; - - p = kmalloc(size, GFP_KERNEL); - if (p) - memset(p, 0, size); - return p; -} - - - -static int rs_init_portstructs(void) +/* + * Initialize the serial port + */ +void __init tx3912_rs_init(void) { - struct rs_port *port; - int i; - - /* Debugging */ func_enter(); + rs_dprintk(TX3912_UART_DEBUG_INIT, "Initializing serial...\n"); - rs_ports = ckmalloc(TX3912_UART_NPORTS * sizeof (struct rs_port)); - if (!rs_ports) - return -ENOMEM; - - rs_termios = ckmalloc(TX3912_UART_NPORTS * sizeof (struct termios *)); - if (!rs_termios) { - kfree (rs_ports); - return -ENOMEM; + /* Allocate critical structures */ + if(!(rs_tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL))) { + return; } - - rs_termios_locked = ckmalloc(TX3912_UART_NPORTS * sizeof (struct termios *)); - if (!rs_termios_locked) { - kfree (rs_ports); - kfree (rs_termios); - return -ENOMEM; + if(!(rs_port = kmalloc(sizeof(struct rs_port), GFP_KERNEL))) { + kfree(rs_tty); + return; + } + if(!(rs_termios = kmalloc(sizeof(struct termios), GFP_KERNEL))) { + kfree(rs_port); + kfree(rs_tty); + return; + } + if(!(rs_termios_locked = kmalloc(sizeof(struct termios), GFP_KERNEL))) { + kfree(rs_termios); + kfree(rs_port); + kfree(rs_tty); + return; } - /* Adjust the values in the "driver" */ - rs_driver.termios = rs_termios; - rs_driver.termios_locked = rs_termios_locked; + /* Zero out the structures */ + memset(rs_tty, 0, sizeof(struct tty_struct)); + memset(rs_port, 0, sizeof(struct rs_port)); + memset(rs_termios, 0, sizeof(struct termios)); + memset(rs_termios_locked, 0, sizeof(struct termios)); + memset(&rs_driver, 0, sizeof(rs_driver)); + memset(&rs_callout_driver, 0, sizeof(rs_callout_driver)); - port = rs_ports; - for (i=0; i < TX3912_UART_NPORTS;i++) { - rs_dprintk (TX3912_UART_DEBUG_INIT, "initing port %d\n", i); - port->gs.callout_termios = tty_std_termios; - port->gs.normal_termios = tty_std_termios; - port->gs.magic = SERIAL_MAGIC; - port->gs.close_delay = HZ/2; - port->gs.closing_wait = 30 * HZ; - port->gs.rd = &rs_real_driver; + /* Fill in hardware specific port structure */ + rs_port->gs.callout_termios = tty_std_termios; + rs_port->gs.normal_termios = tty_std_termios; + rs_port->gs.magic = SERIAL_MAGIC; + rs_port->gs.close_delay = HZ/2; + rs_port->gs.closing_wait = 30 * HZ; + rs_port->gs.rd = &rs_real_driver; #ifdef NEW_WRITE_LOCKING - port->gs.port_write_sem = MUTEX; + rs_port->gs.port_write_sem = MUTEX; #endif #ifdef DECLARE_WAITQUEUE - init_waitqueue_head(&port->gs.open_wait); - init_waitqueue_head(&port->gs.close_wait); + init_waitqueue_head(&rs_port->gs.open_wait); + init_waitqueue_head(&rs_port->gs.close_wait); #endif - port->base = (i == 0) ? TX3912_UARTA_BASE : TX3912_UARTB_BASE; - port->intshift = (i == 0) ? UARTA_SHIFT : UARTB_SHIFT; - rs_dprintk (TX3912_UART_DEBUG_INIT, "base 0x%08lx intshift %d\n", - port->base, port->intshift); - port++; - } - - func_exit(); - return 0; -} - -static int rs_init_drivers(void) -{ - int error; - - func_enter(); - memset(&rs_driver, 0, sizeof(rs_driver)); + /* Fill in generic serial driver structures */ rs_driver.magic = TTY_DRIVER_MAGIC; rs_driver.driver_name = "serial"; rs_driver.name = "ttyS"; rs_driver.major = TTY_MAJOR; rs_driver.minor_start = 64; - rs_driver.num = TX3912_UART_NPORTS; + rs_driver.num = 1; rs_driver.type = TTY_DRIVER_TYPE_SERIAL; rs_driver.subtype = SERIAL_TYPE_NORMAL; rs_driver.init_termios = tty_std_termios; - rs_driver.init_termios.c_cflag = - B115200 | CS8 | CREAD | HUPCL | CLOCAL; + rs_driver.init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; rs_driver.refcount = &rs_refcount; - rs_driver.table = rs_table; + rs_driver.table = rs_tty; rs_driver.termios = rs_termios; rs_driver.termios_locked = rs_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + rs_driver.console = &sercons; +#endif rs_driver.open = rs_open; rs_driver.close = gs_close; rs_driver.write = gs_write; @@ -870,92 +668,59 @@ rs_driver.stop = gs_stop; rs_driver.start = gs_start; rs_driver.hangup = gs_hangup; - rs_callout_driver = rs_driver; rs_callout_driver.name = "cua"; rs_callout_driver.major = TTYAUX_MAJOR; rs_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if ((error = tty_register_driver(&rs_driver))) { - printk(KERN_ERR "Couldn't register serial driver, error = %d\n", - error); - return 1; + /* Register serial and callout drivers */ + if(tty_register_driver(&rs_driver)) { + printk(KERN_ERR "Unable to register serial driver\n"); + goto error; } - if ((error = tty_register_driver(&rs_callout_driver))) { + if(tty_register_driver(&rs_callout_driver)) { tty_unregister_driver(&rs_driver); - printk(KERN_ERR "Couldn't register callout driver, error = %d\n", - error); - return 1; + printk(KERN_ERR "Unable to register callout driver\n"); + goto error; } - func_exit(); - return 0; -} - - -void __init tx3912_rs_init(void) -{ - int rc; - - - func_enter(); - rs_dprintk (TX3912_UART_DEBUG_INIT, "Initing serial module... (rs_debug=%d)\n", rs_debug); + /* Assign IRQs */ + if(request_irq(2, rs_tx_interrupt, SA_SHIRQ, + "uarta_tx", rs_port)) { + printk(KERN_ERR "Cannot allocate IRQ for UARTA_TX.\n"); + goto error; + } - rc = rs_init_portstructs (); - rs_init_drivers (); - if (request_irq(2, rs_tx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT, - "serial", &rs_ports[0])) { - printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n"); - rc = 0; - } - if (request_irq(3, rs_rx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT, - "serial", &rs_ports[0])) { - printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n"); - rc = 0; + if(request_irq(3, rs_rx_interrupt, SA_SHIRQ, + "uarta_rx", rs_port)) { + printk(KERN_ERR "Cannot allocate IRQ for UARTA_RX.\n"); + goto error; } - IntEnable6 |= INT6_UARTARXINT; - rs_enable_rx_interrupts(&rs_ports[0]); + /* Enable the serial receive interrupt */ + rs_enable_rx_interrupts(rs_port); #ifndef CONFIG_SERIAL_TX3912_CONSOLE -{ - unsigned int scratch = 0; + /* Write the control registers */ + outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_CTRL2); + outl(0x00000000, TX3912_UARTA_DMA_CTRL1); + outl(0x00000000, TX3912_UARTA_DMA_CTRL2); + outl(inl(TX3912_UARTA_CTRL1) | TX3912_UART_CTRL1_ENUART, + TX3912_UARTA_CTRL1); - /* Setup master clock for UART */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch &= ~TX3912_CLK_CTRL_SIBMCLKDIV_MASK; - scratch |= ((0x2 << TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT) & - TX3912_CLK_CTRL_SIBMCLKDIV_MASK) - | TX3912_CLK_CTRL_SIBMCLKDIR - | TX3912_CLK_CTRL_ENSIBMCLK - | TX3912_CLK_CTRL_CSERSEL; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Configure UARTA clock */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch |= ((0x3 << TX3912_CLK_CTRL_CSERDIV_SHIFT) & - TX3912_CLK_CTRL_CSERDIV_MASK) - | TX3912_CLK_CTRL_ENCSERCLK - | TX3912_CLK_CTRL_ENUARTACLK; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Setup UARTA for 115200,8N1 */ - outl(0, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_BASE + TX3912_UART_CTRL2); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL1); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL2); - - /* Enable UARTA */ - outl(TX3912_UART_CTRL1_ENUART, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - while (~inl(TX3912_UARTA_BASE + TX3912_UART_CTRL1) & - TX3912_UART_CTRL1_UARTON); -} + /* Loop until the UART is on */ + while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON); #endif - /* Note: I didn't do anything to enable the second UART */ - if (rc >= 0) - rs_initialized++; + rs_initialized = 1; + func_exit(); + return; +error: + kfree(rs_termios_locked); + kfree(rs_termios); + kfree(rs_port); + kfree(rs_tty); func_exit(); } @@ -963,40 +728,37 @@ * Begin serial console routines */ #ifdef CONFIG_SERIAL_TX3912_CONSOLE - void serial_outc(unsigned char c) { int i; unsigned long int2; - #define BUSY_WAIT 10000 - - /* - * Turn UARTA interrupts off - */ - int2 = IntEnable2; - IntEnable2 &= - ~(INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY); - - /* - * The UART_TX_EMPTY bit in UartA_Ctrl1 seems - * not to be very reliable :-( - * - * Wait for the Tx register to become empty - */ - for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++); - IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY; - UartA_Data = c; - for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++); - IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY; + /* Disable UARTA_TX interrupts */ + int2 = inl(TX3912_INT2_ENABLE); + outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_ENABLE); + + /* Wait for UARTA_TX register to empty */ + i = 10000; + while(!(inl(TX3912_INT2_STATUS) & TX3912_INT2_UARTATXINT) && i--); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); + + /* Send the character */ + outl(c, TX3912_UARTA_DATA); + + /* Wait for UARTA_TX register to empty */ + i = 10000; + while(!(inl(TX3912_INT2_STATUS) & TX3912_INT2_UARTATXINT) && i--); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); - IntEnable2 = int2; + /* Enable UARTA_TX interrupts */ + outl(int2, TX3912_INT2_ENABLE); } static void serial_console_write(struct console *co, const char *s, - unsigned count) + unsigned count) { - unsigned int i; + unsigned int i; for (i = 0; i < count; i++) { if (*s == '\n') @@ -1012,36 +774,78 @@ static __init int serial_console_setup(struct console *co, char *options) { - unsigned int scratch = 0; + int baud = 115200; + int bits = 8; + int parity = 'n'; + char *s; + unsigned int ctrl1 = 0; + unsigned int ctrl2 = 0; + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s++ - '0'; + } + + switch(baud) { + case 1200: + ctrl2 = TX3912_UART_CTRL2_B1200; + break; + case 2400: + ctrl2 = TX3912_UART_CTRL2_B2400; + break; + case 4800: + ctrl2 = TX3912_UART_CTRL2_B4800; + break; + case 9600: + ctrl2 = TX3912_UART_CTRL2_B9600; + break; + case 19200: + ctrl2 = TX3912_UART_CTRL2_B19200; + break; + case 38400: + ctrl2 = TX3912_UART_CTRL2_B38400; + break; + case 57600: + ctrl2 = TX3912_UART_CTRL2_B57600; + break; + case 115200: + default: + ctrl2 = TX3912_UART_CTRL2_B115200; + break; + } + + switch(bits) { + case 7: + ctrl1 = TX3912_UART_CTRL1_BIT_7; + break; + default: + break; + } + + switch(parity) { + case 'o': case 'O': + ctrl1 |= TX3912_UART_CTRL1_ENPARITY; + break; + case 'e': case 'E': + ctrl1 |= (TX3912_UART_CTRL1_ENPARITY | + TX3912_UART_CTRL1_EVENPARITY); + break; + default: + break; + } + + /* Write the control registers */ + outl(ctrl2, TX3912_UARTA_CTRL2); + outl(0x00000000, TX3912_UARTA_DMA_CTRL1); + outl(0x00000000, TX3912_UARTA_DMA_CTRL2); + outl((ctrl1 | TX3912_UART_CTRL1_ENUART), TX3912_UARTA_CTRL1); - /* Setup master clock for UART */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch &= ~TX3912_CLK_CTRL_SIBMCLKDIV_MASK; - scratch |= ((0x2 << TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT) & - TX3912_CLK_CTRL_SIBMCLKDIV_MASK) - | TX3912_CLK_CTRL_SIBMCLKDIR - | TX3912_CLK_CTRL_ENSIBMCLK - | TX3912_CLK_CTRL_CSERSEL; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Configure UARTA clock */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch |= ((0x3 << TX3912_CLK_CTRL_CSERDIV_SHIFT) & - TX3912_CLK_CTRL_CSERDIV_MASK) - | TX3912_CLK_CTRL_ENCSERCLK - | TX3912_CLK_CTRL_ENUARTACLK; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Setup UARTA for 115200,8N1 */ - outl(0, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_BASE + TX3912_UART_CTRL2); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL1); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL2); - - /* Enable UARTA */ - outl(TX3912_UART_CTRL1_ENUART, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - while (~inl(TX3912_UARTA_BASE + TX3912_UART_CTRL1) & - TX3912_UART_CTRL1_UARTON); + /* Loop until the UART is on */ + while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON); return 0; } @@ -1059,5 +863,4 @@ { register_console(&sercons); } - #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/serial_tx3912.h linux-2.5/drivers/char/serial_tx3912.h --- linux-2.5.20/drivers/char/serial_tx3912.h Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/char/serial_tx3912.h Fri Mar 15 17:47:45 2002 @@ -1,8 +1,6 @@ /* * drivers/char/serial_tx3912.h * - * Copyright (C) 1999 Harald Koerfgen - * Copyright (C) 2000 Jim Pick * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) * * This program is free software; you can redistribute it and/or modify @@ -14,27 +12,6 @@ #include #include -/* UART Interrupt (Interrupt 2) bits (UARTA,UARTB) */ -#define UART_RX_INT 9 /* receiver holding register full (31, 21) */ -#define UART_RXOVERRUN_INT 8 /* receiver overrun error (30, 20) */ -#define UART_FRAMEERR_INT 7 /* receiver frame error (29, 19) */ -#define UART_BREAK_INT 6 /* received break signal (28, 18) */ -#define UART_PARITYERR_INT 5 /* receiver parity error (27, 17) */ -#define UART_TX_INT 4 /* transmit holding register empty (26, 16) */ -#define UART_TXOVERRUN_INT 3 /* transmit overrun error (25, 15) */ -#define UART_EMPTY_INT 2 /* both trans/recv regs empty (24, 14) */ -#define UART_DMAFULL_INT 1 /* DMA at end of buffer (23, 13) */ -#define UART_DMAHALF_INT 0 /* DMA halfway through buffer (22, 12) */ - -#define UARTA_SHIFT 22 -#define UARTB_SHIFT 12 - -#define INTTYPE(interrupttype) (1 << interrupttype) - -/* - * This driver can spew a whole lot of debugging output at you. If you - * need maximum performance, you should disable the DEBUG define. - */ #undef TX3912_UART_DEBUG #ifdef TX3912_UART_DEBUG @@ -53,39 +30,28 @@ #define TX3912_UART_DEBUG_FIRMWARE 0x00001000 #define TX3912_UART_DEBUG_MEMTEST 0x00002000 #define TX3912_UART_DEBUG_THROTTLE 0x00004000 +#define TX3912_UART_DEBUG_NO_TX 0xffffffdf #define TX3912_UART_DEBUG_ALL 0xffffffff -int rs_debug = TX3912_UART_DEBUG_ALL & ~TX3912_UART_DEBUG_TRANSMIT; - -#define rs_dprintk(f, str...) if (rs_debug & f) printk (str) -#define func_enter() rs_dprintk (TX3912_UART_DEBUG_FLOW, \ +#define rs_dprintk(f, str...) if(TX3912_UART_DEBUG_NO_TX & f) printk(str) +#define func_enter() rs_dprintk(TX3912_UART_DEBUG_FLOW, \ "rs: enter " __FUNCTION__ "\n") -#define func_exit() rs_dprintk (TX3912_UART_DEBUG_FLOW, \ +#define func_exit() rs_dprintk(TX3912_UART_DEBUG_FLOW, \ "rs: exit " __FUNCTION__ "\n") - #else #define rs_dprintk(f, str...) #define func_enter() #define func_exit() - -#endif /* TX3912_UART_DEBUG */ - -/* - * Number of serial ports - */ -#define TX3912_UART_NPORTS 2 +#endif /* * Hardware specific serial port structure */ struct rs_port { struct gs_port gs; /* Must be first field! */ - - unsigned long base; - int intshift; /* Register shift */ struct wait_queue *shutdown_wait; int stat_flags; - struct async_icount icount; /* Counters for 4 input IRQs */ + struct async_icount icount; /* Counters for 4 input IRQs */ int read_status_mask; int ignore_status_mask; int x_char; /* XON/XOFF character */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/serial_txx927.c linux-2.5/drivers/char/serial_txx927.c --- linux-2.5.20/drivers/char/serial_txx927.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/serial_txx927.c Fri Apr 19 20:50:59 2002 @@ -0,0 +1,2329 @@ +/* + * drivers/char/serial_txx927.c + * driver for TX[34]927 SIO + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on drivers/char/serial.c + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define SERIAL_DO_RESTART + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#undef SERIAL_DEBUG_PCI +#undef SERIAL_DEBUG_AUTOCONF + +#ifdef MODULE +#undef CONFIG_TXX927_SERIAL_CONSOLE +#endif + +#define CONFIG_SERIAL_RSA + +#define RS_STROBE_TIME (10*HZ) +#define RS_ISR_PASS_LIMIT 256 + +/* + * End of serial driver configuration section. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_TXX927_SERIAL_CONSOLE +#include +#endif +#ifdef CONFIG_MAGIC_SYSRQ +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_TOSHIBA_JMR3927 +#include +#endif + +#define _INLINE_ inline + +#ifdef CONFIG_MAC_SERIAL +#define SERIAL_DEV_OFFSET 2 +#else +#define SERIAL_DEV_OFFSET 0 +#endif + +static char *serial_name = "TXx927 Serial driver"; +static char *serial_version = "0.02"; + +static DECLARE_TASK_QUEUE(tq_serial); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +static struct timer_list serial_timer; + +extern unsigned long get_txx927_uart_baud(void); + +/* serial subtype definitions */ +#ifndef SERIAL_TYPE_NORMAL +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +#endif + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* + * IRQ_timeout - How long the timeout should be for each IRQ + * should be after the IRQ has been active. + */ + +static struct async_struct *IRQ_ports[NR_IRQS]; +static int IRQ_timeout[NR_IRQS]; +#ifdef CONFIG_TXX927_SERIAL_CONSOLE +static struct console sercons; +#endif +#if defined(CONFIG_TXX927_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +static unsigned long break_pressed; /* break, really ... */ +#endif + +static void change_speed(struct async_struct *info, struct termios *old); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); + +#ifndef PREPARE_FUNC +#define PREPARE_FUNC(dev) (dev->prepare) +#define ACTIVATE_FUNC(dev) (dev->activate) +#define DEACTIVATE_FUNC(dev) (dev->deactivate) +#endif + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) + + +#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) +#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ + kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) +#else +#define DBG_CNT(s) +#endif + +#define SERIAL_DRIVER_NAME "TXx927SIO" + +#ifdef CONFIG_SERIAL +/* "ttyS","cua" is used for standard serial driver */ +#define TXX927_TTY_NAME "ttySC" +#define TXX927_TTY_MINOR_START (64 + 16) /* ttySC0(80), ttySC1(81) */ +#define TXX927_CU_NAME "cuac" +#define TXX927_SERIAL_BH TXX927SERIAL_BH +#else +/* acts like standard serial driver */ +#define TXX927_TTY_NAME "ttyS" +#define TXX927_TTY_MINOR_START 64 +#define TXX927_CU_NAME "cua" +#define TXX927_SERIAL_BH SERIAL_BH +#endif +#define TXX927_TTY_MAJOR TTY_MAJOR +#define TXX927_TTYAUX_MAJOR TTYAUX_MAJOR + +#define ASYNC_HAVE_CTS_LINE ASYNC_BOOT_AUTOCONF /* reuse */ + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) + +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; +#ifdef DECLARE_MUTEX +static DECLARE_MUTEX(tmp_buf_sem); +#else +static struct semaphore tmp_buf_sem = MUTEX; +#endif + +static inline int serial_paranoia_check(struct async_struct *info, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +static inline struct txx927_sio_reg *sio_reg(struct async_struct *info) +{ + return (struct txx927_sio_reg *)info->port; +} + +/* + * Wait for transmitter & holding register to empty + */ +static inline void wait_for_xmitr(struct async_struct *info) +{ + unsigned int tmout = 1000000; + + do { + if (--tmout == 0) break; + } while (!(sio_reg(info)->cisr & TXx927_SICISR_TXALS)); +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + save_flags(flags); cli(); + if (info->IER & UART_IER_THRI) { + info->IER &= ~UART_IER_THRI; + sio_reg(info)->dicr &= ~TXx927_SIDICR_TIE; + } + restore_flags(flags); +} + +static void rs_start(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + save_flags(flags); cli(); + if (info->xmit.head != info->xmit.tail + && info->xmit.buf + && !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + } + restore_flags(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void rs_sched_event(struct async_struct *info, + int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(TXX927_SERIAL_BH); +} + +static _INLINE_ void receive_chars(struct async_struct *info, + int *status) +{ + struct tty_struct *tty = info->tty; + unsigned char ch; + int ignored = 0; + struct async_icount *icount; + + icount = &info->state->icount; + do { + ch = sio_reg(info)->rfifo; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + *tty->flip.char_buf_ptr = ch; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x:%02x...", ch, *status); +#endif + *tty->flip.flag_buf_ptr = 0; + if (*status & (TXx927_SIDISR_UBRK | TXx927_SIDISR_UPER | + TXx927_SIDISR_UFER | TXx927_SIDISR_UOER)) { + /* + * For statistics only + */ + if (*status & TXx927_SIDISR_UBRK) { + *status &= ~(TXx927_SIDISR_UFER | TXx927_SIDISR_UPER); + icount->brk++; + } else if (*status & TXx927_SIDISR_UPER) + icount->parity++; + else if (*status & TXx927_SIDISR_UFER) + icount->frame++; + if (*status & TXx927_SIDISR_UOER) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (*status & info->ignore_status_mask) { + if (++ignored > 100) + break; + goto ignore_char; + } + *status &= info->read_status_mask; + + if (*status & (TXx927_SIDISR_UBRK)) { +#ifdef SERIAL_DEBUG_INTR + printk("handling break...."); +#endif + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (*status & TXx927_SIDISR_UPER) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (*status & TXx927_SIDISR_UFER) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (*status & TXx927_SIDISR_UOER) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + } + } + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + *status = sio_reg(info)->disr; + } while (!(*status & TXx927_SIDISR_UVALID)); + + tty_flip_buffer_push(tty); +} + +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) +{ + int count; + + wait_for_xmitr(info); + + if (info->x_char) { + sio_reg(info)->tfifo = info->x_char; + info->state->icount.tx++; + info->x_char = 0; + if (intr_done) + *intr_done = 0; + return; + } + + if (info->xmit.head == info->xmit.tail + || info->tty->stopped + || info->tty->hw_stopped) { + sio_reg(info)->dicr &= ~TXx927_SIDICR_TIE; + return; + } + + count = info->xmit_fifo_size; + do { + sio_reg(info)->tfifo = info->xmit.buf[info->xmit.tail++]; + info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1); + info->state->icount.tx++; + if (info->xmit.head == info->xmit.tail) + break; + } while (--count > 0); + + if (CIRC_CNT(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + if (intr_done) + *intr_done = 0; + + if (info->xmit.head == info->xmit.tail) { + sio_reg(info)->dicr &= ~TXx927_SIDICR_TIE; + } +} + +static _INLINE_ void check_modem_status(struct async_struct *info) +{ + /* RTS/CTS are controled by HW. (if possible) */ +} + +/* + * This is the serial driver's interrupt routine for a single port + */ +static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + int pass_counter = 0; + struct async_struct * info; + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt_single(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info || !info->tty) + return; + + do { + status = sio_reg(info)->disr; +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (!(sio_reg(info)->dicr & TXx927_SIDICR_TIE)) + status &= ~TXx927_SIDISR_TDIS; + if (!(status & (TXx927_SIDISR_TDIS | TXx927_SIDISR_RDIS | TXx927_SIDISR_TOUT))) + break; + + if (status & TXx927_SIDISR_RDIS) + receive_chars(info, &status); + check_modem_status(info); + if (status & TXx927_SIDISR_TDIS) + transmit_chars(info, 0); + /* Clear TX/RX Int. Status */ + sio_reg(info)->disr &= ~(TXx927_SIDISR_TDIS | TXx927_SIDISR_RDIS | TXx927_SIDISR_TOUT); + + if (pass_counter++ > RS_ISR_PASS_LIMIT) { +#ifdef SERIAL_DEBUG_INTR + printk("rs_single loop break.\n"); +#endif + break; + } + } while (1); + info->last_active = jiffies; +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + } +} + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * by the serial driver to handle ports that do not have an interrupt + * (irq=0). This doesn't work very well for 16450's, but gives barely + * passable results for a 16550A. (Although at the expense of much + * CPU overhead). + */ +static void rs_timer(unsigned long dummy) +{ + static unsigned long last_strobe; + struct async_struct *info; + unsigned int i; + unsigned long flags; + + if ((jiffies - last_strobe) >= RS_STROBE_TIME) { + for (i=0; i < NR_IRQS; i++) { + info = IRQ_ports[i]; + if (!info) + continue; + save_flags(flags); cli(); + rs_interrupt_single(i, NULL, NULL); + restore_flags(flags); + } + } + last_strobe = jiffies; + mod_timer(&serial_timer, jiffies + RS_STROBE_TIME); + +#if 0 + if (IRQ_ports[0]) { + save_flags(flags); cli(); + rs_interrupt_single(0, NULL, NULL); + restore_flags(flags); + + mod_timer(&serial_timer, jiffies + IRQ_timeout[0]); + } +#endif +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + +/* + * This routine figures out the correct timeout for a particular IRQ. + * It uses the smallest timeout of all of the serial ports in a + * particular interrupt chain. Now only used for IRQ 0.... + */ +static void figure_IRQ_timeout(int irq) +{ + struct async_struct *info; + int timeout = 60*HZ; /* 60 seconds === a long time :-) */ + + info = IRQ_ports[irq]; + if (!info) { + IRQ_timeout[irq] = 60*HZ; + return; + } + while (info) { + if (info->timeout < timeout) + timeout = info->timeout; + info = info->next_port; + } + if (!irq) + timeout = timeout / 2; + IRQ_timeout[irq] = timeout ? timeout : 1; +} + +static int startup(struct async_struct * info) +{ + unsigned long flags; + int retval=0; + struct serial_state *state= info->state; + unsigned long page; + + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!state->port) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + if (info->xmit.buf) + free_page(page); + else + info->xmit.buf = (unsigned char *) page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d (irq %d)...", info->line, state->irq); +#endif + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + sio_reg(info)->fcr |= TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE; + /* clear reset */ + sio_reg(info)->fcr &= ~(TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE); + + /* + * Allocate the IRQ if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + retval = -EBUSY; + goto errout; + } + + retval = request_irq(state->irq, rs_interrupt_single, + SA_INTERRUPT, + "txx927serial", NULL); + if (retval) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; + } + goto errout; + } + } + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports[state->irq]; + if (info->next_port) + info->next_port->prev_port = info; + IRQ_ports[state->irq] = info; + figure_IRQ_timeout(state->irq); + + /* + * Clear the interrupt registers. + */ + sio_reg(info)->disr = 0; + + /* + * Now, initialize the UART + */ + /* HW RTS/CTS control */ + if (state->flags & ASYNC_HAVE_CTS_LINE) + sio_reg(info)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + /* Enable RX/TX */ + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); + + /* + * Finally, enable interrupts + */ + sio_reg(info)->dicr = TXx927_SIDICR_RIE; + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit.head = info->xmit.tail = 0; + + /* + * Set up the tty->alt_speed kludge + */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } + + /* + * and set the speed of the serial port + */ + change_speed(info, 0); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct async_struct * info) +{ + unsigned long flags; + struct serial_state *state; + int retval; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + state = info->state; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, NULL); + retval = request_irq(state->irq, rs_interrupt_single, + SA_INTERRUPT, "txx927serial", NULL); + + if (retval) + printk(KERN_WARNING "txx927serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, NULL); + } + + if (info->xmit.buf) { + free_page((unsigned long) info->xmit.buf); + info->xmit.buf = 0; + } + + sio_reg(info)->dicr = 0; /* disable all intrs */ + + /* disable break condition */ + sio_reg(info)->flcr &= ~TXx927_SIFLCR_TBRK; + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + /* drop RTS */ + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + /* TXx927-SIO can not control DTR... */ + } + + /* reset FIFO's */ + sio_reg(info)->fcr |= TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE; + /* clear reset */ + sio_reg(info)->fcr &= ~(TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE); + + /* DON'T disable Rx/Tx here, ie. DON'T set either + * TXx927_SIFLCR_RSDE or TXx927_SIFLCR_TSDE in flcr + */ + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(struct async_struct *info, + struct termios *old_termios) +{ + int quot = 0, baud_base, baud; + unsigned cflag, cval; + int bits; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!info->port) + return; + + cval = sio_reg(info)->lcr; + /* byte size and parity */ + cval &= ~TXx927_SILCR_UMODE_MASK; + switch (cflag & CSIZE) { + case CS7: + cval |= TXx927_SILCR_UMODE_7BIT; + bits = 9; + break; + case CS5: /* not supported */ + case CS6: /* not supported */ + case CS8: + default: + cval |= TXx927_SILCR_UMODE_8BIT; + bits = 10; + break; + } + cval &= ~TXx927_SILCR_USBL_MASK; + if (cflag & CSTOPB) { + cval |= TXx927_SILCR_USBL_2BIT; + bits++; + } else { + cval |= TXx927_SILCR_USBL_1BIT; + } + + cval &= ~(TXx927_SILCR_UPEN|TXx927_SILCR_UEPS); + if (cflag & PARENB) { + cval |= TXx927_SILCR_UPEN; + bits++; + } + if (!(cflag & PARODD)) + cval |= TXx927_SILCR_UEPS; + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + baud_base = info->state->baud_base; + quot = (baud_base + baud / 2) / baud; + /* If the quotient is zero refuse the change */ + if (!quot && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + quot = (baud_base + baud / 2) / baud; + } + /* As a last resort, if the quotient is zero, default to 9600 bps */ + if (!quot) + quot = (baud_base + 9600 / 2) / 9600; + info->quot = quot; + info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + /* CTS flow control flag */ + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + if (info->state->flags & ASYNC_HAVE_CTS_LINE) + sio_reg(info)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + } else { + info->flags &= ~ASYNC_CTS_FLOW; + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); + } + + /* + * Set up parity check flag + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = TXx927_SIDISR_UOER | + TXx927_SIDISR_TDIS | TXx927_SIDISR_RDIS; + if (I_INPCK(info->tty)) + info->read_status_mask |= TXx927_SIDISR_UFER | TXx927_SIDISR_UPER; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= TXx927_SIDISR_UBRK; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= TXx927_SIDISR_UPER | TXx927_SIDISR_UFER; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= TXx927_SIDISR_UBRK; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= TXx927_SIDISR_UOER; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + info->ignore_status_mask |= TXx927_SIDISR_RDIS; + save_flags(flags); cli(); + sio_reg(info)->lcr = cval | TXx927_SILCR_SCS_IMCLK_BG; + sio_reg(info)->bgr = quot | TXx927_SIBGR_BCLK_T0; + restore_flags(flags); +} + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_put_char")) + return; + + if (!tty || !info->xmit.buf) + return; + + save_flags(flags); cli(); + if (CIRC_SPACE(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) == 0) { + restore_flags(flags); + return; + } + + info->xmit.buf[info->xmit.head++] = ch; + info->xmit.head &= SERIAL_XMIT_SIZE-1; + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit.head == info->xmit.tail + || tty->stopped + || tty->hw_stopped + || !info->xmit.buf) + return; + + save_flags(flags); cli(); + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit.buf || !tmp_buf) + return 0; + + save_flags(flags); + + if (from_user) { + down(&tmp_buf_sem); + while (1) { + int c1; + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (count < c) + c = count; + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c1 = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (c1 < c) + c = c1; + memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + cli(); + while (1) { + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (count < c) + c = count; + if (c <= 0) { + break; + } + memcpy(info->xmit.buf + info->xmit.head, buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + buf += c; + count -= c; + ret += c; + } + restore_flags(flags); + } + if (info->xmit.head != info->xmit.tail + && !tty->stopped + && !tty->hw_stopped + && !(info->IER & UART_IER_THRI)) + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + + return ret; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + + return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + + return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + save_flags(flags); cli(); + info->xmit.head = info->xmit.tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + + if (serial_paranoia_check(info, tty->device, "rs_send_char")) + return; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + } +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + rs_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) { + save_flags(flags); cli(); + /* drop RTS */ + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + restore_flags(flags); + } +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } + if (tty->termios->c_cflag & CRTSCTS) { + save_flags(flags); cli(); + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + restore_flags(flags); + } +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_modem_info(struct async_struct * info, unsigned int *value) +{ + unsigned int result; + unsigned long flags; + + save_flags(flags); cli(); + result = ((sio_reg(info)->flcr & TXx927_SIFLCR_RTSSC) ? 0 : TIOCM_RTS) + | ((sio_reg(info)->cisr & TXx927_SICISR_CTSS) ? 0 : TIOCM_CTS); + restore_flags(flags); + return put_user(result,value); +} + +static int set_modem_info(struct async_struct * info, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + unsigned long flags; + + error = get_user(arg, value); + if (error) + return error; + save_flags(flags); cli(); + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + break; + case TIOCMSET: + sio_reg(info)->flcr = + (sio_reg(info)->flcr & ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE)) | + ((arg & TIOCM_RTS) ? 0 : TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + break; + default: + error = -EINVAL; + } + restore_flags(flags); + return error; +} + +/* + * rs_break() --- routine which turns the break handling on or off + */ +static void rs_break(struct tty_struct *tty, int break_state) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_break")) + return; + + if (!info->port) + return; + save_flags(flags); cli(); + if (break_state == -1) + sio_reg(info)->flcr |= TXx927_SIFLCR_TBRK; + else + sio_reg(info)->flcr &= ~TXx927_SIFLCR_TBRK; + restore_flags(flags); +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + return 0; + case TIOCGSERIAL: + printk("TIOCGSERIAL\n"); + return 0; + case TIOCSSERIAL: + printk("TIOCSSERIAL\n"); + return 0; + case TIOCSERCONFIG: + printk("TIOCSERCONFIG\n"); + return 0; + + case TIOCSERGETLSR: /* Get line status register */ + printk("TIOCSERGETLSR\n"); + return 0; + + case TIOCSERGSTRUCT: + printk("TIOCSERGSTRUCT\n"); + return 0; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + printk("TIOCMIWAIT\n"); + return 0; + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + printk("TIOCGICOUNT\n"); + return 0; + + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; + + if ( (cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_speed(info, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(cflag & CBAUD)) { + save_flags(flags); cli(); + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + restore_flags(flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (cflag & CBAUD)) { + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + save_flags(flags); cli(); + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + restore_flags(flags); + } + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + state = info->state; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk(KERN_WARNING "rs_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk(KERN_WARNING "rs_close: bad serial port count for ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->read_status_mask &= ~TXx927_SIDISR_RDIS; + if (info->flags & ASYNC_INITIALIZED) { +#if 0 + sio_reg(info)->dicr &= ~TXx927_SIDICR_RIE; +#endif + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + rs_wait_until_sent(tty, info->timeout); + } + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + restore_flags(flags); +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int cisr; + + if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) + return; + + if (info->xmit_fifo_size == 0) + return; /* Just in case.... */ + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout) + char_time = MIN(char_time, timeout); + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2*info->timeout) + timeout = 2*info->timeout; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + while (!((cisr = sio_reg(info)->cisr) & TXx927_SICISR_TXALS)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("cisr = %d (jiff=%lu)...", cisr, jiffies); +#endif + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; /* make us low-priority */ + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + current->state = TASK_RUNNING; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("cisr = %d (jiff=%lu)...done\n", cisr, jiffies); +#endif +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + state = info->state; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct async_struct *info) +{ + DECLARE_WAITQUEUE(wait, current); + struct serial_state *state = info->state; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (state->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + state->line, state->count); +#endif + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + state->count--; + } + restore_flags(flags); + info->blocked_open++; + while (1) { + save_flags(flags); cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + restore_flags(flags); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING)) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) + state->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + +#ifdef REMOTE_DEBUG + if (kdb_port_info.state && line == kdb_port_info.line) + return -ENODEV; +#endif + sstate = rs_table + line; + sstate->count++; + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + sstate->count--; + return -ENOMEM; + } + memset(info, 0, sizeof(struct async_struct)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->io_type = sstate->io_type; + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree(info); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + + line = minor(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) { + return -ENODEV; + } + retval = get_async_struct(line, &info); + if (retval) { + return retval; + } + tty->driver_data = info; + info->tty = tty; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->state->count); +#endif + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) { + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) { + return retval; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + change_speed(info, 0); + } +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + sercons.cflag = 0; + change_speed(info, 0); + } +#endif + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ + struct async_struct *info = state->info, scr_info; + char stat_buf[30]; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", + state->line, SERIAL_DRIVER_NAME, + state->port, state->irq); + + if (!state->port) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + info->quot = 0; + info->tty = 0; + } + + stat_buf[0] = 0; + stat_buf[1] = 0; + save_flags(flags); cli(); + if (!(sio_reg(info)->flcr & TXx927_SIFLCR_RTSSC)) + strcat(stat_buf, "|RTS"); + if (!(sio_reg(info)->cisr & TXx927_SICISR_CTSS)) + strcat(stat_buf, "|CTS"); + restore_flags(flags); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + return ret; +} + +static int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &rs_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static _INLINE_ void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s\n", serial_name, serial_version); +} + +/* + * The serial driver boot-time initialization code! + */ +static int __init rs_init(void) +{ + int i; + struct serial_state * state; + + if (rs_table[0].port == 0) + return -ENODEV; + + init_bh(TXX927_SERIAL_BH, do_serial_bh); + init_timer(&serial_timer); + serial_timer.function = rs_timer; + mod_timer(&serial_timer, jiffies + RS_STROBE_TIME); + + for (i = 0; i < NR_IRQS; i++) { + IRQ_ports[i] = 0; + IRQ_timeout[i] = 0; + } +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + /* + * The interrupt of the serial console port + * can't be shared. + */ + if (sercons.flags & CON_CONSDEV) { + for(i = 0; i < NR_PORTS; i++) + if (i != sercons.index && + rs_table[i].irq == rs_table[sercons.index].irq) + rs_table[i].irq = 0; + } +#endif + show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "txx927serial"; +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + serial_driver.name = "tts/%d"; +#else + serial_driver.name = "ttyS"; +#endif + serial_driver.major = TXX927_TTY_MAJOR; + serial_driver.minor_start = TXX927_TTY_MINOR_START + SERIAL_DEV_OFFSET; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.send_xchar = rs_send_xchar; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + serial_driver.break_ctl = rs_break; + serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = rs_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + callout_driver.name = "cua/%d"; +#else + callout_driver.name = "cua"; +#endif + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)){ + panic("Couldn't register serial driver\n"); + } + if (tty_register_driver(&callout_driver)) { + panic("Couldn't register callout driver\n"); + } + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + state->irq = irq_cannonicalize(state->irq); + state->xmit_fifo_size = TXx927_SIO_TX_FIFO; + if (state->hub6) + state->io_type = SERIAL_IO_HUB6; + if (state->port) { + continue; + } + } + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + if (state->type == PORT_UNKNOWN) { + continue; + } + printk(KERN_INFO "%s%02d at 0x%04lx (irq = %d) is a %s\n", + TXX927_TTY_NAME, + state->line, + state->port, state->irq, + SERIAL_DRIVER_NAME); + tty_register_devfs(&serial_driver, 0, + serial_driver.minor_start + state->line); + tty_register_devfs(&callout_driver, 0, + callout_driver.minor_start + state->line); + } + return 0; +} + +static void __exit rs_fini(void) +{ + unsigned long flags; + int e1, e2; + int i; + struct async_struct *info; + + del_timer_sync(&serial_timer); + save_flags(flags); cli(); + remove_bh(TXX927_SERIAL_BH); + if ((e1 = tty_unregister_driver(&serial_driver))) + printk(KERN_WARNING "serial: failed to unregister serial driver (%d)\n", + e1); + if ((e2 = tty_unregister_driver(&callout_driver))) + printk(KERN_WARNING "serial: failed to unregister callout driver (%d)\n", + e2); + restore_flags(flags); + + for (i = 0; i < NR_PORTS; i++) { + if ((info = rs_table[i].info)) { + rs_table[i].info = NULL; + kfree(info); + } + } + if (tmp_buf) { + unsigned long pg = (unsigned long) tmp_buf; + tmp_buf = NULL; + free_page(pg); + } +} + +module_init(rs_init); +module_exit(rs_fini); +MODULE_DESCRIPTION("TXX927 serial driver"); + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + +static struct async_struct async_sercons; + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + static struct async_struct *info = &async_sercons; + int ier; + unsigned i; + + /* + * First save the IER then disable the interrupts + */ + ier = sio_reg(info)->dicr; + sio_reg(info)->dicr = 0; + + + /* + * Now, do each character + */ + for (i = 0; i < count; i++, s++) { + wait_for_xmitr(info); + + /* + * Send the character out. + * If a LF, also do CR... + */ + sio_reg(info)->tfifo = *s; + if (*s == 10) { + wait_for_xmitr(info); + sio_reg(info)->tfifo = 13; + } + } + + /* + * Finally, Wait for transmitter & holding register to empty + * and restore the IER + */ + wait_for_xmitr(info); + sio_reg(info)->dicr = ier; +} + +static kdev_t serial_console_device(struct console *c) +{ + return mk_kdev(TXX927_TTY_MAJOR, TXX927_TTY_MINOR_START + c->index); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int serial_console_setup(struct console *co, char *options) +{ + static struct async_struct *info; + struct serial_state *state; + unsigned cval; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int quot = 0; + char *s; + + if (co->index < 0 || co->index >= NR_PORTS) { + return -1; + } + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* + * Divisor, bytesize and parity + */ + state = rs_table + co->index; + info = &async_sercons; + info->magic = SERIAL_MAGIC; + info->state = state; + info->port = state->port; + info->flags = state->flags; + info->io_type = state->io_type; + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; + quot = state->baud_base / baud; + + switch (cflag & CSIZE) { + case CS7: cval = TXx927_SILCR_UMODE_7BIT; break; + default: + case CS8: cval = TXx927_SILCR_UMODE_8BIT; break; + } + if (cflag & CSTOPB) + cval |= TXx927_SILCR_USBL_2BIT; + else + cval |= TXx927_SILCR_USBL_1BIT; + if (cflag & PARENB) + cval |= TXx927_SILCR_UPEN; + if (!(cflag & PARODD)) + cval |= TXx927_SILCR_UEPS; + + /* + * Disable UART interrupts, set DTR and RTS high + * and set speed. + */ + sio_reg(info)->dicr = 0; + sio_reg(info)->lcr = cval | TXx927_SILCR_SCS_IMCLK_BG; + sio_reg(info)->bgr = quot | TXx927_SIBGR_BCLK_T0; + /* HW RTS/CTS control */ + if (info->flags & ASYNC_HAVE_CTS_LINE) + sio_reg(info)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + /* Enable RX/TX */ + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); + + return 0; +} + +static struct console sercons = { + name: TXX927_TTY_NAME, + write: serial_console_write, + device: serial_console_device, + setup: serial_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +/* + * Register console. + */ +void __init txx927_console_init(void) +{ + register_console(&sercons); +} +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/sh-sci.c linux-2.5/drivers/char/sh-sci.c --- linux-2.5.20/drivers/char/sh-sci.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/char/sh-sci.c Sun Jan 6 01:38:27 2002 @@ -1040,7 +1040,9 @@ sci_driver.table = sci_table; sci_driver.termios = sci_termios; sci_driver.termios_locked = sci_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + sci_driver.console = &sercons; +#endif sci_driver.open = sci_open; sci_driver.close = gs_close; sci_driver.write = gs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/sx.c linux-2.5/drivers/char/sx.c --- linux-2.5.20/drivers/char/sx.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/char/sx.c Tue May 21 22:20:45 2002 @@ -353,9 +353,11 @@ 0xc8000, 0xd8000, 0xe8000}; static int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000, 0xc8000, 0xd8000, 0xe8000, 0xa0000}; +static int si1_probe_addrs[]= { 0xd0000}; #define NR_SX_ADDRS (sizeof(sx_probe_addrs)/sizeof (int)) #define NR_SI_ADDRS (sizeof(si_probe_addrs)/sizeof (int)) +#define NR_SI1_ADDRS (sizeof(si1_probe_addrs)/sizeof (int)) /* Set the mask to all-ones. This alas, only supports 32 interrupts. @@ -582,6 +584,8 @@ } } else if (IS_EISA_BOARD(board)) { outb(board->irq<<4, board->eisa_base+0xc02); + } else if (IS_SI1_BOARD(board)) { + write_sx_byte (board, SI1_ISA_RESET, 0); // value does not matter } else { /* Gory details of the SI/ISA board */ write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_SET); @@ -656,6 +660,9 @@ } else if (IS_EISA_BOARD(board)) { write_sx_byte(board, SI2_EISA_OFF, SI2_EISA_VAL); outb((board->irq<<4)|4, board->eisa_base+0xc02); + } else if (IS_SI1_BOARD(board)) { + write_sx_byte (board, SI1_ISA_RESET_CLEAR, 0); + write_sx_byte (board, SI1_ISA_INTCL, 0); } else { /* Don't bug me about the clear_set. I haven't the foggiest idea what it's about -- REW */ @@ -681,6 +688,9 @@ SX_CONF_HOSTIRQ); } else if (IS_EISA_BOARD(board)) { inb(board->eisa_base+0xc03); + } else if (IS_SI1_BOARD(board)) { + write_sx_byte (board, SI1_ISA_INTCL,0); + write_sx_byte (board, SI1_ISA_INTCL_CLEAR,0); } else { switch (board->irq) { case 11:write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);break; @@ -1690,6 +1700,7 @@ if (IS_SX_BOARD (board)) rc = SX_TYPE_SX; if (IS_CF_BOARD (board)) rc = SX_TYPE_CF; if (IS_SI_BOARD (board)) rc = SX_TYPE_SI; + if (IS_SI1_BOARD (board)) rc = SX_TYPE_SI; if (IS_EISA_BOARD (board)) rc = SX_TYPE_SI; sx_dprintk (SX_DEBUG_FIRMWARE, "returning type= %d\n", rc); break; @@ -2184,13 +2195,20 @@ int i; func_enter(); - sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %lx.\n", + sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at %lx.\n", board->hw_base, board->base + SI2_ISA_ID_BASE); if (sx_debug & SX_DEBUG_PROBE) my_hd ((char *)(board->base + SI2_ISA_ID_BASE), 0x8); - if (!IS_EISA_BOARD(board)) { + if (!IS_EISA_BOARD(board) ) { + if( IS_SI1_BOARD(board) ) + { + for (i=0;i<8;i++) { + write_sx_byte (board, SI2_ISA_ID_BASE+7-i,i); + + } + } for (i=0;i<8;i++) { if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) { return 0; @@ -2206,7 +2224,7 @@ board->nports = -1; - /* This resets the processor, and keeps it off the bus. */ + /* This resets the processor, and keeps it off the bus. */ if (!sx_reset (board)) return 0; sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); @@ -2554,6 +2572,21 @@ board->base = (ulong) ioremap(board->hw_base, SI2_ISA_WINDOW_LEN); board->flags &= ~SX_BOARD_TYPE; board->flags |= SI_ISA_BOARD; + board->irq = sx_irqmask ?-1:0; + + if (probe_si (board)) { + found++; + } else { + my_iounmap (board->hw_base, board->base); + } + } + for (i=0;ihw_base = si1_probe_addrs[i]; + board->base2 = + board->base = (ulong) ioremap(board->hw_base, SI1_ISA_WINDOW_LEN); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SI1_ISA_BOARD; board->irq = sx_irqmask ?-1:0; if (probe_si (board)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/sx.h linux-2.5/drivers/char/sx.h --- linux-2.5.20/drivers/char/sx.h Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/char/sx.h Fri May 3 03:49:06 2002 @@ -73,6 +73,7 @@ #define SX_CFPCI_BOARD 0x00000008 #define SX_CFISA_BOARD 0x00000010 #define SI_EISA_BOARD 0x00000020 +#define SI1_ISA_BOARD 0x00000040 #define SX_BOARD_PRESENT 0x00001000 #define SX_BOARD_INITIALIZED 0x00002000 @@ -84,6 +85,7 @@ SX_ISA_BOARD | SX_CFISA_BOARD)) #define IS_SI_BOARD(board) (board->flags & SI_ISA_BOARD) +#define IS_SI1_BOARD(board) (board->flags & SI1_ISA_BOARD) #define IS_EISA_BOARD(board) (board->flags & SI_EISA_BOARD) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/sxboards.h linux-2.5/drivers/char/sxboards.h --- linux-2.5.20/drivers/char/sxboards.h Mon Jun 3 02:44:38 2002 +++ linux-2.5/drivers/char/sxboards.h Fri May 3 03:49:06 2002 @@ -46,12 +46,36 @@ #define CARD_BUS(type) ((type>>4)&0xF) #define CARD_PHASE(type) (type&0xF) +#define TYPE_SI1_ISA CARD_TYPE(BUS_ISA,SI1_Z280) #define TYPE_SI2_ISA CARD_TYPE(BUS_ISA,SI2_Z280) #define TYPE_SI2_EISA CARD_TYPE(BUS_EISA,SI2_Z280) #define TYPE_SI2_PCI CARD_TYPE(BUS_PCI,SI2_Z280) #define TYPE_SX_ISA CARD_TYPE(BUS_ISA,SI3_T225) #define TYPE_SX_PCI CARD_TYPE(BUS_PCI,SI3_T225) +/***************************************************************************** +****************************** ****************************** +****************************** Phase 1 Z280 ****************************** +****************************** ****************************** +*****************************************************************************/ + +/* ISA board details... */ +#define SI1_ISA_WINDOW_LEN 0x10000 /* 64 Kbyte shared memory window */ +//#define SI1_ISA_MEMORY_LEN 0x8000 /* Usable memory - unused define*/ +//#define SI1_ISA_ADDR_LOW 0x0A0000 /* Lowest address = 640 Kbyte */ +//#define SI1_ISA_ADDR_HIGH 0xFF8000 /* Highest address = 16Mbyte - 32Kbyte */ +//#define SI2_ISA_ADDR_STEP SI2_ISA_WINDOW_LEN/* ISA board address step */ +//#define SI2_ISA_IRQ_MASK 0x9800 /* IRQs 15,12,11 */ + +/* ISA board, register definitions... */ +//#define SI2_ISA_ID_BASE 0x7FF8 /* READ: Board ID string */ +#define SI1_ISA_RESET 0x8000 /* WRITE: Host Reset */ +#define SI1_ISA_RESET_CLEAR 0xc000 /* WRITE: Host Reset clear*/ +#define SI1_ISA_WAIT 0x9000 /* WRITE: Host wait */ +#define SI1_ISA_WAIT_CLEAR 0xd000 /* WRITE: Host wait clear */ +#define SI1_ISA_INTCL 0xa000 /* WRITE: Host Reset */ +#define SI1_ISA_INTCL_CLEAR 0xe000 /* WRITE: Host Reset */ + /***************************************************************************** ****************************** ****************************** diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/sysrq.c linux-2.5/drivers/char/sysrq.c --- linux-2.5.20/drivers/char/sysrq.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/char/sysrq.c Sat May 25 19:52:01 2002 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -34,7 +34,6 @@ #include -extern void reset_vc(unsigned int); extern struct list_head super_blocks; /* Whether we react on sysrq keys or just ignore them */ @@ -45,7 +44,8 @@ /* Loglevel sysrq handler */ static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ int i; i = key - '0'; console_loglevel = 7; @@ -62,10 +62,14 @@ /* SAK sysrq handler */ #ifdef CONFIG_VT static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + if (tty) do_SAK(tty); - reset_vc(fg_console); + if ((tty->driver.subtype == SYSTEM_TYPE_CONSOLE) && vc) + reset_vc(vc->display_fg->vc_cons[fg_console]); } static struct sysrq_key_op sysrq_SAK_op = { handler: sysrq_handle_SAK, @@ -77,9 +81,12 @@ /* unraw sysrq handler */ static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { - if (kbd) - kbd->kbdmode = VC_XLATE; + struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + + if ((tty->driver.subtype == SYSTEM_TYPE_CONSOLE) && vc) + vc->kbd_table.kbdmode = VC_XLATE; } static struct sysrq_key_op sysrq_unraw_op = { handler: sysrq_handle_unraw, @@ -90,7 +97,8 @@ /* reboot sysrq handler */ static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ machine_restart(NULL); } static struct sysrq_key_op sysrq_reboot_op = { @@ -99,8 +107,6 @@ action_msg: "Resetting", }; - - /* SYNC SYSRQ HANDLERS BLOCK */ /* do_emergency_sync helper function */ @@ -220,7 +226,8 @@ } static void sysrq_handle_sync(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ emergency_sync_scheduled = EMERG_SYNC; wakeup_bdflush(); } @@ -231,7 +238,8 @@ }; static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ emergency_sync_scheduled = EMERG_REMOUNT; wakeup_bdflush(); } @@ -247,7 +255,8 @@ /* SHOW SYSRQ HANDLERS BLOCK */ static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ if (pt_regs) show_regs(pt_regs); } @@ -259,7 +268,8 @@ static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ show_state(); } static struct sysrq_key_op sysrq_showstate_op = { @@ -268,9 +278,9 @@ action_msg: "Show State", }; - static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ show_mem(); } static struct sysrq_key_op sysrq_showmem_op = { @@ -292,13 +302,14 @@ for_each_task(p) { if (p->mm && p->pid != 1) - /* Not swapper, init nor kernel thread */ + /* Not swapper nor kernel thread */ force_sig(sig, p); } } static void sysrq_handle_term(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ send_sig_all(SIGTERM); console_loglevel = 8; } @@ -309,7 +320,8 @@ }; static void sysrq_handle_kill(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ send_sig_all(SIGKILL); console_loglevel = 8; } @@ -438,13 +450,13 @@ * and any other keycode arrives. */ -void handle_sysrq(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { +void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) +{ if (!sysrq_enabled) return; __sysrq_lock_table(); - __handle_sysrq_nolock(key, pt_regs, kbd, tty); + __handle_sysrq_nolock(key, pt_regs, tty); __sysrq_unlock_table(); } @@ -455,7 +467,8 @@ */ void __handle_sysrq_nolock(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ struct sysrq_key_op *op_p; int orig_log_level; int i, j; @@ -471,7 +484,7 @@ if (op_p) { printk ("%s\n", op_p->action_msg); console_loglevel = orig_log_level; - op_p->handler(key, pt_regs, kbd, tty); + op_p->handler(key, pt_regs, tty); } else { printk("HELP : "); /* Only print the help msg once per handler */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/tty_io.c linux-2.5/drivers/char/tty_io.c --- linux-2.5.20/drivers/char/tty_io.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/char/tty_io.c Fri May 3 03:49:06 2002 @@ -156,7 +156,8 @@ extern void sci_console_init(void); extern void tx3912_console_init(void); extern void tx3912_rs_init(void); -extern void hvc_console_init(void); +extern void txx927_console_init(void); +extern void sb1250_serial_console_init(void); #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -692,8 +693,13 @@ { ssize_t ret = 0, written = 0; - if (down_interruptible(&tty->atomic_write)) { - return -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&tty->atomic_write)) + return -EAGAIN; + } + else { + if (down_interruptible(&tty->atomic_write)) + return -ERESTARTSYS; } if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) { lock_kernel(); @@ -1836,9 +1842,6 @@ for_each_task(p) { if ((p->tty == tty) || ((session > 0) && (p->session == session))) { - printk(KERN_NOTICE "SAK: killed process %d" - " (%s): p->session==tty->session\n", - p->pid, p->comm); send_sig(SIGKILL, p, 1); continue; } @@ -1849,9 +1852,6 @@ filp = fcheck_files(p->files, i); if (filp && (filp->f_op == &tty_fops) && (filp->private_data == tty)) { - printk(KERN_NOTICE "SAK: killed process %d" - " (%s): fd#%d opened to the tty\n", - p->pid, p->comm, i); send_sig(SIGKILL, p, 1); break; } @@ -2180,14 +2180,19 @@ * inform about problems etc.. */ #ifdef CONFIG_VT - con_init(); + vt_console_init(); #endif #ifdef CONFIG_AU1000_SERIAL_CONSOLE - au1000_serial_console_init(); +// au1000_serial_console_init(); #endif #ifdef CONFIG_SERIAL_CONSOLE #if (defined(CONFIG_8xx) || defined(CONFIG_8260)) console_8xx_init(); +#elif defined(CONFIG_MAC_SERIAL) && defined(CONFIG_SERIAL) + if (_machine == _MACH_Pmac) + mac_scc_console_init(); + else + serial_console_init(); #elif defined(CONFIG_MAC_SERIAL) mac_scc_console_init(); #elif defined(CONFIG_PARISC) @@ -2235,8 +2240,11 @@ #ifdef CONFIG_SERIAL_TX3912_CONSOLE tx3912_console_init(); #endif -#ifdef CONFIG_HVC_CONSOLE - hvc_console_init(); +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + txx927_console_init(); +#endif +#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE + sb1250_serial_console_init(); #endif } @@ -2245,9 +2253,8 @@ static struct tty_driver dev_ptmx_driver; #endif #ifdef CONFIG_VT -extern void con_init_devfs (void); -extern void console_map_init(void); static struct tty_driver dev_console_driver; +extern int vty_init(void); #endif /* @@ -2287,13 +2294,6 @@ if (tty_register_driver(&dev_syscons_driver)) panic("Couldn't register /dev/console driver\n"); - /* console calls tty_register_driver() before kmalloc() works. - * Thus, we can't devfs_register() then. Do so now, instead. - */ -#ifdef CONFIG_VT - con_init_devfs(); -#endif - #ifdef CONFIG_UNIX98_PTYS dev_ptmx_driver = dev_tty_driver; dev_ptmx_driver.driver_name = "/dev/ptmx"; @@ -2317,10 +2317,7 @@ if (tty_register_driver(&dev_console_driver)) panic("Couldn't register /dev/tty0 driver\n"); - - vcs_init(); - kbd_init(); - console_map_init(); + vty_init(); #endif #ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/vc_screen.c linux-2.5/drivers/char/vc_screen.c --- linux-2.5.20/drivers/char/vc_screen.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/char/vc_screen.c Mon Feb 25 18:54:26 2002 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -46,20 +45,60 @@ #undef addr #define HEADER_SIZE 4 +/* used by vcs - note the word offset */ +unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed) +{ + return screenpos(vc, 2 * w_offset, viewed); +} + +void getconsxy(struct vc_data *vc, char *p) +{ + p[0] = vc->vc_x; + p[1] = vc->vc_y; +} + +void putconsxy(struct vc_data *vc, char *p) +{ + gotoxy(vc, p[0], p[1]); + set_cursor(vc); +} + +u16 vcs_scr_readw(struct vc_data *vc, const u16 *org) +{ + if ((unsigned long)org == vc->vc_pos && vc->display_fg->cursor_original != -1) + return vc->display_fg->cursor_original; + return scr_readw(org); +} + +void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org) +{ + scr_writew(val, org); + if ((unsigned long)org == vc->vc_pos) { + vc->display_fg->cursor_original = -1; + add_softcursor(vc); + } +} + + static int vcs_size(struct inode *inode) { - int size; int minor = minor(inode->i_rdev); int currcons = minor & 127; + struct vc_data *vc; + int size; + if (currcons == 0) currcons = fg_console; else currcons--; - if (!vc_cons_allocated(currcons)) + + vc = vt_cons->vc_cons[currcons]; + + if (!vc) return -ENXIO; - size = video_num_lines * video_num_columns; + size = vc->vc_rows * vc->vc_cols; if (minor & 128) size = 2*size + HEADER_SIZE; @@ -106,6 +145,7 @@ { struct inode *inode = file->f_dentry->d_inode; unsigned int currcons = minor(inode->i_rdev); + struct vc_data *vc; long pos = *ppos; long viewed, attr, read; int col, maxcol; @@ -129,7 +169,10 @@ viewed = 0; } ret = -ENXIO; - if (!vc_cons_allocated(currcons)) + + vc = vt_cons->vc_cons[currcons]; + + if (!vc) goto unlock_out; ret = -EINVAL; @@ -164,15 +207,15 @@ con_buf_start = con_buf0 = con_buf; orig_count = this_round; - maxcol = video_num_columns; + maxcol = vc->vc_cols; if (!attr) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = p % maxcol; p += maxcol - col; while (this_round-- > 0) { - *con_buf0++ = (vcs_scr_readw(currcons, org++) & 0xff); + *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff); if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -181,9 +224,9 @@ if (p < HEADER_SIZE) { size_t tmp_count; - con_buf0[0] = (char) video_num_lines; - con_buf0[1] = (char) video_num_columns; - getconsxy(currcons, con_buf0 + 2); + con_buf0[0] = (char) vc->vc_rows; + con_buf0[1] = (char) vc->vc_cols; + getconsxy(vc, con_buf0 + 2); con_buf_start += p; this_round += p; @@ -219,7 +262,7 @@ p /= 2; col = p % maxcol; - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); p += maxcol - col; /* Buffer has even length, so we can always copy @@ -229,10 +272,10 @@ this_round = (this_round + 1) >> 1; while (this_round) { - *tmp_buf++ = vcs_scr_readw(currcons, org++); + *tmp_buf++ = vcs_scr_readw(vc, org++); this_round --; if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -275,6 +318,7 @@ { struct inode *inode = file->f_dentry->d_inode; unsigned int currcons = minor(inode->i_rdev); + struct vc_data *vc; long pos = *ppos; long viewed, attr, size, written; char *con_buf0; @@ -300,7 +344,10 @@ viewed = 0; } ret = -ENXIO; - if (!vc_cons_allocated(currcons)) + + vc = vt_cons->vc_cons[currcons]; + + if (!vc) goto unlock_out; size = vcs_size(inode); @@ -354,10 +401,10 @@ con_buf0 = con_buf; orig_count = this_round; - maxcol = video_num_columns; + maxcol = vc->vc_cols; p = pos; if (!attr) { - org0 = org = screen_pos(currcons, p, viewed); + org0 = org = screen_pos(vc, p, viewed); col = p % maxcol; p += maxcol - col; @@ -365,11 +412,11 @@ unsigned char c = *con_buf0++; this_round--; - vcs_scr_writew(currcons, - (vcs_scr_readw(currcons, org) & 0xff00) | c, org); + vcs_scr_writew(vc, + (vcs_scr_readw(vc, org) & 0xff00) | c, org); org++; if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -378,34 +425,34 @@ if (p < HEADER_SIZE) { char header[HEADER_SIZE]; - getconsxy(currcons, header + 2); + getconsxy(vc, header + 2); while (p < HEADER_SIZE && this_round > 0) { this_round--; header[p++] = *con_buf0++; } if (!viewed) - putconsxy(currcons, header + 2); + putconsxy(vc, header + 2); } p -= HEADER_SIZE; col = (p/2) % maxcol; if (this_round > 0) { - org0 = org = screen_pos(currcons, p/2, viewed); + org0 = org = screen_pos(vc, p/2, viewed); if ((p & 1) && this_round > 0) { char c; this_round--; c = *con_buf0++; #ifdef __BIG_ENDIAN - vcs_scr_writew(currcons, c | - (vcs_scr_readw(currcons, org) & 0xff00), org); + vcs_scr_writew(vc, c | + (vcs_scr_readw(vc, org) & 0xff00), org); #else - vcs_scr_writew(currcons, (c << 8) | - (vcs_scr_readw(currcons, org) & 0xff), org); + vcs_scr_writew(vc, (c << 8) | + (vcs_scr_readw(vc, org) & 0xff), org); #endif org++; p++; if (++col == maxcol) { - org = screen_pos(currcons, p/2, viewed); + org = screen_pos(vc, p/2, viewed); col = 0; } } @@ -416,11 +463,11 @@ unsigned short w; w = get_unaligned(((const unsigned short *)con_buf0)); - vcs_scr_writew(currcons, w, org++); + vcs_scr_writew(vc, w, org++); con_buf0 += 2; this_round -= 2; if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -430,9 +477,9 @@ c = *con_buf0++; #ifdef __BIG_ENDIAN - vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org); + vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org); #else - vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org); + vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org); #endif } } @@ -441,7 +488,7 @@ buf += orig_count; pos += orig_count; if (org0) - update_region(currcons, (unsigned long)(org0), org-org0); + update_region(vc, (unsigned long)(org0), org-org0); } *ppos += written; ret = written; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/vme_scc.c linux-2.5/drivers/char/vme_scc.c --- linux-2.5.20/drivers/char/vme_scc.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/char/vme_scc.c Wed Mar 27 13:07:16 2002 @@ -92,10 +92,10 @@ static void scc_break_ctl(struct tty_struct *tty, int break_state); static struct tty_driver scc_driver, scc_callout_driver; - static struct tty_struct *scc_table[2] = { NULL, }; static struct termios * scc_termios[2]; static struct termios * scc_termios_locked[2]; +static struct console sercons; struct scc_port scc_ports[2]; int scc_refcount; @@ -131,7 +131,11 @@ memset(&scc_driver, 0, sizeof(scc_driver)); scc_driver.magic = TTY_DRIVER_MAGIC; scc_driver.driver_name = "scc"; +#ifdef CONFIG_DEVFS_FS + scc_driver.name = "tts/%d"; +#else scc_driver.name = "ttyS"; +#endif scc_driver.major = TTY_MAJOR; scc_driver.minor_start = SCC_MINOR_BASE; scc_driver.num = 2; @@ -145,7 +149,9 @@ scc_driver.table = scc_table; scc_driver.termios = scc_termios; scc_driver.termios_locked = scc_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + scc_driver.console = &sercons; +#endif scc_driver.open = scc_open; scc_driver.close = gs_close; scc_driver.write = gs_write; @@ -164,7 +170,11 @@ scc_driver.break_ctl = scc_break_ctl; scc_callout_driver = scc_driver; +#ifdef CONFIG_DEVFS_FS + scc_callout_driver.name = "cua/%d"; +#else scc_callout_driver.name = "cua"; +#endif scc_callout_driver.major = TTYAUX_MAJOR; scc_callout_driver.subtype = SERIAL_TYPE_CALLOUT; @@ -731,12 +741,10 @@ #ifdef CONFIG_MVME147_SCC if (MACH_IS_MVME147) brgval = (M147_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; - else #endif #ifdef CONFIG_MVME162_SCC if (MACH_IS_MVME16x) brgval = (MVME_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; - else #endif #ifdef CONFIG_BVME6000_SCC if (MACH_IS_BVME6000) @@ -783,6 +791,15 @@ } +/* Comment taken from sx.c (2.4.0): + I haven't the foggiest why the decrement use count has to happen + here. The whole linux serial drivers stuff needs to be redesigned. + My guess is that this is a hack to minimize the impact of a bug + elsewhere. Thinking about it some more. (try it sometime) Try + running minicom on a serial port that is driven by a modularized + driver. Have the modem hangup. Then remove the driver module. Then + exit minicom. I expect an "oops". -- REW */ + static void scc_hungup(void *ptr) { scc_disable_tx_interrupts(ptr); @@ -795,6 +812,7 @@ { scc_disable_tx_interrupts(ptr); scc_disable_rx_interrupts(ptr); + MOD_DEC_USE_COUNT; } @@ -809,6 +827,7 @@ SCC_ACCESS_INIT(port); save_flags(flags); + cli(); t = SCCread(TX_CTRL_REG); if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR); if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS); @@ -933,7 +952,7 @@ if (port->gs.count == 1) { MOD_INC_USE_COUNT; } - retval = block_til_ready(port, filp); + retval = gs_block_til_ready(port, filp); if (retval) { MOD_DEC_USE_COUNT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/vt.c linux-2.5/drivers/char/vt.c --- linux-2.5.20/drivers/char/vt.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/char/vt.c Fri Apr 19 20:52:23 2002 @@ -1,1316 +1,1896 @@ /* - * linux/drivers/char/vt.c + * vt.c - Built-in console device * - * Copyright (C) 1992 obz under the linux copyright + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * Hopefully this will be a rather complete VT102 implementation. + * + * Beeping thanks to John T Kohl. + * + * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics + * Chars, and VT100 enhancements by Peter MacDonald. + * + * Copy and paste function by Andrew Haylett, + * some enhancements by Alessandro Rubini. + * + * Code to check for different video-cards mostly by Galen Hunt, + * + * + * Rudimentary ISO 10646/Unicode/UTF-8 character set support by + * Markus Kuhn, . + * + * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 + * Resizing of consoles, aeb, 940926 + * + * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 + * + * + * User-defined bell sound, new setterm control sequences and printk + * redirection by Martin Mares 19-Nov-95 + * + * APM screenblank bug fixed Takashi Manabe + * + * Merge with the abstract console driver by Geert Uytterhoeven + * , Jan 1997. + * + * Original m68k console driver modifications by + * + * - Arno Griffioen + * - David Carter + * + * Note that the abstract console driver allows all consoles to be of + * potentially different sizes, so the following variables depend on the + * current console (currcons): * - * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 - * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 - * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 - * Some code moved for less code duplication - Andi Kleen - Mar 1997 - * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 + * - video_num_columns + * - video_num_lines + * - video_size_row + * - can_do_color + * + * The abstract console driver provides a generic interface for a text + * console. It supports VGA text mode, frame buffer based graphical consoles + * and special graphics processors that are only accessible through some + * registers (e.g. a TMS340x0 GSP). + * + * The interface to the hardware is specified using a special structure + * (struct consw) which contains function pointers to console operations + * (see for more information). + * + * Support for changeable cursor shape + * by Pavel Machek , August 1997 + * + * Ported to i386 and con_scrolldelta fixed + * by Emmanuel Marty , April 1998 + * + * Resurrected character buffers in videoram plus lots of other trickery + * by Martin Mares , July 1998 + * + * Removed old-style timers, introduced console_timer, made timer + * deletion SMP-safe. 17Jun00, Andrew Morton + * + * Removed console_lock, enabled interrupts across all console operations + * 13 March 2001, Andrew Morton */ -#include -#include -#include +#include #include #include -#include +#include #include -#include -#include #include +#include +#include #include #include -#include +#include #include - -#include -#include - -#include +#include +#include #include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef CONFIG_FB_COMPAT_XPMAC -#include -#endif /* CONFIG_FB_COMPAT_XPMAC */ +#include +#include +#include +#include -char vt_dont_switch; -extern struct tty_driver console_driver; +#include "console_macros.h" -#define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count) -#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons) +const struct consw *conswitchp; -/* - * Console (vt and kd) routines, as defined by USL SVR4 manual, and by - * experimentation and study of X386 SYSV handling. - * - * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and - * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, - * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will - * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to - * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using - * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing - * to the current console is done by the main ioctl code. +/* A bitmap for codes <32. A bit of 1 indicates that the code + * corresponding to that bit number invokes some special action + * (such as cursor movement) and should not be displayed as a + * glyph unless the disp_ctrl mode is explicitly enabled. */ +#define CTRL_ACTION 0x0d00ff81 +#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ -struct vt_struct *vt_cons[MAX_NR_CONSOLES]; +extern void vcs_make_devfs (unsigned int index, int unregister); +extern void console_map_init(void); -/* Keyboard type: Default is KB_101, but can be set by machine - * specific code. - */ -unsigned char keyboard_type = KB_101; +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +static struct tty_struct *console_table[MAX_NR_CONSOLES]; +static struct termios *console_termios[MAX_NR_CONSOLES]; +static struct termios *console_termios_locked[MAX_NR_CONSOLES]; -#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); +#ifndef VT_SINGLE_DRIVER +static const struct consw *con_driver_map[MAX_NR_CONSOLES]; #endif -unsigned int video_font_height; -unsigned int default_font_height; -unsigned int video_scan_lines; +static void con_flush_chars(struct tty_struct *tty); +static void unblank_screen_t(unsigned long private); + +static int printable; /* Is console ready for printing? */ + +/* + * the default colour table, for VGA+ colour systems + */ +int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, + 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; +int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, + 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; +int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, + 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; + +unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, + 8,12,10,14, 9,13,11,15 }; +int do_poke_blanked_console; /* - * these are the valid i/o ports we're allowed to change. they map all the - * video ports + * fg_console is the current virtual console, + * kmsg_redirect is the console for kernel messages, */ -#define GPFIRST 0x3b4 -#define GPLAST 0x3df -#define GPNUM (GPLAST - GPFIRST + 1) +int fg_console; +int kmsg_redirect; /* - * Generates sound of some frequency for some number of clock ticks - * - * If freq is 0, will turn off sound, else will turn it on for that time. - * If msec is 0, will return immediately, else will sleep for msec time, then - * turn sound off. - * - * We also return immediately, which is what was implied within the X - * comments - KDMKTONE doesn't put the process to sleep. + * Hook so that the power management routines can (un)blank + * the console on our behalf. + */ +int (*console_blank_hook)(int); + +/* + * Low-Level Functions */ +#ifdef VT_BUF_VRAM_ONLY +#define DO_UPDATE 0 +#else +#define DO_UPDATE IS_VISIBLE +#endif -#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ - || (defined(__mips__) && defined(CONFIG_ISA)) \ - || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \ - || defined(__x86_64__) +static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data); +static struct pm_dev *pm_con; -static void -kd_nosound(unsigned long ignored) + +void respond_string(const char * p, struct tty_struct * tty) { - /* disable counter 2 */ - outb(inb_p(0x61)&0xFC, 0x61); - return; + while (*p) { + tty_insert_flip_char(tty, *p, 0); + p++; + } + con_schedule_flip(tty); } -void -_kd_mksound(unsigned int hz, unsigned int ticks) +/* + * Console cursor handling + */ +void add_softcursor(struct vc_data *vc) { - static struct timer_list sound_timer = { function: kd_nosound }; - unsigned int count = 0; - unsigned long flags; + int i = scr_readw((u16 *) pos); u32 type = cursor_type; - if (hz > 20 && hz < 32767) - count = 1193180 / hz; - - save_flags(flags); - cli(); - del_timer(&sound_timer); - if (count) { - /* enable counter 2 */ - outb_p(inb_p(0x61)|3, 0x61); - /* set command for counter 2, 2 byte write */ - outb_p(0xB6, 0x43); - /* select desired HZ */ - outb_p(count & 0xff, 0x42); - outb((count >> 8) & 0xff, 0x42); - - if (ticks) { - sound_timer.expires = jiffies+ticks; - add_timer(&sound_timer); - } - } else - kd_nosound(0); - restore_flags(flags); - return; + if (!(type & 0x10)) return; + if (softcursor_original != -1) return; + softcursor_original = i; + i |= ((type >> 8) & 0xff00 ); + i ^= ((type) & 0xff00 ); + if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) + i ^= 0x7000; + if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; + scr_writew(i, (u16 *) pos); + if (DO_UPDATE) + sw->con_putc(vc, i, y, x); } -#else +void hide_cursor(struct vc_data *vc) +{ + if (cons_num == sel_cons) + clear_selection(); + if (softcursor_original != -1) { + scr_writew(softcursor_original,(u16 *) pos); + if (DO_UPDATE) + sw->con_putc(vc, softcursor_original, y, x); + softcursor_original = -1; + } + sw->con_cursor(vc, CM_ERASE); +} -void -_kd_mksound(unsigned int hz, unsigned int ticks) +void set_cursor(struct vc_data *vc) { + if (!IS_VISIBLE || vc->display_fg->vt_blanked || vcmode == KD_GRAPHICS) + return; + if (dectcem) { + if (cons_num == sel_cons) + clear_selection(); + add_softcursor(vc); + if ((cursor_type & 0x0f) != 1) + sw->con_cursor(vc, CM_DRAW); + } else + hide_cursor(vc); } -#endif +/* + * gotoxy() must verify all boundaries, because the arguments + * might also be negative. If the given position is out of + * bounds, the cursor is placed at the nearest margin. + */ +void gotoxy(struct vc_data *vc, int new_x, int new_y) +{ + int min_y, max_y; + + if (new_x < 0) + x = 0; else + if (new_x >= video_num_columns) + x = video_num_columns - 1; + else + x = new_x; + if (decom) { + min_y = top; + max_y = bottom; + } else { + min_y = 0; + max_y = video_num_lines; + } + if (new_y < min_y) + y = min_y; + else if (new_y >= max_y) + y = max_y - 1; + else + y = new_y; + pos = origin + y*video_size_row + (x<<1); + need_wrap = 0; +} -int _kbd_rate(struct kbd_repeat *rep) +/* for absolute user moves, when decom is set */ +void gotoxay(struct vc_data *vc, int new_x, int new_y) { - return -EINVAL; + gotoxy(vc, new_x, decom ? (top+new_y) : new_y); } -void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound; -int (*kbd_rate)(struct kbd_repeat *rep) = _kbd_rate; +/* + * Palettes + */ -#define i (tmp.kb_index) -#define s (tmp.kb_table) -#define v (tmp.kb_value) -static inline int -do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kbd) +void set_palette(struct vc_data *vc) { - struct kbentry tmp; - ushort *key_map, val, ov; + if (vcmode != KD_GRAPHICS) + sw->con_set_palette(vc, color_table); +} - if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) - return -EFAULT; - if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS) - return -EINVAL; +void reset_palette(struct vc_data *vc) +{ + int j, k; - switch (cmd) { - case KDGKBENT: - key_map = key_maps[s]; - if (key_map) { - val = U(key_map[i]); - if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) - val = K_HOLE; - } else - val = (i ? K_HOLE : K_NOSUCHMAP); - return put_user(val, &user_kbe->kb_value); - case KDSKBENT: - if (!perm) - return -EPERM; - if (!i && v == K_NOSUCHMAP) { - /* disallocate map */ - key_map = key_maps[s]; - if (s && key_map) { - key_maps[s] = 0; - if (key_map[0] == U(K_ALLOCATED)) { - kfree(key_map); - keymap_count--; - } - } - break; - } + for (j=k=0; j<16; j++) { + palette[k++] = default_red[j]; + palette[k++] = default_grn[j]; + palette[k++] = default_blu[j]; + } + set_palette(vc); +} - if (KTYP(v) < NR_TYPES) { - if (KVAL(v) > max_vals[KTYP(v)]) - return -EINVAL; - } else - if (kbd->kbdmode != VC_UNICODE) - return -EINVAL; - - /* ++Geert: non-PC keyboards may generate keycode zero */ -#if !defined(__mc68000__) && !defined(__powerpc__) - /* assignment to entry 0 only tests validity of args */ - if (!i) - break; -#endif +/* + * Load palette into the DAC registers. arg points to a colour + * map, 3 bytes per colour, 16 colours, range from 0 to 255. + */ - if (!(key_map = key_maps[s])) { - int j; +static int set_get_cmap(unsigned char *arg, int set) +{ + struct vc_data *vc; + int i, j, k; - if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && - !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - key_map = (ushort *) kmalloc(sizeof(plain_map), - GFP_KERNEL); - if (!key_map) - return -ENOMEM; - key_maps[s] = key_map; - key_map[0] = U(K_ALLOCATED); - for (j = 1; j < NR_KEYS; j++) - key_map[j] = U(K_HOLE); - keymap_count++; + for (i = 0; i < 16; i++) + if (set) { + get_user(default_red[i], arg++); + get_user(default_grn[i], arg++); + get_user(default_blu[i], arg++); + } else { + put_user(default_red[i], arg++); + put_user(default_grn[i], arg++); + put_user(default_blu[i], arg++); + } + if (set) { + for (i = 0; i < MAX_NR_CONSOLES; i++) { + vc = vt_cons->vc_cons[i]; + if (vc) { + for (j = k = 0; j < 16; j++) { + palette[k++] = default_red[j]; + palette[k++] = default_grn[j]; + palette[k++] = default_blu[j]; + } + set_palette(vc); + } } - ov = U(key_map[i]); - if (v == ov) - break; /* nothing to do */ - /* - * Attention Key. - */ - if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - key_map[i] = U(v); - if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) - compute_shiftstate(); - break; } return 0; } -#undef i -#undef s -#undef v -static inline int -do_kbkeycode_ioctl(int cmd, struct kbkeycode *user_kbkc, int perm) +int con_set_cmap(unsigned char *arg) { - struct kbkeycode tmp; - int kc = 0; + return set_get_cmap (arg,1); +} - if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) - return -EFAULT; - switch (cmd) { - case KDGETKEYCODE: - kc = getkeycode(tmp.scancode); - if (kc >= 0) - kc = put_user(kc, &user_kbkc->keycode); - break; - case KDSETKEYCODE: - if (!perm) - return -EPERM; - kc = setkeycode(tmp.scancode, tmp.keycode); - break; - } - return kc; -} - -static inline int -do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm) -{ - struct kbsentry tmp; - char *p; - u_char *q; - int sz; - int delta; - char *first_free, *fj, *fnw; - int i, j, k; +int con_get_cmap(unsigned char *arg) +{ + return set_get_cmap (arg,0); +} - /* we mostly copy too much here (512bytes), but who cares ;) */ - if (copy_from_user(&tmp, user_kdgkb, sizeof(struct kbsentry))) - return -EFAULT; - tmp.kb_string[sizeof(tmp.kb_string)-1] = '\0'; - if (tmp.kb_func >= MAX_NR_FUNC) - return -EINVAL; - i = tmp.kb_func; +/* + * Functions to handle console scrolling. + */ +static inline void scrolldelta(struct vt_struct *vt, int lines) +{ + vt->scrollback_delta += lines; + + schedule_task(&vt->vt_tq); +} - switch (cmd) { - case KDGKBSENT: - sz = sizeof(tmp.kb_string) - 1; /* sz should have been - a struct member */ - q = user_kdgkb->kb_string; - p = func_table[i]; - if(p) - for ( ; *p && sz; p++, sz--) - if (put_user(*p, q++)) - return -EFAULT; - if (put_user('\0', q)) - return -EFAULT; - return ((p && *p) ? -EOVERFLOW : 0); - case KDSKBSENT: - if (!perm) - return -EPERM; - - q = func_table[i]; - first_free = funcbufptr + (funcbufsize - funcbufleft); - for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) - ; - if (j < MAX_NR_FUNC) - fj = func_table[j]; - else - fj = first_free; - - delta = (q ? -strlen(q) : 1) + strlen(tmp.kb_string); - if (delta <= funcbufleft) { /* it fits in current buf */ - if (j < MAX_NR_FUNC) { - memmove(fj + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] += delta; - } - if (!q) - func_table[i] = fj; - funcbufleft -= delta; - } else { /* allocate a larger buffer */ - sz = 256; - while (sz < funcbufsize - funcbufleft + delta) - sz <<= 1; - fnw = (char *) kmalloc(sz, GFP_KERNEL); - if(!fnw) - return -ENOMEM; - - if (!q) - func_table[i] = fj; - if (fj > funcbufptr) - memmove(fnw, funcbufptr, fj - funcbufptr); - for (k = 0; k < j; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr); - - if (first_free > fj) { - memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; - } - if (funcbufptr != func_buf) - kfree(funcbufptr); - funcbufptr = fnw; - funcbufleft = funcbufleft - delta + sz - funcbufsize; - funcbufsize = sz; - } - strcpy(func_table[i], tmp.kb_string); - break; - } - return 0; +void scrollback(struct vc_data *vc, int lines) +{ + if (!lines) + lines = video_num_lines/2; + scrolldelta(vc->display_fg, -lines); } -static inline int -do_fontx_ioctl(int cmd, struct consolefontdesc *user_cfd, int perm) +void scrollfront(struct vc_data *vc, int lines) { - struct consolefontdesc cfdarg; - struct console_font_op op; - int i; + if (!lines) + lines = video_num_lines/2; + scrolldelta(vc->display_fg, lines); +} - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) - return -EFAULT; - - switch (cmd) { - case PIO_FONTX: - if (!perm) - return -EPERM; - op.op = KD_FONT_OP_SET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = cfdarg.charheight; - op.charcount = cfdarg.charcount; - op.data = cfdarg.chardata; - return con_font_op(fg_console, &op); - case GIO_FONTX: { - op.op = KD_FONT_OP_GET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = cfdarg.charheight; - op.charcount = cfdarg.charcount; - op.data = cfdarg.chardata; - i = con_font_op(fg_console, &op); - if (i) - return i; - cfdarg.charheight = op.height; - cfdarg.charcount = op.charcount; - if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) - return -EFAULT; - return 0; - } - } - return -EINVAL; +void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) +{ + unsigned short *d, *s; + + if (t+nr >= b) + nr = b - t; + if (b > video_num_lines || t >= b || nr < 1) + return; + if (IS_VISIBLE && sw->con_scroll(vc, t, b, SM_UP, nr)) + return; + d = (unsigned short *) (origin+video_size_row*t); + s = (unsigned short *) (origin+video_size_row*(t+nr)); + scr_memcpyw(d, s, (b-t-nr) * video_size_row); + scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr); } -static inline int -do_unimap_ioctl(int cmd, struct unimapdesc *user_ud,int perm) +void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) { - struct unimapdesc tmp; - int i = 0; + unsigned short *s; + unsigned int step; - if (copy_from_user(&tmp, user_ud, sizeof tmp)) - return -EFAULT; - if (tmp.entries) { - i = verify_area(VERIFY_WRITE, tmp.entries, - tmp.entry_ct*sizeof(struct unipair)); - if (i) return i; - } - switch (cmd) { - case PIO_UNIMAP: - if (!perm) - return -EPERM; - return con_set_unimap(fg_console, tmp.entry_ct, tmp.entries); - case GIO_UNIMAP: - return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); - } - return 0; + if (t+nr >= b) + nr = b - t; + if (b > video_num_lines || t >= b || nr < 1) + return; + if (IS_VISIBLE && sw->con_scroll(vc, t, b, SM_DOWN, nr)) + return; + s = (unsigned short *) (origin+video_size_row*t); + step = video_num_columns * nr; + scr_memmovew(s + step, s, (b-t-nr)*video_size_row); + scr_memsetw(s, video_erase_char, 2*step); +} + +/* + * Console attribute handling. Structure of attributes is hardware-dependent + */ +void default_attr(struct vc_data *vc) +{ + intensity = 1; + underline = 0; + reverse = 0; + blink = 0; + color = def_color; } /* - * We handle the console-specific ioctl's here. We allow the - * capability to modify any console, not just the fg_console. + * ++roman: I completely changed the attribute format for monochrome + * mode (!can_do_color). The formerly used MDA (monochrome display + * adapter) format didn't allow the combination of certain effects. + * Now the attribute is just a bit vector: + * Bit 0..1: intensity (0..2) + * Bit 2 : underline + * Bit 3 : reverse + * Bit 7 : blink */ -int vt_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) { - int i, perm; - unsigned int console; - unsigned char ucval; - struct kbd_struct * kbd; - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; + if (sw->con_build_attr) + return sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse); - console = vt->vc_num; +#ifndef VT_BUF_VRAM_ONLY + { + u8 a = color; + if (!can_do_color) + return _intensity | + (_underline ? 4 : 0) | + (_reverse ? 8 : 0) | + (_blink ? 0x80 : 0); + if (_underline) + a = (a & 0xf0) | ulcolor; + else if (_intensity == 0) + a = (a & 0xf0) | halfcolor; + if (_reverse) + a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77); + if (_blink) + a ^= 0x80; + if (_intensity == 2) + a ^= 0x08; + if (hi_font_mask == 0x100) + a <<= 1; + return a; + } +#else + return 0; +#endif +} - if (!vc_cons_allocated(console)) /* impossible? */ - return -ENOIOCTLCMD; +void update_attr(struct vc_data *vc) +{ + attr = build_attr(vc, color, intensity, blink, underline, reverse ^ decscnm); + video_erase_char = (build_attr(vc, color, intensity, 0, 0, decscnm) << 8) | ' '; +} - /* - * To have permissions to do most of the vt ioctls, we either have - * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. - */ - perm = 0; - if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG)) - perm = 1; - - kbd = kbd_table + console; - switch (cmd) { - case KIOCSOUND: - if (!perm) - return -EPERM; - if (arg) - arg = 1193180 / arg; - kd_mksound(arg, 0); - return 0; +/* + * Character management + */ +void insert_char(struct vc_data *vc, unsigned int nr) +{ + unsigned short *p, *q = (unsigned short *) pos; - case KDMKTONE: - if (!perm) - return -EPERM; - { - unsigned int ticks, count; - - /* - * Generate the tone for the appropriate number of ticks. - * If the time is zero, turn off sound ourselves. - */ - ticks = HZ * ((arg >> 16) & 0xffff) / 1000; - count = ticks ? (arg & 0xffff) : 0; - if (count) - count = 1193180 / count; - kd_mksound(count, ticks); - return 0; + p = q + video_num_columns - nr - x; + while (--p >= q) + scr_writew(scr_readw(p), p + nr); + scr_memsetw(q, video_erase_char, nr*2); + need_wrap = 0; + if (DO_UPDATE) { + unsigned short oldattr = attr; + + sw->con_bmove(vc, y, x, y, x+nr, 1, video_num_columns-x-nr); + attr = video_erase_char >> 8; + while (nr--) + sw->con_putc(vc, video_erase_char, y, x+nr); + attr = oldattr; } +} - case KDGKBTYPE: - /* - * this is naive. - */ - ucval = keyboard_type; - goto setchar; +void delete_char(struct vc_data *vc, unsigned int nr) +{ + unsigned int i = x; + unsigned short *p = (unsigned short *) pos; -#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) - /* - * These cannot be implemented on any machine that implements - * ioperm() in user level (such as Alpha PCs). - */ - case KDADDIO: - case KDDELIO: - /* - * KDADDIO and KDDELIO may be able to add ports beyond what - * we reject here, but to be safe... - */ - if (arg < GPFIRST || arg > GPLAST) - return -EINVAL; - return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; - - case KDENABIO: - case KDDISABIO: - return sys_ioperm(GPFIRST, GPNUM, - (cmd == KDENABIO)) ? -ENXIO : 0; -#endif + while (++i <= video_num_columns - nr) { + scr_writew(scr_readw(p+nr), p); + p++; + } + scr_memsetw(p, video_erase_char, nr*2); + need_wrap = 0; + if (DO_UPDATE) { + unsigned short oldattr = attr; + sw->con_bmove(vc, y, x+nr, y, x, 1, + video_num_columns-x-nr); + attr = video_erase_char >> 8; + while (nr--) + sw->con_putc(vc, video_erase_char, y, + video_num_columns-1-nr); + attr = oldattr; + } +} - /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ - - case KDKBDREP: - { - struct kbd_repeat kbrep; - - if (!capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; +void insert_line(struct vc_data *vc, unsigned int nr) +{ + scrdown(vc, y, bottom, nr); + need_wrap = 0; +} - if (copy_from_user(&kbrep, (void *)arg, - sizeof(struct kbd_repeat))) - return -EFAULT; - if ((i = kbd_rate( &kbrep ))) - return i; - if (copy_to_user((void *)arg, &kbrep, - sizeof(struct kbd_repeat))) - return -EFAULT; - return 0; - } +void delete_line(struct vc_data *vc, unsigned int nr) +{ + scrup(vc, y, bottom, nr); + need_wrap = 0; +} - case KDSETMODE: - /* - * currently, setting the mode from KD_TEXT to KD_GRAPHICS - * doesn't do a whole lot. i'm not sure if it should do any - * restoration of modes or what... - */ - if (!perm) - return -EPERM; - switch (arg) { - case KD_GRAPHICS: - break; - case KD_TEXT0: - case KD_TEXT1: - arg = KD_TEXT; - case KD_TEXT: - break; - default: - return -EINVAL; - } - if (vt_cons[console]->vc_mode == (unsigned char) arg) - return 0; - vt_cons[console]->vc_mode = (unsigned char) arg; - if (console != fg_console) - return 0; - /* - * explicitly blank/unblank the screen if switching modes - */ - if (arg == KD_TEXT) - unblank_screen(); - else - do_blank_screen(1); - return 0; +/* + * Functions that manage whats displayed on the screen + */ +void set_origin(struct vc_data *vc) +{ + if (!IS_VISIBLE || !sw->con_set_origin || !sw->con_set_origin(vc)) + origin = (unsigned long) screenbuf; + visible_origin = origin; + scr_end = origin + screenbuf_size; + pos = origin + video_size_row*y + 2*x; +} - case KDGETMODE: - ucval = vt_cons[console]->vc_mode; - goto setint; - - case KDMAPDISP: - case KDUNMAPDISP: - /* - * these work like a combination of mmap and KDENABIO. - * this could be easily finished. - */ - return -EINVAL; +inline void clear_region(struct vc_data *vc,int sx,int sy,int width,int height) +{ + /* Clears the video memory, not the screen buffer */ + if (DO_UPDATE && sw->con_clear) + return sw->con_clear(vc, sy, sx, height, width); +} - case KDSKBMODE: - if (!perm) - return -EPERM; - switch(arg) { - case K_RAW: - kbd->kbdmode = VC_RAW; - break; - case K_MEDIUMRAW: - kbd->kbdmode = VC_MEDIUMRAW; - break; - case K_XLATE: - kbd->kbdmode = VC_XLATE; - compute_shiftstate(); - break; - case K_UNICODE: - kbd->kbdmode = VC_UNICODE; - compute_shiftstate(); - break; - default: - return -EINVAL; - } - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - return 0; +inline void save_screen(struct vc_data *vc) +{ + if (sw->con_save_screen) + sw->con_save_screen(vc); +} - case KDGKBMODE: - ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : - (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : - (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : - K_XLATE); - goto setint; - - /* this could be folded into KDSKBMODE, but for compatibility - reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ - case KDSKBMETA: - switch(arg) { - case K_METABIT: - clr_vc_kbd_mode(kbd, VC_META); - break; - case K_ESCPREFIX: - set_vc_kbd_mode(kbd, VC_META); +void do_update_region(struct vc_data *vc, unsigned long start, int count) +{ +#ifndef VT_BUF_VRAM_ONLY + unsigned int xx, yy, offset; + u16 *p; + + p = (u16 *) start; + if (!sw->con_getxy) { + offset = (start - origin) / 2; + xx = offset % video_num_columns; + yy = offset / video_num_columns; + } else { + int nxx, nyy; + start = sw->con_getxy(vc, start, &nxx, &nyy); + xx = nxx; yy = nyy; + } + for(;;) { + u16 attrib = scr_readw(p) & 0xff00; + int startx = xx; + u16 *q = p; + while (xx < video_num_columns && count) { + if (attrib != (scr_readw(p) & 0xff00)) { + if (p > q) + sw->con_putcs(vc, q, p-q, yy, startx); + startx = xx; + q = p; + attrib = scr_readw(p) & 0xff00; + } + p++; + xx++; + count--; + } + if (p > q) + sw->con_putcs(vc, q, p-q, yy, startx); + if (!count) break; - default: - return -EINVAL; + xx = 0; + yy++; + if (sw->con_getxy) { + p = (u16 *)start; + start = sw->con_getxy(vc, start, NULL, NULL); } - return 0; + } +#endif +} - case KDGKBMETA: - ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); - setint: - return put_user(ucval, (int *)arg); - - case KDGETKEYCODE: - case KDSETKEYCODE: - if(!capable(CAP_SYS_TTY_CONFIG)) - perm=0; - return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); - - case KDGKBENT: - case KDSKBENT: - return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd); - - case KDGKBSENT: - case KDSKBSENT: - return do_kdgkb_ioctl(cmd, (struct kbsentry *)arg, perm); +void update_region(struct vc_data *vc, unsigned long start, int count) +{ + if (DO_UPDATE) { + hide_cursor(vc); + do_update_region(vc, start, count); + set_cursor(vc); + } +} - case KDGKBDIACR: - { - struct kbdiacrs *a = (struct kbdiacrs *)arg; +inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) +{ + unsigned short *p; - if (put_user(accent_table_size, &a->kb_cnt)) - return -EFAULT; - if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr))) - return -EFAULT; - return 0; - } + if (!viewed) + p = (unsigned short *)(origin + offset); + else if (!sw->con_screen_pos) + p = (unsigned short *)(visible_origin + offset); + else + p = sw->con_screen_pos(vc, offset); + return p; +} - case KDSKBDIACR: - { - struct kbdiacrs *a = (struct kbdiacrs *)arg; - unsigned int ct; +/* Note: inverting the screen twice should revert to the original state */ +void invert_screen(struct vc_data *vc, int offset, int count, int viewed) +{ + unsigned short *p; - if (!perm) - return -EPERM; - if (get_user(ct,&a->kb_cnt)) - return -EFAULT; - if (ct >= MAX_DIACR) - return -EINVAL; - accent_table_size = ct; - if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr))) - return -EFAULT; - return 0; + count /= 2; + p = screenpos(vc, offset, viewed); + if (sw->con_invert_region) + sw->con_invert_region(vc, p, count); +#ifndef VT_BUF_VRAM_ONLY + else { + u16 *q = p; + int cnt = count; + u16 a; + + if (!can_do_color) { + while (cnt--) { + a = scr_readw(q); + a ^= 0x0800; + scr_writew(a, q); + q++; + } + } else if (hi_font_mask == 0x100) { + while (cnt--) { + a = scr_readw(q); + a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); + scr_writew(a, q); + q++; + } + } else { + while (cnt--) { + a = scr_readw(q); + a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); + scr_writew(a, q); + q++; + } + } } +#endif + if (DO_UPDATE) + do_update_region(vc, (unsigned long) p, count); +} - /* the ioctls below read/set the flags usually shown in the leds */ - /* don't use them - they will go away without warning */ - case KDGKBLED: - ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); - goto setchar; - - case KDSKBLED: - if (!perm) - return -EPERM; - if (arg & ~0x77) - return -EINVAL; - kbd->ledflagstate = (arg & 7); - kbd->default_ledflagstate = ((arg >> 4) & 7); - set_leds(); - return 0; - - /* the ioctls below only set the lights, not the functions */ - /* for those, see KDGKBLED and KDSKBLED above */ - case KDGETLED: - ucval = getledstate(); - setchar: - return put_user(ucval, (char*)arg); - - case KDSETLED: - if (!perm) - return -EPERM; - setledstate(kbd, arg); - return 0; +/* Redrawing of screen */ +void update_screen(struct vc_data *vc) +{ + int update; - /* - * A process can indicate its willingness to accept signals - * generated by pressing an appropriate key combination. - * Thus, one can have a daemon that e.g. spawns a new console - * upon a keypress and then changes to it. - * Probably init should be changed to do this (and have a - * field ks (`keyboard signal') in inittab describing the - * desired action), so that the number of background daemons - * does not increase. - */ - case KDSIGACCEPT: - { - extern int spawnpid, spawnsig; - if (!perm || !capable(CAP_KILL)) - return -EPERM; - if (arg < 1 || arg > _NSIG || arg == SIGKILL) - return -EINVAL; - spawnpid = current->pid; - spawnsig = arg; - return 0; - } + if (!vc) return; - case VT_SETMODE: - { - struct vt_mode tmp; + hide_cursor(vc); + set_origin(vc); - if (!perm) - return -EPERM; - if (copy_from_user(&tmp, (void*)arg, sizeof(struct vt_mode))) - return -EFAULT; - if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) - return -EINVAL; - vt_cons[console]->vt_mode = tmp; - /* the frsig is ignored, so we set it to 0 */ - vt_cons[console]->vt_mode.frsig = 0; - vt_cons[console]->vt_pid = current->pid; - /* no switch is required -- saw@shade.msu.ru */ - vt_cons[console]->vt_newvt = -1; - return 0; - } + update = sw->con_switch(vc); + set_palette(vc); - case VT_GETMODE: - return copy_to_user((void*)arg, &(vt_cons[console]->vt_mode), - sizeof(struct vt_mode)) ? -EFAULT : 0; + if (update && vcmode != KD_GRAPHICS) + do_update_region(vc, origin, screenbuf_size/2); - /* - * Returns global vt state. Note that VT 0 is always open, since - * it's an alias for the current VT, and people can't use it here. - * We cannot return state for more than 16 VTs, since v_state is short. - */ - case VT_GETSTATE: - { - struct vt_stat *vtstat = (struct vt_stat *)arg; - unsigned short state, mask; + set_cursor(vc); +} - if (put_user(fg_console + 1, &vtstat->v_active)) - return -EFAULT; - state = 1; /* /dev/tty0 is always open */ - for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) - if (VT_IS_IN_USE(i)) - state |= mask; - return put_user(state, &vtstat->v_state); +/* used by selection: complement pointer position */ +void complement_pos(struct vc_data *vc, int offset) +{ + static unsigned short *p; + static unsigned short old; + static unsigned short oldx, oldy; + + if (p) { + scr_writew(old, p); + if (DO_UPDATE) + sw->con_putc(vc, old, oldy, oldx); + } + if (offset == -1) + p = NULL; + else { + unsigned short new; + p = screenpos(vc, offset, 1); + old = scr_readw(p); + new = old ^ complement_mask; + scr_writew(new, p); + if (DO_UPDATE) { + oldx = (offset >> 1) % video_num_columns; + oldy = (offset >> 1) / video_num_columns; + sw->con_putc(vc, new, oldy, oldx); + } } +} - /* - * Returns the first available (non-opened) console. - */ - case VT_OPENQRY: - for (i = 0; i < MAX_NR_CONSOLES; ++i) - if (! VT_IS_IN_USE(i)) - break; - ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; - goto setint; +/* + * Screen blanking + */ - /* - * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, - * with num >= 1 (switches to vt 0, our console, are not allowed, just - * to preserve sanity). - */ - case VT_ACTIVATE: - if (!perm) - return -EPERM; - if (arg == 0 || arg > MAX_NR_CONSOLES) - return -ENXIO; - arg--; - i = vc_allocate(arg); - if (i) - return i; - set_console(arg); - return 0; +/* This is a timer handler */ +static void powerdown_screen(unsigned long private) +{ + struct vt_struct *vt = (struct vt_struct *) private; + struct vc_data *vc = vt->vc_cons[fg_console]; - /* - * wait until the specified VT has been activated - */ - case VT_WAITACTIVE: - if (!perm) - return -EPERM; - if (arg == 0 || arg > MAX_NR_CONSOLES) - return -ENXIO; - return vt_waitactive(arg-1); + vt->timer.function = unblank_screen_t; /* - * If a vt is under process control, the kernel will not switch to it - * immediately, but postpone the operation until the process calls this - * ioctl, allowing the switch to complete. - * - * According to the X sources this is the behavior: - * 0: pending switch-from not OK - * 1: pending switch-from OK - * 2: completed switch-to OK + * Power down if currently suspended (1 or 2), + * suspend if currently blanked (0), + * else do nothing (i.e. already powered down (3)). + * Called only if powerdown features are allowed. */ - case VT_RELDISP: - if (!perm) - return -EPERM; - if (vt_cons[console]->vt_mode.mode != VT_PROCESS) - return -EINVAL; - - /* - * Switching-from response - */ - if (vt_cons[console]->vt_newvt >= 0) - { - if (arg == 0) - /* - * Switch disallowed, so forget we were trying - * to do it. - */ - vt_cons[console]->vt_newvt = -1; - - else - { - /* - * The current vt has been released, so - * complete the switch. - */ - int newvt = vt_cons[console]->vt_newvt; - vt_cons[console]->vt_newvt = -1; - i = vc_allocate(newvt); - if (i) - return i; - /* - * When we actually do the console switch, - * make sure we are atomic with respect to - * other console switches.. - */ - acquire_console_sem(); - complete_change_console(newvt); - release_console_sem(); - } - } + switch (vt->blank_mode) { + case VESA_NO_BLANKING: + vt->vt_sw->con_blank(vc, VESA_VSYNC_SUSPEND+1); + break; + case VESA_VSYNC_SUSPEND: + case VESA_HSYNC_SUSPEND: + vt->vt_sw->con_blank(vc, VESA_POWERDOWN+1); + break; + } +} - /* - * Switched-to response - */ - else - { - /* - * If it's just an ACK, ignore it - */ - if (arg != VT_ACKACQ) - return -EINVAL; - } +static void timer_do_blank_screen(struct vt_struct *vt, int entering_gfx, + int from_timer_handler) +{ + struct vc_data *vc = vt->vc_cons[fg_console]; + int i; - return 0; + if (vt->vt_blanked) + return; - /* - * Disallocate memory associated to VT (but leave VT1) - */ - case VT_DISALLOCATE: - if (arg > MAX_NR_CONSOLES) - return -ENXIO; - if (arg == 0) { - /* disallocate all unused consoles, but leave 0 */ - for (i=1; icon_blank(vc, -1); + vt->vt_blanked = fg_console + 1; + set_origin(vc); + return; + } - case VT_RESIZE: - { - struct vt_sizes *vtsizes = (struct vt_sizes *) arg; - ushort ll,cc; - if (!perm) - return -EPERM; - if (get_user(ll, &vtsizes->v_rows) || - get_user(cc, &vtsizes->v_cols)) - return -EFAULT; - return vc_resize_all(ll, cc); + /* don't blank graphics */ + if (vcmode != KD_TEXT) { + vt->vt_blanked = fg_console + 1; + return; } - case VT_RESIZEX: - { - struct vt_consize *vtconsize = (struct vt_consize *) arg; - ushort ll,cc,vlin,clin,vcol,ccol; - if (!perm) - return -EPERM; - if (verify_area(VERIFY_READ, (void *)vtconsize, - sizeof(struct vt_consize))) - return -EFAULT; - __get_user(ll, &vtconsize->v_rows); - __get_user(cc, &vtconsize->v_cols); - __get_user(vlin, &vtconsize->v_vlin); - __get_user(clin, &vtconsize->v_clin); - __get_user(vcol, &vtconsize->v_vcol); - __get_user(ccol, &vtconsize->v_ccol); - vlin = vlin ? vlin : video_scan_lines; - if ( clin ) - { - if ( ll ) - { - if ( ll != vlin/clin ) - return -EINVAL; /* Parameters don't add up */ - } - else - ll = vlin/clin; - } - if ( vcol && ccol ) - { - if ( cc ) - { - if ( cc != vcol/ccol ) - return -EINVAL; - } - else - cc = vcol/ccol; - } - - if ( clin > 32 ) - return -EINVAL; - - if ( vlin ) - video_scan_lines = vlin; - if ( clin ) - video_font_height = clin; - - return vc_resize_all(ll, cc); - } + hide_cursor(vc); + if (!from_timer_handler) + del_timer_sync(&vt->timer); + if (vt->off_interval) { + vt->timer.function = powerdown_screen; + mod_timer(&vt->timer, jiffies + vt->off_interval); + } else { + if (!from_timer_handler) + del_timer_sync(&vt->timer); + vt->timer.function = unblank_screen_t; + } + + save_screen(vc); + /* In case we need to reset origin, blanking hook returns 1 */ + i = sw->con_blank(vc, 1); + vt->vt_blanked = fg_console + 1; + if (i) + set_origin(vc); - case PIO_FONT: { - struct console_font_op op; - if (!perm) - return -EPERM; - op.op = KD_FONT_OP_SET; - op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ - op.width = 8; - op.height = 0; - op.charcount = 256; - op.data = (char *) arg; - return con_font_op(fg_console, &op); - } - - case GIO_FONT: { - struct console_font_op op; - op.op = KD_FONT_OP_GET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = 32; - op.charcount = 256; - op.data = (char *) arg; - return con_font_op(fg_console, &op); - } - - case PIO_CMAP: - if (!perm) - return -EPERM; - return con_set_cmap((char *)arg); - - case GIO_CMAP: - return con_get_cmap((char *)arg); - - case PIO_FONTX: - case GIO_FONTX: - return do_fontx_ioctl(cmd, (struct consolefontdesc *)arg, perm); + if (console_blank_hook && console_blank_hook(1)) + return; + if (vt->blank_mode) + sw->con_blank(vc, vt->blank_mode + 1); +} - case PIO_FONTRESET: - { - if (!perm) - return -EPERM; +void do_blank_screen(struct vt_struct *vt, int entering_gfx) +{ + timer_do_blank_screen(vt, entering_gfx, 0); +} -#ifdef BROKEN_GRAPHICS_PROGRAMS - /* With BROKEN_GRAPHICS_PROGRAMS defined, the default - font is not saved. */ - return -ENOSYS; -#else - { - struct console_font_op op; - op.op = KD_FONT_OP_SET_DEFAULT; - op.data = NULL; - i = con_font_op(fg_console, &op); - if (i) return i; - con_set_default_unimap(fg_console); - return 0; +/* This is both a user-level callable and a timer handler */ +static void blank_screen(unsigned long private) +{ + struct vt_struct *vt = (struct vt_struct *) private; + + timer_do_blank_screen(vt, 0, 1); +} + +/* This is a timer handler */ +static void unblank_screen_t(unsigned long private) +{ + unblank_screen(); +} + +/* Called by timer as well as from vt_console_driver */ +void unblank_screen(void) +{ + struct vt_struct *vt = vt_cons; + struct vc_data *vc = vt->vc_cons[fg_console]; + + if (!vt->vt_blanked) + return; + if (!vc) { + /* impossible */ + printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); + return; + } + if (vcmode != KD_TEXT) + return; /* but leave console_blanked != 0 */ + + vt->timer.function = blank_screen; + if (vt->blank_interval) + mod_timer(&vt->timer, jiffies + vt->blank_interval); + + vt->vt_blanked = 0; + if (console_blank_hook) + console_blank_hook(0); + if (sw->con_blank(vc, 0)) + /* Low-level driver cannot restore -> do it ourselves */ + update_screen(vc); + set_cursor(vc); +} + +void poke_blanked_console(struct vt_struct *vt) +{ + del_timer(&vt->timer); + if (!vt->vc_cons[fg_console] || vt->vc_cons[fg_console]->vc_mode == KD_GRAPHICS) + return; + if (vt->vt_blanked) { + vt->timer.function = unblank_screen_t; + mod_timer(&vt->timer, jiffies); /* Now */ + } else if (vt->blank_interval) { + mod_timer(&vt->timer, jiffies + vt->blank_interval); + } +} + +/* + * Power management for the console system. + */ +static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + struct vt_struct *vt = dev->data; + + if (vt) { + switch (rqst) { + case PM_RESUME: + unblank_screen(); + break; + case PM_SUSPEND: + do_blank_screen(vt, 0); + break; } + } + return 0; +} + +/* + * Allocation, freeing and resizing of VCs. + */ + +int vc_cons_allocated(unsigned int i) +{ + return (i < MAX_NR_CONSOLES && vt_cons->vc_cons[i]); +} + +void set_console(int nr) +{ + struct vt_struct *vt = vt_cons; + + vt->want_vc = vt->vc_cons[nr]; + schedule_task(&vt->vt_tq); +} + +static void visual_init(struct vc_data *vc, int init) +{ + /* ++Geert: sw->con_init determines console size */ + int currcons = cons_num; + + sw = conswitchp; +#ifndef VT_SINGLE_DRIVER + if (con_driver_map[currcons]) + sw = con_driver_map[currcons]; #endif + vc->display_fg->vc_cons[currcons] = vc; + vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; + vc->vc_uni_pagedir = 0; + hi_font_mask = 0; + complement_mask = 0; + can_do_color = 0; + sw->con_init(vc, init); + if (!complement_mask) + complement_mask = can_do_color ? 0x7700 : 0x0800; + s_complement_mask = complement_mask; + video_size_row = video_num_columns<<1; + screenbuf_size = video_num_lines*video_size_row; +} + +static void vc_init(struct vc_data *vc, int do_clear) +{ + set_origin(vc); + pos = origin; + reset_vc(vc); + def_color = 0x07; /* white */ + ulcolor = 0x0f; /* bold white */ + halfcolor = 0x08; /* grey */ + init_waitqueue_head(&vc->paste_wait); + vte_ris(vc, do_clear); +} + +int vc_allocate(unsigned int currcons) /* return 0 on success */ +{ + struct vc_data *vc; + + if (currcons >= MAX_NR_CONSOLES) + return -ENXIO; + if (!vt_cons->vc_cons[currcons]) { + long p, q; + + /* prevent users from taking too much memory */ + if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) + return -EPERM; + + /* due to the granularity of kmalloc, we waste some memory here */ + /* the alloc is done in two steps, to optimize the common situation + of a 25x80 console (structsize=216, screenbuf_size=4000) */ + /* although the numbers above are not valid since long ago, the + point is still up-to-date and the comment still has its value + even if only as a historical artifact. --mj, July 1998 */ + p = (long) kmalloc(sizeof(struct vc_data), GFP_KERNEL); + if (!p) + return -ENOMEM; + vc = (struct vc_data *)p; + cons_num = currcons; + vc->display_fg = vt_cons; + visual_init(vc, 1); + if (!*vc->vc_uni_pagedir_loc) + con_set_default_unimap(vc); + q = (long)kmalloc(screenbuf_size, GFP_KERNEL); + if (!q) { + kfree((char *) p); + vc->display_fg->vc_cons[currcons] = NULL; + return -ENOMEM; + } + screenbuf = (unsigned short *) q; + kmalloced = 1; + vc_init(vc, 1); + + if (!pm_con) { + pm_con = pm_register(PM_SYS_DEV, PM_SYS_VGA, + pm_con_request); + if (pm_con) + pm_con->data = vt_cons; + } } + return 0; +} - case KDFONTOP: { - struct console_font_op op; - if (copy_from_user(&op, (void *) arg, sizeof(op))) - return -EFAULT; - if (!perm && op.op != KD_FONT_OP_GET) - return -EPERM; - i = con_font_op(console, &op); - if (i) return i; - if (copy_to_user((void *) arg, &op, sizeof(op))) - return -EFAULT; +/* + * Change # of rows and columns (0 means unchanged/the size of fg_console) + * [this is to be used together with some user program + * like resize that changes the hardware videomode] + */ +int vc_resize(unsigned int lines, unsigned int cols, + unsigned int first, unsigned int last) +{ + unsigned int cc, ll, ss, sr, todo = 0; + unsigned int currcons = fg_console, i; + unsigned short *newscreens[MAX_NR_CONSOLES]; + struct vc_data *vc = vt_cons->vc_cons[currcons]; + + cc = (cols ? cols : video_num_columns); + ll = (lines ? lines : video_num_lines); + sr = cc << 1; + ss = sr * ll; + + for (currcons = first; currcons <= last; currcons++) { + if (!vc_cons_allocated(currcons) || + (cc == video_num_columns && ll == video_num_lines)) + newscreens[currcons] = NULL; + else { + unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER); + if (!p) { + for (i = first; i < currcons; i++) + if (newscreens[i]) + kfree(newscreens[i]); + return -ENOMEM; + } + newscreens[currcons] = p; + todo++; + } + } + if (!todo) return 0; + + for (currcons = first; currcons <= last; currcons++) { + unsigned int occ, oll, oss, osr; + unsigned long ol, nl, nlend, rlth, rrem; + struct vc_data *vc = vt_cons->vc_cons[currcons]; + + if (!newscreens[currcons] || !vc) + continue; + + oll = video_num_lines; + occ = video_num_columns; + osr = video_size_row; + oss = screenbuf_size; + + video_num_lines = ll; + video_num_columns = cc; + video_size_row = sr; + screenbuf_size = ss; + + rlth = MIN(osr, sr); + rrem = sr - rlth; + ol = origin; + nl = (long) newscreens[currcons]; + nlend = nl + ss; + if (ll < oll) + ol += (oll - ll) * osr; + + update_attr(vc); + + while (ol < scr_end) { + scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); + if (rrem) + scr_memsetw((void *)(nl + rlth), video_erase_char, rrem); + ol += osr; + nl += sr; + } + if (nlend > nl) + scr_memsetw((void *) nl, video_erase_char, nlend - nl); + if (kmalloced) + kfree(screenbuf); + screenbuf = newscreens[currcons]; + kmalloced = 1; + screenbuf_size = ss; + set_origin(vc); + + /* do part of a vte_ris() */ + top = 0; + bottom = video_num_lines; + gotoxy(vc, x, y); + vte_decsc(vc); + + if (console_table[currcons]) { + struct winsize ws, *cws = &console_table[currcons]->winsize; + memset(&ws, 0, sizeof(ws)); + ws.ws_row = video_num_lines; + ws.ws_col = video_num_columns; + if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && + console_table[currcons]->pgrp > 0) + kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1); + *cws = ws; + } + + if (IS_VISIBLE) + update_screen(vc); } + return 0; +} - case PIO_SCRNMAP: - if (!perm) - return -EPERM; - return con_set_trans_old((unsigned char *)arg); - - case GIO_SCRNMAP: - return con_get_trans_old((unsigned char *)arg); - - case PIO_UNISCRNMAP: - if (!perm) - return -EPERM; - return con_set_trans_new((unsigned short *)arg); - - case GIO_UNISCRNMAP: - return con_get_trans_new((unsigned short *)arg); - - case PIO_UNIMAPCLR: - { struct unimapinit ui; - if (!perm) - return -EPERM; - i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit)); - if (i) return -EFAULT; - con_clear_unimap(fg_console, &ui); - return 0; - } +void vc_disallocate(unsigned int currcons) +{ + struct vc_data *vc = vt_cons->vc_cons[currcons]; - case PIO_UNIMAP: - case GIO_UNIMAP: - return do_unimap_ioctl(cmd, (struct unimapdesc *)arg, perm); - - case VT_LOCKSWITCH: - if (!capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; - vt_dont_switch = 1; - return 0; - case VT_UNLOCKSWITCH: - if (!capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; - vt_dont_switch = 0; - return 0; -#ifdef CONFIG_FB_COMPAT_XPMAC - case VC_GETMODE: - { - struct vc_mode mode; - - i = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct vc_mode)); - if (i == 0) - i = console_getmode(&mode); - if (i) - return i; - if (copy_to_user((void *) arg, &mode, sizeof(mode))) - return -EFAULT; - return 0; + acquire_console_sem(); + if (vc) { + sw->con_deinit(vc); + if (kmalloced) + kfree(screenbuf); + if (currcons >= MIN_NR_CONSOLES) + kfree(vt_cons->vc_cons[currcons]); + vt_cons->vc_cons[currcons] = NULL; + } + release_console_sem(); +} + +/* + * Selection stuff for GPM. + */ +void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) +{ + char buf[8]; + + sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), + (char)('!' + mry)); + respond_string(buf, tty); +} + +/* invoked via ioctl(TIOCLINUX) and through set_selection */ +int mouse_reporting(struct vc_data *vc) +{ + return report_mouse; +} + +/* This is a temporary buffer used to prepare a tty console write + * so that we can easily avoid touching user space while holding the + * console spinlock. It is allocated in vt_console_init and is shared by + * this code and the vc_screen read/write tty calls. + * + * We have to allocate this statically in the kernel data section + * since console_init (and thus vt_console_init) are called before any + * kernel memory allocation is available. + */ +char con_buf[PAGE_SIZE]; +#define CON_BUF_SIZE PAGE_SIZE +DECLARE_MUTEX(con_buf_sem); + +static int do_con_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ +#ifdef VT_BUF_VRAM_ONLY +#define FLUSH do { } while(0); +#else +#define FLUSH if (draw_x >= 0) { \ + sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \ + draw_x = -1; \ + } +#endif + + int c, tc, ok, n = 0, draw_x = -1; + unsigned long draw_from = 0, draw_to = 0; + struct vc_data *vc = (struct vc_data *)tty->driver_data; + u16 himask, charmask; + const unsigned char *orig_buf = NULL; + int orig_count; + + if (in_interrupt()) + return count; + + if (!vc) { + /* could this happen? */ + static int error = 0; + if (!error) { + error = 1; + printk("con_write: tty %d not allocated\n", minor(tty->device)); + } + return 0; + } + + orig_buf = buf; + orig_count = count; + + if (from_user) { + down(&con_buf_sem); + +again: + if (count > CON_BUF_SIZE) + count = CON_BUF_SIZE; + console_conditional_schedule(); + if (copy_from_user(con_buf, buf, count)) { + n = 0; /* ?? are error codes legal here ?? */ + goto out; } - case VC_SETMODE: - case VC_INQMODE: - { - struct vc_mode mode; - - if (!perm) - return -EPERM; - if (copy_from_user(&mode, (void *) arg, sizeof(mode))) - return -EFAULT; - return console_setmode(&mode, cmd == VC_SETMODE); + + buf = con_buf; + } + + /* At this point 'buf' is guarenteed to be a kernel buffer + * and therefore no access to userspace (and therefore sleeping) + * will be needed. The con_buf_sem serializes all tty based + * console rendering and vcs write/read operations. We hold + * the console spinlock during the entire write. + */ + + acquire_console_sem(); + + himask = hi_font_mask; + charmask = himask ? 0x1ff : 0xff; + + /* undraw cursor first */ + if (IS_VISIBLE) + hide_cursor(vc); + + while (!tty->stopped && count) { + c = *buf; + buf++; + n++; + count--; + + if (utf) { + /* Combine UTF-8 into Unicode */ + /* Incomplete characters silently ignored */ + if(c > 0x7f) { + if (utf_count > 0 && (c & 0xc0) == 0x80) { + utf_char = (utf_char << 6) | (c & 0x3f); + utf_count--; + if (utf_count == 0) + tc = c = utf_char; + else continue; + } else { + if ((c & 0xe0) == 0xc0) { + utf_count = 1; + utf_char = (c & 0x1f); + } else if ((c & 0xf0) == 0xe0) { + utf_count = 2; + utf_char = (c & 0x0f); + } else if ((c & 0xf8) == 0xf0) { + utf_count = 3; + utf_char = (c & 0x07); + } else if ((c & 0xfc) == 0xf8) { + utf_count = 4; + utf_char = (c & 0x03); + } else if ((c & 0xfe) == 0xfc) { + utf_count = 5; + utf_char = (c & 0x01); + } else + utf_count = 0; + continue; + } + } else { + tc = c; + utf_count = 0; + } + } else { /* no utf */ + tc = translate[toggle_meta ? (c|0x80) : c]; } - case VC_SETCMAP: - { - unsigned char cmap[3][256], *p; - int n_entries, cmap_size, i, j; - - if (!perm) - return -EPERM; - if (arg == (unsigned long) VC_POWERMODE_INQUIRY - || arg <= VESA_POWERDOWN) { - /* compatibility hack: VC_POWERMODE - was changed from 0x766a to 0x766c */ - return console_powermode((int) arg); + + /* If the original code was a control character we + * only allow a glyph to be displayed if the code is + * not normally used (such as for cursor movement) or + * if the disp_ctrl mode has been explicitly enabled. + * Certain characters (as given by the CTRL_ALWAYS + * bitmap) are always displayed as control characters, + * as the console would be pretty useless without + * them; to display an arbitrary font position use the + * direct-to-font zone in UTF-8 mode. + */ + ok = tc && (c >= 32 || + (!utf && !(((disp_ctrl ? CTRL_ALWAYS + : CTRL_ACTION) >> c) & 1))) + && (c != 127 || disp_ctrl) + && (c != 128+27); + + if (!vc_state && ok) { + /* Now try to find out how to display it */ + tc = conv_uni_to_pc(vc, tc); + if ( tc == -4 ) { + /* If we got -4 (not found) then see if we have + defined a replacement character (U+FFFD) */ + tc = conv_uni_to_pc(vc, 0xfffd); + + /* One reason for the -4 can be that we just + did a clear_unimap(); + try at least to show something. */ + if (tc == -4) + tc = c; + } else if ( tc == -3 ) { + /* Bad hash table -- hope for the best */ + tc = c; + } + if (tc & ~charmask) + continue; /* Conversion failed */ + + if (need_wrap || irm) + FLUSH + if (need_wrap) { + vte_cr(vc); + vte_lf(vc); } - if (get_user(cmap_size, (int *) arg)) - return -EFAULT; - if (cmap_size % 3) - return -EINVAL; - n_entries = cmap_size / 3; - if ((unsigned) n_entries > 256) - return -EINVAL; - p = (unsigned char *) (arg + sizeof(int)); - for (j = 0; j < n_entries; ++j) - for (i = 0; i < 3; ++i) - if (get_user(cmap[i][j], p++)) - return -EFAULT; - return console_setcmap(n_entries, cmap[0], - cmap[1], cmap[2]); + if (irm) + insert_char(vc, 1); + scr_writew(himask ? + ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : + (attr << 8) + tc, + (u16 *) pos); + if (DO_UPDATE && draw_x < 0) { + draw_x = x; + draw_from = pos; + } + if (x == video_num_columns - 1) { + need_wrap = decawm; + draw_to = pos+2; + } else { + x++; + draw_to = (pos+=2); + } + continue; } - case VC_GETCMAP: - /* not implemented yet */ - return -ENOIOCTLCMD; - case VC_POWERMODE: - if (!perm) - return -EPERM; - return console_powermode((int) arg); -#endif /* CONFIG_FB_COMPAT_XPMAC */ - default: - return -ENOIOCTLCMD; + FLUSH + terminal_emulation(tty, c); } + FLUSH + console_conditional_schedule(); + release_console_sem(); + +out: + if (from_user) { + /* If the user requested something larger than + * the CON_BUF_SIZE, and the tty is not stopped, + * keep going. + */ + if ((orig_count > CON_BUF_SIZE) && !tty->stopped) { + orig_count -= CON_BUF_SIZE; + orig_buf += CON_BUF_SIZE; + count = orig_count; + buf = orig_buf; + goto again; + } + + up(&con_buf_sem); + } + + return n; +#undef FLUSH } /* - * Sometimes we want to wait until a particular VT has been activated. We - * do it in a very simple manner. Everybody waits on a single queue and - * get woken up at once. Those that are satisfied go on with their business, - * while those not ready go back to sleep. Seems overkill to add a wait - * to each vt just for this - usually this does nothing! + * This is the console switching callback. + * + * Doing console switching in a process context allows + * us to do the switches asynchronously (needed when we want + * to switch due to a keyboard interrupt). Synchronization + * with other console code and prevention of re-entrancy is + * ensured with console_sem. */ -static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); +static void vt_callback(void *private) +{ + struct vt_struct *vt = (struct vt_struct *) private; + + if (!vt || !vt->want_vc || !vt->want_vc->vc_tty) + return; + + acquire_console_sem(); + + if (vt->want_vc->vc_num != fg_console) { + hide_cursor(vt->vc_cons[fg_console]); + change_console(vt->want_vc, vt->vc_cons[fg_console]); + /* we only changed when the console had already + been allocated - a new console is not created + in an interrupt routine */ + } + /* do not unblank for a LED change */ + if (do_poke_blanked_console) { + do_poke_blanked_console = 0; + poke_blanked_console(vt); + } + if (vt->scrollback_delta) { + int currcons = fg_console; + struct vc_data *vc = vt->vc_cons[currcons]; + + clear_selection(); + if (vcmode == KD_TEXT) + sw->con_scrolldelta(vc, vt->scrollback_delta); + vt->scrollback_delta = 0; + } + release_console_sem(); +} /* - * Sleeps until a vt is activated, or the task is interrupted. Returns - * 0 if activation, -EINTR if interrupted. + * Handling of Linux-specific VC ioctls */ -int vt_waitactive(int vt) + +int tioclinux(struct tty_struct *tty, unsigned long arg) { - int retval; - DECLARE_WAITQUEUE(wait, current); + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char type, data; + int ret; - add_wait_queue(&vt_activate_queue, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - retval = 0; - if (vt == fg_console) + if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) + return -EINVAL; + if (current->tty != tty && !capable(CAP_SYS_ADMIN)) + return -EPERM; + if (get_user(type, (char *)arg)) + return -EFAULT; + ret = 0; + switch (type) + { + case 2: + acquire_console_sem(); + ret = set_selection(arg, tty, 1); + release_console_sem(); + break; + case 3: + ret = paste_selection(tty); + break; + case 4: + unblank_screen(); + break; + case 5: + ret = sel_loadlut(arg); + break; + case 6: + + /* + * Make it possible to react to Shift+Mousebutton. + * Note that 'shift_state' is an undocumented + * kernel-internal variable; programs not closely + * related to the kernel should not use this. + */ + data = shift_state; + ret = __put_user(data, (char *) arg); break; - retval = -EINTR; - if (signal_pending(current)) + case 7: + data = mouse_reporting(vc); + ret = __put_user(data, (char *) arg); break; - schedule(); + case 10: + if (get_user(data, (char *)arg+1)) + return -EFAULT; + vc->display_fg->blank_mode = (data < 4) ? data : 0; + break; + case 11: /* set kmsg redirect */ + if (!capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + } else { + if (get_user(data, (char *)arg+1)) + ret = -EFAULT; + else + kmsg_redirect = data; + } + break; + case 12: /* get fg_console */ + ret = fg_console; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +/* + * /dev/ttyN handling + */ + +/* Allocate the console screen memory. */ +static int con_open(struct tty_struct *tty, struct file * filp) +{ + struct vc_data *vc; + unsigned int currcons; + int i; + + currcons = minor(tty->device) - tty->driver.minor_start; + + i = vc_allocate(currcons); + if (i) + return i; + + vc = vt_cons->vc_cons[currcons]; + tty->driver_data = vc; + vc->vc_tty = tty; + + if (!tty->winsize.ws_row && !tty->winsize.ws_col) { + tty->winsize.ws_row = video_num_lines; + tty->winsize.ws_col = video_num_columns; } - remove_wait_queue(&vt_activate_queue, &wait); - current->state = TASK_RUNNING; + if (tty->count == 1) + vcs_make_devfs(currcons, 0); + return 0; +} + +static void con_close(struct tty_struct *tty, struct file * filp) +{ + if (!tty || tty->count != 1) + return; + + vcs_make_devfs (minor(tty->device) - tty->driver.minor_start, 1); + tty->driver_data = 0; +} + +static int con_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int retval; + + pm_access(pm_con); + retval = do_con_write(tty, from_user, buf, count); + con_flush_chars(tty); + return retval; } -#define vt_wake_waitactive() wake_up(&vt_activate_queue) +static void con_put_char(struct tty_struct *tty, unsigned char ch) +{ + if (in_interrupt()) + return; /* n_r3964 calls put_char() from interrupt context */ + pm_access(pm_con); + do_con_write(tty, 0, &ch, 1); +} + +static int con_write_room(struct tty_struct *tty) +{ + if (tty->stopped) + return 0; + return 4096; /* No limit, really; we're not buffering */ +} + +static void con_flush_chars(struct tty_struct *tty) +{ + struct vc_data *vc; + + if (in_interrupt()) /* from flush_to_ldisc */ + return; + + pm_access(pm_con); + lock_kernel(); + acquire_console_sem(); + vc = (struct vc_data *)tty->driver_data; + if (vc) + set_cursor(vc); + release_console_sem(); + unlock_kernel(); +} -void reset_vc(unsigned int new_console) +static int con_chars_in_buffer(struct tty_struct *tty) { - vt_cons[new_console]->vc_mode = KD_TEXT; - kbd_table[new_console].kbdmode = VC_XLATE; - vt_cons[new_console]->vt_mode.mode = VT_AUTO; - vt_cons[new_console]->vt_mode.waitv = 0; - vt_cons[new_console]->vt_mode.relsig = 0; - vt_cons[new_console]->vt_mode.acqsig = 0; - vt_cons[new_console]->vt_mode.frsig = 0; - vt_cons[new_console]->vt_pid = -1; - vt_cons[new_console]->vt_newvt = -1; - if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ - reset_palette(new_console) ; + return 0; /* we're not buffering */ } /* - * Performs the back end of a vt switch + * Turn the Scroll-Lock LED on when the tty is stopped */ -void complete_change_console(unsigned int new_console) +static void con_stop(struct tty_struct *tty) { - unsigned char old_vc_mode; + struct vc_data *vc = (struct vc_data *) tty->driver_data; - last_console = fg_console; + if (!tty || !vc) + return; + set_kbd_led(&vc->kbd_table, VC_SCROLLOCK); + set_leds(); +} - /* - * If we're switching, we could be going from KD_GRAPHICS to - * KD_TEXT mode or vice versa, which means we need to blank or - * unblank the screen later. - */ - old_vc_mode = vt_cons[fg_console]->vc_mode; - switch_screen(new_console); +/* + * Turn the Scroll-Lock LED off when the console is started + */ +static void con_start(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + + if (!tty || !vc) + return; + clr_kbd_led(&vc->kbd_table, VC_SCROLLOCK); + set_leds(); +} - /* - * This can't appear below a successful kill_proc(). If it did, - * then the *blank_screen operation could occur while X, having - * received acqsig, is waking up on another processor. This - * condition can lead to overlapping accesses to the VGA range - * and the framebuffer (causing system lockups). - * - * To account for this we duplicate this code below only if the - * controlling process is gone and we've called reset_vc. - */ - if (old_vc_mode != vt_cons[new_console]->vc_mode) - { - if (vt_cons[new_console]->vc_mode == KD_TEXT) - unblank_screen(); - else - do_blank_screen(1); - } +/* + * con_throttle and con_unthrottle are only used for + * paste_selection(), which has to stuff in a large number of + * characters... + */ +static void con_throttle(struct tty_struct *tty) +{ +} - /* - * If this new console is under process control, send it a signal - * telling it that it has acquired. Also check if it has died and - * clean up (similar to logic employed in change_console()) - */ - if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS) - { - /* - * Send the signal as privileged - kill_proc() will - * tell us if the process has gone or something else - * is awry - */ - if (kill_proc(vt_cons[new_console]->vt_pid, - vt_cons[new_console]->vt_mode.acqsig, - 1) != 0) - { - /* - * The controlling process has died, so we revert back to - * normal operation. In this case, we'll also change back - * to KD_TEXT mode. I'm not sure if this is strictly correct - * but it saves the agony when the X server dies and the screen - * remains blanked due to KD_GRAPHICS! It would be nice to do - * this outside of VT_PROCESS but there is no single process - * to account for and tracking tty count may be undesirable. - */ - reset_vc(new_console); +static void con_unthrottle(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; - if (old_vc_mode != vt_cons[new_console]->vc_mode) - { - if (vt_cons[new_console]->vc_mode == KD_TEXT) - unblank_screen(); - else - do_blank_screen(1); + wake_up_interruptible(&vc->paste_wait); +} + +#ifdef CONFIG_VT_CONSOLE + +/* + * Console on virtual terminal + * + * The console_lock must be held when we get here. + */ + +void vt_console_print(struct console *co, const char * b, unsigned count) +{ + int currcons = fg_console; + unsigned char c; + static unsigned long printing = 0; + struct vc_data *vc; + const ushort *start; + ushort cnt = 0; + ushort myx; + + /* console busy or not yet initialized */ + if (!printable || test_and_set_bit(0, &printing)) + return; + + pm_access(pm_con); + + if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) + currcons = kmsg_redirect - 1; + + vc = vt_cons->vc_cons[currcons]; + + /* read `x' only after setting currecons properly (otherwise + the `x' macro will read the x of the foreground console). */ + myx = x; + + if (!vc) { + /* impossible */ + /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ + goto quit; + } + + if (vcmode != KD_TEXT) + goto quit; + + /* undraw cursor first */ + if (IS_VISIBLE) + hide_cursor(vc); + + start = (ushort *)pos; + + /* Contrived structure to try to emulate original need_wrap behaviour + * Problems caused when we have need_wrap set on '\n' character */ + while (count--) { + c = *b++; + if (c == 10 || c == 13 || c == 8 || need_wrap) { + if (cnt > 0) { + if (IS_VISIBLE) + sw->con_putcs(vc, start, cnt, y, x); + x += cnt; + if (need_wrap) + x--; + cnt = 0; + } + if (c == 8) { /* backspace */ + vte_bs(vc); + start = (ushort *)pos; + myx = x; + continue; } + if (c != 13) + vte_lf(vc); + vte_cr(vc); + start = (ushort *)pos; + myx = x; + if (c == 10 || c == 13) + continue; + } + scr_writew((attr << 8) + c, (unsigned short *) pos); + cnt++; + if (myx == video_num_columns - 1) { + need_wrap = 1; + continue; + } + pos+=2; + myx++; + } + if (cnt > 0) { + if (IS_VISIBLE) + sw->con_putcs(vc, start, cnt, y, x); + x += cnt; + if (x == video_num_columns) { + x--; + need_wrap = 1; } } + set_cursor(vc); + + if (!oops_in_progress) + poke_blanked_console(vc->display_fg); + +quit: + clear_bit(0, &printing); +} + +static kdev_t vt_console_device(struct console *c) +{ + return mk_kdev(TTY_MAJOR, c->index ? c->index : fg_console + 1); +} + +struct console vt_console_driver = { + name: "tty", + write: vt_console_print, + device: vt_console_device, + unblank: unblank_screen, + flags: CON_PRINTBUFFER, + index: -1, +}; +#endif + +/* + * Mapping and unmapping displays to a VT + */ +const char *vt_map_display(struct vt_struct *vt, int init) +{ + const char *display_desc = NULL; + struct vc_data *vc; + unsigned int currcons = 0; + + if (conswitchp) + display_desc = conswitchp->con_startup(); + + if (!display_desc) { + fg_console = 0; + return NULL; + } + + vt->vt_blanked = 0; + vt->blank_interval = 10*60*HZ; + vt->off_interval = 0; + init_timer(&vt->timer); + vt->timer.data = (long) vt; + vt->timer.function = blank_screen; + mod_timer(&vt->timer, jiffies + vt->blank_interval); + INIT_TQUEUE(&vt->vt_tq, vt_callback, vt); /* - * Wake anyone waiting for their VT to activate + * kmalloc is not running yet - we use the bootmem allocator. */ - vt_wake_waitactive(); - return; + for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { + vc = (struct vc_data *) + alloc_bootmem(sizeof(struct vc_data)); + cons_num = currcons; + vc->display_fg = vt_cons; + visual_init(vc, 1); + screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size); + kmalloced = 0; + vc_init(vc, currcons || !sw->con_save_screen); + } +#ifdef CONFIG_VT_CONSOLE + register_console(&vt_console_driver); +#endif + fg_console = 0; + vc = vt->want_vc = vt->last_console = vt->vc_cons[fg_console]; + set_origin(vc); + save_screen(vc); + gotoxy(vc, x, y); + vte_ed(vc, 0); + update_screen(vc); + return display_desc; } /* - * Performs the front-end of a vt switch + * This routine initializes console interrupts, and does nothing + * else. If you want the screen to clear, call tty_write with + * the appropriate escape-sequence. */ -void change_console(unsigned int new_console) + +struct tty_driver console_driver; +static int console_refcount; + +void __init vt_console_init(void) { - if ((new_console == fg_console) || (vt_dont_switch)) - return; - if (!vc_cons_allocated(new_console)) + const char *display_desc = NULL; + struct vc_data *vc; + + vt_cons = (struct vt_struct *) alloc_bootmem(sizeof(struct vt_struct)); + + display_desc = vt_map_display(vt_cons, 0); + + if (!display_desc) { + fg_console = 0; return; + } + vc = vt_cons->vc_cons[fg_console]; - /* - * If this vt is in process mode, then we need to handshake with - * that process before switching. Essentially, we store where that - * vt wants to switch to and wait for it to tell us when it's done - * (via VT_RELDISP ioctl). - * - * We also check to see if the controlling process still exists. - * If it doesn't, we reset this vt to auto mode and continue. - * This is a cheap way to track process control. The worst thing - * that can happen is: we send a signal to a process, it dies, and - * the switch gets "lost" waiting for a response; hopefully, the - * user will try again, we'll detect the process is gone (unless - * the user waits just the right amount of time :-) and revert the - * vt to auto control. - */ - if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS) - { - /* - * Send the signal as privileged - kill_proc() will - * tell us if the process has gone or something else - * is awry - */ - if (kill_proc(vt_cons[fg_console]->vt_pid, - vt_cons[fg_console]->vt_mode.relsig, - 1) == 0) - { - /* - * It worked. Mark the vt to switch to and - * return. The process needs to send us a - * VT_RELDISP ioctl to complete the switch. - */ - vt_cons[fg_console]->vt_newvt = new_console; - return; - } + printk("Console: %s %s %dx%d", + can_do_color ? "colour" : "mono", + display_desc, video_num_columns, video_num_lines); + printable = 1; + printk("\n"); +} - /* - * The controlling process has died, so we revert back to - * normal operation. In this case, we'll also change back - * to KD_TEXT mode. I'm not sure if this is strictly correct - * but it saves the agony when the X server dies and the screen - * remains blanked due to KD_GRAPHICS! It would be nice to do - * this outside of VT_PROCESS but there is no single process - * to account for and tracking tty count may be undesirable. - */ - reset_vc(fg_console); +int __init vty_init(void) +{ + memset(&console_driver, 0, sizeof(struct tty_driver)); + console_driver.magic = TTY_DRIVER_MAGIC; + console_driver.name = "vc/%d"; + console_driver.name_base = 1; + console_driver.major = TTY_MAJOR; + console_driver.minor_start = 1; + console_driver.num = MAX_NR_CONSOLES; + console_driver.type = TTY_DRIVER_TYPE_CONSOLE; + console_driver.init_termios = tty_std_termios; + console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; + console_driver.refcount = &console_refcount; + console_driver.table = console_table; + console_driver.termios = console_termios; + console_driver.termios_locked = console_termios_locked; +#ifdef CONFIG_VT_CONSOLE + console_driver.console = &vt_console_driver; +#endif + console_driver.open = con_open; + console_driver.close = con_close; + console_driver.write = con_write; + console_driver.write_room = con_write_room; + console_driver.put_char = con_put_char; + console_driver.flush_chars = con_flush_chars; + console_driver.chars_in_buffer = con_chars_in_buffer; + console_driver.ioctl = vt_ioctl; + console_driver.stop = con_stop; + console_driver.start = con_start; + console_driver.throttle = con_throttle; + console_driver.unthrottle = con_unthrottle; + + if (tty_register_driver(&console_driver)) + panic("Couldn't register console driver\n"); + + kbd_init(); + console_map_init(); + vcs_init(); + return 0; +} + +#ifndef VT_SINGLE_DRIVER - /* - * Fall through to normal (VT_AUTO) handling of the switch... +static void clear_buffer_attributes(struct vc_data *vc) +{ + unsigned short *p = (unsigned short *) origin; + int count = screenbuf_size/2; + int mask = hi_font_mask | 0xff; + + for (; count > 0; count--, p++) { + scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); + } +} + +/* + * If we support more console drivers, this function is used + * when a driver wants to take over some existing consoles + * and become default driver for newly opened ones. + */ + +void take_over_console(const struct consw *csw, int first, int last, int deflt) +{ + struct vc_data *vc; + const char *desc; + int i, j = -1; + + desc = csw->con_startup(); + if (!desc) return; + if (deflt) + conswitchp = csw; + + for (i = first; i <= last; i++) { + int old_was_color; + + vc = vt_cons->vc_cons[i]; + con_driver_map[i] = csw; + + if (!vc || !sw) + continue; + + j = i; + if (IS_VISIBLE) + save_screen(vc); + old_was_color = can_do_color; + vc->display_fg->vt_sw->con_deinit(vc); + visual_init(vc, 0); + update_attr(vc); + + /* If the console changed between mono <-> color, then + * the attributes in the screenbuf will be wrong. The + * following resets all attributes to something sane. */ + if (old_was_color != can_do_color) + clear_buffer_attributes(vc); + + if (IS_VISIBLE) + update_screen(vc); } + printk("Console: switching "); + if (!deflt) + printk("consoles %d-%d ", first+1, last+1); + if (j >= 0) { + vc = vt_cons->vc_cons[j]; + printk("to %s %s %dx%d\n", can_do_color ? "colour" : "mono", + desc, video_num_columns, video_num_lines); + } else + printk("to %s\n", desc); +} - /* - * Ignore all switches in KD_GRAPHICS+VT_AUTO mode - */ - if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) - return; +void give_up_console(const struct consw *csw) +{ + int i; - complete_change_console(new_console); + for(i = 0; i < MAX_NR_CONSOLES; i++) + if (con_driver_map[i] == csw) + con_driver_map[i] = NULL; } +#endif + +/* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(color_table); +EXPORT_SYMBOL(default_red); +EXPORT_SYMBOL(default_grn); +EXPORT_SYMBOL(default_blu); +EXPORT_SYMBOL(video_font_height); +EXPORT_SYMBOL(video_scan_lines); +EXPORT_SYMBOL(vc_resize); +EXPORT_SYMBOL(fg_console); +EXPORT_SYMBOL(console_blank_hook); +#ifdef CONFIG_VT +EXPORT_SYMBOL(vt_cons); +#endif +#ifndef VT_SINGLE_DRIVER +EXPORT_SYMBOL(take_over_console); +EXPORT_SYMBOL(give_up_console); +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/vt_ioctl.c linux-2.5/drivers/char/vt_ioctl.c --- linux-2.5.20/drivers/char/vt_ioctl.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/vt_ioctl.c Sun Mar 3 23:50:42 2002 @@ -0,0 +1,1439 @@ +/* + * linux/drivers/char/vt_ioctl.c + * + * Copyright (C) 1992 obz under the linux copyright + * Copyright (C) 2001 James Simmons + * + * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 + * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 + * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 + * Some code moved for less code duplication - Andi Kleen - Mar 1997 + * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_FB_COMPAT_XPMAC +#include +#endif /* CONFIG_FB_COMPAT_XPMAC */ + +char vt_dont_switch; +extern struct tty_driver console_driver; + +#define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count) +#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons) + +/* + * Console (vt and kd) routines, as defined by USL SVR4 manual, and by + * experimentation and study of X386 SYSV handling. + * + * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and + * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, + * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will + * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to + * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using + * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing + * to the current console is done by the main ioctl code. + */ + +struct vt_struct *vt_cons; + +/* Keyboard type: Default is KB_101, but can be set by machine + * specific code. + */ +unsigned char keyboard_type = KB_101; + +#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) +asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); +#endif + +unsigned int video_font_height; +unsigned int default_font_height; +unsigned int video_scan_lines; + +/* + * these are the valid i/o ports we're allowed to change. they map all the + * video ports + */ +#define GPFIRST 0x3b4 +#define GPLAST 0x3df +#define GPNUM (GPLAST - GPFIRST + 1) + +/* + * Generates sound of some frequency for some number of clock ticks + * + * If freq is 0, will turn off sound, else will turn it on for that time. + * If msec is 0, will return immediately, else will sleep for msec time, then + * turn sound off. + * + * We also return immediately, which is what was implied within the X + * comments - KDMKTONE doesn't put the process to sleep. + */ + +#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ + || (defined(__mips__) && defined(CONFIG_ISA)) \ + || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \ + || defined(__x86_64__) + +static void +kd_nosound(unsigned long ignored) +{ + /* disable counter 2 */ + outb(inb_p(0x61)&0xFC, 0x61); + return; +} + +void +_kd_mksound(unsigned int hz, unsigned int ticks) +{ + static struct timer_list sound_timer = { function: kd_nosound }; + unsigned int count = 0; + unsigned long flags; + + if (hz > 20 && hz < 32767) + count = 1193180 / hz; + + save_flags(flags); + cli(); + del_timer(&sound_timer); + if (count) { + /* enable counter 2 */ + outb_p(inb_p(0x61)|3, 0x61); + /* set command for counter 2, 2 byte write */ + outb_p(0xB6, 0x43); + /* select desired HZ */ + outb_p(count & 0xff, 0x42); + outb((count >> 8) & 0xff, 0x42); + + if (ticks) { + sound_timer.expires = jiffies+ticks; + add_timer(&sound_timer); + } + } else + kd_nosound(0); + restore_flags(flags); + return; +} + +#else + +void +_kd_mksound(unsigned int hz, unsigned int ticks) +{ +} + +#endif + +int _kbd_rate(struct kbd_repeat *rep) +{ + return -EINVAL; +} + +void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound; +int (*kbd_rate)(struct kbd_repeat *rep) = _kbd_rate; + +#define i (tmp.kb_index) +#define s (tmp.kb_table) +#define v (tmp.kb_value) +static inline int +do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kbd) +{ + struct kbentry tmp; + ushort *key_map, val, ov; + + if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) + return -EFAULT; + if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS) + return -EINVAL; + + switch (cmd) { + case KDGKBENT: + key_map = key_maps[s]; + if (key_map) { + val = U(key_map[i]); + if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) + val = K_HOLE; + } else + val = (i ? K_HOLE : K_NOSUCHMAP); + return put_user(val, &user_kbe->kb_value); + case KDSKBENT: + if (!perm) + return -EPERM; + if (!i && v == K_NOSUCHMAP) { + /* disallocate map */ + key_map = key_maps[s]; + if (s && key_map) { + key_maps[s] = 0; + if (key_map[0] == U(K_ALLOCATED)) { + kfree(key_map); + keymap_count--; + } + } + break; + } + + if (KTYP(v) < NR_TYPES) { + if (KVAL(v) > max_vals[KTYP(v)]) + return -EINVAL; + } else + if (kbd->kbdmode != VC_UNICODE) + return -EINVAL; + + /* ++Geert: non-PC keyboards may generate keycode zero */ +#if !defined(__mc68000__) && !defined(__powerpc__) + /* assignment to entry 0 only tests validity of args */ + if (!i) + break; +#endif + + if (!(key_map = key_maps[s])) { + int j; + + if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && + !capable(CAP_SYS_RESOURCE)) + return -EPERM; + + key_map = (ushort *) kmalloc(sizeof(plain_map), + GFP_KERNEL); + if (!key_map) + return -ENOMEM; + key_maps[s] = key_map; + key_map[0] = U(K_ALLOCATED); + for (j = 1; j < NR_KEYS; j++) + key_map[j] = U(K_HOLE); + keymap_count++; + } + ov = U(key_map[i]); + if (v == ov) + break; /* nothing to do */ + /* + * Attention Key. + */ + if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) + return -EPERM; + key_map[i] = U(v); + if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) + compute_shiftstate(); + break; + } + return 0; +} +#undef i +#undef s +#undef v + +static inline int +do_kbkeycode_ioctl(int cmd, struct kbkeycode *user_kbkc, int perm) +{ + struct kbkeycode tmp; + int kc = 0; + + if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) + return -EFAULT; + switch (cmd) { + case KDGETKEYCODE: + kc = getkeycode(tmp.scancode); + if (kc >= 0) + kc = put_user(kc, &user_kbkc->keycode); + break; + case KDSETKEYCODE: + if (!perm) + return -EPERM; + kc = setkeycode(tmp.scancode, tmp.keycode); + break; + } + return kc; +} + +static inline int +do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm) +{ + struct kbsentry tmp; + char *p; + u_char *q; + int sz; + int delta; + char *first_free, *fj, *fnw; + int i, j, k; + + /* we mostly copy too much here (512bytes), but who cares ;) */ + if (copy_from_user(&tmp, user_kdgkb, sizeof(struct kbsentry))) + return -EFAULT; + tmp.kb_string[sizeof(tmp.kb_string)-1] = '\0'; + if (tmp.kb_func >= MAX_NR_FUNC) + return -EINVAL; + i = tmp.kb_func; + + switch (cmd) { + case KDGKBSENT: + sz = sizeof(tmp.kb_string) - 1; /* sz should have been + a struct member */ + q = user_kdgkb->kb_string; + p = func_table[i]; + if(p) + for ( ; *p && sz; p++, sz--) + if (put_user(*p, q++)) + return -EFAULT; + if (put_user('\0', q)) + return -EFAULT; + return ((p && *p) ? -EOVERFLOW : 0); + case KDSKBSENT: + if (!perm) + return -EPERM; + + q = func_table[i]; + first_free = funcbufptr + (funcbufsize - funcbufleft); + for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) + ; + if (j < MAX_NR_FUNC) + fj = func_table[j]; + else + fj = first_free; + + delta = (q ? -strlen(q) : 1) + strlen(tmp.kb_string); + if (delta <= funcbufleft) { /* it fits in current buf */ + if (j < MAX_NR_FUNC) { + memmove(fj + delta, fj, first_free - fj); + for (k = j; k < MAX_NR_FUNC; k++) + if (func_table[k]) + func_table[k] += delta; + } + if (!q) + func_table[i] = fj; + funcbufleft -= delta; + } else { /* allocate a larger buffer */ + sz = 256; + while (sz < funcbufsize - funcbufleft + delta) + sz <<= 1; + fnw = (char *) kmalloc(sz, GFP_KERNEL); + if(!fnw) + return -ENOMEM; + + if (!q) + func_table[i] = fj; + if (fj > funcbufptr) + memmove(fnw, funcbufptr, fj - funcbufptr); + for (k = 0; k < j; k++) + if (func_table[k]) + func_table[k] = fnw + (func_table[k] - funcbufptr); + + if (first_free > fj) { + memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); + for (k = j; k < MAX_NR_FUNC; k++) + if (func_table[k]) + func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; + } + if (funcbufptr != func_buf) + kfree(funcbufptr); + funcbufptr = fnw; + funcbufleft = funcbufleft - delta + sz - funcbufsize; + funcbufsize = sz; + } + strcpy(func_table[i], tmp.kb_string); + break; + } + return 0; +} + +/* + * Font switching + * + * Currently we only support fonts up to 32 pixels wide, at a maximum height + * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, + * depending on width) reserved for each character which is kinda wasty, but + * this is done in order to maintain compatibility with the EGA/VGA fonts. It + * is upto the actual low-level console-driver convert data into its favorite + * format (maybe we should add a `fontoffset' field to the `display' + * structure so we wont have to convert the fontdata all the time. + * /Jes + */ + +#define max_font_size 65536 + +int con_font_op(struct vc_data *vc, struct console_font_op *op) +{ + int rc = -EINVAL, size = max_font_size, set; + struct console_font_op old_op; + u8 *temp = NULL; + + if (vc->vc_mode != KD_TEXT) + goto quit; + memcpy(&old_op, op, sizeof(old_op)); + if (op->op == KD_FONT_OP_SET) { + if (!op->data) + return -EINVAL; + if (op->charcount > 512) + goto quit; + /* Need to guess font height [compact] */ + if (!op->height) { + u8 *charmap = op->data, tmp; + int h, i; + + /* + * If from KDFONTOP ioctl, don't allow things + * which can in userland, so that we can get + * rid of this soon + */ + if (!(op->flags & KD_FONT_FLAG_OLD)) + goto quit; + rc = -EFAULT; + for (h = 32; h > 0; h--) + for (i = 0; i < op->charcount; i++) { + if (get_user(tmp, &charmap[32*i+h-1])) + goto quit; + if (tmp) + goto nonzero; + } + rc = -EINVAL; + goto quit; + nonzero: + rc = -EINVAL; + op->height = h; + } + if (op->width > 32 || op->height > 32) + goto quit; + size = (op->width+7)/8 * 32 * op->charcount; + if (size > max_font_size) + return -ENOSPC; + set = 1; + } else if (op->op == KD_FONT_OP_GET) + set = 0; + else + return vc->display_fg->vt_sw->con_font_op(vc, op); + if (op->data) { + temp = kmalloc(size, GFP_KERNEL); + if (!temp) + return -ENOMEM; + if (set && copy_from_user(temp, op->data, size)) { + + rc = -EFAULT; + goto quit; + } + op->data = temp; + } + + acquire_console_sem(); + rc = vc->display_fg->vt_sw->con_font_op(vc, op); + release_console_sem(); + + op->data = old_op.data; + if (!rc && !set) { + int c = (op->width+7)/8 * 32 * op->charcount; + + if (op->data && op->charcount > old_op.charcount) + rc = -ENOSPC; + if (!(op->flags & KD_FONT_FLAG_OLD)) { + if (op->width > old_op.width || + op->height > old_op.height) + rc = -ENOSPC; + } else { + if (op->width != 8) + rc = -EIO; + else if ((old_op.height && op->height > old_op.height) || op->height > 32) + rc = -ENOSPC; + } + if (!rc && op->data && copy_to_user(op->data, temp, c)) + rc = -EFAULT; + } +quit: if (temp) + kfree(temp); + return rc; +} + +static inline int +do_fontx_ioctl(int cmd, struct consolefontdesc *user_cfd, int perm) +{ + struct vc_data *vc = vt_cons->vc_cons[fg_console]; + struct consolefontdesc cfdarg; + struct console_font_op op; + int i; + + if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) + return -EFAULT; + + switch (cmd) { + case PIO_FONTX: + if (!perm) + return -EPERM; + op.op = KD_FONT_OP_SET; + op.flags = KD_FONT_FLAG_OLD; + op.width = 8; + op.height = cfdarg.charheight; + op.charcount = cfdarg.charcount; + op.data = cfdarg.chardata; + return con_font_op(vc, &op); + case GIO_FONTX: { + op.op = KD_FONT_OP_GET; + op.flags = KD_FONT_FLAG_OLD; + op.width = 8; + op.height = cfdarg.charheight; + op.charcount = cfdarg.charcount; + op.data = cfdarg.chardata; + i = con_font_op(vc, &op); + if (i) + return i; + cfdarg.charheight = op.height; + cfdarg.charcount = op.charcount; + if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) + return -EFAULT; + return 0; + } + } + return -EINVAL; +} + +static inline int +do_unimap_ioctl(struct vc_data *vc, int cmd, struct unimapdesc *user_ud,int perm) +{ + struct unimapdesc tmp; + int i = 0; + + if (copy_from_user(&tmp, user_ud, sizeof tmp)) + return -EFAULT; + if (tmp.entries) { + i = verify_area(VERIFY_WRITE, tmp.entries, + tmp.entry_ct*sizeof(struct unipair)); + if (i) return i; + } + switch (cmd) { + case PIO_UNIMAP: + if (!perm) + return -EPERM; + return con_set_unimap(vc, tmp.entry_ct, tmp.entries); + case GIO_UNIMAP: + return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); + } + return 0; +} + +/* + * We handle the console-specific ioctl's here. We allow the + * capability to modify any console, not just the fg_console. + */ +int vt_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int i, perm; + unsigned int console; + unsigned char ucval; + struct vc_data *vc = (struct vc_data *) tty->driver_data; + struct kbd_struct *kbd; + + console = vc->vc_num; + + if (!vc) /* impossible? */ + return -ENOIOCTLCMD; + + /* + * To have permissions to do most of the vt ioctls, we either have + * to be the owner of the tty, or super-user. + */ + perm = 0; + if (current->tty == tty || suser()) + perm = 1; + + kbd = &vc->kbd_table; + switch (cmd) { + case KIOCSOUND: + if (!perm) + return -EPERM; + if (arg) + arg = 1193180 / arg; + kd_mksound(arg, 0); + return 0; + + case KDMKTONE: + if (!perm) + return -EPERM; + { + unsigned int ticks, count; + + /* + * Generate the tone for the appropriate number of ticks. + * If the time is zero, turn off sound ourselves. + */ + ticks = HZ * ((arg >> 16) & 0xffff) / 1000; + count = ticks ? (arg & 0xffff) : 0; + if (count) + count = 1193180 / count; + kd_mksound(count, ticks); + return 0; + } + + case KDGKBTYPE: + /* + * this is naive. + */ + ucval = keyboard_type; + goto setchar; + +#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) + /* + * These cannot be implemented on any machine that implements + * ioperm() in user level (such as Alpha PCs). + */ + case KDADDIO: + case KDDELIO: + /* + * KDADDIO and KDDELIO may be able to add ports beyond what + * we reject here, but to be safe... + */ + if (arg < GPFIRST || arg > GPLAST) + return -EINVAL; + return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; + + case KDENABIO: + case KDDISABIO: + return sys_ioperm(GPFIRST, GPNUM, + (cmd == KDENABIO)) ? -ENXIO : 0; +#endif + + /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ + + case KDKBDREP: + { + struct kbd_repeat kbrep; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&kbrep, (void *)arg, + sizeof(struct kbd_repeat))) + return -EFAULT; + if ((i = kbd_rate( &kbrep ))) + return i; + if (copy_to_user((void *)arg, &kbrep, + sizeof(struct kbd_repeat))) + return -EFAULT; + return 0; + } + + case KDSETMODE: + /* + * currently, setting the mode from KD_TEXT to KD_GRAPHICS + * doesn't do a whole lot. i'm not sure if it should do any + * restoration of modes or what... + */ + if (!perm) + return -EPERM; + switch (arg) { + case KD_GRAPHICS: + break; + case KD_TEXT0: + case KD_TEXT1: + arg = KD_TEXT; + case KD_TEXT: + break; + default: + return -EINVAL; + } + if (vc->vc_mode == (unsigned char) arg) + return 0; + vc->vc_mode = (unsigned char) arg; + if (console != fg_console) + return 0; + /* + * explicitly blank/unblank the screen if switching modes + */ + if (arg == KD_TEXT) + unblank_screen(); + else + do_blank_screen(vc->display_fg, 1); + return 0; + + case KDGETMODE: + ucval = vc->vc_mode; + goto setint; + + case KDMAPDISP: + case KDUNMAPDISP: + /* + * these work like a combination of mmap and KDENABIO. + * this could be easily finished. + */ + return -EINVAL; + + case KDSKBMODE: + if (!perm) + return -EPERM; + switch(arg) { + case K_RAW: + kbd->kbdmode = VC_RAW; + break; + case K_MEDIUMRAW: + kbd->kbdmode = VC_MEDIUMRAW; + break; + case K_XLATE: + kbd->kbdmode = VC_XLATE; + compute_shiftstate(); + break; + case K_UNICODE: + kbd->kbdmode = VC_UNICODE; + compute_shiftstate(); + break; + default: + return -EINVAL; + } + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + return 0; + + case KDGKBMODE: + ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : + (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : + (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : + K_XLATE); + goto setint; + + /* this could be folded into KDSKBMODE, but for compatibility + reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ + case KDSKBMETA: + switch(arg) { + case K_METABIT: + clr_kbd_mode(kbd, VC_META); + break; + case K_ESCPREFIX: + set_kbd_mode(kbd, VC_META); + break; + default: + return -EINVAL; + } + return 0; + + case KDGKBMETA: + ucval = (get_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); + setint: + return put_user(ucval, (int *)arg); + + case KDGETKEYCODE: + case KDSETKEYCODE: + if(!capable(CAP_SYS_ADMIN)) + perm=0; + return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); + + case KDGKBENT: + case KDSKBENT: + return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd); + + case KDGKBSENT: + case KDSKBSENT: + return do_kdgkb_ioctl(cmd, (struct kbsentry *)arg, perm); + + case KDGKBDIACR: + { + struct kbdiacrs *a = (struct kbdiacrs *)arg; + + if (put_user(accent_table_size, &a->kb_cnt)) + return -EFAULT; + if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr))) + return -EFAULT; + return 0; + } + + case KDSKBDIACR: + { + struct kbdiacrs *a = (struct kbdiacrs *)arg; + unsigned int ct; + + if (!perm) + return -EPERM; + if (get_user(ct,&a->kb_cnt)) + return -EFAULT; + if (ct >= MAX_DIACR) + return -EINVAL; + accent_table_size = ct; + if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr))) + return -EFAULT; + return 0; + } + + /* the ioctls below read/set the flags usually shown in the leds */ + /* don't use them - they will go away without warning */ + case KDGKBLED: + ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); + goto setchar; + + case KDSKBLED: + if (!perm) + return -EPERM; + if (arg & ~0x77) + return -EINVAL; + kbd->ledflagstate = (arg & 7); + kbd->default_ledflagstate = ((arg >> 4) & 7); + set_leds(); + return 0; + + /* the ioctls below only set the lights, not the functions */ + /* for those, see KDGKBLED and KDSKBLED above */ + case KDGETLED: + ucval = getledstate(); + setchar: + return put_user(ucval, (char*)arg); + + case KDSETLED: + if (!perm) + return -EPERM; + setledstate(kbd, arg); + return 0; + + /* + * A process can indicate its willingness to accept signals + * generated by pressing an appropriate key combination. + * Thus, one can have a daemon that e.g. spawns a new console + * upon a keypress and then changes to it. + * Probably init should be changed to do this (and have a + * field ks (`keyboard signal') in inittab describing the + * desired action), so that the number of background daemons + * does not increase. + */ + case KDSIGACCEPT: + { + extern int spawnpid, spawnsig; + if (!perm || !capable(CAP_KILL)) + return -EPERM; + if (arg < 1 || arg > _NSIG || arg == SIGKILL) + return -EINVAL; + spawnpid = current->pid; + spawnsig = arg; + return 0; + } + + case VT_SETMODE: + { + struct vt_mode tmp; + + if (!perm) + return -EPERM; + if (copy_from_user(&tmp, (void*)arg, sizeof(struct vt_mode))) + return -EFAULT; + if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) + return -EINVAL; + vc->vt_mode = tmp; + /* the frsig is ignored, so we set it to 0 */ + vc->vt_mode.frsig = 0; + vc->vt_pid = current->pid; + /* no switch is required -- saw@shade.msu.ru */ + vc->vt_newvt = -1; + return 0; + } + + case VT_GETMODE: + return copy_to_user((void*)arg, &(vc->vt_mode), + sizeof(struct vt_mode)) ? -EFAULT : 0; + + /* + * Returns global vt state. Note that VT 0 is always open, since + * it's an alias for the current VT, and people can't use it here. + * We cannot return state for more than 16 VTs, since v_state is short. + */ + case VT_GETSTATE: + { + struct vt_stat *vtstat = (struct vt_stat *)arg; + unsigned short state, mask; + + if (put_user(fg_console + 1, &vtstat->v_active)) + return -EFAULT; + state = 1; /* /dev/tty0 is always open */ + for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) + if (VT_IS_IN_USE(i)) + state |= mask; + return put_user(state, &vtstat->v_state); + } + + /* + * Returns the first available (non-opened) console. + */ + case VT_OPENQRY: + for (i = 0; i < MAX_NR_CONSOLES; ++i) + if (! VT_IS_IN_USE(i)) + break; + ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; + goto setint; + + /* + * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, + * with num >= 1 (switches to vt 0, our console, are not allowed, just + * to preserve sanity). + */ + case VT_ACTIVATE: + if (!perm) + return -EPERM; + if (arg == 0 || arg > MAX_NR_CONSOLES) + return -ENXIO; + arg--; + i = vc_allocate(arg); + if (i) + return i; + set_console(arg); + return 0; + + /* + * wait until the specified VT has been activated + */ + case VT_WAITACTIVE: + if (!perm) + return -EPERM; + if (arg == 0 || arg > MAX_NR_CONSOLES) + return -ENXIO; + return vt_waitactive(arg-1); + + /* + * If a vt is under process control, the kernel will not switch to it + * immediately, but postpone the operation until the process calls this + * ioctl, allowing the switch to complete. + * + * According to the X sources this is the behavior: + * 0: pending switch-from not OK + * 1: pending switch-from OK + * 2: completed switch-to OK + */ + case VT_RELDISP: + if (!perm) + return -EPERM; + if (vc->vt_mode.mode != VT_PROCESS) + return -EINVAL; + + /* + * Switching-from response + */ + if (vc->vt_newvt >= 0) { + if (arg == 0) + /* + * Switch disallowed, so forget we were trying + * to do it. + */ + vc->vt_newvt = -1; + + else { + /* + * The current vt has been released, so + * complete the switch. + */ + struct vc_data *tmp; + + int newvt = vc->vt_newvt; + vc->vt_newvt = -1; + i = vc_allocate(newvt); + if (i) + return i; + + tmp = vc->display_fg->vc_cons[newvt]; + /* + * When we actually do the console switch, + * make sure we are atomic with respect to + * other console switches.. + */ + acquire_console_sem(); + complete_change_console(tmp, + vc->display_fg->vc_cons[fg_console]); + release_console_sem(); + } + } + + /* + * Switched-to response + */ + else + { + /* + * If it's just an ACK, ignore it + */ + if (arg != VT_ACKACQ) + return -EINVAL; + } + + return 0; + + /* + * Disallocate memory associated to VT (but leave VT1) + */ + case VT_DISALLOCATE: + if (arg > MAX_NR_CONSOLES) + return -ENXIO; + if (arg == 0) { + /* disallocate all unused consoles, but leave 0 */ + for (i=1; iv_rows) || + get_user(cc, &vtsizes->v_cols)) + return -EFAULT; + return vc_resize_all(ll, cc); + } + + case VT_RESIZEX: + { + struct vt_consize *vtconsize = (struct vt_consize *) arg; + ushort ll,cc,vlin,clin,vcol,ccol; + if (!perm) + return -EPERM; + if (verify_area(VERIFY_READ, (void *)vtconsize, + sizeof(struct vt_consize))) + return -EFAULT; + __get_user(ll, &vtconsize->v_rows); + __get_user(cc, &vtconsize->v_cols); + __get_user(vlin, &vtconsize->v_vlin); + __get_user(clin, &vtconsize->v_clin); + __get_user(vcol, &vtconsize->v_vcol); + __get_user(ccol, &vtconsize->v_ccol); + vlin = vlin ? vlin : video_scan_lines; + if ( clin ) + { + if ( ll ) + { + if ( ll != vlin/clin ) + return -EINVAL; /* Parameters don't add up */ + } + else + ll = vlin/clin; + } + if ( vcol && ccol ) + { + if ( cc ) + { + if ( cc != vcol/ccol ) + return -EINVAL; + } + else + cc = vcol/ccol; + } + + if ( clin > 32 ) + return -EINVAL; + + if ( vlin ) + video_scan_lines = vlin; + if ( clin ) + video_font_height = clin; + + return vc_resize_all(ll, cc); + } + + case PIO_FONT: { + struct console_font_op op; + if (!perm) + return -EPERM; + op.op = KD_FONT_OP_SET; + op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ + op.width = 8; + op.height = 0; + op.charcount = 256; + op.data = (char *) arg; + return con_font_op(vt_cons->vc_cons[fg_console], &op); + } + + case GIO_FONT: { + struct console_font_op op; + op.op = KD_FONT_OP_GET; + op.flags = KD_FONT_FLAG_OLD; + op.width = 8; + op.height = 32; + op.charcount = 256; + op.data = (char *) arg; + return con_font_op(vt_cons->vc_cons[fg_console], &op); + } + + case PIO_CMAP: + if (!perm) + return -EPERM; + return con_set_cmap((char *)arg); + + case GIO_CMAP: + return con_get_cmap((char *)arg); + + case PIO_FONTX: + case GIO_FONTX: + return do_fontx_ioctl(cmd, (struct consolefontdesc *)arg, perm); + + case PIO_FONTRESET: + { + if (!perm) + return -EPERM; + +#ifdef BROKEN_GRAPHICS_PROGRAMS + /* With BROKEN_GRAPHICS_PROGRAMS defined, the default + font is not saved. */ + return -ENOSYS; +#else + { + struct console_font_op op; + op.op = KD_FONT_OP_SET_DEFAULT; + op.data = NULL; + i = con_font_op(vt_cons->vc_cons[fg_console], &op); + if (i) return i; + con_set_default_unimap(vt_cons->vc_cons[fg_console]); + return 0; + } +#endif + } + + case KDFONTOP: { + struct console_font_op op; + if (copy_from_user(&op, (void *) arg, sizeof(op))) + return -EFAULT; + if (!perm && op.op != KD_FONT_OP_GET) + return -EPERM; + i = con_font_op(vc, &op); + if (i) return i; + if (copy_to_user((void *) arg, &op, sizeof(op))) + return -EFAULT; + return 0; + } + + case PIO_SCRNMAP: + if (!perm) + return -EPERM; + return con_set_trans_old((unsigned char *)arg); + + case GIO_SCRNMAP: + return con_get_trans_old((unsigned char *)arg); + + case PIO_UNISCRNMAP: + if (!perm) + return -EPERM; + return con_set_trans_new((unsigned short *)arg); + + case GIO_UNISCRNMAP: + return con_get_trans_new((unsigned short *)arg); + + case PIO_UNIMAPCLR: + { struct unimapinit ui; + if (!perm) + return -EPERM; + i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit)); + if (i) return -EFAULT; + con_clear_unimap(vt_cons->vc_cons[fg_console], &ui); + return 0; + } + + case PIO_UNIMAP: + case GIO_UNIMAP: + return do_unimap_ioctl(vc, cmd, (struct unimapdesc *)arg, perm); + + case VT_LOCKSWITCH: + if (!suser()) + return -EPERM; + vt_dont_switch = 1; + return 0; + case VT_UNLOCKSWITCH: + if (!suser()) + return -EPERM; + vt_dont_switch = 0; + return 0; +#ifdef CONFIG_FB_COMPAT_XPMAC + case VC_GETMODE: + { + struct vc_mode mode; + + i = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct vc_mode)); + if (i == 0) + i = console_getmode(&mode); + if (i) + return i; + if (copy_to_user((void *) arg, &mode, sizeof(mode))) + return -EFAULT; + return 0; + } + case VC_SETMODE: + case VC_INQMODE: + { + struct vc_mode mode; + + if (!perm) + return -EPERM; + if (copy_from_user(&mode, (void *) arg, sizeof(mode))) + return -EFAULT; + return console_setmode(&mode, cmd == VC_SETMODE); + } + case VC_SETCMAP: + { + unsigned char cmap[3][256], *p; + int n_entries, cmap_size, i, j; + + if (!perm) + return -EPERM; + if (arg == (unsigned long) VC_POWERMODE_INQUIRY + || arg <= VESA_POWERDOWN) { + /* compatibility hack: VC_POWERMODE + was changed from 0x766a to 0x766c */ + return console_powermode((int) arg); + } + if (get_user(cmap_size, (int *) arg)) + return -EFAULT; + if (cmap_size % 3) + return -EINVAL; + n_entries = cmap_size / 3; + if ((unsigned) n_entries > 256) + return -EINVAL; + p = (unsigned char *) (arg + sizeof(int)); + for (j = 0; j < n_entries; ++j) + for (i = 0; i < 3; ++i) + if (get_user(cmap[i][j], p++)) + return -EFAULT; + return console_setcmap(n_entries, cmap[0], + cmap[1], cmap[2]); + } + case VC_GETCMAP: + /* not implemented yet */ + return -ENOIOCTLCMD; + case VC_POWERMODE: + if (!perm) + return -EPERM; + return console_powermode((int) arg); +#endif /* CONFIG_FB_COMPAT_XPMAC */ + default: + return -ENOIOCTLCMD; + } +} + +/* + * Sometimes we want to wait until a particular VT has been activated. We + * do it in a very simple manner. Everybody waits on a single queue and + * get woken up at once. Those that are satisfied go on with their business, + * while those not ready go back to sleep. Seems overkill to add a wait + * to each vt just for this - usually this does nothing! + */ +static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); + +/* + * Sleeps until a vt is activated, or the task is interrupted. Returns + * 0 if activation, -EINTR if interrupted. + */ +int vt_waitactive(int vt) +{ + int retval; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&vt_activate_queue, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + retval = 0; + if (vt == fg_console) + break; + retval = -EINTR; + if (signal_pending(current)) + break; + schedule(); + } + remove_wait_queue(&vt_activate_queue, &wait); + current->state = TASK_RUNNING; + return retval; +} + +#define vt_wake_waitactive() wake_up(&vt_activate_queue) + +void reset_vc(struct vc_data *vc) +{ + vc->vc_mode = KD_TEXT; + vc->kbd_table.kbdmode = VC_XLATE; + vc->vt_mode.mode = VT_AUTO; + vc->vt_mode.waitv = 0; + vc->vt_mode.relsig = 0; + vc->vt_mode.acqsig = 0; + vc->vt_mode.frsig = 0; + vc->vt_pid = -1; + vc->vt_newvt = -1; + if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ + reset_palette(vc); +} + +inline void switch_screen(struct vc_data *new_vc, struct vc_data *old_vc) +{ + struct vt_struct *vt = new_vc->display_fg; + + if (!new_vc) + return; + + hide_cursor(old_vc); + if (old_vc->vc_num != new_vc->vc_num) { + int update; + + fg_console = new_vc->vc_num; + save_screen(old_vc); + set_origin(old_vc); + + set_origin(new_vc); + update = vt->vt_sw->con_switch(new_vc); + set_palette(new_vc); + if (update && new_vc->vc_mode != KD_GRAPHICS) + do_update_region(new_vc, new_vc->vc_origin, + new_vc->vc_screenbuf_size/2); + } + set_cursor(new_vc); + set_leds(); + compute_shiftstate(); +} + +/* + * Performs the front-end of a vt switch + */ +void change_console(struct vc_data *new_vc, struct vc_data *old_vc) +{ + /* + * If this vt is in process mode, then we need to handshake with + * that process before switching. Essentially, we store where that + * vt wants to switch to and wait for it to tell us when it's done + * (via VT_RELDISP ioctl). + * + * We also check to see if the controlling process still exists. + * If it doesn't, we reset this vt to auto mode and continue. + * This is a cheap way to track process control. The worst thing + * that can happen is: we send a signal to a process, it dies, and + * the switch gets "lost" waiting for a response; hopefully, the + * user will try again, we'll detect the process is gone (unless + * the user waits just the right amount of time :-) and revert the + * vt to auto control. + */ + if (old_vc->vt_mode.mode == VT_PROCESS) { + /* + * Send the signal as privileged - kill_proc() will + * tell us if the process has gone or something else + * is awry + */ + if (kill_proc(old_vc->vt_pid, old_vc->vt_mode.relsig,1) == 0) { + /* + * It worked. Mark the vt to switch to and + * return. The process needs to send us a + * VT_RELDISP ioctl to complete the switch. + */ + old_vc->vt_newvt = new_vc->vc_num; + return; + } + + /* + * The controlling process has died, so we revert back to + * normal operation. In this case, we'll also change back + * to KD_TEXT mode. I'm not sure if this is strictly correct + * but it saves the agony when the X server dies and the screen + * remains blanked due to KD_GRAPHICS! It would be nice to do + * this outside of VT_PROCESS but there is no single process + * to account for and tracking tty count may be undesirable. + */ + reset_vc(old_vc); + + /* + * Fall through to normal (VT_AUTO) handling of the switch... + */ + } + + /* + * Ignore all switches in KD_GRAPHICS+VT_AUTO mode + */ + if (old_vc->vc_mode == KD_GRAPHICS) + return; + + complete_change_console(new_vc, old_vc); +} + +/* + * Performs the back end of a vt switch + */ +void complete_change_console(struct vc_data *new_vc, struct vc_data *old_vc) +{ + unsigned char old_vc_mode; + + new_vc->display_fg->last_console = old_vc; + + /* + * If we're switching, we could be going from KD_GRAPHICS to + * KD_TEXT mode or vice versa, which means we need to blank or + * unblank the screen later. + */ + old_vc_mode = old_vc->vc_mode; + switch_screen(new_vc, old_vc); + + /* + * This can't appear below a successful kill_proc(). If it did, + * then the *blank_screen operation could occur while X, having + * received acqsig, is waking up on another processor. This + * condition can lead to overlapping accesses to the VGA range + * and the framebuffer (causing system lockups). + * + * To account for this we duplicate this code below only if the + * controlling process is gone and we've called reset_vc. + */ + if (old_vc_mode != new_vc->vc_mode) { + if (new_vc->vc_mode == KD_TEXT) + unblank_screen(); + else + do_blank_screen(new_vc->display_fg, 1); + } + + /* + * If this new console is under process control, send it a signal + * telling it that it has acquired. Also check if it has died and + * clean up (similar to logic employed in change_console()) + */ + if (new_vc->vt_mode.mode == VT_PROCESS) { + /* + * Send the signal as privileged - kill_proc() will + * tell us if the process has gone or something else + * is awry + */ + if (kill_proc(new_vc->vt_pid, new_vc->vt_mode.acqsig,1) != 0) { + /* + * The controlling process has died, so we revert back + * to normal operation. In this case, we'll also change + * back to KD_TEXT mode. I'm not sure if this is + * strictly correct but it saves the agony when the X + * server dies and the screen remains blanked due to + * KD_GRAPHICS! It would be nice to do this outside of + * VT_PROCESS but there is no single process to account + * for and tracking tty count may be undesirable. + */ + reset_vc(new_vc); + + if (old_vc_mode != new_vc->vc_mode) + { + if (new_vc->vc_mode == KD_TEXT) + unblank_screen(); + else + do_blank_screen(new_vc->display_fg, 1); + } + } + } + + /* + * Wake anyone waiting for their VT to activate + */ + vt_wake_waitactive(); + return; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/char/wafer5823wdt.c linux-2.5/drivers/char/wafer5823wdt.c --- linux-2.5.20/drivers/char/wafer5823wdt.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/char/wafer5823wdt.c Sat Apr 13 15:42:55 2002 @@ -0,0 +1,220 @@ +/* + * ICP Wafer 5823 Single Board Computer WDT driver for Linux 2.4.x + * http://www.icpamerica.com/wafer_5823.php + * May also work on other similar models + * + * (c) Copyright 2002 Justin Cormack + * + * Release 0.02 + * + * Based on advantechwdt.c which is based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long wafwdt_is_open; +static spinlock_t wafwdt_lock; + +/* + * You must set these - there is no sane way to probe for this board. + * + * To enable, write the timeout value in seconds (1 to 255) to I/O + * port WDT_START, then read the port to start the watchdog. To pat + * the dog, read port WDT_STOP to stop the timer, then read WDT_START + * to restart it again. + */ + +#define WDT_START 0x443 +#define WDT_STOP 0x843 + +#define WD_TIMO 60 /* 1 minute */ + +static void wafwdt_ping(void) +{ + /* pat watchdog */ + spin_lock(&wafwdt_lock); + inb_p(WDT_STOP); + inb_p(WDT_START); + spin_unlock(&wafwdt_lock); +} + +static void wafwdt_start(void) +{ + /* start up watchdog */ + outb_p(WD_TIMO, WDT_START); + inb_p(WDT_START); +} + +static void +wafwdt_stop(void) +{ + /* stop watchdog */ + inb_p(WDT_STOP); +} + +static ssize_t wafwdt_write(struct file *file, const char *buf, size_t count, loff_t * ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + wafwdt_ping(); + return 1; + } + return 0; +} + +static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident = { + WDIOF_KEEPALIVEPING, 1, "Wafer 5823 WDT" + }; + int one=1; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user + ((struct watchdog_info *) arg, &ident, sizeof (ident))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + if (copy_to_user((int *) arg, &one, sizeof (int))) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + wafwdt_ping(); + break; + + default: + return -ENOTTY; + } + return 0; +} + +static int wafwdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &wafwdt_is_open)) + return -EBUSY; + wafwdt_start(); + return 0; +} + +static int +wafwdt_close(struct inode *inode, struct file *file) +{ + clear_bit(0, &wafwdt_is_open); +#ifndef CONFIG_WATCHDOG_NOWAYOUT + wafwdt_stop(); +#endif + return 0; +} + +/* + * Notifier for system down + */ + +static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Turn the WDT off */ + wafwdt_stop(); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations wafwdt_fops = { + owner:THIS_MODULE, + write:wafwdt_write, + ioctl:wafwdt_ioctl, + open:wafwdt_open, + release:wafwdt_close, +}; + +static struct miscdevice wafwdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wafwdt_fops +}; + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wafwdt_notifier = { + wafwdt_notify_sys, + NULL, + 0 +}; + +static int __init wafwdt_init(void) +{ + printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n"); + + spin_lock_init(&wafwdt_lock); + if(!request_region(WDT_STOP, 1, "Wafer 5823 WDT")) + goto error; + if(!request_region(WDT_START, 1, "Wafer 5823 WDT")) + goto error2; + if(misc_register(&wafwdt_miscdev)<0) + goto error3; + register_reboot_notifier(&wafwdt_notifier); + return 0; +error3: + release_region(WDT_START, 1); +error2: + release_region(WDT_STOP, 1); +error: + return -ENODEV; +} + +static void __exit wafwdt_exit(void) +{ + misc_deregister(&wafwdt_miscdev); + unregister_reboot_notifier(&wafwdt_notifier); + release_region(WDT_STOP, 1); + release_region(WDT_START, 1); +} + +module_init(wafwdt_init); +module_exit(wafwdt_exit); + +MODULE_AUTHOR("Justin Cormack"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + +/* end of wafer5823wdt.c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/hotplug/cpqphp_ctrl.c linux-2.5/drivers/hotplug/cpqphp_ctrl.c --- linux-2.5.20/drivers/hotplug/cpqphp_ctrl.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/hotplug/cpqphp_ctrl.c Sun Mar 3 17:54:35 2002 @@ -1707,6 +1707,7 @@ struct controller *ctrl; lock_kernel(); daemonize(); + reparent_to_init(); // New name strcpy(current->comm, "phpd_event"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/i2c/Config.help linux-2.5/drivers/i2c/Config.help --- linux-2.5.20/drivers/i2c/Config.help Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/i2c/Config.help Fri Feb 15 15:55:24 2002 @@ -80,6 +80,26 @@ . The module will be called i2c-elektor.o. +CONFIG_ITE_I2C_ALGO + This supports the use the ITE8172 I2C interface found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C peripheral driver support below. + + This support is also available as a module. If you want to compile + it as a modules, say M here and read + . + The module will be called i2c-algo-ite.o. + +CONFIG_ITE_I2C_ADAP + This supports the ITE8172 I2C peripheral found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C driver algorithm support above. + + This support is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-adap-ite.o. + CONFIG_I2C_CHARDEV Say Y here to use i2c-* device files, usually found in the /dev directory on your system. They make it possible to have user-space diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/i2c/Config.in linux-2.5/drivers/i2c/Config.in --- linux-2.5.20/drivers/i2c/Config.in Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/i2c/Config.in Thu Dec 27 16:32:31 2001 @@ -39,6 +39,10 @@ fi fi + if [ "$CONFIG_ALL_PPC" = "y" ] ; then + dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C + fi + # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/i2c/Makefile linux-2.5/drivers/i2c/Makefile --- linux-2.5.20/drivers/i2c/Makefile Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/i2c/Makefile Sat Jun 1 00:34:34 2002 @@ -16,6 +16,7 @@ obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o obj-$(CONFIG_I2C_PROC) += i2c-proc.o +obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/i2c/i2c-keywest.c linux-2.5/drivers/i2c/i2c-keywest.c --- linux-2.5.20/drivers/i2c/i2c-keywest.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/i2c/i2c-keywest.c Mon Feb 4 22:15:16 2002 @@ -0,0 +1,680 @@ +/* + i2c Support for Apple Keywest I2C Bus Controller + + Copyright (c) 2001 Benjamin Herrenschmidt + + Original work by + + Copyright (c) 2000 Philip Edelbrock + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Changes: + + 2001/12/13 BenH New implementation + 2001/12/15 BenH Add support for "byte" and "quick" + transfers. Add i2c_xfer routine. + + My understanding of the various modes supported by keywest are: + + - Dumb mode : not implemented, probably direct tweaking of lines + - Standard mode : simple i2c transaction of type + S Addr R/W A Data A Data ... T + - Standard sub mode : combined 8 bit subaddr write with data read + S Addr R/W A SubAddr A Data A Data ... T + - Combined mode : Subaddress and Data sequences appended with no stop + S Addr R/W A SubAddr S Addr R/W A Data A Data ... T + + Currently, this driver uses only Standard mode for i2c xfer, and + smbus byte & quick transfers ; and uses StandardSub mode for + other smbus transfers instead of combined as we need that for the + sound driver to be happy +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "i2c-keywest.h" + +#undef POLLED_MODE + +#define DBG(x...) do {\ + if (debug > 0) \ + printk(KERN_DEBUG "KW:" x); \ + } while(0) + + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("I2C driver for Apple's Keywest"); +MODULE_LICENSE("GPL"); +MODULE_PARM(probe, "i"); +MODULE_PARM(debug, "i"); +EXPORT_NO_SYMBOLS; + +int probe = 0; +int debug = 0; + +static struct keywest_iface *ifaces = NULL; + +#ifdef POLLED_MODE +/* This isn't fast, but will go once I implement interrupt with + * proper timeout + */ +static u8 +wait_interrupt(struct keywest_iface* iface) +{ + int i; + u8 isr; + + for (i = 0; i < POLL_TIMEOUT; i++) { + isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK; + if (isr != 0) + return isr; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } + return isr; +} +#endif /* POLLED_MODE */ + + +static void +do_stop(struct keywest_iface* iface, int result) +{ + write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_STOP); + iface->state = state_stop; + iface->result = result; +} + +/* Main state machine for standard & standard sub mode */ +static void +handle_interrupt(struct keywest_iface *iface, u8 isr) +{ + int ack; + + DBG("handle_interrupt(), got: %x, status: %x, state: %d\n", + isr, read_reg(reg_status), iface->state); + if (isr == 0 && iface->state != state_stop) { + do_stop(iface, -1); + return; + } + if (isr & KW_I2C_IRQ_STOP && iface->state != state_stop) { + iface->result = -1; + iface->state = state_stop; + } + switch(iface->state) { + case state_addr: + if (!(isr & KW_I2C_IRQ_ADDR)) { + do_stop(iface, -1); + break; + } + ack = read_reg(reg_status); + DBG("ack on set address: %x\n", ack); + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + do_stop(iface, -1); + break; + } + /* Handle rw "quick" mode */ + if (iface->datalen == 0) + do_stop(iface, 0); + else if (iface->read_write == I2C_SMBUS_READ) { + iface->state = state_read; + if (iface->datalen > 1) + write_reg(reg_control, read_reg(reg_control) + | KW_I2C_CTL_AAK); + } else { + iface->state = state_write; + DBG("write byte: %x\n", *(iface->data)); + write_reg(reg_data, *(iface->data++)); + iface->datalen--; + } + + break; + case state_read: + if (!(isr & KW_I2C_IRQ_DATA)) { + do_stop(iface, -1); + break; + } + *(iface->data++) = read_reg(reg_data); + DBG("read byte: %x\n", *(iface->data-1)); + iface->datalen--; + if (iface->datalen == 0) + iface->state = state_stop; + else + write_reg(reg_control, 0); + break; + case state_write: + if (!(isr & KW_I2C_IRQ_DATA)) { + do_stop(iface, -1); + break; + } + /* Check ack status */ + ack = read_reg(reg_status); + DBG("ack on data write: %x\n", ack); + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + do_stop(iface, -1); + break; + } + if (iface->datalen) { + DBG("write byte: %x\n", *(iface->data)); + write_reg(reg_data, *(iface->data++)); + iface->datalen--; + } else + do_stop(iface, 0); + break; + + case state_stop: + if (!(isr & KW_I2C_IRQ_STOP) && (++iface->stopretry) < 10) + do_stop(iface, -1); + else { + iface->state = state_idle; + write_reg(reg_control, 0x00); + write_reg(reg_ier, 0x00); +#ifndef POLLED_MODE + complete(&iface->complete); +#endif /* POLLED_MODE */ + } + break; + } + + write_reg(reg_isr, isr); +} + +#ifndef POLLED_MODE + +/* Interrupt handler */ +static void +keywest_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct keywest_iface *iface = (struct keywest_iface *)dev_id; + + spin_lock(&iface->lock); + del_timer(&iface->timeout_timer); + handle_interrupt(iface, read_reg(reg_isr)); + if (iface->state != state_idle) { + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + } + spin_unlock(&iface->lock); +} + +static void +keywest_timeout(unsigned long data) +{ + struct keywest_iface *iface = (struct keywest_iface *)data; + + DBG("timeout !\n"); + spin_lock_irq(&iface->lock); + handle_interrupt(iface, read_reg(reg_isr)); + if (iface->state != state_idle) { + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + } + spin_unlock(&iface->lock); +} + +#endif /* POLLED_MODE */ + +/* + * SMBUS-type transfer entrypoint + */ +static s32 +keywest_smbus_xfer( struct i2c_adapter* adap, + u16 addr, + unsigned short flags, + char read_write, + u8 command, + int size, + union i2c_smbus_data* data) +{ + struct keywest_chan* chan = (struct keywest_chan*)adap->data; + struct keywest_iface* iface = chan->iface; + int len; + u8* buffer; + u16 cur_word; + int rc = 0; + + if (iface->state == state_dead) + return -1; + + /* Prepare datas & select mode */ + iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; + switch (size) { + case I2C_SMBUS_QUICK: + len = 0; + buffer = NULL; + iface->cur_mode |= KW_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE: + len = 1; + buffer = &data->byte; + iface->cur_mode |= KW_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE_DATA: + len = 1; + buffer = &data->byte; + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + break; + case I2C_SMBUS_WORD_DATA: + len = 2; + cur_word = cpu_to_le16(data->word); + buffer = (u8 *)&cur_word; + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + break; + case I2C_SMBUS_BLOCK_DATA: + len = data->block[0]; + buffer = &data->block[1]; + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + break; + default: + return -1; + } + + /* Original driver had this limitation */ + if (len > 32) + len = 32; + + down(&iface->sem); + + DBG("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n", + chan->chan_no, addr, len, read_write == I2C_SMBUS_READ); + + iface->data = buffer; + iface->datalen = len; + iface->state = state_addr; + iface->result = 0; + iface->stopretry = 0; + iface->read_write = read_write; + + /* Setup channel & clear pending irqs */ + write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); + write_reg(reg_isr, read_reg(reg_isr)); + write_reg(reg_status, 0); + + /* Set up address and r/w bit */ + write_reg(reg_addr, + (addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00)); + + /* Set up the sub address */ + if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB + || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) + write_reg(reg_subaddr, command); + + /* Arm timeout */ + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + + /* Start sending address & enable interrupt*/ + write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR); + write_reg(reg_ier, KW_I2C_IRQ_MASK); + +#ifdef POLLED_MODE + DBG("using polled mode...\n"); + /* State machine, to turn into an interrupt handler */ + while(iface->state != state_idle) { + u8 isr = wait_interrupt(iface); + handle_interrupt(iface, isr); + } +#else /* POLLED_MODE */ + DBG("using interrupt mode...\n"); + wait_for_completion(&iface->complete); +#endif /* POLLED_MODE */ + + rc = iface->result; + DBG("transfer done, result: %d\n", rc); + + if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ) + data->word = le16_to_cpu(cur_word); + + /* Release sem */ + up(&iface->sem); + + return rc; +} + +/* + * Generic i2c master transfer entrypoint + */ +static int +keywest_xfer( struct i2c_adapter *adap, + struct i2c_msg msgs[], + int num) +{ + struct keywest_chan* chan = (struct keywest_chan*)adap->data; + struct keywest_iface* iface = chan->iface; + struct i2c_msg *pmsg; + int i, completed; + int rc = 0; + + down(&iface->sem); + + /* Set adapter to standard mode */ + iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; + iface->cur_mode |= KW_I2C_MODE_STANDARD; + + completed = 0; + for (i = 0; rc >= 0 && i < num;) { + u8 addr; + + pmsg = &msgs[i++]; + addr = pmsg->addr; + if (pmsg->flags & I2C_M_TEN) { + printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n"); + rc = -EINVAL; + break; + } + DBG("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n", + chan->chan_no, + pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->len, addr, i, num); + + /* Setup channel & clear pending irqs */ + write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); + write_reg(reg_isr, read_reg(reg_isr)); + write_reg(reg_status, 0); + + iface->data = pmsg->buf; + iface->datalen = pmsg->len; + iface->state = state_addr; + iface->result = 0; + iface->stopretry = 0; + if (pmsg->flags & I2C_M_RD) + iface->read_write = I2C_SMBUS_READ; + else + iface->read_write = I2C_SMBUS_WRITE; + + /* Set up address and r/w bit */ + if (pmsg->flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + write_reg(reg_addr, + (addr << 1) | + ((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00)); + + /* Arm timeout */ + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + + /* Start sending address & enable interrupt*/ + write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR); + write_reg(reg_ier, KW_I2C_IRQ_MASK); + +#ifdef POLLED_MODE + DBG("using polled mode...\n"); + /* State machine, to turn into an interrupt handler */ + while(iface->state != state_idle) { + u8 isr = wait_interrupt(iface); + handle_interrupt(iface, isr); + } +#else /* POLLED_MODE */88 + DBG("using interrupt mode...\n"); + wait_for_completion(&iface->complete); +#endif /* POLLED_MODE */ + + rc = iface->result; + if (rc == 0) + completed++; + DBG("transfer done, result: %d\n", rc); + } + + /* Release sem */ + up(&iface->sem); + + return completed; +} + +static u32 +keywest_func(struct i2c_adapter * adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static void +keywest_inc(struct i2c_adapter *adapter) +{ + MOD_INC_USE_COUNT; +} + +static void +keywest_dec(struct i2c_adapter *adapter) +{ + MOD_DEC_USE_COUNT; +} + +/* For now, we only handle combined mode (smbus) */ +static struct i2c_algorithm keywest_algorithm = { + name: "Keywest i2c", + id: I2C_ALGO_SMBUS, + smbus_xfer: keywest_smbus_xfer, + master_xfer: keywest_xfer, + functionality: keywest_func, +}; + + +static int +create_iface(struct device_node* np) +{ + unsigned long steps, *psteps, *prate; + unsigned bsteps, tsize, i, nchan, addroffset; + struct keywest_iface* iface; + int rc; + + psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL); + steps = psteps ? (*psteps) : 0x10; + + /* Hrm... maybe we can be smarter here */ + for (bsteps = 0; (steps & 0x01) == 0; bsteps++) + steps >>= 1; + + if (!strcmp(np->parent->name, "uni-n")) { + nchan = 2; + addroffset = 3; + } else { + addroffset = 0; + nchan = 1; + } + + tsize = sizeof(struct keywest_iface) + + (sizeof(struct keywest_chan) + 4) * nchan; + iface = (struct keywest_iface *) kmalloc(tsize, GFP_KERNEL); + if (iface == NULL) { + printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n"); + return -ENOMEM; + } + memset(iface, 0, tsize); + init_MUTEX(&iface->sem); + spin_lock_init(&iface->lock); + init_completion(&iface->complete); + iface->bsteps = bsteps; + iface->chan_count = nchan; + iface->state = state_idle; + iface->irq = np->intrs[0].line; + iface->channels = (struct keywest_chan *) + (((unsigned long)(iface + 1) + 3UL) & ~3UL); + iface->base = (unsigned long)ioremap(np->addrs[0].address + addroffset, + np->addrs[0].size); + if (iface->base == 0) { + printk(KERN_ERR "i2c-keywest: can't map inteface !\n"); + kfree(iface); + return -ENOMEM; + } + + init_timer(&iface->timeout_timer); + iface->timeout_timer.function = keywest_timeout; + iface->timeout_timer.data = (unsigned long)iface; + + /* Select interface rate */ + iface->cur_mode = KW_I2C_MODE_100KHZ; + prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL); + if (prate) switch(*prate) { + case 100: + iface->cur_mode = KW_I2C_MODE_100KHZ; + break; + case 50: + iface->cur_mode = KW_I2C_MODE_50KHZ; + break; + case 25: + iface->cur_mode = KW_I2C_MODE_25KHZ; + break; + default: + printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n", + *prate); + } + + /* Select standard sub mode */ + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + + /* Write mode */ + write_reg(reg_mode, iface->cur_mode); + + /* Switch interrupts off & clear them*/ + write_reg(reg_ier, 0x00); + write_reg(reg_isr, KW_I2C_IRQ_MASK); + +#ifndef POLLED_MODE + /* Request chip interrupt */ + rc = request_irq(iface->irq, keywest_irq, 0, "keywest i2c", iface); + if (rc) { + printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq); + iounmap((void *)iface->base); + kfree(iface); + return -ENODEV; + } +#endif /* POLLED_MODE */ + + for (i=0; ichannels[i]; + u8 addr; + + sprintf(chan->adapter.name, "%s %d", np->parent->name, i); + chan->iface = iface; + chan->chan_no = i; + chan->adapter.id = I2C_ALGO_SMBUS; + chan->adapter.algo = &keywest_algorithm; + chan->adapter.algo_data = NULL; + chan->adapter.inc_use = keywest_inc; + chan->adapter.dec_use = keywest_dec; + chan->adapter.client_register = NULL; + chan->adapter.client_unregister = NULL; + chan->adapter.data = chan; + + rc = i2c_add_adapter(&chan->adapter); + if (rc) { + printk("i2c-keywest.c: Adapter %s registration failed\n", + chan->adapter.name); + chan->adapter.data = NULL; + } + if (probe) { + printk("Probe: "); + for (addr = 0x00; addr <= 0x7f; addr++) { + if (i2c_smbus_xfer(&chan->adapter,addr, + 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) + printk("%02x ", addr); + } + printk("\n"); + } + } + + printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n", + np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps); + + iface->next = ifaces; + ifaces = iface; + return 0; +} + +static void +dispose_iface(struct keywest_iface *iface) +{ + int i, rc; + + ifaces = iface->next; + + /* Make sure we stop all activity */ + down(&iface->sem); +#ifndef POLLED_MODE + spin_lock_irq(&iface->lock); + while (iface->state != state_idle) { + spin_unlock_irq(&iface->lock); + schedule(); + spin_lock_irq(&iface->lock); + } +#endif /* POLLED_MODE */ + iface->state = state_dead; +#ifndef POLLED_MODE + spin_unlock_irq(&iface->lock); + free_irq(iface->irq, iface); +#endif /* POLLED_MODE */ + up(&iface->sem); + + /* Release all channels */ + for (i=0; ichan_count; i++) { + struct keywest_chan* chan = &iface->channels[i]; + if (!chan->adapter.data) + continue; + rc = i2c_del_adapter(&chan->adapter); + chan->adapter.data = NULL; + /* We aren't that prepared to deal with this... */ + if (rc) + printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n"); + } + iounmap((void *)iface->base); + kfree(iface); +} + +static int __init +i2c_keywest_init(void) +{ + struct device_node *np; + int rc = -ENODEV; + + np = find_compatible_devices("i2c", "keywest"); + while (np != 0) { + if (np->n_addrs >= 1 && np->n_intrs >= 1) + rc = create_iface(np); + np = np->next; + } + if (ifaces) + rc = 0; + return rc; +} + +static void __exit +i2c_keywest_cleanup(void) +{ + while(ifaces) + dispose_iface(ifaces); +} + +module_init(i2c_keywest_init); +module_exit(i2c_keywest_cleanup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/i2c/i2c-keywest.h linux-2.5/drivers/i2c/i2c-keywest.h --- linux-2.5.20/drivers/i2c/i2c-keywest.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/i2c/i2c-keywest.h Thu Dec 27 16:32:31 2001 @@ -0,0 +1,111 @@ +#ifndef __I2C_KEYWEST_H__ +#define __I2C_KEYWEST_H__ + +/* The Tumbler audio equalizer can be really slow sometimes */ +#define POLL_TIMEOUT (2*HZ) + +/* Register indices */ +typedef enum { + reg_mode = 0, + reg_control, + reg_status, + reg_isr, + reg_ier, + reg_addr, + reg_subaddr, + reg_data +} reg_t; + + +/* Mode register */ +#define KW_I2C_MODE_100KHZ 0x00 +#define KW_I2C_MODE_50KHZ 0x01 +#define KW_I2C_MODE_25KHZ 0x02 +#define KW_I2C_MODE_DUMB 0x00 +#define KW_I2C_MODE_STANDARD 0x04 +#define KW_I2C_MODE_STANDARDSUB 0x08 +#define KW_I2C_MODE_COMBINED 0x0C +#define KW_I2C_MODE_MODE_MASK 0x0C +#define KW_I2C_MODE_CHAN_MASK 0xF0 + +/* Control register */ +#define KW_I2C_CTL_AAK 0x01 +#define KW_I2C_CTL_XADDR 0x02 +#define KW_I2C_CTL_STOP 0x04 +#define KW_I2C_CTL_START 0x08 + +/* Status register */ +#define KW_I2C_STAT_BUSY 0x01 +#define KW_I2C_STAT_LAST_AAK 0x02 +#define KW_I2C_STAT_LAST_RW 0x04 +#define KW_I2C_STAT_SDA 0x08 +#define KW_I2C_STAT_SCL 0x10 + +/* IER & ISR registers */ +#define KW_I2C_IRQ_DATA 0x01 +#define KW_I2C_IRQ_ADDR 0x02 +#define KW_I2C_IRQ_STOP 0x04 +#define KW_I2C_IRQ_START 0x08 +#define KW_I2C_IRQ_MASK 0x0F + +/* Physical interface */ +struct keywest_iface +{ + unsigned long base; + unsigned bsteps; + int irq; + struct semaphore sem; + spinlock_t lock; + struct keywest_chan* channels; + unsigned chan_count; + u8 cur_mode; + char read_write; + u8* data; + unsigned datalen; + int state; + int result; + int stopretry; + struct timer_list timeout_timer; + struct completion complete; + struct keywest_iface* next; +}; + +enum { + state_idle, + state_addr, + state_read, + state_write, + state_stop, + state_dead +}; + +/* Channel on an interface */ +struct keywest_chan +{ + struct i2c_adapter adapter; + struct keywest_iface* iface; + unsigned chan_no; +}; + +/* Register access */ + +static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg) +{ + return in_8(((volatile u8 *)iface->base) + + (((unsigned)reg) << iface->bsteps)); +} + +static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val) +{ + out_8(((volatile u8 *)iface->base) + + (((unsigned)reg) << iface->bsteps), val); + (void)__read_reg(iface, reg); + udelay(10); +} + +#define write_reg(reg, val) __write_reg(iface, reg, val) +#define read_reg(reg) __read_reg(iface, reg) + + + +#endif /* __I2C_KEYWEST_H__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/ide/Config.help linux-2.5/drivers/ide/Config.help --- linux-2.5.20/drivers/ide/Config.help Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/ide/Config.help Sat Jun 1 00:34:34 2002 @@ -282,7 +282,7 @@ motherboard uses a VIA VP2 chipset, in which case you should say N. CONFIG_IDEDMA_IVB - There are unclear terms is ATA-4 and ATA-5 standards how certain + There are unclear terms in ATA-4 and ATA-5 standards how certain hardware (an 80c ribbon) should be detected. Different interpretations of the standards have been released in hardware. This causes problems: for example, a host with Ultra Mode 4 (or higher) will not run diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/ide/ide-tape.c linux-2.5/drivers/ide/ide-tape.c --- linux-2.5.20/drivers/ide/ide-tape.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/ide/ide-tape.c Mon Jun 3 17:10:22 2002 @@ -417,6 +417,7 @@ #include #include #include +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/ieee1394/ieee1394_syms.c linux-2.5/drivers/ieee1394/ieee1394_syms.c --- linux-2.5.20/drivers/ieee1394/ieee1394_syms.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/ieee1394/ieee1394_syms.c Sun Jan 6 19:16:28 2002 @@ -0,0 +1,88 @@ +/* + * IEEE 1394 for Linux + * + * Exported symbols for module usage. + * + * Copyright (C) 1999 Andreas E. Bombe + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "ieee1394_transactions.h" +#include "ieee1394_hotplug.h" +#include "highlevel.h" +#include "nodemgr.h" + +EXPORT_SYMBOL(hpsb_register_lowlevel); +EXPORT_SYMBOL(hpsb_unregister_lowlevel); +EXPORT_SYMBOL(hpsb_get_host); +EXPORT_SYMBOL(hpsb_inc_host_usage); +EXPORT_SYMBOL(hpsb_dec_host_usage); + +EXPORT_SYMBOL(alloc_hpsb_packet); +EXPORT_SYMBOL(free_hpsb_packet); +EXPORT_SYMBOL(hpsb_send_packet); +EXPORT_SYMBOL(hpsb_reset_bus); +EXPORT_SYMBOL(hpsb_bus_reset); +EXPORT_SYMBOL(hpsb_selfid_received); +EXPORT_SYMBOL(hpsb_selfid_complete); +EXPORT_SYMBOL(hpsb_packet_sent); +EXPORT_SYMBOL(hpsb_packet_received); + +EXPORT_SYMBOL(get_tlabel); +EXPORT_SYMBOL(free_tlabel); +EXPORT_SYMBOL(fill_async_readquad); +EXPORT_SYMBOL(fill_async_readquad_resp); +EXPORT_SYMBOL(fill_async_readblock); +EXPORT_SYMBOL(fill_async_readblock_resp); +EXPORT_SYMBOL(fill_async_writequad); +EXPORT_SYMBOL(fill_async_writeblock); +EXPORT_SYMBOL(fill_async_write_resp); +EXPORT_SYMBOL(fill_async_lock); +EXPORT_SYMBOL(fill_async_lock_resp); +EXPORT_SYMBOL(fill_iso_packet); +EXPORT_SYMBOL(fill_phy_packet); +EXPORT_SYMBOL(hpsb_make_readqpacket); +EXPORT_SYMBOL(hpsb_make_readbpacket); +EXPORT_SYMBOL(hpsb_make_writeqpacket); +EXPORT_SYMBOL(hpsb_make_writebpacket); +EXPORT_SYMBOL(hpsb_make_lockpacket); +EXPORT_SYMBOL(hpsb_make_phypacket); +EXPORT_SYMBOL(hpsb_packet_success); +EXPORT_SYMBOL(hpsb_make_packet); +EXPORT_SYMBOL(hpsb_read); +EXPORT_SYMBOL(hpsb_write); +EXPORT_SYMBOL(hpsb_lock); + +EXPORT_SYMBOL(hpsb_register_highlevel); +EXPORT_SYMBOL(hpsb_unregister_highlevel); +EXPORT_SYMBOL(hpsb_register_addrspace); +EXPORT_SYMBOL(hpsb_listen_channel); +EXPORT_SYMBOL(hpsb_unlisten_channel); +EXPORT_SYMBOL(highlevel_read); +EXPORT_SYMBOL(highlevel_write); +EXPORT_SYMBOL(highlevel_lock); +EXPORT_SYMBOL(highlevel_lock64); +EXPORT_SYMBOL(highlevel_add_host); +EXPORT_SYMBOL(highlevel_remove_host); +EXPORT_SYMBOL(highlevel_host_reset); +EXPORT_SYMBOL(highlevel_add_one_host); + +EXPORT_SYMBOL(hpsb_guid_get_entry); +EXPORT_SYMBOL(hpsb_nodeid_get_entry); +EXPORT_SYMBOL(hpsb_get_host_by_ne); +EXPORT_SYMBOL(hpsb_guid_fill_packet); +EXPORT_SYMBOL(hpsb_register_protocol); +EXPORT_SYMBOL(hpsb_unregister_protocol); +EXPORT_SYMBOL(hpsb_release_unit_directory); + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/Config.help linux-2.5/drivers/input/Config.help --- linux-2.5.20/drivers/input/Config.help Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/input/Config.help Sun Jan 27 00:32:29 2002 @@ -64,6 +64,18 @@ The module will be called joydev.o. If you want to compile it as a module, say M here and read . +CONFIG_INPUT_TSDEV + Say Y here if you have an application that only can understand the + Compaq touchscreen protocol for absolute pointer data. This is + useful namely for embedded configurations. + + If unsure, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tsdev.o. If you want to compile it as a + module, say M here and read . + CONFIG_INPUT_EVDEV Say Y here if you want your input device events be accessible under char device 13:64+ - /dev/input/eventX in a generic way. @@ -71,4 +83,18 @@ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called evdev.o. If you want to compile it as a + module, say M here and read . + +CONFIG_INPUT_EVBUG + Say Y here if you have a problem with the input subsystem and + want all events (keypresses, mouse movements), to be output to + the system log. While this is useful for debugging, it's also + a security threat - your keypresses include your passwords, of + course. + + If unsure, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called joydev.o. If you want to compile it as a module, say M here and read . diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/Config.in linux-2.5/drivers/input/Config.in --- linux-2.5.20/drivers/input/Config.in Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/input/Config.in Mon Apr 15 03:22:52 2002 @@ -6,6 +6,8 @@ comment 'Input device support' tristate 'Input core support' CONFIG_INPUT + +comment 'Userland interfaces' dep_tristate ' Keyboard interface' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT dep_tristate ' Mouse interface' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then @@ -13,13 +15,24 @@ int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 fi dep_tristate ' Joystick interface' CONFIG_INPUT_JOYDEV $CONFIG_INPUT +dep_tristate ' Touchscreen interface' CONFIG_INPUT_TSDEV $CONFIG_INPUT +if [ "$CONFIG_INPUT_TSDEV" != "n" ]; then + int ' Horizontal screen resolution' CONFIG_INPUT_TSDEV_SCREEN_X 240 + int ' Vertical screen resolution' CONFIG_INPUT_TSDEV_SCREEN_Y 320 +fi dep_tristate ' Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT +dep_tristate ' Event debugging' CONFIG_INPUT_EVBUG $CONFIG_INPUT +comment 'Input I/O drivers' source drivers/input/gameport/Config.in source drivers/input/serio/Config.in +comment 'Input Device Drivers' if [ "$CONFIG_INPUT" != "n" ]; then + source drivers/input/keyboard/Config.in + source drivers/input/mouse/Config.in source drivers/input/joystick/Config.in + source drivers/input/touchscreen/Config.in fi endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/Makefile linux-2.5/drivers/input/Makefile --- linux-2.5.20/drivers/input/Makefile Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/input/Makefile Sat Jun 1 00:34:35 2002 @@ -4,7 +4,7 @@ # Objects that export symbols. -mod-subdirs := joystick +mod-subdirs := joystick keyboard mouse touchscreen export-objs := input.o # Each configuration option enables a list of files. @@ -14,8 +14,27 @@ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_EVDEV) += evdev.o +obj-$(CONFIG_INPUT_TSDEV) += tsdev.o +obj-$(CONFIG_INPUT_POWER) += power.o +obj-$(CONFIG_INPUT_EVBUG) += evbug.o -obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ +subdir-$(CONFIG_INPUT_KEYBOARD) += keyboard +subdir-$(CONFIG_INPUT_MOUSE) += mouse +subdir-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen + +ifeq ($(CONFIG_INPUT_KEYBOARD),y) + obj-y += keyboard/keybdrv.o +endif + +ifeq ($(CONFIG_INPUT_MOUSE),y) + obj-y += mouse/mousedrv.o +endif + +obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ + +ifeq ($(CONFIG_INPUT_TOUCHSCREEN),y) + obj-y += touchscreen/tsdrv.o +endif # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/evbug.c linux-2.5/drivers/input/evbug.c --- linux-2.5.20/drivers/input/evbug.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/evbug.c Tue Jan 22 17:43:42 2002 @@ -0,0 +1,99 @@ +/* + * $Id: evbug.c,v 1.10 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * Input driver event debug module - dumps all events into syslog + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Input driver event debug module"); +MODULE_LICENSE("GPL"); + +static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value); +} + +static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +{ + struct input_handle *handle; + + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + return NULL; + memset(handle, 0, sizeof(struct input_handle)); + + handle->dev = dev; + handle->handler = handler; + + input_open_device(handle); + + printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys); + + return handle; +} + +static void evbug_disconnect(struct input_handle *handle) +{ + printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys); + + input_close_device(handle); + + kfree(handle); +} + +static struct input_device_id evbug_ids[] = { + { driver_info: 1 }, /* Matches all devices */ + { }, /* Terminating zero entry */ +}; + +MODULE_DEVICE_TABLE(input, evbug_ids); + +static struct input_handler evbug_handler = { + event: evbug_event, + connect: evbug_connect, + disconnect: evbug_disconnect, + name: "evbug", + id_table: evbug_ids, +}; + +int __init evbug_init(void) +{ + input_register_handler(&evbug_handler); + return 0; +} + +void __exit evbug_exit(void) +{ + input_unregister_handler(&evbug_handler); +} + +module_init(evbug_init); +module_exit(evbug_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/gameport/Config.help linux-2.5/drivers/input/gameport/Config.help --- linux-2.5.20/drivers/input/gameport/Config.help Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/input/gameport/Config.help Sun Jan 27 00:32:29 2002 @@ -43,13 +43,22 @@ The module will be called emu10k1-gp.o. If you want to compile it as a module, say M here and read . -CONFIG_GAMEPORT_PCIGAME - Say Y here if you have an Aureal Vortex 1 or 2 or a Trident - 4DWave NX or DX card and want to use its gameport. +CONFIG_GAMEPORT_VORTEX + Say Y here if you have an Vortex 1 or 2 card and want to use its + gameport. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will be called pcigame.o. If you want to compile it as a + The module will be called vortex.o. If you want to compile it as a + module, say M here and read . + +CONFIG_GAMEPORT_VORTEX + Say Y here if you have a ForteMedia FM801 card and want to use its + gameport. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called fm801-gp.o. If you want to compile it as a module, say M here and read . CONFIG_GAMEPORT_CS461X diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/gameport/Config.in linux-2.5/drivers/input/gameport/Config.in --- linux-2.5.20/drivers/input/gameport/Config.in Mon Jun 3 02:44:38 2002 +++ linux-2.5/drivers/input/gameport/Config.in Sat Mar 23 22:53:44 2002 @@ -13,7 +13,7 @@ dep_tristate ' Classic ISA and PnP gameport support' CONFIG_GAMEPORT_NS558 $CONFIG_GAMEPORT dep_tristate ' PDPI Lightning 4 gamecard support' CONFIG_GAMEPORT_L4 $CONFIG_GAMEPORT -dep_tristate ' SB Live and Audigy gameport support' CONFIG_INPUT_EMU10K1 $CONFIG_GAMEPORT -dep_tristate ' Aureal Vortex, Vortex 2 and Trident 4DWave NX/DX gameport support' CONFIG_GAMEPORT_PCIGAME $CONFIG_GAMEPORT +dep_tristate ' SB Live and Audigy gameport support' CONFIG_GAMEPORT_EMU10K1 $CONFIG_GAMEPORT +dep_tristate ' Aureal Vortex and Vortex 2 gameport support' CONFIG_GAMEPORT_VORTEX $CONFIG_GAMEPORT dep_tristate ' ForteMedia FM801 gameport support' CONFIG_GAMEPORT_FM801 $CONFIG_GAMEPORT -dep_tristate ' Crystal SoundFusion gameport support' CONFIG_GAMEPORT_CS461x $CONFIG_GAMEPORT +dep_tristate ' Crystal SoundFusion gameport support' CONFIG_GAMEPORT_CS461X $CONFIG_GAMEPORT diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/gameport/Makefile linux-2.5/drivers/input/gameport/Makefile --- linux-2.5.20/drivers/input/gameport/Makefile Mon Jun 3 02:44:38 2002 +++ linux-2.5/drivers/input/gameport/Makefile Sat Jun 1 00:34:35 2002 @@ -11,9 +11,10 @@ obj-$(CONFIG_GAMEPORT) += gameport.o obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o +obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o obj-$(CONFIG_GAMEPORT_L4) += lightning.o obj-$(CONFIG_GAMEPORT_NS558) += ns558.o -obj-$(CONFIG_GAMEPORT_PCIGAME) += pcigame.o +obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/gameport/fm801-gp.c linux-2.5/drivers/input/gameport/fm801-gp.c --- linux-2.5.20/drivers/input/gameport/fm801-gp.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/gameport/fm801-gp.c Sun Jan 20 17:11:45 2002 @@ -0,0 +1,162 @@ +/* + * FM801 gameport driver for Linux + * + * Copyright (c) by Takashi Iwai + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCI_VENDOR_ID_FORTEMEDIA 0x1319 +#define PCI_DEVICE_ID_FM801_GP 0x0802 + +#define HAVE_COOKED + +struct fm801_gp { + struct gameport gameport; + struct resource *res_port; + char phys[32]; + char name[32]; +}; + +#ifdef HAVE_COOKED +static int fm801_gp_cooked_read(struct gameport *gameport, int *axes, int *buttons) +{ + unsigned short w; + + w = inw(gameport->io + 2); + *buttons = (~w >> 14) & 0x03; + axes[0] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); + w = inw(gameport->io + 4); + axes[1] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); + w = inw(gameport->io + 6); + *buttons |= ((~w >> 14) & 0x03) << 2; + axes[2] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); + w = inw(gameport->io + 8); + axes[3] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); + outw(0xff, gameport->io); /* reset */ + + return 0; +} +#endif + +static int fm801_gp_open(struct gameport *gameport, int mode) +{ + switch (mode) { +#ifdef HAVE_COOKED + case GAMEPORT_MODE_COOKED: + return 0; +#endif + case GAMEPORT_MODE_RAW: + return 0; + default: + return -1; + } + + return 0; +} + +static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id) +{ + struct fm801_gp *gp; + + if (! (gp = kmalloc(sizeof(*gp), GFP_KERNEL))) { + printk("cannot malloc for fm801-gp\n"); + return -1; + } + memset(gp, 0, sizeof(*gp)); + + gp->gameport.open = fm801_gp_open; +#ifdef HAVE_COOKED + gp->gameport.cooked_read = fm801_gp_cooked_read; +#endif + + pci_enable_device(pci); + gp->gameport.io = pci_resource_start(pci, 0); + if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) { + kfree(gp); + printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f); + return -1; + } + + gp->gameport.phys = gp->phys; + gp->gameport.name = gp->name; + gp->gameport.idbus = BUS_PCI; + gp->gameport.idvendor = pci->vendor; + gp->gameport.idproduct = pci->device; + + pci_set_drvdata(pci, gp); + + outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */ + + gameport_register_port(&gp->gameport); + + printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n", + pci->name, pci->slot_name, gp->gameport.speed); + + return 0; +} + +static void __devexit fm801_gp_remove(struct pci_dev *pci) +{ + struct fm801_gp *gp = pci_get_drvdata(pci); + if (gp) { + gameport_unregister_port(&gp->gameport); + release_resource(gp->res_port); + kfree(gp); + } +} + +static struct pci_device_id fm801_gp_id_table[] __devinitdata = { + { PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; + +static struct pci_driver fm801_gp_driver = { + name: "FM801 GP", + id_table: fm801_gp_id_table, + probe: fm801_gp_probe, + remove: fm801_gp_remove, +}; + +int __init fm801_gp_init(void) +{ + return pci_module_init(&fm801_gp_driver); +} + +void __exit fm801_gp_exit(void) +{ + pci_unregister_driver(&fm801_gp_driver); +} + +module_init(fm801_gp_init); +module_exit(fm801_gp_exit); + +MODULE_DEVICE_TABLE(pci, fm801_gp_id_table); + +MODULE_AUTHOR("Takashi Iwai "); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/gameport/ns558.c linux-2.5/drivers/input/gameport/ns558.c --- linux-2.5.20/drivers/input/gameport/ns558.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/input/gameport/ns558.c Tue Jan 22 17:43:42 2002 @@ -1,5 +1,5 @@ /* - * $Id: ns558.c,v 1.43 2002/01/24 19:23:21 vojtech Exp $ + * $Id: ns558.c,v 1.41 2001/12/26 21:08:33 jsimmons Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * Copyright (c) 1999 Brian Gerst @@ -145,6 +145,9 @@ port->gameport.phys = port->phys; port->gameport.name = port->name; port->gameport.idbus = BUS_ISA; + port->gameport.idvendor = 0x0000; + port->gameport.idproduct = 0x0000; + port->gameport.idversion = 0x0000; sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i)); sprintf(port->name, "NS558 ISA"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/gameport/pcigame.c linux-2.5/drivers/input/gameport/pcigame.c --- linux-2.5.20/drivers/input/gameport/pcigame.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/input/gameport/pcigame.c Thu Jan 1 01:00:00 1970 @@ -1,199 +0,0 @@ -/* - * $Id: pcigame.c,v 1.10 2001/04/26 10:24:46 vojtech Exp $ - * - * Copyright (c) 2000-2001 Vojtech Pavlik - * - * Based on the work of: - * Raymond Ingles - * - * Sponsored by SuSE - */ - -/* - * Trident 4DWave and Aureal Vortex gameport driver for Linux - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PCI_VENDOR_ID_AUREAL 0x12eb - -#define PCIGAME_DATA_WAIT 20 /* 20 ms */ - -#define PCIGAME_4DWAVE 0 -#define PCIGAME_VORTEX 1 -#define PCIGAME_VORTEX2 2 - -struct pcigame_data { - int gcr; /* Gameport control register */ - int legacy; /* Legacy port location */ - int axes; /* Axes start */ - int axsize; /* Axis field size */ - int axmax; /* Axis field max value */ - int adcmode; /* Value to enable ADC mode in GCR */ -}; - -static struct pcigame_data pcigame_data[] __devinitdata = -{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 }, - { 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 }, - { 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 }, - { 0 }}; - -struct pcigame { - struct gameport gameport; - struct pci_dev *dev; - unsigned char *base; - struct pcigame_data *data; -}; - -static unsigned char pcigame_read(struct gameport *gameport) -{ - struct pcigame *pcigame = gameport->private; - return readb(pcigame->base + pcigame->data->legacy); -} - -static void pcigame_trigger(struct gameport *gameport) -{ - struct pcigame *pcigame = gameport->private; - writeb(0xff, pcigame->base + pcigame->data->legacy); -} - -static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons) -{ - struct pcigame *pcigame = gameport->private; - int i; - - *buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf; - - for (i = 0; i < 4; i++) { - axes[i] = readw(pcigame->base + pcigame->data->axes + i * pcigame->data->axsize); - if (axes[i] == pcigame->data->axmax) axes[i] = -1; - } - - return 0; -} - -static int pcigame_open(struct gameport *gameport, int mode) -{ - struct pcigame *pcigame = gameport->private; - - switch (mode) { - case GAMEPORT_MODE_COOKED: - writeb(pcigame->data->adcmode, pcigame->base + pcigame->data->gcr); - wait_ms(PCIGAME_DATA_WAIT); - return 0; - case GAMEPORT_MODE_RAW: - writeb(0, pcigame->base + pcigame->data->gcr); - return 0; - default: - return -1; - } - - return 0; -} - -static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct pcigame *pcigame; - int i; - - if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL))) - return -1; - memset(pcigame, 0, sizeof(struct pcigame)); - - - pcigame->data = pcigame_data + id->driver_data; - - pcigame->dev = dev; - pci_set_drvdata(dev, pcigame); - - pcigame->gameport.private = pcigame; - pcigame->gameport.fuzz = 64; - - pcigame->gameport.read = pcigame_read; - pcigame->gameport.trigger = pcigame_trigger; - pcigame->gameport.cooked_read = pcigame_cooked_read; - pcigame->gameport.open = pcigame_open; - - for (i = 0; i < 6; i++) - if (~pci_resource_flags(dev, i) & IORESOURCE_IO) - break; - - pci_enable_device(dev); - - pcigame->base = ioremap(pci_resource_start(pcigame->dev, i), - pci_resource_len(pcigame->dev, i)); - - gameport_register_port(&pcigame->gameport); - - printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n", - pcigame->gameport.number, dev->name, dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed); - - return 0; -} - -static void __devexit pcigame_remove(struct pci_dev *dev) -{ - struct pcigame *pcigame = pci_get_drvdata(dev); - gameport_unregister_port(&pcigame->gameport); - iounmap(pcigame->base); - kfree(pcigame); -} - -static struct pci_device_id pcigame_id_table[] __devinitdata = -{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE }, - { PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE }, - { PCI_VENDOR_ID_AUREAL, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX }, - { PCI_VENDOR_ID_AUREAL, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 }, - { 0 }}; - -static struct pci_driver pcigame_driver = { - name: "pcigame", - id_table: pcigame_id_table, - probe: pcigame_probe, - remove: __devexit_p(pcigame_remove), -}; - -int __init pcigame_init(void) -{ - return pci_module_init(&pcigame_driver); -} - -void __exit pcigame_exit(void) -{ - pci_unregister_driver(&pcigame_driver); -} - -module_init(pcigame_init); -module_exit(pcigame_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/gameport/vortex.c linux-2.5/drivers/input/gameport/vortex.c --- linux-2.5.20/drivers/input/gameport/vortex.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/gameport/vortex.c Tue Jan 22 17:52:50 2002 @@ -0,0 +1,185 @@ +/* + * $Id: vortex.c,v 1.1 2002/01/03 15:33:39 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Raymond Ingles + */ + +/* + * Trident 4DWave and Aureal Vortex gameport driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver"); +MODULE_LICENSE("GPL"); + +#define VORTEX_GCR 0x0c /* Gameport control register */ +#define VORTEX_LEG 0x08 /* Legacy port location */ +#define VORTEX_AXD 0x10 /* Axes start */ +#define VORTEX_DATA_WAIT 20 /* 20 ms */ + +struct vortex { + struct gameport gameport; + struct pci_dev *dev; + unsigned char *base; + unsigned char *io; + char phys[32]; +}; + +static unsigned char vortex_read(struct gameport *gameport) +{ + struct vortex *vortex = gameport->driver; + return readb(vortex->io + VORTEX_LEG); +} + +static void vortex_trigger(struct gameport *gameport) +{ + struct vortex *vortex = gameport->driver; + writeb(0xff, vortex->io + VORTEX_LEG); +} + +static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons) +{ + struct vortex *vortex = gameport->driver; + int i; + + *buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf; + + for (i = 0; i < 4; i++) { + axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32)); + if (axes[i] == 0x1fff) axes[i] = -1; + } + + return 0; +} + +static int vortex_open(struct gameport *gameport, int mode) +{ + struct vortex *vortex = gameport->driver; + + switch (mode) { + case GAMEPORT_MODE_COOKED: + writeb(0x40, vortex->io + VORTEX_GCR); + wait_ms(VORTEX_DATA_WAIT); + return 0; + case GAMEPORT_MODE_RAW: + writeb(0x00, vortex->io + VORTEX_GCR); + return 0; + default: + return -1; + } + + return 0; +} + +static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct vortex *vortex; + int i; + + if (!(vortex = kmalloc(sizeof(struct vortex), GFP_KERNEL))) + return -1; + memset(vortex, 0, sizeof(struct vortex)); + + vortex->dev = dev; + sprintf(vortex->phys, "pci%s/gameport0", dev->slot_name); + + dev->driver_data = vortex; + + vortex->gameport.driver = vortex; + vortex->gameport.fuzz = 64; + + vortex->gameport.read = vortex_read; + vortex->gameport.trigger = vortex_trigger; + vortex->gameport.cooked_read = vortex_cooked_read; + vortex->gameport.open = vortex_open; + + vortex->gameport.name = dev->name; + vortex->gameport.phys = vortex->phys; + vortex->gameport.idbus = BUS_PCI; + vortex->gameport.idvendor = dev->vendor; + vortex->gameport.idproduct = dev->device; + + for (i = 0; i < 6; i++) + if (~pci_resource_flags(dev, i) & IORESOURCE_IO) + break; + + pci_enable_device(dev); + + vortex->base = ioremap(pci_resource_start(vortex->dev, i), + pci_resource_len(vortex->dev, i)); + vortex->io = vortex->base + id->driver_data; + + gameport_register_port(&vortex->gameport); + + printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n", + dev->name, dev->slot_name, vortex->gameport.speed); + + return 0; +} + +static void __devexit vortex_remove(struct pci_dev *dev) +{ + struct vortex *vortex = dev->driver_data; + gameport_unregister_port(&vortex->gameport); + iounmap(vortex->base); + kfree(vortex); +} + +static struct pci_device_id vortex_id_table[] __devinitdata = +{{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 }, + { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 }, + { 0 }}; + +static struct pci_driver vortex_driver = { + name: "vortex", + id_table: vortex_id_table, + probe: vortex_probe, + remove: vortex_remove, +}; + +int __init vortex_init(void) +{ + return pci_module_init(&vortex_driver); +} + +void __exit vortex_exit(void) +{ + pci_unregister_driver(&vortex_driver); +} + +module_init(vortex_init); +module_exit(vortex_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/input.c linux-2.5/drivers/input/input.c --- linux-2.5.20/drivers/input/input.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/input/input.c Fri Jan 25 19:43:55 2002 @@ -61,8 +61,6 @@ static struct input_handler *input_handler; static struct input_handler *input_table[8]; static devfs_handle_t input_devfs_handle; -static int input_number; -static long input_devices[NBITS(INPUT_DEVICES)]; #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_bus_input_dir; @@ -454,17 +452,8 @@ * Add the device. */ - if (input_number >= INPUT_DEVICES) { - printk(KERN_WARNING "input: ran out of input device numbers!\n"); - dev->number = input_number; - } else { - dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES); - set_bit(dev->number, input_devices); - } - dev->next = input_dev; input_dev = dev; - input_number++; /* * Notify handlers. @@ -493,7 +482,6 @@ input_devices_state++; wake_up(&input_devices_poll_wait); #endif - } void input_unregister_device(struct input_dev *dev) @@ -509,7 +497,6 @@ if (dev->pm_dev) pm_unregister(dev->pm_dev); - /* * Kill any pending repeat timers. */ @@ -540,7 +527,6 @@ */ input_find_and_remove(struct input_dev, input_dev, dev, next); - input_number--; /* * Notify /proc. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/Config.help linux-2.5/drivers/input/joystick/Config.help --- linux-2.5.20/drivers/input/joystick/Config.help Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/input/joystick/Config.help Sun Jan 27 00:32:29 2002 @@ -67,6 +67,15 @@ The module will be called grip.o. If you want to compile it as a module, say M here and read . +CONFIG_JOYSTICK_GUILLEMOT + Say Y here if you have a Guillemot joystick using a digital + protocol over the PC gameport. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called guillemot.o. If you want to compile it as a + module, say M here and read . + CONFIG_JOYSTICK_INTERACT Say Y here if you have an InterAct gameport or joystick communicating digitally over the gameport. @@ -156,6 +165,15 @@ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called stinger.o. If you want to compile it as a + module, say M here and read . + +CONFIG_JOYSTICK_TWIDDLER + Say Y here if you have a Handykey Twiddler connected to your + computer's serial port and want to use it as a joystick. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called twidjoy.o. If you want to compile it as a module, say M here and read . CONFIG_JOYSTICK_DB9 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/Config.in linux-2.5/drivers/input/joystick/Config.in --- linux-2.5.20/drivers/input/joystick/Config.in Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/input/joystick/Config.in Sun Jan 20 17:11:45 2002 @@ -10,6 +10,7 @@ dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_JOYSTICK_COBRA $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_JOYSTICK_GF2K $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOYSTICK_GRIP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT +dep_tristate ' Guillemot joysticks and gamepads' CONFIG_JOYSTICK_GUILLEMOT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_JOYSTICK_INTERACT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_JOYSTICK_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOYSTICK_TMDC $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT @@ -21,6 +22,7 @@ dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controllers' CONFIG_JOYSTICK_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' SpaceTec SpaceBall 6dof controllers' CONFIG_JOYSTICK_SPACEBALL $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' Gravis Stinger gamepad' CONFIG_JOYSTICK_STINGER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO +dep_tristate ' Twiddler as as joystick' CONFIG_JOYSTICK_TWIDDLER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_JOYSTICK_DB9 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_JOYSTICK_GAMECON $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/Makefile linux-2.5/drivers/input/joystick/Makefile --- linux-2.5.20/drivers/input/joystick/Makefile Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/input/joystick/Makefile Sat May 25 19:03:28 2002 @@ -2,24 +2,6 @@ # Makefile for the input core drivers. # -# I-Force may need both USB and RS-232 - -CONFIG_JOYSTICK_IFORCE := n - -ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) - ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) - CONFIG_JOYSTICK_IFORCE := y - endif -endif - -ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m) - CONFIG_JOYSTICK_IFORCE := m -endif - -ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m) - CONFIG_JOYSTICK_IFORCE := m -endif - # Each configuration option enables a list of files. obj-$(CONFIG_JOYSTICK_A3D) += a3d.o @@ -31,8 +13,9 @@ obj-$(CONFIG_JOYSTICK_GAMECON) += gamecon.o obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o obj-$(CONFIG_JOYSTICK_GRIP) += grip.o -obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o +obj-$(CONFIG_JOYSTICK_GUILLEMOT) += guillemot.o obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o +obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o @@ -40,7 +23,32 @@ obj-$(CONFIG_JOYSTICK_STINGER) += stinger.o obj-$(CONFIG_JOYSTICK_TMDC) += tmdc.o obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o +obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o + +# I-Force may need both USB and RS-232 + +CONFIG_JOYSTICK_IFORCE := n + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) + ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) + CONFIG_JOYSTICK_IFORCE := y + endif +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m) + CONFIG_JOYSTICK_IFORCE := m +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m) + CONFIG_JOYSTICK_IFORCE := m +endif + +subdir-$(CONFIG_JOYSTICK_IFORCE) += iforce + +ifeq ($(CONFIG_JOYSTICK_IFORCE),y) + obj-y += iforce/iforce-drv.o +endif # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/guillemot.c linux-2.5/drivers/input/joystick/guillemot.c --- linux-2.5.20/drivers/input/joystick/guillemot.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/guillemot.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,285 @@ +/* + * $Id: guillemot.c,v 1.9 2001/12/10 17:01:44 vojtech Exp $ + * + * Copyright (c) 2001 Vojtech Pavlik + */ + +/* + * Guillemot Digital Interface Protocol driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Guillemot Digital joystick driver"); +MODULE_LICENSE("GPL"); + +#define GUILLEMOT_MAX_START 600 /* 600 us */ +#define GUILLEMOT_MAX_STROBE 60 /* 60 us */ +#define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */ +#define GUILLEMOT_REFRESH_TIME HZ/50 /* 20 ms */ + +static short guillemot_abs_pad[] = + { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 }; + +static short guillemot_btn_pad[] = + { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 }; + +static struct { + int x; + int y; +} guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + +struct guillemot_type { + unsigned char id; + short *abs; + short *btn; + int hat; + char *name; +}; + +struct guillemot { + struct gameport *gameport; + struct input_dev dev; + struct timer_list timer; + int used; + int bads; + int reads; + struct guillemot_type *type; + unsigned char length; + char phys[32]; +}; + +static struct guillemot_type guillemot_type[] = { + { 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" }, + { 0 }}; + +/* + * guillemot_read_packet() reads Guillemot joystick data. + */ + +static int guillemot_read_packet(struct gameport *gameport, u8 *data) +{ + unsigned long flags; + unsigned char u, v; + unsigned int t, s; + int i; + + for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++) + data[i] = 0; + + i = 0; + t = gameport_time(gameport, GUILLEMOT_MAX_START); + s = gameport_time(gameport, GUILLEMOT_MAX_STROBE); + + __save_flags(flags); + __cli(); + gameport_trigger(gameport); + v = gameport_read(gameport); + + while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) { + t--; + u = v; v = gameport_read(gameport); + if (v & ~u & 0x10) { + data[i >> 3] |= ((v >> 5) & 1) << (i & 7); + i++; + t = s; + } + } + + __restore_flags(flags); + + return i; +} + +/* + * guillemot_timer() reads and analyzes Guillemot joystick data. + */ + +static void guillemot_timer(unsigned long private) +{ + struct guillemot *guillemot = (struct guillemot *) private; + struct input_dev *dev = &guillemot->dev; + u8 data[GUILLEMOT_MAX_LENGTH]; + int i; + + guillemot->reads++; + + if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 || + data[0] != 0x55 || data[16] != 0xaa) { + guillemot->bads++; + } else { + + for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++) + input_report_abs(dev, guillemot->type->abs[i], data[i + 5]); + + if (guillemot->type->hat) { + input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y); + } + + for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++) + input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1); + } + + mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME); +} + +/* + * guillemot_open() is a callback from the input open routine. + */ + +static int guillemot_open(struct input_dev *dev) +{ + struct guillemot *guillemot = dev->private; + if (!guillemot->used++) + mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME); + return 0; +} + +/* + * guillemot_close() is a callback from the input close routine. + */ + +static void guillemot_close(struct input_dev *dev) +{ + struct guillemot *guillemot = dev->private; + if (!--guillemot->used) + del_timer(&guillemot->timer); +} + +/* + * guillemot_connect() probes for Guillemot joysticks. + */ + +static void guillemot_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct guillemot *guillemot; + u8 data[GUILLEMOT_MAX_LENGTH]; + int i, t; + + if (!(guillemot = kmalloc(sizeof(struct guillemot), GFP_KERNEL))) + return; + memset(guillemot, 0, sizeof(struct guillemot)); + + gameport->private = guillemot; + + guillemot->gameport = gameport; + init_timer(&guillemot->timer); + guillemot->timer.data = (long) guillemot; + guillemot->timer.function = guillemot_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + goto fail1; + + i = guillemot_read_packet(gameport, data); + + if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa) + goto fail2; + + for (i = 0; guillemot_type[i].name; i++) + if (guillemot_type[i].id == data[11]) + break; + + if (!guillemot_type[i].name) { + printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n", + gameport->phys, data[12], data[13], data[11], data[14], data[15]); + goto fail2; + } + + sprintf(guillemot->phys, "%s/input0", gameport->phys); + + guillemot->type = guillemot_type + i; + + guillemot->dev.private = guillemot; + guillemot->dev.open = guillemot_open; + guillemot->dev.close = guillemot_close; + + guillemot->dev.name = guillemot_type[i].name; + guillemot->dev.phys = guillemot->phys; + guillemot->dev.idbus = BUS_GAMEPORT; + guillemot->dev.idvendor = GAMEPORT_ID_VENDOR_GUILLEMOT; + guillemot->dev.idproduct = guillemot_type[i].id; + guillemot->dev.idversion = (int)data[14] << 8 | data[15]; + + guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) { + set_bit(t, guillemot->dev.absbit); + guillemot->dev.absmin[t] = 0; + guillemot->dev.absmax[t] = 255; + } + + if (guillemot->type->hat) + for (i = 0; i < 2; i++) { + t = ABS_HAT0X + i; + set_bit(t, guillemot->dev.absbit); + guillemot->dev.absmin[t] = -1; + guillemot->dev.absmax[t] = 1; + } + + for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++) + set_bit(t, guillemot->dev.keybit); + + input_register_device(&guillemot->dev); + printk(KERN_INFO "input: %s ver %d.%02d on %s\n", + guillemot->type->name, data[14], data[15], gameport->phys); + + return; +fail2: gameport_close(gameport); +fail1: kfree(guillemot); +} + +static void guillemot_disconnect(struct gameport *gameport) +{ + struct guillemot *guillemot = gameport->private; + printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys); + input_unregister_device(&guillemot->dev); + gameport_close(gameport); + kfree(guillemot); +} + +static struct gameport_dev guillemot_dev = { + connect: guillemot_connect, + disconnect: guillemot_disconnect, +}; + +int __init guillemot_init(void) +{ + gameport_register_device(&guillemot_dev); + return 0; +} + +void __exit guillemot_exit(void) +{ + gameport_unregister_device(&guillemot_dev); +} + +module_init(guillemot_init); +module_exit(guillemot_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/iforce/Makefile linux-2.5/drivers/input/joystick/iforce/Makefile --- linux-2.5.20/drivers/input/joystick/iforce/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/Makefile Sun Feb 3 18:03:58 2002 @@ -0,0 +1,41 @@ +# +# Makefile for the I-Force driver +# + +O_TARGET := iforce-drv.o + +# I-Force may need both USB and RS-232 + +CONFIG_JOYSTICK_IFORCE := n + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) + ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) + CONFIG_JOYSTICK_IFORCE := y + endif +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m) + CONFIG_JOYSTICK_IFORCE := m +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m) + CONFIG_JOYSTICK_IFORCE := m +endif + +obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o + +include $(TOPDIR)/Rules.make + +IFORCEOBJS = iforce-ff.o iforce-main.o iforce-packets.o + +ifneq ($(CONFIG_JOYSTICK_IFORCE_232),) + IFORCEOBJS += iforce-serio.o +endif + +ifneq ($(CONFIG_JOYSTICK_IFORCE_USB),) + IFORCEOBJS += iforce-usb.o +endif + +iforce.o: $(IFORCEOBJS) + $(LD) -i $(IFORCEOBJS) -o $@ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/iforce/iforce-ff.c linux-2.5/drivers/input/joystick/iforce/iforce-ff.c --- linux-2.5.20/drivers/input/joystick/iforce/iforce-ff.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce-ff.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,563 @@ +/* + * $Id: iforce-ff.c,v 1.6 2001/11/10 09:45:09 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +/* + * Set the magnitude of a constant force effect + * Return error code + * + * Note: caller must ensure exclusive access to device + */ + +static int make_magnitude_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, __s16 level) +{ + unsigned char data[3]; + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + data[2] = HIFIX80(level); + + iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data); + + iforce_dump_packet("magnitude: ", FF_CMD_MAGNITUDE, data); + return 0; +} + +/* + * Upload the component of an effect dealing with the period, phase and magnitude + */ + +static int make_period_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, + __s16 magnitude, __s16 offset, u16 period, u16 phase) +{ + unsigned char data[7]; + + period = TIME_SCALE(period); + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + + data[2] = HIFIX80(magnitude); + data[3] = HIFIX80(offset); + data[4] = HI(phase); + + data[5] = LO(period); + data[6] = HI(period); + + iforce_send_packet(iforce, FF_CMD_PERIOD, data); + + return 0; +} + +/* + * Uploads the part of an effect setting the shape of the force + */ + +static int make_shape_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, + u16 attack_duration, __s16 initial_level, + u16 fade_duration, __s16 final_level) +{ + unsigned char data[8]; + + attack_duration = TIME_SCALE(attack_duration); + fade_duration = TIME_SCALE(fade_duration); + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + + data[2] = LO(attack_duration); + data[3] = HI(attack_duration); + data[4] = HI(initial_level); + + data[5] = LO(fade_duration); + data[6] = HI(fade_duration); + data[7] = HI(final_level); + + iforce_send_packet(iforce, FF_CMD_SHAPE, data); + + return 0; +} + +/* + * Component of spring, friction, inertia... effects + */ + +static int make_interactive_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, + __u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) +{ + unsigned char data[10]; + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + + data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ + data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */ + + center = (500*center)>>15; + data[4] = LO(center); + data[5] = HI(center); + + db = (1000*db)>>16; + data[6] = LO(db); + data[7] = HI(db); + + data[8] = (100*rsat)>>16; + data[9] = (100*lsat)>>16; + + iforce_send_packet(iforce, FF_CMD_INTERACT, data); + iforce_dump_packet("interactive", FF_CMD_INTERACT, data); + + return 0; +} + +static unsigned char find_button(struct iforce *iforce, signed short button) +{ + int i; + for (i = 1; iforce->type->btn[i] >= 0; i++) + if (iforce->type->btn[i] == button) + return i + 1; + return 0; +} + +/* + * Analyse the changes in an effect, and tell if we need to send an interactive + * parameter packet + */ +static int need_interactive_modifier(struct iforce* iforce, struct ff_effect* new) +{ + int id = new->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (new->type != FF_SPRING && new->type != FF_FRICTION) { + printk(KERN_WARNING "iforce.c: bad effect type in need_interactive_modifier\n"); + return FALSE; + } + + return (old->u.interactive.right_saturation != new->u.interactive.right_saturation + || old->u.interactive.left_saturation != new->u.interactive.left_saturation + || old->u.interactive.right_coeff != new->u.interactive.right_coeff + || old->u.interactive.left_coeff != new->u.interactive.left_coeff + || old->u.interactive.deadband != new->u.interactive.deadband + || old->u.interactive.center != new->u.interactive.center); +} + +/* + * Analyse the changes in an effect, and tell if we need to send a magnitude + * parameter packet + */ +static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect) +{ + int id = effect->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (effect->type != FF_CONSTANT) { + printk(KERN_WARNING "iforce.c: bad effect type in need_shape_modifier\n"); + return FALSE; + } + + return (old->u.constant.level != effect->u.constant.level); +} + +/* + * Analyse the changes in an effect, and tell if we need to send a shape + * parameter packet + */ +static int need_shape_modifier(struct iforce* iforce, struct ff_effect* effect) +{ + int id = effect->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + switch (effect->type) { + case FF_CONSTANT: + if (old->u.constant.shape.attack_length != effect->u.constant.shape.attack_length + || old->u.constant.shape.attack_level != effect->u.constant.shape.attack_level + || old->u.constant.shape.fade_length != effect->u.constant.shape.fade_length + || old->u.constant.shape.fade_level != effect->u.constant.shape.fade_level) + return TRUE; + break; + + case FF_PERIODIC: + if (old->u.periodic.shape.attack_length != effect->u.periodic.shape.attack_length + || old->u.periodic.shape.attack_level != effect->u.periodic.shape.attack_level + || old->u.periodic.shape.fade_length != effect->u.periodic.shape.fade_length + || old->u.periodic.shape.fade_level != effect->u.periodic.shape.fade_level) + return TRUE; + break; + + default: + printk(KERN_WARNING "iforce.c: bad effect type in need_shape_modifier\n"); + } + + return FALSE; +} + +/* + * Analyse the changes in an effect, and tell if we need to send a periodic + * parameter effect + */ +static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) +{ + int id = new->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (new->type != FF_PERIODIC) { + printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n"); + return FALSE; + } + + return (old->u.periodic.period != new->u.periodic.period + || old->u.periodic.magnitude != new->u.periodic.magnitude + || old->u.periodic.offset != new->u.periodic.offset + || old->u.periodic.phase != new->u.periodic.phase); +} + +/* + * Analyse the changes in an effect, and tell if we need to send an effect + * packet + */ +static int need_core(struct iforce* iforce, struct ff_effect* new) +{ + int id = new->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (old->direction != new->direction + || old->trigger.button != new->trigger.button + || old->trigger.interval != new->trigger.interval + || old->replay.length != new->replay.length + || old->replay.delay != new->replay.delay) + return TRUE; + + return FALSE; +} +/* + * Send the part common to all effects to the device + */ +static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, + u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, + u16 interval, u16 direction) +{ + unsigned char data[14]; + + duration = TIME_SCALE(duration); + delay = TIME_SCALE(delay); + interval = TIME_SCALE(interval); + + data[0] = LO(id); + data[1] = effect_type; + data[2] = LO(axes) | find_button(iforce, button); + + data[3] = LO(duration); + data[4] = HI(duration); + + data[5] = HI(direction); + + data[6] = LO(interval); + data[7] = HI(interval); + + data[8] = LO(mod_id1); + data[9] = HI(mod_id1); + data[10] = LO(mod_id2); + data[11] = HI(mod_id2); + + data[12] = LO(delay); + data[13] = HI(delay); + + /* Stop effect */ +/* iforce_control_playback(iforce, id, 0);*/ + + iforce_send_packet(iforce, FF_CMD_EFFECT, data); + + /* If needed, restart effect */ + if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) { + /* BUG: perhaps we should replay n times, instead of 1. But we do not know n */ + iforce_control_playback(iforce, id, 1); + } + + return 0; +} + +/* + * Upload a periodic effect to the device + * See also iforce_upload_constant. + */ +int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update) +{ + u8 wave_code; + int core_id = effect->id; + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; + struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); + struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); + int param1_err = 1; + int param2_err = 1; + int core_err = 0; + + if (!is_update || need_period_modifier(iforce, effect)) { + param1_err = make_period_modifier(iforce, mod1_chunk, + is_update, + effect->u.periodic.magnitude, effect->u.periodic.offset, + effect->u.periodic.period, effect->u.periodic.phase); + if (param1_err) return param1_err; + set_bit(FF_MOD1_IS_USED, core_effect->flags); + } + + if (!is_update || need_shape_modifier(iforce, effect)) { + param2_err = make_shape_modifier(iforce, mod2_chunk, + is_update, + effect->u.periodic.shape.attack_length, + effect->u.periodic.shape.attack_level, + effect->u.periodic.shape.fade_length, + effect->u.periodic.shape.fade_level); + if (param2_err) return param2_err; + set_bit(FF_MOD2_IS_USED, core_effect->flags); + } + + switch (effect->u.periodic.waveform) { + case FF_SQUARE: wave_code = 0x20; break; + case FF_TRIANGLE: wave_code = 0x21; break; + case FF_SINE: wave_code = 0x22; break; + case FF_SAW_UP: wave_code = 0x23; break; + case FF_SAW_DOWN: wave_code = 0x24; break; + default: wave_code = 0x20; break; + } + + if (!is_update || need_core(iforce, effect)) { + core_err = make_core(iforce, effect->id, + mod1_chunk->start, + mod2_chunk->start, + wave_code, + 0x20, + effect->replay.length, + effect->replay.delay, + effect->trigger.button, + effect->trigger.interval, + effect->direction); + } + + /* If one of the parameter creation failed, we already returned an + * error code. + * If the core creation failed, we return its error code. + * Else: if one parameter at least was created, we return 0 + * else we return 1; + */ + return core_err < 0 ? core_err : (param1_err && param2_err); +} + +/* + * Upload a constant force effect + * Return value: + * <0 Error code + * 0 Ok, effect created or updated + * 1 effect did not change since last upload, and no packet was therefore sent + */ +int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update) +{ + int core_id = effect->id; + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; + struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); + struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); + int param1_err = 1; + int param2_err = 1; + int core_err = 0; + + if (!is_update || need_magnitude_modifier(iforce, effect)) { + param1_err = make_magnitude_modifier(iforce, mod1_chunk, + is_update, + effect->u.constant.level); + if (param1_err) return param1_err; + set_bit(FF_MOD1_IS_USED, core_effect->flags); + } + + if (!is_update || need_shape_modifier(iforce, effect)) { + param2_err = make_shape_modifier(iforce, mod2_chunk, + is_update, + effect->u.constant.shape.attack_length, + effect->u.constant.shape.attack_level, + effect->u.constant.shape.fade_length, + effect->u.constant.shape.fade_level); + if (param2_err) return param2_err; + set_bit(FF_MOD2_IS_USED, core_effect->flags); + } + + if (!is_update || need_core(iforce, effect)) { + core_err = make_core(iforce, effect->id, + mod1_chunk->start, + mod2_chunk->start, + 0x00, + 0x20, + effect->replay.length, + effect->replay.delay, + effect->trigger.button, + effect->trigger.interval, + effect->direction); + } + + /* If one of the parameter creation failed, we already returned an + * error code. + * If the core creation failed, we return its error code. + * Else: if one parameter at least was created, we return 0 + * else we return 1; + */ + return core_err < 0 ? core_err : (param1_err && param2_err); +} + +/* + * Upload an interactive effect. Those are for example friction, inertia, springs... + */ +int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect, int is_update) +{ + int core_id = effect->id; + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; + struct resource* mod_chunk = &(core_effect->mod1_chunk); + u8 type, axes; + u16 mod1, mod2, direction; + int param_err = 1; + int core_err = 0; + + switch (effect->type) { + case FF_SPRING: type = 0x40; break; + case FF_FRICTION: type = 0x41; break; + default: return -1; + } + + if (!is_update || need_interactive_modifier(iforce, effect)) { + param_err = make_interactive_modifier(iforce, mod_chunk, + is_update, + effect->u.interactive.right_saturation, + effect->u.interactive.left_saturation, + effect->u.interactive.right_coeff, + effect->u.interactive.left_coeff, + effect->u.interactive.deadband, + effect->u.interactive.center); + if (param_err) return param_err; + set_bit(FF_MOD1_IS_USED, core_effect->flags); + } + + switch ((test_bit(ABS_X, &effect->u.interactive.axis) || + test_bit(ABS_WHEEL, &effect->u.interactive.axis)) | + (!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) { + + case 0: /* Only one axis, choose orientation */ + mod1 = mod_chunk->start; + mod2 = 0xffff; + direction = effect->direction; + axes = 0x20; + break; + + case 1: /* Only X axis */ + mod1 = mod_chunk->start; + mod2 = 0xffff; + direction = 0x5a00; + axes = 0x40; + break; + + case 2: /* Only Y axis */ + mod1 = 0xffff; + mod2 = mod_chunk->start; + direction = 0xb400; + axes = 0x80; + break; + + case 3: /* Both X and Y axes */ + /* TODO: same setting for both axes is not mandatory */ + mod1 = mod_chunk->start; + mod2 = mod_chunk->start; + direction = 0x6000; + axes = 0xc0; + break; + + default: + return -1; + } + + if (!is_update || need_core(iforce, effect)) { + core_err = make_core(iforce, effect->id, + mod1, mod2, + type, axes, + effect->replay.length, effect->replay.delay, + effect->trigger.button, effect->trigger.interval, + direction); + } + + /* If the parameter creation failed, we already returned an + * error code. + * If the core creation failed, we return its error code. + * Else: if a parameter was created, we return 0 + * else we return 1; + */ + return core_err < 0 ? core_err : param_err; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/iforce/iforce-main.c linux-2.5/drivers/input/joystick/iforce/iforce-main.c --- linux-2.5.20/drivers/input/joystick/iforce/iforce-main.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce-main.c Fri Feb 8 11:04:26 2002 @@ -0,0 +1,494 @@ +/* + * $Id: iforce-main.c,v 1.5 2001/11/10 09:46:19 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); +MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); +MODULE_LICENSE("GPL"); + +static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, + BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 }; +static signed short btn_wheel[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, + BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; +static signed short btn_avb_tw[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, + BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; +static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; +static signed short abs_joystick2[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y, -1 }; +static signed short abs_wheel[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 }; +static signed short ff_iforce[] = { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION, + FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 }; + +static struct iforce_device iforce_device[] = { + { 0x044f, 0xa01c, "Thrustmaster Motor Sport GT", btn_wheel, abs_wheel, ff_iforce }, + { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce }, + { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce }, + { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_joystick, abs_joystick2, ff_iforce }, + { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_wheel, abs_wheel, ff_iforce }, + { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_avb_tw, abs_wheel, ff_iforce }, + { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, + { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, + { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } +}; + + + +static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct iforce* iforce = (struct iforce*)(dev->private); + unsigned char data[3]; + + printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value); + + if (type != EV_FF) + return -1; + + switch (code) { + + case FF_GAIN: + + data[0] = value >> 9; + iforce_send_packet(iforce, FF_CMD_GAIN, data); + + return 0; + + case FF_AUTOCENTER: + + data[0] = 0x03; + data[1] = value >> 9; + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); + + data[0] = 0x04; + data[1] = 0x01; + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); + + return 0; + + default: /* Play or stop an effect */ + + if (!CHECK_OWNERSHIP(code, iforce)) { + return -1; + } + if (value > 0) { + set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); + } + else { + clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); + } + + iforce_control_playback(iforce, code, value); + return 0; + } + + return -1; +} + +/* + * Function called when an ioctl is performed on the event dev entry. + * It uploads an effect to the device + */ +static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) +{ + struct iforce* iforce = (struct iforce*)(dev->private); + int id; + int ret; + int is_update; + +/* + * If we want to create a new effect, get a free id + */ + if (effect->id == -1) { + + for (id=0; id < FF_EFFECTS_MAX; ++id) + if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; + + if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) + return -ENOMEM; + + effect->id = id; + iforce->core_effects[id].owner = current->pid; + iforce->core_effects[id].flags[0] = (1<id, iforce)) return -EACCES; + + /* Parameter type cannot be updated */ + if (effect->type != iforce->core_effects[effect->id].effect.type) + return -EINVAL; + + /* Check the effect is not already being updated */ + if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) { + return -EAGAIN; + } + + is_update = TRUE; + } + +/* + * Upload the effect + */ + switch (effect->type) { + + case FF_PERIODIC: + ret = iforce_upload_periodic(iforce, effect, is_update); + break; + + case FF_CONSTANT: + ret = iforce_upload_constant(iforce, effect, is_update); + break; + + case FF_SPRING: + case FF_FRICTION: + ret = iforce_upload_interactive(iforce, effect, is_update); + break; + + default: + return -EINVAL; + } + if (ret == 0) { + /* A packet was sent, forbid new updates until we are notified + * that the packet was updated + */ + set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags); + } + iforce->core_effects[effect->id].effect = *effect; + return ret; +} + +/* + * Erases an effect: it frees the effect id and mark as unused the memory + * allocated for the parameters + */ +static int iforce_erase_effect(struct input_dev *dev, int effect_id) +{ + struct iforce* iforce = (struct iforce*)(dev->private); + int err = 0; + struct iforce_core_effect* core_effect; + + /* Check who is trying to erase this effect */ + if (iforce->core_effects[effect_id].owner != current->pid) { + printk(KERN_WARNING "iforce.c: %d tried to erase an effect belonging to %d\n", current->pid, iforce->core_effects[effect_id].owner); + return -EACCES; + } + + if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) + return -EINVAL; + + core_effect = iforce->core_effects + effect_id; + + if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) + err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); + + if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) + err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); + + /*TODO: remember to change that if more FF_MOD* bits are added */ + core_effect->flags[0] = 0; + + return err; +} + +static int iforce_open(struct input_dev *dev) +{ + struct iforce *iforce = dev->private; + + switch (iforce->bus) { +#ifdef IFORCE_USB + case IFORCE_USB: + if (iforce->open++) + break; + iforce->irq.dev = iforce->usbdev; + if (usb_submit_urb(&iforce->irq, GFP_KERNEL)) + return -EIO; + break; +#endif + } + + /* Enable force feedback */ + iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); + + return 0; +} + +static int iforce_flush(struct input_dev *dev, struct file *file) +{ + struct iforce *iforce = dev->private; + int i; + + /* Erase all effects this process owns */ + for (i=0; iff_effects_max; ++i) { + + if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && + current->pid == iforce->core_effects[i].owner) { + + /* Stop effect */ + input_report_ff(dev, i, 0); + + /* Free ressources assigned to effect */ + if (iforce_erase_effect(dev, i)) { + printk(KERN_WARNING "iforce_flush: (%s) erase effect %d failed\n", dev->phys, i); + } + } + + } + return 0; +} + +static void iforce_close(struct input_dev *dev) +{ + struct iforce *iforce = dev->private; + + printk(KERN_DEBUG "iforce.c: in iforce_close\n"); + + /* Disable force feedback playback */ + iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); + + + switch (iforce->bus) { +#ifdef IFORCE_USB + case IFORCE_USB: + if (!--iforce->open) + usb_unlink_urb(&iforce->irq); + break; +#endif + } +} + +int iforce_init_device(struct iforce *iforce) +{ + unsigned char c[] = "CEOV"; + char path[64]; + int i; + + init_waitqueue_head(&iforce->wait); + spin_lock_init(&iforce->xmit_lock); + init_MUTEX(&iforce->mem_mutex); + iforce->xmit.buf = iforce->xmit_data; + + iforce->dev.ff_effects_max = 10; + + switch (iforce->bus) { +#ifdef IFORCE_232 + case IFORCE_232: + strcpy(path, iforce->serio->phys); + break; +#endif +#ifdef IFORCE_USB + case IFORCE_USB: + usb_make_path(iforce->usbdev, path, 64); + break; +#endif + } + + sprintf(iforce->phys, "%s/input0", path); + +/* + * Input device fields. + */ + + iforce->dev.idbus = BUS_USB; + iforce->dev.private = iforce; + iforce->dev.name = iforce->phys; + iforce->dev.open = iforce_open; + iforce->dev.close = iforce_close; + iforce->dev.flush = iforce_flush; + iforce->dev.event = iforce_input_event; + iforce->dev.upload_effect = iforce_upload_effect; + iforce->dev.erase_effect = iforce_erase_effect; + +/* + * On-device memory allocation. + */ + + iforce->device_memory.name = "I-Force device effect memory"; + iforce->device_memory.start = 0; + iforce->device_memory.end = 200; + iforce->device_memory.flags = IORESOURCE_MEM; + iforce->device_memory.parent = NULL; + iforce->device_memory.child = NULL; + iforce->device_memory.sibling = NULL; + +/* + * Wait until device ready - until it sends its first response. + */ + + for (i = 0; i < 20; i++) + if (!iforce_get_id_packet(iforce, "O")) + break; + + if (i == 20) { /* 5 seconds */ + printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n"); + iforce_close(&iforce->dev); + return -1; + } + +/* + * Get device info. + */ + + if (!iforce_get_id_packet(iforce, "M")) + iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, "P")) + iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, "B")) + iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, "N")) + iforce->dev.ff_effects_max = iforce->edata[1]; + + /* Check if the device can store more effects than the driver can really handle */ + if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) { + printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.c\n", + iforce->dev.ff_effects_max, FF_EFFECTS_MAX); + iforce->dev.ff_effects_max = FF_EFFECTS_MAX; + } + +/* + * Display additional info. + */ + + for (i = 0; c[i]; i++) + if (!iforce_get_id_packet(iforce, c + i)) + iforce_dump_packet("info", iforce->ecmd, iforce->edata); + +/* + * Disable spring, enable force feedback. + * FIXME: We should use iforce_set_autocenter() et al here. + */ + + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); + +/* + * Find appropriate device entry + */ + + for (i = 0; iforce_device[i].idvendor; i++) + if (iforce_device[i].idvendor == iforce->dev.idvendor && + iforce_device[i].idproduct == iforce->dev.idproduct) + break; + + iforce->type = iforce_device + i; + + sprintf(iforce->name, iforce->type->name, + iforce->dev.idproduct, iforce->dev.idvendor); + +/* + * Set input device bitfields and ranges. + */ + + iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); + + for (i = 0; iforce->type->btn[i] >= 0; i++) { + signed short t = iforce->type->btn[i]; + set_bit(t, iforce->dev.keybit); + if (t != BTN_DEAD) + set_bit(FF_BTN(t), iforce->dev.ffbit); + } + + for (i = 0; iforce->type->abs[i] >= 0; i++) { + + signed short t = iforce->type->abs[i]; + set_bit(t, iforce->dev.absbit); + + switch (t) { + + case ABS_X: + case ABS_Y: + case ABS_WHEEL: + + iforce->dev.absmax[t] = 1920; + iforce->dev.absmin[t] = -1920; + iforce->dev.absflat[t] = 128; + iforce->dev.absfuzz[t] = 16; + + set_bit(FF_ABS(t), iforce->dev.ffbit); + break; + + case ABS_THROTTLE: + case ABS_GAS: + case ABS_BRAKE: + + iforce->dev.absmax[t] = 255; + iforce->dev.absmin[t] = 0; + break; + + case ABS_RUDDER: + iforce->dev.absmax[t] = 127; + iforce->dev.absmin[t] = -128; + break; + + case ABS_HAT0X: + case ABS_HAT0Y: + iforce->dev.absmax[t] = 1; + iforce->dev.absmin[t] = -1; + break; + } + } + + for (i = 0; iforce->type->ff[i] >= 0; i++) + set_bit(iforce->type->ff[i], iforce->dev.ffbit); + +/* + * Register input device. + */ + + input_register_device(&iforce->dev); + + printk(KERN_INFO "input: %s [%d effects, %ld bytes memory] on %s\n", + iforce->dev.name, iforce->dev.ff_effects_max, + iforce->device_memory.end, path); + + return 0; +} + +static int __init iforce_init(void) +{ +#ifdef IFORCE_USB + usb_register(&iforce_usb_driver); +#endif +#ifdef IFORCE_232 + serio_register_device(&iforce_serio_dev); +#endif + return 0; +} + +static void __exit iforce_exit(void) +{ +#ifdef IFORCE_USB + usb_deregister(&iforce_usb_driver); +#endif +#ifdef IFORCE_232 + serio_unregister_device(&iforce_serio_dev); +#endif +} + +module_init(iforce_init); +module_exit(iforce_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/iforce/iforce-packets.c linux-2.5/drivers/input/joystick/iforce/iforce-packets.c --- linux-2.5.20/drivers/input/joystick/iforce/iforce-packets.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce-packets.c Fri Feb 8 11:41:51 2002 @@ -0,0 +1,289 @@ +/* + * $Id: iforce-packets.c,v 1.4 2001/10/28 19:10:24 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +static struct { + __s32 x; + __s32 y; +} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + + +void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) +{ + int i; + + printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); + for (i = 0; i < LO(cmd); i++) + printk("%02x ", data[i]); + printk(")\n"); +} + +/* + * Send a packet of bytes to the device + */ +int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) +{ + /* Copy data to buffer */ + int n = LO(cmd); + int c; + int empty; + int head, tail; + unsigned long flags; + +/* + * Update head and tail of xmit buffer + */ + spin_lock_irqsave(&iforce->xmit_lock, flags); + + head = iforce->xmit.head; + tail = iforce->xmit.tail; + + if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) { + printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n"); + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return -1; + } + + empty = head == tail; + XMIT_INC(iforce->xmit.head, n+2); + +/* + * Store packet in xmit buffer + */ + iforce->xmit.buf[head] = HI(cmd); + XMIT_INC(head, 1); + iforce->xmit.buf[head] = LO(cmd); + XMIT_INC(head, 1); + + c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE); + if (n < c) c=n; + + memcpy(&iforce->xmit.buf[head], + data, + c); + if (n != c) { + memcpy(&iforce->xmit.buf[0], + data + c, + n - c); + } + XMIT_INC(head, n); + + spin_unlock_irqrestore(&iforce->xmit_lock, flags); +/* + * If necessary, start the transmission + */ + switch (iforce->bus) { + +#ifdef IFORCE_232 + case IFORCE_232: + if (empty) + iforce_serial_xmit(iforce); + break; +#endif +#ifdef IFORCE_USB + case IFORCE_USB: + + if (empty & !iforce->out.status) { + iforce_usb_xmit(iforce); + } + break; +#endif + } + return 0; +} + +/* Start or stop an effect */ +int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) +{ + unsigned char data[3]; + +printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value); + + data[0] = LO(id); + data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; + data[2] = LO(value); + return iforce_send_packet(iforce, FF_CMD_PLAY, data); +} + +/* Mark an effect that was being updated as ready. That means it can be updated + * again */ +static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) +{ + int i; + for (i=0; idev.ff_effects_max; ++i) { + if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && + (iforce->core_effects[i].mod1_chunk.start == addr || + iforce->core_effects[i].mod2_chunk.start == addr)) { + clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags); + return 0; + } + } + printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr); + return -1; +} + +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) +{ + struct input_dev *dev = &iforce->dev; + int i; + static int being_used = 0; + + if (being_used) + printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used); + being_used++; + +#ifdef IFORCE_232 + if (HI(iforce->expect_packet) == HI(cmd)) { + iforce->expect_packet = 0; + iforce->ecmd = cmd; + memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); + if (waitqueue_active(&iforce->wait)) + wake_up(&iforce->wait); + } +#endif + + if (!iforce->type) { + being_used--; + return; + } + + switch (HI(cmd)) { + + case 0x01: /* joystick position data */ + case 0x03: /* wheel position data */ + + if (HI(cmd) == 1) { + input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); + if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) + input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); + } else { + input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_GAS, 255 - data[2]); + input_report_abs(dev, ABS_BRAKE, 255 - data[3]); + } + + input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); + + for (i = 0; iforce->type->btn[i] >= 0; i++) + input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); + + break; + + case 0x02: /* status report */ + input_report_key(dev, BTN_DEAD, data[0] & 0x02); + + /* Check if an effect was just started or stopped */ + i = data[1] & 0x7f; + if (data[1] & 0x80) { + if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report play event */ + input_report_ff_status(dev, i, FF_STATUS_PLAYING); + } + } + else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report stop event */ + input_report_ff_status(dev, i, FF_STATUS_STOPPED); + } + if (LO(cmd) > 3) { + int j; + for (j=3; jbus) { + +#ifdef IFORCE_USB + case IFORCE_USB: + + iforce->cr.bRequest = packet[0]; + iforce->ctrl.dev = iforce->usbdev; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&iforce->wait, &wait); + + if (usb_submit_urb(&iforce->ctrl, GFP_KERNEL)) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&iforce->wait, &wait); + return -1; + } + + while (timeout && iforce->ctrl.status == -EINPROGRESS) + timeout = schedule_timeout(timeout); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&iforce->wait, &wait); + + if (!timeout) { + usb_unlink_urb(&iforce->ctrl); + return -1; + } + + break; +#endif +#ifdef IFORCE_232 + case IFORCE_232: + + iforce->expect_packet = FF_CMD_QUERY; + iforce_send_packet(iforce, FF_CMD_QUERY, packet); + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&iforce->wait, &wait); + + while (timeout && iforce->expect_packet) + timeout = schedule_timeout(timeout); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&iforce->wait, &wait); + + if (!timeout) { + iforce->expect_packet = 0; + return -1; + } + + break; +#endif + } + + return -(iforce->edata[0] != packet[0]); +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/iforce/iforce-serio.c linux-2.5/drivers/input/joystick/iforce/iforce-serio.c --- linux-2.5.20/drivers/input/joystick/iforce/iforce-serio.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce-serio.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,166 @@ +/* + * $Id: iforce-serio.c,v 1.2 2001/10/16 21:05:57 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +void iforce_serial_xmit(struct iforce *iforce) +{ + unsigned char cs; + int i; + unsigned long flags; + + if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { + set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags); + return; + } + + spin_lock_irqsave(&iforce->xmit_lock, flags); + +again: + if (iforce->xmit.head == iforce->xmit.tail) { + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return; + } + + cs = 0x2b; + + serio_write(iforce->serio, 0x2b); + + serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + cs ^= iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + + for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { + serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + cs ^= iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + } + + serio_write(iforce->serio, cs); + + if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) + goto again; + + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + + spin_unlock_irqrestore(&iforce->xmit_lock, flags); +} + +static void iforce_serio_write_wakeup(struct serio *serio) +{ + iforce_serial_xmit((struct iforce *)serio->private); +} + +static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct iforce* iforce = serio->private; + + if (!iforce->pkt) { + if (data != 0x2b) { + return; + } + iforce->pkt = 1; + return; + } + + if (!iforce->id) { + if (data > 3 && data != 0xff) { + iforce->pkt = 0; + return; + } + iforce->id = data; + return; + } + + if (!iforce->len) { + if (data > IFORCE_MAX_LENGTH) { + iforce->pkt = 0; + iforce->id = 0; + return; + } + iforce->len = data; + return; + } + + if (iforce->idx < iforce->len) { + iforce->csum += iforce->data[iforce->idx++] = data; + return; + } + + if (iforce->idx == iforce->len) { + iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); + iforce->pkt = 0; + iforce->id = 0; + iforce->len = 0; + iforce->idx = 0; + iforce->csum = 0; + } +} + +static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) +{ + struct iforce *iforce; + if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) + return; + + if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; + memset(iforce, 0, sizeof(struct iforce)); + + iforce->bus = IFORCE_232; + iforce->serio = serio; + serio->private = iforce; + + if (serio_open(serio, dev)) { + kfree(iforce); + return; + } + + if (iforce_init_device(iforce)) { + serio_close(serio); + kfree(iforce); + return; + } +} + +static void iforce_serio_disconnect(struct serio *serio) +{ + struct iforce* iforce = serio->private; + + input_unregister_device(&iforce->dev); + serio_close(serio); + kfree(iforce); +} + +struct serio_dev iforce_serio_dev = { + write_wakeup: iforce_serio_write_wakeup, + interrupt: iforce_serio_irq, + connect: iforce_serio_connect, + disconnect: iforce_serio_disconnect, +}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/iforce/iforce-usb.c linux-2.5/drivers/input/joystick/iforce/iforce-usb.c --- linux-2.5.20/drivers/input/joystick/iforce/iforce-usb.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce-usb.c Fri Feb 8 11:42:12 2002 @@ -0,0 +1,165 @@ +/* + * $Id: iforce-usb.c,v 1.3 2001/11/10 09:46:19 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +void iforce_usb_xmit(struct iforce *iforce) +{ + int n, c; + unsigned long flags; + + spin_lock_irqsave(&iforce->xmit_lock, flags); + + if (iforce->xmit.head == iforce->xmit.tail) { + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return; + } + + ((char *)iforce->out.transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + n = iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + + iforce->out.transfer_buffer_length = n + 2; + iforce->out.dev = iforce->usbdev; + + /* Copy rest of data then */ + c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); + if (n < c) c=n; + + memcpy(iforce->out.transfer_buffer + 1, + &iforce->xmit.buf[iforce->xmit.tail], + c); + if (n != c) { + memcpy(iforce->out.transfer_buffer + 1 + c, + &iforce->xmit.buf[0], + n-c); + } + XMIT_INC(iforce->xmit.tail, n); + + if ( (n=usb_submit_urb(&iforce->out, GFP_KERNEL)) ) { + printk(KERN_WARNING "iforce.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n); + } + + spin_unlock_irqrestore(&iforce->xmit_lock, flags); +} + +static void iforce_usb_irq(struct urb *urb) +{ + struct iforce *iforce = urb->context; + if (urb->status) return; + iforce_process_packet(iforce, + (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); +} + +static void iforce_usb_out(struct urb *urb) +{ + struct iforce *iforce = urb->context; + + if (urb->status) return; + + iforce_usb_xmit(iforce); + + if (waitqueue_active(&iforce->wait)) + wake_up(&iforce->wait); +} + +static void iforce_usb_ctrl(struct urb *urb) +{ + struct iforce *iforce = urb->context; + if (urb->status) return; + iforce->ecmd = 0xff00 | urb->actual_length; + if (waitqueue_active(&iforce->wait)) + wake_up(&iforce->wait); +} + +static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_endpoint_descriptor *epirq, *epout; + struct iforce *iforce; + + epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; + epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1; + + if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL; + memset(iforce, 0, sizeof(struct iforce)); + + iforce->bus = IFORCE_USB; + iforce->usbdev = dev; + + iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; + iforce->cr.wIndex = 0; + iforce->cr.wLength = 16; + + FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), + iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); + + FILL_BULK_URB(&iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), + iforce + 1, 32, iforce_usb_out, iforce); + + FILL_CONTROL_URB(&iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), + (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); + + if (iforce_init_device(iforce)) { + kfree(iforce); + return NULL; + } + + return iforce; +} + +static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) +{ + struct iforce *iforce = ptr; + usb_unlink_urb(&iforce->irq); + input_unregister_device(&iforce->dev); + kfree(iforce); +} + +static struct usb_device_id iforce_usb_ids [] = { + { USB_DEVICE(0x044f, 0xa01c) }, /* Thrustmaster Motor Sport GT */ + { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ + { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ + { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ + { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ + { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */ + { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ + { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, iforce_usb_ids); + +struct usb_driver iforce_usb_driver = { + name: "iforce", + probe: iforce_usb_probe, + disconnect: iforce_usb_disconnect, + id_table: iforce_usb_ids, +}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/iforce/iforce.h linux-2.5/drivers/input/joystick/iforce/iforce.h --- linux-2.5.20/drivers/input/joystick/iforce/iforce.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce.h Mon May 6 17:56:45 2002 @@ -0,0 +1,195 @@ +/* + * $Id: iforce.h,v 1.3 2001/10/23 21:20:54 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* FF: This module provides arbitrary resource management routines. + * I use it to manage the device's memory. + * Despite the name of this module, I am *not* going to access the ioports. + */ +#include + +#define IFORCE_MAX_LENGTH 16 + +#if defined(CONFIG_JOYSTICK_IFORCE_232) || defined(CONFIG_JOYSTICK_IFORCE_232_MODULE) +#define IFORCE_232 1 +#endif +#if defined(CONFIG_JOYSTICK_IFORCE_USB) || defined(CONFIG_JOYSTICK_IFORCE_USB_MODULE) +#define IFORCE_USB 2 +#endif + +#define FALSE 0 +#define TRUE 1 + +#define FF_EFFECTS_MAX 32 + +/* Each force feedback effect is made of one core effect, which can be + * associated to at most to effect modifiers + */ +#define FF_MOD1_IS_USED 0 +#define FF_MOD2_IS_USED 1 +#define FF_CORE_IS_USED 2 +#define FF_CORE_IS_PLAYED 3 /* Effect is actually being played */ +#define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */ +#define FF_CORE_UPDATE 5 /* Effect is being updated */ +#define FF_MODCORE_MAX 5 + +#define CHECK_OWNERSHIP(i, iforce) \ + ((i) < FF_EFFECTS_MAX && i >= 0 && \ + test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \ + (current->pid == 0 || \ + (iforce)->core_effects[(i)].owner == current->pid)) + +struct iforce_core_effect { + /* Information about where modifiers are stored in the device's memory */ + struct resource mod1_chunk; + struct resource mod2_chunk; + unsigned long flags[NBITS(FF_MODCORE_MAX)]; + pid_t owner; + /* Used to keep track of parameters of an effect. They are needed + * to know what parts of an effect changed in an update operation. + * We try to send only parameter packets if possible, as sending + * effect parameter requires the effect to be stoped and restarted + */ + struct ff_effect effect; +}; + +#define FF_CMD_EFFECT 0x010e +#define FF_CMD_SHAPE 0x0208 +#define FF_CMD_MAGNITUDE 0x0303 +#define FF_CMD_PERIOD 0x0407 +#define FF_CMD_INTERACT 0x050a + +#define FF_CMD_AUTOCENTER 0x4002 +#define FF_CMD_PLAY 0x4103 +#define FF_CMD_ENABLE 0x4201 +#define FF_CMD_GAIN 0x4301 + +#define FF_CMD_QUERY 0xff01 + +/* Buffer for async write */ +#define XMIT_SIZE 256 +#define XMIT_INC(var, n) (var)+=n; (var)&= XMIT_SIZE -1 +/* iforce::xmit_flags */ +#define IFORCE_XMIT_RUNNING 0 +#define IFORCE_XMIT_AGAIN 1 + +struct iforce_device { + u16 idvendor; + u16 idproduct; + char *name; + signed short *btn; + signed short *abs; + signed short *ff; +}; + +struct iforce { + struct input_dev dev; /* Input device interface */ + struct iforce_device *type; + char name[64]; + char phys[64]; + int open; + int bus; + + unsigned char data[IFORCE_MAX_LENGTH]; + unsigned char edata[IFORCE_MAX_LENGTH]; + u16 ecmd; + u16 expect_packet; + +#ifdef IFORCE_232 + struct serio *serio; /* RS232 transfer */ + int idx, pkt, len, id; + unsigned char csum; +#endif +#ifdef IFORCE_USB + struct usb_device *usbdev; /* USB transfer */ + struct urb irq, out, ctrl; + struct usb_ctrlrequest cr; +#endif + spinlock_t xmit_lock; + /* Buffer used for asynchronous sending of bytes to the device */ + struct circ_buf xmit; + unsigned char xmit_data[XMIT_SIZE]; + long xmit_flags[1]; + + /* Force Feedback */ + wait_queue_head_t wait; + struct resource device_memory; + struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; + struct semaphore mem_mutex; +}; + +/* Get hi and low bytes of a 16-bits int */ +#define HI(a) ((unsigned char)((a) >> 8)) +#define LO(a) ((unsigned char)((a) & 0xff)) + +/* For many parameters, it seems that 0x80 is a special value that should + * be avoided. Instead, we replace this value by 0x7f + */ +#define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8)) + +/* Encode a time value */ +#define TIME_SCALE(a) ((a) == 0xffff ? 0xffff : (a) * 1000 / 256) + + +/* Public functions */ +/* iforce-serio.c */ +void iforce_serial_xmit(struct iforce *iforce); + +/* iforce-usb.c */ +void iforce_usb_xmit(struct iforce *iforce); + +/* iforce-main.c */ +int iforce_init_device(struct iforce *iforce); + +/* iforce-packets.c */ +int iforce_control_playback(struct iforce*, u16 id, unsigned int); +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); +int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); +void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; +int iforce_get_id_packet(struct iforce *iforce, char *packet); + +/* iforce-ff.c */ +int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); +int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); +int iforce_upload_interactive(struct iforce*, struct ff_effect*, int is_update); + +/* Public variables */ +extern struct serio_dev iforce_serio_dev; +extern struct usb_driver iforce_usb_driver; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/iforce.c linux-2.5/drivers/input/joystick/iforce.c --- linux-2.5.20/drivers/input/joystick/iforce.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/input/joystick/iforce.c Thu Jan 1 01:00:00 1970 @@ -1,1224 +0,0 @@ -/* - * $Id: iforce.c,v 1.56 2001/05/27 14:41:26 jdeneux Exp $ - * - * Copyright (c) 2000-2001 Vojtech Pavlik - * Copyright (c) 2001 Johann Deneux - * - * USB/RS232 I-Force joysticks and wheels. - * - * Sponsored by SuSE - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* FF: This module provides arbitrary resource management routines. - * I use it to manage the device's memory. - * Despite the name of this module, I am *not* going to access the ioports. - */ -#include - -MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); -MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); -MODULE_LICENSE("GPL"); - -#define IFORCE_MAX_LENGTH 16 - -#if defined(CONFIG_JOYSTICK_IFORCE_232) || defined(CONFIG_JOYSTICK_IFORCE_232_MODULE) -#define IFORCE_232 1 -#endif -#if defined(CONFIG_JOYSTICK_IFORCE_USB) || defined(CONFIG_JOYSTICK_IFORCE_USB_MODULE) -#define IFORCE_USB 2 -#endif - -#define FF_EFFECTS_MAX 32 - -/* Each force feedback effect is made of one core effect, which can be - * associated to at most to effect modifiers - */ -#define FF_MOD1_IS_USED 0 -#define FF_MOD2_IS_USED 1 -#define FF_CORE_IS_USED 2 -#define FF_CORE_IS_PLAYED 3 -#define FF_MODCORE_MAX 3 - -struct iforce_core_effect { - /* Information about where modifiers are stored in the device's memory */ - struct resource mod1_chunk; - struct resource mod2_chunk; - unsigned long flags[NBITS(FF_MODCORE_MAX)]; -}; - -#define FF_CMD_EFFECT 0x010e -#define FF_CMD_SHAPE 0x0208 -#define FF_CMD_MAGNITUDE 0x0303 -#define FF_CMD_PERIOD 0x0407 -#define FF_CMD_INTERACT 0x050a - -#define FF_CMD_AUTOCENTER 0x4002 -#define FF_CMD_PLAY 0x4103 -#define FF_CMD_ENABLE 0x4201 -#define FF_CMD_GAIN 0x4301 - -#define FF_CMD_QUERY 0xff01 - -static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, - BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 }; -static signed short btn_wheel[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, - BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; -static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; -static signed short abs_wheel[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 }; -static signed short ff_iforce[] = { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION, - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 }; - -static struct iforce_device { - u16 idvendor; - u16 idproduct; - char *name; - signed short *btn; - signed short *abs; - signed short *ff; -} iforce_device[] = { - { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce }, - { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce }, - { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_joystick, abs_joystick, ff_iforce }, - { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_wheel, abs_wheel, ff_iforce }, - { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, - { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } -}; - -struct iforce { - struct input_dev dev; /* Input device interface */ - struct iforce_device *type; - char name[64]; - int open; - int bus; - - unsigned char data[IFORCE_MAX_LENGTH]; - unsigned char edata[IFORCE_MAX_LENGTH]; - u16 ecmd; - u16 expect_packet; - -#ifdef IFORCE_232 - struct serio *serio; /* RS232 transfer */ - int idx, pkt, len, id; - unsigned char csum; -#endif -#ifdef IFORCE_USB - struct usb_device *usbdev; /* USB transfer */ - struct urb *irq, *out, *ctrl; - struct usb_ctrlrequest dr; -#endif - /* Force Feedback */ - wait_queue_head_t wait; - struct resource device_memory; - struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; -}; - -static struct { - __s32 x; - __s32 y; -} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; - -/* Get hi and low bytes of a 16-bits int */ -#define HI(a) ((unsigned char)((a) >> 8)) -#define LO(a) ((unsigned char)((a) & 0xff)) - -/* Encode a time value */ -#define TIME_SCALE(a) ((a) == 0xffff ? 0xffff : (a) * 1000 / 256) - -static void dump_packet(char *msg, u16 cmd, unsigned char *data) -{ - int i; - - printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); - for (i = 0; i < LO(cmd); i++) - printk("%02x ", data[i]); - printk(")\n"); -} - -/* - * Send a packet of bytes to the device - */ -static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) -{ - switch (iforce->bus) { - -#ifdef IFORCE_232 - case IFORCE_232: { - - int i; - unsigned char csum = 0x2b ^ HI(cmd) ^ LO(cmd); - - serio_write(iforce->serio, 0x2b); - serio_write(iforce->serio, HI(cmd)); - serio_write(iforce->serio, LO(cmd)); - - for (i = 0; i < LO(cmd); i++) { - serio_write(iforce->serio, data[i]); - csum = csum ^ data[i]; - } - - serio_write(iforce->serio, csum); - return; - } -#endif -#ifdef IFORCE_USB - case IFORCE_USB: { - - DECLARE_WAITQUEUE(wait, current); - int timeout = HZ; /* 1 second */ - - memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd)); - ((char*)iforce->out->transfer_buffer)[0] = HI(cmd); - iforce->out->transfer_buffer_length = LO(cmd) + 2; - iforce->out->dev = iforce->usbdev; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&iforce->wait, &wait); - - if (usb_submit_urb(iforce->out, GFP_ATOMIC)) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - return; - } - - while (timeout && iforce->out->status == -EINPROGRESS) - timeout = schedule_timeout(timeout); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - - if (!timeout) - usb_unlink_urb(iforce->out); - - return; - } -#endif - } -} - -static void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) -{ - struct input_dev *dev = &iforce->dev; - int i; - -#ifdef IFORCE_232 - if (HI(iforce->expect_packet) == HI(cmd)) { - iforce->expect_packet = 0; - iforce->ecmd = cmd; - memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); - if (waitqueue_active(&iforce->wait)) - wake_up(&iforce->wait); - } -#endif - - if (!iforce->type) - return; - - switch (HI(cmd)) { - - case 0x01: /* joystick position data */ - case 0x03: /* wheel position data */ - - if (HI(cmd) == 1) { - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); - input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - } else { - input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_GAS, 255 - data[2]); - input_report_abs(dev, ABS_BRAKE, 255 - data[3]); - } - - input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); - input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); - - for (i = 0; iforce->type->btn[i] >= 0; i++) - input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); - - break; - - case 0x02: /* status report */ - - input_report_key(dev, BTN_DEAD, data[0] & 0x02); - break; - } -} - -static int get_id_packet(struct iforce *iforce, char *packet) -{ - DECLARE_WAITQUEUE(wait, current); - int timeout = HZ; /* 1 second */ - - switch (iforce->bus) { - -#ifdef IFORCE_USB - case IFORCE_USB: - - iforce->dr.bRequest = packet[0]; - iforce->ctrl->dev = iforce->usbdev; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&iforce->wait, &wait); - - if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - return -1; - } - - while (timeout && iforce->ctrl->status == -EINPROGRESS) - timeout = schedule_timeout(timeout); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - - if (!timeout) { - usb_unlink_urb(iforce->ctrl); - return -1; - } - - break; -#endif -#ifdef IFORCE_232 - case IFORCE_232: - - iforce->expect_packet = FF_CMD_QUERY; - send_packet(iforce, FF_CMD_QUERY, packet); - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&iforce->wait, &wait); - - while (timeout && iforce->expect_packet) - timeout = schedule_timeout(timeout); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - - if (!timeout) { - iforce->expect_packet = 0; - return -1; - } - - break; -#endif - } - - return -(iforce->edata[0] != packet[0]); -} - -static int iforce_open(struct input_dev *dev) -{ - struct iforce *iforce = dev->private; - - switch (iforce->bus) { -#ifdef IFORCE_USB - case IFORCE_USB: - if (iforce->open++) - break; - iforce->irq->dev = iforce->usbdev; - if (usb_submit_urb(iforce->irq, GFP_KERNEL)) - return -EIO; - break; -#endif - } - return 0; -} - -static void iforce_close(struct input_dev *dev) -{ - struct iforce *iforce = dev->private; - - switch (iforce->bus) { -#ifdef IFORCE_USB - case IFORCE_USB: - if (!--iforce->open) - usb_unlink_urb(iforce->irq); - break; -#endif - } -} - -/* - * Start or stop playing an effect - */ - -static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - struct iforce* iforce = (struct iforce*)(dev->private); - unsigned char data[3]; - - printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value); - - if (type != EV_FF) - return -1; - - switch (code) { - - case FF_GAIN: - - data[0] = value >> 9; - send_packet(iforce, FF_CMD_GAIN, data); - - return 0; - - case FF_AUTOCENTER: - - data[0] = 0x03; - data[1] = value >> 9; - send_packet(iforce, FF_CMD_AUTOCENTER, data); - - data[0] = 0x04; - data[1] = 0x01; - send_packet(iforce, FF_CMD_AUTOCENTER, data); - - return 0; - - default: /* Play an effect */ - - if (code >= iforce->dev.ff_effects_max) - return -1; - - data[0] = LO(code); - data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; - data[2] = LO(value); - send_packet(iforce, FF_CMD_PLAY, data); - - return 0; - } - - return -1; -} - -/* - * Set the magnitude of a constant force effect - * Return error code - * - * Note: caller must ensure exclusive access to device - */ - -static int make_magnitude_modifier(struct iforce* iforce, - struct resource* mod_chunk, __s16 level) -{ - unsigned char data[3]; - - if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - return -ENOMEM; - } - - data[0] = LO(mod_chunk->start); - data[1] = HI(mod_chunk->start); - data[2] = HI(level); - - send_packet(iforce, FF_CMD_MAGNITUDE, data); - - return 0; -} - -/* - * Upload the component of an effect dealing with the period, phase and magnitude - */ - -static int make_period_modifier(struct iforce* iforce, struct resource* mod_chunk, - __s16 magnitude, __s16 offset, u16 period, u16 phase) -{ - unsigned char data[7]; - - period = TIME_SCALE(period); - - if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - return -ENOMEM; - } - - data[0] = LO(mod_chunk->start); - data[1] = HI(mod_chunk->start); - - data[2] = HI(magnitude); - data[3] = HI(offset); - data[4] = HI(phase); - - data[5] = LO(period); - data[6] = HI(period); - - send_packet(iforce, FF_CMD_PERIOD, data); - - return 0; -} - -/* - * Uploads the part of an effect setting the shape of the force - */ - -static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk, - u16 attack_duration, __s16 initial_level, - u16 fade_duration, __s16 final_level) -{ - unsigned char data[8]; - - attack_duration = TIME_SCALE(attack_duration); - fade_duration = TIME_SCALE(fade_duration); - - if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - return -ENOMEM; - } - - data[0] = LO(mod_chunk->start); - data[1] = HI(mod_chunk->start); - - data[2] = LO(attack_duration); - data[3] = HI(attack_duration); - data[4] = HI(initial_level); - - data[5] = LO(fade_duration); - data[6] = HI(fade_duration); - data[7] = HI(final_level); - - send_packet(iforce, FF_CMD_SHAPE, data); - - return 0; -} - -/* - * Component of spring, friction, inertia... effects - */ - -static int make_interactive_modifier(struct iforce* iforce, - struct resource* mod_chunk, - __s16 rsat, __s16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) -{ - unsigned char data[10]; - - if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - return -ENOMEM; - } - - data[0] = LO(mod_chunk->start); - data[1] = HI(mod_chunk->start); - - data[2] = HI(rk); - data[3] = HI(lk); - - data[4] = LO(center); - data[5] = HI(center); - - data[6] = LO(db); - data[7] = HI(db); - - data[8] = HI(rsat); - data[9] = HI(lsat); - - send_packet(iforce, FF_CMD_INTERACT, data); - - return 0; -} - -static unsigned char find_button(struct iforce *iforce, signed short button) -{ - int i; - for (i = 1; iforce->type->btn[i] >= 0; i++) - if (iforce->type->btn[i] == button) - return i + 1; - return 0; -} - -/* - * Send the part common to all effects to the device - */ - -static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, - u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, - u16 interval, u16 direction) -{ - unsigned char data[14]; - - duration = TIME_SCALE(duration); - delay = TIME_SCALE(delay); - interval = TIME_SCALE(interval); - - data[0] = LO(id); - data[1] = effect_type; - data[2] = LO(axes) | find_button(iforce, button); - - data[3] = LO(duration); - data[4] = HI(duration); - - data[5] = HI(direction); - - data[6] = LO(interval); - data[7] = HI(interval); - - data[8] = LO(mod_id1); - data[9] = HI(mod_id1); - data[10] = LO(mod_id2); - data[11] = HI(mod_id2); - - data[12] = LO(delay); - data[13] = HI(delay); - - send_packet(iforce, FF_CMD_EFFECT, data); - - return 0; -} - -/* - * Upload a periodic effect to the device - */ - -static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect) -{ - u8 wave_code; - int core_id = effect->id; - struct iforce_core_effect* core_effect = iforce->core_effects + core_id; - struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); - struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); - int err = 0; - - err = make_period_modifier(iforce, mod1_chunk, - effect->u.periodic.magnitude, effect->u.periodic.offset, - effect->u.periodic.period, effect->u.periodic.phase); - if (err) return err; - set_bit(FF_MOD1_IS_USED, core_effect->flags); - - err = make_shape_modifier(iforce, mod2_chunk, - effect->u.periodic.shape.attack_length, - effect->u.periodic.shape.attack_level, - effect->u.periodic.shape.fade_length, - effect->u.periodic.shape.fade_level); - if (err) return err; - set_bit(FF_MOD2_IS_USED, core_effect->flags); - - switch (effect->u.periodic.waveform) { - case FF_SQUARE: wave_code = 0x20; break; - case FF_TRIANGLE: wave_code = 0x21; break; - case FF_SINE: wave_code = 0x22; break; - case FF_SAW_UP: wave_code = 0x23; break; - case FF_SAW_DOWN: wave_code = 0x24; break; - default: wave_code = 0x20; break; - } - - err = make_core(iforce, effect->id, - mod1_chunk->start, - mod2_chunk->start, - wave_code, - 0x20, - effect->replay.length, - effect->replay.delay, - effect->trigger.button, - effect->trigger.interval, - effect->direction); - - return err; -} - -/* - * Upload a constant force effect - */ -static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect) -{ - int core_id = effect->id; - struct iforce_core_effect* core_effect = iforce->core_effects + core_id; - struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); - struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); - int err = 0; - - printk(KERN_DEBUG "iforce.c: make constant effect\n"); - - err = make_magnitude_modifier(iforce, mod1_chunk, effect->u.constant.level); - if (err) return err; - set_bit(FF_MOD1_IS_USED, core_effect->flags); - - err = make_shape_modifier(iforce, mod2_chunk, - effect->u.constant.shape.attack_length, - effect->u.constant.shape.attack_level, - effect->u.constant.shape.fade_length, - effect->u.constant.shape.fade_level); - if (err) return err; - set_bit(FF_MOD2_IS_USED, core_effect->flags); - - err = make_core(iforce, effect->id, - mod1_chunk->start, - mod2_chunk->start, - 0x00, - 0x20, - effect->replay.length, - effect->replay.delay, - effect->trigger.button, - effect->trigger.interval, - effect->direction); - - return err; -} - -/* - * Upload an interactive effect. Those are for example friction, inertia, springs... - */ -static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect) -{ - int core_id = effect->id; - struct iforce_core_effect* core_effect = iforce->core_effects + core_id; - struct resource* mod_chunk = &(core_effect->mod1_chunk); - u8 type, axes; - u16 mod1, mod2, direction; - int err = 0; - - printk(KERN_DEBUG "iforce.c: make interactive effect\n"); - - switch (effect->type) { - case FF_SPRING: type = 0x40; break; - case FF_FRICTION: type = 0x41; break; - default: return -1; - } - - err = make_interactive_modifier(iforce, mod_chunk, - effect->u.interactive.right_saturation, - effect->u.interactive.left_saturation, - effect->u.interactive.right_coeff, - effect->u.interactive.left_coeff, - effect->u.interactive.deadband, - effect->u.interactive.center); - if (err) return err; - set_bit(FF_MOD1_IS_USED, core_effect->flags); - - switch ((test_bit(ABS_X, &effect->u.interactive.axis) || - test_bit(ABS_WHEEL, &effect->u.interactive.axis)) | - (!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) { - - case 0: /* Only one axis, choose orientation */ - mod1 = mod_chunk->start; - mod2 = 0xffff; - direction = effect->direction; - axes = 0x20; - break; - - case 1: /* Only X axis */ - mod1 = mod_chunk->start; - mod2 = 0xffff; - direction = 0x5a00; - axes = 0x40; - break; - - case 2: /* Only Y axis */ - mod1 = 0xffff; - mod2 = mod_chunk->start; - direction = 0xb400; - axes = 0x80; - break; - - case 3: /* Both X and Y axes */ - /* TODO: same setting for both axes is not mandatory */ - mod1 = mod_chunk->start; - mod2 = mod_chunk->start; - direction = 0x6000; - axes = 0xc0; - break; - - default: - return -1; - } - - err = make_core(iforce, effect->id, - mod1, mod2, - type, axes, - effect->replay.length, effect->replay.delay, - effect->trigger.button, effect->trigger.interval, - direction); - - return err; -} - -/* - * Function called when an ioctl is performed on the event dev entry. - * It uploads an effect to the device - */ -static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) -{ - struct iforce* iforce = (struct iforce*)(dev->private); - int id; - - printk(KERN_DEBUG "iforce.c: upload effect\n"); - -/* - * Get a free id - */ - - for (id=0; id < FF_EFFECTS_MAX; ++id) - if (!test_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; - - if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) - return -ENOMEM; - - effect->id = id; - set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags); - -/* - * Upload the effect - */ - - switch (effect->type) { - - case FF_PERIODIC: - return iforce_upload_periodic(iforce, effect); - - case FF_CONSTANT: - return iforce_upload_constant(iforce, effect); - - case FF_SPRING: - case FF_FRICTION: - return iforce_upload_interactive(iforce, effect); - - default: - return -1; - } -} - -/* - * Erases an effect: it frees the effect id and mark as unused the memory - * allocated for the parameters - */ -static int iforce_erase_effect(struct input_dev *dev, int effect_id) -{ - struct iforce* iforce = (struct iforce*)(dev->private); - int err = 0; - struct iforce_core_effect* core_effect; - - printk(KERN_DEBUG "iforce.c: erase effect %d\n", effect_id); - - if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) - return -EINVAL; - - core_effect = iforce->core_effects + effect_id; - - if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) - err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); - - if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) - err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); - - /*TODO: remember to change that if more FF_MOD* bits are added */ - core_effect->flags[0] = 0; - - return err; -} -static int iforce_init_device(struct iforce *iforce) -{ - unsigned char c[] = "CEOV"; - int i; - - init_waitqueue_head(&iforce->wait); - iforce->dev.ff_effects_max = 10; - -/* - * Input device fields. - */ - - iforce->dev.idbus = BUS_USB; - iforce->dev.private = iforce; - iforce->dev.name = iforce->name; - iforce->dev.open = iforce_open; - iforce->dev.close = iforce_close; - iforce->dev.event = iforce_input_event; - iforce->dev.upload_effect = iforce_upload_effect; - iforce->dev.erase_effect = iforce_erase_effect; - -/* - * On-device memory allocation. - */ - - iforce->device_memory.name = "I-Force device effect memory"; - iforce->device_memory.start = 0; - iforce->device_memory.end = 200; - iforce->device_memory.flags = IORESOURCE_MEM; - iforce->device_memory.parent = NULL; - iforce->device_memory.child = NULL; - iforce->device_memory.sibling = NULL; - -/* - * Wait until device ready - until it sends its first response. - */ - - for (i = 0; i < 20; i++) - if (!get_id_packet(iforce, "O")) - break; - - if (i == 20) { /* 5 seconds */ - printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n"); - iforce_close(&iforce->dev); - return -1; - } - -/* - * Get device info. - */ - - if (!get_id_packet(iforce, "M")) - iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1]; - if (!get_id_packet(iforce, "P")) - iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1]; - if (!get_id_packet(iforce, "B")) - iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; - if (!get_id_packet(iforce, "N")) - iforce->dev.ff_effects_max = iforce->edata[1]; - -/* - * Display additional info. - */ - - for (i = 0; c[i]; i++) - if (!get_id_packet(iforce, c + i)) - dump_packet("info", iforce->ecmd, iforce->edata); - -/* - * Disable spring, enable force feedback. - * FIXME: We should use iforce_set_autocenter() et al here. - */ - - send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); - send_packet(iforce, FF_CMD_ENABLE, "\004"); - -/* - * Find appropriate device entry - */ - - for (i = 0; iforce_device[i].idvendor; i++) - if (iforce_device[i].idvendor == iforce->dev.idvendor && - iforce_device[i].idproduct == iforce->dev.idproduct) - break; - - iforce->type = iforce_device + i; - - sprintf(iforce->name, iforce->type->name, - iforce->dev.idproduct, iforce->dev.idvendor); - -/* - * Set input device bitfields and ranges. - */ - - iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF); - - for (i = 0; iforce->type->btn[i] >= 0; i++) { - signed short t = iforce->type->btn[i]; - set_bit(t, iforce->dev.keybit); - if (t != BTN_DEAD) - set_bit(FF_BTN(t), iforce->dev.ffbit); - } - - for (i = 0; iforce->type->abs[i] >= 0; i++) { - - signed short t = iforce->type->abs[i]; - set_bit(t, iforce->dev.absbit); - - switch (t) { - - case ABS_X: - case ABS_Y: - case ABS_WHEEL: - - iforce->dev.absmax[t] = 1920; - iforce->dev.absmin[t] = -1920; - iforce->dev.absflat[t] = 128; - iforce->dev.absfuzz[t] = 16; - - set_bit(FF_ABS(t), iforce->dev.ffbit); - break; - - case ABS_THROTTLE: - case ABS_GAS: - case ABS_BRAKE: - - iforce->dev.absmax[t] = 255; - iforce->dev.absmin[t] = 0; - break; - - case ABS_HAT0X: - case ABS_HAT0Y: - iforce->dev.absmax[t] = 1; - iforce->dev.absmin[t] = -1; - break; - } - } - - for (i = 0; iforce->type->ff[i] >= 0; i++) - set_bit(iforce->type->ff[i], iforce->dev.ffbit); - -/* - * Register input device. - */ - - input_register_device(&iforce->dev); - - return 0; -} - -#ifdef IFORCE_USB - -static void iforce_usb_irq(struct urb *urb) -{ - struct iforce *iforce = urb->context; - if (urb->status) return; - iforce_process_packet(iforce, - (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); -} - -static void iforce_usb_out(struct urb *urb) -{ - struct iforce *iforce = urb->context; - if (urb->status) return; - if (waitqueue_active(&iforce->wait)) - wake_up(&iforce->wait); -} - -static void iforce_usb_ctrl(struct urb *urb) -{ - struct iforce *iforce = urb->context; - if (urb->status) return; - iforce->ecmd = 0xff00 | urb->actual_length; - if (waitqueue_active(&iforce->wait)) - wake_up(&iforce->wait); -} - -static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *id) -{ - struct usb_endpoint_descriptor *epirq, *epout; - struct iforce *iforce; - - epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; - epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1; - - if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL; - memset(iforce, 0, sizeof(struct iforce)); - - iforce->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!iforce->irq) { - kfree(iforce); - return NULL; - } - iforce->out = usb_alloc_urb(0, GFP_KERNEL); - if (!iforce->out) { - usb_free_urb(iforce->irq); - kfree(iforce); - return NULL; - } - iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL); - if (!iforce->ctrl) { - usb_free_urb(iforce->out); - usb_free_urb(iforce->irq); - kfree(iforce); - return NULL; - } - - iforce->bus = IFORCE_USB; - iforce->usbdev = dev; - - iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; - iforce->dr.wIndex = 0; - iforce->dr.wLength = 16; - - FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), - iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); - - FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), - iforce + 1, 32, iforce_usb_out, iforce); - - FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), - (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce); - - if (iforce_init_device(iforce)) { - usb_free_urb(iforce->ctrl); - usb_free_urb(iforce->out); - usb_free_urb(iforce->irq); - kfree(iforce); - return NULL; - } - - printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on usb%d:%d.%d\n", - iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max, - iforce->device_memory.end, dev->bus->busnum, dev->devnum, ifnum); - - return iforce; -} - -static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) -{ - struct iforce *iforce = ptr; - usb_unlink_urb(iforce->irq); - input_unregister_device(&iforce->dev); - usb_free_urb(iforce->ctrl); - usb_free_urb(iforce->out); - usb_free_urb(iforce->irq); - kfree(iforce); -} - -static struct usb_device_id iforce_usb_ids [] = { - { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ - { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ - { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ - { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ - { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, iforce_usb_ids); - -static struct usb_driver iforce_usb_driver = { - name: "iforce", - probe: iforce_usb_probe, - disconnect: iforce_usb_disconnect, - id_table: iforce_usb_ids, -}; - -#endif - -#ifdef IFORCE_232 - -static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) -{ - struct iforce* iforce = serio->private; - - if (!iforce->pkt) { - if (data != 0x2b) { - return; - } - iforce->pkt = 1; - return; - } - - if (!iforce->id) { - if (data > 3 && data != 0xff) { - iforce->pkt = 0; - return; - } - iforce->id = data; - return; - } - - if (!iforce->len) { - if (data > IFORCE_MAX_LENGTH) { - iforce->pkt = 0; - iforce->id = 0; - return; - } - iforce->len = data; - return; - } - - if (iforce->idx < iforce->len) { - iforce->csum += iforce->data[iforce->idx++] = data; - return; - } - - if (iforce->idx == iforce->len) { - iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); - iforce->pkt = 0; - iforce->id = 0; - iforce->len = 0; - iforce->idx = 0; - iforce->csum = 0; - } -} - -static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) -{ - struct iforce *iforce; - if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) - return; - - if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; - memset(iforce, 0, sizeof(struct iforce)); - - iforce->bus = IFORCE_232; - iforce->serio = serio; - serio->private = iforce; - - if (serio_open(serio, dev)) { - kfree(iforce); - return; - } - - if (iforce_init_device(iforce)) { - serio_close(serio); - kfree(iforce); - return; - } - - printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on serio%d\n", - iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max, - iforce->device_memory.end, serio->number); -} - -static void iforce_serio_disconnect(struct serio *serio) -{ - struct iforce* iforce = serio->private; - - input_unregister_device(&iforce->dev); - serio_close(serio); - kfree(iforce); -} - -static struct serio_dev iforce_serio_dev = { - interrupt: iforce_serio_irq, - connect: iforce_serio_connect, - disconnect: iforce_serio_disconnect, -}; - -#endif - -static int __init iforce_init(void) -{ -#ifdef IFORCE_USB - usb_register(&iforce_usb_driver); -#endif -#ifdef IFORCE_232 - serio_register_device(&iforce_serio_dev); -#endif - return 0; -} - -static void __exit iforce_exit(void) -{ -#ifdef IFORCE_USB - usb_deregister(&iforce_usb_driver); -#endif -#ifdef IFORCE_232 - serio_unregister_device(&iforce_serio_dev); -#endif -} - -module_init(iforce_init); -module_exit(iforce_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/joydump.c linux-2.5/drivers/input/joystick/joydump.c --- linux-2.5.20/drivers/input/joystick/joydump.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/joydump.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,152 @@ +/* + * $Id: joydump.c,v 1.6 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1996-2001 Vojtech Pavlik + */ + +/* + * This is just a very simple driver that can dump the data + * out of the joystick port into the syslog ... + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Gameport data dumper module"); +MODULE_LICENSE("GPL"); + +#define BUF_SIZE 256 + +struct joydump { + unsigned int time; + unsigned char data; +}; + +static void __devinit joydump_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct joydump buf[BUF_SIZE]; + int axes[4], buttons; + int i, j, t, timeout; + unsigned long flags; + unsigned char u; + + printk(KERN_INFO "joydump: ,------------------- START ------------------.\n"); + printk(KERN_INFO "joydump: | Dumping gameport%s.\n", gameport->phys); + printk(KERN_INFO "joydump: | Speed: %4d kHz. |\n", gameport->speed); + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) { + + printk(KERN_INFO "joydump: | Raw mode not available - trying cooked. |\n"); + + if (gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) { + + printk(KERN_INFO "joydump: | Cooked not available either. Failing. |\n"); + printk(KERN_INFO "joydump: `-------------------- END -------------------'\n"); + return; + } + + gameport_cooked_read(gameport, axes, &buttons); + + for (i = 0; i < 4; i++) + printk(KERN_INFO "joydump: | Axis %d: %4d. |\n", i, axes[i]); + printk(KERN_INFO "joydump: | Buttons %02x. |\n", buttons); + printk(KERN_INFO "joydump: `-------------------- END -------------------'\n"); + } + + timeout = gameport_time(gameport, 10000); /* 10 ms */ + t = 0; + i = 1; + + save_flags(flags); + cli(); + + u = gameport_read(gameport); + + buf[0].data = u; + buf[0].time = t; + + gameport_trigger(gameport); + + while (i < BUF_SIZE && t < timeout) { + + buf[i].data = gameport_read(gameport); + + if (buf[i].data ^ u) { + u = buf[i].data; + buf[i].time = t; + i++; + } + t++; + } + + restore_flags(flags); + +/* + * Dump data. + */ + + t = i; + + printk(KERN_INFO "joydump: >------------------- DATA -------------------<\n"); + printk(KERN_INFO "joydump: | index: %3d delta: %3d.%02d us data: ", 0, 0, 0); + for (j = 7; j >= 0; j--) + printk("%d",(buf[0].data >> j) & 1); + printk(" |\n"); + for (i = 1; i < t; i++) { + printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", + i, buf[i].time - buf[i-1].time); + for (j = 7; j >= 0; j--) + printk("%d",(buf[i].data >> j) & 1); + printk(" |\n"); + } + + printk(KERN_INFO "joydump: `-------------------- END -------------------'\n"); +} + +static void __devexit joydump_disconnect(struct gameport *gameport) +{ + gameport_close(gameport); +} + +static struct gameport_dev joydump_dev = { + connect: joydump_connect, + disconnect: joydump_disconnect, +}; + +static int __init joydump_init(void) +{ + gameport_register_device(&joydump_dev); + return 0; +} + +static void __exit joydump_exit(void) +{ + gameport_unregister_device(&joydump_dev); +} + +module_init(joydump_init); +module_exit(joydump_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/joystick/twidjoy.c linux-2.5/drivers/input/joystick/twidjoy.c --- linux-2.5.20/drivers/input/joystick/twidjoy.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/joystick/twidjoy.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,264 @@ +/* + * $Id: twidjoy.c,v 1.4 2001/09/25 09:17:15 vojtech Exp $ + * + * derived from CVS-ID "stinger.c,v 1.5 2001/05/29 12:57:18 vojtech Exp" + * + * Copyright (c) 2001 Arndt Schoenewald + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2000 Mark Fletcher + * + * Sponsored by Quelltext AG (http://www.quelltext-ag.de), Dortmund, Germany + */ + +/* + * Driver to use Handykey's Twiddler (the first edition, i.e. the one with + * the RS232 interface) as a joystick under Linux + * + * The Twiddler is a one-handed chording keyboard featuring twelve buttons on + * the front, six buttons on the top, and a built-in tilt sensor. The buttons + * on the front, which are grouped as four rows of three buttons, are pressed + * by the four fingers (this implies only one button per row can be held down + * at the same time) and the buttons on the top are for the thumb. The tilt + * sensor delivers X and Y axis data depending on how the Twiddler is held. + * Additional information can be found at http://www.handykey.com. + * + * This driver does not use the Twiddler for its intended purpose, i.e. as + * a chording keyboard, but as a joystick: pressing and releasing a button + * immediately sends a corresponding button event, and tilting it generates + * corresponding ABS_X and ABS_Y events. This turns the Twiddler into a game + * controller with amazing 18 buttons :-) + * + * Note: The Twiddler2 (the successor of the Twiddler that connects directly + * to the PS/2 keyboard and mouse ports) is NOT supported by this driver! + * + * For questions or feedback regarding this driver module please contact: + * Arndt Schoenewald + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +/* + * Constants. + */ + +#define TWIDJOY_MAX_LENGTH 5 + +static char *twidjoy_name = "Handykey Twiddler"; + +static struct twidjoy_button_spec { + int bitshift; + int bitmask; + int buttons[3]; +} +twidjoy_buttons[] = { + { 0, 3, { BTN_A, BTN_B, BTN_C } }, + { 2, 3, { BTN_X, BTN_Y, BTN_Z } }, + { 4, 3, { BTN_TL, BTN_TR, BTN_TR2 } }, + { 6, 3, { BTN_SELECT, BTN_START, BTN_MODE } }, + { 8, 1, { BTN_BASE5 } }, + { 9, 1, { BTN_BASE } }, + { 10, 1, { BTN_BASE3 } }, + { 11, 1, { BTN_BASE4 } }, + { 12, 1, { BTN_BASE2 } }, + { 13, 1, { BTN_BASE6 } }, + { 0, 0, { 0 } } +}; + +/* + * Per-Twiddler data. + */ + +struct twidjoy { + struct input_dev dev; + int idx; + unsigned char data[TWIDJOY_MAX_LENGTH]; + char phys[32]; +}; + +/* + * twidjoy_process_packet() decodes packets the driver receives from the + * Twiddler. It updates the data accordingly. + */ + +static void twidjoy_process_packet(struct twidjoy *twidjoy) +{ + if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { + struct input_dev *dev = &twidjoy->dev; + unsigned char *data = twidjoy->data; + struct twidjoy_button_spec *bp; + int button_bits, abs_x, abs_y; + + button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f); + + for (bp = twidjoy_buttons; bp->bitmask; bp++) { + int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift; + int i; + + for (i = 0; i < bp->bitmask; i++) + input_report_key(dev, bp->buttons[i], i+1 == value); + } + + abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2); + if (data[4] & 0x08) abs_x -= 256; + + abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0); + if (data[3] & 0x02) abs_y -= 256; + + input_report_abs(dev, ABS_X, -abs_x); + input_report_abs(dev, ABS_Y, +abs_y); + } + + return; +} + +/* + * twidjoy_interrupt() is called by the low level driver when characters + * are ready for us. We then buffer them for further processing, or call the + * packet processing routine. + */ + +static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct twidjoy *twidjoy = serio->private; + + /* All Twiddler packets are 5 bytes. The fact that the first byte + * has a MSB of 0 and all other bytes have a MSB of 1 can be used + * to check and regain sync. */ + + if ((data & 0x80) == 0) + twidjoy->idx = 0; /* this byte starts a new packet */ + else if (twidjoy->idx == 0) + return; /* wrong MSB -- ignore this byte */ + + if (twidjoy->idx < TWIDJOY_MAX_LENGTH) + twidjoy->data[twidjoy->idx++] = data; + + if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { + twidjoy_process_packet(twidjoy); + twidjoy->idx = 0; + } + + return; +} + +/* + * twidjoy_disconnect() is the opposite of twidjoy_connect() + */ + +static void twidjoy_disconnect(struct serio *serio) +{ + struct twidjoy *twidjoy = serio->private; + input_unregister_device(&twidjoy->dev); + serio_close(serio); + kfree(twidjoy); +} + +/* + * twidjoy_connect() is the routine that is called when someone adds a + * new serio device. It looks for the Twiddler, and if found, registers + * it as an input device. + */ + +static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) +{ + struct twidjoy_button_spec *bp; + struct twidjoy *twidjoy; + int i; + + if (serio->type != (SERIO_RS232 | SERIO_TWIDJOY)) + return; + + if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL))) + return; + + memset(twidjoy, 0, sizeof(struct twidjoy)); + + sprintf(twidjoy->phys, "%s/input0", serio->phys); + + twidjoy->dev.name = twidjoy_name; + twidjoy->dev.phys = twidjoy->phys; + twidjoy->dev.idbus = BUS_RS232; + twidjoy->dev.idvendor = SERIO_TWIDJOY; + twidjoy->dev.idproduct = 0x0001; + twidjoy->dev.idversion = 0x0100; + + twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (bp = twidjoy_buttons; bp->bitmask; bp++) { + for (i = 0; i < bp->bitmask; i++) + set_bit(bp->buttons[i], twidjoy->dev.keybit); + } + + twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + + for (i = 0; i < 2; i++) { + twidjoy->dev.absmax[ABS_X+i] = 50; + twidjoy->dev.absmin[ABS_X+i] = -50; + + /* TODO: arndt 20010708: Are these values appropriate? */ + twidjoy->dev.absfuzz[ABS_X+i] = 4; + twidjoy->dev.absflat[ABS_X+i] = 4; + } + + twidjoy->dev.private = twidjoy; + + serio->private = twidjoy; + + if (serio_open(serio, dev)) { + kfree(twidjoy); + return; + } + + input_register_device(&twidjoy->dev); + + printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys); +} + +/* + * The serio device structure. + */ + +static struct serio_dev twidjoy_dev = { + interrupt: twidjoy_interrupt, + connect: twidjoy_connect, + disconnect: twidjoy_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +int __init twidjoy_init(void) +{ + serio_register_device(&twidjoy_dev); + return 0; +} + +void __exit twidjoy_exit(void) +{ + serio_unregister_device(&twidjoy_dev); +} + +module_init(twidjoy_init); +module_exit(twidjoy_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/keybdev.c linux-2.5/drivers/input/keybdev.c --- linux-2.5.20/drivers/input/keybdev.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/input/keybdev.c Sun Jan 20 17:11:46 2002 @@ -154,6 +154,7 @@ #endif /* CONFIG_X86 || CONFIG_IA64 || __alpha__ || __mips__ || CONFIG_PPC */ + static struct input_handler keybdev_handler; void keybdev_ledfunc(unsigned int led) @@ -189,7 +190,10 @@ void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) { if (type != EV_KEY) return; - emulate_raw(code, down); + + if (emulate_raw(code, down)) + printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code); + tasklet_schedule(&keyboard_tasklet); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/keyboard/Config.help linux-2.5/drivers/input/keyboard/Config.help --- linux-2.5.20/drivers/input/keyboard/Config.help Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/Config.help Thu Feb 14 00:58:44 2002 @@ -0,0 +1,66 @@ +CONFIG_INPUT_KEYBOARD + Say Y here, and a list of supported keyboards will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +CONFIG_KEYBOARD_ATKBD + Say Y here if you want to use the standard AT keyboard. Usually + you'll need this, unless you have a different type keyboard (USB, + ADB or other). + + If unsure, say Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called atkbd.o. If you want to compile it as a + module, say M here and read . + +CONFIG_KEYBOARD_SUNKBD + Say Y here if you want to use a Sun Type 4 or Type 5 keyboard, + connected either to the Sun keyboard connector or to an serial + (RS-232) port via a simple adapter. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sunkbd.o. If you want to compile it as a + module, say M here and read . + +CONFIG_KEYBOARD_PS2SERKBD + Say Y here if you want to use a PS/2 to Serial converter with a + keyboard attached to it. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ps2serkbd.o. If you want to compile it as a + module, say M here and read . + +CONFIG_KEYBOARD_XTKBD + Say Y here if you want to use the old IBM PC/XT keyboard (or + compatible) on your system. This is only possible with a + parallel port keyboard adapter, you cannot connect it to the + keyboard port on a PC that runs Linux. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called xtkbd.o. If you want to compile it as a + module, say M here and read . + +CONFIG_KEYBOARD_MAPLE + Say Y here if you have a DreamCast console running Linux and have + a keyboard attached to its Maple bus. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called maple_keyb.o. If you want to compile it as a + module, say M here and read . + +CONFIG_KEYBOARD_AMIGA + Say Y here if you are running Linux on any AMIGA and have a keyboard + attached. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called amikbd.o. If you want to compile it as a + module, say M here and read . + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/keyboard/Config.in linux-2.5/drivers/input/keyboard/Config.in --- linux-2.5.20/drivers/input/keyboard/Config.in Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/Config.in Thu Feb 14 00:58:44 2002 @@ -0,0 +1,18 @@ +# +# Input core configuration +# + +bool 'Keyboards' CONFIG_INPUT_KEYBOARD + +dep_tristate ' AT keyboard support' CONFIG_KEYBOARD_ATKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO +dep_tristate ' Sun Type 4 and Type 5 keyboard support' CONFIG_KEYBOARD_SUNKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO +dep_tristate ' PS/2 to Serial converter support' CONFIG_KEYBOARD_PS2SERKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO +dep_tristate ' XT Keyboard support' CONFIG_KEYBOARD_XTKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO + +if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then + dep_tristate ' Maple bus keyboard support' CONFIG_KEYBOARD_MAPLE $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_MAPLE +fi + +if [ "$CONFIG_AMIGA" = "y" ]; then + dep_tristate ' Amiga keyboard' CONFIG_KEYBOARD_AMIGA $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD +fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/keyboard/Makefile linux-2.5/drivers/input/keyboard/Makefile --- linux-2.5.20/drivers/input/keyboard/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/Makefile Thu Feb 14 00:58:44 2002 @@ -0,0 +1,20 @@ +# +# Makefile for the input core drivers. +# + +# The target object and module list name. + +O_TARGET := keybdrv.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o +obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o +obj-$(CONFIG_KEYBOARD_PS2SERKBD) += ps2serkbd.o +obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o +obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o +obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o + +# The global Rules.make. + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/keyboard/amikbd.c linux-2.5/drivers/input/keyboard/amikbd.c --- linux-2.5.20/drivers/input/keyboard/amikbd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/amikbd.c Fri Feb 15 19:04:42 2002 @@ -0,0 +1,144 @@ +/* + * $Id: amikbd.c,v 1.13 2002/02/01 16:02:24 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Hamish Macdonald + */ + +/* + * Amiga keyboard driver for Linux/m68k + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include + +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Amiga keyboard driver"); +MODULE_LICENSE("GPL"); + +static unsigned char amikbd_keycode[0x78] = { + 41, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 43, 0, 82, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0, 79, 80, 81, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 0, 75, 76, 77, + 0, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 0, 83, 71, 72, 73, + 57, 14, 15, 96, 28, 1,111, 0, 0, 0, 74, 0,103,108,106,105, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 98, 55, 78, 87, + 42, 54, 58, 29, 56,100 +} + +static char *amikbd_messages[] = { + KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n", + KERN_WARNING "amikbd: keyboard lost sync\n", + KERN_WARNING "amikbd: keyboard buffer overflow\n", + KERN_WARNING "amikbd: keyboard controller failure\n", + KERN_ERR "amikbd: keyboard selftest failure\n", + KERN_INFO "amikbd: initiate power-up key stream\n", + KERN_INFO "amikbd: terminate power-up key stream\n", + KERN_WARNING "amikbd: keyboard interrupt\n" +}; + +static struct input_dev amikbd_dev; + +static char *amikbd_name = "Amiga keyboard"; +static char *amikbd_phys = "amikbd/input0"; + +static void amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) +{ + unsigned char scancode, down; + + scancode = ~ciaa.sdr; /* get and invert scancode (keyboard is active low) */ + ciaa.cra |= 0x40; /* switch SP pin to output for handshake */ + udelay(85); /* wait until 85 us have expired */ + ciaa.cra &= ~0x40; /* switch CIA serial port to input mode */ + + down = scancode & 1; /* lowest bit is release bit */ + scancode = scancode >> 1; + + if (scancode < 0x78) { /* scancodes < 0x78 are keys */ + + scancode = amikbd_keycode[scancode]; + + if (scancode == KEY_CAPS) { /* CapsLock is a toggle switch key on Amiga */ + input_report_key(&amikbd_dev, scancode, 1); + input_report_key(&amikbd_dev, scancode, 0); + return; + } + + input_report_key(&amikbd_dev, scancode, down); + + return; + } + + printk(amikbd_messages[scancode - 0x78]); /* scancodes >= 0x78 are error codes */ +} + +static int __init amikbd_init(void) +{ + int i; + + if (!AMIGAHW_PRESENT(AMI_KEYBOARD)) + return -EIO; + + if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb")) + return -EBUSY; + + amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + amikbd_dev.keycode = amikbd_keycode; + + for (i = 0; i < 0x78; i++) + if (amikbd_keycode[i]) + set_bit(amikbd_keycode[i], amikbd_dev.keybit); + + ciaa.cra &= ~0x41; /* serial data in, turn off TA */ + request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", NULL); + + amikbd_dev.name = amikbd_name; + amikbd_dev.phys = amikbd_phys; + amikbd_dev.idbus = BUS_AMIGA; + amikbd_dev.idvendor = 0x0001; + amikbd_dev.idproduct = 0x0001; + amikbd_dev.idversion = 0x0100; + + input_register_device(&amikbd_dev); + + printk(KERN_INFO "input: %s\n", amikbd_name); + + return 0; +} + +static void __exit amikbd_exit(void) +{ + input_unregister_device(&amikbd_dev); + free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt); + release_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100); +} + +module_init(amikbd_init); +module_exit(amikbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/keyboard/atkbd.c linux-2.5/drivers/input/keyboard/atkbd.c --- linux-2.5.20/drivers/input/keyboard/atkbd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/atkbd.c Mon Jan 28 12:38:10 2002 @@ -0,0 +1,551 @@ +/* + * $Id: atkbd.c,v 1.31 2002/01/27 01:48:54 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); +MODULE_PARM(atkbd_set, "1i"); +MODULE_LICENSE("GPL"); + +static int atkbd_set = 2; + +/* + * Scancode to keycode tables. These are just the default setting, and + * are loadable via an userland utility. + */ + +static unsigned char atkbd_set2_keycode[512] = { + 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85, + 0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90, + 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0, + 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0, + 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, + 122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0, + 85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123, + 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, + 252, 0, 0, 65, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, + 0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0, + 136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125, + 0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127, + 159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142, + 157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138, + 0, 0, 0, 0, 0, 0,153,140, 0,255, 96, 0, 0, 0,143, 0, + 133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112, + 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119 +}; + +static unsigned char atkbd_set3_keycode[512] = { + 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, + 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, + 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64, + 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66, + 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68, + 113,114, 40, 84, 26, 13, 87, 99,100, 54, 28, 27, 43, 84, 88, 70, + 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104, + 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55, 85, + 89, 90, 91, 92, 74, 0, 0, 0, 0, 0, 0,125,126,127,112, 0, + 0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168, + 148,149,147,140, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255 +}; + +#define ATKBD_CMD_SETLEDS 0x10ed +#define ATKBD_CMD_GSCANSET 0x11f0 +#define ATKBD_CMD_SSCANSET 0x10f0 +#define ATKBD_CMD_GETID 0x02f2 +#define ATKBD_CMD_ENABLE 0x00f4 +#define ATKBD_CMD_RESET_DIS 0x00f5 +#define ATKBD_CMD_SETALL_MB 0x00f8 +#define ATKBD_CMD_EX_ENABLE 0x10ea +#define ATKBD_CMD_EX_SETLEDS 0x20eb + +#define ATKBD_RET_ACK 0xfa +#define ATKBD_RET_NAK 0xfe + +#define ATKBD_KEY_UNKNOWN 0 +#define ATKBD_KEY_BAT 251 +#define ATKBD_KEY_EMUL0 252 +#define ATKBD_KEY_EMUL1 253 +#define ATKBD_KEY_RELEASE 254 +#define ATKBD_KEY_NULL 255 + +/* + * The atkbd control structure + */ + +struct atkbd { + unsigned char keycode[512]; + struct input_dev dev; + struct serio *serio; + char name[64]; + char phys[32]; + struct tq_struct tq; + unsigned char cmdbuf[4]; + unsigned char cmdcnt; + unsigned char set; + char release; + char ack; + char emul; + char error; + unsigned short id; +}; + +/* + * atkbd_interrupt(). Here takes place processing of data received from + * the keyboard into events. + */ + +static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct atkbd *atkbd = serio->private; + int code = data; + +#ifdef ATKBD_DEBUG + printk(KERN_DEBUG "atkbd.c: Received %02x\n", data); +#endif + + switch (code) { + case ATKBD_RET_ACK: + atkbd->ack = 1; + return; + case ATKBD_RET_NAK: + atkbd->ack = -1; + return; + } + + if (atkbd->cmdcnt) { + atkbd->cmdbuf[--atkbd->cmdcnt] = code; + return; + } + + switch (atkbd->keycode[code]) { + case ATKBD_KEY_BAT: + queue_task(&atkbd->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; + case ATKBD_KEY_EMUL0: + atkbd->emul = 1; + return; + case ATKBD_KEY_EMUL1: + atkbd->emul = 2; + return; + case ATKBD_KEY_RELEASE: + atkbd->release = 1; + return; + } + + if (atkbd->emul) { + if (--atkbd->emul) return; + code |= 0x100; + } + + switch (atkbd->keycode[code]) { + case ATKBD_KEY_NULL: + break; + case ATKBD_KEY_UNKNOWN: + printk(KERN_WARNING "atkbd.c: Unknown key (set %d, scancode %#x, on %s) %s.\n", + atkbd->set, code, serio->phys, atkbd->release ? "released" : "pressed"); + break; + default: + input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release); + } + + atkbd->release = 0; +} + +/* + * atkbd_sendbyte() sends a byte to the keyboard, and waits for + * acknowledge. It doesn't handle resends according to the keyboard + * protocol specs, because if these are needed, the keyboard needs + * replacement anyway, and they only make a mess in the protocol. + */ + +static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) +{ + int timeout = 1000; /* 10 msec */ + atkbd->ack = 0; + +#ifdef ATKBD_DEBUG + printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte); +#endif + serio_write(atkbd->serio, byte); + while (!atkbd->ack && timeout--) udelay(10); + + return -(atkbd->ack <= 0); +} + +/* + * atkbd_command() sends a command, and its parameters to the keyboard, + * then waits for the response and puts it in the param array. + */ + +static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) +{ + int timeout = 10000; /* 100 msec */ + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + int i; + + atkbd->cmdcnt = receive; + + if (command & 0xff) + if (atkbd_sendbyte(atkbd, command & 0xff)) + return (atkbd->cmdcnt = 0) - 1; + + for (i = 0; i < send; i++) + if (atkbd_sendbyte(atkbd, param[i])) + return (atkbd->cmdcnt = 0) - 1; + + while (atkbd->cmdcnt && timeout--) udelay(10); + + for (i = 0; i < receive; i++) + param[i] = atkbd->cmdbuf[(receive - 1) - i]; + + if (atkbd->cmdcnt) + return (atkbd->cmdcnt = 0) - 1; + + return 0; +} + +/* + * Event callback from the input module. Events that change the state of + * the hardware are processed here. + */ + +static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct atkbd *atkbd = dev->private; + char param[2]; + + switch (type) { + + case EV_LED: + + *param = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) + | (test_bit(LED_NUML, dev->led) ? 2 : 0) + | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); + atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS); + + if (atkbd->set == 4) { + param[0] = 0; + param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) + | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) + | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) + | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); + atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS); + } + + return 0; + } + + return -1; +} + +/* + * atkbd_set_3 checks if a keyboard has a working Set 3 support, and + * sets it into that. Unfortunately there are keyboards that can be switched + * to Set 3, but don't work well in that (BTC Multimedia ...) + */ + +static int atkbd_set_3(struct atkbd *atkbd) +{ + unsigned char param; + +/* + * For known special keyboards we can go ahead and set the correct set. + */ + + if (atkbd->id == 0xaca1) { + param = 3; + atkbd_command(atkbd, ¶m, ATKBD_CMD_SSCANSET); + return 3; + } + +/* + * We check for the extra keys on an some keyboards that need extra + * command to get enabled. This shouldn't harm any keyboards not + * knowing the command. + */ + + param = 0x71; + if (!atkbd_command(atkbd, ¶m, ATKBD_CMD_EX_ENABLE)) + return 4; + +/* + * Try to set the set we want. + */ + + param = atkbd_set; + if (atkbd_command(atkbd, ¶m, ATKBD_CMD_SSCANSET)) + return 2; + +/* + * Read set number. Beware here. Some keyboards always send '2' + * or some other number regardless into what mode they have been + * attempted to be set. Other keyboards treat the '0' command as + * 'set to set 0', and not 'report current set' as they should. + * In that case we time out, and return 2. + */ + + param = 0; + if (atkbd_command(atkbd, ¶m, ATKBD_CMD_GSCANSET)) + return 2; + +/* + * Here we return the set number the keyboard reports about + * itself. + */ + + return (param == 3) ? 3 : 2; +} + +/* + * atkbd_probe() probes for an AT keyboard on a serio port. + */ + +static int atkbd_probe(struct atkbd *atkbd) +{ + unsigned char param[2]; + +/* + * Full reset with selftest can on some keyboards be annoyingly slow, + * so we just do a reset-and-disable on the keyboard, which + * is considerably faster, but doesn't have to reset everything. + */ + + if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_DIS)) + return -1; + +/* + * Next, we check if it's a keyboard. It should send 0xab83 + * (0xab84 on IBM ThinkPad, and 0xaca1 on a NCD Sun layout keyboard, + * 0xab02 on unxlated i8042 and 0xab03 on unxlated ThinkPad, 0xab7f + * on Fujitsu Lifebook). + * If it's a mouse, it'll only send 0x00 (0x03 if it's MS mouse), + * and we'll time out here, and report an error. + */ + + param[0] = param[1] = 0; + + if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) + return -1; + + atkbd->id = (param[0] << 8) | param[1]; + + if (atkbd->id != 0xab83 && atkbd->id != 0xab84 && atkbd->id != 0xaca1 && + atkbd->id != 0xab7f && atkbd->id != 0xab02 && atkbd->id != 0xab03) + printk(KERN_WARNING "atkbd.c: Unusual keyboard ID: %#x on %s\n", + atkbd->id, atkbd->serio->phys); + + return 0; +} + +/* + * atkbd_initialize() sets the keyboard into a sane state. + */ + +static void atkbd_initialize(struct atkbd *atkbd) +{ + unsigned char param; + +/* + * Disable autorepeat. We don't need it, as we do it in software anyway, + * because that way can get faster repeat, and have less system load + * (less accesses to the slow ISA hardware). If this fails, we don't care, + * and will just ignore the repeated keys. + */ + + atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB); + +/* + * We also shut off all the leds. The console code will turn them back on, + * if needed. + */ + + param = 0; + atkbd_command(atkbd, ¶m, ATKBD_CMD_SETLEDS); + +/* + * Last, we enable the keyboard so that we get keypresses from it. + */ + + if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE)) + printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n", + atkbd->serio->phys); +} + +/* + * atkbd_disconnect() cleans up behind us ... + */ + +static void atkbd_disconnect(struct serio *serio) +{ + struct atkbd *atkbd = serio->private; + input_unregister_device(&atkbd->dev); + serio_close(serio); + kfree(atkbd); +} + +/* + * atkbd_powerup() is called when the keyboard sends the 0xaa character, + * meaning that it was disconnected and reconnected. We close the port + * in that case and let the upper layer find an appropriate driver for + * the device that was connected. It may be a mouse, or a keyboard, we + * don't know yet. + */ + +static void atkbd_powerup(void *data) +{ + struct atkbd *atkbd = data; + mdelay(40); /* FIXME!!! Wait some nicer way */ + serio_rescan(atkbd->serio); +} + +/* + * atkbd_connect() is called when the serio module finds and interface + * that isn't handled yet by an appropriate device driver. We check if + * there is an AT keyboard out there and if yes, we register ourselves + * to the input module. + */ + +static void atkbd_connect(struct serio *serio, struct serio_dev *dev) +{ + struct atkbd *atkbd; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_8042) + return; + + if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL))) + return; + + memset(atkbd, 0, sizeof(struct atkbd)); + + atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); + + atkbd->serio = serio; + + atkbd->dev.keycode = atkbd->keycode; + atkbd->dev.event = atkbd_event; + atkbd->dev.private = atkbd; + + atkbd->tq.routine = atkbd_powerup; + atkbd->tq.data = atkbd; + + serio->private = atkbd; + + if (serio_open(serio, dev)) { + kfree(atkbd); + return; + } + + if (atkbd_probe(atkbd)) { + serio_close(serio); + kfree(atkbd); + return; + } + + atkbd->set = atkbd_set_3(atkbd); + + if (atkbd->set == 4) { + atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE); + sprintf(atkbd->name, "AT Set 2 Extended keyboard\n"); + } else + sprintf(atkbd->name, "AT Set %d keyboard", atkbd->set); + + sprintf(atkbd->phys, "%s/input0", serio->phys); + + if (atkbd->set == 3) + memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); + else + memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); + + atkbd->dev.name = atkbd->name; + atkbd->dev.phys = atkbd->phys; + atkbd->dev.idbus = BUS_I8042; + atkbd->dev.idvendor = 0x0001; + atkbd->dev.idproduct = atkbd->set; + atkbd->dev.idversion = atkbd->id; + + for (i = 0; i < 512; i++) + if (atkbd->keycode[i] && atkbd->keycode[i] <= 250) + set_bit(atkbd->keycode[i], atkbd->dev.keybit); + + input_register_device(&atkbd->dev); + + printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); + + atkbd_initialize(atkbd); +} + + +static struct serio_dev atkbd_dev = { + interrupt: atkbd_interrupt, + connect: atkbd_connect, + disconnect: atkbd_disconnect +}; + +/* + * Module init and exit. + */ + +void __init atkbd_setup(char *str, int *ints) +{ + if (!ints[0]) atkbd_set = ints[1]; +} + +int __init atkbd_init(void) +{ + serio_register_device(&atkbd_dev); + return 0; +} + +void __exit atkbd_exit(void) +{ + serio_unregister_device(&atkbd_dev); +} + +module_init(atkbd_init); +module_exit(atkbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/keyboard/maple_keyb.c linux-2.5/drivers/input/keyboard/maple_keyb.c --- linux-2.5.20/drivers/input/keyboard/maple_keyb.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/maple_keyb.c Fri Feb 15 18:03:02 2002 @@ -0,0 +1,190 @@ +/* + * $Id: maple_keyb.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $ + * SEGA Dreamcast keyboard driver + * Based on drivers/usb/usbkbd.c + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("YAEGASHI Takeshi "); +MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); + +static unsigned char dc_kbd_keycode[256] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, + 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, + 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189, + 190,191,192,193,194,195,196,197,198, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, + 150,158,159,128,136,177,178,176,142,152,173,140 +}; + + +struct dc_kbd { + struct input_dev dev; + unsigned char new[8]; + unsigned char old[8]; + int open; +}; + + +static void dc_scan_kbd(struct dc_kbd *kbd) +{ + int i; + struct input_dev *dev = &kbd->dev; + + for(i=0; i<8; i++) + input_report_key(dev, + dc_kbd_keycode[i+224], + (kbd->new[0]>>i)&1); + + for(i=2; i<8; i++) { + + if(kbd->old[i]>3&&memscan(kbd->new+2, kbd->old[i], 6)==NULL) { + if(dc_kbd_keycode[kbd->old[i]]) + input_report_key(dev, + dc_kbd_keycode[kbd->old[i]], + 0); + else + printk("Unknown key (scancode %#x) released.", + kbd->old[i]); + } + + if(kbd->new[i]>3&&memscan(kbd->old+2, kbd->new[i], 6)!=NULL) { + if(dc_kbd_keycode[kbd->new[i]]) + input_report_key(dev, + dc_kbd_keycode[kbd->new[i]], + 1); + else + printk("Unknown key (scancode %#x) pressed.", + kbd->new[i]); + } + } + + memcpy(kbd->old, kbd->new, 8); +} + + +static void dc_kbd_callback(struct mapleq *mq) +{ + struct maple_device *mapledev = mq->dev; + struct dc_kbd *kbd = mapledev->private_data; + unsigned long *buf = mq->recvbuf; + + if (buf[1] == mapledev->function) { + memcpy(kbd->new, buf+2, 8); + dc_scan_kbd(kbd); + } +} + + +static int dc_kbd_open(struct input_dev *dev) +{ + struct dc_kbd *kbd = dev->private; + kbd->open++; + return 0; +} + + +static void dc_kbd_close(struct input_dev *dev) +{ + struct dc_kbd *kbd = dev->private; + kbd->open--; +} + + +static int dc_kbd_connect(struct maple_device *dev) +{ + int i; + unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); + struct dc_kbd *kbd; + + if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL))) + return -1; + memset(kbd, 0, sizeof(struct dc_kbd)); + + dev->private_data = kbd; + + kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + + for (i=0; i<255; i++) + set_bit(dc_kbd_keycode[i], kbd->dev.keybit); + clear_bit(0, kbd->dev.keybit); + + kbd->dev.private = kbd; + kbd->dev.open = dc_kbd_open; + kbd->dev.close = dc_kbd_close; + kbd->dev.event = NULL; + + kbd->dev.name = dev->product_name; + kbd->dev.idbus = BUS_MAPLE; + + input_register_device(&kbd->dev); + + maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD); + + printk(KERN_INFO "input%d: keyboard(0x%lx): %s\n", + kbd->dev.number, data, kbd->dev.name); + + MOD_INC_USE_COUNT; + + return 0; +} + + +static void dc_kbd_disconnect(struct maple_device *dev) +{ + struct dc_kbd *kbd = dev->private_data; + + input_unregister_device(&kbd->dev); + + kfree(kbd); + + MOD_DEC_USE_COUNT; +} + + +static struct maple_driver dc_kbd_driver = { + function: MAPLE_FUNC_KEYBOARD, + name: "Dreamcast keyboard", + connect: dc_kbd_connect, + disconnect: dc_kbd_disconnect, +}; + + +static int __init dc_kbd_init(void) +{ + maple_register_driver(&dc_kbd_driver); + return 0; +} + + +static void __exit dc_kbd_exit(void) +{ + maple_unregister_driver(&dc_kbd_driver); +} + + +module_init(dc_kbd_init); +module_exit(dc_kbd_exit); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/keyboard/ps2serkbd.c linux-2.5/drivers/input/keyboard/ps2serkbd.c --- linux-2.5.20/drivers/input/keyboard/ps2serkbd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/ps2serkbd.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,297 @@ +/* + * based on: sunkbd.c and ps2serkbd.c + * + * $Id: ps2serkbd.c,v 1.5 2001/09/25 10:12:07 vojtech Exp $ + */ + +/* + * PS/2 keyboard via adapter at serial port driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ATKBD_CMD_SETLEDS 0x10ed +#define ATKBD_CMD_GSCANSET 0x11f0 +#define ATKBD_CMD_SSCANSET 0x10f0 +#define ATKBD_CMD_GETID 0x02f2 +#define ATKBD_CMD_ENABLE 0x00f4 +#define ATKBD_CMD_RESET_DIS 0x00f5 +#define ATKBD_CMD_SETALL_MB 0x00f8 +#define ATKBD_CMD_EX_ENABLE 0x10ea +#define ATKBD_CMD_EX_SETLEDS 0x20eb + +#define ATKBD_RET_ACK 0xfa +#define ATKBD_RET_NAK 0xfe + +#define ATKBD_KEY_UNKNOWN 0 +#define ATKBD_KEY_BAT 251 +#define ATKBD_KEY_EMUL0 252 +#define ATKBD_KEY_EMUL1 253 +#define ATKBD_KEY_RELEASE 254 +#define ATKBD_KEY_NULL 255 + +static unsigned char ps2serkbd_set2_keycode[512] = { + 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85, + 0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90, + 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0, + 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0, + 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, + 122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0, + 85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123, + 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, + 252, 0, 0, 65, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, + 0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0, + 136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125, + 0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127, + 159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142, + 157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138, + 0, 0, 0, 0, 0, 0,153,140, 0, 0, 96, 0, 0, 0,143, 0, + 133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112, + 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119 +}; + +/* + * Per-keyboard data. + */ + +struct ps2serkbd { + unsigned char keycode[512]; + struct input_dev dev; + struct serio *serio; + char name[64]; + char phys[32]; + struct tq_struct tq; + unsigned char cmdbuf[4]; + unsigned char cmdcnt; + unsigned char set; + char release; + char ack; + char emul; + char error; + unsigned short id; +}; + +/* + * ps2serkbd_interrupt() is called by the low level driver when a character + * is received. + */ + +static void ps2serkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + static int event_count=0; + struct ps2serkbd* ps2serkbd = serio->private; + int code=data; + +#if 0 + printk(KERN_WARNING "ps2serkbd.c(%8d): (scancode %#x)\n", event_count, data); +#endif + event_count++; + + switch (code) { + case ATKBD_RET_ACK: + ps2serkbd->ack = 1; + return; + case ATKBD_RET_NAK: + ps2serkbd->ack = -1; + return; + } + + if (ps2serkbd->cmdcnt) { + ps2serkbd->cmdbuf[--ps2serkbd->cmdcnt] = code; + return; + } + + switch (ps2serkbd->keycode[code]) { + case ATKBD_KEY_BAT: + queue_task(&ps2serkbd->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; + case ATKBD_KEY_EMUL0: + ps2serkbd->emul = 1; + return; + case ATKBD_KEY_EMUL1: + ps2serkbd->emul = 2; + return; + case ATKBD_KEY_RELEASE: + ps2serkbd->release = 1; + return; + } + + if (ps2serkbd->emul) { + if (--ps2serkbd->emul) return; + code |= 0x100; + } + + switch (ps2serkbd->keycode[code]) { + case ATKBD_KEY_NULL: + break; + case ATKBD_KEY_UNKNOWN: + printk(KERN_WARNING "ps2serkbd.c: Unknown key (set %d, scancode %#x) %s.\n", + ps2serkbd->set, code, ps2serkbd->release ? "released" : "pressed"); + break; + default: + input_report_key(&ps2serkbd->dev, ps2serkbd->keycode[code], !ps2serkbd->release); + } + + ps2serkbd->release = 0; +} + +/* + * ps2serkbd_event() handles events from the input module. + */ + +static int ps2serkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + switch (type) { + + case EV_LED: + + return 0; + } + + return -1; +} + +static int ps2serkbd_initialize(struct ps2serkbd *ps2serkbd) +{ + return 0; +} + +static void ps2serkbd_reinit(void *data) +{ +} + + +static void ps2serkbd_connect(struct serio *serio, struct serio_dev *dev) +{ + struct ps2serkbd *ps2serkbd; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_RS232) + return; + + if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_PS2SER) + return; + + + if (!(ps2serkbd = kmalloc(sizeof(struct ps2serkbd), GFP_KERNEL))) + return; + + memset(ps2serkbd, 0, sizeof(struct ps2serkbd)); + + ps2serkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + ps2serkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); + + ps2serkbd->serio = serio; + + ps2serkbd->dev.keycode = ps2serkbd->keycode; + ps2serkbd->dev.event = ps2serkbd_event; + ps2serkbd->dev.private = ps2serkbd; + + ps2serkbd->tq.routine = ps2serkbd_reinit; + ps2serkbd->tq.data = ps2serkbd; + + serio->private = ps2serkbd; + + if (serio_open(serio, dev)) { + kfree(ps2serkbd); + return; + } + + if (ps2serkbd_initialize(ps2serkbd) < 0) { + serio_close(serio); + kfree(ps2serkbd); + return; + } + + ps2serkbd->set = 4; + + if (ps2serkbd->set == 4) { + ps2serkbd->dev.ledbit[0] |= 0; + sprintf(ps2serkbd->name, "AT Set 2 Extended keyboard\n"); + } + memcpy(ps2serkbd->keycode, ps2serkbd_set2_keycode, sizeof(ps2serkbd->keycode)); + + sprintf(ps2serkbd->phys, "%s/input0", serio->phys); + + ps2serkbd->dev.name = ps2serkbd->name; + ps2serkbd->dev.phys = ps2serkbd->phys; + ps2serkbd->dev.idbus = BUS_RS232; + ps2serkbd->dev.idvendor = SERIO_PS2SER; + ps2serkbd->dev.idproduct = ps2serkbd->set; + ps2serkbd->dev.idversion = ps2serkbd->id; + + for (i = 0; i < 512; i++) + if (ps2serkbd->keycode[i] && ps2serkbd->keycode[i] <= 250) + set_bit(ps2serkbd->keycode[i], ps2serkbd->dev.keybit); + + input_register_device(&ps2serkbd->dev); +} + +/* + * ps2serkbd_disconnect() unregisters and closes behind us. + */ + +static void ps2serkbd_disconnect(struct serio *serio) +{ + struct ps2serkbd *ps2serkbd = serio->private; + input_unregister_device(&ps2serkbd->dev); + serio_close(serio); + kfree(ps2serkbd); +} + +static struct serio_dev ps2serkbd_dev = { +interrupt: + ps2serkbd_interrupt, +connect: + ps2serkbd_connect, +disconnect: + ps2serkbd_disconnect +}; + +/* + * The functions for insering/removing us as a module. + */ + +int __init ps2serkbd_init(void) +{ + serio_register_device(&ps2serkbd_dev); + return 0; +} + +void __exit ps2serkbd_exit(void) +{ + serio_unregister_device(&ps2serkbd_dev); +} + +module_init(ps2serkbd_init); +module_exit(ps2serkbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/keyboard/sunkbd.c linux-2.5/drivers/input/keyboard/sunkbd.c --- linux-2.5.20/drivers/input/keyboard/sunkbd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/sunkbd.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,317 @@ +/* + * $Id: sunkbd.c,v 1.14 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * Sun keyboard driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Sun keyboard driver"); +MODULE_LICENSE("GPL"); + +static unsigned char sunkbd_keycode[128] = { + 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64, 0, + 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55, + 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27,111,127, 71, 72, 73, 74,134,135,107, 0, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136, + 104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101, + 79, 80, 81, 0, 0, 0,138, 58,125, 57,126,109, 86, 78 +}; + +#define SUNKBD_CMD_RESET 0x1 +#define SUNKBD_CMD_BELLON 0x2 +#define SUNKBD_CMD_BELLOFF 0x3 +#define SUNKBD_CMD_CLICK 0xa +#define SUNKBD_CMD_NOCLICK 0xb +#define SUNKBD_CMD_SETLED 0xe +#define SUNKBD_CMD_LAYOUT 0xf + +#define SUNKBD_RET_RESET 0xff +#define SUNKBD_RET_ALLUP 0x7f +#define SUNKBD_RET_LAYOUT 0xfe + +#define SUNKBD_LAYOUT_5_MASK 0x20 +#define SUNKBD_RELEASE 0x80 +#define SUNKBD_KEY 0x7f + +/* + * Per-keyboard data. + */ + +struct sunkbd { + unsigned char keycode[128]; + struct input_dev dev; + struct serio *serio; + struct tq_struct tq; + char name[64]; + char phys[32]; + char type; + char reset; + char layout; +}; + +/* + * sunkbd_interrupt() is called by the low level driver when a character + * is received. + */ + +static void sunkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct sunkbd* sunkbd = serio->private; + + if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */ + sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */ + return; + } + + if (sunkbd->layout == -1) { + sunkbd->layout = data; + return; + } + + switch (data) { + + case SUNKBD_RET_RESET: + queue_task(&sunkbd->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + sunkbd->reset = -1; + return; + + case SUNKBD_RET_LAYOUT: + sunkbd->layout = -1; + return; + + case SUNKBD_RET_ALLUP: /* All keys released */ + return; + + default: + if (sunkbd->keycode[data & SUNKBD_KEY]) { + input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); + } else { + printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n", + data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed"); + } + } +} + +/* + * sunkbd_event() handles events from the input module. + */ + +static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct sunkbd *sunkbd = dev->private; + + switch (type) { + + case EV_LED: + + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); + sunkbd->serio->write(sunkbd->serio, + (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | + (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led)); + return 0; + + case EV_SND: + + switch (code) { + + case SND_CLICK: + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); + return 0; + + case SND_BELL: + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); + return 0; + } + + break; + } + + return -1; +} + +/* + * sunkbd_initialize() checks for a Sun keyboard attached, and determines + * its type. + */ + +static int sunkbd_initialize(struct sunkbd *sunkbd) +{ + int t; + + t = 1000; + sunkbd->reset = -2; + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); + while (sunkbd->reset < 0 && --t) mdelay(1); + if (!t) return -1; + + sunkbd->type = sunkbd->reset; + + if (sunkbd->type == 4) { /* Type 4 keyboard */ + t = 250; + sunkbd->layout = -2; + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); + while (sunkbd->layout < 0 && --t) mdelay(1); + if (!t) return -1; + if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; + } + + return 0; +} + +/* + * sunkbd_reinit() sets leds and beeps to a state the computer remembers they + * were in. + */ + +static void sunkbd_reinit(void *data) +{ + struct sunkbd *sunkbd = data; + int t = 1000; + + while (sunkbd->reset < 0 && --t) mdelay(1); + + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); + sunkbd->serio->write(sunkbd->serio, + (!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) | + (!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led)); + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd)); + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd)); +} + +/* + * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. + */ + +static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) +{ + struct sunkbd *sunkbd; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_RS232) + return; + + if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_SUNKBD) + return; + + if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL))) + return; + + memset(sunkbd, 0, sizeof(struct sunkbd)); + + sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); + sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); + sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL); + + sunkbd->serio = serio; + + sunkbd->tq.routine = sunkbd_reinit; + sunkbd->tq.data = sunkbd; + + sunkbd->dev.keycode = sunkbd->keycode; + sunkbd->dev.event = sunkbd_event; + sunkbd->dev.private = sunkbd; + + serio->private = sunkbd; + + if (serio_open(serio, dev)) { + kfree(sunkbd); + return; + } + + if (sunkbd_initialize(sunkbd) < 0) { + serio_close(serio); + kfree(sunkbd); + return; + } + + sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type); + + memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); + for (i = 0; i < 255; i++) + set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); + clear_bit(0, sunkbd->dev.keybit); + + sprintf(sunkbd->name, "%s/input", serio->phys); + + sunkbd->dev.name = sunkbd->name; + sunkbd->dev.phys = sunkbd->phys; + sunkbd->dev.idbus = BUS_RS232; + sunkbd->dev.idvendor = SERIO_SUNKBD; + sunkbd->dev.idproduct = sunkbd->type; + sunkbd->dev.idversion = 0x0100; + + input_register_device(&sunkbd->dev); + + printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys); +} + +/* + * sunkbd_disconnect() unregisters and closes behind us. + */ + +static void sunkbd_disconnect(struct serio *serio) +{ + struct sunkbd *sunkbd = serio->private; + input_unregister_device(&sunkbd->dev); + serio_close(serio); + kfree(sunkbd); +} + +static struct serio_dev sunkbd_dev = { + interrupt: sunkbd_interrupt, + connect: sunkbd_connect, + disconnect: sunkbd_disconnect +}; + +/* + * The functions for insering/removing us as a module. + */ + +int __init sunkbd_init(void) +{ + serio_register_device(&sunkbd_dev); + return 0; +} + +void __exit sunkbd_exit(void) +{ + serio_unregister_device(&sunkbd_dev); +} + +module_init(sunkbd_init); +module_exit(sunkbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/keyboard/xtkbd.c linux-2.5/drivers/input/keyboard/xtkbd.c --- linux-2.5.20/drivers/input/keyboard/xtkbd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/keyboard/xtkbd.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,157 @@ +/* + * $Id: xtkbd.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * XT keyboard driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("XT keyboard driver"); +MODULE_LICENSE("GPL"); + +#define XTKBD_EMUL0 0xe0 +#define XTKBD_EMUL1 0xe1 +#define XTKBD_KEY 0x7f +#define XTKBD_RELEASE 0x80 + +static unsigned char xtkbd_keycode[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 0, 0, 0, 87, 88, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 87, 88, 0, 0, 0, 0,110,111,103,108,105, + 106 +}; + +static char *xtkbd_name = "XT Keyboard"; + +struct xtkbd { + unsigned char keycode[256]; + struct input_dev dev; + struct serio *serio; + char phys[32]; +}; + +void xtkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct xtkbd *xtkbd = serio->private; + + switch (data) { + case XTKBD_EMUL0: + case XTKBD_EMUL1: + return; + default: + + if (xtkbd->keycode[data & XTKBD_KEY]) { + input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); + } else { + printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n", + data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed"); + } + } +} + +void xtkbd_connect(struct serio *serio, struct serio_dev *dev) +{ + struct xtkbd *xtkbd; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_XT) + return; + + if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL))) + return; + + memset(xtkbd, 0, sizeof(struct xtkbd)); + + xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + + xtkbd->serio = serio; + + xtkbd->dev.keycode = xtkbd->keycode; + xtkbd->dev.private = xtkbd; + + serio->private = xtkbd; + + if (serio_open(serio, dev)) { + kfree(xtkbd); + return; + } + + memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); + for (i = 0; i < 255; i++) + set_bit(xtkbd->keycode[i], xtkbd->dev.keybit); + clear_bit(0, xtkbd->dev.keybit); + + sprintf(xtkbd->phys, "%s/input0", serio->phys); + + xtkbd->dev.name = xtkbd_name; + xtkbd->dev.phys = xtkbd->phys; + xtkbd->dev.idbus = BUS_XTKBD; + xtkbd->dev.idvendor = 0x0001; + xtkbd->dev.idproduct = 0x0001; + xtkbd->dev.idversion = 0x0100; + + input_register_device(&xtkbd->dev); + + printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys); +} + +void xtkbd_disconnect(struct serio *serio) +{ + struct xtkbd *xtkbd = serio->private; + input_unregister_device(&xtkbd->dev); + serio_close(serio); + kfree(xtkbd); +} + +struct serio_dev xtkbd_dev = { + interrupt: xtkbd_interrupt, + connect: xtkbd_connect, + disconnect: xtkbd_disconnect +}; + +int __init xtkbd_init(void) +{ + serio_register_device(&xtkbd_dev); + return 0; +} + +void __exit xtkbd_exit(void) +{ + serio_unregister_device(&xtkbd_dev); +} + +module_init(xtkbd_init); +module_exit(xtkbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/Config.help linux-2.5/drivers/input/mouse/Config.help --- linux-2.5.20/drivers/input/mouse/Config.help Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/Config.help Thu Mar 28 00:08:14 2002 @@ -0,0 +1,87 @@ +CONFIG_INPUT_MOUSE + Say Y here, and a list of supported mice will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +CONFIG_MOUSE_PS2 + Say Y here if you have a PS/2 mouse connected to your system. This + includes the standard 2 or 3-button PS/2 mouse, as well as PS/2 + mice with wheels and extra buttons, Microsoft, Logitech or Genius + compatible. + + If unsure, say Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called psmouse.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_SERIAL + Say Y here if you have a serial (RS-232, COM port) mouse connected + to your system. This includes Sun, MouseSystems, Microsoft, + Logitech and all other compatible serial mice. + + If unsure, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sermouse.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_INPORT + Say Y here if you have an InPort, Microsoft or ATI XL busmouse. + They are rather rare these days. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called inport.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_ATIXL + Say Y here if your mouse is of the ATI XL variety. + +CONFIG_MOUSE_LOGIBM + Say Y here if you have a Logitech busmouse. + They are rather rare these days. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called logibm.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_PC110PAD + Say Y if you have the IBM PC-110 micro-notebook and want its + touchscreen supported. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pc110pad.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_MAPLE + Say Y if you have a DreamCast console and a mouse attached to + its Maple bus. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called maplemouse.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_AMIGA + Say Y here if you have an Amiga and want its native mouse + supported by the kernel. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called amimouse.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_ACORN + Say Y here if you have the Acorn RiscPC computer and want its + native mouse supported. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called rpcmouse.o. If you want to compile it as a + module, say M here and read . diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/Config.in linux-2.5/drivers/input/mouse/Config.in --- linux-2.5.20/drivers/input/mouse/Config.in Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/Config.in Thu Mar 28 00:08:14 2002 @@ -0,0 +1,24 @@ +# +# Mouse driver configuration +# + +bool 'Mice' CONFIG_INPUT_MOUSE + +dep_tristate ' PS/2 mouse' CONFIG_MOUSE_PS2 $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO +dep_tristate ' Serial mouse' CONFIG_MOUSE_SERIAL $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO + +dep_tristate ' InPort/MS/ATIXL busmouse' CONFIG_MOUSE_INPORT $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA +if [ "$CONFIG_MOUSE_INPORT" != "n" ]; then + bool ' ATI XL variant' CONFIG_MOUSE_ATIXL +fi +dep_tristate ' Logitech busmouse' CONFIG_MOUSE_LOGIBM $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA +dep_tristate ' IBM PC110 touchpad' CONFIG_MOUSE_PC110PAD $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA +if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then + dep_tristate ' Maple bus mouse' CONFIG_MOUSE_MAPLE $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_MAPLE +fi +if [ "$CONFIG_AMIGA" = "y" ]; then + dep_tristate ' Amiga mouse' CONFIG_MOUSE_AMIGA $CONFIG_INPUT $CONFIG_INPUT_MOUSE +fi +if [ "$CONFIG_ARCH_ACORN" = "y" ]; then + dep_tristate ' Acorn RiscPC mouse' CONFIG_MOUSE_ACORN $CONFIG_INPUT $CONFIG_INPUT_MOUSE +fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/Makefile linux-2.5/drivers/input/mouse/Makefile --- linux-2.5.20/drivers/input/mouse/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/Makefile Thu Mar 28 00:08:14 2002 @@ -0,0 +1,22 @@ +# +# Makefile for the mouse drivers. +# + +# The target object and module list name. + +O_TARGET := mousedrv.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o +obj-$(CONFIG_MOUSE_ACORN) += rpcmouse.o +obj-$(CONFIG_MOUSE_INPORT) += inport.o +obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o +obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o +obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o +obj-$(CONFIG_MOUSE_PS2) += psmouse.o +obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o + +# The global Rules.make. + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/amimouse.c linux-2.5/drivers/input/mouse/amimouse.c --- linux-2.5.20/drivers/input/mouse/amimouse.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/amimouse.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,147 @@ +/* + * $Id: amimouse.c,v 1.9 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Michael Rausch James Banks + * Matther Dillon David Giller + * Nathan Laredo Linus Torvalds + * Johan Myreen Jes Sorensen + * Russel King + */ + +/* + * Amiga mouse driver for Linux/m68k + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Amiga mouse driver"); +MODULE_LICENSE("GPL"); + +static int amimouse_used = 0; +static int amimouse_lastx, amimouse_lasty; +static struct input_dev amimouse_dev; + +static char *amimouse_name = "Amiga mouse"; +static char *amimouse_phys = "amimouse/input0"; + +static void amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp) +{ + unsigned short joy0dat, potgor; + int nx, ny, dx, dy; + + joy0dat = custom.joy0dat; + + nx = joy0dat & 0xff; + ny = joy0dat >> 8; + + dx = nx - amimouse_lastx; + dy = ny - amimouse_lasty; + + if (dx < -127) dx = (256 + nx) - lastx; + if (dx > 127) dx = (nx - 256) - lastx; + if (dy < -127) dy = (256 + ny) - lasty; + if (dy > 127) dy = (ny - 256) - lasty; + + amimouse_lastx = nx; + amimouse_lasty = ny; + + potgor = custom.potgor; + + input_report_rel(&amimouse_dev, REL_X, dx); + input_report_rel(&amimouse_dev, REL_Y, dy); + + input_report_key(&amimouse_dev, BTN_LEFT, ciaa.pra & 0x40); + input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100); + input_report_key(&amimouse_dev, BTN_RIGHT, potgor & 0x0400); +} + +static int amimouse_open(struct input_dev *dev) +{ + unsigned short joy0dat; + + if (amimouse_used++) + return 0; + + joy0dat = custom.joy0dat; + + amimouse_lastx = joy0dat & 0xff; + amimouse_lasty = joy0dat >> 8; + + if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", NULL)) { + amimouse_used--; + printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", amimouse_irq); + return -EBUSY; + } + + return 0; +} + +static void amimouse_close(struct input_dev *dev) +{ + if (!--amimouse_used) + free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt); +} + +static int __init amimouse_init(void) +{ + if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE)) + return -ENODEV; + + amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + amimouse_dev.open = amimouse_open; + amimouse_dev.close = amimouse_close; + + amimouse_dev.name = amimouse_name; + amimouse_dev.phys = amimouse_phys; + amimouse_dev.idbus = BUS_AMIGA; + amimouse_dev.idvendor = 0x0001; + amimouse_dev.idproduct = 0x0002; + amimouse_dev.idversion = 0x0100; + + input_register_device(&amimouse_dev); + + printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name); +} + +static void __exit amimouse_exit(void) +{ + input_unregister_device(&amimouse_dev); +} + +module_init(amimouse_init); +module_exit(amimouse_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/inport.c linux-2.5/drivers/input/mouse/inport.c --- linux-2.5.20/drivers/input/mouse/inport.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/inport.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,193 @@ +/* + * $Id: inport.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + * + * Based on the work of: + * Teemu Rantanen Derrick Cole + * Peter Cervasio Christoph Niemann + * Philip Blundell Russell King + * Bob Harris + */ + +/* + * Inport (ATI XL and Microsoft) busmouse driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver"); +MODULE_LICENSE("GPL"); + +#define INPORT_BASE 0x23c +#define INPORT_EXTENT 4 + +#define INPORT_CONTROL_PORT INPORT_BASE + 0 +#define INPORT_DATA_PORT INPORT_BASE + 1 +#define INPORT_SIGNATURE_PORT INPORT_BASE + 2 + +#define INPORT_REG_BTNS 0x00 +#define INPORT_REG_X 0x01 +#define INPORT_REG_Y 0x02 +#define INPORT_REG_MODE 0x07 +#define INPORT_RESET 0x80 + +#ifdef CONFIG_INPUT_ATIXL +#define INPORT_NAME "ATI XL Mouse" +#define INPORT_VENDOR 0x0002 +#define INPORT_SPEED_30HZ 0x01 +#define INPORT_SPEED_50HZ 0x02 +#define INPORT_SPEED_100HZ 0x03 +#define INPORT_SPEED_200HZ 0x04 +#define INPORT_MODE_BASE INPORT_SPEED_100HZ +#define INPORT_MODE_IRQ 0x08 +#else +#define INPORT_NAME "Microsoft InPort Mouse" +#define INPORT_VENDOR 0x0001 +#define INPORT_MODE_BASE 0x10 +#define INPORT_MODE_IRQ 0x01 +#endif +#define INPORT_MODE_HOLD 0x20 + +#define INPORT_IRQ 5 + +MODULE_PARM(inport_irq, "i"); + +static int inport_irq = INPORT_IRQ; +static int inport_used = 0; + +static void inport_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +static int inport_open(struct input_dev *dev) +{ + if (!inport_used++) { + if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL)) + return -EBUSY; + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); + } + + return 0; +} + +static void inport_close(struct input_dev *dev) +{ + if (!--inport_used) { + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_BASE, INPORT_DATA_PORT); + free_irq(inport_irq, NULL); + } +} + +static struct input_dev inport_dev = { + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, + keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, + relbit: { BIT(REL_X) | BIT(REL_Y) }, + open: inport_open, + close: inport_close, + name: INPORT_NAME, + phys: "isa023c/input0", + idbus: BUS_ISA, + idvendor: INPORT_VENDOR, + idproduct: 0x0001, + idversion: 0x0100, +}; + +static void inport_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned char buttons; + + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); + + outb(INPORT_REG_X, INPORT_CONTROL_PORT); + input_report_rel(&inport_dev, REL_X, inb(INPORT_DATA_PORT)); + + outb(INPORT_REG_Y, INPORT_CONTROL_PORT); + input_report_rel(&inport_dev, REL_Y, inb(INPORT_DATA_PORT)); + + outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT); + buttons = inb(INPORT_DATA_PORT); + + input_report_key(&inport_dev, BTN_MIDDLE, buttons & 1); + input_report_key(&inport_dev, BTN_LEFT, buttons & 2); + input_report_key(&inport_dev, BTN_RIGHT, buttons & 4); + + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); +} + +#ifndef MODULE +static int __init inport_setup(char *str) +{ + int ints[4]; + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) inport_irq = ints[1]; + return 1; +} +__setup("inport_irq=", inport_setup); +#endif + +static int __init inport_init(void) +{ + unsigned char a,b,c; + + if (check_region(INPORT_BASE, INPORT_EXTENT)) + return -EBUSY; + + a = inb(INPORT_SIGNATURE_PORT); + b = inb(INPORT_SIGNATURE_PORT); + c = inb(INPORT_SIGNATURE_PORT); + if (( a == b ) || ( a != c )) + return -ENODEV; + + outb(INPORT_RESET, INPORT_CONTROL_PORT); + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_BASE, INPORT_DATA_PORT); + + request_region(INPORT_BASE, INPORT_EXTENT, "inport"); + + input_register_device(&inport_dev); + + printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n", + INPORT_BASE, inport_irq); + + return 0; +} + +static void __exit inport_exit(void) +{ + input_unregister_device(&inport_dev); + release_region(INPORT_BASE, INPORT_EXTENT); +} + +module_init(inport_init); +module_exit(inport_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/logibm.c linux-2.5/drivers/input/mouse/logibm.c --- linux-2.5.20/drivers/input/mouse/logibm.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/logibm.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,182 @@ +/* + * $Id: logibm.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + * + * Based on the work of: + * James Banks Matthew Dillon + * David Giller Nathan Laredo + * Linus Torvalds Johan Myreen + * Cliff Matthews Philip Blundell + * Russell King + */ + +/* + * Logitech Bus Mouse Driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Logitech busmouse driver"); +MODULE_LICENSE("GPL"); + +#define LOGIBM_BASE 0x23c +#define LOGIBM_EXTENT 4 + +#define LOGIBM_DATA_PORT LOGIBM_BASE + 0 +#define LOGIBM_SIGNATURE_PORT LOGIBM_BASE + 1 +#define LOGIBM_CONTROL_PORT LOGIBM_BASE + 2 +#define LOGIBM_CONFIG_PORT LOGIBM_BASE + 3 + +#define LOGIBM_ENABLE_IRQ 0x00 +#define LOGIBM_DISABLE_IRQ 0x10 +#define LOGIBM_READ_X_LOW 0x80 +#define LOGIBM_READ_X_HIGH 0xa0 +#define LOGIBM_READ_Y_LOW 0xc0 +#define LOGIBM_READ_Y_HIGH 0xe0 + +#define LOGIBM_DEFAULT_MODE 0x90 +#define LOGIBM_CONFIG_BYTE 0x91 +#define LOGIBM_SIGNATURE_BYTE 0xa5 + +#define LOGIBM_IRQ 5 + +MODULE_PARM(logibm_irq, "i"); + +static int logibm_irq = LOGIBM_IRQ; +static int logibm_used = 0; + +static void logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +static int logibm_open(struct input_dev *dev) +{ + if (logibm_used++) + return 0; + if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) { + logibm_used--; + printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq); + return -EBUSY; + } + outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); + return 0; +} + +static void logibm_close(struct input_dev *dev) +{ + if (--logibm_used) + return; + outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); + free_irq(logibm_irq, NULL); +} + +static struct input_dev logibm_dev = { + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, + keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, + relbit: { BIT(REL_X) | BIT(REL_Y) }, + open: logibm_open, + close: logibm_close, + name: "Logitech bus mouse", + phys: "isa023c/input0", + idbus: BUS_ISA, + idvendor: 0x0003, + idproduct: 0x0001, + idversion: 0x0100, +}; + +static void logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + char dx, dy; + unsigned char buttons; + + outb(LOGIBM_READ_X_LOW, LOGIBM_CONTROL_PORT); + dx = (inb(LOGIBM_DATA_PORT) & 0xf); + outb(LOGIBM_READ_X_HIGH, LOGIBM_CONTROL_PORT); + dx |= (inb(LOGIBM_DATA_PORT) & 0xf) << 4; + outb(LOGIBM_READ_Y_LOW, LOGIBM_CONTROL_PORT); + dy = (inb(LOGIBM_DATA_PORT) & 0xf); + outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT); + buttons = inb(LOGIBM_DATA_PORT); + dy |= (buttons & 0xf) << 4; + buttons = ~buttons; + + input_report_rel(&logibm_dev, REL_X, dx); + input_report_rel(&logibm_dev, REL_Y, 255 - dy); + input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 1); + input_report_key(&logibm_dev, BTN_LEFT, buttons & 2); + input_report_key(&logibm_dev, BTN_RIGHT, buttons & 4); +} + +#ifndef MODULE +static int __init logibm_setup(char *str) +{ + int ints[4]; + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) logibm_irq = ints[1]; + return 1; +} +__setup("logibm_irq=", logibm_setup); +#endif + +static int __init logibm_init(void) +{ + if (request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) { + printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE); + return -EBUSY; + } + + outb(LOGIBM_CONFIG_BYTE, LOGIBM_CONFIG_PORT); + outb(LOGIBM_SIGNATURE_BYTE, LOGIBM_SIGNATURE_PORT); + udelay(100); + + if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) { + release_region(LOGIBM_BASE, LOGIBM_EXTENT); + printk(KERN_ERR "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE); + return -ENODEV; + } + + outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT); + outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); + + input_register_device(&logibm_dev); + + printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq); + + return 0; +} + +static void __exit logibm_exit(void) +{ + input_unregister_device(&logibm_dev); + release_region(LOGIBM_BASE, LOGIBM_EXTENT); +} + +module_init(logibm_init); +module_exit(logibm_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/maplemouse.c linux-2.5/drivers/input/mouse/maplemouse.c --- linux-2.5.20/drivers/input/mouse/maplemouse.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/maplemouse.c Fri Feb 15 18:03:10 2002 @@ -0,0 +1,137 @@ +/* + * $Id: maplemouse.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $ + * SEGA Dreamcast mouse driver + * Based on drivers/usb/usbmouse.c + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("YAEGASHI Takeshi "); +MODULE_DESCRIPTION("SEGA Dreamcast mouse driver"); + +struct dc_mouse { + struct input_dev dev; + int open; +}; + + +static void dc_mouse_callback(struct mapleq *mq) +{ + int buttons, relx, rely, relz; + struct maple_device *mapledev = mq->dev; + struct dc_mouse *mouse = mapledev->private_data; + struct input_dev *dev = &mouse->dev; + unsigned char *res = mq->recvbuf; + + buttons = ~res[8]; + relx=*(unsigned short *)(res+12)-512; + rely=*(unsigned short *)(res+14)-512; + relz=*(unsigned short *)(res+16)-512; + + input_report_key(dev, BTN_LEFT, buttons&4); + input_report_key(dev, BTN_MIDDLE, buttons&9); + input_report_key(dev, BTN_RIGHT, buttons&2); + input_report_rel(dev, REL_X, relx); + input_report_rel(dev, REL_Y, rely); + input_report_rel(dev, REL_WHEEL, relz); +} + + +static int dc_mouse_open(struct input_dev *dev) +{ + struct dc_mouse *mouse = dev->private; + mouse->open++; + return 0; +} + + +static void dc_mouse_close(struct input_dev *dev) +{ + struct dc_mouse *mouse = dev->private; + mouse->open--; +} + + +static int dc_mouse_connect(struct maple_device *dev) +{ + unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); + struct dc_mouse *mouse; + + if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL))) + return -1; + memset(mouse, 0, sizeof(struct dc_mouse)); + + dev->private_data = mouse; + + mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); + + mouse->dev.private = mouse; + mouse->dev.open = dc_mouse_open; + mouse->dev.close = dc_mouse_close; + mouse->dev.event = NULL; + + mouse->dev.name = dev->product_name; + mouse->dev.idbus = BUS_MAPLE; + + input_register_device(&mouse->dev); + + maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE); + + printk(KERN_INFO "input%d: mouse(0x%lx): %s\n", + mouse->dev.number, data, mouse->dev.name); + + MOD_INC_USE_COUNT; + + return 0; +} + + +static void dc_mouse_disconnect(struct maple_device *dev) +{ + struct dc_mouse *mouse = dev->private_data; + + input_unregister_device(&mouse->dev); + + kfree(mouse); + + MOD_DEC_USE_COUNT; +} + + +static struct maple_driver dc_mouse_driver = { + function: MAPLE_FUNC_MOUSE, + name: "Dreamcast mouse", + connect: dc_mouse_connect, + disconnect: dc_mouse_disconnect, +}; + + +static int __init dc_mouse_init(void) +{ + maple_register_driver(&dc_mouse_driver); + return 0; +} + + +static void __exit dc_mouse_exit(void) +{ + maple_unregister_driver(&dc_mouse_driver); +} + + +module_init(dc_mouse_init); +module_exit(dc_mouse_exit); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/pc110pad.c linux-2.5/drivers/input/mouse/pc110pad.c --- linux-2.5.20/drivers/input/mouse/pc110pad.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/pc110pad.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,163 @@ +/* + * $Id: pc110pad.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Alan Cox Robin O'Leary + */ + +/* + * IBM PC110 touchpad driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("IBM PC110 touchpad driver"); +MODULE_LICENSE("GPL"); + +#define PC110PAD_OFF 0x30 +#define PC110PAD_ON 0x38 + +static int pc110pad_irq = 10; +static int pc110pad_io = 0x15e0; + +static struct input_dev pc110pad_dev; +static int pc110pad_data[3]; +static int pc110pad_count; +static int pc110pad_used; + +static char *pc110pad_name = "IBM PC110 TouchPad"; +static char *pc110pad_phys = "isa15e0/input0"; + +static void pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + int value = inb_p(pc110pad_io); + int handshake = inb_p(pc110pad_io + 2); + + outb_p(handshake | 1, pc110pad_io + 2); + outb_p(handshake & ~1, pc110pad_io + 2); + inb_p(0x64); + + pc110pad_data[pc110pad_count++] = value; + + if (pc110pad_count < 3) return; + + input_report_key(&pc110pad_dev, BTN_TOUCH, + pc110pad_data[0] & 0x01); + input_report_abs(&pc110pad_dev, ABS_X, + pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100)); + input_report_abs(&pc110pad_dev, ABS_Y, + pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80)); + + pc110pad_count = 0; +} + +static void pc110pad_close(struct input_dev *dev) +{ + if (!--pc110pad_used) + outb(PC110PAD_OFF, pc110pad_io + 2); +} + +static int pc110pad_open(struct input_dev *dev) +{ + unsigned long flags; + + if (pc110pad_used++) + return 0; + + save_flags(flags); + cli(); + pc110pad_interrupt(0,0,0); + pc110pad_interrupt(0,0,0); + pc110pad_interrupt(0,0,0); + outb(PC110PAD_ON, pc110pad_io + 2); + pc110pad_count = 0; + restore_flags(flags); + + return 0; +} + +static int __init pc110pad_init(void) +{ + if (request_region(pc110pad_io, 4, "pc110pad")) + { + printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", pc110pad_io, pc110pad_io + 4); + return -EBUSY; + } + + outb(PC110PAD_OFF, pc110pad_io + 2); + + if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", 0)) + { + release_region(pc110pad_io, 4); + printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq); + return -EBUSY; + } + + pc110pad_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + pc110pad_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + pc110pad_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + pc110pad_dev.absmax[ABS_X] = 0x1ff; + pc110pad_dev.absmax[ABS_Y] = 0x0ff; + + pc110pad_dev.open = pc110pad_open; + pc110pad_dev.close = pc110pad_close; + + pc110pad_dev.name = pc110pad_name; + pc110pad_dev.phys = pc110pad_phys; + pc110pad_dev.idbus = BUS_ISA; + pc110pad_dev.idvendor = 0x0003; + pc110pad_dev.idproduct = 0x0001; + pc110pad_dev.idversion = 0x0100; + + input_register_device(&pc110pad_dev); + + printk(KERN_INFO "input: %s at %#x irq %d\n", + pc110pad_name, pc110pad_io, pc110pad_irq); + + return 0; +} + +static void __exit pc110pad_exit(void) +{ + input_unregister_device(&pc110pad_dev); + + outb(PC110PAD_OFF, pc110pad_io + 2); + + free_irq(pc110pad_irq, 0); + release_region(pc110pad_io, 4); +} + +module_init(pc110pad_init); +module_exit(pc110pad_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/psmouse.c linux-2.5/drivers/input/mouse/psmouse.c --- linux-2.5.20/drivers/input/mouse/psmouse.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/psmouse.c Tue Jan 29 18:23:52 2002 @@ -0,0 +1,651 @@ +/* + * $Id: psmouse.c,v 1.16 2002/01/26 19:20:36 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("PS/2 mouse driver"); +MODULE_LICENSE("GPL"); + +#define PSMOUSE_CMD_SETSCALE11 0x00e6 +#define PSMOUSE_CMD_SETRES 0x10e8 +#define PSMOUSE_CMD_GETINFO 0x03e9 +#define PSMOUSE_CMD_SETSTREAM 0x00ea +#define PSMOUSE_CMD_POLL 0x03eb +#define PSMOUSE_CMD_GETID 0x01f2 +#define PSMOUSE_CMD_SETRATE 0x10f3 +#define PSMOUSE_CMD_ENABLE 0x00f4 +#define PSMOUSE_CMD_RESET_DIS 0x00f6 + +#define PSMOUSE_RET_BAT 0xaa +#define PSMOUSE_RET_ACK 0xfa +#define PSMOUSE_RET_NAK 0xfe + +struct psmouse { + struct input_dev dev; + struct serio *serio; + char *vendor; + char *name; + struct tq_struct tq; + unsigned char cmdbuf[8]; + unsigned char packet[8]; + unsigned char cmdcnt; + unsigned char pktcnt; + unsigned char type; + unsigned long last; + char acking; + char ack; + char error; + char devname[64]; + char phys[32]; +}; + +#define PSMOUSE_PS2 1 +#define PSMOUSE_PS2PP 2 +#define PSMOUSE_PS2TPP 3 +#define PSMOUSE_GENPS 4 +#define PSMOUSE_IMPS 5 +#define PSMOUSE_IMEX 6 + +static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2" }; + +/* + * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and + * reports relevant events to the input module. + */ + +static void psmouse_process_packet(struct psmouse *psmouse) +{ + struct input_dev *dev = &psmouse->dev; + unsigned char *packet = psmouse->packet; + +/* + * The PS2++ protocol is a little bit complex + */ + + if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) { + + if ((packet[0] & 0x40) == 0x40 && (int) packet[1] - (int) ((packet[0] & 0x10) << 4) > 191 ) { + + switch (((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0)) { + + case 1: /* Mouse extra info */ + + input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, + (int) (packet[2] & 7) - (int) (packet[2] & 8)); + input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); + input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); + + break; + + case 3: /* TouchPad extra info */ + + input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, + (int) ((packet[2] >> 4) & 7) - (int) ((packet[2] >> 4) & 8)); + packet[0] = packet[2] | 0x08; + + break; + + default: + + printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", + ((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0)); + + } + + packet[0] &= 0x0f; + packet[1] = 0; + packet[2] = 0; + + } + } + +/* + * Scroll wheel on IntelliMice, scroll buttons on NetMice + */ + + if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS) + input_report_rel(dev, REL_WHEEL, (signed char) packet[3]); + +/* + * Scroll wheel and buttons on IntelliMouse Explorer + */ + + if (psmouse->type == PSMOUSE_IMEX) { + input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 7) - (int) (packet[2] & 8)); + input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); + input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); + } + +/* + * Extra buttons on Genius NewNet 3D + */ + + if (psmouse->type == PSMOUSE_GENPS) { + input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1); + input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1); + } + +/* + * Generic PS/2 Mouse + */ + + input_report_key(dev, BTN_LEFT, packet[0] & 1); + input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); + input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); + + input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0); + input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); + +} + +/* + * psmouse_interrupt() handles incoming characters, either gathering them into + * packets or passing them to the command routine as command output. + */ + +static void psmouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct psmouse *psmouse = serio->private; + + if (psmouse->acking) { + switch (data) { + case PSMOUSE_RET_ACK: + psmouse->ack = 1; + break; + case PSMOUSE_RET_NAK: + psmouse->ack = -1; + break; + default: + psmouse->ack = 1; /* Workaround for mice which don't ACK the Get ID command */ + if (psmouse->cmdcnt) + psmouse->cmdbuf[--psmouse->cmdcnt] = data; + break; + } + psmouse->acking = 0; + return; + } + + if (psmouse->cmdcnt) { + psmouse->cmdbuf[--psmouse->cmdcnt] = data; + return; + } + + if (psmouse->pktcnt && jiffies - psmouse->last > 2) { + printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt); + psmouse->pktcnt = 0; + } + + psmouse->last = jiffies; + psmouse->packet[psmouse->pktcnt++] = data; + + if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) { + if ((psmouse->packet[0] & 0x08) == 0x08) psmouse_process_packet(psmouse); + psmouse->pktcnt = 0; + return; + } + + if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) { + queue_task(&psmouse->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; + } +} + +/* + * psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge. + * It doesn't handle retransmission, though it could - because when there would + * be need for retransmissions, the mouse has to be replaced anyway. + */ + +static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte) +{ + int timeout = 1000; /* 10 msec */ + psmouse->ack = 0; + psmouse->acking = 1; + + serio_write(psmouse->serio, byte); + while (!psmouse->ack && timeout--) udelay(10); + + return -(psmouse->ack <= 0); +} + +/* + * psmouse_command() sends a command and its parameters to the mouse, + * then waits for the response and puts it in the param array. + */ + +static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) +{ + int timeout = 100000; /* 100 msec */ + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + int i; + + psmouse->cmdcnt = receive; + + if (command & 0xff) + if (psmouse_sendbyte(psmouse, command & 0xff)) + return (psmouse->cmdcnt = 0) - 1; + + for (i = 0; i < send; i++) + if (psmouse_sendbyte(psmouse, param[i])) + return (psmouse->cmdcnt = 0) - 1; + + while (psmouse->cmdcnt && timeout--) udelay(1); + + for (i = 0; i < receive; i++) + param[i] = psmouse->cmdbuf[(receive - 1) - i]; + + if (psmouse->cmdcnt) + return (psmouse->cmdcnt = 0) - 1; + + return 0; +} + +/* + * psmouse_ps2pp_cmd() sends a PS2++ command, sliced into two bit + * pieces through the SETRES command. This is needed to send extended + * commands to mice on notebooks that try to understand the PS/2 protocol + * Ugly. + */ + +static int psmouse_ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) +{ + unsigned char d; + int i; + + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) + return -1; + + for (i = 6; i >= 0; i -= 2) { + d = (command >> i) & 3; + if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES)) + return -1; + } + + if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) + return -1; + + return 0; +} + +/* + * psmouse_extensions() probes for any extensions to the basic PS/2 protocol + * the mouse may have. + */ + +static int psmouse_extensions(struct psmouse *psmouse) +{ + unsigned char param[4]; + + param[0] = 0; + psmouse->vendor = "Generic"; + psmouse->name = "Mouse"; + +/* + * Try Genius NetMouse magic init. + */ + + param[0] = 3; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + + if (param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55) { + psmouse->vendor = "Genius"; + psmouse->name = "Mouse"; + + set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(REL_WHEEL, psmouse->dev.relbit); + + return PSMOUSE_GENPS; + } + +/* + * Try Logitech magic ID. + */ + + param[0] = 0; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + + if (param[1]) { + + int i; + static int logitech_4btn[] = { 12, 40, 41, 42, 43, 73, 80, -1 }; + static int logitech_wheel[] = { 75, 76, 80, 81, 83, 88, -1 }; + static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75, + 76, 80, 81, 83, 88, 96, 97, -1 }; + + int devicetype = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); + + psmouse->vendor = "Logitech"; + psmouse->name = "Mouse"; + + if (param[1] < 3) + clear_bit(BTN_MIDDLE, psmouse->dev.keybit); + if (param[1] < 2) + clear_bit(BTN_RIGHT, psmouse->dev.keybit); + + psmouse->type = PSMOUSE_PS2; + + for (i = 0; logitech_ps2pp[i] != -1; i++) + if (logitech_ps2pp[i] == devicetype) psmouse->type = PSMOUSE_PS2PP; + + if (psmouse->type != PSMOUSE_PS2PP) return PSMOUSE_PS2; + + for (i = 0; logitech_4btn[i] != -1; i++) + if (logitech_4btn[i] == devicetype) set_bit(BTN_SIDE, psmouse->dev.keybit); + + for (i = 0; logitech_wheel[i] != -1; i++) + if (logitech_wheel[i] == devicetype) set_bit(REL_WHEEL, psmouse->dev.relbit); + +/* + * Do Logitech PS2++ / PS2T++ magic init. + */ + + if (devicetype == 97) { /* TouchPad 3 */ + + set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(REL_HWHEEL, psmouse->dev.relbit); + + param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ + psmouse_command(psmouse, param, 0x30d1); + param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ + psmouse_command(psmouse, param, 0x30d1); + param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ + psmouse_command(psmouse, param, 0x30d1); + + param[0] = 0; + if (!psmouse_command(psmouse, param, 0x13d1) && + param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) + return PSMOUSE_PS2TPP; + + } else { + psmouse_ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ + psmouse_ps2pp_cmd(psmouse, param, 0xDB); + + if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && + (param[2] & 3) == ((param[1] >> 2) & 3)) + return PSMOUSE_PS2PP; + } + + } + +/* + * Try IntelliMouse magic init. + */ + + param[0] = 200; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + param[0] = 100; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + param[0] = 80; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETID); + + if (param[0] == 3) { + + set_bit(REL_WHEEL, psmouse->dev.relbit); + +/* + * Try IntelliMouse Explorer magic init. + */ + + param[0] = 200; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + param[0] = 200; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + param[0] = 80; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETID); + + if (param[0] == 4) { + + psmouse->vendor = "Microsoft"; + psmouse->name = "IntelliMouse Explorer"; + + set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(BTN_EXTRA, psmouse->dev.keybit); + + return PSMOUSE_IMEX; + } + + psmouse->vendor = "Microsoft"; + psmouse->name = "IntelliMouse"; + + return PSMOUSE_IMPS; + } + +/* + * Okay, all failed, we have a standard mouse here. The number of the buttons is + * still a question, though. + */ + + psmouse->vendor = "Generic"; + psmouse->name = "Mouse"; + + return PSMOUSE_PS2; +} + +/* + * psmouse_probe() probes for a PS/2 mouse. + */ + +static int psmouse_probe(struct psmouse *psmouse) +{ + unsigned char param[2]; + +/* + * First we reset and disable the mouse. + */ + + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) + return -1; + +/* + * Next, we check if it's a mouse. It should send 0x00 or 0x03 + * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer. + */ + + param[0] = param[1] = 0xa5; + + if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID)) + return -1; + + if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04) + return -1; + +/* + * And here we try to determine if it has any extensions over the + * basic PS/2 3-button mouse. + */ + + return psmouse->type = psmouse_extensions(psmouse); +} + +/* + * psmouse_initialize() initializes the mouse to a sane state. + */ + +static void psmouse_initialize(struct psmouse *psmouse) +{ + unsigned char param[2]; + +/* + * We set the mouse report rate to a highest possible value. + * We try 100 first in case mouse fails to set 200. + */ + + param[0] = 100; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + + param[0] = 200; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + +/* + * We also set the resolution and scaling. + */ + + param[0] = 3; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + +/* + * We set the mouse into streaming mode. + */ + + psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM); + +/* + * Last, we enable the mouse so that we get reports from it. + */ + + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) { + printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys); + } + +} + +/* + * psmouse_disconnect() cleans up after we don't want talk + * to the mouse anymore. + */ + +static void psmouse_disconnect(struct serio *serio) +{ + struct psmouse *psmouse = serio->private; + input_unregister_device(&psmouse->dev); + serio_close(serio); + kfree(psmouse); +} + +/* + * psmouse_powerup() is called when we get the powerup + * sequence - 0xaa [0x00], so that the mouse/kbd is re-probed. + */ + +static void psmouse_powerup(void *data) +{ + struct psmouse *psmouse = data; + + if (psmouse->packet[0] == PSMOUSE_RET_BAT && (psmouse->pktcnt == 1 || + (psmouse->pktcnt == 2 && psmouse->packet[1] == 0x00))) { + mdelay(40); /* FIXME!!! Wait some nicer way */ + serio_rescan(psmouse->serio); + } +} + +/* + * psmouse_connect() is a callback form the serio module when + * an unhandled serio port is found. + */ + +static void psmouse_connect(struct serio *serio, struct serio_dev *dev) +{ + struct psmouse *psmouse; + + if ((serio->type & SERIO_TYPE) != SERIO_8042) + return; + + if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) + return; + + memset(psmouse, 0, sizeof(struct psmouse)); + + psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + + psmouse->serio = serio; + psmouse->dev.private = psmouse; + psmouse->tq.routine = psmouse_powerup; + psmouse->tq.data = psmouse; + + serio->private = psmouse; + + if (serio_open(serio, dev)) { + kfree(psmouse); + return; + } + + if (psmouse_probe(psmouse) <= 0) { + serio_close(serio); + kfree(psmouse); + return; + } + + sprintf(psmouse->devname, "%s %s %s", + psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); + sprintf(psmouse->phys, "%s/input0", + serio->phys); + + psmouse->dev.name = psmouse->devname; + psmouse->dev.phys = psmouse->phys; + psmouse->dev.idbus = BUS_I8042; + psmouse->dev.idvendor = psmouse->type; + psmouse->dev.idproduct = 0x0002; + psmouse->dev.idversion = 0x0100; + + input_register_device(&psmouse->dev); + + printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); + + psmouse_initialize(psmouse); +} + +static struct serio_dev psmouse_dev = { + interrupt: psmouse_interrupt, + connect: psmouse_connect, + disconnect: psmouse_disconnect +}; + +int __init psmouse_init(void) +{ + serio_register_device(&psmouse_dev); + return 0; +} + +void __exit psmouse_exit(void) +{ + serio_unregister_device(&psmouse_dev); +} + +module_init(psmouse_init); +module_exit(psmouse_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/rpcmouse.c linux-2.5/drivers/input/mouse/rpcmouse.c --- linux-2.5.20/drivers/input/mouse/rpcmouse.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/rpcmouse.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,111 @@ +/* + * $Id: rpcmouse.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Russel King + */ + +/* + * Acorn RiscPC mouse driver for Linux/ARM + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Acorn RiscPC mouse driver"); +MODULE_LICENSE("GPL"); + +#define IOMD_MOUSEBTN 0x800C4000 + +static short rpcmouse_lastx, rpcmouse_lasty; + +static struct input_dev rpcmouse_dev = { + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, + keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, + relbit: { BIT(REL_X) | BIT(REL_Y) }, + name: "Acorn RiscPC Mouse", + phys: "rpcmouse/input0", + idbus: BUS_ISA, + idvendor: 0x0005, + idproduct: 0x0001, + idversion: 0x0100, +}; + +static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + short x, y, dx, dy, b; + + x = (short) inl(IOMD_MOUSEX); + y = (short) inl(IOMD_MOUSEY); + b = (short) inl(IOMD_MOUSEBTN); + + dx = x - rpcmouse_lastx; + dy = y - rpcmouse_lasty; + + rpcmouse_lastx = x; + rpcmouse_lasty = y; + + input_report_rel(&rpcmouse_dev, REL_X, dx); + input_report_rel(&rpcmouse_dev, REL_Y, dy); + + input_report_key(&amimouse_dev, BTN_LEFT, buttons & 0x10); + input_report_key(&amimouse_dev, BTN_MIDDLE, buttons & 0x20); + input_report_key(&amimouse_dev, BTN_RIGHT, buttons & 0x40); +} + +static int __init rpcmouse_init(void) +{ + rpcmouse_lastx = (short) inl(IOMD_MOUSEX); + rpcmouse_lasty = (short) inl(IOMD_MOUSEY); + + if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", NULL)) { + printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n"); + return -1; + } + + input_register_device(&rpcmouse_dev); + printk(KERN_INFO "input%d: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE); + + return 0; +} + +static void __exit rpcmouse_exit(void) +{ + input_unregister_device(&rpcmouse_dev); + free_irq(IRQ_VSYNCPULSE, NULL); +} + +module_init(rpcmouse_init); +module_exit(rpcmouse_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/mouse/sermouse.c linux-2.5/drivers/input/mouse/sermouse.c --- linux-2.5.20/drivers/input/mouse/sermouse.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/mouse/sermouse.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,299 @@ +/* + * $Id: sermouse.c,v 1.15 2001/10/09 22:34:17 jsimmons Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * Serial mouse driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Serial mouse driver"); +MODULE_LICENSE("GPL"); + +static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", + "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse", + "Logitech MZ++ Mouse"}; + +struct sermouse { + struct input_dev dev; + signed char buf[8]; + unsigned char count; + unsigned char type; + unsigned long last; + char phys[32]; +}; + +/* + * sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and + * applies some prediction to the data, resulting in 96 updates per + * second, which is as good as a PS/2 or USB mouse. + */ + +static void sermouse_process_msc(struct sermouse *sermouse, signed char data) +{ + struct input_dev *dev = &sermouse->dev; + signed char *buf = sermouse->buf; + + switch (sermouse->count) { + + case 0: + if ((data & 0xf8) != 0x80) return; + input_report_key(dev, BTN_LEFT, !(data & 4)); + input_report_key(dev, BTN_RIGHT, !(data & 1)); + input_report_key(dev, BTN_MIDDLE, !(data & 2)); + break; + + case 1: + case 3: + input_report_rel(dev, REL_X, data / 2); + input_report_rel(dev, REL_Y, -buf[1]); + buf[0] = data - data / 2; + break; + + case 2: + case 4: + input_report_rel(dev, REL_X, buf[0]); + input_report_rel(dev, REL_Y, buf[1] - data); + buf[1] = data / 2; + break; + } + + if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1))) + sermouse->count = 0; +} + +/* + * sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and + * generates events. With prediction it gets 80 updates/sec, assuming + * standard 3-byte packets and 1200 bps. + */ + +static void sermouse_process_ms(struct sermouse *sermouse, signed char data) +{ + struct input_dev *dev = &sermouse->dev; + signed char *buf = sermouse->buf; + + if (data & 0x40) sermouse->count = 0; + + switch (sermouse->count) { + + case 0: + buf[1] = data; + input_report_key(dev, BTN_LEFT, (data >> 5) & 1); + input_report_key(dev, BTN_RIGHT, (data >> 4) & 1); + break; + + case 1: + buf[2] = data; + data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f)); + input_report_rel(dev, REL_X, data / 2); + input_report_rel(dev, REL_Y, buf[4]); + buf[3] = data - data / 2; + break; + + case 2: + /* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */ + if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1])) + input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key)); + buf[0] = buf[1]; + + data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f)); + input_report_rel(dev, REL_X, buf[3]); + input_report_rel(dev, REL_Y, data - buf[4]); + buf[4] = data / 2; + break; + + case 3: + + switch (sermouse->type) { + + case SERIO_MS: + sermouse->type = SERIO_MP; + + case SERIO_MP: + if ((data >> 2) & 3) break; /* M++ Wireless Extension packet. */ + input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1); + input_report_key(dev, BTN_SIDE, (data >> 4) & 1); + break; + + case SERIO_MZP: + case SERIO_MZPP: + input_report_key(dev, BTN_SIDE, (data >> 5) & 1); + + case SERIO_MZ: + input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1); + input_report_rel(dev, REL_WHEEL, (data & 7) - (data & 8)); + break; + } + + break; + + case 4: + case 6: /* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */ + buf[1] = (data >> 2) & 0x0f; + break; + + case 5: + case 7: /* Ignore anything besides MZ++ */ + if (sermouse->type != SERIO_MZPP) break; + + switch (buf[1]) { + + case 1: /* Extra mouse info */ + + input_report_key(dev, BTN_SIDE, (data >> 4) & 1); + input_report_key(dev, BTN_EXTRA, (data >> 5) & 1); + input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8)); + + break; + + default: /* We don't decode anything else yet. */ + + printk(KERN_WARNING + "sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]); + break; + } + + break; + } + + sermouse->count++; +} + +/* + * sermouse_interrupt() handles incoming characters, either gathering them into + * packets or passing them to the command routine as command output. + */ + +static void sermouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct sermouse *sermouse = serio->private; + + if (jiffies - sermouse->last > 2) sermouse->count = 0; + sermouse->last = jiffies; + + if (sermouse->type > SERIO_SUN) + sermouse_process_ms(sermouse, data); + else + sermouse_process_msc(sermouse, data); +} + +/* + * sermouse_disconnect() cleans up after we don't want talk + * to the mouse anymore. + */ + +static void sermouse_disconnect(struct serio *serio) +{ + struct sermouse *sermouse = serio->private; + input_unregister_device(&sermouse->dev); + serio_close(serio); + kfree(sermouse); +} + +/* + * sermouse_connect() is a callback form the serio module when + * an unhandled serio port is found. + */ + +static void sermouse_connect(struct serio *serio, struct serio_dev *dev) +{ + struct sermouse *sermouse; + unsigned char c; + + if ((serio->type & SERIO_TYPE) != SERIO_RS232) + return; + + if (!(serio->type & SERIO_PROTO) || ((serio->type & SERIO_PROTO) > SERIO_MZPP)) + return; + + if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL))) + return; + + memset(sermouse, 0, sizeof(struct sermouse)); + + sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); + sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + sermouse->dev.private = sermouse; + + serio->private = sermouse; + + sermouse->type = serio->type & SERIO_PROTO; + c = (serio->type & SERIO_EXTRA) >> 16; + + if (c & 0x01) set_bit(BTN_MIDDLE, &sermouse->dev.keybit); + if (c & 0x02) set_bit(BTN_SIDE, &sermouse->dev.keybit); + if (c & 0x04) set_bit(BTN_EXTRA, &sermouse->dev.keybit); + if (c & 0x10) set_bit(REL_WHEEL, &sermouse->dev.relbit); + if (c & 0x20) set_bit(REL_HWHEEL, &sermouse->dev.relbit); + + sprintf(sermouse->phys, "%s/input0", serio->phys); + + sermouse->dev.name = sermouse_protocols[sermouse->type]; + sermouse->dev.phys = sermouse->phys; + sermouse->dev.idbus = BUS_RS232; + sermouse->dev.idvendor = sermouse->type; + sermouse->dev.idproduct = c; + sermouse->dev.idversion = 0x0100; + + if (serio_open(serio, dev)) { + kfree(sermouse); + return; + } + + input_register_device(&sermouse->dev); + + printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); +} + +static struct serio_dev sermouse_dev = { + interrupt: sermouse_interrupt, + connect: sermouse_connect, + disconnect: sermouse_disconnect +}; + +int __init sermouse_init(void) +{ + serio_register_device(&sermouse_dev); + return 0; +} + +void __exit sermouse_exit(void) +{ + serio_unregister_device(&sermouse_dev); +} + +module_init(sermouse_init); +module_exit(sermouse_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/power.c linux-2.5/drivers/input/power.c --- linux-2.5.20/drivers/input/power.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/power.c Tue Jan 22 17:43:42 2002 @@ -0,0 +1,180 @@ +/* + * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $ + * + * Copyright (c) 2001 "Crazy" James Simmons + * + * Input driver Power Management. + * + * Sponsored by Transvirtual Technology. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct input_handler power_handler; + +/* + * Power management can't be done in a interrupt context. So we have to + * use keventd. + */ +static int suspend_button_pushed = 0; +static void suspend_button_task_handler(void *data) +{ + //extern void pm_do_suspend(void); + udelay(200); /* debounce */ + //pm_do_suspend(); + suspend_button_pushed = 0; +} + +static struct tq_struct suspend_button_task = { + routine: suspend_button_task_handler +}; + +static void power_event(struct input_handle *handle, unsigned int type, + unsigned int code, int down) +{ + struct input_dev *dev = handle->dev; + + printk("Entering power_event\n"); + + if (type != EV_KEY || type != EV_PWR) return; + + if (type == EV_PWR) { + switch (code) { + case KEY_SUSPEND: + printk("Powering down entire device\n"); + + //pm_send_all(PM_SUSPEND, dev); + + if (!suspend_button_pushed) { + suspend_button_pushed = 1; + schedule_task(&suspend_button_task); + } + break; + case KEY_POWER: + /* Hum power down the machine. */ + break; + default: + return; + } + } else { + switch (code) { + case KEY_SUSPEND: + printk("Powering down input device\n"); + /* This is risky. See pm.h for details. */ + if (dev->state != PM_RESUME) + dev->state = PM_RESUME; + else + dev->state = PM_SUSPEND; + pm_send(dev->pm_dev, dev->state, dev); + break; + case KEY_POWER: + /* Turn the input device off completely ? */ + break; + default: + return; + } + } + return; +} + +static struct input_handle *power_connect(struct input_handler *handler, + struct input_dev *dev, + struct input_device_id *id) +{ + struct input_handle *handle; + + if (!test_bit(EV_KEY, dev->evbit) || !test_bit(EV_PWR, dev->evbit)) + return NULL; + + if (!test_bit(KEY_SUSPEND, dev->keybit) || (!test_bit(KEY_POWER, dev->keybit))) + return NULL; + + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + return NULL; + memset(handle, 0, sizeof(struct input_handle)); + + handle->dev = dev; + handle->handler = handler; + + input_open_device(handle); + + printk(KERN_INFO "power.c: Adding power management to input layer\n"); + return handle; +} + +static void power_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + kfree(handle); +} + +static struct input_device_id power_ids[] = { + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + evbit: { BIT(EV_KEY) }, + keybit: { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) } + }, + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + evbit: { BIT(EV_KEY) }, + keybit: { [LONG(KEY_POWER)] = BIT(KEY_POWER) } + }, + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT, + evbit: { BIT(EV_PWR) }, + }, + { }, /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(input, power_ids); + +static struct input_handler power_handler = { + event: power_event, + connect: power_connect, + disconnect: power_disconnect, + name: "power", + id_table: power_ids, +}; + +static int __init power_init(void) +{ + input_register_handler(&power_handler); + return 0; +} + +static void __exit power_exit(void) +{ + input_unregister_handler(&power_handler); +} + +module_init(power_init); +module_exit(power_exit); + +MODULE_AUTHOR("James Simmons "); +MODULE_DESCRIPTION("Input Power Management driver"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/serio/Config.help linux-2.5/drivers/input/serio/Config.help --- linux-2.5.20/drivers/input/serio/Config.help Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/input/serio/Config.help Sun Jan 27 00:32:29 2002 @@ -12,6 +12,18 @@ The module will be called serio.o. If you want to compile it as a module, say M here and read . +CONFIG_SERIO_I8042 + i8042 is the chip over which the standard AT keyboard and PS/2 + mouse are connected to the computer. If you use these devices, + you'll need to say Y here. + + If unsure, say Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called i8042.o. If you want to compile it + as a module, say M here and read . + CONFIG_SERIO_SERPORT Say Y here if you plan to use an input device (mouse, joystick, tablet, 6dof) that communicates over the RS232 serial (COM) port. @@ -24,3 +36,38 @@ inserted in and removed from the running kernel whenever you want). The module will be called serport.o. If you want to compile it as a module, say M here and read . + +CONFIG_SERIO_CT82C710 + Say Y here if you have a Texas Instruments TravelMate notebook + equipped with the ct82c710 chip and want to use a mouse connected + to the "QuickPort". + + If unsure, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ct82c710.o. If you want to compile it as a + module, say M here and read . + +CONFIG_SERIO_PARKBD + Say Y here if you built a simple parallel port adapter to attach + an additional AT keyboard, XT keyboard or PS/2 mouse. + + More information is available: + + If unsure, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called parkbd.o. If you want to compile it as a + module, say M here and read . + +CONFIG_SERIO_ACORN + Say Y here if you have the Acorn RiscPC and want to use an AT + keyboard connected to its keyboard controller. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called rpckbd.o. If you want to compile it as a + module, say M here and read . + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/serio/Config.in linux-2.5/drivers/input/serio/Config.in --- linux-2.5.20/drivers/input/serio/Config.in Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/input/serio/Config.in Sun Feb 3 18:03:58 2002 @@ -4,4 +4,16 @@ tristate 'Serial i/o support' CONFIG_SERIO +dep_tristate ' i8042 PC Keyboard controller' CONFIG_SERIO_I8042 $CONFIG_SERIO $CONFIG_ISA +if [ "$CONFIG_INPUT_I8042" != "n" ]; then + hex ' Register Base Address' CONFIG_I8042_REG_BASE 60 + int ' PS/2 Keyboard IRQ' CONFIG_I8042_KBD_IRQ 1 + int ' PS/2 AUX IRQ' CONFIG_I8042_AUX_IRQ 12 +fi dep_tristate ' Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO +dep_tristate ' ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO $CONFIG_ISA +dep_tristate ' Parallel port keyboard adapter' CONFIG_SERIO_PARKBD $CONFIG_SERIO $CONFIG_PARPORT + +if [ "$CONFIG_ARCH_ACORN" = "y" ]; then + dep_tristate ' Acorn RiscPC keyboard controller' CONFIG_SERIO_ACORN $CONFIG_SERIO +fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/serio/Makefile linux-2.5/drivers/input/serio/Makefile --- linux-2.5.20/drivers/input/serio/Makefile Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/input/serio/Makefile Sat Jun 1 00:34:35 2002 @@ -9,7 +9,11 @@ # Each configuration option enables a list of files. obj-$(CONFIG_SERIO) += serio.o +obj-$(CONFIG_SERIO_I8042) += i8042.o +obj-$(CONFIG_SERIO_PARKBD) += parkbd.o obj-$(CONFIG_SERIO_SERPORT) += serport.o +obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o +obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/serio/ct82c710.c linux-2.5/drivers/input/serio/ct82c710.c --- linux-2.5.20/drivers/input/serio/ct82c710.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/serio/ct82c710.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,210 @@ +/* + * $Id: ct82c710.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * 82C710 C&T mouse port chip driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("82C710 C&T mouse port chip driver"); +MODULE_LICENSE("GPL"); + +static char ct82c710_name[] = "C&T 82c710 mouse port"; +static char ct82c710_phys[16]; + +/* + * ct82c710 interface + */ + +#define CT82C710_DEV_IDLE 0x01 /* Device Idle */ +#define CT82C710_RX_FULL 0x02 /* Device Char received */ +#define CT82C710_TX_IDLE 0x04 /* Device XMIT Idle */ +#define CT82C710_RESET 0x08 /* Device Reset */ +#define CT82C710_INTS_ON 0x10 /* Device Interrupt On */ +#define CT82C710_ERROR_FLAG 0x20 /* Device Error */ +#define CT82C710_CLEAR 0x40 /* Device Clear */ +#define CT82C710_ENABLE 0x80 /* Device Enable */ + +#define CT82C710_IRQ 12 + +static int ct82c710_data = 0; +static int ct82c710_status = 0; + +static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs); + +/* + * Wait for device to send output char and flush any input char. + */ + +static int ct82c170_wait(void) +{ + int timeout = 60000; + + while ((inb(ct82c710_status) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) + != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) { + + if (inb_p(ct82c710_status) & CT82C710_RX_FULL) inb_p(ct82c710_data); + + udelay(1); + timeout--; + } + + return !timeout; +} + +static void ct82c710_close(struct serio *serio) +{ + if (ct82c170_wait()) + printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); + + outb_p(inb_p(ct82c710_status) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), ct82c710_status); + + if (ct82c170_wait()) + printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); + + free_irq(CT82C710_IRQ, NULL); +} + +static int ct82c710_open(struct serio *serio) +{ + unsigned char status; + + if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL)) + return -1; + + status = inb_p(ct82c710_status); + + status |= (CT82C710_ENABLE | CT82C710_RESET); + outb_p(status, ct82c710_status); + + status &= ~(CT82C710_RESET); + outb_p(status, ct82c710_status); + + status |= CT82C710_INTS_ON; + outb_p(status, ct82c710_status); /* Enable interrupts */ + + while (ct82c170_wait()) { + printk(KERN_ERR "ct82c710: Device busy in open()\n"); + status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); + outb_p(status, ct82c710_status); + free_irq(CT82C710_IRQ, NULL); + return -1; + } + + return 0; +} + +/* + * Write to the 82C710 mouse device. + */ + +static int ct82c710_write(struct serio *port, unsigned char c) +{ + if (ct82c170_wait()) return -1; + outb_p(c, ct82c710_data); + return 0; +} + +static struct serio ct82c710_port = +{ + type: SERIO_8042, + name: ct82c710_name, + phys: ct82c710_phys, + write: ct82c710_write, + open: ct82c710_open, + close: ct82c710_close, +}; + +/* + * Interrupt handler for the 82C710 mouse port. A character + * is waiting in the 82C710. + */ + +static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) +{ + if (ct82c710_port.dev) + ct82c710_port.dev->interrupt(&ct82c710_port, inb(ct82c710_data), 0); +} + +/* + * See if we can find a 82C710 device. Read mouse address. + */ + +static int __init ct82c710_probe(void) +{ + outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ + outb_p(0xaa, 0x3fa); /* Inverse of 55 */ + outb_p(0x36, 0x3fa); /* Address the chip */ + outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ + outb_p(0x1b, 0x2fa); /* Inverse of e4 */ + outb_p(0x0f, 0x390); /* Write index */ + if (inb_p(0x391) != 0xe4) /* Config address found? */ + return -1; /* No: no 82C710 here */ + + outb_p(0x0d, 0x390); /* Write index */ + ct82c710_data = inb_p(0x391) << 2; /* Get mouse I/O address */ + ct82c710_status = ct82c710_data + 1; + outb_p(0x0f, 0x390); + outb_p(0x0f, 0x391); /* Close config mode */ + + return 0; +} + +int __init ct82c710_init(void) +{ + if (ct82c710_probe()) + return -ENODEV; + + if (request_region(ct82c710_data, 2, "ct82c710")) + return -EBUSY; + + sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data); + + serio_register_port(&ct82c710_port); + + printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n", + ct82c710_data, CT82C710_IRQ); + + return 0; +} + +void __exit ct82c710_exit(void) +{ + serio_unregister_port(&ct82c710_port); + release_region(ct82c710_data, 2); +} + +module_init(ct82c710_init); +module_exit(ct82c710_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/serio/i8042.c linux-2.5/drivers/input/serio/i8042.c --- linux-2.5.20/drivers/input/serio/i8042.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/serio/i8042.c Tue Jan 29 18:23:52 2002 @@ -0,0 +1,707 @@ +/* + * $Id: i8042.c,v 1.15 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * i8042 keyboard and mouse controller driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "i8042.h" + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(i8042_noaux, "1i"); +MODULE_PARM(i8042_unlock, "1i"); +MODULE_PARM(i8042_reset, "1i"); +MODULE_PARM(i8042_direct, "1i"); + +static int i8042_noaux; +static int i8042_unlock; +static int i8042_reset; +static int i8042_direct; + +spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED; + +struct i8042_values { + int irq; + unsigned char disable; + unsigned char irqen; + unsigned char exists; + unsigned char *name; + unsigned char *phys; +}; + +static struct serio i8042_kbd_port; +static struct serio i8042_aux_port; +static unsigned char i8042_initial_ctr; +static unsigned char i8042_ctr; + +#ifdef I8042_DEBUG_IO +static unsigned long i8042_start; +#endif + +static unsigned long i8042_unxlate_seen[128 / BITS_PER_LONG]; +static unsigned char i8042_unxlate_table[128] = { + 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, + 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, + 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, + 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, + 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, + 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, + 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, + 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 +}; + +static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* + * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to + * be ready for reading values from it / writing values to it. + */ + +static int i8042_wait_read(void) +{ + int i = 0; + while ((~inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { + udelay(50); + i++; + } + return -(i == I8042_CTL_TIMEOUT); +} + +static int i8042_wait_write(void) +{ + int i = 0; + while ((inb(I8042_STATUS_REG) & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { + udelay(50); + i++; + } + return -(i == I8042_CTL_TIMEOUT); +} + +/* + * i8042_flush() flushes all data that may be in the keyboard and mouse buffers + * of the i8042 down the toilet. + */ + +static int i8042_flush(void) +{ + unsigned long flags; + int i = 0; + + spin_lock_irqsave(&i8042_lock, flags); + + while ((inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x <- i8042 (flush) [%d]\n", + inb(I8042_DATA_REG), (int) (jiffies - i8042_start)); +#else + inb(I8042_DATA_REG); +#endif + + spin_unlock_irqrestore(&i8042_lock, flags); + + return i; +} + +/* + * i8042_command() executes a command on the i8042. It also sends the input parameter(s) + * of the commands to it, and receives the output value(s). The parameters are to be + * stored in the param array, and the output is placed into the same array. The number + * of the parameters and output values is encoded in bits 8-11 of the command + * number. + */ + +static int i8042_command(unsigned char *param, int command) +{ + unsigned long flags; + int retval = 0, i = 0; + + spin_lock_irqsave(&i8042_lock, flags); + + retval = i8042_wait_write(); + if (!retval) { +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x -> i8042 (command) [%d]\n", + command & 0xff, (int) (jiffies - i8042_start)); +#endif + outb(command & 0xff, I8042_COMMAND_REG); + } + + if (!retval) + for (i = 0; i < ((command >> 12) & 0xf); i++) { + if ((retval = i8042_wait_write())) break; +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x -> i8042 (parameter) [%d]\n", + param[i], (int) (jiffies - i8042_start)); +#endif + outb(param[i], I8042_DATA_REG); + } + + if (!retval) + for (i = 0; i < ((command >> 8) & 0xf); i++) { + if ((retval = i8042_wait_read())) break; + if (inb(I8042_STATUS_REG) & I8042_STR_AUXDATA) + param[i] = ~inb(I8042_DATA_REG); + else + param[i] = inb(I8042_DATA_REG); +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x <- i8042 (return) [%d]\n", + param[i], (int) (jiffies - i8042_start)); +#endif + } + + spin_unlock_irqrestore(&i8042_lock, flags); + +#ifdef I8042_DEBUG_IO + if (retval) + printk(KERN_DEBUG "i8042.c: -- i8042 (timeout) [%d]\n", + (int) (jiffies - i8042_start)); +#endif + + return retval; +} + +/* + * i8042_kbd_write() sends a byte out through the keyboard interface. + * It also automatically refreshes the CTR value, since some i8042's + * trash their CTR after attempting to send data to an nonexistent + * device. + */ + +static int i8042_kbd_write(struct serio *port, unsigned char c) +{ + unsigned long flags; + int retval = 0; + + spin_lock_irqsave(&i8042_lock, flags); + + if(!(retval = i8042_wait_write())) { +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x -> i8042 (kbd-data) [%d]\n", + c, (int) (jiffies - i8042_start)); +#endif + outb(c, I8042_DATA_REG); + } + + spin_unlock_irqrestore(&i8042_lock, flags); + + return retval; +} + +/* + * i8042_aux_write() sends a byte out through the aux interface. + */ + +static int i8042_aux_write(struct serio *port, unsigned char c) +{ + int retval; + +/* + * Send the byte out. + */ + + retval = i8042_command(&c, I8042_CMD_AUX_SEND); + +/* + * Here we restore the CTR value. I don't know why, but i8042's in half-AT + * mode tend to trash their CTR when doing the AUX_SEND command. + */ + + retval += i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR); + +/* + * Make sure the interrupt happens and the character is received even + * in the case the IRQ isn't wired, so that we can receive further + * characters later. + */ + + i8042_interrupt(0, port, NULL); + return retval; +} + +/* + * i8042_open() is called when a port is open by the higher layer. + * It allocates an interrupt and enables the port. + */ + +static int i8042_open(struct serio *port) +{ + struct i8042_values *values = port->driver; + +/* + * Allocate the interrupt + */ + + if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) { + printk(KERN_ERR "i8042.c: Can't get irq %d for %s\n", values->irq, values->name); + return -1; + } + +/* + * Enable the device and its interrupt. + */ + + i8042_ctr |= values->irqen; + i8042_ctr &= ~values->disable; + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + printk(KERN_ERR "i8042.c: Can't write CTR while opening %s.\n", values->name); + return -1; + } + +/* + * Flush buffers + */ + + i8042_flush(); + + return 0; +} + +/* + * i8042_close() frees the interrupt, and disables the interface when the + * upper layer doesn't need it anymore. + */ + +static void i8042_close(struct serio *port) +{ + struct i8042_values *values = port->driver; + +/* + * Disable the device and its interrupt. + */ + + i8042_ctr &= ~values->irqen; + i8042_ctr |= values->disable; + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name); + return; + } + +/* + * Free the interrupt + */ + + free_irq(values->irq, NULL); +} + +/* + * Structures for registering the devices in the serio.c module. + */ + +static struct i8042_values i8042_kbd_values = { + irq: I8042_KBD_IRQ, + irqen: I8042_CTR_KBDINT, + disable: I8042_CTR_KBDDIS, + name: "KBD", + exists: 0, +}; + +static struct serio i8042_kbd_port = +{ + type: SERIO_8042, + write: i8042_kbd_write, + open: i8042_open, + close: i8042_close, + driver: &i8042_kbd_values, + name: "i8042 Kbd Port", + phys: "isa0060/serio0", +}; + +static struct i8042_values i8042_aux_values = { + irq: I8042_AUX_IRQ, + irqen: I8042_CTR_AUXINT, + disable: I8042_CTR_AUXDIS, + name: "AUX", + exists: 0, +}; + +static struct serio i8042_aux_port = +{ + type: SERIO_8042, + write: i8042_aux_write, + open: i8042_open, + close: i8042_close, + driver: &i8042_aux_values, + name: "i8042 Aux Port", + phys: "isa0060/serio1", +}; + +/* + * i8042_interrupt() is the most important function in this driver - + * it handles the interrupts from the i8042, and sends incoming bytes + * to the upper layers. + */ + +static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + unsigned char str, data; + + spin_lock_irqsave(&i8042_lock, flags); + + while ((str = inb(I8042_STATUS_REG)) & I8042_STR_OBF) { + + data = inb(I8042_DATA_REG); + +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt-%s) [%d]\n", + data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", (int) (jiffies - i8042_start)); +#endif + + if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { + if (i8042_aux_port.dev) + i8042_aux_port.dev->interrupt(&i8042_aux_port, data, 0); + } else { + if (i8042_kbd_values.exists && i8042_kbd_port.dev) { + if (!i8042_direct) { + if (data > 0x7f) { + if (test_and_clear_bit(data & 0x7f, i8042_unxlate_seen)) { + i8042_kbd_port.dev->interrupt(&i8042_kbd_port, 0xf0, 0); + data = i8042_unxlate_table[data & 0x7f]; + } + } else { + set_bit(data, i8042_unxlate_seen); + data = i8042_unxlate_table[data]; + } + } + i8042_kbd_port.dev->interrupt(&i8042_kbd_port, data, 0); + } + } + } + + spin_unlock_irqrestore(&i8042_lock, flags); +} + +/* + * i8042_controller init initializes the i8042 controller, and, + * most importantly, sets it into non-xlated mode. + */ + +static int __init i8042_controller_init(void) +{ + +/* + * Check the i/o region before we touch it. + */ +#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) + if (check_region(I8042_DATA_REG, 16)) { + printk(KERN_ERR "i8042.c: %#x port already in use!\n", I8042_DATA_REG); + return -1; + } +#endif + +/* + * Test the i8042. We need to know if it thinks it's working correctly + * before doing anything else. + */ + + i8042_flush(); + + if (i8042_reset) { + + unsigned char param; + + if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { + printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); + return -1; + } + + if (param != I8042_RET_CTL_TEST) { + printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", + param, I8042_RET_CTL_TEST); + return -1; + } + } + +/* + * Read the CTR. + */ + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { + printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); + return -1; + } + +/* + * Save the CTR for restoral on unload / reboot. + */ + + i8042_initial_ctr = i8042_ctr; + +/* + * Disable both interfaces and their interrupts. + */ + + i8042_ctr |= I8042_CTR_KBDDIS; + i8042_ctr &= ~I8042_CTR_KBDINT; + +/* + * Handle keylock. + */ + + if (~inb(I8042_STATUS_REG) & I8042_STR_KEYLOCK) { + + if (i8042_unlock) { + i8042_ctr |= I8042_CTR_IGNKEYLOCK; + } else { + printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); + } + } + +/* + * Set nontranslated mode for the kbd interface. This is vital for a working + * scancode set 2/3 support. After this the kbd interface becomes a simple serial + * in/out, like the aux interface is. If the user doesn't wish this, the driver + * tries to untranslate the values after the i8042 translates them. + */ + + if (i8042_direct) + i8042_ctr &= ~I8042_CTR_XLATE; + +/* + * Write CTR back. + */ + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); + return -1; + } + + return 0; +} + +/* + * Here we try to reset everything back to a state in which the BIOS will be + * able to talk to the hardware when rebooting. + */ + +void i8042_controller_cleanup(void) +{ + +/* + * Reset the controller. + */ + + if (i8042_reset) { + unsigned char param; + + if (i8042_command(¶m, I8042_CMD_CTL_TEST)) + printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n"); + } + +/* + * Restore the original control register setting. + */ + + i8042_ctr = i8042_initial_ctr; + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) + printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); + +/* + * Reset anything that is connected to the ports if the ports + * are enabled in the original config. + */ + + if (i8042_kbd_values.exists) + i8042_kbd_write(&i8042_kbd_port, 0xff); + + if (i8042_aux_values.exists) + i8042_aux_write(&i8042_aux_port, 0xff); +} + +/* + * i8042_check_aux() applies as much paranoia as it can at detecting + * the presence of an AUX interface. + */ + +static int __init i8042_check_aux(struct i8042_values *values, struct serio *port) +{ + unsigned char param; + + i8042_flush(); + +/* + * Internal loopback test - filters out AT-type i8042's + */ + + param = 0x5a; + + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa5) + return -1; + +/* + * External connection test - filters out AT-soldered PS/2 i8042's + */ + + if (i8042_command(¶m, I8042_CMD_AUX_TEST) || param) + return -1; + +/* + * Bit assignment test - filters out PS/2 i8042's in AT mode + */ + + if (i8042_command(¶m, I8042_CMD_AUX_DISABLE)) + return -1; + + if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) + return -1; + + if (i8042_command(¶m, I8042_CMD_AUX_TEST) || param) { + +/* + * We've got an old AMI i8042 with 'Bad Cache' commands. + */ + + i8042_command(¶m, I8042_CMD_AUX_ENABLE); + return -1; + } + + if (i8042_command(¶m, I8042_CMD_AUX_ENABLE)) + return -1; + + if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS)) + return -1; + +/* + * Disable the interface. + */ + + i8042_ctr |= I8042_CTR_AUXDIS; + i8042_ctr &= ~I8042_CTR_AUXINT; + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) + return -1; + + return 0; +} + +/* + * i8042_port_register() marks the device as existing, + * registers it, and reports to the user. + */ + +static int __init i8042_port_register(struct i8042_values *values, struct serio *port) +{ + values->exists = 1; + serio_register_port(port); + printk(KERN_INFO "serio: i8042 %s port at %#x,%#x irq %d\n", + values->name, I8042_DATA_REG, I8042_COMMAND_REG, values->irq); + + return 0; +} + +/* + * Module init and cleanup functions. + */ + +void __init i8042_setup(char *str, int *ints) +{ + if (!strcmp(str, "i8042_reset=1")) + i8042_reset = 1; + if (!strcmp(str, "i8042_noaux=1")) + i8042_noaux = 1; + if (!strcmp(str, "i8042_unlock=1")) + i8042_unlock = 1; + if (!strcmp(str, "i8042_direct=1")) + i8042_direct = 1; +} + +/* + * Reset the 8042 back to original mode. + */ +static int i8042_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code==SYS_DOWN || code==SYS_HALT) + i8042_controller_cleanup(); + return NOTIFY_DONE; +} + +static struct notifier_block i8042_notifier= +{ + i8042_notify_sys, + NULL, + 0 +}; + +int __init i8042_init(void) +{ +#ifdef I8042_DEBUG_IO + i8042_start = jiffies; +#endif + + if (i8042_controller_init()) + return -ENODEV; + + i8042_port_register(&i8042_kbd_values, &i8042_kbd_port); + + if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values, &i8042_aux_port)) + i8042_port_register(&i8042_aux_values, &i8042_aux_port); + +/* + * On ix86 platforms touching the i8042 data register region can do really + * bad things. Because of this the region is always reserved on ix86 boxes. + */ +#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) + request_region(I8042_DATA_REG, 16, "i8042"); +#endif + register_reboot_notifier(&i8042_notifier); + return 0; +} + +void __exit i8042_exit(void) +{ + unregister_reboot_notifier(&i8042_notifier); + + if (i8042_kbd_values.exists) + serio_unregister_port(&i8042_kbd_port); + + if (i8042_aux_values.exists) + serio_unregister_port(&i8042_aux_port); + + i8042_controller_cleanup(); +#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) + release_region(I8042_DATA_REG, 16); +#endif +} + +module_init(i8042_init); +module_exit(i8042_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/serio/i8042.h linux-2.5/drivers/input/serio/i8042.h --- linux-2.5.20/drivers/input/serio/i8042.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/serio/i8042.h Mon May 6 17:57:35 2002 @@ -0,0 +1,128 @@ +#ifndef _I8042_H +#define _I8042_H + +/* + * $Id: i8042.h,v 1.6 2001/10/05 22:48:09 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +/* + * If you want to reset your i8042 upon boot, define this. + */ + +#undef I8042_RESET + +/* + * If you want to trace all the i/o the i8042 module does for + * debugging purposes, define this. + */ + +#undef I8042_DEBUG_IO + +/* + * On most PC based systems the keyboard IRQ is 1. + */ + +#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ + +/* + * On most PC based systems the aux port IRQ is 12. There are exceptions, + * though. Unfortunately IRQ probing is not possible without touching + * the device attached to the port. + */ + +#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ + +/* + * This is in 50us units, the time we wait for the i8042 to react. This + * has to be long enough for the i8042 itself to timeout on sending a byte + * to a non-existent mouse. + */ + +#define I8042_CTL_TIMEOUT 10000 + +/* + * Register numbers. + */ + +#define I8042_COMMAND_REG CONFIG_I8042_REG_BASE + 4 +#define I8042_STATUS_REG CONFIG_I8042_REG_BASE + 4 +#define I8042_DATA_REG CONFIG_I8042_REG_BASE + +/* + * Status register bits. + */ + +#define I8042_STR_PARITY 0x80 +#define I8042_STR_TIMEOUT 0x40 +#define I8042_STR_AUXDATA 0x20 +#define I8042_STR_KEYLOCK 0x10 +#define I8042_STR_CMDDAT 0x08 +#define I8042_STR_IBF 0x02 +#define I8042_STR_OBF 0x01 + +/* + * Control register bits. + */ + +#define I8042_CTR_KBDINT 0x01 +#define I8042_CTR_AUXINT 0x02 +#define I8042_CTR_IGNKEYLOCK 0x08 +#define I8042_CTR_KBDDIS 0x10 +#define I8042_CTR_AUXDIS 0x20 +#define I8042_CTR_XLATE 0x40 + +/* + * Commands. + */ + +#define I8042_CMD_CTL_RCTR 0x0120 +#define I8042_CMD_CTL_WCTR 0x1060 +#define I8042_CMD_CTL_TEST 0x01aa + +#define I8042_CMD_KBD_DISABLE 0x00ad +#define I8042_CMD_KBD_ENABLE 0x00ae +#define I8042_CMD_KBD_TEST 0x01ab +#define I8042_CMD_KBD_LOOP 0x11d2 + +#define I8042_CMD_AUX_DISABLE 0x00a7 +#define I8042_CMD_AUX_ENABLE 0x00a8 +#define I8042_CMD_AUX_TEST 0x01a9 +#define I8042_CMD_AUX_SEND 0x10d4 +#define I8042_CMD_AUX_LOOP 0x11d3 + +/* + * Return codes. + */ + +#define I8042_RET_CTL_TEST 0x55 + +/* + * Expected maximum internal i8042 buffer size. This is used for flushing + * the i8042 buffers. 32 should be more than enough. + */ + +#define I8042_BUFFER_SIZE 32 + +#endif /* _I8042_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/serio/parkbd.c linux-2.5/drivers/input/serio/parkbd.c --- linux-2.5.20/drivers/input/serio/parkbd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/serio/parkbd.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,203 @@ +/* + * $Id: parkbd.c,v 1.8 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * Parallel port to Keyboard port adapter driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Parallel port to Keyboard port adapter driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(parkbd, "1i"); +MODULE_PARM(parkbd_mode, "1i"); + +#define PARKBD_CLOCK 0x01 /* Strobe & Ack */ +#define PARKBD_DATA 0x02 /* AutoFd & Busy */ + +static int parkbd = 0; +static int parkbd_mode = SERIO_8042; + +static int parkbd_buffer = 0; +static int parkbd_counter = 0; +static int parkbd_last = 0; +static int parkbd_writing = 0; +static unsigned long parkbd_start = 0; + +static struct pardevice *parkbd_dev; + +static char parkbd_name[] = "PARKBD AT/XT keyboard adapter"; +static char parkbd_phys[32]; + +static int parkbd_readlines(void) +{ + return (parport_read_status(parkbd_dev->port) >> 6) ^ 2; +} + +static void parkbd_writelines(int data) +{ + parport_write_control(parkbd_dev->port, (~data & 3) | 0x10); +} + +static int parkbd_write(struct serio *port, unsigned char c) +{ + unsigned char p; + + if (!parkbd_mode) return -1; + + p = c ^ (c >> 4); + p = p ^ (p >> 2); + p = p ^ (p >> 1); + + parkbd_counter = 0; + parkbd_writing = 1; + parkbd_buffer = c | (((int) (~p & 1)) << 8) | 0x600; + + parkbd_writelines(2); + + return 0; +} + +static int parkbd_open(struct serio *port) +{ + return 0; +} + +static void parkbd_close(struct serio *port) +{ +} + +static struct serio parkbd_port = +{ + write: parkbd_write, + open: parkbd_open, + close: parkbd_close, + name: parkbd_name, + phys: parkbd_phys, +}; + +static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + + if (parkbd_writing) { + + if (parkbd_counter && ((parkbd_counter == 11) || (jiffies - parkbd_last > 1))) { + parkbd_counter = 0; + parkbd_buffer = 0; + parkbd_writing = 0; + parkbd_writelines(3); + return; + } + + parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2); + + if (parkbd_counter == 11) { + parkbd_counter = 0; + parkbd_buffer = 0; + parkbd_writing = 0; + parkbd_writelines(3); + } + + } else { + + if ((parkbd_counter == parkbd_mode + 10) || (jiffies - parkbd_last > 1)) { + parkbd_counter = 0; + parkbd_buffer = 0; + } + + parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; + + if (parkbd_counter == parkbd_mode + 10) { + if (parkbd_port.dev) + parkbd_port.dev->interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0); + } + } + + parkbd_last = jiffies; +} + +static int parkbd_getport(void) +{ + struct parport *pp; + + if (parkbd < 0) { + printk(KERN_ERR "parkbd: no port specified\n"); + return -ENODEV; + } + + for (pp = parport_enumerate(); pp != NULL && (parkbd > 0); pp = pp->next) parkbd--; + + if (pp == NULL) { + printk(KERN_ERR "parkbd: no such parport\n"); + return -ENODEV; + } + + parkbd_dev = parport_register_device(pp, "parkbd", NULL, NULL, parkbd_interrupt, PARPORT_DEV_EXCL, NULL); + + if (!parkbd_dev) + return -ENODEV; + + if (parport_claim(parkbd_dev)) { + parport_unregister_device(parkbd_dev); + return -EBUSY; + } + + parkbd_start = jiffies; + + return 0; +} + + +int __init parkbd_init(void) +{ + if (parkbd_getport()) return -1; + parkbd_writelines(3); + parkbd_port.type = parkbd_mode; + + sprintf(parkbd_phys, "%s/serio0", parkbd_dev->port->name); + + serio_register_port(&parkbd_port); + + printk(KERN_INFO "serio: PARKBD %s adapter on %s\n", + parkbd_mode ? "AT" : "XT", parkbd_dev->port->name); + + return 0; +} + +void __exit parkbd_exit(void) +{ + parport_release(parkbd_dev); + serio_unregister_port(&parkbd_port); + parport_unregister_device(parkbd_dev); +} + +module_init(parkbd_init); +module_exit(parkbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/serio/rpckbd.c linux-2.5/drivers/input/serio/rpckbd.c --- linux-2.5.20/drivers/input/serio/rpckbd.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/serio/rpckbd.c Tue Jan 22 17:48:01 2002 @@ -0,0 +1,117 @@ +/* + * $Id: rpckbd.c,v 1.7 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * unknown author + */ + +/* + * Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); +MODULE_LICENSE("GPL"); + +static inline void rpckbd_write(unsigned char val) +{ + while(!(inb(IOMD_KCTRL) & (1 << 7))); + outb(val, IOMD_KARTTX); +} + +static struct serio rpckbd_port = +{ + type: SERIO_8042, + write: rpckbd_write, + name: "RiscPC PS/2 kbd port", + phys: "rpckbd/serio0", +}; + +static void rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs) +{ + kbd_pt_regs = regs; + + while (inb(IOMD_KCTRL) & (1 << 5)) + if (rpckbd_port.dev) + rpckbd_port.dev->interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0); + +} + +static void rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs) +{ +} + +static int __init rpckbd_init(void) +{ + unsigned long flags; + + /* Reset the keyboard state machine. */ + outb(0, IOMD_KCTRL); + outb(8, IOMD_KCTRL); + + save_flags_cli(flags); + + if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", NULL) != 0) { + printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ!\n") + return -EBUSY; + } + + if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", NULL) != 0) { + printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ!\n") + free_irq(IRQ_KEYBOARDRX, NULL); + return -EBUSY; + } + + disable_irq(IRQ_KEYBOARDTX); + (void)IOMD_KARTRX; + + restore_flags(flags); + + register_serio_port(&rpckbd_port); + printk(KERN_INFO "serio: RiscPC PS/2 kbd port irq %d %d\n", IRQ_KEYBOARDRX, IRQ_KEYBOARDTX); + + return 0; +} + +static void __exit rpckbd_exit(void) +{ + free_irq(IRQ_KEYBOARDRX, NULL); + free_irq(IRQ_KEYBOARDTX, NULL); + + unregister_serio_port(&rpckbd_port); +} + +module_init(rpckbd_init); +module_exit(rpckbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/touchscreen/Config.help linux-2.5/drivers/input/touchscreen/Config.help --- linux-2.5.20/drivers/input/touchscreen/Config.help Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/touchscreen/Config.help Thu Mar 28 00:08:14 2002 @@ -0,0 +1,16 @@ +CONFIG_INPUT_TOUCHSCREEN + Say Y here, and a list of supported touchscreens will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +CONFIG_TOUCHSCREEN_GUNZE + Say Y here if you have the Gunze AHL-51 touchscreen connected to + your system. + + If unsure, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called gunze.o. If you want to compile it as a + module, say M here and read . diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/touchscreen/Config.in linux-2.5/drivers/input/touchscreen/Config.in --- linux-2.5.20/drivers/input/touchscreen/Config.in Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/touchscreen/Config.in Thu Mar 28 00:08:14 2002 @@ -0,0 +1,7 @@ +# +# Mouse driver configuration +# + +bool 'Touchscreens' CONFIG_INPUT_TOUCHSCREEN + +dep_tristate ' Gunze AHL-51S touchscreen' CONFIG_TOUCHSCREEN_GUNZE $CONFIG_INPUT $CONFIG_INPUT_TOUCHSCREEN $CONFIG_SERIO diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/touchscreen/Makefile linux-2.5/drivers/input/touchscreen/Makefile --- linux-2.5.20/drivers/input/touchscreen/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/touchscreen/Makefile Thu Mar 28 00:08:14 2002 @@ -0,0 +1,15 @@ +# +# Makefile for the mouse drivers. +# + +# The target object and module list name. + +O_TARGET := tsdrv.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o + +# The global Rules.make. + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/touchscreen/gunze.c linux-2.5/drivers/input/touchscreen/gunze.c --- linux-2.5.20/drivers/input/touchscreen/gunze.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/touchscreen/gunze.c Thu Mar 28 01:23:57 2002 @@ -0,0 +1,178 @@ +/* + * $Id: gunze.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + */ + +/* + * Gunze AHL-51S touchscreen driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Gunze AHL-51S touchscreen driver"); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define GUNZE_MAX_LENGTH 10 + +static char *gunze_name = "Gunze AHL-51S TouchScreen"; + +/* + * Per-touchscreen data. + */ + +struct gunze { + struct input_dev dev; + struct serio *serio; + int idx; + unsigned char data[GUNZE_MAX_LENGTH]; + char phys[32]; +}; + +static void gunze_process_packet(struct gunze* gunze) +{ + struct input_dev *dev = &gunze->dev; + + if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' || + (gunze->data[0] != 'T' && gunze->data[0] != 'R')) { + gunze->data[10] = 0; + printk(KERN_WARNING "gunze.c: bad packet: >%s<\n", gunze->data); + return; + } + + input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10) * 4); + input_report_abs(dev, ABS_Y, 3072 - simple_strtoul(gunze->data + 6, NULL, 10) * 3); + input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T'); +} + +static void gunze_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct gunze* gunze = serio->private; + + if (data == '\r') { + gunze_process_packet(gunze); + gunze->idx = 0; + } else { + if (gunze->idx < GUNZE_MAX_LENGTH) + gunze->data[gunze->idx++] = data; + } +} + +/* + * gunze_disconnect() is the opposite of gunze_connect() + */ + +static void gunze_disconnect(struct serio *serio) +{ + struct gunze* gunze = serio->private; + input_unregister_device(&gunze->dev); + serio_close(serio); + kfree(gunze); +} + +/* + * gunze_connect() is the routine that is called when someone adds a + * new serio device. It looks whether it was registered as a Gunze touchscreen + * and if yes, registers it as an input device. + */ + +static void gunze_connect(struct serio *serio, struct serio_dev *dev) +{ + struct gunze *gunze; + + if (serio->type != (SERIO_RS232 | SERIO_GUNZE)) + return; + + if (!(gunze = kmalloc(sizeof(struct gunze), GFP_KERNEL))) + return; + + memset(gunze, 0, sizeof(struct gunze)); + + gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + gunze->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + gunze->dev.absmin[ABS_X] = 96; gunze->dev.absmin[ABS_Y] = 72; + gunze->dev.absmax[ABS_X] = 4000; gunze->dev.absmax[ABS_Y] = 3000; + + gunze->serio = serio; + serio->private = gunze; + + sprintf(gunze->phys, "%s/input0", serio->phys); + + gunze->dev.private = gunze; + gunze->dev.name = gunze_name; + gunze->dev.phys = gunze->phys; + gunze->dev.idbus = BUS_RS232; + gunze->dev.idvendor = SERIO_GUNZE; + gunze->dev.idproduct = 0x0051; + gunze->dev.idversion = 0x0100; + + if (serio_open(serio, dev)) { + kfree(gunze); + return; + } + + input_register_device(&gunze->dev); + + printk(KERN_INFO "input: %s on %s\n", gunze_name, serio->phys); +} + +/* + * The serio device structure. + */ + +static struct serio_dev gunze_dev = { + interrupt: gunze_interrupt, + connect: gunze_connect, + disconnect: gunze_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +int __init gunze_init(void) +{ + serio_register_device(&gunze_dev); + return 0; +} + +void __exit gunze_exit(void) +{ + serio_unregister_device(&gunze_dev); +} + +module_init(gunze_init); +module_exit(gunze_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/input/tsdev.c linux-2.5/drivers/input/tsdev.c --- linux-2.5.20/drivers/input/tsdev.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/input/tsdev.c Mon Apr 15 03:22:52 2002 @@ -0,0 +1,443 @@ +/* + * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $ + * + * Copyright (c) 2001 "Crazy" james Simmons + * + * Input driver to Touchscreen device driver module. + * + * Sponsored by Transvirtual Technology + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to . + */ + +#define TSDEV_MINOR_BASE 128 +#define TSDEV_MINORS 32 +#define TSDEV_BUFFER_SIZE 64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIG_INPUT_TSDEV_SCREEN_X +#define CONFIG_INPUT_TSDEV_SCREEN_X 240 +#endif +#ifndef CONFIG_INPUT_TSDEV_SCREEN_Y +#define CONFIG_INPUT_TSDEV_SCREEN_Y 320 +#endif + +struct tsdev { + int exist; + int open; + int minor; + char name[16]; + wait_queue_head_t wait; + struct tsdev_list *list; + struct input_handle handle; + devfs_handle_t devfs; +}; + +/* From Compaq's Touch Screen Specification version 0.2 (draft) */ +typedef struct { + short pressure; + short x; + short y; + short millisecs; +} TS_EVENT; + +struct tsdev_list { + struct fasync_struct *fasync; + struct tsdev_list *next; + struct tsdev *tsdev; + int head, tail; + int oldx, oldy, pendown; + TS_EVENT event[TSDEV_BUFFER_SIZE]; +}; + +static struct input_handler tsdev_handler; + +static struct tsdev *tsdev_table[TSDEV_MINORS]; + +static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; +static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; + +static int tsdev_fasync(int fd, struct file *file, int on) +{ + struct tsdev_list *list = file->private_data; + int retval; + + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int tsdev_open(struct inode *inode, struct file *file) +{ + int i = minor(inode->i_rdev) - TSDEV_MINOR_BASE; + struct tsdev_list *list; + + if (i >= TSDEV_MINORS || !tsdev_table[i]) + return -ENODEV; + + if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL))) + return -ENOMEM; + memset(list, 0, sizeof(struct tsdev_list)); + + list->tsdev = tsdev_table[i]; + list->next = tsdev_table[i]->list; + tsdev_table[i]->list = list; + file->private_data = list; + + if (!list->tsdev->open++) + if (list->tsdev->exist) + input_open_device(&list->tsdev->handle); + return 0; +} + +static int tsdev_release(struct inode *inode, struct file *file) +{ + struct tsdev_list *list = file->private_data; + struct tsdev_list **listptr; + + listptr = &list->tsdev->list; + tsdev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + + if (!--list->tsdev->open) { + if (list->tsdev->exist) { + input_close_device(&list->tsdev->handle); + } else { + input_unregister_minor(list->tsdev->devfs); + tsdev_table[list->tsdev->minor] = NULL; + kfree(list->tsdev); + } + } + kfree(list); + return 0; +} + +static ssize_t tsdev_read(struct file *file, char *buffer, size_t count, + loff_t * ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct tsdev_list *list = file->private_data; + int retval = 0; + + if (list->head == list->tail) { + add_wait_queue(&list->tsdev->wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (list->head == list->tail) { + if (!list->tsdev->exist) { + retval = -ENODEV; + break; + } + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&list->tsdev->wait, &wait); + } + + if (retval) + return retval; + + while (list->head != list->tail + && retval + sizeof(TS_EVENT) <= count) { + if (copy_to_user + (buffer + retval, list->event + list->tail, + sizeof(TS_EVENT))) + return -EFAULT; + list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); + retval += sizeof(TS_EVENT); + } + return retval; +} + +/* No kernel lock - fine */ +static unsigned int tsdev_poll(struct file *file, poll_table * wait) +{ + struct tsdev_list *list = file->private_data; + + poll_wait(file, &list->tsdev->wait, wait); + if (list->head != list->tail) + return POLLIN | POLLRDNORM; + return 0; +} + +static int tsdev_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ +/* + struct tsdev_list *list = file->private_data; + struct tsdev *evdev = list->tsdev; + struct input_dev *dev = tsdev->handle.dev; + int retval; + + switch (cmd) { + case HHEHE: + return 0; + case hjff: + return 0; + default: + return 0; + } +*/ + return -EINVAL; +} + +struct file_operations tsdev_fops = { + owner: THIS_MODULE, + open: tsdev_open, + release: tsdev_release, + read: tsdev_read, + poll: tsdev_poll, + fasync: tsdev_fasync, + ioctl: tsdev_ioctl, +}; + +static void tsdev_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + struct tsdev *tsdev = handle->private; + struct tsdev_list *list = tsdev->list; + struct timeval time; + int size; + + while (list) { + switch (type) { + case EV_ABS: + switch (code) { + case ABS_X: + if (!list->pendown) + return; + + size = + handle->dev->absmax[ABS_X] - + handle->dev->absmin[ABS_X]; + if (size > 0) + list->oldx = + ((value - + handle->dev->absmin[ABS_X]) * + xres / size); + else + list->oldx = + ((value - + handle->dev->absmin[ABS_X])); + break; + case ABS_Y: + if (!list->pendown) + return; + + size = + handle->dev->absmax[ABS_Y] - + handle->dev->absmin[ABS_Y]; + if (size > 0) + list->oldy = + ((value - + handle->dev->absmin[ABS_Y]) * + yres / size); + else + list->oldy = + ((value - + handle->dev->absmin[ABS_Y])); + break; + case ABS_PRESSURE: + list->pendown = + ((value > + handle->dev-> + absmin[ABS_PRESSURE])) ? value - + handle->dev->absmin[ABS_PRESSURE] : 0; + break; + } + break; + + case EV_REL: + switch (code) { + case REL_X: + if (!list->pendown) + return; + + list->oldx += value; + if (list->oldx < 0) + list->oldx = 0; + else if (list->oldx > xres) + list->oldx = xres; + break; + case REL_Y: + if (!list->pendown) + return; + + list->oldy += value; + if (list->oldy < 0) + list->oldy = 0; + else if (list->oldy > xres) + list->oldy = xres; + break; + } + break; + + case EV_KEY: + if (code == BTN_TOUCH || code == BTN_MOUSE) { + switch (value) { + case 0: + list->pendown = 0; + break; + case 1: + if (!list->pendown) + list->pendown = 1; + break; + case 2: + return; + } + } else + return; + break; + } + do_gettimeofday(&time); + list->event[list->head].millisecs = time.tv_usec / 100; + list->event[list->head].pressure = list->pendown; + list->event[list->head].x = list->oldx; + list->event[list->head].y = list->oldy; + list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); + kill_fasync(&list->fasync, SIGIO, POLL_IN); + list = list->next; + } + wake_up_interruptible(&tsdev->wait); +} + +static struct input_handle *tsdev_connect(struct input_handler *handler, + struct input_dev *dev, + struct input_device_id *id) +{ + struct tsdev *tsdev; + int minor; + + for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor]; + minor++); + if (minor == TSDEV_MINORS) { + printk(KERN_ERR + "tsdev: You have way too many touchscreens\n"); + return NULL; + } + + if (!(tsdev = kmalloc(sizeof(struct tsdev), GFP_KERNEL))) + return NULL; + memset(tsdev, 0, sizeof(struct tsdev)); + init_waitqueue_head(&tsdev->wait); + + tsdev->minor = minor; + tsdev_table[minor] = tsdev; + sprintf(tsdev->name, "ts%d", minor); + + tsdev->handle.dev = dev; + tsdev->handle.name = tsdev->name; + tsdev->handle.handler = handler; + tsdev->handle.private = tsdev; + + tsdev->devfs = + input_register_minor("ts%d", minor, TSDEV_MINOR_BASE); + + tsdev->exist = 1; + + return &tsdev->handle; +} + +static void tsdev_disconnect(struct input_handle *handle) +{ + struct tsdev *tsdev = handle->private; + + tsdev->exist = 0; + + if (tsdev->open) { + input_close_device(handle); + wake_up_interruptible(&tsdev->wait); + } else { + input_unregister_minor(tsdev->devfs); + tsdev_table[tsdev->minor] = NULL; + kfree(tsdev); + } +} + +static struct input_device_id tsdev_ids[] = { + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, + keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, + relbit: { BIT(REL_X) | BIT(REL_Y) }, + },/* A mouse like device, at least one button, two relative axes */ + + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, + keybit: { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, + absbit: { BIT(ABS_X) | BIT(ABS_Y) }, + },/* A tablet like device, at least touch detection, two absolute axes */ + + {},/* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(input, tsdev_ids); + +static struct input_handler tsdev_handler = { + event: tsdev_event, + connect: tsdev_connect, + disconnect: tsdev_disconnect, + fops: &tsdev_fops, + minor: TSDEV_MINOR_BASE, + name: "tsdev", + id_table: tsdev_ids, +}; + +static int __init tsdev_init(void) +{ + input_register_handler(&tsdev_handler); + printk(KERN_INFO "ts: Compaq touchscreen protocol output\n"); + return 0; +} + +static void __exit tsdev_exit(void) +{ + input_unregister_handler(&tsdev_handler); +} + +module_init(tsdev_init); +module_exit(tsdev_exit); + +MODULE_AUTHOR("James Simmons "); +MODULE_DESCRIPTION("Input driver to touchscreen converter"); +MODULE_PARM(xres, "i"); +MODULE_PARM_DESC(xres, "Horizontal screen resolution"); +MODULE_PARM(yres, "i"); +MODULE_PARM_DESC(yres, "Vertical screen resolution"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/isdn/Config.in linux-2.5/drivers/isdn/Config.in --- linux-2.5.20/drivers/isdn/Config.in Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/isdn/Config.in Sat Apr 27 00:32:14 2002 @@ -19,11 +19,8 @@ comment 'CAPI subsystem' - tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI - if [ "$CONFIG_ISDN_CAPI" != "n" ]; then - source drivers/isdn/capi/Config.in - source drivers/isdn/hardware/Config.in - fi + source drivers/isdn/capi/Config.in + source drivers/isdn/hardware/Config.in fi fi endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/isdn/hardware/avm/b1.c linux-2.5/drivers/isdn/hardware/avm/b1.c --- linux-2.5.20/drivers/isdn/hardware/avm/b1.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/isdn/hardware/avm/b1.c Sat Jun 1 00:34:35 2002 @@ -59,6 +59,21 @@ /* ------------------------------------------------------------- */ +void b1_set_revision(struct capi_driver *driver, char *rev) +{ + char *p; + + if ((p = strchr(rev, ':')) != 0 && p[1]) { + strncpy(driver->revision, p + 2, sizeof(driver->revision)); + driver->revision[sizeof(driver->revision)-1] = 0; + if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision) + *(p-1) = 0; + } + printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); +} + +/* ------------------------------------------------------------- */ + avmcard *b1_alloc_card(int nr_controllers) { avmcard *card; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/isdn/hisax/avma1_cs.c linux-2.5/drivers/isdn/hisax/avma1_cs.c --- linux-2.5.20/drivers/isdn/hisax/avma1_cs.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/isdn/hisax/avma1_cs.c Wed Mar 27 13:07:16 2002 @@ -0,0 +1,552 @@ +/* + * PCMCIA client driver for AVM A1 / Fritz!PCMCIA + * + * Author Carsten Paeth + * Copyright 1998-2001 by Carsten Paeth + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards"); +MODULE_AUTHOR("Carsten Paeth"); +MODULE_LICENSE("GPL"); + +int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot); +void HiSax_closecard(int cardnr); + + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); +static char *version = +"avma1_cs.c 1.00 1998/01/23 10:00:00 (Carsten Paeth)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +static int default_irq_list[11] = { 15, 13, 12, 11, 10, 9, 7, 5, 4, 3, -1 }; +static int irq_list[11] = { -1 }; +static int isdnprot = 2; + +MODULE_PARM(irq_list, "1-11i"); +MODULE_PARM(isdnprot, "1-4i"); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card insertion + and ejection events. They are invoked from the skeleton event + handler. +*/ + +static void avma1cs_config(dev_link_t *link); +static void avma1cs_release(u_long arg); +static int avma1cs_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *avma1cs_attach(void); +static void avma1cs_detach(dev_link_t *); + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "avma1_cs"; + +/* + A linked list of "instances" of the skeleton device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally can't be allocated dynamically. +*/ + +typedef struct local_info_t { + dev_node_t node; +} local_info_t; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + avma1cs_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + +======================================================================*/ + +static dev_link_t *avma1cs_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + local_info_t *local; + int ret, i; + + DEBUG(0, "avma1cs_attach()\n"); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &avma1cs_release; + link->release.data = (u_long)link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts2 = 16; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; + link->io.IOAddrLines = 5; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] != -1) { + for (i = 0; i < 10 && irq_list[i] > 0; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + } else { + for (i = 0; i < 10 && default_irq_list[i] > 0; i++) + link->irq.IRQInfo2 |= 1 << default_irq_list[i]; + } + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + memset(local, 0, sizeof(local_info_t)); + link->priv = local; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &avma1cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + avma1cs_detach(link); + return NULL; + } + + return link; +} /* avma1cs_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void avma1cs_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "avma1cs_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { +#ifdef PCMCIA_DEBUG + printk(KERN_DEBUG "avma1_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + return; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free pieces */ + *linkp = link->next; + if (link->priv) { + kfree(link->priv); + } + kfree(link); + +} /* avma1cs_detach */ + +/*====================================================================== + + avma1cs_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. + +======================================================================*/ + +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i; + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) return i; + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) return i; + return CardServices(ParseTuple, handle, tuple, parse); +} + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +static void avma1cs_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + local_info_t *dev; + int i; + u_char buf[64]; + char devname[128]; + int busy = 0; + + handle = link->handle; + dev = link->priv; + + DEBUG(0, "avma1cs_config(0x%p)\n", link); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + do { + tuple.DesiredTuple = CISTPL_CONFIG; + i = CardServices(GetFirstTuple, handle, &tuple); + if (i != CS_SUCCESS) break; + tuple.TupleData = buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + i = CardServices(GetTupleData, handle, &tuple); + if (i != CS_SUCCESS) break; + i = CardServices(ParseTuple, handle, &tuple, &parse); + if (i != CS_SUCCESS) break; + link->conf.ConfigBase = parse.config.base; + } while (0); + if (i != CS_SUCCESS) { + cs_error(link->handle, ParseTuple, i); + link->state &= ~DEV_CONFIG_PENDING; + return; + } + + /* Configure card */ + link->state |= DEV_CONFIG; + + do { + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = 254; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_VERS_1; + + devname[0] = 0; + if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { + strncpy(devname,parse.version_1.str + parse.version_1.ofs[1], + sizeof(devname)); + } + /* + * find IO port + */ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + i = first_tuple(handle, &tuple, &parse); + while (i == CS_SUCCESS) { + if (cf->io.nwin > 0) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.NumPorts1 = cf->io.win[0].len; + link->io.NumPorts2 = 0; + printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n", + link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1 - 1); + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) goto found_port; + } + i = next_tuple(handle, &tuple, &parse); + } + +found_port: + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + break; + } + + /* + * allocate an interrupt line + */ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + CardServices(ReleaseIO, link->handle, &link->io); + break; + } + + /* + * configure the PCMCIA socket + */ + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + break; + } + + } while (0); + + /* At this point, the dev_node_t structure(s) should be + initialized and arranged in a linked list at link->dev. */ + + strcpy(dev->node.dev_name, "A1"); + dev->node.major = 45; + dev->node.minor = 0; + link->dev = &dev->node; + + link->state &= ~DEV_CONFIG_PENDING; + /* If any step failed, release any partially configured state */ + if (i != 0) { + avma1cs_release((u_long)link); + return; + } + + printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n", + link->io.BasePort1, link->irq.AssignedIRQ); + + if (avm_a1_init_pcmcia((void *)(int)link->io.BasePort1, + link->irq.AssignedIRQ, + &busy, isdnprot) != 0) { + printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1); + return; + } + + i = 0; /* no returncode for cardnr :-( */ + + dev->node.minor = i; + +} /* avma1cs_config */ + +/*====================================================================== + + After a card is removed, avma1cs_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void avma1cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + local_info_t *local = link->priv; + + DEBUG(0, "avma1cs_release(0x%p)\n", link); + + /* + If the device is currently in use, we won't release until it + is actually closed. + */ + if (link->open) { + DEBUG(1, "avma1_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* no unregister function with hisax */ + HiSax_closecard(local->node.minor); + + /* Unlink the device chain */ + link->dev = NULL; + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + avma1cs_detach(link); + +} /* avma1cs_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ + +static int avma1cs_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + + DEBUG(1, "avma1cs_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + link->release.expires = jiffies + HZ/20; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + avma1cs_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + return 0; +} /* avma1cs_event */ + +/*====================================================================*/ + +static int __init init_avma1_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "avma1_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &avma1cs_attach, &avma1cs_detach); + return 0; +} + +static void __exit exit_avma1_cs(void) +{ + DEBUG(0, "avma1_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + if (dev_list->state & DEV_CONFIG) + avma1cs_release((u_long)dev_list); + avma1cs_detach(dev_list); +} + +module_init(init_avma1_cs); +module_exit(exit_avma1_cs); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/isdn/hisax/hfc_pci.c linux-2.5/drivers/isdn/hisax/hfc_pci.c --- linux-2.5.20/drivers/isdn/hisax/hfc_pci.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/isdn/hisax/hfc_pci.c Fri May 3 03:04:58 2002 @@ -76,6 +76,8 @@ { unsigned long flags; + printk(KERN_INFO "HiSax: release hfcpci at %p\n", + cs->hw.hfcpci.pci_io); save_flags(flags); cli(); cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */ @@ -86,9 +88,7 @@ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ -#if CONFIG_PCI pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */ -#endif /* CONFIG_PCI */ del_timer(&cs->hw.hfcpci.timer); iounmap(cs->hw.hfcpci.pci_io); pci_free_consistent(cs->hw.hfcpci.pdev, 32768, cs->hw.hfcpci.fifos, cs->hw.hfcpci.fifos_dma); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/isdn/hisax/w6692.c linux-2.5/drivers/isdn/hisax/w6692.c --- linux-2.5.20/drivers/isdn/hisax/w6692.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/isdn/hisax/w6692.c Fri May 3 03:49:06 2002 @@ -29,11 +29,17 @@ static const PCI_ENTRY id_list[] = { - {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"}, {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"}, - {0, 0, NULL, NULL} + {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"}, + {0, 0, "U.S.Robotics", "ISDN PCI Card TA"} }; +#define W6692_SV_USR 0x16ec +#define W6692_SD_USR 0x3409 +#define W6692_WINBOND 0 +#define W6692_DYNALINK 1 +#define W6692_USR 2 + extern const char *CardType[]; const char *w6692_revision = "$Revision: 1.12.6.6 $"; @@ -859,6 +865,28 @@ return (0); } +void resetW6692(struct IsdnCardState *cs) +{ + cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST); + schedule_timeout((10*HZ)/1000); + cs->writeW6692(cs, W_D_CTL, 0x00); + schedule_timeout((10*HZ)/1000); + cs->writeW6692(cs, W_IMASK, 0xff); + cs->writeW6692(cs, W_D_SAM, 0xff); + cs->writeW6692(cs, W_D_TAM, 0xff); + cs->writeW6692(cs, W_D_EXIM, 0x00); + cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT); + cs->writeW6692(cs, W_IMASK, 0x18); + if (cs->subtyp == W6692_USR) { + /* seems that USR implemented some power control features + * Pin 79 is connected to the oscilator circuit so we + * have to handle it here + */ + cs->writeW6692(cs, W_PCTL, 0x80); + cs->writeW6692(cs, W_XDATA, 0x00); + } +} + void __init initW6692(struct IsdnCardState *cs, int part) { if (part & 1) { @@ -868,15 +896,7 @@ cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); - - cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST); - cs->writeW6692(cs, W_D_CTL, 0x00); - cs->writeW6692(cs, W_IMASK, 0xff); - cs->writeW6692(cs, W_D_SAM, 0xff); - cs->writeW6692(cs, W_D_TAM, 0xff); - cs->writeW6692(cs, W_D_EXIM, 0x00); - cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT); - cs->writeW6692(cs, W_IMASK, 0x18); + resetW6692(cs); ph_command(cs, W_L1CMD_RST); cs->dc.w6692.ph_state = W_L1CMD_RST; W6692_new_ph(cs); @@ -943,9 +963,14 @@ { switch (mt) { case CARD_RESET: + resetW6692(cs); return (0); case CARD_RELEASE: + cs->writeW6692(cs, W_IMASK, 0xff); release_region(cs->hw.w6692.iobase, 256); + if (cs->subtyp == W6692_USR) { + cs->writeW6692(cs, W_XDATA, 0x04); + } return (0); case CARD_INIT: initW6692(cs, 3); @@ -988,6 +1013,7 @@ if (dev_w6692) { if (pci_enable_device(dev_w6692)) continue; + cs->subtyp = id_idx; break; } id_idx++; @@ -998,6 +1024,13 @@ /* I think address 0 is allways the configuration area */ /* and address 1 is the real IO space KKe 03.09.99 */ pci_ioaddr = pci_resource_start(dev_w6692, 1); + /* USR ISDN PCI card TA need some special handling */ + if (cs->subtyp == W6692_WINBOND) { + if ((W6692_SV_USR == dev_w6692->subsystem_vendor) && + (W6692_SD_USR == dev_w6692->subsystem_device)) { + cs->subtyp = W6692_USR; + } + } } if (!found) { printk(KERN_WARNING "W6692: No PCI card found\n"); @@ -1014,18 +1047,18 @@ } cs->hw.w6692.iobase = pci_ioaddr; printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n", - id_list[id_idx].vendor_name, id_list[id_idx].card_name, - pci_ioaddr, dev_w6692->irq); + id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name, + pci_ioaddr, pci_irq); if (check_region((cs->hw.w6692.iobase), 256)) { printk(KERN_WARNING "HiSax: %s I/O ports %x-%x already in use\n", - id_list[id_idx].card_name, + id_list[cs->subtyp].card_name, cs->hw.w6692.iobase, cs->hw.w6692.iobase + 255); return (0); } else { request_region(cs->hw.w6692.iobase, 256, - id_list[id_idx].card_name); + id_list[cs->subtyp].card_name); } #else printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n"); @@ -1035,7 +1068,7 @@ printk(KERN_INFO "HiSax: %s config irq:%d I/O:%x\n", - id_list[id_idx].card_name, cs->irq, + id_list[cs->subtyp].card_name, cs->irq, cs->hw.w6692.iobase); cs->readW6692 = &ReadW6692; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/isdn/isdn_audio.c linux-2.5/drivers/isdn/isdn_audio.c --- linux-2.5.20/drivers/isdn/isdn_audio.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/isdn/isdn_audio.c Fri Feb 8 02:58:29 2002 @@ -0,0 +1,718 @@ +/* $Id: isdn_audio.c,v 1.21.6.2 2001/09/23 22:24:31 kai Exp $ + * + * Linux ISDN subsystem, audio conversion and compression (linklevel). + * + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) + * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at) + * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de) + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include +#include "isdn_audio.h" +#include "isdn_common.h" + +char *isdn_audio_revision = "$Revision: 1.21.6.2 $"; + +/* + * Misc. lookup-tables. + */ + +/* ulaw -> signed 16-bit */ +static short isdn_audio_ulaw_to_s16[] = +{ + 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84, + 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84, + 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84, + 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84, + 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804, + 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004, + 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444, + 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844, + 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64, + 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64, + 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74, + 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74, + 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc, + 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c, + 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0, + 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000, + 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c, + 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c, + 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c, + 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c, + 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc, + 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc, + 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc, + 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc, + 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c, + 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c, + 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c, + 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c, + 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, + 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084, + 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, + 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 +}; + +/* alaw -> signed 16-bit */ +static short isdn_audio_alaw_to_s16[] = +{ + 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4, + 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74, + 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4, + 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64, + 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4, + 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4, + 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4, + 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4, + 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64, + 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34, + 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844, + 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24, + 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64, + 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4, + 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964, + 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4, + 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24, + 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94, + 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924, + 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94, + 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24, + 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14, + 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24, + 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14, + 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4, + 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54, + 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4, + 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64, + 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4, + 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4, + 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4, + 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4 +}; + +/* alaw -> ulaw */ +static char isdn_audio_alaw_to_ulaw[] = +{ + 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, + 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, + 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, + 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, + 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, + 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, + 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, + 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, + 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, + 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, + 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, + 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, + 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, + 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, + 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, + 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, + 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, + 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, + 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, + 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, + 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, + 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, + 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, + 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, + 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, + 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, + 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, + 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, + 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, + 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, + 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, + 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 +}; + +/* ulaw -> alaw */ +static char isdn_audio_ulaw_to_alaw[] = +{ + 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, + 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, + 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, + 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, + 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, + 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, + 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, + 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, + 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, + 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, + 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, + 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, + 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, + 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, + 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, + 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, + 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, + 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, + 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, + 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, + 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, + 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, + 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, + 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, + 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, + 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, + 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, + 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, + 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, + 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, + 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, + 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a +}; + +#define NCOEFF 16 /* number of frequencies to be analyzed */ +#define DTMF_TRESH 25000 /* above this is dtmf */ +#define SILENCE_TRESH 200 /* below this is silence */ +#define H2_TRESH 20000 /* 2nd harmonic */ +#define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */ +#define LOGRP 0 +#define HIGRP 1 + +typedef struct { + int grp; /* low/high group */ + int k; /* k */ + int k2; /* k fuer 2. harmonic */ +} dtmf_t; + +/* For DTMF recognition: + * 2 * cos(2 * PI * k / N) precalculated for all k + */ +static int cos2pik[NCOEFF] = +{ + 55812, 29528, 53603, 24032, 51193, 14443, 48590, 6517, + 38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279 +}; + +static dtmf_t dtmf_tones[8] = +{ + {LOGRP, 0, 1}, /* 697 Hz */ + {LOGRP, 2, 3}, /* 770 Hz */ + {LOGRP, 4, 5}, /* 852 Hz */ + {LOGRP, 6, 7}, /* 941 Hz */ + {HIGRP, 8, 9}, /* 1209 Hz */ + {HIGRP, 10, 11}, /* 1336 Hz */ + {HIGRP, 12, 13}, /* 1477 Hz */ + {HIGRP, 14, 15} /* 1633 Hz */ +}; + +static char dtmf_matrix[4][4] = +{ + {'1', '2', '3', 'A'}, + {'4', '5', '6', 'B'}, + {'7', '8', '9', 'C'}, + {'*', '0', '#', 'D'} +}; + +static inline void +isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n) +{ +#ifdef __i386__ + unsigned long d0, d1, d2, d3; + __asm__ __volatile__( + "cld\n" + "1:\tlodsb\n\t" + "xlatb\n\t" + "stosb\n\t" + "loop 1b\n\t" + : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3) + : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff) + : "memory", "ax"); +#else + while (n--) + *buff = table[*(unsigned char *)buff], buff++; +#endif +} + +void +isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len) +{ + isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len); +} + +void +isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len) +{ + isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len); +} + +/* + * linear <-> adpcm conversion stuff + * Most parts from the mgetty-package. + * (C) by Gert Doering and Klaus Weidner + * Used by permission of Gert Doering + */ + + +#define ZEROTRAP /* turn on the trap as per the MIL-STD */ +#undef ZEROTRAP +#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ +#define CLIP 32635 + +static unsigned char +isdn_audio_linear2ulaw(int sample) +{ + static int exp_lut[256] = + { + 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + }; + int sign, + exponent, + mantissa; + unsigned char ulawbyte; + + /* Get the sample into sign-magnitude. */ + sign = (sample >> 8) & 0x80; /* set aside the sign */ + if (sign != 0) + sample = -sample; /* get magnitude */ + if (sample > CLIP) + sample = CLIP; /* clip the magnitude */ + + /* Convert from 16 bit linear to ulaw. */ + sample = sample + BIAS; + exponent = exp_lut[(sample >> 7) & 0xFF]; + mantissa = (sample >> (exponent + 3)) & 0x0F; + ulawbyte = ~(sign | (exponent << 4) | mantissa); +#ifdef ZEROTRAP + /* optional CCITT trap */ + if (ulawbyte == 0) + ulawbyte = 0x02; +#endif + return (ulawbyte); +} + + +static int Mx[3][8] = +{ + {0x3800, 0x5600, 0, 0, 0, 0, 0, 0}, + {0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0}, + {0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607}, +}; + +static int bitmask[9] = +{ + 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff +}; + +static int +isdn_audio_get_bits(adpcm_state * s, unsigned char **in, int *len) +{ + while (s->nleft < s->nbits) { + int d = *((*in)++); + (*len)--; + s->word = (s->word << 8) | d; + s->nleft += 8; + } + s->nleft -= s->nbits; + return (s->word >> s->nleft) & bitmask[s->nbits]; +} + +static void +isdn_audio_put_bits(int data, int nbits, adpcm_state * s, + unsigned char **out, int *len) +{ + s->word = (s->word << nbits) | (data & bitmask[nbits]); + s->nleft += nbits; + while (s->nleft >= 8) { + int d = (s->word >> (s->nleft - 8)); + *(out[0]++) = d & 255; + (*len)++; + s->nleft -= 8; + } +} + +adpcm_state * +isdn_audio_adpcm_init(adpcm_state * s, int nbits) +{ + if (!s) + s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC); + if (s) { + s->a = 0; + s->d = 5; + s->word = 0; + s->nleft = 0; + s->nbits = nbits; + } + return s; +} + +dtmf_state * +isdn_audio_dtmf_init(dtmf_state * s) +{ + if (!s) + s = (dtmf_state *) kmalloc(sizeof(dtmf_state), GFP_ATOMIC); + if (s) { + s->idx = 0; + s->last = ' '; + } + return s; +} + +/* + * Decompression of adpcm data to a/u-law + * + */ + +int +isdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in, + unsigned char *out, int len) +{ + int a = s->a; + int d = s->d; + int nbits = s->nbits; + int olen = 0; + + while (len) { + int e = isdn_audio_get_bits(s, &in, &len); + int sign; + + if (nbits == 4 && e == 0) + d = 4; + sign = (e >> (nbits - 1)) ? -1 : 1; + e &= bitmask[nbits - 1]; + a += sign * ((e << 1) + 1) * d >> 1; + if (d & 1) + a++; + if (fmt) + *out++ = isdn_audio_ulaw_to_alaw[ + isdn_audio_linear2ulaw(a << 2)]; + else + *out++ = isdn_audio_linear2ulaw(a << 2); + olen++; + d = (d * Mx[nbits - 2][e] + 0x2000) >> 14; + if (d < 5) + d = 5; + } + s->a = a; + s->d = d; + return olen; +} + +int +isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out) +{ + int olen = 0; + + if (s->nleft) + isdn_audio_put_bits(0, 8 - s->nleft, s, &out, &olen); + return olen; +} + +int +isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in, + unsigned char *out, int len) +{ + int a = s->a; + int d = s->d; + int nbits = s->nbits; + int olen = 0; + + while (len--) { + int e = 0, + nmax = 1 << (nbits - 1); + int sign, + delta; + + if (fmt) + delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a; + else + delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a; + if (delta < 0) { + e = nmax; + delta = -delta; + } + while (--nmax && delta > d) { + delta -= d; + e++; + } + if (nbits == 4 && ((e & 0x0f) == 0)) + e = 8; + isdn_audio_put_bits(e, nbits, s, &out, &olen); + sign = (e >> (nbits - 1)) ? -1 : 1; + e &= bitmask[nbits - 1]; + + a += sign * ((e << 1) + 1) * d >> 1; + if (d & 1) + a++; + d = (d * Mx[nbits - 2][e] + 0x2000) >> 14; + if (d < 5) + d = 5; + } + s->a = a; + s->d = d; + return olen; +} + +/* + * Goertzel algorithm. + * See http://ptolemy.eecs.berkeley.edu/~pino/Ptolemy/papers/96/dtmf_ict/ + * for more info. + * Result is stored into an sk_buff and queued up for later + * evaluation. + */ +static void +isdn_audio_goertzel(int *sample, modem_info * info) +{ + int sk, + sk1, + sk2; + int k, + n; + struct sk_buff *skb; + int *result; + + skb = dev_alloc_skb(sizeof(int) * NCOEFF); + if (!skb) { + printk(KERN_WARNING + "isdn_audio: Could not alloc DTMF result for ttyI%d\n", + info->line); + return; + } + result = (int *) skb_put(skb, sizeof(int) * NCOEFF); + for (k = 0; k < NCOEFF; k++) { + sk = sk1 = sk2 = 0; + for (n = 0; n < DTMF_NPOINTS; n++) { + sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2; + sk2 = sk1; + sk1 = sk; + } + result[k] = + ((sk * sk) >> AMP_BITS) - + ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) + + ((sk2 * sk2) >> AMP_BITS); + } + skb_queue_tail(&info->dtmf_queue, skb); + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); +} + +void +isdn_audio_eval_dtmf(modem_info * info) +{ + struct sk_buff *skb; + int *result; + dtmf_state *s; + int silence; + int i; + int di; + int ch; + unsigned long flags; + int grp[2]; + char what; + char *p; + + while ((skb = skb_dequeue(&info->dtmf_queue))) { + result = (int *) skb->data; + s = info->dtmf_state; + grp[LOGRP] = grp[HIGRP] = -2; + silence = 0; + for (i = 0; i < 8; i++) { + if ((result[dtmf_tones[i].k] > DTMF_TRESH) && + (result[dtmf_tones[i].k2] < H2_TRESH)) + grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2) ? i : -1; + else if ((result[dtmf_tones[i].k] < SILENCE_TRESH) && + (result[dtmf_tones[i].k2] < SILENCE_TRESH)) + silence++; + } + if (silence == 8) + what = ' '; + else { + if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) { + what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4]; + if (s->last != ' ' && s->last != '.') + s->last = what; /* min. 1 non-DTMF between DTMF */ + } else + what = '.'; + } + if ((what != s->last) && (what != ' ') && (what != '.')) { + printk(KERN_DEBUG "dtmf: tt='%c'\n", what); + p = skb->data; + *p++ = 0x10; + *p = what; + skb_trim(skb, 2); + if (skb_headroom(skb) < sizeof(isdn_audio_skb)) { + printk(KERN_WARNING + "isdn_audio: insufficient skb_headroom, dropping\n"); + kfree_skb(skb); + return; + } + ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; + ISDN_AUDIO_SKB_LOCK(skb) = 0; + save_flags(flags); + cli(); + di = info->isdn_driver; + ch = info->isdn_channel; + __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); + dev->drv[di]->rcvcount[ch] += 2; + restore_flags(flags); + /* Schedule dequeuing */ + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); + wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); + } else + kfree_skb(skb); + s->last = what; + } +} + +/* + * Decode DTMF tones, queue result in separate sk_buf for + * later examination. + * Parameters: + * s = pointer to state-struct. + * buf = input audio data + * len = size of audio data. + * fmt = audio data format (0 = ulaw, 1 = alaw) + */ +void +isdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt) +{ + dtmf_state *s = info->dtmf_state; + int i; + int c; + + while (len) { + c = DTMF_NPOINTS - s->idx; + if (c > len) + c = len; + if (c <= 0) + break; + for (i = 0; i < c; i++) { + if (fmt) + s->buf[s->idx++] = + isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS); + else + s->buf[s->idx++] = + isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS); + } + if (s->idx == DTMF_NPOINTS) { + isdn_audio_goertzel(s->buf, info); + s->idx = 0; + } + len -= c; + } +} + +silence_state * +isdn_audio_silence_init(silence_state * s) +{ + if (!s) + s = (silence_state *) kmalloc(sizeof(silence_state), GFP_ATOMIC); + if (s) { + s->idx = 0; + s->state = 0; + } + return s; +} + +void +isdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt) +{ + silence_state *s = info->silence_state; + int i; + signed char c; + + if (!info->emu.vpar[1]) return; + + for (i = 0; i < len; i++) { + if (fmt) + c = isdn_audio_alaw_to_ulaw[*buf++]; + else + c = *buf++; + + if (c > 0) c -= 128; + c = abs(c); + + if (c > (info->emu.vpar[1] * 4)) { + s->idx = 0; + s->state = 1; + } else { + if (s->idx < 210000) s->idx++; + } + } +} + +void +isdn_audio_put_dle_code(modem_info * info, u_char code) +{ + struct sk_buff *skb; + unsigned long flags; + int di; + int ch; + char *p; + + skb = dev_alloc_skb(2); + if (!skb) { + printk(KERN_WARNING + "isdn_audio: Could not alloc skb for ttyI%d\n", + info->line); + return; + } + p = (char *) skb_put(skb, 2); + p[0] = 0x10; + p[1] = code; + if (skb_headroom(skb) < sizeof(isdn_audio_skb)) { + printk(KERN_WARNING + "isdn_audio: insufficient skb_headroom, dropping\n"); + kfree_skb(skb); + return; + } + ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; + ISDN_AUDIO_SKB_LOCK(skb) = 0; + save_flags(flags); + cli(); + di = info->isdn_driver; + ch = info->isdn_channel; + __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); + dev->drv[di]->rcvcount[ch] += 2; + restore_flags(flags); + /* Schedule dequeuing */ + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); + wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); +} + +void +isdn_audio_eval_silence(modem_info * info) +{ + silence_state *s = info->silence_state; + char what; + + what = ' '; + + if (s->idx > (info->emu.vpar[2] * 800)) { + s->idx = 0; + if (!s->state) { /* silence from beginning of rec */ + what = 's'; + } else { + what = 'q'; + } + } + if ((what == 's') || (what == 'q')) { + printk(KERN_DEBUG "ttyI%d: %s\n", info->line, + (what=='s') ? "silence":"quiet"); + isdn_audio_put_dle_code(info, what); + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/isdn/isdn_audio.h linux-2.5/drivers/isdn/isdn_audio.h --- linux-2.5.20/drivers/isdn/isdn_audio.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/isdn/isdn_audio.h Thu Jan 3 22:25:54 2002 @@ -0,0 +1,44 @@ +/* $Id: isdn_audio.h,v 1.9.6.1 2001/09/23 22:24:31 kai Exp $ + * + * Linux ISDN subsystem, audio conversion and compression (linklevel). + * + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */ +typedef struct adpcm_state { + int a; + int d; + int word; + int nleft; + int nbits; +} adpcm_state; + +typedef struct dtmf_state { + char last; + int idx; + int buf[DTMF_NPOINTS]; +} dtmf_state; + +typedef struct silence_state { + int state; + unsigned int idx; +} silence_state; + +extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long); +extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long); +extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int); +extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int); +extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int); +extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out); +extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int); +extern void isdn_audio_eval_dtmf(modem_info *); +dtmf_state *isdn_audio_dtmf_init(dtmf_state *); +extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int); +extern void isdn_audio_eval_silence(modem_info *); +silence_state *isdn_audio_silence_init(silence_state *); +extern void isdn_audio_put_dle_code(modem_info *, u_char); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/md/Config.in linux-2.5/drivers/md/Config.in --- linux-2.5.20/drivers/md/Config.in Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/md/Config.in Sun May 26 01:10:56 2002 @@ -13,6 +13,6 @@ dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD -dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD +dep_tristate ' Logical volume manager (LVM) support (EXPERIMENTAL)' CONFIG_BLK_DEV_LVM $CONFIG_MD $CONFIG_EXPERIMENTAL endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/md/lvm-fs.c linux-2.5/drivers/md/lvm-fs.c --- linux-2.5.20/drivers/md/lvm-fs.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/md/lvm-fs.c Sun May 26 01:12:46 2002 @@ -59,9 +59,9 @@ static int _proc_read_global(char *page, char **start, off_t off, int count, int *eof, void *data); -static int _vg_info(vg_t *vg_ptr, char *buf); -static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf); -static int _pv_info(pv_t *pv_ptr, char *buf); +static int _vg_info(kern_vg_t *vg_ptr, char *buf); +static int _lv_info(kern_vg_t *vg_ptr, kern_lv_t *lv_ptr, char *buf); +static int _pv_info(kern_pv_t *pv_ptr, char *buf); static void _show_uuid(const char *src, char *b, char *e); @@ -102,11 +102,16 @@ remove_proc_entry(LVM_DIR, &proc_root); } -void lvm_fs_create_vg(vg_t *vg_ptr) { +void lvm_fs_create_vg(kern_vg_t *vg_ptr) { struct proc_dir_entry *pde; + devfs_handle_t th; - vg_devfs_handle[vg_ptr->vg_number] = - devfs_mk_dir(0, vg_ptr->vg_name, NULL); + th=devfs_get_handle(NULL,vg_ptr->vg_name,0,0,0,0); + + if(th==NULL){ + th=devfs_mk_dir(0, vg_ptr->vg_name, NULL); + } + vg_devfs_handle[vg_ptr->vg_number] = th; ch_devfs_handle[vg_ptr->vg_number] = devfs_register( vg_devfs_handle[vg_ptr->vg_number] , "group", @@ -129,7 +134,7 @@ create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde); } -void lvm_fs_remove_vg(vg_t *vg_ptr) { +void lvm_fs_remove_vg(kern_vg_t *vg_ptr) { int i; devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]); @@ -168,13 +173,13 @@ return name; } -devfs_handle_t lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv) { +devfs_handle_t lvm_fs_create_lv(kern_vg_t *vg_ptr, kern_lv_t *lv) { struct proc_dir_entry *pde; - const char *name = _basename(lv->u.lv_name); + const char *name = _basename(lv->lv_name); - lv_devfs_handle[minor(lv->u.lv_dev)] = devfs_register( + lv_devfs_handle[minor(lv->lv_kdev)] = devfs_register( vg_devfs_handle[vg_ptr->vg_number], name, - DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, minor(lv->u.lv_dev), + DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, minor(lv->lv_kdev), S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, &lvm_blk_dops, NULL); @@ -183,15 +188,15 @@ pde->read_proc = _proc_read_lv; pde->data = lv; } - return lv_devfs_handle[minor(lv->u.lv_dev)]; + return lv_devfs_handle[minor(lv->lv_kdev)]; } -void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv) { - devfs_unregister(lv_devfs_handle[minor(lv->u.lv_dev)]); - lv_devfs_handle[minor(lv->u.lv_dev)] = NULL; +void lvm_fs_remove_lv(kern_vg_t *vg_ptr, kern_lv_t *lv) { + devfs_unregister(lv_devfs_handle[minor(lv->lv_kdev)]); + lv_devfs_handle[minor(lv->lv_kdev)] = NULL; if(vg_ptr->lv_subdir_pde) { - const char *name = _basename(lv->u.lv_name); + const char *name = _basename(lv->lv_name); remove_proc_entry(name, vg_ptr->lv_subdir_pde); } } @@ -211,7 +216,7 @@ *b = '\0'; } -void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv) { +void lvm_fs_create_pv(kern_vg_t *vg_ptr, kern_pv_t *pv) { struct proc_dir_entry *pde; char name[NAME_LEN]; @@ -225,7 +230,7 @@ } } -void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv) { +void lvm_fs_remove_pv(kern_vg_t *vg_ptr, kern_pv_t *pv) { char name[NAME_LEN]; if(!vg_ptr->pv_subdir_pde) @@ -239,7 +244,7 @@ static int _proc_read_vg(char *page, char **start, off_t off, int count, int *eof, void *data) { int sz = 0; - vg_t *vg_ptr = data; + kern_vg_t *vg_ptr = data; char uuid[NAME_LEN]; sz += sprintf(page + sz, "name: %s\n", vg_ptr->vg_name); @@ -267,23 +272,23 @@ static int _proc_read_lv(char *page, char **start, off_t off, int count, int *eof, void *data) { int sz = 0; - lv_t *lv = data; + kern_lv_t *lv = data; - sz += sprintf(page + sz, "name: %s\n", lv->u.lv_name); - sz += sprintf(page + sz, "size: %u\n", lv->u.lv_size); - sz += sprintf(page + sz, "access: %u\n", lv->u.lv_access); - sz += sprintf(page + sz, "status: %u\n", lv->u.lv_status); - sz += sprintf(page + sz, "number: %u\n", lv->u.lv_number); - sz += sprintf(page + sz, "open: %u\n", lv->u.lv_open); - sz += sprintf(page + sz, "allocation: %u\n", lv->u.lv_allocation); - if(lv->u.lv_stripes > 1) { - sz += sprintf(page + sz, "stripes: %u\n", - lv->u.lv_stripes); - sz += sprintf(page + sz, "stripesize: %u\n", - lv->u.lv_stripesize); - } + sz += sprintf(page + sz, "name: %s\n", lv->lv_name); + sz += sprintf(page + sz, "size: %u\n", lv->lv_size); + sz += sprintf(page + sz, "access: %u\n", lv->lv_access); + sz += sprintf(page + sz, "status: %u\n", lv->lv_status); + sz += sprintf(page + sz, "number: %u\n", lv->lv_number); + sz += sprintf(page + sz, "open: %u\n", lv->lv_open); + sz += sprintf(page + sz, "allocation: %u\n", lv->lv_allocation); + if(lv->lv_stripes > 1) { + sz += sprintf(page + sz, "stripes: %u\n", + lv->lv_stripes); + sz += sprintf(page + sz, "stripesize: %u\n", + lv->lv_stripesize); + } sz += sprintf(page + sz, "device: %02u:%02u\n", - major(lv->u.lv_dev), minor(lv->u.lv_dev)); + major(lv->lv_kdev), minor(lv->lv_kdev)); return sz; } @@ -291,7 +296,7 @@ static int _proc_read_pv(char *page, char **start, off_t off, int count, int *eof, void *data) { int sz = 0; - pv_t *pv = data; + kern_pv_t *pv = data; char uuid[NAME_LEN]; sz += sprintf(page + sz, "name: %s\n", pv->pv_name); @@ -304,7 +309,7 @@ sz += sprintf(page + sz, "PE total: %u\n", pv->pe_total); sz += sprintf(page + sz, "PE allocated: %u\n", pv->pe_allocated); sz += sprintf(page + sz, "device: %02u:%02u\n", - major(pv->pv_dev), minor(pv->pv_dev)); + major(pv->pv_kdev), minor(pv->pv_kdev)); _show_uuid(pv->pv_uuid, uuid, uuid + sizeof(uuid)); sz += sprintf(page + sz, "uuid: %s\n", uuid); @@ -323,9 +328,9 @@ off_t sz_last; static char *buf = NULL; static char dummy_buf[160]; /* sized for 2 lines */ - vg_t *vg_ptr; - lv_t *lv_ptr; - pv_t *pv_ptr; + kern_vg_t *vg_ptr; + kern_lv_t *lv_ptr; + kern_pv_t *pv_ptr; #ifdef DEBUG_LVM_PROC_GET_INFO @@ -350,13 +355,13 @@ if (vg_ptr->lv_cur > 0) { for (l = 0; l < vg[v]->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) != NULL) { - pe_t_bytes += lv_ptr->u.lv_allocated_le; + pe_t_bytes += lv_ptr->lv_allocated_le; hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size; - if (lv_ptr->u.lv_block_exception != NULL) - lv_block_exception_t_bytes += lv_ptr->u.lv_remap_end; - if (lv_ptr->u.lv_open > 0) { + if (lv_ptr->lv_block_exception != NULL) + lv_block_exception_t_bytes += lv_ptr->lv_remap_end; + if (lv_ptr->lv_open > 0) { lv_open_counter++; - lv_open_total += lv_ptr->u.lv_open; + lv_open_total += lv_ptr->lv_open; } } } @@ -364,7 +369,7 @@ } } - pe_t_bytes *= sizeof(pe_t); + pe_t_bytes *= sizeof(kern_pe_t); lv_block_exception_t_bytes *= sizeof(lv_block_exception_t); if (buf != NULL) { @@ -403,9 +408,9 @@ sz += sprintf(LVM_PROC_BUF, ")"); sz += sprintf(LVM_PROC_BUF, "\nGlobal: %lu bytes malloced IOP version: %d ", - vg_counter * sizeof(vg_t) + - pv_counter * sizeof(pv_t) + - lv_counter * sizeof(lv_t) + + vg_counter * sizeof(kern_vg_t) + + pv_counter * sizeof(kern_pv_t) + + lv_counter * sizeof(kern_lv_t) + pe_t_bytes + hash_table_bytes + lv_block_exception_t_bytes + sz_last, lvm_iop_version); @@ -497,7 +502,7 @@ /* * provide VG info for proc filesystem use (global) */ -static int _vg_info(vg_t *vg_ptr, char *buf) { +static int _vg_info(kern_vg_t *vg_ptr, char *buf) { int sz = 0; char inactive_flag = ' '; @@ -527,21 +532,21 @@ /* * provide LV info for proc filesystem use (global) */ -static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf) { +static int _lv_info(kern_vg_t *vg_ptr, kern_lv_t *lv_ptr, char *buf) { int sz = 0; char inactive_flag = 'A', allocation_flag = ' ', stripes_flag = ' ', rw_flag = ' ', *basename; - if (!(lv_ptr->u.lv_status & LV_ACTIVE)) + if (!(lv_ptr->lv_status & LV_ACTIVE)) inactive_flag = 'I'; rw_flag = 'R'; - if (lv_ptr->u.lv_access & LV_WRITE) + if (lv_ptr->lv_access & LV_WRITE) rw_flag = 'W'; allocation_flag = 'D'; - if (lv_ptr->u.lv_allocation & LV_CONTIGUOUS) + if (lv_ptr->lv_allocation & LV_CONTIGUOUS) allocation_flag = 'C'; stripes_flag = 'L'; - if (lv_ptr->u.lv_stripes > 1) + if (lv_ptr->lv_stripes > 1) stripes_flag = 'S'; sz += sprintf(buf+sz, "[%c%c%c%c", @@ -549,29 +554,29 @@ rw_flag, allocation_flag, stripes_flag); - if (lv_ptr->u.lv_stripes > 1) + if (lv_ptr->lv_stripes > 1) sz += sprintf(buf+sz, "%-2d", - lv_ptr->u.lv_stripes); + lv_ptr->lv_stripes); else sz += sprintf(buf+sz, " "); /* FIXME: use _basename */ - basename = strrchr(lv_ptr->u.lv_name, '/'); - if ( basename == 0) basename = lv_ptr->u.lv_name; + basename = strrchr(lv_ptr->lv_name, '/'); + if ( basename == 0) basename = lv_ptr->lv_name; else basename++; sz += sprintf(buf+sz, "] %-25s", basename); if (strlen(basename) > 25) sz += sprintf(buf+sz, "\n "); sz += sprintf(buf+sz, "%9d /%-6d ", - lv_ptr->u.lv_size >> 1, - lv_ptr->u.lv_size / vg_ptr->pe_size); + lv_ptr->lv_size >> 1, + lv_ptr->lv_size / vg_ptr->pe_size); - if (lv_ptr->u.lv_open == 0) + if (lv_ptr->lv_open == 0) sz += sprintf(buf+sz, "close"); else sz += sprintf(buf+sz, "%dx open", - lv_ptr->u.lv_open); + lv_ptr->lv_open); return sz; } @@ -580,7 +585,7 @@ /* * provide PV info for proc filesystem use (global) */ -static int _pv_info(pv_t *pv, char *buf) { +static int _pv_info(kern_pv_t *pv, char *buf) { int sz = 0; char inactive_flag = 'A', allocation_flag = ' '; char *pv_name = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/md/lvm-internal.h linux-2.5/drivers/md/lvm-internal.h --- linux-2.5.20/drivers/md/lvm-internal.h Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/md/lvm-internal.h Sun May 26 01:10:56 2002 @@ -42,7 +42,7 @@ extern const char *const lvm_name; -extern vg_t *vg[]; +extern kern_vg_t *vg[]; extern struct file_operations lvm_chr_fops; extern struct block_device_operations lvm_blk_dops; @@ -73,29 +73,29 @@ #define P_DEV(fmt, args...) #endif - +#ifdef BROKEN /* lvm-snap.c */ int lvm_get_blksize(kdev_t); -int lvm_snapshot_alloc(lv_t *); -int lvm_snapshot_fill_COW_page(vg_t *, lv_t *); -int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, vg_t *vg, lv_t *); -int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *); -void lvm_snapshot_release(lv_t *); -int lvm_write_COW_table_block(vg_t *, lv_t *); -void lvm_hash_link(lv_block_exception_t *, kdev_t, ulong, lv_t *); -int lvm_snapshot_alloc_hash_table(lv_t *); -void lvm_drop_snapshot(vg_t *vg, lv_t *, const char *); - +int lvm_snapshot_alloc(kern_lv_t *); +int lvm_snapshot_fill_COW_page(kern_vg_t *, kern_lv_t *); +int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, kern_vg_t *vg, kern_lv_t *); +int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, kern_lv_t *); +void lvm_snapshot_release(kern_lv_t *); +int lvm_write_COW_table_block(kern_vg_t *, kern_lv_t *); +void lvm_hash_link(lv_block_exception_t *, kdev_t, ulong, kern_lv_t *); +int lvm_snapshot_alloc_hash_table(kern_lv_t *); +void lvm_drop_snapshot(kern_vg_t *vg, kern_lv_t *, const char *); +#endif /* lvm_fs.c */ void lvm_init_fs(void); void lvm_fin_fs(void); -void lvm_fs_create_vg(vg_t *vg_ptr); -void lvm_fs_remove_vg(vg_t *vg_ptr); -devfs_handle_t lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv); -void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv); -void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv); -void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv); +void lvm_fs_create_vg(kern_vg_t *vg_ptr); +void lvm_fs_remove_vg(kern_vg_t *vg_ptr); +devfs_handle_t lvm_fs_create_lv(kern_vg_t *vg_ptr, kern_lv_t *lv); +void lvm_fs_remove_lv(kern_vg_t *vg_ptr, kern_lv_t *lv); +void lvm_fs_create_pv(kern_vg_t *vg_ptr, kern_pv_t *pv); +void lvm_fs_remove_pv(kern_vg_t *vg_ptr, kern_pv_t *pv); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/md/lvm-snap.c linux-2.5/drivers/md/lvm-snap.c --- linux-2.5.20/drivers/md/lvm-snap.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/md/lvm-snap.c Sun May 26 01:10:56 2002 @@ -1,3 +1,4 @@ +#ifdef BROKEN /* * kernel/lvm-snap.c * @@ -698,3 +699,4 @@ } MODULE_LICENSE("GPL"); +#endif /* broken */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/md/lvm.c linux-2.5/drivers/md/lvm.c --- linux-2.5.20/drivers/md/lvm.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/md/lvm.c Sun May 26 01:10:56 2002 @@ -1,4 +1,10 @@ +#define IGNORE_AL_VIRO + + +#ifndef IGNORE_AL_VIRO #error Broken until maintainers will sanitize kdev_t handling +#endif + /* * kernel/lvm.c * @@ -243,8 +249,8 @@ static int lvm_blk_open(struct inode *, struct file *); static int lvm_blk_close(struct inode *, struct file *); -static int lvm_get_snapshot_use_rate(lv_t *lv_ptr, void *arg); -static int lvm_user_bmap(struct inode *, struct lv_bmap *); +static int lvm_get_snapshot_use_rate(kern_lv_t *lv_ptr, void *arg); +/*static int lvm_user_bmap(struct inode *, struct lv_bmap *);*/ static int lvm_chr_open(struct inode *, struct file *); static int lvm_chr_close(struct inode *, struct file *); @@ -265,39 +271,49 @@ #endif static int lvm_map(struct bio *); static int lvm_do_lock_lvm(void); -static int lvm_do_le_remap(vg_t *, void *); +//static int lvm_do_le_remap(vg_t *, void *); -static int lvm_do_pv_create(pv_t *, vg_t *, ulong); -static int lvm_do_pv_remove(vg_t *, ulong); -static int lvm_do_lv_create(int, char *, userlv_t *); -static int lvm_do_lv_extend_reduce(int, char *, userlv_t *); +static int lvm_do_pv_create(user_pv_t *, kern_vg_t *, ulong); +static int lvm_do_pv_remove(kern_vg_t *, ulong); +static int lvm_do_lv_create(int, char *, user_lv_t *); +//static int lvm_do_lv_extend_reduce(int, char *, user_lv_t *); static int lvm_do_lv_remove(int, char *, int); -static int lvm_do_lv_rename(vg_t *, lv_req_t *, userlv_t *); -static int lvm_do_lv_status_byname(vg_t *r, void *); -static int lvm_do_lv_status_byindex(vg_t *, void *); -static int lvm_do_lv_status_bydev(vg_t *, void *); +static int lvm_do_lv_rename(kern_vg_t *, lv_req_t *, user_lv_t *); +static int lvm_do_lv_status_byname(kern_vg_t *r, void *); +static int lvm_do_lv_status_byindex(kern_vg_t *, void *); +static int lvm_do_lv_status_bydev(kern_vg_t *, void *); -static int lvm_do_pe_lock_unlock(vg_t *r, void *); +static int lvm_do_pe_lock_unlock(kern_vg_t *r, void *); -static int lvm_do_pv_change(vg_t*, void*); -static int lvm_do_pv_status(vg_t *, void *); +static int lvm_do_pv_change(kern_vg_t*, void*); +static int lvm_do_pv_status(kern_vg_t *, void *); static int lvm_do_pv_flush(void *); static int lvm_do_vg_create(void *, int minor); -static int lvm_do_vg_extend(vg_t *, void *); -static int lvm_do_vg_reduce(vg_t *, void *); -static int lvm_do_vg_rename(vg_t *, void *); +static int lvm_do_vg_extend(kern_vg_t *, void *); +static int lvm_do_vg_reduce(kern_vg_t *, void *); +static int lvm_do_vg_rename(kern_vg_t *, void *); static int lvm_do_vg_remove(int); static void lvm_geninit(struct gendisk *); -static void __update_hardsectsize(lv_t *lv); +static void __update_hardsectsize(kern_lv_t *lv); static void _queue_io(struct bio *bh, int rw); static struct bio *_dequeue_io(void); static void _flush_io(struct bio *bh); -static int _open_pv(pv_t *pv); -static void _close_pv(pv_t *pv); +static int _open_pv(kern_pv_t *pv); +static void _close_pv(kern_pv_t *pv); + +/* function for converting between kernelspace and + userspace versions of structures */ +static void kernpv_to_userpv(const kern_pv_t *const kpv,user_pv_t *const upv); +static void userpv_to_kernpv(const user_pv_t *const upv,kern_pv_t *const kpv); +static void kernvg_to_uservg(const kern_vg_t *const kvg,user_vg_t *const uvg); +static void uservg_to_kernvg(const user_vg_t *const uvg,kern_vg_t *const kvg); +static void kernlv_to_userlv(const kern_lv_t *const klv,user_lv_t *const ulv); +static void userlv_to_kernlv(const user_lv_t *const ulv,kern_lv_t *const klv); + static unsigned long _sectors_to_k(unsigned long sect); @@ -315,7 +331,7 @@ /* volume group descriptor area pointers */ -vg_t *vg[ABS_MAX_VG]; +kern_vg_t *vg[ABS_MAX_VG]; /* map from block minor number to VG and LV numbers */ typedef struct { @@ -326,10 +342,10 @@ /* Request structures (lvm_chr_ioctl()) */ -static pv_change_req_t pv_change_req; +/* static pv_change_req_t pv_change_req; */ static pv_status_req_t pv_status_req; volatile static pe_lock_req_t pe_lock_req; -static le_remap_req_t le_remap_req; +/* static le_remap_req_t le_remap_req; */ static lv_req_t lv_req; #ifdef LVM_TOTAL_RESET @@ -337,7 +353,6 @@ #endif static char pv_name[NAME_LEN]; -/* static char rootvg[NAME_LEN] = { 0, }; */ static int lock = 0; static int _lock_open_count = 0; static uint vg_count = 0; @@ -512,25 +527,25 @@ static int lvm_chr_open(struct inode *inode, struct file *file) { unsigned int minor = minor(inode->i_rdev); - + P_DEV("chr_open MINOR: %d VG#: %d mode: %s%s lock: %d\n", minor, VG_CHR(minor), MODE_TO_STR(file->f_mode), lock); - + /* super user validation */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - + /* Group special file open */ if (VG_CHR(minor) > MAX_VG) return -ENXIO; - - spin_lock(&lvm_lock); - if(lock == current->pid) - _lock_open_count++; - spin_unlock(&lvm_lock); - + + spin_lock(&lvm_lock); + if(lock == current->pid) + _lock_open_count++; + spin_unlock(&lvm_lock); + lvm_chr_open_count++; - + MOD_INC_USE_COUNT; - + return 0; } /* lvm_chr_open() */ @@ -543,13 +558,13 @@ * */ static int lvm_chr_ioctl(struct inode *inode, struct file *file, - uint command, ulong a) + uint command, ulong a) { int minor = minor(inode->i_rdev); uint extendable, l, v; void *arg = (void *) a; - userlv_t ulv; - vg_t* vg_ptr = vg[VG_CHR(minor)]; + user_lv_t ulv; + kern_vg_t* vg_ptr = vg[VG_CHR(minor)]; /* otherwise cc will complain about unused variables */ (void) lvm_lock; @@ -596,7 +611,8 @@ case LE_REMAP: /* remap a logical extent (after moving the physical extent) */ - return lvm_do_le_remap(vg_ptr,arg); + return -ENOSYS; +// return lvm_do_le_remap(vg_ptr,arg); case PE_LOCK_UNLOCK: /* lock/unlock i/o to a physical extent to move it to another @@ -607,10 +623,10 @@ /* create a VGDA */ return lvm_do_vg_create(arg, minor); - case VG_CREATE: - /* create a VGDA, assume VG number is filled in */ + case VG_CREATE: + /* create a VGDA, assume VG number is filled in */ return lvm_do_vg_create(arg, -1); - + case VG_EXTEND: /* extend a volume group */ return lvm_do_vg_extend(vg_ptr, arg); @@ -644,14 +660,23 @@ return 0; - case VG_STATUS: + case VG_STATUS:{ + user_vg_t *tmpuvg; /* get volume group data (only the vg_t struct) */ if (vg_ptr == NULL) return -ENXIO; - if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0) + + tmpuvg=kmalloc(sizeof(user_vg_t),GFP_KERNEL); + if(tmpuvg==NULL){ + return -ENOMEM; + } + kernvg_to_uservg(vg_ptr,tmpuvg); + if(copy_to_user(arg,tmpuvg,sizeof(user_vg_t))!=0){ return -EFAULT; + } + kfree(tmpuvg); return 0; - + } case VG_STATUS_GET_COUNT: /* get volume group count */ if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0) @@ -684,7 +709,7 @@ return -EFAULT; if (command != LV_REMOVE) { - if (copy_from_user(&ulv, lv_req.lv, sizeof(userlv_t)) != 0) + if (copy_from_user(&ulv, lv_req.lv, sizeof(user_lv_t)) != 0) return -EFAULT; } switch (command) { @@ -693,7 +718,7 @@ case LV_EXTEND: case LV_REDUCE: - return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &ulv); + return -ENOSYS;//lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &ulv); case LV_REMOVE: return lvm_do_lv_remove(minor, lv_req.lv_name, -1); @@ -792,8 +817,8 @@ static int lvm_blk_open(struct inode *inode, struct file *file) { int minor = minor(inode->i_rdev); - lv_t *lv_ptr; - vg_t *vg_ptr = vg[VG_BLK(minor)]; + kern_lv_t *lv_ptr; + kern_vg_t *vg_ptr = vg[VG_BLK(minor)]; P_DEV("blk_open MINOR: %d VG#: %d LV#: %d mode: %s%s\n", minor, VG_BLK(minor), LV_BLK(minor), MODE_TO_STR(file->f_mode)); @@ -810,23 +835,23 @@ LV_BLK(minor) < vg_ptr->lv_max) { /* Check parallel LV spindown (LV remove) */ - if (lv_ptr->u.lv_status & LV_SPINDOWN) return -EPERM; + if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; /* Check inactive LV and open for read/write */ /* We need to be able to "read" an inactive LV to re-activate it again */ if ((file->f_mode & FMODE_WRITE) && - (!(lv_ptr->u.lv_status & LV_ACTIVE))) + (!(lv_ptr->lv_status & LV_ACTIVE))) return -EPERM; - if (!(lv_ptr->u.lv_access & LV_WRITE) && + if (!(lv_ptr->lv_access & LV_WRITE) && (file->f_mode & FMODE_WRITE)) return -EACCES; /* be sure to increment VG counter */ - if (lv_ptr->u.lv_open == 0) vg_ptr->lv_open++; - lv_ptr->u.lv_open++; + if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; + lv_ptr->lv_open++; MOD_INC_USE_COUNT; @@ -845,8 +870,8 @@ uint command, ulong a) { int minor = minor(inode->i_rdev); - vg_t *vg_ptr = vg[VG_BLK(minor)]; - lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; + kern_vg_t *vg_ptr = vg[VG_BLK(minor)]; + kern_lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; void *arg = (void *) a; struct hd_geometry *hd = (struct hd_geometry *) a; @@ -861,13 +886,13 @@ case BLKGETSIZE: /* return device size */ - P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->u.lv_size); - if (put_user(lv_ptr->u.lv_size, (unsigned long *)arg)) + P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->lv_size); + if (put_user(lv_ptr->lv_size, (unsigned long *)arg)) return -EFAULT; break; case BLKGETSIZE64: - if (put_user((u64)lv_ptr->u.lv_size << 9, (u64 *)arg)) + if (put_user((u64)lv_ptr->lv_size << 9, (u64 *)arg)) return -EFAULT; break; @@ -891,7 +916,7 @@ unsigned char heads = 64; unsigned char sectors = 32; long start = 0; - short cylinders = lv_ptr->u.lv_size / heads / sectors; + short cylinders = lv_ptr->lv_size / heads / sectors; if (copy_to_user((char *) &hd->heads, &heads, sizeof(heads)) != 0 || @@ -912,34 +937,36 @@ case LV_SET_ACCESS: /* set access flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lv_ptr->u.lv_access = (ulong) arg; - if ( lv_ptr->u.lv_access & LV_WRITE) - set_device_ro(lv_ptr->u.lv_dev, 0); + lv_ptr->lv_access = (ulong) arg; + if ( lv_ptr->lv_access & LV_WRITE) + set_device_ro(lv_ptr->lv_kdev, 0); else - set_device_ro(lv_ptr->u.lv_dev, 1); + set_device_ro(lv_ptr->lv_kdev, 1); break; case LV_SET_STATUS: /* set status flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!((ulong) arg & LV_ACTIVE) && lv_ptr->u.lv_open > 1) + if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1) return -EPERM; - lv_ptr->u.lv_status = (ulong) arg; + lv_ptr->lv_status = (ulong) arg; break; case LV_BMAP: + /* BROKEN */ + return -ENOSYS; /*lvm_user_bmap(inode, (struct lv_bmap *) arg);*/ + + /* turn logical block into (dev_t, block). non privileged. */ /* don't bmap a snapshot, since the mapping can change */ - if(lv_ptr->u.lv_access & LV_SNAPSHOT) + if(lv_ptr->lv_access & LV_SNAPSHOT) return -EPERM; - return lvm_user_bmap(inode, (struct lv_bmap *) arg); - case LV_SET_ALLOCATION: /* set allocation flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lv_ptr->u.lv_allocation = (ulong) arg; + lv_ptr->lv_allocation = (ulong) arg; break; case LV_SNAPSHOT_USE_RATE: @@ -962,26 +989,26 @@ static int lvm_blk_close(struct inode *inode, struct file *file) { int minor = minor(inode->i_rdev); - vg_t *vg_ptr = vg[VG_BLK(minor)]; - lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; + kern_vg_t *vg_ptr = vg[VG_BLK(minor)]; + kern_lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; P_DEV("blk_close MINOR: %d VG#: %d LV#: %d\n", minor, VG_BLK(minor), LV_BLK(minor)); - if (lv_ptr->u.lv_open == 1) vg_ptr->lv_open--; - lv_ptr->u.lv_open--; + if (lv_ptr->lv_open == 1) vg_ptr->lv_open--; + lv_ptr->lv_open--; MOD_DEC_USE_COUNT; return 0; } /* lvm_blk_close() */ -static int lvm_get_snapshot_use_rate(lv_t *lv, void *arg) +static int lvm_get_snapshot_use_rate(kern_lv_t *lv, void *arg) { lv_snapshot_use_rate_req_t lv_rate_req; - if (!(lv->u.lv_access & LV_SNAPSHOT)) - return -EPERM; + if (!(lv->lv_access & LV_SNAPSHOT)) + return -EPERM; /* PERM?? INVAL*/ if (copy_from_user(&lv_rate_req, arg, sizeof(lv_rate_req))) return -EFAULT; @@ -992,7 +1019,7 @@ switch (lv_rate_req.block) { case 0: lv->lv_snapshot_use_rate = lv_rate_req.rate; - if (lv->u.lv_remap_ptr * 100 / lv->u.lv_remap_end < + if (lv->lv_remap_ptr * 100 / lv->lv_remap_end < lv->lv_snapshot_use_rate) interruptible_sleep_on(&lv->lv_snapshot_wait); break; @@ -1003,12 +1030,12 @@ default: return -EINVAL; } - lv_rate_req.rate = lv->u.lv_remap_ptr * 100 / lv->u.lv_remap_end; + lv_rate_req.rate = lv->lv_remap_ptr * 100 / lv->lv_remap_end; return copy_to_user(arg, &lv_rate_req, sizeof(lv_rate_req)) ? -EFAULT : 0; } - +/* static int lvm_user_bmap(struct inode *inode, struct lv_bmap *user_result) { struct bio bio; @@ -1019,8 +1046,8 @@ return -EFAULT; memset(&bio,0,sizeof(bio)); - bio.bi_dev = inode->i_rdev; - bio.bi_size = block_size(bio.bi_dev); /* NEEDED by bio_sectors */ + bio.bi_bdev = inode->i_bdev; + bio.bi_size = block_size(bio.bi_bdev); / NEEDED by bio_sectors / bio.bi_sector = block * bio_sectors(&bio); bio.bi_rw = READ; if ((err=lvm_map(&bio)) < 0) { @@ -1028,12 +1055,12 @@ return -EINVAL; } - return put_user(kdev_t_to_nr(bio.bi_dev), &user_result->lv_dev) || + return put_user(kdev_t_to_nr(bio.bi_bdev), &user_result->lv_dev) || put_user(bio.bi_sector/bio_sectors(&bio), &user_result->lv_block) ? -EFAULT : 0; } - - +*/ +#ifdef BROKEN /* * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c * (see init_module/lvm_init) @@ -1066,20 +1093,20 @@ /* we haven't yet copied this block to the snapshot */ __remap_snapshot(rdev, rsector, pe_start, lv, vg); } - +#endif /* * extents destined for a pe that is on the move should be deferred */ -static inline int _should_defer(kdev_t pv, ulong sector, uint32_t pe_size) { +static inline int _should_defer(struct block_device *pv, ulong sector, uint32_t pe_size) { return ((pe_lock_req.lock == LOCK_PE) && - kdev_same(pv, pe_lock_req.data.pv_dev) && + kdev_same(to_kdev_t(pv->bd_dev), pe_lock_req.data.pv_dev) && (sector >= pe_lock_req.data.pv_offset) && (sector < (pe_lock_req.data.pv_offset + pe_size))); } static inline int _defer_extent(struct bio *bh, int rw, - kdev_t pv, ulong sector, uint32_t pe_size) + struct block_device *pv, ulong sector, uint32_t pe_size) { if (pe_lock_req.lock == LOCK_PE) { down_read(&_pe_lock); @@ -1096,32 +1123,31 @@ return 0; } -static int lvm_map(struct bio *bi) -{ - int minor = minor(bi->bi_dev); +static int lvm_map(struct bio *bi){ + int minor = minor(to_kdev_t(bi->bi_bdev->bd_dev)); ulong index; ulong pe_start; ulong size = bio_sectors(bi); ulong rsector_org = bi->bi_sector; ulong rsector_map; - kdev_t rdev_map; - vg_t *vg_this = vg[VG_BLK(minor)]; - lv_t *lv = vg_this->lv[LV_BLK(minor)]; + struct block_device *rbd_map; + kern_vg_t *vg_this = vg[VG_BLK(minor)]; + kern_lv_t *lv = vg_this->lv[LV_BLK(minor)]; int rw = bio_rw(bi); down_read(&lv->lv_lock); - if (!(lv->u.lv_status & LV_ACTIVE)) { + if (!(lv->lv_status & LV_ACTIVE)) { printk(KERN_ALERT "%s - lvm_map: ll_rw_blk for inactive LV %s\n", - lvm_name, lv->u.lv_name); + lvm_name, lv->lv_name); goto bad; } if ((rw == WRITE || rw == WRITEA) && - !(lv->u.lv_access & LV_WRITE)) { + !(lv->lv_access & LV_WRITE)) { printk(KERN_CRIT "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", - lvm_name, lv->u.lv_name); + lvm_name, lv->lv_name); goto bad; } @@ -1130,7 +1156,7 @@ kdevname(bi->bi_dev), rsector_org, size); - if (rsector_org + size > lv->u.lv_size) { + if (rsector_org + size > lv->lv_size) { printk(KERN_ALERT "%s - lvm_map access beyond end of device; *rsector: " "%lu or size: %lu wrong for minor: %2d\n", @@ -1139,39 +1165,39 @@ } - if (lv->u.lv_stripes < 2) { /* linear mapping */ + if (lv->lv_stripes < 2) { /* linear mapping */ /* get the index */ index = rsector_org / vg_this->pe_size; - pe_start = lv->u.lv_current_pe[index].pe; - rsector_map = lv->u.lv_current_pe[index].pe + + pe_start = lv->lv_current_pe[index].pe; + rsector_map = lv->lv_current_pe[index].pe + (rsector_org % vg_this->pe_size); - rdev_map = lv->u.lv_current_pe[index].dev; + rbd_map = lv->lv_current_pe[index].bdev; P_MAP("u.lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n", - index, lv->u.lv_current_pe[index].pe, + index, lv->lv_current_pe[index].pe, kdevname(rdev_map), rsector_map); } else { /* striped mapping */ ulong stripe_index; ulong stripe_length; - stripe_length = vg_this->pe_size * lv->u.lv_stripes; + stripe_length = vg_this->pe_size * lv->lv_stripes; stripe_index = (rsector_org % stripe_length) / - lv->u.lv_stripesize; + lv->lv_stripesize; index = rsector_org / stripe_length + - (stripe_index % lv->u.lv_stripes) * - (lv->u.lv_allocated_le / lv->u.lv_stripes); - pe_start = lv->u.lv_current_pe[index].pe; - rsector_map = lv->u.lv_current_pe[index].pe + + (stripe_index % lv->lv_stripes) * + (lv->lv_allocated_le / lv->lv_stripes); + pe_start = lv->lv_current_pe[index].pe; + rsector_map = lv->lv_current_pe[index].pe + (rsector_org % stripe_length) - - (stripe_index % lv->u.lv_stripes) * lv->u.lv_stripesize - - stripe_index / lv->u.lv_stripes * - (lv->u.lv_stripes - 1) * lv->u.lv_stripesize; - rdev_map = lv->u.lv_current_pe[index].dev; + (stripe_index % lv->lv_stripes) * lv->lv_stripesize - + stripe_index / lv->lv_stripes * + (lv->lv_stripes - 1) * lv->lv_stripesize; + rbd_map = lv->lv_current_pe[index].bdev; P_MAP("u.lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n" "stripe_length: %ld stripe_index: %ld\n", - index, lv->u.lv_current_pe[index].pe, kdevname(rdev_map), + index, lv->lv_current_pe[index].pe, kdevname(rdev_map), rsector_map, stripe_length, stripe_index); } @@ -1181,24 +1207,24 @@ * we need to queue this request, because this is in the fast path. */ if (rw == WRITE || rw == WRITEA) { - if(_defer_extent(bi, rw, rdev_map, + if(_defer_extent(bi, rw, rbd_map, rsector_map, vg_this->pe_size)) { up_read(&lv->lv_lock); return 0; } - lv->u.lv_current_pe[index].writes++; /* statistic */ + lv->lv_current_pe[index].writes++; /* statistic */ } else - lv->u.lv_current_pe[index].reads++; /* statistic */ + lv->lv_current_pe[index].reads++; /* statistic */ /* snapshot volume exception handling on physical device address base */ - if (!(lv->u.lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG))) + if (!(lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG))) goto out; - +#ifdef BROKEN if (lv->u.lv_access & LV_SNAPSHOT) { /* remap snapshot */ if (lv->u.lv_block_exception) - lvm_snapshot_remap_block(&rdev_map, &rsector_map, + lvm_snapshot_remap_block(&rbd_map, &rsector_map, pe_start, lv); else goto bad; @@ -1216,13 +1242,13 @@ /* Serializes the COW with the accesses to the snapshot device */ - _remap_snapshot(rdev_map, rsector_map, + _remap_snapshot(rbd_map, rsector_map, pe_start, snap, vg_this); } } - +#endif out: - bi->bi_dev = rdev_map; + bi->bi_bdev = rbd_map; bi->bi_sector = rsector_map; up_read(&lv->lv_lock); return 1; @@ -1301,7 +1327,7 @@ /* * character device support function lock/unlock physical extend */ -static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg) +static int lvm_do_pe_lock_unlock(kern_vg_t *vg_ptr, void *arg) { pe_lock_req_t new_lock; struct bio *bh; @@ -1316,7 +1342,7 @@ for (p = 0; p < vg_ptr->pv_max; p++) { if (vg_ptr->pv[p] != NULL && kdev_same(new_lock.data.pv_dev, - vg_ptr->pv[p]->pv_dev)) + vg_ptr->pv[p]->pv_kdev)) break; } if (p == vg_ptr->pv_max) return -ENXIO; @@ -1366,14 +1392,14 @@ return 0; } - +#ifdef BROKEN /* * character device support function logical extend remap */ -static int lvm_do_le_remap(vg_t *vg_ptr, void *arg) +static int lvm_do_le_remap(kern_vg_t *vg_ptr, void *arg) { uint l, le; - lv_t *lv_ptr; + kern_lv_t *lv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&le_remap_req, arg, @@ -1386,7 +1412,7 @@ strcmp(lv_ptr->u.lv_name, le_remap_req.lv_name) == 0) { for (le = 0; le < lv_ptr->u.lv_allocated_le; le++) { - if (kdev_same(lv_ptr->u.lv_current_pe[le].dev, + if (kdev_same(lv_ptr->u.lv_current_pe[le].bdev, le_remap_req.old_dev) && lv_ptr->u.lv_current_pe[le].pe == le_remap_req.old_pe) { @@ -1404,6 +1430,172 @@ } return -ENXIO; } /* lvm_do_le_remap() */ +#endif + +static void userlv_to_kernlv(const user_lv_t *const ulv,kern_lv_t *const klv){ + memcpy(klv->vg_name,ulv->vg_name,NAME_LEN); + memcpy(klv->lv_name,ulv->lv_name,NAME_LEN); + klv->lv_access=ulv->lv_access; + klv->lv_status=ulv->lv_status; + klv->lv_open=ulv->lv_open; + klv->lv_kdev=to_kdev_t(ulv->lv_dev); + klv->lv_number=ulv->lv_number; + klv->lv_size=ulv->lv_size; + klv->lv_current_pe=NULL; + klv->lv_allocated_le=ulv->lv_allocated_le; + klv->lv_current_le=ulv->lv_current_le; + klv->lv_stripes=ulv->lv_stripes; + klv->lv_stripesize=ulv->lv_stripesize; + klv->lv_iobuf=NULL; + klv->lv_COW_table_iobuf=NULL; + init_rwsem(&klv->lv_lock); + klv->lv_snapshot_hash_table=NULL; + klv->lv_snapshot_hash_table_size=0; + klv->lv_snapshot_hash_mask=0; +/* + klv->lv_snapshot_wait=NULL; */ + klv->lv_snapshot_use_rate=0; + klv->vg=NULL; + klv->lv_allocated_snapshot_le=0; + klv->lv_snapshot_org=NULL; + klv->lv_snapshot_prev=NULL; + klv->lv_snapshot_next=NULL; + klv->lv_block_exception=NULL; + klv->lv_remap_ptr=0; + klv->lv_remap_end=0; + klv->lv_chunk_size=0; +} + +static void kernlv_to_userlv(const kern_lv_t *const klv,user_lv_t *const ulv){ + memcpy(ulv->vg_name,klv->vg_name,NAME_LEN); + memcpy(ulv->lv_name,klv->lv_name,NAME_LEN); + ulv->lv_access=klv->lv_access; + ulv->lv_status=klv->lv_status; + ulv->lv_open=klv->lv_open; + ulv->lv_dev=kdev_t_to_nr(klv->lv_kdev); + ulv->lv_number=klv->lv_number; + ulv->lv_size=klv->lv_size; + ulv->lv_allocated_le=klv->lv_allocated_le; + ulv->lv_current_le=klv->lv_current_le; + ulv->lv_stripes=klv->lv_stripes; + ulv->lv_stripesize=klv->lv_stripesize; +} + +static void uservg_to_kernvg(const user_vg_t *const uvg,kern_vg_t *const kvg){ + int i; + memcpy(kvg->vg_name,uvg->vg_name,NAME_LEN); + kvg->vg_number=uvg->vg_number; + kvg->vg_access=uvg->vg_access; + kvg->vg_status=uvg->vg_status; + kvg->lv_max=uvg->lv_max; + kvg->lv_cur=uvg->lv_cur; + kvg->lv_open=uvg->lv_open; + kvg->pv_max=uvg->pv_max; + kvg->pv_cur=uvg->pv_cur; + kvg->pv_act=uvg->pv_act; + kvg->dummy=0; + kvg->vgda=uvg->vgda; + kvg->pe_size=uvg->pe_size; + kvg->pe_total=uvg->pe_total; + kvg->pe_allocated=uvg->pe_allocated; + kvg->pvg_total=uvg->pvg_total; + kvg->proc=NULL; + for(i=0;ipv[i]=NULL; + } + for(i=0;ilv[i]=NULL; + } + memcpy(kvg->vg_uuid,uvg->vg_uuid,UUID_LEN+1); + + kvg->vg_dir_pde=NULL; + kvg->lv_subdir_pde=NULL; + kvg->pv_subdir_pde=NULL; + +} + + +static void kernvg_to_uservg(const kern_vg_t *const kvg,user_vg_t *const uvg){ + int i; + memcpy(uvg->vg_name,kvg->vg_name,NAME_LEN); + uvg->vg_number=kvg->vg_number; + uvg->vg_access=kvg->vg_access; + uvg->vg_status=kvg->vg_status; + uvg->lv_max=kvg->lv_max; + uvg->lv_cur=kvg->lv_cur; + uvg->lv_open=kvg->lv_open; + uvg->pv_max=kvg->pv_max; + uvg->pv_cur=kvg->pv_cur; + uvg->pv_act=kvg->pv_act; + uvg->dummy=0; + uvg->vgda=kvg->vgda; + uvg->pe_size=kvg->pe_size; + uvg->pe_total=kvg->pe_total; + uvg->pe_allocated=kvg->pe_allocated; + uvg->pvg_total=kvg->pvg_total; + for(i=0;ilv[i]=(user_lv_t *)0xDEADBEEF; + } + for(i=0;ipv[i]=(user_pv_t *)0xDEADC0DE; + } + + memcpy(uvg->vg_uuid,kvg->vg_uuid,UUID_LEN+1); +} + +static void userpv_to_kernpv(const user_pv_t *const upv,kern_pv_t *const kpv){ + kpv->id[0]=upv->id[0]; + kpv->id[1]=upv->id[1]; + kpv->version=upv->version; + memcpy(&kpv->pv_on_disk,&upv->pv_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&kpv->vg_on_disk,&upv->vg_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&kpv->pv_uuidlist_on_disk,&upv->pv_uuidlist_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&kpv->lv_on_disk,&upv->lv_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&kpv->pe_on_disk,&upv->pe_on_disk,sizeof(lvm_disk_data_t)); + + memcpy(&kpv->pv_name,&upv->pv_name,NAME_LEN); + memcpy(&kpv->vg_name,&upv->vg_name,NAME_LEN); + memcpy(&kpv->system_id,&upv->system_id,NAME_LEN); + kpv->pv_kdev=to_kdev_t(upv->pv_dev); + kpv->pv_number=upv->pv_number; + kpv->pv_status =upv->pv_status; + kpv->pv_allocatable =upv->pv_allocatable; + kpv->pv_size =upv->pv_size; + kpv->lv_cur =upv->lv_cur; + kpv->pe_size =upv->pe_size; + kpv->pe_total =upv->pe_total; + kpv->pe_allocated =upv->pe_allocated; + kpv->pe_stale =upv->pe_stale; + kpv->pe=NULL; + kpv->bd=NULL; + memcpy(kpv->pv_uuid,upv->pv_uuid,UUID_LEN+1); +} + +static void kernpv_to_userpv(const kern_pv_t *const kpv, user_pv_t *const upv){ + upv->id[0]=kpv->id[0]; + upv->id[1]=kpv->id[1]; + upv->version=kpv->version; + memcpy(&upv->pv_on_disk,&kpv->pv_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&upv->vg_on_disk,&kpv->vg_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&upv->pv_uuidlist_on_disk,&kpv->pv_uuidlist_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&upv->lv_on_disk,&kpv->lv_on_disk,sizeof(lvm_disk_data_t)); + memcpy(&upv->pe_on_disk,&kpv->pe_on_disk,sizeof(lvm_disk_data_t)); + + memcpy(&upv->pv_name,&kpv->pv_name,NAME_LEN); + memcpy(&upv->vg_name,&kpv->vg_name,NAME_LEN); + memcpy(&upv->system_id,&kpv->system_id,NAME_LEN); + upv->pv_dev=kdev_t_to_nr(kpv->pv_kdev); + upv->pv_number=kpv->pv_number; + upv->pv_status =kpv->pv_status; + upv->pv_allocatable =kpv->pv_allocatable; + upv->pv_size =kpv->pv_size; + upv->lv_cur =kpv->lv_cur; + upv->pe_size =kpv->pe_size; + upv->pe_total =kpv->pe_total; + upv->pe_allocated =kpv->pe_allocated; + upv->pe_stale =kpv->pe_stale; + memcpy(upv->pv_uuid,kpv->pv_uuid,UUID_LEN+1); +} /* @@ -1413,26 +1605,31 @@ { int ret = 0; ulong l, ls = 0, p, size; - vg_t *vg_ptr; - lv_t **snap_lv_ptr; - lv_t *tmplv; + kern_vg_t *vg_ptr; + kern_lv_t **snap_lv_ptr; + user_vg_t *tmpuvg; + user_lv_t *tmpulv; + + tmpuvg=kmalloc(sizeof(user_vg_t),GFP_KERNEL); - if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) { + /* this will be our new vg */ + if ((vg_ptr = kmalloc(sizeof(kern_vg_t),GFP_KERNEL)) == NULL) { printk(KERN_CRIT "%s -- VG_CREATE: kmalloc error VG at line %d\n", lvm_name, __LINE__); return -ENOMEM; } - /* get the volume group structure */ - if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) { + /* copy userdata into kernspace */ + if (copy_from_user(tmpuvg, arg, sizeof(user_vg_t)) != 0) { P_IOCTL("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n", arg, sizeof(vg_t)); kfree(vg_ptr); return -EFAULT; } - + /* set up as much as possible from user_vg_t */ + uservg_to_kernvg(tmpuvg,vg_ptr); /* VG_CREATE now uses minor number in VG structure */ if (minor == -1) minor = vg_ptr->vg_number; @@ -1472,10 +1669,16 @@ /* get the physical volume structures */ vg_ptr->pv_act = vg_ptr->pv_cur = 0; for (p = 0; p < vg_ptr->pv_max; p++) { - pv_t *pvp; + user_pv_t tmpupv; + /* user space address */ - if ((pvp = vg_ptr->pv[p]) != NULL) { - ret = lvm_do_pv_create(pvp, vg_ptr, p); + if(tmpuvg->pv[p]!=NULL){ + if (copy_from_user(&tmpupv, tmpuvg->pv[p], sizeof(user_pv_t)) != 0) { + P_IOCTL("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n", + tmpuvg->pv[p], sizeof(user_pv_t)); + return -EFAULT; + } + ret = lvm_do_pv_create(&tmpupv, vg_ptr, p); if ( ret != 0) { lvm_do_vg_remove(minor); return ret; @@ -1483,7 +1686,7 @@ } } - size = vg_ptr->lv_max * sizeof(lv_t *); + size = vg_ptr->lv_max * sizeof(kern_lv_t *); if ((snap_lv_ptr = vmalloc ( size)) == NULL) { printk(KERN_CRIT "%s -- VG_CREATE: vmalloc error snapshot LVs at line %d\n", @@ -1493,7 +1696,7 @@ } memset(snap_lv_ptr, 0, size); - if ((tmplv = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) { + if ((tmpulv = kmalloc(sizeof(user_lv_t),GFP_KERNEL)) == NULL) { printk(KERN_CRIT "%s -- VG_CREATE: kmalloc error LV at line %d\n", lvm_name, __LINE__); @@ -1504,30 +1707,32 @@ /* get the logical volume structures */ vg_ptr->lv_cur = 0; for (l = 0; l < vg_ptr->lv_max; l++) { - lv_t *lvp; - - /* user space address */ - if ((lvp = vg_ptr->lv[l]) != NULL) { - if (copy_from_user(tmplv, lvp, sizeof(userlv_t)) != 0) { + void *lvp; /* user space address */ + + if ((lvp = tmpuvg->lv[l]) != NULL) { + + if (copy_from_user(tmpulv, lvp, sizeof(user_lv_t)) != 0) { P_IOCTL("ERROR: copying LV ptr %p (%d bytes)\n", lvp, sizeof(lv_t)); lvm_do_vg_remove(minor); vfree(snap_lv_ptr); - kfree(tmplv); + kfree(tmpulv); return -EFAULT; } - if ( tmplv->u.lv_access & LV_SNAPSHOT) { + + if ( tmpulv->lv_access & LV_SNAPSHOT) { snap_lv_ptr[ls] = lvp; vg_ptr->lv[l] = NULL; ls++; continue; } vg_ptr->lv[l] = NULL; + /* only create original logical volumes for now */ - if (lvm_do_lv_create(minor, tmplv->u.lv_name, &tmplv->u) != 0) { + if (lvm_do_lv_create(minor, tmpulv->lv_name, tmpulv) != 0) { lvm_do_vg_remove(minor); vfree(snap_lv_ptr); - kfree(tmplv); + kfree(tmpulv); return -EFAULT; } } @@ -1535,24 +1740,25 @@ /* Second path to correct snapshot logical volumes which are not in place during first path above */ +#ifdef BROKEN for (l = 0; l < ls; l++) { lv_t *lvp = snap_lv_ptr[l]; - if (copy_from_user(tmplv, lvp, sizeof(userlv_t)) != 0) { + if (copy_from_user(tmpulv, lvp, sizeof(user_lv_t)) != 0) { lvm_do_vg_remove(minor); vfree(snap_lv_ptr); - kfree(tmplv); + kfree(tmpulv); return -EFAULT; } - if (lvm_do_lv_create(minor, tmplv->u.lv_name, &tmplv->u) != 0) { + if (lvm_do_lv_create(minor, tmpulv->lv_name, tmpulv) != 0) { lvm_do_vg_remove(minor); vfree(snap_lv_ptr); - kfree(tmplv); + kfree(tmpulv); return -EFAULT; } } - +#endif vfree(snap_lv_ptr); - kfree(tmplv); + kfree(tmpulv); vg_count++; @@ -1568,17 +1774,26 @@ /* * character device support function VGDA extend */ -static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg) +static int lvm_do_vg_extend(kern_vg_t *vg_ptr, void *arg) { int ret = 0; uint p; - pv_t *pv_ptr; + kern_pv_t *pv_ptr; if (vg_ptr == NULL) return -ENXIO; if (vg_ptr->pv_cur < vg_ptr->pv_max) { for (p = 0; p < vg_ptr->pv_max; p++) { if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) { - ret = lvm_do_pv_create(arg, vg_ptr, p); + user_pv_t tmpupv; + + /* user space address */ + if (copy_from_user(&tmpupv, arg, sizeof(user_pv_t)) != 0) { + P_IOCTL("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n", + arg, sizeof(user_pv_t)); + return -EFAULT; + } + + ret = lvm_do_pv_create(&tmpupv, vg_ptr, p); if ( ret != 0) return ret; pv_ptr = vg_ptr->pv[p]; vg_ptr->pe_total += pv_ptr->pe_total; @@ -1593,9 +1808,9 @@ /* * character device support function VGDA reduce */ -static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) { +static int lvm_do_vg_reduce(kern_vg_t *vg_ptr, void *arg) { uint p; - pv_t *pv_ptr; + kern_pv_t *pv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0) @@ -1622,9 +1837,10 @@ /* * character device support function VG rename */ -static int lvm_do_vg_rename(vg_t *vg_ptr, void *arg) +static int lvm_do_vg_rename(kern_vg_t *vg_ptr, void *arg) { - int l = 0, p = 0, len = 0; + return -ENOSYS; +/* int l = 0, p = 0, len = 0; char vg_name[NAME_LEN] = { 0,}; char lv_name[NAME_LEN] = { 0,}; char *ptr = NULL; @@ -1642,15 +1858,15 @@ for ( l = 0; l < vg_ptr->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) == NULL) continue; - strncpy(lv_ptr->u.vg_name, vg_name, sizeof ( vg_name)); - ptr = strrchr(lv_ptr->u.lv_name, '/'); - if (ptr == NULL) ptr = lv_ptr->u.lv_name; + strncpy(lv_ptr->vg_name, vg_name, sizeof ( vg_name)); + ptr = strrchr(lv_ptr->lv_name, '/'); + if (ptr == NULL) ptr = lv_ptr->lv_name; strncpy(lv_name, ptr, sizeof ( lv_name)); len = sizeof(LVM_DIR_PREFIX); - strcpy(lv_ptr->u.lv_name, LVM_DIR_PREFIX); - strncat(lv_ptr->u.lv_name, vg_name, NAME_LEN - len); + strcpy(lv_ptr->lv_name, LVM_DIR_PREFIX); + strncat(lv_ptr->lv_name, vg_name, NAME_LEN - len); len += strlen ( vg_name); - strncat(lv_ptr->u.lv_name, lv_name, NAME_LEN - len); + strncat(lv_ptr->lv_name, lv_name, NAME_LEN - len); } for ( p = 0; p < vg_ptr->pv_max; p++) { @@ -1660,7 +1876,7 @@ lvm_fs_create_vg(vg_ptr); - return 0; + return 0;*/ } /* lvm_do_vg_rename */ @@ -1670,8 +1886,8 @@ static int lvm_do_vg_remove(int minor) { int i; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - pv_t *pv_ptr; + kern_vg_t *vg_ptr = vg[VG_CHR(minor)]; + kern_pv_t *pv_ptr; if (vg_ptr == NULL) return -ENXIO; @@ -1692,7 +1908,7 @@ /* first free snapshot logical volumes */ for (i = 0; i < vg_ptr->lv_max; i++) { if (vg_ptr->lv[i] != NULL && - vg_ptr->lv[i]->u.lv_access & LV_SNAPSHOT) { + vg_ptr->lv[i]->lv_access & LV_SNAPSHOT) { lvm_do_lv_remove(minor, NULL, i); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(1); @@ -1730,11 +1946,11 @@ /* * character device support function physical volume create */ -static int lvm_do_pv_create(pv_t *pvp, vg_t *vg_ptr, ulong p) { - pv_t *pv; +static int lvm_do_pv_create(user_pv_t *upv, kern_vg_t *vg_ptr, ulong p) { + kern_pv_t *pv; int err; - pv = kmalloc(sizeof(pv_t),GFP_KERNEL); + pv = kmalloc(sizeof(kern_pv_t),GFP_KERNEL); if (pv == NULL) { printk(KERN_CRIT "%s -- PV_CREATE: kmalloc error PV at line %d\n", @@ -1744,12 +1960,7 @@ memset(pv, 0, sizeof(*pv)); - if (copy_from_user(pv, pvp, sizeof(pv_t)) != 0) { - P_IOCTL("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n", - pvp, sizeof(pv_t)); - kfree(pv); - return -EFAULT; - } + userpv_to_kernpv(upv,pv); if ((err = _open_pv(pv))) { kfree(pv); @@ -1773,8 +1984,8 @@ /* * character device support function physical volume remove */ -static int lvm_do_pv_remove(vg_t *vg_ptr, ulong p) { - pv_t *pv = vg_ptr->pv[p]; +static int lvm_do_pv_remove(kern_vg_t *vg_ptr, ulong p) { + kern_pv_t *pv = vg_ptr->pv[p]; lvm_fs_remove_pv(vg_ptr, pv); @@ -1791,12 +2002,12 @@ } -static void __update_hardsectsize(lv_t *lv) { +static void __update_hardsectsize(kern_lv_t *lv) { int le, e; int max_hardsectsize = 0, hardsectsize; - for (le = 0; le < lv->u.lv_allocated_le; le++) { - hardsectsize = get_hardsect_size(lv->u.lv_current_pe[le].dev); + for (le = 0; le < lv->lv_allocated_le; le++) { + hardsectsize = bdev_hardsect_size(lv->lv_current_pe[le].bdev); if (hardsectsize == 0) hardsectsize = 512; if (hardsectsize > max_hardsectsize) @@ -1804,10 +2015,10 @@ } /* only perform this operation on active snapshots */ - if ((lv->u.lv_access & LV_SNAPSHOT) && - (lv->u.lv_status & LV_ACTIVE)) { - for (e = 0; e < lv->u.lv_remap_end; e++) { - hardsectsize = get_hardsect_size( lv->u.lv_block_exception[e].rdev_new); + if ((lv->lv_access & LV_SNAPSHOT) && + (lv->lv_status & LV_ACTIVE)) { + for (e = 0; e < lv->lv_remap_end; e++) { + hardsectsize = get_hardsect_size( lv->lv_block_exception[e].rdev_new); if (hardsectsize == 0) hardsectsize = 512; if (hardsectsize > max_hardsectsize) @@ -1819,16 +2030,15 @@ /* * character device support function logical volume create */ -static int lvm_do_lv_create(int minor, char *lv_name, userlv_t *ulv) +static int lvm_do_lv_create(int minor, char *lv_name, user_lv_t *ulv) { - int e, ret, l, le, l_new, p, size, activate = 1; + int l, le, l_new, p, size, activate = 1; ulong lv_status_save; - lv_block_exception_t *lvbe = ulv->lv_block_exception; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *lv_ptr = NULL; - pe_t *pep; + kern_vg_t *vg_ptr = vg[VG_CHR(minor)]; + kern_lv_t *lv_ptr = NULL; + void *user_pep; - if (!(pep = ulv->lv_current_pe)) + if (!(user_pep = ulv->lv_current_pe)) return -EINVAL; if (_sectors_to_k(ulv->lv_chunk_size) > LVM_SNAPSHOT_MAX_CHUNK) @@ -1836,7 +2046,7 @@ for (l = 0; l < vg_ptr->lv_cur; l++) { if (vg_ptr->lv[l] != NULL && - strcmp(vg_ptr->lv[l]->u.lv_name, lv_name) == 0) + strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) return -EEXIST; } @@ -1853,37 +2063,28 @@ if (l_new == -1) return -EPERM; else l = l_new; - if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {; + if ((lv_ptr = kmalloc(sizeof(kern_lv_t),GFP_KERNEL)) == NULL) {; printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n", lvm_name, __LINE__); return -ENOMEM; } - /* copy preloaded LV */ - memcpy((char *) lv_ptr, (char *) ulv, sizeof(userlv_t)); - lv_status_save = lv_ptr->u.lv_status; - lv_ptr->u.lv_status &= ~LV_ACTIVE; - lv_ptr->u.lv_snapshot_org = NULL; - lv_ptr->u.lv_snapshot_prev = NULL; - lv_ptr->u.lv_snapshot_next = NULL; - lv_ptr->u.lv_block_exception = NULL; - lv_ptr->lv_iobuf = NULL; - lv_ptr->lv_COW_table_iobuf = NULL; - lv_ptr->lv_snapshot_hash_table = NULL; - lv_ptr->lv_snapshot_hash_table_size = 0; - lv_ptr->lv_snapshot_hash_mask = 0; - init_rwsem(&lv_ptr->lv_lock); - lv_ptr->lv_snapshot_use_rate = 0; + userlv_to_kernlv(ulv,lv_ptr); + + lv_status_save = lv_ptr->lv_status; + lv_ptr->lv_status &= ~LV_ACTIVE; vg_ptr->lv[l] = lv_ptr; /* get the PE structures from user space if this is not a snapshot logical volume */ - if (!(lv_ptr->u.lv_access & LV_SNAPSHOT)) { - size = lv_ptr->u.lv_allocated_le * sizeof(pe_t); + if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { + user_pe_t tmpupe; + + size = lv_ptr->lv_allocated_le * sizeof(kern_pe_t); - if ((lv_ptr->u.lv_current_pe = vmalloc(size)) == NULL) { + if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte " "at line %d\n", @@ -1893,24 +2094,53 @@ vg_ptr->lv[l] = NULL; return -ENOMEM; } - if (copy_from_user(lv_ptr->u.lv_current_pe, pep, size)) { - P_IOCTL("ERROR: copying PE ptr %p (%d bytes)\n", - pep, sizeof(size)); - vfree(lv_ptr->u.lv_current_pe); - kfree(lv_ptr); - vg_ptr->lv[l] = NULL; - return -EFAULT; + + /* just to be sure */ + memset(lv_ptr->lv_current_pe,0,size); + + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + /* copy the pe's one by one */ + if (copy_from_user(&tmpupe, user_pep+(le*sizeof(user_pe_t)), sizeof(user_pe_t))) { + P_IOCTL("ERROR: copying PE(%d) ptr %p (%d bytes)\n", + le,user_pep+(le*sizeof(user_pe_t)), + sizeof(user_lv_t)); + vfree(lv_ptr->lv_current_pe); + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EFAULT; + } + + lv_ptr->lv_current_pe[le].bdev = + bdget(tmpupe.dev); + lv_ptr->lv_current_pe[le].pe = + tmpupe.pe; + lv_ptr->lv_current_pe[le].reads = + tmpupe.reads; + lv_ptr->lv_current_pe[le].writes = + tmpupe.writes; + if(lv_ptr->lv_current_pe[le].bdev==NULL){ + printk(KERN_CRIT "%s bdget failed\n",lvm_name); + vfree(lv_ptr->lv_current_pe); + kfree(lv_ptr); + return -EINVAL; + } } + + /* correct the PE count in PVs */ - for (le = 0; le < lv_ptr->u.lv_allocated_le; le++) { + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { vg_ptr->pe_allocated++; for (p = 0; p < vg_ptr->pv_cur; p++) { - if (kdev_same(vg_ptr->pv[p]->pv_dev, - lv_ptr->u.lv_current_pe[le].dev)) + if (kdev_same(vg_ptr->pv[p]->pv_kdev, + to_kdev_t(lv_ptr->lv_current_pe[le].bdev->bd_dev))) vg_ptr->pv[p]->pe_allocated++; } } - } else { + } else { /* snapshot */ + return -ENOSYS; +#ifdef BROKEN +/* + void *lvbe = ulv->lv_block_exception; */ /* Get snapshot exception data and block list */ if (lvbe != NULL) { lv_ptr->u.lv_snapshot_org = @@ -2003,22 +2233,25 @@ vg_ptr->lv[l] = NULL; return -EINVAL; } +#endif /* BROKEN */ } /* if ( vg[VG_CHR(minor)]->lv[l]->u.lv_access & LV_SNAPSHOT) */ + lv_ptr = vg_ptr->lv[l]; - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].start_sect = 0; - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].nr_sects = lv_ptr->u.lv_size; - lvm_size[minor(lv_ptr->u.lv_dev)] = lv_ptr->u.lv_size >> 1; - vg_lv_map[minor(lv_ptr->u.lv_dev)].vg_number = vg_ptr->vg_number; - vg_lv_map[minor(lv_ptr->u.lv_dev)].lv_number = lv_ptr->u.lv_number; + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].start_sect = 0; + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].nr_sects = lv_ptr->lv_size; + lvm_size[minor(lv_ptr->lv_kdev)] = lv_ptr->lv_size >> 1; + vg_lv_map[minor(lv_ptr->lv_kdev)].vg_number = vg_ptr->vg_number; + vg_lv_map[minor(lv_ptr->lv_kdev)].lv_number = lv_ptr->lv_number; vg_ptr->lv_cur++; - lv_ptr->u.lv_status = lv_status_save; + lv_ptr->lv_status = lv_status_save; __update_hardsectsize(lv_ptr); /* optionally add our new snapshot LV */ - if (lv_ptr->u.lv_access & LV_SNAPSHOT) { - lv_t *org = lv_ptr->u.lv_snapshot_org, *last; + if (lv_ptr->lv_access & LV_SNAPSHOT) { +#ifdef BROKEN + lv_t *org = lv_ptr->lv_snapshot_org, *last; /* sync the original logical volume */ fsync_dev(org->u.lv_dev); @@ -2036,28 +2269,30 @@ lv_ptr->u.lv_snapshot_prev = last; last->u.lv_snapshot_next = lv_ptr; up_write(&org->lv_lock); +#endif /* BROKEN */ } /* activate the logical volume */ if(activate) - lv_ptr->u.lv_status |= LV_ACTIVE; + lv_ptr->lv_status |= LV_ACTIVE; else - lv_ptr->u.lv_status &= ~LV_ACTIVE; + lv_ptr->lv_status &= ~LV_ACTIVE; - if ( lv_ptr->u.lv_access & LV_WRITE) - set_device_ro(lv_ptr->u.lv_dev, 0); + if ( lv_ptr->lv_access & LV_WRITE) + set_device_ro(lv_ptr->lv_kdev, 0); else - set_device_ro(lv_ptr->u.lv_dev, 1); + set_device_ro(lv_ptr->lv_kdev, 1); + #ifdef LVM_VFS_ENHANCEMENT /* VFS function call to unlock the filesystem */ - if (lv_ptr->u.lv_access & LV_SNAPSHOT) - unlockfs(lv_ptr->u.lv_snapshot_org->u.lv_dev); + if (lv_ptr->lv_access & LV_SNAPSHOT) + unlockfs(lv_ptr->lv_snapshot_org->lv_kdev); #endif lv_ptr->vg = vg_ptr; - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].de = + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].de = lvm_fs_create_lv(vg_ptr, lv_ptr); return 0; @@ -2070,13 +2305,13 @@ static int lvm_do_lv_remove(int minor, char *lv_name, int l) { uint le, p; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *lv_ptr; + kern_vg_t *vg_ptr = vg[VG_CHR(minor)]; + kern_lv_t *lv_ptr; if (l == -1) { for (l = 0; l < vg_ptr->lv_max; l++) { if (vg_ptr->lv[l] != NULL && - strcmp(vg_ptr->lv[l]->u.lv_name, lv_name) == 0) { + strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) { break; } } @@ -2085,21 +2320,23 @@ lv_ptr = vg_ptr->lv[l]; #ifdef LVM_TOTAL_RESET - if (lv_ptr->u.lv_open > 0 && lvm_reset_spindown == 0) + if (lv_ptr->lv_open > 0 && lvm_reset_spindown == 0) #else - if (lv_ptr->u.lv_open > 0) + if (lv_ptr->lv_open > 0) #endif return -EBUSY; /* check for deletion of snapshot source while snapshot volume still exists */ - if ((lv_ptr->u.lv_access & LV_SNAPSHOT_ORG) && - lv_ptr->u.lv_snapshot_next != NULL) + if ((lv_ptr->lv_access & LV_SNAPSHOT_ORG) && + lv_ptr->lv_snapshot_next != NULL) return -EPERM; lvm_fs_remove_lv(vg_ptr, lv_ptr); - if (lv_ptr->u.lv_access & LV_SNAPSHOT) { + if (lv_ptr->lv_access & LV_SNAPSHOT) { + return -ENOSYS; +#ifdef BROKEN /* * Atomically make the the snapshot invisible * to the original lv before playing with it. @@ -2124,43 +2361,44 @@ /* Update the VG PE(s) used by snapshot reserve space. */ vg_ptr->pe_allocated -= lv_ptr->lv_allocated_snapshot_le; +#endif } - lv_ptr->u.lv_status |= LV_SPINDOWN; + lv_ptr->lv_status |= LV_SPINDOWN; /* sync the buffers */ - fsync_dev(lv_ptr->u.lv_dev); + fsync_dev(lv_ptr->lv_kdev); - lv_ptr->u.lv_status &= ~LV_ACTIVE; + lv_ptr->lv_status &= ~LV_ACTIVE; /* invalidate the buffers */ - invalidate_buffers(lv_ptr->u.lv_dev); + invalidate_buffers(lv_ptr->lv_kdev); /* reset generic hd */ - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].start_sect = -1; - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].nr_sects = 0; - lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].de = 0; - lvm_size[minor(lv_ptr->u.lv_dev)] = 0; + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].start_sect = -1; + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].nr_sects = 0; + lvm_gendisk.part[minor(lv_ptr->lv_kdev)].de = 0; + lvm_size[minor(lv_ptr->lv_kdev)] = 0; /* reset VG/LV mapping */ - vg_lv_map[minor(lv_ptr->u.lv_dev)].vg_number = ABS_MAX_VG; - vg_lv_map[minor(lv_ptr->u.lv_dev)].lv_number = -1; + vg_lv_map[minor(lv_ptr->lv_kdev)].vg_number = ABS_MAX_VG; + vg_lv_map[minor(lv_ptr->lv_kdev)].lv_number = -1; /* correct the PE count in PVs if this is not a snapshot logical volume */ - if (!(lv_ptr->u.lv_access & LV_SNAPSHOT)) { + if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { /* only if this is no snapshot logical volume because we share the u.lv_current_pe[] structs with the original logical volume */ - for (le = 0; le < lv_ptr->u.lv_allocated_le; le++) { + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { vg_ptr->pe_allocated--; for (p = 0; p < vg_ptr->pv_cur; p++) { - if (kdev_same(vg_ptr->pv[p]->pv_dev, - lv_ptr->u.lv_current_pe[le].dev)) + if (kdev_same(vg_ptr->pv[p]->pv_kdev, + to_kdev_t(lv_ptr->lv_current_pe[le].bdev->bd_dev))) vg_ptr->pv[p]->pe_allocated--; } } - vfree(lv_ptr->u.lv_current_pe); + vfree(lv_ptr->lv_current_pe); } P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__); @@ -2170,11 +2408,11 @@ return 0; } /* lvm_do_lv_remove() */ - +#ifdef BROKEN /* * logical volume extend / reduce */ -static int __extend_reduce_snapshot(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { +static int __extend_reduce_snapshot(kern_vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { ulong size; lv_block_exception_t *lvbe; @@ -2205,12 +2443,12 @@ return 0; } -static int __extend_reduce(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { +static int __extend_reduce(kern_vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { ulong size, l, p, end; pe_t *pe; /* allocate space for new pe structures */ - size = new_lv->u.lv_current_le * sizeof(pe_t); + size = new_lv->lv_current_le * sizeof(pe_t); if ((pe = vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- lvm_do_lv_extend_reduce: " @@ -2220,7 +2458,7 @@ } /* get the PE structures from user space */ - if (copy_from_user(pe, new_lv->u.lv_current_pe, size)) { + if (copy_from_user(pe, new_lv->lv_current_pe, size)) { if(old_lv->u.lv_access & LV_SNAPSHOT) vfree(new_lv->lv_snapshot_hash_table); vfree(pe); @@ -2234,7 +2472,7 @@ vg_ptr->pe_allocated--; for (p = 0; p < vg_ptr->pv_cur; p++) { if (kdev_same(vg_ptr->pv[p]->pv_dev, - old_lv->u.lv_current_pe[l].dev)) { + to_kdev_t(old_lv->u.lv_current_pe[l].bdev->bd_dev))) { vg_ptr->pv[p]->pe_allocated--; break; } @@ -2246,7 +2484,7 @@ vg_ptr->pe_allocated++; for (p = 0; p < vg_ptr->pv_cur; p++) { if (kdev_same(vg_ptr->pv[p]->pv_dev, - new_lv->u.lv_current_pe[l].dev)) { + to_kdev_t(new_lv->u.lv_current_pe[l].bdev->bd_dev))) { vg_ptr->pv[p]->pe_allocated++; break; } @@ -2287,13 +2525,13 @@ return 0; } -static int lvm_do_lv_extend_reduce(int minor, char *lv_name, userlv_t *ulv) +static int lvm_do_lv_extend_reduce(int minor, char *lv_name, user_lv_t *ulv) { int r; ulong l, e, size; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *old_lv; - lv_t *new_lv; + kern_vg_t *vg_ptr = vg[VG_CHR(minor)]; + kern_lv_t *old_lv; + kern_lv_t *new_lv; pe_t *pe; if((new_lv = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL){ @@ -2303,7 +2541,7 @@ return -ENOMEM; } memset(new_lv,0,sizeof(lv_t)); - memcpy(&new_lv->u,ulv,sizeof(userlv_t)); + memcpy(&new_lv->u,ulv,sizeof(user_lv_t)); if ((pe = new_lv->u.lv_current_pe) == NULL) return -EINVAL; @@ -2318,11 +2556,13 @@ old_lv = vg_ptr->lv[l]; if (old_lv->u.lv_access & LV_SNAPSHOT) { + return -ENOSYS; /* only perform this operation on active snapshots */ - if (old_lv->u.lv_status & LV_ACTIVE) +/* if (old_lv->u.lv_status & LV_ACTIVE) r = __extend_reduce_snapshot(vg_ptr, old_lv, new_lv); - else - r = -EPERM; + else + r = -EPERM; +*/ } else r = __extend_reduce(vg_ptr, old_lv, new_lv); @@ -2334,6 +2574,9 @@ down_write(&old_lv->lv_lock); if(new_lv->u.lv_access & LV_SNAPSHOT) { + return -ENOSYS; + +/* size = (new_lv->u.lv_remap_end > old_lv->u.lv_remap_end) ? old_lv->u.lv_remap_ptr : new_lv->u.lv_remap_end; size *= sizeof(lv_block_exception_t); @@ -2353,10 +2596,9 @@ lvm_hash_link(new_lv->u.lv_block_exception + e, new_lv->u.lv_block_exception[e].rdev_org, new_lv->u.lv_block_exception[e].rsector_org, - new_lv); + new_lv);*/ } else { - vfree(old_lv->u.lv_current_pe); vfree(old_lv->lv_snapshot_hash_table); @@ -2394,18 +2636,19 @@ return 0; } /* lvm_do_lv_extend_reduce() */ - +#endif /* * character device support function logical volume status by name */ -static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg) +static int lvm_do_lv_status_byname(kern_vg_t *vg_ptr, void *arg) { uint l; lv_status_byname_req_t lv_status_byname_req; void *saved_ptr1; void *saved_ptr2; - lv_t *lv_ptr; + kern_lv_t *lv_ptr; + user_lv_t tmpulv; /* we're rather heavy on stack here */ if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&lv_status_byname_req, arg, @@ -2414,30 +2657,74 @@ if (lv_status_byname_req.lv == NULL) return -EINVAL; + if (copy_from_user(&tmpulv, lv_status_byname_req.lv, + sizeof(user_lv_t)) != 0) + return -EFAULT; + for (l = 0; l < vg_ptr->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) != NULL && - strcmp(lv_ptr->u.lv_name, + strcmp(lv_ptr->lv_name, lv_status_byname_req.lv_name) == 0) { + /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_byname_req.lv->u.lv_current_pe, sizeof(void*)) != 0) - return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_byname_req.lv->u.lv_block_exception, sizeof(void*)) != 0) - return -EFAULT; + saved_ptr1=tmpulv.lv_current_pe; + saved_ptr2=tmpulv.lv_block_exception; + + kernlv_to_userlv(lv_ptr,&tmpulv); + + /* Restore usermode pointers */ + tmpulv.lv_current_pe=saved_ptr1; + tmpulv.lv_block_exception=saved_ptr2; + if (copy_to_user(lv_status_byname_req.lv, - lv_ptr, - sizeof(userlv_t)) != 0) + &tmpulv, + sizeof(user_lv_t)) != 0) return -EFAULT; if (saved_ptr1 != NULL) { + + +/* REVERSED IS: + + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + if (copy_from_user(&tmpupe, user_pep+(le*sizeof(user_pe_t)), sizeof(user_pe_t))) { + P_IOCTL("ERROR: copying PE(%d) ptr %p (%d bytes)\n", + le,user_pep+(le*sizeof(user_pe_t)), + sizeof(user_lv_t)); + printk(KERN_CRIT "err doin le %d\n",le); + + vfree(lv_ptr->lv_current_pe); + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EFAULT; + } + + lv_ptr->lv_current_pe[le].bdev = + bdget(tmpupe.dev); + lv_ptr->lv_current_pe[le].pe = + tmpupe.pe; + lv_ptr->lv_current_pe[le].reads = + tmpupe.reads; + lv_ptr->lv_current_pe[le].writes = + tmpupe.writes; + if(lv_ptr->lv_current_pe[le].bdev==NULL){ + printk(KERN_CRIT " bdget failed\n"); + return -EINVAL; + } + } + + + + + + // DO CORRECT COPYING! kern vs us pe_t if (copy_to_user(saved_ptr1, - lv_ptr->u.lv_current_pe, - lv_ptr->u.lv_allocated_le * - sizeof(pe_t)) != 0) - return -EFAULT; + lv_ptr->lv_current_pe, + lv_ptr->lv_allocated_le * + sizeof(kern_pe_t)) != 0) + return -EFAULT;*/ } - /* Restore usermode pointers */ - if (copy_to_user(&lv_status_byname_req.lv->u.lv_current_pe, &saved_ptr1, sizeof(void*)) != 0) - return -EFAULT; + return 0; } } @@ -2448,12 +2735,12 @@ /* * character device support function logical volume status by index */ -static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg) +static int lvm_do_lv_status_byindex(kern_vg_t *vg_ptr,void *arg) { lv_status_byindex_req_t lv_status_byindex_req; void *saved_ptr1; void *saved_ptr2; - lv_t *lv_ptr; + kern_lv_t *lv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&lv_status_byindex_req, arg, @@ -2469,23 +2756,23 @@ return -ENXIO; /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_byindex_req.lv->u.lv_current_pe, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr1, &lv_status_byindex_req.lv->lv_current_pe, sizeof(void*)) != 0) return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_byindex_req.lv->u.lv_block_exception, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr2, &lv_status_byindex_req.lv->lv_block_exception, sizeof(void*)) != 0) return -EFAULT; - if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(userlv_t)) != 0) + if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(user_lv_t)) != 0) return -EFAULT; if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, - lv_ptr->u.lv_current_pe, - lv_ptr->u.lv_allocated_le * - sizeof(pe_t)) != 0) + lv_ptr->lv_current_pe, + lv_ptr->lv_allocated_le * + sizeof(kern_pe_t)) != 0) //FIXME!! return -EFAULT; } /* Restore usermode pointers */ - if (copy_to_user(&lv_status_byindex_req.lv->u.lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) + if (copy_to_user(&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) return -EFAULT; return 0; @@ -2495,12 +2782,18 @@ /* * character device support function logical volume status by device number */ -static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void * arg) { + + +/* rewrite this to do proper coping */ +static int lvm_do_lv_status_bydev(kern_vg_t * vg_ptr, void * arg) { + + return -ENOSYS; +#ifdef BROKEN int l; lv_status_bydev_req_t lv_status_bydev_req; void *saved_ptr1; void *saved_ptr2; - lv_t *lv_ptr; + kern_lv_t *lv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&lv_status_bydev_req, arg, @@ -2509,7 +2802,7 @@ for ( l = 0; l < vg_ptr->lv_max; l++) { if ( vg_ptr->lv[l] == NULL) continue; - if ( kdev_same(vg_ptr->lv[l]->u.lv_dev, + if ( kdev_same(vg_ptr->lv[l]->lv_kdev, to_kdev_t(lv_status_bydev_req.dev))) break; } @@ -2518,44 +2811,50 @@ lv_ptr = vg_ptr->lv[l]; /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_bydev_req.lv->u.lv_current_pe, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr1, &lv_status_bydev_req.lv->lv_current_pe, sizeof(void*)) != 0) return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_bydev_req.lv->u.lv_block_exception, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr2, &lv_status_bydev_req.lv->lv_block_exception, sizeof(void*)) != 0) return -EFAULT; - if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) != 0) +/* FIXME! if (copy_kernlv_to_userlv(lv_ptr,lv_status_bydev_req.lv) != 0) + kernlv_to_userlv() + copy_to_user + + */ + if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(user_lv_t)) != 0) return -EFAULT; if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, - lv_ptr->u.lv_current_pe, - lv_ptr->u.lv_allocated_le * - sizeof(pe_t)) != 0) + lv_ptr->lv_current_pe, + lv_ptr->lv_allocated_le * + sizeof(kern_pe_t)) != 0) // BROKEN! return -EFAULT; } /* Restore usermode pointers */ - if (copy_to_user(&lv_status_bydev_req.lv->u.lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) + if (copy_to_user(&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) return -EFAULT; return 0; +#endif } /* lvm_do_lv_status_bydev() */ /* * character device support function rename a logical volume */ -static int lvm_do_lv_rename(vg_t *vg_ptr, lv_req_t *lv_req, userlv_t *ulv) +static int lvm_do_lv_rename(kern_vg_t *vg_ptr, lv_req_t *lv_req, user_lv_t *ulv) { int l = 0; int ret = 0; - lv_t *lv_ptr = NULL; + kern_lv_t *lv_ptr = NULL; for (l = 0; l < vg_ptr->lv_max; l++) { if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue; - if (kdev_same(lv_ptr->u.lv_dev, ulv->lv_dev)) + if (kdev_same(lv_ptr->lv_kdev, to_kdev_t(ulv->lv_dev))) { lvm_fs_remove_lv(vg_ptr, lv_ptr); - strncpy(lv_ptr->u.lv_name, + strncpy(lv_ptr->lv_name, lv_req->lv_name, NAME_LEN); lvm_fs_create_lv(vg_ptr, lv_ptr); @@ -2571,8 +2870,10 @@ /* * character device support function physical volume change */ -static int lvm_do_pv_change(vg_t *vg_ptr, void *arg) +static int lvm_do_pv_change(kern_vg_t *vg_ptr, void *arg) { + return -ENOSYS; +#ifdef BROKEN uint p; pv_t *pv_ptr; struct block_device *bd; @@ -2602,15 +2903,17 @@ } } return -ENXIO; +#endif } /* lvm_do_pv_change() */ /* * character device support function get physical volume status */ -static int lvm_do_pv_status(vg_t *vg_ptr, void *arg) +static int lvm_do_pv_status(kern_vg_t *vg_ptr, void *arg) { uint p; - pv_t *pv_ptr; + kern_pv_t *pv_ptr; + user_pv_t tmpupv; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&pv_status_req, arg, @@ -2622,9 +2925,10 @@ if (pv_ptr != NULL && strcmp(pv_ptr->pv_name, pv_status_req.pv_name) == 0) { + kernpv_to_userpv(pv_ptr,&tmpupv); if (copy_to_user(pv_status_req.pv, - pv_ptr, - sizeof(pv_t)) != 0) + &tmpupv, + sizeof(user_pv_t)) != 0) return -EFAULT; return 0; } @@ -2642,9 +2946,9 @@ if (copy_from_user(&pv_flush_req, arg, sizeof(pv_flush_req)) != 0) return -EFAULT; - - fsync_dev(pv_flush_req.pv_dev); - invalidate_buffers(pv_flush_req.pv_dev); + /* FIXME! find kern__pv and use that? */ + fsync_dev(to_kdev_t(pv_flush_req.pv_dev)); + invalidate_buffers(to_kdev_t(pv_flush_req.pv_dev)); return 0; } @@ -2667,7 +2971,7 @@ } blk_size[MAJOR_NR] = lvm_size; - blksize_size[MAJOR_NR] = lvm_blocksizes; +/* blksize_size[MAJOR_NR] = lvm_blocksizes;*/ return; } /* lvm_gen_init() */ @@ -2714,11 +3018,11 @@ /* * we must open the pv's before we use them */ -static int _open_pv(pv_t *pv) { +static int _open_pv(kern_pv_t *pv) { int err; struct block_device *bd; - if (!(bd = bdget(kdev_t_to_nr(pv->pv_dev)))) + if (!(bd = bdget(kdev_t_to_nr(pv->pv_kdev)))) return -ENOMEM; err = blkdev_get(bd, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE); @@ -2729,7 +3033,7 @@ return 0; } -static void _close_pv(pv_t *pv) { +static void _close_pv(kern_pv_t *pv) { if (pv) { struct block_device *bdev = pv->bd; pv->bd = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/md/md.c linux-2.5/drivers/md/md.c --- linux-2.5.20/drivers/md/md.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/md/md.c Sat Jun 1 00:34:35 2002 @@ -997,6 +997,11 @@ struct list_head *tmp; mdk_rdev_t *rdev; + if (!mddev->sb_dirty) { + printk("hm, md_update_sb() called without ->sb_dirty == 1, from %p.\n", __builtin_return_address(0)); + return 0; + } + mddev->sb_dirty = 0; repeat: mddev->sb->utime = CURRENT_TIME; if (!(++mddev->sb->events_lo)) @@ -1562,6 +1567,7 @@ if (!md_size[mdidx(mddev)]) md_size[mdidx(mddev)] = sb->size * data_disks; + rdev = list_entry(mddev->disks.next, mdk_rdev_t, same_set); readahead = (VM_MAX_READAHEAD * 1024) / PAGE_SIZE; if (!sb->level || (sb->level == 4) || (sb->level == 5)) { readahead = (mddev->sb->chunk_size>>PAGE_SHIFT) * 4 * data_disks; @@ -1718,6 +1724,7 @@ } mddev->sb->state &= ~(1 << MD_SB_CLEAN); + mddev->sb_dirty = 1; md_update_sb(mddev); /* @@ -1834,6 +1841,7 @@ printk(KERN_INFO "md: marking sb clean...\n"); mddev->sb->state |= 1 << MD_SB_CLEAN; } + mddev->sb_dirty = 1; md_update_sb(mddev); } if (ro) @@ -2457,7 +2465,6 @@ mddev->sb->working_disks++; mddev->sb_dirty = 1; - md_update_sb(mddev); /* @@ -3499,6 +3506,8 @@ continue; if (sb->active_disks == sb->raid_disks) continue; + if (mddev->sb_dirty) + md_update_sb(mddev); if (!sb->spare_disks) { printk(KERN_ERR "md%d: no spare disk to reconstruct array! " "-- continuing in degraded mode\n", mdidx(mddev)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/md/multipath.c linux-2.5/drivers/md/multipath.c --- linux-2.5.20/drivers/md/multipath.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/md/multipath.c Fri May 3 12:57:30 2002 @@ -703,11 +703,8 @@ spin_unlock_irqrestore(&retry_list_lock, flags); mddev = mp_bh->mddev; - if (mddev->sb_dirty) { - printk(KERN_INFO "dirty sb detected, updating.\n"); - mddev->sb_dirty = 0; + if (mddev->sb_dirty) md_update_sb(mddev); - } bio = mp_bh->bio; bdev = bio->bi_bdev; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/md/raid1.c linux-2.5/drivers/md/raid1.c --- linux-2.5.20/drivers/md/raid1.c Mon Jun 3 02:44:38 2002 +++ linux-2.5/drivers/md/raid1.c Wed May 1 17:26:08 2002 @@ -1084,11 +1084,8 @@ mddev = r1_bio->mddev; conf = mddev_to_conf(mddev); - if (mddev->sb_dirty) { - printk(KERN_INFO "raid1: dirty sb detected, updating.\n"); - mddev->sb_dirty = 0; + if (mddev->sb_dirty) md_update_sb(mddev); - } bio = r1_bio->master_bio; switch(r1_bio->cmd) { case SPECIAL: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/md/raid5.c linux-2.5/drivers/md/raid5.c --- linux-2.5.20/drivers/md/raid5.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/md/raid5.c Tue May 21 20:54:51 2002 @@ -1342,10 +1342,8 @@ handled = 0; - if (mddev->sb_dirty) { - mddev->sb_dirty = 0; + if (mddev->sb_dirty) md_update_sb(mddev); - } spin_lock_irq(&conf->device_lock); while (1) { struct list_head *first; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/media/video/Config.help linux-2.5/drivers/media/video/Config.help --- linux-2.5.20/drivers/media/video/Config.help Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/media/video/Config.help Fri Feb 15 15:55:23 2002 @@ -54,6 +54,16 @@ Say Y here to include support for the Iomega Buz video card. There is a Buz/Linux homepage at . +CONFIG_VIDEO_ZORAN_DC10 + Say Y to support the Pinnacle Systems Studio DC10 plus TV/Video + card. Linux page at + . Vendor + page at . + +CONFIG_VIDEO_ZORAN_LML33 + Say Y here to support the Linux Media Labs LML33 TV/Video card. + Resources page is at . + CONFIG_VIDEO_ZR36120 Support for ZR36120/ZR36125 based frame grabber/overlay boards. This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/media/video/planb.c linux-2.5/drivers/media/video/planb.c --- linux-2.5.20/drivers/media/video/planb.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/media/video/planb.c Wed Jan 16 00:23:26 2002 @@ -90,11 +90,10 @@ static int planb_open(struct video_device *, int); static void planb_close(struct video_device *); static int planb_ioctl(struct video_device *, unsigned int, void *); -static int planb_init_done(struct video_device *); static int planb_mmap(struct video_device *, const char *, unsigned long); static void planb_irq(int, void *, struct pt_regs *); static void release_planb(void); -int init_planbs(struct video_init *); +static int init_planbs(void); /* ------------------ PlanB Internal Functions ------------------ */ static int planb_prepare_open(struct planb *); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/media/video/stradis.c linux-2.5/drivers/media/video/stradis.c --- linux-2.5.20/drivers/media/video/stradis.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/media/video/stradis.c Sat Apr 13 17:42:55 2002 @@ -1946,7 +1946,9 @@ { struct saa7146 *saa = (struct saa7146 *) dev; - saa->video_dev.busy = 0; + /* FIXME: Don't do it this way, use the video_device->fops + * registration for a sane implementation of multiple opens */ + saa->video_dev.users--; saa->user++; if (saa->user > 1) return 0; /* device open already, don't reset */ @@ -1958,7 +1960,7 @@ { struct saa7146 *saa = (struct saa7146 *) dev; saa->user--; - saa->video_dev.busy = 0; + saa->video_dev.users++; if (saa->user > 0) /* still someone using device */ return; saawrite(0x007f0000, SAA7146_MC1); /* stop all overlay dma */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/media/video/vino.c linux-2.5/drivers/media/video/vino.c --- linux-2.5.20/drivers/media/video/vino.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/media/video/vino.c Sun Mar 3 17:54:35 2002 @@ -1,6 +1,4 @@ -/* $Id: vino.c,v 1.5 1999/10/09 00:01:14 ralf Exp $ - * drivers/char/vino.c - * +/* * (incomplete) Driver for the Vino Video input system found in SGI Indys. * * Copyright (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se) @@ -57,9 +55,7 @@ ".set\tat\n\t" ".set\tmips0" : - :"r" (virt_addr), - "r" (&ret) - :"$1"); + :"r" (virt_addr), "r" (&ret)); restore_flags(flags); return ret; @@ -83,9 +79,7 @@ ".set\tat\n\t" ".set\tmips0" : - :"r" (&value), - "r" (virt_addr) - :"$1"); + :"r" (&value), "r" (virt_addr)); restore_flags(flags); } @@ -93,45 +87,41 @@ unsigned long addr) { unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); - unsigned long flags; + unsigned long tmp, flags; - save_and_cli(flags); + __save_and_cli(flags); __asm__ __volatile__( - ".set\tmips3\n\t" + ".set\tmips3\t\t\t# vino_reg_and\n\t" ".set\tnoat\n\t" - "ld\t$1,(%0)\n\t" - "ld\t$2,(%1)\n\t" - "and\t$1,$1,$2\n\t" - "sd\t$1,(%0)\n\t" + "ld\t$1, (%1)\n\t" + "ld\t%0, (%2)\n\t" + "and\t$1, $1, %0\n\t" + "sd\t$1, (%1)\n\t" ".set\tat\n\t" ".set\tmips0" - : - :"r" (virt_addr), - "r" (&value) - :"$1","$2"); - restore_flags(flags); + : "=&r" (tmp) + : "r" (virt_addr), "r" (&value)); + __restore_flags(flags); } static __inline__ void vino_reg_or(unsigned long long value, unsigned long addr) { unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); - unsigned long flags; + unsigned long tmp, flags; save_and_cli(flags); __asm__ __volatile__( ".set\tmips3\n\t" ".set\tnoat\n\t" - "ld\t$1,(%0)\n\t" - "ld\t$2,(%1)\n\t" - "or\t$1,$1,$2\n\t" - "sd\t$1,(%0)\n\t" + "ld\t$1, (%1)\n\t" + "ld\t%0, (%2)\n\t" + "or\t$1, $1, %0\n\t" + "sd\t$1, (%1)\n\t" ".set\tat\n\t" ".set\tmips0" - : - :"r" (virt_addr), - "r" (&value) - :"$1","$2"); + : "=&r" (tmp) + : "r" (virt_addr), "r" (&value)); restore_flags(flags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/media/video/w9966.c linux-2.5/drivers/media/video/w9966.c --- linux-2.5.20/drivers/media/video/w9966.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/media/video/w9966.c Mon Apr 15 01:00:20 2002 @@ -1,9 +1,7 @@ /* Winbond w9966cf Webcam parport driver. - Version 0.32 - - Copyright (C) 2001 Jakob Kemi + Copyright (C) 2001 Jakob Kemi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,33 +19,16 @@ */ /* Supported devices: - *Lifeview FlyCam Supra (using the Philips saa7111a chip) - - Does any other model using the w9966 interface chip exist ? + * Lifeview FlyCam Supra (using the Philips saa7111a chip) Todo: - - *Add a working EPP mode, since DMA ECP read isn't implemented - in the parport drivers. (That's why it's so sloow) - - *Add support for other ccd-control chips than the saa7111 - please send me feedback on what kind of chips you have. - - *Add proper probing. I don't know what's wrong with the IEEE1284 - parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID) - and nibble read seems to be broken for some peripherals. - - *Add probing for onboard SRAM, port directions etc. (if possible) - - *Add support for the hardware compressed modes (maybe using v4l2) + * Add a working EPP mode + * Support other ccd-control chips than the saa7111 + (what combinations exists?) + * Add proper probing. IEEE1284 probing of w9966 chips haven't + worked since parport drivers changed in 2.4.x. + * Probe for onboard SRAM, port directions etc. (if possible) - *Fix better support for the capture window (no skewed images, v4l - interface to capt. window) - - *Probably some bugs that I don't know of - - Please support me by sending feedback! - Changes: Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE @@ -59,6 +40,8 @@ #include #include #include +#include +#include //#define DEBUG // Undef me for production @@ -99,43 +82,44 @@ #define W9966_I2C_W_CLOCK 0x01 struct w9966_dev { - unsigned char dev_state; - unsigned char i2c_state; - unsigned short ppmode; + u8 dev_state; + u8 i2c_state; + int ppmode; struct parport* pport; struct pardevice* pdev; struct video_device vdev; - unsigned short width; - unsigned short height; - unsigned char brightness; - signed char contrast; - signed char color; - signed char hue; + u16 width; + u16 height; + u8 brightness; + s8 contrast; + s8 color; + s8 hue; + u8* buffer; }; /* * Module specific properties */ -MODULE_AUTHOR("Jakob Kemi "); -MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)"); +MODULE_AUTHOR("Jakob Kemi "); +MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (FlyCam Supra and others)"); MODULE_LICENSE("GPL"); -#ifdef MODULE -static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""}; -#else -static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; -#endif -MODULE_PARM(pardev, "1-" __MODULE_STRING(W9966_MAXCAMS) "s"); -MODULE_PARM_DESC(pardev, "pardev: where to search for\n\ -\teach camera. 'aggressive' means brute-force search.\n\ -\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign -\tcam 1 to parport3 and search every parport for cam 2 etc..."); +static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "auto"}; +MODULE_PARM(pardev, "0-" __MODULE_STRING(W9966_MAXCAMS) "s"); +MODULE_PARM_DESC(pardev,"\n\ + Where to find cameras.\n\ + auto = probe all parports for camera\n\ + name = name of parport (eg parport0)\n\ + none = don't search for this camera\n\ +You can specify all cameras this way, for example: + pardev=parport2,auto,none,parport0 would search for cam1 on parport2, search\n\ + for cam2 on all parports, skip cam3 and search for cam4 on parport0"); static int parmode = 0; MODULE_PARM(parmode, "i"); -MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); +MODULE_PARM_DESC(parmode, "\n<0|1|2> transfer mode (0=auto, 1=ecp, 2=epp)"); static int video_nr = -1; MODULE_PARM(video_nr, "i"); @@ -293,17 +277,23 @@ case 0: if (port->modes & PARPORT_MODE_ECP) cam->ppmode = IEEE1284_MODE_ECP; - else if (port->modes & PARPORT_MODE_EPP) - cam->ppmode = IEEE1284_MODE_EPP; +/* else if (port->modes & PARPORT_MODE_EPP) + cam->ppmode = IEEE1284_MODE_EPP;*/ else - cam->ppmode = IEEE1284_MODE_ECP; + cam->ppmode = IEEE1284_MODE_ECPSWE; break; case 1: // hw- or sw-ecp - cam->ppmode = IEEE1284_MODE_ECP; + if (port->modes & PARPORT_MODE_ECP) + cam->ppmode = IEEE1284_MODE_ECP; + else + cam->ppmode = IEEE1284_MODE_ECPSWE; break; case 2: // hw- or sw-epp - cam->ppmode = IEEE1284_MODE_EPP; - break; + if (port->modes & PARPORT_MODE_EPP) + cam->ppmode = IEEE1284_MODE_EPP; + else + cam->ppmode = IEEE1284_MODE_EPPSWE; + break; } // Tell the parport driver that we exists @@ -333,6 +323,8 @@ w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); + cam->buffer = NULL; + // All ok printk( "w9966cf: Found and initialized a webcam on %s.\n", @@ -345,6 +337,12 @@ // Terminate everything gracefully static void w9966_term(struct w9966_dev* cam) { +// Delete allocated buffer if needed + if (cam->buffer != NULL) { + kfree(cam->buffer); + cam->buffer = NULL; + } + // Unregister from v4l if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { video_unregister_device(&cam->vdev); @@ -439,9 +437,9 @@ { unsigned int i; unsigned int enh_s, enh_e; - unsigned char scale_x, scale_y; - unsigned char regs[0x1c]; - unsigned char saa7111_regs[] = { + u8 scale_x, scale_y; + u8 regs[0x1c]; + u8 saa7111_regs[] = { 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00, 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -568,7 +566,7 @@ if (state) { timeout = jiffies + 100; while (!w9966_i2c_getscl(cam)) { - if (jiffies > timeout) + if (time_after(jiffies, timeout)) return -1; } } @@ -672,6 +670,7 @@ return data; } + // Write a register to the i2c device. // Expects claimed pdev. -1 on error static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data) @@ -700,7 +699,7 @@ */ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) + unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; @@ -719,6 +718,7 @@ minwidth: 2, minheight: 1, }; + struct video_capability *cap = arg; *cap = vcap; return 0; @@ -726,7 +726,7 @@ case VIDIOCGCHAN: { struct video_channel *vch = arg; - if(vch->channel != 0) // We only support one channel (#0) + if(vch->channel != 0) // We only support one channel (#0) return -EINVAL; memset(vch,0,sizeof(*vch)); strcpy(vch->name, "CCD-input"); @@ -890,13 +890,12 @@ while(dleft > 0) { unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; - unsigned char tbuf[W9966_RBUFFER]; - if (parport_read(cam->pport, tbuf, tsize) < tsize) { + if (parport_read(cam->pport, cam->buffer, tsize) < tsize) { w9966_pdev_release(cam); return -EFAULT; } - if (copy_to_user(dest, tbuf, tsize) != 0) { + if (copy_to_user(dest, cam->buffer, tsize) != 0) { w9966_pdev_release(cam); return -EFAULT; } @@ -918,14 +917,14 @@ for (i = 0; i < W9966_MAXCAMS; i++) { + if (strcmp(pardev[i], "none") == 0) // Skip if 'none' + continue; if (w9966_cams[i].dev_state != 0) // Cam is already assigned continue; - if ( - strcmp(pardev[i], "aggressive") == 0 || - strcmp(pardev[i], port->name) == 0 - ) { + if (strcmp(pardev[i], "auto") == 0 || + strcmp(pardev[i], port->name) == 0) { if (w9966_init(&w9966_cams[i], port) != 0) - w9966_term(&w9966_cams[i]); + w9966_term(&w9966_cams[i]); break; // return } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/media/video/zr36067.c linux-2.5/drivers/media/video/zr36067.c --- linux-2.5.20/drivers/media/video/zr36067.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/media/video/zr36067.c Sat Apr 13 17:42:55 2002 @@ -3264,7 +3264,10 @@ btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); - dev->busy = 0; /* Allow second open */ + /* FIXME: Don't do it this way, use the + * video_device->fops registration for a sane + * implementation of multiple opens */ + dev->users--; /* Allow second open */ } break; @@ -3322,6 +3325,7 @@ } } + dev->users++; zr->user--; MOD_DEC_USE_COUNT; @@ -4204,9 +4208,7 @@ /* sleep 1 second */ - timeout = jiffies + 1 * HZ; - while (jiffies < timeout) - schedule(); + schedule_timeout(HZ); /* Get status of video decoder */ @@ -4396,22 +4398,18 @@ } static struct video_device zoran_template = { - THIS_MODULE, - ZORAN_NAME, - VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | - VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, - ZORAN_HARDWARE, - zoran_open, - zoran_close, - zoran_read, - zoran_write, - NULL, - zoran_ioctl, - zoran_mmap, - zoran_init_done, - NULL, - 0, - 0 + owner: THIS_MODULE, + name: ZORAN_NAME, + type: VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | + VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, + hardware: ZORAN_HARDWARE, + open: zoran_open, + close: zoran_close, + read: zoran_read, + write: zoran_write, + ioctl: zoran_ioctl, + mmap: zoran_mmap, + initialize: zoran_init_done, }; /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/message/i2o/README linux-2.5/drivers/message/i2o/README --- linux-2.5.20/drivers/message/i2o/README Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/message/i2o/README Sun Mar 3 17:54:35 2002 @@ -39,6 +39,9 @@ Taneli Vähäkangas, University of Helsinki Finland Fixes to i2o_config +Boji T Kannanthanam + Intel i2o controller work, extending proc/config stuff + CREDITS This work was made possible by @@ -62,32 +65,38 @@ ASUSTeK Loan of I2O motherboard +Promise + Providing a Supertrak 100 board and support info + +DPT + Providing a DPT smartraid I2O card (use dpt_i2o for this + board however) + STATUS: +o Should be stable for x86 32bit -o The core setup works within limits. -o The scsi layer seems to almost work. - I'm still chasing down the hang bug. -o The block OSM is mostly functional -o LAN OSM works with FDDI and Ethernet cards. +KNOWN ISSUES: +o Reports that intel boards die if you load i2o_block and i2o_scsi +o Some promise cards need firmware updates TO DO: General: +o Finish 64bit and big endian cleanup +o Switch to new PCI mapping layer throughout +o Hotswap of controllers o Provide hidden address space if asked o Long term message flow control o PCI IOP's without interrupts are not supported yet o Push FAIL handling into the core o DDM control interfaces for module load etc -o Add I2O 2.0 support (Deffered to 2.5 kernel) Block: -o Multiple major numbers -o Read ahead and cache handling stuff. Talk to Ingo and people +o Multiple major numbers (problem goes away in 2.5) o Power management o Finish Media changers SCSI: -o Find the right way to associate drives/luns/busses Lan: o Performance tuning @@ -95,4 +104,3 @@ Tape: o Anyone seen anything implementing this ? - (D.S: Will attempt to do so if spare cycles permit) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/message/i2o/i2o_block.c linux-2.5/drivers/message/i2o/i2o_block.c --- linux-2.5.20/drivers/message/i2o/i2o_block.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/message/i2o/i2o_block.c Sat May 25 19:52:02 2002 @@ -284,6 +284,7 @@ if(req->cmd == READ) { + DEBUG("READ\n"); __raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); while(bio) { @@ -323,6 +324,7 @@ } else if(req->cmd == WRITE) { + DEBUG("WRITE\n"); __raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); while(bio) { @@ -418,6 +420,7 @@ * It is now ok to complete the request. */ end_that_request_last( req ); + DEBUG("IO COMPLETED\n"); } static int i2ob_flush(struct i2o_controller *c, struct i2ob_device *d, int unit) @@ -441,7 +444,7 @@ __raw_writel(i2ob_context|(unit<<8), msg+8); __raw_writel(0, msg+12); __raw_writel(60<<16, msg+16); - + DEBUG("FLUSH"); i2o_post_message(c,m); return 0; } @@ -464,6 +467,7 @@ */ if(m[0] & (1<<13)) { + DEBUG("FAIL"); /* * FAILed message from controller * We increment the error count and abort it @@ -503,7 +507,7 @@ { spin_lock_irqsave(&I2O_LOCK(c->unit), flags); dev->constipated=0; - DEBUG(("unconstipated\n")); + DEBUG("unconstipated\n"); if(i2ob_backlog_request(c, dev)==0) i2ob_request(dev->req_queue); spin_unlock_irqrestore(&I2O_LOCK(c->unit), flags); @@ -802,7 +806,7 @@ * and tell them to fix their firmware :) */ default: - printk(KERN_INFO "%s: Received event %d we didn't register for\n" + printk(KERN_INFO "%s: Received event 0x%X we didn't register for\n" KERN_INFO " Blame the I2O card manufacturer 8)\n", i2ob_dev[unit].i2odev->dev_name, evt); break; @@ -1400,19 +1404,16 @@ { int i; - i2ob_queues[unit] = (struct i2ob_iop_queue*) - kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC); + i2ob_queues[unit] = (struct i2ob_iop_queue*) kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC); if(!i2ob_queues[unit]) { - printk(KERN_WARNING - "Could not allocate request queue for I2O block device!\n"); + printk(KERN_WARNING "Could not allocate request queue for I2O block device!\n"); return -1; } for(i = 0; i< MAX_I2OB_DEPTH; i++) { - i2ob_queues[unit]->request_queue[i].next = - &i2ob_queues[unit]->request_queue[i+1]; + i2ob_queues[unit]->request_queue[i].next = &i2ob_queues[unit]->request_queue[i+1]; i2ob_queues[unit]->request_queue[i].num = i; } @@ -1456,34 +1457,34 @@ if(c==NULL) continue; - /* - * The device list connected to the I2O Controller is doubly linked - * Here we traverse the end of the list , and start claiming devices - * from that end. This assures that within an I2O controller atleast - * the newly created volumes get claimed after the older ones, thus - * mapping to same major/minor (and hence device file name) after - * every reboot. - * The exception being: - * 1. If there was a TID reuse. - * 2. There was more than one I2O controller. - */ - - if(!bios) - { - for (d=c->devices;d!=NULL;d=d->next) - if(d->next == NULL) - b = d; - } - else - b = c->devices; + /* + * The device list connected to the I2O Controller is doubly linked + * Here we traverse the end of the list , and start claiming devices + * from that end. This assures that within an I2O controller atleast + * the newly created volumes get claimed after the older ones, thus + * mapping to same major/minor (and hence device file name) after + * every reboot. + * The exception being: + * 1. If there was a TID reuse. + * 2. There was more than one I2O controller. + */ - while(b != NULL) - { - d=b; - if(bios) - b = b->next; + if(!bios) + { + for (d=c->devices;d!=NULL;d=d->next) + if(d->next == NULL) + b = d; + } else - b = b->prev; + b = c->devices; + + while(b != NULL) + { + d=b; + if(bios) + b = b->next; + else + b = b->prev; if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE) continue; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/message/i2o/i2o_config.c linux-2.5/drivers/message/i2o/i2o_config.c --- linux-2.5.20/drivers/message/i2o/i2o_config.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/message/i2o/i2o_config.c Sat May 25 19:52:02 2002 @@ -25,7 +25,10 @@ * 2 of the License, or (at your option) any later version. */ +#include // Nuke me with the ifdef. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include #include @@ -47,7 +50,7 @@ static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; struct wait_queue *i2o_wait_queue; -#define MODINC(x,y) (x = x++ % y) +#define MODINC(x,y) ((x) = ((x) + 1) % (y)) struct i2o_cfg_info { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/message/i2o/i2o_core.c linux-2.5/drivers/message/i2o/i2o_core.c --- linux-2.5.20/drivers/message/i2o/i2o_core.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/message/i2o/i2o_core.c Mon Feb 18 21:45:54 2002 @@ -22,9 +22,12 @@ * */ +#include + +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif -#include #include #include #include @@ -210,7 +213,7 @@ static DECLARE_MUTEX(evt_sem); static DECLARE_COMPLETION(evt_dead); -DECLARE_WAIT_QUEUE_HEAD(evt_wait); +static DECLARE_WAIT_QUEUE_HEAD(evt_wait); static struct notifier_block i2o_reboot_notifier = { @@ -1186,7 +1189,8 @@ { struct i2o_handler *i; /* Map the message from the page frame map to kernel virtual */ - m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame); + /* m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame); */ + m=(struct i2o_message *)bus_to_virt(mv); msg=(u32*)m; /* @@ -2560,6 +2564,7 @@ int i2o_post_wait_mem(struct i2o_controller *c, u32 *msg, int len, int timeout, void *mem1, void *mem2) { DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post); + DECLARE_WAITQUEUE(wait, current); int complete = 0; int status; unsigned long flags = 0; @@ -2600,12 +2605,19 @@ * complete will be zero. From the point post_this returns * the wait_data may have been deleted. */ + + add_wait_queue(&wq_i2o_post, &wait); + set_current_state(TASK_INTERRUPTIBLE); if ((status = i2o_post_this(c, msg, len))==0) { - sleep_on_timeout(&wq_i2o_post, HZ * timeout); + schedule_timeout(HZ * timeout); } else + { + remove_wait_queue(&wq_i2o_post, &wait); return -EIO; - + } + remove_wait_queue(&wq_i2o_post, &wait); + if(signal_pending(current)) status = -EINTR; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/message/i2o/i2o_lan.c linux-2.5/drivers/message/i2o/i2o_lan.c --- linux-2.5.20/drivers/message/i2o/i2o_lan.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/message/i2o/i2o_lan.c Sat May 25 19:52:02 2002 @@ -25,9 +25,12 @@ * TODO: tests for other LAN classes (Token Ring, Fibre Channel) */ +#include + +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif -#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/message/i2o/i2o_scsi.c linux-2.5/drivers/message/i2o/i2o_scsi.c --- linux-2.5.20/drivers/message/i2o/i2o_scsi.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/message/i2o/i2o_scsi.c Sat May 25 19:52:02 2002 @@ -31,7 +31,10 @@ * Fix the resource management problems. */ +#include // nuke me later. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include #include @@ -191,7 +194,7 @@ { /* Create a scsi error for this */ current_command = (Scsi_Cmnd *)m[3]; - lock = ¤t_command->host->host_lock; + lock = current_command->host->host_lock; printk("Aborted %ld\n", current_command->serial_number); spin_lock_irq(lock); @@ -286,22 +289,17 @@ * It worked maybe ? */ current_command->result = DID_OK << 16 | ds; - lock = ¤t_command->host->host_lock; + lock = current_command->host->host_lock; spin_lock(lock); current_command->scsi_done(current_command); spin_unlock(lock); return; } -struct i2o_handler i2o_scsi_handler= -{ - i2o_scsi_reply, - NULL, - NULL, - NULL, - "I2O SCSI OSM", - 0, - I2O_CLASS_SCSI_PERIPHERAL +struct i2o_handler i2o_scsi_handler = { + reply: i2o_scsi_reply, + name: "I2O SCSI OSM", + class: I2O_CLASS_SCSI_PERIPHERAL, }; static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/Config.in linux-2.5/drivers/mtd/Config.in --- linux-2.5.20/drivers/mtd/Config.in Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/mtd/Config.in Sat Apr 13 17:42:55 2002 @@ -1,5 +1,5 @@ -# $Id: Config.in,v 1.71 2001/10/03 11:38:38 dwmw2 Exp $ +# $Id: Config.in,v 1.73 2002/03/08 16:34:35 rkaiser Exp $ mainmenu_option next_comment comment 'Memory Technology Devices (MTD)' @@ -12,6 +12,7 @@ int ' Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0 fi dep_tristate ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD + dep_tristate ' MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD dep_tristate ' RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS if [ "$CONFIG_ARM" = "y" ]; then dep_tristate ' Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/Makefile linux-2.5/drivers/mtd/Makefile --- linux-2.5.20/drivers/mtd/Makefile Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/mtd/Makefile Fri May 31 02:42:42 2002 @@ -1,16 +1,14 @@ # # Makefile for the memory technology device drivers. # -# # $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $ mod-subdirs := chips maps devices nand -export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o - -obj-y += chips/ maps/ devices/ nand/ +export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o mtdconcat.o +obj-y += chips/ maps/ devices/ nand/ # *** BIG UGLY NOTE *** # # The shiny new inter_module_xxx has introduced yet another ugly link @@ -29,6 +27,7 @@ # Core functionality. obj-$(CONFIG_MTD) += mtdcore.o +obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/afs.c linux-2.5/drivers/mtd/afs.c --- linux-2.5.20/drivers/mtd/afs.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/mtd/afs.c Sat Apr 13 17:42:55 2002 @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: afs.c,v 1.6 2001/10/02 10:04:51 rmk Exp $ + $Id: afs.c,v 1.7 2001/11/01 20:04:54 rmk Exp $ ======================================================================*/ @@ -80,6 +80,12 @@ * Does it contain the magic number? */ if (fs.signature != 0xa0ffff9f) + ret = 1; + + /* + * Don't touch the SIB. + */ + if (fs.type == 2) ret = 1; *iis_start = fs.image_info_base & mask; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/chips/Makefile linux-2.5/drivers/mtd/chips/Makefile --- linux-2.5.20/drivers/mtd/chips/Makefile Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/mtd/chips/Makefile Fri May 31 02:42:58 2002 @@ -1,7 +1,7 @@ # # linux/drivers/chips/Makefile # -# $Id: Makefile,v 1.7 2001/10/05 06:53:51 dwmw2 Exp $ +# $Id: Makefile,v 1.8 2002/01/10 20:27:40 eric Exp $ export-objs := chipreg.o gen_probe.o @@ -18,7 +18,6 @@ obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o -obj-$(CONFIG_MTD_INTELPROBE) += intel_probe.o obj-$(CONFIG_MTD_JEDEC) += jedec.o obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o obj-$(CONFIG_MTD_RAM) += map_ram.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/chips/amd_flash.c linux-2.5/drivers/mtd/chips/amd_flash.c --- linux-2.5.20/drivers/mtd/chips/amd_flash.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/mtd/chips/amd_flash.c Sat Apr 13 17:42:55 2002 @@ -3,7 +3,7 @@ * * Author: Jonas Holmberg * - * $Id: amd_flash.c,v 1.15 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: amd_flash.c,v 1.17 2002/03/05 17:00:37 jonashg Exp $ * * Copyright (c) 2001 Axis Communications AB * @@ -52,6 +52,7 @@ /* Manufacturers */ #define MANUFACTURER_AMD 0x0001 +#define MANUFACTURER_ATMEL 0x001F #define MANUFACTURER_FUJITSU 0x0004 #define MANUFACTURER_ST 0x0020 #define MANUFACTURER_SST 0x00BF @@ -67,6 +68,9 @@ #define AM29BDS323D 0x22D1 #define AM29BDS643D 0x227E +/* Atmel */ +#define AT49xV16x 0x00C0 +#define AT49xV16xT 0x00C2 /* Fujitsu */ #define MBM29LV160TE 0x22C4 @@ -612,6 +616,26 @@ { offset: 0x000000, erasesize: 0x10000, numblocks: 96 }, { offset: 0x600000, erasesize: 0x10000, numblocks: 31 }, { offset: 0x7f0000, erasesize: 0x02000, numblocks: 8 }, + } + }, { + mfr_id: MANUFACTURER_ATMEL, + dev_id: AT49xV16x, + name: "Atmel AT49xV16x", + size: 0x00200000, + numeraseregions: 2, + regions: { + { offset: 0x000000, erasesize: 0x02000, numblocks: 8 }, + { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } + } + }, { + mfr_id: MANUFACTURER_ATMEL, + dev_id: AT49xV16xT, + name: "Atmel AT49xV16xT", + size: 0x00200000, + numeraseregions: 2, + regions: { + { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, + { offset: 0x1F0000, erasesize: 0x02000, numblocks: 8 } } } }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/chips/jedec.c linux-2.5/drivers/mtd/chips/jedec.c --- linux-2.5.20/drivers/mtd/chips/jedec.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/mtd/chips/jedec.c Sat Apr 13 17:42:55 2002 @@ -11,7 +11,7 @@ * not going to guess how to send commands to them, plus I expect they will * all speak CFI.. * - * $Id: jedec.c,v 1.12 2001/11/06 14:37:35 dwmw2 Exp $ + * $Id: jedec.c,v 1.13 2002/02/08 15:57:21 rkaiser Exp $ */ #include @@ -738,6 +738,7 @@ } //printk("done\n"); + instr->state = MTD_ERASE_DONE; if (instr->callback) instr->callback(instr); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/devices/doc1000.c linux-2.5/drivers/mtd/devices/doc1000.c --- linux-2.5.20/drivers/mtd/devices/doc1000.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/mtd/devices/doc1000.c Sat Apr 13 17:42:55 2002 @@ -1,6 +1,6 @@ /*====================================================================== - $Id: doc1000.c,v 1.15 2001/10/02 15:05:13 dwmw2 Exp $ + $Id: doc1000.c,v 1.16 2001/12/28 22:45:17 dwmw2 Exp $ ======================================================================*/ @@ -482,7 +482,7 @@ else priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING; } - else if (erase->time + erase_timeout < jiffies) + else if (time_after(jiffies, erase->time + erase_timeout)) { printk("Flash erase timed out. The world is broken.\n"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/devices/mtdram.c linux-2.5/drivers/mtd/devices/mtdram.c --- linux-2.5.20/drivers/mtd/devices/mtdram.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/mtd/devices/mtdram.c Sat Apr 13 17:42:55 2002 @@ -1,6 +1,6 @@ /* * mtdram - a test mtd device - * $Id: mtdram.c,v 1.25 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: mtdram.c,v 1.26 2001/12/01 10:24:18 dwmw2 Exp $ * Author: Alexander Larsson * * Copyright (c) 1999 Alexander Larsson @@ -123,7 +123,7 @@ // Allocate some memory mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL); if (!mtd_info) - return 0; + return -ENOMEM; memset(mtd_info, 0, sizeof(*mtd_info)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/ftl.c linux-2.5/drivers/mtd/ftl.c --- linux-2.5.20/drivers/mtd/ftl.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/mtd/ftl.c Sat May 25 19:52:02 2002 @@ -1,5 +1,5 @@ /* This version ported to the Linux-MTD system by dwmw2@infradead.org - * $Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: ftl.c,v 1.43 2002/02/13 15:31:37 dwmw2 Exp $ * * Fixes: Arnaldo Carvalho de Melo * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups @@ -856,11 +856,16 @@ if (ftl_gendisk.part[minor].nr_sects == 0) return -ENXIO; - if (!get_mtd_device(partition->mtd, -1)) - return /* -E'SBUGGEREDOFF */ -ENXIO; + BLK_INC_USE_COUNT; + if (!get_mtd_device(partition->mtd, -1)) { + BLK_DEC_USE_COUNT; + return -ENXIO; + } + if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) { put_mtd_device(partition->mtd); + BLK_DEC_USE_COUNT; return -EROFS; } @@ -881,9 +886,6 @@ DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor); - /* Flush all writes */ - invalidate_device(inode->i_rdev, 1); - /* Wait for any pending erase operations to complete */ if (part->mtd->sync) part->mtd->sync(part->mtd); @@ -896,6 +898,7 @@ atomic_dec(&part->open); put_mtd_device(part->mtd); + BLK_DEC_USE_COUNT; release_return(0); } /* ftl_close */ @@ -1339,7 +1342,7 @@ memset(myparts, 0, sizeof(myparts)); - DEBUG(0, "$Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $\n"); + DEBUG(0, "$Id: ftl.c,v 1.43 2002/02/13 15:31:37 dwmw2 Exp $\n"); if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) { printk(KERN_NOTICE "ftl_cs: unable to grab major " diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/Config.in linux-2.5/drivers/mtd/maps/Config.in --- linux-2.5.20/drivers/mtd/maps/Config.in Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/mtd/maps/Config.in Sat Apr 13 17:42:55 2002 @@ -1,12 +1,12 @@ # drivers/mtd/maps/Config.in -# $Id: Config.in,v 1.16 2001/09/19 18:28:37 dwmw2 Exp $ +# $Id: Config.in,v 1.28 2002/03/08 16:34:35 rkaiser Exp $ mainmenu_option next_comment comment 'Mapping drivers for chip access' -dep_tristate ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI +dep_tristate ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then hex ' Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000 hex ' Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000 @@ -23,20 +23,33 @@ dep_tristate ' CFI Flash device mapped on AMD NetSc520' CONFIG_MTD_NETSC520 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS dep_tristate ' CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS dep_tristate ' CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS + dep_tristate ' CFI Flash device mapped on DIL/Net PC' CONFIG_MTD_DILNETPC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_CONCAT + if [ "$CONFIG_MTD_DILNETPC" = "y" -o "$CONFIG_MTD_DILNETPC" = "m" ]; then + hex ' Size of boot partition' CONFIG_MTD_DILNETPC_BOOTSIZE 0x80000 + fi dep_tristate ' JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC dep_tristate ' JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC dep_tristate ' JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC - dep_tristate ' BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_I386 $CONFIG_MTD_JEDEC + dep_tristate ' BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE + dep_tristate ' ROM connected to AMD766 southbridge' CONFIG_MTD_AMD766ROM $CONFIG_MTD_GEN_PROBE + dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE fi if [ "$CONFIG_PPC" = "y" ]; then - dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI $CONFIG_TQM8xxL $CONFIG_PPC - dep_tristate ' CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI $CONFIG_PPC - dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI_INTELSTD $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI_AMDSTD + dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI $CONFIG_TQM8xxL + dep_tristate ' CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI + dep_tristate ' System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI + dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI dep_tristate ' CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI fi if [ "$CONFIG_MIPS" = "y" ]; then + dep_tristate ' Pb1000 boot flash device' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000 + dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500 + if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" ]; then + bool ' Pb1500 boot flash device' CONFIG_MTD_PB1500_BOOT + bool ' Pb1500 user flash device (2nd 32MB bank)' CONFIG_MTD_PB1500_USER + fi dep_tristate ' Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then hex ' Physical start address of flash mapping' CONFIG_MTD_CSTM_MIPS_IXX_START 0x8000000 @@ -46,8 +59,12 @@ dep_tristate ' Momenco Ocelot boot flash device' CONFIG_MTD_OCELOT $CONFIG_MOMENCO_OCELOT fi -if [ "$CONFIG_SH" = "y" ]; then - dep_tristate ' CFI Flash device mapped on Hitachi SolutionEngine' CONFIG_MTD_SOLUTIONENGINE $CONFIG_MTD_CFI $CONFIG_SH $CONFIG_MTD_REDBOOT_PARTS +if [ "$CONFIG_SUPERH" = "y" ]; then + dep_tristate ' CFI Flash device mapped on Hitachi SolutionEngine' \ + CONFIG_MTD_SOLUTIONENGINE $CONFIG_MTD_PARTITIONS $CONFIG_MTD_CFI + if [ "$CONFIG_MTD_SOLUTIONENGINE" != "n" ]; then + hex ' Default reserved Flash size' CONFIG_MTD_SUPERH_RESERVE 0x00010000 + fi fi if [ "$CONFIG_ARM" = "y" ]; then @@ -57,6 +74,14 @@ dep_tristate ' CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310 + dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT + dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12 fi +if [ "$CONFIG_ALPHA" = "y" ]; then + dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE +fi + +# This needs CFI or JEDEC, depending on the cards found. +dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/Makefile linux-2.5/drivers/mtd/maps/Makefile --- linux-2.5.20/drivers/mtd/maps/Makefile Mon Jun 3 02:44:37 2002 +++ linux-2.5/drivers/mtd/maps/Makefile Fri May 31 02:43:14 2002 @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $ +# $Id: Makefile,v 1.21 2002/02/22 09:34:44 gleixner Exp $ # Chip mappings obj-$(CONFIG_MTD_CDB89712) += cdb89712.o @@ -9,9 +9,15 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o obj-$(CONFIG_MTD_DC21285) += dc21285.o +obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o +obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o obj-$(CONFIG_MTD_IQ80310) += iq80310.o obj-$(CONFIG_MTD_L440GX) += l440gx.o +obj-$(CONFIG_MTD_AMD766ROM) += amd766rom.o +obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o +obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o +obj-$(CONFIG_MTD_MBX860) += mbx860.o obj-$(CONFIG_MTD_NORA) += nora.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o @@ -27,5 +33,9 @@ obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_OCELOT) += ocelot.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o +obj-$(CONFIG_MTD_PCI) += pci.o +obj-$(CONFIG_MTD_PB1000) += pb1xxx-flash.o +obj-$(CONFIG_MTD_PB1500) += pb1xxx-flash.o +obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/amd766rom.c linux-2.5/drivers/mtd/maps/amd766rom.c --- linux-2.5.20/drivers/mtd/maps/amd766rom.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/mtd/maps/amd766rom.c Sun Apr 14 23:00:19 2002 @@ -0,0 +1,245 @@ +/* + * amd766rom.c + * + * Normal mappings of chips in physical memory + * $Id: amd766rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct amd766rom_map_info { + struct map_info map; + struct mtd_info *mtd; + unsigned long window_addr; + u32 window_start, window_size; + struct pci_dev *pdev; +}; + +static __u8 amd766rom_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +static __u16 amd766rom_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +static __u32 amd766rom_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +static void amd766rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +static void amd766rom_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +static void amd766rom_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +static void amd766rom_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +static void amd766rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(map->map_priv_1 + to, from, len); +} + +static struct amd766rom_map_info amd766rom_map = { + map: { + name: "AMD766 rom", + size: 0, + buswidth: 1, + read8: amd766rom_read8, + read16: amd766rom_read16, + read32: amd766rom_read32, + copy_from: amd766rom_copy_from, + write8: amd766rom_write8, + write16: amd766rom_write16, + write32: amd766rom_write32, + copy_to: amd766rom_copy_to, + /* The standard rom socket is for single power supply chips + * that don't have an extra vpp. + */ + }, + mtd: 0, + window_addr: 0, +}; + +static int __devinit amd766rom_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct rom_window { + u32 start; + u32 size; + u8 segen_bits; + }; + static struct rom_window rom_window[] = { + { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), }, + { 0xffc00000, 4*1024*1024, (1<<7), }, + { 0xffff0000, 64*1024, 0 }, + { 0 , 0, 0 }, + }; + static const u32 rom_probe_sizes[] = { + 5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, + 256*1024, 128*1024, 64*1024, 0}; + static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 }; + u8 byte; + struct amd766rom_map_info *info = &amd766rom_map; + struct rom_window *window; + int i; + u32 rom_size; + + window = &rom_window[0]; + while(window->size) { + if (request_mem_region(window->start, window->size, "amd766rom")) { + break; + } + window++; + } + if (!window->size) { + printk(KERN_ERR "amd766rom: cannot reserve rom window"); + goto err_out_none; + } + + /* Enable the selected rom window */ + pci_read_config_byte(pdev, 0x43, &byte); + pci_write_config_byte(pdev, 0x43, byte | window->segen_bits); + + /* Enable writes through the rom window */ + pci_read_config_byte(pdev, 0x40, &byte); + pci_write_config_byte(pdev, 0x40, byte | 1); + + /* FIXME handle registers 0x80 - 0x8C the bios region locks */ + + printk(KERN_NOTICE "amd766rom window : %x at %x\n", + window->size, window->start); + /* For write accesses caches are useless */ + info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size); + + if (!info->window_addr) { + printk(KERN_ERR "Failed to ioremap\n"); + goto err_out_free_mmio_region; + } + info->mtd = 0; + for(i = 0; (rom_size = rom_probe_sizes[i]); i++) { + char **chip_type; + if (rom_size > window->size) { + continue; + } + info->map.map_priv_1 = + info->window_addr + window->size - rom_size; + info->map.size = rom_size; + chip_type = rom_probe_types; + for(; !info->mtd && *chip_type; chip_type++) { + info->mtd = do_map_probe(*chip_type, &amd766rom_map.map); + } + if (info->mtd) { + break; + } + } + if (!info->mtd) { + goto err_out_iounmap; + } + printk(KERN_NOTICE "amd766rom chip at offset: %x\n", + window->size - rom_size); + + info->mtd->module = THIS_MODULE; + add_mtd_device(info->mtd); + info->window_start = window->start; + info->window_size = window->size; + return 0; + +err_out_iounmap: + iounmap((void *)(info->window_addr)); +err_out_free_mmio_region: + release_mem_region(window->start, window->size); +err_out_none: + return -ENODEV; +} + + +static void __devexit amd766rom_remove_one (struct pci_dev *pdev) +{ + struct amd766rom_map_info *info = &amd766rom_map; + u8 byte; + + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = 0; + info->map.map_priv_1 = 0; + + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + + /* Disable writes through the rom window */ + pci_read_config_byte(pdev, 0x40, &byte); + pci_write_config_byte(pdev, 0x40, byte & ~1); + + release_mem_region(info->window_start, info->window_size); +} + +static struct pci_device_id amd766rom_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, + PCI_ANY_ID, PCI_ANY_ID, }, +}; + +MODULE_DEVICE_TABLE(pci, amd766rom_pci_tbl); + +#if 0 +static struct pci_driver amd766rom_driver = { + name: "amd766rom", + id_table: amd766rom_pci_tbl, + probe: amd766rom_init_one, + remove: amd766rom_remove_one, +}; +#endif + +int __init init_amd766rom(void) +{ + struct pci_dev *pdev; + pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0); + if (pdev) { + amd766rom_map.pdev = pdev; + return amd766rom_init_one(pdev, &amd766rom_pci_tbl[0]); + } + return -ENXIO; +#if 0 + return pci_module_init(&amd766rom_driver); +#endif +} + +static void __exit cleanup_amd766rom(void) +{ + amd766rom_remove_one(amd766rom_map.pdev); +} + +module_init(init_amd766rom); +module_exit(cleanup_amd766rom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biederman "); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD766 southbridge"); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/autcpu12-nvram.c linux-2.5/drivers/mtd/maps/autcpu12-nvram.c --- linux-2.5.20/drivers/mtd/maps/autcpu12-nvram.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/mtd/maps/autcpu12-nvram.c Sun Apr 14 23:00:19 2002 @@ -0,0 +1,179 @@ +/* + * NV-RAM memory access on autcpu12 + * (C) 2002 Thomas Gleixner (gleixner@autronix.de) + * + * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__u8 autcpu12_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +__u16 autcpu12_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +__u32 autcpu12_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + while(len) { + __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); + from++; + to++; + len--; + } +} + +static struct mtd_info *sram_mtd; + +struct map_info autcpu12_sram_map = { + name: "SRAM", + size: 32768, + buswidth: 8, + read8: autcpu12_read8, + read16: autcpu12_read16, + read32: autcpu12_read32, + copy_from: autcpu12_copy_from, + write8: autcpu12_write8, + write16: autcpu12_write16, + write32: autcpu12_write32, + copy_to: autcpu12_copy_to +}; + +static int __init init_autcpu12_sram (void) +{ + int err, save0, save1; + + autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K); + if (!autcpu12_sram_map.map_priv_1) { + printk("Failed to ioremap autcpu12 NV-RAM space\n"); + err = -EIO; + goto out; + } + + /* + * Check for 32K/128K + * read ofs 0 + * read ofs 0x10000 + * Write complement to ofs 0x100000 + * Read and check result on ofs 0x0 + * Restore contents + */ + save0 = autcpu12_read32(&autcpu12_sram_map,0); + save1 = autcpu12_read32(&autcpu12_sram_map,0x10000); + autcpu12_write32(&autcpu12_sram_map,~save0,0x10000); + /* if we find this pattern on 0x0, we have 32K size + * restore contents and exit + */ + if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) { + autcpu12_write32(&autcpu12_sram_map,save0,0x0); + goto map; + } + /* We have a 128K found, restore 0x10000 and set size + * to 128K + */ + autcpu12_write32(&autcpu12_sram_map,save1,0x10000); + autcpu12_sram_map.size = SZ_128K; + +map: + sram_mtd = do_map_probe("map_ram", &autcpu12_sram_map); + if (!sram_mtd) { + printk("NV-RAM probe failed\n"); + err = -ENXIO; + goto out_ioremap; + } + + sram_mtd->module = THIS_MODULE; + sram_mtd->erasesize = 16; + + if (add_mtd_device(sram_mtd)) { + printk("NV-RAM device addition failed\n"); + err = -ENOMEM; + goto out_probe; + } + + printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); + + return 0; + +out_probe: + map_destroy(sram_mtd); + sram_mtd = 0; + +out_ioremap: + iounmap((void *)autcpu12_sram_map.map_priv_1); +out: + return err; +} + +static void __exit cleanup_autcpu12_maps(void) +{ + if (sram_mtd) { + del_mtd_device(sram_mtd); + map_destroy(sram_mtd); + iounmap((void *)autcpu12_sram_map.map_priv_1); + } +} + +module_init(init_autcpu12_sram); +module_exit(cleanup_autcpu12_maps); + +MODULE_AUTHOR("Thomas Gleixner"); +MODULE_DESCRIPTION("autcpu12 NV-RAM map driver"); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/dc21285.c linux-2.5/drivers/mtd/maps/dc21285.c --- linux-2.5.20/drivers/mtd/maps/dc21285.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/mtd/maps/dc21285.c Sat Apr 13 17:42:55 2002 @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: dc21285.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: dc21285.c,v 1.7 2001/10/11 16:17:51 nico Exp $ */ #include @@ -44,15 +44,15 @@ void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr) { - *CSR_ROMWRITEREG = adr; + *CSR_ROMWRITEREG = adr & 3; adr &= ~3; *(__u8*)(map->map_priv_1 + adr) = d; } void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr) { - *CSR_ROMWRITEREG = adr; - adr &= ~1; + *CSR_ROMWRITEREG = adr & 3; + adr &= ~3; *(__u16*)(map->map_priv_1 + adr) = d; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/dilnetpc.c linux-2.5/drivers/mtd/maps/dilnetpc.c --- linux-2.5.20/drivers/mtd/maps/dilnetpc.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/mtd/maps/dilnetpc.c Sun Apr 14 23:00:19 2002 @@ -0,0 +1,540 @@ +/* dilnetpc.c -- MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP" + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: dilnetpc.c,v 1.8 2002/03/12 13:07:26 rkaiser Exp $ + * + * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems + * featuring the AMD Elan SC410 processor. There are two variants of this + * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash + * ROM (Intel 28F016S3) and 8 megs of DRAM, the ADNP version has 4 megs + * flash and 16 megs of RAM. + * For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm + * and http://www.ssv-embedded.de/ssv/pc104/p170.htm + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +** The DIL/NetPC keeps it's BIOS in two distinct flash blocks. +** Destroying any of these blocks transforms the DNPC into +** a paperweight (albeit not a very useful one, considering +** it only weighs a few grams). +** +** Therefore, the BIOS blocks must never be erased or written to +** except by people who know exactly what they are doing (e.g. +** to install a BIOS update). These partitions are marked read-only +** by default, but can be made read/write by undefining +** DNPC_BIOS_BLOCKS_WRITEPROTECTED: +*/ +#define DNPC_BIOS_BLOCKS_WRITEPROTECTED + +/* +** The ID string (in ROM) is checked to determine whether we +** are running on a DNP/1486 or ADNP/1486 +*/ +#define BIOSID_BASE 0x000fe100 + +#define ID_DNPC "DNP1486" +#define ID_ADNP "ADNP1486" + +/* +** Address where the flash should appear in CPU space +*/ +#define FLASH_BASE 0x2000000 + +/* +** Chip Setup and Control (CSC) indexed register space +*/ +#define CSC_INDEX 0x22 +#define CSC_DATA 0x23 + +#define CSC_MMSWAR 0x30 /* MMS window C-F attributes register */ +#define CSC_MMSWDSR 0x31 /* MMS window C-F device select register */ + +#define CSC_RBWR 0xa7 /* GPIO Read-Back/Write Register B */ + +#define CSC_CR 0xd0 /* internal I/O device disable/Echo */ + /* Z-bus/configuration register */ + +#define CSC_PCCMDCR 0xf1 /* PC card mode and DMA control register */ + + +/* +** PC Card indexed register space: +*/ + +#define PCC_INDEX 0x3e0 +#define PCC_DATA 0x3e1 + +#define PCC_AWER_B 0x46 /* Socket B Address Window enable register */ +#define PCC_MWSAR_1_Lo 0x58 /* memory window 1 start address low register */ +#define PCC_MWSAR_1_Hi 0x59 /* memory window 1 start address high register */ +#define PCC_MWEAR_1_Lo 0x5A /* memory window 1 stop address low register */ +#define PCC_MWEAR_1_Hi 0x5B /* memory window 1 stop address high register */ +#define PCC_MWAOR_1_Lo 0x5C /* memory window 1 address offset low register */ +#define PCC_MWAOR_1_Hi 0x5D /* memory window 1 address offset high register */ + + +/* +** Access to SC4x0's Chip Setup and Control (CSC) +** and PC Card (PCC) indexed registers: +*/ +static inline void setcsc(int reg, unsigned char data) +{ + outb(reg, CSC_INDEX); + outb(data, CSC_DATA); +} + +static inline unsigned char getcsc(int reg) +{ + outb(reg, CSC_INDEX); + return(inb(CSC_DATA)); +} + +static inline void setpcc(int reg, unsigned char data) +{ + outb(reg, PCC_INDEX); + outb(data, PCC_DATA); +} + +static inline unsigned char getpcc(int reg) +{ + outb(reg, PCC_INDEX); + return(inb(PCC_DATA)); +} + + +/* +************************************************************ +** Enable access to DIL/NetPC's flash by mapping it into +** the SC4x0's MMS Window C. +************************************************************ +*/ +static void dnpc_map_flash(unsigned long flash_base, unsigned long flash_size) +{ + unsigned long flash_end = flash_base + flash_size - 1; + + /* + ** enable setup of MMS windows C-F: + */ + /* - enable PC Card indexed register space */ + setcsc(CSC_CR, getcsc(CSC_CR) | 0x2); + /* - set PC Card controller to operate in standard mode */ + setcsc(CSC_PCCMDCR, getcsc(CSC_PCCMDCR) & ~1); + + /* + ** Program base address and end address of window + ** where the flash ROM should appear in CPU address space + */ + setpcc(PCC_MWSAR_1_Lo, (flash_base >> 12) & 0xff); + setpcc(PCC_MWSAR_1_Hi, (flash_base >> 20) & 0x3f); + setpcc(PCC_MWEAR_1_Lo, (flash_end >> 12) & 0xff); + setpcc(PCC_MWEAR_1_Hi, (flash_end >> 20) & 0x3f); + + /* program offset of first flash location to appear in this window (0) */ + setpcc(PCC_MWAOR_1_Lo, ((0 - flash_base) >> 12) & 0xff); + setpcc(PCC_MWAOR_1_Hi, ((0 - flash_base)>> 20) & 0x3f); + + /* set attributes for MMS window C: non-cacheable, write-enabled */ + setcsc(CSC_MMSWAR, getcsc(CSC_MMSWAR) & ~0x11); + + /* select physical device ROMCS0 (i.e. flash) for MMS Window C */ + setcsc(CSC_MMSWDSR, getcsc(CSC_MMSWDSR) & ~0x03); + + /* enable memory window 1 */ + setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) | 0x02); + + /* now disable PC Card indexed register space again */ + setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2); +} + + +/* +************************************************************ +** Disable access to DIL/NetPC's flash by mapping it into +** the SC4x0's MMS Window C. +************************************************************ +*/ +static void dnpc_unmap_flash(void) +{ + /* - enable PC Card indexed register space */ + setcsc(CSC_CR, getcsc(CSC_CR) | 0x2); + + /* disable memory window 1 */ + setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) & ~0x02); + + /* now disable PC Card indexed register space again */ + setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2); +} + + +static __u8 dnpc_read8(struct map_info *map, unsigned long ofs) +{ + return readb(map->map_priv_1 + ofs); +} + +static __u16 dnpc_read16(struct map_info *map, unsigned long ofs) +{ + return readw(map->map_priv_1 + ofs); +} + +static __u32 dnpc_read32(struct map_info *map, unsigned long ofs) +{ + return readl(map->map_priv_1 + ofs); +} + +static void dnpc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); +} + +static void dnpc_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + writeb(d, map->map_priv_1 + adr); +} + +static void dnpc_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + writew(d, map->map_priv_1 + adr); +} + +static void dnpc_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + writel(d, map->map_priv_1 + adr); +} + +static void dnpc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio((void *)(map->map_priv_1 + to), from, len); +} + +/* +************************************************************ +** Enable/Disable VPP to write to flash +************************************************************ +*/ + +static spinlock_t dnpc_spin = SPIN_LOCK_UNLOCKED; +static int vpp_counter = 0; +/* +** This is what has to be done for the DNP board .. +*/ +static void dnp_set_vpp(struct map_info *not_used, int on) +{ + spin_lock_irq(&dnpc_spin); + + if (on) + { + if(++vpp_counter == 1) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x4); + } + else + { + if(--vpp_counter == 0) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x4); + else if(vpp_counter < 0) + BUG(); + } + spin_unlock_irq(&dnpc_spin); +} + +/* +** .. and this the ADNP version: +*/ +static void adnp_set_vpp(struct map_info *not_used, int on) +{ + spin_lock_irq(&dnpc_spin); + + if (on) + { + if(++vpp_counter == 1) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x8); + } + else + { + if(--vpp_counter == 0) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x8); + else if(vpp_counter < 0) + BUG(); + } + spin_unlock_irq(&dnpc_spin); +} + + + +#define DNP_WINDOW_SIZE 0x00200000 /* DNP flash size is 2MiB */ +#define ADNP_WINDOW_SIZE 0x00400000 /* ADNP flash size is 4MiB */ +#define WINDOW_ADDR FLASH_BASE + +static struct map_info dnpc_map = { + name: "ADNP Flash Bank", + size: ADNP_WINDOW_SIZE, + buswidth: 1, + read8: dnpc_read8, + read16: dnpc_read16, + read32: dnpc_read32, + copy_from: dnpc_copy_from, + write8: dnpc_write8, + write16: dnpc_write16, + write32: dnpc_write32, + copy_to: dnpc_copy_to, + set_vpp: adnp_set_vpp, + map_priv_2: WINDOW_ADDR +}; + +/* +** The layout of the flash is somewhat "strange": +** +** 1. 960 KiB (15 blocks) : Space for ROM Bootloader and user data +** 2. 64 KiB (1 block) : System BIOS +** 3. 960 KiB (15 blocks) : User Data (DNP model) or +** 3. 3008 KiB (47 blocks) : User Data (ADNP model) +** 4. 64 KiB (1 block) : System BIOS Entry +*/ + +static struct mtd_partition partition_info[]= +{ + { + name: "ADNP boot", + offset: 0, + size: 0xf0000, + }, + { + name: "ADNP system BIOS", + offset: MTDPART_OFS_NXTBLK, + size: 0x10000, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + mask_flags: MTD_WRITEABLE, +#endif + }, + { + name: "ADNP file system", + offset: MTDPART_OFS_NXTBLK, + size: 0x2f0000, + }, + { + name: "ADNP system BIOS entry", + offset: MTDPART_OFS_NXTBLK, + size: MTDPART_SIZ_FULL, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + mask_flags: MTD_WRITEABLE, +#endif + }, +}; + +#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) + +static struct mtd_info *mymtd; +static struct mtd_info *lowlvl_parts[NUM_PARTITIONS]; +static struct mtd_info *merged_mtd; + +/* +** "Highlevel" partition info: +** +** Using the MTD concat layer, we can re-arrange partitions to our +** liking: we construct a virtual MTD device by concatenating the +** partitions, specifying the sequence such that the boot block +** is immediately followed by the filesystem block (i.e. the stupid +** system BIOS block is mapped to a different place). When re-partitioning +** this concatenated MTD device, we can set the boot block size to +** an arbitrary (though erase block aligned) value i.e. not one that +** is dictated by the flash's physical layout. We can thus set the +** boot block to be e.g. 64 KB (which is fully sufficient if we want +** to boot an etherboot image) or to -say- 1.5 MB if we want to boot +** a large kernel image. In all cases, the remainder of the flash +** is available as file system space. +*/ + +static struct mtd_partition higlvl_partition_info[]= +{ + { + name: "ADNP boot block", + offset: 0, + size: CONFIG_MTD_DILNETPC_BOOTSIZE, + }, + { + name: "ADNP file system space", + offset: MTDPART_OFS_NXTBLK, + size: ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, + }, + { + name: "ADNP system BIOS + BIOS Entry", + offset: MTDPART_OFS_NXTBLK, + size: MTDPART_SIZ_FULL, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + mask_flags: MTD_WRITEABLE, +#endif + }, +}; + +#define NUM_HIGHLVL_PARTITIONS (sizeof(higlvl_partition_info)/sizeof(partition_info[0])) + + +static int dnp_adnp_probe(void) +{ + char *biosid, rc = -1; + + biosid = (char*)ioremap(BIOSID_BASE, 16); + if(biosid) + { + if(!strcmp(biosid, ID_DNPC)) + rc = 1; /* this is a DNPC */ + else if(!strcmp(biosid, ID_ADNP)) + rc = 0; /* this is a ADNPC */ + } + iounmap((void *)biosid); + return(rc); +} + + +static int __init init_dnpc(void) +{ + int is_dnp; + + /* + ** determine hardware (DNP/ADNP/invalid) + */ + if((is_dnp = dnp_adnp_probe()) < 0) + return -ENXIO; + + /* + ** Things are set up for ADNP by default + ** -> modify all that needs to be different for DNP + */ + if(is_dnp) + { /* + ** Adjust window size, select correct set_vpp function. + ** The partitioning scheme is identical on both DNP + ** and ADNP except for the size of the third partition. + */ + int i; + dnpc_map.size = DNP_WINDOW_SIZE; + dnpc_map.set_vpp = dnp_set_vpp; + partition_info[2].size = 0xf0000; + + /* + ** increment all string pointers so the leading 'A' gets skipped, + ** thus turning all occurrences of "ADNP ..." into "DNP ..." + */ + ++dnpc_map.name; + for(i = 0; i < NUM_PARTITIONS; i++) + ++partition_info[i].name; + higlvl_partition_info[1].size = DNP_WINDOW_SIZE - + CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000; + for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++) + ++higlvl_partition_info[i].name; + } + + printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", + is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.map_priv_2); + + dnpc_map.map_priv_1 = (unsigned long)ioremap_nocache(dnpc_map.map_priv_2, dnpc_map.size); + + dnpc_map_flash(dnpc_map.map_priv_2, dnpc_map.size); + + if (!dnpc_map.map_priv_1) { + printk("Failed to ioremap_nocache\n"); + return -EIO; + } + + printk("FLASH virtual address: 0x%lx\n", dnpc_map.map_priv_1); + + mymtd = do_map_probe("jedec_probe", &dnpc_map); + + if (!mymtd) + mymtd = do_map_probe("cfi_probe", &dnpc_map); + + /* + ** If flash probes fail, try to make flashes accessible + ** at least as ROM. Ajust erasesize in this case since + ** the default one (128M) will break our partitioning + */ + if (!mymtd) + if((mymtd = do_map_probe("map_rom", &dnpc_map))) + mymtd->erasesize = 0x10000; + + if (!mymtd) { + iounmap((void *)dnpc_map.map_priv_1); + return -ENXIO; + } + + mymtd->module = THIS_MODULE; + + /* + ** Supply pointers to lowlvl_parts[] array to add_mtd_partitions() + ** -> add_mtd_partitions() will _not_ register MTD devices for + ** the partitions, but will instead store pointers to the MTD + ** objects it creates into our lowlvl_parts[] array. + ** NOTE: we arrange the pointers such that the sequence of the + ** partitions gets re-arranged: partition #2 follows + ** partition #0. + */ + partition_info[0].mtdp = &lowlvl_parts[0]; + partition_info[1].mtdp = &lowlvl_parts[2]; + partition_info[2].mtdp = &lowlvl_parts[1]; + partition_info[3].mtdp = &lowlvl_parts[3]; + + add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); + + /* + ** now create a virtual MTD device by concatenating the for partitions + ** (in the sequence given by the lowlvl_parts[] array. + */ + merged_mtd = mtd_concat_create(lowlvl_parts, NUM_PARTITIONS, "(A)DNP Flash Concatenated"); + if(merged_mtd) + { /* + ** now partition the new device the way we want it. This time, + ** we do not supply mtd pointers in higlvl_partition_info, so + ** add_mtd_partitions() will register the devices. + */ + add_mtd_partitions(merged_mtd, higlvl_partition_info, NUM_HIGHLVL_PARTITIONS); + } + + return 0; +} + +static void __exit cleanup_dnpc(void) +{ + if(merged_mtd) { + del_mtd_partitions(merged_mtd); + mtd_concat_destroy(merged_mtd); + } + + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + if (dnpc_map.map_priv_1) { + iounmap((void *)dnpc_map.map_priv_1); + dnpc_unmap_flash(); + dnpc_map.map_priv_1 = 0; + } +} + +module_init(init_dnpc); +module_exit(cleanup_dnpc); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH"); +MODULE_DESCRIPTION("MTD map driver for SSV DIL/NetPC DNP & ADNP"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/epxa10db-flash.c linux-2.5/drivers/mtd/maps/epxa10db-flash.c --- linux-2.5.20/drivers/mtd/maps/epxa10db-flash.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/mtd/maps/epxa10db-flash.c Sun Apr 14 23:00:19 2002 @@ -0,0 +1,219 @@ +/* + * Flash memory access on EPXA based devices + * + * (C) 2000 Nicolas Pitre + * Copyright (C) 2001 Altera Corporation + * Copyright (C) 2001 Red Hat, Inc. + * + * $Id: epxa10db-flash.c,v 1.2 2001/12/19 13:00:19 jskov Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int nr_parts = 0; +static struct mtd_partition *parts; + +static struct mtd_info *mymtd; + +extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); +static int epxa10db_default_partitions(struct mtd_info *master, struct mtd_partition **pparts); + +static __u8 epxa10db_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +static __u16 epxa10db_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +static __u32 epxa10db_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +static void epxa10db_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); +} + +static void epxa10db_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +static void epxa10db_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +static void epxa10db_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +static void epxa10db_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio((void *)(map->map_priv_1 + to), from, len); +} + + + +static struct map_info epxa10db_map = { + name: "EPXA10DB flash", + size: FLASH_SIZE, + buswidth: 2, + read8: epxa10db_read8, + read16: epxa10db_read16, + read32: epxa10db_read32, + copy_from: epxa10db_copy_from, + write8: epxa10db_write8, + write16: epxa10db_write16, + write32: epxa10db_write32, + copy_to: epxa10db_copy_to +}; + + +static int __init epxa10db_mtd_init(void) +{ + int i; + printk(KERN_NOTICE "Epxa10db flash device: %x at %x\n", FLASH_SIZE, FLASH_START); + epxa10db_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); + if (!epxa10db_map.map_priv_1) { + printk("Failed to ioremap Epxa10db flash\n"); + return -EIO; + } + + mymtd = do_map_probe("cfi_probe", &epxa10db_map); + if (!mymtd) { + iounmap((void *)epxa10db_map.map_priv_1); + return -ENXIO; + } + + mymtd->module = THIS_MODULE; + + /* Unlock the flash device. */ + for (i=0; inumeraseregions;i++){ + int j; + for(j=0;jeraseregions[i].numblocks;j++){ + mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,4); + } + } + +#ifdef CONFIG_MTD_REDBOOT_PARTS + nr_parts = parse_redboot_partitions(mymtd, &parts); + + if (nr_parts > 0) { + add_mtd_partitions(mymtd, parts, nr_parts); + return 0; + } +#endif +#ifdef CONFIG_MTD_AFS_PARTS + nr_parts = parse_afs_partitions(mymtd, &parts); + + if (nr_parts > 0) { + add_mtd_partitions(mymtd, parts, nr_parts); + return 0; + } +#endif + + /* No recognised partitioning schemes found - use defaults */ + nr_parts = epxa10db_default_partitions(mymtd, &parts); + if (nr_parts > 0) { + add_mtd_partitions(mymtd, parts, nr_parts); + return 0; + } + + /* If all else fails... */ + add_mtd_device(mymtd); + return 0; +} + +static void __exit epxa10db_mtd_cleanup(void) +{ + if (mymtd) { + if (nr_parts) + del_mtd_partitions(mymtd); + else + del_mtd_device(mymtd); + map_destroy(mymtd); + } + if (epxa10db_map.map_priv_1) { + iounmap((void *)epxa10db_map.map_priv_1); + epxa10db_map.map_priv_1 = 0; + } +} + + +/* + * This will do for now, once we decide which bootldr we're finally + * going to use then we'll remove this function and do it properly + * + * Partions are currently (as offsets from base of flash): + * 0x00000000 - 0x003FFFFF - bootloader (!) + * 0x00400000 - 0x00FFFFFF - Flashdisk + */ + +static int __init epxa10db_default_partitions(struct mtd_info *master, struct mtd_partition **pparts) +{ + struct mtd_partition *parts; + int ret, i; + int npartitions = 0; + char *names; + const char *name = "jffs"; + + printk("Using default partitions for epxa10db\n"); + npartitions=1; + parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL); + if (!parts) { + ret = -ENOMEM; + goto out; + } + i=0; + names = (char *)&parts[npartitions]; + parts[i].name = names; + names += strlen(name) + 1; + strcpy(parts[i].name, name); + + parts[i].size = FLASH_SIZE-0x00400000; + parts[i].offset = 0x00400000; + parts[i].mask_flags = 0; + + out: + *pparts = parts; + return npartitions; +} + +module_init(epxa10db_mtd_init); +module_exit(epxa10db_mtd_cleanup); + +MODULE_AUTHOR("Clive Davies"); +MODULE_DESCRIPTION("Altera epxa10db mtd flash map"); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/ich2rom.c linux-2.5/drivers/mtd/maps/ich2rom.c --- linux-2.5.20/drivers/mtd/maps/ich2rom.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/mtd/maps/ich2rom.c Sun Apr 14 23:00:19 2002 @@ -0,0 +1,302 @@ +/* + * ich2rom.c + * + * Normal mappings of chips in physical memory + * $Id: ich2rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RESERVE_MEM_REGION 0 + +#define ICH2_FWH_REGION_START 0xFF000000UL +#define ICH2_FWH_REGION_SIZE 0x01000000UL +#define BIOS_CNTL 0x4e +#define FWH_DEC_EN1 0xE3 +#define FWH_DEC_EN2 0xF0 +#define FWH_SEL1 0xE8 +#define FWH_SEL2 0xEE + +struct ich2rom_map_info { + struct map_info map; + struct mtd_info *mtd; + unsigned long window_addr; +}; + +static inline unsigned long addr(struct map_info *map, unsigned long ofs) +{ + unsigned long offset; + offset = ((8*1024*1024) - map->size) + ofs; + if (offset >= (4*1024*1024)) { + offset += 0x400000; + } + return map->map_priv_1 + 0x400000 + offset; +} + +static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr) +{ + return addr - map->map_priv_1 + ICH2_FWH_REGION_START; +} + +static __u8 ich2rom_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(addr(map, ofs)); +} + +static __u16 ich2rom_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(addr(map, ofs)); +} + +static __u32 ich2rom_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(addr(map, ofs)); +} + +static void ich2rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, addr(map, from), len); +} + +static void ich2rom_write8(struct map_info *map, __u8 d, unsigned long ofs) +{ + __raw_writeb(d, addr(map,ofs)); + mb(); +} + +static void ich2rom_write16(struct map_info *map, __u16 d, unsigned long ofs) +{ + __raw_writew(d, addr(map, ofs)); + mb(); +} + +static void ich2rom_write32(struct map_info *map, __u32 d, unsigned long ofs) +{ + __raw_writel(d, addr(map, ofs)); + mb(); +} + +static void ich2rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(addr(map, to), from, len); +} + +static struct ich2rom_map_info ich2rom_map = { + map: { + name: "ICH2 rom", + size: 0, + buswidth: 1, + read8: ich2rom_read8, + read16: ich2rom_read16, + read32: ich2rom_read32, + copy_from: ich2rom_copy_from, + write8: ich2rom_write8, + write16: ich2rom_write16, + write32: ich2rom_write32, + copy_to: ich2rom_copy_to, + /* Firmware hubs only use vpp when being programmed + * in a factory setting. So in place programming + * needs to use a different method. + */ + }, + mtd: 0, + window_addr: 0, +}; + +enum fwh_lock_state { + FWH_DENY_WRITE = 1, + FWH_IMMUTABLE = 2, + FWH_DENY_READ = 4, +}; + +static int ich2rom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len, + enum fwh_lock_state state) +{ + struct map_info *map = mtd->priv; + unsigned long start = ofs; + unsigned long end = start + len -1; + + /* FIXME do I need to guard against concurrency here? */ + /* round down to 64K boundaries */ + start = start & ~0xFFFF; + end = end & ~0xFFFF; + while (start <= end) { + unsigned long ctrl_addr; + ctrl_addr = addr(map, start) - 0x400000 + 2; + writeb(state, ctrl_addr); + start = start + 0x10000; + } + return 0; +} + +static int ich2rom_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return ich2rom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE); +} + +static int ich2rom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return ich2rom_set_lock_state(mtd, ofs, len, 0); +} + +static int __devinit ich2rom_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + u16 word; + struct ich2rom_map_info *info = &ich2rom_map; + unsigned long map_size; + + /* For now I just handle the ich2 and I assume there + * are not a lot of resources up at the top of the address + * space. It is possible to handle other devices in the + * top 16MB but it is very painful. Also since + * you can only really attach a FWH to an ICH2 there + * a number of simplifications you can make. + * + * Also you can page firmware hubs if an 8MB window isn't enough + * but don't currently handle that case either. + */ + +#if RESERVE_MEM_REGION + /* Some boards have this reserved and I haven't found a good work + * around to say I know what I'm doing! + */ + if (!request_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE, "ich2rom")) { + printk(KERN_ERR "ich2rom: cannot reserve rom window\n"); + goto err_out_none; + } +#endif /* RESERVE_MEM_REGION */ + + /* Enable writes through the rom window */ + pci_read_config_word(pdev, BIOS_CNTL, &word); + if (!(word & 1) && (word & (1<<1))) { + /* The BIOS will generate an error if I enable + * this device, so don't even try. + */ + printk(KERN_ERR "ich2rom: firmware access control, I can't enable writes\n"); + goto err_out_none; + } + pci_write_config_word(pdev, BIOS_CNTL, word | 1); + + + /* Map the firmware hub into my address space. */ + /* Does this use to much virtual address space? */ + info->window_addr = (unsigned long)ioremap( + ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); + if (!info->window_addr) { + printk(KERN_ERR "Failed to ioremap\n"); + goto err_out_free_mmio_region; + } + + /* For now assume the firmware has setup all relavent firmware + * windows. We don't have enough information to handle this case + * intelligently. + */ + + /* FIXME select the firmware hub and enable a window to it. */ + + info->mtd = 0; + info->map.map_priv_1 = info->window_addr; + + map_size = ICH2_FWH_REGION_SIZE; + while(!info->mtd && (map_size > 0)) { + info->map.size = map_size; + info->mtd = do_map_probe("jedec_probe", &ich2rom_map.map); + map_size -= 512*1024; + } + if (!info->mtd) { + goto err_out_iounmap; + } + /* I know I can only be a firmware hub here so put + * in the special lock and unlock routines. + */ + info->mtd->lock = ich2rom_lock; + info->mtd->unlock = ich2rom_unlock; + + info->mtd->module = THIS_MODULE; + add_mtd_device(info->mtd); + return 0; + +err_out_iounmap: + iounmap((void *)(info->window_addr)); +err_out_free_mmio_region: +#if RESERVE_MEM_REGION + release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); +#endif +err_out_none: + return -ENODEV; +} + + +static void __devexit ich2rom_remove_one (struct pci_dev *pdev) +{ + struct ich2rom_map_info *info = &ich2rom_map; + u16 word; + + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = 0; + info->map.map_priv_1 = 0; + + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + + /* Disable writes through the rom window */ + pci_read_config_word(pdev, BIOS_CNTL, &word); + pci_write_config_word(pdev, BIOS_CNTL, word & ~1); + +#if RESERVE_MEM_REGION + release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); +#endif +} + +static struct pci_device_id ich2rom_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, + PCI_ANY_ID, PCI_ANY_ID, }, +}; + +MODULE_DEVICE_TABLE(pci, ich2rom_pci_tbl); + +#if 0 +static struct pci_driver ich2rom_driver = { + name: "ich2rom", + id_table: ich2rom_pci_tbl, + probe: ich2rom_init_one, + remove: ich2rom_remove_one, +}; +#endif + +static struct pci_dev *mydev; +int __init init_ich2rom(void) +{ + struct pci_dev *pdev; + pdev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 0); + if (pdev) { + mydev = pdev; + return ich2rom_init_one(pdev, &ich2rom_pci_tbl[0]); + } + return -ENXIO; +#if 0 + return pci_module_init(&ich2rom_driver); +#endif +} + +static void __exit cleanup_ich2rom(void) +{ + ich2rom_remove_one(mydev); +} + +module_init(init_ich2rom); +module_exit(cleanup_ich2rom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biederman "); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICH2 southbridge"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/integrator-flash.c linux-2.5/drivers/mtd/maps/integrator-flash.c --- linux-2.5.20/drivers/mtd/maps/integrator-flash.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/mtd/maps/integrator-flash.c Sat Apr 13 17:42:56 2002 @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: integrator-flash.c,v 1.6 2001/10/02 16:00:01 dwmw2 Exp $ + $Id: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $ ======================================================================*/ @@ -208,10 +208,10 @@ }; static struct mtd_info *mtd; +static struct mtd_partition *parts; static int __init armflash_cfi_init(void *base, u_int size) { - struct mtd_partition *parts; int ret; armflash_flash_init(); @@ -238,8 +238,6 @@ ret = parse_afs_partitions(mtd, &parts); if (ret > 0) { ret = add_mtd_partitions(mtd, parts, ret); - /* we don't need the partition info any longer */ - kfree(parts); if (ret) printk(KERN_ERR "mtd partition registration " "failed: %d\n", ret); @@ -262,6 +260,8 @@ del_mtd_partitions(mtd); map_destroy(mtd); } + if (parts) + kfree(parts); } static int __init armflash_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/iq80310.c linux-2.5/drivers/mtd/maps/iq80310.c --- linux-2.5.20/drivers/mtd/maps/iq80310.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/mtd/maps/iq80310.c Sat Apr 13 17:42:56 2002 @@ -1,5 +1,5 @@ /* - * $Id: iq80310.c,v 1.8 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $ * * Mapping for the Intel XScale IQ80310 evaluation board * @@ -116,7 +116,7 @@ int parsed_nr_parts = 0; char *part_type = "static"; - iq80310_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0); + iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!iq80310_map.map_priv_1) { printk("Failed to ioremap\n"); return -EIO; @@ -161,7 +161,6 @@ } if (iq80310_map.map_priv_1) iounmap((void *)iq80310_map.map_priv_1); - return 0; } module_init(init_iq80310); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/l440gx.c linux-2.5/drivers/mtd/maps/l440gx.c --- linux-2.5.20/drivers/mtd/maps/l440gx.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/mtd/maps/l440gx.c Sat Apr 13 17:42:56 2002 @@ -1,7 +1,9 @@ /* - * $Id: l440gx.c,v 1.7 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: l440gx.c,v 1.8 2002/01/10 20:27:40 eric Exp $ * * BIOS Flash chip on Intel 440GX board. + * + * Bugs this currently does not work under linuxBIOS. */ #include @@ -12,12 +14,14 @@ #include #include +#define PIIXE_IOBASE_RESOURCE 11 #define WINDOW_ADDR 0xfff00000 #define WINDOW_SIZE 0x00100000 #define BUSWIDTH 1 -#define IOBASE 0xc00 +static u32 iobase; +#define IOBASE iobase #define TRIBUF_PORT (IOBASE+0x37) #define VPP_PORT (IOBASE+0x28) @@ -66,12 +70,17 @@ memcpy_toio(map->map_priv_1 + to, from, len); } +/* Is this really the vpp port? */ void l440gx_set_vpp(struct map_info *map, int vpp) { unsigned long l; l = inl(VPP_PORT); - l = vpp?(l | 1):(l & ~1); + if (vpp) { + l |= 1; + } else { + l &= ~1; + } outl(l, VPP_PORT); } @@ -87,44 +96,86 @@ write16: l440gx_write16, write32: l440gx_write32, copy_to: l440gx_copy_to, +#if 0 + /* FIXME verify that this is the + * appripriate code for vpp enable/disable + */ set_vpp: l440gx_set_vpp +#endif }; static int __init init_l440gx(void) { - struct pci_dev *dev; - unsigned char b; - __u16 w; + struct pci_dev *dev, *pm_dev; + struct resource *pm_iobase; + __u16 word; + + dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_0, NULL); - dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, - NULL); - if (!dev) { + pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + + if (!dev || !pm_dev) { printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue\n"); return -ENODEV; } - l440gx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + l440gx_map.map_priv_1 = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); if (!l440gx_map.map_priv_1) { - printk("Failed to ioremap L440GX flash region\n"); + printk(KERN_WARNING "Failed to ioremap L440GX flash region\n"); return -ENOMEM; } + printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.map_priv_1); + + /* Setup the pm iobase resource + * This code should move into some kind of generic bridge + * driver but for the moment I'm content with getting the + * allocation correct. + */ + pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE]; + if (!(pm_iobase->flags & IORESOURCE_IO)) { + pm_iobase->name = "pm iobase"; + pm_iobase->start = 0; + pm_iobase->end = 63; + pm_iobase->flags = IORESOURCE_IO; + + /* Put the current value in the resource */ + pci_read_config_dword(pm_dev, 0x40, &iobase); + iobase &= ~1; + pm_iobase->start += iobase & ~1; + pm_iobase->end += iobase & ~1; + + /* Allocate the resource region */ + if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) { + printk(KERN_WARNING "Could not allocate pm iobase resource\n"); + iounmap((void *)l440gx_map.map_priv_1); + return -ENXIO; + } + } + /* Set the iobase */ + iobase = pm_iobase->start; + pci_write_config_dword(pm_dev, 0x40, iobase | 1); + + /* Set XBCS# */ - pci_read_config_word(dev, 0x4e, &w); - w |= 0x4; - pci_write_config_word(dev, 0x4e, w); + pci_read_config_word(dev, 0x4e, &word); + word |= 0x4; + pci_write_config_word(dev, 0x4e, word); + + /* Supply write voltage to the chip */ + l440gx_set_vpp(&l440gx_map, 1); /* Enable the gate on the WE line */ - b = inb(TRIBUF_PORT); - b |= 1; - outb(b, TRIBUF_PORT); + outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT); printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n"); - mymtd = do_map_probe("jedec", &l440gx_map); + mymtd = do_map_probe("jedec_probe", &l440gx_map); if (!mymtd) { printk(KERN_NOTICE "JEDEC probe on BIOS chip failed. Using ROM\n"); mymtd = do_map_probe("map_rom", &l440gx_map); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/mbx860.c linux-2.5/drivers/mtd/maps/mbx860.c --- linux-2.5.20/drivers/mtd/maps/mbx860.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/mtd/maps/mbx860.c Sun Apr 14 23:00:19 2002 @@ -0,0 +1,144 @@ +/* + * $Id: mbx860.c,v 1.1 2001/11/18 19:43:09 dwmw2 Exp $ + * + * Handle mapping of the flash on MBX860 boards + * + * Author: Anton Todorov + * Copyright: (C) 2001 Emness Technology + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +#define WINDOW_ADDR 0xfe000000 +#define WINDOW_SIZE 0x00200000 + +/* Flash / Partition sizing */ +#define MAX_SIZE_KiB 8192 +#define BOOT_PARTITION_SIZE_KiB 512 +#define KERNEL_PARTITION_SIZE_KiB 5632 +#define APP_PARTITION_SIZE_KiB 2048 + +#define NUM_PARTITIONS 3 + +/* partition_info gives details on the logical partitions that the split the + * single flash device into. If the size if zero we use up to the end of the + * device. */ +static struct mtd_partition partition_info[]={ + { name: "MBX flash BOOT partition", + offset: 0, + size: BOOT_PARTITION_SIZE_KiB*1024 }, + { name: "MBX flash DATA partition", + offset: BOOT_PARTITION_SIZE_KiB*1024, + size: (KERNEL_PARTITION_SIZE_KiB)*1024 }, + { name: "MBX flash APPLICATION partition", + offset: (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } +}; + + +static struct mtd_info *mymtd; + +__u8 mbx_read8(struct map_info *map, unsigned long ofs) +{ + return readb(map->map_priv_1 + ofs); +} + +__u16 mbx_read16(struct map_info *map, unsigned long ofs) +{ + return readw(map->map_priv_1 + ofs); +} + +__u32 mbx_read32(struct map_info *map, unsigned long ofs) +{ + return readl(map->map_priv_1 + ofs); +} + +void mbx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); +} + +void mbx_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + writeb(d, map->map_priv_1 + adr); +} + +void mbx_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + writew(d, map->map_priv_1 + adr); +} + +void mbx_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + writel(d, map->map_priv_1 + adr); +} + +void mbx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio((void *)(map->map_priv_1 + to), from, len); +} + +struct map_info mbx_map = { + name: "MBX flash", + size: WINDOW_SIZE, + buswidth: 4, + read8: mbx_read8, + read16: mbx_read16, + read32: mbx_read32, + copy_from: mbx_copy_from, + write8: mbx_write8, + write16: mbx_write16, + write32: mbx_write32, + copy_to: mbx_copy_to +}; + +int __init init_mbx(void) +{ + printk(KERN_NOTICE "Motorola MBX flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); + mbx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + + if (!mbx_map.map_priv_1) { + printk("Failed to ioremap\n"); + return -EIO; + } + mymtd = do_map_probe("jedec_probe", &mbx_map); + if (mymtd) { + mymtd->module = THIS_MODULE; + add_mtd_device(mymtd); + add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); + return 0; + } + + iounmap((void *)mbx_map.map_priv_1); + return -ENXIO; +} + +static void __exit cleanup_mbx(void) +{ + if (mymtd) { + del_mtd_device(mymtd); + map_destroy(mymtd); + } + if (mbx_map.map_priv_1) { + iounmap((void *)mbx_map.map_priv_1); + mbx_map.map_priv_1 = 0; + } +} + +module_init(init_mbx); +module_exit(cleanup_mbx); + +MODULE_AUTHOR("Anton Todorov "); +MODULE_DESCRIPTION("MTD map driver for Motorola MBX860 board"); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/pb1xxx-flash.c linux-2.5/drivers/mtd/maps/pb1xxx-flash.c --- linux-2.5.20/drivers/mtd/maps/pb1xxx-flash.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/mtd/maps/pb1xxx-flash.c Sat Apr 13 17:42:56 2002 @@ -0,0 +1,253 @@ +/* + * Flash memory access on Alchemy Pb1xxx boards + * + * (C) 2001 Pete Popov + * + * $Id: pb1xxx-flash.c,v 1.2 2002/02/14 19:36:45 ppopov Exp $ + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef DEBUG_RW +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef CONFIG_MIPS_PB1000 +#define WINDOW_ADDR 0x1F800000 +#define WINDOW_SIZE 0x800000 +#endif + +__u8 physmap_read8(struct map_info *map, unsigned long ofs) +{ + __u8 ret; + ret = __raw_readb(map->map_priv_1 + ofs); + DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +__u16 physmap_read16(struct map_info *map, unsigned long ofs) +{ + __u16 ret; + ret = __raw_readw(map->map_priv_1 + ofs); + DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +__u32 physmap_read32(struct map_info *map, unsigned long ofs) +{ + __u32 ret; + ret = __raw_readl(map->map_priv_1 + ofs); + DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to); + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +void physmap_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from); + memcpy_toio(map->map_priv_1 + to, from, len); +} + + + +static struct map_info pb1xxx_map = { + name: "Pb1xxx flash", + read8: physmap_read8, + read16: physmap_read16, + read32: physmap_read32, + copy_from: physmap_copy_from, + write8: physmap_write8, + write16: physmap_write16, + write32: physmap_write32, + copy_to: physmap_copy_to, +}; + + +#ifdef CONFIG_MIPS_PB1000 + +static unsigned long flash_size = 0x00800000; +static unsigned char flash_buswidth = 4; +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "yamon env", + size: 0x00020000, + offset: 0, + mask_flags: MTD_WRITEABLE + },{ + name: "User FS", + size: 0x003e0000, + offset: 0x20000, + },{ + name: "boot code", + size: 0x100000, + offset: 0x400000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw/kernel", + size: 0x300000, + offset: 0x500000 + } +}; + +#elif defined(CONFIG_MIPS_PB1500) + +static unsigned char flash_buswidth = 4; +#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) +/* both 32MB banks will be used. Combine the first 32MB bank and the + * first 28MB of the second bank together into a single jffs/jffs2 + * partition. + */ +static unsigned long flash_size = 0x04000000; +#define WINDOW_ADDR 0x1C000000 +#define WINDOW_SIZE 0x4000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x3c00000, + offset: 0x0000000 + },{ + name: "yamon", + size: 0x0100000, + offset: 0x3c00000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw kernel", + size: 0x02c0000, + offset: 0x3d00000 + } +}; +#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER) +static unsigned long flash_size = 0x02000000; +#define WINDOW_ADDR 0x1E000000 +#define WINDOW_SIZE 0x2000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x1c00000, + offset: 0x0000000 + },{ + name: "yamon", + size: 0x0100000, + offset: 0x1c00000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw kernel", + size: 0x02c0000, + offset: 0x1d00000 + } +}; +#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) +static unsigned long flash_size = 0x02000000; +#define WINDOW_ADDR 0x1C000000 +#define WINDOW_SIZE 0x2000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x1e00000, + offset: 0x0000000 + },{ + name: "raw kernel", + size: 0x0200000, + offset: 0x1e00000, + } +}; +#else +#error MTD_PB1500 define combo error /* should never happen */ +#endif +#else +#error Unsupported board +#endif + + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_partition *parsed_parts; +static struct mtd_info *mymtd; + +int __init pb1xxx_mtd_init(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + char *part_type; + + /* Default flash buswidth */ + pb1xxx_map.buswidth = flash_buswidth; + + /* + * Static partition definition selection + */ + part_type = "static"; + parts = pb1xxx_partitions; + nb_parts = NB_OF(pb1xxx_partitions); + pb1xxx_map.size = flash_size; + + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", + pb1xxx_map.buswidth*8); + pb1xxx_map.map_priv_1 = + (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + mymtd = do_map_probe("cfi_probe", &pb1xxx_map); + if (!mymtd) return -ENXIO; + mymtd->module = THIS_MODULE; + + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit pb1xxx_mtd_cleanup(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + if (parsed_parts) + kfree(parsed_parts); + } +} + +module_init(pb1xxx_mtd_init); +module_exit(pb1xxx_mtd_cleanup); + +MODULE_AUTHOR("Pete Popov"); +MODULE_DESCRIPTION("Pb1xxx CFI map driver"); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/pci.c linux-2.5/drivers/mtd/maps/pci.c --- linux-2.5.20/drivers/mtd/maps/pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/mtd/maps/pci.c Sun Apr 14 23:00:19 2002 @@ -0,0 +1,385 @@ +/* + * linux/drivers/mtd/maps/pci.c + * + * Copyright (C) 2001 Russell King, All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk Exp $ + * + * Generic PCI memory map driver. We support the following boards: + * - Intel IQ80310 ATU. + * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 + */ +#include +#include +#include +#include + +#include +#include +#include + +struct map_pci_info; + +struct mtd_pci_info { + int (*init)(struct pci_dev *dev, struct map_pci_info *map); + void (*exit)(struct pci_dev *dev, struct map_pci_info *map); + unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); + const char *map_name; +}; + +struct map_pci_info { + struct map_info map; + void *base; + void (*exit)(struct pci_dev *dev, struct map_pci_info *map); + unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); + struct pci_dev *dev; +}; + +/* + * Intel IOP80310 Flash driver + */ + +static int +intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map) +{ + u32 win_base; + + map->map.buswidth = 1; + map->map.size = 0x00800000; + map->base = ioremap_nocache(pci_resource_start(dev, 0), + pci_resource_len(dev, 0)); + + if (!map->base) + return -ENOMEM; + + /* + * We want to base the memory window at Xscale + * bus address 0, not 0x1000. + */ + pci_read_config_dword(dev, 0x44, &win_base); + pci_write_config_dword(dev, 0x44, 0); + + map->map.map_priv_2 = win_base; + + return 0; +} + +static void +intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map) +{ + if (map->base) + iounmap((void *)map->base); + pci_write_config_dword(dev, 0x44, map->map.map_priv_2); +} + +static unsigned long +intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs) +{ + unsigned long page_addr = ofs & 0x00400000; + + /* + * This mundges the flash location so we avoid + * the first 80 bytes (they appear to read nonsense). + */ + if (page_addr) { + writel(0x00000008, map->base + 0x1558); + writel(0x00000000, map->base + 0x1550); + } else { + writel(0x00000007, map->base + 0x1558); + writel(0x00800000, map->base + 0x1550); + ofs += 0x00800000; + } + + return ofs; +} + +static struct mtd_pci_info intel_iq80310_info = { + init: intel_iq80310_init, + exit: intel_iq80310_exit, + translate: intel_iq80310_translate, + map_name: "cfi_probe", +}; + +/* + * Intel DC21285 driver + */ + +static int +intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map) +{ + unsigned long base, len; + + base = pci_resource_start(dev, PCI_ROM_RESOURCE); + len = pci_resource_len(dev, PCI_ROM_RESOURCE); + + if (!len || !base) { + /* + * No ROM resource + */ + base = pci_resource_start(dev, 2); + len = pci_resource_len(dev, 2); + + /* + * We need to re-allocate PCI BAR2 address range to the + * PCI ROM BAR, and disable PCI BAR2. + */ + } else { + /* + * Hmm, if an address was allocated to the ROM resource, but + * not enabled, should we be allocating a new resource for it + * or simply enabling it? + */ + if (!(pci_resource_flags(dev, PCI_ROM_RESOURCE) & + PCI_ROM_ADDRESS_ENABLE)) { + u32 val; + pci_resource_flags(dev, PCI_ROM_RESOURCE) |= PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val); + val |= PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, PCI_ROM_ADDRESS, val); + printk("%s: enabling expansion ROM\n", dev->slot_name); + } + } + + if (!len || !base) + return -ENXIO; + + map->map.buswidth = 4; + map->map.size = len; + map->base = ioremap_nocache(base, len); + + if (!map->base) + return -ENOMEM; + + return 0; +} + +static void +intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map) +{ + u32 val; + + if (map->base) + iounmap((void *)map->base); + + /* + * We need to undo the PCI BAR2/PCI ROM BAR address alteration. + */ + pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val); + val &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, PCI_ROM_ADDRESS, val); +} + +static unsigned long +intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs) +{ + return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5)); +} + +static struct mtd_pci_info intel_dc21285_info = { + init: intel_dc21285_init, + exit: intel_dc21285_exit, + translate: intel_dc21285_translate, + map_name: "jedec_probe", +}; + +/* + * PCI device ID table + */ + +static struct pci_device_id mtd_pci_ids[] __devinitdata = { + { + vendor: PCI_VENDOR_ID_INTEL, + device: 0x530d, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + class: PCI_CLASS_MEMORY_OTHER << 8, + class_mask: 0xffff00, + driver_data: (unsigned long)&intel_iq80310_info, + }, + { + vendor: PCI_VENDOR_ID_DEC, + device: PCI_DEVICE_ID_DEC_21285, + subvendor: 0, /* DC21285 defaults to 0 on reset */ + subdevice: 0, /* DC21285 defaults to 0 on reset */ + class: 0, + class_mask: 0, + driver_data: (unsigned long)&intel_dc21285_info, + }, + { 0, } +}; + +/* + * Generic code follows. + */ + +static u8 mtd_pci_read8(struct map_info *_map, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + u8 val = readb(map->base + map->translate(map, ofs)); +// printk("read8 : %08lx => %02x\n", ofs, val); + return val; +} + +static u16 mtd_pci_read16(struct map_info *_map, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + u16 val = readw(map->base + map->translate(map, ofs)); +// printk("read16: %08lx => %04x\n", ofs, val); + return val; +} + +static u32 mtd_pci_read32(struct map_info *_map, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + u32 val = readl(map->base + map->translate(map, ofs)); +// printk("read32: %08lx => %08x\n", ofs, val); + return val; +} + +static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + memcpy_fromio(to, map->base + map->translate(map, from), len); +} + +static void mtd_pci_write8(struct map_info *_map, u8 val, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; +// printk("write8 : %08lx <= %02x\n", ofs, val); + writeb(val, map->base + map->translate(map, ofs)); +} + +static void mtd_pci_write16(struct map_info *_map, u16 val, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; +// printk("write16: %08lx <= %04x\n", ofs, val); + writew(val, map->base + map->translate(map, ofs)); +} + +static void mtd_pci_write32(struct map_info *_map, u32 val, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; +// printk("write32: %08lx <= %08x\n", ofs, val); + writel(val, map->base + map->translate(map, ofs)); +} + +static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + memcpy_toio(map->base + map->translate(map, to), from, len); +} + +static struct map_info mtd_pci_map = { + read8: mtd_pci_read8, + read16: mtd_pci_read16, + read32: mtd_pci_read32, + copy_from: mtd_pci_copyfrom, + write8: mtd_pci_write8, + write16: mtd_pci_write16, + write32: mtd_pci_write32, + copy_to: mtd_pci_copyto, +}; + +static int __devinit +mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data; + struct map_pci_info *map = NULL; + struct mtd_info *mtd = NULL; + int err; + + err = pci_enable_device(dev); + if (err) + goto out; + + err = pci_request_regions(dev, "pci mtd"); + if (err) + goto out; + + map = kmalloc(sizeof(*map), GFP_KERNEL); + err = -ENOMEM; + if (!map) + goto release; + + map->map = mtd_pci_map; + map->map.name = dev->slot_name; + map->dev = dev; + map->exit = info->exit; + map->translate = info->translate; + + err = info->init(dev, map); + if (err) + goto release; + + /* tsk - do_map_probe should take const char * */ + mtd = do_map_probe((char *)info->map_name, &map->map); + err = -ENODEV; + if (!mtd) + goto release; + + mtd->module = THIS_MODULE; + add_mtd_device(mtd); + + pci_set_drvdata(dev, mtd); + + return 0; + +release: + if (mtd) + map_destroy(mtd); + + if (map) { + map->exit(dev, map); + kfree(map); + } + + pci_release_regions(dev); +out: + return err; +} + +static void __devexit +mtd_pci_remove(struct pci_dev *dev) +{ + struct mtd_info *mtd = pci_get_drvdata(dev); + struct map_pci_info *map = mtd->priv; + + del_mtd_device(mtd); + map_destroy(mtd); + map->exit(dev, map); + kfree(map); + + pci_set_drvdata(dev, NULL); + pci_release_regions(dev); +} + +static struct pci_driver mtd_pci_driver = { + name: "MTD PCI", + probe: mtd_pci_probe, + remove: mtd_pci_remove, + id_table: mtd_pci_ids, +}; + +static int __init mtd_pci_maps_init(void) +{ + return pci_module_init(&mtd_pci_driver); +} + +static void __exit mtd_pci_maps_exit(void) +{ + pci_unregister_driver(&mtd_pci_driver); +} + +module_init(mtd_pci_maps_init); +module_exit(mtd_pci_maps_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("Generic PCI map driver"); +MODULE_DEVICE_TABLE(pci, mtd_pci_ids); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/sa1100-flash.c linux-2.5/drivers/mtd/maps/sa1100-flash.c --- linux-2.5.20/drivers/mtd/maps/sa1100-flash.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/mtd/maps/sa1100-flash.c Sat Apr 13 17:42:56 2002 @@ -3,12 +3,13 @@ * * (C) 2000 Nicolas Pitre * - * $Id: sa1100-flash.c,v 1.22 2001/10/02 10:04:52 rmk Exp $ + * $Id: sa1100-flash.c,v 1.26 2002/03/13 16:30:44 rmk Exp $ */ #include #include #include +#include #include #include @@ -66,32 +67,6 @@ memcpy((void *)(map->map_priv_1 + to), from, len); } - -#ifdef CONFIG_SA1100_H3600 - -static void h3600_set_vpp(struct map_info *map, int vpp) -{ - if (vpp) - set_h3600_egpio(EGPIO_H3600_VPP_ON); - else - clr_h3600_egpio(EGPIO_H3600_VPP_ON); -} - -#endif - -#ifdef CONFIG_SA1100_JORNADA720 - -static void jornada720_set_vpp(int vpp) -{ - if (vpp) - PPSR |= 0x80; - else - PPSR &= ~0x80; - PPDR |= 0x80; -} - -#endif - static struct map_info sa1100_map = { name: "SA1100 flash", read8: sa1100_read8, @@ -104,6 +79,7 @@ copy_to: sa1100_copy_to, map_priv_1: WINDOW_ADDR, + map_priv_2: -1, }; @@ -111,425 +87,687 @@ * Here are partition information for all known SA1100-based devices. * See include/linux/mtd/partitions.h for definition of the mtd_partition * structure. - * + * * The *_max_flash_size is the maximum possible mapped flash size which - * is not necessarily the actual flash size. It must correspond to the - * value specified in the mapping definition defined by the - * "struct map_desc *_io_desc" for the corresponding machine. + * is not necessarily the actual flash size. It must be no more than + * the value specified in the "struct map_desc *_io_desc" mapping + * definition for the corresponding machine. + * + * Please keep these in alphabetical order, and formatted as per existing + * entries. Thanks. */ -#ifdef CONFIG_SA1100_ASSABET +#ifdef CONFIG_SA1100_ADSBITSY +#define ADSBITSY_FLASH_SIZE 0x02000000 +static struct mtd_partition adsbitsy_partitions[] = { + { + name: "bootROM", + size: 0x80000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "zImage", + size: 0x100000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "ramdisk.gz", + size: 0x300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "User FS", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } +}; +#endif +#ifdef CONFIG_SA1100_ASSABET /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */ -static unsigned long assabet4_max_flash_size = 0x00400000; +#define ASSABET4_FLASH_SIZE 0x00400000 static struct mtd_partition assabet4_partitions[] = { - { - name: "bootloader", - size: 0x00020000, - offset: 0, - mask_flags: MTD_WRITEABLE - },{ - name: "bootloader params", - size: 0x00020000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "jffs", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND - } + { + name: "bootloader", + size: 0x00020000, + offset: 0, + mask_flags: MTD_WRITEABLE, + }, { + name: "bootloader params", + size: 0x00020000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "jffs", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } }; /* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */ -static unsigned long assabet5_max_flash_size = 0x02000000; +#define ASSABET5_FLASH_SIZE 0x02000000 static struct mtd_partition assabet5_partitions[] = { - { - name: "bootloader", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE - },{ - name: "bootloader params", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "jffs", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND - } + { + name: "bootloader", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, + }, { + name: "bootloader params", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "jffs", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } }; -#define assabet_max_flash_size assabet5_max_flash_size -#define assabet_partitions assabet5_partitions - +#define ASSABET_FLASH_SIZE ASSABET5_FLASH_SIZE +#define assabet_partitions assabet5_partitions #endif -#ifdef CONFIG_SA1100_FLEXANET +#ifdef CONFIG_SA1100_BADGE4 -/* Flexanet has two 28F128J3A flash parts in bank 0: */ -static unsigned long flexanet_max_flash_size = 0x02000000; -static struct mtd_partition flexanet_partitions[] = { - { - name: "bootloader", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE - },{ - name: "bootloader params", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "kernel", - size: 0x000C0000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "altkernel", - size: 0x000C0000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "root", - size: 0x00400000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "free1", - size: 0x00300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "free2", - size: 0x00300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "free3", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - } +/* + * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit) + * Eight 4 KiW Parameter Bottom Blocks (64 KiB) + * Sixty-three 32 KiW Main Blocks (4032 Ki b) + */ +#define BADGE4_FLASH_SIZE 0x00400000 +static struct mtd_partition badge4_partitions[] = { + { + name: "BLOB boot loader", + offset: 0, + size: 0x0000A000 + }, { + name: "params", + offset: MTDPART_OFS_APPEND, + size: 0x00006000 + }, { + name: "kernel", + offset: MTDPART_OFS_APPEND, + size: 0x00100000 + }, { + name: "root", + offset: MTDPART_OFS_APPEND, + size: MTDPART_SIZ_FULL + } }; #endif -#ifdef CONFIG_SA1100_HUW_WEBPANEL -static unsigned long huw_webpanel_max_flash_size = 0x01000000; -static struct mtd_partition huw_webpanel_partitions[] = { - { - name: "Loader", - size: 0x00040000, - offset: 0, - },{ - name: "Sector 1", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - },{ - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + +#ifdef CONFIG_SA1100_CERF +#ifdef CONFIG_SA1100_CERF_FLASH_32MB +#define CERF_FLASH_SIZE 0x02000000 +static struct mtd_partition cerf_partitions[] = { + { + name: "firmware", + size: 0x00040000, + offset: 0, + }, { + name: "params", + size: 0x00040000, + offset: 0x00040000, + }, { + name: "kernel", + size: 0x00100000, + offset: 0x00080000, + }, { + name: "rootdisk", + size: 0x01E80000, + offset: 0x00180000, } }; -#endif /* CONFIG_SA1100_HUW_WEBPANEL */ - - -#ifdef CONFIG_SA1100_H3600 - -static unsigned long h3600_max_flash_size = 0x02000000; -static struct mtd_partition h3600_partitions[] = { +#elif defined CONFIG_SA1100_CERF_FLASH_16MB +#define CERF_FLASH_SIZE 0x01000000 +static struct mtd_partition cerf_partitions[] = { { - name: "H3600 boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "H3600 kernel", - size: 0x00080000, - offset: 0x40000 - },{ - name: "H3600 params", - size: 0x00040000, - offset: 0xC0000 - },{ -#ifdef CONFIG_JFFS2_FS - name: "H3600 root jffs2", - offset: 0x00100000, - size: MTDPART_SIZ_FULL + name: "firmware", + size: 0x00020000, + offset: 0, + }, { + name: "params", + size: 0x00020000, + offset: 0x00020000, + }, { + name: "kernel", + size: 0x00100000, + offset: 0x00040000, + }, { + name: "rootdisk", + size: 0x00EC0000, + offset: 0x00140000, + } +}; +#elif defined CONFIG_SA1100_CERF_FLASH_8MB +# error "Unwritten type definition" #else - name: "H3600 initrd", - size: 0x00100000, - offset: 0x00100000 - },{ - name: "H3600 root cramfs", - size: 0x00300000, - offset: 0x00200000 - },{ - name: "H3600 usr cramfs", - size: 0x00800000, - offset: 0x00500000 - },{ - name: "H3600 usr local", - offset: 0x00d00000, - size: MTDPART_SIZ_FULL +# error "Undefined memory orientation for CERF in sa1100-flash.c" #endif +#endif + +#ifdef CONFIG_SA1100_CONSUS +#define CONSUS_FLASH_SIZE 0x02000000 +static struct mtd_partition consus_partitions[] = { + { + name: "Consus boot firmware", + offset: 0, + size: 0x00040000, + mask_flags: MTD_WRITABLE, /* force read-only */ + }, { + name: "Consus kernel", + offset: 0x00040000, + size: 0x00100000, + mask_flags: 0, + }, { + name: "Consus disk", + offset: 0x00140000, + /* The rest (up to 16M) for jffs. We could put 0 and + make it find the size automatically, but right now + i have 32 megs. jffs will use all 32 megs if given + the chance, and this leads to horrible problems + when you try to re-flash the image because blob + won't erase the whole partition. */ + size: 0x01000000 - 0x00140000, + mask_flags: 0, + }, { + /* this disk is a secondary disk, which can be used as + needed, for simplicity, make it the size of the other + consus partition, although realistically it could be + the remainder of the disk (depending on the file + system used) */ + name: "Consus disk2", + offset: 0x01000000, + size: 0x01000000 - 0x00140000, + mask_flags: 0, } }; +#endif +#ifdef CONFIG_SA1100_FLEXANET +/* Flexanet has two 28F128J3A flash parts in bank 0: */ +#define FLEXANET_FLASH_SIZE 0x02000000 +static struct mtd_partition flexanet_partitions[] = { + { + name: "bootloader", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, + }, { + name: "bootloader params", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "kernel", + size: 0x000C0000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "altkernel", + size: 0x000C0000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "root", + size: 0x00400000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "free1", + size: 0x00300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "free2", + size: 0x00300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "free3", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + } +}; #endif + #ifdef CONFIG_SA1100_FREEBIRD -static unsigned long freebird_max_flash_size = 0x02000000; +#define FREEBIRD_FLASH_SIZE 0x02000000 static struct mtd_partition freebird_partitions[] = { #if CONFIG_SA1100_FREEBIRD_NEW - { - name: "firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "kernel", - size: 0x00080000, - offset: 0x40000 - },{ - name: "params", - size: 0x00040000, - offset: 0xC0000 - },{ - name: "initrd", - size: 0x00100000, - offset: 0x00100000 - },{ - name: "root cramfs", - size: 0x00300000, - offset: 0x00200000 - },{ - name: "usr cramfs", - size: 0x00C00000, - offset: 0x00500000 - },{ - name: "local", - offset: 0x01100000, - size: MTDPART_SIZ_FULL + { + name: "firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "kernel", + size: 0x00080000, + offset: 0x00040000, + }, { + name: "params", + size: 0x00040000, + offset: 0x000C0000, + }, { + name: "initrd", + size: 0x00100000, + offset: 0x00100000, + }, { + name: "root cramfs", + size: 0x00300000, + offset: 0x00200000, + }, { + name: "usr cramfs", + size: 0x00C00000, + offset: 0x00500000, + }, { + name: "local", + size: MTDPART_SIZ_FULL, + offset: 0x01100000, } #else - { offset: 0, size: 0x00040000, }, - { offset: MTDPART_OFS_APPEND, size: 0x000c0000, }, - { offset: MTDPART_OFS_APPEND, size: 0x00400000, }, - { offset: MTDPART_OFS_APPEND, size: MTDPART_SIZ_FULL } + { + size: 0x00040000, + offset: 0, + }, { + size: 0x000c0000, + offset: MTDPART_OFS_APPEND, + }, { + size: 0x00400000, + offset: MTDPART_OFS_APPEND, + }, { + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } #endif - }; +}; #endif - -#ifdef CONFIG_SA1100_CERF - -static unsigned long cerf_max_flash_size = 0x01000000; -static struct mtd_partition cerf_partitions[] = { - { offset: 0, size: 0x00800000 }, - { offset: MTDPART_OFS_APPEND, size: 0x00800000 } +#ifdef CONFIG_SA1100_FRODO +/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */ +#define FRODO_FLASH_SIZE 0x02000000 +static struct mtd_partition frodo_partitions[] = +{ + { + name: "bootloader", + size: 0x00040000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE + }, { + name: "bootloader params", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE + }, { + name: "kernel", + size: 0x00100000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE + }, { + name: "ramdisk", + size: 0x00400000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE + }, { + name: "file system", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND + } }; - #endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT - -static unsigned long graphicsclient_max_flash_size = 0x01000000; +#define GRAPHICSCLIENT_FLASH_SIZE 0x02000000 static struct mtd_partition graphicsclient_partitions[] = { - { - name: "zImage", - offset: 0, - size: 0x100000 - }, - { - name: "ramdisk.gz", - offset: MTDPART_OFS_APPEND, - size: 0x300000 - }, - { - name: "User FS", - offset: MTDPART_OFS_APPEND, - size: MTDPART_SIZ_FULL + { + name: "zImage", + size: 0x100000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "ramdisk.gz", + size: 0x300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "User FS", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, } }; - #endif #ifdef CONFIG_SA1100_GRAPHICSMASTER - -static unsigned long graphicsmaster_max_flash_size = 0x01000000; +#define GRAPHICSMASTER_FLASH_SIZE 0x01000000 static struct mtd_partition graphicsmaster_partitions[] = { - { - name: "zImage", - offset: 0, - size: 0x100000 + { + name: "zImage", + size: 0x100000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ }, - { - name: "ramdisk.gz", - offset: MTDPART_OFS_APPEND, - size: 0x300000 + { + name: "ramdisk.gz", + size: 0x300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ }, - { - name: "User FS", - offset: MTDPART_OFS_APPEND, - size: MTDPART_SIZ_FULL + { + name: "User FS", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, } }; +#endif +#ifdef CONFIG_SA1100_H3600 +#define H3600_FLASH_SIZE 0x02000000 +static struct mtd_partition h3600_partitions[] = { + { + name: "H3600 boot firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "H3600 kernel", + size: 0x00080000, + offset: 0x00040000, + }, { + name: "H3600 params", + size: 0x00040000, + offset: 0x000C0000, + }, { +#ifdef CONFIG_JFFS2_FS + name: "H3600 root jffs2", + size: MTDPART_SIZ_FULL, + offset: 0x00100000, +#else + name: "H3600 initrd", + size: 0x00100000, + offset: 0x00100000, + }, { + name: "H3600 root cramfs", + size: 0x00300000, + offset: 0x00200000, + }, { + name: "H3600 usr cramfs", + size: 0x00800000, + offset: 0x00500000, + }, { + name: "H3600 usr local", + size: MTDPART_SIZ_FULL, + offset: 0x00d00000, #endif + } +}; -#ifdef CONFIG_SA1100_PANGOLIN +static void h3600_set_vpp(struct map_info *map, int vpp) +{ + assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp); +} +#endif -static unsigned long pangolin_max_flash_size = 0x04000000; -static struct mtd_partition pangolin_partitions[] = { - { - name: "boot firmware", - offset: 0x00000000, - size: 0x00080000, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, - { - name: "kernel", - offset: 0x00080000, - size: 0x00100000, - }, +#ifdef CONFIG_SA1100_HUW_WEBPANEL +#define HUW_WEBPANEL_FLASH_SIZE 0x01000000 +static struct mtd_partition huw_webpanel_partitions[] = { { - name: "initrd", - offset: 0x00180000, - size: 0x00280000, - }, + name: "Loader", + size: 0x00040000, + offset: 0, + }, { + name: "Sector 1", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + }, { + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } +}; +#endif + +#ifdef CONFIG_SA1100_JORNADA720 +#define JORNADA720_FLASH_SIZE 0x02000000 +static struct mtd_partition jornada720_partitions[] = { { - name: "initrd-test", - offset: 0x00400000, - size: 0x03C00000, + name: "JORNADA720 boot firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "JORNADA720 kernel", + size: 0x000c0000, + offset: 0x00040000, + }, { + name: "JORNADA720 params", + size: 0x00040000, + offset: 0x00100000, + }, { + name: "JORNADA720 initrd", + size: 0x00100000, + offset: 0x00140000, + }, { + name: "JORNADA720 root cramfs", + size: 0x00300000, + offset: 0x00240000, + }, { + name: "JORNADA720 usr cramfs", + size: 0x00800000, + offset: 0x00540000, + }, { + name: "JORNADA720 usr local", + size: 0 /* will expand to the end of the flash */ + offset: 0x00d00000, } }; +static void jornada720_set_vpp(int vpp) +{ + if (vpp) + PPSR |= 0x80; + else + PPSR &= ~0x80; + PPDR |= 0x80; +} + #endif -#ifdef CONFIG_SA1100_YOPY +#ifdef CONFIG_SA1100_PANGOLIN +#define PANGOLIN_FLASH_SIZE 0x04000000 +static struct mtd_partition pangolin_partitions[] = { + { + name: "boot firmware", + size: 0x00080000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "kernel", + size: 0x00100000, + offset: 0x00080000, + }, { + name: "initrd", + size: 0x00280000, + offset: 0x00180000, + }, { + name: "initrd-test", + size: 0x03C00000, + offset: 0x00400000, + } +}; +#endif -static unsigned long yopy_max_flash_size = 0x08000000; -static struct mtd_partition yopy_partitions[] = { +#ifdef CONFIG_SA1100_PT_SYSTEM3 +/* erase size is 0x40000 == 256k partitions have to have this boundary */ +#define SYSTEM3_FLASH_SIZE 0x01000000 +static struct mtd_partition system3_partitions[] = { + { + name: "BLOB", + size: 0x00040000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "config", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + }, { + name: "kernel", + size: 0x00100000, + offset: MTDPART_OFS_APPEND, + }, { + name: "root", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } +}; +#endif + +#ifdef CONFIG_SA1100_SHANNON +#define SHANNON_FLASH_SIZE 0x00400000 +static struct mtd_partition shannon_partitions[] = { { - name: "boot firmware", - offset: 0x00000000, - size: 0x00040000, - mask_flags: MTD_WRITEABLE, /* force read-only */ + name: "BLOB boot loader", + offset: 0, + size: 0x20000 }, { name: "kernel", - offset: 0x00080000, - size: 0x00080000, + offset: MTDPART_OFS_APPEND, + size: 0xe0000 }, - { + { name: "initrd", - offset: 0x00100000, - size: 0x00300000, - }, - { - name: "root", - offset: 0x00400000, - size: 0x01000000, - }, + offset: MTDPART_OFS_APPEND, + size: MTDPART_SIZ_FULL + } }; #endif -#ifdef CONFIG_SA1100_JORNADA720 - -static unsigned long jornada720_max_flash_size = 0x02000000; -static struct mtd_partition jornada720_partitions[] = { +#ifdef CONFIG_SA1100_SHERMAN +#define SHERMAN_FLASH_SIZE 0x02000000 +static struct mtd_partition sherman_partitions[] = { { - name: "JORNADA720 boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "JORNADA720 kernel", - size: 0x000c0000, - offset: 0x40000 - },{ - name: "JORNADA720 params", - size: 0x00040000, - offset: 0x100000 - },{ - name: "JORNADA720 initrd", - size: 0x00100000, - offset: 0x00140000 - },{ - name: "JORNADA720 root cramfs", - size: 0x00300000, - offset: 0x00240000 - },{ - name: "JORNADA720 usr cramfs", - size: 0x00800000, - offset: 0x00540000 - },{ - name: "JORNADA720 usr local", - offset: 0x00d00000, - size: 0 /* will expand to the end of the flash */ + size: 0x50000, + offset: 0, + }, { + size: 0x70000, + offset: MTDPART_OFS_APPEND, + }, { + size: 0x600000, + offset: MTDPART_OFS_APPEND, + }, { + size: 0xA0000, + offset: MTDPART_OFS_APPEND, } }; #endif -#ifdef CONFIG_SA1100_SHERMAN - -static unsigned long sherman_max_flash_size = 0x02000000; -static struct mtd_partition sherman_partitions[] = { - { offset: 0, size: 0x50000 }, - { offset: MTDPART_OFS_APPEND, size: 0x70000 }, - { offset: MTDPART_OFS_APPEND, size: 0x600000 }, - { offset: MTDPART_OFS_APPEND, size: 0xA0000 } -}; - +#ifdef CONFIG_SA1100_SIMPAD +#define SIMPAD_FLASH_SIZE 0x02000000 +static struct mtd_partition simpad_partitions[] = { + { + name: "SIMpad boot firmware", + size: 0x00080000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "SIMpad kernel", + size: 0x00100000, + offset: 0x00080000, + }, { +#ifdef CONFIG_JFFS2_FS + name: "SIMpad root jffs2", + size: MTDPART_SIZ_FULL, + offset: 0x00180000, +#else + name: "SIMpad initrd", + size: 0x00300000, + offset: 0x00180000, + }, { + name: "SIMpad root cramfs", + size: 0x00300000, + offset: 0x00480000, + }, { + name: "SIMpad usr cramfs", + size: 0x005c0000, + offset: 0x00780000, + }, { + name: "SIMpad usr local", + size: MTDPART_SIZ_FULL, + offset: 0x00d40000, #endif + } +}; +#endif /* CONFIG_SA1100_SIMPAD */ #ifdef CONFIG_SA1100_STORK - -static unsigned long stork_max_flash_size = 0x02000000; +#define STORK_FLASH_SIZE 0x02000000 static struct mtd_partition stork_partitions[] = { { - name: "STORK boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "STORK params", - size: 0x00040000, - offset: 0x40000 - },{ - name: "STORK kernel", - size: 0x00100000, - offset: 0x80000 - },{ + name: "STORK boot firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "STORK params", + size: 0x00040000, + offset: 0x00040000, + }, { + name: "STORK kernel", + size: 0x00100000, + offset: 0x00080000, + }, { #ifdef CONFIG_JFFS2_FS - name: "STORK root jffs2", - offset: 0x00180000, - size: MTDPART_SIZ_FULL + name: "STORK root jffs2", + offset: 0x00180000, + size: MTDPART_SIZ_FULL, #else - name: "STORK initrd", - size: 0x00100000, - offset: 0x00180000 - },{ - name: "STORK root cramfs", - size: 0x00300000, - offset: 0x00280000 - },{ - name: "STORK usr cramfs", - size: 0x00800000, - offset: 0x00580000 - },{ - name: "STORK usr local", - offset: 0x00d80000, - size: MTDPART_SIZ_FULL + name: "STORK initrd", + size: 0x00100000, + offset: 0x00180000, + }, { + name: "STORK root cramfs", + size: 0x00300000, + offset: 0x00280000, + }, { + name: "STORK usr cramfs", + size: 0x00800000, + offset: 0x00580000, + }, { + name: "STORK usr local", + offset: 0x00d80000, + size: MTDPART_SIZ_FULL, #endif } }; - #endif -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - +#ifdef CONFIG_SA1100_YOPY +#define YOPY_FLASH_SIZE 0x08000000 +static struct mtd_partition yopy_partitions[] = { + { + name: "boot firmware", + size: 0x00040000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "kernel", + size: 0x00080000, + offset: 0x00080000, + }, { + name: "initrd", + size: 0x00300000, + offset: 0x00100000, + }, { + name: "root", + size: 0x01000000, + offset: 0x00400000, + } +}; +#endif extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts); @@ -540,10 +778,11 @@ int __init sa1100_mtd_init(void) { struct mtd_partition *parts; - int nb_parts = 0; + int nb_parts = 0, ret; int parsed_nr_parts = 0; - char *part_type; - + const char *part_type; + unsigned long base = -1UL; + /* Default flash buswidth */ sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4; @@ -551,103 +790,166 @@ * Static partition definition selection */ part_type = "static"; + +#ifdef CONFIG_SA1100_ADSBITSY + if (machine_is_adsbitsy()) { + parts = adsbitsy_partitions; + nb_parts = ARRAY_SIZE(adsbitsy_partitions); + sa1100_map.size = ADSBITSY_FLASH_SIZE; + sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4; + } +#endif #ifdef CONFIG_SA1100_ASSABET if (machine_is_assabet()) { parts = assabet_partitions; - nb_parts = NB_OF(assabet_partitions); - sa1100_map.size = assabet_max_flash_size; + nb_parts = ARRAY_SIZE(assabet_partitions); + sa1100_map.size = ASSABET_FLASH_SIZE; } #endif - -#ifdef CONFIG_SA1100_HUW_WEBPANEL - if (machine_is_huw_webpanel()) { - parts = huw_webpanel_partitions; - nb_parts = NB_OF(huw_webpanel_partitions); - sa1100_map.size = huw_webpanel_max_flash_size; +#ifdef CONFIG_SA1100_BADGE4 + if (machine_is_badge4()) { + parts = badge4_partitions; + nb_parts = ARRAY_SIZE(badge4_partitions); + sa1100_map.size = BADGE4_FLASH_SIZE; } #endif - -#ifdef CONFIG_SA1100_H3600 - if (machine_is_h3600()) { - parts = h3600_partitions; - nb_parts = NB_OF(h3600_partitions); - sa1100_map.size = h3600_max_flash_size; - sa1100_map.set_vpp = h3600_set_vpp; +#ifdef CONFIG_SA1100_CERF + if (machine_is_cerf()) { + parts = cerf_partitions; + nb_parts = ARRAY_SIZE(cerf_partitions); + sa1100_map.size = CERF_FLASH_SIZE; + } +#endif +#ifdef CONFIG_SA1100_CONSUS + if (machine_is_consus()) { + parts = consus_partitions; + nb_parts = ARRAY_SIZE(consus_partitions); + sa1100_map.size = CONSUS_FLASH_SIZE; + } +#endif +#ifdef CONFIG_SA1100_FLEXANET + if (machine_is_flexanet()) { + parts = flexanet_partitions; + nb_parts = ARRAY_SIZE(flexanet_partitions); + sa1100_map.size = FLEXANET_FLASH_SIZE; } #endif #ifdef CONFIG_SA1100_FREEBIRD if (machine_is_freebird()) { parts = freebird_partitions; - nb_parts = NB_OF(freebird_partitions); - sa1100_map.size = freebird_max_flash_size; + nb_parts = ARRAY_SIZE(freebird_partitions); + sa1100_map.size = FREEBIRD_FLASH_SIZE; } #endif -#ifdef CONFIG_SA1100_CERF - if (machine_is_cerf()) { - parts = cerf_partitions; - nb_parts = NB_OF(cerf_partitions); - sa1100_map.size = cerf_max_flash_size; +#ifdef CONFIG_SA1100_FRODO + if (machine_is_frodo()) { + parts = frodo_partitions; + nb_parts = ARRAY_SIZE(frodo_partitions); + sa1100_map.size = FRODO_FLASH_SIZE; + base = 0x00000000; } -#endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT if (machine_is_graphicsclient()) { parts = graphicsclient_partitions; - nb_parts = NB_OF(graphicsclient_partitions); - sa1100_map.size = graphicsclient_max_flash_size; + nb_parts = ARRAY_SIZE(graphicsclient_partitions); + sa1100_map.size = GRAPHICSCLIENT_FLASH_SIZE; sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4; } #endif #ifdef CONFIG_SA1100_GRAPHICSMASTER if (machine_is_graphicsmaster()) { parts = graphicsmaster_partitions; - nb_parts = NB_OF(graphicsmaster_partitions); - sa1100_map.size = graphicsmaster_max_flash_size; + nb_parts = ARRAY_SIZE(graphicsmaster_partitions); + sa1100_map.size = GRAPHICSMASTER_FLASH_SIZE; sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4; } #endif -#ifdef CONFIG_SA1100_PANGOLIN - if (machine_is_pangolin()) { - parts = pangolin_partitions; - nb_parts = NB_OF(pangolin_partitions); - sa1100_map.size = pangolin_max_flash_size; +#ifdef CONFIG_SA1100_H3600 + if (machine_is_h3600()) { + parts = h3600_partitions; + nb_parts = ARRAY_SIZE(h3600_partitions); + sa1100_map.size = H3600_FLASH_SIZE; + sa1100_map.set_vpp = h3600_set_vpp; + } +#endif +#ifdef CONFIG_SA1100_HUW_WEBPANEL + if (machine_is_huw_webpanel()) { + parts = huw_webpanel_partitions; + nb_parts = ARRAY_SIZE(huw_webpanel_partitions); + sa1100_map.size = HUW_WEBPANEL_FLASH_SIZE; } #endif #ifdef CONFIG_SA1100_JORNADA720 if (machine_is_jornada720()) { parts = jornada720_partitions; - nb_parts = NB_OF(jornada720_partitions); - sa1100_map.size = jornada720_max_flash_size; + nb_parts = ARRAY_SIZE(jornada720_partitions); + sa1100_map.size = JORNADA720_FLASH_SIZE; sa1100_map.set_vpp = jornada720_set_vpp; } #endif -#ifdef CONFIG_SA1100_YOPY - if (machine_is_yopy()) { - parts = yopy_partitions; - nb_parts = NB_OF(yopy_partitions); - sa1100_map.size = yopy_max_flash_size; +#ifdef CONFIG_SA1100_PANGOLIN + if (machine_is_pangolin()) { + parts = pangolin_partitions; + nb_parts = ARRAY_SIZE(pangolin_partitions); + sa1100_map.size = PANGOLIN_FLASH_SIZE; + } +#endif +#ifdef CONFIG_SA1100_PT_SYSTEM3 + if (machine_is_pt_system3()) { + parts = system3_partitions; + nb_parts = ARRAY_SIZE(system3_partitions); + sa1100_map.size = SYSTEM3_FLASH_SIZE; + } +#endif +#ifdef CONFIG_SA1100_SHANNON + if (machine_is_shannon()) { + parts = shannon_partitions; + nb_parts = ARRAY_SIZE(shannon_partitions); + sa1100_map.size = SHANNON_FLASH_SIZE; } #endif #ifdef CONFIG_SA1100_SHERMAN if (machine_is_sherman()) { parts = sherman_partitions; - nb_parts = NB_OF(sherman_partitions); - sa1100_map.size = sherman_max_flash_size; + nb_parts = ARRAY_SIZE(sherman_partitions); + sa1100_map.size = SHERMAN_FLASH_SIZE; } #endif -#ifdef CONFIG_SA1100_FLEXANET - if (machine_is_flexanet()) { - parts = flexanet_partitions; - nb_parts = NB_OF(flexanet_partitions); - sa1100_map.size = flexanet_max_flash_size; +#ifdef CONFIG_SA1100_SIMPAD + if (machine_is_simpad()) { + parts = simpad_partitions; + nb_parts = ARRAY_SIZE(simpad_partitions); + sa1100_map.size = SIMPAD_FLASH_SIZE; } #endif #ifdef CONFIG_SA1100_STORK if (machine_is_stork()) { parts = stork_partitions; - nb_parts = NB_OF(stork_partitions); - sa1100_map.size = stork_max_flash_size; + nb_parts = ARRAY_SIZE(stork_partitions); + sa1100_map.size = STORK_FLASH_SIZE; } #endif +#ifdef CONFIG_SA1100_YOPY + if (machine_is_yopy()) { + parts = yopy_partitions; + nb_parts = ARRAY_SIZE(yopy_partitions); + sa1100_map.size = YOPY_FLASH_SIZE; + } +#endif + + /* + * For simple flash devices, use ioremap to map the flash. + */ + if (base != (unsigned long)-1) { + if (!request_mem_region(base, sa1100_map.size, "flash")) + return -EBUSY; + sa1100_map.map_priv_2 = base; + sa1100_map.map_priv_1 = (unsigned long) + ioremap(base, sa1100_map.size); + ret = -ENOMEM; + if (!sa1100_map.map_priv_1) + goto out_err; + } /* * Now let's probe for the actual flash. Do it here since @@ -655,8 +957,9 @@ */ printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8); mymtd = do_map_probe("cfi_probe", &sa1100_map); + ret = -ENXIO; if (!mymtd) - return -ENXIO; + goto out_err; mymtd->module = THIS_MODULE; /* @@ -665,7 +968,7 @@ #ifdef CONFIG_MTD_REDBOOT_PARTS if (parsed_nr_parts == 0) { int ret = parse_redboot_partitions(mymtd, &parsed_parts); - + if (ret > 0) { part_type = "RedBoot"; parsed_nr_parts = ret; @@ -695,6 +998,13 @@ add_mtd_partitions(mymtd, parts, nb_parts); } return 0; + + out_err: + if (sa1100_map.map_priv_2 != -1) { + iounmap((void *)sa1100_map.map_priv_1); + release_mem_region(sa1100_map.map_priv_2, sa1100_map.size); + } + return ret; } static void __exit sa1100_mtd_cleanup(void) @@ -704,6 +1014,10 @@ map_destroy(mymtd); if (parsed_parts) kfree(parsed_parts); + } + if (sa1100_map.map_priv_2 != -1) { + iounmap((void *)sa1100_map.map_priv_1); + release_mem_region(sa1100_map.map_priv_2, sa1100_map.size); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/sc520cdp.c linux-2.5/drivers/mtd/maps/sc520cdp.c --- linux-2.5.20/drivers/mtd/maps/sc520cdp.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/mtd/maps/sc520cdp.c Sat Apr 13 17:42:56 2002 @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: sc520cdp.c,v 1.9 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: sc520cdp.c,v 1.11 2002/03/08 16:34:35 rkaiser Exp $ * * * The SC520CDP is an evaluation board for the Elan SC520 processor available @@ -25,13 +25,14 @@ * For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html */ +#include #include #include #include #include #include #include - +#include /* ** The Embedded Systems BIOS decodes the first FLASH starting at @@ -171,6 +172,7 @@ #define NUM_FLASH_BANKS (sizeof(sc520cdp_map)/sizeof(struct map_info)) static struct mtd_info *mymtd[NUM_FLASH_BANKS]; +static struct mtd_info *merged_mtd; #ifdef REPROGRAM_PAR @@ -307,19 +309,26 @@ } mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]); if(!mymtd[i]) - mymtd[i] = do_map_probe("jedec", &sc520cdp_map[i]); + mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]); if(!mymtd[i]) mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]); if (mymtd[i]) { mymtd[i]->module = THIS_MODULE; - add_mtd_device(mymtd[i]); ++devices_found; } else { iounmap((void *)sc520cdp_map[i].map_priv_1); } } + if(devices_found >= 2) { + /* Combine the two flash banks into a single MTD device & register it: */ + merged_mtd = mtd_concat_create(mymtd, 2, "SC520CDP Flash Banks #0 and #1"); + if(merged_mtd) + add_mtd_device(merged_mtd); + } + if(devices_found == 3) /* register the third (DIL-Flash) device */ + add_mtd_device(mymtd[2]); return(devices_found ? 0 : -ENXIO); } @@ -327,11 +336,16 @@ { int i; + if (merged_mtd) { + del_mtd_device(merged_mtd); + mtd_concat_destroy(merged_mtd); + } + if (mymtd[2]) + del_mtd_device(mymtd[2]); + for (i = 0; i < NUM_FLASH_BANKS; i++) { - if (mymtd[i]) { - del_mtd_device(mymtd[i]); + if (mymtd[i]) map_destroy(mymtd[i]); - } if (sc520cdp_map[i].map_priv_1) { iounmap((void *)sc520cdp_map[i].map_priv_1); sc520cdp_map[i].map_priv_1 = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/solutionengine.c linux-2.5/drivers/mtd/maps/solutionengine.c --- linux-2.5.20/drivers/mtd/maps/solutionengine.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/mtd/maps/solutionengine.c Sat Apr 13 17:42:56 2002 @@ -1,5 +1,5 @@ /* - * $Id: solutionengine.c,v 1.3 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: solutionengine.c,v 1.4 2001/11/07 01:20:59 jsiegel Exp $ * * Flash and EPROM on Hitachi Solution Engine and similar boards. * @@ -15,6 +15,7 @@ #include #include #include +#include extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); @@ -57,20 +58,38 @@ write32: soleng_write32, }; +#ifdef CONFIG_MTD_SUPERH_RESERVE +static struct mtd_partition superh_se_partitions[] = { + /* Reserved for boot code, read-only */ + { + name: "flash_boot", + offset: 0x00000000, + size: CONFIG_MTD_SUPERH_RESERVE, + mask_flags: MTD_WRITEABLE, + }, + /* All else is writable (e.g. JFFS) */ + { + name: "Flash FS", + offset: MTDPART_OFS_NXTBLK, + size: MTDPART_SIZ_FULL, + } +}; +#endif /* CONFIG_MTD_SUPERH_RESERVE */ + static int __init init_soleng_maps(void) { - int nr_parts; + int nr_parts = 0; /* First probe at offset 0 */ soleng_flash_map.map_priv_1 = P2SEGADDR(0); - soleng_eprom_map.map_priv_1 = P1SEGADDR(0x400000); + soleng_eprom_map.map_priv_1 = P1SEGADDR(0x01000000); - printk(KERN_NOTICE "Probing for flash chips at 0x000000:\n"); + printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { /* Not there. Try swapping */ - printk(KERN_NOTICE "Probing for flash chips at 0x400000:\n"); - soleng_flash_map.map_priv_1 = P2SEGADDR(0x400000); + printk(KERN_NOTICE "Probing for flash chips at 0x01000000:\n"); + soleng_flash_map.map_priv_1 = P2SEGADDR(0x01000000); soleng_eprom_map.map_priv_1 = P1SEGADDR(0); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { @@ -90,9 +109,23 @@ add_mtd_device(eprom_mtd); } +#ifdef CONFIG_MTD_REDBOOT_PARTS nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts); + if (nr_parts > 0) + printk(KERN_NOTICE "Found RedBoot partition table.\n"); + else if (nr_parts < 0) + printk(KERN_NOTICE "Error looking for RedBoot partitions.\n"); +#endif /* CONFIG_MTD_REDBOOT_PARTS */ +#if CONFIG_MTD_SUPERH_RESERVE + if (nr_parts == 0) { + printk(KERN_NOTICE "Using configured partition at 0x%08x.\n", + CONFIG_MTD_SUPERH_RESERVE); + parsed_parts = superh_se_partitions; + nr_parts = sizeof(superh_se_partitions)/sizeof(*parsed_parts); + } +#endif /* CONFIG_MTD_SUPERH_RESERVE */ - if (nr_parts) + if (nr_parts > 0) add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); else add_mtd_device(flash_mtd); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/maps/tsunami_flash.c linux-2.5/drivers/mtd/maps/tsunami_flash.c --- linux-2.5.20/drivers/mtd/maps/tsunami_flash.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/mtd/maps/tsunami_flash.c Sun Apr 14 23:00:19 2002 @@ -0,0 +1,110 @@ +/* + * tsunami_flash.c + * + * flash chip on alpha ds10... + * $Id: tsunami_flash.c,v 1.1 2002/01/10 22:59:13 eric Exp $ + */ +#include +#include +#include + +#define FLASH_ENABLE_PORT 0x00C00001 +#define FLASH_ENABLE_BYTE 0x01 +#define FLASH_DISABLE_BYTE 0x00 + +#define MAX_TIG_FLASH_SIZE (12*1024*1024) +static inline __u8 tsunami_flash_read8(struct map_info *map, unsigned long offset) +{ + return tsunami_tig_readb(offset); +} + +static void tsunami_flash_write8(struct map_info *map, __u8 value, unsigned long offset) +{ + tsunami_tig_writeb(value, offset); +} + +static void tsunami_flash_copy_from( + struct map_info *map, void *addr, unsigned long offset, ssize_t len) +{ + unsigned char *dest; + dest = addr; + while(len && (offset < MAX_TIG_FLASH_SIZE)) { + *dest = tsunami_tig_readb(offset); + offset++; + dest++; + len--; + } +} + +static void tsunami_flash_copy_to( + struct map_info *map, unsigned long offset, + const void *addr, ssize_t len) +{ + const unsigned char *src; + src = addr; + while(len && (offset < MAX_TIG_FLASH_SIZE)) { + tsunami_tig_writeb(*src, offset); + offset++; + src++; + len--; + } +} + +/* + * Deliberately don't provide operations wider than 8 bits. I don't + * have then and it scares me to think how you could mess up if + * you tried to use them. Buswidth is correctly so I'm safe. + */ +static struct map_info tsunami_flash_map = { + .name = "flash chip on the Tsunami TIG bus", + .size = MAX_TIG_FLASH_SIZE, + .buswidth = 1, + .read8 = tsunami_flash_read8, + .read16 = 0, + .read32 = 0, + .copy_from = tsunami_flash_copy_from, + .write8 = tsunami_flash_write8, + .write16 = 0, + .write32 = 0, + .copy_to = tsunami_flash_copy_to, + .set_vpp = 0, + .map_priv_1 = 0, + +}; + +static struct mtd_info *tsunami_flash_mtd; + +static void __exit cleanup_tsunami_flash(void) +{ + struct mtd_info *mtd; + mtd = tsunami_flash_mtd; + if (mtd) { + del_mtd_device(mtd); + map_destroy(mtd); + } + tsunami_flash_mtd = 0; +} + + +static int __init init_tsunami_flash(void) +{ + static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 }; + char **type; + + tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT); + + tsunami_flash_mtd = 0; + type = rom_probe_types; + for(; !tsunami_flash_mtd && *type; type++) { + tsunami_flash_mtd = do_map_probe(*type, &tsunami_flash_map); + } + if (tsunami_flash_mtd) { + tsunami_flash_mtd->module = THIS_MODULE; + add_mtd_device(tsunami_flash_mtd); + return 0; + } + return -ENXIO; +} + +module_init(init_tsunami_flash); +module_exit(cleanup_tsunami_flash); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/mtdblock.c linux-2.5/drivers/mtd/mtdblock.c --- linux-2.5.20/drivers/mtd/mtdblock.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/mtd/mtdblock.c Sat Jun 1 00:34:35 2002 @@ -1,7 +1,7 @@ /* * Direct MTD block device access * - * $Id: mtdblock.c,v 1.47 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdblock.c,v 1.51 2001/11/20 11:42:33 dwmw2 Exp $ * * 02-nov-2000 Nicolas Pitre Added read-modify-write with cache */ @@ -47,6 +47,14 @@ static int mtd_sizes[MAX_MTD_DEVICES]; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) +#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT +#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define BLK_INC_USE_COUNT do {} while(0) +#define BLK_DEC_USE_COUNT do {} while(0) +#endif + /* * Cache stuff... * @@ -273,11 +281,14 @@ if (dev >= MAX_MTD_DEVICES) return -EINVAL; + BLK_INC_USE_COUNT; + mtd = get_mtd_device(NULL, dev); if (!mtd) return -ENODEV; if (MTD_ABSENT == mtd->type) { put_mtd_device(mtd); + BLK_DEC_USE_COUNT; return -ENODEV; } @@ -300,6 +311,7 @@ mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); if (!mtdblk) { put_mtd_device(mtd); + BLK_DEC_USE_COUNT; return -ENOMEM; } memset(mtdblk, 0, sizeof(*mtdblk)); @@ -315,6 +327,7 @@ if (!mtdblk->cache_data) { put_mtd_device(mtdblk->mtd); kfree(mtdblk); + BLK_DEC_USE_COUNT; return -ENOMEM; } } @@ -378,6 +391,7 @@ DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + BLK_DEC_USE_COUNT; release_return(0); } @@ -521,8 +535,11 @@ switch (cmd) { case BLKGETSIZE: /* Return device size */ return put_user((mtdblk->mtd->size >> 9), (unsigned long *) arg); + +#ifdef BLKGETSIZE64 case BLKGETSIZE64: return put_user((u64)mtdblk->mtd->size, (u64 *)arg); +#endif case BLKFLSBUF: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) @@ -555,7 +572,9 @@ #else static struct block_device_operations mtd_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) owner: THIS_MODULE, +#endif open: mtdblock_open, release: mtdblock_release, ioctl: mtdblock_ioctl diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/mtdblock_ro.c linux-2.5/drivers/mtd/mtdblock_ro.c --- linux-2.5.20/drivers/mtd/mtdblock_ro.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/mtd/mtdblock_ro.c Sat Jun 1 00:34:35 2002 @@ -1,5 +1,5 @@ /* - * $Id: mtdblock_ro.c,v 1.9 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdblock_ro.c,v 1.12 2001/11/20 11:42:33 dwmw2 Exp $ * * Read-only version of the mtdblock device, without the * read/erase/modify/writeback stuff @@ -34,6 +34,13 @@ MODULE_PARM(debug, "i"); #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) +#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT +#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define BLK_INC_USE_COUNT do {} while(0) +#define BLK_DEC_USE_COUNT do {} while(0) +#endif static int mtd_sizes[MAX_MTD_DEVICES]; @@ -59,6 +66,8 @@ return -EINVAL; } + BLK_INC_USE_COUNT; + mtd_sizes[dev] = mtd->size>>9; DEBUG(1, "ok\n"); @@ -76,13 +85,12 @@ if (inode == NULL) release_return(-ENODEV); - invalidate_device(inode->i_rdev, 1); - dev = minor(inode->i_rdev); mtd = __get_mtd_device(NULL, dev); if (!mtd) { printk(KERN_WARNING "MTD device is absent on mtd_release!\n"); + BLK_DEC_USE_COUNT; release_return(-ENODEV); } @@ -218,9 +226,12 @@ switch (cmd) { case BLKGETSIZE: /* Return device size */ return put_user((mtd->size >> 9), (unsigned long *) arg); + +#ifdef BLKGETSIZE64 case BLKGETSIZE64: return put_user((u64)mtd->size, (u64 *)arg); - +#endif + case BLKFLSBUF: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) if(!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -248,7 +259,9 @@ #else static struct block_device_operations mtd_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) owner: THIS_MODULE, +#endif open: mtdblock_open, release: mtdblock_release, ioctl: mtdblock_ioctl diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/mtdconcat.c linux-2.5/drivers/mtd/mtdconcat.c --- linux-2.5.20/drivers/mtd/mtdconcat.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/mtd/mtdconcat.c Sun Apr 14 23:00:18 2002 @@ -0,0 +1,672 @@ +/* + * MTD device concatenation layer + * + * (C) 2002 Robert Kaiser + * + * This code is GPL + * + * $Id: mtdconcat.c,v 1.2 2002/03/22 08:45:22 dwmw2 Exp $ + */ + +#include +#include +#include +#include + +#include +#include + +/* + * Our storage structure: + * Subdev points to an array of pointers to struct mtd_info objects + * which is allocated along with this structure + * + */ +struct mtd_concat { + struct mtd_info mtd; + int num_subdev; + struct mtd_info **subdev; +}; + +/* + * how to calculate the size required for the above structure, + * including the pointer array subdev points to: + */ +#define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \ + ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *))) + + +/* + * Given a pointer to the MTD object in the mtd_concat structure, + * we can retrieve the pointer to that structure with this macro. + */ +#define CONCAT(x) ((struct mtd_concat *)(x)) + + +/* + * MTD methods which look up the relevant subdevice, translate the + * effective address and pass through to the subdevice. + */ + +static int concat_read (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + *retlen = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (from >= subdev->size) + { + size = 0; + from -= subdev->size; + } + else + { + if (from + len > subdev->size) + size = subdev->size - from; + else + size = len; + + err = subdev->read(subdev, from, size, &retsize, buf); + + if(err) + break; + + *retlen += retsize; + len -= size; + if(len == 0) + break; + + err = -EINVAL; + buf += size; + from = 0; + } + } + return err; +} + +static int concat_write (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + *retlen = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (to >= subdev->size) + { + size = 0; + to -= subdev->size; + } + else + { + if (to + len > subdev->size) + size = subdev->size - to; + else + size = len; + + if (!(subdev->flags & MTD_WRITEABLE)) + err = -EROFS; + else + err = subdev->write(subdev, to, size, &retsize, buf); + + if(err) + break; + + *retlen += retsize; + len -= size; + if(len == 0) + break; + + err = -EINVAL; + buf += size; + to = 0; + } + } + return err; +} + +static void concat_erase_callback (struct erase_info *instr) +{ + wake_up((wait_queue_head_t *)instr->priv); +} + +static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase) +{ + int err; + wait_queue_head_t waitq; + DECLARE_WAITQUEUE(wait, current); + + /* + * This code was stol^H^H^H^Hinspired by mtdchar.c + */ + init_waitqueue_head(&waitq); + + erase->mtd = mtd; + erase->callback = concat_erase_callback; + erase->priv = (unsigned long)&waitq; + + /* + * FIXME: Allow INTERRUPTIBLE. Which means + * not having the wait_queue head on the stack. + */ + err = mtd->erase(mtd, erase); + if (!err) + { + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&waitq, &wait); + if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED) + schedule(); + remove_wait_queue(&waitq, &wait); + set_current_state(TASK_RUNNING); + + err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0; + } + return err; +} + +static int concat_erase (struct mtd_info *mtd, struct erase_info *instr) +{ + struct mtd_concat *concat = CONCAT(mtd); + struct mtd_info *subdev; + int i, err; + u_int32_t length; + struct erase_info *erase; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + if(instr->addr > concat->mtd.size) + return -EINVAL; + + if(instr->len + instr->addr > concat->mtd.size) + return -EINVAL; + + /* + * Check for proper erase block alignment of the to-be-erased area. + * It is easier to do this based on the super device's erase + * region info rather than looking at each particular sub-device + * in turn. + */ + if (!concat->mtd.numeraseregions) + { /* the easy case: device has uniform erase block size */ + if(instr->addr & (concat->mtd.erasesize - 1)) + return -EINVAL; + if(instr->len & (concat->mtd.erasesize - 1)) + return -EINVAL; + } + else + { /* device has variable erase size */ + struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions; + + /* + * Find the erase region where the to-be-erased area begins: + */ + for(i = 0; i < concat->mtd.numeraseregions && + instr->addr >= erase_regions[i].offset; i++) + ; + --i; + + /* + * Now erase_regions[i] is the region in which the + * to-be-erased area begins. Verify that the starting + * offset is aligned to this region's erase size: + */ + if (instr->addr & (erase_regions[i].erasesize-1)) + return -EINVAL; + + /* + * now find the erase region where the to-be-erased area ends: + */ + for(; i < concat->mtd.numeraseregions && + (instr->addr + instr->len) >= erase_regions[i].offset ; ++i) + ; + --i; + /* + * check if the ending offset is aligned to this region's erase size + */ + if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1)) + return -EINVAL; + } + + /* make a local copy of instr to avoid modifying the caller's struct */ + erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL); + + if (!erase) + return -ENOMEM; + + *erase = *instr; + length = instr->len; + + /* + * find the subdevice where the to-be-erased area begins, adjust + * starting offset to be relative to the subdevice start + */ + for(i = 0; i < concat->num_subdev; i++) + { + subdev = concat->subdev[i]; + if(subdev->size <= erase->addr) + erase->addr -= subdev->size; + else + break; + } + if(i >= concat->num_subdev) /* must never happen since size */ + BUG(); /* limit has been verified above */ + + /* now do the erase: */ + err = 0; + for(;length > 0; i++) /* loop for all subevices affected by this request */ + { + subdev = concat->subdev[i]; /* get current subdevice */ + + /* limit length to subdevice's size: */ + if(erase->addr + length > subdev->size) + erase->len = subdev->size - erase->addr; + else + erase->len = length; + + if (!(subdev->flags & MTD_WRITEABLE)) + { + err = -EROFS; + break; + } + length -= erase->len; + if ((err = concat_dev_erase(subdev, erase))) + { + if(err == -EINVAL) /* sanity check: must never happen since */ + BUG(); /* block alignment has been checked above */ + break; + } + /* + * erase->addr specifies the offset of the area to be + * erased *within the current subdevice*. It can be + * non-zero only the first time through this loop, i.e. + * for the first subdevice where blocks need to be erased. + * All the following erases must begin at the start of the + * current subdevice, i.e. at offset zero. + */ + erase->addr = 0; + } + instr->state = MTD_ERASE_DONE; + if (instr->callback) + instr->callback(instr); + kfree(erase); + return err; +} + +static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, err = -EINVAL; + + if ((len + ofs) > mtd->size) + return -EINVAL; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size; + + if (ofs >= subdev->size) + { + size = 0; + ofs -= subdev->size; + } + else + { + if (ofs + len > subdev->size) + size = subdev->size - ofs; + else + size = len; + + err = subdev->lock(subdev, ofs, size); + + if(err) + break; + + len -= size; + if(len == 0) + break; + + err = -EINVAL; + ofs = 0; + } + } + return err; +} + +static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, err = 0; + + if ((len + ofs) > mtd->size) + return -EINVAL; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size; + + if (ofs >= subdev->size) + { + size = 0; + ofs -= subdev->size; + } + else + { + if (ofs + len > subdev->size) + size = subdev->size - ofs; + else + size = len; + + err = subdev->unlock(subdev, ofs, size); + + if(err) + break; + + len -= size; + if(len == 0) + break; + + err = -EINVAL; + ofs = 0; + } + } + return err; +} + +static void concat_sync(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + subdev->sync(subdev); + } +} + +static int concat_suspend(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, rc = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + if((rc = subdev->suspend(subdev)) < 0) + return rc; + } + return rc; +} + +static void concat_resume(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + subdev->resume(subdev); + } +} + +/* + * This function constructs a virtual MTD device by concatenating + * num_devs MTD devices. A pointer to the new device object is + * stored to *new_dev upon success. This function does _not_ + * register any devices: this is the caller's responsibility. + */ +struct mtd_info *mtd_concat_create( + struct mtd_info *subdev[], /* subdevices to concatenate */ + int num_devs, /* number of subdevices */ + char *name) /* name for the new device */ +{ + int i; + size_t size; + struct mtd_concat *concat; + u_int32_t max_erasesize, curr_erasesize; + int num_erase_region; + + printk(KERN_NOTICE "Concatenating MTD devices:\n"); + for(i = 0; i < num_devs; i++) + printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name); + printk(KERN_NOTICE "into device \"%s\"\n", name); + + /* allocate the device structure */ + size = SIZEOF_STRUCT_MTD_CONCAT(num_devs); + concat = kmalloc (size, GFP_KERNEL); + if(!concat) + { + printk ("memory allocation error while creating concatenated device \"%s\"\n", + name); + return NULL; + } + memset(concat, 0, size); + concat->subdev = (struct mtd_info **)(concat + 1); + + /* + * Set up the new "super" device's MTD object structure, check for + * incompatibilites between the subdevices. + */ + concat->mtd.type = subdev[0]->type; + concat->mtd.flags = subdev[0]->flags; + concat->mtd.size = subdev[0]->size; + concat->mtd.erasesize = subdev[0]->erasesize; + concat->mtd.oobblock = subdev[0]->oobblock; + concat->mtd.oobsize = subdev[0]->oobsize; + concat->mtd.ecctype = subdev[0]->ecctype; + concat->mtd.eccsize = subdev[0]->eccsize; + + concat->subdev[0] = subdev[0]; + + for(i = 1; i < num_devs; i++) + { + if(concat->mtd.type != subdev[i]->type) + { + kfree(concat); + printk ("Incompatible device type on \"%s\"\n", subdev[i]->name); + return NULL; + } + if(concat->mtd.flags != subdev[i]->flags) + { /* + * Expect all flags except MTD_WRITEABLE to be equal on + * all subdevices. + */ + if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE) + { + kfree(concat); + printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name); + return NULL; + } + else /* if writeable attribute differs, make super device writeable */ + concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE; + } + concat->mtd.size += subdev[i]->size; + if(concat->mtd.oobblock != subdev[i]->oobblock || + concat->mtd.oobsize != subdev[i]->oobsize || + concat->mtd.ecctype != subdev[i]->ecctype || + concat->mtd.eccsize != subdev[i]->eccsize) + { + kfree(concat); + printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); + return NULL; + } + concat->subdev[i] = subdev[i]; + + } + + concat->num_subdev = num_devs; + concat->mtd.name = name; + + /* + * NOTE: for now, we do not provide any readv()/writev() methods + * because they are messy to implement and they are not + * used to a great extent anyway. + */ + concat->mtd.erase = concat_erase; + concat->mtd.read = concat_read; + concat->mtd.write = concat_write; + concat->mtd.sync = concat_sync; + concat->mtd.lock = concat_lock; + concat->mtd.unlock = concat_unlock; + concat->mtd.suspend = concat_suspend; + concat->mtd.resume = concat_resume; + + + /* + * Combine the erase block size info of the subdevices: + * + * first, walk the map of the new device and see how + * many changes in erase size we have + */ + max_erasesize = curr_erasesize = subdev[0]->erasesize; + num_erase_region = 1; + for(i = 0; i < num_devs; i++) + { + if(subdev[i]->numeraseregions == 0) + { /* current subdevice has uniform erase size */ + if(subdev[i]->erasesize != curr_erasesize) + { /* if it differs from the last subdevice's erase size, count it */ + ++num_erase_region; + curr_erasesize = subdev[i]->erasesize; + if(curr_erasesize > max_erasesize) + max_erasesize = curr_erasesize; + } + } + else + { /* current subdevice has variable erase size */ + int j; + for(j = 0; j < subdev[i]->numeraseregions; j++) + { /* walk the list of erase regions, count any changes */ + if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) + { + ++num_erase_region; + curr_erasesize = subdev[i]->eraseregions[j].erasesize; + if(curr_erasesize > max_erasesize) + max_erasesize = curr_erasesize; + } + } + } + } + + if(num_erase_region == 1) + { /* + * All subdevices have the same uniform erase size. + * This is easy: + */ + concat->mtd.erasesize = curr_erasesize; + concat->mtd.numeraseregions = 0; + } + else + { /* + * erase block size varies across the subdevices: allocate + * space to store the data describing the variable erase regions + */ + struct mtd_erase_region_info *erase_region_p; + u_int32_t begin, position; + + concat->mtd.erasesize = max_erasesize; + concat->mtd.numeraseregions = num_erase_region; + concat->mtd.eraseregions = erase_region_p = kmalloc ( + num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL); + if(!erase_region_p) + { + kfree(concat); + printk ("memory allocation error while creating erase region list" + " for device \"%s\"\n", name); + return NULL; + } + + /* + * walk the map of the new device once more and fill in + * in erase region info: + */ + curr_erasesize = subdev[0]->erasesize; + begin = position = 0; + for(i = 0; i < num_devs; i++) + { + if(subdev[i]->numeraseregions == 0) + { /* current subdevice has uniform erase size */ + if(subdev[i]->erasesize != curr_erasesize) + { /* + * fill in an mtd_erase_region_info structure for the area + * we have walked so far: + */ + erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + erase_region_p->numblocks = (position - begin) / curr_erasesize; + begin = position; + + curr_erasesize = subdev[i]->erasesize; + ++erase_region_p; + } + position += subdev[i]->size; + } + else + { /* current subdevice has variable erase size */ + int j; + for(j = 0; j < subdev[i]->numeraseregions; j++) + { /* walk the list of erase regions, count any changes */ + if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) + { + erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + erase_region_p->numblocks = (position - begin) / curr_erasesize; + begin = position; + + curr_erasesize = subdev[i]->eraseregions[j].erasesize; + ++erase_region_p; + } + position += subdev[i]->eraseregions[j].numblocks * curr_erasesize; + } + } + } + /* Now write the final entry */ + erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + erase_region_p->numblocks = (position - begin) / curr_erasesize; + } + + return &concat->mtd; +} + +/* + * This function destroys an MTD object obtained from concat_mtd_devs() + */ + +void mtd_concat_destroy(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + if(concat->mtd.numeraseregions) + kfree(concat->mtd.eraseregions); + kfree(concat); +} + + +EXPORT_SYMBOL(mtd_concat_create); +EXPORT_SYMBOL(mtd_concat_destroy); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Kaiser "); +MODULE_DESCRIPTION("Generic support for concatenating of MTD devices"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/mtdcore.c linux-2.5/drivers/mtd/mtdcore.c --- linux-2.5.20/drivers/mtd/mtdcore.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/mtd/mtdcore.c Sat Apr 13 17:42:55 2002 @@ -1,5 +1,5 @@ /* - * $Id: mtdcore.c,v 1.31 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdcore.c,v 1.32 2002/03/07 18:38:10 joern Exp $ * * Core registration and callback routines for MTD * drivers and users. @@ -296,7 +296,7 @@ up(&mtd_table_mutex); if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/mtdpart.c linux-2.5/drivers/mtd/mtdpart.c --- linux-2.5.20/drivers/mtd/mtdpart.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/mtd/mtdpart.c Sat Apr 13 17:42:55 2002 @@ -5,8 +5,12 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.23 2001/10/02 15:05:11 dwmw2 Exp $ - */ + * $Id: mtdpart.c,v 1.27 2002/03/08 16:34:35 rkaiser Exp $ + * - with protection register access removed until that code is merged in 2.4. + * + * 02-21-2002 Thomas Gleixner + * added support for read_oob, write_oob + */ #include #include @@ -28,6 +32,7 @@ u_int32_t offset; int index; struct list_head list; + int registered; }; /* @@ -54,6 +59,18 @@ len, retlen, buf); } +static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + if (from >= mtd->size) + len = 0; + else if (from + len > mtd->size) + len = mtd->size - from; + return part->master->read_oob (part->master, from + part->offset, + len, retlen, buf); +} + static int part_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { @@ -68,6 +85,20 @@ len, retlen, buf); } +static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_part *part = PART(mtd); + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (to >= mtd->size) + len = 0; + else if (to + len > mtd->size) + len = mtd->size - to; + return part->master->write_oob (part->master, to + part->offset, + len, retlen, buf); +} + static int part_writev (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen) { @@ -148,7 +179,8 @@ if (slave->master == master) { struct list_head *prev = node->prev; __list_del(prev, node->next); - del_mtd_device(&slave->mtd); + if(slave->registered) + del_mtd_device(&slave->mtd); kfree(slave); node = prev; } @@ -198,18 +230,21 @@ slave->mtd.name = parts[i].name; slave->mtd.bank_size = master->bank_size; - slave->mtd.module = master->module; slave->mtd.read = part_read; slave->mtd.write = part_write; + + if (master->read_oob) + slave->mtd.read_oob = part_read_oob; + if (master->write_oob) + slave->mtd.write_oob = part_write_oob; if (master->sync) slave->mtd.sync = part_sync; if (!i && master->suspend && master->resume) { slave->mtd.suspend = part_suspend; slave->mtd.resume = part_resume; } - if (master->writev) slave->mtd.writev = part_writev; if (master->readv) @@ -225,6 +260,15 @@ if (slave->offset == MTDPART_OFS_APPEND) slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { + u_int32_t emask = master->erasesize-1; + slave->offset = (cur_offset + emask) & ~emask; + if (slave->offset != cur_offset) { + printk(KERN_NOTICE "Moving partition %d: " + "0x%08x -> 0x%08x\n", i, + cur_offset, slave->offset); + } + } if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; cur_offset = slave->offset + slave->mtd.size; @@ -279,8 +323,17 @@ parts[i].name); } - /* register our partition */ - add_mtd_device(&slave->mtd); + if(parts[i].mtdp) + { /* store the object pointer (caller may or may not register it */ + *parts[i].mtdp = &slave->mtd; + slave->registered = 0; + } + else + { + /* register our partition */ + add_mtd_device(&slave->mtd); + slave->registered = 1; + } } return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/nand/nand_ecc.c linux-2.5/drivers/mtd/nand/nand_ecc.c --- linux-2.5.20/drivers/mtd/nand/nand_ecc.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/mtd/nand/nand_ecc.c Sat Apr 13 17:42:56 2002 @@ -4,7 +4,7 @@ * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) * Toshiba America Electronics Components, Inc. * - * $Id: nand_ecc.c,v 1.6 2001/06/28 10:52:26 dwmw2 Exp $ + * $Id: nand_ecc.c,v 1.7 2002/03/21 14:13:50 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -209,3 +209,5 @@ EXPORT_SYMBOL(nand_correct_data); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Steven J. Hill "); +MODULE_DESCRIPTION("Generic NAND ECC support"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/mtd/nftlcore.c linux-2.5/drivers/mtd/nftlcore.c --- linux-2.5.20/drivers/mtd/nftlcore.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/mtd/nftlcore.c Mon Jun 3 17:10:22 2002 @@ -1,7 +1,7 @@ /* Linux driver for NAND Flash Translation Layer */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse */ -/* $Id: nftlcore.c,v 1.82 2001/10/02 15:05:11 dwmw2 Exp $ */ +/* $Id: nftlcore.c,v 1.85 2001/11/20 11:42:33 dwmw2 Exp $ */ /* The contents of this file are distributed under the GNU General @@ -65,6 +65,14 @@ sizes: nftl_sizes, /* block sizes */ }; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) +#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT +#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define BLK_INC_USE_COUNT do {} while(0) +#define BLK_DEC_USE_COUNT do {} while(0) +#endif + struct NFTLrecord *NFTLs[MAX_NFTLS]; static void NFTL_setup(struct mtd_info *mtd) @@ -958,8 +966,11 @@ #endif /* !CONFIG_NFTL_RW */ thisNFTL->usecount++; - if (!get_mtd_device(thisNFTL->mtd, -1)) - return /* -E'SBUGGEREDOFF */ -ENXIO; + BLK_INC_USE_COUNT; + if (!get_mtd_device(thisNFTL->mtd, -1)) { + BLK_DEC_USE_COUNT; + return -ENXIO; + } return 0; } @@ -972,11 +983,10 @@ DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); - invalidate_device(inode->i_rdev, 1); - if (thisNFTL->mtd->sync) thisNFTL->mtd->sync(thisNFTL->mtd); thisNFTL->usecount--; + BLK_DEC_USE_COUNT; put_mtd_device(thisNFTL->mtd); @@ -994,7 +1004,9 @@ #else static struct block_device_operations nftl_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) owner: THIS_MODULE, +#endif open: nftl_open, release: nftl_release, ioctl: nftl_ioctl @@ -1021,7 +1033,7 @@ { #ifdef PRERELEASE - printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.82 $, nftlmount.c %s\n", nftlmountrev); + printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.85 $, nftlmount.c %s\n", nftlmountrev); #endif if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/3c509.c linux-2.5/drivers/net/3c509.c --- linux-2.5.20/drivers/net/3c509.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/net/3c509.c Sat May 11 21:34:27 2002 @@ -47,8 +47,8 @@ - ethtool support v1.18b 1Mar2002 Zwane Mwaikambo - Power Management support - v1.18c 1Mar2002 David Ruggiero - - Full duplex support + v1.18c 1Mar2002 David Ruggiero + - Full duplex support */ #define DRV_NAME "3c509" @@ -142,9 +142,9 @@ #define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */ #define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */ -#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ -#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */ -#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */ +#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ +#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */ +#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */ /* * Must be a power of two (we use a binary and in the @@ -504,10 +504,10 @@ memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); dev->base_addr = ioaddr; dev->irq = irq; - + if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */ dev->if_port = (dev->mem_start & 0x0f); - } else { /* xcvr codes 0/8 */ + } else { /* xcvr codes 0/8 */ /* use eeprom value, but save user's full-duplex selection */ dev->if_port = (if_port | (dev->mem_start & 0x08) ); } @@ -1110,10 +1110,10 @@ if ((dev->if_port & 0x03) == 3) /* BNC interface */ /* Start the thinnet transceiver. We should really wait 50ms...*/ - outw(StartCoax, ioaddr + EL3_CMD); + outw(StartCoax, ioaddr + EL3_CMD); else if ((dev->if_port & 0x03) == 0) { /* 10baseT interface */ /* Combine secondary sw_info word (the adapter level) and primary - sw_info word (duplex setting plus other useless bits) */ + sw_info word (duplex setting plus other useless bits) */ EL3WINDOW(0); sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) | (read_eeprom(ioaddr, 0x0d) & 0xBff0); @@ -1148,7 +1148,7 @@ /* Enable link beat and jabber check. */ outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); } - + /* Switch to the stats window, and clear all stats by reading. */ outw(StatsDisable, ioaddr + EL3_CMD); EL3WINDOW(6); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/82596.c linux-2.5/drivers/net/82596.c --- linux-2.5.20/drivers/net/82596.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/net/82596.c Fri May 3 03:49:06 2002 @@ -64,7 +64,7 @@ #include static char version[] __initdata = - "82596.c $Revision: 1.4 $\n"; + "82596.c $Revision: 1.5 $\n"; /* DEBUG flags */ @@ -421,7 +421,7 @@ while (--delcnt && lp->iscp.stat) udelay(10); if (!delcnt) { - printk("%s: %s, status %4.4x, cmd %4.4x.\n", + printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n", dev->name, str, lp->scb.status, lp->scb.command); return -1; } @@ -435,7 +435,7 @@ while (--delcnt && lp->scb.command) udelay(10); if (!delcnt) { - printk("%s: %s, status %4.4x, cmd %4.4x.\n", + printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n", dev->name, str, lp->scb.status, lp->scb.command); return -1; } @@ -444,6 +444,21 @@ } +static inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int delcnt, char *str) +{ + volatile struct i596_cmd *c = cmd; + + while (--delcnt && c->command) + udelay(10); + if (!delcnt) { + printk(KERN_ERR "%s: %s.\n", dev->name, str); + return -1; + } + else + return 0; +} + + static void i596_display_data(struct net_device *dev) { struct i596_private *lp = (struct i596_private *) dev->priv; @@ -451,37 +466,37 @@ struct i596_rfd *rfd; struct i596_rbd *rbd; - printk("lp and scp at %p, .sysbus = %08lx, .iscp = %p\n", + printk(KERN_ERR "lp and scp at %p, .sysbus = %08lx, .iscp = %p\n", &lp->scp, lp->scp.sysbus, lp->scp.iscp); - printk("iscp at %p, iscp.stat = %08lx, .scb = %p\n", + printk(KERN_ERR "iscp at %p, iscp.stat = %08lx, .scb = %p\n", &lp->iscp, lp->iscp.stat, lp->iscp.scb); - printk("scb at %p, scb.status = %04x, .command = %04x," + printk(KERN_ERR "scb at %p, scb.status = %04x, .command = %04x," " .cmd = %p, .rfd = %p\n", &lp->scb, lp->scb.status, lp->scb.command, lp->scb.cmd, lp->scb.rfd); - printk(" errors: crc %lx, align %lx, resource %lx," + printk(KERN_ERR " errors: crc %lx, align %lx, resource %lx," " over %lx, rcvdt %lx, short %lx\n", lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err, lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err); cmd = lp->cmd_head; while (cmd != I596_NULL) { - printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n", + printk(KERN_ERR "cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n", cmd, cmd->status, cmd->command, cmd->b_next); cmd = cmd->v_next; } rfd = lp->rfd_head; - printk("rfd_head = %p\n", rfd); + printk(KERN_ERR "rfd_head = %p\n", rfd); do { - printk (" %p .stat %04x, .cmd %04x, b_next %p, rbd %p," + printk(KERN_ERR " %p .stat %04x, .cmd %04x, b_next %p, rbd %p," " count %04x\n", rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd, rfd->count); rfd = rfd->v_next; } while (rfd != lp->rfd_head); rbd = lp->rbd_head; - printk("rbd_head = %p\n", rbd); + printk(KERN_ERR "rbd_head = %p\n", rbd); do { - printk(" %p .count %04x, b_next %p, b_data %p, size %04x\n", + printk(KERN_ERR " %p .count %04x, b_next %p, b_data %p, size %04x\n", rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size); rbd = rbd->v_next; } while (rbd != lp->rbd_head); @@ -492,11 +507,23 @@ static void i596_error(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; +#ifdef ENABLE_MVME16x_NET + if (MACH_IS_MVME16x) { + volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; + + pcc2[0x28] = 1; + pcc2[0x2b] = 0x1d; + } +#endif +#ifdef ENABLE_BVME6000_NET + if (MACH_IS_BVME6000) { + volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG; - pcc2[0x28] = 1; - pcc2[0x2b] = 0x1d; - printk("%s: Error interrupt\n", dev->name); + *ethirq = 1; + *ethirq = 3; + } +#endif + printk(KERN_ERR "%s: Error interrupt\n", dev->name); i596_display_data(dev); } #endif @@ -660,7 +687,14 @@ lp->cmd_head = lp->scb.cmd = I596_NULL; - DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name)); +#ifdef ENABLE_BVME6000_NET + if (MACH_IS_BVME6000) { + lp->scb.t_on = 7 * 25; + lp->scb.t_off = 1 * 25; + } +#endif + + DEB(DEB_INIT,printk(KERN_DEBUG "%s: starting i82596.\n", dev->name)); #if defined(ENABLE_APRICOT) (void) inb(ioaddr + 0x10); @@ -670,7 +704,7 @@ if (wait_istat(dev,lp,1000,"initialization timed out")) goto failed; - DEB(DEB_INIT,printk("%s: i82596 initialization successful\n", dev->name)); + DEB(DEB_INIT,printk(KERN_DEBUG "%s: i82596 initialization successful\n", dev->name)); /* Ensure rx frame/buffer descriptors are tidy */ rebuild_rx_bufs(dev); @@ -694,17 +728,17 @@ #endif - DEB(DEB_INIT,printk("%s: queuing CmdConfigure\n", dev->name)); + DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdConfigure\n", dev->name)); memcpy(lp->cf_cmd.i596_config, init_setup, 14); lp->cf_cmd.cmd.command = CmdConfigure; i596_add_cmd(dev, &lp->cf_cmd.cmd); - DEB(DEB_INIT,printk("%s: queuing CmdSASetup\n", dev->name)); + DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name)); memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6); lp->sa_cmd.cmd.command = CmdSASetup; i596_add_cmd(dev, &lp->sa_cmd.cmd); - DEB(DEB_INIT,printk("%s: queuing CmdTDR\n", dev->name)); + DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name)); lp->tdr_cmd.cmd.command = CmdTDR; i596_add_cmd(dev, &lp->tdr_cmd.cmd); @@ -714,7 +748,7 @@ spin_unlock_irqrestore (&lp->lock, flags); goto failed; } - DEB(DEB_INIT,printk("%s: Issuing RX_START\n", dev->name)); + DEB(DEB_INIT,printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name)); lp->scb.command = RX_START; CA(dev); @@ -722,11 +756,11 @@ if (wait_cmd(dev,lp,1000,"RX_START not processed")) goto failed; - DEB(DEB_INIT,printk("%s: Receive unit started OK\n", dev->name)); + DEB(DEB_INIT,printk(KERN_DEBUG "%s: Receive unit started OK\n", dev->name)); return 0; failed: - printk("%s: Failed to initialise 82596\n", dev->name); + printk(KERN_CRIT "%s: Failed to initialise 82596\n", dev->name); MPU_PORT(dev, PORT_RESET, 0); return -1; } @@ -738,7 +772,7 @@ struct i596_rbd *rbd; int frames = 0; - DEB(DEB_RXFRAME,printk ("i596_rx(), rfd_head %p, rbd_head %p\n", + DEB(DEB_RXFRAME,printk(KERN_DEBUG "i596_rx(), rfd_head %p, rbd_head %p\n", lp->rfd_head, lp->rbd_head)); rfd = lp->rfd_head; /* Ref next frame to check */ @@ -749,11 +783,11 @@ else if (rfd->rbd == lp->rbd_head->b_addr) rbd = lp->rbd_head; else { - printk("%s: rbd chain broken!\n", dev->name); + printk(KERN_CRIT "%s: rbd chain broken!\n", dev->name); /* XXX Now what? */ rbd = I596_NULL; } - DEB(DEB_RXFRAME, printk(" rfd %p, rfd.rbd %p, rfd.stat %04x\n", + DEB(DEB_RXFRAME, printk(KERN_DEBUG " rfd %p, rfd.rbd %p, rfd.stat %04x\n", rfd, rfd->rbd, rfd->stat)); if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) { @@ -794,7 +828,7 @@ memory_squeeze: if (skb == NULL) { /* XXX tulip.c can defer packets here!! */ - printk ("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name); + printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; } else { @@ -817,7 +851,7 @@ } } else { - DEB(DEB_ERRORS, printk("%s: Error, rfd.stat = 0x%04x\n", + DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n", dev->name, rfd->stat)); lp->stats.rx_errors++; if ((rfd->stat) & 0x0001) @@ -861,7 +895,7 @@ rfd = lp->rfd_head; } - DEB(DEB_RXFRAME,printk ("frames %d\n", frames)); + DEB(DEB_RXFRAME,printk(KERN_DEBUG "frames %d\n", frames)); return 0; } @@ -904,7 +938,7 @@ { unsigned long flags; - DEB(DEB_RESET,printk("i596_reset\n")); + DEB(DEB_RESET,printk(KERN_DEBUG "i596_reset\n")); spin_lock_irqsave (&lp->lock, flags); @@ -932,7 +966,7 @@ int ioaddr = dev->base_addr; unsigned long flags; - DEB(DEB_ADDCMD,printk("i596_add_cmd\n")); + DEB(DEB_ADDCMD,printk(KERN_DEBUG "i596_add_cmd\n")); cmd->status = 0; cmd->command |= (CMD_EOL | CMD_INTR); @@ -961,7 +995,7 @@ if (tickssofar < ticks_limit) return; - printk("%s: command unit timed out, status resetting.\n", dev->name); + printk(KERN_NOTICE "%s: command unit timed out, status resetting.\n", dev->name); i596_reset(dev, lp, ioaddr); } @@ -971,10 +1005,10 @@ { int res = 0; - DEB(DEB_OPEN,printk("%s: i596_open() irq %d.\n", dev->name, dev->irq)); + DEB(DEB_OPEN,printk(KERN_DEBUG "%s: i596_open() irq %d.\n", dev->name, dev->irq)); if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) { - printk("%s: IRQ %d not free\n", dev->name, dev->irq); + printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq); return -EAGAIN; } #ifdef ENABLE_MVME16x_NET @@ -1004,19 +1038,19 @@ int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ - DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n", + DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n", dev->name)); lp->stats.tx_errors++; /* Try to restart the adaptor */ if (lp->last_restart == lp->stats.tx_packets) { - DEB(DEB_ERRORS,printk ("Resetting board.\n")); + DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n")); /* Shutdown and restart */ i596_reset (dev, lp, ioaddr); } else { /* Issue a channel attention signal */ - DEB(DEB_ERRORS,printk ("Kicking board.\n")); + DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n")); lp->scb.command = CUC_START | RX_START; CA (dev); lp->last_restart = lp->stats.tx_packets; @@ -1035,7 +1069,7 @@ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; dev->trans_start = jiffies; - DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name, + DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%x) called\n", dev->name, skb->len, (unsigned int)skb->data)); netif_stop_queue(dev); @@ -1044,8 +1078,8 @@ tbd = lp->tbds + lp->next_tx_cmd; if (tx_cmd->cmd.command) { - DEB(DEB_ERRORS,printk ("%s: xmit ring full, dropping packet.\n", - dev->name)); + printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n", + dev->name); lp->stats.tx_dropped++; dev_kfree_skb(skb); @@ -1084,7 +1118,7 @@ { int i; - printk("i596 0x%p, ", add); + printk(KERN_DEBUG "i596 0x%p, ", add); for (i = 0; i < 6; i++) printk(" %02X", add[i + 6]); printk(" -->"); @@ -1106,7 +1140,7 @@ #ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) { if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) { - printk("Ethernet probe disabled - chip not present\n"); + printk(KERN_NOTICE "Ethernet probe disabled - chip not present\n"); return -ENODEV; } memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */ @@ -1137,7 +1171,7 @@ /* first check nothing is already registered here */ if (!request_region(ioaddr, I596_TOTAL_SIZE, dev->name)) { - printk("82596: IO address 0x%04x in use\n", ioaddr); + printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr); return -EBUSY; } @@ -1171,14 +1205,14 @@ } ether_setup(dev); - DEB(DEB_PROBE,printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr)); + DEB(DEB_PROBE,printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr)); for (i = 0; i < 6; i++) DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i])); DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq)); - DEB(DEB_PROBE,printk(version)); + DEB(DEB_PROBE,printk(KERN_INFO "%s", version)); /* The 82596-specific entries in the device structure. */ dev->open = i596_open; @@ -1192,7 +1226,7 @@ dev->priv = (void *)(dev->mem_start); lp = (struct i596_private *) dev->priv; - DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n", + DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n", dev->name, (unsigned long)lp, sizeof(struct i596_private), (unsigned long)&lp->scb)); memset((void *) lp, 0, sizeof(struct i596_private)); @@ -1220,13 +1254,13 @@ #ifdef ENABLE_BVME6000_NET if (MACH_IS_BVME6000) { if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) { - i596_error(BVME_IRQ_I596, NULL, NULL); + i596_error(irq, dev_id, regs); return; } } #endif if (dev == NULL) { - printk("i596_interrupt(): irq %d for unknown device.\n", irq); + printk(KERN_ERR "i596_interrupt(): irq %d for unknown device.\n", irq); return; } @@ -1238,7 +1272,7 @@ wait_cmd(dev,lp,100,"i596 interrupt, timeout"); status = lp->scb.status; - DEB(DEB_INTS,printk("%s: i596 interrupt, IRQ %d, status %4.4x.\n", + DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt, IRQ %d, status %4.4x.\n", dev->name, irq, status)); ack_cmd = status & 0xf000; @@ -1247,14 +1281,14 @@ struct i596_cmd *ptr; if ((status & 0x8000)) - DEB(DEB_INTS,printk("%s: i596 interrupt completed command.\n", dev->name)); + DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt completed command.\n", dev->name)); if ((status & 0x2000)) - DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700)); + DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700)); while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) { ptr = lp->cmd_head; - DEB(DEB_STATUS,printk("cmd_head->status = %04x, ->command = %04x\n", + DEB(DEB_STATUS,printk(KERN_DEBUG "cmd_head->status = %04x, ->command = %04x\n", lp->cmd_head->status, lp->cmd_head->command)); lp->cmd_head = ptr->v_next; lp->cmd_backlog--; @@ -1291,20 +1325,21 @@ unsigned short status = ((struct tdr_cmd *)ptr)->status; if (status & 0x8000) { - DEB(DEB_ANY,printk("%s: link ok.\n", dev->name)); + DEB(DEB_TDR,printk(KERN_INFO "%s: link ok.\n", dev->name)); } else { if (status & 0x4000) - printk("%s: Transceiver problem.\n", dev->name); + printk(KERN_ERR "%s: Transceiver problem.\n", dev->name); if (status & 0x2000) - printk("%s: Termination problem.\n", dev->name); + printk(KERN_ERR "%s: Termination problem.\n", dev->name); if (status & 0x1000) - printk("%s: Short circuit.\n", dev->name); + printk(KERN_ERR "%s: Short circuit.\n", dev->name); - DEB(DEB_TDR,printk("%s: Time %d.\n", dev->name, status & 0x07ff)); + DEB(DEB_TDR,printk(KERN_INFO "%s: Time %d.\n", dev->name, status & 0x07ff)); } break; } case CmdConfigure: + case CmdMulticastList: /* Zap command so set_multicast_list() knows it is free */ ptr->command = 0; break; @@ -1325,12 +1360,12 @@ } if ((status & 0x1000) || (status & 0x4000)) { if ((status & 0x4000)) - DEB(DEB_INTS,printk("%s: i596 interrupt received a frame.\n", dev->name)); + DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt received a frame.\n", dev->name)); i596_rx(dev); /* Only RX_START if stopped - RGH 07-07-96 */ if (status & 0x1000) { if (netif_running(dev)) { - DEB(DEB_ERRORS,printk("%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status)); + DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status)); ack_cmd |= RX_START; lp->stats.rx_errors++; lp->stats.rx_fifo_errors++; @@ -1364,7 +1399,7 @@ #endif CA(dev); - DEB(DEB_INTS,printk("%s: exiting interrupt.\n", dev->name)); + DEB(DEB_INTS,printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name)); spin_unlock (&lp->lock); return; @@ -1377,7 +1412,7 @@ netif_stop_queue(dev); - DEB(DEB_INIT,printk("%s: Shutting down ethercard, status was %4.4x.\n", + DEB(DEB_INIT,printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", dev->name, lp->scb.status)); save_flags(flags); @@ -1434,7 +1469,13 @@ struct i596_private *lp = (struct i596_private *) dev->priv; int config = 0, cnt; - DEB(DEB_MULTI,printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF")); + DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n", + dev->name, dev->mc_count, + dev->flags & IFF_PROMISC ? "ON" : "OFF", + dev->flags & IFF_ALLMULTI ? "ON" : "OFF")); + + if (wait_cfg(dev, &lp->cf_cmd.cmd, 1000, "config change request timed out")) + return; if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) { lp->cf_cmd.i596_config[8] |= 0x01; @@ -1453,20 +1494,15 @@ config = 1; } if (config) { - if (lp->cf_cmd.cmd.command) - printk("%s: config change request already queued\n", - dev->name); - else { - lp->cf_cmd.cmd.command = CmdConfigure; - i596_add_cmd(dev, &lp->cf_cmd.cmd); - } + lp->cf_cmd.cmd.command = CmdConfigure; + i596_add_cmd(dev, &lp->cf_cmd.cmd); } cnt = dev->mc_count; if (cnt > MAX_MC_CNT) { cnt = MAX_MC_CNT; - printk("%s: Only %d multicast addresses supported", + printk(KERN_ERR "%s: Only %d multicast addresses supported", dev->name, cnt); } @@ -1475,6 +1511,8 @@ unsigned char *cp; struct mc_cmd *cmd; + if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out")) + return; cmd = &lp->mc_cmd; cmd->cmd.command = CmdMulticastList; cmd->mc_cnt = dev->mc_count * 6; @@ -1482,7 +1520,7 @@ for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) { memcpy(cp, dmi->dmi_addr, 6); if (i596_debug > 1) - DEB(DEB_MULTI,printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", + DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5])); } i596_add_cmd(dev, &cmd->cmd); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/8390.h linux-2.5/drivers/net/8390.h --- linux-2.5.20/drivers/net/8390.h Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/net/8390.h Fri May 3 12:57:30 2002 @@ -106,13 +106,24 @@ /* * Only generate indirect loads given a machine that needs them. + * - removed AMIGA_PCMCIA from this list, handled as ISA io now */ -#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \ +#if defined(CONFIG_MAC) || \ defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \ defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE) || \ defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE) #define EI_SHIFT(x) (ei_local->reg_offset[x]) +#undef inb +#undef inb_p +#undef outb +#undef outb_p + +#define inb(port) in_8(port) +#define outb(val,port) out_8(port,val) +#define inb_p(port) in_8(port) +#define outb_p(val,port) out_8(port,val) + #else #define EI_SHIFT(x) (x) #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/Config.help linux-2.5/drivers/net/Config.help --- linux-2.5.20/drivers/net/Config.help Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/net/Config.help Mon Jun 3 17:10:22 2002 @@ -880,6 +880,10 @@ If you have an Alchemy Semi AU1000 ethernet controller on an SGI MIPS system, say Y. Otherwise, say N. +CONFIG_MIPS_AU1000_ENET + If you have an Alchemy Semi AU1000 ethernet controller + on an SGI MIPS system, say Y. Otherwise, say N. + CONFIG_SGI_IOC3_ETH If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -1441,6 +1445,11 @@ Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet cards. Specifications and data at . + +CONFIG_LP486E + Say Y here to support the 82596-based on-board Ethernet controller + for the Panther motherboard, which is one of the two shipped in the + Intel Professional Workstation. CONFIG_LP486E Say Y here to support the 82596-based on-board Ethernet controller diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/Config.in linux-2.5/drivers/net/Config.in --- linux-2.5.20/drivers/net/Config.in Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/net/Config.in Fri May 3 03:49:06 2002 @@ -36,7 +36,11 @@ bool ' Use AAUI port instead of TP by default' CONFIG_MACE_AAUI_PORT fi dep_tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC $CONFIG_ALL_PPC - tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET + if [ "$CONFIG_4xx" = "y" ]; then + if [ "$CONFIG_STB03xxx" = "y" -o "$CONFIG_403GCX" = "y" ]; then + tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET + fi + fi fi if [ "$CONFIG_ZORRO" = "y" ]; then tristate ' Ariadne support' CONFIG_ARIADNE @@ -205,10 +209,13 @@ fi if [ "$CONFIG_DECSTATION" = "y" ]; then bool ' DEC LANCE ethernet controller support' CONFIG_DECLANCE - fi + fi if [ "$CONFIG_BAGET_MIPS" = "y" ]; then tristate ' Baget AMD LANCE support' CONFIG_BAGETLANCE fi + if [ "$CONFIG_NEC_OSPREY" = "y" ]; then + tristate ' Memory-mapped onboard NE2000-compatible ethernet' CONFIG_NE2000 + fi fi endmenu @@ -273,7 +280,7 @@ dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP fi if [ ! "$CONFIG_ATM" = "n" ]; then - dep_tristate ' PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP + dep_tristate ' PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP $CONFIG_EXPERIMENTAL fi fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/Space.c linux-2.5/drivers/net/Space.c --- linux-2.5.20/drivers/net/Space.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/net/Space.c Fri May 3 03:49:06 2002 @@ -99,7 +99,7 @@ extern int mvme147lance_probe(struct net_device *dev); extern int tc515_probe(struct net_device *dev); extern int lance_probe(struct net_device *dev); -extern int mace68k_probe(struct net_device *dev); +extern int mace_probe(struct net_device *dev); extern int macsonic_probe(struct net_device *dev); extern int mac8390_probe(struct net_device *dev); extern int mac89x0_probe(struct net_device *dev); @@ -354,7 +354,7 @@ {mvme147lance_probe, 0}, #endif #ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */ - {mace68k_probe, 0}, + {mace_probe, 0}, #endif #ifdef CONFIG_MACSONIC /* Mac SONIC-based Ethernet of all sorts */ {macsonic_probe, 0}, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/a2065.c linux-2.5/drivers/net/a2065.c --- linux-2.5.20/drivers/net/a2065.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/net/a2065.c Fri May 3 03:49:06 2002 @@ -639,7 +639,7 @@ volatile u16 *mcast_table = (u16 *)&ib->filter; struct dev_mc_list *dmi=dev->mc_list; char *addrs; - int i, j, bit, byte; + int i; u32 crc; /* set all multicast bits */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/acenic.c linux-2.5/drivers/net/acenic.c --- linux-2.5.20/drivers/net/acenic.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/net/acenic.c Fri May 17 01:33:49 2002 @@ -120,6 +120,10 @@ #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX #define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a #endif +#ifndef PCI_DEVICE_ID_FARALLON_PN9100T +#define PCI_DEVICE_ID_FARALLON_PN9100T 0xfa +#endif + #ifndef PCI_VENDOR_ID_SGI #define PCI_VENDOR_ID_SGI 0x10a9 #endif @@ -144,6 +148,9 @@ */ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_FARALLON_PN9100T, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { } @@ -173,12 +180,12 @@ #endif #ifndef SET_MODULE_OWNER -#define SET_MODULE_OWNER(dev) {do{} while(0);} +#define SET_MODULE_OWNER(dev) do { } while(0) #define ACE_MOD_INC_USE_COUNT MOD_INC_USE_COUNT #define ACE_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT #else -#define ACE_MOD_INC_USE_COUNT {do{} while(0);} -#define ACE_MOD_DEC_USE_COUNT {do{} while(0);} +#define ACE_MOD_INC_USE_COUNT do { } while(0) +#define ACE_MOD_DEC_USE_COUNT do { } while(0) #endif @@ -259,7 +266,7 @@ #define dev_kfree_skb_irq(a) dev_kfree_skb(a) #define netif_wake_queue(dev) clear_bit(0, &dev->tbusy) #define netif_stop_queue(dev) set_bit(0, &dev->tbusy) -#define late_stop_netif_stop_queue(dev) {do{} while(0);} +#define late_stop_netif_stop_queue(dev) do { } while(0) #define early_stop_netif_stop_queue(dev) test_and_set_bit(0,&dev->tbusy) #define early_stop_netif_wake_queue(dev) netif_wake_queue(dev) @@ -273,7 +280,7 @@ #define ace_mark_net_bh() mark_bh(NET_BH) #define netif_queue_stopped(dev) dev->tbusy #define netif_running(dev) dev->start -#define ace_if_down(dev) {do{dev->start = 0;} while(0);} +#define ace_if_down(dev) do { dev->start = 0; } while(0) #define tasklet_struct tq_struct static inline void tasklet_schedule(struct tasklet_struct *tasklet) @@ -291,13 +298,13 @@ tasklet->routine = (void (*)(void *))func; tasklet->data = (void *)data; } -#define tasklet_kill(tasklet) {do{} while(0);} +#define tasklet_kill(tasklet) do { } while(0) #else #define late_stop_netif_stop_queue(dev) netif_stop_queue(dev) #define early_stop_netif_stop_queue(dev) 0 -#define early_stop_netif_wake_queue(dev) {do{} while(0);} -#define ace_mark_net_bh() {do{} while(0);} -#define ace_if_down(dev) {do{} while(0);} +#define early_stop_netif_wake_queue(dev) do { } while(0) +#define ace_mark_net_bh() do { } while(0) +#define ace_if_down(dev) do { } while(0) #endif #if (LINUX_VERSION_CODE >= 0x02031b) @@ -313,7 +320,7 @@ #ifndef ARCH_HAS_PREFETCHW #ifndef prefetchw -#define prefetchw(x) {do{} while(0);} +#define prefetchw(x) do { } while(0) #endif #endif @@ -611,6 +618,8 @@ */ !((pdev->vendor == PCI_VENDOR_ID_DEC) && (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) && + !((pdev->vendor == PCI_VENDOR_ID_ALTEON) && + (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T)) && !((pdev->vendor == PCI_VENDOR_ID_SGI) && (pdev->device == PCI_DEVICE_ID_SGI_ACENIC))) continue; @@ -708,6 +717,13 @@ switch(pdev->vendor) { case PCI_VENDOR_ID_ALTEON: + if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) { + strncpy(ap->name, "Farallon PN9100-T " + "Gigabit Ethernet", sizeof (ap->name)); + printk(KERN_INFO "%s: Farallon PN9100-T ", + dev->name); + break; + } strncpy(ap->name, "AceNIC Gigabit Ethernet", sizeof (ap->name)); printk(KERN_INFO "%s: Alteon AceNIC ", dev->name); @@ -1355,7 +1371,7 @@ tmp &= ~DMA_READ_WRITE_MASK; tmp |= DMA_READ_MAX_128; /* - * All the docs sy MUST NOT. Well, I did. + * All the docs say MUST NOT. Well, I did. * Nothing terrible happens, if we load wrong size. * Bit w&i still works better! */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/appletalk/ltpc.c linux-2.5/drivers/net/appletalk/ltpc.c --- linux-2.5.20/drivers/net/appletalk/ltpc.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/net/appletalk/ltpc.c Fri May 17 02:05:47 2002 @@ -1063,26 +1063,39 @@ int autoirq; unsigned long flags; unsigned long f; + int portfound=0; SET_MODULE_OWNER(dev); save_flags(flags); /* probe for the I/O port address */ - if (io != 0x240 && !check_region(0x220,8)) { + if (io != 0x240 && request_region(0x220,8,"ltpc")) { x = inb_p(0x220+6); - if ( (x!=0xff) && (x>=0xf0) ) io = 0x220; + if ( (x!=0xff) && (x>=0xf0) ) { + io = 0x220; + portfound=1; + } + else { + release_region(0x220,8); + } } - if (io != 0x220 && !check_region(0x240,8)) { + if (io != 0x220 && request_region(0x240,8,"ltpc")) { y = inb_p(0x240+6); - if ( (y!=0xff) && (y>=0xf0) ) io = 0x240; + if ( (y!=0xff) && (y>=0xf0) ){ + io = 0x240; + portfound=1; + } + else { + release_region(0x240,8); + } } - if(io) { - /* found it, now grab it */ - request_region(io,8,"ltpc"); - } else { + if(io && !portfound && request_region(io,8,"ltpc")){ + portfound = 1; + } + if(!portfound) { /* give up in despair */ printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n", x,y); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/atarilance.c linux-2.5/drivers/net/atarilance.c --- linux-2.5.20/drivers/net/atarilance.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/net/atarilance.c Thu May 2 21:36:57 2002 @@ -546,8 +546,11 @@ if (lp->cardtype == PAM_CARD || memaddr == (unsigned short *)0xffe00000) { /* PAMs card and Riebl on ST use level 5 autovector */ - request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO, - "PAM/Riebl-ST Ethernet", dev); + if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO, + "PAM/Riebl-ST Ethernet", dev)) { + printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 ); + return( 0 ); + } dev->irq = (unsigned short)IRQ_AUTO_5; } else { @@ -560,8 +563,11 @@ printk( "Lance: request for VME interrupt failed\n" ); return( 0 ); } - request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, - "Riebl-VME Ethernet", dev); + if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, + "Riebl-VME Ethernet", dev)) { + printk( "Lance: request for irq %d failed\n", irq ); + return( 0 ); + } dev->irq = irq; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/bmac.c linux-2.5/drivers/net/bmac.c --- linux-2.5.20/drivers/net/bmac.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/net/bmac.c Sat May 25 19:52:03 2002 @@ -25,11 +25,11 @@ #include #include #include +#include #ifdef CONFIG_PMAC_PBOOK #include #include -#include -#endif +#endif /* CONFIG_PMAC_PBOOK */ #include "bmac.h" #define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1)))) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/bonding.c linux-2.5/drivers/net/bonding.c --- linux-2.5.20/drivers/net/bonding.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/net/bonding.c Sat Apr 13 17:42:56 2002 @@ -161,6 +161,16 @@ * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr * - Handle hot swap ethernet interface deregistration events to remove * kernel oops following hot swap of enslaved interface + * + * 2002/1/2 - Chad N. Tindel + * - Restore original slave flags at release time. + * + * 2002/02/18 - Erik Habbinga + * - bond_release(): calling kfree on our_slave after call to + * bond_restore_slave_flags, not before + * - bond_enslave(): saving slave flags into original_flags before + * call to netdev_set_master, so the IFF_SLAVE flag doesn't end + * up in original_flags */ #include @@ -208,11 +218,8 @@ #define MII_ENDOF_NWAY 0x20 #undef MII_LINK_READY -/*#define MII_LINK_READY (MII_LINK_UP | MII_ENDOF_NWAY)*/ #define MII_LINK_READY (MII_LINK_UP) -#define MAX_BOND_ADDR 256 - #ifndef BOND_LINK_ARP_INTERV #define BOND_LINK_ARP_INTERV 0 #endif @@ -223,7 +230,7 @@ static u32 my_ip = 0; char *arp_target_hw_addr = NULL; -static int max_bonds = MAX_BONDS; +static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int miimon = BOND_LINK_MON_INTERV; static int mode = BOND_MODE_ROUNDROBIN; static int updelay = 0; @@ -234,7 +241,7 @@ static struct bonding *these_bonds = NULL; static struct net_device *dev_bonds = NULL; -MODULE_PARM(max_bonds, "1-" __MODULE_STRING(INT_MAX) "i"); +MODULE_PARM(max_bonds, "i"); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); MODULE_PARM(miimon, "i"); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); @@ -260,6 +267,7 @@ static void bond_mii_monitor(struct net_device *dev); static void bond_arp_monitor(struct net_device *dev); static int bond_event(struct notifier_block *this, unsigned long event, void *ptr); +static void bond_restore_slave_flags(slave_t *slave); static void bond_set_slave_inactive_flags(slave_t *slave); static void bond_set_slave_active_flags(slave_t *slave); static int bond_enslave(struct net_device *master, struct net_device *slave); @@ -282,6 +290,11 @@ #define IS_UP(dev) ((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \ (netif_running(dev) && netif_carrier_ok(dev))) +static void bond_restore_slave_flags(slave_t *slave) +{ + slave->dev->flags = slave->original_flags; +} + static void bond_set_slave_inactive_flags(slave_t *slave) { slave->state = BOND_STATE_BACKUP; @@ -513,6 +526,8 @@ } memset(new_slave, 0, sizeof(slave_t)); + /* save flags before call to netdev_set_master */ + new_slave->original_flags = slave_dev->flags; err = netdev_set_master(slave_dev, master_dev); if (err) { @@ -838,7 +853,6 @@ } else { printk(".\n"); } - kfree(our_slave); /* release the slave from its bond */ @@ -854,6 +868,9 @@ dev_close(slave); } + bond_restore_slave_flags(our_slave); + kfree(our_slave); + if (bond->current_slave == NULL) { printk(KERN_INFO "%s: now running without any active interface !\n", @@ -2038,6 +2055,13 @@ /* Find a name for this unit */ static struct net_device *dev_bond = NULL; + if (max_bonds < 1 || max_bonds > INT_MAX) { + printk(KERN_WARNING + "bonding_init(): max_bonds (%d) not in range %d-%d, " + "so it was reset to BOND_DEFAULT_MAX_BONDS (%d)", + max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); + max_bonds = BOND_DEFAULT_MAX_BONDS; + } dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device), GFP_KERNEL); if (dev_bond == NULL) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/de600.c linux-2.5/drivers/net/de600.c --- linux-2.5.20/drivers/net/de600.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/net/de600.c Mon May 6 16:10:01 2002 @@ -683,14 +683,10 @@ return -ENODEV; } -#if 0 /* Not yet */ - if (check_region(DE600_IO, 3)) { - printk(", port 0x%x busy\n", DE600_IO); + if (!request_region(DE600_IO, 3, "de600")) { + printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO); return -EBUSY; } -#endif - request_region(DE600_IO, 3, "de600"); - printk(", Ethernet Address: %02X", dev->dev_addr[0]); for (i = 1; i < ETH_ALEN; i++) printk(":%02X",dev->dev_addr[i]); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/defxx.c linux-2.5/drivers/net/defxx.c --- linux-2.5.20/drivers/net/defxx.c Mon Jun 3 02:44:37 2002 +++ linux-2.5/drivers/net/defxx.c Mon Feb 18 22:59:43 2002 @@ -199,7 +199,10 @@ * Feb 2001 davej PCI enable cleanups. */ +#include // Kill me later. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif /* Include files */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/depca.c linux-2.5/drivers/net/depca.c --- linux-2.5.20/drivers/net/depca.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/net/depca.c Wed May 8 13:58:47 2002 @@ -339,16 +339,6 @@ #define MAX_NUM_DEPCAS 2 /* -** Memory Alignment. Each descriptor is 4 longwords long. To force a -** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and -** DESC_ALIGN. ALIGN aligns the start address of the private memory area -** and hence the RX descriptor ring's first entry. -*/ -#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */ -#define ALIGN8 ((u_long)8 - 1) /* 2 longword (quadword) align */ -#define ALIGN ALIGN8 /* Keep the LANCE happy... */ - -/* ** The DEPCA Rx and Tx ring descriptors. */ struct depca_rx_desc { @@ -641,7 +631,7 @@ offset += sizeof(struct depca_init); /* Tx & Rx descriptors (aligned to a quadword boundary) */ - offset = (offset + ALIGN) & ~ALIGN; + offset = ALIGN(offset, 8); lp->rx_ring = (struct depca_rx_desc *)(lp->sh_mem + offset); lp->rx_ring_offset = offset; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/eepro.c linux-2.5/drivers/net/eepro.c --- linux-2.5.20/drivers/net/eepro.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/net/eepro.c Sat May 4 11:45:54 2002 @@ -828,8 +828,10 @@ } /* Grab the region so we can find another board if autoIRQ fails. */ - request_region(ioaddr, EEPRO_IO_EXTENT, dev->name); - + if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { + printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", ioaddr); + goto freeall; + } ((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED; dev->open = eepro_open; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/hamradio/dmascc.c linux-2.5/drivers/net/hamradio/dmascc.c --- linux-2.5.20/drivers/net/hamradio/dmascc.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/net/hamradio/dmascc.c Mon Apr 15 03:45:47 2002 @@ -600,7 +600,10 @@ rtnl_unlock(); } - request_region(card_base, hw[type].io_size, "dmascc"); + if (!request_region(card_base, hw[type].io_size, "dmascc")) { + printk(KERN_WARNING "DMASCC: io-port 0x%04lx in use \n", card_base); + return(-EBUSY); + } info->next = first; first = info; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/hamradio/mkiss.c linux-2.5/drivers/net/hamradio/mkiss.c --- linux-2.5.20/drivers/net/hamradio/mkiss.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/net/hamradio/mkiss.c Fri May 3 03:49:06 2002 @@ -347,6 +347,7 @@ netif_rx(skb); tmp_ax->dev->last_rx = jiffies; tmp_ax->rx_packets++; + tmp_ax->rx_bytes+=count; } /* Encapsulate one AX.25 packet and stuff into a TTY queue. */ @@ -386,6 +387,7 @@ ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); actual = ax->tty->driver.write(ax->tty, 0, ax->xbuff, count); ax->tx_packets++; + ax->tx_bytes+=actual; ax->dev->trans_start = jiffies; ax->xleft = count - actual; ax->xhead = ax->xbuff + actual; @@ -394,6 +396,7 @@ ax->mkiss->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); actual = ax->mkiss->tty->driver.write(ax->mkiss->tty, 0, ax->mkiss->xbuff, count); ax->tx_packets++; + ax->tx_bytes+=actual; ax->mkiss->dev->trans_start = jiffies; ax->mkiss->xleft = count - actual; ax->mkiss->xhead = ax->mkiss->xbuff + actual; @@ -709,6 +712,8 @@ stats.rx_packets = ax->rx_packets; stats.tx_packets = ax->tx_packets; + stats.rx_bytes = ax->rx_bytes; + stats.tx_bytes = ax->tx_bytes; stats.rx_dropped = ax->rx_dropped; stats.tx_dropped = ax->tx_dropped; stats.tx_errors = ax->tx_errors; @@ -936,7 +941,7 @@ memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); /* New-style flags. */ - dev->flags = 0; + dev->flags = IFF_BROADCAST | IFF_MULTICAST; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/hamradio/mkiss.h linux-2.5/drivers/net/hamradio/mkiss.h --- linux-2.5.20/drivers/net/hamradio/mkiss.h Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/net/hamradio/mkiss.h Fri May 3 03:49:07 2002 @@ -31,6 +31,8 @@ /* SLIP interface statistics. */ unsigned long rx_packets; /* inbound frames counter */ unsigned long tx_packets; /* outbound frames counter */ + unsigned long rx_bytes; /* inbound bytes counter */ + unsigned long tx_bytes; /* outbound bytes counter */ unsigned long rx_errors; /* Parity, etc. errors */ unsigned long tx_errors; /* Planned stuff */ unsigned long rx_dropped; /* No memory for skb */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/i82586.h linux-2.5/drivers/net/i82586.h --- linux-2.5.20/drivers/net/i82586.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/i82586.h Tue Jan 22 17:43:48 2002 @@ -0,0 +1,413 @@ +/* + * Intel 82586 IEEE 802.3 Ethernet LAN Coprocessor. + * + * See: + * Intel Microcommunications 1991 + * p1-1 to p1-37 + * Intel order No. 231658 + * ISBN 1-55512-119-5 + * + * Unfortunately, the above chapter mentions neither + * the System Configuration Pointer (SCP) nor the + * Intermediate System Configuration Pointer (ISCP), + * so we probably need to look elsewhere for the + * whole story -- some recommend the "Intel LAN + * Components manual" but I have neither a copy + * nor a full reference. But "elsewhere" may be + * in the same publication... + * The description of a later device, the + * "82596CA High-Performance 32-Bit Local Area Network + * Coprocessor", (ibid. p1-38 to p1-109) does mention + * the SCP and ISCP and also has an i82586 compatibility + * mode. Even more useful is "AP-235 An 82586 Data Link + * Driver" (ibid. p1-337 to p1-417). + */ + +#define I82586_MEMZ (64 * 1024) + +#define I82586_SCP_ADDR (I82586_MEMZ - sizeof(scp_t)) + +#define ADDR_LEN 6 +#define I82586NULL 0xFFFF + +#define toff(t,p,f) (unsigned short)((void *)(&((t *)((void *)0 + (p)))->f) - (void *)0) + +/* + * System Configuration Pointer (SCP). + */ +typedef struct scp_t scp_t; +struct scp_t +{ + unsigned short scp_sysbus; /* 82586 bus width: */ +#define SCP_SY_16BBUS (0x0 << 0) /* 16 bits */ +#define SCP_SY_8BBUS (0x1 << 0) /* 8 bits. */ + unsigned short scp_junk[2]; /* Unused */ + unsigned short scp_iscpl; /* lower 16 bits of ISCP_ADDR */ + unsigned short scp_iscph; /* upper 16 bits of ISCP_ADDR */ +}; + +/* + * Intermediate System Configuration Pointer (ISCP). + */ +typedef struct iscp_t iscp_t; +struct iscp_t +{ + unsigned short iscp_busy; /* set by CPU before first CA, */ + /* cleared by 82586 after read. */ + unsigned short iscp_offset; /* offset of SCB */ + unsigned short iscp_basel; /* base of SCB */ + unsigned short iscp_baseh; /* " */ +}; + +/* + * System Control Block (SCB). + * The 82586 writes its status to scb_status and then + * raises an interrupt to alert the CPU. + * The CPU writes a command to scb_command and + * then issues a Channel Attention (CA) to alert the 82586. + */ +typedef struct scb_t scb_t; +struct scb_t +{ + unsigned short scb_status; /* Status of 82586 */ +#define SCB_ST_INT (0xF << 12) /* Some of: */ +#define SCB_ST_CX (0x1 << 15) /* Cmd completed */ +#define SCB_ST_FR (0x1 << 14) /* Frame received */ +#define SCB_ST_CNA (0x1 << 13) /* Cmd unit not active */ +#define SCB_ST_RNR (0x1 << 12) /* Rcv unit not ready */ +#define SCB_ST_JUNK0 (0x1 << 11) /* 0 */ +#define SCB_ST_CUS (0x7 << 8) /* Cmd unit status */ +#define SCB_ST_CUS_IDLE (0 << 8) /* Idle */ +#define SCB_ST_CUS_SUSP (1 << 8) /* Suspended */ +#define SCB_ST_CUS_ACTV (2 << 8) /* Active */ +#define SCB_ST_JUNK1 (0x1 << 7) /* 0 */ +#define SCB_ST_RUS (0x7 << 4) /* Rcv unit status */ +#define SCB_ST_RUS_IDLE (0 << 4) /* Idle */ +#define SCB_ST_RUS_SUSP (1 << 4) /* Suspended */ +#define SCB_ST_RUS_NRES (2 << 4) /* No resources */ +#define SCB_ST_RUS_RDY (4 << 4) /* Ready */ + unsigned short scb_command; /* Next command */ +#define SCB_CMD_ACK_CX (0x1 << 15) /* Ack cmd completion */ +#define SCB_CMD_ACK_FR (0x1 << 14) /* Ack frame received */ +#define SCB_CMD_ACK_CNA (0x1 << 13) /* Ack CU not active */ +#define SCB_CMD_ACK_RNR (0x1 << 12) /* Ack RU not ready */ +#define SCB_CMD_JUNKX (0x1 << 11) /* Unused */ +#define SCB_CMD_CUC (0x7 << 8) /* Command Unit command */ +#define SCB_CMD_CUC_NOP (0 << 8) /* Nop */ +#define SCB_CMD_CUC_GO (1 << 8) /* Start cbl_offset */ +#define SCB_CMD_CUC_RES (2 << 8) /* Resume execution */ +#define SCB_CMD_CUC_SUS (3 << 8) /* Suspend " */ +#define SCB_CMD_CUC_ABT (4 << 8) /* Abort " */ +#define SCB_CMD_RESET (0x1 << 7) /* Reset chip (hardware) */ +#define SCB_CMD_RUC (0x7 << 4) /* Receive Unit command */ +#define SCB_CMD_RUC_NOP (0 << 4) /* Nop */ +#define SCB_CMD_RUC_GO (1 << 4) /* Start rfa_offset */ +#define SCB_CMD_RUC_RES (2 << 4) /* Resume reception */ +#define SCB_CMD_RUC_SUS (3 << 4) /* Suspend " */ +#define SCB_CMD_RUC_ABT (4 << 4) /* Abort " */ + unsigned short scb_cbl_offset; /* Offset of first command unit */ + /* Action Command */ + unsigned short scb_rfa_offset; /* Offset of first Receive */ + /* Frame Descriptor in the */ + /* Receive Frame Area */ + unsigned short scb_crcerrs; /* Properly aligned frames */ + /* received with a CRC error */ + unsigned short scb_alnerrs; /* Misaligned frames received */ + /* with a CRC error */ + unsigned short scb_rscerrs; /* Frames lost due to no space */ + unsigned short scb_ovrnerrs; /* Frames lost due to slow bus */ +}; + +#define scboff(p,f) toff(scb_t, p, f) + +/* + * The eight Action Commands. + */ +typedef enum acmd_e acmd_e; +enum acmd_e +{ + acmd_nop = 0, /* Do nothing */ + acmd_ia_setup = 1, /* Load an (ethernet) address into the */ + /* 82586 */ + acmd_configure = 2, /* Update the 82586 operating parameters */ + acmd_mc_setup = 3, /* Load a list of (ethernet) multicast */ + /* addresses into the 82586 */ + acmd_transmit = 4, /* Transmit a frame */ + acmd_tdr = 5, /* Perform a Time Domain Reflectometer */ + /* test on the serial link */ + acmd_dump = 6, /* Copy 82586 registers to memory */ + acmd_diagnose = 7, /* Run an internal self test */ +}; + +/* + * Generic Action Command header. + */ +typedef struct ach_t ach_t; +struct ach_t +{ + unsigned short ac_status; /* Command status: */ +#define AC_SFLD_C (0x1 << 15) /* Command completed */ +#define AC_SFLD_B (0x1 << 14) /* Busy executing */ +#define AC_SFLD_OK (0x1 << 13) /* Completed error free */ +#define AC_SFLD_A (0x1 << 12) /* Command aborted */ +#define AC_SFLD_FAIL (0x1 << 11) /* Selftest failed */ +#define AC_SFLD_S10 (0x1 << 10) /* No carrier sense */ + /* during transmission */ +#define AC_SFLD_S9 (0x1 << 9) /* Tx unsuccessful: */ + /* (stopped) lost CTS */ +#define AC_SFLD_S8 (0x1 << 8) /* Tx unsuccessful: */ + /* (stopped) slow DMA */ +#define AC_SFLD_S7 (0x1 << 7) /* Tx deferred: */ + /* other link traffic */ +#define AC_SFLD_S6 (0x1 << 6) /* Heart Beat: collision */ + /* detect after last tx */ +#define AC_SFLD_S5 (0x1 << 5) /* Tx stopped: */ + /* excessive collisions */ +#define AC_SFLD_MAXCOL (0xF << 0) /* Collision count */ + unsigned short ac_command; /* Command specifier: */ +#define AC_CFLD_EL (0x1 << 15) /* End of command list */ +#define AC_CFLD_S (0x1 << 14) /* Suspend on completion */ +#define AC_CFLD_I (0x1 << 13) /* Interrupt on completion */ +#define AC_CFLD_CMD (0x7 << 0) /* acmd_e */ + unsigned short ac_link; /* Next Action Command */ +}; + +#define acoff(p,f) toff(ach_t, p, f) + +/* + * The Nop Action Command. + */ +typedef struct ac_nop_t ac_nop_t; +struct ac_nop_t +{ + ach_t nop_h; +}; + +/* + * The IA-Setup Action Command. + */ +typedef struct ac_ias_t ac_ias_t; +struct ac_ias_t +{ + ach_t ias_h; + unsigned char ias_addr[ADDR_LEN]; /* The (ethernet) address */ +}; + +/* + * The Configure Action Command. + */ +typedef struct ac_cfg_t ac_cfg_t; +struct ac_cfg_t +{ + ach_t cfg_h; + unsigned char cfg_byte_cnt; /* Size foll data: 4-12 */ +#define AC_CFG_BYTE_CNT(v) (((v) & 0xF) << 0) + unsigned char cfg_fifolim; /* FIFO threshold */ +#define AC_CFG_FIFOLIM(v) (((v) & 0xF) << 0) + unsigned char cfg_byte8; +#define AC_CFG_SAV_BF(v) (((v) & 0x1) << 7) /* Save rxd bad frames */ +#define AC_CFG_SRDY(v) (((v) & 0x1) << 6) /* SRDY/ARDY pin means */ + /* external sync. */ + unsigned char cfg_byte9; +#define AC_CFG_ELPBCK(v) (((v) & 0x1) << 7) /* External loopback */ +#define AC_CFG_ILPBCK(v) (((v) & 0x1) << 6) /* Internal loopback */ +#define AC_CFG_PRELEN(v) (((v) & 0x3) << 4) /* Preamble length */ +#define AC_CFG_PLEN_2 0 /* 2 bytes */ +#define AC_CFG_PLEN_4 1 /* 4 bytes */ +#define AC_CFG_PLEN_8 2 /* 8 bytes */ +#define AC_CFG_PLEN_16 3 /* 16 bytes */ +#define AC_CFG_ALOC(v) (((v) & 0x1) << 3) /* Addr/len data is */ + /* explicit in buffers */ +#define AC_CFG_ADDRLEN(v) (((v) & 0x7) << 0) /* Bytes per address */ + unsigned char cfg_byte10; +#define AC_CFG_BOFMET(v) (((v) & 0x1) << 7) /* Use alternate expo. */ + /* backoff method */ +#define AC_CFG_ACR(v) (((v) & 0x7) << 4) /* Accelerated cont. res. */ +#define AC_CFG_LINPRIO(v) (((v) & 0x7) << 0) /* Linear priority */ + unsigned char cfg_ifs; /* Interframe spacing */ + unsigned char cfg_slotl; /* Slot time (low byte) */ + unsigned char cfg_byte13; +#define AC_CFG_RETRYNUM(v) (((v) & 0xF) << 4) /* Max. collision retry */ +#define AC_CFG_SLTTMHI(v) (((v) & 0x7) << 0) /* Slot time (high bits) */ + unsigned char cfg_byte14; +#define AC_CFG_FLGPAD(v) (((v) & 0x1) << 7) /* Pad with HDLC flags */ +#define AC_CFG_BTSTF(v) (((v) & 0x1) << 6) /* Do HDLC bitstuffing */ +#define AC_CFG_CRC16(v) (((v) & 0x1) << 5) /* 16 bit CCITT CRC */ +#define AC_CFG_NCRC(v) (((v) & 0x1) << 4) /* Insert no CRC */ +#define AC_CFG_TNCRS(v) (((v) & 0x1) << 3) /* Tx even if no carrier */ +#define AC_CFG_MANCH(v) (((v) & 0x1) << 2) /* Manchester coding */ +#define AC_CFG_BCDIS(v) (((v) & 0x1) << 1) /* Disable broadcast */ +#define AC_CFG_PRM(v) (((v) & 0x1) << 0) /* Promiscuous mode */ + unsigned char cfg_byte15; +#define AC_CFG_ICDS(v) (((v) & 0x1) << 7) /* Internal collision */ + /* detect source */ +#define AC_CFG_CDTF(v) (((v) & 0x7) << 4) /* Collision detect */ + /* filter in bit times */ +#define AC_CFG_ICSS(v) (((v) & 0x1) << 3) /* Internal carrier */ + /* sense source */ +#define AC_CFG_CSTF(v) (((v) & 0x7) << 0) /* Carrier sense */ + /* filter in bit times */ + unsigned short cfg_min_frm_len; +#define AC_CFG_MNFRM(v) (((v) & 0xFF) << 0) /* Min. bytes/frame (<= 255) */ +}; + +/* + * The MC-Setup Action Command. + */ +typedef struct ac_mcs_t ac_mcs_t; +struct ac_mcs_t +{ + ach_t mcs_h; + unsigned short mcs_cnt; /* No. of bytes of MC addresses */ +#if 0 + unsigned char mcs_data[ADDR_LEN]; /* The first MC address .. */ + ... +#endif +}; + +#define I82586_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ + +/* + * The Transmit Action Command. + */ +typedef struct ac_tx_t ac_tx_t; +struct ac_tx_t +{ + ach_t tx_h; + unsigned short tx_tbd_offset; /* Address of list of buffers. */ +#if 0 +Linux packets are passed down with the destination MAC address +and length/type field already prepended to the data, +so we do not need to insert it. Consistent with this +we must also set the AC_CFG_ALOC(..) flag during the +ac_cfg_t action command. + unsigned char tx_addr[ADDR_LEN]; /* The frame dest. address */ + unsigned short tx_length; /* The frame length */ +#endif /* 0 */ +}; + +/* + * The Time Domain Reflectometer Action Command. + */ +typedef struct ac_tdr_t ac_tdr_t; +struct ac_tdr_t +{ + ach_t tdr_h; + unsigned short tdr_result; /* Result. */ +#define AC_TDR_LNK_OK (0x1 << 15) /* No link problem */ +#define AC_TDR_XCVR_PRB (0x1 << 14) /* Txcvr cable problem */ +#define AC_TDR_ET_OPN (0x1 << 13) /* Open on the link */ +#define AC_TDR_ET_SRT (0x1 << 12) /* Short on the link */ +#define AC_TDR_TIME (0x7FF << 0) /* Distance to problem */ + /* site in transmit */ + /* clock cycles */ +}; + +/* + * The Dump Action Command. + */ +typedef struct ac_dmp_t ac_dmp_t; +struct ac_dmp_t +{ + ach_t dmp_h; + unsigned short dmp_offset; /* Result. */ +}; + +/* + * Size of the result of the dump command. + */ +#define DUMPBYTES 170 + +/* + * The Diagnose Action Command. + */ +typedef struct ac_dgn_t ac_dgn_t; +struct ac_dgn_t +{ + ach_t dgn_h; +}; + +/* + * Transmit Buffer Descriptor (TBD). + */ +typedef struct tbd_t tbd_t; +struct tbd_t +{ + unsigned short tbd_status; /* Written by the CPU */ +#define TBD_STATUS_EOF (0x1 << 15) /* This TBD is the */ + /* last for this frame */ +#define TBD_STATUS_ACNT (0x3FFF << 0) /* Actual count of data */ + /* bytes in this buffer */ + unsigned short tbd_next_bd_offset; /* Next in list */ + unsigned short tbd_bufl; /* Buffer address (low) */ + unsigned short tbd_bufh; /* " " (high) */ +}; + +/* + * Receive Buffer Descriptor (RBD). + */ +typedef struct rbd_t rbd_t; +struct rbd_t +{ + unsigned short rbd_status; /* Written by the 82586 */ +#define RBD_STATUS_EOF (0x1 << 15) /* This RBD is the */ + /* last for this frame */ +#define RBD_STATUS_F (0x1 << 14) /* ACNT field is valid */ +#define RBD_STATUS_ACNT (0x3FFF << 0) /* Actual no. of data */ + /* bytes in this buffer */ + unsigned short rbd_next_rbd_offset; /* Next rbd in list */ + unsigned short rbd_bufl; /* Data pointer (low) */ + unsigned short rbd_bufh; /* " " (high) */ + unsigned short rbd_el_size; /* EL+Data buf. size */ +#define RBD_EL (0x1 << 15) /* This BD is the */ + /* last in the list */ +#define RBD_SIZE (0x3FFF << 0) /* No. of bytes the */ + /* buffer can hold */ +}; + +#define rbdoff(p,f) toff(rbd_t, p, f) + +/* + * Frame Descriptor (FD). + */ +typedef struct fd_t fd_t; +struct fd_t +{ + unsigned short fd_status; /* Written by the 82586 */ +#define FD_STATUS_C (0x1 << 15) /* Completed storing frame */ +#define FD_STATUS_B (0x1 << 14) /* FD was consumed by RU */ +#define FD_STATUS_OK (0x1 << 13) /* Frame rxd successfully */ +#define FD_STATUS_S11 (0x1 << 11) /* CRC error */ +#define FD_STATUS_S10 (0x1 << 10) /* Alignment error */ +#define FD_STATUS_S9 (0x1 << 9) /* Ran out of resources */ +#define FD_STATUS_S8 (0x1 << 8) /* Rx DMA overrun */ +#define FD_STATUS_S7 (0x1 << 7) /* Frame too short */ +#define FD_STATUS_S6 (0x1 << 6) /* No EOF flag */ + unsigned short fd_command; /* Command */ +#define FD_COMMAND_EL (0x1 << 15) /* Last FD in list */ +#define FD_COMMAND_S (0x1 << 14) /* Suspend RU after rx */ + unsigned short fd_link_offset; /* Next FD */ + unsigned short fd_rbd_offset; /* First RBD (data) */ + /* Prepared by CPU, */ + /* updated by 82586 */ +#if 0 +I think the rest is unused since we +have set AC_CFG_ALOC(..). However, just +in case, we leave the space. +#endif /* 0 */ + unsigned char fd_dest[ADDR_LEN]; /* Destination address */ + /* Written by 82586 */ + unsigned char fd_src[ADDR_LEN]; /* Source address */ + /* Written by 82586 */ + unsigned short fd_length; /* Frame length or type */ + /* Written by 82586 */ +}; + +#define fdoff(p,f) toff(fd_t, p, f) + +/* + * This software may only be used and distributed + * according to the terms of the GNU General Public License. + * + * For more details, see wavelan.c. + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/irda/Config.help linux-2.5/drivers/net/irda/Config.help --- linux-2.5.20/drivers/net/irda/Config.help Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/net/irda/Config.help Tue Apr 23 12:29:55 2002 @@ -88,6 +88,18 @@ If you want to compile it as a module, say M here and read . The module will be called vlsi_ir.o. +CONFIG_EP7211_IR + Say Y here if you wish to use the infrared port on the EP7211. Note + that you can't use the first UART and the infrared port at the same + time, and that the EP7211 only supports SIR mode, at speeds up to + 115.2 kbps. To use the I/R port, you will need to get the source to + irda-utils and apply the patch at + . + +CONFIG_SA1100_FIR + Say Y here to enable the on-board IRDA device on a Intel(R) + StrongARM(R) SA-1110 based microporocessor. + CONFIG_DONGLE Say Y here if you have an infrared device that connects to your computer's serial port. These devices are called dongles. Then say Y diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/irda/Config.in linux-2.5/drivers/net/irda/Config.in --- linux-2.5.20/drivers/net/irda/Config.in Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/net/irda/Config.in Tue Apr 23 12:29:55 2002 @@ -25,6 +25,9 @@ dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR $CONFIG_IRDA dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA +if [ "$CONFIG_MIPS" = "y" ]; then + dep_tristate 'Alchemy Au1000 SIR/FIR' CONFIG_AU1000_FIR $CONFIG_IRDA +fi if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA dep_tristate 'ALi M5123 FIR (Experimental)' CONFIG_ALI_FIR $CONFIG_IRDA diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/irda/Makefile linux-2.5/drivers/net/irda/Makefile --- linux-2.5.20/drivers/net/irda/Makefile Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/net/irda/Makefile Sat May 25 19:52:04 2002 @@ -25,5 +25,6 @@ obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o obj-$(CONFIG_EP7211_IR) += ep7211_ir.o obj-$(CONFIG_MCP2120_DONGLE) += mcp2120.o +obj-$(CONFIG_AU1000_FIR) += au1k_ir.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/irda/ali-ircc.c linux-2.5/drivers/net/irda/ali-ircc.c --- linux-2.5.20/drivers/net/irda/ali-ircc.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/net/irda/ali-ircc.c Mon Mar 4 01:32:06 2002 @@ -258,7 +258,6 @@ struct ali_ircc_cb *self; struct pm_dev *pmdev; int dongle_id; - int ret; int err; IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); @@ -291,15 +290,13 @@ self->io.fifo_size = 16; /* SIR: 16, FIR: 32 Benjamin 2000/11/1 */ /* Reserve the ioports that we need */ - ret = check_region(self->io.fir_base, self->io.fir_ext); - if (ret < 0) { + if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) { WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", self->io.fir_base); dev_self[i] = NULL; kfree(self); return -ENODEV; } - request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/irda/au1k_ir.c linux-2.5/drivers/net/irda/au1k_ir.c --- linux-2.5.20/drivers/net/irda/au1k_ir.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/irda/au1k_ir.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,867 @@ +/* + * + * Alchemy Semi Au1000 IrDA driver + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * + */ + +#ifndef __mips__ +#error This driver only works with MIPS architectures! +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "net/irda/au1000_ircc.h" + +static int au1k_irda_net_init(struct net_device *); +static int au1k_irda_start(struct net_device *); +static int au1k_irda_stop(struct net_device *dev); +static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *); +static int au1k_irda_rx(struct net_device *); +static void au1k_irda_interrupt(int, void *, struct pt_regs *); +static void au1k_tx_timeout(struct net_device *); +static struct net_device_stats *au1k_irda_stats(struct net_device *); +static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int); +static int au1k_irda_set_speed(struct net_device *dev, int speed); + +static void *dma_alloc(size_t, dma_addr_t *); +static void dma_free(void *, size_t); + +static int qos_mtt_bits = 0x07; /* 1 ms or more */ +static struct net_device *ir_devs[NUM_IR_IFF]; +static char version[] __devinitdata = + "au1k_ircc:1.0 ppopov@mvista.com\n"; + +#define RUN_AT(x) (jiffies + (x)) + +/* + * IrDA peripheral bug. You have to read the register + * twice to get the right value. + */ +u32 read_ir_reg(u32 addr) +{ + readl(addr); + return readl(addr); +} + + +/* + * Buffer allocation/deallocation routines. The buffer descriptor returned + * has the virtual and dma address of a buffer suitable for + * both, receive and transmit operations. + */ +static db_dest_t *GetFreeDB(struct au1k_private *aup) +{ + db_dest_t *pDB; + pDB = aup->pDBfree; + + if (pDB) { + aup->pDBfree = pDB->pnext; + } + return pDB; +} + +static void ReleaseDB(struct au1k_private *aup, db_dest_t *pDB) +{ + db_dest_t *pDBfree = aup->pDBfree; + if (pDBfree) + pDBfree->pnext = pDB; + aup->pDBfree = pDB; +} + + +/* + DMA memory allocation, derived from pci_alloc_consistent. + However, the Au1000 data cache is coherent (when programmed + so), therefore we return KSEG0 address, not KSEG1. +*/ +static void *dma_alloc(size_t size, dma_addr_t * dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC | GFP_DMA; + + ret = (void *) __get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + ret = KSEG0ADDR(ret); + } + return ret; +} + + +static void dma_free(void *vaddr, size_t size) +{ + vaddr = KSEG0ADDR(vaddr); + free_pages((unsigned long) vaddr, get_order(size)); +} + + +static void +setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base) +{ + int i; + for (i=0; irx_ring[i] = (volatile ring_dest_t *) + (rx_base + sizeof(ring_dest_t)*i); + } + for (i=0; itx_ring[i] = (volatile ring_dest_t *) + (tx_base + sizeof(ring_dest_t)*i); + } +} + + +/* + * Device has already been stopped at this point. + */ +static void au1k_irda_net_uninit(struct net_device *dev) +{ + dev->hard_start_xmit = NULL; + dev->open = NULL; + dev->stop = NULL; + dev->do_ioctl = NULL; + dev->get_stats = NULL; + dev->priv = NULL; +} + + +static int au1k_irda_init(void) +{ + static unsigned version_printed = 0; + struct net_device *dev; + int err; + + if (version_printed++ == 0) printk(version); + + rtnl_lock(); + dev = dev_alloc("irda%d", &err); + if (dev) { + dev->irq = AU1000_IRDA_RX_INT; /* TX has its own interrupt */ + dev->init = au1k_irda_net_init; + dev->uninit = au1k_irda_net_uninit; + err = register_netdevice(dev); + + if (err) + kfree(dev); + else + ir_devs[0] = dev; + printk(KERN_INFO "IrDA: Registered device %s\n", dev->name); + } + rtnl_unlock(); + return err; +} + +static int au1k_irda_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL); + if (io->head != NULL) { + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + } + return io->head ? 0 : -ENOMEM; +} + +static int au1k_irda_net_init(struct net_device *dev) +{ + struct au1k_private *aup = NULL; + int i, retval = 0, err; + db_dest_t *pDB, *pDBfree; + unsigned long temp; + + dev->priv = kmalloc(sizeof(struct au1k_private), GFP_KERNEL); + if (dev->priv == NULL) { + retval = -ENOMEM; + goto out; + } + memset(dev->priv, 0, sizeof(struct au1k_private)); + aup = dev->priv; + + err = au1k_irda_init_iobuf(&aup->rx_buff, 14384); + if (err) + goto out; + + dev->open = au1k_irda_start; + dev->hard_start_xmit = au1k_irda_hard_xmit; + dev->stop = au1k_irda_stop; + dev->get_stats = au1k_irda_stats; + dev->do_ioctl = au1k_irda_ioctl; + dev->tx_timeout = au1k_tx_timeout; + + irda_device_setup(dev); + irda_init_max_qos_capabilies(&aup->qos); + + /* The only value we must override it the baudrate */ + aup->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000 |(IR_4000000 << 8); + + aup->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&aup->qos); + + + /* Tx ring follows rx ring + 512 bytes */ + /* we need a 1k aligned buffer */ + aup->rx_ring[0] = (ring_dest_t *) + dma_alloc(2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)), &temp); + + /* allocate the data buffers */ + aup->db[0].vaddr = + (void *)dma_alloc(MAX_BUF_SIZE * 2*NUM_IR_DESC, &temp); + if (!aup->db[0].vaddr || !aup->rx_ring[0]) { + retval = -ENOMEM; + goto out; + } + + setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512); + + pDBfree = NULL; + pDB = aup->db; + for (i=0; i<(2*NUM_IR_DESC); i++) { + pDB->pnext = pDBfree; + pDBfree = pDB; + pDB->vaddr = + (u32 *)((unsigned)aup->db[0].vaddr + MAX_BUF_SIZE*i); + pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); + pDB++; + } + aup->pDBfree = pDBfree; + + /* attach a data buffer to each descriptor */ + for (i=0; irx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff); + aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff); + aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff); + aup->rx_db_inuse[i] = pDB; + } + for (i=0; itx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff); + aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff); + aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff); + aup->tx_ring[i]->count_0 = 0; + aup->tx_ring[i]->count_1 = 0; + aup->tx_ring[i]->flags = 0; + aup->tx_db_inuse[i] = pDB; + } + return 0; + +out: + if (aup->db[0].vaddr) + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2*NUM_IR_DESC); + if (aup->rx_ring[0]) + kfree((void *)aup->rx_ring[0]); + if (aup->rx_buff.head) + kfree(aup->rx_buff.head); + if (dev->priv != NULL) + kfree(dev->priv); + unregister_netdevice(dev); + printk(KERN_ERR "%s: au1k_init_module failed. Returns %d\n", + dev->name, retval); + return retval; +} + + +static int au1k_init(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + int i; + u32 control; + u32 ring_address; + + /* bring the device out of reset */ + control = 0xe; /* coherent, clock enable, one half system clock */ + +#ifndef CONFIG_CPU_LITTLE_ENDIAN + control |= 1; +#endif + aup->tx_head = 0; + aup->tx_tail = 0; + aup->rx_head = 0; + + for (i=0; irx_ring[i]->flags = AU_OWN; + } + + writel(control, IR_INTERFACE_CONFIG); + au_sync_delay(10); + + writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); /* disable PHY */ + au_sync_delay(1); + + writel(MAX_BUF_SIZE, IR_MAX_PKT_LEN); + + ring_address = (u32)virt_to_phys((void *)aup->rx_ring[0]); + writel(ring_address >> 26, IR_RING_BASE_ADDR_H); + writel((ring_address >> 10) & 0xffff, IR_RING_BASE_ADDR_L); + + writel(RING_SIZE_64<<8 | RING_SIZE_64<<12, IR_RING_SIZE); + + writel(1<<2 | IR_ONE_PIN, IR_CONFIG_2); /* 48MHz */ + writel(0, IR_RING_ADDR_CMPR); + + au1k_irda_set_speed(dev, 9600); + return 0; +} + +static int au1k_irda_start(struct net_device *dev) +{ + int retval; + char hwname[32]; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + MOD_INC_USE_COUNT; + + if ((retval = au1k_init(dev))) { + printk(KERN_ERR "%s: error in au1k_init\n", dev->name); + MOD_DEC_USE_COUNT; + return retval; + } + + if ((retval = request_irq(AU1000_IRDA_TX_INT, &au1k_irda_interrupt, + 0, dev->name, dev))) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + if ((retval = request_irq(AU1000_IRDA_RX_INT, &au1k_irda_interrupt, + 0, dev->name, dev))) { + free_irq(AU1000_IRDA_TX_INT, dev); + printk(KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + + /* Give self a hardware name */ + sprintf(hwname, "Au1000 SIR/FIR"); + aup->irlap = irlap_open(dev, &aup->qos, hwname); + netif_start_queue(dev); + + writel(read_ir_reg(IR_CONFIG_2) | 1<<8, IR_CONFIG_2); /* int enable */ + + aup->timer.expires = RUN_AT((3*HZ)); + aup->timer.data = (unsigned long)dev; + return 0; +} + +static int au1k_irda_stop(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + /* disable interrupts */ + writel(read_ir_reg(IR_CONFIG_2) & ~(1<<8), IR_CONFIG_2); + writel(0, IR_CONFIG_1); + writel(0, IR_INTERFACE_CONFIG); /* disable clock */ + au_sync(); + + if (aup->irlap) { + irlap_close(aup->irlap); + aup->irlap = NULL; + } + + netif_stop_queue(dev); + del_timer(&aup->timer); + + /* disable the interrupt */ + free_irq(AU1000_IRDA_TX_INT, dev); + free_irq(AU1000_IRDA_RX_INT, dev); + MOD_DEC_USE_COUNT; + return 0; +} + +static void __exit au1k_irda_exit(void) +{ + struct net_device *dev = ir_devs[0]; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + if (!dev) { + printk(KERN_ERR "au1k_ircc no dev found\n"); + return; + } + if (aup->db[0].vaddr) { + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2*NUM_IR_DESC); + aup->db[0].vaddr = 0; + } + if (aup->rx_ring[0]) { + dma_free((void *)aup->rx_ring[0], + 2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t))); + aup->rx_ring[0] = 0; + } + rtnl_lock(); + unregister_netdevice(dev); + rtnl_unlock(); + ir_devs[0] = 0; +} + + +static inline void +update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; + + ps->tx_packets++; + ps->tx_bytes += pkt_len; + + if (status & IR_TX_ERROR) { + ps->tx_errors++; + ps->tx_aborted_errors++; + } +} + + +static void au1k_tx_ack(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + volatile ring_dest_t *ptxd; + + ptxd = aup->tx_ring[aup->tx_tail]; + while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) { + update_tx_stats(dev, ptxd->flags, + ptxd->count_1<<8 | ptxd->count_0); + ptxd->count_0 = 0; + ptxd->count_1 = 0; + au_sync(); + + aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1); + ptxd = aup->tx_ring[aup->tx_tail]; + + if (aup->tx_full) { + aup->tx_full = 0; + netif_wake_queue(dev); + } + } + + if (aup->tx_tail == aup->tx_head) { + if (aup->newspeed) { + au1k_irda_set_speed(dev, aup->newspeed); + aup->newspeed = 0; + } + else { + writel(read_ir_reg(IR_CONFIG_1) & ~IR_TX_ENABLE, + IR_CONFIG_1); + au_sync(); + writel(read_ir_reg(IR_CONFIG_1) | IR_RX_ENABLE, + IR_CONFIG_1); + writel(0, IR_RING_PROMPT); + au_sync(); + } + } +} + + +/* + * Au1000 transmit routine. + */ +static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + int speed = irda_get_next_speed(skb); + volatile ring_dest_t *ptxd; + u32 len; + + u32 flags; + db_dest_t *pDB; + + if (speed != aup->speed && speed != -1) { + aup->newspeed = speed; + } + + if ((skb->len == 0) && (aup->newspeed)) { + if (aup->tx_tail == aup->tx_head) { + au1k_irda_set_speed(dev, speed); + aup->newspeed = 0; + } + dev_kfree_skb(skb); + return 0; + } + + ptxd = aup->tx_ring[aup->tx_head]; + flags = ptxd->flags; + + if (flags & AU_OWN) { + printk(KERN_INFO "%s: tx_full\n", dev->name); + netif_stop_queue(dev); + aup->tx_full = 1; + return 1; + } + else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { + printk(KERN_INFO "%s: tx_full\n", dev->name); + netif_stop_queue(dev); + aup->tx_full = 1; + return 1; + } + + pDB = aup->tx_db_inuse[aup->tx_head]; + +#if 0 + if (read_ir_reg(IR_RX_BYTE_CNT) != 0) { + printk("tx warning: rx byte cnt %x\n", + read_ir_reg(IR_RX_BYTE_CNT)); + } +#endif + + if (aup->speed == 4000000) { + /* FIR */ + memcpy((void *)pDB->vaddr, skb->data, skb->len); + ptxd->count_0 = skb->len & 0xff; + ptxd->count_1 = (skb->len >> 8) & 0xff; + } + else { + /* SIR */ + len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE); + ptxd->count_0 = len & 0xff; + ptxd->count_1 = (len >> 8) & 0xff; + ptxd->flags |= IR_DIS_CRC; + } + ptxd->flags |= AU_OWN; + au_sync(); + + writel(read_ir_reg(IR_CONFIG_1) | IR_TX_ENABLE, IR_CONFIG_1); + writel(0, IR_RING_PROMPT); + au_sync(); + + dev_kfree_skb(skb); + aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1); + dev->trans_start = jiffies; + return 0; +} + + +static inline void +update_rx_stats(struct net_device *dev, u32 status, u32 count) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; + + ps->rx_packets++; + + if (status & IR_RX_ERROR) { + ps->rx_errors++; + if (status & (IR_PHY_ERROR|IR_FIFO_OVER)) + ps->rx_missed_errors++; + if (status & IR_MAX_LEN) + ps->rx_length_errors++; + if (status & IR_CRC_ERROR) + ps->rx_crc_errors++; + } + else + ps->rx_bytes += count; +} + +/* + * Au1000 receive routine. + */ +static int au1k_irda_rx(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct sk_buff *skb; + volatile ring_dest_t *prxd; + u32 flags, count; + db_dest_t *pDB; + + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + + while (!(flags & AU_OWN)) { + pDB = aup->rx_db_inuse[aup->rx_head]; + count = prxd->count_1<<8 | prxd->count_0; + if (!(flags & IR_RX_ERROR)) { + /* good frame */ + update_rx_stats(dev, flags, count); + skb=alloc_skb(count+1,GFP_ATOMIC); + if (skb == NULL) { + aup->stats.rx_dropped++; + continue; + } + skb_reserve(skb, 1); + if (aup->speed == 4000000) + skb_put(skb, count); + else + skb_put(skb, count-2); + memcpy(skb->data, (void *)pDB->vaddr, count-2); + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + prxd->count_0 = 0; + prxd->count_1 = 0; + } + prxd->flags |= AU_OWN; + aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1); + writel(0, IR_RING_PROMPT); + au_sync(); + + /* next descriptor */ + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + dev->last_rx = jiffies; + + } + return 0; +} + + +void au1k_irda_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + + if (dev == NULL) { + printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); + return; + } + + writel(0, IR_INT_CLEAR); /* ack irda interrupts */ + + au1k_irda_rx(dev); + au1k_tx_ack(dev); +} + + +/* + * The Tx ring has been full longer than the watchdog timeout + * value. The transmitter must be hung? + */ +static void au1k_tx_timeout(struct net_device *dev) +{ + u32 speed; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + printk(KERN_ERR "%s: tx timeout\n", dev->name); + speed = aup->speed; + aup->speed = 0; + au1k_irda_set_speed(dev, speed); + aup->tx_full = 0; + netif_wake_queue(dev); +} + + +/* + * Set the IrDA communications speed. + */ +static int +au1k_irda_set_speed(struct net_device *dev, int speed) +{ + unsigned long flags; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + u32 control; + int ret = 0, timeout = 10, i; + volatile ring_dest_t *ptxd; + + if (speed == aup->speed) + return ret; + + save_flags(flags); + cli(); + + /* disable PHY first */ + writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); + + /* disable RX/TX */ + writel(read_ir_reg(IR_CONFIG_1) & ~(IR_RX_ENABLE|IR_TX_ENABLE), + IR_CONFIG_1); + au_sync_delay(1); + while (read_ir_reg(IR_ENABLE) & (IR_RX_STATUS | IR_TX_STATUS)) { + mdelay(1); + if (!timeout--) { + printk(KERN_ERR "%s: rx/tx disable timeout\n", + dev->name); + break; + } + } + + /* disable DMA */ + writel(read_ir_reg(IR_CONFIG_1) & ~IR_DMA_ENABLE, IR_CONFIG_1); + au_sync_delay(1); + + /* + * After we disable tx/rx. the index pointers + * go back to zero. + */ + aup->tx_head = aup->tx_tail = aup->rx_head = 0; + for (i=0; itx_ring[i]; + ptxd->flags = 0; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + } + + for (i=0; irx_ring[i]; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + ptxd->flags = AU_OWN; + } + + if (speed == 4000000) + writel(1<<13, CPLD_AUX1); + else + writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1); + + switch (speed) { + case 9600: + writel(11<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 19200: + writel(5<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 38400: + writel(2<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 57600: + writel(1<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 115200: + writel(12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 4000000: + writel(0xF, IR_WRITE_PHY_CONFIG); + writel(IR_FIR|IR_DMA_ENABLE|IR_RX_ENABLE, IR_CONFIG_1); + break; + default: + printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed); + ret = -EINVAL; + break; + } + + aup->speed = speed; + writel(read_ir_reg(IR_ENABLE) | 0x8000, IR_ENABLE); + au_sync(); + + control = read_ir_reg(IR_ENABLE); + writel(0, IR_RING_PROMPT); + au_sync(); + + if (control & (1<<14)) { + printk(KERN_ERR "%s: configuration error\n", dev->name); + } + else { + if (control & (1<<11)) + printk(KERN_INFO "%s Valid SIR config\n", dev->name); + if (control & (1<<12)) + printk(KERN_INFO "%s Valid MIR config\n", dev->name); + if (control & (1<<13)) + printk(KERN_INFO "%s Valid FIR config\n", dev->name); + if (control & (1<<10)) + printk(KERN_INFO "%s TX enabled\n", dev->name); + if (control & (1<<9)) + printk(KERN_INFO "%s RX enabled\n", dev->name); + } + + restore_flags(flags); + return ret; +} + +static int +au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct au1k_private *aup = dev->priv; + int ret = -EOPNOTSUPP; + + switch (cmd) { + case SIOCSBANDWIDTH: + if (capable(CAP_NET_ADMIN)) { + /* + * We are unable to set the speed if the + * device is not running. + */ + if (aup->open) + ret = au1k_irda_set_speed(dev, + rq->ifr_baudrate); + else { + printk(KERN_ERR "%s ioctl: !netif_running\n", + dev->name); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + rq->ifr_receiving = 0; + break; + default: + break; + } + return ret; +} + + +static struct net_device_stats *au1k_irda_stats(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + return &aup->stats; +} + +#ifdef MODULE +MODULE_AUTHOR("Pete Popov "); +MODULE_DESCRIPTION("Au1000 IrDA Device Driver"); + +module_init(au1k_irda_init); +module_exit(au1k_irda_exit); +#endif /* MODULE */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/irda/irda-usb.c linux-2.5/drivers/net/irda/irda-usb.c --- linux-2.5.20/drivers/net/irda/irda-usb.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/net/irda/irda-usb.c Sat Jun 1 00:34:35 2002 @@ -857,7 +857,7 @@ new->mac.raw = new->data; new->protocol = htons(ETH_P_IRDA); netif_rx(new); - self->netdev->last_rx = jiffies; + self->netdev->last_rx = jiffies; done: /* Note : at this point, the URB we've just received (urb) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/macmace.c linux-2.5/drivers/net/macmace.c --- linux-2.5.20/drivers/net/macmace.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/net/macmace.c Fri May 3 03:49:07 2002 @@ -10,6 +10,8 @@ * * Copyright (C) 1996 Paul Mackerras. * Copyright (C) 1998 Alan Cox + * + * Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver */ @@ -18,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -26,14 +27,13 @@ #include #include #include +#include #include "mace.h" +#define N_TX_RING 1 #define N_RX_RING 8 -#define N_TX_RING 2 -#define MAX_TX_ACTIVE 1 -#define NCMDS_TX 1 /* dma commands per element in tx ring */ -#define RX_BUFLEN (ETH_FRAME_LEN + 8) -#define TX_TIMEOUT HZ /* 1 second */ +#define N_RX_PAGES ((N_RX_RING * 0x0800 + PAGE_SIZE - 1) / PAGE_SIZE) +#define TX_TIMEOUT HZ /* Bits in transmit DMA status */ #define TX_DMA_ERR 0x80 @@ -43,22 +43,19 @@ #define MACE_BASE (void *)(0x50F1C000) #define MACE_PROM (void *)(0x50F08001) -struct mace68k_data -{ +struct mace_data { volatile struct mace *mace; volatile unsigned char *tx_ring; + volatile unsigned char *tx_ring_phys; volatile unsigned char *rx_ring; + volatile unsigned char *rx_ring_phys; int dma_intr; - unsigned char maccc; struct net_device_stats stats; - struct timer_list tx_timeout; - int timeout_active; - int rx_slot, rx_done; - int tx_slot, tx_count; + int rx_slot, rx_tail; + int tx_slot, tx_sloti, tx_count; }; -struct mace_frame -{ +struct mace_frame { u16 len; u16 status; u16 rntpc; @@ -69,271 +66,227 @@ /* And frame continues.. */ }; -#define PRIV_BYTES sizeof(struct mace68k_data) +#define PRIV_BYTES sizeof(struct mace_data) extern void psc_debug_dump(void); -static int mace68k_open(struct net_device *dev); -static int mace68k_close(struct net_device *dev); -static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *mace68k_stats(struct net_device *dev); -static void mace68k_set_multicast(struct net_device *dev); -static void mace68k_reset(struct net_device *dev); -static int mace68k_set_address(struct net_device *dev, void *addr); -static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs); -static void mace68k_set_timeout(struct net_device *dev); -static void mace68k_tx_timeout(unsigned long data); +static int mace_open(struct net_device *dev); +static int mace_close(struct net_device *dev); +static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *mace_stats(struct net_device *dev); +static void mace_set_multicast(struct net_device *dev); +static int mace_set_address(struct net_device *dev, void *addr); +static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs); +static void mace_tx_timeout(struct net_device *dev); -/* - * PSC DMA engine control. As you'd expect on a macintosh its - * more like a lawnmower engine supplied without instructions - * - * The basic theory of operation appears to be as follows. - * - * There are two sets of receive DMA registers and two sets - * of transmit DMA registers. Instead of the more traditional - * "ring buffer" approach the Mac68K DMA engine expects you - * to be loading one chain while the other runs, and then - * to flip register set. Each entry in the chain is a fixed - * length. - */ +/* Bit-reverse one byte of an ethernet hardware address. */ + +static int bitrev(int b) +{ + int d = 0, i; + + for (i = 0; i < 8; ++i, b >>= 1) { + d = (d << 1) | (b & 1); + } + + return d; +} /* - * Load a receive DMA channel with a base address and ring length + * Load a receive DMA channel with a base address and ring length */ - -static void psc_load_rxdma_base(int set, void *base) + +static void mace_load_rxdma_base(struct net_device *dev, int set) { + struct mace_data *mp = (struct mace_data *) dev->priv; + psc_write_word(PSC_ENETRD_CMD + set, 0x0100); - psc_write_long(PSC_ENETRD_ADDR + set, (u32)base); + psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys); psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING); psc_write_word(PSC_ENETRD_CMD + set, 0x9800); + mp->rx_tail = 0; } /* - * Reset the receive DMA subsystem + * Reset the receive DMA subsystem */ - -static void mace68k_rxdma_reset(struct net_device *dev) + +static void mace_rxdma_reset(struct net_device *dev) { - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mace = mp->mace; - u8 mcc = mace->maccc; - - /* - * Turn off receive - */ - - mcc&=~ENRCV; - mace->maccc=mcc; + u8 maccc = mace->maccc; - /* - * Program the DMA - */ + mace->maccc = maccc & ~ENRCV; psc_write_word(PSC_ENETRD_CTL, 0x8800); - psc_load_rxdma_base(0x0, (void *)virt_to_bus(mp->rx_ring)); + mace_load_rxdma_base(dev, 0x00); psc_write_word(PSC_ENETRD_CTL, 0x0400); psc_write_word(PSC_ENETRD_CTL, 0x8800); - psc_load_rxdma_base(0x10, (void *)virt_to_bus(mp->rx_ring)); + mace_load_rxdma_base(dev, 0x10); psc_write_word(PSC_ENETRD_CTL, 0x0400); - mace->maccc=mcc|ENRCV; - -#if 0 - psc_write_word(PSC_ENETRD_CTL, 0x9800); - psc_write_word(PSC_ENETRD_CTL+0x10, 0x9800); -#endif + mace->maccc = maccc; + mp->rx_slot = 0; + + psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x9800); + psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x9800); } /* - * Reset the transmit DMA subsystem + * Reset the transmit DMA subsystem */ -static void mace68k_txdma_reset(struct net_device *dev) +static void mace_txdma_reset(struct net_device *dev) { - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mace = mp->mace; - u8 mcc = mace->maccc; + u8 maccc; - psc_write_word(PSC_ENETWR_CTL,0x8800); - - mace->maccc = mcc&~ENXMT; - psc_write_word(PSC_ENETWR_CTL,0x0400); - mace->maccc = mcc; + psc_write_word(PSC_ENETWR_CTL, 0x8800); + + maccc = mace->maccc; + mace->maccc = maccc & ~ENXMT; + + mp->tx_slot = mp->tx_sloti = 0; + mp->tx_count = N_TX_RING; + + psc_write_word(PSC_ENETWR_CTL, 0x0400); + mace->maccc = maccc; } /* - * Disable DMA + * Disable DMA */ -static void mace68k_dma_off(struct net_device *dev) +static void mace_dma_off(struct net_device *dev) { psc_write_word(PSC_ENETRD_CTL, 0x8800); psc_write_word(PSC_ENETRD_CTL, 0x1000); - psc_write_word(PSC_ENETRD_CMD, 0x1100); - psc_write_word(PSC_ENETRD_CMD+0x10, 0x1100); - + psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x1100); + psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x1100); + psc_write_word(PSC_ENETWR_CTL, 0x8800); psc_write_word(PSC_ENETWR_CTL, 0x1000); - psc_write_word(PSC_ENETWR_CMD, 0x1100); - psc_write_word(PSC_ENETWR_CMD+0x10, 0x1100); -} - -/* Bit-reverse one byte of an ethernet hardware address. */ - -static int bitrev(int b) -{ - int d = 0, i; - - for (i = 0; i < 8; ++i, b >>= 1) - d = (d << 1) | (b & 1); - return d; + psc_write_word(PSC_ENETWR_CMD + PSC_SET0, 0x1100); + psc_write_word(PSC_ENETWR_CMD + PSC_SET1, 0x1100); } /* - * Not really much of a probe. The hardware table tells us if this - * model of Macintrash has a MACE (AV macintoshes) + * Not really much of a probe. The hardware table tells us if this + * model of Macintrash has a MACE (AV macintoshes) */ -int mace68k_probe(struct net_device *unused) +int mace_probe(struct net_device *unused) { int j; static int once; - struct mace68k_data *mp; + struct mace_data *mp; unsigned char *addr; struct net_device *dev; unsigned char checksum = 0; + static int found = 0; - /* - * There can be only one... - */ - - if (once) return -ENODEV; - - once = 1; + if (found || macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; - if (macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; + found = 1; /* prevent 'finding' one on every device probe */ - printk("MACE ethernet should be present "); - dev = init_etherdev(0, PRIV_BYTES); - if(dev==NULL) - { - printk("no free memory.\n"); - return -ENOMEM; - } - mp = (struct mace68k_data *) dev->priv; + if (!dev) return -ENOMEM; + + mp = (struct mace_data *) dev->priv; dev->base_addr = (u32)MACE_BASE; mp->mace = (volatile struct mace *) MACE_BASE; - printk("at 0x%p", mp->mace); - - /* - * 16K RX ring and 4K TX ring should do nicely - */ - - mp->rx_ring=(void *)__get_free_pages(GFP_KERNEL, 2); - mp->tx_ring=(void *)__get_free_page(GFP_KERNEL); - - printk("."); - - if(mp->tx_ring==NULL || mp->rx_ring==NULL) - { - if(mp->tx_ring) - free_page((u32)mp->tx_ring); -// if(mp->rx_ring) -// __free_pages(mp->rx_ring,2); - printk("\nNo memory for ring buffers.\n"); - return -ENOMEM; - } - - /* We want the receive data to be uncached. We dont care about the - byte reading order */ - - printk("."); - kernel_set_cachemode((void *)mp->rx_ring, 16384, IOMAP_NOCACHE_NONSER); - - printk("."); - /* The transmit buffer needs to be write through */ - kernel_set_cachemode((void *)mp->tx_ring, 4096, IOMAP_WRITETHROUGH); - - printk(" Ok\n"); dev->irq = IRQ_MAC_MACE; - printk(KERN_INFO "%s: MACE at", dev->name); + mp->dma_intr = IRQ_MAC_MACE_DMA; /* - * The PROM contains 8 bytes which total 0xFF when XOR'd - * together. Due to the usual peculiar apple brain damage - * the bytes are spaced out in a strange boundary and the - * bits are reversed. + * The PROM contains 8 bytes which total 0xFF when XOR'd + * together. Due to the usual peculiar apple brain damage + * the bytes are spaced out in a strange boundary and the + * bits are reversed. */ addr = (void *)MACE_PROM; - for (j = 0; j < 6; ++j) - { + for (j = 0; j < 6; ++j) { u8 v=bitrev(addr[j<<4]); - checksum^=v; + checksum ^= v; dev->dev_addr[j] = v; - printk("%c%.2x", (j ? ':' : ' '), dev->dev_addr[j]); } - for (; j < 8; ++j) - { - checksum^=bitrev(addr[j<<4]); + for (; j < 8; ++j) { + checksum ^= bitrev(addr[j<<4]); } - if(checksum!=0xFF) - { - printk(" (invalid checksum)\n"); - return -ENODEV; - } - printk("\n"); + if (checksum != 0xFF) return -ENODEV; memset(&mp->stats, 0, sizeof(mp->stats)); - init_timer(&mp->tx_timeout); - mp->timeout_active = 0; - dev->open = mace68k_open; - dev->stop = mace68k_close; - dev->hard_start_xmit = mace68k_xmit_start; - dev->get_stats = mace68k_stats; - dev->set_multicast_list = mace68k_set_multicast; - dev->set_mac_address = mace68k_set_address; + dev->open = mace_open; + dev->stop = mace_close; + dev->hard_start_xmit = mace_xmit_start; + dev->tx_timeout = mace_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->get_stats = mace_stats; + dev->set_multicast_list = mace_set_multicast; + dev->set_mac_address = mace_set_address; ether_setup(dev); - mp = (struct mace68k_data *) dev->priv; - mp->maccc = ENXMT | ENRCV; - mp->dma_intr = IRQ_MAC_MACE_DMA; + printk(KERN_INFO "%s: 68K MACE, hardware address %.2X", dev->name, dev->dev_addr[0]); + for (j = 1 ; j < 6 ; j++) printk(":%.2X", dev->dev_addr[j]); + printk("\n"); - psc_write_word(PSC_ENETWR_CTL, 0x9000); - psc_write_word(PSC_ENETRD_CTL, 0x9000); - psc_write_word(PSC_ENETWR_CTL, 0x0400); - psc_write_word(PSC_ENETRD_CTL, 0x0400); - - /* apple's driver doesn't seem to do this */ - /* except at driver shutdown time... */ -#if 0 - mace68k_dma_off(dev); -#endif + return 0; +} + +/* + * Load the address on a mace controller. + */ + +static int mace_set_address(struct net_device *dev, void *addr) +{ + unsigned char *p = addr; + struct mace_data *mp = (struct mace_data *) dev->priv; + volatile struct mace *mb = mp->mace; + int i; + unsigned long flags; + u8 maccc; + + save_flags(flags); + cli(); + + maccc = mb->maccc; + + /* load up the hardware address */ + mb->iac = ADDRCHG | PHYADDR; + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 6; ++i) { + mb->padr = dev->dev_addr[i] = p[i]; + } + + mb->maccc = maccc; + restore_flags(flags); return 0; } /* - * Reset a MACE controller + * Open the Macintosh MACE. Most of this is playing with the DMA + * engine. The ethernet chip is quite friendly. */ -static void mace68k_reset(struct net_device *dev) +static int mace_open(struct net_device *dev) { - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; +#if 0 int i; - /* soft-reset the chip */ i = 200; while (--i) { mb->biucc = SWRST; @@ -344,18 +297,59 @@ break; } if (!i) { - printk(KERN_ERR "mace: cannot reset chip!\n"); - return; + printk(KERN_ERR "%s: software reset failed!!\n", dev->name); + return -EAGAIN; } +#endif mb->biucc = XMTSP_64; - mb->imr = 0xff; /* disable all intrs for now */ - i = mb->ir; - mb->maccc = 0; /* turn off tx, rx */ - mb->utr = RTRD; - mb->fifocc = RCVFW_64; - mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ + mb->fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | XMTBRST | RCVBRST; + mb->xmtfc = AUTO_PAD_XMIT; + mb->plscc = PORTSEL_AUI; + /* mb->utr = RTRD; */ + + if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) { + printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq); + return -EAGAIN; + } + if (request_irq(mp->dma_intr, mace_dma_intr, 0, dev->name, dev)) { + printk(KERN_ERR "%s: can't get irq %d\n", dev->name, mp->dma_intr); + free_irq(dev->irq, dev); + return -EAGAIN; + } + + /* Allocate the DMA ring buffers */ + + mp->rx_ring = (void *) __get_free_pages(GFP_DMA, N_RX_PAGES); + mp->tx_ring = (void *) __get_free_pages(GFP_DMA, 0); + + if (mp->tx_ring==NULL || mp->rx_ring==NULL) { + if (mp->rx_ring) free_pages((u32) mp->rx_ring, N_RX_PAGES); + if (mp->tx_ring) free_pages((u32) mp->tx_ring, 0); + free_irq(dev->irq, dev); + free_irq(mp->dma_intr, dev); + printk(KERN_ERR "%s: unable to allocate DMA buffers\n", dev->name); + return -ENOMEM; + } + + mp->rx_ring_phys = (unsigned char *) virt_to_bus(mp->rx_ring); + mp->tx_ring_phys = (unsigned char *) virt_to_bus(mp->tx_ring); + + /* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */ + + kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER); + kernel_set_cachemode((void *)mp->tx_ring, PAGE_SIZE, IOMAP_WRITETHROUGH); + + mace_dma_off(dev); + + /* Not sure what these do */ + psc_write_word(PSC_ENETWR_CTL, 0x9000); + psc_write_word(PSC_ENETRD_CTL, 0x9000); + psc_write_word(PSC_ENETWR_CTL, 0x0400); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + +#if 0 /* load up the hardware address */ mb->iac = ADDRCHG | PHYADDR; @@ -374,245 +368,158 @@ mb->ladrf = 0; mb->plscc = PORTSEL_GPSI + ENPLSIO; -} - -/* - * Load the address on a mace controller. - */ - -static int mace68k_set_address(struct net_device *dev, void *addr) -{ - unsigned char *p = addr; - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; - volatile struct mace *mb = mp->mace; - int i; - unsigned long flags; - save_flags(flags); - cli(); + mb->maccc = ENXMT | ENRCV; + mb->imr = RCVINT; +#endif - /* load up the hardware address */ - mb->iac = ADDRCHG | PHYADDR; - while ((mb->iac & ADDRCHG) != 0); + mace_rxdma_reset(dev); + mace_txdma_reset(dev); - for (i = 0; i < 6; ++i) - mb->padr = dev->dev_addr[i] = p[i]; - /* note: setting ADDRCHG clears ENRCV */ - mb->maccc = mp->maccc; - restore_flags(flags); return 0; } /* - * Open the Macintosh MACE. Most of this is playing with the DMA - * engine. The ethernet chip is quite friendly. + * Shut down the mace and its interrupt channel */ -static int mace68k_open(struct net_device *dev) +static int mace_close(struct net_device *dev) { - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; - /* reset the chip */ - mace68k_reset(dev); - - mp->rx_done = 0; - mace68k_rxdma_reset(dev); - - /* - * The interrupt is fixed and comes off the PSC. - */ - - if (request_irq(dev->irq, mace68k_interrupt, 0, "68K MACE", dev)) - { - printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); - return -EAGAIN; - } + mb->maccc = 0; /* disable rx and tx */ + mb->imr = 0xFF; /* disable all irqs */ + mace_dma_off(dev); /* disable rx and tx dma */ - /* - * Ditto the DMA interrupt. - */ - - if (request_irq(IRQ_MAC_MACE_DMA, mace68k_dma_intr, 0, "68K MACE DMA", - dev)) - { - printk(KERN_ERR "MACE: can't get irq %d\n", IRQ_MAC_MACE_DMA); - return -EAGAIN; - } + free_irq(dev->irq, dev); + free_irq(IRQ_MAC_MACE_DMA, dev); - /* Activate the Mac DMA engine */ + free_pages((u32) mp->rx_ring, N_RX_PAGES); + free_pages((u32) mp->tx_ring, 0); - mp->tx_slot = 0; /* Using register set 0 */ - mp->tx_count = 1; /* 1 Buffer ready for use */ - mace68k_txdma_reset(dev); - - /* turn it on! */ - mb->maccc = mp->maccc; - /* enable all interrupts except receive interrupts */ - mb->imr = RCVINT; return 0; } /* - * Shut down the mace and its interrupt channel + * Transmit a frame */ -static int mace68k_close(struct net_device *dev) +static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) { - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; - volatile struct mace *mb = mp->mace; + struct mace_data *mp = (struct mace_data *) dev->priv; - /* disable rx and tx */ - mb->maccc = 0; - mb->imr = 0xff; /* disable all intrs */ + /* Stop the queue if the buffer is full */ - /* disable rx and tx dma */ + if (!mp->tx_count) { + netif_stop_queue(dev); + return 1; + } + mp->tx_count--; + + mp->stats.tx_packets++; + mp->stats.tx_bytes += skb->len; - mace68k_dma_off(dev); + /* We need to copy into our xmit buffer to take care of alignment and caching issues */ - free_irq(dev->irq, dev); - free_irq(IRQ_MAC_MACE_DMA, dev); - return 0; -} + memcpy((void *) mp->tx_ring, skb->data, skb->len); -static inline void mace68k_set_timeout(struct net_device *dev) -{ - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; - unsigned long flags; + /* load the Tx DMA and fire it off */ - save_flags(flags); - cli(); - if (mp->timeout_active) - del_timer(&mp->tx_timeout); - mp->tx_timeout.expires = jiffies + TX_TIMEOUT; - mp->tx_timeout.function = mace68k_tx_timeout; - mp->tx_timeout.data = (unsigned long) dev; - add_timer(&mp->tx_timeout); - mp->timeout_active = 1; - restore_flags(flags); -} + psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, (u32) mp->tx_ring_phys); + psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len); + psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800); -/* - * Transmit a frame - */ - -static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev) -{ - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; - /* - * This may need atomic types ??? - */ + mp->tx_slot ^= 0x10; + + dev_kfree_skb(skb); - printk("mace68k_xmit_start: mp->tx_count = %d, dev->tbusy = %d, mp->tx_ring = %p (%p)\n", - mp->tx_count, dev->tbusy, - mp->tx_ring, virt_to_bus(mp->tx_ring)); - psc_debug_dump(); - - if(mp->tx_count == 0) - { - dev->tbusy=1; - mace68k_dma_intr(IRQ_MAC_MACE_DMA, dev, NULL); - return 1; - } - mp->tx_count--; - - /* - * FIXME: - * This is hackish. The memcpy probably isnt needed but - * the rules for alignment are not known. Ideally we'd like - * to just blast the skb directly to ethernet. We also don't - * use the ring properly - just a one frame buffer. That - * also requires cache pushes ;). - */ - memcpy((void *)mp->tx_ring, skb, skb->len); - psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, virt_to_bus(mp->tx_ring)); - psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len); - psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800); - mp->stats.tx_packets++; - mp->stats.tx_bytes+=skb->len; - dev_kfree_skb(skb); return 0; } -static struct net_device_stats *mace68k_stats(struct net_device *dev) +static struct net_device_stats *mace_stats(struct net_device *dev) { - struct mace68k_data *p = (struct mace68k_data *) dev->priv; + struct mace_data *p = (struct mace_data *) dev->priv; return &p->stats; } -static void mace68k_set_multicast(struct net_device *dev) +static void mace_set_multicast(struct net_device *dev) { - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; int i, j, k, b; u32 crc; + u8 maccc; + + maccc = mb->maccc; + mb->maccc &= ~PROM; - mp->maccc &= ~PROM; - if (dev->flags & IFF_PROMISC) - { - mp->maccc |= PROM; - } else - { + if (dev->flags & IFF_PROMISC) { + mb->maccc |= PROM; + } else { unsigned char multicast_filter[8]; struct dev_mc_list *dmi = dev->mc_list; - if (dev->flags & IFF_ALLMULTI) - { - for (i = 0; i < 8; i++) - multicast_filter[i] = 0xff; - } else - { - for (i = 0; i < 8; i++) + if (dev->flags & IFF_ALLMULTI) { + for (i = 0; i < 8; i++) { + multicast_filter[i] = 0xFF; + } + } else { + for (i = 0; i < 8; i++) { multicast_filter[i] = 0; - for (i = 0; i < dev->mc_count; i++) - { + } + for (i = 0; i < dev->mc_count; i++) { crc = ether_crc_le(6, dmi->dmi_addr); j = crc >> 26; /* bit number in multicast_filter */ multicast_filter[j >> 3] |= 1 << (j & 7); dmi = dmi->next; } } -#if 0 - printk("Multicast filter :"); - for (i = 0; i < 8; i++) - printk("%02x ", multicast_filter[i]); - printk("\n"); -#endif mb->iac = ADDRCHG | LOGADDR; - while ((mb->iac & ADDRCHG) != 0); + while (mb->iac & ADDRCHG); - for (i = 0; i < 8; ++i) + for (i = 0; i < 8; ++i) { mb->ladrf = multicast_filter[i]; + } } - /* reset maccc */ - mb->maccc = mp->maccc; + + mb->maccc = maccc; } /* - * Miscellaneous interrupts are handled here. We may end up - * having to bash the chip on the head for bad errors + * Miscellaneous interrupts are handled here. We may end up + * having to bash the chip on the head for bad errors */ -static void mace68k_handle_misc_intrs(struct mace68k_data *mp, int intr) +static void mace_handle_misc_intrs(struct mace_data *mp, int intr) { volatile struct mace *mb = mp->mace; - static int mace68k_babbles, mace68k_jabbers; + static int mace_babbles, mace_jabbers; - if (intr & MPCO) + if (intr & MPCO) { mp->stats.rx_missed_errors += 256; + } mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ - if (intr & RNTPCO) + + if (intr & RNTPCO) { mp->stats.rx_length_errors += 256; + } mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ - if (intr & CERR) + + if (intr & CERR) { ++mp->stats.tx_heartbeat_errors; - if (intr & BABBLE) - if (mace68k_babbles++ < 4) + } + if (intr & BABBLE) { + if (mace_babbles++ < 4) { printk(KERN_DEBUG "mace: babbling transmitter\n"); - if (intr & JABBER) - if (mace68k_jabbers++ < 4) + } + } + if (intr & JABBER) { + if (mace_jabbers++ < 4) { printk(KERN_DEBUG "mace: jabbering transceiver\n"); + } + } } /* @@ -620,191 +527,172 @@ * the DMA completion) */ -static void mace68k_xmit_error(struct net_device *dev) +static void mace_xmit_error(struct net_device *dev) { - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; u8 xmtfs, xmtrc; xmtfs = mb->xmtfs; xmtrc = mb->xmtrc; - if(xmtfs & XMTSV) - { - if(xmtfs & UFLO) - { + if (xmtfs & XMTSV) { + if (xmtfs & UFLO) { printk("%s: DMA underrun.\n", dev->name); mp->stats.tx_errors++; mp->stats.tx_fifo_errors++; - mace68k_reset(dev); + mace_txdma_reset(dev); } - if(xmtfs & RTRY) + if (xmtfs & RTRY) { mp->stats.collisions++; + } } - mark_bh(NET_BH); } /* * A receive interrupt occurred. */ -static void mace68k_recv_interrupt(struct net_device *dev) +static void mace_recv_interrupt(struct net_device *dev) { -// struct mace68k_data *mp = (struct mace68k_data *) dev->priv; +/* struct mace_data *mp = (struct mace_data *) dev->priv; */ // volatile struct mace *mb = mp->mace; } /* - * Process the chip interrupt + * Process the chip interrupt */ -static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; u8 ir; ir = mb->ir; - mace68k_handle_misc_intrs(mp, ir); + mace_handle_misc_intrs(mp, ir); - if(ir&XMTINT) - mace68k_xmit_error(dev); - if(ir&RCVINT) - mace68k_recv_interrupt(dev); + if (ir & XMTINT) { + mace_xmit_error(dev); + } + if (ir & RCVINT) { + mace_recv_interrupt(dev); + } } -static void mace68k_tx_timeout(unsigned long data) +static void mace_tx_timeout(struct net_device *dev) { -// struct net_device *dev = (struct net_device *) data; -// struct mace68k_data *mp = (struct mace68k_data *) dev->priv; +/* struct mace_data *mp = (struct mace_data *) dev->priv; */ // volatile struct mace *mb = mp->mace; } /* - * Handle a newly arrived frame + * Handle a newly arrived frame */ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) { - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct mace_data *mp = (struct mace_data *) dev->priv; struct sk_buff *skb; - if(mf->status&RS_OFLO) - { + if (mf->status & RS_OFLO) { printk("%s: fifo overflow.\n", dev->name); mp->stats.rx_errors++; mp->stats.rx_fifo_errors++; } - if(mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR)) + if (mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR)) mp->stats.rx_errors++; - if(mf->status&RS_CLSN) + if (mf->status&RS_CLSN) { mp->stats.collisions++; - if(mf->status&RS_FRAMERR) + } + if (mf->status&RS_FRAMERR) { mp->stats.rx_frame_errors++; - if(mf->status&RS_FCSERR) + } + if (mf->status&RS_FCSERR) { mp->stats.rx_crc_errors++; + } skb = dev_alloc_skb(mf->len+2); - if(skb==NULL) - { + if (!skb) { mp->stats.rx_dropped++; return; } skb_reserve(skb,2); memcpy(skb_put(skb, mf->len), mf->data, mf->len); + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; mp->stats.rx_packets++; - mp->stats.rx_bytes+=mf->len; + mp->stats.rx_bytes += mf->len; } /* - * The PSC has passed us a DMA interrupt event. + * The PSC has passed us a DMA interrupt event. */ -static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs) +static void mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct mace_data *mp = (struct mace_data *) dev->priv; + int left, head; + u16 status; + u32 baka; -#if 0 - u32 psc_status; - - /* It seems this must be allowed to stabilise ?? */ - - while((psc_status=psc_read_long(0x0804))!=psc_read_long(0x0804)); + /* Not sure what this does */ + + while ((baka = psc_read_long(PSC_MYSTERY)) != psc_read_long(PSC_MYSTERY)); + if (!(baka & 0x60000000)) return; /* - * Was this an ethernet event ? + * Process the read queue */ - - if(psc_status&0x60000000) - { -#endif - /* - * Process the read queue - */ - u16 psc_status = psc_read_word(PSC_ENETRD_CTL); + status = psc_read_word(PSC_ENETRD_CTL); - printk("mace68k_dma_intr: PSC_ENETRD_CTL = %04X\n", (uint) psc_status); - - if (psc_status & 0x2000) { - mace68k_rxdma_reset(dev); - mp->rx_done = 0; - } else if (psc_status & 0x100) { - int left; - - psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100); - left=psc_read_long(PSC_ENETRD_LEN + mp->rx_slot); - /* read packets */ - - while(mp->rx_done < left) - { - struct mace_frame *mf=((struct mace_frame *) - mp->rx_ring)+mp->rx_done++; - mace_dma_rx_frame(dev, mf); - } + if (status & 0x2000) { + mace_rxdma_reset(dev); + } else if (status & 0x0100) { + psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100); + + left = psc_read_long(PSC_ENETRD_LEN + mp->rx_slot); + head = N_RX_RING - left; + + /* Loop through the ring buffer and process new packages */ + + while (mp->rx_tail < head) { + mace_dma_rx_frame(dev, (struct mace_frame *) (mp->rx_ring + (mp->rx_tail * 0x0800))); + mp->rx_tail++; + } - if(left == 0) /* Out of DMA room */ - { - psc_load_rxdma_base(mp->rx_slot, - (void *)virt_to_phys(mp->rx_ring)); - mp->rx_slot^=16; - mp->rx_done = 0; - } - else - { - psc_write_word(PSC_ENETRD_CMD+mp->rx_slot, - 0x9800); - } - + /* If we're out of buffers in this ring then switch to */ + /* the other set, otherwise just reactivate this one. */ + + if (!left) { + mace_load_rxdma_base(dev, mp->rx_slot); + mp->rx_slot ^= 0x10; + } else { + psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x9800); } + } - /* - * Process the write queue - */ - - psc_status = psc_read_word(PSC_ENETWR_CTL); - printk("mace68k_dma_intr: PSC_ENETWR_CTL = %04X\n", (uint) psc_status); + /* + * Process the write queue + */ - /* apple's driver seems to loop over this until neither */ - /* condition is true. - jmt */ + status = psc_read_word(PSC_ENETWR_CTL); - if (psc_status & 0x2000) { - mace68k_txdma_reset(dev); - } else if (psc_status & 0x0100) { - psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x0100); - mp->tx_slot ^=16; - mp->tx_count++; - dev->tbusy = 0; - mark_bh(NET_BH); - } -#if 0 + if (status & 0x2000) { + mace_txdma_reset(dev); + } else if (status & 0x0100) { + psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100); + mp->tx_sloti ^= 0x10; + mp->tx_count++; + netif_wake_queue(dev); } -#endif } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/macsonic.c linux-2.5/drivers/net/macsonic.c --- linux-2.5.20/drivers/net/macsonic.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/net/macsonic.c Sat May 25 19:52:04 2002 @@ -20,6 +20,9 @@ * and duplicating packets. Needs more testing. * * 99/01/03 MSch: upgraded to version 0.92 of the core driver, fixed. + * + * 00/10/31 sammy@sammy.net: Updated driver for 2.4 kernels, fixed problems + * on centris. */ #include @@ -46,6 +49,7 @@ #include #include #include +#include #include @@ -125,36 +129,42 @@ int __init macsonic_init(struct net_device* dev) { - struct sonic_local* lp = (struct sonic_local *)dev->priv; + struct sonic_local* lp; int i; /* Allocate the entire chunk of memory for the descriptors. Note that this cannot cross a 64K boundary. */ for (i = 0; i < 20; i++) { unsigned long desc_base, desc_top; - if ((lp->sonic_desc = - kmalloc(SIZEOF_SONIC_DESC - * SONIC_BUS_SCALE(lp->dma_bitmode), GFP_KERNEL | GFP_DMA)) == NULL) { + if((lp = kmalloc(sizeof(struct sonic_local), GFP_KERNEL | GFP_DMA)) == NULL) { printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name); return -ENOMEM; } - desc_base = (unsigned long) lp->sonic_desc; - desc_top = desc_base + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode); + + desc_base = (unsigned long) lp; + desc_top = desc_base + sizeof(struct sonic_local); if ((desc_top & 0xffff) >= (desc_base & 0xffff)) break; /* Hmm. try again (FIXME: does this actually work?) */ - kfree(lp->sonic_desc); + kfree(lp); printk(KERN_DEBUG "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n", dev->name, desc_base, desc_top); } - if (lp->sonic_desc == NULL) { + if (lp == NULL) { printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n", dev->name); return -ENOMEM; } + dev->priv = lp; + +#if 0 + /* this code is only here as a curiousity... mainly, where the + fuck did SONIC_BUS_SCALE come from, and what was it supposed + to do? the normal allocation works great for 32 bit stuffs.. */ + /* Now set up the pointers to point to the appropriate places */ lp->cda = lp->sonic_desc; lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); @@ -163,6 +173,15 @@ lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); +#endif + + memset(lp, 0, sizeof(struct sonic_local)); + + lp->cda_laddr = (unsigned int)&(lp->cda); + lp->tda_laddr = (unsigned int)lp->tda; + lp->rra_laddr = (unsigned int)lp->rra; + lp->rda_laddr = (unsigned int)lp->rda; + /* FIXME, maybe we should use skbs */ if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) { @@ -172,15 +191,17 @@ return -ENOMEM; } + lp->rba_laddr = (unsigned int)lp->rba; + { int rs, ds; /* almost always 12*4096, but let's not take chances */ rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096; /* almost always under a page, but let's not take chances */ - ds = ((SIZEOF_SONIC_DESC + 4095) / 4096) * 4096; + ds = ((sizeof(struct sonic_local) + 4095) / 4096) * 4096; kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER); - kernel_set_cachemode(lp->sonic_desc, ds, IOMAP_NOCACHE_SER); + kernel_set_cachemode(lp, ds, IOMAP_NOCACHE_SER); } #if 0 @@ -277,6 +298,7 @@ static int once_is_more_than_enough; struct sonic_local* lp; int i; + int dma_bitmode; if (once_is_more_than_enough) return -ENODEV; @@ -316,7 +338,7 @@ printk("yes\n"); - if (dev) { + if (dev) dev = init_etherdev(dev, sizeof(struct sonic_local)); if (!dev) return -ENOMEM; @@ -328,13 +350,17 @@ } } else { dev = init_etherdev(NULL, sizeof(struct sonic_local)); - } if (dev == NULL) return -ENOMEM; - lp = (struct sonic_local*) dev->priv; - memset(lp, 0, sizeof(struct sonic_local)); + if(dev->priv) { + printk("%s: warning! sonic entering with priv already allocated!\n", + dev->name); + printk("%s: discarding, will attempt to reallocate\n", dev->name); + dev->priv = NULL; + } + /* Danger! My arms are flailing wildly! You *must* set this before using sonic_read() */ @@ -356,8 +382,11 @@ /* The PowerBook's SONIC is 16 bit always. */ if (macintosh_config->ident == MAC_MODEL_PB520) { - lp->reg_offset = 0; - lp->dma_bitmode = 0; + reg_offset = 0; + dma_bitmode = 0; + } else if (macintosh_config->ident == MAC_MODEL_C610) { + reg_offset = 0; + dma_bitmode = 1; } else { /* Some of the comm-slot cards are 16 bit. But some of them are not. The 32-bit cards use offset 2 and @@ -368,27 +397,41 @@ /* Technically this is not necessary since we zeroed it above */ - lp->reg_offset = 0; - lp->dma_bitmode = 0; + reg_offset = 0; + dma_bitmode = 0; sr = sonic_read(dev, SONIC_SR); if (sr == 0 || sr == 0xffff) { - lp->reg_offset = 2; + reg_offset = 2; /* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */ sr = sonic_read(dev, SONIC_SR); - lp->dma_bitmode = 1; + dma_bitmode = 1; } printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", - dev->name, sr, lp->dma_bitmode?32:16, lp->reg_offset); + dev->name, sr, dma_bitmode?32:16, reg_offset); } + - + /* this carries my sincere apologies -- by the time I got to updating + the driver, support for "reg_offsets" appeares nowhere in the sonic + code, going back for over a year. Fortunately, my Mac does't seem + to use whatever this was. + + If you know how this is supposed to be implemented, either fix it, + or contact me (sammy@sammy.net) to explain what it is. --Sam */ + + if(reg_offset) { + printk("%s: register offset unsupported. please fix this if you know what it is.\n", dev->name); + return -ENODEV; + } + /* Software reset, then initialize control registers. */ sonic_write(dev, SONIC_CMD, SONIC_CR_RST); sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | - (lp->dma_bitmode ? SONIC_DCR_DW : 0)); + (dma_bitmode ? SONIC_DCR_DW : 0)); + /* This *must* be written back to in order to restore the extended programmable output bits */ sonic_write(dev, SONIC_DCR2, 0); @@ -452,7 +495,7 @@ u16 sonic_dcr; int id; int i; - int reg_offset, dma_bitmode; + int dma_bitmode; /* Find the first SONIC that hasn't been initialized already */ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, @@ -538,8 +581,6 @@ memset(lp, 0, sizeof(struct sonic_local)); /* Danger! My arms are flailing wildly! You *must* set this before using sonic_read() */ - lp->reg_offset = reg_offset; - lp->dma_bitmode = dma_bitmode; dev->base_addr = base_addr; dev->irq = SLOT2IRQ(ndev->board->slot); @@ -552,6 +593,11 @@ printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset); + if(reg_offset) { + printk("%s: register offset unsupported. please fix this if you know what it is.\n", dev->name); + return -ENODEV; + } + /* Software reset, then initialize control registers. */ sonic_write(dev, SONIC_CMD, SONIC_CR_RST); sonic_write(dev, SONIC_DCR, sonic_dcr @@ -614,6 +660,9 @@ #define vdma_free(baz) #define sonic_chiptomem(bat) (bat) #define PHYSADDR(quux) (quux) + +#define sonic_request_irq request_irq +#define sonic_free_irq free_irq #include "sonic.c" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/natsemi.c linux-2.5/drivers/net/natsemi.c --- linux-2.5.20/drivers/net/natsemi.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/net/natsemi.c Fri Mar 1 01:25:56 2002 @@ -101,19 +101,56 @@ version 1.0.13: * ETHTOOL_[GS]EEPROM support (Tim Hockin) - - version 1.0.13: * crc cleanup (Matt Domsch ) + version 1.0.14: + * Cleanup some messages and autoneg in ethtool (Tim Hockin) + * OOM error handling. + * reinit_ring() instead of {drain,init}_ring(). + * Rx status FIFO overrun bug fixed: + The nic sets that bit instead of IntrRxDone, + just call netdev_rx and hang is gone. + TODO: * big endian support with CFG:BEM instead of cpu_to_le32 * support for an external PHY * flow control */ +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include + #define DRV_NAME "natsemi" -#define DRV_VERSION "1.07+LK1.0.13" -#define DRV_RELDATE "Nov 12, 2001" +#define DRV_VERSION "1.07+LK1.0.14" +#define DRV_RELDATE "Nov 27, 2001" /* Updated to recommendations in pci-skeleton v2.03. */ @@ -132,7 +169,12 @@ /* The user-configurable values. These may be modified when a driver module is loaded.*/ -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +#define NATSEMI_DEF_MSG (NETIF_MSG_DRV | \ + NETIF_MSG_LINK | \ + NETIF_MSG_WOL | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) +static int debug = NATSEMI_DEF_MSG; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -164,7 +206,7 @@ There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */ -#define RX_RING_SIZE 64 +#define RX_RING_SIZE 32 /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -183,37 +225,6 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ -#if !defined(__OPTIMIZE__) -#warning You must compile this file with the correct options! -#warning See the last lines of the source file. -#error You must compile this driver with "-O". -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Processor type for cache alignment. */ -#include -#include -#include -#include - /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = KERN_INFO DRV_NAME ".c:v1.07 1/9/2001 Written by Donald Becker \n" @@ -232,7 +243,7 @@ MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(max_interrupt_work, "DP8381x maximum events handled per interrupt"); MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); -MODULE_PARM_DESC(debug, "DP8381x debug level (0-5)"); +MODULE_PARM_DESC(debug, "DP8381x debug bitmask"); MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex"); MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)"); @@ -421,6 +432,7 @@ enum ChipConfig_bits { CfgPhyDis = 0x200, CfgPhyRst = 0x400, + CfgExtPhy = 0x1000, CfgAnegEnable = 0x2000, CfgAneg100 = 0x4000, CfgAnegFull = 0x8000, @@ -619,6 +631,7 @@ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int oom; /* These values are keep track of the transceiver/media in use. */ unsigned int full_duplex; /* Rx filter. */ @@ -634,6 +647,7 @@ u16 advertising; /* NWay media advertisement */ unsigned int iosize; spinlock_t lock; + u32 msg_enable; }; static int eeprom_read(long ioaddr, int location); @@ -647,9 +661,12 @@ static void netdev_timer(unsigned long data); static void tx_timeout(struct net_device *dev); static int alloc_ring(struct net_device *dev); +static void refill_rx(struct net_device *dev); static void init_ring(struct net_device *dev); +static void drain_tx(struct net_device *dev); static void drain_ring(struct net_device *dev); static void free_ring(struct net_device *dev); +static void reinit_ring(struct net_device *dev); static void init_registers(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); @@ -753,6 +770,7 @@ pci_set_drvdata(pdev, dev); np->iosize = iosize; spin_lock_init(&np->lock); + np->msg_enable = debug; /* Reset the chip to erase previous misconfiguration. */ natsemi_reload_eeprom(dev); @@ -767,7 +785,8 @@ if (option & 0x200) np->full_duplex = 1; if (option & 15) - printk(KERN_INFO "%s: ignoring user supplied media type %d", + printk(KERN_INFO + "%s: ignoring user supplied media type %d", dev->name, option & 15); } if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) @@ -796,14 +815,17 @@ } netif_carrier_off(dev); - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, natsemi_pci_info[chip_idx].name, ioaddr); - for (i = 0; i < ETH_ALEN-1; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + if (netif_msg_drv(np)) { + printk(KERN_INFO "%s: %s at %#08lx, ", + dev->name, natsemi_pci_info[chip_idx].name, ioaddr); + for (i = 0; i < ETH_ALEN-1; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x, IRQ %d.\n", dev->dev_addr[i], irq); + } np->advertising = mdio_read(dev, 1, MII_ADVERTISE); - if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) { + if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000 + && netif_msg_probe(np)) { u32 chip_config = readl(ioaddr + ChipConfig); printk(KERN_INFO "%s: Transceiver default autonegotiation %s " "10%s %s duplex.\n", @@ -812,12 +834,18 @@ chip_config & CfgAneg100 ? "0" : "", chip_config & CfgAnegFull ? "full" : "half"); } - printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", - dev->name, mdio_read(dev, 1, MII_BMSR), - np->advertising); + if (netif_msg_probe(np)) + printk(KERN_INFO + "%s: Transceiver status %#04x advertising %#04x.\n", + dev->name, mdio_read(dev, 1, MII_BMSR), + np->advertising); /* save the silicon revision for later querying */ np->srr = readl(ioaddr + SiliconRev); + if (netif_msg_hw(np)) + printk(KERN_INFO "%s: silicon revision %#04x.\n", + dev->name, np->srr); + return 0; } @@ -914,6 +942,7 @@ u32 rfcr; u16 pmatch[3]; u16 sopass[3]; + struct netdev_private *np = dev->priv; /* * Resetting the chip causes some registers to be lost. @@ -947,10 +976,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: reset did not complete in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: reset completed in %d usec.\n", dev->name, i*5); } @@ -979,6 +1008,7 @@ static void natsemi_reload_eeprom(struct net_device *dev) { + struct netdev_private *np = dev->priv; int i; writel(EepromReload, dev->base_addr + PCIBusCfg); @@ -987,10 +1017,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: EEPROM did not reload in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: EEPROM reloaded in %d usec.\n", dev->name, i*5); } @@ -999,6 +1029,7 @@ static void natsemi_stop_rxtx(struct net_device *dev) { long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; int i; writel(RxOff | TxOff, ioaddr + ChipCmd); @@ -1007,10 +1038,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n", dev->name, i*5); } @@ -1028,7 +1059,7 @@ i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); if (i) return i; - if (debug > 1) + if (netif_msg_ifup(np)) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", dev->name, dev->irq); i = alloc_ring(dev); @@ -1043,8 +1074,8 @@ netif_start_queue(dev); - if (debug > 2) - printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n", + if (netif_msg_ifup(np)) + printk(KERN_DEBUG "%s: Done netdev_open(), status: %#08x.\n", dev->name, (int)readl(ioaddr + ChipCmd)); /* Set the timer to check for link beat. */ @@ -1064,19 +1095,18 @@ int duplex; int chipcfg = readl(ioaddr + ChipConfig); - if(!(chipcfg & CfgLink)) { + if (!(chipcfg & CfgLink)) { if (netif_carrier_ok(dev)) { - if (debug) - printk(KERN_INFO "%s: no link. Disabling watchdog.\n", + if (netif_msg_link(np)) + printk(KERN_NOTICE "%s: link down.\n", dev->name); netif_carrier_off(dev); } return; } if (!netif_carrier_ok(dev)) { - if (debug) - printk(KERN_INFO "%s: link is back. Enabling watchdog.\n", - dev->name); + if (netif_msg_link(np)) + printk(KERN_NOTICE "%s: link up.\n", dev->name); netif_carrier_on(dev); } @@ -1084,10 +1114,11 @@ /* if duplex is set then bit 28 must be set, too */ if (duplex ^ !!(np->rx_config & RxAcceptTx)) { - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link" - " capability.\n", dev->name, - duplex ? "full" : "half"); + if (netif_msg_link(np)) + printk(KERN_INFO + "%s: Setting %s-duplex based on negotiated " + "link capability.\n", dev->name, + duplex ? "full" : "half"); if (duplex) { np->rx_config |= RxAcceptTx; np->tx_config |= TxCarrierIgn | TxHeartIgn; @@ -1106,17 +1137,12 @@ long ioaddr = dev->base_addr; int i; - /* save the silicon revision for later */ - if (debug > 4) - printk(KERN_DEBUG "%s: found silicon revision %xh.\n", - dev->name, np->srr); - for (i=0;ibase_addr + ChipConfig) & CfgAnegDone) break; udelay(10); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_link(np)) { printk(KERN_INFO "%s: autonegotiation did not complete in %d usec.\n", dev->name, i*10); @@ -1181,8 +1207,8 @@ * nothing will be written to memory. */ np->SavedClkRun = readl(ioaddr + ClkRun); writel(np->SavedClkRun & ~PMEEnable, ioaddr + ClkRun); - if (np->SavedClkRun & PMEStatus) { - printk(KERN_NOTICE "%s: Wake-up event %8.8x\n", + if (np->SavedClkRun & PMEStatus && netif_msg_wol(np)) { + printk(KERN_NOTICE "%s: Wake-up event %#08x\n", dev->name, readl(ioaddr + WOLCmd)); } @@ -1198,11 +1224,15 @@ } /* - * The frequency on this has been increased because of a nasty little problem. + * netdev_timer: + * Purpose: + * 1) check for link changes. Usually they are handled by the MII interrupt + * 2) check for sudden death of the NIC: * It seems that a reference set for this chip went out with incorrect info, * and there exist boards that aren't quite right. An unexpected voltage drop * can cause the PHY to get itself in a weird state (basically reset..). * NOTE: this only seems to affect revC chips. + * 3) check of death of the RX path due to OOM. */ static void netdev_timer(unsigned long data) { @@ -1212,7 +1242,7 @@ long ioaddr = dev->base_addr; u16 dspcfg; - if (debug > 3) { + if (netif_msg_timer(np)) { /* DO NOT read the IntrStatus register, * a read clears any pending interrupts. */ @@ -1220,17 +1250,23 @@ dev->name); } + spin_lock_irq(&np->lock); + /* check for a nasty random phy-reset - use dspcfg as a flag */ writew(1, ioaddr+PGSEL); dspcfg = readw(ioaddr+DSPCFG); writew(0, ioaddr+PGSEL); if (dspcfg != DSPCFG_VAL) { if (!netif_queue_stopped(dev)) { - printk(KERN_INFO - "%s: possible phy reset: re-initializing\n", - dev->name); + spin_unlock_irq(&np->lock); + if (netif_msg_hw(np)) + printk(KERN_NOTICE + "%s: possible phy reset: re-initializing\n", + dev->name); disable_irq(dev->irq); spin_lock_irq(&np->lock); + natsemi_reset(dev); + reinit_ring(dev); init_registers(dev); spin_unlock_irq(&np->lock); enable_irq(dev->irq); @@ -1240,9 +1276,19 @@ } } else { /* init_registers() calls check_link() for the above case */ - spin_lock_irq(&np->lock); check_link(dev); - spin_unlock_irq(&np->lock); + } + spin_unlock_irq(&np->lock); + if (np->oom) { + disable_irq(dev->irq); + np->oom = 0; + refill_rx(dev); + enable_irq(dev->irq); + if (!np->oom) { + writel(RxOn, dev->base_addr + ChipCmd); + } else { + next_tick = 1; + } } mod_timer(&np->timer, jiffies + next_tick); } @@ -1251,18 +1297,18 @@ { struct netdev_private *np = dev->priv; - if (debug > 2) { + if (netif_msg_pktdata(np)) { int i; printk(KERN_DEBUG " Tx ring at %p:\n", np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) { - printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n", i, np->tx_ring[i].next_desc, np->tx_ring[i].cmd_status, np->tx_ring[i].addr); } printk(KERN_DEBUG " Rx ring %p:\n", np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) { - printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n", i, np->rx_ring[i].next_desc, np->rx_ring[i].cmd_status, np->rx_ring[i].addr); @@ -1278,14 +1324,15 @@ disable_irq(dev->irq); spin_lock_irq(&np->lock); if (netif_device_present(dev)) { - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", - dev->name, readl(ioaddr + IntrStatus)); + if (netif_msg_tx_err(np)) + printk(KERN_WARNING + "%s: Transmit timed out, status %#08x," + " resetting...\n", + dev->name, readl(ioaddr + IntrStatus)); dump_ring(dev); natsemi_reset(dev); - drain_ring(dev); - init_ring(dev); + reinit_ring(dev); init_registers(dev); } else { printk(KERN_WARNING @@ -1312,15 +1359,53 @@ return 0; } +static void refill_rx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + int entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_dma[entry] = pci_map_single(np->pci_dev, + skb->data, skb->len, PCI_DMA_FROMDEVICE); + np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); + } + np->rx_ring[entry].cmd_status = + cpu_to_le32(np->rx_buf_sz); + } + if (np->cur_rx - np->dirty_rx == RX_RING_SIZE) { + if (debug > 2) + printk(KERN_INFO "%s: going OOM.\n", dev->name); + np->oom = 1; + } +} + /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void init_ring(struct net_device *dev) { struct netdev_private *np = dev->priv; int i; - np->cur_rx = np->cur_tx = 0; - np->dirty_rx = np->dirty_tx = 0; + /* 1) TX ring */ + np->dirty_tx = np->cur_tx = 0; + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = NULL; + np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma + +sizeof(struct netdev_desc) + *((i+1)%TX_RING_SIZE+RX_RING_SIZE)); + np->tx_ring[i].cmd_status = 0; + } + /* 2) RX ring */ + np->dirty_rx = 0; + np->cur_rx = RX_RING_SIZE; np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); np->rx_head_desc = &np->rx_ring[0]; @@ -1335,29 +1420,25 @@ np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn); np->rx_skbuff[i] = NULL; } + refill_rx(dev); + dump_ring(dev); +} - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_dma[i] = pci_map_single(np->pci_dev, - skb->data, skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[i].addr = cpu_to_le32(np->rx_dma[i]); - np->rx_ring[i].cmd_status = cpu_to_le32(np->rx_buf_sz); - } - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); +static void drain_tx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + int i; for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_skbuff[i]) { + pci_unmap_single(np->pci_dev, + np->rx_dma[i], + np->rx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(np->tx_skbuff[i]); + } np->tx_skbuff[i] = NULL; - np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma - +sizeof(struct netdev_desc) - *((i+1)%TX_RING_SIZE+RX_RING_SIZE)); - np->tx_ring[i].cmd_status = 0; } - dump_ring(dev); } static void drain_ring(struct net_device *dev) @@ -1378,16 +1459,29 @@ } np->rx_skbuff[i] = NULL; } - for (i = 0; i < TX_RING_SIZE; i++) { - if (np->tx_skbuff[i]) { - pci_unmap_single(np->pci_dev, - np->rx_dma[i], - np->rx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb(np->tx_skbuff[i]); - } - np->tx_skbuff[i] = NULL; - } + drain_tx(dev); +} + +static void reinit_ring(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + int i; + + /* drain TX ring */ + drain_tx(dev); + np->dirty_tx = np->cur_tx = 0; + for (i=0;itx_ring[i].cmd_status = 0; + + /* RX Ring */ + np->dirty_rx = 0; + np->cur_rx = RX_RING_SIZE; + np->rx_head_desc = &np->rx_ring[0]; + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) + np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn); + + refill_rx(dev); } static void free_ring(struct net_device *dev) @@ -1438,7 +1532,7 @@ dev->trans_start = jiffies; - if (debug > 4) { + if (netif_msg_tx_queued(np)) { printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } @@ -1451,14 +1545,11 @@ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; - if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) { - if (debug > 4) - printk(KERN_DEBUG "%s: tx frame #%d is busy.\n", - dev->name, np->dirty_tx); + if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) break; - } - if (debug > 4) - printk(KERN_DEBUG "%s: tx frame #%d finished with status %8.8xh.\n", + if (netif_msg_tx_done(np)) + printk(KERN_DEBUG + "%s: tx frame #%d finished, status %#08x.\n", dev->name, np->dirty_tx, le32_to_cpu(np->tx_ring[entry].cmd_status)); if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescPktOK)) { @@ -1495,21 +1586,18 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = dev_instance; - struct netdev_private *np; - long ioaddr; + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; int boguscnt = max_interrupt_work; - ioaddr = dev->base_addr; - np = dev->priv; - if (!netif_device_present(dev)) return; do { /* Reading automatically acknowledges all int sources. */ u32 intr_status = readl(ioaddr + IntrStatus); - if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + if (netif_msg_intr(np)) + printk(KERN_DEBUG "%s: Interrupt, status %#08x.\n", dev->name, intr_status); if (intr_status == 0) @@ -1530,13 +1618,13 @@ if (--boguscnt < 0) { printk(KERN_WARNING "%s: Too much work at interrupt, " - "status=0x%4.4x.\n", + "status=%#08x.\n", dev->name, intr_status); break; } } while (1); - if (debug > 4) + if (netif_msg_intr(np)) printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name); } @@ -1552,22 +1640,24 @@ /* If the driver owns the next entry it's a new packet. Send it up. */ while (desc_status < 0) { /* e.g. & DescOwn */ - if (debug > 4) - printk(KERN_DEBUG " In netdev_rx() entry %d status was %8.8x.\n", - entry, desc_status); + if (netif_msg_rx_status(np)) + printk(KERN_DEBUG + " netdev_rx() entry %d status was %#08x.\n", + entry, desc_status); if (--boguscnt < 0) break; - if ((desc_status & (DescMore|DescPktOK|DescRxLong)) != DescPktOK) { + if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){ if (desc_status & DescMore) { - printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " - "multiple buffers, entry %#x status %x.\n", - dev->name, np->cur_rx, desc_status); + if (netif_msg_rx_err(np)) + printk(KERN_WARNING + "%s: Oversized(?) Ethernet " + "frame spanned multiple " + "buffers, entry %#08x " + "status %#08x.\n", dev->name, + np->cur_rx, desc_status); np->stats.rx_length_errors++; } else { - /* There was a error. */ - if (debug > 2) - printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", - desc_status); + /* There was an error. */ np->stats.rx_errors++; if (desc_status & (DescRxAbort|DescRxOver)) np->stats.rx_over_errors++; @@ -1582,8 +1672,8 @@ struct sk_buff *skb; /* Omit CRC size. */ int pkt_len = (desc_status & DescSizeMask) - 4; - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ + /* Check if the packet is long enough to accept + * without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; @@ -1617,26 +1707,14 @@ desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); } - /* Refill the Rx ring buffers. */ - for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { - struct sk_buff *skb; - entry = np->dirty_rx % RX_RING_SIZE; - if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[entry] = skb; - if (skb == NULL) - break; /* Better luck next round. */ - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_dma[entry] = pci_map_single(np->pci_dev, - skb->data, skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); - } - np->rx_ring[entry].cmd_status = - cpu_to_le32(np->rx_buf_sz); - } + refill_rx(dev); /* Restart Rx engine if stopped. */ - writel(RxOn, dev->base_addr + ChipCmd); + if (np->oom) + mod_timer(&np->timer, jiffies + 1); + else + writel(RxOn, dev->base_addr + ChipCmd); + } static void netdev_error(struct net_device *dev, int intr_status) @@ -1646,11 +1724,16 @@ spin_lock(&np->lock); if (intr_status & LinkChange) { - printk(KERN_NOTICE - "%s: Link changed: Autonegotiation advertising" - " %4.4x partner %4.4x.\n", dev->name, - (int)mdio_read(dev, 1, MII_ADVERTISE), - (int)mdio_read(dev, 1, MII_LPA)); + u16 adv = mdio_read(dev, 1, MII_ADVERTISE); + u16 lpa = mdio_read(dev, 1, MII_LPA); + if (mdio_read(dev, 1, MII_BMCR) & BMCR_ANENABLE + && netif_msg_link(np)) { + printk(KERN_INFO + "%s: Autonegotiation advertising" + " %#04x partner %#04x.\n", dev->name, + adv, lpa); + } + /* read MII int status to clear the flag */ readw(ioaddr + MIntrStatus); check_link(dev); @@ -1661,18 +1744,19 @@ if (intr_status & IntrTxUnderrun) { if ((np->tx_config & TxDrthMask) < 62) np->tx_config += 2; - if (debug > 2) - printk(KERN_NOTICE "%s: increasing Tx theshold, new tx cfg %8.8xh.\n", - dev->name, np->tx_config); + if (netif_msg_tx_err(np)) + printk(KERN_NOTICE + "%s: increased Tx theshold, txcfg %#08x.\n", + dev->name, np->tx_config); writel(np->tx_config, ioaddr + TxConfig); } - if (intr_status & WOLPkt) { + if (intr_status & WOLPkt && netif_msg_wol(np)) { int wol_status = readl(ioaddr + WOLCmd); - printk(KERN_NOTICE "%s: Link wake-up event %8.8x\n", + printk(KERN_NOTICE "%s: Link wake-up event %#08x\n", dev->name, wol_status); } if (intr_status & RxStatusFIFOOver) { - if (debug >= 2) { + if (netif_msg_rx_err(np) && netif_msg_intr(np)) { printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", dev->name); } @@ -1680,10 +1764,8 @@ } /* Hmmmmm, it's not clear how to recover from PCI faults. */ if (intr_status & IntrPCIErr) { - if (debug) { - printk(KERN_NOTICE "%s: PCI error %08x\n", dev->name, - intr_status & IntrPCIErr); - } + printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name, + intr_status & IntrPCIErr); np->stats.tx_fifo_errors++; np->stats.rx_fifo_errors++; } @@ -1761,7 +1843,8 @@ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ - printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", + dev->name); rx_mode = RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys; } else if ((dev->mc_count > multicast_filter_limit) @@ -1896,7 +1979,7 @@ /* get message-level */ case ETHTOOL_GMSGLVL: { struct ethtool_value edata = {ETHTOOL_GMSGLVL}; - edata.data = debug; + edata.data = np->msg_enable; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; @@ -1906,7 +1989,7 @@ struct ethtool_value edata; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; - debug = edata.data; + np->msg_enable = edata.data; return 0; } /* restart autonegotiation */ @@ -2096,18 +2179,22 @@ ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_TP); + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); - /* only supports twisted-pair */ - ecmd->port = PORT_TP; + /* only supports twisted-pair or MII */ + tmp = readl(dev->base_addr + ChipConfig); + if (tmp & CfgExtPhy) + ecmd->port = PORT_MII; + else + ecmd->port = PORT_TP; /* only supports internal transceiver */ ecmd->transceiver = XCVR_INTERNAL; - /* this isn't fully supported at higher layers */ + /* not sure what this is for */ ecmd->phy_address = readw(dev->base_addr + PhyCtrl) & PhyAddrMask; - ecmd->advertising = ADVERTISED_TP; + ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; tmp = mdio_read(dev, 1, MII_ADVERTISE); if (tmp & ADVERTISE_10HALF) ecmd->advertising |= ADVERTISED_10baseT_Half; @@ -2118,20 +2205,21 @@ if (tmp & ADVERTISE_100FULL) ecmd->advertising |= ADVERTISED_100baseT_Full; - tmp = readl(dev->base_addr + ChipConfig); - if (tmp & CfgAnegEnable) { + tmp = mdio_read(dev, 1, MII_BMCR); + if (tmp & BMCR_ANENABLE) { ecmd->advertising |= ADVERTISED_Autoneg; ecmd->autoneg = AUTONEG_ENABLE; } else { ecmd->autoneg = AUTONEG_DISABLE; } + tmp = readl(dev->base_addr + ChipConfig); if (tmp & CfgSpeed100) { ecmd->speed = SPEED_100; } else { ecmd->speed = SPEED_10; } - + if (tmp & CfgFullDuplex) { ecmd->duplex = DUPLEX_FULL; } else { @@ -2152,7 +2240,7 @@ return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; - if (ecmd->port != PORT_TP) + if (ecmd->port != PORT_TP && ecmd->port != PORT_MII) return -EINVAL; if (ecmd->transceiver != XCVR_INTERNAL) return -EINVAL; @@ -2162,39 +2250,22 @@ /* WHEW! now lets bang some bits */ + tmp = mdio_read(dev, 1, MII_BMCR); if (ecmd->autoneg == AUTONEG_ENABLE) { - /* advertise only what has been requested */ - tmp = readl(dev->base_addr + ChipConfig); - tmp &= ~(CfgAneg100 | CfgAnegFull); - tmp |= CfgAnegEnable; - if (ecmd->advertising & ADVERTISED_100baseT_Half - || ecmd->advertising & ADVERTISED_100baseT_Full) { - tmp |= CfgAneg100; - } - if (ecmd->advertising & ADVERTISED_10baseT_Full - || ecmd->advertising & ADVERTISED_100baseT_Full) { - tmp |= CfgAnegFull; - } - writel(tmp, dev->base_addr + ChipConfig); - /* turn on autonegotiation, and force a renegotiate */ - tmp = mdio_read(dev, 1, MII_BMCR); - tmp |= (BMCR_ANENABLE | BMCR_ANRESTART); - mdio_write(dev, 1, MII_BMCR, tmp); + /* turn on autonegotiation */ + tmp |= BMCR_ANENABLE; np->advertising = mdio_read(dev, 1, MII_ADVERTISE); } else { /* turn off auto negotiation, set speed and duplexity */ - tmp = mdio_read(dev, 1, MII_BMCR); tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); - if (ecmd->speed == SPEED_100) { + if (ecmd->speed == SPEED_100) tmp |= BMCR_SPEED100; - } - if (ecmd->duplex == DUPLEX_FULL) { + if (ecmd->duplex == DUPLEX_FULL) tmp |= BMCR_FULLDPLX; - } else { + else np->full_duplex = 0; - } - mdio_write(dev, 1, MII_BMCR, tmp); } + mdio_write(dev, 1, MII_BMCR, tmp); return 0; } @@ -2229,7 +2300,7 @@ /* the interrupt status is clear-on-read - see if we missed any */ if (rbuf[4] & rbuf[5]) { printk(KERN_WARNING - "%s: shoot, we dropped an interrupt (0x%x)\n", + "%s: shoot, we dropped an interrupt (%#08x)\n", dev->name, rbuf[4] & rbuf[5]); } @@ -2269,18 +2340,15 @@ case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ data->phy_id = 1; /* Fall Through */ case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, @@ -2296,7 +2364,7 @@ long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; - if (debug > 1) + if (netif_msg_wol(np)) printk(KERN_INFO "%s: remaining active for wake-on-lan\n", dev->name); @@ -2319,7 +2387,8 @@ /* enable the WOL interrupt. * Could be used to send a netlink message. */ - writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask); + writel(WOLPkt, ioaddr + IntrMask); + writel(1, ioaddr + IntrEnable); } } @@ -2329,22 +2398,28 @@ struct netdev_private *np = dev->priv; netif_stop_queue(dev); - netif_carrier_off(dev); - if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", - dev->name, (int)readl(ioaddr + ChipCmd)); - printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", - dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); - } + if (netif_msg_ifdown(np)) + printk(KERN_DEBUG + "%s: Shutting down ethercard, status was %#04x.\n", + dev->name, (int)readl(ioaddr + ChipCmd)); + if (netif_msg_pktdata(np)) + printk(KERN_DEBUG + "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, + np->cur_rx, np->dirty_rx); + /* Disable interrupts, and flush posted writes */ + writel(0, ioaddr + IntrEnable); + readl(ioaddr + IntrEnable); + free_irq(dev->irq, dev); del_timer_sync(&np->timer); - - disable_irq(dev->irq); + /* Interrupt disabled, interrupt handler released, + * queue stopped, timer deleted. All async codepaths + * that access the driver are disabled. + */ spin_lock_irq(&np->lock); - /* Disable and clear interrupts */ - writel(0, ioaddr + IntrEnable); readl(ioaddr + IntrMask); readw(ioaddr + MIntrStatus); @@ -2357,17 +2432,6 @@ __get_stats(dev); spin_unlock_irq(&np->lock); - /* race: shared irq and as most nics the DP83815 - * reports _all_ interrupt conditions in IntrStatus, even - * disabled ones. - * packet received after disable_irq, but before stop_rxtx - * --> race. intr_handler would restart the rx process. - * netif_device_{de,a}tach around {enable,free}_irq. - */ - netif_device_detach(dev); - enable_irq(dev->irq); - free_irq(dev->irq, dev); - netif_device_attach(dev); /* clear the carrier last - an interrupt could reenable it otherwise */ netif_carrier_off(dev); @@ -2375,7 +2439,7 @@ drain_ring(dev); free_ring(dev); - { + { u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary; if (wol) { /* restart the NIC in WOL mode. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/ni65.c linux-2.5/drivers/net/ni65.c --- linux-2.5.20/drivers/net/ni65.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/net/ni65.c Fri May 17 01:32:54 2002 @@ -353,18 +353,21 @@ unsigned long flags; for(i=0;i= 0) { if(inb(ioaddr+cards[i].id_offset+0) != cards[i].id0 || inb(ioaddr+cards[i].id_offset+1) != cards[i].id1) { + release_region(ioaddr, cards[i].total_size); continue; } } if(cards[i].vendor_id) { for(j=0;j<3;j++) - if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j]) + if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j]) { + release_region(ioaddr, cards[i].total_size); continue; + } } break; } @@ -374,8 +377,10 @@ for(j=0;j<6;j++) dev->dev_addr[j] = inb(ioaddr+cards[i].addr_offset+j); - if( (j=ni65_alloc_buffer(dev)) < 0) + if( (j=ni65_alloc_buffer(dev)) < 0) { + release_region(ioaddr, cards[i].total_size); return j; + } p = (struct priv *) dev->priv; p->cmdr_addr = ioaddr + cards[i].cmd_offset; p->cardno = i; @@ -386,6 +391,7 @@ if( (j=readreg(CSR0)) != 0x4) { printk(KERN_ERR "can't RESET card: %04x\n",j); ni65_free_buffer(p); + release_region(ioaddr, cards[p->cardno].total_size); return -EAGAIN; } @@ -437,6 +443,7 @@ if(i == 5) { printk("Can't detect DMA channel!\n"); ni65_free_buffer(p); + release_region(ioaddr, cards[p->cardno].total_size); return -EAGAIN; } dev->dma = dmatab[i]; @@ -459,6 +466,7 @@ { printk("Failed to detect IRQ line!\n"); ni65_free_buffer(p); + release_region(ioaddr, cards[p->cardno].total_size); return -EAGAIN; } printk("IRQ %d (autodetected).\n",dev->irq); @@ -471,13 +479,9 @@ { printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma); ni65_free_buffer(p); + release_region(ioaddr, cards[p->cardno].total_size); return -EAGAIN; } - - /* - * Grab the region so we can find another board. - */ - request_region(ioaddr,cards[p->cardno].total_size,cards[p->cardno].cardname); dev->base_addr = ioaddr; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/pcmcia/Config.help linux-2.5/drivers/net/pcmcia/Config.help --- linux-2.5.20/drivers/net/pcmcia/Config.help Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/net/pcmcia/Config.help Tue Feb 26 21:24:49 2002 @@ -145,7 +145,7 @@ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will be called xircom_tulip_cb.o. If you want to compile + The module will be called xircom_cb.o. If you want to compile it as a module, say M here and read . If unsure, say N. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/pcmcia/Config.in linux-2.5/drivers/net/pcmcia/Config.in --- linux-2.5.20/drivers/net/pcmcia/Config.in Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/net/pcmcia/Config.in Tue Mar 12 22:45:36 2002 @@ -11,10 +11,10 @@ dep_tristate ' 3Com 3c574 PCMCIA support' CONFIG_PCMCIA_3C574 $CONFIG_PCMCIA dep_tristate ' Fujitsu FMV-J18x PCMCIA support' CONFIG_PCMCIA_FMVJ18X $CONFIG_PCMCIA dep_tristate ' NE2000 compatible PCMCIA support' CONFIG_PCMCIA_PCNET $CONFIG_PCMCIA + dep_tristate ' Asix AX88190 PCMCIA support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA dep_tristate ' New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA - dep_tristate ' broken NS8390-cards support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA if [ "$CONFIG_IBMTR" != "y" ]; then dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/pcmcia/axnet_cs.c linux-2.5/drivers/net/pcmcia/axnet_cs.c --- linux-2.5.20/drivers/net/pcmcia/axnet_cs.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/net/pcmcia/axnet_cs.c Thu Dec 13 16:32:36 2001 @@ -11,7 +11,7 @@ Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net - axnet_cs.c 1.11 2001/06/12 12:42:40 + axnet_cs.c 1.24 2001/11/18 02:46:51 The network driver code is based on Donald Becker's NE2000 code: @@ -20,7 +20,7 @@ Director, National Security Agency. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov + Donald Becker may be reached at becker@scyld.com ======================================================================*/ @@ -33,12 +33,13 @@ #include #include #include +#include #include #include #include #include -#include "ax8390.h" +#include "../8390.h" #include #include @@ -51,7 +52,6 @@ #define AXNET_CMD 0x00 #define AXNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */ #define AXNET_RESET 0x1f /* Issue a read to reset, a write to clear. */ -#define AXNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */ #define AXNET_MII_EEP 0x14 /* Offset of MII access port */ #define AXNET_START_PG 0x40 /* First page of TX buffer */ @@ -59,26 +59,13 @@ #define AXNET_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */ -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"axnet_cs.c 1.11 2001/06/12 12:42:40 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - -#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb); -#define skb_tx_check(dev, skb) -#define add_rx_bytes(stats, n) (stats)->rx_bytes += n; -#define add_tx_bytes(stats, n) (stats)->tx_bytes += n; -#define netif_mark_up(dev) do { } while (0) -#define netif_mark_down(dev) do { } while (0) - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver"); +MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") @@ -87,9 +74,14 @@ static int irq_list[4] = { -1 }; MODULE_PARM(irq_list, "1-4i"); -/* Ugh! Let the user hardwire the hardware address for queer cards */ -static int hw_addr[6] = { 0, /* ... */ }; -MODULE_PARM(hw_addr, "6i"); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"axnet_cs.c 1.24 2001/11/18 02:46:51 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -120,6 +112,11 @@ static dev_info_t dev_info = "axnet_cs"; static dev_link_t *dev_list; +static int axdev_init(struct net_device *dev); +static void AX88190_init(struct net_device *dev, int startp); +static int ax_open(struct net_device *dev); +static void ax_interrupt(int irq, void *dev_id, struct pt_regs *regs); + /*====================================================================*/ typedef struct axnet_dev_t { @@ -210,7 +207,7 @@ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - ethdev_init(dev); + axdev_init(dev); dev->init = &axnet_init; dev->open = &axnet_open; dev->stop = &axnet_close; @@ -302,7 +299,7 @@ {0x00, EN0_RCNTHI}, {0x00, EN0_IMR}, /* Mask completion irq. */ {0xFF, EN0_ISR}, - {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_RXOFF|0x40, EN0_RXCR}, /* 0x60 Set to monitor */ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ {0x10, EN0_RCNTLO}, {0x00, EN0_RCNTHI}, @@ -331,30 +328,6 @@ /*====================================================================== - This should be totally unnecessary... but when we can't figure - out the hardware address any other way, we'll let the user hard - wire it when the module is initialized. - -======================================================================*/ - -static int get_hwired(dev_link_t *link) -{ - struct net_device *dev = link->priv; - int i; - - for (i = 0; i < 6; i++) - if (hw_addr[i] != 0) break; - if (i == 6) - return 0; - - for (i = 0; i < 6; i++) - dev->dev_addr[i] = hw_addr[i]; - - return 1; -} /* get_hwired */ - -/*====================================================================== - axnet_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the ethernet device available to the system. @@ -419,7 +392,8 @@ CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; + /* don't trust the CIS on this; Linksys got it wrong */ + link->conf.Present = 0x63; /* Configure card */ link->state |= DEV_CONFIG; @@ -440,7 +414,7 @@ if ((cfg->index == 0) || (cfg->io.nwin == 0)) goto next_entry; - link->conf.ConfigIndex = cfg->index; + link->conf.ConfigIndex = 0x05; /* For multifunction cards, by convention, we configure the network function with window 0, and serial with window 1 */ if (io->nwin > 1) { @@ -480,9 +454,9 @@ goto failed; } - if (!get_prom(link) && !get_hwired(link)) { - printk(KERN_NOTICE "axnet_cs: unable to read hardware net" - " address for io base %#3lx\n", dev->base_addr); + if (!get_prom(link)) { + printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n"); + printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n"); unregister_netdev(dev); goto failed; } @@ -542,7 +516,7 @@ if (link->open) { DEBUG(1, "axnet_cs: release postponed, '%s' still open\n", - info->node.dev_name); + ((axnet_dev_t *)(link->priv))->node.dev_name); link->state |= DEV_STALE_CONFIG; return; } @@ -602,7 +576,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { axnet_reset_8390(&info->dev); - NS8390_init(&info->dev, 1); + AX88190_init(&info->dev, 1); netif_device_attach(&info->dev); } } @@ -692,7 +666,7 @@ info->watchdog.expires = jiffies + HZ; add_timer(&info->watchdog); - return ei_open(dev); + return ax_open(dev); } /* axnet_open */ /*====================================================================*/ @@ -708,7 +682,6 @@ link->open--; netif_stop_queue(dev); - netif_mark_down(dev); del_timer(&info->watchdog); if (link->state & DEV_STALE_CONFIG) mod_timer(&link->release, jiffies + HZ/20); @@ -755,7 +728,7 @@ { axnet_dev_t *info = dev_id; info->stale = 0; - ei_interrupt(irq, dev_id, regs); + ax_interrupt(irq, dev_id, regs); } static void ei_watchdog(u_long arg) @@ -807,7 +780,7 @@ else printk(KERN_INFO "%s: link partner did not autonegotiate\n", dev->name); - NS8390_init(dev, 1); + AX88190_init(dev, 1); } info->link_status = link; } @@ -944,10 +917,11 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + This is the chip-specific code for many 8390-based ethernet adaptors. This is not a complete driver, it must be combined with board-specific code such as ne.c, wd.c, 3c503.c, etc. @@ -957,7 +931,6 @@ a simple innocent change. Please contact me or Donald if you think you have found something that needs changing. -- PG - Changelog: Paul Gortmaker : remove set_bit lock, other cleanups. @@ -981,8 +954,8 @@ */ -static const char *version = - "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; +static const char *version_8390 = + "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@scyld.com)\n"; #include #include @@ -1062,25 +1035,23 @@ * them. */ - - /** - * ei_open - Open/initialize the board. + * ax_open - Open/initialize the board. * @dev: network device to initialize * * This routine goes all-out, setting everything * up anew at each open, even though many of these registers should only * need to be set once at boot. */ -static int ei_open(struct net_device *dev) +static int ax_open(struct net_device *dev) { unsigned long flags; struct ei_device *ei_local = (struct ei_device *) dev->priv; - /* This can't happen unless somebody forgot to call ethdev_init(). */ + /* This can't happen unless somebody forgot to call axdev_init(). */ if (ei_local == NULL) { - printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name); + printk(KERN_EMERG "%s: ax_open passed a non-existent device!\n", dev->name); return -ENXIO; } @@ -1099,10 +1070,9 @@ */ spin_lock_irqsave(&ei_local->page_lock, flags); - NS8390_init(dev, 1); + AX88190_init(dev, 1); /* Set the flag before we drop the lock, That way the IRQ arrives after its set and we get no silly warnings */ - netif_mark_up(dev); netif_start_queue(dev); spin_unlock_irqrestore(&ei_local->page_lock, flags); ei_local->irqlock = 0; @@ -1110,27 +1080,6 @@ } /** - * ei_close - shut down network device - * @dev: network device to close - * - * Opposite of ei_open(). Only used when "ifconfig down" is done. - */ -static int ei_close(struct net_device *dev) -{ - unsigned long flags; - - /* - * Hold the page lock during close - */ - - spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags); - NS8390_init(dev, 0); - spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags); - netif_stop_queue(dev); - return 0; -} - -/** * ei_tx_timeout - handle transmit time out condition * @dev: network device which has apparently fallen asleep * @@ -1169,7 +1118,7 @@ /* Try to restart the card. Perhaps the user has fixed something. */ ei_reset_8390(dev); - NS8390_init(dev, 1); + AX88190_init(dev, 1); spin_unlock(&ei_local->page_lock); enable_irq(dev->irq); @@ -1192,7 +1141,6 @@ unsigned long flags; netif_stop_queue(dev); - skb_tx_check(dev, skb); length = skb->len; @@ -1205,7 +1153,6 @@ outb_p(0x00, e8390_base + EN0_IMR); spin_unlock_irqrestore(&ei_local->page_lock, flags); - /* * Slow phase with lock held. */ @@ -1218,8 +1165,6 @@ send_length = ETH_ZLEN < length ? length : ETH_ZLEN; -#ifdef EI_PINGPONG - /* * We have two Tx slots available for use. Find the first free * slot, and then perform some sanity checks. With two Tx bufs, @@ -1288,22 +1233,6 @@ else netif_start_queue(dev); -#else /* EI_PINGPONG */ - - /* - * Only one Tx buffer in use. You need two Tx bufs to come close to - * back-to-back transmits. Expect a 20 -> 25% performance hit on - * reasonable hardware if you only use one Tx buffer. - */ - - ei_block_output(dev, length, skb->data, ei_local->tx_start_page); - ei_local->txing = 1; - NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); - dev->trans_start = jiffies; - netif_stop_queue(dev); - -#endif /* EI_PINGPONG */ - /* Turn 8390 interrupts back on. */ ei_local->irqlock = 0; outb_p(ENISR_ALL, e8390_base + EN0_IMR); @@ -1311,14 +1240,14 @@ spin_unlock(&ei_local->page_lock); enable_irq(dev->irq); - DEV_KFREE_SKB (skb); - add_tx_bytes(&ei_local->stat, send_length); + dev_kfree_skb (skb); + ei_local->stat.tx_bytes += send_length; return 0; } /** - * ei_interrupt - handle the interrupts from an 8390 + * ax_interrupt - handle the interrupts from an 8390 * @irq: interrupt number * @dev_id: a pointer to the net_device * @regs: unused @@ -1330,7 +1259,7 @@ * needed. */ -static void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static void ax_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; long e8390_base; @@ -1497,8 +1426,6 @@ struct ei_device *ei_local = (struct ei_device *) dev->priv; int status = inb(e8390_base + EN0_TSR); -#ifdef EI_PINGPONG - /* * There are two Tx buffers, see which one finished, and trigger * the send of another one if it exists. @@ -1541,13 +1468,6 @@ // else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n", // dev->name, ei_local->lasttx); -#else /* EI_PINGPONG */ - /* - * Single Tx buffer: mark it free so another packet can be loaded. - */ - ei_local->txing = 0; -#endif - /* Minimize Tx latency: update the statistics after we restart TXing. */ if (status & ENTSR_COL) ei_local->stat.collisions++; @@ -1655,7 +1575,7 @@ netif_rx(skb); dev->last_rx = jiffies; ei_local->stat.rx_packets++; - add_rx_bytes(&ei_local->stat, pkt_len); + ei_local->stat.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) ei_local->stat.multicast++; } @@ -1801,11 +1721,11 @@ long e8390_base = dev->base_addr; if(dev->flags&IFF_PROMISC) - outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR); + outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR); else if(dev->flags&IFF_ALLMULTI || dev->mc_list) - outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR); + outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR); else - outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); + outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); } /* @@ -1813,28 +1733,30 @@ * be parallel to just about everything else. Its also fairly quick and * not called too often. Must protect against both bh and irq users */ - + +#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock) + static void set_multicast_list(struct net_device *dev) { unsigned long flags; - spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags); + spin_lock_irqsave(&dev_lock(dev), flags); do_set_multicast_list(dev); - spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags); + spin_unlock_irqrestore(&dev_lock(dev), flags); } /** - * ethdev_init - init rest of 8390 device struct + * axdev_init - init rest of 8390 device struct * @dev: network device structure to init * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ -static int ethdev_init(struct net_device *dev) +static int axdev_init(struct net_device *dev) { if (ei_debug > 1) - printk(version); + printk(version_8390); if (dev->priv == NULL) { @@ -1857,20 +1779,18 @@ return 0; } - - /* This page of functions should be 8390 generic */ /* Follow National Semi's recommendations for initializing the "NIC". */ /** - * NS8390_init - initialize 8390 hardware + * AX88190_init - initialize 8390 hardware * @dev: network device to initialize * @startp: boolean. non-zero value to initiate chip processing * * Must be called with lock held. */ -static void NS8390_init(struct net_device *dev, int startp) +static void AX88190_init(struct net_device *dev, int startp) { axnet_dev_t *info = (axnet_dev_t *)dev; long e8390_base = dev->base_addr; @@ -1887,7 +1807,7 @@ outb_p(0x00, e8390_base + EN0_RCNTLO); outb_p(0x00, e8390_base + EN0_RCNTHI); /* Set to monitor and loopback mode -- this is vital!. */ - outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */ + outb_p(E8390_RXOFF|0x40, e8390_base + EN0_RXCR); /* 0x60 */ outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */ /* Set the transmit page and receive ring. */ outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR); @@ -1931,7 +1851,7 @@ outb_p(E8390_TXCONFIG | info->duplex_flag, e8390_base + EN0_TXCR); /* xmit on. */ /* 3c503 TechMan says rxconfig only after the NIC is started. */ - outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */ + outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); /* rx on, */ do_set_multicast_list(dev); /* (re)load the mcast table */ } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/pcmcia/i82593.h linux-2.5/drivers/net/pcmcia/i82593.h --- linux-2.5.20/drivers/net/pcmcia/i82593.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/pcmcia/i82593.h Tue Jan 22 17:43:48 2002 @@ -0,0 +1,224 @@ +/* + * Definitions for Intel 82593 CSMA/CD Core LAN Controller + * The definitions are taken from the 1992 users manual with Intel + * order number 297125-001. + * + * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp + * + * Copyright 1994, Anders Klemets + * + * This software may be freely distributed for noncommercial purposes + * as long as this notice is retained. + * + * HISTORY + * i82593.h,v + * Revision 1.1 1996/07/17 15:23:12 root + * Initial revision + * + * Revision 1.3 1995/04/05 15:13:58 adj + * Initial alpha release + * + * Revision 1.2 1994/06/16 23:57:31 klemets + * Mirrored all the fields in the configuration block. + * + * Revision 1.1 1994/06/02 20:25:34 klemets + * Initial revision + * + * + */ +#ifndef _I82593_H +#define _I82593_H + +/* Intel 82593 CSMA/CD Core LAN Controller */ + +/* Port 0 Command Register definitions */ + +/* Execution operations */ +#define OP0_NOP 0 /* CHNL = 0 */ +#define OP0_SWIT_TO_PORT_1 0 /* CHNL = 1 */ +#define OP0_IA_SETUP 1 +#define OP0_CONFIGURE 2 +#define OP0_MC_SETUP 3 +#define OP0_TRANSMIT 4 +#define OP0_TDR 5 +#define OP0_DUMP 6 +#define OP0_DIAGNOSE 7 +#define OP0_TRANSMIT_NO_CRC 9 +#define OP0_RETRANSMIT 12 +#define OP0_ABORT 13 +/* Reception operations */ +#define OP0_RCV_ENABLE 8 +#define OP0_RCV_DISABLE 10 +#define OP0_STOP_RCV 11 +/* Status pointer control operations */ +#define OP0_FIX_PTR 15 /* CHNL = 1 */ +#define OP0_RLS_PTR 15 /* CHNL = 0 */ +#define OP0_RESET 14 + +#define CR0_CHNL (1 << 4) /* 0=Channel 0, 1=Channel 1 */ +#define CR0_STATUS_0 0x00 +#define CR0_STATUS_1 0x20 +#define CR0_STATUS_2 0x40 +#define CR0_STATUS_3 0x60 +#define CR0_INT_ACK (1 << 7) /* 0=No ack, 1=acknowledge */ + +/* Port 0 Status Register definitions */ + +#define SR0_NO_RESULT 0 /* dummy */ +#define SR0_EVENT_MASK 0x0f +#define SR0_IA_SETUP_DONE 1 +#define SR0_CONFIGURE_DONE 2 +#define SR0_MC_SETUP_DONE 3 +#define SR0_TRANSMIT_DONE 4 +#define SR0_TDR_DONE 5 +#define SR0_DUMP_DONE 6 +#define SR0_DIAGNOSE_PASSED 7 +#define SR0_TRANSMIT_NO_CRC_DONE 9 +#define SR0_RETRANSMIT_DONE 12 +#define SR0_EXECUTION_ABORTED 13 +#define SR0_END_OF_FRAME 8 +#define SR0_RECEPTION_ABORTED 10 +#define SR0_DIAGNOSE_FAILED 15 +#define SR0_STOP_REG_HIT 11 + +#define SR0_CHNL (1 << 4) +#define SR0_EXECUTION (1 << 5) +#define SR0_RECEPTION (1 << 6) +#define SR0_INTERRUPT (1 << 7) +#define SR0_BOTH_RX_TX (SR0_EXECUTION | SR0_RECEPTION) + +#define SR3_EXEC_STATE_MASK 0x03 +#define SR3_EXEC_IDLE 0 +#define SR3_TX_ABORT_IN_PROGRESS 1 +#define SR3_EXEC_ACTIVE 2 +#define SR3_ABORT_IN_PROGRESS 3 +#define SR3_EXEC_CHNL (1 << 2) +#define SR3_STP_ON_NO_RSRC (1 << 3) +#define SR3_RCVING_NO_RSRC (1 << 4) +#define SR3_RCV_STATE_MASK 0x60 +#define SR3_RCV_IDLE 0x00 +#define SR3_RCV_READY 0x20 +#define SR3_RCV_ACTIVE 0x40 +#define SR3_RCV_STOP_IN_PROG 0x60 +#define SR3_RCV_CHNL (1 << 7) + +/* Port 1 Command Register definitions */ + +#define OP1_NOP 0 +#define OP1_SWIT_TO_PORT_0 1 +#define OP1_INT_DISABLE 2 +#define OP1_INT_ENABLE 3 +#define OP1_SET_TS 5 +#define OP1_RST_TS 7 +#define OP1_POWER_DOWN 8 +#define OP1_RESET_RING_MNGMT 11 +#define OP1_RESET 14 +#define OP1_SEL_RST 15 + +#define CR1_STATUS_4 0x00 +#define CR1_STATUS_5 0x20 +#define CR1_STATUS_6 0x40 +#define CR1_STOP_REG_UPDATE (1 << 7) + +/* Receive frame status bits */ + +#define RX_RCLD (1 << 0) +#define RX_IA_MATCH (1 << 1) +#define RX_NO_AD_MATCH (1 << 2) +#define RX_NO_SFD (1 << 3) +#define RX_SRT_FRM (1 << 7) +#define RX_OVRRUN (1 << 8) +#define RX_ALG_ERR (1 << 10) +#define RX_CRC_ERR (1 << 11) +#define RX_LEN_ERR (1 << 12) +#define RX_RCV_OK (1 << 13) +#define RX_TYP_LEN (1 << 15) + +/* Transmit status bits */ + +#define TX_NCOL_MASK 0x0f +#define TX_FRTL (1 << 4) +#define TX_MAX_COL (1 << 5) +#define TX_HRT_BEAT (1 << 6) +#define TX_DEFER (1 << 7) +#define TX_UND_RUN (1 << 8) +#define TX_LOST_CTS (1 << 9) +#define TX_LOST_CRS (1 << 10) +#define TX_LTCOL (1 << 11) +#define TX_OK (1 << 13) +#define TX_COLL (1 << 15) + +struct i82593_conf_block { + u_char fifo_limit : 4, + forgnesi : 1, + fifo_32 : 1, + d6mod : 1, + throttle_enb : 1; + u_char throttle : 6, + cntrxint : 1, + contin : 1; + u_char addr_len : 3, + acloc : 1, + preamb_len : 2, + loopback : 2; + u_char lin_prio : 3, + tbofstop : 1, + exp_prio : 3, + bof_met : 1; + u_char : 4, + ifrm_spc : 4; + u_char : 5, + slottim_low : 3; + u_char slottim_hi : 3, + : 1, + max_retr : 4; + u_char prmisc : 1, + bc_dis : 1, + : 1, + crs_1 : 1, + nocrc_ins : 1, + crc_1632 : 1, + : 1, + crs_cdt : 1; + u_char cs_filter : 3, + crs_src : 1, + cd_filter : 3, + : 1; + u_char : 2, + min_fr_len : 6; + u_char lng_typ : 1, + lng_fld : 1, + rxcrc_xf : 1, + artx : 1, + sarec : 1, + tx_jabber : 1, /* why is this called max_len in the manual? */ + hash_1 : 1, + lbpkpol : 1; + u_char : 6, + fdx : 1, + : 1; + u_char dummy_6 : 6, /* supposed to be ones */ + mult_ia : 1, + dis_bof : 1; + u_char dummy_1 : 1, /* supposed to be one */ + tx_ifs_retrig : 2, + mc_all : 1, + rcv_mon : 2, + frag_acpt : 1, + tstrttrs : 1; + u_char fretx : 1, + runt_eop : 1, + hw_sw_pin : 1, + big_endn : 1, + syncrqs : 1, + sttlen : 1, + tx_eop : 1, + rx_eop : 1; + u_char rbuf_size : 5, + rcvstop : 1, + : 2; +}; + +#define I82593_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ + +#endif /* _I82593_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/pcmcia/nmclan_cs.c linux-2.5/drivers/net/pcmcia/nmclan_cs.c --- linux-2.5.20/drivers/net/pcmcia/nmclan_cs.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/net/pcmcia/nmclan_cs.c Thu Dec 27 16:32:31 2001 @@ -106,6 +106,10 @@ ---------------------------------------------------------------------------- */ +#define DRV_NAME "nmclan_cs" +#define DRV_VERSION "0.16" + + /* ---------------------------------------------------------------------------- Conditional Compilation Options ---------------------------------------------------------------------------- */ @@ -130,6 +134,9 @@ #include #include #include +#include + +#include #include #include #include @@ -375,7 +382,7 @@ static char rcsid[] = "nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao"; static char *version = -"nmclan_cs 0.16 (Roger C. Pao)"; +DRV_NAME " " DRV_VERSION " (Roger C. Pao)"; #endif static dev_info_t dev_info="nmclan_cs"; @@ -1001,6 +1008,66 @@ return 0; } /* mace_close */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + +#ifdef PCMCIA_DEBUG + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = pc_debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + pc_debug = edata.data; + return 0; + } +#endif + + default: + break; + } + + return -EOPNOTSUPP; +} + +static int smc91c92_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + + default: + return -EOPNOTSUPP; + } + return 0; +} /* ---------------------------------------------------------------------------- mace_start_xmit diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/pcmcia/wavelan.h linux-2.5/drivers/net/pcmcia/wavelan.h --- linux-2.5.20/drivers/net/pcmcia/wavelan.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/pcmcia/wavelan.h Tue Jan 22 17:43:48 2002 @@ -0,0 +1,386 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganization and extension of the driver. + * Original copyright follow. See wavelan_cs.h for details. + * + * This file contain the declarations of the Wavelan hardware. Note that + * the Pcmcia Wavelan include a i82593 controller (see definitions in + * file i82593.h). + * + * The main difference between the pcmcia hardware and the ISA one is + * the Ethernet Controller (i82593 instead of i82586). The i82593 allow + * only one send buffer. The PSA (Parameter Storage Area : EEprom for + * permanent storage of various info) is memory mapped, but not the + * MMI (Modem Management Interface). + */ + +/* + * Definitions for the AT&T GIS (formerly NCR) WaveLAN PCMCIA card: + * An Ethernet-like radio transceiver controlled by an Intel 82593 + * coprocessor. + * + * + **************************************************************************** + * Copyright 1995 + * Anthony D. Joseph + * Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this program + * for any purpose and without fee is hereby granted, provided + * that this copyright and permission notice appear on all copies + * and supporting documentation, the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * program without specific prior permission, and notice be given + * in supporting documentation that copying and distribution is + * by permission of M.I.T. M.I.T. makes no representations about + * the suitability of this software for any purpose. It is pro- + * vided "as is" without express or implied warranty. + **************************************************************************** + * + * + * Credits: + * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht for + * providing extremely useful information about WaveLAN PCMCIA hardware + * + * This driver is based upon several other drivers, in particular: + * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter + * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter + * Anders Klemets' PCMCIA WaveLAN adapter driver + * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter + */ + +#ifndef _WAVELAN_H +#define _WAVELAN_H + +/************************** MAGIC NUMBERS ***************************/ + +/* The detection of the wavelan card is made by reading the MAC address + * from the card and checking it. If you have a non AT&T product (OEM, + * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this + * part to accomodate your hardware... + */ +const unsigned char MAC_ADDRESSES[][3] = +{ + { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ + { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ + { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ + { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ + /* Add your card here and send me the patch ! */ +}; + +/* + * Constants used to convert channels to frequencies + */ + +/* Frequency available in the 2.0 modem, in units of 250 kHz + * (as read in the offset register of the dac area). + * Used to map channel numbers used by `wfreqsel' to frequencies + */ +const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, + 0xD0, 0xF0, 0xF8, 0x150 }; + +/* Frequencies of the 1.0 modem (fixed frequencies). + * Use to map the PSA `subband' to a frequency + * Note : all frequencies apart from the first one need to be multiplied by 10 + */ +const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; + + +/*************************** PC INTERFACE ****************************/ + +/* WaveLAN host interface definitions */ + +#define LCCR(base) (base) /* LAN Controller Command Register */ +#define LCSR(base) (base) /* LAN Controller Status Register */ +#define HACR(base) (base+0x1) /* Host Adapter Command Register */ +#define HASR(base) (base+0x1) /* Host Adapter Status Register */ +#define PIORL(base) (base+0x2) /* Program I/O Register Low */ +#define RPLL(base) (base+0x2) /* Receive Pointer Latched Low */ +#define PIORH(base) (base+0x3) /* Program I/O Register High */ +#define RPLH(base) (base+0x3) /* Receive Pointer Latched High */ +#define PIOP(base) (base+0x4) /* Program I/O Port */ +#define MMR(base) (base+0x6) /* MMI Address Register */ +#define MMD(base) (base+0x7) /* MMI Data Register */ + +/* Host Adaptor Command Register bit definitions */ + +#define HACR_LOF (1 << 3) /* Lock Out Flag, toggle every 250ms */ +#define HACR_PWR_STAT (1 << 4) /* Power State, 1=active, 0=sleep */ +#define HACR_TX_DMA_RESET (1 << 5) /* Reset transmit DMA ptr on high */ +#define HACR_RX_DMA_RESET (1 << 6) /* Reset receive DMA ptr on high */ +#define HACR_ROM_WEN (1 << 7) /* EEPROM write enabled when true */ + +#define HACR_RESET (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET) +#define HACR_DEFAULT (HACR_PWR_STAT) + +/* Host Adapter Status Register bit definitions */ + +#define HASR_MMI_BUSY (1 << 2) /* MMI is busy when true */ +#define HASR_LOF (1 << 3) /* Lock out flag status */ +#define HASR_NO_CLK (1 << 4) /* active when modem not connected */ + +/* Miscellaneous bit definitions */ + +#define PIORH_SEL_TX (1 << 5) /* PIOR points to 0=rx/1=tx buffer */ +#define MMR_MMI_WR (1 << 0) /* Next MMI cycle is 0=read, 1=write */ +#define PIORH_MASK 0x1f /* only low 5 bits are significant */ +#define RPLH_MASK 0x1f /* only low 5 bits are significant */ +#define MMI_ADDR_MASK 0x7e /* Bits 1-6 of MMR are significant */ + +/* Attribute Memory map */ + +#define CIS_ADDR 0x0000 /* Card Information Status Register */ +#define PSA_ADDR 0x0e00 /* Parameter Storage Area address */ +#define EEPROM_ADDR 0x1000 /* EEPROM address (unused ?) */ +#define COR_ADDR 0x4000 /* Configuration Option Register */ + +/* Configuration Option Register bit definitions */ + +#define COR_CONFIG (1 << 0) /* Config Index, 0 when unconfigured */ +#define COR_SW_RESET (1 << 7) /* Software Reset on true */ +#define COR_LEVEL_IRQ (1 << 6) /* Level IRQ */ + +/* Local Memory map */ + +#define RX_BASE 0x0000 /* Receive memory, 8 kB */ +#define TX_BASE 0x2000 /* Transmit memory, 2 kB */ +#define UNUSED_BASE 0x2800 /* Unused, 22 kB */ +#define RX_SIZE (TX_BASE-RX_BASE) /* Size of receive area */ +#define RX_SIZE_SHIFT 6 /* Bits to shift in stop register */ + +#define TRUE 1 +#define FALSE 0 + +#define MOD_ENAL 1 +#define MOD_PROM 2 + +/* Size of a MAC address */ +#define WAVELAN_ADDR_SIZE 6 + +/* Maximum size of Wavelan packet */ +#define WAVELAN_MTU 1500 + +#define MAXDATAZ (6 + 6 + 2 + WAVELAN_MTU) + +/********************** PARAMETER STORAGE AREA **********************/ + +/* + * Parameter Storage Area (PSA). + */ +typedef struct psa_t psa_t; +struct psa_t +{ + /* For the PCMCIA Adapter, locations 0x00-0x0F are unused and fixed at 00 */ + unsigned char psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ + unsigned char psa_io_base_addr_2; /* [0x01] Base address 2 */ + unsigned char psa_io_base_addr_3; /* [0x02] Base address 3 */ + unsigned char psa_io_base_addr_4; /* [0x03] Base address 4 */ + unsigned char psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ + unsigned char psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ + unsigned char psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ + unsigned char psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ + unsigned char psa_int_req_no; /* [0x08] Interrupt Request Line */ + unsigned char psa_unused0[7]; /* [0x09-0x0F] unused */ + + unsigned char psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x10-0x15] Universal (factory) MAC Address */ + unsigned char psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ + unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ +#define PSA_UNIVERSAL 0 /* Universal (factory) */ +#define PSA_LOCAL 1 /* Local */ + unsigned char psa_comp_number; /* [0x1D] Compatability Number: */ +#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ +#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ +#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ +#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ +#define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ + unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ + unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ +#define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ + unsigned char psa_subband; /* [0x20] Subband */ +#define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ +#define PSA_SUBBAND_2425 1 /* 2425 MHz */ +#define PSA_SUBBAND_2460 2 /* 2460 MHz */ +#define PSA_SUBBAND_2484 3 /* 2484 MHz */ +#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ + unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ + unsigned char psa_mod_delay; /* [0x22] Modem Delay ??? (reserved) */ + unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ + unsigned char psa_nwid_select; /* [0x25] Network ID Select On Off */ + unsigned char psa_encryption_select; /* [0x26] Encryption On Off */ + unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ + unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ + unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ + unsigned char psa_nwid_prefix[2]; /* [0x38-0x39] Roaming domain */ + unsigned char psa_reserved[2]; /* [0x3A-0x3B] Reserved - fixed 00 */ + unsigned char psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ + unsigned char psa_crc[2]; /* [0x3D] CRC-16 over PSA */ + unsigned char psa_crc_status; /* [0x3F] CRC Valid Flag */ +}; + +/* Size for structure checking (if padding is correct) */ +#define PSA_SIZE 64 + +/* Calculate offset of a field in the above structure + * Warning : only even addresses are used */ +#define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) + +/******************** MODEM MANAGEMENT INTERFACE ********************/ + +/* + * Modem Management Controller (MMC) write structure. + */ +typedef struct mmw_t mmw_t; +struct mmw_t +{ + unsigned char mmw_encr_key[8]; /* encryption key */ + unsigned char mmw_encr_enable; /* enable/disable encryption */ +#define MMW_ENCR_ENABLE_MODE 0x02 /* Mode of security option */ +#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option */ + unsigned char mmw_unused0[1]; /* unused */ + unsigned char mmw_des_io_invert; /* Encryption option */ +#define MMW_DES_IO_INVERT_RES 0x0F /* Reserved */ +#define MMW_DES_IO_INVERT_CTRL 0xF0 /* Control ??? (set to 0) */ + unsigned char mmw_unused1[5]; /* unused */ + unsigned char mmw_loopt_sel; /* looptest selection */ +#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* disable NWID filtering */ +#define MMW_LOOPT_SEL_INT 0x20 /* activate Attention Request */ +#define MMW_LOOPT_SEL_LS 0x10 /* looptest w/o collision avoidance */ +#define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ +#define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ +#define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ +#define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ + unsigned char mmw_jabber_enable; /* jabber timer enable */ + /* Abort transmissions > 200 ms */ + unsigned char mmw_freeze; /* freeze / unfreeeze signal level */ + /* 0 : signal level & qual updated for every new message, 1 : frozen */ + unsigned char mmw_anten_sel; /* antenna selection */ +#define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ +#define MMW_ANTEN_SEL_ALG_EN 0x02 /* antenna selection algo. enable */ + unsigned char mmw_ifs; /* inter frame spacing */ + /* min time between transmission in bit periods (.5 us) - bit 0 ignored */ + unsigned char mmw_mod_delay; /* modem delay (synchro) */ + unsigned char mmw_jam_time; /* jamming time (after collision) */ + unsigned char mmw_unused2[1]; /* unused */ + unsigned char mmw_thr_pre_set; /* level threshold preset */ + /* Discard all packet with signal < this value (4) */ + unsigned char mmw_decay_prm; /* decay parameters */ + unsigned char mmw_decay_updat_prm; /* decay update parameterz */ + unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ + /* Discard all packet with quality < this value (3) */ + unsigned char mmw_netw_id_l; /* NWID low order byte */ + unsigned char mmw_netw_id_h; /* NWID high order byte */ + /* Network ID or Domain : create virtual net on the air */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmw_mode_select; /* for analog tests (set to 0) */ + unsigned char mmw_unused3[1]; /* unused */ + unsigned char mmw_fee_ctrl; /* frequency eeprom control */ +#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions */ +#define MMW_FEE_CTRL_DWLD 0x08 /* Download eeprom to mmc */ +#define MMW_FEE_CTRL_CMD 0x07 /* EEprom commands : */ +#define MMW_FEE_CTRL_READ 0x06 /* Read */ +#define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ +#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address */ +#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses */ +#define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ +#define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ +#define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ +#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers */ +#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write addr in protect register */ +#define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ + /* Never issue this command (PRDS) : it's irreversible !!! */ + + unsigned char mmw_fee_addr; /* EEprom address */ +#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel */ +#define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ +#define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ +#define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ +#define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ +#define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ + + unsigned char mmw_fee_data_l; /* Write data to EEprom */ + unsigned char mmw_fee_data_h; /* high octet */ + unsigned char mmw_ext_ant; /* Setting for external antenna */ +#define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ +#define MMW_EXT_ANT_POL 0x02 /* Polarity of the antenna */ +#define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ +#define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ +#define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ +}; + +/* Size for structure checking (if padding is correct) */ +#define MMW_SIZE 37 + +/* Calculate offset of a field in the above structure */ +#define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) + + +/* + * Modem Management Controller (MMC) read structure. + */ +typedef struct mmr_t mmr_t; +struct mmr_t +{ + unsigned char mmr_unused0[8]; /* unused */ + unsigned char mmr_des_status; /* encryption status */ + unsigned char mmr_des_avail; /* encryption available (0x55 read) */ +#define MMR_DES_AVAIL_DES 0x55 /* DES available */ +#define MMR_DES_AVAIL_AES 0x33 /* AES (AT&T) available */ + unsigned char mmr_des_io_invert; /* des I/O invert register */ + unsigned char mmr_unused1[5]; /* unused */ + unsigned char mmr_dce_status; /* DCE status */ +#define MMR_DCE_STATUS_RX_BUSY 0x01 /* receiver busy */ +#define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ +#define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ +#define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ +#define MMR_DCE_STATUS 0x0F /* mask to get the bits */ + unsigned char mmr_dsp_id; /* DSP id (AA = Daedalus rev A) */ + unsigned char mmr_unused2[2]; /* unused */ + unsigned char mmr_correct_nwid_l; /* # of correct NWID's rxd (low) */ + unsigned char mmr_correct_nwid_h; /* # of correct NWID's rxd (high) */ + /* Warning : Read high order octet first !!! */ + unsigned char mmr_wrong_nwid_l; /* # of wrong NWID's rxd (low) */ + unsigned char mmr_wrong_nwid_h; /* # of wrong NWID's rxd (high) */ + unsigned char mmr_thr_pre_set; /* level threshold preset */ +#define MMR_THR_PRE_SET 0x3F /* level threshold preset */ +#define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ + unsigned char mmr_signal_lvl; /* signal level */ +#define MMR_SIGNAL_LVL 0x3F /* signal level */ +#define MMR_SIGNAL_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_silence_lvl; /* silence level (noise) */ +#define MMR_SILENCE_LVL 0x3F /* silence level */ +#define MMR_SILENCE_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_sgnl_qual; /* signal quality */ +#define MMR_SGNL_QUAL 0x0F /* signal quality */ +#define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ + unsigned char mmr_netw_id_l; /* NWID low order byte ??? */ + unsigned char mmr_unused3[3]; /* unused */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmr_fee_status; /* Status of frequency eeprom */ +#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision id */ +#define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ +#define MMR_FEE_STATUS_BUSY 0x04 /* EEprom busy */ + unsigned char mmr_unused4[1]; /* unused */ + unsigned char mmr_fee_data_l; /* Read data from eeprom (low) */ + unsigned char mmr_fee_data_h; /* Read data from eeprom (high) */ +}; + +/* Size for structure checking (if padding is correct) */ +#define MMR_SIZE 36 + +/* Calculate offset of a field in the above structure */ +#define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) + + +/* Make the two above structures one */ +typedef union mm_t +{ + struct mmw_t w; /* Write to the mmc */ + struct mmr_t r; /* Read from the mmc */ +} mm_t; + +#endif /* _WAVELAN_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/pcmcia/wavelan_cs.c linux-2.5/drivers/net/pcmcia/wavelan_cs.c --- linux-2.5.20/drivers/net/pcmcia/wavelan_cs.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/pcmcia/wavelan_cs.c Tue Jan 22 17:43:49 2002 @@ -0,0 +1,4837 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * Original copyright follow. See wavelan_cs.h for details. + * + * This code is derived from Anthony D. Joseph's code and all the changes here + * are also under the original copyright below. + * + * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and + * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services + * + * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added + * critical code in the routine to initialize the Modem Management Controller. + * + * Thanks to Alan Cox and Bruce Janson for their advice. + * + * -- Yunzhou Li (scip4166@nus.sg) + * +#ifdef WAVELAN_ROAMING + * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu) + * based on patch by Joe Finney from Lancaster University. +#endif + * + * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An + * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor. + * + * A non-shared memory PCMCIA ethernet driver for linux + * + * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu) + * + * + * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu) + * + * Apr 2 '98 made changes to bring the i82593 control/int handling in line + * with offical specs... + * + **************************************************************************** + * Copyright 1995 + * Anthony D. Joseph + * Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this program + * for any purpose and without fee is hereby granted, provided + * that this copyright and permission notice appear on all copies + * and supporting documentation, the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * program without specific prior permission, and notice be given + * in supporting documentation that copying and distribution is + * by permission of M.I.T. M.I.T. makes no representations about + * the suitability of this software for any purpose. It is pro- + * vided "as is" without express or implied warranty. + **************************************************************************** + * + */ + +#include "wavelan_cs.h" /* Private header */ + +/************************* MISC SUBROUTINES **************************/ +/* + * Subroutines which won't fit in one of the following category + * (wavelan modem or i82593) + */ + +/*------------------------------------------------------------------*/ +/* + * Wrapper for disabling interrupts. + * (note : inline, so optimised away) + */ +static inline void +wv_splhi(net_local * lp, + unsigned long * pflags) +{ + spin_lock_irqsave(&lp->spinlock, *pflags); + /* Note : above does the cli(); itself */ +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for re-enabling interrupts. + */ +static inline void +wv_splx(net_local * lp, + unsigned long * pflags) +{ + spin_unlock_irqrestore(&lp->spinlock, *pflags); + + /* Note : enabling interrupts on the hardware is done in wv_ru_start() + * via : outb(OP1_INT_ENABLE, LCCR(base)); + */ +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for reporting error to cardservices + */ +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +#ifdef STRUCT_CHECK +/*------------------------------------------------------------------*/ +/* + * Sanity routine to verify the sizes of the various WaveLAN interface + * structures. + */ +static char * +wv_structuct_check(void) +{ +#define SC(t,s,n) if (sizeof(t) != s) return(n); + + SC(psa_t, PSA_SIZE, "psa_t"); + SC(mmw_t, MMW_SIZE, "mmw_t"); + SC(mmr_t, MMR_SIZE, "mmr_t"); + +#undef SC + + return((char *) NULL); +} /* wv_structuct_check */ +#endif /* STRUCT_CHECK */ + +/******************* MODEM MANAGEMENT SUBROUTINES *******************/ +/* + * Useful subroutines to manage the modem of the wavelan + */ + +/*------------------------------------------------------------------*/ +/* + * Read from card's Host Adaptor Status Register. + */ +static inline u_char +hasr_read(u_long base) +{ + return(inb(HASR(base))); +} /* hasr_read */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. + */ +static inline void +hacr_write(u_long base, + u_char hacr) +{ + outb(hacr, HACR(base)); +} /* hacr_write */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. Include a delay for + * those times when it is needed. + */ +static inline void +hacr_write_slow(u_long base, + u_char hacr) +{ + hacr_write(base, hacr); + /* delay might only be needed sometimes */ + mdelay(1); +} /* hacr_write_slow */ + +/*------------------------------------------------------------------*/ +/* + * Read the Parameter Storage Area from the WaveLAN card's memory + */ +static void +psa_read(device * dev, + int o, /* offset in PSA */ + u_char * b, /* buffer to fill */ + int n) /* size to read */ +{ + u_char * ptr = ((u_char *)dev->mem_start) + PSA_ADDR + (o << 1); + + while(n-- > 0) + { + *b++ = readb(ptr); + /* Due to a lack of address decode pins, the WaveLAN PCMCIA card + * only supports reading even memory addresses. That means the + * increment here MUST be two. + * Because of that, we can't use memcpy_fromio()... + */ + ptr += 2; + } +} /* psa_read */ + +/*------------------------------------------------------------------*/ +/* + * Write the Paramter Storage Area to the WaveLAN card's memory + */ +static void +psa_write(device * dev, + int o, /* Offset in psa */ + u_char * b, /* Buffer in memory */ + int n) /* Length of buffer */ +{ + u_char * ptr = ((u_char *) dev->mem_start) + PSA_ADDR + (o << 1); + int count = 0; + ioaddr_t base = dev->base_addr; + /* As there seem to have no flag PSA_BUSY as in the ISA model, we are + * oblige to verify this address to know when the PSA is ready... */ + volatile u_char * verify = ((u_char *) dev->mem_start) + PSA_ADDR + + (psaoff(0, psa_comp_number) << 1); + + /* Authorize writting to PSA */ + hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN); + + while(n-- > 0) + { + /* write to PSA */ + writeb(*b++, ptr); + ptr += 2; + + /* I don't have the spec, so I don't know what the correct + * sequence to write is. This hack seem to work for me... */ + count = 0; + while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100)) + mdelay(1); + } + + /* Put the host interface back in standard state */ + hacr_write(base, HACR_DEFAULT); +} /* psa_write */ + +#ifdef SET_PSA_CRC +/*------------------------------------------------------------------*/ +/* + * Calculate the PSA CRC + * Thanks to Valster, Nico for the code + * NOTE: By specifying a length including the CRC position the + * returned value should be zero. (i.e. a correct checksum in the PSA) + * + * The Windows drivers don't use the CRC, but the AP and the PtP tool + * depend on it. + */ +static u_short +psa_crc(unsigned char * psa, /* The PSA */ + int size) /* Number of short for CRC */ +{ + int byte_cnt; /* Loop on the PSA */ + u_short crc_bytes = 0; /* Data in the PSA */ + int bit_cnt; /* Loop on the bits of the short */ + + for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) + { + crc_bytes ^= psa[byte_cnt]; /* Its an xor */ + + for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ ) + { + if(crc_bytes & 0x0001) + crc_bytes = (crc_bytes >> 1) ^ 0xA001; + else + crc_bytes >>= 1 ; + } + } + + return crc_bytes; +} /* psa_crc */ +#endif /* SET_PSA_CRC */ + +/*------------------------------------------------------------------*/ +/* + * update the checksum field in the Wavelan's PSA + */ +static void +update_psa_checksum(device * dev) +{ +#ifdef SET_PSA_CRC + psa_t psa; + u_short crc; + + /* read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + + /* update the checksum */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) + - sizeof(psa.psa_crc_status)); + + psa.psa_crc[0] = crc & 0xFF; + psa.psa_crc[1] = (crc & 0xFF00) >> 8; + + /* Write it ! */ + psa_write(dev, (char *)&psa.psa_crc - (char *)&psa, + (unsigned char *)&psa.psa_crc, 2); + +#ifdef DEBUG_IOCTL_INFO + printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", + dev->name, psa.psa_crc[0], psa.psa_crc[1]); + + /* Check again (luxury !) */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc_status)); + + if(crc != 0) + printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name); +#endif /* DEBUG_IOCTL_INFO */ +#endif /* SET_PSA_CRC */ +} /* update_psa_checksum */ + +/*------------------------------------------------------------------*/ +/* + * Write 1 byte to the MMC. + */ +static inline void +mmc_out(u_long base, + u_short o, + u_char d) +{ + /* Wait for MMC to go idle */ + while(inb(HASR(base)) & HASR_MMI_BUSY) + ; + + outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base)); + outb(d, MMD(base)); +} + +/*------------------------------------------------------------------*/ +/* + * Routine to write bytes to the Modem Management Controller. + * We start by the end because it is the way it should be ! + */ +static inline void +mmc_write(u_long base, + u_char o, + u_char * b, + int n) +{ + o += n; + b += n; + + while(n-- > 0 ) + mmc_out(base, --o, *(--b)); +} /* mmc_write */ + +/*------------------------------------------------------------------*/ +/* + * Read 1 byte from the MMC. + * Optimised version for 1 byte, avoid using memory... + */ +static inline u_char +mmc_in(u_long base, + u_short o) +{ + while(inb(HASR(base)) & HASR_MMI_BUSY) + ; + outb(o << 1, MMR(base)); /* Set the read address */ + + outb(0, MMD(base)); /* Required dummy write */ + + while(inb(HASR(base)) & HASR_MMI_BUSY) + ; + return (u_char) (inb(MMD(base))); /* Now do the actual read */ +} + +/*------------------------------------------------------------------*/ +/* + * Routine to read bytes from the Modem Management Controller. + * The implementation is complicated by a lack of address lines, + * which prevents decoding of the low-order bit. + * (code has just been moved in the above function) + * We start by the end because it is the way it should be ! + */ +static inline void +mmc_read(u_long base, + u_char o, + u_char * b, + int n) +{ + o += n; + b += n; + + while(n-- > 0) + *(--b) = mmc_in(base, --o); +} /* mmc_read */ + +/*------------------------------------------------------------------*/ +/* + * Get the type of encryption available... + */ +static inline int +mmc_encr(u_long base) /* i/o port of the card */ +{ + int temp; + + temp = mmc_in(base, mmroff(0, mmr_des_avail)); + if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) + return 0; + else + return temp; +} + +/*------------------------------------------------------------------*/ +/* + * Wait for the frequency EEprom to complete a command... + * I hope this one will be optimally inlined... + */ +static inline void +fee_wait(u_long base, /* i/o port of the card */ + int delay, /* Base delay to wait for */ + int number) /* Number of time to wait */ +{ + int count = 0; /* Wait only a limited time */ + + while((count++ < number) && + (mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY)) + udelay(delay); +} + +/*------------------------------------------------------------------*/ +/* + * Read bytes from the Frequency EEprom (frequency select cards). + */ +static void +fee_read(u_long base, /* i/o port of the card */ + u_short o, /* destination offset */ + u_short * b, /* data buffer */ + int n) /* number of registers */ +{ + b += n; /* Position at the end of the area */ + + /* Write the address */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while(n-- > 0) + { + /* Write the read command */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ); + + /* Wait until EEprom is ready (should be quick !) */ + fee_wait(base, 10, 100); + + /* Read the value */ + *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) | + mmc_in(base, mmroff(0, mmr_fee_data_l))); + } +} + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + +/*------------------------------------------------------------------*/ +/* + * Write bytes from the Frequency EEprom (frequency select cards). + * This is a bit complicated, because the frequency eeprom has to + * be unprotected and the write enabled. + * Jean II + */ +static void +fee_write(u_long base, /* i/o port of the card */ + u_short o, /* destination offset */ + u_short * b, /* data buffer */ + int n) /* number of registers */ +{ + b += n; /* Position at the end of the area */ + +#ifdef EEPROM_IS_PROTECTED /* disabled */ +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* Ask to read the protected register */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); + + fee_wait(base, 10, 100); + + /* Read the protected register */ + printk("Protected 2 : %02X-%02X\n", + mmc_in(base, mmroff(0, mmr_fee_data_h)), + mmc_in(base, mmroff(0, mmr_fee_data_l))); +#endif /* DOESNT_SEEM_TO_WORK */ + + /* Enable protected register */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); + + fee_wait(base, 10, 100); + + /* Unprotect area */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* Or use : */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); +#endif /* DOESNT_SEEM_TO_WORK */ + + fee_wait(base, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ + + /* Write enable */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); + + fee_wait(base, 10, 100); + + /* Write the EEprom address */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while(n-- > 0) + { + /* Write the value */ + mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); + mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF); + + /* Write the write command */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); + + /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */ + mdelay(10); + fee_wait(base, 10, 100); + } + + /* Write disable */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); + + fee_wait(base, 10, 100); + +#ifdef EEPROM_IS_PROTECTED /* disabled */ + /* Reprotect EEprom */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); + + fee_wait(base, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ +} +#endif /* WIRELESS_EXT */ + +/******************* WaveLAN Roaming routines... ********************/ + +#ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ + +unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00}; + +void wv_roam_init(struct net_device *dev) +{ + net_local *lp= (net_local *)dev->priv; + + /* Do not remove this unless you have a good reason */ + printk(KERN_NOTICE "%s: Warning, you have enabled roaming on" + " device %s !\n", dev->name, dev->name); + printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature" + " of the Wavelan driver.\n"); + printk(KERN_NOTICE "It may work, but may also make the driver behave in" + " erratic ways or crash.\n"); + + lp->wavepoint_table.head=NULL; /* Initialise WavePoint table */ + lp->wavepoint_table.num_wavepoints=0; + lp->wavepoint_table.locked=0; + lp->curr_point=NULL; /* No default WavePoint */ + lp->cell_search=0; + + lp->cell_timer.data=(long)lp; /* Start cell expiry timer */ + lp->cell_timer.function=wl_cell_expiry; + lp->cell_timer.expires=jiffies+CELL_TIMEOUT; + add_timer(&lp->cell_timer); + + wv_nwid_filter(NWID_PROMISC,lp) ; /* Enter NWID promiscuous mode */ + /* to build up a good WavePoint */ + /* table... */ + printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); +} + +void wv_roam_cleanup(struct net_device *dev) +{ + wavepoint_history *ptr,*old_ptr; + net_local *lp= (net_local *)dev->priv; + + printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name); + + /* Fixme : maybe we should check that the timer exist before deleting it */ + del_timer(&lp->cell_timer); /* Remove cell expiry timer */ + ptr=lp->wavepoint_table.head; /* Clear device's WavePoint table */ + while(ptr!=NULL) + { + old_ptr=ptr; + ptr=ptr->next; + wl_del_wavepoint(old_ptr,lp); + } +} + +/* Enable/Disable NWID promiscuous mode on a given device */ +void wv_nwid_filter(unsigned char mode, net_local *lp) +{ + mm_t m; + unsigned long flags; + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name); +#endif + + /* Disable interrupts & save flags */ + wv_splhi(lp, &flags); + + m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; + mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); + + if(mode==NWID_PROMISC) + lp->cell_search=1; + else + lp->cell_search=0; + + /* ReEnable interrupts & restore flags */ + wv_splx(lp, &flags); +} + +/* Find a record in the WavePoint table matching a given NWID */ +wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) +{ + wavepoint_history *ptr=lp->wavepoint_table.head; + + while(ptr!=NULL){ + if(ptr->nwid==nwid) + return ptr; + ptr=ptr->next; + } + return NULL; +} + +/* Create a new wavepoint table entry */ +wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) +{ + wavepoint_history *new_wavepoint; + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid); +#endif + + if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS) + return NULL; + + new_wavepoint=(wavepoint_history *) kmalloc(sizeof(wavepoint_history),GFP_ATOMIC); + if(new_wavepoint==NULL) + return NULL; + + new_wavepoint->nwid=nwid; /* New WavePoints NWID */ + new_wavepoint->average_fast=0; /* Running Averages..*/ + new_wavepoint->average_slow=0; + new_wavepoint->qualptr=0; /* Start of ringbuffer */ + new_wavepoint->last_seq=seq-1; /* Last sequence no.seen */ + memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */ + + new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */ + new_wavepoint->prev=NULL; + + if(lp->wavepoint_table.head!=NULL) + lp->wavepoint_table.head->prev=new_wavepoint; + + lp->wavepoint_table.head=new_wavepoint; + + lp->wavepoint_table.num_wavepoints++; /* no. of visible wavepoints */ + + return new_wavepoint; +} + +/* Remove a wavepoint entry from WavePoint table */ +void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) +{ + if(wavepoint==NULL) + return; + + if(lp->curr_point==wavepoint) + lp->curr_point=NULL; + + if(wavepoint->prev!=NULL) + wavepoint->prev->next=wavepoint->next; + + if(wavepoint->next!=NULL) + wavepoint->next->prev=wavepoint->prev; + + if(lp->wavepoint_table.head==wavepoint) + lp->wavepoint_table.head=wavepoint->next; + + lp->wavepoint_table.num_wavepoints--; + kfree(wavepoint); +} + +/* Timer callback function - checks WavePoint table for stale entries */ +void wl_cell_expiry(unsigned long data) +{ + net_local *lp=(net_local *)data; + wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; + +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name); +#endif + + if(lp->wavepoint_table.locked) + { +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n"); +#endif + + lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */ + add_timer(&lp->cell_timer); + return; + } + + while(wavepoint!=NULL) + { + if(wavepoint->last_seen < jiffies-CELL_TIMEOUT) + { +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid); +#endif + + old_point=wavepoint; + wavepoint=wavepoint->next; + wl_del_wavepoint(old_point,lp); + } + else + wavepoint=wavepoint->next; + } + lp->cell_timer.expires=jiffies+CELL_TIMEOUT; + add_timer(&lp->cell_timer); +} + +/* Update SNR history of a wavepoint */ +void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) +{ + int i=0,num_missed=0,ptr=0; + int average_fast=0,average_slow=0; + + num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed + any beacons? */ + if(num_missed) + for(i=0;isigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */ + wavepoint->qualptr %=WAVEPOINT_HISTORY; /* in the ringbuffer. */ + } + wavepoint->last_seen=jiffies; /* Add beacon to history */ + wavepoint->last_seq=seq; + wavepoint->sigqual[wavepoint->qualptr++]=sigqual; + wavepoint->qualptr %=WAVEPOINT_HISTORY; + ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY; + + for(i=0;isigqual[ptr++]; + ptr %=WAVEPOINT_HISTORY; + } + + average_slow=average_fast; + for(i=WAVEPOINT_FAST_HISTORY;isigqual[ptr++]; + ptr %=WAVEPOINT_HISTORY; + } + + wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY; + wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY; +} + +/* Perform a handover to a new WavePoint */ +void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) +{ + ioaddr_t base = lp->dev->base_addr; + mm_t m; + unsigned long flags; + + if(wavepoint==lp->curr_point) /* Sanity check... */ + { + wv_nwid_filter(!NWID_PROMISC,lp); + return; + } + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name); +#endif + + /* Disable interrupts & save flags */ + wv_splhi(lp, &flags); + + m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; + m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; + + mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); + + /* ReEnable interrupts & restore flags */ + wv_splx(lp, &flags); + + wv_nwid_filter(!NWID_PROMISC,lp); + lp->curr_point=wavepoint; +} + +/* Called when a WavePoint beacon is received */ +static inline void wl_roam_gather(device * dev, + u_char * hdr, /* Beacon header */ + u_char * stats) /* SNR, Signal quality + of packet */ +{ + wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */ + unsigned short nwid=ntohs(beacon->nwid); + unsigned short sigqual=stats[2] & MMR_SGNL_QUAL; /* SNR of beacon */ + wavepoint_history *wavepoint=NULL; /* WavePoint table entry */ + net_local *lp=(net_local *)dev->priv; /* Device info */ + +#if 0 + /* Some people don't need this, some other may need it */ + nwid=nwid^ntohs(beacon->domain_id); +#endif + +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name); + printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual); +#endif + + lp->wavepoint_table.locked=1; /* */ + + wavepoint=wl_roam_check(nwid,lp); /* Find WavePoint table entry */ + if(wavepoint==NULL) /* If no entry, Create a new one... */ + { + wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp); + if(wavepoint==NULL) + goto out; + } + if(lp->curr_point==NULL) /* If this is the only WavePoint, */ + wv_roam_handover(wavepoint, lp); /* Jump on it! */ + + wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history + stats. */ + + if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */ + if(!lp->cell_search) /* WavePoint is getting faint, */ + wv_nwid_filter(NWID_PROMISC,lp); /* start looking for a new one */ + + if(wavepoint->average_slow > + lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA) + wv_roam_handover(wavepoint, lp); /* Handover to a better WavePoint */ + + if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */ + if(lp->cell_search) /* getting better, drop out of cell search mode */ + wv_nwid_filter(!NWID_PROMISC,lp); + +out: + lp->wavepoint_table.locked=0; /* :-) */ +} + +/* Test this MAC frame a WavePoint beacon */ +static inline int WAVELAN_BEACON(unsigned char *data) +{ + wavepoint_beacon *beacon= (wavepoint_beacon *)data; + static wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00}; + + if(memcmp(beacon,&beacon_template,9)==0) + return 1; + else + return 0; +} +#endif /* WAVELAN_ROAMING */ + +/************************ I82593 SUBROUTINES *************************/ +/* + * Useful subroutines to manage the Ethernet controller + */ + +/*------------------------------------------------------------------*/ +/* + * Routine to synchronously send a command to the i82593 chip. + * Should be called with interrupts disabled. + * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(), + * wv_82593_config() & wv_diag()) + */ +static int +wv_82593_cmd(device * dev, + char * str, + int cmd, + int result) +{ + ioaddr_t base = dev->base_addr; + int status; + int wait_completed; + long spin; + + /* Spin until the chip finishes executing its current command (if any) */ + spin = 1000; + do + { + /* Time calibration of the loop */ + udelay(10); + + /* Read the interrupt register */ + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + } + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); + + /* If the interrupt hasn't be posted */ + if(spin <= 0) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n", + str, status); +#endif + return(FALSE); + } + + /* Issue the command to the controller */ + outb(cmd, LCCR(base)); + + /* If we don't have to check the result of the command + * Note : this mean that the irq handler will deal with that */ + if(result == SR0_NO_RESULT) + return(TRUE); + + /* We are waiting for command completion */ + wait_completed = TRUE; + + /* Busy wait while the LAN controller executes the command. */ + spin = 1000; + do + { + /* Time calibration of the loop */ + udelay(10); + + /* Read the interrupt register */ + outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); + status = inb(LCSR(base)); + + /* Check if there was an interrupt posted */ + if((status & SR0_INTERRUPT)) + { + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + + /* Check if interrupt is a command completion */ + if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) && + ((status & SR0_BOTH_RX_TX) != 0x0) && + !(status & SR0_RECEPTION)) + { + /* Signal command completion */ + wait_completed = FALSE; + } + else + { + /* Note : Rx interrupts will be handled later, because we can + * handle multiple Rx packets at once */ +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO "wv_82593_cmd: not our interrupt\n"); +#endif + } + } + } + while(wait_completed && (spin-- > 0)); + + /* If the interrupt hasn't be posted */ + if(wait_completed) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n", + str, status); +#endif + return(FALSE); + } + + /* Check the return code returned by the card (see above) against + * the expected return code provided by the caller */ + if((status & SR0_EVENT_MASK) != result) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n", + str, status); +#endif + return(FALSE); + } + + return(TRUE); +} /* wv_82593_cmd */ + +/*------------------------------------------------------------------*/ +/* + * This routine does a 593 op-code number 7, and obtains the diagnose + * status for the WaveLAN. + */ +static inline int +wv_diag(device * dev) +{ + int ret = FALSE; + + if(wv_82593_cmd(dev, "wv_diag(): diagnose", + OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED)) + ret = TRUE; + +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n"); +#endif + return(ret); +} /* wv_diag */ + +/*------------------------------------------------------------------*/ +/* + * Routine to read len bytes from the i82593's ring buffer, starting at + * chip address addr. The results read from the chip are stored in buf. + * The return value is the address to use for next the call. + */ +static int +read_ringbuf(device * dev, + int addr, + char * buf, + int len) +{ + ioaddr_t base = dev->base_addr; + int ring_ptr = addr; + int chunk_len; + char * buf_ptr = buf; + + /* Get all the buffer */ + while(len > 0) + { + /* Position the Program I/O Register at the ring buffer pointer */ + outb(ring_ptr & 0xff, PIORL(base)); + outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base)); + + /* First, determine how much we can read without wrapping around the + ring buffer */ + if((addr + len) < (RX_BASE + RX_SIZE)) + chunk_len = len; + else + chunk_len = RX_BASE + RX_SIZE - addr; + insb(PIOP(base), buf_ptr, chunk_len); + buf_ptr += chunk_len; + len -= chunk_len; + ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE; + } + return(ring_ptr); +} /* read_ringbuf */ + +/*------------------------------------------------------------------*/ +/* + * Reconfigure the i82593, or at least ask for it... + * Because wv_82593_config use the transmission buffer, we must do it + * when we are sure that there is no transmission, so we do it now + * or in wavelan_packet_xmit() (I can't find any better place, + * wavelan_interrupt is not an option...), so you may experience + * some delay sometime... + */ +static inline void +wv_82593_reconfig(device * dev) +{ + net_local * lp = (net_local *)dev->priv; + dev_link_t * link = ((net_local *) dev->priv)->link; + unsigned long flags; + + /* Arm the flag, will be cleard in wv_82593_config() */ + lp->reconfig_82593 = TRUE; + + /* Check if we can do it now ! */ + if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) + { + wv_splhi(lp, &flags); /* Disable interrupts */ + wv_82593_config(dev); + wv_splx(lp, &flags); /* Re-enable interrupts */ + } + else + { +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n", + dev->name, dev->state, link->open); +#endif + } +} + +/********************* DEBUG & INFO SUBROUTINES *********************/ +/* + * This routines are used in the code to show debug informations. + * Most of the time, it dump the content of hardware structures... + */ + +#ifdef DEBUG_PSA_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted contents of the Parameter Storage Area. + */ +static void +wv_psa_show(psa_t * p) +{ + printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); + printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", + p->psa_io_base_addr_1, + p->psa_io_base_addr_2, + p->psa_io_base_addr_3, + p->psa_io_base_addr_4); + printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", + p->psa_rem_boot_addr_1, + p->psa_rem_boot_addr_2, + p->psa_rem_boot_addr_3); + printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); + printk("psa_int_req_no: %d\n", p->psa_int_req_no); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_unused0[0], + p->psa_unused0[1], + p->psa_unused0[2], + p->psa_unused0[3], + p->psa_unused0[4], + p->psa_unused0[5], + p->psa_unused0[6]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_univ_mac_addr[0], + p->psa_univ_mac_addr[1], + p->psa_univ_mac_addr[2], + p->psa_univ_mac_addr[3], + p->psa_univ_mac_addr[4], + p->psa_univ_mac_addr[5]); + printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_local_mac_addr[0], + p->psa_local_mac_addr[1], + p->psa_local_mac_addr[2], + p->psa_local_mac_addr[3], + p->psa_local_mac_addr[4], + p->psa_local_mac_addr[5]); + printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); + printk("psa_comp_number: %d, ", p->psa_comp_number); + printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); + printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", + p->psa_feature_select); + printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); + printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); + printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); + printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]); + printk("psa_nwid_select: %d\n", p->psa_nwid_select); + printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select); + printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_encryption_key[0], + p->psa_encryption_key[1], + p->psa_encryption_key[2], + p->psa_encryption_key[3], + p->psa_encryption_key[4], + p->psa_encryption_key[5], + p->psa_encryption_key[6], + p->psa_encryption_key[7]); + printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); + printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", + p->psa_call_code[0]); + printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_call_code[0], + p->psa_call_code[1], + p->psa_call_code[2], + p->psa_call_code[3], + p->psa_call_code[4], + p->psa_call_code[5], + p->psa_call_code[6], + p->psa_call_code[7]); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n", + p->psa_reserved[0], + p->psa_reserved[1], + p->psa_reserved[2], + p->psa_reserved[3]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); + printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); + printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); +} /* wv_psa_show */ +#endif /* DEBUG_PSA_SHOW */ + +#ifdef DEBUG_MMC_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the Modem Management Controller. + * This function need to be completed... + */ +static void +wv_mmc_show(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *)dev->priv; + mmr_t m; + + /* Basic check */ + if(hasr_read(base) & HASR_NO_CLK) + { + printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n", + dev->name); + return; + } + + wv_splhi(lp, &flags); + + /* Read the mmc */ + mmc_out(base, mmwoff(0, mmw_freeze), 1); + mmc_read(base, 0, (u_char *)&m, sizeof(m)); + mmc_out(base, mmwoff(0, mmw_freeze), 0); + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + /* Don't forget to update statistics */ + lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; +#endif /* WIRELESS_EXT */ + + wv_splx(lp, &flags); + + printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused0[0], + m.mmr_unused0[1], + m.mmr_unused0[2], + m.mmr_unused0[3], + m.mmr_unused0[4], + m.mmr_unused0[5], + m.mmr_unused0[6], + m.mmr_unused0[7]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n", + m.mmr_des_avail, m.mmr_des_status); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused1[0], + m.mmr_unused1[1], + m.mmr_unused1[2], + m.mmr_unused1[3], + m.mmr_unused1[4]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", + m.mmr_dce_status, + (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"", + (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? + "loop test indicated," : "", + (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "", + (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? + "jabber timer expired," : ""); + printk(KERN_DEBUG "Dsp ID: %02X\n", + m.mmr_dsp_id); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", + m.mmr_unused2[0], + m.mmr_unused2[1]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", + (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, + (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); + printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", + m.mmr_thr_pre_set & MMR_THR_PRE_SET, + (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below"); + printk(KERN_DEBUG "signal_lvl: %d [%s], ", + m.mmr_signal_lvl & MMR_SIGNAL_LVL, + (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg"); + printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL, + (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update"); + printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, + (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); +#endif /* DEBUG_SHOW_UNUSED */ +} /* wv_mmc_show */ +#endif /* DEBUG_MMC_SHOW */ + +#ifdef DEBUG_I82593_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the i82593's receive unit. + */ +static void +wv_ru_show(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + + printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n"); + printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop); + /* + * Not implemented yet... + */ + printk("\n"); +} /* wv_ru_show */ +#endif /* DEBUG_I82593_SHOW */ + +#ifdef DEBUG_DEVICE_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver. + */ +static void +wv_dev_show(device * dev) +{ + printk(KERN_DEBUG "dev:"); + printk(" state=%lX,", dev->state); + printk(" trans_start=%ld,", dev->trans_start); + printk(" flags=0x%x,", dev->flags); + printk("\n"); +} /* wv_dev_show */ + +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver's + * private information. + */ +static void +wv_local_show(device * dev) +{ + net_local *lp; + + lp = (net_local *)dev->priv; + + printk(KERN_DEBUG "local:"); + /* + * Not implemented yet... + */ + printk("\n"); +} /* wv_local_show */ +#endif /* DEBUG_DEVICE_SHOW */ + +#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) +/*------------------------------------------------------------------*/ +/* + * Dump packet header (and content if necessary) on the screen + */ +static inline void +wv_packet_info(u_char * p, /* Packet to dump */ + int length, /* Length of the packet */ + char * msg1, /* Name of the device */ + char * msg2) /* Name of the function */ +{ + int i; + int maxi; + + printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", + msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); + printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", + msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]); + +#ifdef DEBUG_PACKET_DUMP + + printk(KERN_DEBUG "data=\""); + + if((maxi = length) > DEBUG_PACKET_DUMP) + maxi = DEBUG_PACKET_DUMP; + for(i = 14; i < maxi; i++) + if(p[i] >= ' ' && p[i] <= '~') + printk(" %c", p[i]); + else + printk("%02X", p[i]); + if(maxi < length) + printk(".."); + printk("\"\n"); + printk(KERN_DEBUG "\n"); +#endif /* DEBUG_PACKET_DUMP */ +} +#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ + +/*------------------------------------------------------------------*/ +/* + * This is the information which is displayed by the driver at startup + * There is a lot of flag to configure it at your will... + */ +static inline void +wv_init_info(device * dev) +{ + ioaddr_t base = dev->base_addr; + psa_t psa; + int i; + + /* Read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + +#ifdef DEBUG_PSA_SHOW + wv_psa_show(&psa); +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82593_SHOW + wv_ru_show(dev); +#endif + +#ifdef DEBUG_BASIC_SHOW + /* Now, let's go for the basic stuff */ + printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr", + dev->name, base, dev->irq); + for(i = 0; i < WAVELAN_ADDR_SIZE; i++) + printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); + + /* Print current network id */ + if(psa.psa_nwid_select) + printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]); + else + printk(", nwid off"); + + /* If 2.00 card */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + unsigned short freq; + + /* Ask the EEprom to read the frequency from the first area */ + fee_read(base, 0x00 /* 1st area - frequency... */, + &freq, 1); + + /* Print frequency */ + printk(", 2.00, %ld", (freq >> 6) + 2400L); + + /* Hack !!! */ + if(freq & 0x20) + printk(".5"); + } + else + { + printk(", PCMCIA, "); + switch (psa.psa_subband) + { + case PSA_SUBBAND_915: + printk("915"); + break; + case PSA_SUBBAND_2425: + printk("2425"); + break; + case PSA_SUBBAND_2460: + printk("2460"); + break; + case PSA_SUBBAND_2484: + printk("2484"); + break; + case PSA_SUBBAND_2430_5: + printk("2430.5"); + break; + default: + printk("???"); + } + } + + printk(" MHz\n"); +#endif /* DEBUG_BASIC_SHOW */ + +#ifdef DEBUG_VERSION_SHOW + /* Print version information */ + printk(KERN_NOTICE "%s", version); +#endif +} /* wv_init_info */ + +/********************* IOCTL, STATS & RECONFIG *********************/ +/* + * We found here routines that are called by Linux on differents + * occasions after the configuration and not for transmitting data + * These may be called when the user use ifconfig, /proc/net/dev + * or wireless extensions + */ + +/*------------------------------------------------------------------*/ +/* + * Get the current ethernet statistics. This may be called with the + * card open or closed. + * Used when the user read /proc/net/dev + */ +static en_stats * +wavelan_get_stats(device * dev) +{ +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); +#endif + + return(&((net_local *) dev->priv)->stats); +} + +/*------------------------------------------------------------------*/ +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + */ + +static void +wavelan_set_multicast_list(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name); +#endif + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", + dev->name, dev->flags, dev->mc_count); +#endif + + if(dev->flags & IFF_PROMISC) + { + /* + * Enable promiscuous mode: receive all packets. + */ + if(!lp->promiscuous) + { + lp->promiscuous = 1; + lp->allmulticast = 0; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + + /* Tell the kernel that we are doing a really bad job... */ + dev->flags |= IFF_PROMISC; + } + } + else + /* If all multicast addresses + * or too much multicast addresses for the hardware filter */ + if((dev->flags & IFF_ALLMULTI) || + (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES)) + { + /* + * Disable promiscuous mode, but active the all multicast mode + */ + if(!lp->allmulticast) + { + lp->promiscuous = 0; + lp->allmulticast = 1; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + + /* Tell the kernel that we are doing a really bad job... */ + dev->flags |= IFF_ALLMULTI; + } + } + else + /* If there is some multicast addresses to send */ + if(dev->mc_list != (struct dev_mc_list *) NULL) + { + /* + * Disable promiscuous mode, but receive all packets + * in multicast list + */ +#ifdef MULTICAST_AVOID + if(lp->promiscuous || lp->allmulticast || + (dev->mc_count != lp->mc_count)) +#endif + { + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = dev->mc_count; + + wv_82593_reconfig(dev); + } + } + else + { + /* + * Switch to normal mode: disable promiscuous mode and + * clear the multicast list. + */ + if(lp->promiscuous || lp->mc_count == 0) + { + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + } + } +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This function doesn't exist... + * (Note : it was a nice way to test the reconfigure stuff...) + */ +#ifdef SET_MAC_ADDRESS +static int +wavelan_set_mac_address(device * dev, + void * addr) +{ + struct sockaddr * mac = addr; + + /* Copy the address */ + memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); + + /* Reconfig the beast */ + wv_82593_reconfig(dev); + + return 0; +} +#endif /* SET_MAC_ADDRESS */ + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + +/*------------------------------------------------------------------*/ +/* + * Frequency setting (for hardware able of it) + * It's a bit complicated and you don't really want to look into it... + * (called in wavelan_ioctl) + */ +static inline int +wv_set_frequency(u_long base, /* i/o port of the card */ + iw_freq * frequency) +{ + const int BAND_NUM = 10; /* Number of bands */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ +#ifdef DEBUG_IOCTL_INFO + int i; +#endif + + /* Setting by frequency */ + /* Theoritically, you may set any frequency between + * the two limits with a 0.5 MHz precision. In practice, + * I don't want you to have trouble with local + * regulations... */ + if((frequency->e == 1) && + (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) + { + freq = ((frequency->m / 10000) - 24000L) / 5; + } + + /* Setting by channel (same as wfreqsel) */ + /* Warning : each channel is 22MHz wide, so some of the channels + * will interfere... */ + if((frequency->e == 0) && + (frequency->m >= 0) && (frequency->m < BAND_NUM)) + { + /* Get frequency offset. */ + freq = channel_bands[frequency->m] >> 1; + } + + /* Verify if the frequency is allowed */ + if(freq != 0L) + { + u_short table[10]; /* Authorized frequency table */ + + /* Read the frequency table */ + fee_read(base, 0x71 /* frequency table */, + table, 10); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Frequency table :"); + for(i = 0; i < 10; i++) + { + printk(" %04X", + table[i]); + } + printk("\n"); +#endif + + /* Look in the table if the frequency is allowed */ + if(!(table[9 - ((freq - 24) / 16)] & + (1 << ((freq - 24) % 16)))) + return -EINVAL; /* not allowed */ + } + else + return -EINVAL; + + /* If we get a usable frequency */ + if(freq != 0L) + { + unsigned short area[16]; + unsigned short dac[2]; + unsigned short area_verify[16]; + unsigned short dac_verify[2]; + /* Corresponding gain (in the power adjust value table) + * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8 + * & WCIN062D.DOC, page 6.2.9 */ + unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; + int power_band = 0; /* Selected band */ + unsigned short power_adjust; /* Correct value */ + + /* Search for the gain */ + power_band = 0; + while((freq > power_limit[power_band]) && + (power_limit[++power_band] != 0)) + ; + + /* Read the first area */ + fee_read(base, 0x00, + area, 16); + + /* Read the DAC */ + fee_read(base, 0x60, + dac, 2); + + /* Read the new power adjust value */ + fee_read(base, 0x6B - (power_band >> 1), + &power_adjust, 1); + if(power_band & 0x1) + power_adjust >>= 8; + else + power_adjust &= 0xFF; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); + for(i = 0; i < 16; i++) + { + printk(" %04X", + area[i]); + } + printk("\n"); + + printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", + dac[0], dac[1]); +#endif + + /* Frequency offset (for info only...) */ + area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); + + /* Receiver Principle main divider coefficient */ + area[3] = (freq >> 1) + 2400L - 352L; + area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Transmitter Main divider coefficient */ + area[13] = (freq >> 1) + 2400L; + area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Others part of the area are flags, bit streams or unused... */ + + /* Set the value in the DAC */ + dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); + dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); + + /* Write the first area */ + fee_write(base, 0x00, + area, 16); + + /* Write the DAC */ + fee_write(base, 0x60, + dac, 2); + + /* We now should verify here that the EEprom writting was ok */ + + /* ReRead the first area */ + fee_read(base, 0x00, + area_verify, 16); + + /* ReRead the DAC */ + fee_read(base, 0x60, + dac_verify, 2); + + /* Compare */ + if(memcmp(area, area_verify, 16 * 2) || + memcmp(dac, dac_verify, 2 * 2)) + { +#ifdef DEBUG_IOCTL_ERROR + printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n"); +#endif + return -EOPNOTSUPP; + } + + /* We must download the frequency parameters to the + * synthetisers (from the EEprom - area 1) + * Note : as the EEprom is auto decremented, we set the end + * if the area... */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + + /* We must now download the power adjust value (gain) to + * the synthetisers (from the EEprom - area 7 - DAC) */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + +#ifdef DEBUG_IOCTL_INFO + /* Verification of what we have done... */ + + printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); + for(i = 0; i < 16; i++) + { + printk(" %04X", + area_verify[i]); + } + printk("\n"); + + printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", + dac_verify[0], dac_verify[1]); +#endif + + return 0; + } + else + return -EINVAL; /* Bah, never get there... */ +} + +/*------------------------------------------------------------------*/ +/* + * Give the list of available frequencies + */ +static inline int +wv_frequency_list(u_long base, /* i/o port of the card */ + iw_freq * list, /* List of frequency to fill */ + int max) /* Maximum number of frequencies */ +{ + u_short table[10]; /* Authorized frequency table */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ + int i; /* index in the table */ +#if WIRELESS_EXT > 7 + const int BAND_NUM = 10; /* Number of bands */ + int c = 0; /* Channel number */ +#endif /* WIRELESS_EXT */ + + /* Read the frequency table */ + fee_read(base, 0x71 /* frequency table */, + table, 10); + + /* Look all frequencies */ + i = 0; + for(freq = 0; freq < 150; freq++) + /* Look in the table if the frequency is allowed */ + if(table[9 - (freq / 16)] & (1 << (freq % 16))) + { +#if WIRELESS_EXT > 7 + /* Compute approximate channel number */ + while((((channel_bands[c] >> 1) - 24) < freq) && + (c < BAND_NUM)) + c++; + list[i].i = c; /* Set the list index */ +#endif /* WIRELESS_EXT */ + + /* put in the list */ + list[i].m = (((freq + 24) * 5) + 24000L) * 10000; + list[i++].e = 1; + + /* Check number */ + if(i >= max) + return(i); + } + + return(i); +} + +#ifdef WIRELESS_SPY +/*------------------------------------------------------------------*/ +/* + * Gather wireless spy statistics : for each packet, compare the source + * address with out list, and if match, get the stats... + * Sorry, but this function really need wireless extensions... + */ +static inline void +wl_spy_gather(device * dev, + u_char * mac, /* MAC address */ + u_char * stats) /* Statistics to gather */ +{ + net_local * lp = (net_local *) dev->priv; + int i; + + /* Look all addresses */ + for(i = 0; i < lp->spy_number; i++) + /* If match */ + if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) + { + /* Update statistics */ + lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; + lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; + lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; + lp->spy_stat[i].updated = 0x7; + } +} +#endif /* WIRELESS_SPY */ + +#ifdef HISTOGRAM +/*------------------------------------------------------------------*/ +/* + * This function calculate an histogram on the signal level. + * As the noise is quite constant, it's like doing it on the SNR. + * We have defined a set of interval (lp->his_range), and each time + * the level goes in that interval, we increment the count (lp->his_sum). + * With this histogram you may detect if one wavelan is really weak, + * or you may also calculate the mean and standard deviation of the level... + */ +static inline void +wl_his_gather(device * dev, + u_char * stats) /* Statistics to gather */ +{ + net_local * lp = (net_local *) dev->priv; + u_char level = stats[0] & MMR_SIGNAL_LVL; + int i; + + /* Find the correct interval */ + i = 0; + while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])) + ; + + /* Increment interval counter */ + (lp->his_sum[i])++; +} +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Perform ioctl : config & info stuff + * This is here that are treated the wireless extensions (iwconfig) + */ +static int +wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ + struct ifreq * rq, /* Data passed */ + int cmd) /* Ioctl number */ +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *)dev->priv; /* lp is not unused */ + struct iwreq * wrq = (struct iwreq *) rq; + psa_t psa; + mm_t m; + unsigned long flags; + int ret = 0; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); +#endif + + /* Disable interrupts & save flags */ + wv_splhi(lp, &flags); + + /* Look what is the request */ + switch(cmd) + { + /* --------------- WIRELESS EXTENSIONS --------------- */ + + case SIOCGIWNAME: + strcpy(wrq->u.name, "Wavelan"); + break; + + case SIOCSIWNWID: + /* Set NWID in wavelan */ +#if WIRELESS_EXT > 8 + if(!wrq->u.nwid.disabled) + { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; +#else /* WIRELESS_EXT > 8 */ + if(wrq->u.nwid.on) + { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; +#endif /* WIRELESS_EXT > 8 */ + psa.psa_nwid_select = 0x01; + psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, + (unsigned char *)psa.psa_nwid, 3); + + /* Set NWID in mmc */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, + (unsigned char *)&m.w.mmw_netw_id_l, 2); + mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); + } + else + { + /* Disable nwid in the psa */ + psa.psa_nwid_select = 0x00; + psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa, + (unsigned char *)&psa.psa_nwid_select, 1); + + /* Disable nwid in the mmc (no filtering) */ + mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); + break; + + case SIOCGIWNWID: + /* Read the NWID */ + psa_read(dev, (char *)psa.psa_nwid - (char *)&psa, + (unsigned char *)psa.psa_nwid, 3); +#if WIRELESS_EXT > 8 + wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.disabled = !(psa.psa_nwid_select); + wrq->u.nwid.fixed = 1; /* Superfluous */ +#else /* WIRELESS_EXT > 8 */ + wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.on = psa.psa_nwid_select; +#endif /* WIRELESS_EXT > 8 */ + break; + + case SIOCSIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(base, &(wrq->u.freq)); + else + ret = -EOPNOTSUPP; + break; + + case SIOCGIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) + * (does it work for everybody ??? - especially old cards...) */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + unsigned short freq; + + /* Ask the EEprom to read the frequency from the first area */ + fee_read(base, 0x00 /* 1st area - frequency... */, + &freq, 1); + wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrq->u.freq.e = 1; + } + else + { + psa_read(dev, (char *)&psa.psa_subband - (char *)&psa, + (unsigned char *)&psa.psa_subband, 1); + + if(psa.psa_subband <= 4) + { + wrq->u.freq.m = fixed_bands[psa.psa_subband]; + wrq->u.freq.e = (psa.psa_subband != 0); + } + else + ret = -EOPNOTSUPP; + } + break; + + case SIOCSIWSENS: + /* Set the level threshold */ +#if WIRELESS_EXT > 7 + /* We should complain loudly if wrq->u.sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; +#else /* WIRELESS_EXT > 7 */ + psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; +#endif /* WIRELESS_EXT > 7 */ + psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *)&psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); + break; + + case SIOCGIWSENS: + /* Read the level threshold */ + psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *)&psa.psa_thr_pre_set, 1); +#if WIRELESS_EXT > 7 + wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; + wrq->u.sens.fixed = 1; +#else /* WIRELESS_EXT > 7 */ + wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; +#endif /* WIRELESS_EXT > 7 */ + break; + +#if WIRELESS_EXT > 8 + case SIOCSIWENCODE: + /* Set encryption key */ + if(!mmc_encr(base)) + { + ret = -EOPNOTSUPP; + break; + } + + /* Basic checking... */ + if(wrq->u.encoding.pointer != (caddr_t) 0) + { + /* Check the size of the key */ + if(wrq->u.encoding.length != 8) + { + ret = -EINVAL; + break; + } + + /* Copy the key in the driver */ + if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer, + wrq->u.encoding.length)) + { + ret = -EFAULT; + break; + } + + psa.psa_encryption_select = 1; + psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 8+1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); + mmc_write(base, mmwoff(0, mmw_encr_key), + (unsigned char *) &psa.psa_encryption_key, 8); + } + + if(wrq->u.encoding.flags & IW_ENCODE_DISABLED) + { /* disable encryption */ + psa.psa_encryption_select = 0; + psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), 0); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); + break; + + case SIOCGIWENCODE: + /* Read the encryption key */ + if(!mmc_encr(base)) + { + ret = -EOPNOTSUPP; + break; + } + + /* only super-user can see encryption key */ + if(!capable(CAP_NET_ADMIN)) + { + ret = -EPERM; + break; + } + + /* Basic checking... */ + if(wrq->u.encoding.pointer != (caddr_t) 0) + { + psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 1+8); + + /* encryption is enabled ? */ + if(psa.psa_encryption_select) + wrq->u.encoding.flags = IW_ENCODE_ENABLED; + else + wrq->u.encoding.flags = IW_ENCODE_DISABLED; + wrq->u.encoding.flags |= mmc_encr(base); + + /* Copy the key to the user buffer */ + wrq->u.encoding.length = 8; + if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8)) + ret = -EFAULT; + } + break; +#endif /* WIRELESS_EXT > 8 */ + +#ifdef WAVELAN_ROAMING_EXT +#if WIRELESS_EXT > 5 + case SIOCSIWESSID: + /* Check if disable */ + if(wrq->u.data.flags == 0) + lp->filter_domains = 0; + else + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + char essid[IW_ESSID_MAX_SIZE + 1]; + char * endp; + + /* Check the size of the string */ + if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1) + { + ret = -E2BIG; + break; + } + + /* Copy the string in the driver */ + if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length)) + { + ret = -EFAULT; + break; + } + essid[IW_ESSID_MAX_SIZE] = '\0'; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); +#endif /* DEBUG_IOCTL_INFO */ + + /* Convert to a number (note : Wavelan specific) */ + lp->domain_id = simple_strtoul(essid, &endp, 16); + /* Has it worked ? */ + if(endp > essid) + lp->filter_domains = 1; + else + { + lp->filter_domains = 0; + ret = -EINVAL; + } + } + break; + + case SIOCGIWESSID: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + char essid[IW_ESSID_MAX_SIZE + 1]; + + /* Is the domain ID active ? */ + wrq->u.data.flags = lp->filter_domains; + + /* Copy Domain ID into a string (Wavelan specific) */ + /* Sound crazy, be we can't have a snprintf in the kernel !!! */ + sprintf(essid, "%lX", lp->domain_id); + essid[IW_ESSID_MAX_SIZE] = '\0'; + + /* Set the length */ + wrq->u.data.length = strlen(essid) + 1; + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length)) + ret = -EFAULT; + } + break; + + case SIOCSIWAP: +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", + wrq->u.ap_addr.sa_data[0], + wrq->u.ap_addr.sa_data[1], + wrq->u.ap_addr.sa_data[2], + wrq->u.ap_addr.sa_data[3], + wrq->u.ap_addr.sa_data[4], + wrq->u.ap_addr.sa_data[5]); +#endif /* DEBUG_IOCTL_INFO */ + + ret = -EOPNOTSUPP; /* Not supported yet */ + break; + + case SIOCGIWAP: + /* Should get the real McCoy instead of own Ethernet address */ + memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + + ret = -EOPNOTSUPP; /* Not supported yet */ + break; +#endif /* WIRELESS_EXT > 5 */ +#endif /* WAVELAN_ROAMING_EXT */ + +#if WIRELESS_EXT > 8 +#ifdef WAVELAN_ROAMING + case SIOCSIWMODE: + switch(wrq->u.mode) + { + case IW_MODE_ADHOC: + if(do_roaming) + { + wv_roam_cleanup(dev); + do_roaming = 0; + } + break; + case IW_MODE_INFRA: + if(!do_roaming) + { + wv_roam_init(dev); + do_roaming = 1; + } + break; + default: + ret = -EINVAL; + } + break; + + case SIOCGIWMODE: + if(do_roaming) + wrq->u.mode = IW_MODE_INFRA; + else + wrq->u.mode = IW_MODE_ADHOC; + break; +#endif /* WAVELAN_ROAMING */ +#endif /* WIRELESS_EXT > 8 */ + + case SIOCGIWRANGE: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + struct iw_range range; + + /* Set the length (very important for backward compatibility) */ + wrq->u.data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know about to zero */ + memset(&range, 0, sizeof(range)); + +#if WIRELESS_EXT > 10 + /* Set the Wireless Extension versions */ + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 9; /* Nothing for us in v10 and v11 */ +#endif /* WIRELESS_EXT > 10 */ + + /* Set information in the range struct */ + range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ + range.min_nwid = 0x0000; + range.max_nwid = 0xFFFF; + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + range.num_channels = 10; + range.num_frequency = wv_frequency_list(base, range.freq, + IW_MAX_FREQUENCIES); + } + else + range.num_channels = range.num_frequency = 0; + + range.sensitivity = 0x3F; + range.max_qual.qual = MMR_SGNL_QUAL; + range.max_qual.level = MMR_SIGNAL_LVL; + range.max_qual.noise = MMR_SILENCE_LVL; +#if WIRELESS_EXT > 11 + range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ + /* Need to get better values for those two */ + range.avg_qual.level = 30; + range.avg_qual.noise = 8; +#endif /* WIRELESS_EXT > 11 */ + +#if WIRELESS_EXT > 7 + range.num_bitrates = 1; + range.bitrate[0] = 2000000; /* 2 Mb/s */ +#endif /* WIRELESS_EXT > 7 */ + +#if WIRELESS_EXT > 8 + /* Encryption supported ? */ + if(mmc_encr(base)) + { + range.encoding_size[0] = 8; /* DES = 64 bits key */ + range.num_encoding_sizes = 1; + range.max_encoding_tokens = 1; /* Only one key possible */ + } + else + { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } +#endif /* WIRELESS_EXT > 8 */ + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, &range, + sizeof(struct iw_range))) + ret = -EFAULT; + } + break; + + case SIOCGIWPRIV: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + struct iw_priv_args priv[] = + { /* cmd, set_args, get_args, name */ + { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, + { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, + { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, + { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, + { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" }, + { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, + }; + + /* Set the number of ioctl available */ + wrq->u.data.length = 6; + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, + sizeof(priv))) + ret = -EFAULT; + } + break; + +#ifdef WIRELESS_SPY + case SIOCSIWSPY: + /* Set the spy list */ + + /* Check the number of addresses */ + if(wrq->u.data.length > IW_MAX_SPY) + { + ret = -E2BIG; + break; + } + lp->spy_number = wrq->u.data.length; + + /* If there is some addresses to copy */ + if(lp->spy_number > 0) + { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses to the driver */ + if(copy_from_user(address, wrq->u.data.pointer, + sizeof(struct sockaddr) * lp->spy_number)) + { + ret = -EFAULT; + break; + } + + /* Copy addresses to the lp structure */ + for(i = 0; i < lp->spy_number; i++) + { + memcpy(lp->spy_address[i], address[i].sa_data, + WAVELAN_ADDR_SIZE); + } + + /* Reset structure... */ + memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n"); + for(i = 0; i < wrq->u.data.length; i++) + printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n", + lp->spy_address[i][0], + lp->spy_address[i][1], + lp->spy_address[i][2], + lp->spy_address[i][3], + lp->spy_address[i][4], + lp->spy_address[i][5]); +#endif /* DEBUG_IOCTL_INFO */ + } + + break; + + case SIOCGIWSPY: + /* Get the spy list and spy stats */ + + /* Set the number of addresses */ + wrq->u.data.length = lp->spy_number; + + /* If the user want to have the addresses back... */ + if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) + { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses from the lp structure */ + for(i = 0; i < lp->spy_number; i++) + { + memcpy(address[i].sa_data, lp->spy_address[i], + WAVELAN_ADDR_SIZE); + address[i].sa_family = ARPHRD_ETHER; + } + + /* Copy addresses to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, address, + sizeof(struct sockaddr) * lp->spy_number)) + { + ret = -EFAULT; + break; + } + + /* Copy stats to the user buffer (just after) */ + if(copy_to_user(wrq->u.data.pointer + + (sizeof(struct sockaddr) * lp->spy_number), + lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) + { + ret = -EFAULT; + break; + } + + /* Reset updated flags */ + for(i = 0; i < lp->spy_number; i++) + lp->spy_stat[i].updated = 0x0; + } /* if(pointer != NULL) */ + + break; +#endif /* WIRELESS_SPY */ + + /* ------------------ PRIVATE IOCTL ------------------ */ + + case SIOCSIPQTHR: + if(!capable(CAP_NET_ADMIN)) + { + ret = -EPERM; + break; + } + psa.psa_quality_thr = *(wrq->u.name) & 0x0F; + psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, + (unsigned char *)&psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr); + break; + + case SIOCGIPQTHR: + psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa, + (unsigned char *)&psa.psa_quality_thr, 1); + *(wrq->u.name) = psa.psa_quality_thr & 0x0F; + break; + +#ifdef WAVELAN_ROAMING + case SIOCSIPROAM: + /* Note : should check if user == root */ + if(do_roaming && (*wrq->u.name)==0) + wv_roam_cleanup(dev); + else if(do_roaming==0 && (*wrq->u.name)!=0) + wv_roam_init(dev); + + do_roaming = (*wrq->u.name); + + break; + + case SIOCGIPROAM: + *(wrq->u.name) = do_roaming; + break; +#endif /* WAVELAN_ROAMING */ + +#ifdef HISTOGRAM + case SIOCSIPHISTO: + /* Verif if the user is root */ + if(!capable(CAP_NET_ADMIN)) + { + ret = -EPERM; + } + + /* Check the number of intervals */ + if(wrq->u.data.length > 16) + { + ret = -E2BIG; + break; + } + lp->his_number = wrq->u.data.length; + + /* If there is some addresses to copy */ + if(lp->his_number > 0) + { + /* Copy interval ranges to the driver */ + if(copy_from_user(lp->his_range, wrq->u.data.pointer, + sizeof(char) * lp->his_number)) + { + ret = -EFAULT; + break; + } + + /* Reset structure... */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } + break; + + case SIOCGIPHISTO: + /* Set the number of intervals */ + wrq->u.data.length = lp->his_number; + + /* Give back the distribution statistics */ + if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) + { + /* Copy data to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, lp->his_sum, + sizeof(long) * lp->his_number)) + ret = -EFAULT; + + } /* if(pointer != NULL) */ + break; +#endif /* HISTOGRAM */ + + /* ------------------- OTHER IOCTL ------------------- */ + + default: + ret = -EOPNOTSUPP; + } + + /* ReEnable interrupts & restore flags */ + wv_splx(lp, &flags); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); +#endif + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Get wireless statistics + * Called by /proc/net/wireless... + */ +static iw_stats * +wavelan_get_wireless_stats(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + mmr_t m; + iw_stats * wstats; + unsigned long flags; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); +#endif + + /* Disable interrupts & save flags */ + wv_splhi(lp, &flags); + + wstats = &lp->wstats; + + /* Get data from the mmc */ + mmc_out(base, mmwoff(0, mmw_freeze), 1); + + mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); + mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2); + mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4); + + mmc_out(base, mmwoff(0, mmw_freeze), 0); + + /* Copy data to wireless stuff */ + wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; + wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; + wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; + wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; + wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | + ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | + ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); + wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; + wstats->discard.code = 0L; + wstats->discard.misc = 0L; + + /* ReEnable interrupts & restore flags */ + wv_splx(lp, &flags); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); +#endif + return &lp->wstats; +} +#endif /* WIRELESS_EXT */ + +/************************* PACKET RECEPTION *************************/ +/* + * This part deal with receiving the packets. + * The interrupt handler get an interrupt when a packet has been + * successfully received and called this part... + */ + +/*------------------------------------------------------------------*/ +/* + * Calculate the starting address of the frame pointed to by the receive + * frame pointer and verify that the frame seem correct + * (called by wv_packet_rcv()) + */ +static inline int +wv_start_of_frame(device * dev, + int rfp, /* end of frame */ + int wrap) /* start of buffer */ +{ + ioaddr_t base = dev->base_addr; + int rp; + int len; + + rp = (rfp - 5 + RX_SIZE) % RX_SIZE; + outb(rp & 0xff, PIORL(base)); + outb(((rp >> 8) & PIORH_MASK), PIORH(base)); + len = inb(PIOP(base)); + len |= inb(PIOP(base)) << 8; + + /* Sanity checks on size */ + /* Frame too big */ + if(len > MAXDATAZ + 100) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n", + dev->name, rfp, len); +#endif + return(-1); + } + + /* Frame too short */ + if(len < 7) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n", + dev->name, rfp, len); +#endif + return(-1); + } + + /* Wrap around buffer */ + if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE)) /* magic formula ! */ + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n", + dev->name, wrap, rfp, len); +#endif + return(-1); + } + + return((rp - len + RX_SIZE) % RX_SIZE); +} /* wv_start_of_frame */ + +/*------------------------------------------------------------------*/ +/* + * This routine does the actual copy of data (including the ethernet + * header structure) from the WaveLAN card to an sk_buff chain that + * will be passed up to the network interface layer. NOTE: We + * currently don't handle trailer protocols (neither does the rest of + * the network interface), so if that is needed, it will (at least in + * part) be added here. The contents of the receive ring buffer are + * copied to a message chain that is then passed to the kernel. + * + * Note: if any errors occur, the packet is "dropped on the floor" + * (called by wv_packet_rcv()) + */ +static inline void +wv_packet_read(device * dev, + int fd_p, + int sksize) +{ + net_local * lp = (net_local *) dev->priv; + struct sk_buff * skb; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", + dev->name, fd_p, sksize); +#endif + + /* Allocate some buffer for the new packet */ + if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n", + dev->name, sksize); +#endif + lp->stats.rx_dropped++; + /* + * Not only do we want to return here, but we also need to drop the + * packet on the floor to clear the interrupt. + */ + return; + } + + skb->dev = dev; + + skb_reserve(skb, 2); + fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize); + skb->protocol = eth_type_trans(skb, dev); + +#ifdef DEBUG_RX_INFO + wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); +#endif /* DEBUG_RX_INFO */ + + /* Statistics gathering & stuff associated. + * It seem a bit messy with all the define, but it's really simple... */ + if( +#ifdef WIRELESS_SPY + (lp->spy_number > 0) || +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + (lp->his_number > 0) || +#endif /* HISTOGRAM */ +#ifdef WAVELAN_ROAMING + (do_roaming) || +#endif /* WAVELAN_ROAMING */ + 0) + { + u_char stats[3]; /* Signal level, Noise level, Signal quality */ + + /* read signal level, silence level and signal quality bytes */ + fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE, + stats, 3); +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", + dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F); +#endif + +#ifdef WAVELAN_ROAMING + if(do_roaming) + if(WAVELAN_BEACON(skb->data)) + wl_roam_gather(dev, skb->data, stats); +#endif /* WAVELAN_ROAMING */ + +#ifdef WIRELESS_SPY + wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + wl_his_gather(dev, stats); +#endif /* HISTOGRAM */ + } + + /* + * Hand the packet to the Network Module + */ + netif_rx(skb); + + /* Keep stats up to date */ + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += sksize; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); +#endif + return; +} + +/*------------------------------------------------------------------*/ +/* + * This routine is called by the interrupt handler to initiate a + * packet transfer from the card to the network interface layer above + * this driver. This routine checks if a buffer has been successfully + * received by the WaveLAN card. If so, the routine wv_packet_read is + * called to do the actual transfer of the card's data including the + * ethernet header into a packet consisting of an sk_buff chain. + * (called by wavelan_interrupt()) + * Note : the spinlock is already grabbed for us and irq are disabled. + */ +static inline void +wv_packet_rcv(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + int newrfp; + int rp; + int len; + int f_start; + int status; + int i593_rfp; + int stat_ptr; + u_char c[4]; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name); +#endif + + /* Get the new receive frame pointer from the i82593 chip */ + outb(CR0_STATUS_2 | OP0_NOP, LCCR(base)); + i593_rfp = inb(LCSR(base)); + i593_rfp |= inb(LCSR(base)) << 8; + i593_rfp %= RX_SIZE; + + /* Get the new receive frame pointer from the WaveLAN card. + * It is 3 bytes more than the increment of the i82593 receive + * frame pointer, for each packet. This is because it includes the + * 3 roaming bytes added by the mmc. + */ + newrfp = inb(RPLL(base)); + newrfp |= inb(RPLH(base)) << 8; + newrfp %= RX_SIZE; + +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + +#ifdef DEBUG_RX_ERROR + /* If no new frame pointer... */ + if(lp->overrunning || newrfp == lp->rfp) + printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + + /* Read all frames (packets) received */ + while(newrfp != lp->rfp) + { + /* A frame is composed of the packet, followed by a status word, + * the length of the frame (word) and the mmc info (SNR & qual). + * It's because the length is at the end that we can only scan + * frames backward. */ + + /* Find the first frame by skipping backwards over the frames */ + rp = newrfp; /* End of last frame */ + while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) && + (f_start != -1)) + rp = f_start; + + /* If we had a problem */ + if(f_start == -1) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "wavelan_cs: cannot find start of frame "); + printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + lp->rfp = rp; /* Get to the last usable frame */ + continue; + } + + /* f_start point to the beggining of the first frame received + * and rp to the beggining of the next one */ + + /* Read status & length of the frame */ + stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE; + stat_ptr = read_ringbuf(dev, stat_ptr, c, 4); + status = c[0] | (c[1] << 8); + len = c[2] | (c[3] << 8); + + /* Check status */ + if((status & RX_RCV_OK) != RX_RCV_OK) + { + lp->stats.rx_errors++; + if(status & RX_NO_SFD) + lp->stats.rx_frame_errors++; + if(status & RX_CRC_ERR) + lp->stats.rx_crc_errors++; + if(status & RX_OVRRUN) + lp->stats.rx_over_errors++; + +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n", + dev->name, status); +#endif + } + else + /* Read the packet and transmit to Linux */ + wv_packet_read(dev, f_start, len - 2); + + /* One frame has been processed, skip it */ + lp->rfp = rp; + } + + /* + * Update the frame stop register, but set it to less than + * the full 8K to allow space for 3 bytes of signal strength + * per packet. + */ + lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; + outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); + outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); + outb(OP1_SWIT_TO_PORT_0, LCCR(base)); + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name); +#endif +} + +/*********************** PACKET TRANSMISSION ***********************/ +/* + * This part deal with sending packet through the wavelan + * We copy the packet to the send buffer and then issue the send + * command to the i82593. The result of this operation will be + * checked in wavelan_interrupt() + */ + +/*------------------------------------------------------------------*/ +/* + * This routine fills in the appropriate registers and memory + * locations on the WaveLAN card and starts the card off on + * the transmit. + * (called in wavelan_packet_xmit()) + */ +static inline void +wv_packet_write(device * dev, + void * buf, + short length) +{ + net_local * lp = (net_local *) dev->priv; + ioaddr_t base = dev->base_addr; + unsigned long flags; + int clen = length; + register u_short xmtdata_base = TX_BASE; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); +#endif + + wv_splhi(lp, &flags); + + /* Check if we need some padding */ + if(clen < ETH_ZLEN) + clen = ETH_ZLEN; + + /* Write the length of data buffer followed by the buffer */ + outb(xmtdata_base & 0xff, PIORL(base)); + outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(clen & 0xff, PIOP(base)); /* lsb */ + outb(clen >> 8, PIOP(base)); /* msb */ + + /* Send the data */ + outsb(PIOP(base), buf, clen); + + /* Indicate end of transmit chain */ + outb(OP0_NOP, PIOP(base)); + /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */ + outb(OP0_NOP, PIOP(base)); + + /* Reset the transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + /* Send the transmit command */ + wv_82593_cmd(dev, "wv_packet_write(): transmit", + OP0_TRANSMIT, SR0_NO_RESULT); + + /* Keep stats up to date */ + lp->stats.tx_bytes += length; + + wv_splx(lp, &flags); + +#ifdef DEBUG_TX_INFO + wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); +#endif /* DEBUG_TX_INFO */ + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This routine is called when we want to send a packet (NET3 callback) + * In this routine, we check if the harware is ready to accept + * the packet. We also prevent reentrance. Then, we call the function + * to send the packet... + */ +static int +wavelan_packet_xmit(struct sk_buff * skb, + device * dev) +{ + net_local * lp = (net_local *)dev->priv; + unsigned long flags; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, + (unsigned) skb); +#endif + + /* + * Block a timer-based transmit from overlapping a previous transmit. + * In other words, prevent reentering this routine. + */ + netif_stop_queue(dev); + + /* If somebody has asked to reconfigure the controller, + * we can do it now */ + if(lp->reconfig_82593) + { + wv_splhi(lp, &flags); /* Disable interrupts */ + wv_82593_config(dev); + wv_splx(lp, &flags); /* Re-enable interrupts */ + /* Note : the configure procedure was totally synchronous, + * so the Tx buffer is now free */ + } + +#ifdef DEBUG_TX_ERROR + if (skb->next) + printk(KERN_INFO "skb has next\n"); +#endif + + wv_packet_write(dev, skb->data, skb->len); + + dev_kfree_skb(skb); + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); +#endif + return(0); +} + +/********************** HARDWARE CONFIGURATION **********************/ +/* + * This part do the real job of starting and configuring the hardware. + */ + +/*------------------------------------------------------------------*/ +/* + * Routine to initialize the Modem Management Controller. + * (called by wv_hw_config()) + */ +static inline int +wv_mmc_init(device * dev) +{ + ioaddr_t base = dev->base_addr; + psa_t psa; + mmw_t m; + int configured; + int i; /* Loop counter */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); +#endif + + /* Read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + + /* + * Check the first three octets of the MAC addr for the manufacturer's code. + * Note: If you get the error message below, you've got a + * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on + * how to configure your card... + */ + for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) + if((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) && + (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) && + (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2])) + break; + + /* If we have not found it... */ + if(i == (sizeof(MAC_ADDRESSES) / sizeof(char) / 3)) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n", + dev->name, psa.psa_univ_mac_addr[0], + psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]); +#endif + return FALSE; + } + + /* Get the MAC address */ + memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE); + +#ifdef USE_PSA_CONFIG + configured = psa.psa_conf_status & 1; +#else + configured = 0; +#endif + + /* Is the PSA is not configured */ + if(!configured) + { + /* User will be able to configure NWID after (with iwconfig) */ + psa.psa_nwid[0] = 0; + psa.psa_nwid[1] = 0; + + /* As NWID is not set : no NWID checking */ + psa.psa_nwid_select = 0; + + /* Disable encryption */ + psa.psa_encryption_select = 0; + + /* Set to standard values + * 0x04 for AT, + * 0x01 for MCA, + * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) + */ + if (psa.psa_comp_number & 1) + psa.psa_thr_pre_set = 0x01; + else + psa.psa_thr_pre_set = 0x04; + psa.psa_quality_thr = 0x03; + + /* It is configured */ + psa.psa_conf_status |= 1; + +#ifdef USE_PSA_CONFIG + /* Write the psa */ + psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, + (unsigned char *)psa.psa_nwid, 4); + psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *)&psa.psa_thr_pre_set, 1); + psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, + (unsigned char *)&psa.psa_quality_thr, 1); + psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa, + (unsigned char *)&psa.psa_conf_status, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); +#endif /* USE_PSA_CONFIG */ + } + + /* Zero the mmc structure */ + memset(&m, 0x00, sizeof(m)); + + /* Copy PSA info to the mmc */ + m.mmw_netw_id_l = psa.psa_nwid[1]; + m.mmw_netw_id_h = psa.psa_nwid[0]; + + if(psa.psa_nwid_select & 1) + m.mmw_loopt_sel = 0x00; + else + m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; + + memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, + sizeof(m.mmw_encr_key)); + + if(psa.psa_encryption_select) + m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; + else + m.mmw_encr_enable = 0; + + m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; + m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; + + /* + * Set default modem control parameters. + * See NCR document 407-0024326 Rev. A. + */ + m.mmw_jabber_enable = 0x01; + m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; + m.mmw_ifs = 0x20; + m.mmw_mod_delay = 0x04; + m.mmw_jam_time = 0x38; + + m.mmw_des_io_invert = 0; + m.mmw_freeze = 0; + m.mmw_decay_prm = 0; + m.mmw_decay_updat_prm = 0; + + /* Write all info to mmc */ + mmc_write(base, 0, (u_char *)&m, sizeof(m)); + + /* The following code start the modem of the 2.00 frequency + * selectable cards at power on. It's not strictly needed for the + * following boots... + * The original patch was by Joe Finney for the PCMCIA driver, but + * I've cleaned it a bit and add documentation. + * Thanks to Loeke Brederveld from Lucent for the info. + */ + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) + * (does it work for everybody ??? - especially old cards...) */ + /* Note : WFREQSEL verify that it is able to read from EEprom + * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID + * is 0xA (Xilinx version) or 0xB (Ariadne version). + * My test is more crude but do work... */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + /* We must download the frequency parameters to the + * synthetisers (from the EEprom - area 1) + * Note : as the EEprom is auto decremented, we set the end + * if the area... */ + m.mmw_fee_addr = 0x0F; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, + (unsigned char *)&m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + +#ifdef DEBUG_CONFIG_INFO + /* The frequency was in the last word downloaded... */ + mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m, + (unsigned char *)&m.mmw_fee_data_l, 2); + + /* Print some info for the user */ + printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n", + dev->name, + ((m.mmw_fee_data_h << 4) | + (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L); +#endif + + /* We must now download the power adjust value (gain) to + * the synthetisers (from the EEprom - area 7 - DAC) */ + m.mmw_fee_addr = 0x61; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, + (unsigned char *)&m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished */ + } /* if 2.00 card */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * Routine to gracefully turn off reception, and wait for any commands + * to complete. + * (called in wv_ru_start() and wavelan_close() and wavelan_event()) + */ +static int +wv_ru_stop(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + unsigned long flags; + int status; + int spin; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); +#endif + + wv_splhi(lp, &flags); + + /* First, send the LAN controller a stop receive command */ + wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", + OP0_STOP_RCV, SR0_NO_RESULT); + + /* Then, spin until the receive unit goes idle */ + spin = 300; + do + { + udelay(10); + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + } + while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0)); + + /* Now, spin until the chip finishes executing its current command */ + do + { + udelay(10); + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + } + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); + + wv_splx(lp, &flags); + + /* If there was a problem */ + if(spin <= 0) + { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n", + dev->name); +#endif + return FALSE; + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name); +#endif + return TRUE; +} /* wv_ru_stop */ + +/*------------------------------------------------------------------*/ +/* + * This routine starts the receive unit running. First, it checks if + * the card is actually ready. Then the card is instructed to receive + * packets again. + * (called in wv_hw_reset() & wavelan_open()) + */ +static int +wv_ru_start(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + unsigned long flags; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); +#endif + + /* + * We need to start from a quiescent state. To do so, we could check + * if the card is already running, but instead we just try to shut + * it down. First, we disable reception (in case it was already enabled). + */ + if(!wv_ru_stop(dev)) + return FALSE; + + wv_splhi(lp, &flags); + + /* Now we know that no command is being executed. */ + + /* Set the receive frame pointer and stop pointer */ + lp->rfp = 0; + outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); + + /* Reset ring management. This sets the receive frame pointer to 1 */ + outb(OP1_RESET_RING_MNGMT, LCCR(base)); + +#if 0 + /* XXX the i82593 manual page 6-4 seems to indicate that the stop register + should be set as below */ + /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/ +#elif 0 + /* but I set it 0 instead */ + lp->stop = 0; +#else + /* but I set it to 3 bytes per packet less than 8K */ + lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; +#endif + outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); + outb(OP1_INT_ENABLE, LCCR(base)); + outb(OP1_SWIT_TO_PORT_0, LCCR(base)); + + /* Reset receive DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write_slow(base, HACR_DEFAULT); + + /* Receive DMA on channel 1 */ + wv_82593_cmd(dev, "wv_ru_start(): rcv-enable", + CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT); + +#ifdef DEBUG_I82593_SHOW + { + int status; + int opri; + int spin = 10000; + + /* spin until the chip starts receiving */ + do + { + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + if(spin-- <= 0) + break; + } + while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) && + ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY)); + printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n", + (status & SR3_RCV_STATE_MASK), i); + } +#endif + + wv_splx(lp, &flags); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * This routine does a standard config of the WaveLAN controller (i82593). + * In the ISA driver, this is integrated in wavelan_hardware_reset() + * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) + */ +static int +wv_82593_config(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + struct i82593_conf_block cfblk; + int ret = TRUE; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name); +#endif + + /* Create & fill i82593 config block + * + * Now conform to Wavelan document WCIN085B + */ + memset(&cfblk, 0x00, sizeof(struct i82593_conf_block)); + cfblk.d6mod = FALSE; /* Run in i82593 advanced mode */ + cfblk.fifo_limit = 5; /* = 56 B rx and 40 B tx fifo thresholds */ + cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ + cfblk.fifo_32 = 1; + cfblk.throttle_enb = FALSE; + cfblk.contin = TRUE; /* enable continuous mode */ + cfblk.cntrxint = FALSE; /* enable continuous mode receive interrupts */ + cfblk.addr_len = WAVELAN_ADDR_SIZE; + cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */ + cfblk.preamb_len = 0; /* 2 bytes preamble (SFD) */ + cfblk.loopback = FALSE; + cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */ + cfblk.exp_prio = 5; /* conform to 802.3 backoff algoritm */ + cfblk.bof_met = 1; /* conform to 802.3 backoff algoritm */ + cfblk.ifrm_spc = 0x20; /* 32 bit times interframe spacing */ + cfblk.slottim_low = 0x20; /* 32 bit times slot time */ + cfblk.slottim_hi = 0x0; + cfblk.max_retr = 15; + cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE); /* Promiscuous mode */ + cfblk.bc_dis = FALSE; /* Enable broadcast reception */ + cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ + cfblk.nocrc_ins = FALSE; /* i82593 generates CRC */ + cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ + cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ + cfblk.cs_filter = 0; /* CS is recognized immediately */ + cfblk.crs_src = FALSE; /* External carrier sense */ + cfblk.cd_filter = 0; /* CD is recognized immediately */ + cfblk.min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length 64 bytes */ + cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ + cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ + cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ + cfblk.artx = TRUE; /* Disable automatic retransmission */ + cfblk.sarec = TRUE; /* Disable source addr trig of CD */ + cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ + cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ + cfblk.lbpkpol = TRUE; /* Loopback pin active high */ + cfblk.fdx = FALSE; /* Disable full duplex operation */ + cfblk.dummy_6 = 0x3f; /* all ones */ + cfblk.mult_ia = FALSE; /* No multiple individual addresses */ + cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ + cfblk.dummy_1 = TRUE; /* set to 1 */ + cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ +#ifdef MULTICAST_ALL + cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE); /* Allow all multicasts */ +#else + cfblk.mc_all = FALSE; /* No multicast all mode */ +#endif + cfblk.rcv_mon = 0; /* Monitor mode disabled */ + cfblk.frag_acpt = TRUE; /* Do not accept fragments */ + cfblk.tstrttrs = FALSE; /* No start transmission threshold */ + cfblk.fretx = TRUE; /* FIFO automatic retransmission */ + cfblk.syncrqs = FALSE; /* Synchronous DRQ deassertion... */ + cfblk.sttlen = TRUE; /* 6 byte status registers */ + cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ + cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ + cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */ + cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ + +#ifdef DEBUG_I82593_SHOW + { + u_char *c = (u_char *) &cfblk; + int i; + printk(KERN_DEBUG "wavelan_cs: config block:"); + for(i = 0; i < sizeof(struct i82593_conf_block); i++,c++) + { + if((i % 16) == 0) printk("\n" KERN_DEBUG); + printk("%02x ", *c); + } + printk("\n"); + } +#endif + + /* Copy the config block to the i82593 */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base)); /* lsb */ + outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base)); /* msb */ + outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block)); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): configure", + OP0_CONFIGURE, SR0_CONFIGURE_DONE)) + ret = FALSE; + + /* Initialize adapter's ethernet MAC address */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(WAVELAN_ADDR_SIZE, PIOP(base)); /* byte count lsb */ + outb(0, PIOP(base)); /* byte count msb */ + outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup", + OP0_IA_SETUP, SR0_IA_SETUP_DONE)) + ret = FALSE; + +#ifdef WAVELAN_ROAMING + /* If roaming is enabled, join the "Beacon Request" multicast group... */ + /* But only if it's not in there already! */ + if(do_roaming) + dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1); +#endif /* WAVELAN_ROAMING */ + + /* If any multicast address to set */ + if(lp->mc_count) + { + struct dev_mc_list * dmi; + int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", + dev->name, lp->mc_count); + for(dmi=dev->mc_list; dmi; dmi=dmi->next) + printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n", + dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], + dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] ); +#endif + + /* Initialize adapter's ethernet multicast addresses */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(addrs_len & 0xff, PIOP(base)); /* byte count lsb */ + outb((addrs_len >> 8), PIOP(base)); /* byte count msb */ + for(dmi=dev->mc_list; dmi; dmi=dmi->next) + outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", + OP0_MC_SETUP, SR0_MC_SETUP_DONE)) + ret = FALSE; + lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ + } + + /* Job done, clear the flag */ + lp->reconfig_82593 = FALSE; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name); +#endif + return(ret); +} + +/*------------------------------------------------------------------*/ +/* + * Read the Access Configuration Register, perform a software reset, + * and then re-enable the card's software. + * + * If I understand correctly : reset the pcmcia interface of the + * wavelan. + * (called by wv_config()) + */ +static inline int +wv_pcmcia_reset(device * dev) +{ + int i; + conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; + dev_link_t * link = ((net_local *) dev->priv)->link; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name); +#endif + + i = CardServices(AccessConfigurationRegister, link->handle, ®); + if(i != CS_SUCCESS) + { + cs_error(link->handle, AccessConfigurationRegister, i); + return FALSE; + } + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n", + dev->name, (u_int) reg.Value); +#endif + + reg.Action = CS_WRITE; + reg.Value = reg.Value | COR_SW_RESET; + i = CardServices(AccessConfigurationRegister, link->handle, ®); + if(i != CS_SUCCESS) + { + cs_error(link->handle, AccessConfigurationRegister, i); + return FALSE; + } + + reg.Action = CS_WRITE; + reg.Value = COR_LEVEL_IRQ | COR_CONFIG; + i = CardServices(AccessConfigurationRegister, link->handle, ®); + if(i != CS_SUCCESS) + { + cs_error(link->handle, AccessConfigurationRegister, i); + return FALSE; + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * wavelan_hw_config() is called after a CARD_INSERTION event is + * received, to configure the wavelan hardware. + * Note that the reception will be enabled in wavelan->open(), so the + * device is configured but idle... + * Performs the following actions: + * 1. A pcmcia software reset (using wv_pcmcia_reset()) + * 2. A power reset (reset DMA) + * 3. Reset the LAN controller + * 4. Initialize the radio modem (using wv_mmc_init) + * 5. Configure LAN controller (using wv_82593_config) + * 6. Perform a diagnostic on the LAN controller + * (called by wavelan_event() & wv_hw_reset()) + */ +static int +wv_hw_config(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + ioaddr_t base = dev->base_addr; + unsigned long flags; + int ret = FALSE; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name); +#endif + +#ifdef STRUCT_CHECK + if(wv_structuct_check() != (char *) NULL) + { + printk(KERN_WARNING "%s: wv_hw_config: structure/compiler botch: \"%s\"\n", + dev->name, wv_structuct_check()); + return FALSE; + } +#endif /* STRUCT_CHECK == 1 */ + + /* Reset the pcmcia interface */ + if(wv_pcmcia_reset(dev) == FALSE) + return FALSE; + + /* Disable interrupts */ + wv_splhi(lp, &flags); + + /* Disguised goto ;-) */ + do + { + /* Power UP the module + reset the modem + reset host adapter + * (in fact, reset DMA channels) */ + hacr_write_slow(base, HACR_RESET); + hacr_write(base, HACR_DEFAULT); + + /* Check if the module has been powered up... */ + if(hasr_read(base) & HASR_NO_CLK) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", + dev->name); +#endif + break; + } + + /* initialize the modem */ + if(wv_mmc_init(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n", + dev->name); +#endif + break; + } + + /* reset the LAN controller (i82593) */ + outb(OP0_RESET, LCCR(base)); + mdelay(1); /* A bit crude ! */ + + /* Initialize the LAN controller */ + if(wv_82593_config(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", + dev->name); +#endif + break; + } + + /* Diagnostic */ + if(wv_diag(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n", + dev->name); +#endif + break; + } + + /* + * insert code for loopback test here + */ + + /* The device is now configured */ + lp->configured = 1; + ret = TRUE; + } + while(0); + + /* Re-enable interrupts */ + wv_splx(lp, &flags); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); +#endif + return(ret); +} + +/*------------------------------------------------------------------*/ +/* + * Totally reset the wavelan and restart it. + * Performs the following actions: + * 1. Call wv_hw_config() + * 2. Start the LAN controller's receive unit + * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) + */ +static inline void +wv_hw_reset(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name); +#endif + + lp->nresets++; + lp->configured = 0; + + /* Call wv_hw_config() for most of the reset & init stuff */ + if(wv_hw_config(dev) == FALSE) + return; + + /* start receive unit */ + wv_ru_start(dev); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * wv_pcmcia_config() is called after a CARD_INSERTION event is + * received, to configure the PCMCIA socket, and to make the ethernet + * device available to the system. + * (called by wavelan_event()) + */ +static inline int +wv_pcmcia_config(dev_link_t * link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + struct net_device * dev; + int i; + u_char buf[64]; + win_req_t req; + memreq_t mem; + + handle = link->handle; + dev = (device *) link->priv; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); +#endif + + /* + * This reads the card's CONFIG tuple to find its configuration + * registers. + */ + do + { + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + i = CardServices(GetFirstTuple, handle, &tuple); + if(i != CS_SUCCESS) + break; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + i = CardServices(GetTupleData, handle, &tuple); + if(i != CS_SUCCESS) + break; + i = CardServices(ParseTuple, handle, &tuple, &parse); + if(i != CS_SUCCESS) + break; + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + } + while(0); + if(i != CS_SUCCESS) + { + cs_error(link->handle, ParseTuple, i); + link->state &= ~DEV_CONFIG_PENDING; + return FALSE; + } + + /* Configure card */ + link->state |= DEV_CONFIG; + do + { + i = CardServices(RequestIO, link->handle, &link->io); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestIO, i); + break; + } + + /* + * Now allocate an interrupt line. Note that this does not + * actually assign a handler to the interrupt. + */ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestIRQ, i); + break; + } + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping. + */ + link->conf.ConfigIndex = 1; + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestConfiguration, i); + break; + } + + /* + * Allocate a small memory window. Note that the dev_link_t + * structure provides space for one window handle -- if your + * device needs several windows, you'll need to keep track of + * the handles in your private data structure, link->priv. + */ + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + req.Base = req.Size = 0; + req.AccessSpeed = mem_speed; + link->win = (window_handle_t)link->handle; + i = CardServices(RequestWindow, &link->win, &req); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestWindow, i); + break; + } + + dev->rmem_start = dev->mem_start = + (u_long)ioremap(req.Base, req.Size); + dev->rmem_end = dev->mem_end = dev->mem_start + req.Size; + + mem.CardOffset = 0; mem.Page = 0; + i = CardServices(MapMemPage, link->win, &mem); + if(i != CS_SUCCESS) + { + cs_error(link->handle, MapMemPage, i); + break; + } + + /* Feed device with this info... */ + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + netif_start_queue(dev); + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n", + (u_int) dev->mem_start, dev->irq, (u_int) dev->base_addr); +#endif + + i = register_netdev(dev); + if(i != 0) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n"); +#endif + break; + } + } + while(0); /* Humm... Disguised goto !!! */ + + link->state &= ~DEV_CONFIG_PENDING; + /* If any step failed, release any partially configured state */ + if(i != 0) + { + wv_pcmcia_release((u_long) link); + return FALSE; + } + + strcpy(((net_local *) dev->priv)->node.dev_name, dev->name); + link->dev = &((net_local *) dev->priv)->node; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "<-wv_pcmcia_config()\n"); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * After a card is removed, wv_pcmcia_release() will unregister the net + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ +static void +wv_pcmcia_release(u_long arg) /* Address of the interface struct */ +{ + dev_link_t * link = (dev_link_t *) arg; + device * dev = (device *) link->priv; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); +#endif + + /* If the device is currently in use, we won't release until it is + * actually closed. */ + if(link->open) + { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wv_pcmcia_release: release postponed, device still open\n", + dev->name); +#endif + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Don't bother checking to see if these succeed or not */ + iounmap((u_char *)dev->mem_start); + CardServices(ReleaseWindow, link->win); + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); +#endif +} /* wv_pcmcia_release */ + +/*------------------------------------------------------------------*/ +/* + * Sometimes, wavelan_detach can't be performed following a call from + * cardmgr (device still open, pcmcia_release not done) and the device + * is put in a STALE_LINK state and remains in memory. + * + * This function run through our current list of device and attempt + * another time to remove them. We hope that since last time the + * device has properly been closed. + * + * (called by wavelan_attach() & cleanup_module()) + */ +static void +wv_flush_stale_links(void) +{ + dev_link_t * link; /* Current node in linked list */ + dev_link_t * next; /* Next node in linked list */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "-> wv_flush_stale_links(0x%p)\n", dev_list); +#endif + + /* Go through the list */ + for (link = dev_list; link; link = next) + { + next = link->next; + + /* Check if in need of being removed */ + if((link->state & DEV_STALE_LINK) || + (! (link->state & DEV_PRESENT))) + wavelan_detach(link); + + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "<- wv_flush_stale_links()\n"); +#endif +} + +/************************ INTERRUPT HANDLING ************************/ + +/* + * This function is the interrupt handler for the WaveLAN card. This + * routine will be called whenever: + * 1. A packet is received. + * 2. A packet has successfully been transferred and the unit is + * ready to transmit another packet. + * 3. A command has completed execution. + */ +static void +wavelan_interrupt(int irq, + void * dev_id, + struct pt_regs * regs) +{ + device * dev; + net_local * lp; + ioaddr_t base; + int status0; + u_int tx_status; + + if((dev = (device *)dev_id) == (device *) NULL) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n", + irq); +#endif + return; + } + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); +#endif + + lp = (net_local *) dev->priv; + base = dev->base_addr; + +#ifdef DEBUG_INTERRUPT_INFO + /* Check state of our spinlock (it should be cleared) */ + if(spin_is_locked(&lp->spinlock)) + printk(KERN_DEBUG + "%s: wavelan_interrupt(): spinlock is already locked !!!\n", + dev->name); +#endif + + /* Prevent reentrancy. We need to do that because we may have + * multiple interrupt handler running concurently. + * It is safe because wv_splhi() disable interrupts before aquiring + * the spinlock. */ + spin_lock(&lp->spinlock); + + /* Treat all pending interrupts */ + while(1) + { + /* ---------------- INTERRUPT CHECKING ---------------- */ + /* + * Look for the interrupt and verify the validity + */ + outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); + status0 = inb(LCSR(base)); + +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, + (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT); + if(status0&SR0_INTERRUPT) + { + printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" : + ((status0 & SR0_EXECUTION) ? "cmd" : + ((status0 & SR0_RECEPTION) ? "recv" : "unknown")), + (status0 & SR0_EVENT_MASK)); + } + else + printk("\n"); +#endif + + /* Return if no actual interrupt from i82593 (normal exit) */ + if(!(status0 & SR0_INTERRUPT)) + break; + + /* If interrupt is both Rx and Tx or none... + * This code in fact is there to catch the spurious interrupt + * when you remove the wavelan pcmcia card from the socket */ + if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) || + ((status0 & SR0_BOTH_RX_TX) == 0x0)) + { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n", + dev->name, status0); +#endif + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + break; + } + + /* ----------------- RECEIVING PACKET ----------------- */ + /* + * When the wavelan signal the reception of a new packet, + * we call wv_packet_rcv() to copy if from the buffer and + * send it to NET3 + */ + if(status0 & SR0_RECEPTION) + { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name); +#endif + + if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n", + dev->name); +#endif + lp->stats.rx_over_errors++; + lp->overrunning = 1; + } + + /* Get the packet */ + wv_packet_rcv(dev); + lp->overrunning = 0; + + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + continue; + } + + /* ---------------- COMMAND COMPLETION ---------------- */ + /* + * Interrupts issued when the i82593 has completed a command. + * Most likely : transmission done + */ + + /* If a transmission has been done */ + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) + { +#ifdef DEBUG_TX_ERROR + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) + printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n", + dev->name); +#endif + + /* Get transmission status */ + tx_status = inb(LCSR(base)); + tx_status |= (inb(LCSR(base)) << 8); +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n", + dev->name); + { + u_int rcv_bytes; + u_char status3; + rcv_bytes = inb(LCSR(base)); + rcv_bytes |= (inb(LCSR(base)) << 8); + status3 = inb(LCSR(base)); + printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n", + tx_status, rcv_bytes, (u_int) status3); + } +#endif + /* Check for possible errors */ + if((tx_status & TX_OK) != TX_OK) + { + lp->stats.tx_errors++; + + if(tx_status & TX_FRTL) + { +#ifdef DEBUG_TX_ERROR + printk(KERN_INFO "%s: wv_interrupt(): frame too long\n", + dev->name); +#endif + } + if(tx_status & TX_UND_RUN) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n", + dev->name); +#endif + lp->stats.tx_aborted_errors++; + } + if(tx_status & TX_LOST_CTS) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name); +#endif + lp->stats.tx_carrier_errors++; + } + if(tx_status & TX_LOST_CRS) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n", + dev->name); +#endif + lp->stats.tx_carrier_errors++; + } + if(tx_status & TX_HRT_BEAT) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name); +#endif + lp->stats.tx_heartbeat_errors++; + } + if(tx_status & TX_DEFER) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n", + dev->name); +#endif + } + /* Ignore late collisions since they're more likely to happen + * here (the WaveLAN design prevents the LAN controller from + * receiving while it is transmitting). We take action only when + * the maximum retransmit attempts is exceeded. + */ + if(tx_status & TX_COLL) + { + if(tx_status & TX_MAX_COL) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n", + dev->name); +#endif + if(!(tx_status & TX_NCOL_MASK)) + { + lp->stats.collisions += 0x10; + } + } + } + } /* if(!(tx_status & TX_OK)) */ + + lp->stats.collisions += (tx_status & TX_NCOL_MASK); + lp->stats.tx_packets++; + + netif_wake_queue(dev); + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ + } + else /* if interrupt = transmit done or retransmit done */ + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n", + status0); +#endif + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ + } + } /* while(1) */ + + spin_unlock(&lp->spinlock); + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); +#endif +} /* wv_interrupt */ + +/*------------------------------------------------------------------*/ +/* + * Watchdog: when we start a transmission, a timer is set for us in the + * kernel. If the transmission completes, this timer is disabled. If + * the timer expires, we are called and we try to unlock the hardware. + * + * Note : This watchdog is move clever than the one in the ISA driver, + * because it try to abort the current command before reseting + * everything... + * On the other hand, it's a bit simpler, because we don't have to + * deal with the multiple Tx buffers... + */ +static void +wavelan_watchdog(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + ioaddr_t base = dev->base_addr; + unsigned long flags; + int aborted = FALSE; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); +#endif + +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", + dev->name); +#endif + + wv_splhi(lp, &flags); + + /* Ask to abort the current command */ + outb(OP0_ABORT, LCCR(base)); + + /* Wait for the end of the command (a bit hackish) */ + if(wv_82593_cmd(dev, "wavelan_watchdog(): abort", + OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED)) + aborted = TRUE; + + /* Release spinlock here so that wv_hw_reset() can grab it */ + wv_splx(lp, &flags); + + /* Check if we were successful in aborting it */ + if(!aborted) + { + /* It seem that it wasn't enough */ +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n", + dev->name); +#endif + wv_hw_reset(dev); + } + +#ifdef DEBUG_PSA_SHOW + { + psa_t psa; + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + wv_psa_show(&psa); + } +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82593_SHOW + wv_ru_show(dev); +#endif + + /* We are no more waiting for something... */ + netif_wake_queue(dev); + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); +#endif +} + +/********************* CONFIGURATION CALLBACKS *********************/ +/* + * Here are the functions called by the pcmcia package (cardmgr) and + * linux networking (NET3) for initialization, configuration and + * deinstallations of the Wavelan Pcmcia Hardware. + */ + +/*------------------------------------------------------------------*/ +/* + * Configure and start up the WaveLAN PCMCIA adaptor. + * Called by NET3 when it "open" the device. + */ +static int +wavelan_open(device * dev) +{ + dev_link_t * link = ((net_local *) dev->priv)->link; + net_local * lp = (net_local *)dev->priv; + ioaddr_t base = dev->base_addr; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* Check if the modem is powered up (wavelan_close() power it down */ + if(hasr_read(base) & HASR_NO_CLK) + { + /* Power up (power up time is 250us) */ + hacr_write(base, HACR_DEFAULT); + + /* Check if the module has been powered up... */ + if(hasr_read(base) & HASR_NO_CLK) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n", + dev->name); +#endif + return FALSE; + } + } + + /* Start reception and declare the driver ready */ + if(!lp->configured) + return FALSE; + if(!wv_ru_start(dev)) + wv_hw_reset(dev); /* If problem : reset */ + netif_start_queue(dev); + + /* Mark the device as used */ + link->open++; + MOD_INC_USE_COUNT; + +#ifdef WAVELAN_ROAMING + if(do_roaming) + wv_roam_init(dev); +#endif /* WAVELAN_ROAMING */ + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Shutdown the WaveLAN PCMCIA adaptor. + * Called by NET3 when it "close" the device. + */ +static int +wavelan_close(device * dev) +{ + dev_link_t * link = ((net_local *) dev->priv)->link; + ioaddr_t base = dev->base_addr; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* If the device isn't open, then nothing to do */ + if(!link->open) + { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name); +#endif + return 0; + } + +#ifdef WAVELAN_ROAMING + /* Cleanup of roaming stuff... */ + if(do_roaming) + wv_roam_cleanup(dev); +#endif /* WAVELAN_ROAMING */ + + link->open--; + MOD_DEC_USE_COUNT; + + /* If the card is still present */ + if(netif_running(dev)) + { + netif_stop_queue(dev); + + /* Stop receiving new messages and wait end of transmission */ + wv_ru_stop(dev); + + /* Power down the module */ + hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT)); + } + else + /* The card is no more there (flag is activated in wv_pcmcia_release) */ + if(link->state & DEV_STALE_CONFIG) + wv_pcmcia_release((u_long)link); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * wavelan_attach() creates an "instance" of the driver, allocating + * local data structures for one device (one interface). The device + * is registered with Card Services. + * + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a + * card insertion event. + */ +static dev_link_t * +wavelan_attach(void) +{ + client_reg_t client_reg; /* Register with cardmgr */ + dev_link_t * link; /* Info for cardmgr */ + device * dev; /* Interface generic data */ + net_local * lp; /* Interface specific data */ + int i, ret; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "-> wavelan_attach()\n"); +#endif + + /* Perform some cleanup */ + wv_flush_stale_links(); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) return NULL; + memset(link, 0, sizeof(struct dev_link_t)); + + /* Unused for the Wavelan */ + link->release.function = &wv_pcmcia_release; + link->release.data = (u_long) link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 8; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = 3; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = wavelan_interrupt; + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Chain drivers */ + link->next = dev_list; + dev_list = link; + + /* Allocate the generic data structure */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (!dev) { + kfree(link); + return NULL; + } + memset(dev, 0x00, sizeof(struct net_device)); + link->priv = link->irq.Instance = dev; + + /* Allocate the wavelan-specific data structure. */ + dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); + if (!lp) { + kfree(link); + kfree(dev); + return NULL; + } + memset(lp, 0x00, sizeof(net_local)); + + /* Init specific data */ + lp->configured = 0; + lp->reconfig_82593 = FALSE; + lp->nresets = 0; + /* Multicast stuff */ + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = 0; + + /* Init spinlock */ + spin_lock_init(&lp->spinlock); + + /* back links */ + lp->link = link; + lp->dev = dev; + + /* Standard setup for generic data */ + ether_setup(dev); + + /* wavelan NET3 callbacks */ + dev->open = &wavelan_open; + dev->stop = &wavelan_close; + dev->hard_start_xmit = &wavelan_packet_xmit; + dev->get_stats = &wavelan_get_stats; + dev->set_multicast_list = &wavelan_set_multicast_list; +#ifdef SET_MAC_ADDRESS + dev->set_mac_address = &wavelan_set_mac_address; +#endif /* SET_MAC_ADDRESS */ + + /* Set the watchdog timer */ + dev->tx_timeout = &wavelan_watchdog; + dev->watchdog_timeo = WATCHDOG_JIFFIES; + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + dev->do_ioctl = wavelan_ioctl; /* wireless extensions */ + dev->get_wireless_stats = wavelan_get_wireless_stats; +#endif + + /* Other specific data */ + dev->mtu = WAVELAN_MTU; + + /* Register with Card Services */ + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_REGISTRATION_COMPLETE | + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &wavelan_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wavelan_attach(): almost done, calling CardServices\n"); +#endif + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if(ret != 0) + { + cs_error(link->handle, RegisterClient, ret); + wavelan_detach(link); + return NULL; + } + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<- wavelan_attach()\n"); +#endif + + return link; +} + +/*------------------------------------------------------------------*/ +/* + * This deletes a driver "instance". The device is de-registered with + * Card Services. If it has been released, all local data structures + * are freed. Otherwise, the structures will be freed when the device + * is released. + */ +static void +wavelan_detach(dev_link_t * link) +{ +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); +#endif + + /* + * If the device is currently configured and active, we won't + * actually delete it yet. Instead, it is marked so that when the + * release() function is called, that will trigger a proper + * detach(). + */ + if(link->state & DEV_CONFIG) + { + /* Some others haven't done their job : give them another chance */ + wv_pcmcia_release((u_long) link); + if(link->state & DEV_STALE_CONFIG) + { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wavelan_detach: detach postponed," + " '%s' still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + return; + } + } + + /* Break the link with Card Services */ + if(link->handle) + CardServices(DeregisterClient, link->handle); + + /* Remove the interface data from the linked list */ + if(dev_list == link) + dev_list = link->next; + else + { + dev_link_t * prev = dev_list; + + while((prev != (dev_link_t *) NULL) && (prev->next != link)) + prev = prev->next; + + if(prev == (dev_link_t *) NULL) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "wavelan_detach : Attempting to remove a nonexistent device.\n"); +#endif + return; + } + + prev->next = link->next; + } + + /* Free pieces */ + if(link->priv) + { + device * dev = (device *) link->priv; + + /* Remove ourselves from the kernel list of ethernet devices */ + /* Warning : can't be called from interrupt, timer or wavelan_close() */ + if(link->dev != NULL) + unregister_netdev(dev); + link->dev = NULL; + + if(dev->priv) + { + /* Sound strange, but safe... */ + ((net_local *) dev->priv)->link = (dev_link_t *) NULL; + ((net_local *) dev->priv)->dev = (device *) NULL; + kfree(dev->priv); + } + kfree(link->priv); + } + kfree(link); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<- wavelan_detach()\n"); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * The card status event handler. Mostly, this schedules other stuff + * to run after an event is received. A CARD_REMOVAL event also sets + * some flags to discourage the net drivers from trying to talk to the + * card any more. + */ +static int +wavelan_event(event_t event, /* The event received */ + int priority, + event_callback_args_t * args) +{ + dev_link_t * link = (dev_link_t *) args->client_data; + device * dev = (device *) link->priv; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "->wavelan_event(): %s\n", + ((event == CS_EVENT_REGISTRATION_COMPLETE)?"registration complete" : + ((event == CS_EVENT_CARD_REMOVAL) ? "card removal" : + ((event == CS_EVENT_CARD_INSERTION) ? "card insertion" : + ((event == CS_EVENT_PM_SUSPEND) ? "pm suspend" : + ((event == CS_EVENT_RESET_PHYSICAL) ? "physical reset" : + ((event == CS_EVENT_PM_RESUME) ? "pm resume" : + ((event == CS_EVENT_CARD_RESET) ? "card reset" : + "unknown")))))))); +#endif + + switch(event) + { + case CS_EVENT_REGISTRATION_COMPLETE: +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wavelan_cs: registration complete\n"); +#endif + break; + + case CS_EVENT_CARD_REMOVAL: + /* Oups ! The card is no more there */ + link->state &= ~DEV_PRESENT; + if(link->state & DEV_CONFIG) + { + /* Accept no more transmissions */ + netif_device_detach(dev); + + /* Release the card */ + wv_pcmcia_release((u_long) link); + } + break; + + case CS_EVENT_CARD_INSERTION: + /* Reset and configure the card */ + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + if(wv_pcmcia_config(link) && + wv_hw_config(dev)) + wv_init_info(dev); + else + dev->irq = 0; + break; + + case CS_EVENT_PM_SUSPEND: + /* NB: wavelan_close will be called, but too late, so we are + * obliged to close nicely the wavelan here. David, could you + * close the device before suspending them ? And, by the way, + * could you, on resume, add a "route add -net ..." after the + * ifconfig up ??? Thanks... */ + + /* Stop receiving new messages and wait end of transmission */ + wv_ru_stop(dev); + + /* Power down the module */ + hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT)); + + /* The card is now suspended */ + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if(link->state & DEV_CONFIG) + { + if(link->open) + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); + } + break; + + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if(link->state & DEV_CONFIG) + { + CardServices(RequestConfiguration, link->handle, &link->conf); + if(link->open) /* If RESET -> True, If RESUME -> False ??? */ + { + wv_hw_reset(dev); + netif_device_attach(dev); + } + } + break; + } + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<-wavelan_event()\n"); +#endif + return 0; +} + +/****************************** MODULE ******************************/ +/* + * Module entry points : insertion & removal + */ + +/*------------------------------------------------------------------*/ +/* + * Module insertion : initialisation of the module. + * Register the card with cardmgr... + */ +static int __init +init_wavelan_cs(void) +{ + servinfo_t serv; + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "-> init_wavelan_cs()\n"); +#ifdef DEBUG_VERSION_SHOW + printk(KERN_DEBUG "%s", version); +#endif +#endif + + CardServices(GetCardServicesInfo, &serv); + if(serv.Revision != CS_RELEASE_CODE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "init_wavelan_cs: Card Services release does not match!\n"); +#endif + return -1; + } + + register_pccard_driver(&dev_info, &wavelan_attach, &wavelan_detach); + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "<- init_wavelan_cs()\n"); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Module removal + */ +static void __exit +exit_wavelan_cs(void) +{ +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "-> cleanup_module()\n"); +#endif +#ifdef DEBUG_BASIC_SHOW + printk(KERN_NOTICE "wavelan_cs: unloading\n"); +#endif + + /* Do some cleanup of the device list */ + wv_flush_stale_links(); + + /* If there remain some devices... */ +#ifdef DEBUG_CONFIG_ERRORS + if(dev_list != NULL) + { + /* Honestly, if this happen we are in a deep s**t */ + printk(KERN_INFO "wavelan_cs: devices remaining when removing module\n"); + printk(KERN_INFO "Please flush your disks and reboot NOW !\n"); + } +#endif + + unregister_pccard_driver(&dev_info); + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "<- cleanup_module()\n"); +#endif +} + +module_init(init_wavelan_cs); +module_exit(exit_wavelan_cs); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/pcmcia/wavelan_cs.h linux-2.5/drivers/net/pcmcia/wavelan_cs.h --- linux-2.5.20/drivers/net/pcmcia/wavelan_cs.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/pcmcia/wavelan_cs.h Tue Jan 22 17:44:56 2002 @@ -0,0 +1,825 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * + * This file contain all definition and declarations necessary for the + * wavelan pcmcia driver. This file is a private header, so it should + * be included only on wavelan_cs.c !!! + */ + +#ifndef WAVELAN_CS_H +#define WAVELAN_CS_H + +/************************** DOCUMENTATION **************************/ +/* + * This driver provide a Linux interface to the Wavelan Pcmcia hardware + * The Wavelan is a product of Lucent (http://www.wavelan.com/). + * This division was formerly part of NCR and then AT&T. + * Wavelan are also distributed by DEC (RoamAbout DS)... + * + * To know how to use this driver, read the PCMCIA HOWTO. + * If you want to exploit the many other fonctionalities, look comments + * in the code... + * + * This driver is the result of the effort of many peoples (see below). + */ + +/* ------------------------ SPECIFIC NOTES ------------------------ */ +/* + * Web page + * -------- + * I try to maintain a web page with the Wireless LAN Howto at : + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + * + * SMP + * --- + * We now are SMP compliant (I eventually fixed the remaining bugs). + * The driver has been tested on a dual P6-150 and survived my usual + * set of torture tests. + * Anyway, I spent enough time chasing interrupt re-entrancy during + * errors or reconfigure, and I designed the locked/unlocked sections + * of the driver with great care, and with the recent addition of + * the spinlock (thanks to the new API), we should be quite close to + * the truth. + * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), + * but better safe than sorry (especially at 2 Mb/s ;-). + * + * I have also looked into disabling only our interrupt on the card + * (via HACR) instead of all interrupts in the processor (via cli), + * so that other driver are not impacted, and it look like it's + * possible, but it's very tricky to do right (full of races). As + * the gain would be mostly for SMP systems, it can wait... + * + * Debugging and options + * --------------------- + * You will find below a set of '#define" allowing a very fine control + * on the driver behaviour and the debug messages printed. + * The main options are : + * o WAVELAN_ROAMING, for the experimental roaming support. + * o SET_PSA_CRC, to have your card correctly recognised by + * an access point and the Point-to-Point diagnostic tool. + * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) + * (otherwise we always start afresh with some defaults) + * + * wavelan_cs.o is darn too big + * ------------------------- + * That's true ! There is a very simple way to reduce the driver + * object by 33% (yes !). Comment out the following line : + * #include + * Other compile options can also reduce the size of it... + * + * MAC address and hardware detection : + * ---------------------------------- + * The detection code of the wavelan chech that the first 3 + * octets of the MAC address fit the company code. This type of + * detection work well for AT&T cards (because the AT&T code is + * hardcoded in wavelan.h), but of course will fail for other + * manufacturer. + * + * If you are sure that your card is derived from the wavelan, + * here is the way to configure it : + * 1) Get your MAC address + * a) With your card utilities (wfreqsel, instconf, ...) + * b) With the driver : + * o compile the kernel with DEBUG_CONFIG_INFO enabled + * o Boot and look the card messages + * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h) + * 3) Compile & verify + * 4) Send me the MAC code - I will include it in the next version... + * + */ + +/* --------------------- WIRELESS EXTENSIONS --------------------- */ +/* + * This driver is the first one to support "wireless extensions". + * This set of extensions provide you some way to control the wireless + * caracteristics of the hardware in a standard way and support for + * applications for taking advantage of it (like Mobile IP). + * + * You will need to enable the CONFIG_NET_RADIO define in the kernel + * configuration to enable the wireless extensions (this is the one + * giving access to the radio network device choice). + * + * It might also be a good idea as well to fetch the wireless tools to + * configure the device and play a bit. + */ + +/* ---------------------------- FILES ---------------------------- */ +/* + * wavelan_cs.c : The actual code for the driver - C functions + * + * wavelan_cs.h : Private header : local types / vars for the driver + * + * wavelan.h : Description of the hardware interface & structs + * + * i82593.h : Description if the Ethernet controller + */ + +/* --------------------------- HISTORY --------------------------- */ +/* + * The history of the Wavelan drivers is as complicated as history of + * the Wavelan itself (NCR -> AT&T -> Lucent). + * + * All started with Anders Klemets , + * writting a Wavelan ISA driver for the MACH microkernel. Girish + * Welling had also worked on it. + * Keith Moore modify this for the Pcmcia hardware. + * + * Robert Morris port these two drivers to BSDI + * and add specific Pcmcia support (there is currently no equivalent + * of the PCMCIA package under BSD...). + * + * Jim Binkley port both BSDI drivers to FreeBSD. + * + * Bruce Janson port the BSDI ISA driver to Linux. + * + * Anthony D. Joseph started modify Bruce driver + * (with help of the BSDI PCMCIA driver) for PCMCIA. + * Yunzhou Li finished is work. + * Joe Finney patched the driver to start + * correctly 2.00 cards (2.4 GHz with frequency selection). + * David Hinds integrated the whole in his + * Pcmcia package (+ bug corrections). + * + * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some + * patchs to the Pcmcia driver. After, I added code in the ISA driver + * for Wireless Extensions and full support of frequency selection + * cards. Now, I'm doing the same to the Pcmcia driver + some + * reorganisation. + * Loeke Brederveld from Lucent has given me + * much needed informations on the Wavelan hardware. + */ + +/* By the way : for the copyright & legal stuff : + * Almost everybody wrote code under GNU or BSD license (or alike), + * and want that their original copyright remain somewhere in the + * code (for myself, I go with the GPL). + * Nobody want to take responsibility for anything, except the fame... + */ + +/* --------------------------- CREDITS --------------------------- */ +/* + * Credits: + * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and + * Loeke Brederveld of Lucent for providing extremely useful + * information about WaveLAN PCMCIA hardware + * + * This driver is based upon several other drivers, in particular: + * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter + * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter + * Anders Klemets' PCMCIA WaveLAN adapter driver + * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter + * + * Additional Credits: + * + * This software was originally developed under Linux 1.2.3 + * (Slackware 2.0 distribution). + * And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+) + * with an HP OmniBook 4000 and then a 5500. + * + * It is based on other device drivers and information either written + * or supplied by: + * James Ashton (jaa101@syseng.anu.edu.au), + * Ajay Bakre (bakre@paul.rutgers.edu), + * Donald Becker (becker@super.org), + * Jim Binkley , + * Loeke Brederveld , + * Allan Creighton (allanc@cs.su.oz.au), + * Brent Elphick , + * Joe Finney , + * Matthew Geier (matthew@cs.su.oz.au), + * Remo di Giovanni (remo@cs.su.oz.au), + * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), + * David Hinds , + * Jan Hoogendoorn (c/o marteijn@lucent.com), + * Bruce Janson , + * Anthony D. Joseph , + * Anders Klemets (klemets@paul.rutgers.edu), + * Yunzhou Li , + * Marc Meertens (mmeertens@lucent.com), + * Keith Moore, + * Robert Morris (rtm@das.harvard.edu), + * Ian Parkin (ian@cs.su.oz.au), + * John Rosenberg (johnr@cs.su.oz.au), + * George Rossi (george@phm.gov.au), + * Arthur Scott (arthur@cs.su.oz.au), + * Stanislav Sinyagin + * Peter Storey, + * Jean Tourrilhes , + * Girish Welling (welling@paul.rutgers.edu) + * Clark Woodworth + * Yongguang Zhang ... + */ + +/* ------------------------- IMPROVEMENTS ------------------------- */ +/* + * I proudly present : + * + * Changes made in 2.8.22 : + * ---------------------- + * - improved wv_set_multicast_list + * - catch spurious interrupt + * - correct release of the device + * + * Changes mades in release : + * ------------------------ + * - Reorganisation of the code, function name change + * - Creation of private header (wavelan_cs.h) + * - Reorganised debug messages + * - More comments, history, ... + * - Configure earlier (in "insert" instead of "open") + * and do things only once + * - mmc_init : configure the PSA if not done + * - mmc_init : 2.00 detection better code for 2.00 init + * - better info at startup + * - Correct a HUGE bug (volatile & uncalibrated busy loop) + * in wv_82593_cmd => config speedup + * - Stop receiving & power down on close (and power up on open) + * use "ifconfig down" & "ifconfig up ; route add -net ..." + * - Send packets : add watchdog instead of pooling + * - Receive : check frame wrap around & try to recover some frames + * - wavelan_set_multicast_list : avoid reset + * - add wireless extensions (ioctl & get_wireless_stats) + * get/set nwid/frequency on fly, info for /proc/net/wireless + * - Suppress useless stuff from lp (net_local), but add link + * - More inlines + * - Lot of others minor details & cleanups + * + * Changes made in second release : + * ------------------------------ + * - Optimise wv_85893_reconfig stuff, fix potential problems + * - Change error values for ioctl + * - Non blocking wv_ru_stop() + call wv_reset() in case of problems + * - Remove development printk from wavelan_watchdog() + * - Remove of the watchdog to wavelan_close instead of wavelan_release + * fix potential problems... + * - Start debugging suspend stuff (but it's still a bit weird) + * - Debug & optimize dump header/packet in Rx & Tx (debug) + * - Use "readb" and "writeb" to be kernel 2.1 compliant + * - Better handling of bogus interrupts + * - Wireless extension : SETSPY and GETSPY + * - Remove old stuff (stats - for those needing it, just ask me...) + * - Make wireless extensions optional + * + * Changes made in third release : + * ----------------------------- + * - cleanups & typos + * - modif wireless ext (spy -> only one pointer) + * - new private ioctl to set/get quality & level threshold + * - Init : correct default value of level threshold for pcmcia + * - kill watchdog in hw_reset + * - more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) + * - Add message level (debug stuff in /var/adm/debug & errors not + * displayed at console and still in /var/adm/messages) + * + * Changes made in fourth release : + * ------------------------------ + * - multicast support (yes !) thanks to Yongguang Zhang. + * + * Changes made in fifth release (2.9.0) : + * ------------------------------------- + * - Revisited multicast code (it was mostly wrong). + * - protect code in wv_82593_reconfig with dev->tbusy (oups !) + * + * Changes made in sixth release (2.9.1a) : + * -------------------------------------- + * - Change the detection code for multi manufacturer code support + * - Correct bug (hang kernel) in init when we were "rejecting" a card + * + * Changes made in seventh release (2.9.1b) : + * ---------------------------------------- + * - Update to wireless extensions changes + * - Silly bug in card initial configuration (psa_conf_status) + * + * Changes made in eigth release : + * ----------------------------- + * - Small bug in debug code (probably not the last one...) + * - 1.2.13 support (thanks to Clark Woodworth) + * + * Changes made for release in 2.9.2b : + * ---------------------------------- + * - Level threshold is now a standard wireless extension (version 4 !) + * - modules parameters types for kernel > 2.1.17 + * - updated man page + * - Others cleanup from David Hinds + * + * Changes made for release in 2.9.5 : + * --------------------------------- + * - byte count stats (courtesy of David Hinds) + * - Remove dev_tint stuff (courtesy of David Hinds) + * - Others cleanup from David Hinds + * - Encryption setting from Brent Elphick (thanks a lot !) + * - 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) + * + * Changes made for release in 2.9.6 : + * --------------------------------- + * - fix bug : no longuer disable watchdog in case of bogus interrupt + * - increase timeout in config code for picky hardware + * - mask unused bits in status (Wireless Extensions) + * + * Changes integrated by Justin Seger & David Hinds : + * ----------------------------------------------------------------- + * - Roaming "hack" from Joe Finney + * - PSA CRC code from Bob Gray + * - Better initialisation of the i82593 controller + * from Joseph K. O'Sullivan + * + * Changes made for release in 3.0.10 : + * ---------------------------------- + * - Fix eject "hang" of the driver under 2.2.X : + * o create wv_flush_stale_links() + * o Rename wavelan_release to wv_pcmcia_release & move up + * o move unregister_netdev to wavelan_detach() + * o wavelan_release() no longer call wavelan_detach() + * o Suppress "release" timer + * o Other cleanups & fixes + * - New MAC address in the probe + * - Reorg PSA_CRC code (endian neutral & cleaner) + * - Correct initialisation of the i82593 from Lucent manual + * - Put back the watchdog, with larger timeout + * - TRANSMIT_NO_CRC is a "normal" error, so recover from it + * from Derrick J Brashear + * - Better handling of TX and RX normal failure conditions + * - #ifdef out all the roaming code + * - Add ESSID & "AP current address" ioctl stubs + * - General cleanup of the code + * + * Changes made for release in 3.0.13 : + * ---------------------------------- + * - Re-enable compilation of roaming code by default, but with + * do_roaming = 0 + * - Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather + * at the demand of John Carol Langford + * - Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff. + * + * Changes made for release in 3.0.15 : + * ---------------------------------- + * - Change e-mail and web page addresses + * - Watchdog timer is now correctly expressed in HZ, not in jiffies + * - Add channel number to the list of frequencies in range + * - Add the (short) list of bit-rates in range + * - Developp a new sensitivity... (sens.value & sens.fixed) + * + * Changes made for release in 3.1.2 : + * --------------------------------- + * - Fix check for root permission (break instead of exit) + * - New nwid & encoding setting (Wireless Extension 9) + * + * Changes made for release in 3.1.12 : + * ---------------------------------- + * - reworked wv_82593_cmd to avoid using the IRQ handler and doing + * ugly things with interrupts. + * - Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog + * - Update to new network API (softnet - 2.3.43) : + * o replace dev->tbusy (David + me) + * o replace dev->tstart (David + me) + * o remove dev->interrupt (David) + * o add SMP locking via spinlock in splxx (me) + * o add spinlock in interrupt handler (me) + * o use kernel watchdog instead of ours (me) + * o verify that all the changes make sense and work (me) + * - Re-sync kernel/pcmcia versions (not much actually) + * - A few other cleanups (David & me)... + * + * Changes made for release in 3.1.22 : + * ---------------------------------- + * - Check that SMP works, remove annoying log message + * + * Changes made for release in 3.1.24 : + * ---------------------------------- + * - Fix unfrequent card lockup when watchdog was reseting the hardware : + * o control first busy loop in wv_82593_cmd() + * o Extend spinlock protection in wv_hw_config() + * + * Wishes & dreams: + * ---------------- + * - Cleanup and integrate the roaming code + * (std debug, set DomainID, decay avg and co...) + */ + +/***************************** INCLUDES *****************************/ + +/* Linux headers that we need */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_NET_PCMCIA_RADIO +#include /* Wireless extensions */ +#endif + +/* Pcmcia headers that we need */ +#include +#include +#include +#include +#include +#include + +/* Wavelan declarations */ +#include "i82593.h" /* Definitions for the Intel chip */ + +#include "wavelan.h" /* Others bits of the hardware */ + +/************************** DRIVER OPTIONS **************************/ +/* + * `#define' or `#undef' the following constant to change the behaviour + * of the driver... + */ +#define WAVELAN_ROAMING /* Include experimental roaming code */ +#undef WAVELAN_ROAMING_EXT /* Enable roaming wireless extensions */ +#undef SET_PSA_CRC /* Set the CRC in PSA (slower) */ +#define USE_PSA_CONFIG /* Use info from the PSA */ +#undef STRUCT_CHECK /* Verify padding of structures */ +#undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */ +#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ +#undef SET_MAC_ADDRESS /* Experimental */ + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ +/* Warning : these stuff will slow down the driver... */ +#define WIRELESS_SPY /* Enable spying addresses */ +#undef HISTOGRAM /* Enable histogram of sig level... */ +#endif + +/****************************** DEBUG ******************************/ + +#undef DEBUG_MODULE_TRACE /* Module insertion/removal */ +#undef DEBUG_CALLBACK_TRACE /* Calls made by Linux */ +#undef DEBUG_INTERRUPT_TRACE /* Calls to handler */ +#undef DEBUG_INTERRUPT_INFO /* type of interrupt & so on */ +#define DEBUG_INTERRUPT_ERROR /* problems */ +#undef DEBUG_CONFIG_TRACE /* Trace the config functions */ +#undef DEBUG_CONFIG_INFO /* What's going on... */ +#define DEBUG_CONFIG_ERRORS /* Errors on configuration */ +#undef DEBUG_TX_TRACE /* Transmission calls */ +#undef DEBUG_TX_INFO /* Header of the transmitted packet */ +#undef DEBUG_TX_FAIL /* Normal failure conditions */ +#define DEBUG_TX_ERROR /* Unexpected conditions */ +#undef DEBUG_RX_TRACE /* Transmission calls */ +#undef DEBUG_RX_INFO /* Header of the transmitted packet */ +#undef DEBUG_RX_FAIL /* Normal failure conditions */ +#define DEBUG_RX_ERROR /* Unexpected conditions */ +#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen */ +#undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ +#undef DEBUG_IOCTL_INFO /* Various debug info */ +#define DEBUG_IOCTL_ERROR /* What's going wrong */ +#define DEBUG_BASIC_SHOW /* Show basic startup info */ +#undef DEBUG_VERSION_SHOW /* Print version info */ +#undef DEBUG_PSA_SHOW /* Dump psa to screen */ +#undef DEBUG_MMC_SHOW /* Dump mmc to screen */ +#undef DEBUG_SHOW_UNUSED /* Show also unused fields */ +#undef DEBUG_I82593_SHOW /* Show i82593 status */ +#undef DEBUG_DEVICE_SHOW /* Show device parameters */ + +/************************ CONSTANTS & MACROS ************************/ + +#ifdef DEBUG_VERSION_SHOW +static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n"; +#endif + +/* Watchdog temporisation */ +#define WATCHDOG_JIFFIES (256*HZ/100) + +/* Fix a bug in some old wireless extension definitions */ +#ifndef IW_ESSID_MAX_SIZE +#define IW_ESSID_MAX_SIZE 32 +#endif + +/* ------------------------ PRIVATE IOCTL ------------------------ */ + +/* Wireless Extension Backward compatibility - Jean II + * If the new wireless device private ioctl range is not defined, + * default to standard device private ioctl range */ +#ifndef SIOCIWFIRSTPRIV +#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE +#endif /* SIOCIWFIRSTPRIV */ + +#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ +#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ +#define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ +#define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */ + +#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ + +/*************************** WaveLAN Roaming **************************/ +#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ + +#define WAVELAN_ROAMING_DEBUG 0 /* 1 = Trace of handover decisions */ + /* 2 = Info on each beacon rcvd... */ +#define MAX_WAVEPOINTS 7 /* Max visible at one time */ +#define WAVEPOINT_HISTORY 5 /* SNR sample history slow search */ +#define WAVEPOINT_FAST_HISTORY 2 /* SNR sample history fast search */ +#define SEARCH_THRESH_LOW 10 /* SNR to enter cell search */ +#define SEARCH_THRESH_HIGH 13 /* SNR to leave cell search */ +#define WAVELAN_ROAMING_DELTA 1 /* Hysteresis value (+/- SNR) */ +#define CELL_TIMEOUT 2*HZ /* in jiffies */ + +#define FAST_CELL_SEARCH 1 /* Boolean values... */ +#define NWID_PROMISC 1 /* for code clarity. */ + +typedef struct wavepoint_beacon +{ + unsigned char dsap, /* Unused */ + ssap, /* Unused */ + ctrl, /* Unused */ + O,U,I, /* Unused */ + spec_id1, /* Unused */ + spec_id2, /* Unused */ + pdu_type, /* Unused */ + seq; /* WavePoint beacon sequence number */ + unsigned short domain_id, /* WavePoint Domain ID */ + nwid; /* WavePoint NWID */ +} wavepoint_beacon; + +typedef struct wavepoint_history +{ + unsigned short nwid; /* WavePoint's NWID */ + int average_slow; /* SNR running average */ + int average_fast; /* SNR running average */ + unsigned char sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */ + unsigned char qualptr; /* Index into ringbuffer */ + unsigned char last_seq; /* Last seq. no seen for WavePoint */ + struct wavepoint_history *next; /* Next WavePoint in table */ + struct wavepoint_history *prev; /* Previous WavePoint in table */ + unsigned long last_seen; /* Time of last beacon recvd, jiffies */ +} wavepoint_history; + +struct wavepoint_table +{ + wavepoint_history *head; /* Start of ringbuffer */ + int num_wavepoints; /* No. of WavePoints visible */ + unsigned char locked; /* Table lock */ +}; + +#endif /* WAVELAN_ROAMING */ + +/****************************** TYPES ******************************/ + +/* Shortcuts */ +typedef struct net_device device; +typedef struct net_device_stats en_stats; +typedef struct iw_statistics iw_stats; +typedef struct iw_quality iw_qual; +typedef struct iw_freq iw_freq; +typedef struct net_local net_local; +typedef struct timer_list timer_list; + +/* Basic types */ +typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ + +/* + * Static specific data for the interface. + * + * For each network interface, Linux keep data in two structure. "device" + * keep the generic data (same format for everybody) and "net_local" keep + * the additional specific data. + * Note that some of this specific data is in fact generic (en_stats, for + * example). + */ +struct net_local +{ + dev_node_t node; /* ???? What is this stuff ???? */ + device * dev; /* Reverse link... */ + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ + dev_link_t * link; /* pcmcia structure */ + en_stats stats; /* Ethernet interface statistics */ + int nresets; /* Number of hw resets */ + u_char configured; /* If it is configured */ + u_char reconfig_82593; /* Need to reconfigure the controller */ + u_char promiscuous; /* Promiscuous mode */ + u_char allmulticast; /* All Multicast mode */ + int mc_count; /* Number of multicast addresses */ + + int stop; /* Current i82593 Stop Hit Register */ + int rfp; /* Last DMA machine receive pointer */ + int overrunning; /* Receiver overrun flag */ + +#ifdef WIRELESS_EXT + iw_stats wstats; /* Wireless specific stats */ +#endif + +#ifdef WIRELESS_SPY + int spy_number; /* Number of addresses to spy */ + mac_addr spy_address[IW_MAX_SPY]; /* The addresses to spy */ + iw_qual spy_stat[IW_MAX_SPY]; /* Statistics gathered */ +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + int his_number; /* Number of intervals */ + u_char his_range[16]; /* Boundaries of interval ]n-1; n] */ + u_long his_sum[16]; /* Sum in interval */ +#endif /* HISTOGRAM */ +#ifdef WAVELAN_ROAMING + u_long domain_id; /* Domain ID we lock on for roaming */ + int filter_domains; /* Check Domain ID of beacon found */ + struct wavepoint_table wavepoint_table; /* Table of visible WavePoints*/ + wavepoint_history * curr_point; /* Current wavepoint */ + int cell_search; /* Searching for new cell? */ + struct timer_list cell_timer; /* Garbage collection */ +#endif /* WAVELAN_ROAMING */ +}; + +/**************************** PROTOTYPES ****************************/ + +#ifdef WAVELAN_ROAMING +/* ---------------------- ROAMING SUBROUTINES -----------------------*/ + +wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp); +wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp); +void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp); +void wl_cell_expiry(unsigned long data); +wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp); +void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq); +void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp); +void wv_nwid_filter(unsigned char mode, net_local *lp); +void wv_roam_init(struct net_device *dev); +void wv_roam_cleanup(struct net_device *dev); +#endif /* WAVELAN_ROAMING */ + +/* ----------------------- MISC SUBROUTINES ------------------------ */ +static inline void + wv_splhi(net_local *, /* Disable interrupts */ + unsigned long *); /* flags */ +static inline void + wv_splx(net_local *, /* ReEnable interrupts */ + unsigned long *); /* flags */ +static void + cs_error(client_handle_t, /* Report error to cardmgr */ + int, + int); +/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ +static inline u_char /* data */ + hasr_read(u_long); /* Read the host interface : base address */ +static inline void + hacr_write(u_long, /* Write to host interface : base address */ + u_char), /* data */ + hacr_write_slow(u_long, + u_char); +static void + psa_read(device *, /* Read the Parameter Storage Area */ + int, /* offset in PSA */ + u_char *, /* buffer to fill */ + int), /* size to read */ + psa_write(device *, /* Write to the PSA */ + int, /* Offset in psa */ + u_char *, /* Buffer in memory */ + int); /* Length of buffer */ +static inline void + mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */ + u_short, + u_char), + mmc_write(u_long, /* Write n bytes to the MMC */ + u_char, + u_char *, + int); +static inline u_char /* Read 1 byte from the MMC */ + mmc_in(u_long, + u_short); +static inline void + mmc_read(u_long, /* Read n bytes from the MMC */ + u_char, + u_char *, + int), + fee_wait(u_long, /* Wait for frequency EEprom : base address */ + int, /* Base delay to wait for */ + int); /* Number of time to wait */ +static void + fee_read(u_long, /* Read the frequency EEprom : base address */ + u_short, /* destination offset */ + u_short *, /* data buffer */ + int); /* number of registers */ +/* ---------------------- I82593 SUBROUTINES ----------------------- */ +static int + wv_82593_cmd(device *, /* synchronously send a command to i82593 */ + char *, + int, + int); +static inline int + wv_diag(device *); /* Diagnostique the i82593 */ +static int + read_ringbuf(device *, /* Read a receive buffer */ + int, + char *, + int); +static inline void + wv_82593_reconfig(device *); /* Reconfigure the controller */ +/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ +static inline void + wv_init_info(device *); /* display startup info */ +/* ------------------- IOCTL, STATS & RECONFIG ------------------- */ +static en_stats * + wavelan_get_stats(device *); /* Give stats /proc/net/dev */ +/* ----------------------- PACKET RECEPTION ----------------------- */ +static inline int + wv_start_of_frame(device *, /* Seek beggining of current frame */ + int, /* end of frame */ + int); /* start of buffer */ +static inline void + wv_packet_read(device *, /* Read a packet from a frame */ + int, + int), + wv_packet_rcv(device *); /* Read all packets waiting */ +/* --------------------- PACKET TRANSMISSION --------------------- */ +static inline void + wv_packet_write(device *, /* Write a packet to the Tx buffer */ + void *, + short); +static int + wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ + device *); +/* -------------------- HARDWARE CONFIGURATION -------------------- */ +static inline int + wv_mmc_init(device *); /* Initialize the modem */ +static int + wv_ru_stop(device *), /* Stop the i82593 receiver unit */ + wv_ru_start(device *); /* Start the i82593 receiver unit */ +static int + wv_82593_config(device *); /* Configure the i82593 */ +static inline int + wv_pcmcia_reset(device *); /* Reset the pcmcia interface */ +static int + wv_hw_config(device *); /* Reset & configure the whole hardware */ +static inline void + wv_hw_reset(device *); /* Same, + start receiver unit */ +static inline int + wv_pcmcia_config(dev_link_t *); /* Configure the pcmcia interface */ +static void + wv_pcmcia_release(u_long), /* Remove a device */ + wv_flush_stale_links(void); /* "detach" all possible devices */ +/* ---------------------- INTERRUPT HANDLING ---------------------- */ +static void + wavelan_interrupt(int, /* Interrupt handler */ + void *, + struct pt_regs *); +static void + wavelan_watchdog(device *); /* Transmission watchdog */ +/* ------------------- CONFIGURATION CALLBACKS ------------------- */ +static int + wavelan_open(device *), /* Open the device */ + wavelan_close(device *); /* Close the device */ +static dev_link_t * + wavelan_attach(void); /* Create a new device */ +static void + wavelan_detach(dev_link_t *); /* Destroy a removed device */ +static int + wavelan_event(event_t, /* Manage pcmcia events */ + int, + event_callback_args_t *); + +/**************************** VARIABLES ****************************/ + +static dev_info_t dev_info = "wavelan_cs"; +static dev_link_t *dev_list = NULL; /* Linked list of devices */ + +/* + * Parameters that can be set with 'insmod' + * The exact syntax is 'insmod wavelan_cs.o =' + */ + +/* Bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4 and 3 */ +static int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +/* Shared memory speed, in ns */ +static int mem_speed = 0; + +/* New module interface */ +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(mem_speed, "i"); + +#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ +/* Enable roaming mode ? No ! Please keep this to 0 */ +static int do_roaming = 0; +MODULE_PARM(do_roaming, "i"); +#endif /* WAVELAN_ROAMING */ + +MODULE_LICENSE("GPL"); + +#endif /* WAVELAN_CS_H */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/rclanmtl.c linux-2.5/drivers/net/rclanmtl.c --- linux-2.5.20/drivers/net/rclanmtl.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/net/rclanmtl.c Mon Mar 25 22:24:17 2002 @@ -305,15 +305,15 @@ PU8 p_phymsgbuf = (PU8) virt_to_bus ((void *) p_msgbuf); dprintk - ("InitI2O: Adapter:0x%04ux ATU:0x%08ulx msgbuf:0x%08ulx phymsgbuf:0x%08ulx\n" - "TransmitCallbackFunction:0x%08ulx ReceiveCallbackFunction:0x%08ulx\n", + ("InitI2O: Adapter:0x%x ATU:0x%x msgbuf:0x%x phymsgbuf:0x%x\n" + "TransmitCallbackFunction:0x%x ReceiveCallbackFunction:0x%x\n", pDpa->id, pciBaseAddr, (u32) p_msgbuf, (u32) p_phymsgbuf, (u32) TransmitCallbackFunction, (u32) ReceiveCallbackFunction); /* Check if this interface already initialized - if so, shut it down */ if (pDpa->pPab != NULL) { - printk (KERN_WARNING - "(rcpci45 driver:) pDpa->pPab [%d] != NULL\n", + dprintk (KERN_WARNING + "pDpa->pPab [%d] != NULL\n", pDpa->id); /* RCResetLANCard(pDpa->id, 0, (PU32)NULL, (PFNCALLBACK)NULL); */ pDpa->pPab = NULL; @@ -324,8 +324,8 @@ pPab = kmalloc (sizeof (*pPab), GFP_KERNEL); if (!pPab) { - printk (KERN_ERR - "(rcpci45 driver:) RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n"); + dprintk (KERN_ERR + "RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n"); result = RC_RTN_MALLOC_ERROR; goto err_out; } @@ -354,8 +354,7 @@ goto err_out_dealloc; if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) { - printk (KERN_INFO - "(rcpci45 driver:) pPab->IOPState == op: resetting adapter\n"); + dprintk (KERN_INFO "pPab->IOPState == op: resetting adapter\n"); RCResetLANCard (dev, 0, (PU32) NULL, (PFNCALLBACK) NULL); } @@ -445,7 +444,7 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock); @@ -502,7 +501,7 @@ dprintk ("RCPostRecvBuffers(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock); @@ -570,13 +569,13 @@ dev); } else if (I2O_LAN_RECEIVE_POST == p8Msg[7]) { /* Receive Packet Reply Msg */ dprintk - ("I2O_RECV_REPLY pPab:0x%08ulx p8Msg:0x%08ulx p32:0x%08ulx\n", + ("I2O_RECV_REPLY pPab:0x%x p8Msg:0x%x p32:0x%x\n", (u32) pPab, (u32) p8Msg, (u32) p32); - dprintk ("msg: 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + dprintk ("msg: 0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], p32[2], p32[3]); - dprintk (" 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + dprintk (" 0x%x:0x%x:0x%x:0x%x\n", p32[4], p32[5], p32[6], p32[7]); - dprintk (" 0x%08ulx:0X%08ulx:0x%08ulx:0x%08ulx\n", + dprintk (" 0x%x:0X%x:0x%x:0x%x\n", p32[8], p32[9], p32[10], p32[11]); /* status, count, buckets remaining, packetParmBlock, adapter */ (*pPab->pRecvCallbackFunc) (p8Msg[19], p8Msg[12], @@ -623,8 +622,8 @@ dev); break; default: - printk (KERN_WARNING - "(rcpci45 driver:) Unknown private I2O msg received: 0x%x\n", + dprintk (KERN_WARNING + "Unknown private I2O msg received: 0x%x\n", p32[5]); break; } @@ -658,14 +657,13 @@ PFNWAITCALLBACK WaitCallback) { U32 msgOffset; - volatile U32 timeout; volatile PU32 pMsg; volatile PU32 p32, pReturnAddr; P_NICSTAT pStats; int i; PPAB pPab = ((PDPA) dev->priv)->pPab; -/*dprintk("Get82558Stats() StatsReturnAddr:0x%08ulx\n", StatsReturnAddr); */ +/*dprintk("Get82558Stats() StatsReturnAddr:0x%x\n", StatsReturnAddr); */ if (pPab == NULL) return RC_RTN_ADPTR_NOT_REGISTERED; @@ -677,10 +675,10 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); -/*dprintk("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ +/*dprintk("Get82558Stats - pMsg = 0x%x, InQ msgOffset = 0x%x\n", pMsg, msgOffset);*/ /*dprintk("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -690,30 +688,22 @@ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_STATS; pMsg[5] = pPab->outMsgBlockPhyAddr; - p32 = (PU32) pPab->outMsgBlockPhyAddr; +// p32 = (PU32) pPab->outMsgBlockPhyAddr; + p32 = (PU32)pPab->pLinOutMsgBlock; pStats = (P_NICSTAT) pPab->pLinOutMsgBlock; pStats->dump_status = 0xFFFFFFFF; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; - timeout = 100000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (pStats->dump_status != 0xFFFFFFFF) - break; - - if (!timeout--) { - dprintk - ("RCGet82558Stats() Timeout waiting for NIC statistics\n"); + i = 0; + while (pStats->dump_status == 0xFFFFFFFF) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for NIC statistics\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(50); } - pReturnAddr = (PU32) StatsReturnAddr; /* copy Nic stats to user's structure */ @@ -732,13 +722,13 @@ RCGetLinkStatus (struct net_device * dev, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback) { + int i; U32 msgOffset; - volatile U32 timeout; volatile PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA) dev->priv)->pPab; - dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%08ulx\n", + dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%x\n", (u32) ReturnAddr); if (pPab == NULL) @@ -751,9 +741,9 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); -/*dprintk("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ +/*dprintk("Get82558LinkStatus - pMsg = 0x%x, InQ msgOffset = 0x%x\n", pMsg, msgOffset);*/ /*dprintk("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -769,20 +759,13 @@ /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; - timeout = 100000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (*p32 != 0xFFFFFFFF) - break; - - if (!timeout--) { + i = 0; + while (*p32 == 0xFFFFFFFF) { + if (i++ > 0xff) { dprintk ("Timeout waiting for link status\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(50); } *ReturnAddr = *p32; /* 1 = up 0 = down */ @@ -802,8 +785,7 @@ RC_RETURN RCGetMAC (struct net_device * dev, PFNWAITCALLBACK WaitCallback) { - unsigned timeout; - U32 off; + U32 off, i; PU8 mac = dev->dev_addr; PU32 p; U32 temp[2]; @@ -839,17 +821,13 @@ (uint) p_atu, (uint) off, (uint) p); /* wait for the rcpci45 board to update the info */ - timeout = 1000000; + i = 0; while (0 == p_atu->EtherMacLow) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (!timeout--) { - printk ("rc_getmac: Timeout\n"); + if (i++ > 0xff) { + dprintk ("rc_getmac: Timeout\n"); return RC_RTN_MSG_REPLY_TIMEOUT; - } + } + udelay(50); } /* read the mac address */ @@ -1001,16 +979,16 @@ RCGetPromiscuousMode (struct net_device * dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; PU32 pMsg; volatile PU32 p32; + U32 msgOffset, i; PPAB pPab = ((PDPA) dev->priv)->pPab; msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + dprintk (KERN_WARNING + "RCGetLinkSpeed(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } @@ -1034,23 +1012,15 @@ pPab->p_atu->InQueue = msgOffset; - /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ + i = 0; - if (p32[0] != 0xff) - break; - - if (!timeout--) { - dprintk - ("Timeout waiting for promiscuous mode from adapter\n"); - dprintk ("0x%8x\n", p32[0]); + /* wait for response */ + while (p32[0] == 0xff) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for promiscuous mode\n"); return RC_RTN_NO_LINK_SPEED; } + udelay(50); } /* get mode */ @@ -1115,7 +1085,7 @@ RCGetBroadcastMode (struct net_device * dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; + U32 msgOffset; PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA) dev->priv)->pPab; @@ -1123,8 +1093,8 @@ msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + dprintk (KERN_WARNING + "RCGetLinkSpeed(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } @@ -1149,23 +1119,10 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - printk (KERN_WARNING - "(rcpci45 driver:) Timeout waiting for promiscuous mode from adapter\n"); - printk (KERN_WARNING "(rcpci45 driver:) 0x%8x\n", - p32[0]); - return RC_RTN_NO_LINK_SPEED; - } + if (p32[0] == 0xff) { + dprintk (KERN_WARNING + "Timeout waiting for promiscuous mode\n"); + return RC_RTN_NO_LINK_SPEED; } /* get mode */ @@ -1192,7 +1149,7 @@ RCGetLinkSpeed (struct net_device * dev, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; volatile PU32 p32; U8 IOPLinkSpeed; @@ -1201,8 +1158,8 @@ msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + dprintk (KERN_WARNING + "RCGetLinkSpeed(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } @@ -1227,26 +1184,16 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - dprintk ("Timeout waiting for link speed from IOP\n"); - dprintk ("0x%8x\n", p32[0]); + i = 0; + while (p32[0] == 0xff) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for link speed\n"); return RC_RTN_NO_LINK_SPEED; } + udelay(50); } - /* get Link speed */ IOPLinkSpeed = (U8) ((volatile PU8) p32)[0] & 0x0f; - *pLinkSpeedCode = IOPLinkSpeed; return RC_RTN_NO_ERROR; @@ -1304,7 +1251,7 @@ RCGetFirmwareVer (struct net_device * dev, PU8 pFirmString, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA) dev->priv)->pPab; @@ -1336,22 +1283,14 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - dprintk ("Timeout waiting for link speed from IOP\n"); + i = 0; + while (p32[0] == 0xff) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for link speed\n"); return RC_RTN_NO_FIRM_VER; } + udelay(50); } - strcpy (pFirmString, (PU8) p32); return RC_RTN_NO_ERROR; } @@ -1403,9 +1342,9 @@ or until timer goes off */ while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) { RCProcI2OMsgQ (dev); - udelay (1000); /* please don't hog the bus!!! */ + mdelay (1); timeout++; - if (timeout > 10000) { + if (timeout > 200) { break; } } @@ -1427,7 +1366,7 @@ RC_RETURN RCResetIOP (struct net_device * dev) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; PPAB pPab = ((PDPA) dev->priv)->pPab; volatile PU32 p32; @@ -1452,7 +1391,7 @@ pMsg[7] = 0; pMsg[8] = 1; /* return 1 byte */ - /* virual pointer to return buffer - clear first two dwords */ + /* virtual pointer to return buffer - clear first two dwords */ p32 = (volatile PU32) pPab->pLinOutMsgBlock; p32[0] = 0; p32[1] = 0; @@ -1462,17 +1401,13 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] || p32[1]) - break; - - if (!timeout--) { + i = 0; + while (!p32[0] && !p32[1]) { + if (i++ > 0xff) { dprintk ("RCResetIOP timeout\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(100); } return RC_RTN_NO_ERROR; } @@ -1525,11 +1460,11 @@ or until timer goes off */ while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) { RCProcI2OMsgQ (dev); - udelay (1000); /* please don't hog the bus!!! */ + mdelay (1); timeout++; - if (timeout > 10000) { - printk (KERN_WARNING - "(rcpci45 driver:) RCShutdownLANCard(): timeout\n"); + if (timeout > 200) { + dprintk (KERN_WARNING + "RCShutdownLANCard(): timeout\n"); break; } } @@ -1594,14 +1529,13 @@ RCGetRavlinIPandMask (struct net_device * dev, PU32 pIpAddr, PU32 pNetMask, PFNWAITCALLBACK WaitCallback) { - unsigned timeout; - U32 off; + U32 off, i; PU32 pMsg, p32; PPAB pPab = ((PDPA) dev->priv)->pPab; PATU p_atu; dprintk - ("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", + ("RCGetRavlinIPandMask: pIpAddr is 0x%x, *IpAddr is 0x%x\n", (u32) pIpAddr, *pIpAddr); if (pPab == NULL) @@ -1619,7 +1553,7 @@ pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); dprintk - ("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", + ("RCGetRavlinIPandMask: p_atu 0x%x, off 0x%x, p32 0x%x\n", (u32) p_atu, off, (u32) p32); /* setup private message */ pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1631,25 +1565,21 @@ p_atu->InQueue = off; /* send it to the I2O device */ dprintk - ("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", + ("RCGetRavlinIPandMask: p_atu 0x%x, off 0x%x, p32 0x%x\n", (u32) p_atu, off, (u32) p32); /* wait for the rcpci45 board to update the info */ - timeout = 100000; + i = 0; while (0xffffffff == *p32) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (!timeout--) { + if (i++ > 0xff) { dprintk ("RCGetRavlinIPandMask: Timeout\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(50); } dprintk - ("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%08ulx, p32[1] (IPmask) 0x%08ulx\n", + ("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%x, p32[1] (IPmask) 0x%x\n", p32[0], p32[1]); /* send IP and mask to user's space */ @@ -1657,7 +1587,7 @@ *pNetMask = p32[1]; dprintk - ("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", + ("RCGetRavlinIPandMask: pIpAddr is 0x%x, *IpAddr is 0x%x\n", (u32) pIpAddr, *pIpAddr); return RC_RTN_NO_ERROR; @@ -1682,7 +1612,7 @@ static int SendI2OOutboundQInitMsg (PPAB pPab) { - U32 msgOffset, timeout, phyOutQFrames, i; + U32 msgOffset, phyOutQFrames, i; volatile PU32 pMsg; volatile PU32 p32; @@ -1693,11 +1623,11 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); dprintk - ("SendI2OOutboundQInitMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", + ("SendI2OOutboundQInitMsg - pMsg = 0x%x, InQ msgOffset = 0x%x\n", (u32) pMsg, msgOffset); pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6; @@ -1711,7 +1641,7 @@ /* phys address to return status - area right after PAB */ pMsg[7] = pPab->outMsgBlockPhyAddr; - /* virual pointer to return buffer - clear first two dwords */ + /* virtual pointer to return buffer - clear first two dwords */ p32 = (PU32) pPab->pLinOutMsgBlock; p32[0] = 0; @@ -1719,34 +1649,19 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 100000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0]) - break; - - if (!timeout--) { - dprintk - ("Timeout wait for InitOutQ InPrgress status from IOP\n"); + i = 0; + while (!p32[0]) { + if (i++ > 0xff) { + printk("rc: InitOutQ timeout\n"); return RC_RTN_NO_I2O_STATUS; } + udelay(50); } - - timeout = 100000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE) - break; - - if (!timeout--) { - dprintk - ("Timeout wait for InitOutQ Complete status from IOP\n"); - return RC_RTN_NO_I2O_STATUS; - } + if (p32[0] != I2O_EXEC_OUTBOUND_INIT_COMPLETE) { + printk("rc: exec outbound init failed (%x)\n", + p32[0]); + return RC_RTN_NO_I2O_STATUS; } - /* load PCI outbound free Q with MF physical addresses */ phyOutQFrames = pPab->outMsgBlockPhyAddr; @@ -1768,7 +1683,7 @@ static int GetI2OStatus (PPAB pPab) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; volatile PU32 p32; @@ -1779,7 +1694,7 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1793,51 +1708,41 @@ pMsg[7] = 0; pMsg[8] = 88; /* return 88 bytes */ - /* virual pointer to return buffer - clear first two dwords */ + /* virtual pointer to return buffer - clear first two dwords */ p32 = (volatile PU32) pPab->pLinOutMsgBlock; p32[0] = 0; p32[1] = 0; dprintk - ("GetI2OStatus - pMsg:0x%08ulx, msgOffset:0x%08ulx, [1]:0x%08ulx, [6]:0x%08ulx\n", + ("GetI2OStatus - pMsg:0x%x, msgOffset:0x%x, [1]:0x%x, [6]:0x%x\n", (u32) pMsg, msgOffset, pMsg[1], pMsg[6]); /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; - dprintk ("Return status to p32 = 0x%08ulx\n", (u32) p32); + dprintk ("Return status to p32 = 0x%x\n", (u32) p32); /* wait for response */ - timeout = 1000000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] && p32[1]) - break; - - if (!timeout--) { + i = 0; + while (!p32[0] || !p32[1]) { + if (i++ > 0xff) { dprintk ("Timeout waiting for status from IOP\n"); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[0], p32[1], p32[2], p32[3]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[4], p32[5], p32[6], p32[7]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[8], p32[9], p32[10], p32[11]); return RC_RTN_NO_I2O_STATUS; } + udelay(50); } - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], + dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], p32[2], p32[3]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], + dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[4], p32[5], p32[6], p32[7]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9], + dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[8], p32[9], p32[10], p32[11]); /* get IOP state */ pPab->IOPState = ((volatile PU8) p32)[10]; pPab->InboundMFrameSize = ((volatile PU16) p32)[6]; - dprintk ("IOP state 0x%02x InFrameSize = 0x%04x\n", + dprintk ("IOP state 0x%x InFrameSize = 0x%x\n", pPab->IOPState, pPab->InboundMFrameSize); return RC_RTN_NO_ERROR; } @@ -1862,11 +1767,11 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); dprintk - ("SendEnableSysMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", + ("SendEnableSysMsg - pMsg = 0x%x, InQ msgOffset = 0x%x\n", (u32) pMsg, msgOffset); pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1885,7 +1790,7 @@ ** ========================================================================= ** FillI2OMsgFromTCB() ** -** inputs pMsgU32 - virual pointer (mapped to physical) of message frame +** inputs pMsgU32 - virtual pointer (mapped to physical) of message frame ** pXmitCntrlBlock - pointer to caller buffer control block. ** ** fills in LAN SGL after Transaction Control Word or Bucket Count. @@ -1908,9 +1813,9 @@ nmbrDwords = 0; dprintk ("FillI2OMsgSGLFromTCBX\n"); - dprintk ("TCB 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + dprintk ("TCB 0x%x:0x%x:0x%x:0x%x:0x%x\n", pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]); - dprintk ("pTCB 0x%08ulx, pMsg 0x%08ulx\n", (u32) pTCB, (u32) pMsg); + dprintk ("pTCB 0x%x, pMsg 0x%x\n", (u32) pTCB, (u32) pMsg); nmbrBuffers = *pTCB++; @@ -1987,11 +1892,11 @@ p32 = (PU32) p8Msg; dprintk - ("VXD: ProcessOutboundI2OMsg - pPab 0x%08ulx, phyAdr 0x%08ulx, linAdr 0x%08ulx\n", + ("VXD: ProcessOutboundI2OMsg - pPab 0x%x, phyAdr 0x%x, linAdr 0x%x\n", (u32) pPab, phyAddrMsg, (u32) p8Msg); - dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], + dprintk ("msg :0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], p32[2], p32[3]); - dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], + dprintk ("msg :0x%x:0x%x:0x%x:0x%x\n", p32[4], p32[5], p32[6], p32[7]); if (p32[4] >> 24 != I2O_REPLY_STATUS_SUCCESS) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/rclanmtl.h linux-2.5/drivers/net/rclanmtl.h --- linux-2.5.20/drivers/net/rclanmtl.h Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/net/rclanmtl.h Thu May 2 23:31:31 2002 @@ -54,10 +54,10 @@ #include /* Debug stuff. Define for debug output */ -#define RCDEBUG +#undef RCDEBUG #ifdef RCDEBUG -#define dprintk(args...) printk(KERN_DEBUG "(rcpci45 driver:) " args) +#define dprintk(args...) printk("rc: " args) #else #define dprintk(args...) { } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/rcpci45.c linux-2.5/drivers/net/rcpci45.c --- linux-2.5.20/drivers/net/rcpci45.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/net/rcpci45.c Mon Feb 18 22:04:29 2002 @@ -29,6 +29,9 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** +** Pete Popov, Oct 2001: Fixed a few bugs to make the driver functional +** again. Note that this card is not supported or manufactured by +** RedCreek anymore. ** ** Rasmus Andersen, December 2000: Converted to new PCI API and general ** cleanup. @@ -44,7 +47,10 @@ ** ***************************************************************************/ +#include // nuke me later. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include #include @@ -64,7 +70,7 @@ #include static char version[] __initdata = - "RedCreek Communications PCI linux driver version 2.03\n"; + "RedCreek Communications PCI linux driver version 2.20\n"; #define RC_LINUX_MODULE #include "rclanmtl.h" @@ -89,6 +95,14 @@ /* RedCreek's OSM default LAN receive Initiator */ #define DEFAULT_RECV_INIT_CONTEXT 0xA17 +/* minimum msg buffer size needed by the card + * Note that the size of this buffer is hard code in the + * ipsec card's firmware. Thus, the size MUST be a minimum + * of 16K. Otherwise the card will end up using memory + * that does not belong to it. + */ +#define MSG_BUF_SIZE 16384 + static U32 DriverControlWord; static void rc_timer (unsigned long); @@ -122,39 +136,25 @@ PDPA pDpa = dev->priv; if (!dev) { - printk (KERN_ERR - "(rcpci45 driver:) remove non-existent device\n"); + printk (KERN_ERR "%s: remove non-existent device\n", + dev->name); return; } - dprintk ("remove_one: IOP reset: 0x%x\n", RCResetIOP (dev)); - - /* RAA Inspired by starfire.c and yellowfin.c we keep these - * here. */ + RCResetIOP (dev); unregister_netdev (dev); free_irq (dev->irq, dev); iounmap ((void *) dev->base_addr); pci_release_regions (pdev); - kfree (pDpa->PLanApiPA); - kfree (pDpa->pPab); - kfree (pDpa); + if (pDpa->msgbuf) + kfree (pDpa->msgbuf); + if (pDpa->pPab) + kfree (pDpa->pPab); kfree (dev); pci_set_drvdata (pdev, NULL); } static int -RCinit (struct net_device *dev) -{ - dev->open = &RCopen; - dev->hard_start_xmit = &RC_xmit_packet; - dev->stop = &RCclose; - dev->get_stats = &RCget_stats; - dev->do_ioctl = &RCioctl; - dev->set_config = &RCconfig; - return 0; -} - -static int rcpci45_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned long *vaddr; @@ -168,17 +168,17 @@ /* * Allocate and fill new device structure. - * We need enough for struct net_device plus DPA plus the LAN API private - * area, which requires a minimum of 16KB. The top of the allocated - * area will be assigned to struct net_device; the next chunk will be - * assigned to DPA; and finally, the rest will be assigned to the - * the LAN API layer. + * We need enough for struct net_device plus DPA plus the LAN + * API private area, which requires a minimum of 16KB. The top + * of the allocated area will be assigned to struct net_device; + * the next chunk will be assigned to DPA; and finally, the rest + * will be assigned to the the LAN API layer. */ dev = init_etherdev (NULL, sizeof (*pDpa)); if (!dev) { printk (KERN_ERR - "(rcpci45 driver:) unable to allocate in init_etherdev\n"); + "(rcpci45 driver:) init_etherdev alloc failed\n"); error = -ENOMEM; goto err_out; } @@ -186,13 +186,14 @@ error = pci_enable_device (pdev); if (error) { printk (KERN_ERR - "(rcpci45 driver:) %d: unable to enable pci device, aborting\n", + "(rcpci45 driver:) %d: pci enable device error\n", card_idx); goto err_out; } error = -ENOMEM; pci_start = pci_resource_start (pdev, 0); pci_len = pci_resource_len (pdev, 0); + printk("pci_start %x pci_len %x\n", pci_start, pci_len); pci_set_drvdata (pdev, dev); @@ -202,29 +203,30 @@ if (!pci_start || !(pci_resource_flags (pdev, 0) & IORESOURCE_MEM)) { printk (KERN_ERR - "(rcpci45 driver:) No PCI memory resources! Aborting.\n"); + "(rcpci45 driver:) No PCI mem resources! Aborting\n"); error = -EBUSY; goto err_out_free_dev; } /* - * Save the starting address of the LAN API private area. We'll - * pass that to RCInitI2OMsgLayer(). + * pDpa->msgbuf is where the card will dma the I2O + * messages. Thus, we need contiguous physical pages of + * memory. */ - /* RAA FIXME: This size should be a #define somewhere after I - * clear up some questions: What flags are neeeded in the alloc below - * and what needs to be done before the memarea is long word aligned? - * (Look in old code for an approach.) (Also note that the 16K below - * is substantially less than the 32K allocated before (even though - * some of the spacce was used for data structures.) */ - pDpa->msgbuf = kmalloc (16384, GFP_KERNEL); + pDpa->msgbuf = kmalloc (MSG_BUF_SIZE, GFP_DMA|GFP_ATOMIC|GFP_KERNEL); if (!pDpa->msgbuf) { - printk (KERN_ERR "(rcpci45 driver:) Could not allocate %d byte memory for the private msgbuf!\n", 16384); /* RAA FIXME not hardcoded! */ + printk (KERN_ERR "(rcpci45 driver:) \ + Could not allocate %d byte memory for the \ + private msgbuf!\n", MSG_BUF_SIZE); goto err_out_free_dev; } - pDpa->PLanApiPA = (void *) (((long) pDpa->msgbuf + 0xff) & ~0xff); - dprintk ("pDpa->PLanApiPA = 0x%x\n", (uint) pDpa->PLanApiPA); + /* + * Save the starting address of the LAN API private area. We'll + * pass that to RCInitI2OMsgLayer(). + * + */ + pDpa->PLanApiPA = (void *) (((long) pDpa->msgbuf + 0xff) & ~0xff); /* The adapter is accessible through memory-access read/write, not * I/O read/write. Thus, we need to map it to some virtual address @@ -237,17 +239,20 @@ vaddr = (ulong *) ioremap (pci_start, pci_len); if (!vaddr) { printk (KERN_ERR - "(rcpci45 driver:) Unable to remap address range from %lu to %lu\n", + "(rcpci45 driver:) \ + Unable to remap address range from %lu to %lu\n", pci_start, pci_start + pci_len); goto err_out_free_region; } - dprintk ("rcpci45_init_one: 0x%x, priv = 0x%x, vaddr = 0x%x\n", - (uint) dev, (uint) dev->priv, (uint) vaddr); dev->base_addr = (unsigned long) vaddr; dev->irq = pdev->irq; - - dev->init = &RCinit; + dev->open = &RCopen; + dev->hard_start_xmit = &RC_xmit_packet; + dev->stop = &RCclose; + dev->get_stats = &RCget_stats; + dev->do_ioctl = &RCioctl; + dev->set_config = &RCconfig; return 0; /* success */ @@ -260,7 +265,7 @@ kfree (dev); err_out: card_idx--; - return error; + return -ENODEV; } static struct pci_driver rcpci45_driver = { @@ -274,9 +279,8 @@ rcpci_init_module (void) { int rc = pci_module_init (&rcpci45_driver); - if (!rc) - printk (KERN_INFO "%s", version); + printk (KERN_ERR "%s", version); return rc; } @@ -289,56 +293,56 @@ int requested = 0; int error; - dprintk ("(rcpci45 driver:) RCopen\n"); + MOD_INC_USE_COUNT; + if (pDpa->nexus) { + /* This is not the first time RCopen is called. Thus, + * the interface was previously opened and later closed + * by RCclose(). RCclose() does a Shutdown; to wake up + * the adapter, a reset is mandatory before we can post + * receive buffers. However, if the adapter initiated + * a reboot while the interface was closed -- and interrupts + * were turned off -- we need will need to reinitialize + * the adapter, rather than simply waking it up. + */ + printk (KERN_INFO "Waking up adapter...\n"); + RCResetLANCard (dev, 0, 0, 0); + } else { + pDpa->nexus = 1; + /* + * RCInitI2OMsgLayer is done only once, unless the + * adapter was sent a warm reboot + */ + error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, + (PFNRXCALLBACK) RCrecv_callback, + (PFNCALLBACK) RCreboot_callback); + if (error) { + printk (KERN_ERR "%s: Unable to init msg layer (%x)\n", + dev->name, error); + goto err_out; + } + if ((error = RCGetMAC (dev, NULL))) { + printk (KERN_ERR "%s: Unable to get adapter MAC\n", + dev->name); + goto err_out; + } + } /* Request a shared interrupt line. */ error = request_irq (dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev); if (error) { - printk (KERN_ERR "(rcpci45 driver:) %s: unable to get IRQ %d\n", - dev->name, dev->irq); + printk (KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); goto err_out; } - error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, - (PFNRXCALLBACK) RCrecv_callback, - (PFNCALLBACK) RCreboot_callback); - if (error) { - printk (KERN_ERR - "(rcpci45 driver:) Unable to initialize msg layer\n"); - goto err_out_free_irq; - } - if ((error = RCGetMAC (dev, NULL))) { - printk (KERN_ERR - "(rcpci45 driver:) Unable to get adapter MAC\n"); - goto err_out_free_irq; - } - DriverControlWord |= WARM_REBOOT_CAPABLE; RCReportDriverCapability (dev, DriverControlWord); printk (KERN_INFO "%s: RedCreek Communications IPSEC VPN adapter\n", dev->name); - /* RAA: Old RCopen starts here */ RCEnableI2OInterrupts (dev); - /* RAA Hmm, how does the comment below jibe with the newly imported - * code above? A FIXME!!*/ - if (pDpa->nexus) { - /* This is not the first time RCopen is called. Thus, - * the interface was previously opened and later closed - * by RCclose(). RCclose() does a Shutdown; to wake up - * the adapter, a reset is mandatory before we can post - * receive buffers. However, if the adapter initiated - * a reboot while the interface was closed -- and interrupts - * were turned off -- we need will need to reinitialize - * the adapter, rather than simply waking it up. - */ - dprintk (KERN_INFO "Waking up adapter...\n"); - RCResetLANCard (dev, 0, 0, 0); - } else - pDpa->nexus = 1; - while (post_buffers) { if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG) requested = MAX_NMBR_POST_BUFFERS_PER_MSG; @@ -348,29 +352,30 @@ if (count < requested) { /* - * Check to see if we were able to post any buffers at all. + * Check to see if we were able to post + * any buffers at all. */ if (post_buffers == MAX_NMBR_RCV_BUFFERS) { - printk (KERN_ERR - "(rcpci45 driver:) Error RCopen: not able to allocate any buffers\r\n"); - return (-ENOMEM); + printk (KERN_ERR "%s: \ + unable to allocate any buffers\n", + dev->name); + goto err_out_free_irq; } - printk (KERN_WARNING - "(rcpci45 driver:) Warning RCopen: not able to allocate all requested buffers\r\n"); + printk (KERN_WARNING "%s: \ + unable to allocate all requested buffers\n", dev->name); break; /* we'll try to post more buffers later */ } else post_buffers -= count; } pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers; pDpa->shutdown = 0; /* just in case */ - dprintk ("RCopen: posted %d buffers\n", (uint) pDpa->numOutRcvBuffers); - MOD_INC_USE_COUNT; netif_start_queue (dev); return 0; err_out_free_irq: free_irq (dev->irq, dev); err_out: + MOD_DEC_USE_COUNT; return error; } @@ -386,15 +391,16 @@ netif_stop_queue (dev); if (pDpa->shutdown || pDpa->reboot) { - dprintk ("RC_xmit_packet: tbusy!\n"); + printk ("RC_xmit_packet: tbusy!\n"); return 1; } /* - * The user is free to reuse the TCB after RCI2OSendPacket() returns, since - * the function copies the necessary info into its own private space. Thus, - * our TCB can be a local structure. The skb, on the other hand, will be - * freed up in our interrupt handler. + * The user is free to reuse the TCB after RCI2OSendPacket() + * returns, since the function copies the necessary info into its + * own private space. Thus, our TCB can be a local structure. + * The skb, on the other hand, will be freed up in our interrupt + * handler. */ ptcb->bcount = 1; @@ -408,11 +414,9 @@ ptcb->b.size = skb->len; ptcb->b.addr = virt_to_bus ((void *) skb->data); - dprintk ("RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n", - (uint) skb, (uint) pDpa, (uint) pDpa->id, (uint) ptcb); if ((status = RCI2OSendPacket (dev, (U32) NULL, (PRCTCB) ptcb)) != RC_RTN_NO_ERROR) { - dprintk ("RC send error 0x%x\n", (uint) status); + printk ("%s: send error 0x%x\n", dev->name, (uint) status); return 1; } else { dev->trans_start = jiffies; @@ -442,23 +446,20 @@ PDPA pDpa = dev->priv; if (!pDpa) { - printk (KERN_ERR - "(rcpci45 driver:) Fatal error: xmit callback, !pDpa\n"); + printk (KERN_ERR "%s: Fatal Error in xmit callback, !pDpa\n", + dev->name); return; } -/* dprintk("xmit_callback: Status = 0x%x\n", (uint)Status); */ if (Status != I2O_REPLY_STATUS_SUCCESS) - dprintk ("xmit_callback: Status = 0x%x\n", (uint) Status); + printk (KERN_INFO "%s: xmit_callback: Status = 0x%x\n", + dev->name, (uint) Status); if (pDpa->shutdown || pDpa->reboot) - dprintk ("xmit callback: shutdown||reboot\n"); - - dprintk ("xmit_callback: PcktCount = %d, BC = 0x%x\n", - (uint) PcktCount, (uint) BufferContext); + printk (KERN_INFO "%s: xmit callback: shutdown||reboot\n", + dev->name); while (PcktCount--) { skb = (struct sk_buff *) (BufferContext[0]); - dprintk ("skb = 0x%x\n", (uint) skb); BufferContext++; dev_kfree_skb_irq (skb); } @@ -470,19 +471,18 @@ { PDPA pDpa = dev->priv; - dprintk ("RCreset_callback Status 0x%x\n", (uint) Status); + printk ("RCreset_callback Status 0x%x\n", (uint) Status); /* * Check to see why we were called. */ if (pDpa->shutdown) { - printk (KERN_INFO - "(rcpci45 driver:) Shutting down interface\n"); + printk (KERN_INFO "%s: shutting down interface\n", + dev->name); pDpa->shutdown = 0; pDpa->reboot = 0; - MOD_DEC_USE_COUNT; } else if (pDpa->reboot) { - printk (KERN_INFO - "(rcpci45 driver:) reboot, shutdown adapter\n"); + printk (KERN_INFO "%s: reboot, shutdown adapter\n", + dev->name); /* * We don't set any of the flags in RCShutdownLANCard() * and we don't pass a callback routine to it. @@ -491,7 +491,7 @@ */ RCDisableI2OInterrupts (dev); RCShutdownLANCard (dev, 0, 0, 0); - printk (KERN_INFO "(rcpci45 driver:) scheduling timer...\n"); + printk (KERN_INFO "%s: scheduling timer...\n", dev->name); init_timer (&pDpa->timer); pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 4 sec. */ pDpa->timer.data = (unsigned long) dev; @@ -505,12 +505,12 @@ { PDPA pDpa = dev->priv; - dprintk ("RCreboot: rcv buffers outstanding = %d\n", - (uint) pDpa->numOutRcvBuffers); + printk (KERN_INFO "%s: reboot: rcv buffers outstanding = %d\n", + dev->name, (uint) pDpa->numOutRcvBuffers); if (pDpa->shutdown) { - printk (KERN_INFO - "(rcpci45 driver:) skipping reboot sequence -- shutdown already initiated\n"); + printk (KERN_INFO "%s: skip reboot, shutdown initiated\n", + dev->name); return; } pDpa->reboot = 1; @@ -562,12 +562,9 @@ ptcb->bcount = 1; - dprintk ("RCrecv_callback: 0x%x, 0x%x, 0x%x\n", - (uint) PktCount, (uint) BucketsRemain, (uint) PacketDescBlock); - if ((pDpa->shutdown || pDpa->reboot) && !Status) - dprintk ("shutdown||reboot && !Status: PktCount = %d\n", - PktCount); + printk (KERN_INFO "%s: shutdown||reboot && !Status (%d)\n", + dev->name, PktCount); if ((Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown) { /* @@ -576,76 +573,38 @@ */ if (!pDpa->shutdown && !pDpa->reboot) - printk (KERN_INFO - "(rcpci45 driver:) RCrecv error: status = 0x%x\n", - (uint) Status); + printk (KERN_INFO "%s: recv error status = 0x%x\n", + dev->name, (uint) Status); else - dprintk ("Returning %d buffers, status = 0x%x\n", - PktCount, (uint) Status); + printk (KERN_DEBUG "%s: Returning %d buffs stat 0x%x\n", + dev->name, PktCount, (uint) Status); /* - * TO DO: check the nature of the failure and put the adapter in - * failed mode if it's a hard failure. Send a reset to the adapter - * and free all outstanding memory. + * TO DO: check the nature of the failure and put the + * adapter in failed mode if it's a hard failure. + * Send a reset to the adapter and free all outstanding memory. */ - if (Status == I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER) - dprintk ("RCrecv status ABORT NO DATA TRANSFER\n"); - - /* check for reset status: I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */ if (PacketDescBlock) { while (PktCount--) { skb = (struct sk_buff *) PacketDescBlock[0]; - dprintk ("free skb 0x%p\n", skb); dev_kfree_skb (skb); pDpa->numOutRcvBuffers--; - PacketDescBlock += BD_SIZE; /* point to next context field */ + /* point to next context field */ + PacketDescBlock += BD_SIZE; } } return; } else { while (PktCount--) { skb = (struct sk_buff *) PacketDescBlock[0]; - if (pDpa->shutdown) - dprintk ("shutdown: skb=0x%x\n", (uint) skb); - - dprintk ("skb = 0x%x: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", - (uint) skb, (uint) skb->data[0], - (uint) skb->data[1], (uint) skb->data[2], - (uint) skb->data[3], (uint) skb->data[4], - (uint) skb->data[5]); - -#ifdef PROMISCUOUS_BY_DEFAULT /* early 2.x firmware */ - if ((memcmp (dev->dev_addr, skb->data, 6)) && - (!broadcast_packet (skb->data))) { - /* - * Re-post the buffer to the adapter. Since the adapter usually - * return 1 to 2 receive buffers at a time, it's not too inefficient - * post one buffer at a time but ... may be that should be - * optimized at some point. - */ - ptcb->b.context = (U32) skb; - ptcb->b.scount = 1; - ptcb->b.size = MAX_ETHER_SIZE; - ptcb->b.addr = virt_to_bus ((void *) skb->data); - - if (RCPostRecvBuffers (dev, (PRCTCB) ptcb) != - RC_RTN_NO_ERROR) { - printk (KERN_WARNING - "(rcpci45 driver:) RCrecv_callback: post buffer failed!\n"); - dev_kfree_skb (skb); - } else - pDpa->numOutRcvBuffers++; - } else -#endif /* PROMISCUOUS_BY_DEFAULT */ - { - len = PacketDescBlock[2]; - skb->dev = dev; - skb_put (skb, len); /* adjust length and tail */ - skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); /* send the packet to the kernel */ - dev->last_rx = jiffies; - } - pDpa->numOutRcvBuffers--; - PacketDescBlock += BD_SIZE; /* point to next context field */ + len = PacketDescBlock[2]; + skb->dev = dev; + skb_put (skb, len); /* adjust length and tail */ + skb->protocol = eth_type_trans (skb, dev); + netif_rx (skb); /* send the packet to the kernel */ + dev->last_rx = jiffies; + pDpa->numOutRcvBuffers--; + /* point to next context field */ + PacketDescBlock += BD_SIZE; } } @@ -682,11 +641,8 @@ pDpa = dev->priv; if (pDpa->shutdown) - dprintk ("shutdown: service irq\n"); - - dprintk ("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n", - (uint) pDpa, (uint) dev, (uint) pDpa->id); - dprintk ("dev = 0x%x\n", (uint) dev); + printk (KERN_DEBUG "%s: shutdown, service irq\n", + dev->name); RCProcI2OMsgQ (dev); } @@ -717,62 +673,60 @@ RCReportDriverCapability (dev, DriverControlWord); RCEnableI2OInterrupts (dev); - if (dev->flags & IFF_UP) { - while (post_buffers) { - if (post_buffers > - MAX_NMBR_POST_BUFFERS_PER_MSG) - requested = - MAX_NMBR_POST_BUFFERS_PER_MSG; - else - requested = post_buffers; - count = - RC_allocate_and_post_buffers (dev, - requested); - post_buffers -= count; - if (count < requested) - break; - } - pDpa->numOutRcvBuffers = - MAX_NMBR_RCV_BUFFERS - post_buffers; - dprintk ("rc: posted %d buffers \r\n", - (uint) pDpa->numOutRcvBuffers); + + if (!(dev->flags & IFF_UP)) { + retry = 0; + return; + } + while (post_buffers) { + if (post_buffers > + MAX_NMBR_POST_BUFFERS_PER_MSG) + requested = + MAX_NMBR_POST_BUFFERS_PER_MSG; + else + requested = post_buffers; + count = + RC_allocate_and_post_buffers (dev, + requested); + post_buffers -= count; + if (count < requested) + break; } - dprintk ("Initialization done.\n"); + pDpa->numOutRcvBuffers = + MAX_NMBR_RCV_BUFFERS - post_buffers; + printk ("Initialization done.\n"); netif_wake_queue (dev); retry = 0; return; case RC_RTN_FREE_Q_EMPTY: retry++; - printk (KERN_WARNING - "(rcpci45 driver:) inbound free q empty\n"); + printk (KERN_WARNING "%s inbound free q empty\n", + dev->name); break; default: retry++; - printk (KERN_WARNING - "(rcpci45 driver:) bad status after reboot: %d\n", - init_status); + printk (KERN_WARNING "%s bad stat after reboot: %d\n", + dev->name, init_status); break; } if (retry > REBOOT_REINIT_RETRY_LIMIT) { - printk (KERN_WARNING - "(rcpci45 driver:) unable to reinitialize adapter after reboot\n"); - printk (KERN_WARNING - "(rcpci45 driver:) decrementing driver and closing interface\n"); + printk (KERN_WARNING "%s unable to reinitialize adapter after reboot\n", dev->name); + printk (KERN_WARNING "%s decrementing driver and closing interface\n", dev->name); RCDisableI2OInterrupts (dev); dev->flags &= ~IFF_UP; MOD_DEC_USE_COUNT; } else { - printk (KERN_INFO - "(rcpci45 driver:) rescheduling timer...\n"); + printk (KERN_INFO "%s: rescheduling timer...\n", + dev->name); init_timer (&pDpa->timer); - pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 3 sec. */ + pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); pDpa->timer.data = (unsigned long) dev; - pDpa->timer.function = &rc_timer; /* timer handler */ + pDpa->timer.function = &rc_timer; add_timer (&pDpa->timer); } } else - printk (KERN_WARNING "(rcpci45 driver:) timer??\n"); + printk (KERN_WARNING "%s: unexpected timer irq\n", dev->name); } static int @@ -780,19 +734,16 @@ { PDPA pDpa = dev->priv; + printk("RCclose\n"); netif_stop_queue (dev); - dprintk ("RCclose\r\n"); - if (pDpa->reboot) { - printk (KERN_INFO - "(rcpci45 driver:) skipping reset -- adapter already in reboot mode\n"); + printk (KERN_INFO "%s skipping reset -- adapter already in reboot mode\n", dev->name); dev->flags &= ~IFF_UP; pDpa->shutdown = 1; + MOD_DEC_USE_COUNT; return 0; } - dprintk ("receive buffers outstanding: %d\n", - (uint) pDpa->numOutRcvBuffers); pDpa->shutdown = 1; @@ -808,6 +759,7 @@ (PFNCALLBACK) RCreset_callback); dev->flags &= ~IFF_UP; + MOD_DEC_USE_COUNT; return 0; } @@ -819,56 +771,42 @@ PDPA pDpa = dev->priv; if (!pDpa) { - dprintk ("RCget_stats: !pDpa\n"); return 0; } else if (!(dev->flags & IFF_UP)) { - dprintk ("RCget_stats: device down\n"); return 0; } memset (&RCstats, 0, sizeof (RCLINKSTATS)); if ((RCGetLinkStatistics (dev, &RCstats, (void *) 0)) == RC_RTN_NO_ERROR) { - dprintk ("TX_good 0x%x\n", (uint) RCstats.TX_good); - dprintk ("TX_maxcol 0x%x\n", (uint) RCstats.TX_maxcol); - dprintk ("TX_latecol 0x%x\n", (uint) RCstats.TX_latecol); - dprintk ("TX_urun 0x%x\n", (uint) RCstats.TX_urun); - dprintk ("TX_crs 0x%x\n", (uint) RCstats.TX_crs); - dprintk ("TX_def 0x%x\n", (uint) RCstats.TX_def); - dprintk ("TX_singlecol 0x%x\n", (uint) RCstats.TX_singlecol); - dprintk ("TX_multcol 0x%x\n", (uint) RCstats.TX_multcol); - dprintk ("TX_totcol 0x%x\n", (uint) RCstats.TX_totcol); - - dprintk ("Rcv_good 0x%x\n", (uint) RCstats.Rcv_good); - dprintk ("Rcv_CRCerr 0x%x\n", (uint) RCstats.Rcv_CRCerr); - dprintk ("Rcv_alignerr 0x%x\n", (uint) RCstats.Rcv_alignerr); - dprintk ("Rcv_reserr 0x%x\n", (uint) RCstats.Rcv_reserr); - dprintk ("Rcv_orun 0x%x\n", (uint) RCstats.Rcv_orun); - dprintk ("Rcv_cdt 0x%x\n", (uint) RCstats.Rcv_cdt); - dprintk ("Rcv_runt 0x%x\n", (uint) RCstats.Rcv_runt); - - pDpa->stats.rx_packets = RCstats.Rcv_good; /* total packets received */ - pDpa->stats.tx_packets = RCstats.TX_good; /* total packets transmitted */ - pDpa->stats.rx_errors = RCstats.Rcv_CRCerr + RCstats.Rcv_alignerr + RCstats.Rcv_reserr + RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt; /* bad packets received */ + /* total packets received */ + pDpa->stats.rx_packets = RCstats.Rcv_good + /* total packets transmitted */; + pDpa->stats.tx_packets = RCstats.TX_good; + + pDpa->stats.rx_errors = RCstats.Rcv_CRCerr + + RCstats.Rcv_alignerr + RCstats.Rcv_reserr + + RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt; - pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs + RCstats.TX_def + RCstats.TX_totcol; /* packet transmit problems */ + pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs + + RCstats.TX_def + RCstats.TX_totcol; /* * This needs improvement. */ - pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ - pDpa->stats.tx_dropped = 0; /* no space available in linux */ - pDpa->stats.multicast = 0; /* multicast packets received */ + pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ + pDpa->stats.tx_dropped = 0; /* no space available in linux */ + pDpa->stats.multicast = 0; /* multicast packets received */ pDpa->stats.collisions = RCstats.TX_totcol; /* detailed rx_errors: */ pDpa->stats.rx_length_errors = 0; - pDpa->stats.rx_over_errors = RCstats.Rcv_orun; /* receiver ring buff overflow */ - pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; /* recved pkt with crc error */ - pDpa->stats.rx_frame_errors = 0; /* recv'd frame alignment error */ - pDpa->stats.rx_fifo_errors = 0; /* recv'r fifo overrun */ - pDpa->stats.rx_missed_errors = 0; /* receiver missed packet */ + pDpa->stats.rx_over_errors = RCstats.Rcv_orun; + pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; + pDpa->stats.rx_frame_errors = 0; + pDpa->stats.rx_fifo_errors = 0; + pDpa->stats.rx_missed_errors = 0; /* detailed tx_errors */ pDpa->stats.tx_aborted_errors = 0; @@ -888,8 +826,6 @@ RCuser_struct RCuser; PDPA pDpa = dev->priv; - dprintk ("RCioctl: cmd = 0x%x\n", cmd); - if (!capable (CAP_NET_ADMIN)) return -EPERM; @@ -913,16 +849,12 @@ switch (RCuser.cmd) { case RCUC_GETFWVER: - printk (KERN_INFO - "(rcpci45 driver:) RC GETFWVER\n"); RCUD_GETFWVER = &RCuser.RCUS_GETFWVER; RCGetFirmwareVer (dev, (PU8) & RCUD_GETFWVER-> FirmString, NULL); break; case RCUC_GETINFO: - printk (KERN_INFO - "(rcpci45 driver:) RC GETINFO\n"); RCUD_GETINFO = &RCuser.RCUS_GETINFO; RCUD_GETINFO->mem_start = dev->base_addr; RCUD_GETINFO->mem_end = @@ -931,8 +863,6 @@ RCUD_GETINFO->irq = dev->irq; break; case RCUC_GETIPANDMASK: - printk (KERN_INFO - "(rcpci45 driver:) RC GETIPANDMASK\n"); RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK; RCGetRavlinIPandMask (dev, (PU32) & @@ -942,8 +872,6 @@ NetMask, NULL); break; case RCUC_GETLINKSTATISTICS: - printk (KERN_INFO - "(rcpci45 driver:) RC GETLINKSTATISTICS\n"); RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS; RCGetLinkStatistics (dev, @@ -952,75 +880,39 @@ StatsReturn, NULL); break; case RCUC_GETLINKSTATUS: - printk (KERN_INFO - "(rcpci45 driver:) RC GETLINKSTATUS\n"); RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS; RCGetLinkStatus (dev, (PU32) & RCUD_GETLINKSTATUS-> ReturnStatus, NULL); break; case RCUC_GETMAC: - printk (KERN_INFO - "(rcpci45 driver:) RC GETMAC\n"); RCUD_GETMAC = &RCuser.RCUS_GETMAC; RCGetMAC (dev, NULL); + memcpy(RCUD_GETMAC, dev->dev_addr, 8); break; case RCUC_GETPROM: - printk (KERN_INFO - "(rcpci45 driver:) RC GETPROM\n"); RCUD_GETPROM = &RCuser.RCUS_GETPROM; RCGetPromiscuousMode (dev, (PU32) & RCUD_GETPROM-> PromMode, NULL); break; case RCUC_GETBROADCAST: - printk (KERN_INFO - "(rcpci45 driver:) RC GETBROADCAST\n"); RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST; RCGetBroadcastMode (dev, (PU32) & RCUD_GETBROADCAST-> BroadcastMode, NULL); break; case RCUC_GETSPEED: - printk (KERN_INFO - "(rcpci45 driver:) RC GETSPEED\n"); if (!(dev->flags & IFF_UP)) { - printk (KERN_ERR - "(rcpci45 driver:) RCioctl, GETSPEED error: interface down\n"); return -ENODATA; } RCUD_GETSPEED = &RCuser.RCUS_GETSPEED; RCGetLinkSpeed (dev, (PU32) & RCUD_GETSPEED-> LinkSpeedCode, NULL); - printk (KERN_INFO - "(rcpci45 driver:) RC speed = 0x%u\n", - RCUD_GETSPEED->LinkSpeedCode); break; case RCUC_SETIPANDMASK: - printk (KERN_INFO - "(rcpci45 driver:) RC SETIPANDMASK\n"); RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK; - printk (KERN_INFO - "(rcpci45 driver:) RC New IP Addr = %d.%d.%d.%d, ", - (U8) ((RCUD_SETIPANDMASK-> - IpAddr) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - IpAddr >> 8) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - IpAddr >> 16) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - IpAddr >> 24) & 0xff)); - printk (KERN_INFO - "(rcpci45 driver:) RC New Mask = %d.%d.%d.%d\n", - (U8) ((RCUD_SETIPANDMASK-> - NetMask) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - NetMask >> 8) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - NetMask >> 16) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - NetMask >> 24) & 0xff)); RCSetRavlinIPandMask (dev, (U32) RCUD_SETIPANDMASK-> IpAddr, @@ -1028,61 +920,33 @@ NetMask); break; case RCUC_SETMAC: - printk (KERN_INFO - "(rcpci45 driver:) RC SETMAC\n"); - RCUD_SETMAC = &RCuser.RCUS_SETMAC; - printk (KERN_INFO - "(rcpci45 driver:) RC New MAC addr = %02X:%02X:%02X:%02X:%02X:%02X\n", - (U8) (RCUD_SETMAC->mac[0]), - (U8) (RCUD_SETMAC->mac[1]), - (U8) (RCUD_SETMAC->mac[2]), - (U8) (RCUD_SETMAC->mac[3]), - (U8) (RCUD_SETMAC->mac[4]), - (U8) (RCUD_SETMAC->mac[5])); RCSetMAC (dev, (PU8) & RCUD_SETMAC->mac); break; case RCUC_SETSPEED: - printk (KERN_INFO - "(rcpci45 driver:) RC SETSPEED\n"); RCUD_SETSPEED = &RCuser.RCUS_SETSPEED; RCSetLinkSpeed (dev, (U16) RCUD_SETSPEED-> LinkSpeedCode); - printk (KERN_INFO - "(rcpci45 driver:) RC New speed = 0x%x\n", - RCUD_SETSPEED->LinkSpeedCode); break; case RCUC_SETPROM: - printk (KERN_INFO - "(rcpci45 driver:) RC SETPROM\n"); RCUD_SETPROM = &RCuser.RCUS_SETPROM; RCSetPromiscuousMode (dev, (U16) RCUD_SETPROM-> PromMode); - printk (KERN_INFO - "(rcpci45 driver:) RC New prom mode = 0x%x\n", - RCUD_SETPROM->PromMode); break; case RCUC_SETBROADCAST: - printk (KERN_INFO - "(rcpci45 driver:) RC SETBROADCAST\n"); RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST; RCSetBroadcastMode (dev, (U16) RCUD_SETBROADCAST-> BroadcastMode); - printk (KERN_INFO - "(rcpci45 driver:) RC New broadcast mode = 0x%x\n", - RCUD_SETBROADCAST->BroadcastMode); break; default: - printk (KERN_INFO - "(rcpci45 driver:) RC command default\n"); RCUD_DEFAULT = &RCuser.RCUS_DEFAULT; RCUD_DEFAULT->rc = 0x11223344; break; } - if (copy_to_user - (rq->ifr_data, &RCuser, sizeof (RCuser))) + if (copy_to_user (rq->ifr_data, &RCuser, + sizeof (RCuser))) return -EFAULT; break; } /* RCU_COMMAND */ @@ -1100,15 +964,14 @@ /* * To be completed ... */ - dprintk ("RCconfig\n"); return 0; if (dev->flags & IFF_UP) /* can't act on a running interface */ return -EBUSY; /* Don't allow changing the I/O address */ if (map->base_addr != dev->base_addr) { - printk (KERN_WARNING - "(rcpci45 driver:) Change I/O address not implemented\n"); + printk (KERN_WARNING "%s Change I/O address not implemented\n", + dev->name); return -EOPNOTSUPP; } return 0; @@ -1137,44 +1000,36 @@ if (!numBuffers) return 0; else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) { - dprintk ("Too many buffers requested!\n"); - dprintk ("attempting to allocate only 32 buffers\n"); + printk (KERN_ERR "%s: Too many buffers requested!\n", + dev->name); numBuffers = 32; } p = (PU32) kmalloc (sizeof (U32) + numBuffers * sizeof (singleB), - GFP_KERNEL); - - dprintk ("TCB = 0x%x\n", (uint) p); + GFP_DMA|GFP_ATOMIC|GFP_KERNEL); if (!p) { - printk (KERN_WARNING - "(rcpci45 driver:) RCopen: unable to allocate TCB\n"); + printk (KERN_WARNING "%s unable to allocate TCB\n", + dev->name); return 0; } p[0] = 0; /* Buffer Count */ - pB = (psingleB) ((U32) p + sizeof (U32)); /* point to the first buffer */ - - dprintk ("p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint) p[0], (uint) p, - (uint) pB); - dprintk ("pB = 0x%x\n", (uint) pB); + pB = (psingleB) ((U32) p + sizeof (U32));/* point to the first buffer */ for (i = 0; i < numBuffers; i++) { skb = dev_alloc_skb (MAX_ETHER_SIZE + 2); if (!skb) { - dprintk - ("Doh! RCopen: unable to allocate enough skbs!\n"); - if (*p != 0) { /* did we allocate any buffers at all? */ - dprintk ("will post only %d buffers \n", - (uint) (*p)); + printk (KERN_WARNING + "%s: unable to allocate enough skbs!\n", + dev->name); + if (*p != 0) { /* did we allocate any buffers */ break; } else { kfree (p); /* Free the TCB */ return 0; } } - dprintk ("post 0x%x\n", (uint) skb); skb_reserve (skb, 2); /* Align IP on 16 byte boundaries */ pB->context = (U32) skb; pB->scount = 1; /* segment count */ @@ -1185,18 +1040,16 @@ } if ((status = RCPostRecvBuffers (dev, (PRCTCB) p)) != RC_RTN_NO_ERROR) { - printk (KERN_WARNING - "(rcpci45 driver:) Post buffer failed with error code 0x%x!\n", - status); - pB = (psingleB) ((U32) p + sizeof (U32)); /* point to the first buffer */ + printk (KERN_WARNING "%s: Post buffer failed, error 0x%x\n", + dev->name, status); + /* point to the first buffer */ + pB = (psingleB) ((U32) p + sizeof (U32)); while (p[0]) { skb = (struct sk_buff *) pB->context; - dprintk ("freeing 0x%x\n", (uint) skb); dev_kfree_skb (skb); p[0]--; pB++; } - dprintk ("freed all buffers, p[0] = %d\n", (uint) p[0]); } res = p[0]; kfree (p); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/rrunner.c linux-2.5/drivers/net/rrunner.c --- linux-2.5.20/drivers/net/rrunner.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/net/rrunner.c Sun Mar 3 17:54:35 2002 @@ -21,13 +21,15 @@ * ODS/Essential. */ +#include +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #define DEBUG 1 #define RX_DMA_SKBUFF 1 #define PKT_COPY_THRESHOLD 512 -#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/sonic.h linux-2.5/drivers/net/sonic.h --- linux-2.5.20/drivers/net/sonic.h Mon Jun 3 02:44:38 2002 +++ linux-2.5/drivers/net/sonic.h Fri May 3 03:49:07 2002 @@ -87,6 +87,7 @@ #define SONIC_FAET 0x2d #define SONIC_MPT 0x2e +#define SONIC_DCR2 0x3f /* * SONIC command bits diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/sun3_82586.c linux-2.5/drivers/net/sun3_82586.c --- linux-2.5.20/drivers/net/sun3_82586.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/net/sun3_82586.c Fri May 3 03:49:07 2002 @@ -282,11 +282,11 @@ unsigned long ioaddr, iopte; static int found = 0; - /* check that this machine has an onboard lance */ + /* check that this machine has an onboard 82586 */ switch(idprom->id_machtype) { case SM_SUN3|SM_3_160: case SM_SUN3|SM_3_260: - /* these machines have lance */ + /* these machines have 82586 */ break; default: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/sungem.c linux-2.5/drivers/net/sungem.c --- linux-2.5.20/drivers/net/sungem.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/net/sungem.c Fri May 3 03:49:07 2002 @@ -102,11 +102,6 @@ #define GEM_MODULE_NAME "gem" #define PFX GEM_MODULE_NAME ": " -/* Until this gets merged from 2.4.x... */ -#ifndef PCI_DEVICE_ID_APPLE_UNI_N_GMACP -#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024 -#endif - static struct pci_device_id gem_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_GEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, @@ -405,6 +400,10 @@ gp->dev->name, rxmac_stat); if (rxmac_stat & MAC_RXSTAT_OFLW) { + u32 smac = readl(gp->regs + MAC_SMACHINE); + + printk(KERN_ERR "%s: RX MAC fifo overflow smac[%08x].\n", + dev->name, smac); gp->net_stats.rx_over_errors++; gp->net_stats.rx_fifo_errors++; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/tc35815.c linux-2.5/drivers/net/tc35815.c --- linux-2.5.20/drivers/net/tc35815.c Mon Jun 3 02:44:38 2002 +++ linux-2.5/drivers/net/tc35815.c Fri May 17 01:42:48 2002 @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/tlan.c linux-2.5/drivers/net/tlan.c --- linux-2.5.20/drivers/net/tlan.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/net/tlan.c Sat May 25 19:52:04 2002 @@ -166,7 +166,10 @@ * Thanks to Gunnar Eikman *******************************************************************************/ +#include // nuke me later +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/tokenring/madgemc.c linux-2.5/drivers/net/tokenring/madgemc.c --- linux-2.5.20/drivers/net/tokenring/madgemc.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/net/tokenring/madgemc.c Sat Apr 27 00:00:52 2002 @@ -227,16 +227,12 @@ goto getout; } - request_region(dev->base_addr, MADGEMC_IO_EXTENT, "madgemc"); -#if 0 - /* why is this not working? */ - if (request_region(dev->base_addr, MADGEMC_IO_EXTENT, + if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT, "madgemc")) { printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", slot, dev->base_addr); dev->base_addr += MADGEMC_SIF_OFFSET; goto getout; } -#endif dev->base_addr += MADGEMC_SIF_OFFSET; /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/tokenring/tmspci.c linux-2.5/drivers/net/tokenring/tmspci.c --- linux-2.5.20/drivers/net/tokenring/tmspci.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/net/tokenring/tmspci.c Sun Feb 17 23:08:54 2002 @@ -253,7 +253,7 @@ return 0; } -static void __exit tms_pci_rmmod (void) +static void __devexit tms_pci_rmmod (void) { pci_unregister_driver (&tms_pci_driver); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/tulip/ChangeLog linux-2.5/drivers/net/tulip/ChangeLog --- linux-2.5.20/drivers/net/tulip/ChangeLog Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/net/tulip/ChangeLog Sun May 19 16:39:09 2002 @@ -15,17 +15,22 @@ PCI transaction. Fix bugs in tulip MWI config also. +2002-02-07 Uwe Bonnes + + * tulip_core (tulip_pci_tbl[]): + Add PCI id for comet tulip clone. + 2002-01-28 Stefan Rompf , Jeff Garzik - * 21142.c (t21142_timer): Use return value of - tulip_check_duplex() to indicate to system whether or not - carrier is present. Use carrier presence/absence to determine - when next the 21142 media timer should check for link beat. - - * timer (tulip_timer): Un-comment-out calls to - netif_carrier_{on,off}, as there is now value in - reporting link beta information to userspace. + * 21142.c (t21142_timer): Use return value of + tulip_check_duplex() to indicate to system whether or not + carrier is present. Use carrier presence/absence to determine + when next the 21142 media timer should check for link beat. + + * timer (tulip_timer): Un-comment-out calls to + netif_carrier_{on,off}, as there is now value in + reporting link beta information to userspace. 2002-01-28 Pavel Roskin @@ -39,8 +44,22 @@ 2002-02-07 Uwe Bonnes - * tulip_core (tulip_pci_tbl[]): - Add PCI id for comet tulip clone. + * tulip_core (tulip_pci_tbl[]): + Add PCI id for comet tulip clone. + +2001-12-19 John Zielinski + + * tulip_core.c (tulip_up, tulip_init_one): + More places to revert PHY autoconfiguration bit removal. + +2001-12-18 Jeff Garzik + + * tulip.h: revert PHY autoconfiguration bit removal + +2001-12-16 Andrew Lambeth + + * tulip_core.c (tulip_start_xmit): Use the more-portable + spin_lock_irqsave. 2001-12-11 Jeff Garzik diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/tulip/tulip.h linux-2.5/drivers/net/tulip/tulip.h --- linux-2.5.20/drivers/net/tulip/tulip.h Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/net/tulip/tulip.h Thu May 2 23:29:22 2002 @@ -198,8 +198,8 @@ csr13_cac = (1<<2), /* CSR13/14/15 autoconfiguration */ csr13_srl = (1<<0), /* When reset, resets all SIA functions, machines */ - csr13_mask_auibnc = (csr13_eng | csr13_aui | csr13_srl), - csr13_mask_10bt = (csr13_eng | csr13_srl), + csr13_mask_auibnc = (csr13_eng | csr13_aui | csr13_srl | csr13_cac), + csr13_mask_10bt = (csr13_eng | csr13_srl | csr13_cac), }; enum t21143_csr6_bits { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/tulip/tulip_core.c linux-2.5/drivers/net/tulip/tulip_core.c --- linux-2.5.20/drivers/net/tulip/tulip_core.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/net/tulip/tulip_core.c Sun May 19 16:39:09 2002 @@ -2,7 +2,7 @@ /* Maintained by Jeff Garzik - Copyright 2000,2001 The Linux Kernel Team + Copyright 2000-2002 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms @@ -94,6 +94,8 @@ static int csr0 = 0x01A00000 | 0x9000; #elif defined(__arm__) || defined(__sh__) static int csr0 = 0x01A00000 | 0x4800; +#elif defined(__mips__) +static int csr0 = 0x00200000 | 0x4000; #else #warning Processor architecture undefined! static int csr0 = 0x00A00000 | 0x4800; @@ -649,8 +651,9 @@ int entry; u32 flag; dma_addr_t mapping; + unsigned long eflags; - spin_lock_irq(&tp->lock); + spin_lock_irqsave(&tp->lock, eflags); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % TX_RING_SIZE; @@ -685,7 +688,7 @@ /* Trigger an immediate transmit demand. */ outl(0, dev->base_addr + CSR1); - spin_unlock_irq(&tp->lock); + spin_unlock_irqrestore(&tp->lock, eflags); dev->trans_start = jiffies; @@ -1487,6 +1490,16 @@ tp->flags &= ~HAS_MEDIA_TABLE; } #endif +#ifdef CONFIG_MIPS_COBALT + if ((pdev->bus->number == 0) && + ((PCI_SLOT(pdev->devfn) == 7) || + (PCI_SLOT(pdev->devfn) == 12))) { + /* Cobalt MAC address in first EEPROM locations. */ + sa_offset = 0; + /* No media table either */ + tp->flags &= ~HAS_MEDIA_TABLE; + } +#endif for (i = 0; i < 6; i ++) { dev->dev_addr[i] = ee_data[i + sa_offset]; sum += ee_data[i + sa_offset]; @@ -1524,7 +1537,7 @@ #endif #if defined(__i386__) /* Patch up x86 BIOS bug. */ if (last_irq) - irq = last_irq; + dev->irq = last_irq; #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/tulip/winbond-840.c linux-2.5/drivers/net/tulip/winbond-840.c --- linux-2.5.20/drivers/net/tulip/winbond-840.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/net/tulip/winbond-840.c Fri Feb 8 01:55:36 2002 @@ -36,8 +36,10 @@ power management. support for big endian descriptors Copyright (C) 2001 Manfred Spraul - * ethtool support (jgarzik) + * ethtool support (jgarzik) * Replace some MII-related magic numbers with constants (jgarzik) + * OOM handling + Copyright (C) 2002 Manfred Spraul TODO: * enable pci_power_off @@ -341,7 +343,6 @@ DescIntr=0x80000000, }; -#define PRIV_ALIGN 15 /* Required alignment mask */ #define MII_CNT 1 /* winbond only supports one MII */ struct netdev_private { struct w840_rx_desc *rx_ring; @@ -363,6 +364,7 @@ struct w840_rx_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ + int oom; unsigned int cur_tx, dirty_tx; unsigned int tx_q_bytes; unsigned int tx_full; /* The Tx queue is full. */ @@ -378,6 +380,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int netdev_open(struct net_device *dev); static int update_link(struct net_device *dev); +static void refill_rx(struct net_device *dev); static void netdev_timer(unsigned long data); static void init_rxtx_rings(struct net_device *dev); static void free_rxtx_rings(struct netdev_private *np); @@ -828,11 +831,40 @@ np->mii_if.full_duplex = 1; } +static void refill_rx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + /* Refill the Rx ring buffers. */ + np->oom = 0; + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + int entry; + entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_addr[entry] = pci_map_single(np->pci_dev, + skb->tail, + skb->len, PCI_DMA_FROMDEVICE); + np->rx_ring[entry].buffer1 = np->rx_addr[entry]; + } + wmb(); + np->rx_ring[entry].status = DescOwn; + } + if (np->cur_rx-np->dirty_rx == RX_RING_SIZE) + np->oom = 1; +} + static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; + long next = 10*HZ; if (debug > 2) printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " @@ -842,8 +874,16 @@ spin_lock_irq(&np->lock); update_csr6(dev, update_link(dev)); spin_unlock_irq(&np->lock); - np->timer.expires = jiffies + 10*HZ; - add_timer(&np->timer); + if (np->oom) { + disable_irq(dev->irq); + refill_rx(dev); + if (np->oom) + next = 1; + else + writel(0, ioaddr + RxStartDemand); + enable_irq(dev->irq); + } + mod_timer(&np->timer, jiffies + next); } static void init_rxtx_rings(struct net_device *dev) @@ -863,22 +903,9 @@ /* Mark the last entry as wrapping the ring. */ np->rx_ring[i-1].length |= DescEndRing; - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail, - skb->len,PCI_DMA_FROMDEVICE); - - np->rx_ring[i].buffer1 = np->rx_addr[i]; - np->rx_ring[i].status = DescOwn; - } - - np->cur_rx = 0; - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + np->cur_rx = RX_RING_SIZE; + np->dirty_rx = 0; + refill_rx(dev); /* Initialize the Tx descriptors */ for (i = 0; i < TX_RING_SIZE; i++) { @@ -1196,8 +1223,9 @@ if (intr_status & (IntrRxDone | RxNoBuf)) netdev_rx(dev); - if (intr_status & RxNoBuf) - writel(0, ioaddr + RxStartDemand); + /* RxNoBuf is an error interrupt, we kick + * RxStartDemand in netdev_error() + */ if (intr_status & (TxIdle | IntrTxDone) && np->cur_tx != np->dirty_tx) { @@ -1329,25 +1357,7 @@ entry = (++np->cur_rx) % RX_RING_SIZE; np->rx_head_desc = &np->rx_ring[entry]; } - - /* Refill the Rx ring buffers. */ - for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { - struct sk_buff *skb; - entry = np->dirty_rx % RX_RING_SIZE; - if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[entry] = skb; - if (skb == NULL) - break; /* Better luck next round. */ - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[entry] = pci_map_single(np->pci_dev, - skb->tail, - skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[entry].buffer1 = np->rx_addr[entry]; - } - wmb(); - np->rx_ring[entry].status = DescOwn; - } + refill_rx(dev); return 0; } @@ -1391,8 +1401,14 @@ if (netif_device_present(dev)) writel(0x1A0F5, ioaddr + IntrEnable); } + /* strictly only needed with RxNoBuf, but + * kicking too often probably doesn't hurt. + */ + if (np->oom) + mod_timer(&np->timer, jiffies+1); + else + writel(0, ioaddr + RxStartDemand); np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; - writel(0, ioaddr + RxStartDemand); spin_unlock(&np->lock); } @@ -1572,6 +1588,7 @@ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); } + del_timer_sync(&np->timer); /* Stop the chip's Tx and Rx processes. */ spin_lock_irq(&np->lock); netif_device_detach(dev); @@ -1590,10 +1607,10 @@ if (debug > 2) { int i; - printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + printk(KERN_DEBUG" Tx ring at %8.8x:\n", (int)np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) - printk(" #%d desc. %4.4x %4.4x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x.\n", i, np->tx_ring[i].length, np->tx_ring[i].status, np->tx_ring[i].buffer1); printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", @@ -1606,8 +1623,6 @@ } #endif /* __i386__ debugging only */ - del_timer_sync(&np->timer); - free_rxtx_rings(np); free_ringdesc(np); @@ -1693,7 +1708,6 @@ return 0; } - static int w840_resume (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); @@ -1717,8 +1731,7 @@ netif_wake_queue(dev); - np->timer.expires = jiffies + 1*HZ; - add_timer(&np->timer); + mod_timer(&np->timer, jiffies + 1*HZ); } else { netif_device_attach(dev); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/via-rhine.c linux-2.5/drivers/net/via-rhine.c --- linux-2.5.20/drivers/net/via-rhine.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/net/via-rhine.c Sun May 19 16:39:10 2002 @@ -359,9 +359,9 @@ { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, { "VIA VT6105 Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, + CanHaveMII | HasWOL }, { "VIA VT6105M Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, + CanHaveMII | HasWOL }, }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = @@ -369,7 +369,7 @@ {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102}, {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105}, - {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M}, + {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M}, {0,} /* terminate list */ }; MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl); @@ -390,7 +390,7 @@ /* Bits in ConfigD (select backoff algorithm (Ethernet capture effect)) */ enum backoff_bits { - BackOpt=0x01, BackAMD=0x02, BackDEC=0x04, BackRandom=0x08 + BackOpt=0x01, BackAMD=0x02, BackDEC=0x04, BackRandom=0x08 }; #ifdef USE_MEM @@ -980,6 +980,8 @@ writeb(dev->dev_addr[i], ioaddr + StationAddr + i); /* Initialize other registers. */ + + writew(0x0006, ioaddr + PCIBusConfig); /* Store & forward */ /* Configure initial FIFO thresholds. */ writeb(0x20, ioaddr + TxConfig); @@ -1041,7 +1043,7 @@ if (phy_id == np->phys[0]) { switch (regnum) { - case MII_BMCR: /* Is user forcing speed/duplex? */ + case MII_BMCR: /* Is user forcing speed/duplex? */ if (value & 0x9000) /* Autonegotiation. */ np->mii_if.duplex_lock = 0; else diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253x.h linux-2.5/drivers/net/wan/8253x/8253x.h --- linux-2.5.20/drivers/net/wan/8253x/8253x.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253x.h Fri May 3 19:35:14 2002 @@ -0,0 +1,986 @@ +/* -*- linux-c -*- */ +/* $Id: 8253x.h,v 1.14 2002/02/10 22:17:25 martillo Exp $ + * sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * + * Modified Aug 1, 2000 Francois Wautier + * Modified for complete driver Joachim Martillo + */ + +/* Modifications: + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +#ifndef _SAB82532_H +#define _SAB82532_H + +#include +#include +#include /* need struct async_icount for ioctl */ +#include + +#include "8253xioc.h" +#include "ring.h" + +#define SAB8253X_MAX_TEC_DELAY 200000 /* 1 character time (at 50 baud) */ +#define SAB8253X_MAX_CEC_DELAY 50000 /* 2.5 TX CLKs (at 50 baud) */ + +#define SERIAL_TYPE_SYNCTTY 3 /* check tty driver to make sure okay */ + /* SERIAL_TYPE_NORMAL and SERIAL_TYPE_CALLOUT */ + /* seem to be used by the tty driver */ + /* only to print out a warning not to */ + /* use callout devices - next version of */ + /* the code, for now want to be able to */ + /* maintain some of the structure of */ + /* a 2.2.* driver for those that are */ + /* running old kernels. */ + +#define READB(port, rreg) (*port->readbyte)(port,\ + (unsigned char *)&(port->regs->async_read.rreg)) +#define WRITEB(port, rreg, val) (*port->writebyte)(port,\ + (unsigned char *)&(port->regs->async_write.rreg), val) +#ifdef DEFINE_VARIABLE +static unsigned char tmpval; +#endif + /* Used in the macro below -- don't create a variable called tmpval*/ +#define SET_REG_BIT(port,rreg,bit)\ + tmpval=(*port->readbyte)(port,\ + (unsigned char *)&(port->regs->async_read.rreg));\ + tmpval |= bit;\ + (*port->writebyte)(port,\ + (unsigned char *)&(port->regs->async_write.rreg), tmpval); +#define CLEAR_REG_BIT(port,rreg,bit)\ + tmpval=(*port->readbyte)(port,\ + (unsigned char *)&(port->regs->async_read.rreg));\ + tmpval &= ~(bit);\ + (*port->writebyte)(port,\ + (unsigned char *)&(port->regs->async_write.rreg), tmpval); +#define MASK_REG_BIT(port,rreg,bit)\ + tmpval=(*port->readbyte)(port,\ + (unsigned char *)&(port->regs->async_read.rreg));\ + tmpval &= bit;\ + (*port->writebyte)(port,\ + (unsigned char *)&(port->regs->async_write.rreg), tmpval); +#define READ_X_WRITEB(port,rreg,op,val)\ + tmpval=(*port->readbyte)(port,\ + (unsigned char *)&(port->regs->async_read.rreg));\ + tmpval op= val;\ + (*port->writebyte)(port,\ + (unsigned char *)&(port->regs->async_write.rreg), tmpval); + + +struct sab82532_async_rd_regs +{ + volatile unsigned char rfifo[0x20]; /* Receive FIFO */ + volatile unsigned char star; /* Status Register */ + volatile unsigned char rsta; /* actually an HDLC register */ + volatile unsigned char mode; /* Mode Register */ + volatile unsigned char timr; /* Timer Register */ + volatile unsigned char xon; /* XON Character */ + volatile unsigned char xoff; /* XOFF Character */ + volatile unsigned char tcr; /* Termination Character Register */ + volatile unsigned char dafo; /* Data Format */ + volatile unsigned char rfc; /* RFIFO Control Register */ + volatile unsigned char __pad2; + volatile unsigned char rbcl; /* Receive Byte Count Low */ + volatile unsigned char rbch; /* Receive Byte Count High */ + volatile unsigned char ccr0; /* Channel Configuration Register 0 */ + volatile unsigned char ccr1; /* Channel Configuration Register 1 */ + volatile unsigned char ccr2; /* Channel Configuration Register 2 */ + volatile unsigned char ccr3; /* Channel Configuration Register 3 */ + volatile unsigned char __pad3[4]; + volatile unsigned char vstr; /* Version Status Register */ + volatile unsigned char __pad4[3]; + volatile unsigned char gis; /* Global Interrupt Status */ + volatile unsigned char ipc; /* Interrupt Port Configuration */ + volatile unsigned char isr0; /* Interrupt Status 0 */ + volatile unsigned char isr1; /* Interrupt Status 1 */ + volatile unsigned char pvr; /* Port Value Register */ + volatile unsigned char pis; /* Port Interrupt Status */ + volatile unsigned char pcr; /* Port Configuration Register */ + volatile unsigned char ccr4; /* Channel Configuration Register 4 */ +}; + +struct sab82532_async_wr_regs +{ + unsigned char xfifo[0x20]; /* Transmit FIFO */ + unsigned char cmdr; /* Command Register */ + unsigned char __pad1; + unsigned char mode; + unsigned char timr; + unsigned char xon; + unsigned char xoff; + unsigned char tcr; + unsigned char dafo; + unsigned char rfc; + unsigned char __pad2; + unsigned char xbcl; /* Transmit Byte Count Low */ + unsigned char xbch; /* Transmit Byte Count High */ + unsigned char ccr0; + unsigned char ccr1; + unsigned char ccr2; + unsigned char ccr3; + unsigned char tsax; /* Time-Slot Assignment Reg. Transmit */ + unsigned char tsar; /* Time-Slot Assignment Reg. Receive */ + unsigned char xccr; /* Transmit Channel Capacity Register */ + unsigned char rccr; /* Receive Channel Capacity Register */ + unsigned char bgr; /* Baud Rate Generator Register */ + unsigned char tic; /* Transmit Immediate Character */ + unsigned char mxn; /* Mask XON Character */ + unsigned char mxf; /* Mask XOFF Character */ + unsigned char iva; /* Interrupt Vector Address */ + unsigned char ipc; + unsigned char imr0; /* Interrupt Mask Register 0 */ + unsigned char imr1; /* Interrupt Mask Register 1 */ + unsigned char pvr; + unsigned char pim; /* Port Interrupt Mask */ + unsigned char pcr; + unsigned char ccr4; +}; + +struct sab82532_async_rw_regs +{ /* Read/Write registers */ + volatile unsigned char __pad1[0x20]; + volatile unsigned char __pad2; + volatile unsigned char __pad3; + volatile unsigned char mode; + volatile unsigned char timr; + volatile unsigned char xon; + volatile unsigned char xoff; + volatile unsigned char tcr; + volatile unsigned char dafo; + volatile unsigned char rfc; + volatile unsigned char __pad4; + volatile unsigned char __pad5; + volatile unsigned char __pad6; + volatile unsigned char ccr0; + volatile unsigned char ccr1; + volatile unsigned char ccr2; + volatile unsigned char ccr3; + volatile unsigned char __pad7; + volatile unsigned char __pad8; + volatile unsigned char __pad9; + volatile unsigned char __pad10; + volatile unsigned char __pad11; + volatile unsigned char __pad12; + volatile unsigned char __pad13; + volatile unsigned char __pad14; + volatile unsigned char __pad15; + volatile unsigned char ipc; + volatile unsigned char __pad16; + volatile unsigned char __pad17; + volatile unsigned char pvr; + volatile unsigned char __pad18; + volatile unsigned char pcr; + volatile unsigned char ccr4; +}; + +union sab82532_async_regs +{ + __volatile__ struct sab82532_async_rd_regs r; + __volatile__ struct sab82532_async_wr_regs w; + __volatile__ struct sab82532_async_rw_regs rw; +}; + +/* not really used yet */ +struct sab82532_hdlc_rd_regs +{ + volatile unsigned char rfifo[0x20]; /* Receive FIFO */ + volatile unsigned char star; /* Status Register */ + volatile unsigned char rsta; + volatile unsigned char mode; /* Mode Register */ + volatile unsigned char timr; /* Timer Register */ + volatile unsigned char xad1; /* Tx Address High 1 */ + volatile unsigned char xad2; /* Tx Address High 2 */ + volatile unsigned char __pad1[2]; + volatile unsigned char ral1; /* Rx Address Low 1 */ + volatile unsigned char rhcr; /* Received HDLC Control */ + volatile unsigned char rbcl; /* Receive Byte Count Low */ + volatile unsigned char rbch; /* Receive Byte Count High */ + volatile unsigned char ccr0; /* Channel Configuration Register 0 */ + volatile unsigned char ccr1; /* Channel Configuration Register 1 */ + volatile unsigned char ccr2; /* Channel Configuration Register 2 */ + volatile unsigned char ccr3; /* Channel Configuration Register 3 */ + volatile unsigned char __pad2[4]; + volatile unsigned char vstr; /* Version Status Register */ + volatile unsigned char __pad3[3]; + volatile unsigned char gis; /* Global Interrupt Status */ + volatile unsigned char ipc; /* Interrupt Port Configuration */ + volatile unsigned char isr0; /* Interrupt Status 0 */ + volatile unsigned char isr1; /* Interrupt Status 1 */ + volatile unsigned char pvr; /* Port Value Register */ + volatile unsigned char pis; /* Port Interrupt Status */ + volatile unsigned char pcr; /* Port Configuration Register */ + volatile unsigned char ccr4; /* Channel Configuration Register 4 */ +}; + +struct sab82532_hdlc_wr_regs +{ + unsigned char xfifo[0x20]; /* Transmit FIFO */ + unsigned char cmdr; /* Command Register */ + unsigned char pre; /* Preamble */ + unsigned char mode; + unsigned char timr; + unsigned char xad1; /* Tx Address High 1 */ + unsigned char xad2; /* Tx Address High 2 */ + unsigned char rah1; /* Rx Address High 1 */ + unsigned char rah2; /* Rx Address High 2 */ + unsigned char ral1; /* Rx Address Low 1 */ + unsigned char ral2; /* Rx Address Low 2 */ + unsigned char xbcl; /* Transmit Byte Count Low */ + unsigned char xbch; /* Transmit Byte Count High */ + unsigned char ccr0; + unsigned char ccr1; + unsigned char ccr2; + unsigned char ccr3; + unsigned char tsax; /* Time-Slot Assignment Reg. Transmit */ + unsigned char tsar; /* Time-Slot Assignment Reg. Receive */ + unsigned char xccr; /* Transmit Channel Capacity Register */ + unsigned char rccr; /* Receive Channel Capacity Register */ + unsigned char bgr; /* Baud Rate Generator Register */ + unsigned char rlcr; /* Rx Frame Length Check */ + unsigned char aml; /* Address Mask Low */ + unsigned char amh; /* Address Mask High */ + unsigned char iva; /* Interrupt Vector Address */ + unsigned char ipc; + unsigned char imr0; /* Interrupt Mask Register 0 */ + unsigned char imr1; /* Interrupt Mask Register 1 */ + unsigned char pvr; + unsigned char pim; /* Port Interrupt Mask */ + unsigned char pcr; + unsigned char ccr4; +}; + +union sab82532_regs +{ + __volatile__ struct sab82532_async_rd_regs async_read; + __volatile__ struct sab82532_async_wr_regs async_write; + __volatile__ struct sab82532_hdlc_rd_regs hdlc_read; + __volatile__ struct sab82532_hdlc_wr_regs hdlc_write; +}; + +/* + * Modem signal definition + */ + +typedef struct mctlsig +{ + unsigned char *reg; /* chip register offset */ + unsigned char inverted; /* interpret the results as inverted */ + unsigned char mask; /* bit within that register */ + unsigned char val; /* cached value */ + unsigned int irq; /* address of correct isr register */ + unsigned char irqmask; /* */ + unsigned char cnst; /* A value that should always be set for + * this signal register */ +} mctlsig_t, MCTLSIG; + +union sab8253x_irq_status +{ + unsigned int stat; + unsigned char images[4]; + struct + { + unsigned char isr0; + unsigned char isr1; + unsigned char pis; + } sreg; +}; + /* the following are deprecated */ + /* older version of structure above */ + /* used array*/ +#define ISR0_IDX 0 +#define ISR1_IDX 1 +#define PIS_IDX 2 + +/* + * Each port has a structure like this associated to it. + * All the port are linked with the next fields + * All the port of one chip are linked with the next_by_chip + */ + +#define FUNCTION_NR 0 +#define FUNCTION_AO 1 +#define FUNCTION_NA 2 +#define FUNCTION_UN 3 + +typedef struct sab_port +{ + int magic; + union sab82532_regs *regs; + struct sab_chip *chip; + struct sab_board *board; + struct tty_struct *tty; + unsigned char *xmit_buf; + int xmit_head; /* put characters on write */ + int xmit_tail; /* read from here -- in writeb or writefifo */ + int xmit_cnt; + + /* + * Various linked list pertinent to this link + */ + struct sab_port * next; + struct sab_port * next_by_chip; + struct sab_port * next_by_board; + struct sab_port * next_by_cim; + + struct net_device *dev; + struct net_device *next_dev; + + struct fasync_struct * async_queue; + struct sk_buff_head *sab8253xbuflist; /* need to keep */ + /* a list of all */ + /* skbuffs so that */ + /* we can guarantee */ + /* freeing all when */ + /* the PPC is stopped */ + /* on close*/ + struct sk_buff_head *sab8253xc_rcvbuflist; /* used for passing */ + /* buffers from interrupt */ + /* receive process*/ + + + DCONTROL2 dcontrol2; + DCONTROL2 active2; + DCONTROL2 sabnext2; + + int DoingInterrupt; + int irq; + int flags; /* suggested by serial.h + * but this driver is + * more general */ + int syncflags; + int type; /* SAB82532/8 version */ + unsigned int function; + int read_status_mask; + int ignore_status_mask; + int timeout; + int xmit_fifo_size; + int recv_fifo_size; + int custom_divisor; + unsigned long baud; + unsigned int ebrg; + unsigned int cec_timeout; + unsigned int tec_timeout; + + int x_char; + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + int all_sent; + int is_console; +#define OPEN_NOT 0 +#define OPEN_ASYNC 1 +#define OPEN_SYNC 2 +#define OPEN_BSC 3 +#define OPEN_RAW 4 +#define OPEN_SYNC_NET 5 +#define OPEN_SYNC_CHAR 6 + unsigned int open_type; /* Sync? Async?, int better for hw bps */ + unsigned char interrupt_mask0; + unsigned char interrupt_mask1; + /* Modem signals */ + mctlsig_t dtr; + mctlsig_t dsr; + mctlsig_t dcd; + mctlsig_t cts; + mctlsig_t rts; + mctlsig_t txclkdir; /* Direction of TxClk */ + unsigned long custspeed; /* Custom speed */ + unsigned long event; + unsigned long last_active; + int line; + int count; + int blocked_open; + long session; + long pgrp; + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + struct async_icount icount; + struct termios normal_termios; + struct termios callout_termios; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + wait_queue_head_t delta_msr_wait; + wait_queue_head_t read_wait; + wait_queue_head_t write_wait; + + /* + * Pointer to FIFO access routines. These are individualized + * by hardware because different hardware may have different + * ways to get to the FIFOs. + */ + + void (*readfifo)(struct sab_port *port, + unsigned char *buf, + u32 nbytes); + void (*writefifo)(struct sab_port *port); + + /* + * Pointer to register access routines. These are individualized + * by hardware because different hardware may have different + * ways to get to the register. + */ + unsigned char (*readbyte)(struct sab_port *port, + unsigned char *reg); + void (*writebyte)(struct sab_port *port, + unsigned char *reg, + unsigned char val); + u16 (*readword)(struct sab_port *port, + u16 *reg); + void (*writeword)(struct sab_port *port, + u16 *reg, + u16 val); + + /* + * Pointer to protocol functions + * + */ + + unsigned int portno; + void (*receive_chars)(struct sab_port *port, + union sab8253x_irq_status *stat); + void (*transmit_chars)(struct sab_port *port, + union sab8253x_irq_status *stat); + void (*check_status)(struct sab_port *port, + union sab8253x_irq_status *stat); + unsigned int receive_test; + unsigned int transmit_test; + unsigned int check_status_test; + struct channelcontrol ccontrol; + + unsigned int tx_full; + unsigned int rx_empty; + struct counters Counters; + struct net_device_stats stats; + + /* collect statistics for netstat */ + /* etc. those programs don't know */ + /* about priorities*/ + + int msgbufindex; + char msgbuf[RXSIZE]; + unsigned int buffergreedy; + unsigned int sigmode; +} sab_port_t, SAB_PORT; + +/* + * per-parallel port structure + */ + +/* SAB82538 4 8-bits parallel ports + * To summarize the use of the parallel port: + * RS-232 + * Parallel port A -- TxClkdir control (output) ports 0 - 7 + * Parallel port B -- DTR (output) ports 0 - 7 + * Parallel port C -- DSR (input) ports 0 - 7 + * Parallel port D -- driver power down (output) drivers 0 - 3 + * + * SAB82532 (Aurora) 1 8-bit parallel port + * To summarize the use of the parallel port: + * RS-232 + * A B I/O descr + * P0 P4 output TxClk ctrl + * P1 P5 output DTR + * P2 P6 input DSR + * P3 P7 output 485 control + * + * Note that this new version of the driver + * does not support the SPARC motherboard ESCC2 + * + * SAB82532 (Sun) 1 8-bit parallel port + * To summarize the use of the parallel port: + * RS-232 + * A B I/O descr + * P0 P3 input DSR + * P1 P2 output DTR + * P5 P6 input ? + * P4 P7 output ? + * + */ + /* not sure how usefule */ +typedef struct sabparport +{ + /* cached values: */ + unsigned char pp_pcr; + unsigned char pp_pim; + unsigned char pp_pvr; + + /* register offsets: */ + unsigned int pp_pcrreg; + unsigned int pp_pimreg; + unsigned int pp_pisreg; + unsigned int pp_pvrreg; +} sabparport_t, SABPARPORT; + +#define ESCC2 2 +#define ESCC8 8 + +/* + * Per-chip structure + */ + + +typedef struct sab_chip +{ + unsigned int chip_type; + struct sab_board *c_board; /* Parent board */ + struct aura_cim *c_cim; /* if present */ + unsigned char c_chipno; /* chip number */ + unsigned char c_revision; /* the revision code from the VSTR */ + unsigned char c_nports; /* number of ports per chip */ + void *c_regs; /* base address for chip registers */ + struct sab_port *c_portbase; + struct sab_chip *next; /* the next chip in the chip chain */ + struct sab_chip *next_by_board; /* the next chip on the board */ + struct sab_chip *next_by_cim; + void (*int_disable)(struct sab_chip* chip); +} sab_chip_t, SAB_CHIP; + + +/* Some useful facts */ +#define SAB82532_REG_SIZE 0x40 +#define SAB82538_REG_SIZE 0x40 + +/* RFIFO Status Byte */ +#define SAB82532_RSTAT_PE 0x80 +#define SAB82532_RSTAT_FE 0x40 +#define SAB82532_RSTAT_PARITY 0x01 + +/* Status Register (STAR) */ +#define SAB82532_STAR_XDOV 0x80 +#define SAB82532_STAR_XFW 0x40 +#define SAB82532_STAR_RFNE 0x20 +#define SAB82532_STAR_FCS 0x10 +#define SAB82532_STAR_TEC 0x08 +#define SAB82532_STAR_RLI 0x08 +#define SAB82532_STAR_CEC 0x04 +#define SAB82532_STAR_CTS 0x02 + +/* Command Register (CMDR) */ +#define SAB82532_CMDR_RMC 0x80 +#define SAB82532_CMDR_RRES 0x40 +#define SAB82532_CMDR_RHR 0x40 +#define SAB82532_CMDR_RFRD 0x20 +#define SAB82532_CMDR_STI 0x10 +#define SAB82532_CMDR_XF 0x08 +#define SAB82532_CMDR_XTF 0x08 +#define SAB82532_CMDR_XME 0x02 +#define SAB82532_CMDR_XRES 0x01 + + /* leaving them for reference */ + /* they are now defined in 8253xioc.h*/ +#if 0 +/* Mode Register (MODE) */ +#define SAB82532_MODE_TM0 0x80 +#define SAB82532_MODE_FRTS 0x40 +#define SAB82532_MODE_FCTS 0x20 +#define SAB82532_MODE_FLON 0x10 +#define SAB82532_MODE_TCPU 0x10 +#define SAB82532_MODE_RAC 0x08 +#define SAB82532_MODE_RTS 0x04 +#define SAB82532_MODE_TRS 0x02 +#define SAB82532_MODE_TLP 0x01 +#endif + +/* Receive Status Register (READ) */ +#define SAB82532_RSTA_VFR 0x80 +#define SAB82532_RSTA_RDO 0x40 +#define SAB82532_RSTA_CRC 0x20 +#define SAB82532_RSTA_RAB 0x10 + +/* Timer Register (TIMR) */ +#define SAB82532_TIMR_CNT_MASK 0xe0 +#define SAB82532_TIMR_VALUE_MASK 0x1f + +/* Data Format (DAFO) */ +#define SAB82532_DAFO_XBRK 0x40 +#define SAB82532_DAFO_STOP 0x20 +#define SAB82532_DAFO_PAR_SPACE 0x00 +#define SAB82532_DAFO_PAR_ODD 0x08 +#define SAB82532_DAFO_PAR_EVEN 0x10 +#define SAB82532_DAFO_PAR_MARK 0x18 +#define SAB82532_DAFO_PARE 0x04 +#define SAB82532_DAFO_CHL8 0x00 +#define SAB82532_DAFO_CHL7 0x01 +#define SAB82532_DAFO_CHL6 0x02 +#define SAB82532_DAFO_CHL5 0x03 + +/* RFIFO Control Register (RFC) */ +#define SAB82532_RFC_DPS 0x40 +#define SAB82532_RFC_DXS 0x20 +#define SAB82532_RFC_RFDF 0x10 +#define SAB82532_RFC_RFTH_1 0x00 +#define SAB82532_RFC_RFTH_4 0x04 +#define SAB82532_RFC_RFTH_16 0x08 +#define SAB82532_RFC_RFTH_32 0x0c +#define SAB82532_RFC_TCDE 0x01 + +/* Received Byte Count High (RBCH) */ +#define SAB82532_RBCH_DMA 0x80 +#define SAB82532_RBCH_CAS 0x20 +#define SAB82532_RBCH_OV 0x10 +#define SAB82532_RBCH_HMSK 0x0F + +/* Transmit Byte Count High (XBCH) */ +#define SAB82532_XBCH_DMA 0x80 +#define SAB82532_XBCH_CAS 0x20 +#define SAB82532_XBCH_XC 0x10 + + /* leaving them for reference */ + /* they are now defined in 8253xioc.h*/ +#if 0 +/* Channel Configuration Register 0 (CCR0) */ +#define SAB82532_CCR0_PU 0x80 +#define SAB82532_CCR0_MCE 0x40 +#define SAB82532_CCR0_SC_NRZ 0x00 +#define SAB82532_CCR0_SC_NRZI 0x08 +#define SAB82532_CCR0_SC_FM0 0x10 +#define SAB82532_CCR0_SC_FM1 0x14 +#define SAB82532_CCR0_SC_MANCH 0x18 +#define SAB82532_CCR0_SM_HDLC 0x00 +#define SAB82532_CCR0_SM_SDLC_LOOP 0x01 +#define SAB82532_CCR0_SM_BISYNC 0x02 +#define SAB82532_CCR0_SM_ASYNC 0x03 + +/* Channel Configuration Register 1 (CCR1) */ +#define SAB82532_CCR1_SFLG 0x80 +#define SAB82532_CCR1_ODS 0x10 +#define SAB82532_CCR1_BCR 0x08 +#define SAB82532_CCR1_IFF 0x08 +#define SAB82532_CCR1_ITF 0x00 +#define SAB82532_CCR1_CM_MASK 0x07 + +/* Channel Configuration Register 2 (CCR2) */ +#define SAB82532_CCR2_SOC1 0x80 +#define SAB82532_CCR2_SOC0 0x40 +#define SAB82532_CCR2_BR9 0x80 +#define SAB82532_CCR2_BR8 0x40 +#define SAB82532_CCR2_BDF 0x20 +#define SAB82532_CCR2_SSEL 0x10 +#define SAB82532_CCR2_XCS0 0x20 +#define SAB82532_CCR2_RCS0 0x10 +#define SAB82532_CCR2_TOE 0x08 +#define SAB82532_CCR2_RWX 0x04 +#define SAB82532_CCR2_C32 0x02 +#define SAB82532_CCR2_DIV 0x01 + +/* Channel Configuration Register 3 (CCR3) */ +#define SAB82532_CCR3_PSD 0x01 +#define SAB82532_CCR3_RCRC 0x04 +#endif + +/* Time Slot Assignment Register Transmit (TSAX) */ +#define SAB82532_TSAX_TSNX_MASK 0xfc +#define SAB82532_TSAX_XCS2 0x02 /* see also CCR2 */ +#define SAB82532_TSAX_XCS1 0x01 + +/* Time Slot Assignment Register Receive (TSAR) */ +#define SAB82532_TSAR_TSNR_MASK 0xfc +#define SAB82532_TSAR_RCS2 0x02 /* see also CCR2 */ +#define SAB82532_TSAR_RCS1 0x01 + +/* Version Status Register (VSTR) */ +#define SAB85232_REG_VSTR 0x34 +#define SAB82532_VSTR_CD 0x80 +#define SAB82532_VSTR_DPLA 0x40 +#define SAB82532_VSTR_VN_MASK 0x0f +#define SAB82532_VSTR_VN_1 0x00 +#define SAB82532_VSTR_VN_2 0x01 +#define SAB82532_VSTR_VN_3_2 0x02 + +/* Global Interrupt Status Register (GIS) */ +#define SAB82532_GIS_PI 0x80 +#define SAB82532_GIS_ISA1 0x08 +#define SAB82532_GIS_ISA0 0x04 +#define SAB82532_GIS_ISB1 0x02 +#define SAB82532_GIS_ISB0 0x01 +#define SAB82532_GIS_MASK 0x8f +#define SAB82538_GIS_PIA 0x80 +#define SAB82538_GIS_PIB 0x40 +#define SAB82538_GIS_PIC 0x20 +#define SAB82538_GIS_PID 0x10 +#define SAB82538_GIS_CII 0x08 +#define SAB82538_GIS_CHNL_MASK 0x07 +#define SAB82538_GIS_MASK 0x28 /* Port C and CII ! */ + +/* Interrupt Vector Address (IVA) */ +#define SAB82532_REG_IVA 0x38 +#define SAB82532_IVA_MASK 0xf1 +#define SAB82538_IVA_ROT 0x02 + +/* Interrupt Port Configuration (IPC) */ +#define SAB82532_REG_IPC 0x39 +#define SAB82532_IPC_VIS 0x80 +#define SAB82532_IPC_SLA1 0x10 +#define SAB82532_IPC_SLA0 0x08 +#define SAB82532_IPC_CASM 0x04 +#define SAB82532_IPC_IC_OPEN_DRAIN 0x00 +#define SAB82532_IPC_IC_ACT_LOW 0x01 +#define SAB82532_IPC_IC_ACT_HIGH 0x03 + +/* Interrupt Status Register 0 (ISR0) */ +#define SAB82532_ISR0_TCD 0x80 +#define SAB82532_ISR0_RME 0x80 +#define SAB82532_ISR0_TIME 0x40 +#define SAB82532_ISR0_RFS 0x40 +#define SAB82532_ISR0_PERR 0x20 +#define SAB82532_ISR0_FERR 0x10 +#define SAB82532_ISR0_PLLA 0x08 +#define SAB82532_ISR0_CDSC 0x04 +#define SAB82532_ISR0_RFO 0x02 +#define SAB82532_ISR0_RPF 0x01 + +/* Interrupt Status Register 1 (ISR1) */ +#define SAB82532_ISR1_BRK 0x80 +#define SAB82532_ISR1_BRKT 0x40 +#define SAB82532_ISR1_RDO 0x40 +#define SAB82532_ISR1_ALLS 0x20 +#define SAB82532_ISR1_XOFF 0x10 +#define SAB82532_ISR1_XDU 0x10 +#define SAB82532_ISR1_TIN 0x08 +#define SAB82532_ISR1_CSC 0x04 +#define SAB82532_ISR1_XON 0x02 +#define SAB82532_ISR1_XPR 0x01 + +/* Interrupt Mask Register 0 (IMR0) */ +#define SAB82532_IMR0_TCD 0x80 +#define SAB82532_IMR0_RME 0x80 +#define SAB82532_IMR0_TIME 0x40 +#define SAB82532_IMR0_RFS 0x40 +#define SAB82532_IMR0_PERR 0x20 +#define SAB82532_IMR0_RSC 0x20 +#define SAB82532_IMR0_FERR 0x10 +#define SAB82532_IMR0_PCE 0x10 +#define SAB82532_IMR0_PLLA 0x08 +#define SAB82532_IMR0_CDSC 0x04 +#define SAB82532_IMR0_RFO 0x02 +#define SAB82532_IMR0_RPF 0x01 + +/* Interrupt Mask Register 1 (IMR1) */ +#define SAB82532_IMR1_BRK 0x80 +#define SAB82532_IMR1_EOP 0x80 +#define SAB82532_IMR1_BRKT 0x40 +#define SAB82532_IMR1_RDO 0x40 +#define SAB82532_IMR1_ALLS 0x20 +#define SAB82532_IMR1_XOFF 0x10 +#define SAB82532_IMR1_EXE 0x10 +#define SAB82532_IMR1_TIN 0x08 +#define SAB82532_IMR1_CSC 0x04 +#define SAB82532_IMR1_XON 0x02 +#define SAB82532_IMR1_XMR 0x02 +#define SAB82532_IMR1_XPR 0x01 + +/* Port Value Register (PVR) */ +#define SAB82532_REG_PVR 0x3c +#define SAB82538_REG_PVR_A 0x3c +#define SAB82538_REG_PVR_B 0xbc +#define SAB82538_REG_PVR_C 0x13c +#define SAB82538_REG_PVR_D 0x1bc + +/* Port Value Register (PIM) */ +#define SAB82532_REG_PIM 0x3d +#define SAB82538_REG_PIM_A 0x3d +#define SAB82538_REG_PIM_B 0xbd +#define SAB82538_REG_PIM_C 0x13d +#define SAB82538_REG_PIM_D 0x1bd +/* Port Value Register (PIS) */ +#define SAB82532_REG_PIS 0x3d +#define SAB82538_REG_PIS_A 0x3d +#define SAB82538_REG_PIS_B 0xbd +#define SAB82538_REG_PIS_C 0x13d +#define SAB82538_REG_PIS_D 0x1bd + +/* Port Value Register (PCR) */ +#define SAB82532_REG_PCR 0x3e +#define SAB82538_REG_PCR_A 0x3e +#define SAB82538_REG_PCR_B 0xbe +#define SAB82538_REG_PCR_C 0x13e +#define SAB82538_REG_PCR_D 0x1be + + /* leaving them for reference */ + /* they are now defined in 8253xioc.h*/ + +#if 0 +/* Channel Configuration Register 4 (CCR4) */ +#define SAB82532_CCR4_MCK4 0x80/* needs to be set when board clock */ + /* over 10 Mhz (?)*/ +#define SAB82532_CCR4_EBRG 0x40 +#define SAB82532_CCR4_TST1 0x20 +#define SAB82532_CCR4_ICD 0x10 +#endif + + +/* Port Interrupt Status Register (PIS) */ +#define SAB82532_PIS_SYNC_B 0x08 +#define SAB82532_PIS_DTR_B 0x04 +#define SAB82532_PIS_DTR_A 0x02 +#define SAB82532_PIS_SYNC_A 0x01 + + +/* More things useful */ +#define SAB_MAGIC 5977 + +/* When computing the baudrate, we "encode" it by multiplying + * the actual baudrate by 2. This way we can use 134.5 + */ +#define ENCODEBR(x) ((x)<<1) + +/* + * Raise a modem signal y on port x, tmpval must exist! */ +#define RAISE(xx,y) \ +{ \ + unsigned char __tmpval__; \ + __tmpval__= (xx)->readbyte((xx),(xx)->y.reg);\ + if((xx)->y.inverted)\ + __tmpval__ &= ~((xx)->y.mask);\ + else\ + __tmpval__ |= (xx)->y.mask;\ + __tmpval__ |= (xx)->y.cnst;\ + (xx)->y.val=1;\ + (xx)->writebyte((xx),(xx)->y.reg,__tmpval__);\ +} +/* + * Lower a modem signal y on port x, __tmpval__ must exist! */ +#define LOWER(xx,y) \ +{\ + unsigned char __tmpval__; \ + __tmpval__= (xx)->readbyte((xx),(xx)->y.reg);\ + if((xx)->y.inverted)\ + __tmpval__ |= (xx)->y.mask;\ + else\ + __tmpval__ &= ~((xx)->y.mask);\ + __tmpval__ |= (xx)->y.cnst;\ + (xx)->y.val=0;\ + (xx)->writebyte((xx),(xx)->y.reg,__tmpval__);\ +} + +#define ISON(xx,y) \ + ((xx)->y.inverted != (((xx)->readbyte((xx),(xx)->y.reg)&(xx)->y.mask) ==(xx)->y.mask) ) +/* + * Now let's define all those functions we need else where. + * + * This should probably be reorganized + */ +extern void sab8253x_setup_ttydriver(void); +extern int finish_sab8253x_setup_ttydriver(void); +extern void sab8253x_setup_ttyport(struct sab_port *port); +extern void sab8253x_cleanup_ttydriver(void); +extern void sab8253x_start_txS(struct sab_port *port); + +static int inline sab8253x_serial_paranoia_check(struct sab_port *port, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null sab8253x for (%s) in %s\n"; + + if (!port) + { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (port->magic != SAB_MAGIC) + { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +static void inline sab8253x_cec_wait(struct sab_port *port) +{ + int timeout = port->cec_timeout; + +#if 1 /* seems to work for 82532s */ + while ((READB(port, star) & SAB82532_STAR_CEC) && --timeout) + { + udelay(1); + } +#else + if (READB(port,star) & SAB82532_STAR_CEC) + { + udelay(1); + } +#endif +} + +extern void sab8253x_transmit_charsS(struct sab_port *port, union sab8253x_irq_status *stat); +extern void sab8253x_flush_charsS(struct tty_struct *tty); +extern void sab8253x_set_termiosS(struct tty_struct *tty, struct termios *old_termios); +extern void sab8253x_stopS(struct tty_struct *tty); +extern void sab8253x_startS(struct tty_struct *tty); +extern void sab8253x_send_xcharS(struct tty_struct *tty, char ch); +extern void sab8253x_transmit_charsN(struct sab_port *port, + union sab8253x_irq_status *stat); +extern SAB_PORT *AuraPortRoot; + +#define MAX_SAB8253X_RCV_QUEUE_LEN 50 + +struct ebrg_struct +{ + int baud; + int n; + int m; +}; + +extern task_queue tq_8253x_serial; + +extern int sab8253x_openS(struct tty_struct *tty, struct file * filp); +extern void sab8253x_closeS(struct tty_struct *tty, struct file * filp); +extern int sab8253x_writeS(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count); +extern void sab8253x_throttleS(struct tty_struct * tty); +extern void sab8253x_unthrottleS(struct tty_struct * tty); +extern void sab8253x_hangupS(struct tty_struct *tty); +extern void sab8253x_breakS(struct tty_struct *tty, int break_state); +extern void Sab8253xCleanUpTransceiveN(SAB_PORT* priv); + + /* used for running routines in the */ + /* soft int part of the driver */ + /* at one time the flip buffer routines */ + /* seem to have been too time consuming */ + /* to invoke in the hardware interrupt */ + /* routing -- I am not so sure there is */ + /* a problem with modern processor and */ + /* memory speeds, but maybe there is a */ + /* requirement that certain tty routines */ + /* not be executed with ints turned off.*/ + +static void inline sab8253x_sched_event(struct sab_port *port, int event) +{ + port->event |= 1 << event; + queue_task(&port->tqueue, &tq_8253x_serial); + mark_bh(AURORA_BH); +} + +extern unsigned int +sab8253x_baud(sab_port_t *port, unsigned long encbaud, + unsigned char *bgr, unsigned char *ccr2, + unsigned char *ccr4, unsigned long *truebaudp); +extern void Sab8253xFreeAllReceiveListSKBUFFS(SAB_PORT* priv); +extern int Sab8253xSetUpLists(SAB_PORT *priv); +extern int Sab8253xCountTransmitDescriptors(SAB_PORT *port); +extern int Sab8253xCountTransmit(SAB_PORT *port); +extern void sab8253x_init_lineS(struct sab_port *port); +extern void sab8253x_init_lineS(struct sab_port *port); +extern int getccr2configS(struct sab_port *port); +extern void sab8253x_change_speedN(struct sab_port *port); +extern void sab8253x_shutdownN(struct sab_port *port); +extern int sab8253x_startupN(struct sab_port *port); +extern int sab8253x_block_til_ready(struct tty_struct *tty, struct file * filp, + struct sab_port *port); +extern void sab8253x_wait_until_sent(struct tty_struct *tty, int timeout); +extern void sab8253x_flush_buffer(struct tty_struct *tty); +extern void aura_sp502_program(SAB_PORT *port, unsigned int index); +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xchr.c linux-2.5/drivers/net/wan/8253x/8253xchr.c --- linux-2.5.20/drivers/net/wan/8253x/8253xchr.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xchr.c Fri May 3 19:38:48 2002 @@ -0,0 +1,760 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Reg9050.h" +#include "8253xctl.h" +#include "ring.h" +#include "8253x.h" +#include "crc32dcl.h" + +/* a raw character driver -- theoretically for implementing custom protocols, + * async interrupts can be used for getting indication that a packet has + * been successfully transmitted. + */ + + + /* the application read routine, can block according */ + /* to flag, returns one packet at a time */ +int sab8253xc_read(struct file *filep, char *cptr, size_t cnt, loff_t *loffp) +{ + unsigned int length; + unsigned long flags; + SAB_PORT *port = filep->private_data; + struct sk_buff *skb; + + DEBUGPRINT((KERN_ALERT "Attempting to read %i bytes.\n", cnt)); + + + if(port->sab8253xc_rcvbuflist == NULL) + { + return -ENOMEM; + } + + save_flags(flags); cli(); + if(skb_queue_len(port->sab8253xc_rcvbuflist) == 0) + { + port->rx_empty = 1; + if(filep->f_flags & O_NONBLOCK) + { + restore_flags(flags); + return -EAGAIN; + } + restore_flags(flags); + interruptible_sleep_on(&port->read_wait); + } + else + { + restore_flags(flags); + } + + skb = skb_peek(port->sab8253xc_rcvbuflist); + length = skb->tail - skb->data; + if(cnt < length) + { + return -ENOMEM; + } + + skb = skb_dequeue(port->sab8253xc_rcvbuflist); + + save_flags(flags); cli(); + if(skb_queue_len(port->sab8253xc_rcvbuflist) <= 0) + { + port->rx_empty = 1; + } + restore_flags(flags); + + DEBUGPRINT((KERN_ALERT "Copying to user space %s.\n", skb->data)); + copy_to_user(cptr, skb->data, length); + dev_kfree_skb_any(skb); + return length; +} + +/* application write */ + +int sab8253xc_write(struct file *filep, const char *cptr, size_t cnt, loff_t *loffp) +{ + struct sk_buff *skb; + unsigned long flags; + SAB_PORT *port = filep->private_data; + + if(cnt > sab8253xc_rbufsize) /* should not send bigger than can be received */ + { + return -ENOMEM; + } + + if(port->active2.transmit == NULL) + { + return -ENOMEM; + } + + save_flags(flags); cli(); /* can block on write when */ + /* no space in transmit circular */ + /* array. */ + if((port->active2.transmit->Count & OWNER) == OWN_SAB) + { + ++(port->Counters.tx_drops); + port->tx_full = 1; + restore_flags(flags); + if(filep->f_flags & O_NONBLOCK) + { + return -EAGAIN; + } + interruptible_sleep_on(&port->write_wait); + } + else + { + restore_flags(flags); + } + +#ifndef FREEINTERRUPT + if((port->active2.transmit->HostVaddr != NULL) || /* not OWN_SAB from above */ + (port->active2.transmit->crcindex != 0)) + { + register RING_DESCRIPTOR *freeme; + + freeme = port->active2.transmit; + do + { + if((freeme->crcindex == 0) && (freeme->HostVaddr == NULL)) + { + break; + } + if(freeme->HostVaddr) + { + skb_unlink((struct sk_buff*)freeme->HostVaddr); + dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr); + freeme->HostVaddr = NULL; + } + freeme->sendcrc = 0; + freeme->crcindex = 0; + freeme = (RING_DESCRIPTOR*) freeme->VNext; + } + while((freeme->Count & OWNER) != OWN_SAB); + } +#endif + + skb = alloc_skb(cnt, GFP_KERNEL); /* not called from int as with tty */ + if(skb == NULL) + { + return -ENOMEM; + } + copy_from_user(skb->data, cptr, cnt); + skb->tail = (skb->data + cnt); + skb->len = cnt; + skb->data_len = cnt; + + skb_queue_head(port->sab8253xbuflist, skb); + port->active2.transmit->HostVaddr = skb; + port->active2.transmit->sendcrc = 0; + port->active2.transmit->crcindex = 0; + port->active2.transmit->Count = (OWN_SAB|cnt); /* must be this order */ + port->active2.transmit = + (RING_DESCRIPTOR*) port->active2.transmit->VNext; + port->Counters.transmitbytes += cnt; + sab8253x_start_txS(port); + return cnt; +} + +static void sab8253x_receive_charsC(struct sab_port *port, + union sab8253x_irq_status *stat) +{ + unsigned char buf[32]; + int free_fifo = 0; + int reset_fifo = 0; + int msg_done = 0; + int msg_bad = 0; + int count = 0; + int total_size = 0; + int rstatus = 0; + struct sk_buff *skb; + + /* Read number of BYTES (Character + Status) available. */ + + if((stat->images[ISR1_IDX] & SAB82532_ISR1_RDO) || (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) ) + { + ++msg_bad; + ++free_fifo; + ++reset_fifo; + } + else + { + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RPF) + { + count = port->recv_fifo_size; + ++free_fifo; + } + + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RME) + { + count = READB(port, rbcl); + count &= (port->recv_fifo_size - 1); + ++msg_done; + ++free_fifo; + + total_size = READB(port, rbch); + if(total_size & SAB82532_RBCH_OV) /* need to revisit for 4096 byte frames */ + { + msg_bad++; + } + + rstatus = READB(port, rsta); + if((rstatus & SAB82532_RSTA_VFR) == 0) + { + msg_bad++; + } + if(rstatus & SAB82532_RSTA_RDO) + { + msg_bad++; + } + if((rstatus & SAB82532_RSTA_CRC) == 0) + { + msg_bad++; + } + if(rstatus & SAB82532_RSTA_RAB) + { + msg_bad++; + } + } + } + + /* Read the FIFO. */ + + (*port->readfifo)(port, buf, count); + + + /* Issue Receive Message Complete command. */ + + if (free_fifo) + { + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_RMC); + } + + if(reset_fifo) + { + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_RHR); + } + + if(msg_bad) + { + port->msgbufindex = 0; + return; + } + + memcpy(&port->msgbuf[port->msgbufindex], buf, count); + port->msgbufindex += count; + + if(msg_done) + { + + if(port->msgbufindex <= 3) /* min is 1 char + 2 CRC + status byte */ + { + port->msgbufindex = 0; + return; + } + + total_size = port->msgbufindex - 3; /* strip off the crc16 and the status byte */ + port->msgbufindex = 0; + + /* ignore the receive buffer waiting -- we know the correct size here */ + + if(skb = dev_alloc_skb(total_size), skb) + { + memcpy(skb->data, &port->msgbuf[0], total_size); + skb->tail = (skb->data + total_size); + skb->data_len = total_size; + skb->len = total_size; + skb_queue_tail(port->sab8253xc_rcvbuflist, skb); + if(port->rx_empty) + { + port->rx_empty = 0; + wake_up_interruptible(&port->read_wait); + } + if(port->async_queue) + { + kill_fasync(&port->async_queue, SIGIO, POLL_IN); + } + } + } +} + +static void sab8253x_check_statusC(struct sab_port *port, + union sab8253x_irq_status *stat) +{ + int modem_change = 0; + mctlsig_t *sig; + + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) + { + port->icount.buf_overrun++; + } + + /* Checking DCD */ + sig = &port->dcd; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,dcd); + port->icount.dcd++; + modem_change++; + } + /* Checking CTS */ + sig = &port->cts; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,cts); + port->icount.cts++; + modem_change++; + } + /* Checking DSR */ + sig = &port->dsr; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,dsr); + port->icount.dsr++; + modem_change++; + } + if (modem_change) + { + wake_up_interruptible(&port->delta_msr_wait); + } + + sig = &port->dcd; + if ((port->flags & FLAG8253X_CHECK_CD) && + (stat->images[sig->irq] & sig->irqmask)) + { + + if (sig->val) + { + wake_up_interruptible(&port->open_wait); /* in case waiting in block_til_ready */ + } + else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) && + (port->flags & FLAG8253X_CALLOUT_NOHUP))) + { + /* I think the code needs to walk through all the proces that have opened this + * port and send a SIGHUP to them -- need to investigate somewhat more*/ + } + } +} + +static int sab8253x_startupC(struct sab_port *port) +{ + unsigned long flags; + int retval = 0; + + save_flags(flags); cli(); + + if (port->flags & FLAG8253X_INITIALIZED) + { + goto errout; + } + + if (!port->regs) + { + retval = -ENODEV; + goto errout; + } + /* + * Initialize the Hardware + */ + sab8253x_init_lineS(port); /* nothing in this function + * refers to tty structure */ + + /* Activate RTS */ + RAISE(port,rts); + + /* Activate DTR */ + RAISE(port,dtr); + + + /* + * Initialize the modem signals values + */ + port->dcd.val=ISON(port,dcd); + port->cts.val=ISON(port,cts); + port->dsr.val=ISON(port,dsr); + + /* + * Finally, enable interrupts + */ + + port->interrupt_mask0 = SAB82532_IMR0_RFS | SAB82532_IMR0_PCE | + SAB82532_IMR0_PLLA | SAB82532_IMR0_RSC | SAB82532_IMR0_CDSC; +#if 0 + ((port->ccontrol.ccr2 & SAB82532_CCR2_TOE) ? SAB82532_IMR0_CDSC : 0); /* the weird way the cards work + * when clocking CD seems to + * monitor txclk*/ +#endif + WRITEB(port,imr0,port->interrupt_mask0); + port->interrupt_mask1 = SAB82532_IMR1_EOP | SAB82532_IMR1_XMR | + SAB82532_IMR1_TIN | SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + port->all_sent = 1; + + + /* + * and set the speed of the serial port + */ + sab8253x_change_speedN(port); + + port->flags |= FLAG8253X_INITIALIZED; /* bad name for indicating to other functionalities status */ + port->receive_chars = sab8253x_receive_charsC; + port->transmit_chars = sab8253x_transmit_charsS; + port->check_status = sab8253x_check_statusC; + port->receive_test = (SAB82532_ISR0_RME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF); + port->transmit_test = (SAB82532_ISR1_ALLS | SAB82532_ISR1_RDO | SAB82532_ISR1_XPR | + SAB82532_ISR1_XDU | SAB82532_ISR1_CSC); + port->check_status_test = SAB82532_ISR1_CSC; + + restore_flags(flags); + return 0; + + errout: + restore_flags(flags); + return retval; +} + +static int sab8253x_block_til_readyC(struct file* filp, struct sab_port *port) +{ + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 1; /* cheating -- I need to understand how + signals behave synchronously better*/ + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (port->flags & FLAG8253X_CLOSING) + { + interruptible_sleep_on(&port->close_wait); /* finish up previous close */ + +#ifdef SERIAL_DO_RESTART + if (port->flags & FLAG8253X_HUP_NOTIFY) + { + return -EAGAIN; + } + else + { + return -ERESTARTSYS; + } +#else + return -EAGAIN; +#endif + } + + /* sort out async vs sync tty, not call out */ + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + + if (filp->f_flags & O_NONBLOCK) + { + if (port->flags & FLAG8253X_CALLOUT_ACTIVE) + { + return -EBUSY; + } + port->flags |= FLAG8253X_NORMAL_ACTIVE; + return 0; + } + + if (port->flags & FLAG8253X_CALLOUT_ACTIVE) + { + if (port->normal_termios.c_cflag & CLOCAL) + { + do_clocal = 1; + } + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, port->count is dropped by one, so that + * sab8253x_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + + /* The port decrement logic is probably */ + /* broken -- hence if def'd out -- it does*/ + retval = 0; + add_wait_queue(&port->open_wait, &wait); /* starts the wait but does not block here */ + port->blocked_open++; + while (1) /* on some devices when providing clock have to just assume connection */ + { + save_flags(flags); + cli(); + if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE)) + { + RAISE(port, dtr); + RAISE(port, rts); /* maybe not correct for sync */ + /* + * ??? Why changing the mode here? + * port->regs->rw.mode |= SAB82532_MODE_FRTS; + * port->regs->rw.mode &= ~(SAB82532_MODE_RTS); + */ + } + restore_flags(flags);; + current->state = TASK_INTERRUPTIBLE; + if (!(port->flags & FLAG8253X_INITIALIZED)) + { +#ifdef SERIAL_DO_RESTART + if (port->flags & FLAG8253X_HUP_NOTIFY) + { + retval = -EAGAIN; + } + else + { + retval = -ERESTARTSYS; + } +#else + retval = -EAGAIN; +#endif + break; + } + + if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE) && + !(port->flags & FLAG8253X_CLOSING) && + (do_clocal || ISON(port,dcd))) + { + break; + } +#ifdef DEBUG_OPEN + printk("sab8253x_block_til_ready:2 flags = 0x%x\n",port->flags); +#endif + if (signal_pending(current)) + { + retval = -ERESTARTSYS; + break; + } +#ifdef DEBUG_OPEN + printk("sab8253x_block_til_readyC blocking: ttyS%d, count = %d, flags = %x, clocal = %d, vstr = %02x\n", + port->line, port->count, port->flags, do_clocal, READB(port,vstr)); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&port->open_wait, &wait); + port->blocked_open--; + +#ifdef DEBUG_OPEN + printk("sab8253x_block_til_ready after blockingC: ttys%d, count = %d\n", + port->line, port->count); +#endif + + if (retval) + { + return retval; + } + port->flags |= FLAG8253X_NORMAL_ACTIVE; + return 0; +} + + +int sab8253xc_open(struct inode *inodep, struct file *filep) +{ + unsigned int line; + unsigned int retval; + unsigned int counter; + SAB_PORT *port; + + line = minor(inodep->i_rdev); /* let's find which physical device to use */ + /* minor dev number indexes through the port */ + /* list */ + + for(counter = 0, port = AuraPortRoot; + (counter < line) && (port != NULL); + ++counter) + { + port = port->next; + } + + + if (!port) + { + printk(KERN_ALERT "sab8253xc_open: can't find structure for line %d\n", + line); + return -ENODEV; + } + + if(port->function == FUNCTION_NA) + { /* port 2 on 1020s and 1520s */ + return -ENODEV; + } + + switch(port->open_type) + { + case OPEN_ASYNC: + if(!(port->flags & FLAG8253X_CALLOUT_ACTIVE)) + { + return -EBUSY; + } + break; + + case OPEN_SYNC_CHAR: + case OPEN_NOT: + port->tty = NULL; + port->open_type = OPEN_SYNC_CHAR; + break; + + default: + return -EBUSY; + } + + /* + * Maybe start up serial port -- may already be running in callout mode + */ + + if(Sab8253xSetUpLists(port)) + { + if(port->open_type == OPEN_SYNC_CHAR) + { + port->open_type = OPEN_NOT; + } + return -ENODEV; + } + if(Sab8253xInitDescriptors2(port, sab8253xc_listsize, sab8253xc_rbufsize)) + { + Sab8253xCleanUpTransceiveN(port); /* the network functions should be okay -- only difference */ + /* is the crc32 that is appended */ + if(port->open_type == OPEN_SYNC_CHAR) + { + port->open_type = OPEN_NOT; + } + return -ENODEV; + } + retval = sab8253x_startupC(port); /* does not do anything if call out active */ + if (retval) + { + if(port->open_type == OPEN_SYNC_CHAR) + { + port->open_type = OPEN_NOT; + } + return retval; + } + + MOD_INC_USE_COUNT; /* might block */ + /* note logic different from tty + open failure does not call the + close routine */ + retval = sab8253x_block_til_readyC(filep, port); /* need to wait for completion of callout */ + if(retval) + { + if(port->open_type == OPEN_SYNC_CHAR) + { + port->open_type = OPEN_NOT; + } + MOD_DEC_USE_COUNT; /* something went wrong */ + return retval; + } + + port->tty = NULL; + port->open_type = OPEN_SYNC_CHAR; + if(Sab8253xSetUpLists(port)) + { + port->open_type = OPEN_NOT; + return -ENODEV; + } + if(Sab8253xInitDescriptors2(port, sab8253xc_listsize, sab8253xc_rbufsize)) + { + port->open_type = OPEN_NOT; + Sab8253xCleanUpTransceiveN(port); /* the network functions should be okay -- only difference */ + /* is the crc32 that is appended */ + return -ENODEV; + } + retval = sab8253x_startupC(port); /* ditto */ + if (retval) + { + port->open_type = OPEN_NOT; + Sab8253xCleanUpTransceiveN(port); + return retval; + } + port->tx_full = 0; + port->rx_empty = 1; + port->count++; + port->session = current->session; + port->pgrp = current->pgrp; + filep->private_data = port; + MOD_INC_USE_COUNT; + return 0; /* success */ +} + +int sab8253xc_release(struct inode *inodep, struct file *filep) +{ + SAB_PORT *port = (SAB_PORT*) filep->private_data; + unsigned long flags; + + save_flags(flags); cli(); + + --(port->count); + if(port->count <= 0) + { + sab8253x_shutdownN(port); + Sab8253xCleanUpTransceiveN(port); + port->count = 0; + port->open_type = OPEN_NOT; + } + sab8253xc_fasync(-1, filep, 0); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return 0; +} + +unsigned int sab8253xc_poll(struct file *fileobj, struct poll_table_struct *polltab) +{ + SAB_PORT *port = fileobj->private_data; + unsigned int mask = 0; + + poll_wait(fileobj, &port->write_wait, polltab); + poll_wait(fileobj, &port->read_wait, polltab); + if(port->rx_empty == 0) + { + mask |= POLLIN | POLLRDNORM; + } + if(port->tx_full == 0) + { + mask |= POLLOUT | POLLWRNORM; + } + return mask; +} + +int sab8253xc_ioctl(struct inode *iobj, struct file *fileobj, unsigned int cmd, unsigned long length) +{ + return 0; +} + +int sab8253xc_fasync(int fd, struct file * fileobj, int mode) +{ + SAB_PORT *port = fileobj->private_data; + + return fasync_helper(fd, fileobj, mode, &port->async_queue); /* I am a little baffled -- does async_helper */ + /* work on the basis of a port or on an open */ + /* basis*/ +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xctl.h linux-2.5/drivers/net/wan/8253x/8253xctl.h --- linux-2.5.20/drivers/net/wan/8253x/8253xctl.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xctl.h Fri May 3 03:49:07 2002 @@ -0,0 +1,337 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +/* These structures and symbols are less related to the ESCC2s and ESCC8s per se and more to */ +/* the architecture of Aurora cards or to the logic of the driver */ + +#ifndef _ATICNTRL_H_ +#define _ATICNTRL_H_ + +#include +#include +#include +#include +#include +#include "Reg9050.h" +#include "8253x.h" + +#define FALSE 0 +#define TRUE 1 + +#define NUMINTS 32 + +/* The following are suggested by serial.h -- all not currently used */ +#define FLAG8253X_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes + on the callout port */ +#define FLAG8253X_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ +#define FLAG8253X_SAK 0x0004 /* Secure Attention Key (Orange book) */ +#define FLAG8253X_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ +#define FLAG8253X_SPD_MASK 0x1030 +#define FLAG8253X_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ +#define FLAG8253X_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ +#define FLAG8253X_SPD_CUST 0x0030 /* Use user-specified divisor */ +#define FLAG8253X_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ +#define FLAG8253X_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ + +#define FLAG8253X_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ +#define FLAG8253X_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ +#define FLAG8253X_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ + +#define FLAG8253X_HARDPPS_CD 0x0800 /* Call hardpps when CD goes high */ +#define FLAG8253X_SPD_SHI 0x1000 /* Use 230400 instead of 38400 bps */ +#define FLAG8253X_SPD_WARP 0x1010 /* Use 460800 instead of 38400 bps */ + +#define FLAG8253X_LOW_LATENCY 0x2000 /* Request low latency behaviour */ + +#define FLAG8253X_BUGGY_UART 0x4000 /* This is a buggy UART, skip some safety + * checks. Note: can be dangerous! */ + +#define FLAG8253X_AUTOPROBE 0x8000 /* Port was autoprobed by PCI or PNP code */ + +#define FLAG8253X_FLAGS 0x7FFF /* Possible legal async flags */ +#define FLAG8253X_USR_MASK 0x3430 /* Legal flags that non-privileged + * users can set or reset */ + +/* Internal flags used only by the 8253x driver */ +#define FLAG8253X_INITIALIZED 0x80000000 /* Serial port was initialized */ +#define FLAG8253X_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ +#define FLAG8253X_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ +#define FLAG8253X_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ +#define FLAG8253X_CLOSING 0x08000000 /* Serial port is closing */ +#define FLAG8253X_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define FLAG8253X_CHECK_CD 0x02000000 /* i.e., CLOCAL */ +#define FLAG8253X_NETWORK 0x01000000 /* the logic of callout + * and reconnect works differently + * for network ports*/ + +#define FLAG8253X_CONS_FLOW 0x00800000 /* flow control for console */ + +#define FLAG8253X_INTERNAL_FLAGS 0xFF800000 /* Internal flags */ + +#define SAB8253X_CLOSING_WAIT_INF 0 +#define SAB8253X_CLOSING_WAIT_NONE 65535 + +#define SAB8253X_EVENT_WRITE_WAKEUP 0 + +typedef struct AuraXX20params +{ + unsigned debug; /* lots of kernel warnings */ + unsigned listsize; /* size of descriptor list */ +} AURAXX20PARAMS; + +/* initialization functions */ +extern unsigned int +plx9050_eprom_read(unsigned int* eprom_ctl, unsigned short *ptr, unsigned char addr, unsigned short len); +extern unsigned int +plx9050_eprom_cmd(unsigned int* eprom_ctl, unsigned char cmd, unsigned char addr, unsigned short data); +extern void dump_ati_adapter_registers(unsigned int *addr, int len); + +/* common routine */ +extern void sab8253x_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* net device functions */ +extern int Sab8253xInitDescriptors2(SAB_PORT *priv, int listsize, int rbufsize); +extern int sab8253xn_init(struct net_device *dev); /* called by registration */ +extern int sab8253xn_write2(struct sk_buff *skb, struct net_device *dev); + /* hard_start_xmit */ +extern int sab8253xn_ioctl(struct net_device *dev, struct ifreq *ifr, + int cmd); + /* interrupt handler */ +extern void sab8253xn_handler2(int irq, void *devidp, struct pt_regs* ptregsp); +extern int sab8253xn_open(struct net_device *dev); +extern int sab8253xn_release(struct net_device *dev); /* stop */ +extern struct net_device_stats *sab8253xn_stats(struct net_device *dev); + +extern struct net_device *Sab8253xRoot; +extern struct net_device auraXX20n_prototype; +extern SAB_PORT *current_sab_port; +extern int sab8253xn_listsize; +extern int sab8253xn_rbufsize; +extern int sab8253xt_listsize; +extern int sab8253xt_rbufsize; +extern int sab8253xs_listsize; +extern int sab8253xs_rbufsize; +extern int sab8253xc_listsize; +extern int sab8253xc_rbufsize; + +/* character device functions */ + +extern int +sab8253xc_read(struct file *filep, char *cptr, size_t cnt, loff_t *loffp); +extern int sab8253xc_write(struct file *filep, const char *cptr, size_t cnt, loff_t *loffp); +extern int sab8253xc_open(struct inode *inodep, struct file *filep); +extern int sab8253xc_release(struct inode *inodep, struct file *filep); +extern unsigned int sab8253xc_poll(struct file *, struct poll_table_struct *); +extern int sab8253xc_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +extern int sab8253xc_fasync(int, struct file *, int); + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +#define SERIAL_PARANOIA_CHECK +#define SERIAL_DO_RESTART + +/* sync tty functions */ + +/* general macros */ +#define DEBUGPRINT(arg) if(DRIVER_DEBUG()) printk arg +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +extern AURAXX20PARAMS AuraXX20DriverParams; +#define DRIVER_DEBUG() (AuraXX20DriverParams.debug) +#define DRIVER_LISTSIZE() (AuraXX20DriverParams.listsize) +#define XSETDRIVER_LISTSIZE(arg) (AuraXX20DriverParams.listsize = (arg)) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#define net_device_stats enet_statistics +#define net_device device +#define pci_base_address(p, n) (p)->base_address[n] +#define dev_kfree_skb_irq(s) dev_kfree_skb((s)) +#define dev_kfree_skb_any(s) dev_kfree_skb((s)) +#else /* LINUX_VERSION_CODE */ +#define NETSTATS_VER2 +#define pci_base_address(p, n) pci_resource_start((p), (n)) +#endif /* LINUX_VERSION_CODE */ + + /* The sample LINUX driver */ + /* uses these no reason not */ + /* to be more dynamic.*/ + +/* Below are things that should be placed in */ +#ifndef PCI_VENDOR_ID_AURORATECH +#define PCI_VENDOR_ID_AURORATECH 0x125c + /* Saturn and Apollo boards */ +#define PCI_DEVICE_ID_AURORATECH_MULTI 0x0101 + /* WAN/LAN Multiservers */ +#define PCI_DEVICE_ID_AURORATECH_WANMS 0x0102 + /* Comnpact PCI boards */ +#define PCI_DEVICE_ID_AURORATECH_CPCI 0x0103 +#endif /* PCI_VENDOR_ID_AURORATECH */ + +extern int sab8253x_vendor_id; +extern int sab8253x_cpci_device_id; +extern int sab8253x_wmcs_device_id; +extern int sab8253x_mpac_device_id; + +#define PCIMEMVALIDMULTI ((sab8253x_vendor_id << 16) | sab8253x_mpac_device_id) +#define PCIMEMVALIDCPCI ((sab8253x_vendor_id << 16) | sab8253x_cpci_device_id) +#define PCIMEMVALIDWMCS (sab8253x_vendor_id | (sab8253x_wmcs_device_id << 16)) + +/* + * Some values defining boards + * + * First 1, 2, 4 and 8 ports Multiports + */ + +#define AURORA_8X20_CHIP_NPORTS 8 +#define AURORA_4X20_CHIP_NPORTS 2 /* uses two ESCC2s */ +#define AURORA_2X20_CHIP_NPORTS 2 +#define AURORA_1X20_CHIP_NPORTS 1 + + /* sizes of PLX9050 address space */ +#define AURORA_4X20_SIZE 0x800 +#define AURORA_4X20_CHIP_OFFSET 0x400 +#define AURORA_8X20_SIZE 0x200 +#define AURORA_8X20_CHIP_OFFSET 0x0 +#define AURORA_2X20_SIZE 0x80 /* This looks wrong probably las0 size */ +#define AURORA_2X20_CHIP_OFFSET 0x0 + +#define AURORA_MULTI_1PORTBIT PLX_CTRL_USERIO3DATA +#define AURORA_MULTI_SYNCBIT PLX_CTRL_USERIO3DIR + +#define AURORA_MULTI_CLKSPEED ((unsigned long) 29491200) /* 29.4912 MHz */ +#define SUN_SE_CLKSPEED ((unsigned long) 29491200) /* 29.4912 MHz */ + +/* + * Per-CIM structure + */ + +#define CIM_SEPLEN 128 /* serial EPROM length on a CIM */ +#define CIM_REVLEN 17 +#define CIM_SNLEN 17 +#define CIM_MFGLOCLEN 17 +#define CIM_MFGDATELEN 33 + +/* CIM types: */ +#define CIM_UNKNOWN 0 +#define CIM_RS232 1 /* RS-232 only CIM */ +#define CIM_SP502 2 /* SP502 multi-mode CIM */ + +/* CIM flags: */ +#define CIM_SYNC 0x0000001 /* sync allowed */ +#define CIM_PROTOTYPE 0x0000002 /* prototype */ +#define CIM_LAST 0x0000100 /* the last CIM */ + +typedef struct aura_cim +{ + int ci_type; /* CIM type */ + unsigned long ci_flags; /* CIM flags */ + int ci_num; /* the canonical number of this CIM */ + int ci_port0lbl; /* what's the label on port 0 */ + unsigned int ci_nports; /* the number of ports on this CIM */ + struct sab_board *ci_board; /* pointer back to the board */ + struct sab_chip *ci_chipbase; /* first chip */ + struct sab_port *ci_portbase; /* first port */ + unsigned long ci_clkspeed; /* the clock speed */ + unsigned int ci_clkspdsrc; + int ci_spdgrd; /* chip speed grade */ + unsigned int ci_spdgrdsrc; + unsigned char ci_sep[CIM_SEPLEN]; + unsigned char ci_rev[CIM_REVLEN]; /* revision information */ + unsigned char ci_sn[CIM_SNLEN]; /* serial number */ + unsigned char ci_mfgdate[CIM_MFGDATELEN]; + unsigned char ci_mfgloc[CIM_MFGLOCLEN]; + struct aura_cim *next; + struct aura_cim *next_by_mcs; +} aura_cim_t, AURA_CIM; + +/* + * Board structure + */ + +typedef struct sab_board +{ + struct sab_board *nextboard; + struct sab_board *next_on_interrupt; + + struct sab_chip *board_chipbase; /* chip list for this board */ + struct sab_port *board_portbase; /* port list for this board */ + unsigned int board_number; + +#define BD_1020P 1 +#define BD_1520P 2 +#define BD_2020P 3 +#define BD_2520P 4 +#define BD_4020P 5 +#define BD_4520P 6 +#define BD_8020P 7 +#define BD_8520P 8 +#define BD_SUNSE 9 /* Sun's built-in 82532 -- not supported by this driver*/ +#define BD_WANMCS 10 +#define BD_1020CP 11 /* CPCI start here */ +#define BD_1520CP 12 +#define BD_2020CP 13 +#define BD_2520CP 14 +#define BD_4020CP 15 +#define BD_4520CP 16 +#define BD_8020CP 17 +#define BD_8520CP 18 +#define BD_ISCPCI(x) ((x) == BD_1020CP || (x) == BD_1520CP \ + || (x) == BD_2020CP || (x) == BD_2520CP \ + || (x) == BD_4020CP || (x) == BD_4520CP \ + || (x) == BD_8020CP || (x) == BD_8520CP) + + unsigned char b_type; + unsigned char b_nchips; /* num chips for this board */ + unsigned char b_nports; /* num ports for this board */ + unsigned char b_flags; /* flags: */ +#define BD_SYNC 0x01 /* sync is allowed on this board */ +#define BD_INTRHI 0x02 /* intr is hi level (SPARC only) */ + struct pci_dev b_dev; /* what does PCI knows about us */ + int b_irq; /* For faster access */ + unsigned char *b_chipregbase; /* chip register io */ + long b_clkspeed; /* the clock speed */ + int b_spdgrd; /* chip speed grade */ + unsigned short b_intrmask; /* wanmcs interrupt mask */ + unsigned char* virtbaseaddress0; + unsigned int length0; + unsigned char* virtbaseaddress1; + unsigned int length1; + unsigned char* virtbaseaddress2; + unsigned int length2; + unsigned char* virtbaseaddress3; + unsigned int length3; + + /* + * Pointer to hardware-specific electrical interface code. This + * routine will set the electrical interface to whatever is in + * the given interface/txena pair. + * Returns 0 if it could not set the value, non-zero otherwise. + */ + int (*b_setif)(struct sab_port *line, + int interface, int txena); + /* + * hardware mapping + */ + unsigned int b_eprom[64]; /* serial EPROM contents */ + AURA_CIM *b_cimbase; /* CIM information */ + PLX9050 *b_bridge; /* PCI bridge ctlr. regs. */ +} sab_board_t, SAB_BOARD; /* really hate the _t convention */ + +#define SEPROM 1 /* driver got clock speed from SEPROM */ + +#define SAB8253X_XMIT_SIZE PAGE_SIZE + +extern char *aura_functionality[]; + +#endif /* _ATICNTRL_H_ */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xdbg.c linux-2.5/drivers/net/wan/8253x/8253xdbg.c --- linux-2.5.20/drivers/net/wan/8253x/8253xdbg.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xdbg.c Fri May 3 03:49:07 2002 @@ -0,0 +1,64 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "8253xctl.h" +#include "Reg9050.h" +#if 0 /* only during debugging */ +#undef DEBUGPRINT +#define DEBUGPRINT(arg) printk arg +#endif + +void dump_ati_adapter_registers(unsigned int *addr, int len) +{ + int index; + int flag = 1; + + for(index = 0; index < (len/(sizeof(unsigned int*))); ++index) + { + if(flag) + { + DEBUGPRINT((KERN_ALERT "bridge: %4.4x:%8.8x", (4*index), *addr++)); + } + else + { + DEBUGPRINT(("%8.8x", *addr++)); + } + if(((index + 1) % 8) == 0) + { + DEBUGPRINT(("\n")); + flag = 1; + } + else + { + DEBUGPRINT((" ")); + flag = 0; + } + } + if(flag == 0) + { + DEBUGPRINT(("\n")); + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xini.c linux-2.5/drivers/net/wan/8253x/8253xini.c --- linux-2.5.20/drivers/net/wan/8253x/8253xini.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xini.c Fri May 3 03:49:07 2002 @@ -0,0 +1,3043 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Reg9050.h" +#include "8253xctl.h" +#include "ring.h" +#include "8253x.h" +#include "crc32dcl.h" +#include "8253xmcs.h" +#include "sp502.h" + +/* card names */ + +char *aura_functionality[] = +{ + "NR", + "AO", + "NA", + "UN" +}; + +char *board_type[] = +{ + "unknown", + "1020P", + "1520P", + "2020P", + "2520P", + "4020P", + "4520P", + "8020P", + "8520P", + "SUNSE", + "WANMS", + "1020C", + "1520C", + "2020C", + "2520C", + "4020C", + "4520C", + "8020C", + "8520C", +}; + +unsigned int sab8253x_rebootflag = 0; + +AURAXX20PARAMS AuraXX20DriverParams; /* loaded at startup */ + /* from variables below */ +SAB_BOARD *AuraBoardRoot = NULL; /* The order of this list is not important */ +SAB_CHIP *AuraChipRoot = NULL; /* chips grouped by board chip0 before chip1 */ +SAB_PORT *AuraPortRoot = NULL; /* ports grouped by board and by chip, chip0, chip1, etc */ +AURA_CIM *AuraCimRoot = NULL; /* only used for deallocating the cim structures, etc */ +/* CIM stands for Communications Interface Module -- the G.Link logic provided by the Altera parts. */ + +/* Arrays of lists of boards of each type on a given interrupt */ +SAB_BOARD *AuraBoardESCC2IrqRoot[NUMINTS]; +SAB_BOARD *AuraBoardESCC8IrqRoot[NUMINTS]; +SAB_BOARD *AuraBoardMCSIrqRoot[NUMINTS]; + +unsigned int NumSab8253xPorts = 0; + +unsigned BD1020Pcounter = 0; /* keep count of each board */ +unsigned BD1520Pcounter = 0; /* may change to just keeping count */ +unsigned BD2020Pcounter = 0; /* of the total number of boards */ +unsigned BD2520Pcounter = 0; +unsigned BD4020Pcounter = 0; +unsigned BD4520Pcounter = 0; +unsigned BD8020Pcounter = 0; +unsigned BD8520Pcounter = 0; + +unsigned BD1020CPcounter = 0; /* keep count of each board */ +unsigned BD1520CPcounter = 0; /* may change to just keeping count */ +unsigned BD2020CPcounter = 0; /* of the total number of boards */ +unsigned BD2520CPcounter = 0; +unsigned BD4020CPcounter = 0; +unsigned BD4520CPcounter = 0; +unsigned BD8020CPcounter = 0; +unsigned BD8520CPcounter = 0; + +unsigned BDMCScounter = 0; + + +static int auraXX20n_debug = 0; /* turns on lots of */ + /* debugging messages*/ +static char* auraXX20n_name = 0;/* set net dev name on command line */ +static char *sab8253xc_name = "sab8253xc"; +static int sab8253xc_major = 0; +int sab8253xn_listsize = 32; /* recommend descriptor list size */ +int sab8253xn_rbufsize = RXSIZE; /* recommend rbuf list size */ +int sab8253xt_listsize = 256; /* recommend descriptor list size */ +int sab8253xt_rbufsize = 32; /* recommend rbuf list size for tty */ +int sab8253xs_listsize = 64; /* recommend descriptor list size */ +int sab8253xs_rbufsize = RXSIZE; /* recommend rbuf list size */ +int sab8253xc_listsize = 64; /* recommend descriptor list size */ +int sab8253xc_rbufsize = RXSIZE; /* recommend rbuf list size for tty */ +int xx20_minorstart = 128; +int sab8253x_vendor_id = PCI_VENDOR_ID_AURORATECH; +int sab8253x_cpci_device_id = PCI_DEVICE_ID_AURORATECH_CPCI; +int sab8253x_wmcs_device_id = PCI_DEVICE_ID_AURORATECH_WANMS; +int sab8253x_mpac_device_id = PCI_DEVICE_ID_AURORATECH_MULTI; +int sab8253x_default_sp502_mode = SP502_RS232_MODE; + +MODULE_PARM(sab8253x_vendor_id, "i"); +MODULE_PARM(sab8253x_cpci_device_id, "i"); +MODULE_PARM(sab8253x_wmcs_device_id, "i"); +MODULE_PARM(sab8253x_mpac_device_id, "i"); +MODULE_PARM(sab8253x_default_sp502_mode, "i"); + +MODULE_PARM(xx20_minorstart, "i"); +MODULE_PARM(sab8253xc_major, "i"); +MODULE_PARM(auraXX20n_debug, "i"); +MODULE_PARM(auraXX20n_name, "s"); /* this and the following for sync */ +MODULE_PARM(sab8253xn_listsize, "i"); /* network driver */ +MODULE_PARM(sab8253xn_rbufsize, "i"); /* network driver */ +MODULE_PARM(sab8253xt_listsize, "i"); /* tty driver */ +MODULE_PARM(sab8253xt_rbufsize, "i"); /* tty driver */ +MODULE_PARM(sab8253xc_listsize, "i"); /* network driver */ +MODULE_PARM(sab8253xc_rbufsize, "i"); /* network driver */ +MODULE_PARM(sab8253xs_listsize, "i"); /* tty driver */ +MODULE_PARM(sab8253xs_rbufsize, "i"); /* tty driver */ +MODULE_PARM(sab8253xc_name, "s"); + +struct pci_dev *XX20lastpdev = NULL; /* just used for finding all PCI devices */ +static SAB_BOARD *find_ati_multiport_card(void); /* actually implemented */ +static SAB_BOARD *find_ati_cpci_card(void); /* to be done */ +static SAB_BOARD *find_ati_wanms_card(void); /* to be done */ + +#if (!defined(MODULE)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) + /* unpleasantness for 2.2 kernels + * and probe illogic */ + + /* The LRP project is still working on + 2.2.* kernels but I suspect + that initially we will see more + purchases for complete Linux + machines using 2.4.*, LRP + machines tend to be underpowered + and have a paucity of PCI slots + */ + +unsigned int do_probe = 1; +#endif + + /* One could argue that these could be in */ + /* the 8253xnet.c file but they are fairly */ + /* intimately involved with initialization.*/ +struct net_device *Sab8253xRoot = NULL; + +struct net_device auraXX20n_prototype = /* used for the network device */ +{ + "8253x0", + 0, 0, 0, 0, + 0x000, + -1, /* bad irq */ + 0, 0, 0, + NULL, + sab8253xn_init /* network driver initialization */ +}; + +struct file_operations sab8253xc_fops = +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)) + NULL, +#endif + NULL, /* llseek */ + sab8253xc_read, /* read */ + sab8253xc_write, /* write */ + NULL, /* readdir */ + sab8253xc_poll, /* poll */ + sab8253xc_ioctl, /* ioctl */ + NULL, /* mmap */ + sab8253xc_open, /* open */ + NULL, /* flush */ + sab8253xc_release, /* release */ + NULL, /* fsync */ + sab8253xc_fasync, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ +}; + + +/* A few function defined in this file */ +/* These functions are basically functionality */ +/* independent -- they are used with asynchronous ttys */ +/* synchronous ttys, the network device and the */ +/* raw character device */ + + /* used for reading and writing ports + readw and writew require some reprogramming + of the PLX9050 + */ +static unsigned char aura_readb(struct sab_port *port, unsigned char *reg); +static unsigned char wmsaura_readb(struct sab_port *port, unsigned char *reg); +static unsigned short aura_readw(struct sab_port *port, unsigned short *reg); +static unsigned short wmsaura_readw(struct sab_port *port, unsigned short *reg); +static void aura_writeb(struct sab_port *port, unsigned char *reg,unsigned char val); +static void wmsaura_writeb(struct sab_port *port, unsigned char *reg,unsigned char val); +static void aura_writew(struct sab_port *port, unsigned short *reg,unsigned short val); +static void wmsaura_writew(struct sab_port *port, unsigned short *reg,unsigned short val); + +static void aura_readfifo(struct sab_port *port, unsigned char *buf, unsigned int nbytes); +static void aura_writefifo(struct sab_port *port); + +static void wmsaura_readfifo(struct sab_port *port, unsigned char *buf, unsigned int nbytes); +static void wmsaura_writefifo(struct sab_port *port); + +/* function definitions */ + +/* [124]X20 type cards */ +static void DisableESCC2Interrupts(SAB_CHIP *chipptr) /* in processing ports may have to disable ints */ +{ + struct sab82532_async_wr_regs *regs; + + regs = chipptr->c_regs; + writeb(0xff,®s->pim); /* All interrupts off */ + /* Note that regs/->c_regs + is set to base reg + address, thus taking + address or regs->pim + gets the address of + the PIM register/int mask */ +} + +static SAB_CHIP* CreateESCC2(SAB_BOARD *bptr, unsigned int offset) +{ + SAB_CHIP *cptr; + struct sab82532_async_wr_regs *regs; + + printk(KERN_ALERT + "auraXX20n: creating ESCC2 structure on board %p at offset %x.\n", + bptr, offset); + + cptr = (SAB_CHIP*) kmalloc(sizeof(SAB_CHIP), GFP_KERNEL); + if(cptr == NULL) + { + printk(KERN_ALERT + "auraXX20n: Failed to create ESCC2 structure on board %p at offset %x.\n", + bptr, offset); + return NULL; + } + memset(cptr, 0, sizeof(SAB_CHIP)); + cptr->chip_type = ESCC2; + cptr->c_board = bptr; + cptr->c_cim = NULL; + cptr->c_chipno = (offset ? 1 : 0); /* first or second chip on board */ + cptr->c_revision = + (readb(((char *)bptr->virtbaseaddress2) + offset + SAB85232_REG_VSTR) & + SAB82532_VSTR_VN_MASK); + cptr->c_nports = 2; + cptr->c_portbase = NULL; + cptr->next = AuraChipRoot; /* chips are added to chiplist in reverse order */ + AuraChipRoot = cptr; + cptr->next_by_board = bptr->board_chipbase; /* likewise for the local board chiplist */ + bptr->board_chipbase = cptr; + printk(KERN_ALERT "auraXX20n: chip %d on board %p is revision %d.\n", + cptr->c_chipno, bptr, cptr->c_revision); + + /* lets set up the generic parallel + * port register which is used to + * control signaling and other stuff*/ + /* + * SAB82532 (Aurora) 1 8-bit parallel port + * To summarize the use of the parallel port: + * RS-232 + * A B I/O descr + * P0 P4 output TxClk ctrl + * P1 P5 output DTR + * P2 P6 input DSR + * P3 P7 output 485 control + * + */ + /* + * Configuring the parallel port + */ + + regs = (struct sab82532_async_wr_regs *)(((char *)bptr->virtbaseaddress2) + offset); + + DEBUGPRINT((KERN_ALERT "Writing 0x44 to 0x%p + 0x%x for chip %d\n", + regs, SAB82532_REG_PCR, cptr->c_chipno)); + + writeb(0x44,®s->pcr); /* 2 input bits */ + writeb(0xff,®s->pim);/* All interrupts off */ + writeb(0x33,®s->pvr); /* Txclk and DTR low */ + + cptr->c_regs = (void*) regs; + cptr->int_disable = DisableESCC2Interrupts; + return cptr; +} + +static void CreateESCC2Port(SAB_CHIP *cptr, unsigned int portno, unsigned int function) +{ + SAB_BOARD *bptr; + SAB_PORT *pptr; + extern void sab8253x_setup_ttyport(struct sab_port *p_port) ; + + ++NumSab8253xPorts; + bptr = cptr->c_board; + pptr = (SAB_PORT*) kmalloc(sizeof(SAB_PORT), GFP_KERNEL); + if(pptr == NULL) + { + printk(KERN_ALERT + "auraXX20n: Failed to create ESCC2 port structure on chip %p on board %p.\n", + cptr, bptr); + return; + } + memset(pptr, 0, sizeof(SAB_PORT)); + DEBUGPRINT + ((KERN_ALERT "Setting up port %d, chipno %d for %s type board number %d.\n", + portno, cptr->c_chipno, board_type[bptr->b_type],bptr->board_number)); + pptr->portno = portno; + pptr->chip=cptr; + pptr->board=bptr; + pptr->open_type=OPEN_NOT; + pptr->is_console=0; + pptr->regs= + (union sab82532_regs *) + (((unsigned int)cptr->c_regs) + + (portno * SAB82532_REG_SIZE)); + pptr->type = cptr->c_revision; + pptr->function = function; + + /* Simpify reading */ +#define PVR pptr->regs->async_write.pvr +#define PCR pptr->regs->async_write.pcr +#define PIM pptr->regs->async_write.pim +#define ISR0 pptr->regs->async_read.isr0 +#define IMR0 pptr->regs->async_write.imr0 +#define IMR1 pptr->regs->async_write.imr1 +#define PIS pptr->regs->async_read.pis +#define VSTR pptr->regs->async_read.vstr +#define STAR pptr->regs->async_read.star +#define MODE pptr->regs->async_read.mode + + pptr->irq = bptr->b_irq; + if(portno == 0) + { /* Port A .... */ + pptr->dsr.reg=(unsigned char *)&(PVR); + pptr->dsr.mask=0x04; + pptr->dsr.irq=PIS_IDX; + pptr->dsr.irqmask=0x04; + + pptr->dtr.reg=(unsigned char *)&(PVR); + pptr->dtr.mask=0x02; + + pptr->txclkdir.reg=(unsigned char *)&(PVR); + pptr->txclkdir.mask=0x01; + } + else + { /* Port B */ + pptr->dsr.reg=(unsigned char *)&(PVR); + pptr->dsr.mask=0x40; + pptr->dsr.irq=PIS_IDX; + pptr->dsr.irqmask=0x40; + + pptr->dtr.reg=(unsigned char *)&(PVR); + pptr->dtr.mask=0x20; + + pptr->txclkdir.reg=(unsigned char *)&(PVR); + pptr->txclkdir.mask=0x10; + } + pptr->dsr.inverted=1; + pptr->dsr.cnst = 0; + pptr->dtr.inverted=1; + pptr->dtr.cnst = 0; + pptr->txclkdir.inverted=1; + + pptr ->dcd.reg =(unsigned char *) &(VSTR); + + DEBUGPRINT((KERN_ALERT "cd register set to 0x%p\n", pptr ->dcd.reg)); + + pptr->dcd.mask = SAB82532_VSTR_CD; + pptr->dcd.inverted = 1; + pptr->dcd.irq=ISR0_IDX; + pptr->dcd.irqmask=SAB82532_ISR0_CDSC; + pptr->dcd.cnst = 0; + + pptr->cts.reg = (unsigned char *)&(STAR); + pptr->cts.mask = SAB82532_STAR_CTS; + pptr->cts.inverted = 0; + pptr->cts.irq=ISR1_IDX; + pptr->cts.irqmask=SAB82532_ISR1_CSC; + pptr->cts.cnst = 0; + + pptr->rts.reg = (unsigned char *)&(MODE); + pptr->rts.mask = SAB82532_MODE_FRTS; + pptr->rts.inverted = 1; + pptr->rts.cnst = SAB82532_MODE_RTS; + + + /* Set the read and write function */ + pptr->readbyte=aura_readb; + pptr->readword=aura_readw; + pptr->writebyte=aura_writeb; + pptr->writeword=aura_writew; + pptr->readfifo=aura_readfifo; + pptr->writefifo=aura_writefifo; + + sab8253x_setup_ttyport(pptr); /* asynchronous */ + /* ttys are default, basic */ + /* initialization, everything */ + /* else works as a modification */ + /* thereof */ + + pptr->next = AuraPortRoot; + AuraPortRoot = pptr; + pptr->next_by_chip = cptr->c_portbase; + cptr->c_portbase = pptr; + pptr->next_by_board = bptr->board_portbase; + bptr->board_portbase = pptr; +} + +/* 8x20 type functions */ + +static void DisableESCC8Interrupts(SAB_CHIP *chipptr) +{ + unsigned int regbase; /* a lot more to do for ESCC8 */ + + regbase = (unsigned int) chipptr->c_regs; + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_A); /* All interrupts off */ + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_B); /* All interrupts off */ + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_C); /* All interrupts off */ + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_D); /* All interrupts off */ +} + +static SAB_CHIP* CreateESCC8(SAB_BOARD *bptr, unsigned int offset) +{ + SAB_CHIP *cptr; + unsigned int regbase; + + printk(KERN_ALERT + "auraXX20n: creating ESCC8 structure on board %p at offset %x.\n", + bptr, offset); + + cptr = (SAB_CHIP*) kmalloc(sizeof(SAB_CHIP), GFP_KERNEL); + if(cptr == NULL) + { + printk(KERN_ALERT + "auraXX20n: Failed to create ESCC8 structure on board %p at offset %x.\n", + bptr, offset); + return NULL; + } + memset(cptr, 0, sizeof(SAB_CHIP)); + cptr->chip_type = ESCC8; + cptr->c_board = bptr; + cptr->c_cim = NULL; + cptr->c_chipno = (offset ? 1 : 0); /* no card actually has 2 ESCC8s on it */ + cptr->c_revision = + (readb(((char *)bptr->virtbaseaddress2) + offset + SAB85232_REG_VSTR) & + SAB82532_VSTR_VN_MASK); + cptr->c_nports = 8; + cptr->c_portbase = NULL; /* used for the list of ports associated + with this chip + */ + cptr->next = AuraChipRoot; + AuraChipRoot = cptr; + cptr->next_by_board = bptr->board_chipbase; + bptr->board_chipbase = cptr; + printk(KERN_ALERT "auraXX20n: chip %d on board %p is revision %d.\n", + cptr->c_chipno, bptr, cptr->c_revision); + + /* lets set up the generic parallel + * port register which is used to + * control signaling and other stuff*/ + + /* SAB82538 4 8-bits parallel ports + * To summarize the use of the parallel port: + * RS-232 + * Parallel port A -- TxClkdir control (output) ports 0 - 7 + * Parallel port B -- DTR (output) ports 0 - 7 + * Parallel port C -- DSR (input) ports 0 - 7 + * Parallel port D -- driver power down (output) drivers 0 - 3 + * + * Note port D is not used on recent boards + */ + + regbase = (unsigned int)(((char *)bptr->virtbaseaddress2) + offset); + + DEBUGPRINT((KERN_ALERT "Setting up parallel port A (0x%x), 0x%x, 0x%x, 0x%x\n", regbase, + SAB82538_REG_PCR_A, SAB82538_REG_PIM_A, SAB82538_REG_PVR_A)); + + /* Configuring Parallel Port A (Clkdir)*/ + writeb(0x0,((unsigned char *)regbase) + SAB82538_REG_PCR_A); /* All output bits */ + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_A); /* All interrupts off */ + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PVR_A); /* All low */ + + DEBUGPRINT((KERN_ALERT "Setting up parallel port B (0x%x), 0x%x, 0x%x, 0x%x\n", regbase, + SAB82538_REG_PCR_B,SAB82538_REG_PIM_B,SAB82538_REG_PVR_B)); + + writeb(0x0,((unsigned char *)regbase) + SAB82538_REG_PCR_B); /* All output bits */ + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_B); /* All interrupts off */ + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PVR_B); /* All low */ + + DEBUGPRINT((KERN_ALERT "Setting up parallel port C (0x%x), 0x%x, 0x%x, 0x%x\n", regbase, + SAB82538_REG_PCR_C, SAB82538_REG_PIM_C, SAB82538_REG_PVR_C)); + + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PCR_C); /* All intput bits */ + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_C); /* All interrupts off */ + /* don't set port value register on input register */ + + /* Configuring Parallel Port D */ + + DEBUGPRINT((KERN_ALERT "Setting up parallel port D (0x%x), 0x%x, 0x%x, 0x%x\n", regbase, + SAB82538_REG_PCR_D, SAB82538_REG_PIM_D, SAB82538_REG_PVR_D)); + writeb(0x0f,((unsigned char *)regbase) + SAB82538_REG_PCR_D); /* 4 input bits */ + writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_D); /* All interrupts off */ + /* don't set port value register on input register */ + + /* The priority rotation thing */ + + DEBUGPRINT((KERN_ALERT "Setting IVA (0x%x + 0x%x = 0x%x\n", regbase, + SAB82532_REG_IVA, regbase + SAB82532_REG_IVA)); + + writeb(SAB82538_IVA_ROT, ((unsigned char *)regbase) + SAB82532_REG_IVA); + + cptr->c_regs = (void*) regbase; + cptr->int_disable = DisableESCC8Interrupts; + return cptr; +} + +static void DisableESCC8InterruptsFromCIM(SAB_CHIP *chipptr) +{ + unsigned int regbase; /* a lot more to do for ESCC8 */ + + regbase = (unsigned int) chipptr->c_regs; + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_A)); /* All interrupts off */ + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_B)); /* All interrupts off */ + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_C)); /* All interrupts off */ + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_D)); /* All interrupts off */ +} + +static void CreateESCC8Port(SAB_CHIP *cptr, unsigned int portno, unsigned int function) +{ + SAB_BOARD *bptr; + SAB_PORT *pptr; + extern void sab8253x_setup_ttyport(struct sab_port *p_port) ; + + ++NumSab8253xPorts; + bptr = cptr->c_board; + pptr = (SAB_PORT*) kmalloc(sizeof(SAB_PORT), GFP_KERNEL); + if(pptr == NULL) + { + printk(KERN_ALERT + "auraXX20n: Failed to create ESCC2 port structure on chip %p on board %p.\n", + cptr, bptr); + return; + } + memset(pptr, 0, sizeof(SAB_PORT)); + DEBUGPRINT + ((KERN_ALERT "Setting up port %d, chipno %d for %s type board number %d.\n", + portno, cptr->c_chipno, board_type[bptr->b_type],bptr->board_number)); + pptr->portno = portno; + pptr->chip=cptr; + pptr->board=bptr; + pptr->open_type=OPEN_NOT; + pptr->is_console=0; + pptr->regs= + (union sab82532_regs *) + (((unsigned int)cptr->c_regs) + + (portno * SAB82538_REG_SIZE)); + pptr->type = cptr->c_revision; + pptr->function = function; + + pptr->irq = bptr->b_irq; + + pptr->dsr.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_C; + pptr->dsr.mask = 0x1 << portno; + pptr->dsr.inverted = 1; + pptr->dsr.irq=PIS_IDX; /* need to check this constant */ + pptr->dsr.irqmask=0x1 << portno; + pptr->dsr.cnst = 0; + + pptr->txclkdir.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_A; + pptr->txclkdir.mask = 0x1 << portno; + /* NOTE: Early 8 ports boards had different tx clkdir sense */ + pptr->txclkdir.inverted = 1; + + pptr->dtr.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_B; + pptr->dtr.mask = 0x1 << portno; + pptr->dtr.inverted = 1; + pptr->dtr.cnst = 0; + + pptr ->dcd.reg = (unsigned char *)&(VSTR); + + DEBUGPRINT((KERN_ALERT "cd register set to 0x%p\n", pptr ->dcd.reg)); + + pptr->dcd.mask = SAB82532_VSTR_CD; + pptr->dcd.inverted = 1; + pptr->dcd.irq=ISR0_IDX; + pptr->dcd.irqmask=SAB82532_ISR0_CDSC; + pptr->dcd.cnst = 0; + + pptr->cts.reg = (unsigned char *)&(STAR); + pptr->cts.mask = SAB82532_STAR_CTS; + pptr->cts.inverted = 0; + pptr->cts.irq=ISR1_IDX; + pptr->cts.irqmask=SAB82532_ISR1_CSC; + pptr->cts.cnst = 0; + + pptr->rts.reg = (unsigned char *)&(MODE); + pptr->rts.mask = SAB82532_MODE_FRTS; + pptr->rts.inverted = 1; + pptr->rts.cnst = SAB82532_MODE_RTS; + + + /* Set the read and write function */ + pptr->readbyte=aura_readb; + pptr->readword=aura_readw; + pptr->writebyte=aura_writeb; + pptr->writeword=aura_writew; + pptr->readfifo=aura_readfifo; + pptr->writefifo=aura_writefifo; + + sab8253x_setup_ttyport(pptr); /* asynchronous */ + /* ttys are default, basic */ + /* initialization, everything */ + /* else works as a modification */ + /* thereof */ + + pptr->next = AuraPortRoot; + AuraPortRoot = pptr; + pptr->next_by_chip = cptr->c_portbase; + cptr->c_portbase = pptr; + pptr->next_by_board = bptr->board_portbase; + bptr->board_portbase = pptr; +} + +/* Multichannel server functions */ + +static SAB_CHIP* CreateESCC8fromCIM(SAB_BOARD *bptr, AURA_CIM *cim, unsigned int chipno) +{ + SAB_CHIP *cptr; + unsigned int regbase; + + printk(KERN_ALERT + "auraXX20n: creating ESCC8 %d structure on board %p from cim %p.\n", + chipno, bptr, cim); + + cptr = (SAB_CHIP*) kmalloc(sizeof(SAB_CHIP), GFP_KERNEL); + if(cptr == NULL) + { + printk(KERN_ALERT + "auraXX20n: Failed to create ESCC8 structure %d on board %p at from cim %p.\n", + chipno, bptr, cim); + return NULL; + } + + memset(cptr, 0, sizeof(SAB_CHIP)); + cptr->chip_type = ESCC8; + cptr->c_board = bptr; + cptr->c_cim = cim; + cptr->c_chipno = chipno; + cptr->c_revision = + (readb((unsigned char *) (bptr->CIMCMD_REG + + (CIMCMD_RDREGB | (((chipno*8) << 6) | SAB85232_REG_VSTR)))) + & SAB82532_VSTR_VN_MASK); + cptr->c_nports = 8; + cptr->c_portbase = NULL; /* used for the list of ports associated + with this chip + */ + cptr->next = AuraChipRoot; + AuraChipRoot = cptr; + cptr->next_by_board = bptr->board_chipbase; + bptr->board_chipbase = cptr; + + cptr->next_by_cim = cim->ci_chipbase; + cim->ci_chipbase = cptr; + + printk(KERN_ALERT "auraXX20n: chip %d on board %p is revision %d.\n", + cptr->c_chipno, bptr, cptr->c_revision); + + /* lets set up the generic parallel + * port register which is used to + * control signaling and other stuff*/ + + /* SAB82538 4 8-bits parallel ports + * To summarize the use of the parallel port: + * RS-232 + * Parallel port A -- TxClkdir control (output) ports 0 - 7 + * Parallel port B -- DTR (output) ports 0 - 7 + * Parallel port C -- DSR (input) ports 0 - 7 + * Parallel port D -- driver power down (output) drivers 0 - 3 + * + * Note port D is not used on recent boards + */ + + regbase = (unsigned int) + (bptr->CIMCMD_REG + (0 | (((chipno*8) << 6) | 0))); /* need to add in RDB/WRB cmd bits + * and reg offset (> 32) */ + + DEBUGPRINT((KERN_ALERT "Setting up parallel port A (0x%x), 0x%x, 0x%x, 0x%x\n", regbase, + SAB82538_REG_PCR_A, SAB82538_REG_PIM_A, SAB82538_REG_PVR_A)); + + /* Configuring Parallel Port A (Clkdir)*/ + writeb(0x00,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PCR_A)); /* All output bits */ + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_A)); /* All interrupts off */ + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PVR_A)); /* All low */ + + DEBUGPRINT((KERN_ALERT "Setting up parallel port B (0x%x), 0x%x, 0x%x, 0x%x\n", regbase, + SAB82538_REG_PCR_B,SAB82538_REG_PIM_B,SAB82538_REG_PVR_B)); + + writeb(0x00,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PCR_B)); /* All output bits */ + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_B)); /* All interrupts off */ + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PVR_B)); /* All low */ + + DEBUGPRINT((KERN_ALERT "Setting up parallel port C (0x%x), 0x%x, 0x%x, 0x%x\n", regbase, + SAB82538_REG_PCR_C, SAB82538_REG_PIM_C, SAB82538_REG_PVR_C)); + + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PCR_C)); /* All intput bits */ + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_C)); /* All interrupts off */ + /* don't set port value register on input register */ + + /* Configuring Parallel Port D */ + + DEBUGPRINT((KERN_ALERT "Setting up parallel port D (0x%x), 0x%x, 0x%x, 0x%x\n", regbase, + SAB82538_REG_PCR_D, SAB82538_REG_PIM_D, SAB82538_REG_PVR_D)); + writeb(0x0f,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PCR_D)); /* 4 input bits */ + writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_D)); /* All interrupts off */ + /* don't set port value register on input register */ + + /* The priority rotation thing */ + + DEBUGPRINT((KERN_ALERT "Setting IVA (0x%x + 0x%x = 0x%x\n", regbase, + SAB82532_REG_IVA, regbase + SAB82532_REG_IVA)); + + writeb(SAB82538_IVA_ROT, ((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82532_REG_IVA)); + writeb(0, ((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82532_REG_IPC)); + + cptr->c_regs = (void*) regbase; + cptr->int_disable = DisableESCC8InterruptsFromCIM; + return cptr; +} + +static void CreateESCC8PortWithCIM(SAB_CHIP *cptr, unsigned int portno, + AURA_CIM *cim, unsigned flag) +{ + SAB_BOARD *bptr; + SAB_PORT *pptr; + extern void sab8253x_setup_ttyport(struct sab_port *p_port) ; + + ++NumSab8253xPorts; + bptr = cptr->c_board; + pptr = (SAB_PORT*) kmalloc(sizeof(SAB_PORT), GFP_KERNEL); + if(pptr == NULL) + { + printk(KERN_ALERT + "auraXX20n: Failed to create ESCC2 port structure on chip %p on board %p.\n", + cptr, bptr); + return; + } + memset(pptr, 0, sizeof(SAB_PORT)); + DEBUGPRINT + ((KERN_ALERT "Setting up port %d, chipno %d for %s type board number %d.\n", + portno, cptr->c_chipno, board_type[bptr->b_type],bptr->board_number)); + pptr->portno = portno; + pptr->chip=cptr; + pptr->board=bptr; + pptr->open_type=OPEN_NOT; + pptr->is_console=0; + pptr->regs= + (union sab82532_regs *) + (((unsigned int)cptr->c_regs) + + (portno << 6)); /* addressing is different when there is a cim */ + pptr->type = cptr->c_revision; + pptr->function = (((cim->ci_flags & CIM_SYNC) || flag) ? FUNCTION_NR : + FUNCTION_AO); + + pptr->irq = bptr->b_irq; + + pptr->dsr.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_C; + pptr->dsr.mask = 0x1 << portno; + pptr->dsr.inverted = 1; + pptr->dsr.irq=PIS_IDX; /* need to check this constant */ + pptr->dsr.irqmask=0x1 << portno; + pptr->dsr.cnst = 0; + + pptr->txclkdir.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_A; + pptr->txclkdir.mask = 0x1 << portno; + /* NOTE: Early 8 ports boards had different tx clkdir sense */ + pptr->txclkdir.inverted = 1; + + pptr->dtr.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_B; + pptr->dtr.mask = 0x1 << portno; + pptr->dtr.inverted = 1; + pptr->dtr.cnst = 0; + + pptr->dcd.reg = ((unsigned char *)pptr->regs) + SAB85232_REG_VSTR; + + DEBUGPRINT((KERN_ALERT "cd register set to 0x%p\n", pptr->dcd.reg)); + + pptr->dcd.mask = SAB82532_VSTR_CD; + pptr->dcd.inverted = 1; + pptr->dcd.irq=ISR0_IDX; + pptr->dcd.irqmask=SAB82532_ISR0_CDSC; + pptr->dcd.cnst = 0; + + pptr->cts.reg = (unsigned char *)&(STAR); + pptr->cts.mask = SAB82532_STAR_CTS; + pptr->cts.inverted = 0; + pptr->cts.irq=ISR1_IDX; + pptr->cts.irqmask=SAB82532_ISR1_CSC; + pptr->cts.cnst = 0; + + pptr->rts.reg = (unsigned char *)&(MODE); + pptr->rts.mask = SAB82532_MODE_FRTS; + pptr->rts.inverted = 1; + pptr->rts.cnst = SAB82532_MODE_RTS; + + + /* Set the read and write function */ + pptr->readbyte=wmsaura_readb; + pptr->readword=wmsaura_readw; + pptr->writebyte=wmsaura_writeb; + pptr->writeword=wmsaura_writew; + pptr->readfifo=wmsaura_readfifo; + pptr->writefifo=wmsaura_writefifo; + + sab8253x_setup_ttyport(pptr); /* asynchronous */ + /* ttys are default, basic */ + /* initialization, everything */ + /* else works as a modification */ + /* thereof */ + + pptr->next = AuraPortRoot; + AuraPortRoot = pptr; + + pptr->next_by_chip = cptr->c_portbase; + cptr->c_portbase = pptr; + + pptr->next_by_board = bptr->board_portbase; + bptr->board_portbase = pptr; + + pptr->next_by_cim = cim->ci_portbase; + cim->ci_portbase = pptr; +} + +static void CreateCIMs(SAB_BOARD *bptr) +{ + unsigned int cimnum; + unsigned char *wrcsr; + unsigned char *rdcsr; + unsigned char tmp; + AURA_CIM *cim; + unsigned short intrmask; + + for(intrmask = 0, cimnum = 0; cimnum < MAX_NCIMS; ++cimnum) + { + intrmask >>= 2; + + /* + * The hardware is mapped. Try writing to CIM CSR. + */ + wrcsr = bptr->CIMCMD_REG + + (CIMCMD_WRCIMCSR | (cimnum << CIMCMD_CIMSHIFT)); + rdcsr = bptr->CIMCMD_REG + + (CIMCMD_RDCIMCSR | (cimnum << CIMCMD_CIMSHIFT)); + + /* Try to write an 0xff */ + writeb((unsigned char) 0xff, (unsigned char *) wrcsr); + /* and read it back */ + tmp = (unsigned char) readb((unsigned char *) rdcsr); + DEBUGPRINT((KERN_ALERT + "aura wan mcs: wrcsr %p rdcsr %p cim %d 0xff readback: 0x%x.\n", + (void*) wrcsr, (void*) rdcsr, cimnum, tmp)); + + /* make sure it's really all ones. */ + if ((tmp & CIMCMD_CIMCSR_TESTMASK) != CIMCMD_CIMCSR_TESTMASK) + { + printk(KERN_ALERT + "aura wan mcs: not found -- wrcsr %p rdcsr %p cim %d 0xff readback: 0x%x.\n", + (void*) wrcsr, (void*) rdcsr, cimnum, tmp); + continue; + } + + /* Try to write a zero */ + writeb((unsigned char) 0, (unsigned char*) wrcsr); + /* and read it back */ + tmp = (unsigned char) readb((unsigned char *) rdcsr); + DEBUGPRINT((KERN_ALERT + "aura wan mcs: wrcsr %p rdcsr %p cim %d 0x0 readback: 0x%x.\n", + (void*) wrcsr, (void*) rdcsr, cimnum, tmp)); + + /* make sure it's really zero. */ + if ((tmp & CIMCMD_CIMCSR_TESTMASK) != 0) + { + printk(KERN_ALERT + "aura wan mcs: not found -- wrcsr %p rdcsr %p cim %d 0x0 readback: 0x%x.\n", + (void*) wrcsr, (void*) rdcsr, cimnum, tmp); + continue; + } + cim = (AURA_CIM*) kmalloc(sizeof(AURA_CIM), GFP_KERNEL); + if(cim == NULL) + { + printk(KERN_ALERT + "aura wan mcs: unable to allocate memory, board %p, cim %d.\n", + bptr, cimnum); + continue; + } + cim->ci_num = cimnum; + cim->ci_board = bptr; + cim->ci_chipbase = NULL; + cim->ci_portbase = NULL; + cim->ci_nports = CIM_NPORTS; + cim->ci_port0lbl = cimnum * CIM_NPORTS; + if (mcs_ciminit(bptr, cim) == FALSE) + { + kfree(cim); + continue; + } + intrmask |= 0xc0; /* turn on the high two bits + * a little obscure, borrowed + * from solaris driver 0th cim + * gets lowest two bits*/ + cim->next = AuraCimRoot; + AuraCimRoot = cim; + cim->next_by_mcs = bptr->b_cimbase; + bptr->b_cimbase = cim; + printk(KERN_ALERT + "aura wan mcs: Created cim %d type %d on board %p.\n", + cim->ci_num, cim->ci_type, bptr); + } + bptr->b_intrmask = intrmask; +} + +/* put the chips on the boards */ + +static void SetupAllChips(SAB_BOARD *bptr) +{ /* note that port ordering */ + /* is important in chip setup */ + /* the open routine walks the */ + /* port list for sync and async */ + /* ttys */ + SAB_CHIP *chip; + AURA_CIM *cim; + unsigned int chipno; + + switch(bptr->b_type) + { + case BD_1020P: + case BD_1020CP: + /* setup 1 ESCC2 */ + chip = CreateESCC2(bptr, 0); + if(chip != NULL) + { + CreateESCC2Port(chip, 1, FUNCTION_NA); + CreateESCC2Port(chip, 0, FUNCTION_AO); + } + + break; + case BD_1520P: + case BD_1520CP: + /* setup 1 ESCC2 */ + chip = CreateESCC2(bptr, 0); + if(chip != NULL) + { + CreateESCC2Port(chip, 1, FUNCTION_NA); + CreateESCC2Port(chip, 0, FUNCTION_NR); + } + break; + case BD_2020P: + case BD_2020CP: + /* setup 1 ESCC2 */ + chip = CreateESCC2(bptr, 0); + if(chip != NULL) + { + CreateESCC2Port(chip, 1, FUNCTION_AO); + CreateESCC2Port(chip, 0, FUNCTION_AO); + } + break; + case BD_2520P: + case BD_2520CP: + /* setup 1 ESCC2 */ + chip = CreateESCC2(bptr, 0); + if(chip != NULL) + { + CreateESCC2Port(chip, 1, FUNCTION_NR); + CreateESCC2Port(chip, 0, FUNCTION_NR); + } + break; + case BD_4020P: + case BD_4020CP: /* do chips in reverCse + order so that they + are on lists in forward + order + */ + /* setup 2 ESCC2 */ + chip = CreateESCC2(bptr, AURORA_4X20_CHIP_OFFSET); + if(chip != NULL) + { + CreateESCC2Port(chip, 1, FUNCTION_AO); + CreateESCC2Port(chip, 0, FUNCTION_AO); + } + chip = CreateESCC2(bptr, 0); + if(chip != NULL) + { + CreateESCC2Port(chip, 1, FUNCTION_AO); + CreateESCC2Port(chip, 0, FUNCTION_AO); + } + break; + case BD_4520P: + case BD_4520CP: + /* setup 2 ESCC2 */ + chip = CreateESCC2(bptr, AURORA_4X20_CHIP_OFFSET); + if(chip != NULL) + { + CreateESCC2Port(chip, 1, FUNCTION_NR); + CreateESCC2Port(chip, 0, FUNCTION_NR); + } + chip = CreateESCC2(bptr, 0); + if(chip != NULL) + { + CreateESCC2Port(chip, 1, FUNCTION_NR); + CreateESCC2Port(chip, 0, FUNCTION_NR); + } + break; + case BD_8020P: + case BD_8020CP: + /* setup 1 ESCC8 */ + chip = CreateESCC8(bptr, 0); + if(chip != NULL) + { + CreateESCC8Port(chip, 7, FUNCTION_AO); + CreateESCC8Port(chip, 6, FUNCTION_AO); + CreateESCC8Port(chip, 5, FUNCTION_AO); + CreateESCC8Port(chip, 4, FUNCTION_AO); + CreateESCC8Port(chip, 3, FUNCTION_AO); + CreateESCC8Port(chip, 2, FUNCTION_AO); + CreateESCC8Port(chip, 1, FUNCTION_AO); + CreateESCC8Port(chip, 0, FUNCTION_AO); + } + break; + case BD_8520P: + case BD_8520CP: + /* setup 1 ESCC8 */ + chip = CreateESCC8(bptr, 0); + if(chip != NULL) + { + CreateESCC8Port(chip, 7, FUNCTION_NR); + CreateESCC8Port(chip, 6, FUNCTION_NR); + CreateESCC8Port(chip, 5, FUNCTION_NR); + CreateESCC8Port(chip, 4, FUNCTION_NR); + CreateESCC8Port(chip, 3, FUNCTION_NR); + CreateESCC8Port(chip, 2, FUNCTION_NR); + CreateESCC8Port(chip, 1, FUNCTION_NR); + CreateESCC8Port(chip, 0, FUNCTION_NR); + } + break; + + case BD_WANMCS: + CreateCIMs(bptr); + for(chipno = 7, cim = bptr->b_cimbase; + cim != NULL; cim = cim->next_by_mcs) + { + chip = CreateESCC8fromCIM(bptr, cim, chipno--); + if(chip != NULL) + { + CreateESCC8PortWithCIM(chip, 7, cim, 0); + CreateESCC8PortWithCIM(chip, 6, cim, 0); + CreateESCC8PortWithCIM(chip, 5, cim, 0); + CreateESCC8PortWithCIM(chip, 4, cim, 0); + CreateESCC8PortWithCIM(chip, 3, cim, 0); + CreateESCC8PortWithCIM(chip, 2, cim, 0); + CreateESCC8PortWithCIM(chip, 1, cim, 0); + CreateESCC8PortWithCIM(chip, 0, cim, 0); + } + chip = CreateESCC8fromCIM(bptr, cim, chipno--); + if(chip != NULL) + { + CreateESCC8PortWithCIM(chip, 7, cim, 0); + CreateESCC8PortWithCIM(chip, 6, cim, 0); + CreateESCC8PortWithCIM(chip, 5, cim, 0); + CreateESCC8PortWithCIM(chip, 4, cim, 0); + CreateESCC8PortWithCIM(chip, 3, cim, 0); + CreateESCC8PortWithCIM(chip, 2, cim, 0); + CreateESCC8PortWithCIM(chip, 1, cim, 0); + CreateESCC8PortWithCIM(chip, 0, cim, 1); + } + } + break; + + default: + printk(KERN_ALERT "auraXX20n: unable to set up chip for board %p.\n", bptr); + break; + } +} + +/* finding the cards by PCI device type */ + +static SAB_BOARD* find_ati_cpci_card(void) +{ + struct pci_dev *pdev; + unsigned char bus; + unsigned char devfn; + unsigned char pci_latency; + unsigned short pci_command; + SAB_BOARD *bptr; + unsigned control; + unsigned does_sync; + unsigned use_1port; + + printk(KERN_ALERT "auraXX20n: finding ati cpci cards.\n"); + + bptr = (SAB_BOARD*)kmalloc(sizeof(SAB_BOARD), GFP_KERNEL); + if(bptr == NULL) + { + printk(KERN_ALERT "auraXX20n: could not allocate board memory!\n"); + return 0; + } + memset(bptr, 0, sizeof(SAB_BOARD)); + + if(!pcibios_present()) + { + printk(KERN_ALERT "auraXX20n: system does not support PCI bus.\n"); + kfree(bptr); + return 0; + } + DEBUGPRINT((KERN_ALERT "auraXX20n: System supports PCI bus.\n")); + + CPCIRESTART: + if(pdev = pci_find_device(sab8253x_vendor_id, sab8253x_cpci_device_id, XX20lastpdev), + pdev == NULL) + { + printk(KERN_ALERT "auraXX20n: could not find cpci card.\n"); + kfree(bptr); + return 0; + } + + DEBUGPRINT((KERN_ALERT "auraXX20n: found multiport CPCI serial card.\n")); + + XX20lastpdev = pdev; + DEBUGPRINT((KERN_ALERT "auraXX20n: found ATI PLX 9050, %p.\n", pdev)); + bptr->b_dev = *pdev; + + /* the Solaris and model linux drivers + * comment that there are problems with + * getting the length via PCI operations + * seems to work for 2.4 + */ + bptr->length0 = (unsigned int) pci_resource_len(pdev, 0); + bptr->length1 = (unsigned int) pci_resource_len(pdev, 1); + bptr->length2 = (unsigned int) pci_resource_len(pdev, 2); + bptr->b_irq = pdev->irq; + + + DEBUGPRINT((KERN_ALERT + "auraXX20n: base address 0 is %p, len is %x.\n", + (void*) pci_base_address(pdev, 0), bptr->length0)); + DEBUGPRINT((KERN_ALERT + "auraXX20n: base address 1 is %p, len is %x.\n", + (void*) pci_base_address(pdev, 1), bptr->length1)); + DEBUGPRINT((KERN_ALERT + "auraXX20n: base address 2 is %p, len is %x.\n", + (void*) pci_base_address(pdev, 2), + bptr->length2)); + + DEBUGPRINT((KERN_ALERT "auraXX20n: interrupt is %i.\n", pdev->irq)); + bus = pdev->bus->number; + devfn = pdev->devfn; + DEBUGPRINT((KERN_ALERT "auraXX20n: bus is %x, slot is %x.\n", bus, PCI_SLOT(devfn))); + pcibios_read_config_word(bus, devfn, PCI_COMMAND, &pci_command); +#if 0 + /* The Aurora card does not act as a PCI master + * ugh!! + */ + new_command = pci_command | PCI_COMMAND_MASTER; + if(pci_command != new_command) + { + DEBUGPRINT((KERN_ALERT + "auraXX20n: the PCI BIOS has not enabled this device!" + " Updating PCI command %4.4x->%4.4x.\n", + pci_command, + new_command)); + pcibios_write_config_word(bus, devfn, PCI_COMMAND, + new_command); + } + else + { + DEBUGPRINT + ((KERN_ALERT + "auraXX20n: the PCI BIOS has enabled this device as master!\n")); + } +#endif + if((pci_command & PCI_COMMAND_MASTER) != PCI_COMMAND_MASTER) + { + DEBUGPRINT((KERN_ALERT "auraXX20n: Aurora card is not a bus master.\n")); + } + + pcibios_read_config_byte(bus, devfn, PCI_LATENCY_TIMER, + &pci_latency); + if (pci_latency < 32) + { + DEBUGPRINT + ((KERN_ALERT + "auraXX20n: PCI latency timer (CFLT) is low at %i.\n", pci_latency)); + /* may need to change the latency */ +#if 0 + pcibios_write_config_byte(bus, devfn, PCI_LATENCY_TIMER, 32); +#endif + } + else + { + DEBUGPRINT((KERN_ALERT + "auraXX20n: PCI latency timer (CFLT) is %#x.\n", + pci_latency)); + } + bptr->virtbaseaddress0 = ioremap_nocache(pci_base_address(pdev, 0), + bptr->length0); + if(bptr->virtbaseaddress0 == NULL) + { + printk(KERN_ALERT + "auraXX20n: unable to remap physical address %p.\n", + (void*) pci_base_address(pdev, 0)); + + goto CPCIRESTART; + } + + bptr->b_bridge = (PLX9050*) bptr->virtbaseaddress0; /* MAKE SURE INTS ARE OFF */ + writel(PLX_INT_OFF, &(bptr->b_bridge->intr)); + + printk + (KERN_ALERT + "auraXX20n: remapped physical address %p to virtual address %p.\n", + (void*) pci_base_address(pdev, 0), (void*) bptr->virtbaseaddress0); + + dump_ati_adapter_registers((unsigned int*) bptr->virtbaseaddress0, bptr->length0); + + if(*(unsigned int*)bptr->virtbaseaddress0 == -1) /* XP7 problem? */ + { + printk(KERN_ALERT + "auraXX20n: unable to access PLX 9050 registers at %p.\n", + (void*)bptr->virtbaseaddress0); + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress0); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + + goto CPCIRESTART; + } + + bptr->virtbaseaddress2 = ioremap_nocache(pci_base_address(pdev, 2), + bptr->length2); + if(bptr->virtbaseaddress2 == NULL) + { + printk(KERN_ALERT + "auraXX20n: unable to remap physical address %p.\n", + (void*) pci_base_address(pdev, 2)); + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress0); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + + goto CPCIRESTART; + } + + DEBUGPRINT + ((KERN_ALERT + "auraXX20n: remapped physical address %p to virtual address %p.\n", + (void*) pci_base_address(pdev, 2), (void*) bptr->virtbaseaddress2)); + + /* we get clockrate from serial eeprom */ + if (!plx9050_eprom_read(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + (unsigned short*) bptr->b_eprom, + (unsigned char) 0, EPROM9050_SIZE)) + { + printk(KERN_ALERT "auraXX20n: Could not read serial eprom.\n"); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + iounmap((void*)bptr->virtbaseaddress2); + bptr->virtbaseaddress2 = 0; + + goto CPCIRESTART; + } + + printk(KERN_ALERT "auraXX20n: dumping serial eprom.\n"); + dump_ati_adapter_registers((unsigned int*) bptr->b_eprom, 2 * EPROM9050_SIZE); + + if(*(unsigned int*)bptr->b_eprom != PCIMEMVALIDCPCI) /* bridge problem? */ + { + printk(KERN_ALERT "auraXX20n: unable to access valid serial eprom data.\n"); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + iounmap((void*)bptr->virtbaseaddress2); + bptr->virtbaseaddress2 = 0; + + goto CPCIRESTART; + } + + if(((unsigned short*) bptr->b_eprom)[EPROMPREFETCHOFFSET] & PREFETCHBIT) + { + ++sab8253x_rebootflag; + printk(KERN_ALERT "8253x: eeprom programmed for prefetchable memory resources; must reprogram!!\n"); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WENCMD, NM93_WENADDR, 0); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WRITECMD, + 9, + (((unsigned short*) bptr->b_eprom)[EPROMPREFETCHOFFSET] & (~PREFETCHBIT))); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WDSCMD, NM93_WDSADDR, 0); + } + /* get SYNC and ONEPORT values */ + + control = readl(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl); + /* note we use the actual address + * of the control register in + * memory + */ + + if(control & AURORA_MULTI_SYNCBIT) + { + does_sync = 0; + } + else + { + does_sync = 1; + } + + if(control & AURORA_MULTI_1PORTBIT) + { + use_1port = 1; + } + else + { + use_1port = 0; + } + + + /* Figure out the board */ + switch(bptr->length2) + { + case AURORA_4X20_SIZE: + if(does_sync) + { + bptr->b_type = BD_4520CP; + bptr->b_nchips = 2; + bptr->b_nports = 4; + bptr->b_flags = BD_SYNC; + bptr->b_cimbase = NULL; + bptr->board_number = BD4520CPcounter; /* keep track of boardnumber for naming devices */ + ++BD4520CPcounter; + printk(KERN_ALERT "auraXX20n: Found Saturn 4520CP.\n"); + } + else + { + bptr->b_type = BD_4020CP; + bptr->b_nchips = 2; + bptr->b_nports = 4; + bptr->b_flags = 0x0; + bptr->b_cimbase = NULL; + bptr->board_number = BD4020CPcounter; + ++BD4020CPcounter; + printk(KERN_ALERT "auraXX20n: Found Apollo 4020CP.\n"); + } + break; + case AURORA_8X20_SIZE: + if(does_sync) + { + bptr->b_type = BD_8520CP; + bptr->b_nchips = 1; + bptr->b_nports = 8; + bptr->b_flags = BD_SYNC; + bptr->b_cimbase = NULL; + bptr->board_number = BD8520CPcounter; + ++BD8520CPcounter; + printk(KERN_ALERT "auraXX20n: Found Saturn 8520CP.\n"); + } + else + { + bptr->b_type = BD_8020CP; + bptr->b_nchips = 1; + bptr->b_nports = 8; + bptr->b_flags = 0x0; + bptr->b_cimbase = NULL; + bptr->board_number = BD8020CPcounter; + ++BD8020CPcounter; + printk(KERN_ALERT "auraXX20n: Found Apollo 8020CP.\n"); + } + break; + case AURORA_2X20_SIZE: + if(does_sync) + { + if(use_1port) + { + bptr->b_type = BD_1520CP; + printk(KERN_ALERT "auraXX20n: Found Saturn 1520CP.\n"); + bptr->b_nchips = 1; + bptr->b_nports = 1; + bptr->b_flags = BD_SYNC; + bptr->b_cimbase = NULL; + bptr->board_number = BD1520CPcounter; + ++BD1520CPcounter; + printk(KERN_ALERT "auraXX20n: Found Saturn 1520CP.\n"); + } + else + { + bptr->b_type = BD_2520CP; + bptr->b_nchips = 1; + bptr->b_nports = 2; + bptr->b_flags = BD_SYNC; + bptr->b_cimbase = NULL; + bptr->board_number = BD2520CPcounter; + ++BD2520CPcounter; + printk(KERN_ALERT "auraXX20n: Found Saturn 2520CP.\n"); + } + } + else + { + if(use_1port) + { + bptr->b_type = BD_1020CP; + bptr->b_nchips = 1; + bptr->b_nports = 1; + bptr->b_flags = 0x0; + bptr->b_cimbase = NULL; + bptr->board_number = BD1020CPcounter; + ++BD1020CPcounter; + printk(KERN_ALERT "auraXX20n: Found Apollo 1020CP.\n"); + } + else + { + bptr->b_type = BD_2020CP; + bptr->b_nchips = 1; + bptr->b_nports = 2; + bptr->b_flags = 0x0; + bptr->b_cimbase = NULL; + bptr->board_number = BD2020CPcounter; + ++BD2020CPcounter; + printk(KERN_ALERT "auraXX20n: Found Apollo 2020CP.\n"); + } + } + break; + default: + printk(KERN_ALERT "Error: Board could not be identified\n"); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + iounmap((void*)bptr->virtbaseaddress2); + bptr->virtbaseaddress2 = 0; + + goto CPCIRESTART; + } + + /* Let's get the clockrate right -- ugh!*/ + + bptr->b_clkspeed = bptr->b_eprom[AURORA_MULTI_EPROM_CLKLSW/2]; + + if(bptr->b_clkspeed == -1) /* misprogrammed -- ugh. */ + { + switch(bptr->b_type) + { + case BD_8520CP: + case BD_8020CP: + bptr->b_clkspeed = AURORA_MULTI_CLKSPEED/4; + break; + default: + bptr->b_clkspeed = AURORA_MULTI_CLKSPEED; + break; + + } + printk(KERN_ALERT "auraXX20n: UNKNOWN CLOCKSPEED -- ASSUMING %ld.\n", bptr->b_clkspeed); + + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WENCMD, NM93_WENADDR, 0); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WRITECMD, + 54, (unsigned short) bptr->b_clkspeed); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WRITECMD, + 55, (unsigned short) (bptr->b_clkspeed >> 16)); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WDSCMD, NM93_WDSADDR, 0); + } + + return bptr; +} + +static SAB_BOARD* find_ati_wanms_card(void) /* wan multichanner server == mcs [ multichannel server] */ +{ + struct pci_dev *pdev; + unsigned char bus; + unsigned char devfn; + unsigned char pci_latency; + unsigned short pci_command; + SAB_BOARD *bptr; + int resetresult; + + printk(KERN_ALERT "auraXX20n: finding ati mcs cards.\n"); + + bptr = (SAB_BOARD*)kmalloc(sizeof(SAB_BOARD), GFP_KERNEL); + if(bptr == NULL) + { + printk(KERN_ALERT "auraXX20n: could not allocate board memory!\n"); + return 0; + } + memset(bptr, 0, sizeof(SAB_BOARD)); + + if(!pcibios_present()) + { + printk(KERN_ALERT "auraXX20n: system does not support PCI bus.\n"); + kfree(bptr); + return 0; + } + DEBUGPRINT((KERN_ALERT "auraXX20n: System supports PCI bus.\n")); + + MCSRESTART: + if(pdev = pci_find_device(sab8253x_vendor_id, sab8253x_wmcs_device_id, XX20lastpdev), + pdev == NULL) + { + printk(KERN_ALERT "auraXX20n: could not find mcs card.\n"); + kfree(bptr); + return 0; + } + + DEBUGPRINT((KERN_ALERT "auraXX20n: found mcs card.\n")); + + XX20lastpdev = pdev; + DEBUGPRINT((KERN_ALERT "auraXX20n: found ATI S5920, %p.\n", pdev)); + bptr->b_dev = *pdev; + + /* the Solaris and model linux drivers + * comment that there are problems with + * getting the length via PCI operations + * seems to work for 2.4 + */ + bptr->length0 = (unsigned int) pci_resource_len(pdev, 0); /* AMCC 5920 operation registers + includes access to serial eprom */ + bptr->length1 = (unsigned int) pci_resource_len(pdev, 1); /* commands to remote cards */ + bptr->length2 = (unsigned int) pci_resource_len(pdev, 2); /* command to host card */ + bptr->length3 = (unsigned int) pci_resource_len(pdev, 3); /* RFIFO cache */ + bptr->b_irq = pdev->irq; + + DEBUGPRINT((KERN_ALERT + "auraXX20n: base address 0 is %p, len is %x.\n", + (void*) pci_base_address(pdev, 0), bptr->length0)); + DEBUGPRINT((KERN_ALERT + "auraXX20n: base address 1 is %p, len is %x.\n", + (void*) pci_base_address(pdev, 1), bptr->length1)); + DEBUGPRINT((KERN_ALERT + "auraXX20n: base address 2 is %p, len is %x.\n", + (void*) pci_base_address(pdev, 2), + bptr->length2)); + DEBUGPRINT((KERN_ALERT + "auraXX20n: base address 3 is %p, len is %x.\n", + (void*) pci_base_address(pdev, 3), + bptr->length3)); + + DEBUGPRINT((KERN_ALERT "auraXX20n: interrupt is %i.\n", pdev->irq)); + bus = pdev->bus->number; + devfn = pdev->devfn; + DEBUGPRINT((KERN_ALERT "auraXX20n: bus is %x, slot is %x.\n", bus, PCI_SLOT(devfn))); + pcibios_read_config_word(bus, devfn, PCI_COMMAND, &pci_command); + +#if 0 + /* The Aurora card does not act as a PCI master + * ugh!! + */ + new_command = pci_command | PCI_COMMAND_MASTER; + if(pci_command != new_command) + { + DEBUGPRINT((KERN_ALERT + "auraXX20n: the PCI BIOS has not enabled this device!" + " Updating PCI command %4.4x->%4.4x.\n", + pci_command, + new_command)); + pcibios_write_config_word(bus, devfn, PCI_COMMAND, + new_command); + } + else + { + DEBUGPRINT + ((KERN_ALERT + "auraXX20n: the PCI BIOS has enabled this device as master!\n")); + } +#endif + + if((pci_command & PCI_COMMAND_MASTER) != PCI_COMMAND_MASTER) + { + DEBUGPRINT((KERN_ALERT "auraXX20n: Aurora card is not a bus master.\n")); + } + + pcibios_read_config_byte(bus, devfn, PCI_LATENCY_TIMER, + &pci_latency); + if (pci_latency < 32) + { + DEBUGPRINT + ((KERN_ALERT + "auraXX20n: PCI latency timer (CFLT) is low at %i.\n", pci_latency)); + /* may need to change the latency */ +#if 0 + pcibios_write_config_byte(bus, devfn, PCI_LATENCY_TIMER, 32); +#endif + } + else + { + DEBUGPRINT((KERN_ALERT + "auraXX20n: PCI latency timer (CFLT) is %#x.\n", + pci_latency)); + } + + bptr->virtbaseaddress0 = ioremap_nocache(pci_base_address(pdev, 0), + bptr->length0); + if(bptr->virtbaseaddress0 == NULL) + { + printk(KERN_ALERT + "auraXX20n: unable to remap physical address %p.\n", + (void*) pci_base_address(pdev, 0)); + goto MCSRESTART; + } + + bptr->b_bridge = (void*) bptr->virtbaseaddress0; /* b_bridge is not supposed + to be used by the AMCC based + products -- it is set just + in case */ + + printk(KERN_ALERT + "auraXX20n: remapped physical address %p to virtual address %p.\n", + (void*) pci_base_address(pdev, 0), (void*) bptr->virtbaseaddress0); + + /* unfortunate name -- works for any bridge */ + dump_ati_adapter_registers((unsigned int*) bptr->virtbaseaddress0, bptr->length0); + + if(*(unsigned int*)bptr->virtbaseaddress0 == -1) /* XP7 problem? */ + { + printk(KERN_ALERT + "auraXX20n: unable to access AMCC registers at %p.\n", + (void*)bptr->virtbaseaddress0); + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress0); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + goto MCSRESTART; /* try the next one if any */ + } + + writel(AMCC_INT_OFF, (unsigned int*)(bptr->AMCC_REG + AMCC_INTCSR)); + + bptr->virtbaseaddress1 = ioremap_nocache(pci_base_address(pdev, 1), + bptr->length1); + if(bptr->virtbaseaddress1 == NULL) + { + printk(KERN_ALERT + "auraXX20n: unable to remap physical address %p.\n", + (void*) pci_base_address(pdev, 1)); + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress0); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + goto MCSRESTART; + } + + DEBUGPRINT + ((KERN_ALERT + "auraXX20n: remapped physical address %p to virtual address %p.\n", + (void*) pci_base_address(pdev, 1), (void*) bptr->virtbaseaddress1)); + + /* next address space */ + bptr->virtbaseaddress2 = ioremap_nocache(pci_base_address(pdev, 2), + bptr->length2); + if(bptr->virtbaseaddress2 == NULL) + { + printk(KERN_ALERT + "auraXX20n: unable to remap physical address %p.\n", + (void*) pci_base_address(pdev, 2)); + + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress0); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress1); + iounmap((void*)bptr->virtbaseaddress1); + bptr->virtbaseaddress1 = 0; + goto MCSRESTART; + } + + DEBUGPRINT + ((KERN_ALERT + "auraXX20n: remapped physical address %p to virtual address %p.\n", + (void*) pci_base_address(pdev, 2), (void*) bptr->virtbaseaddress2)); + + bptr->virtbaseaddress3 = ioremap_nocache(pci_base_address(pdev, 3), + bptr->length3); + if(bptr->virtbaseaddress3 == NULL) + { + printk(KERN_ALERT + "auraXX20n: unable to remap physical address %p.\n", + (void*) pci_base_address(pdev, 3)); + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress0); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress1); + iounmap((void*)bptr->virtbaseaddress1); + bptr->virtbaseaddress1 = 0; + + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress2); + iounmap((void*)bptr->virtbaseaddress2); + bptr->virtbaseaddress2 = 0; + + goto MCSRESTART; + } + + DEBUGPRINT + ((KERN_ALERT + "auraXX20n: remapped physical address %p to virtual address %p.\n", + (void*) pci_base_address(pdev, 3), (void*) bptr->virtbaseaddress3)); + + bptr->b_type = BD_WANMCS; + + resetresult = wanmcs_reset(bptr); + writel(AMCC_INT_OFF, (unsigned int*)(bptr->AMCC_REG + AMCC_INTCSR)); + + if(resetresult == FALSE) + { + printk(KERN_ALERT "auraXX20n: unable to reset wan mcs %p.\n", bptr); + + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress0); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress1); + iounmap((void*)bptr->virtbaseaddress1); + bptr->virtbaseaddress1 = 0; + + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress2); + iounmap((void*)bptr->virtbaseaddress2); + bptr->virtbaseaddress2 = 0; + + + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress3); + iounmap((void*)bptr->virtbaseaddress3); + bptr->virtbaseaddress3 = 0; + + goto MCSRESTART; + } + + /* we get clockrate from serial eeprom */ + if (amcc_read_nvram((unsigned char*) bptr->b_eprom, + AMCC_NVRAM_SIZE, bptr->AMCC_REG) == FALSE) + { + printk(KERN_ALERT "auraXX20n: Could not read serial eprom.\n"); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + iounmap((void*)bptr->virtbaseaddress1); + bptr->virtbaseaddress1 = 0; + iounmap((void*)bptr->virtbaseaddress2); + bptr->virtbaseaddress2 = 0; + iounmap((void*)bptr->virtbaseaddress3); + bptr->virtbaseaddress3 = 0; + goto MCSRESTART; + } + printk(KERN_ALERT "auraXX20n: dumping serial eprom.\n"); + dump_ati_adapter_registers((unsigned int*) bptr->b_eprom, 2 * AMCC_NVRAM_SIZE); + if(bptr->b_eprom[AMCC_NVR_VENDEVID] != PCIMEMVALIDWMCS) + { + printk(KERN_ALERT "auraXX20: bad serial eprom, board %p.\n", bptr); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + iounmap((void*)bptr->virtbaseaddress1); + bptr->virtbaseaddress1 = 0; + iounmap((void*)bptr->virtbaseaddress2); + bptr->virtbaseaddress2 = 0; + iounmap((void*)bptr->virtbaseaddress3); + bptr->virtbaseaddress3 = 0; + goto MCSRESTART; + } + return bptr; +} + +/* initialize the auraXX20 */ +static SAB_BOARD* find_ati_multiport_card(void) +{ + struct pci_dev *pdev; + unsigned char bus; + unsigned char devfn; + unsigned char pci_latency; + unsigned short pci_command; + SAB_BOARD *bptr; + unsigned control; + unsigned does_sync; + unsigned use_1port; + + printk(KERN_ALERT "auraXX20n: finding ati cards.\n"); + + bptr = (SAB_BOARD*)kmalloc(sizeof(SAB_BOARD), GFP_KERNEL); + if(bptr == NULL) + { + printk(KERN_ALERT "auraXX20n: could not allocate board memory!\n"); + return 0; + } + memset(bptr, 0, sizeof(SAB_BOARD)); + + if(!pcibios_present()) + { + printk(KERN_ALERT "auraXX20n: system does not support PCI bus.\n"); + kfree(bptr); + return 0; + } + DEBUGPRINT((KERN_ALERT "auraXX20n: System supports PCI bus.\n")); + + MULTIPORTRESTART: + if(pdev = pci_find_device(sab8253x_vendor_id, sab8253x_mpac_device_id, XX20lastpdev), + pdev == NULL) + { + printk(KERN_ALERT "auraXX20n: could not find multiport card.\n"); + kfree(bptr); + return 0; + } + + DEBUGPRINT((KERN_ALERT "auraXX20n: found multiport PCI serial card.\n")); + + XX20lastpdev = pdev; + DEBUGPRINT((KERN_ALERT "auraXX20n: found ATI PLX 9050, %p.\n", pdev)); + bptr->b_dev = *pdev; + + /* the Solaris and model linux drivers + * comment that there are problems with + * getting the length via PCI operations + * seems to work for 2.4 + */ + bptr->length0 = (unsigned int) pci_resource_len(pdev, 0); + bptr->length1 = (unsigned int) pci_resource_len(pdev, 1); + bptr->length2 = (unsigned int) pci_resource_len(pdev, 2); + bptr->b_irq = pdev->irq; + + + DEBUGPRINT((KERN_ALERT + "auraXX20n: base address 0 is %p, len is %x.\n", + (void*) pci_base_address(pdev, 0), bptr->length0)); + DEBUGPRINT((KERN_ALERT + "auraXX20n: base address 1 is %p, len is %x.\n", + (void*) pci_base_address(pdev, 1), bptr->length1)); + DEBUGPRINT((KERN_ALERT + "auraXX20n: base address 2 is %p, len is %x.\n", + (void*) pci_base_address(pdev, 2), + bptr->length2)); + + DEBUGPRINT((KERN_ALERT "auraXX20n: interrupt is %i.\n", pdev->irq)); + bus = pdev->bus->number; + devfn = pdev->devfn; + DEBUGPRINT((KERN_ALERT "auraXX20n: bus is %x, slot is %x.\n", bus, PCI_SLOT(devfn))); + pcibios_read_config_word(bus, devfn, PCI_COMMAND, &pci_command); +#if 0 + /* The Aurora card does not act as a PCI master + * ugh!! + */ + new_command = pci_command | PCI_COMMAND_MASTER; + if(pci_command != new_command) + { + DEBUGPRINT((KERN_ALERT + "auraXX20n: the PCI BIOS has not enabled this device!" + " Updating PCI command %4.4x->%4.4x.\n", + pci_command, + new_command)); + pcibios_write_config_word(bus, devfn, PCI_COMMAND, + new_command); + } + else + { + DEBUGPRINT + ((KERN_ALERT + "auraXX20n: the PCI BIOS has enabled this device as master!\n")); + } +#endif + if((pci_command & PCI_COMMAND_MASTER) != PCI_COMMAND_MASTER) + { + DEBUGPRINT((KERN_ALERT "auraXX20n: Aurora card is not a bus master.\n")); + } + + pcibios_read_config_byte(bus, devfn, PCI_LATENCY_TIMER, + &pci_latency); + if (pci_latency < 32) + { + DEBUGPRINT + ((KERN_ALERT + "auraXX20n: PCI latency timer (CFLT) is low at %i.\n", pci_latency)); + /* may need to change the latency */ +#if 0 + pcibios_write_config_byte(bus, devfn, PCI_LATENCY_TIMER, 32); +#endif + } + else + { + DEBUGPRINT((KERN_ALERT + "auraXX20n: PCI latency timer (CFLT) is %#x.\n", + pci_latency)); + } + bptr->virtbaseaddress0 = ioremap_nocache(pci_base_address(pdev, 0), + bptr->length0); + if(bptr->virtbaseaddress0 == NULL) + { + printk(KERN_ALERT + "auraXX20n: unable to remap physical address %p.\n", + (void*) pci_base_address(pdev, 0)); + + goto MULTIPORTRESTART; + } + + bptr->b_bridge = (PLX9050*) bptr->virtbaseaddress0; /* MAKE SURE INTS ARE OFF */ + writel(PLX_INT_OFF, &(bptr->b_bridge->intr)); + + printk(KERN_ALERT + "auraXX20n: remapped physical address %p to virtual address %p.\n", + (void*) pci_base_address(pdev, 0), (void*) bptr->virtbaseaddress0); + + dump_ati_adapter_registers((unsigned int*) bptr->virtbaseaddress0, bptr->length0); + + if(*(unsigned int*)bptr->virtbaseaddress0 == -1) /* XP7 problem? */ + { + printk(KERN_ALERT + "auraXX20n: unable to access PLX 9050 registers at %p.\n", + (void*)bptr->virtbaseaddress0); + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress0); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + + goto MULTIPORTRESTART; + } + + bptr->virtbaseaddress2 = ioremap_nocache(pci_base_address(pdev, 2), + bptr->length2); + if(bptr->virtbaseaddress2 == NULL) + { + printk(KERN_ALERT + "auraXX20n: unable to remap physical address %p.\n", + (void*) pci_base_address(pdev, 2)); + printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)bptr->virtbaseaddress0); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + + goto MULTIPORTRESTART; + } + + DEBUGPRINT((KERN_ALERT + "auraXX20n: remapped physical address %p to virtual address %p.\n", + (void*) pci_base_address(pdev, 2), (void*) bptr->virtbaseaddress2)); + + if (!plx9050_eprom_read(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + (unsigned short*) bptr->b_eprom, + (unsigned char) 0, EPROM9050_SIZE)) + { + printk(KERN_ALERT "auraXX20n: Could not read serial eprom.\n"); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + iounmap((void*)bptr->virtbaseaddress2); + bptr->virtbaseaddress2 = 0; + + goto MULTIPORTRESTART; + } + + printk(KERN_ALERT "auraXX20n: dumping serial eprom.\n"); + dump_ati_adapter_registers((unsigned int*) bptr->b_eprom, 2 * EPROM9050_SIZE); + + if(*(unsigned int*)bptr->b_eprom != PCIMEMVALIDMULTI) /* bridge problem? */ + { + printk(KERN_ALERT "auraXX20n: unable to access valid serial eprom data.\n"); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + iounmap((void*)bptr->virtbaseaddress2); + bptr->virtbaseaddress2 = 0; + + goto MULTIPORTRESTART; + } + + if(((unsigned short*) bptr->b_eprom)[EPROMPREFETCHOFFSET] & PREFETCHBIT) + { + ++sab8253x_rebootflag; + printk(KERN_ALERT "8253x: eeprom programmed for prefetchable memory resources; must reprogram!!\n"); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WENCMD, NM93_WENADDR, 0); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WRITECMD, + 9, + (((unsigned short*) bptr->b_eprom)[EPROMPREFETCHOFFSET] & (~PREFETCHBIT))); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WDSCMD, NM93_WDSADDR, 0); + } + + /* get SYNC and ONEPORT values */ + + control = readl(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl); + /* note we use the actual address + * of the control register in + * memory + */ + + if(control & AURORA_MULTI_SYNCBIT) + { + does_sync = 0; + } + else + { + does_sync = 1; + } + + if(control & AURORA_MULTI_1PORTBIT) + { + use_1port = 1; + } + else + { + use_1port = 0; + } + + + /* Figure out the board */ + switch(bptr->length2) + { + case AURORA_4X20_SIZE: + if(does_sync) + { + bptr->b_type = BD_4520P; + bptr->b_nchips = 2; + bptr->b_nports = 4; + bptr->b_flags = BD_SYNC; + bptr->b_cimbase = NULL; + bptr->board_number = BD4520Pcounter; /* keep track of boardnumber for naming devices */ + ++BD4520Pcounter; + printk(KERN_ALERT "auraXX20n: Found Saturn 4520P.\n"); + } + else + { + bptr->b_type = BD_4020P; + bptr->b_nchips = 2; + bptr->b_nports = 4; + bptr->b_flags = 0x0; + bptr->b_cimbase = NULL; + bptr->board_number = BD4020Pcounter; + ++BD4020Pcounter; + printk(KERN_ALERT "auraXX20n: Found Apollo 4020P.\n"); + } + break; + case AURORA_8X20_SIZE: + if(does_sync) + { + bptr->b_type = BD_8520P; + bptr->b_nchips = 1; + bptr->b_nports = 8; + bptr->b_flags = BD_SYNC; + bptr->b_cimbase = NULL; + bptr->board_number = BD8520Pcounter; + ++BD8520Pcounter; + printk(KERN_ALERT "auraXX20n: Found Saturn 8520P.\n"); + } + else + { + bptr->b_type = BD_8020P; + bptr->b_nchips = 1; + bptr->b_nports = 8; + bptr->b_flags = 0x0; + bptr->b_cimbase = NULL; + bptr->board_number = BD8020Pcounter; + ++BD8020Pcounter; + printk(KERN_ALERT "auraXX20n: Found Apollo 8020P.\n"); + } + break; + case AURORA_2X20_SIZE: + if(does_sync) + { + if(use_1port) + { + bptr->b_type = BD_1520P; + printk(KERN_ALERT "auraXX20n: Found Saturn 1520P.\n"); + bptr->b_nchips = 1; + bptr->b_nports = 1; + bptr->b_flags = BD_SYNC; + bptr->b_cimbase = NULL; + bptr->board_number = BD1520Pcounter; + ++BD1520Pcounter; + printk(KERN_ALERT "auraXX20n: Found Saturn 1520P.\n"); + } + else + { + bptr->b_type = BD_2520P; + bptr->b_nchips = 1; + bptr->b_nports = 2; + bptr->b_flags = BD_SYNC; + bptr->b_cimbase = NULL; + bptr->board_number = BD2520Pcounter; + ++BD2520Pcounter; + printk(KERN_ALERT "auraXX20n: Found Saturn 2520P.\n"); + } + } + else + { + if(use_1port) + { + bptr->b_type = BD_1020P; + bptr->b_nchips = 1; + bptr->b_nports = 1; + bptr->b_flags = 0x0; + bptr->b_cimbase = NULL; + bptr->board_number = BD1020Pcounter; + ++BD1020Pcounter; + printk(KERN_ALERT "auraXX20n: Found Apollo 1020P.\n"); + } + else + { + bptr->b_type = BD_2020P; + bptr->b_nchips = 1; + bptr->b_nports = 2; + bptr->b_flags = 0x0; + bptr->b_cimbase = NULL; + bptr->board_number = BD2020Pcounter; + ++BD2020Pcounter; + printk(KERN_ALERT "auraXX20n: Found Apollo 2020P.\n"); + } + } + break; + default: + printk(KERN_ALERT "Error: Board could not be identified\n"); + iounmap((void*)bptr->virtbaseaddress0); + bptr->virtbaseaddress0 = 0; + iounmap((void*)bptr->virtbaseaddress2); + bptr->virtbaseaddress2 = 0; + + goto MULTIPORTRESTART; + } + /* Let's get the clockrate right -- ugh!*/ + + bptr->b_clkspeed = bptr->b_eprom[AURORA_MULTI_EPROM_CLKLSW/2]; + + if(bptr->b_clkspeed == -1) /* misprogrammed -- ugh. */ + { + switch(bptr->b_type) + { + case BD_8520P: + case BD_8020P: + bptr->b_clkspeed = AURORA_MULTI_CLKSPEED/4; + break; + default: + bptr->b_clkspeed = AURORA_MULTI_CLKSPEED; + break; + + } + printk(KERN_ALERT "auraXX20n: UNKNOWN CLOCKSPEED -- ASSUMING %ld.\n", bptr->b_clkspeed); + + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WENCMD, NM93_WENADDR, 0); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WRITECMD, + 54, (unsigned short) bptr->b_clkspeed); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WRITECMD, + 55, (bptr->b_clkspeed >> 16)); + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WDSCMD, NM93_WDSADDR, 0); + } + + return bptr; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#ifdef MODULE +int init_module(void) /* all OS */ +#else +int auraXX20_probe(struct net_device *devp) /* passed default device structure */ +#endif +#else +static int __init auraXX20_probe(void) /* legacy device initialization 2.4.* */ +#endif +{ + SAB_BOARD *boardptr; + SAB_PORT *portptr; + struct net_device *dev; + unsigned int result; + unsigned int namelength; + unsigned int portno; + int intr_val; + + int mp_probe_count = 0; /* multiport count */ + int cp_probe_count = 0; /* compact pci count */ + int wm_probe_count = 0; /* wan multiserver count */ + + printk(KERN_ALERT "aurora interea miseris mortalibus almam extulerat lucem\n"); + printk(KERN_ALERT " referens opera atque labores\n"); + + memset(AuraBoardESCC8IrqRoot, 0, sizeof(AuraBoardESCC8IrqRoot)); + memset(AuraBoardESCC2IrqRoot, 0, sizeof(AuraBoardESCC2IrqRoot)); + memset(AuraBoardMCSIrqRoot, 0, sizeof(AuraBoardMCSIrqRoot)); + +#if !defined(MODULE) && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) + if(do_probe == 0) + return -1; /* only allow to be called one 2.2.* */ + do_probe = 0; +#endif + + fn_init_crc_table(); /* used in faking ethernet packets for */ + /* the network driver -- crcs are currently */ + /* not being checked by this software */ + /* but is good to have them in case a frame */ + /* passes through a WAN LAN bridge */ + + sab8253x_setup_ttydriver(); /* add synchronous tty and synchronous network + driver initialization */ + + AuraBoardRoot = NULL; /* basic lists */ + AuraChipRoot = NULL; + AuraPortRoot = NULL; + NumSab8253xPorts = 0; + + AuraXX20DriverParams.debug = auraXX20n_debug; + AuraXX20DriverParams.listsize = sab8253xn_listsize; + + if(auraXX20n_name != 0) + { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + auraXX20n_prototype.name = auraXX20n_name; +#else + strcpy(auraXX20n_prototype.name, auraXX20n_name); +#endif + } + + /* find all multiport cards */ + XX20lastpdev = NULL; + while(1) + { + boardptr = find_ati_multiport_card(); + if(boardptr == NULL) + { + printk(KERN_ALERT + "auraXX20n: found %d AURAXX20 multiport device%s.\n", + mp_probe_count, ((mp_probe_count == 1) ? "" : "s")); + break; + } + boardptr->nextboard = AuraBoardRoot; + AuraBoardRoot = boardptr; + printk(KERN_ALERT "auraXX20n: found AURAXX20 multiport device #%d.\n", + mp_probe_count); + ++mp_probe_count; + } + + /* find all cpci cards */ + XX20lastpdev = NULL; + while(1) + { + boardptr = find_ati_cpci_card(); + if(boardptr == NULL) + { + printk(KERN_ALERT + "auraXX20n: found %d AURAXX20 CPCI device%s.\n", + cp_probe_count, ((cp_probe_count == 1) ? "" : "s")); + break; + } + boardptr->nextboard = AuraBoardRoot; + AuraBoardRoot = boardptr; + printk(KERN_ALERT "auraXX20n: found AURAXX20 CPCI device #%d.\n", + cp_probe_count); + ++cp_probe_count; + } + /* find all WAN MS cards */ + XX20lastpdev = NULL; + while(1) + { + boardptr = find_ati_wanms_card(); + if(boardptr == NULL) + { + printk(KERN_ALERT + "auraXX20n: found %d AURAXX20 WANMS device%s.\n", + wm_probe_count, ((wm_probe_count == 1) ? "" : "s")); + break; + } + boardptr->nextboard = AuraBoardRoot; + AuraBoardRoot = boardptr; + printk(KERN_ALERT "auraXX20n: found AURAXX20 WANMS device #%d.\n", + wm_probe_count); + ++wm_probe_count; + } + + /* Now do the chips! */ + + for(boardptr = AuraBoardRoot; boardptr != NULL; boardptr = boardptr->nextboard) + { + SetupAllChips(boardptr); /* sets up the ports on the chips */ + } + + /* set up global driver structures + * for async tty, call out device + * for sync tty and for network device + */ + + /* NOW TURN ON THE PLX INTS */ + /* note all port ints (only receive right now) + * are off */ + + /* interrupts cannot be turned on by port + this seems to be the only sensible place + to do it*/ + + /* only at this point is the number of + * ttys to be created known. */ + + if(finish_sab8253x_setup_ttydriver() == -1) /* only as many termios are allocated */ + /* as needed */ + { + return 0; + } + for(portno = 0, portptr = AuraPortRoot; portptr != NULL; ++portno, portptr = portptr->next) + { + portptr->line = portno; /* set up the line number == minor dev associated with port */ + portptr->sigmode = sab8253x_default_sp502_mode; + /* if we have SP502s let getty work with RS232 by default */ + /* unless overridden in module setup. */ + } + /* Now lets set up the network devices */ + for(portno = 0, portptr = AuraPortRoot; portptr != NULL; ++portno, portptr = portptr->next) + { + + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if(!dev) + { + break; + } + memset(dev, 0, sizeof(struct net_device)); + *dev = auraXX20n_prototype; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + dev->name = kmalloc(IFNAMSIZ+1, GFP_KERNEL); + if(!dev->name) + { + kfree(dev); + break; + } +#endif + namelength = MIN(strlen(auraXX20n_prototype.name), IFNAMSIZ); + strcpy(dev->name, auraXX20n_prototype.name); + sprintf(&dev->name[namelength-1], "%3.3d", portno); + +#if 1 + current_sab_port = portptr; +#else + dev->priv = portptr; +#endif + result = register_netdev(dev); + if(result) + { /* if we run into some internal kernel limit */ + break; + } + printk(KERN_ALERT "sab8253xn: found sab8253x network device #%d.\n", + portno); + } + printk(KERN_ALERT + "sab8253xn: found %d sab8253x network device%s.\n", + portno, ((portno == 1) ? "" : "s")); + + /* Now lets set up the character device */ + + if(sab8253xc_name) + { + result = register_chrdev(sab8253xc_major, sab8253xc_name, &sab8253xc_fops); + if(result < 0) + { + sab8253xc_major = result; + printk(KERN_ALERT "Could not install sab8253xc device.\n"); + } + else if(result > 0) + { + sab8253xc_major = result; + } + } + + for(boardptr = AuraBoardRoot; boardptr != NULL; boardptr = boardptr->nextboard) + { /* let's set up port interrupt lists */ + intr_val = boardptr->b_irq; + if((intr_val < 0) || (intr_val >= NUMINTS)) + { + printk(KERN_ALERT "sab8253xn: bad interrupt %i board %p.\n", intr_val, boardptr); + continue; + } + switch(boardptr->b_type) + { + case BD_WANMCS: + boardptr->next_on_interrupt = AuraBoardMCSIrqRoot[intr_val]; + AuraBoardMCSIrqRoot[intr_val] = boardptr; + break; + case BD_8520P: + case BD_8520CP: + boardptr->next_on_interrupt = AuraBoardESCC8IrqRoot[intr_val]; + AuraBoardESCC8IrqRoot[intr_val] = boardptr; + break; + default: + boardptr->next_on_interrupt = AuraBoardESCC2IrqRoot[intr_val]; + AuraBoardESCC2IrqRoot[intr_val] = boardptr; + break; + } + } + + for(intr_val = 0; intr_val < NUMINTS; ++intr_val) /* trying to install as few int handlers as possible */ + { /* one for each group of boards on a given irq */ + if((AuraBoardESCC2IrqRoot[intr_val] != NULL) || (AuraBoardESCC8IrqRoot[intr_val] != NULL) || + (AuraBoardMCSIrqRoot[intr_val] != NULL)) + { + if (request_irq(intr_val, sab8253x_interrupt, SA_SHIRQ, + "sab8253x", &AuraBoardESCC2IrqRoot[intr_val]) == 0) + /* interrupts on perboard basis + * cycle through chips and then + * ports */ + /* NOTE PLX INTS ARE OFF -- so turn them on */ + { + for(boardptr = AuraBoardESCC2IrqRoot[intr_val]; boardptr != NULL; + boardptr = boardptr->next_on_interrupt) + { + writel(PLX_INT_ON, &(boardptr->b_bridge->intr)); + } + for(boardptr = AuraBoardESCC8IrqRoot[intr_val]; boardptr != NULL; + boardptr = boardptr->next_on_interrupt) + { + writel(PLX_INT_ON, &(boardptr->b_bridge->intr)); + } + for(boardptr = AuraBoardMCSIrqRoot[intr_val]; boardptr != NULL; + boardptr = boardptr->next_on_interrupt) + { + /* write to the MIC csr to reset the PCI interrupt */ + writeb(0, (unsigned char*)(boardptr->MICCMD_REG + MICCMD_MICCSR)); + + /* now, write to the CIM interrupt ena to re-enable interrupt generation */ + writeb(0, (unsigned char*)(boardptr->CIMCMD_REG + CIMCMD_WRINTENA)); + + /* now, activate PCI interrupts */ + writel(AMCC_AOINTPINENA, (unsigned int*)(boardptr->AMCC_REG + AMCC_INTCSR)); + } + } + else + { + printk(KERN_ALERT "Unable to get interrupt, board set up not complete %i.\n", intr_val); + } + } + } + + /* all done! a lot of work */ + +#if !defined(MODULE) && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) + return -1; /* otherwise 2.2 probe uses up + * a default device structure*/ +#else + return 0; +#endif +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#ifdef MODULE +/* cleanup module/free up virtual memory */ +/* space*/ +void cleanup_module(void) +#endif +#else +void auraXX20_cleanup(void) +#endif +{ + SAB_BOARD *boardptr; + SAB_CHIP *chipptr; + SAB_PORT *portptr; + AURA_CIM *cimptr; + int intr_val; + extern void sab8253x_cleanup_ttydriver(void); + + printk(KERN_ALERT "auraXX20n: unloading AURAXX20 driver.\n"); + + sab8253x_cleanup_ttydriver(); /* clean up tty */ + + /* unallocate and turn off ints */ + for(intr_val = 0; intr_val < NUMINTS; ++intr_val) + { + if((AuraBoardESCC2IrqRoot[intr_val] != NULL) || (AuraBoardESCC8IrqRoot[intr_val] != NULL) || + (AuraBoardMCSIrqRoot[intr_val] != NULL)) + { + for(boardptr = AuraBoardESCC2IrqRoot[intr_val]; boardptr != NULL; + boardptr = boardptr->next_on_interrupt) + { + writel(PLX_INT_OFF, &(boardptr->b_bridge->intr)); + } + for(boardptr = AuraBoardESCC8IrqRoot[intr_val]; boardptr != NULL; + boardptr = boardptr->next_on_interrupt) + { + writel(PLX_INT_OFF, &(boardptr->b_bridge->intr)); + } + for(boardptr = AuraBoardMCSIrqRoot[intr_val]; boardptr != NULL; + boardptr = boardptr->next_on_interrupt) + { + writel(AMCC_INT_OFF, (unsigned int*)(boardptr->AMCC_REG + AMCC_INTCSR)); + (void) wanmcs_reset(boardptr); + writel(AMCC_INT_OFF, (unsigned int*)(boardptr->AMCC_REG + AMCC_INTCSR)); + } + + free_irq(intr_val, &AuraBoardESCC2IrqRoot[intr_val]); /* free up board int + * note that if two boards + * share an int, two int + * handlers were registered + * + */ + } + } + + /* disable chips and free board memory*/ + while(AuraBoardRoot) + { + boardptr = AuraBoardRoot; + for(chipptr = boardptr->board_chipbase; chipptr != NULL; chipptr = chipptr->next_by_board) + { + (*chipptr->int_disable)(chipptr); /* make sure no ints can come int */ + } + AuraBoardRoot = boardptr->nextboard; + if(boardptr->b_type == BD_WANMCS) + { + if(boardptr->virtbaseaddress0 != 0) + { + DEBUGPRINT((KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)boardptr->virtbaseaddress0)); + iounmap((void*)boardptr->virtbaseaddress0); + boardptr->virtbaseaddress0 = 0; + } + + if(boardptr->virtbaseaddress1 != 0) + { + DEBUGPRINT((KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)boardptr->virtbaseaddress1)); + iounmap((void*)boardptr->virtbaseaddress1); + boardptr->virtbaseaddress1 = 0; + } + + if(boardptr->virtbaseaddress2 != 0) + { + DEBUGPRINT((KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)boardptr->virtbaseaddress2)); + iounmap((void*)boardptr->virtbaseaddress2); + boardptr->virtbaseaddress2 = 0; + } + + if(boardptr->virtbaseaddress3 != 0) + { + DEBUGPRINT((KERN_ALERT "auraXX20n: unmapping virtual address %p.\n", + (void*)boardptr->virtbaseaddress3)); + iounmap((void*)boardptr->virtbaseaddress3); + boardptr->virtbaseaddress3 = 0; + } + + } + else /* everything but wan multichannel servers */ + { + if(boardptr->virtbaseaddress0) + { + DEBUGPRINT((KERN_ALERT + "auraXX20n: unmapping virtual address %p.\n", + (void*)boardptr->virtbaseaddress0)); + iounmap((void*)boardptr->virtbaseaddress0); + boardptr->virtbaseaddress0 = 0; + } + if(boardptr->virtbaseaddress2) + { + DEBUGPRINT((KERN_ALERT + "auraXX20n: unmapping virtual address %p.\n", + (void*)boardptr->virtbaseaddress2)); + iounmap((void*)boardptr->virtbaseaddress2); + boardptr->virtbaseaddress2 = 0; + } + } + kfree(boardptr); + } + + while(AuraCimRoot) + { + cimptr = AuraCimRoot; + AuraCimRoot = cimptr->next; + kfree(cimptr); + } + + + while(AuraChipRoot) /* free chip memory */ + { + chipptr = AuraChipRoot; + AuraChipRoot = chipptr->next; + kfree(chipptr); + } + + if(sab8253xc_name && (sab8253xc_major > 0)) /* unregister the chr device */ + { + unregister_chrdev(sab8253xc_major, sab8253xc_name); + } + + while(Sab8253xRoot) /* free up network stuff */ + { + SAB_PORT *priv; + priv = (SAB_PORT *)Sab8253xRoot->priv; + unregister_netdev(Sab8253xRoot); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + kfree(Sab8253xRoot.name); +#endif + kfree(Sab8253xRoot); + Sab8253xRoot = priv->next_dev; + } + + while(AuraPortRoot) /* free up port memory */ + { + portptr = AuraPortRoot; + AuraPortRoot = portptr->next; + if(portptr->dcontrol2.receive) + { + kfree(portptr->dcontrol2.receive); + } + if(portptr->dcontrol2.transmit) + { + kfree(portptr->dcontrol2.transmit); + } + kfree(portptr); + } +} + +/* + * Hardware dependent read and write functions. + * We have functions to write/read a byte, write/read + * a word and read and write the FIFO + */ + + +/*************************************************************************** + * aura_readb: Function to read a byte on a 4X20P, 8X20P or Sun serial + * + * + * Parameters : + * port: The port being accessed + * reg: The address of the register + * + * Return value : The value of the register. + * + * Prerequisite : The port must have been opened + * + * Remark : + * + * Author : fw + * + * Revision : Oct 10 2000, creation + ***************************************************************************/ + +static unsigned char aura_readb(struct sab_port *port, unsigned char *reg) +{ + return readb(reg); +} + +/*************************************************************************** + * aura_writeb: Function to write a byte on a 4X20P, 8X20P or Sun serial + * + * + * Parameters : + * port: The port being accessed + * reg: The address of the register + * val: The value to put into the register + * + * Return value : None + * + * Prerequisite : The port must have been opened + * + * Remark : + * + * Author : fw + * + * Revision : Oct 10 2000, creation + ***************************************************************************/ + +static void aura_writeb(struct sab_port *port, unsigned char *reg,unsigned char val) +{ + writeb(val,reg); +} + +/*************************************************************************** + * aura_readw: Function to read a word on a 4X20P, 8X20P or Sun serial + * + * + * Parameters : + * port: The port being accessed + * reg: The address of the hw memory to access + * + * Return value : The value of the memory area. + * + * Prerequisite : The port must have been opened + * + * Remark : + * + * Author : fw + * + * Revision : Oct 10 2000, creation + ***************************************************************************/ +static unsigned short aura_readw(struct sab_port *port, unsigned short *reg) +{ + return readw(reg); +} + +/*************************************************************************** + * aura_writew: Function to write a word on a 4X20P, 8X20P or Sun serial + * + * + * Parameters : + * port: The port being accessed + * reg: The address of the hw memory to access + * val: The value to put into the register + * + * Return value : The value of the memory area. + * + * Prerequisite : The port must have been opened + * + * Remark : + * + * Author : fw + * + * Revision : Oct 10 2000, creation + ***************************************************************************/ + +static void aura_writew(struct sab_port *port, unsigned short *reg,unsigned short val) +{ + writew(val,reg); +} + +/*************************************************************************** + * aura_readfifo: Function to read the FIFO on a 4X20P, 8X20P or Sun serial + * + * + * Parameters : + * port: The port being accessed + * buf: The address of a buffer where we should put + * what we read + * nbytes: How many chars to read. + * + * Return value : none + * + * Prerequisite : The port must have been opened + * + * Remark : + * + * Author : fw + * + * Revision : Oct 13 2000, creation + ***************************************************************************/ +static void aura_readfifo(struct sab_port *port, unsigned char *buf, unsigned int nbytes) +{ + int i; + unsigned short *wptr = (unsigned short*) buf; + int nwords = ((nbytes+1)/2); + for(i = 0; i < nwords; i ++) + { + wptr[i] = readw(((unsigned short *)port->regs)); + } +} + +/*************************************************************************** + * aura_writefifo: Function to write the FIFO on a 4X20P, 8X20P or Sun serial + * + * + * Parameters : + * port: The port being accessed + * + * Return value : none + * + * Prerequisite : The port must have been opened + * + * Remark : + * + * Author : fw + * + * Revision : Oct 13 2000, creation + ***************************************************************************/ +static void aura_writefifo(struct sab_port *port) +{ + int i,max,maxw; + unsigned short *wptr; + unsigned char buffer[32]; + + if(port->xmit_cnt <= 0) + { + return; + } + max= (port->xmit_fifo_size < port->xmit_cnt) ? port->xmit_fifo_size : port->xmit_cnt; + + for (i = 0; i < max; i++) + { + buffer[i] = port->xmit_buf[port->xmit_tail++]; + port->xmit_tail &= (SAB8253X_XMIT_SIZE - 1); + port->icount.tx++; + port->xmit_cnt--; + } + + maxw = max/2; + wptr = (unsigned short*) buffer; + + for(i = 0; i < maxw; ++i) + { + writew(wptr[i], (unsigned short *)port->regs); + } + + if(max & 1) + { + writeb(buffer[max-1], (unsigned char*)port->regs); + } +} + +/*************************************************************************** + * wmsaura_readb: Function to read a byte on a LMS, WMS + * + * + * Parameters : + * port: The port being accessed + * reg: The address of the register + * + * Return value : The value of the register. + * + * Prerequisite : The port must have been opened + * + * Remark : TO BE IMPLEMENTED + * + * Author : fw + * + * Revision : Oct 10 2000, creation + ***************************************************************************/ + +static unsigned char wmsaura_readb(struct sab_port *port, unsigned char *reg) +{ + return readb((unsigned char*) (((unsigned int) reg) + CIMCMD_RDREGB)); +} + +/*************************************************************************** + * wmsaura_writeb: Function to write a byte on a LMS, WMS + * + * + * Parameters : + * port: The port being accessed + * reg: The address of the register + * val: The value to put into the register + * + * Return value : None + * + * Prerequisite : The port must have been opened + * + * Remark : TO BE IMPLEMENTED + * + * Author : fw + * + * Revision : Oct 10 2000, creation + ***************************************************************************/ + +static void wmsaura_writeb(struct sab_port *port, unsigned char *reg,unsigned char val) +{ + writeb(val, (unsigned char*) (((unsigned int) reg) + CIMCMD_WRREGB)); +} + +/*************************************************************************** + * wmsaura_readw: Function to read a word on a LMS, WMS + * + * + * Parameters : + * port: The port being accessed + * reg: The address of the hw memory to access + * + * Return value : The value of the memory area. + * + * Prerequisite : The port must have been opened + * + * Remark : TO BE IMPLEMENTED + * + * Author : fw + * + * Revision : Oct 10 2000, creation + ***************************************************************************/ +static unsigned short wmsaura_readw(struct sab_port *port, unsigned short *reg) +{ + unsigned short readval; + unsigned int address; + address = (unsigned int) reg; + + readval = readb((unsigned char*) (address + CIMCMD_RDREGB)); + ++address; + return (readval | (readb((unsigned char*) (address + CIMCMD_RDREGB)) << 8)); +} + +/*************************************************************************** + * wmsaura_writew: Function to write a word on a LMS, WMS + * + * + * Parameters : + * port: The port being accessed + * reg: The address of the hw memory to access + * val: The value to put into the register + * + * Return value : The value of the memory area. + * + * Prerequisite : The port must have been opened + * + * Remark : TO BE IMPLEMENTED + * + * Author : fw + * + * Revision : Oct 10 2000, creation + ***************************************************************************/ + +static void wmsaura_writew(struct sab_port *port, unsigned short *reg, unsigned short val) +{ + unsigned char vallow; + unsigned char valhigh; + unsigned int address; + + address = (unsigned int) reg; + + vallow = (unsigned char) val; + valhigh = (unsigned char) (val >> 8); + + writeb(vallow, (unsigned char*) (address + CIMCMD_WRREGB)); + ++address; + writeb(valhigh, (unsigned char*) (address + CIMCMD_WRREGB)); +} + +static void wmsaura_readfifo(struct sab_port *port, unsigned char *buf, unsigned int nbytes) +{ +#ifdef FIFO_DIRECT + unsigned short fifo[32/2]; /* this array is word aligned + * buf may not be word aligned*/ + unsigned int nwords; + int i; + int wcount; + unsigned int address; + + if (nbytes == 0) + { + return; + } + + wcount = ((nbytes + 1) >> 1); + /* Read the thing into the local FIFO and copy it out. */ + address = (unsigned int) port->regs; + + for(i = 0; i < wcount; ++i) + { + fifo[i] = readw((unsigned short*)(address + CIMCMD_RDFIFOW)); + } + + memcpy((unsigned char*) buf, (unsigned char*) &(fifo[0]), (unsigned int) nbytes); + +#else /* FIFO_DIRECT */ + unsigned short fifo[32/2]; + int i; + int wcount; + SAB_BOARD *bptr; + unsigned int channel; + + if (nbytes == 0) + { + return; + } + + bptr = port->board; + wcount = ((nbytes + 1) >> 1); + channel = (((unsigned char*) port->regs) - bptr->CIMCMD_REG); /* should be properly shifted */ + + /* + * Trigger a cache read by writing the nwords - 1 to the + * magic place. + */ + + writeb((unsigned char) wcount, bptr->MICCMD_REG + (MICCMD_CACHETRIG + channel)); + + /* + * Now, read out the contents. + */ + + channel >>= 1; + + for(i = 0; i < wcount; ++i) + { + fifo[i] = readw((unsigned short*)(bptr->FIFOCACHE_REG + (channel + (i << 1)))); + } + + memcpy((unsigned char*) buf, (unsigned char*) &(fifo[0]), (unsigned int) nbytes); +#endif /* !FIFO_DIRECT */ +} + +static void wmsaura_writefifo(struct sab_port *port) +{ + unsigned short fifo[32/2]; + unsigned char* fifob = (unsigned char*) fifo; + int i,max; + int wcount; + unsigned int address; + + if(port->xmit_cnt <= 0) + { + return; + } + max = (port->xmit_fifo_size < port->xmit_cnt) ? port->xmit_fifo_size:port->xmit_cnt; + for (i = 0; i < max; i++) + { + fifob[i] = port->xmit_buf[port->xmit_tail++]; + port->xmit_tail &= (SAB8253X_XMIT_SIZE - 1); + port->icount.tx++; + port->xmit_cnt--; + } + + wcount = (max >> 1); + /* Copy from the linear local FIFO into the hardware fifo. */ + address = (unsigned int) port->regs; + + for(i = 0; i < wcount; ++i) + { + writew(fifo[i], (unsigned short*)(address + CIMCMD_WRFIFOW)); + } + if(max & 1) /* odd byte */ + { + --max; + writeb(fifob[max], (unsigned short*)(address + CIMCMD_WRFIFOB)); + } +} + +module_init(auraXX20_probe); +module_exit(auraXX20_cleanup); +MODULE_DESCRIPTION("Aurora Multiport Multiprotocol Serial Driver"); +MODULE_AUTHOR("Joachim Martillo "); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xint.c linux-2.5/drivers/net/wan/8253x/8253xint.c --- linux-2.5.20/drivers/net/wan/8253x/8253xint.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xint.c Fri May 3 03:49:07 2002 @@ -0,0 +1,458 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +/* Standard in kernel modules */ +#include /* Specifically, a module */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "8253xctl.h" +#include "8253xmcs.h" + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * sab8253x_interrupt(). They were separated out for readability's sake. + * + * Note: sab8253x_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * sab8253x_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* Note: the inline interrupt routines constitute the smallest hardware + unit that must be examined when an interrupt comes up. On the 4520 + type cards, two ESCC2s must be examined. Because the ESCC2s are in + a null terminated list the sab82532_interrupt also works for 2 port/1 port + single ESCC2 cards. + + On an 8520 type card there is but one ESCC8 thus the sab82538_interrupt + routine does not walk through a list. But this requires some contortion + in dealing with the multichannel server. The multichannel server has + at most 4 channel interface modules (CIM) 1/EB. Each CIM has at most + two ESCC8s, thus the host card can have a list of 8 ESCC8s. But by + walking the CIMs the exact ESCC8 that is interrupting can be identified. + Thus despite the complexity, really the MCS is a collection of 8520 type + cards multiplexed on one interrupt. Thus after making some temporary + modifications of the board structure, the generic interrupt handler invokes + sab82538_interrupt handler just as for an 8520 type card. +*/ + +/* static forces inline compilation */ +static void inline sab82532_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sab_port *port; + struct sab_chip *chip=NULL; + struct sab_board *bptr = (struct sab_board*) dev_id; + union sab8253x_irq_status status; + unsigned char gis; + + for(chip = bptr->board_chipbase; chip != NULL; chip = chip->next_by_board) + { + port= chip->c_portbase; + gis = READB(port, gis); /* Global! */ + status.stat=0; + + /* Since the PORT interrupt are global, + * we do check all the ports for this chip + */ + + /* A 2 ports chip */ + + if(!(gis & SAB82532_GIS_MASK)) + { + continue; /* no interrupt on this chip */ + } + + if (gis & SAB82532_GIS_ISA0) + { + status.sreg.isr0 = READB(port, isr0); + } + else + { + status.sreg.isr0 = 0; + } + if (gis & SAB82532_GIS_ISA1) + { + status.sreg.isr1 = READB(port, isr1); + } + else + { + status.sreg.isr1 = 0; + } + + if (gis & SAB82532_GIS_PI) + { + status.sreg.pis = READB(port, pis); + } + else + { + status.sreg.pis = 0; + } + + if (status.stat) + { + if (status.images[ISR0_IDX] & port->receive_test) + { + (*port->receive_chars)(port, &status); /* when the fifo is full */ + /* no time to schedule thread*/ + } + + if ((status.images[port->dcd.irq] & port->dcd.irqmask) || + (status.images[port->cts.irq] & port->cts.irqmask) || + (status.images[port->dsr.irq] & port->dsr.irqmask) || + (status.images[ISR1_IDX] & port->check_status_test)) + { + (*port->check_status)(port, &status); /* this stuff should be */ + /* be moveable to scheduler */ + /* thread*/ + } + + if (status.images[ISR1_IDX] & port->transmit_test) + { + (*port->transmit_chars)(port, &status); /* needs to be moved to task */ + } + } + + /* Get to next port on chip */ + port = port->next_by_chip; + /* Port B */ + if (gis & SAB82532_GIS_ISB0) + { + status.images[ISR0_IDX] = READB(port, isr0); + } + else + { + status.images[ISR0_IDX] = 0; + } + if (gis & SAB82532_GIS_ISB1) + { + status.images[ISR1_IDX] = READB(port,isr1); + } + else + { + status.images[ISR1_IDX] = 0; + } + /* DO NOT SET PIS. IT was reset! */ + + + if (status.stat) + { + if (status.images[ISR0_IDX] & port->receive_test) + { + (*port->receive_chars)(port, &status); + } + if ((status.images[port->dcd.irq] & port->dcd.irqmask) || + (status.images[port->cts.irq] & port->cts.irqmask) || + (status.images[port->dsr.irq] & port->dsr.irqmask) || + (status.images[ISR1_IDX] & port->check_status_test)) + { + (*port->check_status)(port, &status); + } + if (status.images[ISR1_IDX] & port->transmit_test) + { + (*port->transmit_chars)(port, &status); + } + } + } +} + +static void inline sab82538_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sab_port *port; + struct sab_chip *chip=NULL; + struct sab_board *bptr = (struct sab_board*) dev_id; + union sab8253x_irq_status status; + unsigned char gis,i; + + chip = bptr->board_chipbase; + port = chip->c_portbase; + + gis = READB(port, gis); /* Global! */ + status.stat=0; + + /* Since the PORT interrupt are global, + * we do check all the ports for this chip + */ + + /* 8 ports chip */ + if(!(gis & SAB82538_GIS_MASK)) + { + return; + } + + if(gis & SAB82538_GIS_CII) + { /* A port interrupt! */ + /* Get the port */ + int portindex; + + portindex = (gis & SAB82538_GIS_CHNL_MASK); + + port = chip->c_portbase; + + while(portindex) + { + port = port->next_by_chip; + --portindex; + } + + status.images[ISR0_IDX] = READB(port,isr0); + status.images[ISR1_IDX] = READB(port,isr1); + if (gis & SAB82538_GIS_PIC) + { + status.images[PIS_IDX] = + (*port->readbyte)(port, + ((unsigned char *)(port->regs)) + + SAB82538_REG_PIS_C); + } + else + { + status.images[PIS_IDX] = 0; + } + + if (status.stat) + { + if (status.images[ISR0_IDX] & port->receive_test) + { + (*port->receive_chars)(port, &status); + } + if ((status.images[port->dcd.irq] & port->dcd.irqmask) || + (status.images[port->cts.irq] & port->cts.irqmask) || + (status.images[port->dsr.irq] & port->dsr.irqmask) || + (status.images[ISR1_IDX] & port->check_status_test)) + { + (*port->check_status)(port, &status); + } + /* + * We know that with 8 ports chip, the bit corresponding to channel + * number is used in the parallel port... So we clear it + * Not too elegant! + */ + status.images[PIS_IDX] &= ~(1 << (gis&SAB82538_GIS_CHNL_MASK)); + if (status.images[ISR1_IDX] & port->transmit_test) + { + (*port->transmit_chars)(port, &status); + } + } + } + + /* + * Now we handle the "channel interrupt" case. The chip manual for the + * 8 ports chip states that "channel" and "port" interrupt are set + * independently so we still must check the parrallel port + * + * We should probably redesign the whole thing to be less AD HOC that we + * are now... We know that port C is used for DSR so we only check that one. + * PIS for port C was already recorded in status.images[PIS_IDX], so we + * check the ports that are set + */ + + if (status.images[PIS_IDX]) + { + for(i=0, port = chip->c_portbase; + i < chip->c_nports; + i++, port=port->next_by_chip) + { + if(status.images[PIS_IDX] & (0x1 << i)) + { /* Match */ + /* Checking DSR */ + if(port->dsr.inverted) + { + port->dsr.val = (((*port->readbyte) + (port, port->dsr.reg) & + port->dsr.mask) ? 0 : 1); + } + else + { + port->dsr.val = ((*port->readbyte)(port, port->dsr.reg) & + port->dsr.mask); + } + + port->icount.dsr++; + wake_up_interruptible(&port->delta_msr_wait); /* in case waiting on modem change */ + } + } + } +} + +/* + * This is the serial driver's generic interrupt routine + */ + +void sab8253x_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + extern SAB_BOARD *AuraBoardESCC2IrqRoot[]; + extern SAB_BOARD *AuraBoardESCC8IrqRoot[]; + extern SAB_BOARD *AuraBoardMCSIrqRoot[]; + AURA_CIM *cim; + SAB_CHIP *chip; + SAB_PORT *port; + register SAB_BOARD *boardptr; + register unsigned char intrmask; + unsigned char stat; + SAB_CHIP *save_chiplist; + SAB_PORT *save_portlist; + + if((irq < 0) || (irq >= NUMINTS)) + { + printk(KERN_ALERT "sab8253x: bad interrupt value %i.\n", irq); + return; + } + /* walk through all the cards on the interrupt that occurred. */ + for(boardptr = AuraBoardESCC2IrqRoot[irq]; boardptr != NULL; boardptr = boardptr->next_on_interrupt) + { + sab82532_interrupt(irq, boardptr, regs); + } + + for(boardptr = AuraBoardESCC8IrqRoot[irq]; boardptr != NULL; boardptr = boardptr->next_on_interrupt) + { + sab82538_interrupt(irq, boardptr, regs); + } + + for(boardptr = AuraBoardMCSIrqRoot[irq]; boardptr != NULL; boardptr = boardptr->next_on_interrupt) + { + + while(1) + { + writeb(0, (unsigned char*)(boardptr->CIMCMD_REG + CIMCMD_WRINTDIS)); /* prevent EBs from raising + * any more ints through the + * host card */ + stat = ~(unsigned char) /* active low !!!!! */ + readw((unsigned short*) + (((unsigned char*)boardptr->CIMCMD_REG) + CIMCMD_RDINT)); /* read out the ints */ + /* write to the MIC csr to reset the PCI interrupt */ + writeb(0, (unsigned char*)(boardptr->MICCMD_REG + MICCMD_MICCSR)); + /* reset the interrupt generation + * hardware on the host card*/ + /* now, write to the CIM interrupt ena to re-enable interrupt generation */ + writeb(0, (unsigned char*)(boardptr->CIMCMD_REG + CIMCMD_WRINTENA)); /* allow EBs to request ints + * through the host card */ + if(!stat) + { + break; + } + cim = boardptr->b_cimbase; /* cims in reverse order */ + for(intrmask = boardptr->b_intrmask; + intrmask != 0; + intrmask <<= 2, stat <<=2) + { + if(cim == NULL) + { + break; /* no cim no ports */ + } + if((intrmask & 0xc0) == 0) /* means no cim for these ints */ + { /* cim not on list do not go to next */ + continue; + } + save_portlist = boardptr->board_portbase; + save_chiplist = boardptr->board_chipbase; + /* the goal is temporarily to make the structures + * look like 8x20 structures -- thus if I find + * a bug related to escc8s I need fix it in + * only one place. */ + switch(stat & 0xc0) /* possible ints */ + { + default: + break; + + case 0x80: /* esccB */ + chip = cim->ci_chipbase; + if(!chip) + { + printk(KERN_ALERT "aura mcs: missing cim.\n"); + break; + } + chip = chip->next_by_cim; + if(!chip) + { + printk(KERN_ALERT "aura mcs: missing 2nd cim.\n"); + break; + } + port = chip->c_portbase; + boardptr->board_portbase = port; + boardptr->board_chipbase = chip; + sab82538_interrupt(irq, boardptr, regs); + break; + + case 0x40: /* esccA */ + chip = cim->ci_chipbase; + if(!chip) + { + printk(KERN_ALERT "aura mcs: missing cim.\n"); + break; + } + port = chip->c_portbase; + boardptr->board_portbase = port; + boardptr->board_chipbase = chip; + sab82538_interrupt(irq, boardptr, regs); + break; + + case 0xc0: /* esccB and esccA */ + chip = cim->ci_chipbase; + if(!chip) + { + printk(KERN_ALERT "aura mcs: missing cim.\n"); + break; + } + port = chip->c_portbase; + boardptr->board_portbase = port; + boardptr->board_chipbase = chip; + sab82538_interrupt(irq, boardptr, regs); + + chip = cim->ci_chipbase; + if(!chip) + { + printk(KERN_ALERT "aura mcs: missing cim.\n"); + break; + } + chip = chip->next_by_cim; + if(!chip) + { + printk(KERN_ALERT "aura mcs: missing 2nd cim.\n"); + break; + } + port = chip->c_portbase; + boardptr->board_portbase = port; + boardptr->board_chipbase = chip; + sab82538_interrupt(irq, boardptr, regs); + break; + } + boardptr->board_portbase = save_portlist; + boardptr->board_chipbase = save_chiplist; + cim = cim->next_by_mcs; + } + } + } +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xioc.h linux-2.5/drivers/net/wan/8253x/8253xioc.h --- linux-2.5.20/drivers/net/wan/8253x/8253xioc.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xioc.h Fri May 3 03:49:07 2002 @@ -0,0 +1,143 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +#ifndef _SABIOCTL_H_ +#define _SABIOCTL_H_ + +#include +#include +#include +#include "ring.h" +#include "Reg9050.h" + +/* Channel Configuration Register 0 (CCR0) */ +#define SAB82532_CCR0_PU 0x80 +#define SAB82532_CCR0_MCE 0x40 +#define SAB82532_CCR0_SC_NRZ 0x00 +#define SAB82532_CCR0_SC_NRZI 0x08 +#define SAB82532_CCR0_SC_FM0 0x10 +#define SAB82532_CCR0_SC_FM1 0x14 +#define SAB82532_CCR0_SC_MANCH 0x18 +#define SAB82532_CCR0_SM_HDLC 0x00 +#define SAB82532_CCR0_SM_SDLC_LOOP 0x01 +#define SAB82532_CCR0_SM_BISYNC 0x02 +#define SAB82532_CCR0_SM_ASYNC 0x03 + +/* Channel Configuration Register 1 (CCR1) */ +#define SAB82532_CCR1_SFLG 0x80 +#define SAB82532_CCR1_ODS 0x10 +#define SAB82532_CCR1_BCR 0x08 +#define SAB82532_CCR1_IFF 0x08 +#define SAB82532_CCR1_ITF 0x00 +#define SAB82532_CCR1_CM_MASK 0x07 + +/* Channel Configuration Register 2 (CCR2) */ +#define SAB82532_CCR2_SOC1 0x80 +#define SAB82532_CCR2_SOC0 0x40 +#define SAB82532_CCR2_BR9 0x80 +#define SAB82532_CCR2_BR8 0x40 +#define SAB82532_CCR2_BDF 0x20 +#define SAB82532_CCR2_SSEL 0x10 +#define SAB82532_CCR2_XCS0 0x20 +#define SAB82532_CCR2_RCS0 0x10 +#define SAB82532_CCR2_TOE 0x08 +#define SAB82532_CCR2_RWX 0x04 +#define SAB82532_CCR2_C32 0x02 +#define SAB82532_CCR2_DIV 0x01 + +/* Channel Configuration Register 3 (CCR3) */ +#define SAB82532_CCR3_PSD 0x01 +#define SAB82532_CCR3_RCRC 0x04 + +/* Channel Configuration Register 4 (CCR4) */ +#define SAB82532_CCR4_MCK4 0x80 +#define SAB82532_CCR4_EBRG 0x40 +#define SAB82532_CCR4_TST1 0x20 +#define SAB82532_CCR4_ICD 0x10 +#define SAB82532_CCR4_RF32 0x00 +#define SAB82532_CCR4_RF16 0x01 +#define SAB82532_CCR4_RF04 0x02 +#define SAB82532_CCR4_RF02 0x03 + +/* Mode Register (MODE) */ +#define SAB82532_MODE_TM0 0x80 +#define SAB82532_MODE_FRTS 0x40 +#define SAB82532_MODE_FCTS 0x20 +#define SAB82532_MODE_FLON 0x10 +#define SAB82532_MODE_TCPU 0x10 +#define SAB82532_MODE_RAC 0x08 +#define SAB82532_MODE_RTS 0x04 +#define SAB82532_MODE_TRS 0x02 +#define SAB82532_MODE_TLP 0x01 + +struct channelcontrol +{ + unsigned char ccr0; + unsigned char ccr1; + unsigned char ccr2; + unsigned char ccr3; + unsigned char ccr4; + unsigned char mode; + unsigned char rlcr; +}; + +struct sep9050 +{ + unsigned short values[EPROM9050_SIZE]; +}; + + /* EXTERNAL-CLOCKING */ +#define DEFAULT_CCR0 (SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | SAB82532_CCR0_SM_HDLC) +#define DEFAULT_CCR1 (SAB82532_CCR1_SFLG | SAB82532_CCR1_ODS | SAB82532_CCR1_IFF) /* clock mode 0 */ +#define DEFAULT_CCR2 0 /*SAB82532_CCR2_SOC1*/ /* 0a -- RTS high*/ +#define DEFAULT_CCR3 SAB82532_CCR3_RCRC +#define DEFAULT_CCR4 0 +#define DEFAULT_MODE (SAB82532_MODE_TM0 | SAB82532_MODE_RTS | SAB82532_MODE_RAC) +#define DEFAULT_RLCR ((RXSIZE/32) - 1) + +#define DEFAULT_RLCR_NET ((RXSIZE/32) - 1) + + /* Internal-Clocking */ + +#define DCE_CCR0 (SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | SAB82532_CCR0_SM_HDLC) +#define DCE_CCR1 (SAB82532_CCR1_SFLG | SAB82532_CCR1_ODS | SAB82532_CCR1_IFF | 6) /* clock mode 6 */ +#define DCE_CCR2 (SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL | SAB82532_CCR2_TOE) /* 6b */ +#define DCE_CCR3 (SAB82532_CCR3_RCRC) +#define DCE_CCR4 (SAB82532_CCR4_MCK4|SAB82532_CCR4_EBRG) +#define DCE_MODE SAB82532_MODE_TM0 | SAB82532_MODE_RTS | SAB82532_MODE_RAC +#define DCE_RLCR ((RXSIZE/32) - 1) + +#define ATIS_MAGIC_IOC 'A' +#define ATIS_IOCSPARAMS _IOW(ATIS_MAGIC_IOC,0,struct channelcontrol) +#define ATIS_IOCGPARAMS _IOR(ATIS_MAGIC_IOC,1,struct channelcontrol) +#define ATIS_IOCSSPEED _IOW(ATIS_MAGIC_IOC,2,unsigned long) +#define ATIS_IOCGSPEED _IOR(ATIS_MAGIC_IOC,3,unsigned long) +#define ATIS_IOCSSEP9050 _IOW(ATIS_MAGIC_IOC,4,struct sep9050) +#define ATIS_IOCGSEP9050 _IOR(ATIS_MAGIC_IOC,5,struct sep9050) +#define ATIS_IOCSSIGMODE _IOW(ATIS_MAGIC_IOC,6,unsigned int) +#define ATIS_IOCGSIGMODE _IOW(ATIS_MAGIC_IOC,7,unsigned int) + +/* same order as the bytes in sp502.h and as the names in 8253xtty.c */ + +#define SP502_OFF_MODE 0 +#define SP502_RS232_MODE 1 +#define SP502_V28_MODE SP502_RS232_MODE +#define SP502_RS422_MODE 2 +#define SP502_V11_MODE SP502_RS422_MODE +#define SP502_X27_MODE SP502_RS422_MODE +#define SP502_RS485_MODE 3 +#define SP502_RS449_MODE 4 +#define SP502_EIA530_MODE 5 +#define SP502_V35_MODE 6 + +#define SAB8253XCLEARCOUNTERS (SIOCDEVPRIVATE + 5 + 1) + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xmcs.c linux-2.5/drivers/net/wan/8253x/8253xmcs.c --- linux-2.5.20/drivers/net/wan/8253x/8253xmcs.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xmcs.c Fri May 3 03:49:07 2002 @@ -0,0 +1,637 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Reg9050.h" +#include "8253xctl.h" +#include "ring.h" +#include "8253x.h" +#include "crc32dcl.h" +#include "8253xmcs.h" +#include "sp502.h" + +/* Just to guarantee that strings are null terminated */ +#define MEMCPY(dest, src, cnt) \ +{ \ + memcpy((dest), (src), (cnt)); \ + (dest)[cnt] = 0; \ +} + +static unsigned char sp502progbyte[] = +{ + SP502_OFF, + SP502_RS232, + SP502_RS422, + SP502_RS485, + SP502_RS449, + SP502_EIA530, + SP502_V35 +}; + +/* + * The following routines are the multichannel server I2C serial EPROM routines. + */ + +/* + * Set the clock and the data lines of the SEP. + */ +static void +mcs_sep_set(mcs_sep_t *msp, unsigned sdavalid, unsigned sda, + unsigned sclvalid, unsigned scl) +{ +#ifdef MAX +#undef MAX +#endif /* MAX */ + +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + + unsigned char csr; + unsigned int sleeptime; + + /* + * Ensure sufficient clock + */ + + sleeptime = 0; + + if (sclvalid) + { + if (msp->s_scl && !scl) + { /* do we have a downgoing transition? */ + sleeptime = MAX(1, sleeptime); + } + else if (!msp->s_scl && scl) + { /* upgoing */ + sleeptime = MAX(2, sleeptime); + } + msp->s_scl = scl; + } + + if (sdavalid) + { + if ((msp->s_sda && !sda) || (!msp->s_sda && sda)) + { + sleeptime = MAX(1, sleeptime); + } + + msp->s_sda = sda; + } + + if (sleeptime > 0) + { + udelay(sleeptime); + } + + /* + * Construct the CSR byte. + */ + csr = 0; + if (msp->s_sda) + { + csr |= CIMCMD_CIMCSR_SDA; + } + + if (msp->s_scl) + { + csr |= CIMCMD_CIMCSR_SCL; + } + + writeb((unsigned char) csr, msp->s_wrptr); +} + +static void +mcs_sep_start(mcs_sep_t *msp) +{ + /* + * Generate a START condition + */ + mcs_sep_set(msp, TRUE, TRUE, TRUE, TRUE); + mcs_sep_set(msp, TRUE, FALSE, TRUE, TRUE); +} + +static void +mcs_sep_stop(mcs_sep_t *msp) +{ + /* + * Generate a STOP condition + */ + mcs_sep_set(msp, TRUE, FALSE, TRUE, TRUE); + mcs_sep_set(msp, TRUE, TRUE, TRUE, TRUE); +} + +/* + * Send out a single byte. + */ +static void +mcs_sep_byte(mcs_sep_t *msp, unsigned char val) +{ + register int bitcount; + + /* Clock may be high ... lower the clock */ + mcs_sep_set(msp, TRUE, FALSE, TRUE, FALSE); + + bitcount = 8; + + while (TRUE) + { + mcs_sep_set(msp, TRUE, (val & 0x80) != 0, TRUE, FALSE); + mcs_sep_set(msp, TRUE, (val & 0x80) != 0, TRUE, TRUE); + + bitcount--; + if (bitcount == 0) + { + break; + } + val <<= 1; + } + + /* Clock is high ... lower the clock */ + mcs_sep_set(msp, FALSE, FALSE, TRUE, FALSE); +} + +/* + * Wait for an acknowledge cycle. Expects the clock to be low. + */ +static unsigned +mcs_sep_waitsep(mcs_sep_t *msp) +{ + int loopcount; + unsigned char cimcsr; + + /* Stop driving SDA */ + mcs_sep_set(msp, TRUE, TRUE, FALSE, FALSE); + /* Raise the clock */ + mcs_sep_set(msp, FALSE, FALSE, TRUE, TRUE); + + loopcount = 1000; + while (loopcount != 0) + { + cimcsr = readb(msp->s_rdptr); + + if ((cimcsr & CIMCMD_CIMCSR_SDA) == 0) + { + break; + } + loopcount--; + } + + /* Lower the clock */ + mcs_sep_set(msp, FALSE, FALSE, TRUE, FALSE); + + if (loopcount == 0) + { + return FALSE; + } + else + { + return TRUE; + } +} + +/* + * Read the given CIM's SEP, starting at the given address, into + * the given buffer, for the given length. + * + * Returns -1 if there was a failure, otherwise the byte count. + */ + +static int +mcs_sep_read(mcs_sep_t *msp, unsigned short addr, + unsigned char *buf, unsigned int nbytes) +{ + unsigned char cmdaddr, val, cimcsr; + unsigned int bytecount, bitcount; + + mcs_sep_start(msp); + + /* + * First, send out a dummy WRITE command with no data. + */ + + cmdaddr = 0xa0 | (((addr >> 8) & 0x7) << 1) | 0x0; + + mcs_sep_byte(msp, cmdaddr); + + if (!mcs_sep_waitsep(msp)) + { + return -1; + } + + /* + * Now, send the reset of the address. + */ + + mcs_sep_byte(msp, (unsigned char) addr); + + if (!mcs_sep_waitsep(msp)) + { + return -1; + } + + /* + * Now, restart with a read command. + */ + + mcs_sep_start(msp); + + cmdaddr = 0xa0 | (((addr >> 8) & 0x7) << 1) | 0x1; + + mcs_sep_byte(msp, cmdaddr); + + if (!mcs_sep_waitsep(msp)) + { + return -1; + } + + /* + * Now, start reading the bytes. + */ + bytecount = 0; + while (TRUE) + { + bitcount = 8; + val = 0; + while (TRUE) + { + mcs_sep_set(msp, TRUE, TRUE, TRUE, TRUE); + + cimcsr = readb(msp->s_rdptr); + + if ((cimcsr & CIMCMD_CIMCSR_SDA) != 0) + { + val |= 0x01; + } + + mcs_sep_set(msp, FALSE, FALSE, TRUE, FALSE); + bitcount--; + + if (bitcount == 0) + { + break; + } + val <<= 1; + } + + *buf++ = val; + bytecount++; + nbytes--; + + if (nbytes == 0) + { + break; + } + + /* + * Send the acknowledge. + */ + + mcs_sep_set(msp, FALSE, FALSE, TRUE, FALSE); + mcs_sep_set(msp, TRUE, FALSE, TRUE, TRUE); + mcs_sep_set(msp, FALSE, FALSE, TRUE, FALSE); + } + + mcs_sep_stop(msp); + + return (int) bytecount; +} + + +unsigned int mcs_ciminit(SAB_BOARD *bptr, AURA_CIM *cim) +{ + mcs_sep_t ms; + + ms.s_rdptr = (unsigned char *) + (bptr->CIMCMD_REG + (CIMCMD_RDCIMCSR | (cim->ci_num << CIMCMD_CIMSHIFT))); + ms.s_wrptr = (unsigned char *) + (bptr->CIMCMD_REG + (CIMCMD_WRCIMCSR | (cim->ci_num << CIMCMD_CIMSHIFT))); + ms.s_scl = ms.s_sda = FALSE; + + if (mcs_sep_read(&ms, (unsigned short) 0, &(cim->ci_sep[0]), + sizeof(cim->ci_sep)) != sizeof(cim->ci_sep) + || cim->ci_sep[MCS_SEP_MAGIC] != MCS_SEP_MAGICVAL) + { + + if (cim->ci_sep[MCS_SEP_MAGIC] != MCS_SEP_MAGICVAL) + { + DEBUGPRINT((KERN_ALERT + "auraXX20: invalid CIM %d serial EPROM on board %d", + cim->ci_num, bptr->board_number)); + } + else + { + DEBUGPRINT((KERN_ALERT + "auraXX20: error reading CIM %d serial EPROM on board %d", + cim->ci_num, bptr->board_number)); + } + + cim->ci_clkspeed = WANMCS_CLKSPEED; + cim->ci_clkspdsrc = -1; + cim->ci_spdgrd = 10; + cim->ci_spdgrdsrc = -1; + cim->ci_flags = 0; + cim->ci_rev[0] = '\0'; + cim->ci_sn[0] = '\0'; + cim->ci_mfgdate[0] = '\0'; + cim->ci_mfgloc[0] = '\0'; + + /* + * Diddle the port setup registers to determine if this + * CIM was built up for RS232 or SP502. + */ + + writew((unsigned short) 0xffff, (unsigned short *) + (bptr->CIMCMD_REG + + (CIMCMD_WRSETUP | (cim->ci_num << CIMCMD_CIMSHIFT)))); + +#ifdef RICHARD_DELAY + udelay(1); +#endif /* RICHARD_DELAY */ + + if (readw((unsigned short *) + (bptr->CIMCMD_REG + + (CIMCMD_RDSETUP | (cim->ci_num << CIMCMD_CIMSHIFT)))) == 0xffff) + { + + writew(0, (unsigned short *) + (bptr->CIMCMD_REG + + (CIMCMD_WRSETUP | (cim->ci_num << CIMCMD_CIMSHIFT)))); + +#ifdef RICHARD_DELAY + udelay(1); +#endif /* RICHARD_DELAY */ + + if (readw((unsigned short *) + (bptr->CIMCMD_REG + + (CIMCMD_RDSETUP | (cim->ci_num << CIMCMD_CIMSHIFT)))) == 0) + { + + cim->ci_type = CIM_SP502; + } + else + { + cim->ci_type = CIM_RS232; + } + } + else + { + cim->ci_type = CIM_RS232; + } + + if (cim->ci_type == CIM_SP502) + { + cim->ci_flags |= CIM_SYNC; + } + } + else + { + /* + * Pick through the serial EPROM contents and derive + * the values we need. + */ + MEMCPY(&(cim->ci_rev[0]), &(cim->ci_sep[MCS_SEP_REV]), + MCS_SEP_REVLEN); + MEMCPY(&(cim->ci_sn[0]), &(cim->ci_sep[MCS_SEP_SN]), + MCS_SEP_SNLEN); + MEMCPY(&(cim->ci_mfgdate[0]), &(cim->ci_sep[MCS_SEP_MFGDATE]), + MCS_SEP_MFGDATELEN); + MEMCPY(&(cim->ci_mfgloc[0]), &(cim->ci_sep[MCS_SEP_MFGLOC]), + MCS_SEP_MFGLOCLEN); + + cim->ci_clkspeed = (unsigned long) cim->ci_sep[MCS_SEP_CLKSPD] + | ((unsigned long) cim->ci_sep[MCS_SEP_CLKSPD + 1] << 8) + | ((unsigned long) cim->ci_sep[MCS_SEP_CLKSPD + 2] << 16) + | ((unsigned long) cim->ci_sep[MCS_SEP_CLKSPD + 3] << 24); + + cim->ci_clkspdsrc = SEPROM; + + cim->ci_spdgrd = (int) cim->ci_sep[MCS_SEP_SPDGRD]; + cim->ci_spdgrdsrc = SEPROM; + + cim->ci_flags = (unsigned long) cim->ci_sep[MCS_SEP_FLAGS]; + + cim->ci_type = (int) cim->ci_sep[MCS_SEP_TYPE]; + } + + /* + * Possibly initialize the port setup registers. + */ + + if (cim->ci_type == CIM_SP502) + { + unsigned short alloff; +#ifdef DEBUG_VERBOSE + unsigned short readback; +#endif + int offset; + + /* + * Turn off all of the electrical interfaces. The + * hardware *should* initialize to this state, but the + * prototype, at least, does not. Note that this setting + * is reflected in the SIF_OFF setting of l_interface in + * mustard_lineinit, above. + */ + + alloff = (unsigned short) SP502_OFF + | ((unsigned short) SP502_OFF << 4) + | ((unsigned short) SP502_OFF << 8) + | ((unsigned short) SP502_OFF << 12); + for (offset = 0; offset < 8; offset++) + { +#ifdef DEBUG_VERBOSE + DEBUGPRINT((KERN_ALERT "cim %d setup reg #%d: writing 0x%x to 0x%x", + cim->ci_num, offset, (unsigned) alloff, + (CIMCMD_WRSETUP | (offset << 1) | + (cim->ci_num << CIMCMD_CIMSHIFT)))); +#endif /* DEBUG_VERBOSE */ + + writew((unsigned short) alloff, (unsigned short *) + (bptr->CIMCMD_REG + + (CIMCMD_WRSETUP | (offset << 1) | + (cim->ci_num << CIMCMD_CIMSHIFT)))); +#ifdef RICHARD_DELAY + udelay(1); +#endif /* RICHARD_DELAY */ +#ifdef DEBUG_VERBOSE + readback = readw((unsigned short *) + (bptr->CIMCMD_REG + + (CIMCMD_RDSETUP | (offset << 1) | + (cim->ci_num << CIMCMD_CIMSHIFT)))); + if (readback != alloff) + { + DEBUGPRINT((KERN_ALERT "cim %d setup reg #%d: readback (0x%x) should be 0x%x", + cim->ci_num, offset, readback, alloff)); + } +#endif /* DEBUG_VERBOSE */ + } + } + + /* + * Clear out the CIM CSR with the exception of the LED. + */ + + writeb((unsigned char) 0, + (unsigned char *) (bptr->CIMCMD_REG + + (CIMCMD_WRCIMCSR | (cim->ci_num << CIMCMD_CIMSHIFT)))); + + return TRUE; +} + + +int wanmcs_reset(SAB_BOARD* bptr) /* note the board is the host card not the + * individual extension boards + */ +{ + int counter; + +#if 0 /* from the ASE driver */ + /* + * Program the AMCC to deactivate the write FIFO. + */ + + ASE_PUT32(cboard->b_bridgehandle, + (aseuint32_t *) (cboard->b_bridge + AMCC_PTCR), + ((aseuint32_t) (AMCC_PTMODE | AMCC_WRFIFODIS) << 24) | + ((aseuint32_t) (AMCC_PTMODE | AMCC_WRFIFODIS) << 16) | + ((aseuint32_t) (AMCC_PTMODE | AMCC_WRFIFODIS) << 8) | + (aseuint32_t) (AMCC_PTMODE | AMCC_WRFIFODIS)); +#endif /* 0 */ + + /* + * First thing: do a reset of the local bus on the MIC + * by diddling the Add-On Reset bit in the RCR. + */ + + writel((unsigned int) AMCC_AORESET, + (unsigned int *)(bptr->AMCC_REG + AMCC_RCR)); + + udelay(10); /* wait for 10 us. */ + + writel((unsigned int) 0, + (unsigned int *)(bptr->AMCC_REG + AMCC_RCR)); + + udelay(10); /* wait for 10 us. */ + + /* + * Now the PCI bridge is reset. Try to establish + * a link through the Glink chipset. + */ + + for (counter = 1000; counter != 0; counter--) + { + writeb(0, (unsigned char*) (bptr->MICCMD_REG + MICCMD_MICCSR)); + + udelay(5); + + if((readb((unsigned char*) + (bptr->MICCMD_REG + MICCMD_MICCSR)) & MICCMD_MICCSR_GLE) == 0) + { + break; + } + } + + /* + * Did we run out of time? + */ + + if (counter == 0) + { + printk(KERN_ALERT + "AMCC5920: board %p: GLink did not reset -- is the MEB on?", + bptr); + + return FALSE; + } + + /* + * Now, hit the reset in the MEB. + */ + + writeb(0, (unsigned int *) (bptr->CIMCMD_REG + CIMCMD_RESETENA)); + + udelay(5); + + writeb(0, (unsigned int *) (bptr->CIMCMD_REG + CIMCMD_RESETDIS)); + + /* + * And we're done! + */ + + return TRUE; +} + +void aura_sp502_program(SAB_PORT *port, register unsigned int sigindex) +{ + register unsigned char prognibble; + SAB_BOARD *bptr; + unsigned int cimnum; + unsigned int chipno; + unsigned int portno; + unsigned int rdaddressreceiver; + unsigned int rdaddresstransmitter; + unsigned int wraddressreceiver; + unsigned int wraddresstransmitter; + unsigned short datareceiver; + unsigned short datatransmitter; + + bptr = port->board; + cimnum = port->chip->c_cim->ci_num; + chipno = (port->chip->c_chipno & 1); /* chip number relative to EB not MCS */ + portno = (port->portno + (8 * chipno)); /* portno on a per EB basis */ + + prognibble = (sp502progbyte[sigindex] & 0x0F); + + /* first 4 shorts contain receiver control bits */ + rdaddressreceiver = + (((unsigned int)bptr->CIMCMD_REG) + + ((cimnum << CIMCMD_CIMSHIFT) | CIMCMD_RDSETUP | ((portno/4) << CIMCMD_CTRLSHIFT))); + /* second 4 shorts contain transmitter control bits */ + rdaddresstransmitter = + (((unsigned int)bptr->CIMCMD_REG) + + ((cimnum << CIMCMD_CIMSHIFT) | CIMCMD_RDSETUP | ((4+(portno/4)) << CIMCMD_CTRLSHIFT))); + + wraddressreceiver = + (((unsigned int)bptr->CIMCMD_REG) + + ((cimnum << CIMCMD_CIMSHIFT) | CIMCMD_WRSETUP | ((portno/4) << CIMCMD_CTRLSHIFT))); + wraddresstransmitter = + (((unsigned int)bptr->CIMCMD_REG) + + ((cimnum << CIMCMD_CIMSHIFT) | CIMCMD_WRSETUP | ((4+(portno/4)) << CIMCMD_CTRLSHIFT))); + + /* read out the current receiver status */ + datareceiver = readw((unsigned short*) rdaddressreceiver); + /* clear out nibble that corresponds to current port */ + datareceiver &= (unsigned short) ~(0x0F << ((3 - (portno % 4)) * 4)); + /* or in new receiver control field */ + datareceiver |= (prognibble << ((3 - (portno % 4)) * 4)); + /* write back the short that corresponds to 4 ports */ + writew(datareceiver, (unsigned short*) wraddressreceiver); + + /* just as above except that next 4 shorts correspond to transmitters */ + datatransmitter = readw((unsigned short*) rdaddresstransmitter); + datatransmitter &= (unsigned short) ~(0x0F << ((3 - (portno % 4)) * 4)); + datatransmitter |= (prognibble << ((3 - (portno % 4)) * 4)); + writew(datatransmitter, (unsigned short*) wraddresstransmitter); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xmcs.h linux-2.5/drivers/net/wan/8253x/8253xmcs.h --- linux-2.5.20/drivers/net/wan/8253x/8253xmcs.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xmcs.h Fri May 3 03:49:07 2002 @@ -0,0 +1,313 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +#ifndef _8253XMCS_H_ +#define _8253XMCS_H_ + +#include "8253xctl.h" + +/* structures for the multi channel server, the host card, GLINK and + * extensions cards. This system uses the AMCC S5920 instead of the + * PLX 9050 */ + +/* ------------------------------------------------------------------------- */ +/* Useful macros */ + +/* + * NOTICE: pciat_identify: pci125c,102 unit 1 + * NOTICE: pciat_probe: pci125c,102 unit 1 + * NOTICE: pciat_attach: pci125c,102 instance 1 + * NOTICE: Reg End Size Pointer AccHandle + * NOTICE: 0 -- 00000000 5093a000 5033f160 + * NOTICE: 0 be 00000000 5093c000 5033f128 + * NOTICE: 0 le 00000000 50940000 5033f0f0 + * NOTICE: 1 -- 00000080 50942000 5033f0b8 + * NOTICE: 1 be 00000080 50944000 5033f080 + * NOTICE: 1 le 00000080 50946000 5033f048 + * NOTICE: 2 -- 00004000 50948000 5033f010 + * NOTICE: 2 be 00004000 5094c000 5033efd8 + * NOTICE: 2 le 00004000 50950000 5033efa0 + * NOTICE: 3 -- 00008000 50954000 5033ef68 + * NOTICE: 3 be 00008000 5095c000 5033ef30 + * NOTICE: 3 le 00008000 50964000 5033eef8 + * NOTICE: 4 -- 00000800 5096c000 5033eec0 + * NOTICE: 4 be 00000800 5096e000 5033ee88 + * NOTICE: 4 le 00000800 50970000 5033ee50 + * NOTICE: pciat_attach: pci125c,102 1: PCI reg property + * NOTICE: Idx Bus Dev Fun Reg Spc Addr Size + * NOTICE: 0 000 004 000 000 CFG 00000000 00000000 00000000 00000000 + * NOTICE: 1 000 004 000 010 MEM 00000000 00000000 00000000 00000080 + * NOTICE: 2 000 004 000 014 MEM 00000000 00000000 00000000 00004000 + * NOTICE: 3 000 004 000 018 MEM 00000000 00000000 00000000 00008000 + * NOTICE: 4 000 004 000 01c MEM 00000000 00000000 00000000 00000800 + * PCI-device: pci125c,102@4, pciat #1 + */ + +/* + * Serial EPROM information: + * + * + chip speed grade [ one byte ] + * + chip oscillator speed [ 4 bytes ] + * + board revision [ ascii string ] + * + date of manufacture [ ascii string ] + * + location of manufacture [ ascii string ] + * + serial number [ ascii string ] + * + prototype/production flag [ one bit ] + * + sync/async license [ one bit ] + * + CIM type [ one byte ] + * + assembly house [ ascii string ] + */ + +/* + * Serial EPROM map. + */ + +#define MCS_SEP_TYPE 0x00 +#define MCS_SEP_FLAGS 0x01 +#define MCS_SEP_SPDGRD 0x02 +#define MCS_SEP_MAGIC 0x03 +#define MCS_SEP_CLKSPD 0x04 +#define MCS_SEP_SN 0x10 +#define MCS_SEP_SNLEN 0x10 +#define MCS_SEP_REV 0x20 +#define MCS_SEP_REVLEN 0x10 +#define MCS_SEP_MFGLOC 0x30 +#define MCS_SEP_MFGLOCLEN 0x10 +#define MCS_SEP_MFGDATE 0x40 +#define MCS_SEP_MFGDATELEN 0x20 + +#define MCS_SEP_MAGICVAL 0x65 + +/* Host NVRAM DEFINES */ + +#define AMCC_NVR_VENDEVID 0x10 /* offset in 32bit quantities */ + +/* + * PCI spaces on the CIM. + */ +#if 0 /* Solaris driver stuff */ +#define AMCC_REG 1 +#define CIMCMD_REG 2 +#define MICCMD_REG 3 +#define FIFOCACHE_REG 4 +#else +#define AMCC_REG virtbaseaddress0 /* bridge */ +#define CIMCMD_REG virtbaseaddress1 +#define MICCMD_REG virtbaseaddress2 +#define FIFOCACHE_REG virtbaseaddress3 +#endif + +/* + * AMCC registers: + */ + +#define AMCC_OMB 0x0c /* 4 bytes */ +#define AMCC_IMB 0x1c /* 4 bytes */ +#define AMCC_MBEF 0x34 /* 4 bytes */ +#define AMCC_INTCSR 0x38 /* 4 bytes */ +#define AMCC_INTASSERT 0x00800000 /* RO */ +#define AMCC_AOINTPIN 0x00400000 /* RO */ +#define AMCC_IMINT 0x00020000 /* R/WC */ +#define AMCC_OMINT 0x00010000 /* R/WC */ +#define AMCC_AOINTPINENA 0x00002000 /* R/W */ +#define AMCC_RCR 0x3c /* 4 bytes */ +#define AMCC_NVRACCCTRLMASK 0xe0000000 /* nvRAM Acc. Ctrl */ +#define AMCC_NVRACCFAIL 0x10000000 /* RO */ +#define AMCC_NVRBUSY 0x80000000 +#define AMCC_NVRWRLA 0x80000000 +#define AMCC_NVRWRHA 0xa0000000 +#define AMCC_NVRRDDB 0xe0000000 +#define AMCC_NVROPPMASK 0x000f0000 /* R/W */ +#define AMCC_MBXFLGRESET 0x08000000 /* WO */ +#define AMCC_RDFIFORESET 0x02000000 /* WO */ +#define AMCC_AORESET 0x01000000 /* R/W */ +#define AMCC_PTCR 0x60 /* 4 bytes */ +#define AMCC_AMWTSTATEMASK 0x07 +#define AMCC_PREFETCHMASK 0x18 +#define AMCC_WRFIFODIS 0x20 +#define AMCC_ENDCONV 0x40 +#define AMCC_PTMODE 0x80 + +#define AMCC_SIZE 0x80 /* space size, in bytes */ +#define AMCC_NVRAM_SIZE 0x40 /* in shorts just to be consistent with + * other eprom and nvram sizes*/ + +/* + * CIM Command space 0x0000 - 0x3fff + */ + +#define CIMCMD_CHANSHIFT 6 /* shift channel# to the left */ +#define CIMCMD_CHANMASK 0x3f /* 6 bits of mask */ +#define CIMCMD_CIMSHIFT 10 /* shift cim# to the left */ +#define CIMCMD_CIMMASK 0x3 /* 2 bits of mask */ +#define CIMCMD_CTRLSHIFT 1 /* shift control address to the left */ +#define CIMCMD_CTRLMASK 0x7 /* 3 bits of mask */ +#define CIMCMD_CHIPSHIFT 9 + +#define CIMCMD_RESET 0x0000 +#define CIMCMD_RDINT 0x0002 +#define CIMCMD_RDINT_ESCCMASK 0x00ff +#define CIMCMD_WRINT 0x0003 +#define CIMCMD_WRINTENA 0x0004 +#define CIMCMD_WRINTDIS 0x0006 +#define CIMCMD_RESETENA 0x0007 /* assert reset */ +#define CIMCMD_RESETDIS 0x0000 /* deassert the reset */ +#define CIMCMD_RDFIFOW 0x1000 /* add channel# */ +#define CIMCMD_WRFIFOB 0x2002 /* add channel# */ +#define CIMCMD_WRFIFOW 0x2000 /* add channel# */ +#define CIMCMD_RDREGB 0x1000 /* add channel# and reg# (>= 0x20) */ +#define CIMCMD_WRREGB 0x2000 /* add channel# and reg# (>= 0x20) */ +#define CIMCMD_RDSETUP 0x3200 /* add cim# and address (word acc) */ +#define CIMCMD_WRSETUP 0x3220 /* add cim# and address (word acc) */ +#define CIMCMD_RDCIMCSR 0x3000 /* add cim# */ +#define CIMCMD_CIMCSR_LED 0x01 +#define CIMCMD_CIMCSR_SWI 0x02 +#define CIMCMD_CIMCSR_SDA 0x04 +#define CIMCMD_CIMCSR_SCL 0x08 +#define CIMCMD_CIMCSR_TESTMASK 0xc0 +#define CIMCMD_WRCIMCSR 0x3020 /* add cim# */ + +#define CIMCMD_SIZE 0x4000 /* space size, in bytes */ + +/* + * MIC Command space 0x0000 - 0x5fc0 + */ + +#define MICCMD_CHANSHIFT 6 /* shift channel# to the left */ +#define MICCMD_CHANMASK 0x3f /* 6 bits of mask */ + +#define MICCMD_MICCSR 0x0000 /* R/W (byte) */ +#define MICCMD_MICCSR_END 0x80 +#define MICCMD_MICCSR_ENL 0x40 +#define MICCMD_MICCSR_LPN 0x20 +#define MICCMD_MICCSR_DGM 0x10 +#define MICCMD_MICCSR_CPY 0x08 +#define MICCMD_MICCSR_GLE 0x04 +#define MICCMD_MICCSR_RXE 0x02 +#define MICCMD_MICCSR_IRQ 0x01 +#define MICCMD_REV 0x0001 /* RO (byte) */ +#define MICCMD_CACHETRIG 0x5000 /* WO (byte: #words-1) add channel# */ + +#define MICCMD_SIZE 0x8000 /* space size, in bytes */ + +/* + * FIFO Cache space 0x000 - 0x7ff + */ + +#define FIFOCACHE_CHANSHIFT 5 /* shift channel# to the left */ +#define FIFOCACHE_CHANMASK 0x3f /* 6 bits of mask */ + +#define FIFOCACHE_FIFOCACHE 0x000 /* add channel# and word offset */ + +#define FIFOCACHE_SIZE 0x800 /* space size, in bytes */ + +/* + * Other miscellaneous constants + */ + +#define MAX_NCIMS 4 /* maximum of 4 CIMS */ +#define CIM_NPORTS 16 /* 16 ports per CIM */ +#define CIM_NCHIPS 2 /* 2 ESCC8s/CIM */ +#define CHIP_NPORTS 8 /* 8 ports per chip */ + +#define WANMCS_CLKSPEED 7372800 /* 7.3728 MHz */ + + +/* PCR/PVR (Universal Port) */ + +/* + * To summarize the use of the parallel port: + * RS-232 + * Parallel port A -- TxClkdir control (output) ports 0 - 7 + * Parallel port B -- DTR (output) ports 0 - 7 + * Parallel port C -- DSR (input) ports 0 - 7 + * Parallel port D -- unused + */ + +#define WANMCS_PCRAVAL 0x00 /* all output bits */ +#define WANMCS_PCRBVAL 0x00 /* all output bits */ +#define WANMCS_PCRCVAL 0xff /* all input bits */ +#define WANMCS_PCRDVAL 0x0f /* 4 input bits */ + +#define WANMCS_PIMAVAL 0xff /* all interrupts off */ +#define WANMCS_PIMBVAL 0xff /* all interrupts off */ +#define WANMCS_PIMCVAL 0xff /* all interrupts off */ +#define WANMCS_PIMDVAL 0x0f /* all interrupts off */ + +#define WANMCS_PVRAVAL 0xff /* all high */ +#define WANMCS_PVRBVAL 0xff /* all high */ + +#define ANY_BITS_ARE_ON(x, b) (((x) & (b)) != 0) +#define ANY_BITS_ARE_OFF(x, b) ((((x) & (b)) ^ (b)) != 0) +#define ALL_BITS_ARE_ON(x, b) ((((x) & (b)) ^ (b)) == 0) + +/* ------------------------------------------------------------------------- */ +/* New types and type specific macros */ + +typedef struct _mcs_sep +{ +#if 0 + ddi_acc_handle_t s_handle; /* something from Solaris */ +#endif + unsigned char *s_rdptr; + unsigned char *s_wrptr; + unsigned int s_scl; + unsigned int s_sda; +} mcs_sep_t; + +/* + * Per-line private information for wanmcs. + */ + +typedef struct _wanmcspriv +{ + unsigned char r_chipunit; /* [0, 1] or [0, 7] */ + + /* these items are for accessing the ESCCx registers as bytes */ +#if 0 + ddi_acc_handle_t r_reghandle; /* handle for access to ESCCx regs */ +#endif + unsigned char *r_rdregbase; /* base for reading ESCCx registers */ + unsigned char *r_wrregbase; /* base for writing ESCCx registers */ + + /* these items are for accessing the ESCCx FIFOs as bytes and words */ +#if 0 + ddi_acc_handle_t r_fifohandle; +#endif + unsigned short *r_rdfifow; /* read FIFO word */ + unsigned char *r_wrfifob; /* write FIFO byte */ + unsigned short *r_wrfifow; /* write FIFO word */ + + /* these items are for accessing the MIC command space */ +#if 0 + ddi_acc_handle_t r_miccmdhandle; +#endif + unsigned char *r_wrcachetrig; /* the FIFO cache trigger */ + + /* these itmes are for accessing the FIFO cache space */ +#if 0 + ddi_acc_handle_t r_fifocachehandle; +#endif + unsigned short *r_fifocachebase; +} wanmcspriv_t; + +#define AMCC_INT_OFF 0 + +extern unsigned int +amcc_read_nvram(unsigned char* buffer, + unsigned length, + unsigned char *bridge_space); + +extern unsigned int mcs_ciminit(SAB_BOARD *bptr, AURA_CIM *cim); + +extern int wanmcs_reset(SAB_BOARD* bptr); + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xmode.c linux-2.5/drivers/net/wan/8253x/8253xmode.c --- linux-2.5.20/drivers/net/wan/8253x/8253xmode.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xmode.c Fri May 3 03:49:07 2002 @@ -0,0 +1,108 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +#include +#include +#include +#include +#include +#include "8253xioc.h" + +static char *signaling[] = +{ + "OFF", + "RS232", + "RS422", + "RS485", + "RS449", + "RS530", + "V.35" +}; + + /* This application shows how to set sigmode + * on those devices that support software + * programmable signaling. */ +int main(int argc, char **argv) +{ + int fd; + unsigned int oldmode, newmode; + + if(argc != 3) + { + fprintf(stderr, "Syntax: %s {portname} {new mode}.\n", *argv); + fprintf(stderr, "{new mode} = off | 232 | 422 | 485 | 449 | 530 | v.35\n"); + exit(-1); + } + fd = open(argv[1], O_RDWR); + if(fd < 0) + { + perror("open failed."); + exit(-2); + } + if(!strcmp("off", argv[2])) + { + newmode = SP502_OFF_MODE; + } + else if(!strcmp("232", argv[2])) + { + newmode = SP502_RS232_MODE; + } + else if(!strcmp("422", argv[2])) + { + newmode = SP502_RS422_MODE; + } + else if(!strcmp("485", argv[2])) + { + newmode = SP502_RS485_MODE; + } + else if(!strcmp("449", argv[2])) + { + newmode = SP502_RS449_MODE; + } + else if(!strcmp("530", argv[2])) + { + newmode = SP502_EIA530_MODE; + } + else if(!strcmp("v.35", argv[2])) + { + newmode = SP502_V35_MODE; + } + else + { + fprintf(stderr, "Unknown mode %s.\n", argv[2]); + fprintf(stderr, "Syntax: %s {portname} {new mode}.\n", *argv); + fprintf(stderr, "{new mode} = off | 232 | 422 | 485 | 449 | 530 | v.35\n"); + exit(-1); + } + + /* get the current values */ + if(ioctl(fd, ATIS_IOCGSIGMODE, &oldmode) < 0) + { + perror("ATIS_IOCGSIGMODE ioctl failed."); + exit(-3); + } + fprintf(stderr, "old mode = %s.\n", signaling[oldmode]); + + if(ioctl(fd, ATIS_IOCSSIGMODE, &newmode) < 0) + { + perror("ATIS_IOCSSIGMODE ioctl failed."); + exit(-3); + } + + /* get the current values */ + if(ioctl(fd, ATIS_IOCGSIGMODE, &oldmode) < 0) + { + perror("ATIS_IOCGSIGMODE ioctl failed."); + exit(-3); + } + fprintf(stderr, "new mode = %s.\n", signaling[oldmode]); + fflush(stdout); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xnet.c linux-2.5/drivers/net/wan/8253x/8253xnet.c --- linux-2.5.20/drivers/net/wan/8253x/8253xnet.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xnet.c Fri May 3 03:49:07 2002 @@ -0,0 +1,702 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Reg9050.h" +#include "8253xctl.h" +#include "ring.h" +#include "8253x.h" +#include "crc32dcl.h" + + /* turns network packet into a pseudoethernet */ + /* frame -- does ethernet stuff that 8253x does */ + /* not do -- makes minimum 64 bytes add crc, etc*/ +int +sab8253xn_write2(struct sk_buff *skb, struct net_device *dev) +{ + size_t cnt; + unsigned int flags; + SAB_PORT *priv = (SAB_PORT*) dev->priv; + struct sk_buff *substitute; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + if(dev->tbusy != 0) /* something of an error */ + { + ++(priv->Counters.tx_drops); + dev_kfree_skb_any(skb); + return -EBUSY; /* only during release */ + } +#endif + + if(priv->active2.transmit == NULL) + { + return -ENOMEM; + } + + DEBUGPRINT((KERN_ALERT "sab8253x: sending IP packet(bytes):\n")); + + DEBUGPRINT((KERN_ALERT "sab8253x: start address is %p.\n", skb->data)); + + cnt = skb->tail - skb->data; + cnt = MIN(cnt, sab8253xn_rbufsize); + if(cnt < ETH_ZLEN) + { + if((skb->end - skb->data) >= ETH_ZLEN) + { + skb->tail = (skb->data + ETH_ZLEN); + cnt = ETH_ZLEN; + } + else + { + substitute = dev_alloc_skb(ETH_ZLEN); + if(substitute == NULL) + { + dev_kfree_skb_any(skb); + return 0; + } + substitute->tail = (substitute->data + ETH_ZLEN); + memcpy(substitute->data, skb->data, cnt); + cnt = ETH_ZLEN; + dev_kfree_skb_any(skb); + skb = substitute; + } + } + + save_flags(flags); cli(); + if((priv->active2.transmit->Count & OWNER) == OWN_SAB) + { + ++(priv->Counters.tx_drops); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + dev->tbusy = 1; +#else + netif_stop_queue (dev); +#endif + priv->tx_full = 1; + restore_flags(flags); + return 1; + } + restore_flags(flags); +#ifndef FREEINTERRUPT + if(priv->active2.transmit->HostVaddr != NULL) + { + register RING_DESCRIPTOR *freeme; + + freeme = priv->active2.transmit; + do + { + skb_unlink((struct sk_buff*)freeme->HostVaddr); + dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr); + freeme->HostVaddr = NULL; + freeme = (RING_DESCRIPTOR*) freeme->VNext; + } + while(((freeme->Count & OWNER) != OWN_SAB) && + (freeme->HostVaddr != NULL)); + } +#endif + dev->trans_start = jiffies; + skb_queue_head(priv->sab8253xbuflist, skb); + priv->active2.transmit->HostVaddr = skb; + priv->active2.transmit->sendcrc = 1; + priv->active2.transmit->crcindex = 0; + priv->active2.transmit->crc = fn_calc_memory_crc32(skb->data, cnt); + priv->active2.transmit->Count = (OWN_SAB|cnt); /* must be this order */ + priv->active2.transmit = + (RING_DESCRIPTOR*) priv->active2.transmit->VNext; + priv->Counters.transmitbytes += cnt; + sab8253x_start_txS(priv); + return 0; +} + + /* packetizes the received character */ + /* stream */ +static void sab8253x_receive_charsN(struct sab_port *port, + union sab8253x_irq_status *stat) +{ + unsigned char buf[32]; + int free_fifo = 0; + int reset_fifo = 0; + int msg_done = 0; + int msg_bad = 0; + int count = 0; + int total_size = 0; + int rstatus = 0; + struct sk_buff *skb; + + /* Read number of BYTES (Character + Status) available. */ + + if((stat->images[ISR1_IDX] & SAB82532_ISR1_RDO) || (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) ) + { + ++msg_bad; + ++free_fifo; + ++reset_fifo; + } + else + { + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RPF) + { + count = port->recv_fifo_size; + ++free_fifo; + } + + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RME) + { + count = READB(port,rbcl); + count &= (port->recv_fifo_size - 1); + ++msg_done; + ++free_fifo; + + total_size = READB(port, rbch); + if(total_size & SAB82532_RBCH_OV) + { + msg_bad++; + } + + rstatus = READB(port, rsta); + if((rstatus & SAB82532_RSTA_VFR) == 0) + { + msg_bad++; + } + if(rstatus & SAB82532_RSTA_RDO) + { + msg_bad++; + } + if((rstatus & SAB82532_RSTA_CRC) == 0) + { + msg_bad++; + } + if(rstatus & SAB82532_RSTA_RAB) + { + msg_bad++; + } + } + } + + /* Read the FIFO. */ + (*port->readfifo)(port, buf, count); + + /* Issue Receive Message Complete command. */ + + if (free_fifo) + { + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_RMC); + } + + if(reset_fifo) + { + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_RHR); + } + + if(port->active2.receive == NULL) + { + return; + } + + if(msg_bad) + { + ++(port->Counters.rx_drops); + port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; /* clear the buffer */ + port->active2.receive->Count = sab8253xn_rbufsize|OWN_SAB; + return; + } + + memcpy(port->active2.receive->HostVaddr->tail, buf, count); + port->active2.receive->HostVaddr->tail += count; + + if(msg_done) + { + port->active2.receive->Count = + (port->active2.receive->HostVaddr->tail - port->active2.receive->HostVaddr->data); + if((port->active2.receive->Count < (ETH_ZLEN+4+3)) || /* 4 is the CRC32 size 3 bytes from the SAB part */ + (skb = dev_alloc_skb(sab8253xn_rbufsize), skb == NULL)) + { + ++(port->Counters.rx_drops); + port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; + /* clear the buffer */ + port->active2.receive->Count = sab8253xn_rbufsize|OWN_SAB; + } + else + { + port->active2.receive->Count -= 3; + port->active2.receive->HostVaddr->len = port->active2.receive->Count; + port->active2.receive->HostVaddr->pkt_type = PACKET_HOST; + port->active2.receive->HostVaddr->dev = port->dev; + port->active2.receive->HostVaddr->protocol = + eth_type_trans(port->active2.receive->HostVaddr, port->dev); + port->active2.receive->HostVaddr->tail -= 3; + ++(port->Counters.receivepacket); + port->Counters.receivebytes += port->active2.receive->Count; + skb_unlink(port->active2.receive->HostVaddr); + + netif_rx(port->active2.receive->HostVaddr); + + skb_queue_head(port->sab8253xbuflist, skb); + port->active2.receive->HostVaddr = skb; + port->active2.receive->Count = sab8253xn_rbufsize|OWN_SAB; + } + } +} + +static void sab8253x_check_statusN(struct sab_port *port, + union sab8253x_irq_status *stat) +{ + int modem_change = 0; + mctlsig_t *sig; + + + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) + { + port->icount.buf_overrun++; + } + + /* Checking DCD */ + sig = &port->dcd; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,dcd); + port->icount.dcd++; + modem_change++; + } + /* Checking CTS */ + sig = &port->cts; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,cts); + port->icount.cts++; + modem_change++; + } + /* Checking DSR */ + sig = &port->dsr; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,dsr); + port->icount.dsr++; + modem_change++; + } + if (modem_change) + { + wake_up_interruptible(&port->delta_msr_wait); + } + + sig = &port->dcd; + if ((port->flags & FLAG8253X_CHECK_CD) && + (stat->images[sig->irq] & sig->irqmask)) + { + + if (sig->val) + { + netif_carrier_on(port->dev); + } + else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) && + (port->flags & FLAG8253X_CALLOUT_NOHUP))) + { + netif_carrier_off(port->dev); + } + } +#if 0 /* need to think about CTS/RTS stuff for a network driver */ + sig = &port->cts; + if (port->flags & FLAG8253X_CTS_FLOW) + { /* not setting this yet */ + if (port->tty->hw_stopped) + { + if (sig->val) + { + + port->tty->hw_stopped = 0; + sab8253x_sched_event(port, RS_EVENT_WRITE_WAKEUP); + port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); + WRITEB(port, imr1, port->interrupt_mask1); + sab8253x_start_txS(port); + } + } + else + { + if (!(sig->val)) + { + port->tty->hw_stopped = 1; + } + } + } +#endif +} + +static void Sab8253xCollectStats(struct net_device *dev) +{ + + struct net_device_stats *statsp = + &((SAB_PORT*) dev->priv)->stats; + + memset(statsp, 0, sizeof(struct net_device_stats)); + + statsp->rx_packets += + ((SAB_PORT*)dev->priv)->Counters.receivepacket; + statsp->tx_packets += + ((SAB_PORT*)dev->priv)->Counters.transmitpacket; + statsp->tx_dropped += + ((SAB_PORT*)dev->priv)->Counters.tx_drops; + statsp->rx_dropped += + ((SAB_PORT*)dev->priv)->Counters.rx_drops; +} + +struct net_device_stats *sab8253xn_stats(struct net_device *dev) +{ + SAB_PORT *priv = (SAB_PORT*) dev->priv; + + Sab8253xCollectStats(dev); + return &priv->stats; +} + +/* minimal ioctls -- more to be added later */ +int sab8253xn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + + SAB_PORT *priv = (SAB_PORT*) dev->priv; + + switch(cmd) + { + case SAB8253XCLEARCOUNTERS: + memset(&priv->Counters, 0, sizeof(struct counters)); + break; + + default: + break; + } + return 0; +} + +#if 0 +static int sab8253x_block_til_readyN(SAB_PORT *port) +{ + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (port->flags & FLAG8253X_CLOSING) + { + if (port->flags & FLAG8253X_CLOSING) + { + interruptible_sleep_on(&port->close_wait); + } +#ifdef SERIAL_DO_RESTART + if (port->flags & FLAG8253X_HUP_NOTIFY) + { + return -EAGAIN; + } + else + { + return -ERESTARTSYS; + } +#else + return -EAGAIN; +#endif + } + + /* + * this is not a callout device + */ + + /* suppose callout active */ + if (port->flags & FLAG8253X_CALLOUT_ACTIVE) + { + if (port->normal_termios.c_cflag & CLOCAL) + { + do_clocal = 1; + } + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, port->count is dropped by one, so that + * sab8253x_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&port->open_wait, &wait); + port->blocked_open++; + while (1) + { + save_flags(flags); cli(); + if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE)) + { + RAISE(port,dtr); + RAISE(port,rts); /* maybe not correct for sync */ + /* + * ??? Why changing the mode here? + * port->regs->rw.mode |= SAB82532_MODE_FRTS; + * port->regs->rw.mode &= ~(SAB82532_MODE_RTS); + */ + } + restore_flags(flags); + current->state = TASK_INTERRUPTIBLE; + if (!(port->flags & FLAG8253X_INITIALIZED)) + { +#ifdef SERIAL_DO_RESTART + if (port->flags & FLAG8253X_HUP_NOTIFY) + { + retval = -EAGAIN; + } + else + { + retval = -ERESTARTSYS; + } +#else + retval = -EAGAIN; +#endif + break; + } + if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE) && + !(port->flags & FLAG8253X_CLOSING) && + (do_clocal || ISON(port,dcd))) + { + break; + } +#ifdef DEBUG_OPEN + printk("block_til_readyN:2 flags = 0x%x\n",port->flags); +#endif + if (signal_pending(current)) + { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&port->open_wait, &wait); + port->blocked_open--; + if (retval) + { + return retval; + } + port->flags |= FLAG8253X_NORMAL_ACTIVE; /* is this a good flag? */ + return 0; +} +#endif + +int sab8253x_startupN(struct sab_port *port) +{ + unsigned long flags; + int retval = 0; + + save_flags(flags); cli(); + + if (port->flags & FLAG8253X_INITIALIZED) + { + goto errout; + } + + if (!port->regs) + { + retval = -ENODEV; + goto errout; + } + /* + * Initialize the Hardware + */ + sab8253x_init_lineS(port); /* nothing in this function + * refers to tty structure */ + + /* Activate RTS */ + RAISE(port,rts); + /* Activate DTR */ + RAISE(port,dtr); + /* + * Initialize the modem signals values + */ + port->dcd.val=ISON(port,dcd); + port->cts.val=ISON(port,cts); + port->dsr.val=ISON(port,dsr); + /* + * Finally, enable interrupts + */ + + port->interrupt_mask0 = SAB82532_IMR0_RFS | SAB82532_IMR0_PCE | + SAB82532_IMR0_PLLA | SAB82532_IMR0_RSC | SAB82532_IMR0_CDSC; + /*((port->ccontrol.ccr2 & SAB82532_CCR2_TOE) ? SAB82532_IMR0_CDSC : 0); */ + + WRITEB(port,imr0,port->interrupt_mask0); + port->interrupt_mask1 = SAB82532_IMR1_EOP | SAB82532_IMR1_XMR | + SAB82532_IMR1_TIN | SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + port->all_sent = 1; + + + /* + * and set the speed of the serial port + */ + sab8253x_change_speedN(port); + + port->flags |= FLAG8253X_INITIALIZED; /* bad name for indicating to other functionalities status */ + port->receive_chars = sab8253x_receive_charsN; + port->transmit_chars = sab8253x_transmit_charsS; + port->check_status = sab8253x_check_statusN; + port->receive_test = (SAB82532_ISR0_RME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF); + port->transmit_test = (SAB82532_ISR1_ALLS | SAB82532_ISR1_RDO | SAB82532_ISR1_XPR | + SAB82532_ISR1_XDU | SAB82532_ISR1_CSC); + port->check_status_test = (SAB82532_ISR1_CSC); + + /*((port->ccontrol.ccr2 & SAB82532_CCR2_TOE) ? 0 : SAB82532_ISR0_CDSC));*/ + + restore_flags(flags); + return 0; + + errout: + restore_flags(flags); + return retval; +} + +int sab8253xn_open(struct net_device *dev) +{ + unsigned int retval; + SAB_PORT *priv = (SAB_PORT*) dev->priv; + + if(priv->function != FUNCTION_NR) + { + return -ENODEV; /* only allowed if there are no restrictions on the port */ + } + + + if(priv->flags & FLAG8253X_CLOSING) /* try again after the TTY close finishes */ + { +#ifdef SERIAL_DO_RESTART + return ((priv->flags & FLAG8253X_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); /* The ifconfig UP will just fail */ +#else + return -EAGAIN; +#endif + } + + /* + * Maybe start up serial port -- may already be running a TTY + */ + if(priv->flags & FLAG8253X_NORMAL_ACTIVE) /* probably should be a test open at all */ + { + return -EBUSY; /* can't reopen in NET */ + } + + if(Sab8253xSetUpLists(priv)) + { + return -ENODEV; + } + + if(Sab8253xInitDescriptors2(priv, sab8253xn_listsize, sab8253xn_rbufsize)) + { + Sab8253xCleanUpTransceiveN(priv); + return -ENODEV; + } + netif_carrier_off(dev); + + priv->open_type = OPEN_SYNC_NET; + priv->tty = 0; + + retval = sab8253x_startupN(priv); + if (retval) + { + Sab8253xCleanUpTransceiveN(priv); + return retval; + } + + priv->flags |= FLAG8253X_NETWORK; /* flag the call out driver that it has to reinitialize the port */ + priv->tx_full = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + dev->start = 1; + dev->tbusy = 0; +#else + netif_start_queue(dev); +#endif + + priv->flags |= FLAG8253X_NORMAL_ACTIVE; /* is this a good flag? */ + MOD_INC_USE_COUNT; + return 0; /* success */ +} +/* stop the PPC, free all skbuffers */ +int sab8253xn_release(struct net_device *dev) /* stop */ +{ + SAB_PORT *priv = (SAB_PORT*) dev->priv; + unsigned long flags; + + printk(KERN_ALERT "sab8253xn: network interface going down.\n"); + save_flags(flags); cli(); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + dev->start = 0; + dev->tbusy = 1; +#else + netif_stop_queue (dev); +#endif + + sab8253x_shutdownN(priv); + Sab8253xCleanUpTransceiveN(priv); + netif_carrier_off(dev); + priv->flags &= ~FLAG8253X_NETWORK; + priv->flags &= ~(FLAG8253X_NORMAL_ACTIVE|/*FLAG8253X_CALLOUT_ACTIVE|*/ + FLAG8253X_CLOSING); + priv->open_type = OPEN_NOT; + MOD_DEC_USE_COUNT; + restore_flags(flags); + return 0; +} + +SAB_PORT *current_sab_port = NULL; + +int sab8253xn_init(struct net_device *dev) +{ + + SAB_PORT *priv; + + printk(KERN_ALERT "sab8253xn: initializing SAB8253X network driver instance.\n"); + + priv = current_sab_port; + dev->priv = priv; + + if(dev->priv == NULL) + { + printk(KERN_ALERT "sab8253xn: could not find active port!\n"); + return -ENOMEM; + } + priv->dev = dev; + + ether_setup(dev); + + dev->irq = priv->irq; + dev->hard_start_xmit = sab8253xn_write2; + dev->do_ioctl = sab8253xn_ioctl; + dev->open = sab8253xn_open; + dev->stop = sab8253xn_release; + dev->get_stats = sab8253xn_stats; + dev->base_addr = (unsigned) priv->regs; + /* should I do a request region here */ + priv->next_dev = Sab8253xRoot; + Sab8253xRoot = dev; + return 0; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xplx.c linux-2.5/drivers/net/wan/8253x/8253xplx.c --- linux-2.5.20/drivers/net/wan/8253x/8253xplx.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xplx.c Fri May 3 03:49:07 2002 @@ -0,0 +1,299 @@ +/* -*- linux-c -*- */ + +/* plx9050.c + * Copyright (C) 2000 by Francois Wautier + * based on code from Bjorn Davis + * + * Read and write command for the eprom attached to + * the PLX9050 + */ + +/* Modifications and extensions + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + **/ + +/* We handle PCI devices */ +#include + +/* We need to use ioremap */ +#include + +#include + + /* Joachim Martillo modified this file */ + /* so that it had no dependencies on specific */ + /* Aurora adapter card or ESSC* structures*/ + /* The original file use TRUE for 1 and */ + /* FALSE for 0. This convention conflicted */ + /* with other conventions throughout LINUX */ + /* also TRUE was used for setting an eprom */ + /* bit which is a slight semantic confusion. */ + /* I just used 0 and 1 */ +#include "Reg9050.h" + +/* + * Write a single bit to the serial EPROM interface. + */ + + /* eprom_ctl is the */ + /* address of the 9050 */ + /* eprom control register */ + /* The original & operation */ + /* looks wrong. I am surprised */ + /* the code worked */ + /* but I left the parentheses */ + /* because readl, writel etc */ + /* are macros*/ + + /* The following function */ + /* assumes the proper bit */ + /* in the serial eprom */ + /* has already been selected*/ + + /* The 9050 registers are 32 bits */ + /* hence the readl and writel */ + /* macros are invoked*/ + + /* eprom_ctl must be a virtual */ + /* address*/ + +static void plx9050_eprom_wbit(unsigned int* eprom_ctl, unsigned int val) +{ + unsigned int ctrl; + + /* get the initial value of the CTRL register */ + ctrl = readl((eprom_ctl)); + + /* set or clear the data bit */ + if (val) + { + ctrl |= PLX_CTRL_SEPWD; + } + else + { + ctrl &= ~PLX_CTRL_SEPWD; + } + + writel(ctrl, (eprom_ctl)); + + udelay(1); + + /* Toggle the clock line */ + /* gets to the next bit */ + /* in the serial eprom */ + ctrl |= PLX_CTRL_SEPCLK; + writel(ctrl, (eprom_ctl)); + + udelay(1); + + /* Toggle the clock line */ + ctrl &= ~PLX_CTRL_SEPCLK; + writel(ctrl, (eprom_ctl)); + udelay(1); +} + +/* + * Run a serial EPROM command. Returns 1 on success, + * 0 otherwise. + */ + +/* This routine does the write of data but only sets up */ +/* for a read*/ +/* the write goes from most significant to least significant */ +unsigned int plx9050_eprom_cmd(unsigned int* eprom_ctl, unsigned char cmd, unsigned char addr, unsigned short data) +{ + unsigned int ctrl; + unsigned char shiftb; + unsigned short shiftw; + unsigned int l, v; + unsigned char ret; + int i; + + ret = 1; + shiftb = addr << (NM93_BITS_PER_BYTE - NM93_ADDRBITS); /* looks a bizarre way to mask out unused bits */ + + ctrl = readl((eprom_ctl)); + + ctrl &= ~(PLX_CTRL_SEPCLK | PLX_CTRL_SEPWD); + writel(ctrl, (eprom_ctl)); + udelay(1); + + ctrl |= PLX_CTRL_SEPCS; + writel(ctrl, (eprom_ctl)); + + plx9050_eprom_wbit(eprom_ctl, 1); + + /* + * Clock out the command + */ + + plx9050_eprom_wbit(eprom_ctl, (cmd & 0x02) != 0); + plx9050_eprom_wbit(eprom_ctl, (cmd & 0x01) != 0); + + /* + * Clock out the address + */ + + i = NM93_ADDRBITS; + while (i != 0) /* here we get to the correct */ + /* short in the serial eprom*/ + { + /* printf("Loop #1\n"); */ + plx9050_eprom_wbit(eprom_ctl, (shiftb & 0x80) != 0); + + shiftb <<= 1; + i--; + } + + if (cmd == NM93_WRITECMD) /* now do the write if */ + /* a write is to be done*/ + { + /* write data? */ + /* + * Clock out the data + */ + + shiftw = data; + + i = NM93_BITS_PER_WORD; + while (i != 0) { + /* printf("Loop #2\n"); */ + plx9050_eprom_wbit(eprom_ctl, (shiftw & 0x8000) != 0); + + shiftw <<= 1; + i--; + } + + /* + * De-assert chip select for a short period of time + */ + ctrl = readl((eprom_ctl)); + + ctrl &= ~PLX_CTRL_SEPCS; + writel(ctrl, (eprom_ctl)); + udelay(2); + + /* + * Re-assert chip select + */ + ctrl |= PLX_CTRL_SEPCS; + writel(ctrl, (eprom_ctl)); + + /* + * Wait for a low to high transition of DO + */ + + i = 20000; + ctrl = readl((eprom_ctl)); + l = (ctrl & PLX_CTRL_SEPRD); + + while (i != 0) + { + /* printf("Loop #3\n"); */ + ctrl = readl((eprom_ctl)); + v = (ctrl & PLX_CTRL_SEPRD); + if (v != 0 && l == 0) + { + break; + } + l = v; + udelay(1); + i--; + } + + if (i == 0) + { + printk("plx9050: eprom didn't go low to high"); + ret = 0; + } + } + + if (cmd != NM93_READCMD) /* not a read -- terminate */ + { + /* + * De-assert the chip select. + */ + + ctrl = readl((eprom_ctl)); + ctrl &= ~PLX_CTRL_SEPCS; + writel(ctrl,(eprom_ctl)); + } + /* otherwise left in read state */ + return ret; +} + +/* + * Read the serial EPROM. Returns 1 on success, 0 on failure. + * reads in shorts (i.e., 16 bits at a time.) + * + */ + +unsigned int +plx9050_eprom_read(unsigned int* eprom_ctl, unsigned short *ptr, unsigned char addr, unsigned short len) +{ + unsigned short shiftw; + int i; + unsigned int ctrl; + + if (!plx9050_eprom_cmd(eprom_ctl, NM93_READCMD, addr, (unsigned short) 0x0)) /* set up read */ + { + return 0; + } + + ctrl = readl((eprom_ctl)); /* synchronize */ + + while (len-- > 0) /* now read one word at a time */ + { + shiftw = 0; + + ctrl &= ~PLX_CTRL_SEPCLK; + writel(ctrl, (eprom_ctl)); + + udelay(1); + + i = NM93_BITS_PER_WORD; + while (1) /* now read one bit at a time, */ + /* left shifting each bit */ + { + ctrl |= PLX_CTRL_SEPCLK; + writel(ctrl, (eprom_ctl)); + + udelay(1); + + ctrl = readl((eprom_ctl)); + + + if ((ctrl & PLX_CTRL_SEPRD) != 0) + { + shiftw |= 0x1; + } + + i--; + if (i == 0) + { + break; + } + shiftw <<= 1; + + ctrl &= ~PLX_CTRL_SEPCLK; + writel(ctrl, (eprom_ctl)); + udelay(1); + } + + *ptr++ = shiftw; + } + + ctrl &= ~PLX_CTRL_SEPCS; + writel(ctrl, (eprom_ctl)); + + udelay(1); + ctrl &= ~PLX_CTRL_SEPCLK; + writel(ctrl, (eprom_ctl)); + + return 1; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xsyn.c linux-2.5/drivers/net/wan/8253x/8253xsyn.c --- linux-2.5.20/drivers/net/wan/8253x/8253xsyn.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xsyn.c Fri May 3 19:43:56 2002 @@ -0,0 +1,1339 @@ +/* -*- linux-c -*- */ +/* $Id: 8253xsyn.c,v 1.17 2002/02/10 22:17:25 martillo Exp $ + * 8253xsyn.c: SYNC TTY Driver for the SIEMENS SAB8253X DUSCC. + * + * Implementation, modifications and extensions + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* Standard in kernel modules */ +#define DEFINE_VARIABLE +#include /* Specifically, a module */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "8253xctl.h" +#include "8253x.h" +#include +#include + +#ifdef MODULE +#undef XCONFIG_SERIAL_CONSOLE +#endif + + +static void sab8253x_flush_to_ldiscS(void *private_) /* need a separate version for sync + there are no flags associated with + received sync TTY data*/ +{ + struct tty_struct *tty = (struct tty_struct *) private_; + unsigned char *cp; + int count; + struct sab_port *port; + struct sk_buff *skb; + + if(tty) + { + port = (struct sab_port *)tty->driver_data; + } + else + { + return; + } + if(port == NULL) + { + return; + } + + if (test_bit(TTY_DONT_FLIP, &tty->flags)) + { + queue_task(&tty->flip.tqueue, &tq_timer); + return; + } + /* note that a hangup may have occurred -- perhaps should check for that */ + port->DoingInterrupt = 1; + while(port->sab8253xc_rcvbuflist && (skb_queue_len(port->sab8253xc_rcvbuflist) > 0)) + { + skb = skb_dequeue(port->sab8253xc_rcvbuflist); + count = skb->data_len; + cp = skb->data; + (*tty->ldisc.receive_buf)(tty, cp, 0, count); + dev_kfree_skb_any(skb); + } + port->DoingInterrupt = 0; +} + +void sab8253x_flush_charsS(struct tty_struct *tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_flush_chars")) + { + return; + } + + if ((Sab8253xCountTransmit(port) <= 0) || tty->stopped || tty->hw_stopped) + { /* can't flush */ + return; + } + + sab8253x_start_txS(port); +} + +/* + * ------------------------------------------------------------ + * sab8253x_stopS() and sab8253x_startS() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ + +void sab8253x_stopS(struct tty_struct *tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + /* can't do anything here */ + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_stop")) + { + return; + } + /* interrupt handles it all*/ + /* turning off XPR is not an option in sync mode */ +} + +void sab8253x_startS(struct tty_struct *tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_start")) + { + return; + } + sab8253x_start_txS(port); +} + + +static void sab8253x_receive_charsS(struct sab_port *port, + union sab8253x_irq_status *stat) +{ + struct tty_struct *tty = port->tty; + unsigned char buf[32]; + int free_fifo = 0; + int reset_fifo = 0; + int msg_done = 0; + int msg_bad = 0; + int count = 0; + int total_size = 0; + int rstatus = 0; + struct sk_buff *skb; + + /* Read number of BYTES (Character + Status) available. */ + + if((stat->images[ISR1_IDX] & SAB82532_ISR1_RDO) || (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) ) + { + ++msg_bad; + ++free_fifo; + ++reset_fifo; + } + else + { + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RPF) + { + count = port->recv_fifo_size; + ++free_fifo; + } + + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RME) + { + count = READB(port, rbcl); + count &= (port->recv_fifo_size - 1); + ++msg_done; + ++free_fifo; + + total_size = READB(port, rbch); + if(total_size & SAB82532_RBCH_OV) /* need to revisit for 4096 byte frames */ + { + msg_bad++; + } + + rstatus = READB(port, rsta); + if((rstatus & SAB82532_RSTA_VFR) == 0) + { + msg_bad++; + } + if(rstatus & SAB82532_RSTA_RDO) + { + msg_bad++; + } + if((rstatus & SAB82532_RSTA_CRC) == 0) + { + msg_bad++; + } + if(rstatus & SAB82532_RSTA_RAB) + { + msg_bad++; + } + } + } + + /* Read the FIFO. */ + + (*port->readfifo)(port, buf, count); + + + /* Issue Receive Message Complete command. */ + + if (free_fifo) + { + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_RMC); + } + + if(reset_fifo) + { + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_RHR); + } + + if(msg_bad) + { + port->msgbufindex = 0; + return; + } + + memcpy(&port->msgbuf[port->msgbufindex], buf, count); + port->msgbufindex += count; + +#ifdef CONSOLE_SUPPORT + if (port->is_console) + { + wake_up(&keypress_wait); + } +#endif + + if(msg_done) + { + + if(port->msgbufindex <= 3) /* min is 1 char + 2 CRC + status byte */ + { + port->msgbufindex = 0; + return; + } + + total_size = port->msgbufindex - 3; /* strip off the crc16 and the status byte */ + port->msgbufindex = 0; + + /* ignore the receive buffer waiting -- we know the correct size here */ + + if (!tty) + { + return; + } + if(skb = dev_alloc_skb(total_size), skb) + { + memcpy(skb->data, &port->msgbuf[0], total_size); + skb->tail = (skb->data + total_size); + skb->data_len = total_size; + skb->len = total_size; + skb_queue_tail(port->sab8253xc_rcvbuflist, skb); + } + queue_task(&tty->flip.tqueue, &tq_timer); /* clear out flip buffer as fast as possible + * maybe should not be done unconditionally hear + * but should be within the above consequence + * clause */ + } +} + + +static void sab8253x_check_statusS(struct sab_port *port, + union sab8253x_irq_status *stat) +{ + struct tty_struct *tty = port->tty; + int modem_change = 0; + mctlsig_t *sig; + + if (!tty) + { + return; + } + + /* check_modem:*/ + /* Checking DCD */ + sig = &port->dcd; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,dcd); + port->icount.dcd++; + modem_change++; + } + /* Checking CTS */ + sig = &port->cts; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,cts); + port->icount.cts++; + modem_change++; + } + /* Checking DSR */ + sig = &port->dsr; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,dsr); + port->icount.dsr++; + modem_change++; + } + if (modem_change) + { + wake_up_interruptible(&port->delta_msr_wait); + } + + sig = &port->dcd; + if ((port->flags & FLAG8253X_CHECK_CD) && + (stat->images[sig->irq] & sig->irqmask)) + { + + if (sig->val) + { + wake_up_interruptible(&port->open_wait); + } + else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) && + (port->flags & FLAG8253X_CALLOUT_NOHUP))) + { +#if 0 /* requires more investigation */ + MOD_INC_USE_COUNT; + if (schedule_task(&port->tqueue_hangup) == 0) + { + MOD_DEC_USE_COUNT; + } +#endif + } + } + + sig = &port->cts; + if (port->flags & FLAG8253X_CTS_FLOW) + { /* not setting this yet */ + if (port->tty->hw_stopped) + { + if (sig->val) + { + port->tty->hw_stopped = 0; + sab8253x_sched_event(port, SAB8253X_EVENT_WRITE_WAKEUP); + sab8253x_start_txS(port); + } + } + + else + { + if(!(getccr2configS(port) & SAB82532_CCR2_TOE)) + { + if (!(sig->val)) + { + port->tty->hw_stopped = 1; + } + } + } + } +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void sab8253x_change_speedS(struct sab_port *port) +{ + unsigned long flags,baud; + tcflag_t cflag; + u8 ccr2=0,ccr4=0,ebrg=0; + int i, bits; +#ifdef DEBUGGING + printk("Change speed! "); +#endif + if (!port->tty || !port->tty->termios) + { +#ifdef DEBUGGING + printk("NOT!\n"); +#endif + return; + } + +#ifdef DEBUGGING + printk(" for real.\n"); +#endif + + cflag = port->tty->termios->c_cflag; + + /* Byte size and parity */ + switch (cflag & CSIZE) + { + case CS5: + bits = 7; + break; + case CS6: + bits = 8; + break; + case CS7: + bits = 9; + break; + default: + case CS8: + bits = 10; + break; + } + + if (cflag & CSTOPB) + { + bits++; + } + + if (cflag & PARENB) + { + bits++; + } + + /* Determine EBRG values based on the "encoded"baud rate */ + i = cflag & CBAUD; + switch(i) + { + case B0: + baud=0; + break; + case B50: + baud=100; + break; + case B75: + baud=150; + break; + case B110: + baud=220; + break; + case B134: + baud=269; + break; + case B150: + baud=300; + break; + case B200: + baud=400; + break; + case B300: + baud=600; + break; + case B600: + baud=1200; + break; + case B1200: + baud=2400; + break; + case B1800: + baud=3600; + break; + case B2400: + baud=4800; + break; + case B4800: + baud=9600; + break; + case B9600: + baud=19200; + break; + case B19200: + baud=38400; + break; + case B38400: + if(port->custspeed) + { + baud=port->custspeed<<1; + } + else + { + baud=76800; + } + break; + case B57600: + baud=115200; + break; +#ifdef SKIPTHIS + case B76800: + baud=153600; + break; + case B153600: + baud=307200; + break; +#endif + case B230400: + baud=460800; + break; + case B460800: + baud=921600; + break; + case B115200: + default: + baud=230400; + break; + } + + if(!sab8253x_baud(port,baud,&ebrg,&ccr2,&ccr4,&(port->baud))) + { + printk("Aurora Warning. baudrate %ld could not be set! Using 115200",baud); + baud=230400; + sab8253x_baud(port,baud,&ebrg,&ccr2,&ccr4,&(port->baud)); + } + + if (port->baud) + port->timeout = (port->xmit_fifo_size * HZ * bits) / port->baud; + else + port->timeout = 0; + port->timeout += HZ / 50; /* Add .02 seconds of slop */ + + /* CTS flow control flags */ + if (cflag & CRTSCTS) + port->flags |= FLAG8253X_CTS_FLOW; + else + port->flags &= ~(FLAG8253X_CTS_FLOW); + + if (cflag & CLOCAL) + port->flags &= ~(FLAG8253X_CHECK_CD); + else + port->flags |= FLAG8253X_CHECK_CD; + if (port->tty) + port->tty->hw_stopped = 0; + + /* + * Set up parity check flag + * XXX: not implemented, yet. + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + /* + * Characters to ignore + * XXX: not implemented, yet. + */ + + /* + * !!! ignore all characters if CREAD is not set + * XXX: not implemented, yet. + */ + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= SAB82532_ISR0_RPF; + + save_flags(flags); + cli(); + sab8253x_cec_wait(port); + + WRITEB(port, bgr, ebrg); + WRITEB(port, ccr2, READB(port, ccr2) & ~(0xc0)); /* clear out current baud rage */ + WRITEB(port, ccr2, READB(port, ccr2) | ccr2); + WRITEB(port, ccr4, (READB(port,ccr4) & ~SAB82532_CCR4_EBRG) | ccr4); + + if (port->flags & FLAG8253X_CTS_FLOW) + { + WRITEB(port, mode, READB(port,mode) & ~(SAB82532_MODE_RTS)); + port->interrupt_mask1 &= ~(SAB82532_IMR1_CSC); + WRITEB(port, imr1, port->interrupt_mask1); + } + else + { + WRITEB(port, mode, READB(port,mode) | SAB82532_MODE_RTS); + port->interrupt_mask1 |= SAB82532_IMR1_CSC; + WRITEB(port, imr1, port->interrupt_mask1); + } + WRITEB(port, mode, READB(port, mode) | SAB82532_MODE_RAC); + restore_flags(flags); +} + +void sab8253x_set_termiosS(struct tty_struct *tty, + struct termios *old_termios) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if((tty->termios->c_cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) + { + return; + } + if(!port) + { + return; + } + sab8253x_change_speedS(port); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(tty->termios->c_cflag & CBAUD)) + { + LOWER(port,rts); + LOWER(port,dtr); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (tty->termios->c_cflag & CBAUD)) + { + RAISE(port,dtr); + if (!tty->hw_stopped || + !(tty->termios->c_cflag & CRTSCTS)) + { + RAISE(port,rts); + } + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) + { + tty->hw_stopped = 0; + sab8253x_startS(tty); + } +} + +static int sab8253x_startupS(struct sab_port *port) +{ + unsigned long flags; + int retval = 0; + + save_flags(flags); cli(); + + port->msgbufindex = 0; + port->xmit_buf = NULL; + port->buffergreedy = 0; + + if (port->flags & FLAG8253X_INITIALIZED) + { + goto errout; + } + + if (!port->regs) + { + if (port->tty) + { + set_bit(TTY_IO_ERROR, &port->tty->flags); + } + retval = -ENODEV; + goto errout; + } + /* + * Initialize the Hardware + */ + sab8253x_init_lineS(port); + +#if 0 /* maybe should be conditional */ + if (port->tty->termios->c_cflag & CBAUD) + { +#endif + /* Activate RTS */ + RAISE(port,rts); + /* Activate DTR */ + RAISE(port,dtr); +#if 0 + } +#endif + + /* + * Initialize the modem signals values + */ + port->dcd.val=ISON(port,dcd); + port->cts.val=ISON(port,cts); + port->dsr.val=ISON(port,dsr); + /* + * Finally, enable interrupts + */ + + port->interrupt_mask0 = SAB82532_IMR0_RFS | SAB82532_IMR0_PCE | + SAB82532_IMR0_PLLA | SAB82532_IMR0_RSC | SAB82532_IMR0_CDSC; + + /*((port->ccontrol.ccr2 & SAB82532_CCR2_TOE) ? SAB82532_IMR0_CDSC : 0); */ + + WRITEB(port,imr0,port->interrupt_mask0); + port->interrupt_mask1 = SAB82532_IMR1_EOP | SAB82532_IMR1_XMR | + SAB82532_IMR1_TIN | SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + port->all_sent = 1; + + if (port->tty) + { + clear_bit(TTY_IO_ERROR, &port->tty->flags); + } + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + + /* + * and set the speed of the serial port + */ + sab8253x_change_speedS(port); + + port->flags |= FLAG8253X_INITIALIZED; + port->receive_chars = sab8253x_receive_charsS; + port->transmit_chars = sab8253x_transmit_charsS; + port->check_status = sab8253x_check_statusS; + port->receive_test = (SAB82532_ISR0_RME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF); + port->transmit_test = (SAB82532_ISR1_ALLS | SAB82532_ISR1_RDO | SAB82532_ISR1_XPR | + SAB82532_ISR1_XDU | SAB82532_ISR1_CSC); + port->check_status_test = (SAB82532_ISR1_CSC); + + /*((port->ccontrol.ccr2 & SAB82532_CCR2_TOE) ? 0 : SAB82532_ISR0_CDSC));*/ + + + restore_flags(flags); + return 0; + + errout: + restore_flags(flags); + return retval; +} + +static void sab8253x_shutdownS(struct sab_port *port) +{ + unsigned long flags; + + if (!(port->flags & FLAG8253X_INITIALIZED)) + { + return; + } + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&port->delta_msr_wait); + + if (port->xmit_buf) + { + port->xmit_buf = 0; + } +#ifdef XCONFIG_SERIAL_CONSOLE + if (port->is_console) + { + port->interrupt_mask0 = + SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + /*SAB82532_IMR0_TIME |*/ + SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; + WRITEB(port,imr0,port->interrupt_mask0); + port->interrupt_mask1 = + SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + WRITEB(port,imr1,port->interrupt_mask1); + if (port->tty) + { + set_bit(TTY_IO_ERROR, &port->tty->flags); + } + port->flags &= ~FLAG8253X_INITIALIZED; + restore_flags(flags); + return; + } +#endif + + /* Disable Interrupts */ + + port->interrupt_mask0 = 0xff; + WRITEB(port, imr0, port->interrupt_mask0); + port->interrupt_mask1 = 0xff; + WRITEB(port, imr1, port->interrupt_mask1); + + if (!port->tty || (port->tty->termios->c_cflag & HUPCL)) + { + LOWER(port,rts); + LOWER(port,dtr); + } + + /* Disable Receiver */ + CLEAR_REG_BIT(port,mode,SAB82532_MODE_RAC); + + /* Power Down */ + CLEAR_REG_BIT(port,ccr0,SAB82532_CCR0_PU); + + if (port->tty) + { + set_bit(TTY_IO_ERROR, &port->tty->flags); + } + + port->flags &= ~FLAG8253X_INITIALIZED; + restore_flags(flags); +} + +int sab8253x_writeS(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + struct sk_buff *skb; + int truelength = 0; + int do_queue = 1; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_write")) + { + return 0; + } + + if(count == 0) + { + return 0; + } + + if(port->active2.transmit == NULL) + { + return 0; + } + + if((port->active2.transmit->Count & OWNER) == OWN_SAB) + { + sab8253x_start_txS(port); /* no descriptor slot */ + return 0; + } + +#ifndef FREEININTERRUPT + skb = port->active2.transmit->HostVaddr; /* current slot value */ + + if(port->buffergreedy == 0) /* are we avoiding buffer free's */ + { /* no */ + if((skb != NULL) || /* not OWN_SAB from above */ + (port->active2.transmit->crcindex != 0)) + { + register RING_DESCRIPTOR *freeme; + + freeme = port->active2.transmit; + do + { + if((freeme->crcindex == 0) && (freeme->HostVaddr == NULL)) + { + break; + } + if(freeme->HostVaddr) + { + skb_unlink((struct sk_buff*)freeme->HostVaddr); + dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr); + freeme->HostVaddr = NULL; + } + freeme->sendcrc = 0; + freeme->crcindex = 0; + freeme = (RING_DESCRIPTOR*) freeme->VNext; + } + while((freeme->Count & OWNER) != OWN_SAB); + } + skb = NULL; /* buffer was freed */ + } + + if(skb != NULL) /* potentially useful */ + { + truelength = (skb->end - skb->head); + if(truelength >= count) + { + skb->data = skb->head; /* this buffer is already queued */ + skb->tail = skb->head; + do_queue = 0; + } + else + { + skb_unlink(skb); + dev_kfree_skb_any(skb); + skb = NULL; + port->active2.transmit->HostVaddr = NULL; + } + } + /* in all cases the following is allowed */ + port->active2.transmit->sendcrc = 0; + port->active2.transmit->crcindex = 0; +#endif + + if(skb == NULL) + { + if(port->DoingInterrupt) + { + skb = alloc_skb(count, GFP_ATOMIC); + } + else + { + skb = alloc_skb(count, GFP_KERNEL); + } + } + + if(skb == NULL) + { + printk(KERN_ALERT "sab8253xs: no skbuffs available.\n"); + return 0; + } + if(from_user) + { + copy_from_user(skb->data, buf, count); + } + else + { + memcpy(skb->data, buf, count); + } + skb->tail = (skb->data + count); + skb->data_len = count; + skb->len = count; + + if(do_queue) + { + skb_queue_head(port->sab8253xbuflist, skb); + } + + port->active2.transmit->HostVaddr = skb; + port->active2.transmit->sendcrc = 0; + port->active2.transmit->crcindex = 0; + port->active2.transmit->Count = (OWN_SAB|count); + port->active2.transmit = port->active2.transmit->VNext; + + sab8253x_start_txS(port); + return count; +} + +void sab8253x_throttleS(struct tty_struct * tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_throttleS")) + { + return; + } + + if (!tty) + { + return; + } + + if (I_IXOFF(tty)) + { + sab8253x_send_xcharS(tty, STOP_CHAR(tty)); + } +} + +void sab8253x_unthrottleS(struct tty_struct * tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_unthrottle")) + { + return; + } + + if (!tty) + { + return; + } + + if (I_IXOFF(tty)) + { + sab8253x_send_xcharS(tty, START_CHAR(tty)); + } +} + +void sab8253x_send_xcharS(struct tty_struct *tty, char ch) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + unsigned long flags; + int stopped; + int hw_stopped; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_send_xcharS")) + { + return; + } + + if (!tty) + { + return; + } + + if(port->sabnext2.transmit == NULL) + { + return; + } + + save_flags(flags); cli(); + + if((port->sabnext2.transmit->Count & OWNER) == OWN_SAB) /* may overwrite a character + * -- but putting subsequent + * XONs or XOFFs later in the + * stream could cause problems + * with the XON and XOFF protocol */ + { + port->sabnext2.transmit->sendcrc = 1; + port->sabnext2.transmit->crcindex = 3; + port->sabnext2.transmit->crc = (ch << 24); /* LITTLE ENDIAN */ + restore_flags(flags); + } + else + { + restore_flags(flags); + sab8253x_writeS(tty, 0, &ch, 1); + } + + stopped = tty->stopped; + hw_stopped = tty->hw_stopped; + tty->stopped = 0; + tty->hw_stopped = 0; + + sab8253x_start_txS(port); + + tty->stopped = stopped; + tty->hw_stopped = hw_stopped; +} + + +void sab8253x_breakS(struct tty_struct *tty, int break_state) +{ + struct sab_port *port = (struct sab_port *) tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_breakS")) + { + return; + } /* can't break in sync mode */ +} + +void sab8253x_closeS(struct tty_struct *tty, struct file * filp) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + unsigned long flags; + + MOD_DEC_USE_COUNT; + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_closeS")) + { + return; + } + + if(port->open_type == OPEN_SYNC_NET) + { /* port->tty field should already be NULL */ + return; + } + + save_flags(flags); cli(); + --(port->count); + if (tty_hung_up_p(filp)) + { + if(port->count == 0) /* I think the reason for the weirdness + relates to freeing of structures in + the tty driver */ + { + port->open_type = OPEN_NOT; + } + else if(port->count < 0) + { + printk(KERN_ALERT "XX20: port->count went negative.\n"); + port->count = 0; + port->open_type = OPEN_NOT; + } + restore_flags(flags); + return; + } + +#if 0 + if ((tty->count == 1) && (port->count != 0)) + { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. port->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("sab8253x_close: bad serial port count; tty->count is 1," + " port->count is %d\n", port->count); + port->count = 0; + } +#endif + + if (port->count < 0) + { + printk(KERN_ALERT "sab8253x_close: bad serial port count for ttys%d: %d\n", + port->line, port->count); + port->count = 0; + } + if (port->count) + { + restore_flags(flags); + return; + } + port->flags |= FLAG8253X_CLOSING; + + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (port->flags & FLAG8253X_NORMAL_ACTIVE) + { + port->normal_termios = *tty->termios; + } + if (port->flags & FLAG8253X_CALLOUT_ACTIVE) + { + port->callout_termios = *tty->termios; + } + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (port->closing_wait != SAB8253X_CLOSING_WAIT_NONE) + { + tty_wait_until_sent(tty, port->closing_wait); + } + + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and turn off + * the receiver. + */ + +#if 0 + port->interrupt_mask0 |= SAB82532_IMR0_TCD; /* not needed for sync */ +#endif + WRITEB(port,imr0,port->interrupt_mask0); + + CLEAR_REG_BIT(port, mode, SAB82532_MODE_RAC); /* turn off receiver */ + + if (port->flags & FLAG8253X_INITIALIZED) + { + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + sab8253x_wait_until_sent(tty, port->timeout); + } + sab8253x_shutdownS(port); + Sab8253xCleanUpTransceiveN(port); + if (tty->driver.flush_buffer) + { + tty->driver.flush_buffer(tty); + } + if (tty->ldisc.flush_buffer) + { + tty->ldisc.flush_buffer(tty); + } + tty->closing = 0; + port->event = 0; + port->tty = 0; + if (port->blocked_open) + { + if (port->close_delay) + { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(port->close_delay); + } + wake_up_interruptible(&port->open_wait); + } + port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE| + FLAG8253X_CLOSING); + wake_up_interruptible(&port->close_wait); + port->open_type = OPEN_NOT; + restore_flags(flags); +} + + +void sab8253x_hangupS(struct tty_struct *tty) +{ + struct sab_port * port = (struct sab_port *)tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_hangupS")) + { + return; + } + +#ifdef XCONFIG_SERIAL_CONSOLE + if (port->is_console) + { + return; + } +#endif + + sab8253x_flush_buffer(tty); + if(port) + { + sab8253x_shutdownS(port); + Sab8253xCleanUpTransceiveN(port); + port->event = 0; + port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE); + port->tty = 0; + wake_up_interruptible(&port->open_wait); + } +} + +int sab8253x_openS(struct tty_struct *tty, struct file * filp) +{ + struct sab_port *port; + int retval, line; + int counter; + unsigned long flags; + + MOD_INC_USE_COUNT; + line = minor(tty->device) - tty->driver.minor_start; + + for(counter = 0, port = AuraPortRoot; + (counter < line) && (port != NULL); + ++counter) + { + port = port->next; + } + + if (!port) + { + printk(KERN_ALERT "sab8253x_openS: can't find structure for line %d\n", + line); + return -ENODEV; + } + + save_flags(flags); /* Need to protect port->tty element */ + cli(); + + if(port->tty == 0) + { + port->tty = tty; + tty->flip.tqueue.routine = sab8253x_flush_to_ldiscS; + } + tty->driver_data = port; + + if(port->function != FUNCTION_NR) + { + ++(port->count); + restore_flags(flags); + return -ENODEV; /* only allowed if there are no restrictions on the port */ + } + + if(port->open_type == OPEN_SYNC_NET) + { + port->tty = NULL; /* Don't bother with open counting here + but make sure the tty field is NULL*/ + restore_flags(flags); + return -EBUSY; + } + + restore_flags(flags); + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_openS")) + { + ++(port->count); + return -ENODEV; + } + +#ifdef DEBUG_OPEN + printk("sab8253x_open %s%d, count = %d\n", tty->driver.name, port->line, + port->count); +#endif + + /* + * If the port is in the middle of closing, bail out now. + */ + if (tty_hung_up_p(filp) || + (port->flags & FLAG8253X_CLOSING)) + { + + if (port->flags & FLAG8253X_CLOSING) + { + interruptible_sleep_on(&port->close_wait); + } +#ifdef SERIAL_DO_RESTART + ++(port->count); + return ((port->flags & FLAG8253X_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + ++(port->count); + return -EAGAIN; +#endif + } + + if(port->flags & FLAG8253X_NORMAL_ACTIVE) + { + if(port->open_type == OPEN_ASYNC) + { + ++(port->count); + return -EBUSY; /* can't reopen in sync mode */ + } + } + if(port->open_type > OPEN_SYNC) /* can reopen a SYNC_TTY */ + { + return -EBUSY; + } + if(Sab8253xSetUpLists(port)) + { + ++(port->count); + return -ENODEV; + } + if(Sab8253xInitDescriptors2(port, sab8253xs_listsize, sab8253xs_rbufsize)) + { + ++(port->count); + return -ENODEV; + } + + retval = sab8253x_startupS(port); + if (retval) + { + ++(port->count); + return retval; /* does not check channel mode */ + } + + retval = sab8253x_block_til_ready(tty, filp, port); /* checks channel mode */ + ++(port->count); + if (retval) + { + return retval; + } + + port->tty = tty; /* may change here once through the block */ + /* because now the port belongs to an new tty */ + tty->flip.tqueue.routine = sab8253x_flush_to_ldiscS; + if(Sab8253xSetUpLists(port)) + { + return -ENODEV; + } + if(Sab8253xInitDescriptors2(port, sab8253xs_listsize, sab8253xs_rbufsize)) + { + Sab8253xCleanUpTransceiveN(port); /* the network functions should be okay -- only difference */ + /* is the crc32 that is appended */ + return -ENODEV; + } + + /* + * Start up serial port + */ + retval = sab8253x_startupS(port); /* in case cu was running the first time + * the function was called*/ + if (retval) + { + return retval; /* does not check channel mode */ + } + + if ((port->count == 1) && + (port->flags & FLAG8253X_SPLIT_TERMIOS)) + { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + { + *tty->termios = port->normal_termios; + } + else + { + *tty->termios = port->callout_termios; + } + sab8253x_change_speedS(port); + } + + +#ifdef XCONFIG_SERIAL_CONSOLE + if (sab8253x_console.cflag && sab8253x_console.index == line) + { + tty->termios->c_cflag = sab8253x_console.cflag; + sab8253x_console.cflag = 0; + change_speed(port); + } +#endif + + port->session = current->session; + port->pgrp = current->pgrp; + port->open_type = OPEN_SYNC; + return 0; +} + + + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xtty.c linux-2.5/drivers/net/wan/8253x/8253xtty.c --- linux-2.5.20/drivers/net/wan/8253x/8253xtty.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xtty.c Fri May 3 19:50:40 2002 @@ -0,0 +1,2925 @@ +/* -*- linux-c -*- */ +/* $Id: 8253xtty.c,v 1.23 2002/02/10 22:17:25 martillo Exp $ + * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * + * Modified by Francois Wautier 2000 (fw@auroratech.com) + * + * Extended extensively by Joachim Martillo 2001 (Telford002@aol.com) + * to provide synchronous/asynchronous TTY/Callout/character/network device + * capabilities. + * + * Modifications and extensions + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + + +/* Standard in kernel modules */ +#define DEFINE_VARIABLE +#include /* Specifically, a module */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "8253xctl.h" +#include "sp502.h" + +DECLARE_TASK_QUEUE(tq_8253x_serial); /* this just initializes a list head called */ + /* tq_8253x_serial*/ + +struct tty_driver sab8253x_serial_driver, sab8253x_callout_driver, sync_sab8253x_serial_driver; +int sab8253x_refcount; + +/* Trace things on serial device, useful for console debugging: */ +#undef SERIAL_LOG_DEVICE + +#ifdef SERIAL_LOG_DEVICE +static void dprint_init(int tty); +#endif + +static void sab8253x_change_speed(struct sab_port *port); + +static struct tty_struct **sab8253x_tableASY = 0; /* make dynamic */ +static struct tty_struct **sab8253x_tableCUA = 0; /* make dynamic */ +static struct tty_struct **sab8253x_tableSYN = 0; /* make dynamic */ +static struct termios **sab8253x_termios = 0 ; +static struct termios **sab8253x_termios_locked = 0; + +#ifdef MODULE +#undef XCONFIG_SERIAL_CONSOLE /* leaving out CONFIG_SERIAL_CONSOLE for now */ +#endif + +#ifdef XCONFIG_SERIAL_CONSOLE /* not really implemented yet */ +extern int serial_console; +struct console sab8253x_console; +int sab8253x_console_init(void); +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +char sab8253x_serial_version[16]; + +static void sab8253x_flush_to_ldisc(void *private_) +{ + struct tty_struct *tty = (struct tty_struct *) private_; + unsigned char *cp; + char *fp; + int count; + struct sab_port *port; + struct sk_buff *skb; + + if(tty) + { + port = (struct sab_port *)tty->driver_data; /* probably a silly check */ + } + else + { + return; + } + + if(!port) + { + return; + } + + if (test_bit(TTY_DONT_FLIP, &tty->flags)) + { + queue_task(&tty->flip.tqueue, &tq_timer); + return; + } + /* note that a hangup may have occurred -- perhaps should check for that */ + port->DoingInterrupt = 1; + while(port->sab8253xc_rcvbuflist && (skb_queue_len(port->sab8253xc_rcvbuflist) > 0)) + { + skb = skb_dequeue(port->sab8253xc_rcvbuflist); + count = skb->data_len; + cp = skb->data; + fp = skb->data + (count/2); + (*tty->ldisc.receive_buf)(tty, cp, fp, count/2); + dev_kfree_skb_any(skb); + } + port->DoingInterrupt = 0; +} + +/* only used asynchronously */ +static void inline sab8253x_tec_wait(struct sab_port *port) +{ + int count = port->tec_timeout; + + while((READB(port, star) & SAB82532_STAR_TEC) && --count) + { + udelay(1); + } +} + +void sab8253x_start_tx(struct sab_port *port) +{ + unsigned long flags; + register int count; + register int total; + register int offset; + char temporary[32]; + register unsigned int slopspace; + register int sendsize; + unsigned int totaltransmit; + unsigned fifospace; + unsigned loadedcount; + struct tty_struct *tty = port->tty; + + fifospace = port->xmit_fifo_size; + loadedcount = 0; + + if(port->sabnext2.transmit == NULL) + { + return; + } + + save_flags(flags); + cli(); + + + while(count = port->sabnext2.transmit->Count, (count & OWNER) == OWN_SAB) + { + count &= ~OWN_SAB; /* OWN_SAB is really 0 but cannot guarantee in the future */ + + if(port->sabnext2.transmit->HostVaddr) + { + total = (port->sabnext2.transmit->HostVaddr->tail - + port->sabnext2.transmit->HostVaddr->data); /* packet size */ + } + else + { + total = 0; /* the data is only in the crc/trailer */ + } + + if(tty && (tty->stopped || tty->hw_stopped)) + { /* works for frame that only has a trailer (crc) */ + port->interrupt_mask1 |= SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + restore_flags(flags); /* can't send */ + return; + } + + offset = (total - count); /* offset to data still to send */ + + port->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS); + WRITEB(port, imr1, port->interrupt_mask1); + port->all_sent = 0; + + + if(READB(port,star) & SAB82532_STAR_XFW) + { + if(count <= fifospace) + { + port->xmit_cnt = count; + slopspace = 0; + sendsize = 0; + if(port->sabnext2.transmit->sendcrc) + /* obviously should not happen for async but might use for + priority transmission */ + { + slopspace = fifospace - count; + } + if(slopspace) + { + if(count) + { + memcpy(temporary, &port->sabnext2.transmit->HostVaddr->data[offset], + count); + } + sendsize = MIN(slopspace, (4 - port->sabnext2.transmit->crcindex)); + /* how many bytes to send */ + memcpy(&temporary[count], + &((unsigned char*)(&port->sabnext2.transmit->crc)) + [port->sabnext2.transmit->crcindex], + sendsize); + port->sabnext2.transmit->crcindex += sendsize; + if(port->sabnext2.transmit->crcindex >= 4) + { + port->sabnext2.transmit->sendcrc = 0; + } + port->xmit_buf = temporary; + } + else + { + port->xmit_buf = /* set up wrifefifo variables */ + &port->sabnext2.transmit->HostVaddr->data[offset]; + } + port->xmit_cnt += sendsize; + count = 0; + } + else + { + count -= fifospace; + port->xmit_cnt = fifospace; + port->xmit_buf = /* set up wrifefifo variables */ + &port->sabnext2.transmit->HostVaddr->data[offset]; + + } + port->xmit_tail= 0; + loadedcount = port->xmit_cnt; + (*port->writefifo)(port); + totaltransmit = Sab8253xCountTransmitDescriptors(port); + if((sab8253xt_listsize - totaltransmit) > 2) + { + sab8253x_sched_event(port, SAB8253X_EVENT_WRITE_WAKEUP); + } + + if((sab8253xt_listsize - totaltransmit) > (sab8253xt_listsize/2)) + { + port->buffergreedy = 0; + } + else + { + port->buffergreedy = 1; + } + + port->xmit_buf = NULL; /* this var is used to indicate whether to call kfree */ + + fifospace -= loadedcount; + + if ((count <= 0) && (port->sabnext2.transmit->sendcrc == 0)) + { + port->sabnext2.transmit->Count = OWN_DRIVER; +#ifdef FREEININTERRUPT /* treat this routine as if taking place in interrupt */ + if(port->sabnext2.transmit->HostVaddr) + { + skb_unlink(port->sabnext2.transmit->HostVaddr); + dev_kfree_skb_any(port->sabnext2.transmit->HostVaddr); + port->sabnext2.transmit->HostVaddr = 0; /* no skb */ + } + port->sabnext2.transmit->crcindex = 0; /* no single byte */ +#endif + port->sabnext2.transmit = port->sabnext2.transmit->VNext; + if((port->sabnext2.transmit->Count & OWNER) == OWN_SAB) + { + if(fifospace > 0) + { + continue; /* the only place where this code really loops */ + } + if(fifospace < 0) + { + printk(KERN_ALERT "sab8253x: bad math in interrupt handler.\n"); + } + port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); + WRITEB(port, imr1, port->interrupt_mask1); + } + else + { + port->interrupt_mask1 |= SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + } + sab8253x_cec_wait(port); + /* Issue a Transmit Frame command. */ + WRITEB(port, cmdr, SAB82532_CMDR_XF); + /* This could be optimized to load from next skbuff */ + /* SAB82532_CMDR_XF is the same as SAB82532_CMDR_XTF */ + restore_flags(flags); + return; + } + sab8253x_cec_wait(port); + /* Issue a Transmit Frame command. */ + WRITEB(port, cmdr, SAB82532_CMDR_XF); /* same as SAB82532_CMDR_XTF */ + port->sabnext2.transmit->Count = (count|OWN_SAB); + } + port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); + WRITEB(port, imr1, port->interrupt_mask1); + restore_flags(flags); + return; + } + /* The While loop only exits via return*/ + /* we get here by skipping the loop */ + port->interrupt_mask1 |= SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + restore_flags(flags); + return; +} + +/* + * ------------------------------------------------------------ + * sab8253x_stop() and sab8253x_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ + +static void sab8253x_stop(struct tty_struct *tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + unsigned long flags; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_stop")) + { + return; + } + + save_flags(flags); + cli(); /* maybe should turn off ALLS as well + but the stop flags are checked + so ALLS is probably harmless + and I have seen too much evil + associated with that interrupt*/ + port->interrupt_mask1 |= SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + restore_flags(flags); +} + +static void sab8253x_start(struct tty_struct *tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_start")) + { + return; + } + + sab8253x_start_tx(port); +} + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +/* no obvious changes for sync tty */ + +static void sab8253x_receive_chars(struct sab_port *port, + union sab8253x_irq_status *stat) +{ + struct tty_struct *tty = port->tty; + unsigned char buf[32]; + unsigned char reordered[32]; + unsigned char status; + int free_fifo = 0; + int i, count = 0; + struct sk_buff *skb; + + /* Read number of BYTES (Character + Status) available. */ + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RPF) + { + count = port->recv_fifo_size; + free_fifo++; + } + + if (stat->images[ISR0_IDX] & SAB82532_ISR0_TCD) + { + count = READB(port,rbcl) & (port->recv_fifo_size - 1); + free_fifo++; + } + + /* Issue a FIFO read command in case we where idle. */ + if (stat->sreg.isr0 & SAB82532_ISR0_TIME) + { + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_RFRD); + } + + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) + { /* FIFO overflow */ + free_fifo++; + } + + /* Read the FIFO. */ + (*port->readfifo)(port, buf, count); + + /* Issue Receive Message Complete command. */ + if (free_fifo) + { + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_RMC); + } + +#ifdef CONSOLE_SUPPORT + if (port->is_console) + { + wake_up(&keypress_wait); + } +#endif + if (!tty) + { + return; + } + + if(!count) + { + return; + } + + for(i = 0; i < count; i += 2) + { + reordered[i/2] = buf[i]; + status = buf[i+1]; + if (status & SAB82532_RSTAT_PE) + { + status = TTY_PARITY; + port->icount.parity++; + } + else if (status & SAB82532_RSTAT_FE) + { + status = TTY_FRAME; + port->icount.frame++; + } + else + { + status = TTY_NORMAL; + } + reordered[(count+i)/2] = status; + } + + if(port->active2.receive == NULL) + { + return; + } + + memcpy(port->active2.receive->HostVaddr->tail, reordered, count); + port->active2.receive->HostVaddr->tail += count; + port->active2.receive->HostVaddr->data_len = count; + port->active2.receive->HostVaddr->len = count; + if(skb = dev_alloc_skb(port->recv_fifo_size), skb == NULL) /* use dev_alloc_skb because at int + there is header space but so what*/ + { + port->icount.buf_overrun++; + port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; /* clear the buffer */ + port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB); + port->active2.receive->HostVaddr->data_len = 0; + port->active2.receive->HostVaddr->len = 0; + } + else + { + skb_unlink(port->active2.receive->HostVaddr); + skb_queue_tail(port->sab8253xc_rcvbuflist, port->active2.receive->HostVaddr); + skb_queue_head(port->sab8253xbuflist, skb); + port->active2.receive->HostVaddr = skb; + port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB); + } + queue_task(&tty->flip.tqueue, &tq_timer); +} + +static void sab8253x_transmit_chars(struct sab_port *port, + union sab8253x_irq_status *stat) +{ + + if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) /* got an all sent int? */ + { + port->interrupt_mask1 |= SAB82532_IMR1_ALLS; + WRITEB(port, imr1, port->interrupt_mask1); + port->all_sent = 1; /* not much else to do */ + } /* a very weird chip -- this int only indicates this int */ + + sab8253x_start_tx(port); +} + +static void sab8253x_check_status(struct sab_port *port, + union sab8253x_irq_status *stat) +{ + struct tty_struct *tty = port->tty; + int modem_change = 0; + mctlsig_t *sig; + struct sk_buff *skb; + + if (!tty) + { + return; + } + + if(port->active2.receive == NULL) + { + goto check_modem; + } + + if (stat->images[ISR1_IDX] & SAB82532_ISR1_BRK) + { +#ifdef XCONFIG_SERIAL_CONSOLE + if (port->is_console) + { + batten_down_hatches(info); /* need to add this function */ + return; + } +#endif + + port->active2.receive->HostVaddr->tail[0] = 0; + port->active2.receive->HostVaddr->tail[1] = TTY_PARITY; + port->active2.receive->HostVaddr->tail += 2; + port->active2.receive->HostVaddr->data_len = 2; + port->active2.receive->HostVaddr->len = 2; + + if(skb = dev_alloc_skb(port->recv_fifo_size), skb == NULL) + { + port->icount.buf_overrun++; + port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; + /* clear the buffer */ + port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB); + port->active2.receive->HostVaddr->data_len = 0; + port->active2.receive->HostVaddr->len = 0; + } + else + { + skb_unlink(port->active2.receive->HostVaddr); + skb_queue_tail(port->sab8253xc_rcvbuflist, port->active2.receive->HostVaddr); + skb_queue_head(port->sab8253xbuflist, skb); + port->active2.receive->HostVaddr = skb; + port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB); + } + queue_task(&tty->flip.tqueue, &tq_timer); + port->icount.brk++; + } + + if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) + { + port->active2.receive->HostVaddr->tail[0] = 0; + port->active2.receive->HostVaddr->tail[1] = TTY_PARITY; + port->active2.receive->HostVaddr->tail += 2; + port->active2.receive->HostVaddr->data_len = 2; + port->active2.receive->HostVaddr->len = 2; + if(skb = dev_alloc_skb(port->recv_fifo_size), skb == NULL) + { + port->icount.buf_overrun++; + port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; + /* clear the buffer */ + port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB); + port->active2.receive->HostVaddr->data_len = 0; + port->active2.receive->HostVaddr->len = 0; + } + else + { + skb_unlink(port->active2.receive->HostVaddr); + skb_queue_tail(port->sab8253xc_rcvbuflist, port->active2.receive->HostVaddr); + skb_queue_head(port->sab8253xbuflist, skb); + port->active2.receive->HostVaddr = skb; + port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB); + } + queue_task(&tty->flip.tqueue, &tq_timer); + port->icount.overrun++; + } + + check_modem: + /* Checking DCD */ + sig = &port->dcd; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,dcd); + port->icount.dcd++; + modem_change++; + } + /* Checking CTS */ + sig = &port->cts; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,cts); + port->icount.cts++; + modem_change++; + } + /* Checking DSR */ + sig = &port->dsr; + if (stat->images[sig->irq] & sig->irqmask) + { + sig->val = ISON(port,dsr); + port->icount.dsr++; + modem_change++; + } + if (modem_change) + { + wake_up_interruptible(&port->delta_msr_wait); /* incase kernel proc level was waiting on modem change */ + } + + sig = &port->dcd; + if ((port->flags & FLAG8253X_CHECK_CD) && + (stat->images[sig->irq] & sig->irqmask)) + { + + if (sig->val) + { + wake_up_interruptible(&port->open_wait); /* in case waiting in block_til_ready */ + } + else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) && + (port->flags & FLAG8253X_CALLOUT_NOHUP))) + { + + MOD_INC_USE_COUNT; /* in case a close is already in progress + don't want structures to vanish during + late processing of hangup */ + if (schedule_task(&port->tqueue_hangup) == 0) + { + MOD_DEC_USE_COUNT; /* task schedule failed */ + } + } + } + + sig = &port->cts; + if (port->flags & FLAG8253X_CTS_FLOW) + { + if (port->tty->hw_stopped) + { + if (sig->val) + { + + port->tty->hw_stopped = 0; + sab8253x_sched_event(port, SAB8253X_EVENT_WRITE_WAKEUP); + sab8253x_start_tx(port); + } + } + else + { + if (!(sig->val)) + { + port->tty->hw_stopped = 1; + } + } + } +} + + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * sab8253x_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using sab8253x_sched_event(), and they get done here. + */ + /* The following routine is installed */ + /* in the bottom half -- just search */ + /* for the init_bh() call */ + /* The logic: sab8253x_sched_event() */ + /* enqueues the tqueue port entry on */ + /* the tq_8253x_serial task list -- */ + /* whenever the bottom half is run */ + /* sab8253x_do_softint is invoked for */ + /* every port that has invoked the bottom */ + /* half via sab8253x_sched_event(). */ + /* currently only a write wakeevent */ + /* wakeup is scheduled -- to tell the */ + /* tty driver to send more chars */ + /* down to the serial driver.*/ + +static void sab8253x_do_serial_bh(void) +{ + run_task_queue(&tq_8253x_serial); +} + + /* I believe the reason for the */ + /* bottom half processing below is */ + /* the length of time needed to transfer */ + /* characters to the TTY driver. */ + +static void sab8253x_do_softint(void *private_) +{ + struct sab_port *port = (struct sab_port *)private_; + struct tty_struct *tty; + + tty = port->tty; + if (!tty) + { + return; + } + + port->DoingInterrupt = 1; + if (test_and_clear_bit(SAB8253X_EVENT_WRITE_WAKEUP, &port->event)) + { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); /* in case tty driver waiting on write */ + } + port->DoingInterrupt = 0; +} + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> sab8253x_hangup() + * + */ +/* This logic takes place at kernel */ +/* process context through the scheduler*/ +/* schedule_task(tqueue_hangup) */ +/* takes place in the interrupt handler*/ +static void sab8253x_do_serial_hangup(void *private_) +{ + struct sab_port *port = (struct sab_port *) private_; + struct tty_struct *tty; + + tty = port->tty; + if (tty) + { + tty_hangup(tty); + } + MOD_DEC_USE_COUNT; /* in case busy waiting to unload module */ +} + +static void +sab8253x_init_line(struct sab_port *port) +{ + unsigned char stat; + + if(port->chip->c_cim) + { + if(port->chip->c_cim->ci_type == CIM_SP502) + { + aura_sp502_program(port, SP502_OFF_MODE); + } + } + + /* + * Wait for any commands or immediate characters + */ + sab8253x_cec_wait(port); + sab8253x_tec_wait(port); + + /* + * Clear the FIFO buffers. + */ + + WRITEB(port, cmdr, SAB82532_CMDR_RRES); + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_XRES); + + + /* + * Clear the interrupt registers. + */ + stat = READB(port, isr0); + stat = READB(port, isr1); + + /* + * Now, initialize the UART + */ + WRITEB(port, ccr0, 0); /* power-down */ + WRITEB(port, ccr0, + SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | SAB82532_CCR0_SM_ASYNC); + WRITEB(port, ccr1, + SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7); + WRITEB(port, ccr2, + SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL | SAB82532_CCR2_TOE); + WRITEB(port, ccr3, 0); + WRITEB(port, ccr4, + SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG); + WRITEB(port, mode, + SAB82532_MODE_RTS | SAB82532_MODE_FCTS | SAB82532_MODE_RAC); + WRITEB(port, rfc, + SAB82532_RFC_DPS | SAB82532_RFC_RFDF); + switch (port->recv_fifo_size) + { + case 1: + SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_1); + break; + case 4: + SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_4); + break; + case 16: + SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_16); + break; + default: + port->recv_fifo_size = 32; + case 32: + SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_32); + break; + } + /* power-up */ + SET_REG_BIT(port, ccr0, SAB82532_CCR0_PU); + if(port->chip->c_cim) + { + if(port->chip->c_cim->ci_type == CIM_SP502) + { + aura_sp502_program(port, port->sigmode); + } + } +} + + +static int sab8253x_startup(struct sab_port *port) +{ + unsigned long flags; + + int retval = 0; + + save_flags(flags); cli(); + + if (port->flags & FLAG8253X_INITIALIZED) + { + goto errout; + } + + port->msgbufindex = 0; + port->xmit_buf = NULL; + port->buffergreedy = 0; + + if (!port->regs) + { + if (port->tty) + { + set_bit(TTY_IO_ERROR, &port->tty->flags); + } + retval = -ENODEV; + goto errout; + } + + /* + * Initialize the Hardware + */ + sab8253x_init_line(port); + + if (port->tty->termios->c_cflag & CBAUD) + { + /* Activate RTS */ + RAISE(port,rts); + + /* Activate DTR */ + RAISE(port,dtr); + } + + /* + * Initialize the modem signals values + */ + port->dcd.val=ISON(port,dcd); + port->cts.val=ISON(port,cts); + port->dsr.val=ISON(port,dsr); + + /* + * Finally, enable interrupts + */ + + port->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + SAB82532_IMR0_PLLA; + WRITEB(port, imr0, port->interrupt_mask0); + port->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_XOFF | + SAB82532_IMR1_TIN | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + port->all_sent = 1; + + if (port->tty) + { + clear_bit(TTY_IO_ERROR, &port->tty->flags); + } + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + + /* + * and set the speed of the serial port + */ + sab8253x_change_speed(port); + + port->flags |= FLAG8253X_INITIALIZED; + port->receive_chars = sab8253x_receive_chars; + port->transmit_chars = sab8253x_transmit_chars; + port->check_status = sab8253x_check_status; + port->receive_test = (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | + SAB82532_ISR0_RFO | SAB82532_ISR0_RPF); + port->transmit_test = (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR); + port->check_status_test = SAB82532_ISR1_BRK; + + restore_flags(flags); + return 0; + + errout: + restore_flags(flags); + return retval; +} + + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void sab8253x_shutdown(struct sab_port *port) +{ + unsigned long flags; + + if (!(port->flags & FLAG8253X_INITIALIZED)) + { + return; + } + + save_flags(flags); + cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&port->delta_msr_wait); /* shutting down port modem status is pointless */ + + if (port->xmit_buf) + { + port->xmit_buf = NULL; + } + +#ifdef XCONFIG_SERIAL_CONSOLE + if (port->is_console) + { + port->interrupt_mask0 = + SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + /*SAB82532_IMR0_TIME |*/ + SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; + WRITEB(port,imr0,port->interrupt_mask0); + port->interrupt_mask1 = + SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + WRITEB(port,imr1,port->interrupt_mask1); + if (port->tty) + { + set_bit(TTY_IO_ERROR, &port->tty->flags); + } + port->flags &= ~FLAG8253X_INITIALIZED; + restore_flags(flags); + return; + } +#endif + + /* Disable Interrupts */ + + port->interrupt_mask0 = 0xff; + WRITEB(port, imr0, port->interrupt_mask0); + port->interrupt_mask1 = 0xff; + WRITEB(port, imr1, port->interrupt_mask1); + + if (!port->tty || (port->tty->termios->c_cflag & HUPCL)) + { + LOWER(port,rts); + LOWER(port,dtr); + } + + /* Disable break condition */ + CLEAR_REG_BIT(port,dafo,SAB82532_DAFO_XBRK); + + /* Disable Receiver */ + CLEAR_REG_BIT(port,mode,SAB82532_MODE_RAC); + + /* Power Down */ + CLEAR_REG_BIT(port,ccr0,SAB82532_CCR0_PU); + + if (port->tty) + { + set_bit(TTY_IO_ERROR, &port->tty->flags); + } + + port->flags &= ~FLAG8253X_INITIALIZED; + restore_flags(flags); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void sab8253x_change_speed(struct sab_port *port) +{ + unsigned long flags,baud; + tcflag_t cflag; + u8 dafo,ccr2=0,ccr4=0,ebrg=0,mode; + int i, bits; +#ifdef DEBUGGING + printk("Change speed! "); +#endif + if (!port->tty || !port->tty->termios) + { +#ifdef DEBUGGING + printk("NOT!\n"); +#endif + return; + } + +#ifdef DEBUGGING + printk(" for real.\n"); +#endif + + cflag = port->tty->termios->c_cflag; + + /* Byte size and parity */ + switch (cflag & CSIZE) + { + case CS5: + dafo = SAB82532_DAFO_CHL5; + bits = 7; + break; + case CS6: + dafo = SAB82532_DAFO_CHL6; + bits = 8; + break; + case CS7: + dafo = SAB82532_DAFO_CHL7; + bits = 9; + break; + default: + case CS8: + dafo = SAB82532_DAFO_CHL8; + bits = 10; + break; + } + + if (cflag & CSTOPB) + { + dafo |= SAB82532_DAFO_STOP; + bits++; + } + + if (cflag & PARENB) + { + dafo |= SAB82532_DAFO_PARE; + bits++; + } + + if (cflag & PARODD) + { +#ifdef CMSPAR + if (cflag & CMSPAR) + dafo |= SAB82532_DAFO_PAR_MARK; + else +#endif + dafo |= SAB82532_DAFO_PAR_ODD; + } + else + { +#ifdef CMSPAR + if (cflag & CMSPAR) + dafo |= SAB82532_DAFO_PAR_SPACE; + else +#endif + dafo |= SAB82532_DAFO_PAR_EVEN; + } + + /* Determine EBRG values based on the "encoded"baud rate */ + i = cflag & CBAUD; + switch(i) + { + case B0: + baud=0; + break; + case B50: + baud=100; + break; + case B75: + baud=150; + break; + case B110: + baud=220; + break; + case B134: + baud=269; + break; + case B150: + baud=300; + break; + case B200: + baud=400; + break; + case B300: + baud=600; + break; + case B600: + baud=1200; + break; + case B1200: + baud=2400; + break; + case B1800: + baud=3600; + break; + case B2400: + baud=4800; + break; + case B4800: + baud=9600; + break; + case B9600: + baud=19200; + break; + case B19200: + baud=38400; + break; + case B38400: + if(port->custspeed) + { + baud=port->custspeed<<1; + } + else + { + baud=76800; + } + break; + case B57600: + baud=115200; + break; +#ifdef SKIPTHIS + case B76800: + baud=153600; + break; + case B153600: + baud=307200; + break; +#endif + case B230400: + baud=460800; + break; + case B460800: + baud=921600; + break; + case B115200: + default: + baud=230400; + break; + } + + if(!sab8253x_baud(port,baud,&ebrg,&ccr2,&ccr4,&(port->baud))) + { + printk("Aurora Warning. baudrate %ld could not be set! Using 115200",baud); + baud=230400; + sab8253x_baud(port,baud,&ebrg,&ccr2,&ccr4,&(port->baud)); + } + + if (port->baud) + port->timeout = (port->xmit_fifo_size * HZ * bits) / port->baud; + else + port->timeout = 0; + port->timeout += HZ / 50; /* Add .02 seconds of slop */ + + /* CTS flow control flags */ + if (cflag & CRTSCTS) + port->flags |= FLAG8253X_CTS_FLOW; + else + port->flags &= ~(FLAG8253X_CTS_FLOW); + + if (cflag & CLOCAL) + port->flags &= ~(FLAG8253X_CHECK_CD); + else + port->flags |= FLAG8253X_CHECK_CD; + if (port->tty) + port->tty->hw_stopped = 0; + + /* + * Set up parity check flag + * XXX: not implemented, yet. + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + /* + * Characters to ignore + * XXX: not implemented, yet. + */ + + /* + * !!! ignore all characters if CREAD is not set + * XXX: not implemented, yet. + */ + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= SAB82532_ISR0_RPF | + /* SAB82532_ISR0_TIME |*/ + SAB82532_ISR0_TCD ; + + save_flags(flags); + cli(); + sab8253x_cec_wait(port); + sab8253x_tec_wait(port); + WRITEB(port,dafo,dafo); + WRITEB(port,bgr,ebrg); + ccr2 |= READB(port,ccr2) & ~(0xc0); + WRITEB(port,ccr2,ccr2); + ccr4 |= READB(port,ccr4) & ~(SAB82532_CCR4_EBRG); + WRITEB(port,ccr4,ccr4); + + if (port->flags & FLAG8253X_CTS_FLOW) + { + mode = READB(port,mode) & ~(SAB82532_MODE_RTS); + mode |= SAB82532_MODE_FRTS; + mode &= ~(SAB82532_MODE_FCTS); + } + else + { + mode = READB(port,mode) & ~(SAB82532_MODE_FRTS); + mode |= SAB82532_MODE_RTS; + mode |= SAB82532_MODE_FCTS; + } + WRITEB(port,mode,mode); + mode |= SAB82532_MODE_RAC; + WRITEB(port,mode,mode); + restore_flags(flags); +} + +static void sab8253x_flush_chars(struct tty_struct *tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_flush_chars")) + { + return; + } + + if ((Sab8253xCountTransmit(port) <= 0) || tty->stopped || tty->hw_stopped) + { + return; + } + + sab8253x_start_tx(port); +} + +static int sab8253x_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + struct sk_buff *skb = NULL; + int truelength = 0; + int do_queue = 1; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_write")) + { + return 0; + } + + if(count == 0) + { + return 0; + } + + if(port->active2.transmit == NULL) + { + return 0; + } + + if((port->active2.transmit->Count & OWNER) == OWN_SAB) + { + sab8253x_start_tx(port); + return 0; + } + +#ifndef FREEININTERRUPT + skb = port->active2.transmit->HostVaddr; /* current slot value */ + + if(port->buffergreedy == 0) /* are we avoiding buffer free's */ + { /* no */ + if((skb != NULL) || /* not OWN_SAB from above */ + (port->active2.transmit->crcindex != 0)) + { + register RING_DESCRIPTOR *freeme; + + freeme = port->active2.transmit; + do + { + if((freeme->crcindex == 0) && (freeme->HostVaddr == NULL)) + { + break; + } + if(freeme->HostVaddr) + { + skb_unlink((struct sk_buff*)freeme->HostVaddr); + dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr); + freeme->HostVaddr = NULL; + } + freeme->sendcrc = 0; + freeme->crcindex = 0; + freeme = (RING_DESCRIPTOR*) freeme->VNext; + } + while((freeme->Count & OWNER) != OWN_SAB); + } + skb = NULL; /* buffer was freed */ + } + + if(skb != NULL) /* potentially useful */ + { + truelength = (skb->end - skb->head); + if(truelength >= count) + { + skb->data = skb->head; /* this buffer is already queued */ + skb->tail = skb->head; + do_queue = 0; + } + else + { + skb_unlink(skb); + dev_kfree_skb_any(skb); + skb = NULL; + port->active2.transmit->HostVaddr = NULL; + } + } + /* in all cases the following is allowed */ + port->active2.transmit->sendcrc = 0; + port->active2.transmit->crcindex = 0; +#endif + + if(skb == NULL) + { + if(port->DoingInterrupt) + { + skb = alloc_skb(count, GFP_ATOMIC); + } + else + { + skb = alloc_skb(count, GFP_KERNEL); + } + } + + if(skb == NULL) + { + printk(KERN_ALERT "sab8253xt: no skbuffs available.\n"); + return 0; + } + if(from_user) + { + copy_from_user(skb->data, buf, count); + } + else + { + memcpy(skb->data, buf, count); + } + skb->tail = (skb->data + count); + skb->data_len = count; + skb->len = count; + + if(do_queue) + { + skb_queue_head(port->sab8253xbuflist, skb); + } + + port->active2.transmit->HostVaddr = skb; + port->active2.transmit->sendcrc = 0; + port->active2.transmit->crcindex = 0; + port->active2.transmit->Count = (OWN_SAB|count); + port->active2.transmit = port->active2.transmit->VNext; + + sab8253x_start_tx(port); + return count; +} + +static int sab8253x_write_room(struct tty_struct *tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if(sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_write_room")) + { + return 0; + } + + if(port->active2.transmit == NULL) + { + return 0; + } + + if((port->active2.transmit->Count & OWNER) == OWN_SAB) + { + return 0; + } + return ((sab8253xt_rbufsize) * /* really should not send buffs bigger than 32 I guess */ + (sab8253xt_listsize - + Sab8253xCountTransmitDescriptors(port))); +} + +static int sab8253x_chars_in_buffer(struct tty_struct *tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_chars_in_bufferS")) + { + return 0; + } + + return Sab8253xCountTransmit(port); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void sab8253x_send_xchar(struct tty_struct *tty, char ch) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + unsigned long flags; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_send_xchar")) + { + return; + } + + save_flags(flags); + cli(); + sab8253x_tec_wait(port); + WRITEB(port, tic, ch); + restore_flags(flags); +} + +/* + * ------------------------------------------------------------ + * sab8253x_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void sab8253x_throttle(struct tty_struct * tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_throttle")) + { + return; + } + + if (I_IXOFF(tty)) + { + sab8253x_send_xchar(tty, STOP_CHAR(tty)); + } +} + +static void sab8253x_unthrottle(struct tty_struct * tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_unthrottle")) + { + return; + } + + if (I_IXOFF(tty)) + { + if (port->x_char) + { + port->x_char = 0; + } + else + { + sab8253x_send_xchar(tty, START_CHAR(tty)); + } + } +} + +/* + * ------------------------------------------------------------ + * sab8253x_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int sab8253x_get_serial_info(struct sab_port *port, + struct serial_struct *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + { + return -EFAULT; + } + memset(&tmp, 0, sizeof(tmp)); + tmp.type = port->type; + tmp.line = port->line; + tmp.port = (unsigned long)port->regs; + tmp.irq = port->irq; + tmp.flags = port->flags; + tmp.xmit_fifo_size = port->xmit_fifo_size; + tmp.baud_base = 0; + tmp.close_delay = port->close_delay; + tmp.closing_wait = port->closing_wait; + tmp.custom_divisor = port->custom_divisor; + tmp.hub6 = 0; + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + { + return -EFAULT; + } + return 0; +} + +static int sab8253x_set_serial_info(struct sab_port *port, + struct serial_struct *new_info) +{ + return 0; +} + + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int sab8253x_get_lsr_info(struct sab_port * port, unsigned int *value) +{ + unsigned int result; + + result = (((Sab8253xCountTransmit(port) <= 0) && port->all_sent) ? TIOCSER_TEMT : 0); + return put_user(result, value); +} + + +static int sab8253x_get_modem_info(struct sab_port * port, unsigned int *value) +{ + unsigned int result; + + /* Using the cached values !! After all when changed int occurs + and the cache is updated */ + result= + ((port->dtr.val) ? TIOCM_DTR : 0) + | ((port->rts.val) ? TIOCM_RTS : 0) + | ((port->cts.val) ? TIOCM_CTS : 0) + | ((port->dsr.val) ? TIOCM_DSR : 0) + | ((port->dcd.val) ? TIOCM_CAR : 0); + + return put_user(result,value); +} + +static int sab8253x_set_modem_info(struct sab_port * port, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + unsigned long flags; + + error = get_user(arg, value); + if (error) + { + return error; + } + + save_flags(flags); + cli(); + switch (cmd) + { + case TIOCMBIS: + if (arg & TIOCM_RTS) + { + RAISE(port, rts); + } + if (arg & TIOCM_DTR) + { + RAISE(port, dtr); + } + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + { + LOWER(port,rts); + } + if (arg & TIOCM_DTR) + { + LOWER(port,dtr); + } + break; + case TIOCMSET: + if (arg & TIOCM_RTS) + { + RAISE(port, rts); + } + else + { + LOWER(port,rts); + } + if (arg & TIOCM_DTR) + { + RAISE(port, dtr); + } + else + { + LOWER(port,dtr); + } + break; + default: + restore_flags(flags); + return -EINVAL; + } + restore_flags(flags); + return 0; +} + +/* + * This routine sends a break character out the serial port. + */ +static void sab8253x_break(struct tty_struct *tty, int break_state) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + unsigned long flags; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_break")) + { + return; + } + + if (!port->regs) + { + return; + } + + save_flags(flags); + cli(); + if (break_state == -1) + { + SET_REG_BIT(port,dafo,SAB82532_DAFO_XBRK); + } + else + { + CLEAR_REG_BIT(port,dafo,SAB82532_DAFO_XBRK); + } + restore_flags(flags); +} + +static int sab8253x_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + unsigned int wordindex; + unsigned short *wordptr; + struct sab_port *port = (struct sab_port *)tty->driver_data; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + SAB_BOARD *bptr; + unsigned long flags; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_ioctl")) + { + return -ENODEV; + } + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) + { + if (tty->flags & (1 << TTY_IO_ERROR)) + { + return -EIO; + } + } + + switch (cmd) + { + case ATIS_IOCSPARAMS: + copy_from_user(&port->ccontrol, (struct channelcontrol*)arg , sizeof(struct channelcontrol)); + break; + case ATIS_IOCGPARAMS: + copy_to_user((struct channelcontrol*) arg, &port->ccontrol, sizeof(struct channelcontrol)); + break; + + case ATIS_IOCSSPEED: + copy_from_user(&port->custspeed, (unsigned long*)arg , sizeof(unsigned long)); + break; + case ATIS_IOCGSPEED: + copy_to_user((unsigned long*) arg, &port->custspeed, sizeof(unsigned long)); + break; + + case ATIS_IOCSSEP9050: + bptr = port->board; + if(bptr->b_type == BD_WANMCS) + { + return -EINVAL; + } + copy_from_user((unsigned char*) bptr->b_eprom, (unsigned char*) arg , sizeof(struct sep9050)); + + wordptr = (unsigned short*) bptr->b_eprom; + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WENCMD, NM93_WENADDR, 0); + for(wordindex = 0; wordindex < EPROM9050_SIZE; ++wordindex) + { + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WRITECMD, + wordindex, wordptr[wordindex]); + } + plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + NM93_WDSCMD, NM93_WDSADDR, 0); + break; + case ATIS_IOCGSEP9050: + bptr = port->board; + if(bptr->b_type == BD_WANMCS) + { + return -EINVAL; + } + if (!plx9050_eprom_read(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, + (unsigned short*) bptr->b_eprom, + (unsigned char) 0, EPROM9050_SIZE)) + { + printk(KERN_ALERT "auraXX20n: Could not read serial eprom.\n"); + return -EIO; + } + copy_to_user((unsigned char*) arg, (unsigned char*) bptr->b_eprom, sizeof(struct sep9050)); + break; + + case TIOCGSOFTCAR: + return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); + + case TIOCSSOFTCAR: + error = get_user(arg, (unsigned int *) arg); + if (error) + { + return error; + } + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCMGET: + return sab8253x_get_modem_info(port, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return sab8253x_set_modem_info(port, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return sab8253x_get_serial_info(port, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return sab8253x_set_serial_info(port, + (struct serial_struct *) arg); + + case TIOCSERGETLSR: /* Get line status register */ + return sab8253x_get_lsr_info(port, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + if (copy_to_user((struct sab_port *) arg, + port, sizeof(struct sab_port))) + return -EFAULT; + return 0; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + save_flags(flags); + cli(); + /* note the counters on entry */ + cprev = port->icount; + restore_flags(flags); + while (1) + { + interruptible_sleep_on(&port->delta_msr_wait); /* waits for a modem signal change */ + /* see if a signal did it */ + if (signal_pending(current)) + { + return -ERESTARTSYS; + } + save_flags(flags); + cli(); + cnow = port->icount; /* atomic copy */ + restore_flags(flags); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + { + return -EIO; /* no change => error */ + } + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + { + return 0; + } + } + cprev = cnow; + } + /* NOTREACHED */ + break; + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + save_flags(flags); + cli(); + cnow = port->icount; + restore_flags(flags); + p_cuser = (struct serial_icounter_struct *) arg; + error = put_user(cnow.cts, &p_cuser->cts); + if (error) + { + return error; + } + error = put_user(cnow.dsr, &p_cuser->dsr); + if (error) + { + return error; + } + error = put_user(cnow.rng, &p_cuser->rng); + if (error) + { + return error; + } + error = put_user(cnow.dcd, &p_cuser->dcd); + if (error) + { + return error; + } + return 0; + + case ATIS_IOCSSIGMODE: + if(port->chip->c_cim) + { + if(port->chip->c_cim->ci_type == CIM_SP502) + { + copy_from_user(&port->sigmode, (unsigned int*)arg , sizeof(unsigned int)); + return 0; + } + } + return -EINVAL; + + case ATIS_IOCGSIGMODE: + if(port->chip->c_cim) + { + if(port->chip->c_cim->ci_type == CIM_SP502) + { + copy_to_user((unsigned int*) arg, &port->sigmode, sizeof(unsigned int)); + return 0; + } + } + return -EINVAL; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void sab8253x_set_termios(struct tty_struct *tty, + struct termios *old_termios) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if((tty->termios->c_cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) + { + return; + } + if(!port) + { + return; + } + sab8253x_change_speed(port); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(tty->termios->c_cflag & CBAUD)) + { + LOWER(port,rts); + LOWER(port,dtr); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (tty->termios->c_cflag & CBAUD)) + { + RAISE(port, dtr); + if (!tty->hw_stopped || + !(tty->termios->c_cflag & CRTSCTS)) + { + RAISE(port, rts); + } + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) + { + tty->hw_stopped = 0; + sab8253x_start(tty); + } +} + +/* + * ------------------------------------------------------------ + * sab8253x_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void sab8253x_close(struct tty_struct *tty, struct file * filp) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + unsigned long flags; + + MOD_DEC_USE_COUNT; + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_close")) + { + return; + } + if(port->open_type == OPEN_SYNC_NET) + { /* port->tty field should already be NULL */ + /* port count was not incremented */ + return; + } + + --(port->count); /* have a valid port */ + if (tty_hung_up_p(filp)) + { + + if(port->count == 0) /* shutdown took place in hangup context */ + { + port->open_type = OPEN_NOT; + } + else if(port->count < 0) + { + printk(KERN_ALERT "XX20: port->count went negative.\n"); + port->count = 0; + port->open_type = OPEN_NOT; + } + return; + } + + if (port->count < 0) + { + printk(KERN_ALERT "sab8253x_close: bad serial port count for ttys%d: %d\n", + port->line, port->count); + port->count = 0; + } + + if (port->count) + { + return; + } + + port->flags |= FLAG8253X_CLOSING; + + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (port->flags & FLAG8253X_NORMAL_ACTIVE) + { + port->normal_termios = *tty->termios; + } + if (port->flags & FLAG8253X_CALLOUT_ACTIVE) + { + port->callout_termios = *tty->termios; + } + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (port->closing_wait != SAB8253X_CLOSING_WAIT_NONE) + { + tty_wait_until_sent(tty, port->closing_wait); /* wait for drain */ + } + + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and turn off + * the receiver. + */ + + save_flags(flags); + cli(); + port->interrupt_mask0 |= SAB82532_IMR0_TCD; + WRITEB(port,imr0,port->interrupt_mask0); + + CLEAR_REG_BIT(port,mode,SAB82532_MODE_RAC); /* ??????? */ + restore_flags(flags); + + if (port->flags & FLAG8253X_INITIALIZED) + { + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + sab8253x_wait_until_sent(tty, port->timeout); + } + sab8253x_shutdown(port); /* no more ints on port */ + Sab8253xCleanUpTransceiveN(port); /* should be okay */ + if (tty->driver.flush_buffer) + { + tty->driver.flush_buffer(tty); + } + if (tty->ldisc.flush_buffer) + { + tty->ldisc.flush_buffer(tty); + } + tty->closing = 0; + port->event = 0; + port->tty = 0; + if (port->blocked_open) + { + if (port->close_delay) + { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(port->close_delay); + } + wake_up_interruptible(&port->open_wait); /* deal with open blocks */ + } + + if((port->flags & (FLAG8253X_CALLOUT_ACTIVE | FLAG8253X_NETWORK)) == + (FLAG8253X_CALLOUT_ACTIVE | FLAG8253X_NETWORK) && + port->dev) + { + port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE| + FLAG8253X_CLOSING); /* leave network set */ + netif_carrier_off(port->dev); + port->open_type = OPEN_SYNC_NET; + sab8253x_startupN(port); + } + else + { + port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE| + FLAG8253X_CLOSING); + wake_up_interruptible(&port->close_wait); + port->open_type = OPEN_NOT; + } +} + +/* + * sab8253x_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void sab8253x_hangup(struct tty_struct *tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_hangup")) + { + return; + } + +#ifdef XCONFIG_SERIAL_CONSOLE + if (port->is_console) + { + return; + } +#endif + + sab8253x_flush_buffer(tty); + if(port) + { + sab8253x_shutdown(port); + Sab8253xCleanUpTransceiveN(port); /* this logic is a bit contorted + Are we cleaning up the lists + because we are waking up a + blocked open? There is possibly + an order problem here perhaps the + open count should have increased in the + int handler so that it could decrease here*/ + port->event = 0; + port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE); + port->tty = 0; + wake_up_interruptible(&port->open_wait); /* deal with blocking open */ + } +} +/* + * ------------------------------------------------------------ + * sab8253x_open() and friends + * ------------------------------------------------------------ + */ + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ + +static int sab8253x_open(struct tty_struct *tty, struct file * filp) +{ + struct sab_port *port; + int retval, line; + int counter; + unsigned long flags; + + MOD_INC_USE_COUNT; + line = minor(tty->device) - tty->driver.minor_start; + + for(counter = 0, port = AuraPortRoot; + (counter < line) && (port != NULL); + ++counter) + { + port = port->next; + } + + if (!port) + { + printk(KERN_ALERT "sab8253x_open: can't find structure for line %d\n", + line); + return -ENODEV; + } + + save_flags(flags); /* Need to protect the port->tty field */ + cli(); + + if(port->tty == NULL) + { + port->tty = tty; /* may be a standard tty waiting on a call out device */ + tty->flip.tqueue.routine = sab8253x_flush_to_ldisc; + } + + tty->driver_data = port; /* but the tty devices are unique for each type of open */ + + if(port->function == FUNCTION_NA) + { /* port 2 on 1020s and 1520s */ + ++(port->count); + restore_flags(flags); + return -ENODEV; + } + + /* Check whether or not the port is open in SYNC mode */ + if(port->open_type == OPEN_SYNC_NET) + { + if(port->dev && netif_carrier_ok(port->dev)); + { + port->tty= NULL; /* Don't bother with open counting here + but make sure the tty field is NULL*/ + restore_flags(flags); + return -EBUSY; + } + sab8253x_flush_buffer(tty); /* don't restore flags here */ + sab8253x_shutdownN(port); + } + else if (port->open_type > OPEN_ASYNC) /* can't have a callout or async line + * if already open in some sync mode */ + { + ++(port->count); + restore_flags(flags); + return -EBUSY; + } + restore_flags(flags); + + if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_open")) + { + ++(port->count); + return -ENODEV; + } + +#ifdef DEBUG_OPEN + printk("sab8253x_open %s%d, count = %d\n", tty->driver.name, port->line, + port->count); +#endif + + /* + * If the port is in the middle of closing, bail out now. + */ + if (tty_hung_up_p(filp) || + (port->flags & FLAG8253X_CLOSING)) + { + + if (port->flags & FLAG8253X_CLOSING) + { + interruptible_sleep_on(&port->close_wait); + } +#ifdef SERIAL_DO_RESTART + ++(port->count); + return ((port->flags & FLAG8253X_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + ++(port->count); + return -EAGAIN; +#endif + } + + if(Sab8253xSetUpLists(port)) + { + ++(port->count); + return -ENODEV; + } + if(Sab8253xInitDescriptors2(port, sab8253xt_listsize, sab8253xt_rbufsize)) + { + ++(port->count); + return -ENODEV; + } + + retval = sab8253x_startup(port); + if (retval) + { + ++(port->count); + return retval; + } + + retval = sab8253x_block_til_ready(tty, filp, port); + ++(port->count); + if (retval) + { + return retval; + } + + port->tty = tty; /* may change here once through the block */ + /* because now the port belongs to an new tty */ + tty->flip.tqueue.routine = sab8253x_flush_to_ldisc; /* in case it was changed */ + + if(Sab8253xSetUpLists(port)) + { + return -ENODEV; + } + if(Sab8253xInitDescriptors2(port, sab8253xt_listsize, sab8253xt_rbufsize)) + { + Sab8253xCleanUpTransceiveN(port); /* the network functions should be okay -- only difference */ + /* is the crc32 that is appended */ + return -ENODEV; + } + + /* + * Start up serial port + */ + retval = sab8253x_startup(port); /* just in case closing the cu dev + * shutdown the port (but left CD) */ + if (retval) + { + return retval; + } + + if ((port->count == 1) && /* first open */ + (port->flags & FLAG8253X_SPLIT_TERMIOS)) + { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + { + *tty->termios = port->normal_termios; + } + else + { + *tty->termios = port->callout_termios; + } + sab8253x_change_speed(port); + } + + +#ifdef XCONFIG_SERIAL_CONSOLE + if (sab8253x_console.cflag && sab8253x_console.index == line) + { + tty->termios->c_cflag = sab8253x_console.cflag; + sab8253x_console.cflag = 0; + sab8253x_change_speed(port); + } +#endif + + port->session = current->session; + port->pgrp = current->pgrp; + port->open_type = OPEN_ASYNC; + return 0; +} + +static char *signaling[] = +{ + "OFF ", + "RS232", + "RS422", + "RS485", + "RS449", + "RS530", + "V.35 " +}; + +static int sab8253x_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + extern struct sab_port * AuraPortRoot; + struct sab_port *port = AuraPortRoot; + extern char *board_type[]; + off_t begin = 0; + int len = 0; + int portno; + unsigned int typeno; + extern int sab8253x_rebootflag; + +#ifdef FREEININTERRUPT + len += sprintf(page, "serinfo:2.01I driver:%s\n", sab8253x_serial_version); +#else + len += sprintf(page, "serinfo:2.01N driver:%s\n", sab8253x_serial_version); +#endif + if(sab8253x_rebootflag) + { + len += sprintf(page+len, + "WARNING: Found %d cards that required reprogramming. Reboot machine!.\n", + sab8253x_rebootflag); + } + len += sprintf(page+len, "TTY MAJOR = %d, CUA MAJOR = %d, STTY MAJOR = %d.\n", + sab8253x_serial_driver.major, sab8253x_callout_driver.major, + sync_sab8253x_serial_driver.major); + for (portno = 0; port != NULL; port = port->next, ++portno) + { + typeno = port->board->b_type; + if(typeno > BD_8520P) + { + typeno = 0; + } + len += sprintf(page+len, + "%d: port %d: %s: v%d: chip %d: ATI %s: bus %d: slot %d: %s: ", + sab8253x_serial_driver.minor_start + portno, + port->portno, + (port->chip->chip_type == ESCC2) ? "sab82532" : "sab82538", + port->type, + port->chip->c_chipno, + board_type[port->board->b_type], + port->board->b_dev.bus->number, + PCI_SLOT(port->board->b_dev.devfn), + aura_functionality[((port->function > FUNCTION_UN) ? FUNCTION_UN : port->function)]); + switch(port->open_type) + { + case OPEN_ASYNC: + len += sprintf(page+len, "openA"); + break; + case OPEN_SYNC: + len += sprintf(page+len, "openS"); + break; + case OPEN_SYNC_NET: + len += sprintf(page+len, "openN"); + break; + case OPEN_SYNC_CHAR: + len += sprintf(page+len, "openC"); + break; + case OPEN_NOT: + len += sprintf(page+len, "close"); + break; + default: + len += sprintf(page+len, "open?"); + break; + } + if(port->chip->c_cim) + { + if(port->chip->c_cim->ci_type == CIM_SP502) + { + len += sprintf(page+len, ": %s\n", signaling[port->sigmode]); + } + else + { + len += sprintf(page+len, ": NOPRG\n"); + } + } + else + { + len += sprintf(page+len, ": NOPRG\n"); + } + + if (len+begin > off+count) + { + goto done; + } + if (len+begin < off) + { + begin += len; + len = 0; + } + } + *eof = 1; + done: + if (off >= len+begin) + { + return 0; + } + *start = page + (off-begin); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * sab8253x_init() and friends + * + * sab8253x_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +static void inline show_aurora_version(void) +{ + char *revision = "$Revision: 1.23 $"; + char *version, *p; + + version = strchr(revision, ' '); + strcpy(sab8253x_serial_version, ++version); + p = strchr(sab8253x_serial_version, ' '); + *p = '\0'; + printk("Aurora serial driver version %s\n", sab8253x_serial_version); +} + +#ifndef MODULE +static int GetMinorStart(void) +{ + struct tty_driver *ttydriver; + int minor_start = 0; + kdev_t device; + + device = mk_kdev(TTY_MAJOR, minor_start); + while(ttydriver = get_tty_driver(device), ttydriver != NULL) + { + minor_start += ttydriver->num; + device = mk_kdev(TTY_MAJOR, minor_start); + } + return minor_start; + +} +#endif + +int finish_sab8253x_setup_ttydriver(void) +{ + extern unsigned int NumSab8253xPorts; + + sab8253x_tableASY = (struct tty_struct **) kmalloc(NumSab8253xPorts*sizeof(struct tty_struct *), GFP_KERNEL); + if(sab8253x_tableASY == NULL) + { + printk(KERN_ALERT "auraXX20: Could not allocate memory for sab8253x_tableASY.\n"); + return -1; + } + memset(sab8253x_tableASY, 0, NumSab8253xPorts*sizeof(struct tty_struct *)); + sab8253x_tableCUA = (struct tty_struct **) kmalloc(NumSab8253xPorts*sizeof(struct tty_struct *), GFP_KERNEL); + if(sab8253x_tableCUA == NULL) + { + printk(KERN_ALERT "auraXX20: Could not allocate memory for sab8253x_tableCUA.\n"); + return -1; + } + memset(sab8253x_tableCUA, 0, NumSab8253xPorts*sizeof(struct tty_struct *)); + sab8253x_tableSYN = (struct tty_struct **) kmalloc(NumSab8253xPorts*sizeof(struct tty_struct *), GFP_KERNEL); + if(sab8253x_tableSYN == NULL) + { + printk(KERN_ALERT "auraXX20: Could not allocate memory for sab8253x_tableSYN.\n"); + return -1; + } + memset(sab8253x_tableSYN, 0, NumSab8253xPorts*sizeof(struct tty_struct *)); + + sab8253x_termios = (struct termios **) kmalloc(NumSab8253xPorts*sizeof(struct termios *), GFP_KERNEL); + if(sab8253x_termios == NULL) + { + printk(KERN_ALERT "auraXX20: Could not allocate memory for sab8253x_termios.\n"); + return -1; + } + memset(sab8253x_termios, 0, NumSab8253xPorts*sizeof(struct termios *)); + sab8253x_termios_locked = (struct termios **) kmalloc(NumSab8253xPorts*sizeof(struct termios *), GFP_KERNEL); + if(sab8253x_termios_locked == NULL) + { + printk(KERN_ALERT "auraXX20: Could not allocate memory for sab8253x_termios_locked.\n"); + return -1; + } + memset(sab8253x_termios_locked, 0, NumSab8253xPorts*sizeof(struct termios *)); + sync_sab8253x_serial_driver.num = sab8253x_callout_driver.num = sab8253x_serial_driver.num = NumSab8253xPorts; + sab8253x_serial_driver.table = sab8253x_tableASY; + sab8253x_callout_driver.table = sab8253x_tableCUA; + sync_sab8253x_serial_driver.table = sab8253x_tableSYN; + sync_sab8253x_serial_driver.termios = sab8253x_callout_driver.termios = sab8253x_serial_driver.termios = + sab8253x_termios; + sync_sab8253x_serial_driver.termios_locked = sab8253x_callout_driver.termios_locked = + sab8253x_serial_driver.termios_locked = sab8253x_termios_locked; + + if (tty_register_driver(&sab8253x_serial_driver) < 0) + { + printk(KERN_ALERT "auraXX20: Could not register serial driver.\n"); + return -1; + } + if (tty_register_driver(&sab8253x_callout_driver) < 0) + { + printk(KERN_ALERT "auraXX20: Could not register call out device.\n"); + return -1; + } + if (tty_register_driver(&sync_sab8253x_serial_driver) < 0) + { + printk(KERN_ALERT "auraXX20: Could not register sync serial device.\n"); + return -1; + } + return 0; + +} + +void sab8253x_setup_ttydriver(void) +{ +#ifdef MODULE + extern int xx20_minorstart; +#endif + init_bh(AURORA_BH, sab8253x_do_serial_bh); + + show_aurora_version(); + + /* Initialize the tty_driver structure */ + + memset(&sab8253x_serial_driver, 0, sizeof(struct tty_driver)); + sab8253x_serial_driver.magic = TTY_DRIVER_MAGIC; + sab8253x_serial_driver.driver_name = "auraserial"; + sab8253x_serial_driver.name = "ttyS"; + sab8253x_serial_driver.major = TTY_MAJOR; +#ifdef MODULE + sab8253x_serial_driver.minor_start = xx20_minorstart; +#else + sab8253x_serial_driver.minor_start = GetMinorStart(); +#endif + sab8253x_serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + sab8253x_serial_driver.subtype = SERIAL_TYPE_NORMAL; + sab8253x_serial_driver.init_termios = tty_std_termios; + sab8253x_serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + sab8253x_serial_driver.flags = TTY_DRIVER_REAL_RAW; + sab8253x_serial_driver.refcount = &sab8253x_refcount; + + sab8253x_serial_driver.open = sab8253x_open; + sab8253x_serial_driver.close = sab8253x_close; + sab8253x_serial_driver.write = sab8253x_write; + sab8253x_serial_driver.put_char = NULL; /*sab8253x_put_char is evil.*/ + sab8253x_serial_driver.flush_chars = sab8253x_flush_chars; + sab8253x_serial_driver.write_room = sab8253x_write_room; + sab8253x_serial_driver.chars_in_buffer = sab8253x_chars_in_buffer; + sab8253x_serial_driver.flush_buffer = sab8253x_flush_buffer; + sab8253x_serial_driver.ioctl = sab8253x_ioctl; + sab8253x_serial_driver.throttle = sab8253x_throttle; + sab8253x_serial_driver.unthrottle = sab8253x_unthrottle; + sab8253x_serial_driver.send_xchar = sab8253x_send_xchar; + sab8253x_serial_driver.set_termios = sab8253x_set_termios; + sab8253x_serial_driver.stop = sab8253x_stop; + sab8253x_serial_driver.start = sab8253x_start; + sab8253x_serial_driver.hangup = sab8253x_hangup; + sab8253x_serial_driver.break_ctl = sab8253x_break; + sab8253x_serial_driver.wait_until_sent = sab8253x_wait_until_sent; + sab8253x_serial_driver.read_proc = sab8253x_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + sab8253x_callout_driver = sab8253x_serial_driver; + sab8253x_callout_driver.name = "cua"; + sab8253x_callout_driver.major = TTYAUX_MAJOR; + sab8253x_callout_driver.subtype = SERIAL_TYPE_CALLOUT; + sab8253x_callout_driver.read_proc = 0; + sab8253x_callout_driver.proc_entry = 0; + + sync_sab8253x_serial_driver = sab8253x_serial_driver; + sync_sab8253x_serial_driver.name = "sttyS"; + sync_sab8253x_serial_driver.major = 0; + sync_sab8253x_serial_driver.subtype = SERIAL_TYPE_SYNCTTY; + + sync_sab8253x_serial_driver.open = sab8253x_openS; + sync_sab8253x_serial_driver.close = sab8253x_closeS; + sync_sab8253x_serial_driver.write = sab8253x_writeS; + sync_sab8253x_serial_driver.put_char = NULL; /*sab8253x_put_char logic is evil*/ + sync_sab8253x_serial_driver.flush_chars = sab8253x_flush_charsS; + sync_sab8253x_serial_driver.write_room = sab8253x_write_room; + sync_sab8253x_serial_driver.chars_in_buffer = sab8253x_chars_in_buffer; + sync_sab8253x_serial_driver.flush_buffer = sab8253x_flush_buffer; + sync_sab8253x_serial_driver.ioctl = sab8253x_ioctl; + sync_sab8253x_serial_driver.throttle = sab8253x_throttleS; + sync_sab8253x_serial_driver.unthrottle = sab8253x_unthrottleS; + sync_sab8253x_serial_driver.send_xchar = sab8253x_send_xcharS; + sync_sab8253x_serial_driver.set_termios = sab8253x_set_termiosS; + sync_sab8253x_serial_driver.stop = sab8253x_stopS; + sync_sab8253x_serial_driver.start = sab8253x_startS; + sync_sab8253x_serial_driver.hangup = sab8253x_hangupS; + sync_sab8253x_serial_driver.break_ctl = sab8253x_breakS; + sync_sab8253x_serial_driver.wait_until_sent = sab8253x_wait_until_sent; + sync_sab8253x_serial_driver.read_proc = 0; + sync_sab8253x_serial_driver.proc_entry = 0; +} + +void sab8253x_setup_ttyport(struct sab_port *p_port) +{ + p_port->magic = SAB_MAGIC; + p_port->custom_divisor = 16; + p_port->close_delay = 5*HZ/10; + p_port->closing_wait = 30*HZ; + p_port->tec_timeout = SAB8253X_MAX_TEC_DELAY; + p_port->cec_timeout = SAB8253X_MAX_CEC_DELAY; + p_port->x_char = 0; + p_port->event = 0; + p_port->flags= FLAG8253X_BOOT_AUTOCONF | FLAG8253X_SKIP_TEST; + p_port->blocked_open = 0; + + p_port->all_sent = 1; /* probably not needed */ + + p_port->tqueue.sync = 0; /* for later */ + p_port->tqueue.routine = sab8253x_do_softint; + p_port->tqueue.data = p_port; + p_port->tqueue_hangup.sync = 0; /* for later */ + p_port->tqueue_hangup.routine = sab8253x_do_serial_hangup; + p_port->tqueue_hangup.data = p_port; + p_port->callout_termios = sab8253x_callout_driver.init_termios; + p_port->normal_termios = sab8253x_serial_driver.init_termios; /* these are being shared */ + /* between asynchronous and */ + /* asynchronous ttys */ + init_waitqueue_head(&p_port->open_wait); + init_waitqueue_head(&p_port->close_wait); + init_waitqueue_head(&p_port->delta_msr_wait); + init_waitqueue_head(&p_port->write_wait); + init_waitqueue_head(&p_port->read_wait); + + p_port->count = 0; /* maybe not needed */ + p_port->icount.cts = p_port->icount.dsr = + p_port->icount.rng = p_port->icount.dcd = 0; + p_port->cts.val = p_port->dsr.val = + p_port->dcd.val = 0; + p_port->icount.rx = p_port->icount.tx = 0; + p_port->icount.frame = p_port->icount.parity = 0; + p_port->icount.overrun = p_port->icount.brk = 0; + + p_port->xmit_fifo_size = 32; + p_port->recv_fifo_size = 32; + p_port->xmit_buf = NULL; + p_port->receive_chars = sab8253x_receive_chars; + p_port->transmit_chars = sab8253x_transmit_chars; + p_port->check_status = sab8253x_check_status; + p_port->receive_test = (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | + SAB82532_ISR0_RFO | SAB82532_ISR0_RPF); + p_port->transmit_test = (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR); + p_port->check_status_test = SAB82532_ISR1_BRK; + + /* put in default sync control channel values + * not needed for async -- I think these work + * for bisync*/ + p_port->ccontrol.ccr0 = DEFAULT_CCR0; + p_port->ccontrol.ccr1 = DEFAULT_CCR1; + p_port->ccontrol.ccr2 = DEFAULT_CCR2; + p_port->ccontrol.ccr3 = DEFAULT_CCR3; + p_port->ccontrol.ccr4 = DEFAULT_CCR4; + p_port->ccontrol.mode = DEFAULT_MODE; + p_port->ccontrol.rlcr = DEFAULT_RLCR; +} + +void sab8253x_cleanup_ttydriver(void) +{ + unsigned long flags; + int e1, e2; + + save_flags(flags); + cli(); + + if(sab8253x_tableASY) + kfree(sab8253x_tableASY); + if(sab8253x_tableCUA) + kfree(sab8253x_tableCUA); + if(sab8253x_tableSYN) + kfree(sab8253x_tableSYN); + if(sab8253x_termios) + kfree(sab8253x_termios); + if(sab8253x_termios_locked) + kfree(sab8253x_termios_locked); + + remove_bh(AURORA_BH); + if ((e1 = tty_unregister_driver(&sab8253x_serial_driver))) + { + printk("SERIAL: failed to unregister serial driver (%d)\n", + e1); + } + if ((e2 = tty_unregister_driver(&sab8253x_callout_driver))) + { + printk("SERIAL: failed to unregister callout driver (%d)\n", + e2); + } + if ((e2 = tty_unregister_driver(&sync_sab8253x_serial_driver))) + { + printk("SERIAL: failed to unregister callout driver (%d)\n", + e2); + } + restore_flags(flags); +} + +/* THE CODE BELOW HAS NOT YET BEEN MODIFIED!!!! FW */ +#ifdef XCONFIG_SERIAL_CONSOLE + +static inline void +sab8253x_console_putchar(struct sab8253x *info, char c) +{ + unsigned long flags; + + save_flags(flags); cli(); + sab8253x_tec_wait(info); + WRITEB(port,tic,c); + restore_flags(flags); +} + +static void +sab8253x_console_write(struct console *con, const char *s, unsigned n) +{ + struct sab8253x *info; + int i; + + info = sab8253x_chain; + for (i = con->index; i; i--) { + info = info->next; + if (!info) + return; + } + + for (i = 0; i < n; i++) { + if (*s == '\n') + sab8253x_console_putchar(info, '\r'); + sab8253x_console_putchar(info, *s++); + } + sab8253x_tec_wait(info); +} + +static int +sab8253x_console_wait_key(struct console *con) +{ + sleep_on(&keypress_wait); + return 0; +} + +static kdev_t +sab8253x_console_device(struct console *con) +{ + return mk_kdev(TTY_MAJOR, 64 + con->index); +} + +static int +sab8253x_console_setup(struct console *con, char *options) +{ + struct sab8253x *info; + unsigned int ebrg; + tcflag_t cflag; + unsigned char dafo; + int i, bits; + unsigned long flags; + + info = sab8253x_chain; + for (i = con->index; i; i--) + { + info = info->next; + if (!info) + return -ENODEV; + } + info->is_console = 1; + + /* + * Initialize the hardware + */ + sab8253x_init_line(info); + + /* + * Finally, enable interrupts + */ + info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + /*SAB82532_IMR0_TIME*/ | SAB82532_IMR0_PLLA/*| SAB82532_IMR0_CDSC*/; + WRITEB(port,imr0,info->interrupt_mask0); + info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + WRITEB(port,imr1,info->interrupt_mask1); + + printk("Console: ttyS%d (SAB82532)\n", info->line); + + sunserial_console_termios(con); + cflag = con->cflag; + + /* Byte size and parity */ + switch (cflag & CSIZE) + { + case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; + case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; + case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + } + + if (cflag & CSTOPB) + { + dafo |= SAB82532_DAFO_STOP; + bits++; + } + + if (cflag & PARENB) + { + dafo |= SAB82532_DAFO_PARE; + bits++; + } + + if (cflag & PARODD) + { +#ifdef CMSPAR + if (cflag & CMSPAR) + dafo |= SAB82532_DAFO_PAR_MARK; + else +#endif + dafo |= SAB82532_DAFO_PAR_ODD; + } + else + { +#ifdef CMSPAR + if (cflag & CMSPAR) + dafo |= SAB82532_DAFO_PAR_SPACE; + else +#endif + dafo |= SAB82532_DAFO_PAR_EVEN; + } + + /* Determine EBRG values based on baud rate */ + i = cflag & CBAUD; + if (i & CBAUDEX) + { + i &= ~(CBAUDEX); + if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES)) + cflag &= ~CBAUDEX; + else + i += 15; + } + ebrg = ebrg_tabl[i].n; + ebrg |= (ebrg_table[i].m << 6); + + info->baud = ebrg_table[i].baud; + if (info->baud) + info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud; + else + info->timeout = 0; + info->timeout += HZ / 50; /* Add .02 seconds of slop */ + + /* CTS flow control flags */ + if (cflag & CRTSCTS) + info->flags |= FLAG8253X_CTS_FLOW; + else + info->flags &= ~(FLAG8253X_CTS_FLOW); + + if (cflag & CLOCAL) + info->flags &= ~(FLAG8253X_CHECK_CD); + else + info->flags |= FLAG8253X_CHECK_CD; + + save_flags(flags); cli(); + sab8253x_cec_wait(info); + sab8253x_tec_wait(info); + WRITEB(port,dafo,dafo); + WRITEB(port,bgr,ebrg & 0xff); + info->regs->rw.ccr2 &= ~(0xc0); + info->regs->rw.ccr2 |= (ebrg >> 2) & 0xc0; + if (info->flags & FLAG8253X_CTS_FLOW) + { + info->regs->rw.mode &= ~(SAB82532_MODE_RTS); + info->regs->rw.mode |= SAB82532_MODE_FRTS; + info->regs->rw.mode &= ~(SAB82532_MODE_FCTS); + } + else + { + info->regs->rw.mode |= SAB82532_MODE_RTS; + info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); + info->regs->rw.mode |= SAB82532_MODE_FCTS; + } + info->regs->rw.pvr &= ~(info->pvr_dtr_bit); + info->regs->rw.mode |= SAB82532_MODE_RAC; + restore_flags(flags); + + return 0; +} + +static struct console sab8253x_console = +{ + "ttyS", + sab8253x_console_write, + NULL, + sab8253x_console_device, + sab8253x_console_wait_key, + NULL, + sab8253x_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +int sab8253x_console_init(void) +{ + extern int con_is_present(void); + extern int su_console_registered; + + if (con_is_present() || su_console_registered) + return 0; + + if (!sab8253x_chain) + { + prom_printf("sab8253x_console_setup: can't get SAB8253X chain"); + prom_halt(); + } + + sab8253x_console.index = serial_console - 1; + register_console(&sab8253x_console); + return 0; +} + +#ifdef SERIAL_LOG_DEVICE + +static int serial_log_device = 0; + +static void +dprint_init(int tty) +{ + serial_console = tty + 1; + sab8253x_console.index = tty; + sab8253x_console_setup(&sab8253x_console, ""); + serial_console = 0; + serial_log_device = tty + 1; +} + +int +dprintf(const char *fmt, ...) +{ + static char buffer[4096]; + va_list args; + int i; + + if (!serial_log_device) + return 0; + + va_start(args, fmt); + i = vsprintf(buffer, fmt, args); + va_end(args); + sab8253x_console.write(&sab8253x_console, buffer, i); + return i; +} + +#endif /* SERIAL_LOG_DEVICE */ +#endif /* XCONFIG_SERIAL_CONSOLE */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/8253xutl.c linux-2.5/drivers/net/wan/8253x/8253xutl.c --- linux-2.5.20/drivers/net/wan/8253x/8253xutl.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/8253xutl.c Fri May 3 19:41:50 2002 @@ -0,0 +1,1427 @@ +/* -*- linux-c -*- */ +/* $Id: 8253xutl.c,v 1.3 2002/02/10 22:17:26 martillo Exp $ + * 8253xutl.c: SYNC TTY Driver for the SIEMENS SAB8253X DUSCC. + * + * Implementation, modifications and extensions + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* Standard in kernel modules */ +#define DEFINE_VARIABLE +#include /* Specifically, a module */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "8253xctl.h" +#include "8253x.h" +#include +#include +#include "sp502.h" + +#ifdef MODULE +#undef XCONFIG_SERIAL_CONSOLE +#endif + +void sab8253x_start_txS(struct sab_port *port) +{ + unsigned long flags; + register int count; + register int total; + register int offset; + char temporary[32]; + register unsigned int slopspace; + register int sendsize; + unsigned int totaltransmit; + unsigned fifospace; + unsigned loadedcount; + struct tty_struct *tty = port->tty; /* a little gross tty flags whether + invoked from a tty or the network */ + + fifospace = port->xmit_fifo_size; /* This code can handle fragmented frames + although currently none are generated*/ + loadedcount = 0; + + if(port->sabnext2.transmit == NULL) + { + return; + } + + save_flags(flags); + cli(); + + + if(count = port->sabnext2.transmit->Count, (count & OWNER) == OWN_SAB) + { + count &= ~OWN_SAB; /* OWN_SAB is really 0 but cannot guarantee in the future */ + + if(port->sabnext2.transmit->HostVaddr) + { + total = (port->sabnext2.transmit->HostVaddr->tail - + port->sabnext2.transmit->HostVaddr->data); /* packet size */ + } + else + { + total = 0; /* the data is only the crc/trailer */ + } + + if(tty && (tty->stopped || tty->hw_stopped) && (count == total)) + { /* works for frame that only has a trailer (crc) */ + port->interrupt_mask1 |= SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + restore_flags(flags); /* can't send */ + return; + } + + offset = (total - count); /* offset to data still to send */ + + port->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS); + WRITEB(port, imr1, port->interrupt_mask1); + port->all_sent = 0; + + if(READB(port,star) & SAB82532_STAR_XFW) + { + if(count <= fifospace) + { + port->xmit_cnt = count; + slopspace = 0; + sendsize = 0; + if(port->sabnext2.transmit->sendcrc) + /* obviously should not happen for async but might use for + priority transmission */ + { + slopspace = fifospace - count; + } + if(slopspace) + { + if(count) + { + memcpy(temporary, &port->sabnext2.transmit->HostVaddr->data[offset], + count); + } + sendsize = MIN(slopspace, (4 - port->sabnext2.transmit->crcindex)); + /* how many bytes to send */ + memcpy(&temporary[count], + &((unsigned char*)(&port->sabnext2.transmit->crc)) + [port->sabnext2.transmit->crcindex], + sendsize); + port->sabnext2.transmit->crcindex += sendsize; + if(port->sabnext2.transmit->crcindex >= 4) + { + port->sabnext2.transmit->sendcrc = 0; + } + port->xmit_buf = temporary; + } + else + { + port->xmit_buf = /* set up wrifefifo variables */ + &port->sabnext2.transmit->HostVaddr->data[offset]; + } + port->xmit_cnt += sendsize; + count = 0; + } + else + { + count -= fifospace; + port->xmit_cnt = fifospace; + port->xmit_buf = /* set up wrifefifo variables */ + &port->sabnext2.transmit->HostVaddr->data[offset]; + + } + port->xmit_tail= 0; + loadedcount = port->xmit_cnt; + (*port->writefifo)(port); + totaltransmit = Sab8253xCountTransmitDescriptors(port); + if(tty && (totaltransmit < (sab8253xs_listsize/2))) /* only makes sense on a TTY */ + { + sab8253x_sched_event(port, SAB8253X_EVENT_WRITE_WAKEUP); + } + + if((sab8253xt_listsize - totaltransmit) > (sab8253xt_listsize/2)) + { + port->buffergreedy = 0; + } + else + { + port->buffergreedy = 1; + } + + port->xmit_buf = NULL; /* this var is used to indicate whether to call kfree */ + + /* fifospace -= loadedcount;*/ + /* Here to make mods to handle arbitrarily fragmented frames look to 8253xtty.c for help */ + + if ((count <= 0) && (port->sabnext2.transmit->sendcrc == 0)) + { + port->sabnext2.transmit->Count = OWN_DRIVER; + if(!tty) + { /* called by network driver */ + ++(port->Counters.transmitpacket); + } +#ifdef FREEININTERRUPT /* treat this routine as if taking place in interrupt */ + if(port->sabnext2.transmit->HostVaddr) + { + skb_unlink(port->sabnext2.transmit->HostVaddr); + dev_kfree_skb_any(port->sabnext2.transmit->HostVaddr); + port->sabnext2.transmit->HostVaddr = 0; /* no skb */ + } + port->sabnext2.transmit->crcindex = 0; /* no single byte */ +#endif + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_XME|SAB82532_CMDR_XTF); /* Terminate the frame */ + + port->sabnext2.transmit = port->sabnext2.transmit->VNext; + + if(!tty && port->tx_full) /* invoked from the network driver */ + { + port->tx_full = 0; /* there is a free slot */ + switch(port->open_type) + { + case OPEN_SYNC_NET: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + port->dev->start = 1; + port->dev->tbusy = 0; /* maybe need mark_bh here */ +#else + netif_start_queue(port->dev); +#endif + break; + + case OPEN_SYNC_CHAR: + wake_up_interruptible(&port->write_wait); + break; + + default: + break; + } + } + + if((port->sabnext2.transmit->Count & OWNER) == OWN_SAB) + { /* new frame to send */ + port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); + WRITEB(port, imr1, port->interrupt_mask1); + } + else + { + port->interrupt_mask1 |= SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + if((port->open_type == OPEN_SYNC_CHAR) && port->async_queue) + { /* if indication of transmission is needed by the */ + /* application on a per-frame basis kill_fasync */ + /* can provide it */ + kill_fasync(&port->async_queue, SIGIO, POLL_OUT); + } + } + restore_flags(flags); + return; + } + /* Issue a Transmit FIFO command. */ + sab8253x_cec_wait(port); + WRITEB(port, cmdr, SAB82532_CMDR_XTF); + port->sabnext2.transmit->Count = (count|OWN_SAB); + } + port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); /* more to send */ + WRITEB(port, imr1, port->interrupt_mask1); + } + else + { /* nothing to send */ + port->interrupt_mask1 |= SAB82532_IMR1_XPR; + WRITEB(port, imr1, port->interrupt_mask1); + } + restore_flags(flags); + return; +} + +void sab8253x_transmit_charsS(struct sab_port *port, + union sab8253x_irq_status *stat) +{ + if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) + { + port->interrupt_mask1 |= SAB82532_IMR1_ALLS; + WRITEB(port, imr1, port->interrupt_mask1); + port->all_sent = 1; + } + sab8253x_start_txS(port); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ + +/*************************************************************************** + * sab_baudenh: Function to compute the "enhanced" baudrate. + * + * + * Parameters : + * encbaud 2* the baudrate. We use the + * double value so as to support 134.5 (in only) + * clkspeed The board clock speed in Hz. + * bgr Value of reg BGR for baudrate(output) + * ccr2 Value of reg // CCR2 for baudrate (output) + * ccr4 Value of reg CCR4 for baudrate (output) + * truebaud The actual baudrate achieved (output). + * + * + * Return value : Return FALSE the parameters could not be computed, + * + * Prerequisite : The various ports must have been initialized + * + * Remark : Stolen from the Aurora ase driver. + * + * Author : fw + * + * Revision : Oct 9 2000, creation + ***************************************************************************/ +/* + * Macro to check to see if the high n bits of the given unsigned long + * are zero. + */ +#define HIZERO(x, n) ( ((unsigned long) ((x) << (n)) >> (n)) == (x)) +/* form an n-bit bitmask */ +#define NBM(n) (~(((~(unsigned long) 0) >> (n)) << (n))) +/* shift x by y bits to right, rounded */ +#define ROUND_SHIFT(x, y) (((unsigned long) (x) + (NBM(y - 1) + 1)) >> (y)) +/* perform rounded division */ +#define ROUND_DIV(x, y) (((x) + ((y) >> 1)) / (y)) +#define ABSDIF(x, y) ((x) > (y) ? ((x) - (y)) : ((y) - (x))) +static unsigned int +sab8253x_baudenh(unsigned long encbaud, unsigned long clk_speed, + unsigned char *bgr, unsigned char *ccr2, + unsigned long *truebaudp) +{ + register unsigned short tmp; + register unsigned char ccr2tmp; + unsigned long power2, mant; + unsigned int fastclock; + + if (encbaud == 0) { + return FALSE; + } + + /* + * Keep dividing quotien by two until it is between the value of 1 and 64, + * inclusive. + */ + + fastclock = (clk_speed >= 10000000); /* >= 10 MHz */ + + for (power2 = 0; power2 < 16; power2++) + { + /* divisor = baud * 2^M * 16 */ + if (!HIZERO(encbaud, power2 + 3)) + { + if (!HIZERO(encbaud, power2)) + { /* baud rate still too big? */ + mant = ROUND_DIV(ROUND_SHIFT(clk_speed, power2 + 3), encbaud); + + /* mant = (clk_speed / (8 * 2^M)) / (baud * 2) */ + /* = clk_speed / (baud * 16 * 2^M) */ + } + else + { + mant = ROUND_DIV(ROUND_SHIFT(clk_speed, 3), encbaud << power2); + /* mant = (clk_speed / 8) / (baud * 2 * 2^M) */ + /* = clk_speed / (baud * 16 * 2^M) */ + } + } + else + { + mant = ROUND_DIV(clk_speed, encbaud << (power2 + 3)); + /* mant = clk_speed / (baud * 2 * 8 * 2^M) */ + /* = clk_speed / (baud * 16 * 2^M) */ + } + + /* mant = clk_speed / (baud * 2^M * 16) */ + + if (mant < 2 + || (mant <= 64 && (!fastclock || power2 != 0))) + { + break; + } + } + + /* + * Did we not succeed? (Baud rate is too small) + */ + if (mant > 64) + { + return FALSE; + } + + /* + * Now, calculate the true baud rate. + */ + + if (mant < 1 || (mant == 1 && power2 == 0)) + { + /* bgr and ccr2 should be initialized to 0 */ + *truebaudp = ROUND_SHIFT(clk_speed, 4); + } + else + { + *truebaudp = ROUND_DIV(clk_speed, mant << (4 + power2)); + /* divisor is not zero because mant is [1, 64] */ + mant--; /* now [0, 63] */ + + /* + * Encode the N and M values into the bgr and ccr2 registers. + */ + + tmp = ((unsigned short) mant) | ((unsigned short) power2 << 6); + + ccr2tmp = SAB82532_CCR2_BDF; + if ((tmp & 0x200) != 0) + { + ccr2tmp |= SAB82532_CCR2_BR9; + } + if ((tmp & 0x100) != 0) + { + ccr2tmp |= SAB82532_CCR2_BR8; + } + + *ccr2 = ccr2tmp | (*ccr2 & ~(SAB82532_CCR2_BDF|SAB82532_CCR2_BR8|SAB82532_CCR2_BR9)); + *bgr = (unsigned char) tmp; + } + + return TRUE; +} + +/* + * Calculate the standard mode baud divisor using an integral algorithm. + */ +/*************************************************************************** + * sab_baudstd: Function to compute the "standard " baudrate. + * + * + * Parameters : + * encbaud 2* the baudrate. We use the + * double value so as to support 134.5 (in only) + * clkspeed The board clock speed in Hz. + * bgr Value of reg BGR for baudrate(output) + * ccr2 Value of reg CCR2 for baudrate (output) + * ccr4 Value of reg CCR4 for baudrate (output) + * truebaud The actual baudrate achieved (output). + * + * + * Return value : Return FALSE the parameters could not be computed, + * + * Prerequisite : The various ports must have been initialized + * + * Remark : Stolen from the Aurora ase driver. + * + * Author : fw + * + * Revision : Oct 9 2000, creation + ***************************************************************************/ +static unsigned int +sab8253x_baudstd(unsigned long encbaud, unsigned long clk_speed, + unsigned char *bgr, unsigned char *ccr2, + unsigned long *truebaudp) +{ + register unsigned short quot; + register unsigned char ccr2tmp; + + if (encbaud == 0) + { + return FALSE; + } + + /* + * This divisor algorithm is a little strange. The + * divisors are all multiples of 2, except for the + * magic value of 1. + * + * What we do is do most of the algorithm for multiples + * of 1, and then switch at the last minute to multiples + * of 2. + */ + + /* + * Will we lose any information by left shifting encbaud? + * If so, then right shift clk_speed instead. + */ + if (!HIZERO(encbaud, 3)) + { + quot = (unsigned short) ROUND_DIV(ROUND_SHIFT(clk_speed, 3), + encbaud); + /* quot = (clk_speed / 8) / (baud * 2) = clk_speed / (16 * baud) */ + } + else + { + /* encbaud isn't a multiple of 2^29 (baud not mult. of 2^28) */ + quot = (unsigned short) ROUND_DIV(clk_speed, encbaud << 3); + } + + /* quot = clk_speed / (baud * 16) */ + if (quot < 2) + { + /* bgr and ccr2 should be initialized to 0 */ + *truebaudp = ROUND_SHIFT(clk_speed, 4); + return TRUE; + } + + /* + * Divide the quotient by two. + */ + quot = ROUND_SHIFT(quot, 1); + + if (quot <= 0x400) + { + /* quot = [1, 0x400] -> (quot << 5) != 0 */ + *truebaudp = ROUND_DIV(clk_speed, ((unsigned long) quot << 5)); + quot--; + + ccr2tmp = SAB82532_CCR2_BDF; + if ((quot & 0x200) != 0) + { + ccr2tmp |= SAB82532_CCR2_BR9; + } + if ((quot & 0x100) != 0) + { + ccr2tmp |=SAB82532_CCR2_BR8; + } + + *ccr2 = ccr2tmp | (*ccr2 & ~(SAB82532_CCR2_BDF|SAB82532_CCR2_BR8|SAB82532_CCR2_BR9)); + *bgr = (unsigned char) quot; + } + else + { /* the baud rate is too small. */ + return FALSE; + } + + return TRUE; +} + +/*************************************************************************** + * sab_baud: Function to compute the best register value to achieve + * a given baudrate. + * + * + * Parameters : + * port: The port being used (in only) + * encbaud: 2* the baudrate. We use the + * double value so as to support 134.5 (in only) + * bgr Value of reg BGR for baudrate(output) + * ccr2 Value of reg CCR2 for baudrate (output) + * ccr4 Value of reg CCR4 for baudrate (output) + * truebaud The actual baudrate achieved (output). + * + * + * Return value : Return TRUE if the vaudrate can be set, FALSE otherwise + * + * Prerequisite : The various ports must have been initialized + * + * Remark : Stolen from the Aurora ase driver. + * + * Author : fw + * + * Revision : Oct 9 2000, creation + ***************************************************************************/ +unsigned int +sab8253x_baud(sab_port_t *port, unsigned long encbaud, + unsigned char *bgr, unsigned char *ccr2, + unsigned char *ccr4, unsigned long *truebaudp) +{ + unsigned char bgr_std, bgr_enh, ccr2_std, ccr2_enh, ccr4_enh; + unsigned int ok_std, ok_enh; + unsigned long truebaud_std, truebaud_enh, truebaud,clkspeed; + + bgr_std = bgr_enh = 0; + ccr2_std = ccr2_enh = 0; + ccr4_enh = 0; + + /* + * the port/chip/board structure will tell us: + * 1) clock speed + * 2) chip revision (to figure out if the enhanced method is + * available. + */ + + clkspeed = port->chip->c_cim ? port->chip->c_cim->ci_clkspeed : port->board->b_clkspeed; + +#ifdef NODEBUGGING + printk("With clk speed %ld, baud rate = %ld\n",clkspeed, encbaud); +#endif + + ok_std = sab8253x_baudstd(encbaud, clkspeed, &bgr_std, + &ccr2_std, &truebaud_std); +#ifdef NODEBUGGING + printk("Std gives bgr = 0x%x, ccr2=0x%x for speed %ld\n",bgr_std,ccr2_std,truebaud_std); +#endif + if(port->chip->c_revision >= SAB82532_VSTR_VN_3_2) + { + ok_enh = sab8253x_baudenh(encbaud, clkspeed, + &bgr_enh, &ccr2_enh, &truebaud_enh); +#ifdef NODEBUGGING + printk("Enh gives bgr = 0x%x, ccr2=0x%x for speed %ld\n",bgr_enh,ccr2_enh,truebaud_enh); +#endif + } + else + ok_enh = FALSE; + + /* + * Did both methods return values? + */ + if (ok_std && ok_enh) + { + /* + * Find the closest of the two. + */ + if (ABSDIF((truebaud_enh<<1), encbaud) < + ABSDIF((truebaud_std<<1), encbaud)) + { + ok_std = FALSE; + } + else + { + ok_enh = FALSE; + } + } + + /* + * Now return the values. + */ + + if (ok_std || ok_enh) + { + truebaud = ok_std ? truebaud_std : truebaud_enh; + + /* + * If the true baud rate is off by more than 5%, then + * we don't support it. + */ + if (ROUND_DIV(ABSDIF((truebaud<<1), encbaud), encbaud) != 0) + { + /* + * We're not even in the right ballpark. This + * test is here to deal with overflow conditions. + */ + return FALSE; + } + else if (ROUND_DIV(ABSDIF((truebaud<<1), encbaud) * 100, + encbaud) >= 5) + { + return FALSE; + } + + *truebaudp = truebaud; + + if (ok_enh) + { + *ccr4 |= SAB82532_CCR4_EBRG; + *ccr2 = ccr2_enh; + *bgr = bgr_enh; +#ifdef DEBUGGING + printk("Enhanced Baud at %ld, ccr4 = 0x%x, ccr2 = 9x%x, bgr = 0x%x\n", + truebaud,*ccr4,*ccr2,*bgr); +#endif + } + else + { + *ccr4 &= ~SAB82532_CCR4_EBRG; + *ccr2 = ccr2_std; + *bgr = bgr_std; +#ifdef DEBUGGING + printk("Standard Baud at %ld, ccr4 = 0x%x, ccr2 = 9x%x, bgr = 0x%x\n", + truebaud,*ccr4,*ccr2,*bgr); +#endif + } + + return TRUE; + } + else + { + return FALSE; + } +} + +int Sab8253xCountTransmit(SAB_PORT *port) +{ + register RING_DESCRIPTOR *rd; + register int total; + register int count; + unsigned long flags; + RING_DESCRIPTOR *start; + + if(port->sabnext2.transmit == NULL) + { + return 0; + } + + save_flags(flags); + cli(); + rd = port->sabnext2.transmit; + start = rd; + total = 0; + while(1) + { + count = rd->Count; + if((count & OWNER) == OWN_DRIVER) + { + break; + } + total += (count & ~OWNER); + if(rd->sendcrc) + { + total += (4 - rd->crcindex); + } + rd = rd->VNext; + if(rd == start) + { + break; + } + } + restore_flags(flags); + return total; +} + +int Sab8253xCountTransmitDescriptors(SAB_PORT *port) +{ + register RING_DESCRIPTOR *rd; + register int total; + register int count; + unsigned long flags; + RING_DESCRIPTOR *start; + + if(port->sabnext2.transmit == NULL) + { + return 0; + } + + save_flags(flags); + cli(); + rd = port->sabnext2.transmit; + start = rd; + total = 0; + while(1) + { + count = rd->Count; + if((count & OWNER) == OWN_DRIVER) + { + break; + } + ++total; + rd = rd->VNext; + if(rd == start) + { + break; + } + } + restore_flags(flags); + return total; +} + +int getccr0configS(struct sab_port *port) +{ + return port->ccontrol.ccr0; +} + +int getccr1configS(struct sab_port *port) +{ + return port->ccontrol.ccr1; +} + +int getccr2configS(struct sab_port *port) +{ + return port->ccontrol.ccr2; +} + +int getccr3configS(struct sab_port *port) +{ + return port->ccontrol.ccr3; +} + +int getccr4configS(struct sab_port *port) +{ + return port->ccontrol.ccr4; +} + +int getrlcrconfigS(struct sab_port *port) +{ + return port->ccontrol.rlcr; +} + +int getmodeS(struct sab_port *port) +{ + return port->ccontrol.mode; +} + +void sab8253x_init_lineS(struct sab_port *port) +{ + unsigned char stat; + + if(port->chip->c_cim) + { + if(port->chip->c_cim->ci_type == CIM_SP502) + { + aura_sp502_program(port, SP502_OFF_MODE); + } + } + + /* + * Wait for any commands or immediate characters + */ + sab8253x_cec_wait(port); +#if 0 + sab8253x_tec_wait(port); /* I have to think about this one + * should I assume the line was + * previously in async mode*/ +#endif + + /* + * Clear the FIFO buffers. + */ + + WRITEB(port, cmdr, SAB82532_CMDR_RHR); + sab8253x_cec_wait(port); + WRITEB(port,cmdr,SAB82532_CMDR_XRES); + + + /* + * Clear the interrupt registers. + */ + stat = READB(port, isr0); /* acks ints */ + stat = READB(port, isr1); + + /* + * Now, initialize the UART + */ + WRITEB(port, ccr0, 0); /* power-down */ + WRITEB(port, ccr0, getccr0configS(port)); + WRITEB(port, ccr1, getccr1configS(port)); + WRITEB(port, ccr2, getccr2configS(port)); + WRITEB(port, ccr3, getccr3configS(port)); + WRITEB(port, ccr4, getccr4configS(port)); /* 32 byte receive fifo */ + WRITEB(port, mode, getmodeS(port)); + WRITEB(port, tic /* really rlcr */, getrlcrconfigS(port)); + /* power-up */ + + switch(port->ccontrol.ccr4 & SAB82532_CCR4_RF02) + { + case SAB82532_CCR4_RF32: + port->recv_fifo_size = 32; + break; + case SAB82532_CCR4_RF16: + port->recv_fifo_size = 16; + break; + case SAB82532_CCR4_RF04: + port->recv_fifo_size = 4; + break; + case SAB82532_CCR4_RF02: + port->recv_fifo_size = 2; + break; + default: + port->recv_fifo_size = 32; + port->ccontrol.ccr4 &= ~SAB82532_CCR4_RF02; + break; + } + + if(port->ccontrol.ccr2 & SAB82532_CCR2_TOE) + { + RAISE(port, txclkdir); + } + else + { + LOWER(port, txclkdir); + } + + SET_REG_BIT(port,ccr0,SAB82532_CCR0_PU); + + if(port->chip->c_cim) + { + if(port->chip->c_cim->ci_type == CIM_SP502) + { + aura_sp502_program(port, port->sigmode); + } + } +} + +/* frees up all skbuffs currently */ +/* held by driver */ +void Sab8253xFreeAllFreeListSKBUFFS(SAB_PORT* priv) /* empty the skbuffer list */ +/* either on failed open */ +/* or on close*/ +{ + struct sk_buff* skb; + + if(priv->sab8253xbuflist == NULL) + { + return; + } + + DEBUGPRINT((KERN_ALERT "sab8253x: freeing %i skbuffs.\n", + skb_queue_len(priv->sab8253xbuflist))); + + while(skb_queue_len(priv->sab8253xbuflist) > 0) + { + skb = skb_dequeue(priv->sab8253xbuflist); + dev_kfree_skb_any(skb); + } + kfree(priv->sab8253xbuflist); + priv->sab8253xbuflist = NULL; +} + +int Sab8253xSetUpLists(SAB_PORT *priv) +{ + if(priv->sab8253xbuflist) + { + if(priv->sab8253xc_rcvbuflist) + { + return 0; + } + else + { + return -1; + } + return 0; + } + else if(priv->sab8253xc_rcvbuflist) + { + return -1; + } + + priv->sab8253xbuflist = (struct sk_buff_head*) kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL); + if(priv->sab8253xbuflist == NULL) + { + return -1; + } + priv->sab8253xc_rcvbuflist = (struct sk_buff_head*) kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL); + if(priv->sab8253xc_rcvbuflist == NULL) + { + kfree(priv->sab8253xbuflist); + return -1; + } + skb_queue_head_init(priv->sab8253xbuflist); + skb_queue_head_init(priv->sab8253xc_rcvbuflist); + return 0; +} + +/* sets up transmit ring and one receive sk_buff */ + +/* set up transmit and receive + sk_buff control structures */ +int Sab8253xInitDescriptors2(SAB_PORT *priv, int listsize, int rbufsize) +{ + RING_DESCRIPTOR *desc; + RING_DESCRIPTOR *xdesc; + + if(priv->dcontrol2.transmit != NULL) + + { + if(priv->dcontrol2.receive != NULL) + { + return 0; + } + return -1; + } + else if(priv->dcontrol2.receive != NULL) + { + return -1; + } + + priv->dcontrol2.transmit = (RING_DESCRIPTOR*) + kmalloc(sizeof(RING_DESCRIPTOR) * listsize, GFP_KERNEL); + /* dcontrol2 is an historical + artifact from when the code + talked to an intelligent controller */ + if(priv->dcontrol2.transmit == NULL) + { + return -1; + } + + priv->dcontrol2.receive = (RING_DESCRIPTOR*) + kmalloc(sizeof(RING_DESCRIPTOR), GFP_KERNEL); /* only one receive sk_buffer */ + if(priv->dcontrol2.receive == NULL) + { + kfree(priv->dcontrol2.transmit); + priv->dcontrol2.transmit = NULL; + return -1; + } + + for(xdesc = priv->dcontrol2.transmit; + xdesc < &priv->dcontrol2.transmit[listsize - 1]; + xdesc = &xdesc[1]) /* set up transmit descriptors */ + { + xdesc->HostVaddr = NULL; + xdesc->VNext = &xdesc[1]; + xdesc->Count = 0 | OWN_DRIVER; + xdesc->crc = 0; + xdesc->sendcrc = 0; + xdesc->crcindex = 0; + } + xdesc->HostVaddr = NULL; + xdesc->VNext = priv->dcontrol2.transmit; /* circular list */ + xdesc->Count = 0 | OWN_DRIVER; + xdesc->crc = 0; + xdesc->sendcrc = 0; + xdesc->crcindex = 0; + + desc = priv->dcontrol2.receive; /* only need one descriptor for receive */ + desc->HostVaddr = NULL; + desc->VNext = &desc[0]; + + desc = priv->dcontrol2.receive; + desc->HostVaddr = dev_alloc_skb(rbufsize); + if(desc->HostVaddr == NULL) + { + printk(KERN_ALERT "Unable to allocate skb_buffers (rx 0).\n"); + printk(KERN_ALERT "Driver initialization failed.\n"); + kfree(priv->dcontrol2.transmit); + kfree(priv->dcontrol2.receive); + priv->dcontrol2.transmit = NULL; /* get rid of descriptor ring */ + priv->dcontrol2.receive = NULL; /* get rid of descriptor */ + /* probably should do some deallocation of sk_buffs*/ + /* but will take place in the open */ + return -1; + } + skb_queue_head(priv->sab8253xbuflist, (struct sk_buff*) desc->HostVaddr); + desc->Count = rbufsize|OWN_SAB; /* belongs to int handler */ + desc->crc = 0; + desc->sendcrc = 0; + desc->crcindex = 0; + + /* setup the various pointers */ + priv->active2 = priv->dcontrol2; /* insert new skbuff */ + priv->sabnext2 = priv->dcontrol2; /* transmit from here */ + + return 0; +} + +/* loads program, waits for PPC */ +/* and completes initialization*/ + +void Sab8253xCleanUpTransceiveN(SAB_PORT* priv) +{ + Sab8253xFreeAllFreeListSKBUFFS(priv); + Sab8253xFreeAllReceiveListSKBUFFS(priv); + + /* these are also cleaned up in the module cleanup routine */ + /* should probably only be done here */ + if(priv->dcontrol2.receive) + { + kfree(priv->dcontrol2.receive); + priv->dcontrol2.receive = NULL; + } + if(priv->dcontrol2.transmit) + { + kfree(priv->dcontrol2.transmit); + priv->dcontrol2.transmit = NULL; + } + priv->active2 = priv->dcontrol2; + priv->sabnext2 = priv->dcontrol2; +} + +void Sab8253xFreeAllReceiveListSKBUFFS(SAB_PORT* priv) /* empty the skbuffer list */ +/* either on failed open */ +/* or on close*/ +{ + struct sk_buff* skb; + + if(priv->sab8253xc_rcvbuflist == NULL) + { + return; + } + + DEBUGPRINT((KERN_ALERT "sab8253x: freeing %i skbuffs.\n", + skb_queue_len(priv->sab8253xc_rcvbuflist))); + + while(skb_queue_len(priv->sab8253xc_rcvbuflist) > 0) + { + skb = skb_dequeue(priv->sab8253xc_rcvbuflist); + dev_kfree_skb_any(skb); + } + kfree(priv->sab8253xc_rcvbuflist); + priv->sab8253xc_rcvbuflist = NULL; +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ + +void sab8253x_change_speedN(struct sab_port *port) +{ + unsigned long flags; + unsigned char ccr2=0, ccr4=0, ebrg=0; + int bits = 8; + +#ifdef DEBUGGING + printk("Change speed! "); +#endif + + if(!sab8253x_baud(port, (port->baud)*2, &ebrg, &ccr2, &ccr4, &(port->baud))) + { + printk("Aurora Warning. baudrate %ld could not be set! Using 115200", port->baud); + port->baud = 115200; + sab8253x_baud(port, (port->baud*2), &ebrg, &ccr2, &ccr4, &(port->baud)); + } + + if (port->baud) + { + port->timeout = (port->xmit_fifo_size * HZ * bits) / port->baud; + port->cec_timeout = port->tec_timeout >> 2; + } + else + { + port->timeout = 0; + port->cec_timeout = SAB8253X_MAX_CEC_DELAY; + } + port->timeout += HZ / 50; /* Add .02 seconds of slop */ + + save_flags(flags); + cli(); + sab8253x_cec_wait(port); + + WRITEB(port, bgr, ebrg); + WRITEB(port, ccr2, READB(port, ccr2) & ~(0xc0)); /* clear out current baud rage */ + WRITEB(port, ccr2, READB(port, ccr2) | ccr2); + WRITEB(port, ccr4, (READB(port,ccr4) & ~SAB82532_CCR4_EBRG) | ccr4); + + if (port->flags & FLAG8253X_CTS_FLOW) + { + WRITEB(port, mode, READB(port,mode) & ~(SAB82532_MODE_RTS)); + port->interrupt_mask1 &= ~(SAB82532_IMR1_CSC); + WRITEB(port, imr1, port->interrupt_mask1); + } + else + { + WRITEB(port, mode, READB(port,mode) | SAB82532_MODE_RTS); + port->interrupt_mask1 |= SAB82532_IMR1_CSC; + WRITEB(port, imr1, port->interrupt_mask1); + } + WRITEB(port, mode, READB(port, mode) | SAB82532_MODE_RAC); + restore_flags(flags); +} + +void sab8253x_shutdownN(struct sab_port *port) +{ + unsigned long flags; + + if (!(port->flags & FLAG8253X_INITIALIZED)) + { + return; + } + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&port->delta_msr_wait); + + /* Disable Interrupts */ + + port->interrupt_mask0 = 0xff; + WRITEB(port, imr0, port->interrupt_mask0); + port->interrupt_mask1 = 0xff; + WRITEB(port, imr1, port->interrupt_mask1); + + LOWER(port,rts); + LOWER(port,dtr); + + /* Disable Receiver */ + CLEAR_REG_BIT(port,mode,SAB82532_MODE_RAC); + + /* Power Down */ + CLEAR_REG_BIT(port,ccr0,SAB82532_CCR0_PU); + + port->flags &= ~FLAG8253X_INITIALIZED; + restore_flags(flags); +} + +int sab8253x_block_til_ready(struct tty_struct *tty, struct file * filp, + struct sab_port *port) +{ + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (port->flags & FLAG8253X_CLOSING)) + { + if (port->flags & FLAG8253X_CLOSING) + { + interruptible_sleep_on(&port->close_wait); /* finish up previous close */ + } +#ifdef SERIAL_DO_RESTART + if (port->flags & FLAG8253X_HUP_NOTIFY) + { + return -EAGAIN; + } + else + { + return -ERESTARTSYS; + } +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) + { + if (port->flags & FLAG8253X_NORMAL_ACTIVE) + { + return -EBUSY; /* async, sync tty or network driver active */ + } + if ((port->flags & FLAG8253X_CALLOUT_ACTIVE) && + (port->flags & FLAG8253X_SESSION_LOCKOUT) && + (port->session != current->session)) + { + return -EBUSY; + } + if ((port->flags & FLAG8253X_CALLOUT_ACTIVE) && + (port->flags & FLAG8253X_PGRP_LOCKOUT) && + (port->pgrp != current->pgrp)) + { + return -EBUSY; + } + port->flags |= FLAG8253X_CALLOUT_ACTIVE; /* doing a callout */ + return 0; + } + + /* sort out async vs sync tty, not call out */ + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) + { + if (port->flags & FLAG8253X_CALLOUT_ACTIVE) + { + return -EBUSY; + } + port->flags |= FLAG8253X_NORMAL_ACTIVE; + return 0; + } + + if (port->flags & FLAG8253X_CALLOUT_ACTIVE) + { + if (port->normal_termios.c_cflag & CLOCAL) + { + do_clocal = 1; + } + } + else if (tty->termios->c_cflag & CLOCAL) + { + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, port->count is dropped by one, so that + * sab8253x_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + + /* The port decrement logic is probably */ + /* broken -- hence if def'd out -- it does*/ + retval = 0; + add_wait_queue(&port->open_wait, &wait); /* starts the wait but does not block here */ + port->blocked_open++; + while (1) + { + save_flags(flags); + cli(); + if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) + { + RAISE(port, dtr); + RAISE(port, rts); /* maybe not correct for sync */ + /* + * ??? Why changing the mode here? + * port->regs->rw.mode |= SAB82532_MODE_FRTS; + * port->regs->rw.mode &= ~(SAB82532_MODE_RTS); + */ + } + restore_flags(flags); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(port->flags & FLAG8253X_INITIALIZED)) + { +#ifdef SERIAL_DO_RESTART + if (port->flags & FLAG8253X_HUP_NOTIFY) + { + retval = -EAGAIN; + } + else + { + retval = -ERESTARTSYS; + } +#else + retval = -EAGAIN; +#endif + break; + } + if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE) && + !(port->flags & FLAG8253X_CLOSING) && + (do_clocal || ISON(port,dcd))) + { + break; + } +#ifdef DEBUG_OPEN + printk("sab8253x_block_til_ready:2 flags = 0x%x\n",port->flags); +#endif + if (signal_pending(current)) + { + retval = -ERESTARTSYS; + break; + } +#ifdef DEBUG_OPEN + printk("sab8253x_block_til_ready blocking: ttyS%d, count = %d, flags = %x, clocal = %d, vstr = %02x\n", + port->line, port->count, port->flags, do_clocal, READB(port,vstr)); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&port->open_wait, &wait); + port->blocked_open--; +#ifdef DEBUG_OPEN + printk("sab8253x_block_til_ready after blocking: ttys%d, count = %d\n", + port->line, port->count); +#endif + if (retval) + { + return retval; + } + port->flags |= FLAG8253X_NORMAL_ACTIVE; + return 0; +} + +/* + * sab8253x_wait_until_sent() --- wait until the transmitter is empty + */ +void sab8253x_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + unsigned long orig_jiffies, char_time; + + if (sab8253x_serial_paranoia_check(port,tty->device,"sab8253x_wait_until_sent")) + { + return; + } + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (port->timeout - HZ/50) / port->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + { + char_time = 1; + } + if (timeout) + { + char_time = MIN(char_time, timeout); + } + while ((Sab8253xCountTransmit(port) > 0) || !port->all_sent) + { + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; + schedule_timeout(char_time); + if (signal_pending(current)) + { + break; + } + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + { + break; + } + } + +#if 0 + current->state = TASK_RUNNING; /* probably not necessary in 2.4.* */ +#endif +} + +void sab8253x_flush_buffer(struct tty_struct *tty) +{ + struct sab_port *port = (struct sab_port *)tty->driver_data; + unsigned long flags; + register RING_DESCRIPTOR *freeme; + + if(sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_flush_buffer")) + { + return; + } + + if(port->sabnext2.transmit == NULL) + { + return; + } + + save_flags(flags); + cli(); /* need to turn off ints because mucking + with sabnext2 */ +#ifndef FREEININTERRUPT + freeme = port->active2.transmit; + do /* just go all around */ + { + if(freeme->HostVaddr) + { + skb_unlink((struct sk_buff*)freeme->HostVaddr); + dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr); + freeme->HostVaddr = NULL; + } + freeme->sendcrc = 0; + freeme->crcindex = 0; + freeme->Count = OWN_DRIVER; + freeme = (RING_DESCRIPTOR*) freeme->VNext; + } + while(freeme != port->active2.transmit); +#else /* buffers only from sabnext2.transmit to active2.transmit */ + while((port->sabnext2.transmit->Count & OWNER) == OWN_SAB) /* clear out stuff waiting to be transmitted */ + { + freeme = port->sabnext2.transmit; + if(freeme->HostVaddr) + { + skb_unlink((struct sk_buff*)freeme->HostVaddr); + dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr); + freeme->HostVaddr = NULL; + } + freeme->sendcrc = 0; + freeme->crcindex = 0; + freeme->Count = OWN_DRIVER; + port->sabnext2.transmit = freeme->VNext; + } +#endif + port->sabnext2.transmit = port->active2.transmit; /* should already be equal to be sure */ + sab8253x_cec_wait(port); + WRITEB(port,cmdr,SAB82532_CMDR_XRES); + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); /* wake up tty driver */ + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + { + (*tty->ldisc.write_wakeup)(tty); + } +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/Makefile linux-2.5/drivers/net/wan/8253x/Makefile --- linux-2.5.20/drivers/net/wan/8253x/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/Makefile Sun May 19 17:27:50 2002 @@ -0,0 +1,28 @@ +# Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version +# 2 of the License, or (at your option) any later version. + +# File: drivers/net/WAN/atiXX50/Makefile +# +# Makefile for the Aurora ESSC based cards +# Specifically the 2520, 4020, 4520, 8520 +# + +all: ASLX.o + +O_TARGET := ASLX.o + +obj-y := 8253xini.o 8253xnet.o 8253xsyn.o crc32.o 8253xdbg.o 8253xplx.o 8253xtty.o 8253xchr.o 8253xint.o amcc5920.o 8253xmcs.o 8253xutl.o +obj-m := ASLX.o + +#EXTRA_CFLAGS += -I. -DFREEININTERRUPT +EXTRA_CFLAGS += -I. + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s *~ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/PciRegs.h linux-2.5/drivers/net/wan/8253x/PciRegs.h --- linux-2.5.20/drivers/net/wan/8253x/PciRegs.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/PciRegs.h Fri May 3 03:49:07 2002 @@ -0,0 +1,68 @@ +/* -*- linux-c -*- */ +#ifndef __PCIREGS_H +#define __PCIREGS_H + +#include + +/******************************************************************************* + * Copyright (c) 1997 - 1999 PLX Technology, Inc. + * + * PLX Technology Inc. licenses this software under specific terms and + * conditions. Use of any of the software or derviatives thereof in any + * product without a PLX Technology chip is strictly prohibited. + * + * PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY, + * EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. PLX makes no guarantee + * or representations regarding the use of, or the results of the use of, + * the software and documentation in terms of correctness, accuracy, + * reliability, currentness, or otherwise; and you rely on the software, + * documentation and results solely at your own risk. + * + * IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS, + * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES + * OF ANY KIND. IN NO EVENT SHALL PLX'S TOTAL LIABILITY EXCEED THE SUM + * PAID TO PLX FOR THE PRODUCT LICENSED HEREUNDER. + * + ******************************************************************************/ + +/* Modifications and extensions + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + **/ + +/****************************************************************************** + * + * File Name: PciRegs.h + * + * Module Name: IOP API and PCI API + * + * Description: This file defines the generic PCI Configuration Registers + * + * Revision: + * 09-03-99 : PCI SDK v3.00 Release + * + ******************************************************************************/ + +#define CFG_VENDOR_ID PCI_VENDOR_ID +#define CFG_COMMAND PCI_COMMAND +#define CFG_REV_ID PCI_REVISION_ID +#define CFG_CACHE_SIZE PCI_CACHE_LINE_SIZE +#define CFG_BAR0 PCI_BASE_ADDRESS_0 +#define CFG_BAR1 PCI_BASE_ADDRESS_1 +#define CFG_BAR2 PCI_BASE_ADDRESS_2 +#define CFG_BAR3 PCI_BASE_ADDRESS_3 +#define CFG_BAR4 PCI_BASE_ADDRESS_4 +#define CFG_BAR5 PCI_BASE_ADDRESS_5 +#define CFG_CIS_PTR PCI_CARDBUS_CIS +#define CFG_SUB_VENDOR_ID PCI_SUBSYSTEM_VENDOR_ID +#define CFG_EXP_ROM_BASE PCI_ROM_ADDRESS +#define CFG_RESERVED1 PCI_CAPABILITY_LIST +#define CFG_RESERVED2 (PCI_CAPABILITY_LIST + 4) +#define CFG_INT_LINE PCI_INTERRUPT_LINE + +#endif /* __PCIREGS_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/Reg9050.h linux-2.5/drivers/net/wan/8253x/Reg9050.h --- linux-2.5.20/drivers/net/wan/8253x/Reg9050.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/Reg9050.h Fri May 3 03:49:07 2002 @@ -0,0 +1,244 @@ +/* -*- linux-c -*- */ +#ifndef __REG9050_H +#define __REG9050_H + +/******************************************************************************* + * Copyright (c) 2001 PLX Technology, Inc. + * + * PLX Technology Inc. licenses this software under specific terms and + * conditions. Use of any of the software or derviatives thereof in any + * product without a PLX Technology chip is strictly prohibited. + * + * PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY, + * EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. PLX makes no guarantee + * or representations regarding the use of, or the results of the use of, + * the software and documentation in terms of correctness, accuracy, + * reliability, currentness, or otherwise; and you rely on the software, + * documentation and results solely at your own risk. + * + * IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS, + * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES + * OF ANY KIND. IN NO EVENT SHALL PLX'S TOTAL LIABILITY EXCEED THE SUM + * PAID TO PLX FOR THE PRODUCT LICENSED HEREUNDER. + * + ******************************************************************************/ + +/* Modifications and extensions + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + **/ + + +/****************************************************************************** + * + * File Name: + * + * Reg9050.h + * + * Description: + * + * This file defines all the PLX 9050 chip Registers. + * + * Revision: + * + * 01-30-01 : PCI SDK v3.20 + * + ******************************************************************************/ + + +#include "PciRegs.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* PCI Configuration Registers */ +#define PCI9050_VENDOR_ID CFG_VENDOR_ID +#define PCI9050_COMMAND CFG_COMMAND +#define PCI9050_REV_ID CFG_REV_ID +#define PCI9050_CACHE_SIZE CFG_CACHE_SIZE +#define PCI9050_PCI_BASE_0 CFG_BAR0 +#define PCI9050_PCI_BASE_1 CFG_BAR1 +#define PCI9050_PCI_BASE_2 CFG_BAR2 +#define PCI9050_PCI_BASE_3 CFG_BAR3 +#define PCI9050_PCI_BASE_4 CFG_BAR4 +#define PCI9050_PCI_BASE_5 CFG_BAR5 +#define PCI9050_CIS_PTR CFG_CIS_PTR +#define PCI9050_SUB_ID CFG_SUB_VENDOR_ID +#define PCI9050_PCI_BASE_EXP_ROM CFG_EXP_ROM_BASE +#define PCI9050_CAP_PTR CFG_CAP_PTR +#define PCI9050_PCI_RESERVED CFG_RESERVED2 +#define PCI9050_INT_LINE CFG_INT_LINE + + +#if 0 /* from PLX header file */ +/* Local Configuration Registers */ +#define PCI9050_RANGE_SPACE0 0x000 +#define PCI9050_RANGE_SPACE1 0x004 +#define PCI9050_RANGE_SPACE2 0x008 +#define PCI9050_RANGE_SPACE3 0x00C +#define PCI9050_RANGE_EXP_ROM 0x010 +#define PCI9050_REMAP_SPACE0 0x014 +#define PCI9050_REMAP_SPACE1 0x018 +#define PCI9050_REMAP_SPACE2 0x01C +#define PCI9050_REMAP_SPACE3 0x020 +#define PCI9050_REMAP_EXP_ROM 0x024 +#define PCI9050_DESC_SPACE0 0x028 +#define PCI9050_DESC_SPACE1 0x02C +#define PCI9050_DESC_SPACE2 0x030 +#define PCI9050_DESC_SPACE3 0x034 +#define PCI9050_DESC_EXP_ROM 0x038 +#define PCI9050_BASE_CS0 0x03C +#define PCI9050_BASE_CS1 0x040 +#define PCI9050_BASE_CS2 0x044 +#define PCI9050_BASE_CS3 0x048 +#define PCI9050_INT_CTRL_STAT 0x04C +#define PCI9050_EEPROM_CTRL 0x050 + +#endif + + +/* Additional register defintions */ +#define MAX_PCI9050_REG_OFFSET 0x054 + +#define PCI9050_EEPROM_SIZE 0x064 + +/* + * PLX 9050 registers: + */ + +typedef struct plx9050_s +{ + /* Local Address Space */ + unsigned int las0; /* 0x00 */ + unsigned int las1; /* 0x04 */ + unsigned int las2; /* 0x08 */ + unsigned int las3; /* 0x0c */ + /* Expansion ROM range */ + unsigned int e_rom; /* 0x10 */ + /* Local Base Adresses */ + unsigned int lba0; /* 0x14 */ + unsigned int lba1; /* 0x18 */ + unsigned int lba2; /* 0x1c */ + unsigned int lba3; /* 0x20 */ + unsigned int e_rom_lba; /* 0x24 */ + /* Bus region description */ + unsigned int brd0; /* 0x28 */ + unsigned int brd1; /* 0x2c */ + unsigned int brd2; /* 0x30 */ + unsigned int brd3; /* 0x34 */ + unsigned int e_rom_brd; /* 0x38 */ + /* Chip Select X Base address */ + unsigned int csba0; /* 0x3c */ + unsigned int csba1; /* 0x40 */ + unsigned int csba2; /* 0x44 */ + unsigned int csba3; /* 0x48 */ + /* Interupt Control/Status */ + unsigned int intr; /* 0x4c */ + /* Control */ + unsigned int ctrl; /* 0x50 */ +} plx9050_t, PLX9050; + +#define PLX_REG_LAS0RR 0x0 +#define PLX_REG_LAS1RR 0x4 +#define PLX_REG_LAS2RR 0x8 +#define PLX_REG_LAS3RR 0x0c +#define PLX_REG_EROMRR 0x10 +#define PLX_REG_LAS0BA 0x14 +#define PLX_REG_LAS1BA 0x18 +#define PLX_REG_LAS2BA 0x1c +#define PLX_REG_LAS3BA 0x20 +#define PLX_REG_EROMBA 0x24 +#define PLX_REG_LAS0BRD 0x28 +#define PLX_REG_LAS1BRD 0x2c +#define PLX_REG_LAS2BRD 0x30 +#define PLX_REG_LAS3BRD 0x34 +#define PLX_REG_EROMBRD 0x38 +#define PLX_REG_CS0BASE 0x3c +#define PLX_REG_CS1BASE 0x40 +#define PLX_REG_CS2BASE 0x44 +#define PLX_REG_CS3BASE 0x48 +#define PLX_REG_INTCSR 0x4c +#define PLX_REG_CTRL 0x50 + +/* + * Bits within those registers: + */ +/* LAS0 */ +#define PLX_LAS0_MEM_MASK 0x0ffffff0 + +/* INTCSR: */ +#define PLX_INT_INTR1ENA 0x00000001 /* Local interrupt 1 enable */ +#define PLX_INT_INTR1POL 0x00000002 /* Local interrupt 1 polarity */ +#define PLX_INT_INTR1STS 0x00000004 /* Local interrupt 1 status */ +#define PLX_INT_INTR2ENA 0x00000008 /* Local interrupt 2 enable */ +#define PLX_INT_INTR2POL 0x00000010 /* Local interrupt 2 polarity */ +#define PLX_INT_INTR2STS 0x00000020 /* Local interrupt 2 status */ +#define PLX_INT_PCIINTRENA 0x00000040 /* PCI interrupt enable */ +#define PLX_INT_SOFTINTR 0x00000080 /* Software interrupt */ +#if 0 +#define PLX_INT_ON (PLX_INT_INTR1ENA | PLX_INT_PCIINTRENA | PLX_INT_INTR2POL) +#define PLX_INT_OFF PLX_INT_INTR2POL +#elif 0 +#define PLX_INT_ON PLX_INT_PCIINTRENA +#define PLX_INT_OFF 0 +#else +#define PLX_INT_ON (PLX_INT_INTR1ENA | PLX_INT_PCIINTRENA) +#define PLX_INT_OFF 0x0000 +#endif + +/* BRD */ +#define PLX_BRD_BIGEND 0x01000000 +#define PLX_BRD_BIGEND_LANE 0x02000000 + + + /* CTRL: */ /* 87654321 */ +#define PLX_CTRL_RESET 0x40000000 +#define PLX_CTRL_USERIO3DIR 0x00000400 +#define PLX_CTRL_USERIO3DATA 0x00000800 +#define PLX_CTRL_SEPCLK 0x01000000 +#define PLX_CTRL_SEPCS 0x02000000 +#define PLX_CTRL_SEPWD 0x04000000 +#define PLX_CTRL_SEPRD 0x08000000 + +/* Definition for the EPROM */ + /* # of addressing bits for NM93CS06, NM93CS46 */ +#define NM93_ADDRBITS 6 +#define NM93_WENCMD ((u8) 0x00) +#define NM93_WRITECMD ((u8) 0x01) +#define NM93_READCMD ((u8) 0x02) +#define NM93_WRALLCMD ((u8) 0x00) /* same as WEN */ +#define NM93_WDSCMD ((u8) 0x00) /* ditto */ + +#define NM93_WDSADDR ((u8) 0x00) +#define NM93_WRALLADDR ((u8) 0x10) +#define NM93_WENADDR ((u8) 0x30) + +#define NM93_BITS_PER_BYTE 8 +#define NM93_BITS_PER_WORD 16 + +#define EPROMPREFETCHOFFSET 9 +#define PREFETCHBIT 0x0008 + +#define EPROM9050_SIZE 0x40 /* for loading the 9050 */ + +#define AURORA_MULTI_EPROM_SIZE 0x40 /* serial EPROM size */ +/* serial EPROM offsets */ +#define AURORA_MULTI_EPROM_CLKLSW 0x36 /* clock speed LSW */ +#define AURORA_MULTI_EPROM_CLKMSW 0x37 /* clock speed MSW */ +#define AURORA_MULTI_EPROM_REV 0x38 /* revision begins here */ +#define AURORA_MULTI_EPROM_REVLEN 0x0f /* length (in bytes) */ +#define AURORA_MULTI_EPROM_SPDGRD 0x3f /* speed grade is here */ + +#ifdef __cplusplus +} +#endif + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/amcc5920.c linux-2.5/drivers/net/wan/8253x/amcc5920.c --- linux-2.5.20/drivers/net/wan/8253x/amcc5920.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/amcc5920.c Fri May 3 03:49:07 2002 @@ -0,0 +1,92 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + /* This file is linked in, but I am + not sure there is ever any + reason directly to read the + serial eprom on the multichannel + server host card. */ + +/* We handle PCI devices */ +#include + +/* We need to use ioremap */ +#include + +#include + +#include "8253xmcs.h" +#include "8253xctl.h" + +/* read a byte out of the serial eeprom/nvram by means of + * 16 short commands */ + +static unsigned int amcc_nvram_breadw(unsigned char *bridge_space, + unsigned short address, + unsigned char *value) +{ + unsigned int count; + unsigned rhr; + + for(count = 0; count < 20000; ++count) + { + rhr = readl(bridge_space + AMCC_RCR); + if((rhr & AMCC_NVRBUSY) == 0) + { + break; + } + udelay(1); + } + if(count >= 20000) + { + return FALSE; + } + rhr = AMCC_NVRWRLA | ((address & 0x00FF) << 16); + writel(rhr, bridge_space + AMCC_RCR); + rhr = AMCC_NVRWRHA | ((address & 0xFF00) << 8); + writel(rhr, bridge_space + AMCC_RCR); + writel(AMCC_NVRRDDB, bridge_space + AMCC_RCR); + for(count = 0; count < 20000; ++count) + { + rhr = readl(bridge_space + AMCC_RCR); + if((rhr & AMCC_NVRBUSY) == 0) + { + break; + } + udelay(1); + } + if(count >= 20000) + { + return FALSE; + } + if(rhr & AMCC_NVRACCFAIL) + { + return FALSE; + } + *value = (unsigned char) (rhr >> 16); + return TRUE; +} + +/* read the whole serial eeprom from the host card */ + +unsigned int amcc_read_nvram(unsigned char* buffer, unsigned length, unsigned char *bridge_space) +{ + unsigned int count; + length <<= 1; /* covert words to bytes */ + + for(count = 0; count < length; ++count) + { + if(amcc_nvram_breadw(bridge_space, count, &buffer[count]) == FALSE) + { + return FALSE; + } + } + return TRUE; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/crc32.c linux-2.5/drivers/net/wan/8253x/crc32.c --- linux-2.5.20/drivers/net/wan/8253x/crc32.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/crc32.c Fri May 3 03:49:07 2002 @@ -0,0 +1,148 @@ +/* -*- linux-c -*- */ +/****************************************************************************** + * FILE: crc32.c + * + * Copyright: Telford Tools, Inc. + * 1996 + * + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + ****************************************************************************** + */ +/****************************************************************************** + * REVISION HISTORY: (Most Recent First) + * ------------------------------------- + * 2-Apr-91 ALEX Introduced "fn_calc_novram_crc32()". + ****************************************************************************** + */ + +/****************************************************/ +/* header files */ +/****************************************************/ + +#include +#include + +/****************************************************/ +/* constants */ +/****************************************************/ + +#define k_poly ((unsigned int)(0xedb88320)) +#define k_crc_table_size (256) + +#if defined (AMD29K) +pragma Code ("rkernel"); +pragma Off(cross_jump); +#endif + +/****************************************************/ +/* static data */ +/****************************************************/ + +#if defined(AMD29K) +pragma Data (Export,"fastbss"); +#endif defined(AMD29K) + +unsigned int gg_a_crc_table[k_crc_table_size]; + +#if defined(AMD29K) +pragma Data; +#endif defined(AMD29K) + + +/****************************************************/ +/* global procedures */ +/****************************************************/ + +void +fn_init_crc_table() +{ + short i_table; + + for (i_table = 0; i_table < k_crc_table_size; i_table++) + { + unsigned int result = 0; + short i_bit; + + for (i_bit = 0; i_bit < 8; i_bit++) + { + unsigned int bit = ((i_table & (1 << i_bit)) != 0); + + if ((bit ^ (result & 1)) != 0) + result = (result >> 1) ^ k_poly; + else + result >>= 1; + } + + gg_a_crc_table[i_table] = result; + } + +} /* end of fn_init_crc_table */ + +/****************************************************/ + +static unsigned int +fn_calc_memory_chunk_crc32(void *p, unsigned int n_bytes, unsigned int crc) +{ + unsigned char *p_uc = (unsigned char*)p; + unsigned int result = ~crc; + + while (n_bytes-- > 0) + { + result = (result >> 8) ^ gg_a_crc_table[(result ^ *p_uc++) & 0xff]; + } + + return(~result); + +} /* end of fn_calc_memory_chunk_crc32 */ + +/****************************************************/ + +unsigned int +fn_calc_memory_crc32(void *p, unsigned int n_bytes) +{ + fnm_assert_stmt(n_bytes > 4); + + return(fn_calc_memory_chunk_crc32(p, n_bytes, k_initial_crc_value)); + +} /* end of fn_calc_memory_crc32 */ + +/****************************************************/ + +unsigned int +fn_check_memory_crc32(void *p, unsigned int n_bytes, unsigned int crc) +{ + return(fn_calc_memory_crc32(p, n_bytes) == crc); + +} /* end of fn_check_memory_crc32 */ + + +/****************************************************/ +/* Adds current longword to the crc value and */ +/* returns that value. */ +unsigned int +fn_update_crc(char *val, unsigned int crcval) +{ + long i; + + /* ----< break long into bytes >---- */ + /* ----< put bytes into crc >---- */ + for (i = 0; i < 4; i++) + { + crcval = gg_a_crc_table[(crcval ^ val[i]) & 0xff] ^ + ((crcval >> 8) & 0x00ffffff); + } + return(crcval); +} /* endfunc--fn_update_crc */ + + +/****************************************************/ +/****************************************************/ +/* End source file "crc32.c" */ +/****************************************************/ +/****************************************************/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/crc32.h linux-2.5/drivers/net/wan/8253x/crc32.h --- linux-2.5.20/drivers/net/wan/8253x/crc32.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/crc32.h Fri May 3 03:49:07 2002 @@ -0,0 +1,27 @@ +/* -*- linux-c -*- */ +/****************************************************/ +/****************************************************/ +/* Begin source file "crc32.h" */ +/****************************************************/ +/****************************************************/ + +#if !defined(_CRC32_H_) +#define _CRC32_H_ + +/****************************************************/ +/* header files */ +/****************************************************/ + +/****************************************************/ +/* constants */ +/****************************************************/ + +#define k_initial_crc_value ((unsigned int) 0) + +#endif + +/****************************************************/ +/****************************************************/ +/* End source file "crc32.h" */ +/****************************************************/ +/****************************************************/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/crc32dcl.h linux-2.5/drivers/net/wan/8253x/crc32dcl.h --- linux-2.5.20/drivers/net/wan/8253x/crc32dcl.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/crc32dcl.h Fri May 3 03:49:07 2002 @@ -0,0 +1,45 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +/****************************************************/ +/****************************************************/ +/* Begin source file "crc32dcl.h" */ +/****************************************************/ +/****************************************************/ + +#if !defined(_CRC32_HP_) +#define _CRC32_HP_ + +/****************************************************/ +/* header files */ +/****************************************************/ + +#include + +/****************************************************/ +/* global procedure prototypes */ +/****************************************************/ + +extern void fn_init_crc_table(void); +extern unsigned int fn_calc_memory_chunk_crc32(void *p, unsigned int n_bytes, unsigned int crc); +extern unsigned int fn_calc_memory_crc32(void *p, unsigned int n_bytes); +extern unsigned int fn_check_memory_crc32(void *p, unsigned int n_bytes, unsigned int crc); + +extern unsigned int gg_a_crc_table[]; + + +#endif + +/****************************************************/ +/****************************************************/ +/* End source file "crc32dcl.h" */ +/****************************************************/ +/****************************************************/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/endian.h linux-2.5/drivers/net/wan/8253x/endian.h --- linux-2.5.20/drivers/net/wan/8253x/endian.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/endian.h Fri May 3 03:49:07 2002 @@ -0,0 +1,341 @@ +/* -*- linux-c -*- */ +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +/****************************************************/ +/****************************************************/ +/* Begin header file "endian.h" */ +/****************************************************/ +/****************************************************/ + +#if !defined(_ENDIAN_HP_) +#define _ENDIAN_HP_ + +/****************************************************/ +/* header files */ +/****************************************************/ + + +/****************************************************/ +/* let's see if we know this is a big endian */ +/****************************************************/ +#ifndef INLINE +#define INLINE inline +#endif + +#define fnm_assert_stmt(a) + +#ifndef BYTE_ORDER +#if defined(AMD29K) || defined(mc68000) + +#define BIG_ENDIAN 4321 + +#endif + +/****************************************************/ +/* global macro functions handling endian issues */ +/****************************************************/ + +#if !defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN) +#define LITTLE_ENDIAN 1234 +#endif +#endif + +#define fnm_get_i_big_endian(p_uc, x) fnm_get_ui_big_endian(p_uc, x) +#define fnm_get_s_big_endian(p_uc, x) fnm_get_us_big_endian(p_uc, x) +#define fnm_get_i_little_endian(p_uc, x) fnm_get_ui_little_endian(p_uc, x) +#define fnm_get_s_little_endian(p_uc, x) fnm_get_us_little_endian(p_uc, x) + +#define fnm_get_ui_big_endian(p_uc, x) \ +{ \ + (x) = (((unsigned int)(*(p_uc)++)) << 24); \ + (x) += (((unsigned int)(*(p_uc)++)) << 16); \ + (x) += (((unsigned int)(*(p_uc)++)) << 8); \ + (x) += ((unsigned int)(*(p_uc)++)); \ +} + +#define fnm_get_us_big_endian(p_uc, x) \ +{ \ + (x) = (((unsigned short)(*(p_uc)++)) << 8); \ + (x) += ((unsigned short)(*(p_uc)++)); \ +} + +#define fnm_get_ui_little_endian(p_uc, x) \ +{ \ + (x) = ((unsigned int)(*(p_uc)++)); \ + (x) += (((unsigned int)(*(p_uc)++)) << 8); \ + (x) += (((unsigned int)(*(p_uc)++)) << 16); \ + (x) += (((unsigned int)(*(p_uc)++)) << 24); \ +} + +#define fnm_get_us_little_endian(p_uc, x) \ +{ \ + (x) = ((unsigned short)(*(p_uc)++)); \ + (x) += (((unsigned short)(*(p_uc)++)) << 8); \ +} + +#define fnm_store_i_big_endian(p_uc, x) fnm_store_ui_big_endian(p_uc, x) +#define fnm_store_s_big_endian(p_uc, x) fnm_store_us_big_endian(p_uc, x) +#define fnm_store_i_little_endian(p_uc, x) fnm_store_ui_little_endian(p_uc, x) +#define fnm_store_s_little_endian(p_uc, x) fnm_store_us_little_endian(p_uc, x) + +#define fnm_store_ui_big_endian(p_uc, x) \ +{ \ + *(p_uc)++ = (((unsigned int)(x)) >> 24); \ + *(p_uc)++ = (((unsigned int)(x)) >> 16); \ + *(p_uc)++ = (((unsigned int)(x)) >> 8); \ + *(p_uc)++ = ((unsigned int)(x)); \ +} + +#define fnm_store_us_big_endian(p_uc, x) \ +{ \ + *(p_uc)++ = (unsigned char) (((unsigned short)(x)) >> 8); \ + *(p_uc)++ = (unsigned char) ((unsigned short)(x)); \ +} + +#define fnm_store_ui_little_endian(p_uc, x) \ +{ \ + *(p_uc)++ = ((unsigned int)(x)); \ + *(p_uc)++ = (((unsigned int)(x)) >> 8); \ + *(p_uc)++ = (((unsigned int)(x)) >> 16); \ + *(p_uc)++ = (((unsigned int)(x)) >> 24); \ +} + +#define fnm_store_us_little_endian(p_uc, x) \ +{ \ + *(p_uc)++ = ((unsigned short)(x)); \ + *(p_uc)++ = (((unsigned short)(x)) >> 8); \ +} + +/* for now lets always use the macroes instead of the inline procedures + so that we are sure they work */ + +#if 1 || defined(AMD29K) + +#define fnm_convert_us_endian(x) \ + ((unsigned short)((((unsigned short)(x)) << 8) + (((unsigned short)(x)) >> 8))) + +#define fnm_convert_ui_endian(x) \ + ((unsigned int)((((unsigned int)(x)) >> 24) + ((((unsigned int)(x)) & 0x00ff0000) >> 8) + \ + ((((unsigned int)(x)) & 0x0000ff00) << 8) + (((unsigned int)(x)) << 24))) + +#define fnm_make_ui_from_2_us(us_high_part, us_low_part) \ + ((unsigned int)((((unsigned int)(us_high_part)) << 16) + ((unsigned short)(us_low_part)))) + +#define fnm_make_ui_from_4_uc(p1, p2, p3, p4) \ + ((unsigned int)(((((((unsigned int)((t_uc)p1) << 8) + ((t_uc)p2)) << 8) \ + + ((t_uc)p3)) << 8) + ((t_uc)p4))) + +#define fnm_make_us_from_2_uc(uc_high_part, uc_low_part) \ + ((unsigned short)((((unsigned short)(uc_high_part)) << 8) + ((t_uc)(uc_low_part)))) + +#else + +INLINE unsigned short fni_convert_us_endian(const unsigned short x) +{ + return((x << 8) + (x >> 8)); +} + +INLINE unsigned int fni_convert_ui_endian(const unsigned int x) +{ + return((x >> 24) + ((x & 0x00ff0000) >> 8) + + ((x & 0x0000ff00) << 8) + (x << 24)); +} + +INLINE unsigned int fni_make_ui_from_2_us(const unsigned short us_high_part, + const unsigned short us_low_part) +{ + return((((unsigned int)us_high_part) << 16) + us_low_part); +} + +INLINE unsigned int fni_make_ui_from_4_uc(const unsigned char p1, const unsigned char p2, + const unsigned char p3, const unsigned char p4) +{ + return(((((((unsigned int)p1 << 8) + p2) << 8) + p3) << 8) + p4); +} + +INLINE unsigned short fni_make_us_from_2_uc(const unsigned char uc_high_part, + const unsigned char uc_low_part) +{ + return((((unsigned short)uc_high_part) << 8) + uc_low_part); +} + +#define fnm_convert_us_endian(x) fni_convert_us_endian(x) +#define fnm_convert_ui_endian(x) fni_convert_ui_endian(x) + +#define fnm_make_ui_from_2_us(us_high_part, us_low_part) \ + fni_make_ui_from_2_us(us_high_part, us_low_part) + +#define fnm_make_ui_from_4_uc(p1, p2, p3, p4) \ + fni_make_ui_from_4_uc(p1, p2, p3, p4) + +#define fnm_make_us_from_2_uc(uc_high_part, uc_low_part) \ + fni_make_us_from_2_uc(uc_high_part, uc_low_part) + +#endif + +#define fnm_convert_s_endian(x) ((short)(fnm_convert_us_endian(x))) +#define fnm_convert_i_endian(x) ((int)(fnm_convert_ui_endian(x))) + +#if defined(BIG_ENDIAN) + +#define fnm_convert_us_big_endian(x) ((unsigned short)(x)) +#define fnm_convert_s_big_endian(x) ((short)(x)) +#define fnm_convert_ui_big_endian(x) ((unsigned int)(x)) +#define fnm_convert_i_big_endian(x) ((int)(x)) + +#define fnm_convert_us_little_endian(x) fnm_convert_us_endian(x) +#define fnm_convert_s_little_endian(x) fnm_convert_s_endian(x) +#define fnm_convert_ui_little_endian(x) fnm_convert_ui_endian(x) +#define fnm_convert_i_little_endian(x) fnm_convert_i_endian(x) + +#else + +#define fnm_convert_us_big_endian(x) fnm_convert_us_endian(x) +#define fnm_convert_s_big_endian(x) fnm_convert_s_endian(x) +#define fnm_convert_ui_big_endian(x) fnm_convert_ui_endian(x) +#define fnm_convert_i_big_endian(x) fnm_convert_i_endian(x) + +#define fnm_convert_us_little_endian(x) ((unsigned short)(x)) +#define fnm_convert_s_little_endian(x) ((short)(x)) +#define fnm_convert_ui_little_endian(x) ((unsigned int)(x)) +#define fnm_convert_i_little_endian(x) ((int)(x)) + +#endif + +/****************************************************/ +/* test macro functions handling endian issues */ +/****************************************************/ + +#if defined(NDEBUG) + +#define fnm_test_definitions() + +#else + +#define fnm_test_definitions() \ +{ \ + union \ + { \ + t_c a_c[4]; \ + unsigned short a_us[2]; \ + unsigned int ul; \ + \ + } t1 = { "\x01\x02\x03\x04" }; \ + \ + unsigned char *p; \ + unsigned short us_one, us_two; \ + unsigned int ul_one; \ + \ + fnm_assert_stmt((t1.a_c[0] == 1) && (t1.a_c[1] == 2) && \ + (t1.a_c[2] == 3) && (t1.a_c[3] == 4)); \ + \ + fnm_assert_stmt(fnm_convert_ui_big_endian(t1.ul) == 0x01020304); \ + fnm_assert_stmt(fnm_convert_ui_little_endian(t1.ul) == 0x04030201); \ + fnm_assert_stmt(fnm_convert_us_big_endian(t1.a_us[0]) == 0x0102); \ + fnm_assert_stmt(fnm_convert_us_little_endian(t1.a_us[0]) == 0x0201); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_get_us_little_endian(p, us_one); \ + fnm_get_us_little_endian(p, us_two); \ + \ + fnm_assert_stmt((us_one == 0x0201) && (us_two == 0x0403)); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_get_us_big_endian(p, us_one); \ + fnm_get_us_big_endian(p, us_two); \ + \ + fnm_assert_stmt((us_one == 0x0102) && (us_two == 0x0304)); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_get_ui_little_endian(p, ul_one); \ + \ + fnm_assert_stmt(ul_one == 0x04030201); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_get_ui_big_endian(p, ul_one); \ + \ + fnm_assert_stmt(ul_one == 0x01020304); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_store_us_little_endian(p, 0x1234); \ + fnm_store_us_little_endian(p, 0x5678); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_get_us_little_endian(p, us_one); \ + fnm_get_us_little_endian(p, us_two); \ + \ + fnm_assert_stmt((us_one == 0x1234) && (us_two == 0x5678)); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_store_us_big_endian(p, 0x1234); \ + fnm_store_us_big_endian(p, 0x5678); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_get_us_big_endian(p, us_one); \ + fnm_get_us_big_endian(p, us_two); \ + \ + fnm_assert_stmt((us_one == 0x1234) && (us_two == 0x5678)); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_store_ui_little_endian(p, 0x12345678); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_get_ui_little_endian(p, ul_one); \ + \ + fnm_assert_stmt(ul_one == 0x12345678); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_store_ui_big_endian(p, 0x12345678); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + p = (unsigned char*)(&t1); \ + \ + fnm_get_ui_big_endian(p, ul_one); \ + \ + fnm_assert_stmt(ul_one == 0x12345678); \ + fnm_assert_stmt((p-4) == ((unsigned char*)(&t1))); \ + \ + fnm_assert_stmt(fnm_make_ui_from_2_us(1, 2) == 0x00010002); \ + fnm_assert_stmt(fnm_make_ui_from_4_uc(1, 2, 3, 4) == 0x01020304); \ + fnm_assert_stmt(fnm_make_us_from_2_uc(1, 2) == 0x0102); \ + \ +} + +#endif + +#endif + +/****************************************************/ +/****************************************************/ +/* End header file "endian.h" */ +/****************************************************/ +/****************************************************/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/readme.txt linux-2.5/drivers/net/wan/8253x/readme.txt --- linux-2.5.20/drivers/net/wan/8253x/readme.txt Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/readme.txt Sun May 19 17:38:06 2002 @@ -0,0 +1,185 @@ +10 February 2002 + +1) This release reformats the files according to kernel linux-c +conventions. If you do not have kernel linux-c mode configured +for your version of emacs, add the following to your .emacs file. + +(defun linux-c-mode () + "C mode with adjusted defaults for use with the Linux kernel." + (interactive) + (c-mode) + (c-set-style "K&R") + (setq c-basic-offset 8)) + +Then you will be able to manually invoke linux-c-mode as a Meta-X +command. + +The line + +/* -*- linux-c -*- */ + +that is now found at the top of each C source file automatically puts +the buffer into linux-c-mode when emacs opens the file for editing. + +2) The following network ioctl have been removed + +#define SAB8253XSETMAC (SIOCDEVPRIVATE + 5 + 2) +#define SAB8253XGETMAC (SIOCDEVPRIVATE + 5 + 3) + +along with the PSEUDOMAC structure and references to this structure. + +The following standard ioctls provide the same functionality. + +#define SIOCSIFHWADDR 0x8924 /* set hardware address */ +#define SIOCGIFHWADDR 0x8927 /* Get hardware address */ + +The 8253xmac tool has been removed. To start the ASLX sab8253x +network interface, you should use a command like the following with +the substitutions appropriate to your environment. + +ifconfig 8253x006 hw ether 000000030405 test1 + +You should substitute for 8253x006 the network interface that you are +using. For 000000030405 you should substitute the MAC address that +you desire to use. For test1 you should substitute the host name or +host IP address that you wish to use for this interface. + +3) As many functions and non-local variables as possible have been +declared static in order to prevent name space polution. + +4) Support has been added for programmatic selection of signaling +interface for the Aurora WAN multiserver 3500 series extension boards. + +Ports associated with this cards can be programmed via the + +#define ATIS_IOCSSIGMODE _IOW(ATIS_MAGIC_IOC,6,unsigned int) + +ioctl to have either RS232, RS422, RS449, RS530, V.35 or no (=off) +physical layer signaling. + +The program 8253xmode.c has been added to demonstrate the use +of this set ioctl as well as the associated get ioctl. + +#define ATIS_IOCGSIGMODE _IOW(ATIS_MAGIC_IOC,7,unsigned int) + +The program is invoked as follows. + +8253xmode /dev/ttyS* mode + +where mode is 232, 442, 449, 530, v.35 or off. + +The proc file has been modified to show information associated with +the signaling state. + +martillo@ylith:~ > cat /proc/tty/driver/auraserial +serinfo:2.01N driver:1.22 +TTY MAJOR = 4, CUA MAJOR = 5, STTY MAJOR = 254. +128: port 0: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: close: NOPRG +129: port 1: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: openA: NOPRG +130: port 2: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: openA: NOPRG +131: port 3: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: close: NOPRG +132: port 4: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: close: NOPRG +133: port 5: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: openS: NOPRG +134: port 6: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: close: NOPRG +135: port 7: sab82538: v3: chip 0: ATI 8520P: bus 2: slot 10: NR: close: NOPRG +136: port 0: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +137: port 1: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +138: port 2: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +139: port 3: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: close: RS232 +140: port 4: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: close: RS232 +141: port 5: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: close: RS232 +142: port 6: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: close: RS232 +143: port 7: sab82538: v2: chip 0: ATI WANMS: bus 2: slot 11: NR: close: RS232 +144: port 0: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +145: port 1: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS232 +146: port 2: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS232 +147: port 3: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS232 +148: port 4: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS530 +149: port 5: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS232 +150: port 6: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: close: RS232 +151: port 7: sab82538: v2: chip 1: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +152: port 0: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +153: port 1: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +154: port 2: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +155: port 3: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +156: port 4: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +157: port 5: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +158: port 6: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: close: RS232 +159: port 7: sab82538: v2: chip 2: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +160: port 0: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +161: port 1: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +162: port 2: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +163: port 3: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +164: port 4: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +165: port 5: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +166: port 6: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +167: port 7: sab82538: v2: chip 3: ATI WANMS: bus 2: slot 11: NR: close: RS232 +168: port 0: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +169: port 1: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +170: port 2: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +171: port 3: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +172: port 4: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +173: port 5: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +174: port 6: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +175: port 7: sab82538: v2: chip 4: ATI WANMS: bus 2: slot 11: NR: close: RS232 +176: port 0: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +177: port 1: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +178: port 2: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +179: port 3: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +180: port 4: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +181: port 5: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +182: port 6: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +183: port 7: sab82538: v2: chip 5: ATI WANMS: bus 2: slot 11: NR: close: RS232 +184: port 0: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: openA: RS232 +185: port 1: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +186: port 2: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +187: port 3: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +188: port 4: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +189: port 5: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +190: port 6: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +191: port 7: sab82538: v2: chip 6: ATI WANMS: bus 2: slot 11: NR: close: RS232 +192: port 0: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +193: port 1: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +194: port 2: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +195: port 3: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +196: port 4: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +197: port 5: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +198: port 6: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: close: RS232 +199: port 7: sab82538: v2: chip 7: ATI WANMS: bus 2: slot 11: NR: openA: RS232 + +The above file indicates the minor device number, port number relative +to chip, chip type, chip version number, chip number (meaningful for +4X20 and multichannel servers), interface type, bus number, slot +number, port availability (AO = asynchronous only, NR = No +Restrictions, or NA = Not Available), status (closed, open +Synchronous, open Asynchronous, open Character, or open Network), and +signaling type (NOPRG = not selectable programmatically; other +possibilities inclue OFF, RS232, RS442, RS449, RS530 and V.35). + +Note that by default ports come up in RS232 mode. + +The following module parameter has been added. + +MODULE_PARM(sab8253x_default_sp502_mode, "i"); + +The asynchronous TTY functionality can immediately be used without +extra configuration. [Note that immediate use of the WMS3500 products +is possible because the default value of sab8253x_default_sp502_mode +is SP502_RS232_MODE (== 1). If a different default mode is needed, it +can be set as options in the /etc/modules.conf file. OFF = 0. +RS232 = 1, RS422 = 2, RS485 = 3, RS449 = 4, EIA530 = 5 and V.35 = 6, as +defined in 8253xioc.h.] + +5) I added a readme.txt an an overview of the driver sab8253xov.txt +and the functional and design specifications (sab8253xfs.txt and +sab8253xds.txt) to the patch. The functional and design +specifications were blindly exported to text from the html versions. + +The documents are more nicely formated at + +http://www.telfordtools.com/sab8253x/sab8253xfs.html + +and + +http://www.telfordtools.com/sab8253x/sab8253xds.html + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/ring.h linux-2.5/drivers/net/wan/8253x/ring.h --- linux-2.5.20/drivers/net/wan/8253x/ring.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/ring.h Fri May 3 03:49:07 2002 @@ -0,0 +1,67 @@ +/* -*- linux-c -*- */ +#ifndef _RING_H_ +#define _RING_H_ + +/* + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#ifdef __KERNEL__ +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#define dev_kfree_skb_irq(s) dev_kfree_skb((s)) +#define dev_kfree_skb_any(s) dev_kfree_skb((s)) +#define net_device_stats enet_statistics +#define net_device device +#else +#define NETSTATS_VER2 +#endif +#endif + +#define OWNER ((unsigned short)0x8000) /* mask for ownership bit */ +#define OWN_DRIVER ((unsigned short)0x8000) /* value of owner bit == host */ +#define OWN_SAB ((unsigned short)0x0000) /* value of owner bit == sab or + * receive or send */ +#define LISTSIZE 32 +#define RXSIZE (8192+3) +#define MAXNAMESIZE 11 +#define MAXSAB8253XDEVICES 256 + +struct counters +{ + unsigned int interruptcount; + unsigned int freecount; + unsigned int receivepacket; + unsigned int receivebytes; + unsigned int transmitpacket; + unsigned int transmitbytes; + unsigned int tx_drops; + unsigned int rx_drops; +}; + +typedef struct ring_descriptor +{ + unsigned short Count; + unsigned char sendcrc; + unsigned char crcindex; + unsigned int crc; + struct sk_buff* HostVaddr; + struct ring_descriptor* VNext; +} RING_DESCRIPTOR; + +typedef struct dcontrol2 +{ + RING_DESCRIPTOR *receive; + RING_DESCRIPTOR *transmit; +} DCONTROL2; + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/sab8253xov.txt linux-2.5/drivers/net/wan/8253x/sab8253xov.txt --- linux-2.5.20/drivers/net/wan/8253x/sab8253xov.txt Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/sab8253xov.txt Fri May 3 03:49:07 2002 @@ -0,0 +1,47 @@ +The Aurora Linux 2.4.* software package for the Siemens/Infineon 8253X +based PCI adapter card product line (2520, 4520, 4020, 8520, WMS and LMS +communications controllers) provides the following benefits to the user. + + + +1. A Linux Asynchronous TTY driver that supports serial +connections to asynchronous TTYs with the standard Linux/Unix terminal +capabilities as well as custom baud rates. The asynchronous TTY driver +can also support connections to computers that support standard +asynchronous terminal emulation programs, such as cu, tip, kermit or +hyperterm. The asynchronous TTY driver can also support file transfer +via standard asynchronous file transfer programs like kermit. In +addition, the asynchronous TTY driver can be used by asynchronous SLIP +or PPP to provide network connectivity. + +2. A Linux Synchronous TTY driver that supports all of the above +for synchronous TTY connections. Because one cannot generally purchase +synchronous TTYs, this functionality is most useful with software +terminal emulators and with synchronous PPP implementations that assume +an underlying synchronous terminal driver. + +3. A Linux Synchronous Network driver that provides a synchronous +serial ethernet interface. This interface provides a simple +straightforward method of synchronous wide-area interconnection that +works via the standard Linux Ethernet network and bridging interfaces. +Some routers and bridges support this interface. + +4. A Linux Synchronous Character driver that provides a standard +read/write interface to the network driver functionality (i.e., packet +read and packet write capability) and that can emulate the Solaris +putmsg/getmsg interface. This driver is useful for users that wish to +implement their own protocol software within user applications. + +5. The Aurora Linux software provides the capability of dial-up +connection set-up for any of the previous drivers. This dial-up +capability follows the /dev/cua convention of Linux 2.2* and Linux 2.4.* +kernels. + +6. Source is provided so that users may make custom modifications +to drivers. Adding BISYNC or cHDLC support would be fairly +straightforward and may become available in later releases. This source +could provide a starting point for implementing drivers for other +operating systems. The source is partitioned by functionality and comes +with functional and design specifications as well as other documentation +useful to users and implementers. + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/8253x/sp502.h linux-2.5/drivers/net/wan/8253x/sp502.h --- linux-2.5.20/drivers/net/wan/8253x/sp502.h Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/8253x/sp502.h Fri May 3 19:42:09 2002 @@ -0,0 +1,48 @@ +/* -*- linux-c -*- */ +/* + * sp502.h - chip definitions for the + * Sipex SP502 Multi-Mode Serial Transceiver + * + * Bjoren Davis, Aurora Technologies, 21. January, 1995. + * + * COPYRIGHT (c) 1995-1999 BY AURORA TECHNOLOGIES, INC., WALTHAM, MA. + * + * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * file: sp502.h + * author: bkd + * created: 1/21/95 + * revision info: $Id: sp502.h,v 1.3 2002/02/10 22:17:26 martillo Exp $ + * ripped off from: Header: /vol/sources.cvs/dev/acs/include/sp502.h,v 1.4 1996/11/07 21:35:10 bkd Exp + * Used without modification in the multichannel server portion of the Linux driver by Joachim Martillo + */ + +#ifndef _SP502_H +#define _SP502_H + +#ifdef sun +# pragma ident "@(#)$Header: /usr/local/cvs/linux-2.4.6/drivers/net/wan/8253x/sp502.h,v 1.3 2002/02/10 22:17:26 martillo Exp $" +#endif + +/* + * These following nibble values are from the SP502 Data Sheet, which + * is in the Sipex Interface Products Catalog, 1994 Edition, pages + * 168 and 170. + */ + +/* same order as the modes in 8253xioc.h and as the names in 8253xtty.c and as the progbytes in 8253xmcs.c*/ + +#define SP502_OFF ((unsigned char) 0x00) +#define SP502_RS232 ((unsigned char) 0x02) +#define SP502_RS422 ((unsigned char) 0x04) +#define SP502_RS485 ((unsigned char) 0x05) +#define SP502_RS449 ((unsigned char) 0x0c) +#define SP502_EIA530 ((unsigned char) 0x0d) +#define SP502_V35 ((unsigned char) 0x0e) + +#endif /* !_SP502_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/Config.help linux-2.5/drivers/net/wan/Config.help --- linux-2.5.20/drivers/net/wan/Config.help Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/net/wan/Config.help Fri May 3 12:57:31 2002 @@ -429,6 +429,37 @@ If unsure, say N here. +CONFIG_COMX_HW_MUNICH + Hardware driver for the 'SliceCOM' (channelized E1) and 'PciCOM' + boards (X21) from the MultiGate family. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called comx-hw-munich.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + + Read linux/Documentation/networking/slicecom.txt for help on + configuring and using SliceCOM interfaces. Further info on these cards + can be found at http://www.itc.hu or . + +CONFIG_HDLC_RAW + Say Y to this option if you want generic HDLC driver to support + raw HDLC over WAN (Wide Area Network) connections. + + If unsure, say N here. + +CONFIG_HDLC_CISCO + Say Y to this option if you want generic HDLC driver to support + Cisco HDLC over WAN (Wide Area Network) connections. + + If unsure, say N here. + +CONFIG_HDLC_FR + Say Y to this option if you want generic HDLC driver to support + Frame-Relay protocol over WAN (Wide Area Network) connections. + + If unsure, say N here. + CONFIG_HDLC_PPP Say Y to this option if you want generic HDLC driver to support PPP over WAN (Wide Area Network) connections. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/Config.in linux-2.5/drivers/net/wan/Config.in --- linux-2.5.20/drivers/net/wan/Config.in Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/net/wan/Config.in Mon May 6 13:57:06 2002 @@ -47,6 +47,12 @@ tristate ' LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA +# +# ATI's sync/async boards. Currently 2520, 4020, 4520, 8520 -- 0 in second digit means async only +# + + tristate ' Aurora Technology, Inc. synchronous asynchronous PCI cards V2' CONFIG_ATI_XX20 + # There is no way to detect a Sealevel board. Force it modular dep_tristate ' Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/Makefile linux-2.5/drivers/net/wan/Makefile --- linux-2.5.20/drivers/net/wan/Makefile Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/net/wan/Makefile Sat May 25 19:07:44 2002 @@ -51,6 +51,13 @@ obj-$(CONFIG_LANMEDIA) += lmc/ +subdir-$(CONFIG_ATI_XX20) += 8253x + +ifeq ($(CONFIG_ATI_XX20),y) + obj-y += 8253x/ASLX.o +endif + + obj-$(CONFIG_DLCI) += dlci.o obj-$(CONFIG_SDLA) += sdla.o ifeq ($(CONFIG_WANPIPE_MULTPPP),y) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/farsync.c linux-2.5/drivers/net/wan/farsync.c --- linux-2.5.20/drivers/net/wan/farsync.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/net/wan/farsync.c Sat May 25 19:52:05 2002 @@ -1466,10 +1466,6 @@ + BUF_OFFSET ( txBuffer[i][0][0]); dev->mem_end = card->phys_mem + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]); - dev->rmem_start = card->phys_mem - + BUF_OFFSET ( rxBuffer[i][0][0]); - dev->rmem_end = card->phys_mem - + BUF_OFFSET ( rxBuffer[i][NUM_RX_BUFFER][0]); dev->base_addr = card->pci_conf; dev->irq = card->irq; @@ -1528,6 +1524,13 @@ } memset ( card, 0, sizeof ( struct fst_card_info )); + /* Try to enable the device */ + if (( err = pci_enable_device ( pdev )) != 0 ) + { + printk_err ("Failed to enable card. Err %d\n", -err ); + goto error_free_card; + } + /* Record info we need*/ card->irq = pdev->irq; card->pci_conf = pci_resource_start ( pdev, 1 ); @@ -1567,12 +1570,6 @@ goto error_release_mem; } - /* Try to enable the device */ - if (( err = pci_enable_device ( pdev )) != 0 ) - { - printk_err ("Failed to enable card. Err %d\n", -err ); - goto error_release_ctlmem; - } /* Get virtual addresses of memory regions */ if (( card->mem = ioremap ( card->phys_mem, FST_MEMSIZE )) == NULL ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/hdlc.c linux-2.5/drivers/net/wan/hdlc.c --- linux-2.5.20/drivers/net/wan/hdlc.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/net/wan/hdlc.c Sun Mar 3 20:15:15 2002 @@ -0,0 +1,1461 @@ +/* + * Generic HDLC support routines for Linux + * + * Copyright (C) 1999, 2000 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Current status: + * - this is work in progress + * - not heavily tested on SMP + * - currently supported: + * * raw IP-in-HDLC + * * Cisco HDLC + * * Frame Relay with ANSI or CCITT LMI (both user and network side) + * * PPP (using syncppp.c) + * * X.25 + * + * Use sethdlc utility to set line parameters, protocol and PVCs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define DEBUG_PKT */ +/* #define DEBUG_HARD_HEADER */ +/* #define DEBUG_FECN */ +/* #define DEBUG_BECN */ + +static const char* version = "HDLC support module revision 1.02 for Linux 2.4"; + + +#define CISCO_MULTICAST 0x8F /* Cisco multicast address */ +#define CISCO_UNICAST 0x0F /* Cisco unicast address */ +#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ +#define CISCO_SYS_INFO 0x2000 /* Cisco interface/system info */ +#define CISCO_ADDR_REQ 0 /* Cisco address request */ +#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ +#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ + +static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + +/******************************************************** + * + * Cisco HDLC support + * + *******************************************************/ + +static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, + u16 type, void *daddr, void *saddr, + unsigned int len) +{ + hdlc_header *data; +#ifdef DEBUG_HARD_HEADER + printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); +#endif + + skb_push(skb, sizeof(hdlc_header)); + data = (hdlc_header*)skb->data; + if (type == CISCO_KEEPALIVE) + data->address = CISCO_MULTICAST; + else + data->address = CISCO_UNICAST; + data->control = 0; + data->protocol = htons(type); + + return sizeof(hdlc_header); +} + + + +static void cisco_keepalive_send(hdlc_device *hdlc, u32 type, + u32 par1, u32 par2) +{ + struct sk_buff *skb; + cisco_packet *data; + + skb = dev_alloc_skb(sizeof(hdlc_header)+sizeof(cisco_packet)); + if (!skb) { + printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n", + hdlc_to_name(hdlc)); + return; + } + skb_reserve(skb, 4); + cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE, + NULL, NULL, 0); + data = (cisco_packet*)skb->tail; + + data->type = htonl(type); + data->par1 = htonl(par1); + data->par2 = htonl(par2); + data->rel = 0xFFFF; + data->time = htonl(jiffies * 1000 / HZ); + + skb_put(skb, sizeof(cisco_packet)); + skb->priority = TC_PRIO_CONTROL; + skb->dev = hdlc_to_dev(hdlc); + + dev_queue_xmit(skb); +} + + + +static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb) +{ + hdlc_header *data = (hdlc_header*)skb->data; + cisco_packet *cisco_data; + struct in_device *in_dev; + u32 addr, mask; + + if (skb->lenaddress != CISCO_MULTICAST && + data->address != CISCO_UNICAST) + goto rx_error; + + skb_pull(skb, sizeof(hdlc_header)); + + switch(ntohs(data->protocol)) { + case ETH_P_IP: + case ETH_P_IPX: + case ETH_P_IPV6: + skb->protocol = data->protocol; + skb->dev = hdlc_to_dev(hdlc); + skb->dev->last_rx = jiffies; + netif_rx(skb); + return; + + case CISCO_SYS_INFO: + /* Packet is not needed, drop it. */ + dev_kfree_skb_any(skb); + return; + + case CISCO_KEEPALIVE: + if (skb->len != CISCO_PACKET_LEN && + skb->len != CISCO_BIG_PACKET_LEN) { + printk(KERN_INFO "%s: Invalid length of Cisco " + "control packet (%d bytes)\n", + hdlc_to_name(hdlc), skb->len); + goto rx_error; + } + + cisco_data = (cisco_packet*)skb->data; + + switch(ntohl (cisco_data->type)) { + case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ + in_dev = hdlc_to_dev(hdlc)->ip_ptr; + addr = 0; + mask = ~0; /* is the mask correct? */ + + if (in_dev != NULL) { + struct in_ifaddr **ifap = &in_dev->ifa_list; + + while (*ifap != NULL) { + if (strcmp(hdlc_to_name(hdlc), + (*ifap)->ifa_label) == 0) { + addr = (*ifap)->ifa_local; + mask = (*ifap)->ifa_mask; + break; + } + ifap = &(*ifap)->ifa_next; + } + + cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY, + addr, mask); + } + dev_kfree_skb_any(skb); + return; + + case CISCO_ADDR_REPLY: + printk(KERN_INFO "%s: Unexpected Cisco IP address " + "reply\n", hdlc_to_name(hdlc)); + goto rx_error; + + case CISCO_KEEPALIVE_REQ: + hdlc->lmi.rxseq = ntohl(cisco_data->par1); + if (ntohl(cisco_data->par2) == hdlc->lmi.txseq) { + hdlc->lmi.last_poll = jiffies; + if (!(hdlc->lmi.state & LINK_STATE_RELIABLE)) { + u32 sec, min, hrs, days; + sec = ntohl(cisco_data->time) / 1000; + min = sec / 60; sec -= min * 60; + hrs = min / 60; min -= hrs * 60; + days = hrs / 24; hrs -= days * 24; + printk(KERN_INFO "%s: Link up (peer " + "uptime %ud%uh%um%us)\n", + hdlc_to_name(hdlc), days, hrs, + min, sec); + } + hdlc->lmi.state |= LINK_STATE_RELIABLE; + } + + dev_kfree_skb_any(skb); + return; + } /* switch(keepalive type) */ + } /* switch(protocol) */ + + printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc), + data->protocol); + dev_kfree_skb_any(skb); + return; + + rx_error: + hdlc->stats.rx_errors++; /* Mark error */ + dev_kfree_skb_any(skb); +} + + + +static void cisco_timer(unsigned long arg) +{ + hdlc_device *hdlc = (hdlc_device*)arg; + + if ((hdlc->lmi.state & LINK_STATE_RELIABLE) && + (jiffies - hdlc->lmi.last_poll >= hdlc->lmi.T392 * HZ)) { + hdlc->lmi.state &= ~LINK_STATE_RELIABLE; + printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc)); + } + + cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, ++hdlc->lmi.txseq, + hdlc->lmi.rxseq); + hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ; + + hdlc->timer.function = cisco_timer; + hdlc->timer.data = arg; + add_timer(&hdlc->timer); +} + + + +/****************************************************************** + * + * generic Frame Relay routines + * + *****************************************************************/ + + +static int fr_hard_header(struct sk_buff *skb, struct net_device *dev, + u16 type, void *daddr, void *saddr, unsigned int len) +{ + u16 head_len; + + if (!daddr) + daddr = dev->broadcast; + +#ifdef DEBUG_HARD_HEADER + printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name); +#endif + + switch(type) { + case ETH_P_IP: + head_len = 4; + skb_push(skb, head_len); + skb->data[3] = NLPID_IP; + break; + + case ETH_P_IPV6: + head_len = 4; + skb_push(skb, head_len); + skb->data[3] = NLPID_IPV6; + break; + + case LMI_PROTO: + head_len = 4; + skb_push(skb, head_len); + skb->data[3] = LMI_PROTO; + break; + + default: + head_len = 10; + skb_push(skb, head_len); + skb->data[3] = FR_PAD; + skb->data[4] = NLPID_SNAP; + skb->data[5] = FR_PAD; + skb->data[6] = FR_PAD; + skb->data[7] = FR_PAD; + skb->data[8] = type>>8; + skb->data[9] = (u8)type; + } + + memcpy(skb->data, daddr, 2); + skb->data[2] = FR_UI; + + return head_len; +} + + + +static inline void fr_log_dlci_active(pvc_device *pvc) +{ + printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc), + pvc->state & PVC_STATE_ACTIVE ? "" : "in", + pvc->state & PVC_STATE_NEW ? " new" : ""); +} + + + +static inline u8 fr_lmi_nextseq(u8 x) +{ + x++; + return x ? x : 1; +} + + + +static void fr_lmi_send(hdlc_device *hdlc, int fullrep) +{ + struct sk_buff *skb; + pvc_device *pvc = hdlc->first_pvc; + int len = mode_is(hdlc, MODE_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH; + int stat_len = 3; + u8 *data; + int i = 0; + + if (mode_is(hdlc, MODE_DCE) && fullrep) { + len += hdlc->pvc_count * (2 + stat_len); + if (len > HDLC_MAX_MTU) { + printk(KERN_WARNING "%s: Too many PVCs while sending " + "LMI full report\n", hdlc_to_name(hdlc)); + return; + } + } + + skb = dev_alloc_skb(len); + if (!skb) { + printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n", + hdlc_to_name(hdlc)); + return; + } + memset(skb->data, 0, len); + skb_reserve(skb, 4); + fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0); + data = skb->tail; + data[i++] = LMI_CALLREF; + data[i++] = mode_is(hdlc, MODE_DCE) ? LMI_STATUS : LMI_STATUS_ENQUIRY; + if (mode_is(hdlc, MODE_FR_ANSI)) + data[i++] = LMI_ANSI_LOCKSHIFT; + data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : + LMI_REPTYPE; + data[i++] = LMI_REPT_LEN; + data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; + + data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE; + data[i++] = LMI_INTEG_LEN; + data[i++] = hdlc->lmi.txseq = fr_lmi_nextseq(hdlc->lmi.txseq); + data[i++] = hdlc->lmi.rxseq; + + if (mode_is(hdlc, MODE_DCE) && fullrep) { + while (pvc) { + data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? + LMI_CCITT_PVCSTAT:LMI_PVCSTAT; + data[i++] = stat_len; + + if ((hdlc->lmi.state & LINK_STATE_RELIABLE) && + (pvc->netdev.flags & IFF_UP) && + !(pvc->state & (PVC_STATE_ACTIVE|PVC_STATE_NEW))) { + pvc->state |= PVC_STATE_NEW; + fr_log_dlci_active(pvc); + } + + dlci_to_status(hdlc, netdev_dlci(&pvc->netdev), + data+i, pvc->state); + i += stat_len; + pvc = pvc->next; + } + } + + skb_put(skb, i); + skb->priority = TC_PRIO_CONTROL; + skb->dev = hdlc_to_dev(hdlc); + + dev_queue_xmit(skb); +} + + + +static void fr_timer(unsigned long arg) +{ + hdlc_device *hdlc = (hdlc_device*)arg; + int i, cnt = 0, reliable; + u32 list; + + if (mode_is(hdlc, MODE_DCE)) + reliable = (jiffies - hdlc->lmi.last_poll < hdlc->lmi.T392*HZ); + else { + hdlc->lmi.last_errors <<= 1; /* Shift the list */ + if (hdlc->lmi.state & LINK_STATE_REQUEST) { + printk(KERN_INFO "%s: No LMI status reply received\n", + hdlc_to_name(hdlc)); + hdlc->lmi.last_errors |= 1; + } + + for (i = 0, list = hdlc->lmi.last_errors; i < hdlc->lmi.N393; + i++, list >>= 1) + cnt += (list & 1); /* errors count */ + + reliable = (cnt < hdlc->lmi.N392); + } + + if ((hdlc->lmi.state & LINK_STATE_RELIABLE) != + (reliable ? LINK_STATE_RELIABLE : 0)) { + pvc_device *pvc = hdlc->first_pvc; + + while (pvc) {/* Deactivate all PVCs */ + pvc->state &= ~(PVC_STATE_NEW | PVC_STATE_ACTIVE); + pvc = pvc->next; + } + + hdlc->lmi.state ^= LINK_STATE_RELIABLE; + printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc), + reliable ? "" : "un"); + + if (reliable) { + hdlc->lmi.N391cnt = 0; /* Request full status */ + hdlc->lmi.state |= LINK_STATE_CHANGED; + } + } + + if (mode_is(hdlc, MODE_DCE)) + hdlc->timer.expires = jiffies + hdlc->lmi.T392*HZ; + else { + if (hdlc->lmi.N391cnt) + hdlc->lmi.N391cnt--; + + fr_lmi_send(hdlc, hdlc->lmi.N391cnt == 0); + + hdlc->lmi.state |= LINK_STATE_REQUEST; + hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ; + } + + hdlc->timer.function = fr_timer; + hdlc->timer.data = arg; + add_timer(&hdlc->timer); +} + + + +static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) +{ + int stat_len; + pvc_device *pvc; + int reptype = -1, error; + u8 rxseq, txseq; + int i; + + if (skb->len < (mode_is(hdlc, MODE_FR_ANSI) ? + LMI_ANSI_LENGTH : LMI_LENGTH)) { + printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc)); + return 1; + } + + if (skb->data[5] != (!mode_is(hdlc, MODE_DCE) ? + LMI_STATUS : LMI_STATUS_ENQUIRY)) { + printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n", + hdlc_to_name(hdlc), skb->data[2], + mode_is(hdlc, MODE_DCE) ? "enquiry" : "reply"); + return 1; + } + + i = mode_is(hdlc, MODE_FR_ANSI) ? 7 : 6; + + if (skb->data[i] != + (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) { + printk(KERN_INFO "%s: Not a report type=%x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + i++; /* Skip length field */ + + reptype = skb->data[i++]; + + if (skb->data[i]!= + (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) { + printk(KERN_INFO "%s: Unsupported status element=%x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + i++; /* Skip length field */ + + hdlc->lmi.rxseq = skb->data[i++]; /* TX sequence from peer */ + rxseq = skb->data[i++]; /* Should confirm our sequence */ + + txseq = hdlc->lmi.txseq; + + if (mode_is(hdlc, MODE_DCE)) { + if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) { + printk(KERN_INFO "%s: Unsupported report type=%x\n", + hdlc_to_name(hdlc), reptype); + return 1; + } + } + + error = 0; + if (!(hdlc->lmi.state & LINK_STATE_RELIABLE)) + error = 1; + + if (rxseq == 0 || rxseq != txseq) { + hdlc->lmi.N391cnt = 0; /* Ask for full report next time */ + error = 1; + } + + if (mode_is(hdlc, MODE_DCE)) { + if ((hdlc->lmi.state & LINK_STATE_FULLREP_SENT) && !error) { +/* Stop sending full report - the last one has been confirmed by DTE */ + hdlc->lmi.state &= ~LINK_STATE_FULLREP_SENT; + pvc = hdlc->first_pvc; + while (pvc) { + if (pvc->state & PVC_STATE_NEW) { + pvc->state &= ~PVC_STATE_NEW; + pvc->state |= PVC_STATE_ACTIVE; + fr_log_dlci_active(pvc); + +/* Tell DTE that new PVC is now active */ + hdlc->lmi.state |= LINK_STATE_CHANGED; + } + pvc = pvc->next; + } + } + + if (hdlc->lmi.state & LINK_STATE_CHANGED) { + reptype = LMI_FULLREP; + hdlc->lmi.state |= LINK_STATE_FULLREP_SENT; + hdlc->lmi.state &= ~LINK_STATE_CHANGED; + } + + fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0); + return 0; + } + + /* DTE */ + + if (reptype != LMI_FULLREP || error) + return 0; + + stat_len = 3; + pvc = hdlc->first_pvc; + + while (pvc) { + pvc->newstate = 0; + pvc = pvc->next; + } + + while (skb->len >= i + 2 + stat_len) { + u16 dlci; + u8 state = 0; + + if (skb->data[i] != (mode_is(hdlc, MODE_FR_CCITT) ? + LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) { + printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + if (skb->data[i] != stat_len) { + printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + dlci = status_to_dlci(hdlc, skb->data+i, &state); + pvc = find_pvc(hdlc, dlci); + + if (pvc) + pvc->newstate = state; + else if (state == PVC_STATE_NEW) + printk(KERN_INFO "%s: new PVC available, DLCI=%u\n", + hdlc_to_name(hdlc), dlci); + + i += stat_len; + } + + pvc = hdlc->first_pvc; + + while (pvc) { + if (pvc->newstate == PVC_STATE_NEW) + pvc->newstate = PVC_STATE_ACTIVE; + + pvc->newstate |= (pvc->state & + ~(PVC_STATE_NEW|PVC_STATE_ACTIVE)); + if (pvc->state != pvc->newstate) { + pvc->state = pvc->newstate; + fr_log_dlci_active(pvc); + } + pvc = pvc->next; + } + + /* Next full report after N391 polls */ + hdlc->lmi.N391cnt = hdlc->lmi.N391; + + return 0; +} + + + +static void fr_netif(hdlc_device *hdlc, struct sk_buff *skb) +{ + fr_hdr *fh = (fr_hdr*)skb->data; + u8 *data = skb->data; + u16 dlci; + pvc_device *pvc; + + if (skb->len<4 || fh->ea1 || data[2] != FR_UI) + goto rx_error; + + dlci = q922_to_dlci(skb->data); + + if (dlci == LMI_DLCI) { + if (data[3] == LMI_PROTO) { + if (fr_lmi_recv(hdlc, skb)) + goto rx_error; + else { + /* No request pending */ + hdlc->lmi.state &= ~LINK_STATE_REQUEST; + hdlc->lmi.last_poll = jiffies; + dev_kfree_skb_any(skb); + return; + } + } + + printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n", + hdlc_to_name(hdlc)); + goto rx_error; + } + + pvc = find_pvc(hdlc, dlci); + if (!pvc) { +#ifdef DEBUG_PKT + printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", + hdlc_to_name(hdlc), dlci); +#endif + goto rx_error; + } + + if ((pvc->netdev.flags & IFF_UP) == 0) { +#ifdef DEBUG_PKT + printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n", + hdlc_to_name(hdlc), dlci); +#endif + goto rx_error; + } + + pvc->stats.rx_packets++; /* PVC traffic */ + pvc->stats.rx_bytes += skb->len; + + if ((pvc->state & PVC_STATE_FECN) != (fh->fecn ? PVC_STATE_FECN : 0)) { +#ifdef DEBUG_FECN + printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc), + fh->fecn ? "N" : "FF"); +#endif + pvc->state ^= PVC_STATE_FECN; + } + + if ((pvc->state & PVC_STATE_BECN) != (fh->becn ? PVC_STATE_BECN : 0)) { +#ifdef DEBUG_FECN + printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc), + fh->becn ? "N" : "FF"); +#endif + pvc->state ^= PVC_STATE_BECN; + } + + if (pvc->state & PVC_STATE_BECN) + pvc->stats.rx_compressed++; + + if (data[3] == NLPID_IP) { + skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ + skb->protocol = htons(ETH_P_IP); + skb->dev = &pvc->netdev; + skb->dev->last_rx = jiffies; + netif_rx(skb); + return; + } + + + if (data[3] == NLPID_IPV6) { + skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ + skb->protocol = htons(ETH_P_IPV6); + skb->dev = &pvc->netdev; + skb->dev->last_rx = jiffies; + netif_rx(skb); + return; + } + + if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD && + data[6] == FR_PAD && data[7] == FR_PAD && + ((data[8]<<8) | data[9]) == ETH_P_ARP) { + skb_pull(skb, 10); + skb->protocol = htons(ETH_P_ARP); + skb->dev = &pvc->netdev; + skb->dev->last_rx = jiffies; + netif_rx(skb); + return; + } + + printk(KERN_INFO "%s: Unusupported protocol %x\n", + hdlc_to_name(hdlc), data[3]); + dev_kfree_skb_any(skb); + return; + + rx_error: + hdlc->stats.rx_errors++; /* Mark error */ + dev_kfree_skb_any(skb); +} + + + +static void fr_cisco_open(hdlc_device *hdlc) +{ + hdlc->lmi.state = LINK_STATE_CHANGED; + hdlc->lmi.txseq = hdlc->lmi.rxseq = 0; + hdlc->lmi.last_errors = 0xFFFFFFFF; + hdlc->lmi.N391cnt = 0; + + init_timer(&hdlc->timer); + hdlc->timer.expires = jiffies + HZ; /* First poll after 1 second */ + hdlc->timer.function = mode_is(hdlc, MODE_FR) ? fr_timer : cisco_timer; + hdlc->timer.data = (unsigned long)hdlc; + add_timer(&hdlc->timer); +} + + + +static void fr_cisco_close(hdlc_device *hdlc) +{ + pvc_device *pvc = hdlc->first_pvc; + + del_timer_sync(&hdlc->timer); + + while(pvc) { /* NULL in Cisco mode */ + dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */ + pvc = pvc->next; + } +} + + + +/****************************************************************** + * + * generic HDLC routines + * + *****************************************************************/ + + + +static int hdlc_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + + + +/******************************************************** + * + * PVC device routines + * + *******************************************************/ + +static int pvc_open(struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + int result = 0; + + if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0) + return -EIO; /* Master must be UP in order to activate PVC */ + + memset(&(pvc->stats), 0, sizeof(struct net_device_stats)); + pvc->state = 0; + + if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->open_pvc) + result = pvc->master->open_pvc(pvc); + if (result) + return result; + + pvc->master->lmi.state |= LINK_STATE_CHANGED; + return 0; +} + + + +static int pvc_close(struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + pvc->state = 0; + + if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->close_pvc) + pvc->master->close_pvc(pvc); + + pvc->master->lmi.state |= LINK_STATE_CHANGED; + return 0; +} + + + +static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + + if (pvc->state & PVC_STATE_ACTIVE) { + skb->dev = hdlc_to_dev(pvc->master); + pvc->stats.tx_bytes += skb->len; + pvc->stats.tx_packets++; + if (pvc->state & PVC_STATE_FECN) + pvc->stats.tx_compressed++; /* TX Congestion counter */ + dev_queue_xmit(skb); + } else { + pvc->stats.tx_dropped++; + dev_kfree_skb(skb); + } + + return 0; +} + + + +static struct net_device_stats *pvc_get_stats(struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + return &pvc->stats; +} + + + +static int pvc_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + + + +static void destroy_pvc_list(hdlc_device *hdlc) +{ + pvc_device *pvc = hdlc->first_pvc; + while(pvc) { + pvc_device *next = pvc->next; + unregister_netdevice(&pvc->netdev); + kfree(pvc); + pvc = next; + } + + hdlc->first_pvc = NULL; /* All PVCs destroyed */ + hdlc->pvc_count = 0; + hdlc->lmi.state |= LINK_STATE_CHANGED; +} + + + +/******************************************************** + * + * X.25 protocol support routines + * + *******************************************************/ + +#ifdef CONFIG_HDLC_X25 +/* These functions are callbacks called by LAPB layer */ + +void x25_connect_disconnect(void *token, int reason, int code) +{ + hdlc_device *hdlc = token; + struct sk_buff *skb; + unsigned char *ptr; + + if ((skb = dev_alloc_skb(1)) == NULL) { + printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc)); + return; + } + + ptr = skb_put(skb, 1); + *ptr = code; + + skb->dev = hdlc_to_dev(hdlc); + skb->protocol = htons(ETH_P_X25); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_HOST; + + skb->dev->last_rx = jiffies; + netif_rx(skb); +} + +void x25_connected(void *token, int reason) +{ + x25_connect_disconnect(token, reason, 1); +} + +void x25_disconnected(void *token, int reason) +{ + x25_connect_disconnect(token, reason, 2); +} + + +int x25_data_indication(void *token, struct sk_buff *skb) +{ + hdlc_device *hdlc = token; + unsigned char *ptr; + + ptr = skb_push(skb, 1); + *ptr = 0; + + skb->dev = hdlc_to_dev(hdlc); + skb->protocol = htons(ETH_P_X25); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_HOST; + + skb->dev->last_rx = jiffies; + return netif_rx(skb); +} + + +void x25_data_transmit(void *token, struct sk_buff *skb) +{ + hdlc_device *hdlc = token; + hdlc->xmit(hdlc, skb); /* Ignore return value :-( */ +} +#endif /* CONFIG_HDLC_X25 */ + + +/******************************************************** + * + * HDLC device routines + * + *******************************************************/ + +static int hdlc_open(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + int result; + + if (hdlc->mode == MODE_NONE) + return -ENOSYS; + + memset(&(hdlc->stats), 0, sizeof(struct net_device_stats)); + + if (mode_is(hdlc, MODE_FR | MODE_SOFT) || + mode_is(hdlc, MODE_CISCO | MODE_SOFT)) + fr_cisco_open(hdlc); +#ifdef CONFIG_HDLC_PPP + else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) { + sppp_attach(&hdlc->pppdev); + /* sppp_attach nukes them. We don't need syncppp's ioctl */ + dev->do_ioctl = hdlc_ioctl; + hdlc->pppdev.sppp.pp_flags &= ~PP_CISCO; + dev->type = ARPHRD_PPP; + result = sppp_open(dev); + if (result) { + sppp_detach(dev); + return result; + } + } +#endif +#ifdef CONFIG_HDLC_X25 + else if (mode_is(hdlc, MODE_X25)) { + struct lapb_register_struct cb; + + cb.connect_confirmation = x25_connected; + cb.connect_indication = x25_connected; + cb.disconnect_confirmation = x25_disconnected; + cb.disconnect_indication = x25_disconnected; + cb.data_indication = x25_data_indication; + cb.data_transmit = x25_data_transmit; + + result = lapb_register(hdlc, &cb); + if (result != LAPB_OK) + return result; + } +#endif + result = hdlc->open(hdlc); + if (result) { + if (mode_is(hdlc, MODE_FR | MODE_SOFT) || + mode_is(hdlc, MODE_CISCO | MODE_SOFT)) + fr_cisco_close(hdlc); +#ifdef CONFIG_HDLC_PPP + else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) { + sppp_close(dev); + sppp_detach(dev); + dev->rebuild_header = NULL; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + dev->hard_header_len = 16; + } +#endif +#ifdef CONFIG_HDLC_X25 + else if (mode_is(hdlc, MODE_X25)) + lapb_unregister(hdlc); +#endif + } + + return result; +} + + + +static int hdlc_close(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + hdlc->close(hdlc); + + if (mode_is(hdlc, MODE_FR | MODE_SOFT) || + mode_is(hdlc, MODE_CISCO | MODE_SOFT)) + fr_cisco_close(hdlc); +#ifdef CONFIG_HDLC_PPP + else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) { + sppp_close(dev); + sppp_detach(dev); + dev->rebuild_header = NULL; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + dev->hard_header_len = 16; + } +#endif +#ifdef CONFIG_HDLC_X25 + else if (mode_is(hdlc, MODE_X25)) + lapb_unregister(hdlc); +#endif + return 0; +} + + + +static int hdlc_xmit(struct sk_buff *skb, struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + +#ifdef CONFIG_HDLC_X25 + if (mode_is(hdlc, MODE_X25 | MODE_SOFT)) { + int result; + + + /* X.25 to LAPB */ + switch (skb->data[0]) { + case 0: /* Data to be transmitted */ + skb_pull(skb, 1); + if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK) + dev_kfree_skb(skb); + return 0; + + case 1: + if ((result = lapb_connect_request(hdlc))!= LAPB_OK) { + if (result == LAPB_CONNECTED) { + /* Send connect confirm. msg to level 3 */ + x25_connected(hdlc, 0); + } else { + printk(KERN_ERR "%s: LAPB connect " + "request failed, error code = " + "%i\n", hdlc_to_name(hdlc), + result); + } + } + break; + + case 2: + if ((result=lapb_disconnect_request(hdlc))!=LAPB_OK) { + if (result == LAPB_NOTCONNECTED) { + /* Send disconnect confirm. msg to level 3 */ + x25_disconnected(hdlc, 0); + } else { + printk(KERN_ERR "%s: LAPB disconnect " + "request failed, error code = " + "%i\n", hdlc_to_name(hdlc), + result); + } + } + break; + + default: + /* to be defined */ + break; + } + + dev_kfree_skb(skb); + return 0; + } /* MODE_X25 */ +#endif /* CONFIG_HDLC_X25 */ + + return hdlc->xmit(hdlc, skb); +} + + + +void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb) +{ +/* skb contains raw HDLC frame, in both hard- and software modes */ + skb->mac.raw = skb->data; + + switch(hdlc->mode & MODE_MASK) { + case MODE_HDLC: + skb->protocol = htons(ETH_P_IP); + skb->dev = hdlc_to_dev(hdlc); + skb->dev->last_rx = jiffies; + netif_rx(skb); + return; + + case MODE_FR: + fr_netif(hdlc, skb); + return; + + case MODE_CISCO: + cisco_netif(hdlc, skb); + return; + +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: +#if 0 + sppp_input(hdlc_to_dev(hdlc), skb); +#else + skb->protocol = htons(ETH_P_WAN_PPP); + skb->dev = hdlc_to_dev(hdlc); + skb->dev->last_rx = jiffies; + netif_rx(skb); +#endif + return; +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: + skb->dev = hdlc_to_dev(hdlc); + if (lapb_data_received(hdlc, skb) == LAPB_OK) + return; + break; +#endif + } + + hdlc->stats.rx_errors++; + dev_kfree_skb_any(skb); +} + + + +static struct net_device_stats *hdlc_get_stats(struct net_device *dev) +{ + return &dev_to_hdlc(dev)->stats; +} + + + +static int hdlc_set_mode(hdlc_device *hdlc, int mode) +{ + int result = -1; /* Default to soft modes */ + struct net_device *dev = hdlc_to_dev(hdlc); + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + if(dev->flags & IFF_UP) + return -EBUSY; + + dev->addr_len = 0; + dev->hard_header = NULL; + hdlc->mode = MODE_NONE; + + if (!(mode & MODE_SOFT)) + switch(mode & MODE_MASK) { + case MODE_HDLC: + result = hdlc->set_mode ? + hdlc->set_mode(hdlc, MODE_HDLC) : 0; + break; + + case MODE_CISCO: /* By card */ +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: +#endif + case MODE_FR: + result = hdlc->set_mode ? + hdlc->set_mode(hdlc, mode) : -ENOSYS; + break; + + default: + return -EINVAL; + } + + if (result) { + mode |= MODE_SOFT; /* Try "host software" protocol */ + + switch(mode & MODE_MASK) { + case MODE_CISCO: + dev->hard_header = cisco_hard_header; + break; + +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: + break; +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: + break; +#endif + + case MODE_FR: + dev->hard_header = fr_hard_header; + dev->addr_len = 2; + *(u16*)dev->dev_addr = htons(LMI_DLCI); + dlci_to_q922(dev->broadcast, LMI_DLCI); + break; + + default: + return -EINVAL; + } + + result = hdlc->set_mode ? + hdlc->set_mode(hdlc, MODE_HDLC) : 0; + } + + if (result) + return result; + + hdlc->mode = mode; + switch(mode & MODE_MASK) { +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: dev->type = ARPHRD_PPP; break; +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: dev->type = ARPHRD_X25; break; +#endif + case MODE_FR: dev->type = ARPHRD_FRAD; break; + case MODE_CISCO: dev->type = ARPHRD_CISCO; break; + default: dev->type = ARPHRD_RAWHDLC; + } + + memset(&(hdlc->stats), 0, sizeof(struct net_device_stats)); + destroy_pvc_list(hdlc); + return 0; +} + + + +static int hdlc_fr_pvc(hdlc_device *hdlc, int dlci) +{ + pvc_device **pvc_p = &hdlc->first_pvc; + pvc_device *pvc; + int result, create = 1; /* Create or delete PVC */ + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + if(dlci<0) { + dlci = -dlci; + create = 0; + } + + if(dlci <= 0 || dlci >= 1024) + return -EINVAL; /* Only 10 bits for DLCI, DLCI=0 is reserved */ + + if(!mode_is(hdlc, MODE_FR)) + return -EINVAL; /* Only meaningfull on FR */ + + while(*pvc_p) { + if (netdev_dlci(&(*pvc_p)->netdev) == dlci) + break; + pvc_p = &(*pvc_p)->next; + } + + if (create) { /* Create PVC */ + if (*pvc_p != NULL) + return -EEXIST; + + pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL); + if (!pvc) { + printk(KERN_WARNING "%s: Memory squeeze on " + "hdlc_fr_pvc()\n", hdlc_to_name(hdlc)); + return -ENOBUFS; + } + memset(pvc, 0, sizeof(pvc_device)); + + pvc->netdev.hard_start_xmit = pvc_xmit; + pvc->netdev.get_stats = pvc_get_stats; + pvc->netdev.open = pvc_open; + pvc->netdev.stop = pvc_close; + pvc->netdev.change_mtu = pvc_change_mtu; + pvc->netdev.mtu = HDLC_MAX_MTU; + + pvc->netdev.type = ARPHRD_DLCI; + pvc->netdev.hard_header_len = 16; + pvc->netdev.hard_header = fr_hard_header; + pvc->netdev.tx_queue_len = 0; + pvc->netdev.flags = IFF_POINTOPOINT; + + pvc->master = hdlc; + *(u16*)pvc->netdev.dev_addr = htons(dlci); + dlci_to_q922(pvc->netdev.broadcast, dlci); + pvc->netdev.addr_len = 2; + pvc->netdev.irq = hdlc_to_dev(hdlc)->irq; + + result = dev_alloc_name(&pvc->netdev, "pvc%d"); + if (result < 0) { + kfree(pvc); + *pvc_p = NULL; + return result; + } + + if (register_netdevice(&pvc->netdev) != 0) { + kfree(pvc); + *pvc_p = NULL; + return -EIO; + } + + if (!mode_is(hdlc, MODE_SOFT) && hdlc->create_pvc) { + result = hdlc->create_pvc(pvc); + if (result) { + unregister_netdevice(&pvc->netdev); + kfree(pvc); + *pvc_p = NULL; + return result; + } + } + + hdlc->lmi.state |= LINK_STATE_CHANGED; + hdlc->pvc_count++; + return 0; + } + + if (*pvc_p == NULL) /* Delete PVC */ + return -ENOENT; + + pvc = *pvc_p; + + if (pvc->netdev.flags & IFF_UP) + return -EBUSY; /* PVC in use */ + + if (!mode_is(hdlc, MODE_SOFT) && hdlc->destroy_pvc) + hdlc->destroy_pvc(pvc); + + hdlc->lmi.state |= LINK_STATE_CHANGED; + hdlc->pvc_count--; + *pvc_p = pvc->next; + unregister_netdevice(&pvc->netdev); + kfree(pvc); + return 0; +} + + + +static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + switch(cmd) { + case HDLCGMODE: + ifr->ifr_ifru.ifru_ivalue = hdlc->mode; + return 0; + + case HDLCSMODE: + return hdlc_set_mode(hdlc, ifr->ifr_ifru.ifru_ivalue); + + case HDLCPVC: + return hdlc_fr_pvc(hdlc, ifr->ifr_ifru.ifru_ivalue); + + default: + if (hdlc->ioctl != NULL) + return hdlc->ioctl(hdlc, ifr, cmd); + } + + return -EINVAL; +} + + + +static int hdlc_init(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + memset(&(hdlc->stats), 0, sizeof(struct net_device_stats)); + + dev->get_stats = hdlc_get_stats; + dev->open = hdlc_open; + dev->stop = hdlc_close; + dev->hard_start_xmit = hdlc_xmit; + dev->do_ioctl = hdlc_ioctl; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + + dev->type = ARPHRD_RAWHDLC; + dev->hard_header_len = 16; + + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + + return 0; +} + + + +int register_hdlc_device(hdlc_device *hdlc) +{ + int result; + struct net_device *dev = hdlc_to_dev(hdlc); + + dev->init = hdlc_init; + dev->priv = &hdlc->syncppp_ptr; + hdlc->syncppp_ptr = &hdlc->pppdev; + hdlc->pppdev.dev = dev; + hdlc->mode = MODE_NONE; + hdlc->lmi.T391 = 10; /* polling verification timer */ + hdlc->lmi.T392 = 15; /* link integrity verification polling timer */ + hdlc->lmi.N391 = 6; /* full status polling counter */ + hdlc->lmi.N392 = 3; /* error threshold */ + hdlc->lmi.N393 = 4; /* monitored events count */ + + result = dev_alloc_name(dev, "hdlc%d"); + if (result<0) + return result; + + result = register_netdev(dev); + if (result != 0) + return -EIO; + + MOD_INC_USE_COUNT; + return 0; +} + + + +void unregister_hdlc_device(hdlc_device *hdlc) +{ + destroy_pvc_list(hdlc); + unregister_netdev(hdlc_to_dev(hdlc)); + MOD_DEC_USE_COUNT; +} + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("HDLC support module"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(hdlc_netif_rx); +EXPORT_SYMBOL(register_hdlc_device); +EXPORT_SYMBOL(unregister_hdlc_device); + +static int __init hdlc_module_init(void) +{ + printk(KERN_INFO "%s\n", version); + return 0; +} + + +module_init(hdlc_module_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/lapbether.c linux-2.5/drivers/net/wan/lapbether.c --- linux-2.5.20/drivers/net/wan/lapbether.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/net/wan/lapbether.c Sat May 25 19:52:05 2002 @@ -170,6 +170,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; return netif_rx(skb); } @@ -264,6 +265,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; netif_rx(skb); } @@ -286,6 +288,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; netif_rx(skb); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/lmc/lmc_debug.c linux-2.5/drivers/net/wan/lmc/lmc_debug.c --- linux-2.5.20/drivers/net/wan/lmc/lmc_debug.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/net/wan/lmc/lmc_debug.c Wed Mar 27 13:07:16 2002 @@ -72,12 +72,12 @@ if(in_interrupt()){ printk("%s: * %s\n", dev->name, msg); -// while(jiffies < j+10) +// while(time_before(jiffies, j+10)) // ; } else { printk("%s: %s\n", dev->name, msg); - while(jiffies < j) + while(time_before(jiffies, j)) schedule(); } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/lmc/lmc_proto.c linux-2.5/drivers/net/wan/lmc/lmc_proto.c --- linux-2.5.20/drivers/net/wan/lmc/lmc_proto.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/net/wan/lmc/lmc_proto.c Sun Mar 3 20:15:15 2002 @@ -254,6 +254,7 @@ case LMC_PPP: case LMC_NET: default: + skb->dev->last_rx = jiffies; netif_rx(skb); break; case LMC_RAW: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/lmc/lmc_var.h linux-2.5/drivers/net/wan/lmc/lmc_var.h --- linux-2.5.20/drivers/net/wan/lmc/lmc_var.h Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/net/wan/lmc/lmc_var.h Thu May 2 23:29:43 2002 @@ -87,7 +87,7 @@ lmc_delay(); \ LMC_CSR_WRITE((sc), csr_9, 0x30000); \ lmc_delay(); \ - n--; }} while(0); + n--; }} while(0) struct lmc_regfile_t { lmc_csrptr_t csr_busmode; /* CSR0 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/sbni.c linux-2.5/drivers/net/wan/sbni.c --- linux-2.5.20/drivers/net/wan/sbni.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/net/wan/sbni.c Sun May 26 01:09:33 2002 @@ -203,7 +203,7 @@ sbni_isa_probe( struct net_device *dev ) { if( dev->base_addr > 0x1ff - && !check_region( dev->base_addr, SBNI_IO_EXTENT ) + && request_region( dev->base_addr, SBNI_IO_EXTENT, dev->name ) && sbni_probe1( dev, dev->base_addr, dev->irq ) ) return 0; @@ -258,7 +258,7 @@ for( i = 0; netcard_portlist[ i ]; ++i ) { int ioaddr = netcard_portlist[ i ]; - if( !check_region( ioaddr, SBNI_IO_EXTENT ) + if( request_region( ioaddr, SBNI_IO_EXTENT, dev->name ) && sbni_probe1( dev, ioaddr, 0 )) return 0; } @@ -289,7 +289,7 @@ pci_irq_line = pdev->irq; /* Avoid already found cards from previous calls */ - if( check_region( pci_ioaddr, SBNI_IO_EXTENT ) ) { + if( !pci_request_region( pci_ioaddr, SBNI_IO_EXTENT, dev->name ) ) { pci_read_config_word( pdev, PCI_SUBSYSTEM_ID, &subsys ); if( subsys != 2 || /* Dual adapter is present */ check_region( pci_ioaddr += 4, SBNI_IO_EXTENT ) ) @@ -318,9 +318,6 @@ sbni_probe1( struct net_device *dev, unsigned long ioaddr, int irq ) { struct net_local *nl; - - if( !request_region( ioaddr, SBNI_IO_EXTENT, dev->name ) ) - return 0; if( sbni_card_probe( ioaddr ) ) { release_region( ioaddr, SBNI_IO_EXTENT ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/sdla_chdlc.c linux-2.5/drivers/net/wan/sdla_chdlc.c --- linux-2.5.20/drivers/net/wan/sdla_chdlc.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/net/wan/sdla_chdlc.c Fri May 3 03:49:07 2002 @@ -2230,6 +2230,7 @@ skb->dev = dev; skb->mac.raw = skb->data; netif_rx(skb); + dev->last_rx = jiffies; } rx_exit: @@ -3287,6 +3288,7 @@ new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + dev->last_rx = jiffies; } else { printk(KERN_INFO "%s: no socket buffers available!\n", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/sdla_fr.c linux-2.5/drivers/net/wan/sdla_fr.c --- linux-2.5.20/drivers/net/wan/sdla_fr.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/net/wan/sdla_fr.c Fri May 3 03:49:07 2002 @@ -162,14 +162,9 @@ #include /* frame relay firmware API definitions */ -#if defined(LINUX_2_1) || defined(LINUX_2_4) - #include - #include - #include - -#else - #include -#endif +#include +#include +#include #include /* Dynamic Route Creation */ #include /* eth_type_trans() used for bridging */ @@ -2357,6 +2352,7 @@ /* Send a packed up the IP stack */ + skb->dev->last_rx = jiffies; netif_rx(skb); ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; ++chan->ifstats.rx_packets; @@ -2815,7 +2811,7 @@ chan->name, NIPQUAD(chan->ip_remote)); }else { - printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%U\n", + printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%u\n", card->devname,NIPQUAD(chan->ip_remote)); chan->route_flag = ROUTE_ADDED; } @@ -4348,9 +4344,9 @@ card->devname,NIPQUAD(arphdr->ar_sip)); printk(KERN_INFO "%s: mask %u.%u.%u.%u\n", - card->devname, NIPQUAD(in_dev->ida_list->ifa_mask)); + card->devname, NIPQUAD(in_dev->ifa_list->ifa_mask)); printk(KERN_INFO "%s: local %u.%u.%u.%u\n", - card->devname,NIPQUAD(in_dev->ida_list->ifa_local)); + card->devname,NIPQUAD(in_dev->ifa_list->ifa_local)); return -1; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/sdla_ppp.c linux-2.5/drivers/net/wan/sdla_ppp.c --- linux-2.5.20/drivers/net/wan/sdla_ppp.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/net/wan/sdla_ppp.c Fri May 3 03:49:07 2002 @@ -1902,6 +1902,7 @@ #endif ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; netif_rx(skb); + dev->last_rx = jiffies; } } else { @@ -2456,7 +2457,7 @@ #endif default: - printk(KERN_INFO "%s: ERROR: Unsuported PPP Mode Selected\n", + printk(KERN_INFO "%s: ERROR: Unsupported PPP Mode Selected\n", card->devname); printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", card->devname); @@ -2948,6 +2949,7 @@ new_skb->dev = dev; new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + dev->last_rx = jiffies; } else { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/sdlamain.c linux-2.5/drivers/net/wan/sdlamain.c --- linux-2.5.20/drivers/net/wan/sdlamain.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/net/wan/sdlamain.c Fri May 17 02:00:03 2002 @@ -604,7 +604,13 @@ /* Reserve I/O region and schedule background task */ if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) - request_region(card->hw.port, card->hw.io_range, wandev->name); + if (!request_region(card->hw.port, card->hw.io_range, + wandev->name)) { + printk(KERN_WARNING "port 0x%04x busy\n", card->hw.port); + release_hw(card); + wandev->state = WAN_UNCONFIGURED; + return -EBUSY; + } /* Only use the polling routine for the X25 protocol */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/sealevel.c linux-2.5/drivers/net/wan/sealevel.c --- linux-2.5.20/drivers/net/wan/sealevel.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/net/wan/sealevel.c Mon Jan 14 22:39:45 2002 @@ -219,7 +219,7 @@ * Get the needed I/O space */ - if(!request_region(iobase, 8, "Sealevel 4021")) + if(!request_region(iobase, 8, "Sealevel 4021")) { printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); return NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/syncppp.c linux-2.5/drivers/net/wan/syncppp.c --- linux-2.5.20/drivers/net/wan/syncppp.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/net/wan/syncppp.c Sun Mar 3 20:15:16 2002 @@ -275,6 +275,7 @@ printk(KERN_DEBUG "Yow an IP frame.\n"); skb->protocol=htons(ETH_P_IP); netif_rx(skb); + dev->last_rx = jiffies; return; } break; @@ -284,6 +285,7 @@ if (sp->lcp.state == LCP_STATE_OPENED) { skb->protocol=htons(ETH_P_IPX); netif_rx(skb); + dev->last_rx = jiffies; return; } break; @@ -311,12 +313,14 @@ case ETH_P_IP: skb->protocol=htons(ETH_P_IP); netif_rx(skb); + dev->last_rx = jiffies; return; #endif #ifdef CONFIG_IPX case ETH_P_IPX: skb->protocol=htons(ETH_P_IPX); netif_rx(skb); + dev->last_rx = jiffies; return; #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/wanpipe_multppp.c linux-2.5/drivers/net/wan/wanpipe_multppp.c --- linux-2.5.20/drivers/net/wan/wanpipe_multppp.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/net/wan/wanpipe_multppp.c Sun Mar 3 20:15:16 2002 @@ -1572,6 +1572,7 @@ skb->dev = dev; skb->mac.raw = skb->data; netif_rx(skb); + dev->last_rx = jiffies; } rx_exit: @@ -2175,6 +2176,7 @@ new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + dev->last_rx = jiffies; } else { printk(KERN_INFO "%s: no socket buffers available!\n", @@ -2470,6 +2472,7 @@ new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + dev->last_rx = jiffies; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wan/x25_asy.c linux-2.5/drivers/net/wan/x25_asy.c --- linux-2.5.20/drivers/net/wan/x25_asy.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/net/wan/x25_asy.c Sun Mar 3 20:15:16 2002 @@ -250,6 +250,7 @@ else { netif_rx(skb); + sl->dev->last_rx = jiffies; sl->rx_packets++; } } @@ -397,6 +398,7 @@ static int x25_asy_data_indication(void *token, struct sk_buff *skb) { + skb->dev->last_rx = jiffies; return netif_rx(skb); } @@ -449,6 +451,7 @@ skb->pkt_type = PACKET_HOST; netif_rx(skb); + sl->dev->last_rx = jiffies; } static void x25_asy_disconnected(void *token, int reason) @@ -471,6 +474,7 @@ skb->pkt_type = PACKET_HOST; netif_rx(skb); + sl->dev->last_rx = jiffies; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wd.c linux-2.5/drivers/net/wd.c --- linux-2.5.20/drivers/net/wd.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/net/wd.c Fri May 3 12:57:31 2002 @@ -286,7 +286,7 @@ ei_status.rx_start_page = WD_START_PG + TX_PAGES; /* Don't map in the shared memory until the board is actually opened. */ - ei_status.rmem_start = dev->mem_start + TX_PAGES*256; + dev->rmem_start = dev->mem_start + TX_PAGES*256; /* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */ if (dev->mem_end != 0) { @@ -295,7 +295,7 @@ ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG; dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256; } - ei_status.rmem_end = dev->mem_end; + dev->rmem_end = dev->mem_end; printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n", model_name, dev->irq, dev->mem_start, dev->mem_end-1); @@ -389,12 +389,12 @@ int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ unsigned long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8); - if (xfer_start + count > ei_status.rmem_end) { + if (xfer_start + count > dev->rmem_end) { /* We must wrap the input move. */ - int semi_count = ei_status.rmem_end - xfer_start; + int semi_count = dev->rmem_end - xfer_start; isa_memcpy_fromio(skb->data, xfer_start, semi_count); count -= semi_count; - isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count); + isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); } else { /* Packet is in one chunk -- we can copy + cksum. */ isa_eth_io_copy_and_sum(skb, xfer_start, count, 0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wireless/airo_cs.c linux-2.5/drivers/net/wireless/airo_cs.c --- linux-2.5.20/drivers/net/wireless/airo_cs.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/net/wireless/airo_cs.c Mon Jan 14 22:39:45 2002 @@ -244,6 +244,11 @@ /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) { + printk(KERN_ERR "airo_cs: no memory for new device\n"); + kfree (link); + return NULL; + } memset(local, 0, sizeof(local_info_t)); link->priv = local; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wireless/wavelan.c linux-2.5/drivers/net/wireless/wavelan.c --- linux-2.5.20/drivers/net/wireless/wavelan.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/net/wireless/wavelan.c Tue Jan 22 17:43:48 2002 @@ -24,6 +24,28 @@ /*------------------------------------------------------------------*/ /* + * Wrapper for disabling interrupts and locking the driver. + * (note : inline, so optimised away) + */ +static inline void wv_splhi(net_local * lp, + unsigned long * pflags) +{ + spin_lock_irqsave(&lp->spinlock, *pflags); + /* Note : above does the cli(); itself */ +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for re-enabling interrupts and un-locking the driver. + */ +static inline void wv_splx(net_local * lp, + unsigned long * pflags) +{ + spin_unlock_irqrestore(&lp->spinlock, *pflags); +} + +/*------------------------------------------------------------------*/ +/* * Translate irq number to PSA irq parameter */ static u8 wv_irq_to_psa(int irq) @@ -848,10 +870,10 @@ /* Check if we can do it now ! */ if((netif_running(dev)) && !(netif_queue_stopped(dev))) { - spin_lock_irqsave(&lp->spinlock, flags); + wv_splhi(lp, &flags); /* May fail */ wv_82586_config(dev); - spin_unlock_irqrestore(&lp->spinlock, flags); + wv_splx(lp, &flags); } else { #ifdef DEBUG_CONFIG_INFO @@ -1764,287 +1786,170 @@ /*------------------------------------------------------------------*/ /* - * Wireless Handler : get protocol name + * Perform ioctl for configuration and information. + * It is here that the wireless extensions are treated (iwconfig). */ -static int wavelan_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - strcpy(wrqu->name, "WaveLAN"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set NWID - */ -static int wavelan_set_nwid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ +static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is applied */ + struct ifreq *rq, /* data passed */ + int cmd) +{ /* ioctl number */ unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct iwreq *wrq = (struct iwreq *) rq; psa_t psa; mm_t m; unsigned long flags; int ret = 0; + int err = 0; - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Set NWID in WaveLAN. */ - if (!wrqu->nwid.disabled) { - /* Set NWID in psa */ - psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; - psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; - psa.psa_nwid_select = 0x01; - psa_write(ioaddr, lp->hacr, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 3); - - /* Set NWID in mmc. */ - m.w.mmw_netw_id_l = psa.psa_nwid[1]; - m.w.mmw_netw_id_h = psa.psa_nwid[0]; - mmc_write(ioaddr, - (char *) &m.w.mmw_netw_id_l - - (char *) &m, - (unsigned char *) &m.w.mmw_netw_id_l, 2); - mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); - } else { - /* Disable NWID in the psa. */ - psa.psa_nwid_select = 0x00; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_nwid_select - - (char *) &psa, - (unsigned char *) &psa.psa_nwid_select, - 1); - - /* Disable NWID in the mmc (no filtering). */ - mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), - MMW_LOOPT_SEL_DIS_NWID); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get NWID - */ -static int wavelan_get_nwid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Read the NWID. */ - psa_read(ioaddr, lp->hacr, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 3); - wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrqu->nwid.disabled = !(psa.psa_nwid_select); - wrqu->nwid.fixed = 1; /* Superfluous */ - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set frequency - */ -static int wavelan_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - unsigned long flags; - int ret; +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, + cmd); +#endif /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); + wv_splhi(lp, &flags); - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - ret = wv_set_frequency(ioaddr, &(wrqu->freq)); - else - ret = -EOPNOTSUPP; - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} + /* Look what is the request */ + switch (cmd) { + /* --------------- WIRELESS EXTENSIONS --------------- */ + + case SIOCGIWNAME: + strcpy(wrq->u.name, "WaveLAN"); + break; + + case SIOCSIWNWID: + /* Set NWID in WaveLAN. */ + if (!wrq->u.nwid.disabled) { + /* Set NWID in psa */ + psa.psa_nwid[0] = + (wrq->u.nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; + psa.psa_nwid_select = 0x01; + psa_write(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get frequency - */ -static int wavelan_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - psa_t psa; - unsigned long flags; - int ret = 0; + /* Set NWID in mmc. */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(ioaddr, + (char *) &m.w.mmw_netw_id_l - + (char *) &m, + (unsigned char *) &m.w.mmw_netw_id_l, 2); + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); + } else { + /* Disable NWID in the psa. */ + psa.psa_nwid_select = 0x00; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_nwid_select - + (char *) &psa, + (unsigned char *) &psa.psa_nwid_select, + 1); - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). - * Does it work for everybody, especially old cards? */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - unsigned short freq; + /* Disable NWID in the mmc (no filtering). */ + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), + MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + break; - /* Ask the EEPROM to read the frequency from the first area. */ - fee_read(ioaddr, 0x00, &freq, 1); - wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; - wrqu->freq.e = 1; - } else { + case SIOCGIWNWID: + /* Read the NWID. */ psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_subband - (char *) &psa, - (unsigned char *) &psa.psa_subband, 1); - - if (psa.psa_subband <= 4) { - wrqu->freq.m = fixed_bands[psa.psa_subband]; - wrqu->freq.e = (psa.psa_subband != 0); - } else + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + wrq->u.nwid.value = + (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.disabled = !(psa.psa_nwid_select); + wrq->u.nwid.fixed = 1; /* Superfluous */ + break; + + case SIOCSIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(ioaddr, &(wrq->u.freq)); + else ret = -EOPNOTSUPP; - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set level threshold - */ -static int wavelan_set_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Set the level threshold. */ - /* We should complain loudly if wrqu->sens.fixed = 0, because we - * can't set auto mode... */ - psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), - psa.psa_thr_pre_set); - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get level threshold - */ -static int wavelan_get_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Read the level threshold. */ - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; - wrqu->sens.fixed = 1; - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set encryption key - */ -static int wavelan_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - unsigned long flags; - psa_t psa; - int ret = 0; + break; - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); + case SIOCGIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). + * Does it work for everybody, especially old cards? */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); + wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrq->u.freq.e = 1; + } else { + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_subband - (char *) &psa, + (unsigned char *) &psa.psa_subband, 1); + + if (psa.psa_subband <= 4) { + wrq->u.freq.m = + fixed_bands[psa.psa_subband]; + wrq->u.freq.e = (psa.psa_subband != 0); + } else + ret = -EOPNOTSUPP; + } + break; - /* Check if capable of encryption */ - if (!mmc_encr(ioaddr)) { - ret = -EOPNOTSUPP; - } + case SIOCSIWSENS: + /* Set the level threshold. */ + /* We should complain loudly if wrq->u.sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), + psa.psa_thr_pre_set); + break; - /* Check the size of the key */ - if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { - ret = -EINVAL; - } + case SIOCGIWSENS: + /* Read the level threshold. */ + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; + wrq->u.sens.fixed = 1; + break; + + case SIOCSIWENCODE: + /* Set encryption key */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + break; + } - if(!ret) { /* Basic checking... */ - if (wrqu->encoding.length == 8) { + if (wrq->u.encoding.pointer != (caddr_t) 0) { + /* Check the size of the key */ + if (wrq->u.encoding.length != 8) { + ret = -EINVAL; + break; + } + /* Copy the key in the driver */ - memcpy(psa.psa_encryption_key, extra, - wrqu->encoding.length); - psa.psa_encryption_select = 1; + wv_splx(lp, &flags); + err = copy_from_user(psa.psa_encryption_key, + wrq->u.encoding.pointer, + wrq->u.encoding.length); + wv_splhi(lp, &flags); + if (err) { + ret = -EFAULT; + break; + } + psa.psa_encryption_select = 1; psa_write(ioaddr, lp->hacr, (char *) &psa.psa_encryption_select - (char *) &psa, @@ -2058,8 +1963,7 @@ psa_encryption_key, 8); } - /* disable encryption */ - if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { + if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) { /* disable encryption */ psa.psa_encryption_select = 0; psa_write(ioaddr, lp->hacr, (char *) &psa.psa_encryption_select - @@ -2071,430 +1975,350 @@ } /* update the Wavelan checksum */ update_psa_checksum(dev, ioaddr, lp->hacr); - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} + break; -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get encryption key - */ -static int wavelan_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Check if encryption is available */ - if (!mmc_encr(ioaddr)) { - ret = -EOPNOTSUPP; - } else { + case SIOCGIWENCODE: /* Read the encryption key */ - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - - (char *) &psa, - (unsigned char *) &psa. - psa_encryption_select, 1 + 8); - - /* encryption is enabled ? */ - if (psa.psa_encryption_select) - wrqu->encoding.flags = IW_ENCODE_ENABLED; - else - wrqu->encoding.flags = IW_ENCODE_DISABLED; - wrqu->encoding.flags |= mmc_encr(ioaddr); - - /* Copy the key to the user buffer */ - wrqu->encoding.length = 8; - memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get range info - */ -static int wavelan_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - struct iw_range *range = (struct iw_range *) extra; - unsigned long flags; - int ret = 0; - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(struct iw_range); - - /* Set all the info we don't care or don't know about to zero */ - memset(range, 0, sizeof(struct iw_range)); + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + break; + } - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 9; - - /* Set information in the range struct. */ - range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ - range->min_nwid = 0x0000; - range->max_nwid = 0xFFFF; - - range->sensitivity = 0x3F; - range->max_qual.qual = MMR_SGNL_QUAL; - range->max_qual.level = MMR_SIGNAL_LVL; - range->max_qual.noise = MMR_SILENCE_LVL; - range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ - /* Need to get better values for those two */ - range->avg_qual.level = 30; - range->avg_qual.noise = 8; + /* only super-user can see encryption key */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } - range->num_bitrates = 1; - range->bitrate[0] = 2000000; /* 2 Mb/s */ + /* Basic checking... */ + if (wrq->u.encoding.pointer != (caddr_t) 0) { + /* Verify the user buffer */ + ret = + verify_area(VERIFY_WRITE, + wrq->u.encoding.pointer, 8); + if (ret) + break; + + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1 + 8); + + /* encryption is enabled ? */ + if (psa.psa_encryption_select) + wrq->u.encoding.flags = IW_ENCODE_ENABLED; + else + wrq->u.encoding.flags = IW_ENCODE_DISABLED; + wrq->u.encoding.flags |= mmc_encr(ioaddr); - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - range->num_channels = 10; - range->num_frequency = wv_frequency_list(ioaddr, range->freq, - IW_MAX_FREQUENCIES); - } else - range->num_channels = range->num_frequency = 0; + /* Copy the key to the user buffer */ + wrq->u.encoding.length = 8; + wv_splx(lp, &flags); + if (copy_to_user(wrq->u.encoding.pointer, + psa.psa_encryption_key, 8)) + ret = -EFAULT; + wv_splhi(lp, &flags); + } + break; - /* Encryption supported ? */ - if (mmc_encr(ioaddr)) { - range->encoding_size[0] = 8; /* DES = 64 bits key */ - range->num_encoding_sizes = 1; - range->max_encoding_tokens = 1; /* Only one key possible */ - } else { - range->num_encoding_sizes = 0; - range->max_encoding_tokens = 0; - } + case SIOCGIWRANGE: + /* basic checking */ + if (wrq->u.data.pointer != (caddr_t) 0) { + struct iw_range range; + + /* Set the length (very important for backward + * compatibility) */ + wrq->u.data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know + * about to zero */ + memset(&range, 0, sizeof(range)); + + /* Set the Wireless Extension versions */ + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 9; + + /* Set information in the range struct. */ + range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ + range.min_nwid = 0x0000; + range.max_nwid = 0xFFFF; + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + range.num_channels = 10; + range.num_frequency = + wv_frequency_list(ioaddr, range.freq, + IW_MAX_FREQUENCIES); + } else + range.num_channels = range.num_frequency = + 0; + + range.sensitivity = 0x3F; + range.max_qual.qual = MMR_SGNL_QUAL; + range.max_qual.level = MMR_SIGNAL_LVL; + range.max_qual.noise = MMR_SILENCE_LVL; + range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ + /* Need to get better values for those two */ + range.avg_qual.level = 30; + range.avg_qual.noise = 8; + + range.num_bitrates = 1; + range.bitrate[0] = 2000000; /* 2 Mb/s */ + + /* Encryption supported ? */ + if (mmc_encr(ioaddr)) { + range.encoding_size[0] = 8; /* DES = 64 bits key */ + range.num_encoding_sizes = 1; + range.max_encoding_tokens = 1; /* Only one key possible */ + } else { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); + /* Copy structure to the user buffer. */ + wv_splx(lp, &flags); + if (copy_to_user(wrq->u.data.pointer, + &range, + sizeof(struct iw_range))) + ret = -EFAULT; + wv_splhi(lp, &flags); + } + break; - return ret; -} + case SIOCGIWPRIV: + /* Basic checking */ + if (wrq->u.data.pointer != (caddr_t) 0) { + struct iw_priv_args priv[] = { + /* { cmd, + set_args, + get_args, + name } */ + { SIOCSIPQTHR, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + 0, + "setqualthr" }, + { SIOCGIPQTHR, + 0, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + "getqualthr" }, + { SIOCSIPHISTO, + IW_PRIV_TYPE_BYTE | 16, + 0, + "sethisto" }, + { SIOCGIPHISTO, + 0, + IW_PRIV_TYPE_INT | 16, + "gethisto" }, + }; + + /* Set the number of available ioctls. */ + wrq->u.data.length = 4; + + /* Copy structure to the user buffer. */ + wv_splx(lp, &flags); + if (copy_to_user(wrq->u.data.pointer, + (u8 *) priv, + sizeof(priv))) + ret = -EFAULT; + wv_splhi(lp, &flags); + } + break; #ifdef WIRELESS_SPY -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set spy list - */ -static int wavelan_set_spy(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - struct sockaddr *address = (struct sockaddr *) extra; - int i; - int ret = 0; + case SIOCSIWSPY: + /* Set the spy list */ - /* Disable spy while we copy the addresses. - * As we don't disable interrupts, we need to do this */ - lp->spy_number = 0; - - /* Are there are addresses to copy? */ - if (wrqu->data.length > 0) { - /* Copy addresses to the lp structure. */ - for (i = 0; i < wrqu->data.length; i++) { - memcpy(lp->spy_address[i], address[i].sa_data, - WAVELAN_ADDR_SIZE); + /* Check the number of addresses. */ + if (wrq->u.data.length > IW_MAX_SPY) { + ret = -E2BIG; + break; } + lp->spy_number = wrq->u.data.length; - /* Reset structure. */ - memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG - "SetSpy: set of new addresses is: \n"); - for (i = 0; i < wrqu->data.length; i++) - printk(KERN_DEBUG - "%02X:%02X:%02X:%02X:%02X:%02X \n", - lp->spy_address[i][0], - lp->spy_address[i][1], - lp->spy_address[i][2], - lp->spy_address[i][3], - lp->spy_address[i][4], - lp->spy_address[i][5]); -#endif /* DEBUG_IOCTL_INFO */ - } - - /* Now we can set the number of addresses */ - lp->spy_number = wrqu->data.length; - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get spy list - */ -static int wavelan_get_spy(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - struct sockaddr *address = (struct sockaddr *) extra; - int i; + /* Are there are addresses to copy? */ + if (lp->spy_number > 0) { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses to the driver. */ + wv_splx(lp, &flags); + err = copy_from_user(address, + wrq->u.data.pointer, + sizeof(struct sockaddr) + * lp->spy_number); + wv_splhi(lp, &flags); + if (err) { + ret = -EFAULT; + break; + } - /* Set the number of addresses */ - wrqu->data.length = lp->spy_number; + /* Copy addresses to the lp structure. */ + for (i = 0; i < lp->spy_number; i++) { + memcpy(lp->spy_address[i], + address[i].sa_data, + WAVELAN_ADDR_SIZE); + } - /* Copy addresses from the lp structure. */ - for (i = 0; i < lp->spy_number; i++) { - memcpy(address[i].sa_data, - lp->spy_address[i], - WAVELAN_ADDR_SIZE); - address[i].sa_family = AF_UNIX; - } - /* Copy stats to the user buffer (just after). */ - if(lp->spy_number > 0) - memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number), - lp->spy_stat, sizeof(iw_qual) * lp->spy_number); + /* Reset structure. */ + memset(lp->spy_stat, 0x00, + sizeof(iw_qual) * IW_MAX_SPY); - /* Reset updated flags. */ - for (i = 0; i < lp->spy_number; i++) - lp->spy_stat[i].updated = 0x0; +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "SetSpy: set of new addresses is: \n"); + for (i = 0; i < wrq->u.data.length; i++) + printk(KERN_DEBUG + "%02X:%02X:%02X:%02X:%02X:%02X \n", + lp->spy_address[i][0], + lp->spy_address[i][1], + lp->spy_address[i][2], + lp->spy_address[i][3], + lp->spy_address[i][4], + lp->spy_address[i][5]); +#endif /* DEBUG_IOCTL_INFO */ + } - return(0); -} -#endif /* WIRELESS_SPY */ + break; -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : set quality threshold - */ -static int wavelan_set_qthr(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - psa_t psa; - unsigned long flags; + case SIOCGIWSPY: + /* Get the spy list and spy stats. */ - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - psa.psa_quality_thr = *(extra) & 0x0F; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), - psa.psa_quality_thr); + /* Set the number of addresses */ + wrq->u.data.length = lp->spy_number; - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); + /* Does the user want to have the addresses back? */ + if ((lp->spy_number > 0) + && (wrq->u.data.pointer != (caddr_t) 0)) { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses from the lp structure. */ + for (i = 0; i < lp->spy_number; i++) { + memcpy(address[i].sa_data, + lp->spy_address[i], + WAVELAN_ADDR_SIZE); + address[i].sa_family = AF_UNIX; + } - return 0; -} + /* Copy addresses to the user buffer. */ + wv_splx(lp, &flags); + err = copy_to_user(wrq->u.data.pointer, + address, + sizeof(struct sockaddr) + * lp->spy_number); + + /* Copy stats to the user buffer (just after). */ + err |= copy_to_user(wrq->u.data.pointer + + (sizeof(struct sockaddr) + * lp->spy_number), + lp->spy_stat, + sizeof(iw_qual) * lp->spy_number); + wv_splhi(lp, &flags); + if (err) { + ret = -EFAULT; + break; + } -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get quality threshold - */ -static int wavelan_get_qthr(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - psa_t psa; - unsigned long flags; + /* Reset updated flags. */ + for (i = 0; i < lp->spy_number; i++) + lp->spy_stat[i].updated = 0x0; + } + /* if(pointer != NULL) */ + break; +#endif /* WIRELESS_SPY */ - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - *(extra) = psa.psa_quality_thr & 0x0F; + /* ------------------ PRIVATE IOCTL ------------------ */ - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); + case SIOCSIPQTHR: + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + psa.psa_quality_thr = *(wrq->u.name) & 0x0F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), + psa.psa_quality_thr); + break; - return 0; -} + case SIOCGIPQTHR: + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + *(wrq->u.name) = psa.psa_quality_thr & 0x0F; + break; #ifdef HISTOGRAM -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : set histogram - */ -static int wavelan_set_histo(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + case SIOCSIPHISTO: + /* Verify that the user is root. */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } - /* Check the number of intervals. */ - if (wrqu->data.length > 16) { - return(-E2BIG); - } + /* Check the number of intervals. */ + if (wrq->u.data.length > 16) { + ret = -E2BIG; + break; + } + lp->his_number = wrq->u.data.length; - /* Disable histo while we copy the addresses. - * As we don't disable interrupts, we need to do this */ - lp->his_number = 0; - - /* Are there ranges to copy? */ - if (wrqu->data.length > 0) { - /* Copy interval ranges to the driver */ - memcpy(lp->his_range, extra, wrqu->data.length); + /* Are there addresses to copy? */ + if (lp->his_number > 0) { + /* Copy interval ranges to the driver */ + wv_splx(lp, &flags); + err = copy_from_user(lp->his_range, + wrq->u.data.pointer, + sizeof(char) * lp->his_number); + wv_splhi(lp, &flags); + if (err) { + ret = -EFAULT; + break; + } - { - int i; - printk(KERN_DEBUG "Histo :"); - for(i = 0; i < wrqu->data.length; i++) - printk(" %d", lp->his_range[i]); - printk("\n"); + /* Reset structure. */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); } + break; - /* Reset result structure. */ - memset(lp->his_sum, 0x00, sizeof(long) * 16); - } + case SIOCGIPHISTO: + /* Set the number of intervals. */ + wrq->u.data.length = lp->his_number; + + /* Give back the distribution statistics */ + if ((lp->his_number > 0) + && (wrq->u.data.pointer != (caddr_t) 0)) { + /* Copy data to the user buffer. */ + wv_splx(lp, &flags); + if (copy_to_user(wrq->u.data.pointer, + lp->his_sum, + sizeof(long) * lp->his_number); + ret = -EFAULT; + wv_splhi(lp, &flags); - /* Now we can set the number of ranges */ - lp->his_number = wrqu->data.length; - - return(0); -} + } /* if(pointer != NULL) */ + break; +#endif /* HISTOGRAM */ -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get histogram - */ -static int wavelan_get_histo(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + /* ------------------- OTHER IOCTL ------------------- */ - /* Set the number of intervals. */ - wrqu->data.length = lp->his_number; + default: + ret = -EOPNOTSUPP; + } /* switch (cmd) */ - /* Give back the distribution statistics */ - if(lp->his_number > 0) - memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); + /* Enable interrupts and restore flags. */ + wv_splx(lp, &flags); - return(0); +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); +#endif + return ret; } -#endif /* HISTOGRAM */ - -/*------------------------------------------------------------------*/ -/* - * Structures to export the Wireless Handlers - */ - -static const iw_handler wavelan_handler[] = -{ - NULL, /* SIOCSIWNAME */ - wavelan_get_name, /* SIOCGIWNAME */ - wavelan_set_nwid, /* SIOCSIWNWID */ - wavelan_get_nwid, /* SIOCGIWNWID */ - wavelan_set_freq, /* SIOCSIWFREQ */ - wavelan_get_freq, /* SIOCGIWFREQ */ - NULL, /* SIOCSIWMODE */ - NULL, /* SIOCGIWMODE */ - wavelan_set_sens, /* SIOCSIWSENS */ - wavelan_get_sens, /* SIOCGIWSENS */ - NULL, /* SIOCSIWRANGE */ - wavelan_get_range, /* SIOCGIWRANGE */ - NULL, /* SIOCSIWPRIV */ - NULL, /* SIOCGIWPRIV */ - NULL, /* SIOCSIWSTATS */ - NULL, /* SIOCGIWSTATS */ -#ifdef WIRELESS_SPY - wavelan_set_spy, /* SIOCSIWSPY */ - wavelan_get_spy, /* SIOCGIWSPY */ -#else /* WIRELESS_SPY */ - NULL, /* SIOCSIWSPY */ - NULL, /* SIOCGIWSPY */ -#endif /* WIRELESS_SPY */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - NULL, /* SIOCSIWAP */ - NULL, /* SIOCGIWAP */ - NULL, /* -- hole -- */ - NULL, /* SIOCGIWAPLIST */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - NULL, /* SIOCSIWESSID */ - NULL, /* SIOCGIWESSID */ - NULL, /* SIOCSIWNICKN */ - NULL, /* SIOCGIWNICKN */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - NULL, /* SIOCSIWRATE */ - NULL, /* SIOCGIWRATE */ - NULL, /* SIOCSIWRTS */ - NULL, /* SIOCGIWRTS */ - NULL, /* SIOCSIWFRAG */ - NULL, /* SIOCGIWFRAG */ - NULL, /* SIOCSIWTXPOW */ - NULL, /* SIOCGIWTXPOW */ - NULL, /* SIOCSIWRETRY */ - NULL, /* SIOCGIWRETRY */ - /* Bummer ! Why those are only at the end ??? */ - wavelan_set_encode, /* SIOCSIWENCODE */ - wavelan_get_encode, /* SIOCGIWENCODE */ -}; - -static const iw_handler wavelan_private_handler[] = -{ - wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ - wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ -#ifdef HISTOGRAM - wavelan_set_histo, /* SIOCIWFIRSTPRIV + 2 */ - wavelan_get_histo, /* SIOCIWFIRSTPRIV + 3 */ -#endif /* HISTOGRAM */ -}; - -static const struct iw_priv_args wavelan_private_args[] = { -/*{ cmd, set_args, get_args, name } */ - { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, - { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, - { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, - { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, -}; - -static const struct iw_handler_def wavelan_handler_def = -{ - num_standard: sizeof(wavelan_handler)/sizeof(iw_handler), - num_private: sizeof(wavelan_private_handler)/sizeof(iw_handler), - num_private_args: sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), - standard: (iw_handler *) wavelan_handler, - private: (iw_handler *) wavelan_private_handler, - private_args: (struct iw_priv_args *) wavelan_private_args, -}; /*------------------------------------------------------------------*/ /* @@ -2519,7 +2343,7 @@ return (iw_stats *) NULL; /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); + wv_splhi(lp, &flags); wstats = &lp->wstats; @@ -2547,7 +2371,7 @@ wstats->discard.misc = 0L; /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", @@ -2881,7 +2705,7 @@ if (clen < ETH_ZLEN) clen = ETH_ZLEN; - spin_lock_irqsave(&lp->spinlock, flags); + wv_splhi(lp, &flags); /* Check nothing bad has happened */ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { @@ -2889,7 +2713,7 @@ printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", dev->name); #endif - spin_unlock_irqrestore(&lp->spinlock, flags); + wv_splx(lp, &flags); return 1; } @@ -2967,7 +2791,7 @@ if (lp->tx_n_in_use < NTXBLOCKS - 1) netif_wake_queue(dev); - spin_unlock_irqrestore(&lp->spinlock, flags); + wv_splx(lp, &flags); #ifdef DEBUG_TX_INFO wv_packet_info((u8 *) buf, length, dev->name, @@ -3008,9 +2832,9 @@ * we can do it now. */ if (lp->reconfig_82586) { - spin_lock_irqsave(&lp->spinlock, flags); + wv_splhi(lp, &flags); wv_82586_config(dev); - spin_unlock_irqrestore(&lp->spinlock, flags); + wv_splx(lp, &flags); /* Check that we can continue */ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) return 1; @@ -3870,7 +3694,7 @@ /* Prevent reentrancy. We need to do that because we may have * multiple interrupt handler running concurrently. - * It is safe because interrupts are disabled before acquiring + * It is safe because wv_splhi() disables interrupts before acquiring * the spinlock. */ spin_lock(&lp->spinlock); @@ -3998,7 +3822,7 @@ return; } - spin_lock_irqsave(&lp->spinlock, flags); + wv_splhi(lp, &flags); /* Try to see if some buffers are not free (in case we missed * an interrupt */ @@ -4038,7 +3862,7 @@ if (lp->tx_n_in_use < NTXBLOCKS - 1) netif_wake_queue(dev); - spin_unlock_irqrestore(&lp->spinlock, flags); + wv_splx(lp, &flags); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); @@ -4085,7 +3909,7 @@ return -EAGAIN; } - spin_lock_irqsave(&lp->spinlock, flags); + wv_splhi(lp, &flags); if (wv_hw_reset(dev) != -1) { netif_start_queue(dev); @@ -4096,10 +3920,10 @@ "%s: wavelan_open(): impossible to start the card\n", dev->name); #endif - spin_unlock_irqrestore(&lp->spinlock, flags); + wv_splx(lp, &flags); return -EAGAIN; } - spin_unlock_irqrestore(&lp->spinlock, flags); + wv_splx(lp, &flags); #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); @@ -4127,9 +3951,9 @@ /* * Flush the Tx and disable Rx. */ - spin_lock_irqsave(&lp->spinlock, flags); + wv_splhi(lp, &flags); wv_82586_stop(dev); - spin_unlock_irqrestore(&lp->spinlock, flags); + wv_splx(lp, &flags); free_irq(dev->irq, dev); @@ -4245,8 +4069,8 @@ #endif /* SET_MAC_ADDRESS */ #ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ + dev->do_ioctl = wavelan_ioctl; dev->get_wireless_stats = wavelan_get_wireless_stats; - dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def; #endif dev->mtu = WAVELAN_MTU; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/net/wireless/wavelan.p.h linux-2.5/drivers/net/wireless/wavelan.p.h --- linux-2.5.20/drivers/net/wireless/wavelan.p.h Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/net/wireless/wavelan.p.h Thu May 2 23:30:54 2002 @@ -345,12 +345,6 @@ * - Fix spinlock stupid bugs that I left in. The driver is now SMP * compliant and doesn't lockup at startup. * - * Changes made for release in 2.5.2 : - * --------------------------------- - * - Use new driver API for Wireless Extensions : - * o got rid of wavelan_ioctl() - * o use a bunch of iw_handler instead - * * Wishes & dreams: * ---------------- * - roaming (see Pcmcia driver) @@ -385,7 +379,6 @@ #include #include /* Wireless extensions */ -#include /* Wireless handlers */ /* WaveLAN declarations */ #include "i82586.h" @@ -443,7 +436,7 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v24 (SMP + wireless extensions) 11/12/01\n"; +static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/00\n"; #endif /* Watchdog temporisation */ @@ -456,9 +449,11 @@ #define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ #define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ +#define SIOCSIPLTHR SIOCIWFIRSTPRIV + 2 /* Set level threshold */ +#define SIOCGIPLTHR SIOCIWFIRSTPRIV + 3 /* Get level threshold */ -#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */ -#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */ +#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ /****************************** TYPES ******************************/ @@ -521,6 +516,12 @@ /**************************** PROTOTYPES ****************************/ /* ----------------------- MISC. SUBROUTINES ------------------------ */ +static inline void + wv_splhi(net_local *, /* Disable interrupts, lock driver */ + unsigned long *); /* flags */ +static inline void + wv_splx(net_local *, /* Enable interrupts, unlock driver */ + unsigned long *); /* flags */ static u_char wv_irq_to_psa(int); static int diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/parport/ChangeLog linux-2.5/drivers/parport/ChangeLog --- linux-2.5.20/drivers/parport/ChangeLog Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/parport/ChangeLog Fri May 3 01:38:21 2002 @@ -1,8 +1,7 @@ -2001-11-14 Tim Waugh +2002-04-25 Tim Waugh - * parport_pc.c (parport_pc_pci_probe): Hooks for PCI cards before - and after probing for ports. - * parport_serial.c (parport_register): Likewise. + * parport_serial.c, parport_pc.c: Move some SIIG cards around. + Patch from Andrey Panin. 2002-01-20 Tim Waugh @@ -21,17 +20,17 @@ * daisy.c: Apply patch from Max Vorobiev to make parport_daisy_select work for ECP/EPP modes. -2002-01-04 Tim Waugh - - * share.c (parport_claim_or_block): Sleep interruptibly to prevent - a possible deadlock. - 2002-01-13 Niels Kristian Bech Jensen * parport_pc.c: Change some occurrences of frob_set_mode to ECR_WRITE. This fixes PLIP. -2001-10-25 Damian Gruszka +2002-01-04 Tim Waugh + + * share.c (parport_claim_or_block): Sleep interruptibly to prevent + a possible deadlock. + +2001-12-07 Damian Gruszka * parport_pc.c (ECR_WRITE): Define. If there are forbidden bits in the ECR register for some chips, this will be a useful place to @@ -68,7 +67,7 @@ (parport_irq_probe): If no IRQ is found, take ackIntEn out of the writable bit set. -2001-10-25 Tim Waugh +2001-12-07 Tim Waugh * parport_pc.c (parport_pc_fifo_write_block_pio): Correct typo. (parport_pc_init_state): Only set ackIntEn if we know which IRQ @@ -85,6 +84,16 @@ too buggy at the moment. Use 'dma=auto' to restore the previous behaviour. +2001-12-07 Tim Waugh + + * daisy.c (DEBUG): Undefine. + +2001-12-06 Tim Waugh + + * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off + PARPORT_CONTROL_AUTOFD as well. Bug spotted by Joe + . + 2001-12-03 Rich Liu * parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port @@ -94,11 +103,11 @@ * parport_pc.c: Fix compiler warning. -2001-12-06 Tim Waugh +2001-11-14 Tim Waugh - * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off - PARPORT_CONTROL_AUTOFD as well. Bug spotted by Joe - . + * parport_pc.c (parport_pc_pci_probe): Hooks for PCI cards before + and after probing for ports. + * parport_serial.c (parport_register): Likewise. 2001-11-12 Tim Waugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/parport/daisy.c linux-2.5/drivers/parport/daisy.c --- linux-2.5.20/drivers/parport/daisy.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/parport/daisy.c Wed Feb 6 18:54:10 2002 @@ -23,7 +23,7 @@ #include #include -#define DEBUG /* undef me for production */ +#undef DEBUG /* undef me for production */ #ifdef DEBUG #define DPRINTK(stuff...) printk (stuff) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/parport/parport_cs.c linux-2.5/drivers/parport/parport_cs.c --- linux-2.5.20/drivers/parport/parport_cs.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/parport/parport_cs.c Tue Dec 18 14:53:28 2001 @@ -5,7 +5,7 @@ (specifically, for the Quatech SPP-100 EPP card: other cards will probably require driver tweaks) - parport_cs.c 1.20 2000/11/02 23:15:05 + parport_cs.c 1.24 2001/10/13 14:04:05 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -58,32 +58,31 @@ #include #include -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"parport_cs.c 1.20 2000/11/02 23:15:05 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif +/*====================================================================*/ -#ifndef VERSION -#define VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -#endif +/* Module parameters */ -/*====================================================================*/ +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("PCMCIA parallel port card driver"); +MODULE_LICENSE("Dual MPL/GPL"); -/* Parameters that can be set with 'insmod' */ +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; -static int epp_mode = 1; - -MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(epp_mode, "i"); + +INT_MODULE_PARM(epp_mode, 1); + +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"parport_cs.c 1.24 2001/10/13 14:04:05 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -106,8 +105,6 @@ static dev_info_t dev_info = "parport_cs"; static dev_link_t *dev_list = NULL; -extern struct parport_operations parport_pc_ops; - /*====================================================================*/ static void cs_error(client_handle_t handle, int func, int ret) @@ -307,19 +304,6 @@ goto failed; } -#if (LINUX_VERSION_CODE < VERSION(2,3,6)) -#if (LINUX_VERSION_CODE >= VERSION(2,2,8)) - p->private_data = kmalloc(sizeof(struct parport_pc_private), - GFP_KERNEL); - ((struct parport_pc_private *)(p->private_data))->ctr = 0x0c; -#endif - parport_proc_register(p); - p->flags |= PARPORT_FLAG_COMA; - parport_pc_write_econtrol(p, 0x00); - parport_pc_write_control(p, 0x0c); - parport_pc_write_data(p, 0x00); -#endif - p->modes |= PARPORT_MODE_PCSPP; if (epp_mode) p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP; @@ -365,14 +349,8 @@ if (info->ndev) { struct parport *p = info->port; -#if (LINUX_VERSION_CODE < VERSION(2,3,6)) - if (!(p->flags & PARPORT_FLAG_COMA)) - parport_quiesce(p); -#endif parport_proc_unregister(p); -#if (LINUX_VERSION_CODE >= VERSION(2,2,8)) kfree(p->private_data); -#endif parport_unregister_port(p); } info->ndev = 0; @@ -430,24 +408,6 @@ /*====================================================================*/ -#if (LINUX_VERSION_CODE < VERSION(2,3,6)) - -static void inc_use_count(void) -{ - MOD_INC_USE_COUNT; - parport_pc_ops.inc_use_count(); -} - -static void dec_use_count(void) -{ - MOD_DEC_USE_COUNT; - parport_pc_ops.dec_use_count(); -} - -#endif - -/*====================================================================*/ - static int __init init_parport_cs(void) { servinfo_t serv; @@ -473,4 +433,3 @@ module_init(init_parport_cs); module_exit(exit_parport_cs); -MODULE_LICENSE("Dual MPL/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/parport/parport_pc.c linux-2.5/drivers/parport/parport_pc.c --- linux-2.5.20/drivers/parport/parport_pc.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/parport/parport_pc.c Fri May 3 03:49:07 2002 @@ -2650,25 +2650,10 @@ enum parport_pc_pci_cards { - siig_1s1p_10x_550 = last_sio, - siig_1s1p_10x_650, - siig_1s1p_10x_850, - siig_1p_10x, + siig_1p_10x = last_sio, siig_2p_10x, - siig_2s1p_10x_550, - siig_2s1p_10x_650, - siig_2s1p_10x_850, siig_1p_20x, siig_2p_20x, - siig_2p1s_20x_550, - siig_2p1s_20x_650, - siig_2p1s_20x_850, - siig_1s1p_20x_550, - siig_1s1p_20x_650, - siig_1s1p_20x_850, - siig_2s1p_20x_550, - siig_2s1p_20x_650, - siig_2s1p_20x_850, lava_parallel, lava_parallel_dual_a, lava_parallel_dual_b, @@ -2706,6 +2691,7 @@ oxsemi_954, oxsemi_840, aks_0100, + mobility_pp, }; @@ -2729,25 +2715,10 @@ * is non-zero we couldn't use any of the ports. */ void (*postinit_hook) (struct pci_dev *pdev, int failed); } cards[] __devinitdata = { - /* siig_1s1p_10x_550 */ { 1, { { 3, 4 }, } }, - /* siig_1s1p_10x_650 */ { 1, { { 3, 4 }, } }, - /* siig_1s1p_10x_850 */ { 1, { { 3, 4 }, } }, /* siig_1p_10x */ { 1, { { 2, 3 }, } }, /* siig_2p_10x */ { 2, { { 2, 3 }, { 4, 5 }, } }, - /* siig_2s1p_10x_550 */ { 1, { { 4, 5 }, } }, - /* siig_2s1p_10x_650 */ { 1, { { 4, 5 }, } }, - /* siig_2s1p_10x_850 */ { 1, { { 4, 5 }, } }, /* siig_1p_20x */ { 1, { { 0, 1 }, } }, /* siig_2p_20x */ { 2, { { 0, 1 }, { 2, 3 }, } }, - /* siig_2p1s_20x_550 */ { 2, { { 1, 2 }, { 3, 4 }, } }, - /* siig_2p1s_20x_650 */ { 2, { { 1, 2 }, { 3, 4 }, } }, - /* siig_2p1s_20x_850 */ { 2, { { 1, 2 }, { 3, 4 }, } }, - /* siig_1s1p_20x_550 */ { 1, { { 1, 2 }, } }, - /* siig_1s1p_20x_650 */ { 1, { { 1, 2 }, } }, - /* siig_1s1p_20x_850 */ { 1, { { 1, 2 }, } }, - /* siig_2s1p_20x_550 */ { 1, { { 2, 3 }, } }, - /* siig_2s1p_20x_650 */ { 1, { { 2, 3 }, } }, - /* siig_2s1p_20x_850 */ { 1, { { 2, 3 }, } }, /* lava_parallel */ { 1, { { 0, -1 }, } }, /* lava_parallel_dual_a */ { 1, { { 0, -1 }, } }, /* lava_parallel_dual_b */ { 1, { { 0, -1 }, } }, @@ -2789,6 +2760,7 @@ /* oxsemi_954 */ { 1, { { 0, -1 }, } }, /* oxsemi_840 */ { 1, { { 0, -1 }, } }, /* aks_0100 */ { 1, { { 0, 1 }, } }, + /* mobility_pp */ { 1, { { 0, 1 }, } }, }; static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = { @@ -2798,44 +2770,14 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_ite_8872 }, /* PCI cards */ - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_550 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_650 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_850 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_10x }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_10x }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_550 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_650 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_850 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_20x }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_20x }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_550 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_650 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_850 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_550 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x_650 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x_850 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_550 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_650 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_850 }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A, @@ -2870,6 +2812,7 @@ { 0x1409, 0x7268, 0x1409, 0x0103, 0, 0, timedia_4008a }, { 0x1409, 0x7268, 0x1409, 0x0104, 0, 0, timedia_4018 }, { 0x1409, 0x7268, 0x1409, 0x9018, 0, 0, timedia_9018a }, + { 0x14f2, 0x0121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, mobility_pp }, { PCI_VENDOR_ID_SYBA, PCI_DEVICE_ID_SYBA_2P_EPP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_2p_epp }, { PCI_VENDOR_ID_SYBA, PCI_DEVICE_ID_SYBA_1P_ECP, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/parport/parport_serial.c linux-2.5/drivers/parport/parport_serial.c --- linux-2.5.20/drivers/parport/parport_serial.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/parport/parport_serial.c Fri May 3 03:49:07 2002 @@ -41,6 +41,11 @@ avlab_2s1p, avlab_2s1p_650, avlab_2s1p_850, + siig_1s1p_10x, + siig_2s1p_10x, + siig_2p1s_20x, + siig_1s1p_20x, + siig_2s1p_20x, }; @@ -74,6 +79,11 @@ /* avlab_2s1p */ { 1, { { 2, 3}, } }, /* avlab_2s1p_650 */ { 1, { { 2, 3}, } }, /* avlab_2s1p_850 */ { 1, { { 2, 3}, } }, + /* siig_1s1p_10x */ { 1, { { 3, 4 }, } }, + /* siig_2s1p_10x */ { 1, { { 4, 5 }, } }, + /* siig_2p1s_20x */ { 2, { { 1, 2 }, { 3, 4 }, } }, + /* siig_1s1p_20x */ { 1, { { 1, 2 }, } }, + /* siig_2s1p_20x */ { 1, { { 2, 3 }, } }, }; static struct pci_device_id parport_serial_pci_tbl[] __devinitdata = { @@ -92,6 +102,37 @@ { 0x14db, 0x2160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p}, { 0x14db, 0x2161, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_650}, { 0x14db, 0x2162, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_850}, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, + { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); @@ -107,6 +148,16 @@ int first_uart_offset; }; +static int __devinit siig10x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable) +{ + return pci_siig10x_fn(dev, NULL, enable); +} + +static int __devinit siig20x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable) +{ + return pci_siig20x_fn(dev, NULL, enable); +} + static struct pci_board_no_ids pci_boards[] __devinitdata = { /* * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, @@ -129,6 +180,11 @@ /* avlab_2s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* avlab_2s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* avlab_2s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +/* siig_1s1p_10x */ { SPCI_FL_BASE2, 1, 460800, 0, 0, siig10x_init_fn }, +/* siig_2s1p_10x */ { SPCI_FL_BASE2, 1, 921600, 0, 0, siig10x_init_fn }, +/* siig_2p1s_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, +/* siig_1s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, +/* siig_2s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, }; struct parport_serial_private { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pci/Makefile linux-2.5/drivers/pci/Makefile --- linux-2.5.20/drivers/pci/Makefile Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/pci/Makefile Sat Jun 1 00:34:35 2002 @@ -22,9 +22,9 @@ obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o obj-$(CONFIG_PARISC) += setup-bus.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o -obj-$(CONFIG_PPC32) += setup-irq.o -obj-$(CONFIG_DDB5476) += setup-bus.o +obj-$(CONFIG_PPC32) += setup-bus.o obj-$(CONFIG_SGI_IP27) += setup-irq.o +obj-$(CONFIG_SGI_IP32) += setup-irq.o ifndef CONFIG_X86 obj-y += syscall.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pci/gen-devlist.c linux-2.5/drivers/pci/gen-devlist.c --- linux-2.5.20/drivers/pci/gen-devlist.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/pci/gen-devlist.c Sat Apr 13 17:42:56 2002 @@ -1,7 +1,7 @@ /* * Generate devlist.h and classlist.h from the PCI ID file. * - * (c) 1999--2000 Martin Mares + * (c) 1999--2002 Martin Mares */ #include @@ -15,8 +15,13 @@ while (*c) { if (*c == '"') fprintf(f, "\\\""); - else + else { fputc(*c, f); + if (*c == '?' && c[1] == '?') { + /* Avoid trigraphs */ + fprintf(f, "\" \""); + } + } c++; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pci/quirks.c linux-2.5/drivers/pci/quirks.c --- linux-2.5.20/drivers/pci/quirks.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/pci/quirks.c Mon May 6 16:13:15 2002 @@ -90,7 +90,7 @@ * VIA Apollo KT133 needs PCI latency patch * Made according to a windows driver based patch by George E. Breese * see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm - * Also see http://home.tiscalinet.de/au-ja/review-kt133a-1-en.html for + * Also see http://www.au-ja.org/review-kt133a-1-en.phtml for * the info on which Mr Breese based his work. * * Updated based on further information from the site and also on diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pci/setup-bus.c linux-2.5/drivers/pci/setup-bus.c --- linux-2.5.20/drivers/pci/setup-bus.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/pci/setup-bus.c Sat Jun 1 00:34:35 2002 @@ -106,6 +106,14 @@ DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n", bus->number, bridge->name)); + /* Add bridge resources to the resource tree. */ + if (bus->resource[0]->end > bus->resource[0]->start && + request_resource(bus->resource[0], bus->resource[0]) < 0) + printk(KERN_ERR "PCI: failed to reserve IO for bus %d\n", bus->number); + if (bus->resource[1]->end > bus->resource[1]->start && + request_resource(bus->resource[1], bus->resource[1]) < 0) + printk(KERN_ERR "PCI: failed to reserve MEM for bus %d\n", bus->number); + /* Set up the top and bottom of the PCI I/O segment for this bus. */ if (bus->resource[0]->flags & IORESOURCE_IO) { pci_read_config_dword(bridge, PCI_IO_BASE, &l); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/Config.in linux-2.5/drivers/pcmcia/Config.in --- linux-2.5.20/drivers/pcmcia/Config.in Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/pcmcia/Config.in Sun May 26 00:38:18 2002 @@ -19,8 +19,10 @@ dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA fi if [ "$CONFIG_ARM" = "y" ]; then - dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA + dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA + fi + if [ "$CONFIG_8xx" = "y" ]; then + tristate ' M8xx support' CONFIG_PCMCIA_M8XX fi fi - endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/Makefile linux-2.5/drivers/pcmcia/Makefile --- linux-2.5.20/drivers/pcmcia/Makefile Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/pcmcia/Makefile Sat Jun 1 00:34:35 2002 @@ -14,6 +14,7 @@ obj-$(CONFIG_TCIC) += tcic.o obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o +obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o yenta_socket-objs := pci_socket.o yenta.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/au1000_generic.c linux-2.5/drivers/pcmcia/au1000_generic.c --- linux-2.5.20/drivers/pcmcia/au1000_generic.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/pcmcia/au1000_generic.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,696 @@ +/* + * + * Alchemy Semi Au1000 pcmcia driver + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" + +#include +#include +#include + +#include +#include + +#ifdef PCMCIA_DEBUG +static int pc_debug; +#endif + +MODULE_AUTHOR("Pete Popov, MontaVista Software "); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller"); + +#define MAP_SIZE 0x1000000 + +/* This structure maintains housekeeping state for each socket, such + * as the last known values of the card detect pins, or the Card Services + * callback value associated with the socket: + */ +static struct au1000_pcmcia_socket *pcmcia_socket; +static int socket_count; + + +/* Returned by the low-level PCMCIA interface: */ +static struct pcmcia_low_level *pcmcia_low_level; + +/* Event poll timer structure */ +static struct timer_list poll_timer; + + +/* Prototypes for routines which are used internally: */ + +static int au1000_pcmcia_driver_init(void); +static void au1000_pcmcia_driver_shutdown(void); +static void au1000_pcmcia_task_handler(void *data); +static void au1000_pcmcia_poll_event(u32 data); +static void au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs); +static struct tq_struct au1000_pcmcia_task; + +#ifdef CONFIG_PROC_FS +static int au1000_pcmcia_proc_status(char *buf, char **start, + off_t pos, int count, int *eof, void *data); +#endif + + +/* Prototypes for operations which are exported to the + * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core: + */ + +static int au1000_pcmcia_init(u32 sock); +static int au1000_pcmcia_suspend(u32 sock); +static int au1000_pcmcia_register_callback(u32 sock, + void (*handler)(void *, u32), void *info); +static int au1000_pcmcia_inquire_socket(u32 sock, socket_cap_t *cap); +static int au1000_pcmcia_get_status(u32 sock, u_int *value); +static int au1000_pcmcia_get_socket(u32 sock, socket_state_t *state); +static int au1000_pcmcia_set_socket(u32 sock, socket_state_t *state); +static int au1000_pcmcia_get_io_map(u32 sock, struct pccard_io_map *io); +static int au1000_pcmcia_set_io_map(u32 sock, struct pccard_io_map *io); +static int au1000_pcmcia_get_mem_map(u32 sock, struct pccard_mem_map *mem); +static int au1000_pcmcia_set_mem_map(u32 sock, struct pccard_mem_map *mem); +#ifdef CONFIG_PROC_FS +static void au1000_pcmcia_proc_setup(u32 sock, struct proc_dir_entry *base); +#endif + +static struct pccard_operations au1000_pcmcia_operations = { + au1000_pcmcia_init, + au1000_pcmcia_suspend, + au1000_pcmcia_register_callback, + au1000_pcmcia_inquire_socket, + au1000_pcmcia_get_status, + au1000_pcmcia_get_socket, + au1000_pcmcia_set_socket, + au1000_pcmcia_get_io_map, + au1000_pcmcia_set_io_map, + au1000_pcmcia_get_mem_map, + au1000_pcmcia_set_mem_map, +#ifdef CONFIG_PROC_FS + au1000_pcmcia_proc_setup +#endif +}; + +static int __init au1000_pcmcia_driver_init(void) +{ + servinfo_t info; + struct pcmcia_init pcmcia_init; + struct pcmcia_state state; + unsigned int i; + unsigned long timing3; + + printk("\nAu1x00 PCMCIA (CS release %s)\n", CS_RELEASE); + + CardServices(GetCardServicesInfo, &info); + + if(info.Revision!=CS_RELEASE_CODE){ + printk(KERN_ERR "Card Services release codes do not match\n"); + return -1; + } + +#ifdef CONFIG_MIPS_PB1000 + pcmcia_low_level=&pb1000_pcmcia_ops; +#elif defined(CONFIG_MIPS_PB1500) + pcmcia_low_level=&pb1500_pcmcia_ops; +#else +#error Unsupported AU1000 board. +#endif + + pcmcia_init.handler=au1000_pcmcia_interrupt; + if((socket_count=pcmcia_low_level->init(&pcmcia_init))<0) { + printk(KERN_ERR "Unable to initialize PCMCIA service.\n"); + return -EIO; + } + + /* setup the static bus controller */ + timing3 = 0x100e3a07; + writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */ + writel(timing3, MEM_STTIME3); + writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */ + au_sync_delay(1); + + pcmcia_socket = + kmalloc(sizeof(struct au1000_pcmcia_socket) * socket_count, + GFP_KERNEL); + if (!pcmcia_socket) { + printk(KERN_ERR "Card Services can't get memory \n"); + return -1; + } + memset(pcmcia_socket, 0, + sizeof(struct au1000_pcmcia_socket) * socket_count); + + for(i=0; i < socket_count; i++) { + + if(pcmcia_low_level->socket_state(i, &state)<0){ + printk(KERN_ERR "Unable to get PCMCIA status\n"); + return -EIO; + } + pcmcia_socket[i].k_state=state; + pcmcia_socket[i].cs_state.csc_mask=SS_DETECT; + + if (i == 0) { + pcmcia_socket[i].virt_io = + (u32)ioremap(0xC0000000, 0x1000); + pcmcia_socket[i].phys_attr = 0xC4000000; + pcmcia_socket[i].phys_mem = 0xC8000000; + } + else { + printk(KERN_ERR "au1000: socket 1 not supported\n"); + return 1; + } + } + + /* Only advertise as many sockets as we can detect: */ + if(register_ss_entry(socket_count, &au1000_pcmcia_operations)<0){ + printk(KERN_ERR "Unable to register socket service routine\n"); + return -ENXIO; + } + + /* Start the event poll timer. + * It will reschedule by itself afterwards. + */ + au1000_pcmcia_poll_event(0); + + DEBUG(1, "au1000: initialization complete\n"); + return 0; + +} /* au1000_pcmcia_driver_init() */ + +module_init(au1000_pcmcia_driver_init); + +static void __exit au1000_pcmcia_driver_shutdown(void) +{ + int i; + + del_timer_sync(&poll_timer); + unregister_ss_entry(&au1000_pcmcia_operations); + pcmcia_low_level->shutdown(); + flush_scheduled_tasks(); + for(i=0; i < socket_count; i++) { + if (pcmcia_socket[i].virt_io) + iounmap((void *)pcmcia_socket[i].virt_io); + } + DEBUG(1, "au1000: shutdown complete\n"); +} + +module_exit(au1000_pcmcia_driver_shutdown); + +static int au1000_pcmcia_init(unsigned int sock) { return 0; } + +static int au1000_pcmcia_suspend(unsigned int sock) +{ + return 0; +} + + +static inline unsigned +au1000_pcmcia_events(struct pcmcia_state *state, + struct pcmcia_state *prev_state, + unsigned int mask, unsigned int flags) +{ + unsigned int events=0; + + if(state->detect!=prev_state->detect){ + DEBUG(2, "%s(): card detect value %u\n", + __FUNCTION__, state->detect); + events |= mask&SS_DETECT; + } + + + if(state->ready!=prev_state->ready){ + DEBUG(2, "%s(): card ready value %u\n", + __FUNCTION__, state->ready); + events |= mask&((flags&SS_IOCARD)?0:SS_READY); + } + + *prev_state=*state; + return events; + +} /* au1000_pcmcia_events() */ + + +/* + * Au1000_pcmcia_task_handler() + * Processes socket events. + */ +static void au1000_pcmcia_task_handler(void *data) +{ + struct pcmcia_state state; + int i, events, irq_status; + + for(i=0; isocket_state(i, &state))<0) + printk(KERN_ERR "low-level PCMCIA error\n"); + + events = au1000_pcmcia_events(&state, + &pcmcia_socket[i].k_state, + pcmcia_socket[i].cs_state.csc_mask, + pcmcia_socket[i].cs_state.flags); + if(pcmcia_socket[i].handler!=NULL) { + pcmcia_socket[i].handler(pcmcia_socket[i].handler_info, + events); + } + } + +} /* au1000_pcmcia_task_handler() */ + +static struct tq_struct au1000_pcmcia_task = { + routine: au1000_pcmcia_task_handler +}; + + +static void au1000_pcmcia_poll_event(u32 dummy) +{ + poll_timer.function = au1000_pcmcia_poll_event; + poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD; + add_timer(&poll_timer); + schedule_task(&au1000_pcmcia_task); +} + + +/* + * au1000_pcmcia_interrupt() + * The actual interrupt work is performed by au1000_pcmcia_task(), + * because the Card Services event handling code performs scheduling + * operations which cannot be executed from within an interrupt context. + */ +static void +au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + schedule_task(&au1000_pcmcia_task); +} + + +static int +au1000_pcmcia_register_callback(unsigned int sock, + void (*handler)(void *, unsigned int), void *info) +{ + if(handler==NULL){ + pcmcia_socket[sock].handler=NULL; + MOD_DEC_USE_COUNT; + } else { + MOD_INC_USE_COUNT; + pcmcia_socket[sock].handler=handler; + pcmcia_socket[sock].handler_info=info; + } + return 0; +} + + +/* au1000_pcmcia_inquire_socket() + * + * From the sa1100 socket driver : + * + * Implements the inquire_socket() operation for the in-kernel PCMCIA + * service (formerly SS_InquireSocket in Card Services). We set + * SS_CAP_STATIC_MAP, which disables the memory resource database check. + * (Mapped memory is set up within the socket driver itself.) + * + * In conjunction with the STATIC_MAP capability is a new field, + * `io_offset', recommended by David Hinds. Rather than go through + * the SetIOMap interface (which is not quite suited for communicating + * window locations up from the socket driver), we just pass up + * an offset which is applied to client-requested base I/O addresses + * in alloc_io_space(). + * + * Returns: 0 on success, -1 if no pin has been configured for `sock' + */ +static int au1000_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap) +{ + struct pcmcia_irq_info irq_info; + + if(sock > socket_count){ + printk(KERN_ERR "au1000: socket %u not configured\n", sock); + return -1; + } + + /* from the sa1100_generic driver: */ + + /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the + * force_low argument to validate_mem() in rsrc_mgr.c -- since in + * general, the mapped * addresses of the PCMCIA memory regions + * will not be within 0xffff, setting force_low would be + * undesirable. + * + * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory + * resource database; we instead pass up physical address ranges + * and allow other parts of Card Services to deal with remapping. + * + * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but + * not 32-bit CardBus devices. + */ + cap->features=(SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD); + + irq_info.sock=sock; + irq_info.irq=-1; + + if(pcmcia_low_level->get_irq_info(&irq_info)<0){ + printk(KERN_ERR "Error obtaining IRQ info socket %u\n", sock); + return -1; + } + + cap->irq_mask=0; + cap->map_size=MAP_SIZE; + cap->pci_irq=irq_info.irq; + cap->io_offset=pcmcia_socket[sock].virt_io; + + return 0; + +} /* au1000_pcmcia_inquire_socket() */ + + +static int +au1000_pcmcia_get_status(unsigned int sock, unsigned int *status) +{ + struct pcmcia_state state; + + + if((pcmcia_low_level->socket_state(sock, &state))<0){ + printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); + return -1; + } + + pcmcia_socket[sock].k_state = state; + + *status = state.detect?SS_DETECT:0; + + *status |= state.ready?SS_READY:0; + + *status |= pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0; + + if(pcmcia_socket[sock].cs_state.flags&SS_IOCARD) + *status |= state.bvd1?SS_STSCHG:0; + else { + if(state.bvd1==0) + *status |= SS_BATDEAD; + else if(state.bvd2 == 0) + *status |= SS_BATWARN; + } + + *status|=state.vs_3v?SS_3VCARD:0; + + *status|=state.vs_Xv?SS_XVCARD:0; + + DEBUG(2, "\tstatus: %s%s%s%s%s%s%s%s\n", + (*status&SS_DETECT)?"DETECT ":"", + (*status&SS_READY)?"READY ":"", + (*status&SS_BATDEAD)?"BATDEAD ":"", + (*status&SS_BATWARN)?"BATWARN ":"", + (*status&SS_POWERON)?"POWERON ":"", + (*status&SS_STSCHG)?"STSCHG ":"", + (*status&SS_3VCARD)?"3VCARD ":"", + (*status&SS_XVCARD)?"XVCARD ":""); + + return 0; + +} /* au1000_pcmcia_get_status() */ + + +static int +au1000_pcmcia_get_socket(unsigned int sock, socket_state_t *state) +{ + *state = pcmcia_socket[sock].cs_state; + return 0; +} + + +static int +au1000_pcmcia_set_socket(unsigned int sock, socket_state_t *state) +{ + struct pcmcia_configure configure; + + DEBUG(2, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" + "\tVcc %d Vpp %d irq %d\n", + (state->csc_mask==0)?"":"", + (state->csc_mask&SS_DETECT)?"DETECT ":"", + (state->csc_mask&SS_READY)?"READY ":"", + (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", + (state->csc_mask&SS_BATWARN)?"BATWARN ":"", + (state->csc_mask&SS_STSCHG)?"STSCHG ":"", + (state->flags==0)?"":"", + (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", + (state->flags&SS_IOCARD)?"IOCARD ":"", + (state->flags&SS_RESET)?"RESET ":"", + (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", + (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", + state->Vcc, state->Vpp, state->io_irq); + + configure.sock=sock; + configure.vcc=state->Vcc; + configure.vpp=state->Vpp; + configure.output=(state->flags&SS_OUTPUT_ENA)?1:0; + configure.speaker=(state->flags&SS_SPKR_ENA)?1:0; + configure.reset=(state->flags&SS_RESET)?1:0; + + if(pcmcia_low_level->configure_socket(&configure)<0){ + printk(KERN_ERR "Unable to configure socket %u\n", sock); + return -1; + } + + pcmcia_socket[sock].cs_state = *state; + return 0; + +} /* au1000_pcmcia_set_socket() */ + + +static int +au1000_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map) +{ + DEBUG(1, "au1000_pcmcia_get_io_map: sock %d\n", sock); + if(map->map>=MAX_IO_WIN){ + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + *map=pcmcia_socket[sock].io_map[map->map]; + return 0; +} + + +int +au1000_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) +{ + unsigned int speed; + unsigned long start; + + if(map->map>=MAX_IO_WIN){ + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + + if(map->flags&MAP_ACTIVE){ + speed=(map->speed>0)?map->speed:AU1000_PCMCIA_IO_SPEED; + pcmcia_socket[sock].speed_io=speed; + } + + start=map->start; + + if(map->stop==1) { + map->stop=PAGE_SIZE-1; + } + + map->start=pcmcia_socket[sock].virt_io; + map->stop=map->start+(map->stop-start); + pcmcia_socket[sock].io_map[map->map]=*map; + DEBUG(3, "set_io_map %d start %x stop %x\n", + map->map, map->start, map->stop); + return 0; + +} /* au1000_pcmcia_set_io_map() */ + + +static int +au1000_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + + if(map->map>=MAX_WIN) { + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + *map=pcmcia_socket[sock].mem_map[map->map]; + return 0; +} + + +static int +au1000_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + unsigned int speed; + unsigned long start; + u_long flags; + + if(map->map>=MAX_WIN){ + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + + if(map->flags&MAP_ACTIVE){ + speed=(map->speed>0)?map->speed:AU1000_PCMCIA_MEM_SPEED; + + /* TBD */ + if(map->flags&MAP_ATTRIB){ + pcmcia_socket[sock].speed_attr=speed; + } + else { + pcmcia_socket[sock].speed_mem=speed; + } + } + + save_flags(flags); + cli(); + start=map->sys_start; + + if(map->sys_stop==0) + map->sys_stop=MAP_SIZE-1; + + if (map->flags & MAP_ATTRIB) { + map->sys_start = pcmcia_socket[sock].phys_attr + + map->card_start; + } + else { + map->sys_start = pcmcia_socket[sock].phys_mem + + map->card_start; + } + + map->sys_stop=map->sys_start+(map->sys_stop-start); + pcmcia_socket[sock].mem_map[map->map]=*map; + restore_flags(flags); + DEBUG(3, "set_mem_map %d start %x stop %x card_start %x\n", + map->map, map->sys_start, map->sys_stop, + map->card_start); + return 0; + +} /* au1000_pcmcia_set_mem_map() */ + + +#if defined(CONFIG_PROC_FS) + +static void +au1000_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base) +{ + struct proc_dir_entry *entry; + + if((entry=create_proc_entry("status", 0, base))==NULL){ + printk(KERN_ERR "Unable to install \"status\" procfs entry\n"); + return; + } + + entry->read_proc=au1000_pcmcia_proc_status; + entry->data=(void *)sock; +} + + +/* au1000_pcmcia_proc_status() + * Implements the /proc/bus/pccard/??/status file. + * + * Returns: the number of characters added to the buffer + */ +static int +au1000_pcmcia_proc_status(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + char *p=buf; + unsigned int sock=(unsigned int)data; + + p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n", + pcmcia_socket[sock].k_state.detect?"detect ":"", + pcmcia_socket[sock].k_state.ready?"ready ":"", + pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"", + pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"", + pcmcia_socket[sock].k_state.wrprot?"wrprot ":"", + pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"", + pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":""); + + p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", + pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"", + pcmcia_socket[sock].k_state.ready?"SS_READY ":"", + pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"", + pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ + "SS_IOCARD ":"", + (pcmcia_socket[sock].cs_state.flags&SS_IOCARD && + pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"", + ((pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && + (pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"", + ((pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && + (pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"", + pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"", + pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":""); + + p+=sprintf(p, "mask : %s%s%s%s%s\n", + pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\ + "SS_DETECT ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\ + "SS_READY ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\ + "SS_BATDEAD ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\ + "SS_BATWARN ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\ + "SS_STSCHG ":""); + + p+=sprintf(p, "cs_flags : %s%s%s%s%s\n", + pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\ + "SS_PWR_AUTO ":"", + pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ + "SS_IOCARD ":"", + pcmcia_socket[sock].cs_state.flags&SS_RESET?\ + "SS_RESET ":"", + pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\ + "SS_SPKR_ENA ":"", + pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\ + "SS_OUTPUT_ENA ":""); + + p+=sprintf(p, "Vcc : %d\n", pcmcia_socket[sock].cs_state.Vcc); + p+=sprintf(p, "Vpp : %d\n", pcmcia_socket[sock].cs_state.Vpp); + p+=sprintf(p, "irq : %d\n", pcmcia_socket[sock].cs_state.io_irq); + p+=sprintf(p, "I/O : %u\n", pcmcia_socket[sock].speed_io); + p+=sprintf(p, "attribute: %u\n", pcmcia_socket[sock].speed_attr); + p+=sprintf(p, "common : %u\n", pcmcia_socket[sock].speed_mem); + return p-buf; +} + + +#endif /* defined(CONFIG_PROC_FS) */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/au1000_pb1000.c linux-2.5/drivers/pcmcia/au1000_pb1000.c --- linux-2.5.20/drivers/pcmcia/au1000_pb1000.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/pcmcia/au1000_pb1000.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,307 @@ +/* + * + * Alchemy Semi PB1000 board specific pcmcia routines. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" + +#include +#include +#include + +#include +#include +#include + + +extern struct pcmcia_x_table x_table; + +static int pb1000_pcmcia_init(struct pcmcia_init *init) +{ + u32 pcr; + pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; + + writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */ + au_sync_delay(100); + writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */ + au_sync(); + + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); + writew(pcr, PB1000_PCR); + au_sync_delay(20); + + /* There's two sockets, but only the first one, 0, is used and tested */ + return 1; +} + +static int pb1000_pcmcia_shutdown(void) +{ + u16 pcr; + pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); + writew(pcr, PB1000_PCR); + au_sync_delay(20); + return 0; +} + +static int +pb1000_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state) +{ + u16 levels, pcr; + unsigned char vs; + + levels = readw(PB1000_ACR1); + pcr = readw(PB1000_PCR); + + state->ready = 0; + state->vs_Xv = 0; + state->vs_3v = 0; + state->detect = 0; + + /* + * This is tricky. The READY pin is also the #IRQ pin. We'll treat + * READY as #IRQ and set state->ready to 1 whenever state->detect + * is true. + */ + + /* + * CD1/2 are active low; so are the VSS pins; Ready is active high + */ + if (sock == 0) { + if (!(levels & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2))) { + state->detect = 1; + vs = (levels >> 4) & 0x3; + switch (vs) { + case 0: + case 1: + case 2: + state->vs_3v=1; + break; + case 3: + default: + break; + } + } + } + else if (sock == 1) { + if (!(levels & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2))) { + state->detect = 1; + vs = (levels >> 12) & 0x3; + switch (vs) { + case 0: + case 1: + case 2: + state->vs_3v=1; + break; + case 3: + default: + break; + } + } + } + else { + printk(KERN_ERR "pb1000 socket_state bad sock %d\n", sock); + } + + if (state->detect) + state->ready = 1; + + state->bvd1=1; + state->bvd2=1; + state->wrprot=0; + return 1; +} + + +static int pb1000_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + + if(info->sock > PCMCIA_MAX_SOCK) return -1; + + if(info->sock == 0) + info->irq = AU1000_GPIO_15; + else + info->irq = -1; + + return 0; +} + + +static int +pb1000_pcmcia_configure_socket(const struct pcmcia_configure *configure) +{ + u16 pcr; + + if(configure->sock > PCMCIA_MAX_SOCK) return -1; + + pcr = readw(PB1000_PCR); + + if (configure->sock == 0) { + pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 | + PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1); + } + else { + pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 | + PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1); + } + + pcr &= ~PCR_SLOT_0_RST; + /* + writew(pcr, PB1000_PCR); + au_sync_delay(200); + */ + DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x\n", + configure->vcc, configure->vpp, pcr); + switch(configure->vcc){ + case 0: /* Vcc 0 */ + switch(configure->vpp) { + case 0: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND, + configure->sock); + break; + case 12: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V, + configure->sock); + break; + case 50: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V, + configure->sock); + break; + case 33: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V, + configure->sock); + break; + default: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, + configure->sock); + printk("%s: bad Vcc/Vpp (%d:%d)\n", + __FUNCTION__, + configure->vcc, + configure->vpp); + break; + } + break; + case 50: /* Vcc 5V */ + switch(configure->vpp) { + case 0: + pcr |= SET_VCC_VPP(VCC_5V,VPP_GND, + configure->sock); + break; + case 50: + pcr |= SET_VCC_VPP(VCC_5V,VPP_5V, + configure->sock); + break; + case 12: + pcr |= SET_VCC_VPP(VCC_5V,VPP_12V, + configure->sock); + break; + case 33: + pcr |= SET_VCC_VPP(VCC_5V,VPP_3V, + configure->sock); + break; + default: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, + configure->sock); + printk("%s: bad Vcc/Vpp (%d:%d)\n", + __FUNCTION__, + configure->vcc, + configure->vpp); + break; + } + break; + case 33: /* Vcc 3.3V */ + switch(configure->vpp) { + case 0: + pcr |= SET_VCC_VPP(VCC_3V,VPP_GND, + configure->sock); + break; + case 50: + pcr |= SET_VCC_VPP(VCC_3V,VPP_5V, + configure->sock); + break; + case 12: + pcr |= SET_VCC_VPP(VCC_3V,VPP_12V, + configure->sock); + break; + case 33: + pcr |= SET_VCC_VPP(VCC_3V,VPP_3V, + configure->sock); + break; + default: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, + configure->sock); + printk("%s: bad Vcc/Vpp (%d:%d)\n", + __FUNCTION__, + configure->vcc, + configure->vpp); + break; + } + break; + default: /* what's this ? */ + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock); + printk(KERN_ERR "%s: bad Vcc %d\n", + __FUNCTION__, configure->vcc); + break; + } + + pcr &= ~(PCR_SLOT_0_RST); + if (configure->reset) { + pcr |= PCR_SLOT_0_RST; + } + writew(pcr, PB1000_PCR); + au_sync_delay(300); + return 0; +} + +struct pcmcia_low_level pb1000_pcmcia_ops = { + pb1000_pcmcia_init, + pb1000_pcmcia_shutdown, + pb1000_pcmcia_socket_state, + pb1000_pcmcia_get_irq_info, + pb1000_pcmcia_configure_socket +}; + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/cistpl.c linux-2.5/drivers/pcmcia/cistpl.c --- linux-2.5.20/drivers/pcmcia/cistpl.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/pcmcia/cistpl.c Thu Dec 13 16:32:36 2001 @@ -264,11 +264,11 @@ (s->cis_mem.sys_start == 0)) { int low = !(s->cap.features & SS_CAP_PAGE_REGS); vs = s; - validate_mem(cis_readable, checksum_match, low); + validate_mem(cis_readable, checksum_match, low, s); s->cis_mem.sys_start = 0; vs = NULL; if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size, - s->cap.map_size, low, "card services")) { + s->cap.map_size, low, "card services", s)) { printk(KERN_NOTICE "cs: unable to map card memory!\n"); return CS_OUT_OF_RESOURCE; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/cs.c linux-2.5/drivers/pcmcia/cs.c --- linux-2.5.20/drivers/pcmcia/cs.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/pcmcia/cs.c Fri Mar 1 20:36:36 2002 @@ -809,7 +809,7 @@ return 1; for (i = 0; i < MAX_IO_WIN; i++) { if (s->io[i].NumPorts == 0) { - if (find_io_region(base, num, align, name) == 0) { + if (find_io_region(base, num, align, name, s) == 0) { s->io[i].Attributes = attr; s->io[i].BasePort = *base; s->io[i].NumPorts = s->io[i].InUse = num; @@ -821,7 +821,7 @@ /* Try to extend top of window */ try = s->io[i].BasePort + s->io[i].NumPorts; if ((*base == 0) || (*base == try)) - if (find_io_region(&try, num, 0, name) == 0) { + if (find_io_region(&try, num, 0, name, s) == 0) { *base = try; s->io[i].NumPorts += num; s->io[i].InUse += num; @@ -830,7 +830,7 @@ /* Try to extend bottom of window */ try = s->io[i].BasePort - num; if ((*base == 0) || (*base == try)) - if (find_io_region(&try, num, 0, name) == 0) { + if (find_io_region(&try, num, 0, name, s) == 0) { s->io[i].BasePort = *base = try; s->io[i].NumPorts += num; s->io[i].InUse += num; @@ -1268,7 +1268,7 @@ } else c = CONFIG(handle); if ((c != NULL) && (c->state & CONFIG_LOCKED) && - (c->IntType & INT_MEMORY_AND_IO)) { + (c->IntType & (INT_MEMORY_AND_IO|INT_ZOOMED_VIDEO))) { u_char reg; if (c->Present & PRESENT_PIN_REPLACE) { read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); @@ -1696,6 +1696,8 @@ c->Attributes = req->Attributes; if (req->IntType & INT_MEMORY_AND_IO) s->socket.flags |= SS_IOCARD; + if (req->IntType & INT_ZOOMED_VIDEO) + s->socket.flags |= SS_ZVCARD|SS_IOCARD; if (req->Attributes & CONF_ENABLE_DMA) s->socket.flags |= SS_DMA_MODE; if (req->Attributes & CONF_ENABLE_SPKR) @@ -1974,7 +1976,7 @@ find_mem_region(&win->base, win->size, align, (req->Attributes & WIN_MAP_BELOW_1MB) || !(s->cap.features & SS_CAP_PAGE_REGS), - (*handle)->dev_info)) + (*handle)->dev_info, s)) return CS_IN_USE; (*handle)->state |= CLIENT_WIN_REQ(w); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/cs_internal.h linux-2.5/drivers/pcmcia/cs_internal.h --- linux-2.5.20/drivers/pcmcia/cs_internal.h Mon Jun 3 02:44:38 2002 +++ linux-2.5/drivers/pcmcia/cs_internal.h Sun Mar 31 15:11:43 2002 @@ -238,11 +238,11 @@ /* In rsrc_mgr */ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low); + int force_low, socket_info_t *s); int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, - char *name); + char *name, socket_info_t *s); int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name); + int force_low, char *name, socket_info_t *s); int try_irq(u_int Attributes, int irq, int specific); void undo_irq(u_int Attributes, int irq); int adjust_resource_info(client_handle_t handle, adjust_t *adj); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/m8xx_pcmcia.c linux-2.5/drivers/pcmcia/m8xx_pcmcia.c --- linux-2.5.20/drivers/pcmcia/m8xx_pcmcia.c Thu Jan 1 01:00:00 1970 +++ linux-2.5/drivers/pcmcia/m8xx_pcmcia.c Fri May 3 03:49:07 2002 @@ -0,0 +1,1236 @@ +/* + * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series. + * + * (C) 1999-2000 Magnus Damm + * (C) 2001-2002 Montavista Software, Inc. + * + * + * "The ExCA standard specifies that socket controllers should provide + * two IO and five memory windows per socket, which can be independently + * configured and positioned in the host address space and mapped to + * arbitrary segments of card address space. " - David A Hinds. 1999 + * + * This controller does _not_ meet the ExCA standard. + * + * m8xx pcmcia controller brief info: + * + 8 windows (attrib, mem, i/o) + * + up to two slots (SLOT_A and SLOT_B) + * + inputpins, outputpins, event and mask registers. + * - no offset register. sigh. + * + * Because of the lacking offset register we must map the whole card. + * We assign each memory window PCMCIA_MEM_WIN_SIZE address space. + * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO + * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE. + * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE. + * They are maximum 64KByte each... + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) printk(KERN_DEBUG "m8xx_pcmcia: " args); +#else +#define DEBUG(n, args...) +#endif + +#define PCMCIA_INFO(args...) printk(KERN_INFO "m8xx_pcmcia: "args) +#define PCMCIA_ERROR(args...) printk(KERN_ERR "m8xx_pcmcia: "args) + +static const char *version = "Version 0.05, 14-Apr-2002"; +MODULE_LICENSE("Dual MPL/GPL"); + +/* The RPX series use SLOT_B */ + +#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE) +#define CONFIG_PCMCIA_SLOT_B +#endif + +/* The MBX board use SLOT_A */ + +#ifdef CONFIG_MBX +#define CONFIG_PCMCIA_SLOT_A +#endif + +/* The FADS860T board use SLOT_A */ + +#ifdef CONFIG_FADS +#define CONFIG_PCMCIA_SLOT_A +#endif + +/* ------------------------------------------------------------------------- */ + +#define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0 */ +#define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte */ +#define PCMCIA_IO_WIN_BASE _IO_BASE /* base address for io window 0 */ + +#define PCMCIA_SCHLVL PCMCIA_INTERRUPT /* Status Change Interrupt Level */ + +/* ------------------------------------------------------------------------- */ + +#define PCMCIA_SOCKETS_NO 1 + +#define PCMCIA_MEM_WIN_NO 5 +#define PCMCIA_IO_WIN_NO 2 + +/* define _slot_ to be able to optimize macros */ + +#ifdef CONFIG_PCMCIA_SLOT_A +#define _slot_ 0 +#define PCMCIA_SLOT_MSG "SLOT_A" +#else +#define _slot_ 1 +#define PCMCIA_SLOT_MSG "SLOT_B" +#endif + +#define M8XX_BUSFREQ ((((bd_t *)&(__res))->bi_busfreq)) + +static int pcmcia_schlvl = PCMCIA_SCHLVL; + +/* ------------------------------------------------------------------------- */ + +#define PCMCIA_SOCKET_KEY_5V 1 +#define PCMCIA_SOCKET_KEY_LV 2 + + +/* look up table for pgcrx registers */ + +static u_int *m8xx_pgcrx[2] = { + &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcra, + &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcrb +}; + +/* + * This structure is used to address each window in the PCMCIA controller. + * + * Keep in mind that we assume that pcmcia_win_t[n+1] is mapped directly + * after pcmcia_win_t[n]... + */ + +typedef struct { + uint br; + uint or; +} pcmcia_win_t; + +/* + * For some reason the hardware guys decided to make both slots share + * some registers. + * + * Could someone invent object oriented hardware ? + * + * The macros are used to get the right bit from the registers. + * SLOT_A : slot = 0 + * SLOT_B : slot = 1 + */ + +#define M8XX_PCMCIA_VS1(slot) (0x80000000 >> (slot << 4)) +#define M8XX_PCMCIA_VS2(slot) (0x40000000 >> (slot << 4)) +#define M8XX_PCMCIA_VS_MASK(slot) (0xc0000000 >> (slot << 4)) +#define M8XX_PCMCIA_VS_SHIFT(slot) (30 - (slot << 4)) + +#define M8XX_PCMCIA_WP(slot) (0x20000000 >> (slot << 4)) +#define M8XX_PCMCIA_CD2(slot) (0x10000000 >> (slot << 4)) +#define M8XX_PCMCIA_CD1(slot) (0x08000000 >> (slot << 4)) +#define M8XX_PCMCIA_BVD2(slot) (0x04000000 >> (slot << 4)) +#define M8XX_PCMCIA_BVD1(slot) (0x02000000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY(slot) (0x01000000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_L(slot) (0x00800000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_H(slot) (0x00400000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_R(slot) (0x00200000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_F(slot) (0x00100000 >> (slot << 4)) +#define M8XX_PCMCIA_MASK(slot) (0xFFFF0000 >> (slot << 4)) + +#define M8XX_PGCRX(slot) (*m8xx_pgcrx[slot]) + +#define M8XX_PGCRX_CXOE 0x00000080 +#define M8XX_PGCRX_CXRESET 0x00000040 + +/* we keep one lookup table per socket to check flags */ + +#define PCMCIA_EVENTS_MAX 5 /* 4 max at a time + termination */ + +typedef struct { + u_int regbit; + u_int eventbit; +} event_table_t; + +typedef struct socket_info_t { + void (*handler)(void *info, u_int events); + void *info; + + u_int slot; + + socket_state_t state; + struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO]; + struct pccard_io_map io_win[PCMCIA_IO_WIN_NO]; + event_table_t events[PCMCIA_EVENTS_MAX]; +} socket_info_t; + +static socket_info_t socket[PCMCIA_SOCKETS_NO]; + +static socket_cap_t capabilities = { + SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP, /* features - + only 16-bit cards, + memory windows must be + size-aligned */ + 0x000, /* irq_mask - SIU_LEVEL 7 -> 0 */ + 0x1000, /* map_size - 4K minimum window size */ + 0, /* io_offset - */ + 9, /* pci_irq */ + 0 /* No PCI or CardBus support */ +}; + +/* + * Search this table to see if the windowsize is + * supported... + */ + +#define M8XX_SIZES_NO 32 + +static const u_int m8xx_size_to_gray[M8XX_SIZES_NO] = +{ 0x00000001, 0x00000002, 0x00000008, 0x00000004, + 0x00000080, 0x00000040, 0x00000010, 0x00000020, + 0x00008000, 0x00004000, 0x00001000, 0x00002000, + 0x00000100, 0x00000200, 0x00000800, 0x00000400, + + 0x0fffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x01000000, 0x02000000, 0xffffffff, 0x04000000, + 0x00010000, 0x00020000, 0x00080000, 0x00040000, + 0x00800000, 0x00400000, 0x00100000, 0x00200000 }; + + +/* ------------------------------------------------------------------------- */ + +static void m8xx_interrupt(int irq, void *dev, struct pt_regs *regs); + +#define PCMCIA_BMT_LIMIT (15*4) /* Bus Monitor Timeout value */ + +/* ------------------------------------------------------------------------- */ +/* board specific stuff: */ +/* voltage_set(), hardware_enable() and hardware_disable() */ +/* ------------------------------------------------------------------------- */ +/* RPX Boards from Embedded Planet */ + +#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE) + +/* The RPX boards seems to have it's bus monitor timeout set to 6*8 clocks. + * SYPCR is write once only, therefore must the slowest memory be faster + * than the bus monitor or we will get a machine check due to the bus timeout. + */ + +#define PCMCIA_BOARD_MSG "RPX CLASSIC or RPX LITE" + +#undef PCMCIA_BMT_LIMIT +#define PCMCIA_BMT_LIMIT (6*8) + +static int voltage_set(int slot, int vcc, int vpp) +{ + u_int reg = 0; + + switch(vcc) { + case 0: break; + case 33: reg |= BCSR1_PCVCTL4; break; + case 50: reg |= BCSR1_PCVCTL5; break; + default: return 1; + } + + switch(vpp) { + case 0: break; + case 33: + case 50: + if(vcc == vpp) + reg |= BCSR1_PCVCTL6; + else + return 1; + break; + case 120: + reg |= BCSR1_PCVCTL7; + default: return 1; + } + + if(!((vcc == 50) || (vcc == 0))) + return 1; + + /* first, turn off all power */ + + *((uint *)RPX_CSR_ADDR) &= ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5 + | BCSR1_PCVCTL6 | BCSR1_PCVCTL7); + + /* enable new powersettings */ + + *((uint *)RPX_CSR_ADDR) |= reg; + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V +#define hardware_enable(_slot_) /* No hardware to enable */ +#define hardware_disable(_slot_) /* No hardware to disable */ + +#endif /* CONFIG_RPXCLASSIC */ + +/* ------------------------------------------------------------------------- */ +/* FADS Boards from Motorola */ + +#if defined(CONFIG_FADS) + +#define PCMCIA_BOARD_MSG "FADS" + +static int voltage_set(int slot, int vcc, int vpp) +{ + uint reg = 0; + + switch(vcc) { + case 0: break; + case 33: reg |= BCSR1_PCCVCC0; break; + case 50: reg |= BCSR1_PCCVCC1; break; + default: return 1; + } + + switch(vpp) { + case 0: break; + case 33: + case 50: + if(vcc == vpp) + reg |= BCSR1_PCCVPP1; + else + return 1; + break; + case 120: + if ((vcc == 33) || (vcc == 50)) + reg |= BCSR1_PCCVPP0; + else + return 1; + default: return 1; + } + + /* first, turn off all power */ + *((uint *)BCSR1) &= ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK); + + /* enable new powersettings */ + *((uint *)BCSR1) |= reg; + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V + +static void hardware_enable(int slot) +{ + *((uint *)BCSR1) &= ~BCSR1_PCCEN; +} + +static void hardware_disable(int slot) +{ + *((uint *)BCSR1) |= BCSR1_PCCEN; +} + +#endif + +/* ------------------------------------------------------------------------- */ +/* Motorola MBX860 */ + +#if defined(CONFIG_MBX) + +#define PCMCIA_BOARD_MSG "MBX" + +static int voltage_set(int slot, int vcc, int vpp) +{ + unsigned char reg = 0; + + switch(vcc) { + case 0: break; + case 33: reg |= CSR2_VCC_33; break; + case 50: reg |= CSR2_VCC_50; break; + default: return 1; + } + + switch(vpp) { + case 0: break; + case 33: + case 50: + if(vcc == vpp) + reg |= CSR2_VPP_VCC; + else + return 1; + break; + case 120: + if ((vcc == 33) || (vcc == 50)) + reg |= CSR2_VPP_12; + else + return 1; + default: return 1; + } + + /* first, turn off all power */ + *((unsigned char *)MBX_CSR2_ADDR) &= ~(CSR2_VCC_MASK | CSR2_VPP_MASK); + + /* enable new powersettings */ + *((unsigned char *)MBX_CSR2_ADDR) |= reg; + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V +#define hardware_enable(_slot_) /* No hardware to enable */ +#define hardware_disable(_slot_) /* No hardware to disable */ + +#endif /* CONFIG_MBX */ + +/* ------------------------------------------------------------------------- */ + +static void m8xx_shutdown(void) +{ + u_int m; + pcmcia_win_t *w; + + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + + + ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = + M8XX_PCMCIA_MASK(_slot_); + ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per + &= ~M8XX_PCMCIA_MASK(_slot_); + + /* turn off interrupt and disable CxOE */ + + M8XX_PGCRX(_slot_) = M8XX_PGCRX_CXOE; + + /* turn off memory windows */ + + for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { + w->or = 0; /* set to not valid */ + w++; + } + + /* turn off voltage */ + + voltage_set(_slot_, 0, 0); + + /* disable external hardware */ + + hardware_disable(_slot_); + + free_irq(pcmcia_schlvl, NULL); + +} + +/* ------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------- */ + +static u_int pending_events[PCMCIA_SOCKETS_NO]; +static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED; + +static void m8xx_pcmcia_bh(void *dummy) +{ + u_int events; + int i; + + for (i=0; i < PCMCIA_SOCKETS_NO; i++) { + spin_lock_irq(&pending_event_lock); + events = pending_events[i]; + pending_events[i] = 0; + spin_unlock_irq(&pending_event_lock); + /* + SS_DETECT events need a small delay here. The reason for this is that + the "is there a card" electronics need time to see the card after the + "we have a card coming in" electronics have seen it. + */ + if (events & SS_DETECT) + mdelay(4); + if (socket[i].handler) + socket[i].handler(socket[i].info, events); + } +} + +static struct tq_struct m8xx_pcmcia_task = { + routine: m8xx_pcmcia_bh +}; + + +static void m8xx_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + socket_info_t *s; + event_table_t *e; + u_int events, pscr, pipr; + + DEBUG(3,"Interrupt!\n"); + + /* get interrupt sources */ + + pscr = ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr; + pipr = ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr; + + s = &socket[0]; + + if(s->handler) { + + e = &s->events[0]; + events = 0; + + while(e->regbit) { + if(pscr & e->regbit) + events |= e->eventbit; + + e++; + } + + /* + * report only if both card detect signals are the same + * not too nice done, + * we depend on that CD2 is the bit to the left of CD1... + */ + + if(events & SS_DETECT) + if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) + ^ (pipr & M8XX_PCMCIA_CD1(_slot_))) + events &= ~SS_DETECT; + +#ifdef PCMCIA_GLITCHY_CD + + /* + * I've experienced CD problems with my ADS board. + * We make an extra check to see if there was a + * real change of Card detection. + */ + + if((events & SS_DETECT) && + ((pipr & + (M8XX_PCMCIA_CD2(_slot_) | M8XX_PCMCIA_CD1(_slot_))) + == 0) && (s->state.Vcc | s->state.Vpp)) { + events &= ~SS_DETECT; + printk( "CD glitch workaround - CD = 0x%08x!\n", + (pipr & (M8XX_PCMCIA_CD2(_slot_) + | M8XX_PCMCIA_CD1(_slot_)))); + } +#endif + + /* call the handler */ + + DEBUG(3,"slot %u: events = 0x%02x, pscr = 0x%08x, " + "pipr = 0x%08x\n", + _slot_, events, pscr, pipr); + + if(events) { + spin_lock(&pending_event_lock); + pending_events[0] |= events; + spin_unlock(&pending_event_lock); + schedule_task(&m8xx_pcmcia_task); + } + + } + + + /* clear the interrupt sources */ + + ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr; + + DEBUG(3,"Interrupt done.\n"); + +} + +/* ------------------------------------------------------------------------- */ + +static u_int m8xx_get_graycode(u_int size) +{ + u_int k; + + for(k = 0; k < M8XX_SIZES_NO; k++) + if(m8xx_size_to_gray[k] == size) + break; + + if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1)) + k = -1; + + return k; +} + +/* ------------------------------------------------------------------------- */ + +static u_int m8xx_get_speed(u_int ns, u_int is_io) +{ + u_int reg, clocks, psst, psl, psht; + + if(!ns) { + + /* + * We get called with IO maps setup to 0ns + * if not specified by the user. + * They should be 255ns. + */ + + if(is_io) + ns = 255; + else + ns = 100; /* fast memory if 0 */ + } + + /* + * In PSST, PSL, PSHT fields we tell the controller + * timing parameters in CLKOUT clock cycles. + * CLKOUT is the same as GCLK2_50. + */ + +/* how we want to adjust the timing - in percent */ + +#define ADJ 180 /* 80 % longer accesstime - to be sure */ + + + clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000; + clocks = (clocks * ADJ) / (100*1000); + if(clocks >= PCMCIA_BMT_LIMIT) { + printk( "Max access time limit reached\n"); + clocks = PCMCIA_BMT_LIMIT-1; + } + + psst = clocks / 7; /* setup time */ + psht = clocks / 7; /* hold time */ + psl = (clocks * 5) / 7; /* strobe length */ + + psst += clocks - (psst + psht + psl); + + reg = psst << 12; + reg |= psl << 7; + reg |= psht << 16; + + return reg; +} + +/* ------------------------------------------------------------------------- */ + +static int m8xx_register_callback(unsigned int sock, void (*handler)(void *, unsigned int), void * info) +{ + socket[sock].handler = handler; + socket[sock].info = info; + if (handler == NULL) { + MOD_DEC_USE_COUNT; + } + else { + MOD_INC_USE_COUNT; + } + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static int m8xx_get_status(unsigned int lsock, u_int *value) +{ + socket_info_t *s = &socket[lsock]; + u_int pipr, reg; + + + pipr = ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr; + + *value = ((pipr & (M8XX_PCMCIA_CD1(_slot_) + | M8XX_PCMCIA_CD2(_slot_))) == 0) ? SS_DETECT : 0; + *value |= (pipr & M8XX_PCMCIA_WP(_slot_)) ? SS_WRPROT : 0; + + if (s->state.flags & SS_IOCARD) + *value |= (pipr & M8XX_PCMCIA_BVD1(_slot_)) ? SS_STSCHG : 0; + else { + *value |= (pipr & M8XX_PCMCIA_RDY(_slot_)) ? SS_READY : 0; + *value |= (pipr & M8XX_PCMCIA_BVD1(_slot_)) ? SS_BATDEAD : 0; + *value |= (pipr & M8XX_PCMCIA_BVD2(_slot_)) ? SS_BATWARN : 0; + } + + if (s->state.Vcc | s->state.Vpp) + *value |= SS_POWERON; + + /* + * Voltage detection: + * This driver only supports 16-Bit pc-cards. + * Cardbus is not handled here. + * + * To determine what voltage to use we must read the VS1 and VS2 pin. + * Depending on what socket type is present, + * different combinations mean different things. + * + * Card Key Socket Key VS1 VS2 Card Vcc for CIS parse + * + * 5V 5V, LV* NC NC 5V only 5V (if available) + * + * 5V 5V, LV* GND NC 5 or 3.3V as low as possible + * + * 5V 5V, LV* GND GND 5, 3.3, x.xV as low as possible + * + * LV* 5V - - shall not fit into socket + * + * LV* LV* GND NC 3.3V only 3.3V + * + * LV* LV* NC GND x.xV x.xV (if avail.) + * + * LV* LV* GND GND 3.3 or x.xV as low as possible + * + * *LV means Low Voltage + * + * + * That gives us the following table: + * + * Socket VS1 VS2 Voltage + * + * 5V NC NC 5V + * 5V NC GND none (should not be possible) + * 5V GND NC >= 3.3V + * 5V GND GND >= x.xV + * + * LV NC NC 5V (if available) + * LV NC GND x.xV (if available) + * LV GND NC 3.3V + * LV GND GND >= x.xV + * + * So, how do I determine if I have a 5V or a LV + * socket on my board? Look at the socket! + * + * + * Socket with 5V key: + * ++--------------------------------------------+ + * || | + * || || + * || || + * | | + * +---------------------------------------------+ + * + * Socket with LV key: + * ++--------------------------------------------+ + * || | + * | || + * | || + * | | + * +---------------------------------------------+ + * + * + * With other words - LV only cards does not fit + * into the 5V socket! + */ + + /* read out VS1 and VS2 */ + + reg = (pipr & M8XX_PCMCIA_VS_MASK(_slot_)) + >> M8XX_PCMCIA_VS_SHIFT(_slot_); + + if(socket_get(_slot_) == PCMCIA_SOCKET_KEY_LV) { + switch(reg) { + case 1: *value |= SS_3VCARD; break; /* GND, NC - 3.3V only */ + case 2: *value |= SS_XVCARD; break; /* NC. GND - x.xV only */ + }; + } + + DEBUG(3,"GetStatus(%d) = %#2.2x\n", lsock, *value); + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static int m8xx_inquire_socket(unsigned int lsock, socket_cap_t *cap) +{ + *cap = capabilities; + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static int m8xx_get_socket(unsigned int lsock, socket_state_t *state) +{ + *state = socket[lsock].state; /* copy the whole structure */ + + DEBUG(3,"GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x\n", lsock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static int m8xx_set_socket(unsigned int lsock, socket_state_t *state) +{ + socket_info_t *s = &socket[lsock]; + event_table_t *e; + u_int reg; + u_long flags; + + DEBUG(3, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + + /* First, set voltage - bail out if invalid */ + + if(voltage_set(_slot_, state->Vcc, state->Vpp)) + return -EINVAL; + + + /* Take care of reset... */ + + if(state->flags & SS_RESET) + M8XX_PGCRX(_slot_) |= M8XX_PGCRX_CXRESET; /* active high */ + else + M8XX_PGCRX(_slot_) &= ~M8XX_PGCRX_CXRESET; + + /* ... and output enable. */ + + /* The CxOE signal is connected to a 74541 on the ADS. + I guess most other boards used the ADS as a reference. + I tried to control the CxOE signal with SS_OUTPUT_ENA, + but the reset signal seems connected via the 541. + If the CxOE is left high are some signals tristated and + no pullups are present -> the cards act wierd. + So right now the buffers are enabled if the power is on. */ + + if(state->Vcc || state->Vpp) + M8XX_PGCRX(_slot_) &= ~M8XX_PGCRX_CXOE; /* active low */ + else + M8XX_PGCRX(_slot_) |= M8XX_PGCRX_CXOE; + + /* + * We'd better turn off interrupts before + * we mess with the events-table.. + */ + + save_flags(flags); + cli(); + + /* + * Play around with the interrupt mask to be able to + * give the events the generic pcmcia driver wants us to. + */ + + e = &s->events[0]; + reg = 0; + + if(state->csc_mask & SS_DETECT) { + e->eventbit = SS_DETECT; + reg |= e->regbit = (M8XX_PCMCIA_CD2(_slot_) + | M8XX_PCMCIA_CD1(_slot_)); + e++; + } + + if(state->flags & SS_IOCARD) { + + /* + * I/O card + */ + + if(state->csc_mask & SS_STSCHG) { + e->eventbit = SS_STSCHG; + reg |= e->regbit = M8XX_PCMCIA_BVD1(_slot_); + e++; + } + + + /* + * If io_irq is non-zero we should enable irq. + */ + + if(state->io_irq) { + M8XX_PGCRX(_slot_) |= + mk_int_int_mask(state->io_irq) << 24; + + /* + * Strange thing here: + * The manual does not tell us which interrupt + * the sources generate. + * Anyhow, I found out that RDY_L generates IREQLVL. + * + * We use level triggerd interrupts, and they don't + * have to be cleared in PSCR in the interrupt handler. + */ + + reg |= M8XX_PCMCIA_RDY_L(_slot_); + } + else + M8XX_PGCRX(_slot_) &= 0x00ffffff; + + } + else { + + /* + * Memory card + */ + + if(state->csc_mask & SS_BATDEAD) { + e->eventbit = SS_BATDEAD; + reg |= e->regbit = M8XX_PCMCIA_BVD1(_slot_); + e++; + } + + if(state->csc_mask & SS_BATWARN) { + e->eventbit = SS_BATWARN; + reg |= e->regbit = M8XX_PCMCIA_BVD2(_slot_); + e++; + } + + /* What should I trigger on - low/high,raise,fall? */ + if(state->csc_mask & SS_READY) { + e->eventbit = SS_READY; + reg |= e->regbit = 0; //?? + e++; + } + } + + e->regbit = 0; /* terminate list */ + + /* + * Clear the status changed . + * Port A and Port B share the same port. + * Writing ones will clear the bits. + */ + + ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = reg; + + /* + * Write the mask. + * Port A and Port B share the same port. + * Need for read-modify-write. + * Ones will enable the interrupt. + */ + + reg |= ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per + & M8XX_PCMCIA_MASK(_slot_); + + ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per = reg; + + restore_flags(flags); + + /* copy the struct and modify the copy */ + + s->state = *state; + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static int m8xx_get_io_map(unsigned int lsock, struct pccard_io_map *io) +{ + if(io->map >= PCMCIA_IO_WIN_NO) + return -EINVAL; + + *io = socket[lsock].io_win[io->map]; /* copy the struct */ + + DEBUG(3,"GetIOMap(%d, %d) = %#2.2x, %d ns, " + "%#4.4x-%#4.4x\n", lsock, io->map, io->flags, + io->speed, io->start, io->stop); + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static int m8xx_set_io_map(unsigned int lsock, struct pccard_io_map *io) +{ + socket_info_t *s = &socket[lsock]; + pcmcia_win_t *w; + u_int reg, winnr; + + +#define M8XX_SIZE (io->stop - io->start + 1) +#define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start) + + DEBUG(3, "SetIOMap(%d, %d, %#2.2x, %d ns, " + "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags, + io->speed, io->start, io->stop); + + if ((io->map >= PCMCIA_IO_WIN_NO) || (io->start > 0xffff) + || (io->stop > 0xffff) || (io->stop < io->start)) + return -EINVAL; + + if((reg = m8xx_get_graycode(M8XX_SIZE)) == -1) + return -EINVAL; + + if(io->flags & MAP_ACTIVE) { + + winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO) + + (lsock * PCMCIA_IO_WIN_NO) + io->map; + + /* setup registers */ + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w += winnr; + + w->or = 0; /* turn off window first */ + w->br = M8XX_BASE; + + reg <<= 27; + reg |= 0x00018 + (_slot_ << 2); + + reg |= m8xx_get_speed(io->speed, 1); + + if(io->flags & MAP_WRPROT) + reg |= 0x00000002; + + if(io->flags & (MAP_16BIT | MAP_AUTOSZ)) + reg |= 0x00000040; + + if(io->flags & MAP_ACTIVE) + reg |= 0x00000001; + + w->or = reg; + + DEBUG(3,"Socket %u: Mapped io window %u at %#8.8x, " + "OR = %#8.8x.\n", lsock, io->map, w->br, w->or); + } + + + /* copy the struct and modify the copy */ + + s->io_win[io->map] = *io; + s->io_win[io->map].flags &= (MAP_WRPROT + | MAP_16BIT + | MAP_ACTIVE); + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static int m8xx_get_mem_map(unsigned int lsock, struct pccard_mem_map *mem) +{ + if(mem->map >= PCMCIA_MEM_WIN_NO) + return -EINVAL; + + *mem = socket[lsock].mem_win[mem->map]; /* copy the struct */ + + DEBUG(3, "GetMemMap(%d, %d) = %#2.2x, %d ns, " + "%#5.5lx-%#5.5lx, %#5.5x\n", lsock, mem->map, mem->flags, + mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static int m8xx_set_mem_map(unsigned int lsock, struct pccard_mem_map *mem) +{ + socket_info_t *s = &socket[lsock]; + pcmcia_win_t *w; + struct pccard_mem_map *old; + u_int reg, winnr; + + DEBUG(3, "SetMemMap(%d, %d, %#2.2x, %d ns, " + "%#5.5lx-%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, + mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); + + if ((mem->map >= PCMCIA_MEM_WIN_NO) || (mem->sys_start > mem->sys_stop) + || ((mem->sys_stop - mem->sys_start) >= PCMCIA_MEM_WIN_SIZE) + || (mem->card_start >= 0x04000000) + || (mem->sys_start & 0xfff) /* 4KByte resolution */ + || (mem->card_start & 0xfff)) + return -EINVAL; + + if((reg = m8xx_get_graycode(PCMCIA_MEM_WIN_SIZE)) == -1) { + printk( "Cannot set size to 0x%08x.\n", PCMCIA_MEM_WIN_SIZE); + return -EINVAL; + } + + winnr = (lsock * PCMCIA_MEM_WIN_NO) + mem->map; + + /* Setup the window in the pcmcia controller */ + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w += winnr; + + reg <<= 27; + reg |= _slot_ << 2; + + reg |= m8xx_get_speed(mem->speed, 0); + + if(mem->flags & MAP_ATTRIB) + reg |= 0x00000010; + + if(mem->flags & MAP_WRPROT) + reg |= 0x00000002; + + if(mem->flags & MAP_16BIT) + reg |= 0x00000040; + + if(mem->flags & MAP_ACTIVE) + reg |= 0x00000001; + + w->or = reg; + + DEBUG(3, "Socket %u: Mapped memory window %u at %#8.8x, " + "OR = %#8.8x.\n", lsock, mem->map, w->br, w->or); + + if(mem->flags & MAP_ACTIVE) { + + mem->sys_stop -= mem->sys_start; + + /* get the new base address */ + + mem->sys_start = PCMCIA_MEM_WIN_BASE + + (PCMCIA_MEM_WIN_SIZE * winnr) + + mem->card_start; + + mem->sys_stop += mem->sys_start; + } + +DEBUG(3, "SetMemMap(%d, %d, %#2.2x, %d ns, " + "%#5.5lx-%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, + mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); + + /* copy the struct and modify the copy */ + + old = &s->mem_win[mem->map]; + + *old = *mem; + old->flags &= (MAP_ATTRIB + | MAP_WRPROT + | MAP_16BIT + | MAP_ACTIVE); + + return 0; +} + +static int m8xx_sock_init(unsigned int s) +{ + int i; + pccard_io_map io = { 0, 0, 0, 0, 1 }; + pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; + + DEBUG(3, "sock_init(%d)\n", s); + + mem.sys_stop = 0x1000; + m8xx_set_socket(s, &dead_socket); + for (i = 0; i < PCMCIA_IO_WIN_NO; i++) { + io.map = i; + m8xx_set_io_map(s, &io); + } + for (i = 0; i < PCMCIA_MEM_WIN_NO; i++) { + mem.map = i; + m8xx_set_mem_map(s, &mem); + } + + return 0; + +} + +static int m8xx_suspend(unsigned int s) +{ + return(m8xx_set_socket(s, &dead_socket)); +} +static void m8xx_proc_setup(unsigned int sock, struct proc_dir_entry *base) +{ +} +/* ------------------------------------------------------------------------- */ + +static struct pccard_operations m8xx_services = { + &m8xx_sock_init, + &m8xx_suspend, + &m8xx_register_callback, + &m8xx_inquire_socket, + &m8xx_get_status, + &m8xx_get_socket, + &m8xx_set_socket, + &m8xx_get_io_map, + &m8xx_set_io_map, + &m8xx_get_mem_map, + &m8xx_set_mem_map, + &m8xx_proc_setup +}; + +static int __init m8xx_init(void) +{ + servinfo_t serv; + pcmcia_win_t *w; + u_int m; + + PCMCIA_INFO("%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + PCMCIA_ERROR("Card Services release does not match!\n"); + return -1; + } + + PCMCIA_INFO(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG + " with IRQ %u.\n", pcmcia_schlvl); + + /* Configure Status change interrupt */ + + if(request_8xxirq(pcmcia_schlvl, m8xx_interrupt, 0, + "m8xx_pcmcia", NULL)) { + PCMCIA_ERROR("Cannot allocate IRQ %u for SCHLVL!\n", + pcmcia_schlvl); + return -1; + } + + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + + socket[0].slot = _slot_; + + ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = + M8XX_PCMCIA_MASK(_slot_); + ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per + &= ~M8XX_PCMCIA_MASK(_slot_); + +/* connect interrupt and disable CxOE */ + + M8XX_PGCRX(_slot_) = M8XX_PGCRX_CXOE | + (mk_int_int_mask(pcmcia_schlvl) << 16); + +/* intialize the fixed memory windows */ + + for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { + w->br = PCMCIA_MEM_WIN_BASE + + (PCMCIA_MEM_WIN_SIZE + * (m + 0 * PCMCIA_MEM_WIN_NO)); + + w->or = 0; /* set to not valid */ + + DEBUG(3,"Socket %u: MemWin %u: Base 0x%08x.\n", + 0, m, w->br); + + w++; + } + +/* turn off voltage */ + voltage_set(_slot_, 0, 0); + +/* Enable external hardware */ + hardware_enable(_slot_); + + if(register_ss_entry(PCMCIA_SOCKETS_NO, &m8xx_services) != 0) { + PCMCIA_ERROR("register_ss_entry() failed.\n"); + m8xx_shutdown(); + return -ENODEV; + } + + return 0; +} + +static void __exit m8xx_exit(void) +{ + unregister_ss_entry(&m8xx_services); + + m8xx_shutdown(); +} + +module_init(m8xx_init); +module_exit(m8xx_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/pci_socket.h linux-2.5/drivers/pcmcia/pci_socket.h --- linux-2.5.20/drivers/pcmcia/pci_socket.h Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/pcmcia/pci_socket.h Sun Mar 3 17:54:35 2002 @@ -23,7 +23,9 @@ struct socket_info_t *pcmcia_socket; struct tq_struct tq_task; struct timer_list poll_timer; - + /* Zoom video behaviour is so chip specific its not worth adding + this to _ops */ + void (*zoom_video)(struct pci_socket *, int); /* A few words of private data for the low-level driver.. */ unsigned int private[8]; } pci_socket_t; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/ricoh.h linux-2.5/drivers/pcmcia/ricoh.h --- linux-2.5.20/drivers/pcmcia/ricoh.h Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/pcmcia/ricoh.h Sat Apr 13 17:42:56 2002 @@ -110,6 +110,8 @@ #define RL5C4XX_CMD_SHIFT 4 #define RL5C4XX_HOLD_MASK 0x1c00 #define RL5C4XX_HOLD_SHIFT 10 +#define RL5C4XX_MISC_CONTROL 0x2F /* 8 bit */ +#define RL5C4XX_ZV_ENABLE 0x08 #ifdef __YENTA_H @@ -134,14 +136,45 @@ return 0; } +static void ricoh_zoom_video(pci_socket_t *socket, int onoff) +{ + u8 reg; + + reg = exca_readb(socket, RL5C4XX_MISC_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= RL5C4XX_ZV_ENABLE; + else + reg &= ~RL5C4XX_ZV_ENABLE; + + exca_writeb(socket, RL5C4XX_MISC_CONTROL, reg); +} + +static void ricoh_set_zv(pci_socket_t *socket) +{ + if(socket->dev->vendor == PCI_VENDOR_ID_RICOH) + { + switch(socket->dev->device) + { + /* There may be more .. */ + case PCI_DEVICE_ID_RICOH_RL5C478: + socket->zoom_video = ricoh_zoom_video; + break; + } + } +} + + static int ricoh_init(pci_socket_t *socket) { yenta_init(socket); + ricoh_set_zv(socket); config_writew(socket, RL5C4XX_MISC, rl_misc(socket)); config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket)); config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket)); config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket)); + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/rsrc_mgr.c linux-2.5/drivers/pcmcia/rsrc_mgr.c --- linux-2.5.20/drivers/pcmcia/rsrc_mgr.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/pcmcia/rsrc_mgr.c Thu Dec 13 16:32:36 2001 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -103,8 +104,82 @@ ======================================================================*/ -#define check_io_resource(b,n) check_resource(&ioport_resource, (b), (n)) -#define check_mem_resource(b,n) check_resource(&iomem_resource, (b), (n)) +static struct resource *resource_parent(unsigned long b, unsigned long n, + int flags, struct pci_dev *dev) +{ +#ifdef CONFIG_PCI + struct resource res, *pr; + + if (dev != NULL) { + res.start = b; + res.end = b + n - 1; + res.flags = flags; + pr = pci_find_parent_resource(dev, &res); + if (pr) + return pr; + } +#endif /* CONFIG_PCI */ + if (flags & IORESOURCE_MEM) + return &iomem_resource; + return &ioport_resource; +} + +static inline int check_io_resource(unsigned long b, unsigned long n, + struct pci_dev *dev) +{ + return check_resource(resource_parent(b, n, IORESOURCE_IO, dev), b, n); +} + +static inline int check_mem_resource(unsigned long b, unsigned long n, + struct pci_dev *dev) +{ + return check_resource(resource_parent(b, n, IORESOURCE_MEM, dev), b, n); +} + +static struct resource *make_resource(unsigned long b, unsigned long n, + int flags, char *name) +{ + struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL); + + if (res) { + memset(res, 0, sizeof(*res)); + res->name = name; + res->start = b; + res->end = b + n - 1; + res->flags = flags | IORESOURCE_BUSY; + } + return res; +} + +static int request_io_resource(unsigned long b, unsigned long n, + char *name, struct pci_dev *dev) +{ + struct resource *res = make_resource(b, n, IORESOURCE_IO, name); + struct resource *pr = resource_parent(b, n, IORESOURCE_IO, dev); + int err = -ENOMEM; + + if (res) { + err = request_resource(pr, res); + if (err) + kfree(res); + } + return err; +} + +static int request_mem_resource(unsigned long b, unsigned long n, + char *name, struct pci_dev *dev) +{ + struct resource *res = make_resource(b, n, IORESOURCE_MEM, name); + struct resource *pr = resource_parent(b, n, IORESOURCE_MEM, dev); + int err = -ENOMEM; + + if (res) { + err = request_resource(pr, res); + if (err) + kfree(res); + } + return err; +} /*====================================================================== @@ -194,7 +269,7 @@ } memset(b, 0, 256); for (i = base, most = 0; i < base+num; i += 8) { - if (check_io_resource(i, 8)) + if (check_io_resource(i, 8, NULL)) continue; hole = inb(i); for (j = 1; j < 8; j++) @@ -207,7 +282,7 @@ bad = any = 0; for (i = base; i < base+num; i += 8) { - if (check_io_resource(i, 8)) + if (check_io_resource(i, 8, NULL)) continue; for (j = 0; j < 8; j++) if (inb(i+j) != most) break; @@ -247,7 +322,8 @@ ======================================================================*/ static int do_mem_probe(u_long base, u_long num, - int (*is_valid)(u_long), int (*do_cksum)(u_long)) + int (*is_valid)(u_long), int (*do_cksum)(u_long), + socket_info_t *s) { u_long i, j, bad, fail, step; @@ -258,13 +334,14 @@ for (i = j = base; i < base+num; i = j + step) { if (!fail) { for (j = i; j < base+num; j += step) - if ((check_mem_resource(j, step) == 0) && is_valid(j)) + if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) && + is_valid(j)) break; fail = ((i == base) && (j == base+num)); } if (fail) { for (j = i; j < base+num; j += 2*step) - if ((check_mem_resource(j, 2*step) == 0) && + if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) && do_cksum(j) && do_cksum(j+step)) break; } @@ -283,12 +360,12 @@ static u_long inv_probe(int (*is_valid)(u_long), int (*do_cksum)(u_long), - resource_map_t *m) + resource_map_t *m, socket_info_t *s) { u_long ok; if (m == &mem_db) return 0; - ok = inv_probe(is_valid, do_cksum, m->next); + ok = inv_probe(is_valid, do_cksum, m->next, s); if (ok) { if (m->base >= 0x100000) sub_interval(&mem_db, m->base, m->num); @@ -296,11 +373,11 @@ } if (m->base < 0x100000) return 0; - return do_mem_probe(m->base, m->num, is_valid, do_cksum); + return do_mem_probe(m->base, m->num, is_valid, do_cksum, s); } void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low) + int force_low, socket_info_t *s) { resource_map_t *m, *n; static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; @@ -310,7 +387,7 @@ if (!probe_mem) return; /* We do up to four passes through the list */ if (!force_low) { - if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0)) + if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0)) return; printk(KERN_NOTICE "cs: warning: no high memory space " "available!\n"); @@ -321,7 +398,7 @@ /* Only probe < 1 MB */ if (m->base >= 0x100000) continue; if ((m->base | m->num) & 0xffff) { - ok += do_mem_probe(m->base, m->num, is_valid, do_cksum); + ok += do_mem_probe(m->base, m->num, is_valid, do_cksum, s); continue; } /* Special probe for 64K-aligned block */ @@ -331,7 +408,7 @@ if (ok >= mem_limit) sub_interval(&mem_db, b, 0x10000); else - ok += do_mem_probe(b, 0x10000, is_valid, do_cksum); + ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s); } } } @@ -340,7 +417,7 @@ #else /* CONFIG_ISA */ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low) + int force_low, socket_info_t *s) { resource_map_t *m; static int done = 0; @@ -348,7 +425,7 @@ if (!probe_mem || done++) return; for (m = mem_db.next; m != &mem_db; m = m->next) - if (do_mem_probe(m->base, m->num, is_valid, do_cksum)) + if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s)) return; } @@ -368,7 +445,7 @@ ======================================================================*/ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, - char *name) + char *name, socket_info_t *s) { ioaddr_t try; resource_map_t *m; @@ -378,9 +455,8 @@ for (try = (try >= m->base) ? try : try+align; (try >= m->base) && (try+num <= m->base+m->num); try += align) { - if (check_io_resource(try, num) == 0) { + if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) { *base = try; - request_region(try, num, name); return 0; } if (!align) break; @@ -390,7 +466,7 @@ } int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name) + int force_low, char *name, socket_info_t *s) { u_long try; resource_map_t *m; @@ -403,8 +479,7 @@ for (try = (try >= m->base) ? try : try+align; (try >= m->base) && (try+num <= m->base+m->num); try += align) { - if (check_mem_resource(try, num) == 0) { - request_mem_region(try, num, name); + if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) { *base = try; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/ti113x.h linux-2.5/drivers/pcmcia/ti113x.h --- linux-2.5.20/drivers/pcmcia/ti113x.h Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/pcmcia/ti113x.h Sun Mar 31 15:11:50 2002 @@ -170,9 +170,88 @@ return 0; } +/* + * Zoom video control for TI122x/113x chips + */ + +static void ti_zoom_video(pci_socket_t *socket, int onoff) +{ + u8 reg; + + /* If we don't have a Zoom Video switch this is harmless, + we just tristate the unused (ZV) lines */ + reg = config_readb(socket, TI113X_CARD_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= TI113X_CCR_ZVENABLE; + else + reg &= ~TI113X_CCR_ZVENABLE; + config_writeb(socket, TI113X_CARD_CONTROL, reg); +} + +/* + * The 145x series can also use this. They have an additional + * ZV autodetect mode we don't use but don't actually need. + * FIXME: manual says its in func0 and func1 but disagrees with + * itself about this - do we need to force func0, if so we need + * to know a lot more about socket pairings in pci_socket than we + * do now.. uggh. + */ + +static void ti1250_zoom_video(pci_socket_t *socket, int onoff) +{ + int shift = 0; + u8 reg; + + ti_zoom_video(socket, onoff); + + reg = config_readb(socket, 0x84); + reg |= (1<<7); /* ZV bus enable */ + + if(PCI_FUNC(socket->dev->devfn)==1) + shift = 1; + + if(onoff) + { + reg &= ~(1<<6); /* Clear select bit */ + reg |= shift<<6; /* Favour our socket */ + reg |= 1<dev->vendor == PCI_VENDOR_ID_TI) + { + switch(socket->dev->device) + { + /* There may be more .. */ + case PCI_DEVICE_ID_TI_1220: + case PCI_DEVICE_ID_TI_1221: + case PCI_DEVICE_ID_TI_1225: + socket->zoom_video = ti_zoom_video; + break; + case PCI_DEVICE_ID_TI_1250: + case PCI_DEVICE_ID_TI_1251A: + case PCI_DEVICE_ID_TI_1251B: + case PCI_DEVICE_ID_TI_1450: + socket->zoom_video = ti1250_zoom_video; + } + } +} + static int ti_init(pci_socket_t *socket) { yenta_init(socket); + ti_set_zv(socket); ti_intctl(socket); return 0; } @@ -251,7 +330,7 @@ static int ti1250_init(pci_socket_t *socket) { yenta_init(socket); - + ti_set_zv(socket); config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket)); ti_intctl(socket); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pcmcia/yenta.c linux-2.5/drivers/pcmcia/yenta.c --- linux-2.5.20/drivers/pcmcia/yenta.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/pcmcia/yenta.c Mon Feb 4 16:35:16 2002 @@ -234,6 +234,8 @@ static int yenta_set_socket(pci_socket_t *socket, socket_state_t *state) { + /* hack for the moment */ + static void yenta_set_zoomvideo(pci_socket_t *s, int onoff); u16 bridge; if (state->flags & SS_DEBOUNCED) { @@ -286,6 +288,8 @@ } exca_writeb(socket, I365_CSCINT, reg); exca_readb(socket, I365_CSC); + + yenta_set_zoomvideo(socket, state->flags & SS_ZVCARD); } config_writew(socket, CB_BRIDGE_CONTROL, bridge); /* Socket event mask: get card insert/remove events.. */ @@ -688,7 +692,7 @@ /* * This does not work currently. The controller - * loses too much informationduring D3 to come up + * loses too much information during D3 to come up * cleanly. We should probably fix yenta_init() * to update all the critical registers, notably * the IO and MEM bridging region data.. That is @@ -783,6 +787,29 @@ #include "ti113x.h" #include "ricoh.h" + +/* + * This belongs somewhere else - maybe as a pci socket op - as + * it is only valid for TI devices + */ + +static void yenta_set_zoomvideo(pci_socket_t *socket, int onoff) +{ + u8 reg; + + if(socket->dev->vendor != PCI_VENDOR_ID_TI) + return; + + /* If we don't have a Zoom Video switch this is harmless, + we just tristate the unused (ZV) lines */ + reg = config_readb(socket, TI113X_CARD_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= TI113X_CCR_ZVENABLE; + else + reg &= ~TI113X_CCR_ZVENABLE; + config_writeb(socket, TI113X_CARD_CONTROL, reg); +} /* * Different cardbus controllers have slightly different diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/pnp/isapnp.c linux-2.5/drivers/pnp/isapnp.c --- linux-2.5.20/drivers/pnp/isapnp.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/pnp/isapnp.c Sat Mar 23 22:55:28 2002 @@ -56,10 +56,6 @@ #define ISAPNP_DEBUG #endif -struct resource *pidxr_res; -struct resource *pnpwrp_res; -struct resource *isapnp_rdp_res; - int isapnp_disable; /* Disable ISA PnP */ int isapnp_rdp; /* Read Data Port */ int isapnp_reset = 1; /* reset all PnP cards (deactivate) */ @@ -2147,13 +2143,10 @@ static void isapnp_free_all_resources(void) { #ifdef ISAPNP_REGION_OK - if (pidxr_res) - release_resource(pidxr_res); + release_region(_PIDXR, 1); #endif - if (pnpwrp_res) - release_resource(pnpwrp_res); - if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff && isapnp_rdp_res) - release_resource(isapnp_rdp_res); + release_region(_PNPWRP, 1); + release_region(isapnp_rdp, 1); #ifdef MODULE #ifdef CONFIG_PROC_FS isapnp_proc_done(); @@ -2317,14 +2310,12 @@ return 0; } #ifdef ISAPNP_REGION_OK - pidxr_res=request_region(_PIDXR, 1, "isapnp index"); - if(!pidxr_res) { + if (!request_region(_PIDXR, 1, "isapnp index")) { printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR); return -EBUSY; } #endif - pnpwrp_res=request_region(_PNPWRP, 1, "isapnp write"); - if(!pnpwrp_res) { + if (!request_region(_PNPWRP, 1, "isapnp write")) { printk(KERN_ERR "isapnp: Write Data Register 0x%x already used\n", _PNPWRP); #ifdef ISAPNP_REGION_OK release_region(_PIDXR, 1); @@ -2340,13 +2331,12 @@ printk(KERN_INFO "isapnp: Scanning for PnP cards...\n"); if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) { isapnp_rdp |= 3; - isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read"); - if(!isapnp_rdp_res) { + if (!request_region(isapnp_rdp, 1, "isapnp read")) { printk(KERN_ERR "isapnp: Read Data Register 0x%x already used\n", isapnp_rdp); #ifdef ISAPNP_REGION_OK release_region(_PIDXR, 1); #endif - release_region(isapnp_rdp, 1); + release_region(_PNPWRP, 1); return -EBUSY; } isapnp_set_rdp(); @@ -2356,12 +2346,15 @@ cards = isapnp_isolate(); if (cards < 0 || (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) { - isapnp_free_all_resources(); +#ifdef ISAPNP_REGION_OK + release_region(_PIDXR, 1); +#endif + release_region(_PNPWRP, 1); isapnp_detected = 0; printk(KERN_INFO "isapnp: No Plug & Play device found\n"); return 0; } - isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read"); + request_region(isapnp_rdp, 1, "isapnp read"); } isapnp_build_device_list(); cards = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/s390/Config.help linux-2.5/drivers/s390/Config.help --- linux-2.5.20/drivers/s390/Config.help Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/s390/Config.help Tue Mar 26 11:45:21 2002 @@ -321,6 +321,18 @@ CONFIG_DASD_FBA FBA devices are currently unsupported. +CONFIG_DASD_AUTO_DIAG + Enable this option if you want your DIAG discipline module loaded + on DASD driver startup. + +CONFIG_DASD_AUTO_ECKD + Enable this option if you want your ECKD discipline module loaded + on DASD driver startup. + +CONFIG_DASD_AUTO_FBA + Enable this option if you want your FBA discipline module loaded + on DASD driver startup. + CONFIG_TN3215 Include support for IBM 3215 line-mode terminals. @@ -342,6 +354,15 @@ CONFIG_HWC_CONSOLE Include support for using an IBM HWC line-mode terminal as the Linux system console. + +CONFIG_HWC_CPI + This option enables the hardware console interface for system + identification This is commonly used for workload management and + gives you a nice name for the system on the service element. + Please select this option as a module since built-in operation is + completely untested. + You should only select this option if you know what you are doing, + need this feature and intend to run your kernel in LPAR. CONFIG_S390_TAPE Select this option if you want to access channel-attached tape diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/s390/ccwcache.c linux-2.5/drivers/s390/ccwcache.c --- linux-2.5.20/drivers/s390/ccwcache.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/s390/ccwcache.c Fri May 3 03:49:07 2002 @@ -291,9 +291,11 @@ /* Shrink the caches, if available */ for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) { if ( ccw_cache[cachind] ) { +#if 0 /* this is useless and could cause an OOPS in the worst case */ if ( kmem_cache_shrink(ccw_cache[cachind]) == 0 ) { ccw_cache[cachind] = NULL; } +#endif kmem_cache_destroy(ccw_cache[cachind]); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/s390/char/ctrlchar.c linux-2.5/drivers/s390/char/ctrlchar.c --- linux-2.5.20/drivers/s390/char/ctrlchar.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/s390/char/ctrlchar.c Sun Mar 3 23:50:42 2002 @@ -26,7 +26,7 @@ static void ctrlchar_handle_sysrq(struct tty_struct *tty) { - handle_sysrq(ctrlchar_sysrq_key, NULL, NULL, tty); + handle_sysrq(ctrlchar_sysrq_key, NULL, tty); } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/s390/misc/chandev.c linux-2.5/drivers/s390/misc/chandev.c --- linux-2.5.20/drivers/s390/misc/chandev.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/s390/misc/chandev.c Mon Jun 3 17:10:22 2002 @@ -902,25 +902,6 @@ (int)lo_devno,(int)hi_devno); return; } - chandev_lock(); - for_each(parms,chandev_parms_head) - { - if(chan_type&(parms->chan_type)) - { - u16 lomax=MAX(parms->lo_devno,lo_devno), - himin=MIN(parms->hi_devno,lo_devno); - if(lomax<=himin) - { - chandev_unlock(); - printk("chandev_add_parms detected overlapping " - "parameter definitions for chan_type=0x%02x" - " lo_devno=0x%04x hi_devno=0x%04x\n," - " do a del_parms.",chan_type,(int)lo_devno,(int)hi_devno); - return; - } - } - } - chandev_unlock(); if((parms=chandev_allocstr(parmstr,offsetof(chandev_parms,parmstr)))) { parms->chan_type=chan_type; @@ -1724,8 +1705,16 @@ read->sch.devno>=curr_parms->lo_devno&& read->sch.devno<=curr_parms->hi_devno) { - probeinfo.parmstr=curr_parms->parmstr; - break; + if (!probeinfo.parmstr) { + probeinfo.parmstr = vmalloc(sizeof(curr_parms->parmstr)+1); + strcpy(probeinfo.parmstr, curr_parms->parmstr); + } else { + char *buf; + + buf = vmalloc(strlen(probeinfo.parmstr)+strlen(curr_parms->parmstr)+2); + sprintf(buf, "%s,%s",probeinfo.parmstr, curr_parms->parmstr); + probeinfo.parmstr=buf; + } } } if(force) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/sbus/char/jsflash.c linux-2.5/drivers/sbus/char/jsflash.c --- linux-2.5.20/drivers/sbus/char/jsflash.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/sbus/char/jsflash.c Sat May 25 19:52:05 2002 @@ -43,11 +43,8 @@ #define MAJOR_NR JSFD_MAJOR #define DEVICE_NAME "jsfd" -#define DEVICE_REQUEST jsfd_do_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) -#define DEVICE_NO_RANDOM +#define LOCAL_END_REQUEST #include @@ -198,6 +195,14 @@ } } +static inline void jfsd_end_request(struct request *req, int uptodate) +{ + if (!end_that_request_first(req, uptodate, req->hard_cur_sectors)) { + blkdev_dequeue_request(req); + end_that_request_last(req); + } +} + static void jsfd_do_request(request_queue_t *q) { struct request *req; @@ -205,6 +210,7 @@ struct jsfd_part *jdp; unsigned long offset; size_t len; + int uptodate; for (;;) { if (blk_queue_empty(QUEUE)) { @@ -216,7 +222,7 @@ dev = MINOR(req->rq_dev); if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { - end_request(0); + jfsd_end_request(req, 0); continue; } jdp = &jsf0.dv[dev & JSF_PART_MASK]; @@ -224,31 +230,31 @@ offset = req->sector << 9; len = req->current_nr_sectors << 9; if ((offset + len) > jdp->dsize) { - end_request(0); + jfsd_end_request(req, 0); continue; } if (req->cmd == WRITE) { printk(KERN_ERR "jsfd: write\n"); - end_request(0); + jfsd_end_request(req, 0); continue; } if (req->cmd != READ) { printk(KERN_ERR "jsfd: bad req->cmd %d\n", req->cmd); - end_request(0); + jfsd_end_request(req, 0); continue; } if ((jdp->dbase & 0xff000000) != 0x20000000) { printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase); - end_request(0); + jfsd_end_request(req, 0); continue; } /* printk("jsfd%d: read buf %p off %x len %x\n", dev, req->buffer, (int)offset, (int)len); */ /* P3 */ jsfd_read(req->buffer, jdp->dbase + offset, len); - end_request(1); + jfsd_end_request(req, 1); } } @@ -668,7 +674,7 @@ blk_size[JSFD_MAJOR] = jsfd_sizes; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), jsfd_do_request); for (i = 0; i < JSF_MAX; i++) { if ((i & JSF_PART_MASK) >= JSF_NPART) continue; jsf = &jsf0; /* actually, &jsfv[i >> JSF_PART_BITS] */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/sbus/char/riowatchdog.c linux-2.5/drivers/sbus/char/riowatchdog.c --- linux-2.5.20/drivers/sbus/char/riowatchdog.c Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/sbus/char/riowatchdog.c Thu Jan 24 19:36:18 2002 @@ -1,4 +1,4 @@ -/* $Id: riowatchdog.c,v 1.3 2001/10/08 22:19:51 davem Exp $ +/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $ * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -127,8 +127,11 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - static struct watchdog_info info = { 0, 0, "Natl. Semiconductor PC97317" }; + static struct watchdog_info info = { + WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317" + }; unsigned int options; + int new_margin; switch (cmd) { case WDIOC_GETSUPPORT: @@ -158,6 +161,18 @@ return -EINVAL; break; + + case WDIOC_SETTIMEOUT: + if (get_user(new_margin, (int *)arg)) + return -EFAULT; + if ((new_margin < 60) || (new_margin > (255 * 60))) + return -EINVAL; + riowd_timeout = (new_margin + 59) / 60; + riowd_pingtimer(); + /* Fall */ + + case WDIOC_GETTIMEOUT: + return put_user(riowd_timeout * 60, (int *)arg); default: return -EINVAL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/sbus/char/sab82532.c linux-2.5/drivers/sbus/char/sab82532.c --- linux-2.5.20/drivers/sbus/char/sab82532.c Mon Jun 3 02:44:47 2002 +++ linux-2.5/drivers/sbus/char/sab82532.c Tue Jan 15 12:22:32 2002 @@ -2251,7 +2251,9 @@ serial_driver.table = sab82532_table; serial_driver.termios = sab82532_termios; serial_driver.termios_locked = sab82532_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sab82532_console; +#endif serial_driver.open = sab82532_open; serial_driver.close = sab82532_close; serial_driver.write = sab82532_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/sbus/char/su.c linux-2.5/drivers/sbus/char/su.c --- linux-2.5.20/drivers/sbus/char/su.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/sbus/char/su.c Tue Jan 15 12:22:32 2002 @@ -2506,7 +2506,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = su_open; serial_driver.close = su_close; serial_driver.write = su_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/sbus/char/sunkbd.c linux-2.5/drivers/sbus/char/sunkbd.c --- linux-2.5.20/drivers/sbus/char/sunkbd.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/sbus/char/sunkbd.c Sun Mar 3 23:50:42 2002 @@ -504,7 +504,7 @@ } do_poke_blanked_console = 1; - schedule_console_callback(); + schedule_task(&vt_cons->vt_tq); add_keyboard_randomness(keycode); tty = ttytab? ttytab[fg_console]: NULL; @@ -544,7 +544,7 @@ #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq hack */ if (l1a_state.l1_down) { if (!up_flag) - handle_sysrq(sun_sysrq_xlate[keycode], pt_regs, kbd, tty); + handle_sysrq(sun_sysrq_xlate[keycode], pt_regs, tty); goto out; } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/sbus/char/zs.c linux-2.5/drivers/sbus/char/zs.c --- linux-2.5.20/drivers/sbus/char/zs.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/sbus/char/zs.c Wed Jan 16 00:23:26 2002 @@ -2460,7 +2460,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &zs_console; +#endif serial_driver.open = zs_open; serial_driver.close = zs_close; serial_driver.write = zs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/Config.help linux-2.5/drivers/scsi/Config.help --- linux-2.5.20/drivers/scsi/Config.help Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/scsi/Config.help Mon May 6 18:48:03 2002 @@ -179,6 +179,10 @@ there should be no noticeable performance impact as long as you have logging turned off. +CONFIG_SGIWD93_SCSI + If you have a Western Digital WD93 SCSI controller on + an SGI MIPS system, say Y. Otherwise, say N. + CONFIG_SCSI_DECNCR Say Y here to support the NCR53C94 SCSI controller chips on IOASIC based TURBOchannel DECstations and TURBOchannel PMAZ-A cards. @@ -978,6 +982,11 @@ The module will be called qlogicfc.o. If you want to compile it as a module, say M here and read . +CONFIG_SCSI_QLOGIC_FC_FIRMWARE + Say Y to include ISP2100 Fabric Initiator/Target Firmware, with + expanded LUN addressing and FcTape (FCP-2) support, in the + Qlogic QLA 1280 driver. + CONFIG_SCSI_QLOGIC_1280 Say Y if you have a QLogic ISP1x80/1x160 SCSI host adapter. @@ -1384,4 +1393,13 @@ which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read . + +CONFIG_BROKEN_SCSI_ERROR_HANDLING + SCSI error handling in 2.5 is somewhat different to 2.4. In particular, + the old-style error handling is non-existant any more. Some SCSI drivers + however are still not updated, and still reference the old method of + handling errors, which breaks compilation. + Choosing this option will allow the drivers to compile again, but with + *NO* error handling whatsoever. This is dangerous, and should not be used + with a filesystem you particularly care about. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/Config.in linux-2.5/drivers/scsi/Config.in --- linux-2.5.20/drivers/scsi/Config.in Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/scsi/Config.in Wed May 29 15:32:27 2002 @@ -1,5 +1,7 @@ comment 'SCSI support type (disk, tape, CD-ROM)' +bool ' Use SCSI drivers with broken error handling [DANGEROUS]' CONFIG_BROKEN_SCSI_ERROR_HANDLING + dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then @@ -208,7 +210,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI fi -if [ "$CONFIG_PPC" = "y" ]; then +if [ "$CONFIG_ALL_PPC" = "y" ]; then dep_tristate 'MESH (Power Mac internal SCSI) support' CONFIG_SCSI_MESH $CONFIG_SCSI if [ "$CONFIG_SCSI_MESH" != "n" ]; then int ' maximum synchronous transfer rate (MB/s) (0 = async)' CONFIG_SCSI_MESH_SYNC_RATE 5 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/README.st linux-2.5/drivers/scsi/README.st --- linux-2.5.20/drivers/scsi/README.st Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/scsi/README.st Mon Apr 15 01:52:37 2002 @@ -1,8 +1,8 @@ This file contains brief information about the SCSI tape driver. -The driver is currently maintained by Kai M{kisara (email +The driver is currently maintained by Kai Mäkisara (email Kai.Makisara@metla.fi) -Last modified: Tue Jan 22 21:08:57 2002 by makisara +Last modified: Tue Feb 5 21:33:23 2002 by makisara BASICS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/dtc.c linux-2.5/drivers/scsi/dtc.c --- linux-2.5.20/drivers/scsi/dtc.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/scsi/dtc.c Thu Dec 13 16:32:36 2001 @@ -1,13 +1,11 @@ - #define AUTOSENSE #define PSEUDO_DMA #define DONT_USE_INTR -#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */ +#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */ #define xNDEBUG (NDEBUG_INTR+NDEBUG_RESELECTION+\ NDEBUG_SELECTION+NDEBUG_ARBITRATION) #define DMA_WORKS_RIGHT - /* * DTC 3180/3280 driver, by * Ray Van Tassle rayvt@comm.mot.com @@ -65,6 +63,7 @@ 6 = yellow 7 = white */ + #if 0 #define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);} #else @@ -102,336 +101,318 @@ */ /* - */ + */ /* Offset from DTC_5380_OFFSET */ #define DTC_CONTROL_REG 0x100 /* rw */ #define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ #define CSR_DIR_READ 0x40 /* rw direction, 1 = read 0 = write */ -#define CSR_RESET 0x80 /* wo Resets 53c400 */ -#define CSR_5380_REG 0x80 /* ro 5380 registers can be accessed */ -#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ -#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ -#define CSR_5380_INTR 0x10 /* rw Enable 5380 interrupts */ -#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ -#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Host buffer not ready */ -#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer ready */ -#define CSR_GATED_5380_IRQ 0x01 /* ro Last block xferred */ +#define CSR_RESET 0x80 /* wo Resets 53c400 */ +#define CSR_5380_REG 0x80 /* ro 5380 registers can be accessed */ +#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ +#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ +#define CSR_5380_INTR 0x10 /* rw Enable 5380 interrupts */ +#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ +#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Host buffer not ready */ +#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer ready */ +#define CSR_GATED_5380_IRQ 0x01 /* ro Last block xferred */ #define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR) -#define DTC_BLK_CNT 0x101 /* rw +#define DTC_BLK_CNT 0x101 /* rw * # of 128-byte blocks to transfer */ -#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ +#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ #define DTC_SWITCH_REG 0x3982 /* ro - DIP switches */ #define DTC_RESUME_XFER 0x3982 /* wo - resume data xfer - * after disconnect/reconnect*/ + * after disconnect/reconnect */ #define DTC_5380_OFFSET 0x3880 /* 8 registers here, see NCR5380.h */ /*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */ -#define DTC_DATA_BUF 0x3900 /* rw 128 bytes long */ +#define DTC_DATA_BUF 0x3900 /* rw 128 bytes long */ static struct override { - unsigned int address; - int irq; + unsigned int address; + int irq; } overrides #ifdef OVERRIDE [] __initdata = OVERRIDE; #else -[4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO}}; +[4] __initdata = { + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO} +}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned long address; - int noauto; -} bases[] __initdata = {{0xcc000, 0}, {0xc8000, 0}, {0xdc000, 0}, {0xd8000, 0}}; + unsigned long address; + int noauto; +} bases[] __initdata = { + {0xcc000, 0}, + {0xc8000, 0}, + {0xdc000, 0}, + {0xd8000, 0} +}; #define NO_BASES (sizeof (bases) / sizeof (struct base)) static const struct signature { - const char *string; - int offset; -} signatures[] = { {"DATA TECHNOLOGY CORPORATION BIOS", 0x25}, }; + const char *string; + int offset; +} signatures[] = { + {"DATA TECHNOLOGY CORPORATION BIOS", 0x25}, +}; #define NO_SIGNATURES (sizeof (signatures) / sizeof (struct signature)) -/* - * Function : dtc_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. +/** + * dtc_setup - option setup for dtc3x80 * -*/ + * LILO command line initialization of the overrides array, + */ -void __init dtc_setup(char *str, int *ints){ - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("dtc_setup: usage dtc=address,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].address = ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; - } +static int __init dtc_setup(char *str) +{ + static int commandline_current = 0; + int i; + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + + if (ints[0] != 2) + printk(KERN_ERR "dtc_setup: usage dtc=address,irq\n"); + else if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].address = ints[1]; + overrides[commandline_current].irq = ints[2]; + for (i = 0; i < NO_BASES; ++i) + if (bases[i].address == ints[1]) { + bases[i].noauto = 1; + break; + } + ++commandline_current; + } + return 1; } -/* - * Function : int dtc_detect(Scsi_Host_Template * tpnt) +__setup("dtc=", dtc_setup); + +/** + * dtc_detect - detect DTC 3x80 controllers + * @tpnt: controller template * - * Purpose : detects and initializes DTC 3180/3280 controllers + * Detects and initializes DTC 3180/3280 controllers * that were autoprobed, overridden on the LILO command line, * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * -*/ - -int __init dtc_detect(Scsi_Host_Template * tpnt){ - static int current_override = 0, current_base = 0; - struct Scsi_Host *instance; - unsigned int base; - int sig, count; - - tpnt->proc_name = "dtc3x80"; - tpnt->proc_info = &dtc_proc_info; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - base = 0; - - if (overrides[current_override].address) - base = overrides[current_override].address; - else - for (; !base && (current_base < NO_BASES); ++current_base) { -#if (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : probing address %08x\n", bases[current_base].address); -#endif - for (sig = 0; sig < NO_SIGNATURES; ++sig) - if (!bases[current_base].noauto && - isa_check_signature(bases[current_base].address + - signatures[sig].offset, - signatures[sig].string, strlen(signatures[sig].string))) { - base = bases[current_base].address; -#if (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : detected board.\n"); -#endif - break; - } - } - -#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : base = %08x\n", base); -#endif - - if (!base) - break; + */ - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->base = base; - - NCR5380_init(instance, 0); - - NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */ - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, DTC_IRQS); +int __init dtc_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0, current_base = 0; + struct Scsi_Host *instance; + unsigned int base; + int sig, count; + + tpnt->proc_name = "dtc3x80"; + tpnt->proc_info = &dtc_proc_info; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) + { + base = 0; + + if (overrides[current_override].address) + base = overrides[current_override].address; + else + { + for (; !base && (current_base < NO_BASES); ++current_base) { + for (sig = 0; sig < NO_SIGNATURES; ++sig) + { + if (!bases[current_base].noauto && isa_check_signature(bases[current_base].address + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) { + base = bases[current_base].address; + break; + } + } + } + } + + if (!base) + break; + + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) + break; + + instance->base = base; + + NCR5380_init(instance, 0); + + NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */ + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, DTC_IRQS); #ifndef DONT_USE_INTR -/* With interrupts enabled, it will sometimes hang when doing heavy - * reads. So better not enable them until I finger it out. */ - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc", instance)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } - - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } + /* With interrupts enabled, it will sometimes hang when doing heavy + * reads. So better not enable them until I figure it out. */ + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc")) + { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + } #else - if (instance->irq != IRQ_NONE) - printk("scsi%d : interrupts not used. Might as well not jumper it.\n", - instance->host_no); - instance->irq = IRQ_NONE; + if (instance->irq != IRQ_NONE) + printk(KERN_INFO "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no); + instance->irq = IRQ_NONE; #endif -#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif - - printk("scsi%d : at 0x%05X", instance->host_no, (int)instance->base); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; + printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); + + ++current_override; + ++count; + } + return count; } -/* - * Function : int dtc_biosparam(Disk * disk, kdev_t dev, int *ip) +/** + * dtc_biosparam - compute disk geometry + * @disk: disk to generate for + * @dev: major/minor of device + * @ip: returned geometry * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for + * Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. - * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * -*/ - -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. -*/ + */ -int dtc_biosparam(Disk * disk, kdev_t dev, int * ip) +int dtc_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; + int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - return 0; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + return 0; } -/**************************************************************** - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) - * - * Purpose : Fast 5380 pseudo-dma read function, reads len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. -*/ - static int dtc_maxi = 0; static int dtc_wmaxi = 0; -static inline int NCR5380_pread (struct Scsi_Host *instance, - unsigned char *dst, int len) - { - unsigned char *d = dst; - int i; /* For counting time spent in the poll-loop */ - NCR5380_local_declare(); - NCR5380_setup(instance); - - i = 0; - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); - if (instance->irq == IRQ_NONE) - NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ); - else - NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE); - NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ - rtrc(1); - while (len > 0) { - rtrc(2); - while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) - ++i; - rtrc(3); - isa_memcpy_fromio(d, base + DTC_DATA_BUF, 128); - d += 128; - len -= 128; - rtrc(7); /*** with int's on, it sometimes hangs after here. +/** + * NCR5380_pread - fast pseudo DMA read + * @instance: controller + * @dst: destination buffer + * @len: expected/max size + * + * Fast 5380 pseudo-dma read function, reads len bytes from the controller + * mmio area into dst. + */ + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + unsigned char *d = dst; + int i; /* For counting time spent in the poll-loop */ + NCR5380_local_declare(); + NCR5380_setup(instance); + + i = 0; + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); + if (instance->irq == IRQ_NONE) + NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ); + else + NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE); + NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ + rtrc(1); + while (len > 0) { + rtrc(2); + while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) + ++i; + rtrc(3); + isa_memcpy_fromio(d, base + DTC_DATA_BUF, 128); + d += 128; + len -= 128; + rtrc(7); + /*** with int's on, it sometimes hangs after here. * Looks like something makes HBNR go away. */ - } - rtrc(4); - while ( !(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) - ++i; - NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ - rtrc(0); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - if (i > dtc_maxi) - dtc_maxi = i; - return(0); + } + rtrc(4); + while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) + ++i; + NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ + rtrc(0); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + if (i > dtc_maxi) + dtc_maxi = i; + return (0); } -/**************************************************************** - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) +/** + * NCR5380_pwrite - fast pseudo DMA write + * @instance: controller + * @dst: destination buffer + * @len: expected/max size * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. -*/ + * Fast 5380 pseudo-dma write function, writes len bytes to the + * controller mmio area from src. + */ -static inline int NCR5380_pwrite (struct Scsi_Host *instance, - unsigned char *src, int len) { - int i; - NCR5380_local_declare(); - NCR5380_setup(instance); - - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); - /* set direction (write) */ - if (instance->irq == IRQ_NONE) - NCR5380_write(DTC_CONTROL_REG, 0); - else - NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); - NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ - for (i = 0; len > 0; ++i) { - rtrc(5); - /* Poll until the host buffer can accept data. */ - while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) - ++i; - rtrc(3); - isa_memcpy_toio(base + DTC_DATA_BUF, src, 128); - src += 128; - len -= 128; - } - rtrc(4); - while ( !(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) - ++i; - rtrc(6); - /* Wait until the last byte has been sent to the disk */ - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) - ++i; - rtrc(7); - /* Check for parity error here. fixme. */ - NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ - rtrc(0); - if (i > dtc_wmaxi) - dtc_wmaxi = i; - return (0); +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + int i; + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); + /* set direction (write) */ + if (instance->irq == IRQ_NONE) + NCR5380_write(DTC_CONTROL_REG, 0); + else + NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); + NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ + for (i = 0; len > 0; ++i) { + rtrc(5); + /* Poll until the host buffer can accept data. */ + while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) + ++i; + rtrc(3); + isa_memcpy_toio(base + DTC_DATA_BUF, src, 128); + src += 128; + len -= 128; + } + rtrc(4); + while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) + ++i; + rtrc(6); + /* Wait until the last byte has been sent to the disk */ + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) + ++i; + rtrc(7); + /* Check for parity error here. fixme. */ + NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ + rtrc(0); + if (i > dtc_wmaxi) + dtc_wmaxi = i; + return (0); } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/fdomain.c linux-2.5/drivers/scsi/fdomain.c --- linux-2.5.20/drivers/scsi/fdomain.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/scsi/fdomain.c Thu Jan 31 01:44:15 2002 @@ -730,13 +730,13 @@ switch (Quantum) { case 2: /* ISA_200S */ case 3: /* ISA_250MG */ - base = readb(bios_base + 0x1fa2) + (readb(bios_base + 0x1fa3) << 8); + base = isa_readb(bios_base + 0x1fa2) + (isa_readb(bios_base + 0x1fa3) << 8); break; case 4: /* ISA_200S (another one) */ - base = readb(bios_base + 0x1fa3) + (readb(bios_base + 0x1fa4) << 8); + base = isa_readb(bios_base + 0x1fa3) + (isa_readb(bios_base + 0x1fa4) << 8); break; default: - base = readb(bios_base + 0x1fcc) + (readb(bios_base + 0x1fcd) << 8); + base = isa_readb(bios_base + 0x1fcc) + (isa_readb(bios_base + 0x1fcd) << 8); break; } @@ -1956,7 +1956,7 @@ offset = bios_base + 0x1f31 + drive * 25; break; } - memcpy_fromio( &i, offset, sizeof( struct drive_info ) ); + isa_memcpy_fromio( &i, offset, sizeof( struct drive_info ) ); info_array[0] = i.heads; info_array[1] = i.sectors; info_array[2] = i.cylinders; @@ -2043,6 +2043,7 @@ if (shpnt->io_port && shpnt->n_io_port) release_region(shpnt->io_port, shpnt->n_io_port); + return 0; } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/g_NCR5380.h linux-2.5/drivers/scsi/g_NCR5380.h --- linux-2.5.20/drivers/scsi/g_NCR5380.h Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/scsi/g_NCR5380.h Sun Feb 10 19:55:31 2002 @@ -43,24 +43,18 @@ #define NCR5380_BIOSPARAM NULL #endif -#ifndef ASM int generic_NCR5380_abort(Scsi_Cmnd *); int generic_NCR5380_detect(Scsi_Host_Template *); int generic_NCR5380_release_resources(struct Scsi_Host *); -int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int generic_NCR5380_reset(Scsi_Cmnd *, unsigned int); -int notyet_generic_proc_info (char *buffer ,char **start, off_t offset, - int length, int hostno, int inout); -const char* generic_NCR5380_info(struct Scsi_Host *); +int notyet_generic_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); +const char *generic_NCR5380_info(struct Scsi_Host *); #ifdef BIOSPARAM int generic_NCR5380_biosparam(Disk *, kdev_t, int *); #endif -int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout); - -#ifndef NULL -#define NULL 0 -#endif +int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); #ifndef CMD_PER_LUN #define CMD_PER_LUN 2 @@ -92,19 +86,15 @@ #define STRVAL(x) __STRVAL(x) #ifdef CONFIG_SCSI_G_NCR5380_PORT - #define NCR5380_map_config port - #define NCR5380_map_type int - #define NCR5380_map_name port - #define NCR5380_instance_name io_port - #define NCR53C400_register_offset 0 - #define NCR53C400_address_adjust 8 - +/* + * FIXME: size should be runtime decided + */ #ifdef NCR53C400 #define NCR5380_region_size 16 #else @@ -114,30 +104,21 @@ #define NCR5380_read(reg) (inb(NCR5380_map_name + (reg))) #define NCR5380_write(reg, value) (outb((value), (NCR5380_map_name + (reg)))) -#else +#else /* therefore CONFIG_SCSI_G_NCR5380_MEM */ #define NCR5380_map_config memory - #define NCR5380_map_type unsigned long - #define NCR5380_map_name base - #define NCR5380_instance_name base - #define NCR53C400_register_offset 0x108 - #define NCR53C400_address_adjust 0 - #define NCR53C400_mem_base 0x3880 - #define NCR53C400_host_buffer 0x3900 - #define NCR5380_region_size 0x3a00 - #define NCR5380_read(reg) isa_readb(NCR5380_map_name + NCR53C400_mem_base + (reg)) -#define NCR5380_write(reg, value) isa_writeb(NCR5380_map_name + NCR53C400_mem_base + (reg), value) +#define NCR5380_write(reg, value) isa_writeb(value, NCR5380_map_name + NCR53C400_mem_base + (reg)) #endif @@ -164,7 +145,5 @@ #define BOARD_NCR53C400A 2 #define BOARD_DTC3181E 3 -#endif /* else def HOSTS_C */ -#endif /* ndef ASM */ -#endif /* GENERIC_NCR5380_H */ - +#endif /* else def HOSTS_C */ +#endif /* GENERIC_NCR5380_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/hosts.h linux-2.5/drivers/scsi/hosts.h --- linux-2.5.20/drivers/scsi/hosts.h Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/scsi/hosts.h Sun May 26 19:08:10 2002 @@ -165,40 +165,10 @@ int (*eh_bus_reset_handler)(Scsi_Cmnd *); int (*eh_host_reset_handler)(Scsi_Cmnd *); - /* - * Since the mid level driver handles time outs, etc, we want to - * be able to abort the current command. Abort returns 0 if the - * abortion was successful. The field SCpnt->abort reason - * can be filled in with the appropriate reason why we wanted - * the abort in the first place, and this will be used - * in the mid-level code instead of the host_byte(). - * If non-zero, the code passed to it - * will be used as the return code, otherwise - * DID_ABORT should be returned. - * - * Note that the scsi driver should "clean up" after itself, - * resetting the bus, etc. if necessary. - * - * NOTE - this interface is depreciated, and will go away. Use - * the eh_ routines instead. - */ - int (* abort)(Scsi_Cmnd *); - - /* - * The reset function will reset the SCSI bus. Any executing - * commands should fail with a DID_RESET in the host byte. - * The Scsi_Cmnd is passed so that the reset routine can figure - * out which host adapter should be reset, and also which command - * within the command block was responsible for the reset in - * the first place. Some hosts do not implement a reset function, - * and these hosts must call scsi_request_sense(SCpnt) to keep - * the command alive. - * - * NOTE - this interface is depreciated, and will go away. Use - * the eh_ routines instead. - */ - int (* reset)(Scsi_Cmnd *, unsigned int); - +#ifdef CONFIG_BROKEN_SCSI_ERROR_HANDLING + int (* abort)(Scsi_Cmnd *); + int (* reset)(Scsi_Cmnd *, unsigned int); +#endif /* * This function is used to select synchronous communications, * which will result in a higher data throughput. Not implemented diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/i60uscsi.c linux-2.5/drivers/scsi/i60uscsi.c --- linux-2.5.20/drivers/scsi/i60uscsi.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/scsi/i60uscsi.c Sat May 25 19:52:05 2002 @@ -640,7 +640,6 @@ ULONG idx; UCHAR index; UCHAR i; - ULONG flags; Ch = hcsp->HCS_Index; for (i = 0; i < 8; i++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/ibmmca.c linux-2.5/drivers/scsi/ibmmca.c --- linux-2.5.20/drivers/scsi/ibmmca.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/scsi/ibmmca.c Fri Feb 8 02:15:53 2002 @@ -1406,9 +1406,9 @@ io_base = 0; id_base = 0; if (str) { - token = strtok(str,","); j = 0; - while (token) { + while ((token = strsep(&str,",")) != NULL) { + if (!*token) continue; if (!strcmp(token,"activity")) display_mode |= LED_ACTIVITY; if (!strcmp(token,"display")) display_mode |= LED_DISP; if (!strcmp(token,"adisplay")) display_mode |= LED_ADISP; @@ -1424,7 +1424,6 @@ scsi_id[id_base++] = simple_strtoul(token,NULL,0); j++; } - token = strtok(NULL,","); } } else if (ints) { for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/ide-scsi.c linux-2.5/drivers/scsi/ide-scsi.c --- linux-2.5.20/drivers/scsi/ide-scsi.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/scsi/ide-scsi.c Mon Jun 3 17:10:22 2002 @@ -678,18 +678,16 @@ kfree (rq); cmd->result = DID_ERROR << 16; done(cmd); - return 0; } -/* FIXME: This needs further investigation. - */ -static int idescsi_device_reset(Scsi_Cmnd *cmd) +/* try to do correct thing for scsi subsystem's new eh */ +static int idescsi_device_reset (Scsi_Cmnd *cmd) { return SUCCESS; } -static int idescsi_bios(Disk *disk, kdev_t dev, int *parm) +static int idescsi_bios (Disk *disk, kdev_t dev, int *parm) { idescsi_scsi_t *scsi = (idescsi_scsi_t *) disk->device->host->hostdata[0]; struct ata_device *drive = scsi->drive; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/imm.c linux-2.5/drivers/scsi/imm.c --- linux-2.5.20/drivers/scsi/imm.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/scsi/imm.c Wed Jan 23 01:45:56 2002 @@ -998,7 +998,7 @@ case 4: if (cmd->use_sg) { /* if many buffers are available, start filling the first */ - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; + cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset; } else { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/ips.c linux-2.5/drivers/scsi/ips.c --- linux-2.5.20/drivers/scsi/ips.c Mon Jun 3 02:44:38 2002 +++ linux-2.5/drivers/scsi/ips.c Tue May 21 22:20:46 2002 @@ -83,7 +83,7 @@ /* 2.3.18 and later */ /* - Sync with other changes from the 2.3 kernels */ /* 4.00.06 - Fix timeout with initial FFDC command */ -/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig */ +/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig */ /* 4.10.00 - Add support for ServeRAID 4M/4L */ /* 4.10.13 - Fix for dynamic unload and proc file system */ /* 4.20.03 - Rename version to coincide with new release schedules */ @@ -194,6 +194,7 @@ #ifdef MODULE static char *ips = NULL; MODULE_PARM(ips, "s"); + MODULE_LICENSE("GPL"); #endif /* @@ -887,7 +888,7 @@ DEBUG_VAR(1, "(%s%d) detect, IO region %x, size: %d", ips_name, ips_next_controller, io_addr, io_len); - if (check_region(io_addr, io_len)) { + if (!request_region(io_addr, io_len, "ips")) { /* Couldn't allocate io space */ printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n", ips_name, ips_next_controller, io_addr, io_len); @@ -896,8 +897,6 @@ continue; } - - request_region(io_addr, io_len, "ips"); } /* get planer status */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/megaraid.c linux-2.5/drivers/scsi/megaraid.c --- linux-2.5.20/drivers/scsi/megaraid.c Mon Jun 3 02:44:38 2002 +++ linux-2.5/drivers/scsi/megaraid.c Thu Apr 25 03:00:03 2002 @@ -587,10 +587,10 @@ #define DRIVER_LOCK(p) #define DRIVER_UNLOCK(p) #define IO_LOCK_T unsigned long io_flags = 0 -#define IO_LOCK(host) spin_lock_irqsave(host->host_lock,io_flags) -#define IO_UNLOCK(host) spin_unlock_irqrestore(host->host_lock,io_flags) -#define IO_LOCK_IRQ(host) spin_lock_irq(host->host_lock) -#define IO_UNLOCK_IRQ(host) spin_unlock_irq(host->host_lock) +#define IO_LOCK(host) spin_lock_irqsave((host)->host_lock,io_flags) +#define IO_UNLOCK(host) spin_unlock_irqrestore((host)->host_lock,io_flags) +#define IO_LOCK_IRQ(host) spin_lock_irq((host)->host_lock) +#define IO_UNLOCK_IRQ(host) spin_unlock_irq((host)->host_lock) #define queue_task_irq(a,b) queue_task(a,b) #define queue_task_irq_off(a,b) queue_task(a,b) @@ -615,8 +615,8 @@ #define DRIVER_LOCK(p) #define DRIVER_UNLOCK(p) #define IO_LOCK_T unsigned long io_flags = 0 -#define IO_LOCK(host) spin_lock_irqsave(host->host_lock,io_flags); -#define IO_UNLOCK(host) spin_unlock_irqrestore(host->host_lock,io_flags); +#define IO_LOCK(host) spin_lock_irqsave(&io_request_lock,io_flags); +#define IO_UNLOCK(host) spin_unlock_irqrestore(&io_request_lock,io_flags); #define pci_free_consistent(a,b,c,d) #define pci_unmap_single(a,b,c,d) @@ -1153,12 +1153,12 @@ if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) { memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14); } else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) { - SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1); + SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1); memcpy( SCpnt->sense_buffer, epthru->reqsensearea, 14 ); - SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1); + SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1); /*SCpnt->result = (DRIVER_SENSE << 24) | (DID_ERROR << 16) | status;*/ @@ -4534,7 +4534,6 @@ unsigned int cmd, unsigned long arg) { int adapno; - kdev_t dev; u32 inlen; struct uioctl_t ioc; char *kvaddr = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/pas16.c linux-2.5/drivers/scsi/pas16.c --- linux-2.5.20/drivers/scsi/pas16.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/scsi/pas16.c Mon Jan 7 23:17:50 2002 @@ -1,7 +1,7 @@ #define AUTOSENSE #define PSEUDO_DMA -#define FOO -#define UNSAFE /* Not unsafe for PAS16 -- use it */ +#define BOARD_REQUIRES_NO_UDELAY /* PAS16 needs no I/O recovery delays */ +#define UNSAFE /* Not unsafe for PAS16 -- use it */ /* * This driver adapted from Drew Eckhardt's Trantor T128 driver @@ -52,8 +52,6 @@ * * PARITY - enable parity checking. Not supported. * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. This * parameter comes from the NCR5380 code. It is NOT unsafe with * the PAS16 and you should use it. If you don't you will have @@ -62,8 +60,6 @@ * want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or * twiddle with the transfer size in the high level code. * - * USLEEP - enable support for devices that don't disconnect. Untested. - * * The card is detected and initialized in one of several ways : * 1. Autoprobe (default) - There are many different models of * the Pro Audio Spectrum/Studio 16, and I only have one of @@ -109,7 +105,7 @@ * * (IRQ_AUTO == 254, IRQ_NONE == 255 in NCR5380.h) */ - + #include #include @@ -133,467 +129,402 @@ static int pas_wmaxi = 0; static unsigned short pas16_addr = 0; static int pas16_irq = 0; - -int scsi_irq_translate[] = - { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 }; +static int scsi_irq_translate[] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 }; /* The default_irqs array contains values used to set the irq into the * board via software (as must be done on newer model boards without * irq jumpers on the board). The first value in the array will be * assigned to logical board 0, the next to board 1, etc. */ -int default_irqs[] __initdata = - { PAS16_DEFAULT_BOARD_1_IRQ, - PAS16_DEFAULT_BOARD_2_IRQ, - PAS16_DEFAULT_BOARD_3_IRQ, - PAS16_DEFAULT_BOARD_4_IRQ - }; + +static int default_irqs[] __initdata = { + PAS16_DEFAULT_BOARD_1_IRQ, + PAS16_DEFAULT_BOARD_2_IRQ, + PAS16_DEFAULT_BOARD_3_IRQ, + PAS16_DEFAULT_BOARD_4_IRQ +}; static struct override { - unsigned short io_port; - int irq; -} overrides + unsigned short io_port; + int irq; +} overrides #ifdef PAS16_OVERRIDE - [] __initdata = PAS16_OVERRIDE; +[] __initdata = PAS16_OVERRIDE; #else - [4] __initdata = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO}, - {0,IRQ_AUTO}}; +[4] __initdata = { + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO} +}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned short io_port; - int noauto; -} bases[] __initdata = - { {PAS16_DEFAULT_BASE_1, 0}, - {PAS16_DEFAULT_BASE_2, 0}, - {PAS16_DEFAULT_BASE_3, 0}, - {PAS16_DEFAULT_BASE_4, 0} - }; + unsigned short io_port; + int noauto; +} bases[] __initdata = { + {PAS16_DEFAULT_BASE_1, 0}, + {PAS16_DEFAULT_BASE_2, 0}, + {PAS16_DEFAULT_BASE_3, 0}, + {PAS16_DEFAULT_BASE_4, 0} +}; #define NO_BASES (sizeof (bases) / sizeof (struct base)) -unsigned short pas16_offset[ 8 ] = - { - 0x1c00, /* OUTPUT_DATA_REG */ - 0x1c01, /* INITIATOR_COMMAND_REG */ - 0x1c02, /* MODE_REG */ - 0x1c03, /* TARGET_COMMAND_REG */ - 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */ - 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */ - 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?) - * START_DMA_TARGET_RECEIVE_REG wo - */ - 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro, - * START_DMA_INITIATOR_RECEIVE_REG wo - */ - }; +unsigned short pas16_offset[8] = { + 0x1c00, /* OUTPUT_DATA_REG */ + 0x1c01, /* INITIATOR_COMMAND_REG */ + 0x1c02, /* MODE_REG */ + 0x1c03, /* TARGET_COMMAND_REG */ + 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */ + 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */ + 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?) + * START_DMA_TARGET_RECEIVE_REG wo + */ + 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro, + * START_DMA_INITIATOR_RECEIVE_REG wo + */ +}; /*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at */ -/* 1 = blue - 2 = green - 3 = cyan - 4 = red - 5 = magenta - 6 = yellow - 7 = white -*/ -#if 1 -#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);} -#else -#define rtrc(i) {} -#endif - -/* - * Function : enable_board( int board_num, unsigned short port ) - * - * Purpose : set address in new model board - * - * Inputs : board_num - logical board number 0-3, port - base address +/** + * enable_board - enable a pas16 board + * @board_num: logical board id + * @port: port to assign it * + * Sets the address on new model PAS16 hardware */ -static void __init - enable_board( int board_num, unsigned short port ) +static void __init enable_board(int board_num, unsigned short port) { - outb( 0xbc + board_num, MASTER_ADDRESS_PTR ); - outb( port >> 2, MASTER_ADDRESS_PTR ); + outb(0xbc + board_num, MASTER_ADDRESS_PTR); + outb(port >> 2, MASTER_ADDRESS_PTR); } - - -/* - * Function : init_board( unsigned short port, int irq ) - * - * Purpose : Set the board up to handle the SCSI interface - * - * Inputs : port - base address of the board, - * irq - irq to assign to the SCSI port - * force_irq - set it even if it conflicts with sound driver +/** + * init_board - set up board + * @port: board address + * @irq: interrupt line + * @force_irq: if true allow scsi/audio on the same int * + * Set the board up to handle the SCSI interface */ -static void __init - init_board( unsigned short io_port, int irq, int force_irq ) +static void __init init_board(unsigned short io_port, int irq, int force_irq) { - unsigned int tmp; - unsigned int pas_irq_code; + unsigned int tmp; + unsigned int pas_irq_code; /* Initialize the SCSI part of the board */ - outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG ); /* Timeout counter */ - outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */ - outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */ + outb(0x30, io_port + P_TIMEOUT_COUNTER_REG); /* Timeout counter */ + outb(0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET); /* Reset TC */ + outb(0x01, io_port + WAIT_STATE); /* 1 Wait state */ - NCR5380_read( RESET_PARITY_INTERRUPT_REG ); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); - /* Set the SCSI interrupt pointer without mucking up the sound - * interrupt pointer in the same byte. + /* + * Set the SCSI interrupt pointer without mucking up the sound + * interrupt pointer in the same byte. */ - pas_irq_code = ( irq < 16 ) ? scsi_irq_translate[irq] : 0; - tmp = inb( io_port + IO_CONFIG_3 ); - - if( (( tmp & 0x0f ) == pas_irq_code) && pas_irq_code > 0 - && !force_irq ) - { - printk( "pas16: WARNING: Can't use same irq as sound " - "driver -- interrupts disabled\n" ); - /* Set up the drive parameters, disable 5380 interrupts */ - outb( 0x4d, io_port + SYS_CONFIG_4 ); - } - else - { - tmp = ( tmp & 0x0f ) | ( pas_irq_code << 4 ); - outb( tmp, io_port + IO_CONFIG_3 ); + + pas_irq_code = (irq < 16) ? scsi_irq_translate[irq] : 0; + tmp = inb(io_port + IO_CONFIG_3); + + if (((tmp & 0x0f) == pas_irq_code) && pas_irq_code > 0 && !force_irq) { + printk(KERN_WARNING "pas16: WARNING: Can't use same irq as sound " "driver -- interrupts disabled\n"); + /* Set up the drive parameters, disable 5380 interrupts */ + outb(0x4d, io_port + SYS_CONFIG_4); + } else { + tmp = (tmp & 0x0f) | (pas_irq_code << 4); + outb(tmp, io_port + IO_CONFIG_3); - /* Set up the drive parameters and enable 5380 interrupts */ - outb( 0x6d, io_port + SYS_CONFIG_4 ); + /* Set up the drive parameters and enable 5380 interrupts */ + outb(0x6d, io_port + SYS_CONFIG_4); } } -/* - * Function : pas16_hw_detect( unsigned short board_num ) - * - * Purpose : determine if a pas16 board is present - * - * Inputs : board_num - logical board number ( 0 - 3 ) +/** + * pas16_hw_detect - probe for hardware + * @board_num: logical board ID to probe for * - * Returns : 0 if board not found, 1 if found. + * Determine if a pas16 board is present */ -static int __init - pas16_hw_detect( unsigned short board_num ) +static int __init pas16_hw_detect(unsigned short board_num) { - unsigned char board_rev, tmp; - unsigned short io_port = bases[ board_num ].io_port; + unsigned char board_rev, tmp; + unsigned short io_port = bases[board_num].io_port; - /* See if we can find a PAS16 board at the address associated - * with this logical board number. - */ - - /* First, attempt to take a newer model board out of reset and - * give it a base address. This shouldn't affect older boards. - */ - enable_board( board_num, io_port ); + /* See if we can find a PAS16 board at the address associated + * with this logical board number. + */ - /* Now see if it looks like a PAS16 board */ - board_rev = inb( io_port + PCB_CONFIG ); + /* First, attempt to take a newer model board out of reset and + * give it a base address. This shouldn't affect older boards. + */ + enable_board(board_num, io_port); - if( board_rev == 0xff ) - return 0; + /* Now see if it looks like a PAS16 board */ + board_rev = inb(io_port + PCB_CONFIG); - tmp = board_rev ^ 0xe0; + if (board_rev == 0xff) + return 0; - outb( tmp, io_port + PCB_CONFIG ); - tmp = inb( io_port + PCB_CONFIG ); - outb( board_rev, io_port + PCB_CONFIG ); + tmp = board_rev ^ 0xe0; - if( board_rev != tmp ) /* Not a PAS-16 */ - return 0; + outb(tmp, io_port + PCB_CONFIG); + tmp = inb(io_port + PCB_CONFIG); + outb(board_rev, io_port + PCB_CONFIG); - if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 ) - return 0; /* return if no SCSI interface found */ + if (board_rev != tmp) /* Not a PAS-16 */ + return 0; - /* Mediavision has some new model boards that return ID bits - * that indicate a SCSI interface, but they're not (LMS). We'll - * put in an additional test to try to weed them out. - */ - - outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */ - NCR5380_write( MODE_REG, 0x20 ); /* Is it really SCSI? */ - if( NCR5380_read( MODE_REG ) != 0x20 ) /* Write to a reg. */ - return 0; /* and try to read */ - NCR5380_write( MODE_REG, 0x00 ); /* it back. */ - if( NCR5380_read( MODE_REG ) != 0x00 ) - return 0; + if ((inb(io_port + OPERATION_MODE_1) & 0x03) != 0x03) + return 0; /* return if no SCSI interface found */ - return 1; -} + /* Mediavision has some new model boards that return ID bits + * that indicate a SCSI interface, but they're not (LMS). We'll + * put in an additional test to try to weed them out. + */ + outb(0x01, io_port + WAIT_STATE); /* 1 Wait state */ + NCR5380_write(MODE_REG, 0x20); /* Is it really SCSI? */ + if (NCR5380_read(MODE_REG) != 0x20) /* Write to a reg. */ + return 0; /* and try to read */ + NCR5380_write(MODE_REG, 0x00); /* it back. */ + if (NCR5380_read(MODE_REG) != 0x00) + return 0; -/* - * Function : pas16_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + return 1; +} + +/** + * pas16_setup - parse command line + * @str: command line block * + * LILO command line initialization of the overrides array from + * the passed in pas16= options */ -void __init pas16_setup(char *str, int *ints) +int __init pas16_setup(char *str) { - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("pas16_setup : usage pas16=io_port,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].io_port = (unsigned short) ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].io_port == (unsigned short) ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; + static int commandline_current = 0; + int i; + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + if (ints[0] != 2) + printk(KERN_ERR "pas16_setup : usage pas16=io_port,irq\n"); + else if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].io_port = (unsigned short) ints[1]; + overrides[commandline_current].irq = ints[2]; + for (i = 0; i < NO_BASES; ++i) + if (bases[i].io_port == (unsigned short) ints[1]) { + bases[i].noauto = 1; + break; + } + ++commandline_current; } + return 1; } -/* - * Function : int pas16_detect(Scsi_Host_Template * tpnt) - * - * Purpose : detects and initializes PAS16 controllers - * that were autoprobed, overridden on the LILO command line, - * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. +__setup("pas16=", pas16_setup); + +/** + * pas16_detect - detect and configure a pas16 + * @tpnt: template * + * Detects and initializes PAS16 controllers that were autoprobed, + * overridden on the LILO command line, or specified at compile time. */ int __init pas16_detect(Scsi_Host_Template * tpnt) { - static int current_override = 0; - static unsigned short current_base = 0; - struct Scsi_Host *instance; - unsigned short io_port; - int count; + static int current_override = 0; + static unsigned short current_base = 0; + struct Scsi_Host *instance; + unsigned short io_port; + int count; + + tpnt->proc_name = "pas16"; + tpnt->proc_info = &pas16_proc_info; + + if (pas16_addr != 0) { + overrides[0].io_port = pas16_addr; + /* + * This is how we avoid seeing more than + * one host adapter at the same I/O port. + * Cribbed shamelessly from pas16_setup(). + */ + for (count = 0; count < NO_BASES; ++count) + if (bases[count].io_port == pas16_addr) { + bases[count].noauto = 1; + break; + } + } + if (pas16_irq != 0) + overrides[0].irq = pas16_irq; - tpnt->proc_name = "pas16"; - tpnt->proc_info = &pas16_proc_info; + for (count = 0; current_override < NO_OVERRIDES; ++current_override) { + io_port = 0; - if (pas16_addr != 0) { - overrides[0].io_port = pas16_addr; - /* - * This is how we avoid seeing more than - * one host adapter at the same I/O port. - * Cribbed shamelessly from pas16_setup(). - */ - for (count = 0; count < NO_BASES; ++count) - if (bases[count].io_port == pas16_addr) { - bases[count].noauto = 1; - break; - } - } - if (pas16_irq != 0) - overrides[0].irq = pas16_irq; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - io_port = 0; - - if (overrides[current_override].io_port) - { - io_port = overrides[current_override].io_port; - enable_board( current_override, io_port ); - init_board( io_port, overrides[current_override].irq, 1 ); - } - else - for (; !io_port && (current_base < NO_BASES); ++current_base) { -#if (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port); -#endif - if ( !bases[current_base].noauto && - pas16_hw_detect( current_base ) ){ - io_port = bases[current_base].io_port; - init_board( io_port, default_irqs[ current_base ], 0 ); -#if (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : detected board.\n"); -#endif + if (overrides[current_override].io_port) { + io_port = overrides[current_override].io_port; + enable_board(current_override, io_port); + init_board(io_port, overrides[current_override].irq, 1); + } + else + { + for (; !io_port && (current_base < NO_BASES); ++current_base) { + if (!bases[current_base].noauto && pas16_hw_detect(current_base)) { + io_port = bases[current_base].io_port; + init_board(io_port, default_irqs[current_base], 0); + } + } } - } + if (!io_port) + break; -#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port); -#endif + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) + break; + + instance->io_port = io_port; + + NCR5380_init(instance, 0); + + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", NULL)) { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + /* Disable 5380 interrupts, leave drive params the same */ + outb(0x4d, io_port + SYS_CONFIG_4); + outb((inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3); + } - if (!io_port) - break; + printk(KERN_INFO "scsi%d : at 0x%04x", instance->host_no, (int) + instance->io_port); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->io_port = io_port; - - NCR5380_init(instance, 0); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS); - - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", instance)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } - - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - /* Disable 5380 interrupts, leave drive params the same */ - outb( 0x4d, io_port + SYS_CONFIG_4 ); - outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 ); + ++current_override; + ++count; } - -#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif - - printk("scsi%d : at 0x%04x", instance->host_no, (int) - instance->io_port); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; + return count; } -/* - * Function : int pas16_biosparam(Disk *disk, kdev_t dev, int *ip) +/** + * pas16_biosparam - generate C/H/S data + * @disk: Disk to set up + * @dev: device ident of disk + * @ip: array to return C/H/S mapping * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for + * Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. - * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * */ -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. - */ - -int pas16_biosparam(Disk * disk, kdev_t dev, int * ip) +int pas16_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; /* I think I have it as /(32*64) */ - if( ip[2] > 1024 ) { /* yes, >, not >= */ - ip[0]=255; - ip[1]=63; - ip[2]=size/(63*255); - if( ip[2] > 1023 ) /* yes >1023... */ - ip[2] = 1023; - } + int size = disk->capacity; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; /* I think I have it as /(32*64) */ + if (ip[2] > 1024) { /* yes, >, not >= */ + ip[0] = 255; + ip[1] = 63; + ip[2] = size / (63 * 255); + if (ip[2] > 1023) /* yes >1023... */ + ip[2] = 1023; + } - return 0; + return 0; } -/* - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) - * - * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. +/** + * NCR5380_pread - pseudo DMA read + * @instance: board to read from + * @dst: destination for data + * @len: expected/max block length + * + * Fast 5380 pseudo-dma read function, transfers len bytes to + * dst. Unlike most boards the PAS has IRQs enabled here, which + * helps no end. */ -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, - int len) { - register unsigned char *d = dst; - register unsigned short reg = (unsigned short) (instance->io_port + - P_DATA_REG_OFFSET); - register int i = len; - int ii = 0; - - while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) ) - ++ii; - - insb( reg, d, i ); - - if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { - outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); - printk("scsi%d : watchdog timer fired in NCR5380_pread()\n", - instance->host_no); - return -1; - } - if (ii > pas_maxi) - pas_maxi = ii; - return 0; +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + unsigned char *d = dst; + unsigned short reg = (unsigned short) (instance->io_port + P_DATA_REG_OFFSET); + int i = len; + int ii = 0; + + while (!(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY)) + ++ii; + + insb(reg, d, i); + + if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { + outb(P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); + printk(KERN_ERR "scsi%d : watchdog timer fired in NCR5380_pread()\n", instance->host_no); + return -1; + } + if (ii > pas_maxi) + pas_maxi = ii; + return 0; } -/* - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) - * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. +/** + * NCR5380_pwrite - pseudo DMA write + * @instance: board to write to + * @src: source for data + * @len: expected/max block length + * + * Fast 5380 pseudo-dma write function, transfers len bytes from + * src. Unlike most boards the PAS has IRQs enabled here, which + * helps no end. */ -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, - int len) { - register unsigned char *s = src; - register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET); - register int i = len; - int ii = 0; - - while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) ) - ++ii; - - outsb( reg, s, i ); - - if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { - outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); - printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n", - instance->host_no); - return -1; - } - if (ii > pas_maxi) - pas_wmaxi = ii; - return 0; +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + unsigned char *s = src; + unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET); + int i = len; + int ii = 0; + + while (!((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY)) + ++ii; + + outsb(reg, s, i); + + if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { + outb(P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); + printk(KERN_ERR "scsi%d : watchdog timer fired in NCR5380_pwrite()\n", instance->host_no); + return -1; + } + if (ii > pas_maxi) + pas_wmaxi = ii; + return 0; } #include "NCR5380.c" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/pci2000.c linux-2.5/drivers/scsi/pci2000.c --- linux-2.5.20/drivers/scsi/pci2000.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/scsi/pci2000.c Sun Jan 6 19:17:51 2002 @@ -389,7 +389,7 @@ OpDone (SCpnt, DID_OK << 16); irq_return: - spin_unlock_irqrestore(&shost->host_lock, flags); + spin_unlock_irqrestore(shost->host_lock, flags); out:; } /**************************************************************** diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/pcmcia/aha152x_stub.c linux-2.5/drivers/scsi/pcmcia/aha152x_stub.c --- linux-2.5.20/drivers/scsi/pcmcia/aha152x_stub.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/scsi/pcmcia/aha152x_stub.c Thu Dec 27 22:10:28 2001 @@ -5,7 +5,7 @@ This driver supports the Adaptec AHA-1460, the New Media Bus Toaster, and the New Media Toast & Jam. - aha152x_cs.c 1.54 2000/06/12 21:27:25 + aha152x_cs.c 1.58 2001/10/13 00:08:51 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -22,8 +22,8 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision @@ -57,42 +57,39 @@ #include #include -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"aha152x_cs.c 1.54 2000/06/12 21:27:25 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("Adaptec AHA152x-compatible PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); -/* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); -/* SCSI bus setup options */ -static int host_id = 7; -static int reconnect = 1; -static int parity = 1; -static int synchronous = 0; -static int reset_delay = 100; -static int ext_trans = 0; +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(host_id, "i"); -MODULE_PARM(reconnect, "i"); -MODULE_PARM(parity, "i"); -MODULE_PARM(synchronous, "i"); -MODULE_PARM(reset_delay, "i"); -MODULE_PARM(ext_trans, "i"); +INT_MODULE_PARM(irq_mask, 0xdeb8); +INT_MODULE_PARM(host_id, 7); +INT_MODULE_PARM(reconnect, 1); +INT_MODULE_PARM(parity, 1); +INT_MODULE_PARM(synchronous, 0); +INT_MODULE_PARM(reset_delay, 100); +INT_MODULE_PARM(ext_trans, 0); -MODULE_LICENSE("Dual MPL/GPL"); +#ifdef AHA152X_DEBUG +INT_MODULE_PARM(debug, 0); +#endif + +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"aha152x_cs.c 1.58 2001/10/13 00:08:51 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -277,7 +274,6 @@ release_region(link->io.BasePort1, link->io.NumPorts1); /* Set configuration options for the aha152x driver */ - ints[0] = 7; ints[1] = link->io.BasePort1; ints[2] = link->irq.AssignedIRQ; ints[3] = host_id; @@ -285,9 +281,13 @@ ints[5] = parity; ints[6] = synchronous; ints[7] = reset_delay; - if (ext_trans) { - ints[8] = ext_trans; ints[0] = 8; - } + ints[8] = ext_trans; +#ifdef AHA152X_DEBUG + ints[9] = debug; + ints[0] = 9; +#else + ints[0] = 8; +#endif aha152x_setup("PCMCIA setup", ints); scsi_register_host(&driver_template); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/pcmcia/fdomain_stub.c linux-2.5/drivers/scsi/pcmcia/fdomain_stub.c --- linux-2.5.20/drivers/scsi/pcmcia/fdomain_stub.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/scsi/pcmcia/fdomain_stub.c Thu Dec 27 22:10:28 2001 @@ -2,7 +2,7 @@ A driver for Future Domain-compatible PCMCIA SCSI cards - fdomain_cs.c 1.43 2000/06/12 21:27:25 + fdomain_cs.c 1.47 2001/10/13 00:08:52 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision @@ -54,27 +54,30 @@ #include #include -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"fdomain_cs.c 1.43 2000/06/12 21:27:25 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; - -MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + /*====================================================================*/ typedef struct scsi_info_t { @@ -212,6 +215,7 @@ u_char tuple_data[64]; Scsi_Device *dev; dev_node_t *node, **tail; + char str[16]; struct Scsi_Host *host; DEBUG(0, "fdomain_config(0x%p)\n", link); @@ -252,7 +256,8 @@ ints[0] = 2; ints[1] = link->io.BasePort1; ints[2] = link->irq.AssignedIRQ; - fdomain_setup("PCMCIA setup", ints); + sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ); + fdomain_setup(str, ints); scsi_register_host(&driver_template); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/pcmcia/qlogic_stub.c linux-2.5/drivers/scsi/pcmcia/qlogic_stub.c --- linux-2.5.20/drivers/scsi/pcmcia/qlogic_stub.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/scsi/pcmcia/qlogic_stub.c Thu Dec 27 22:10:28 2001 @@ -2,7 +2,7 @@ A driver for the Qlogic SCSI card - qlogic_cs.c 1.79 2000/06/12 21:27:26 + qlogic_cs.c 1.83 2001/10/13 00:08:53 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -61,26 +62,29 @@ extern void qlogicfas_preset(int port, int irq); -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"qlogic_cs.c 1.79 2000/06/12 21:27:26 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("Qlogic PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; - -MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); + +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"qlogic_cs.c 1.83 2001/10/13 00:08:53 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/ppa.c linux-2.5/drivers/scsi/ppa.c --- linux-2.5.20/drivers/scsi/ppa.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/scsi/ppa.c Tue Feb 19 00:43:15 2002 @@ -152,7 +152,6 @@ "pardevice is owning the port for too longtime!\n", i); parport_unregister_device(ppa_hosts[i].dev); - spin_lock_irq(ppa_hosts[i].cur_cmd->host->host_lock); return 0; } } @@ -221,13 +220,11 @@ printk(" supported by the imm (ZIP Plus) driver. If the\n"); printk(" cable is marked with \"AutoDetect\", this is what has\n"); printk(" happened.\n"); - spin_lock_irq(hreg->host_lock); return 0; } try_again = 1; goto retry_entry; } else { - spin_lock_irq(hreg->host_lock); return 1; /* return number of hosts detected */ } } @@ -792,6 +789,7 @@ { ppa_struct *tmp = (ppa_struct *) data; Scsi_Cmnd *cmd = tmp->cur_cmd; + struct Scsi_Host *host = cmd->host; unsigned long flags; if (!cmd) { @@ -843,11 +841,12 @@ if (cmd->SCp.phase > 0) ppa_pb_release(cmd->host->unique_id); + spin_lock_irqsave(host->host_lock, flags); tmp->cur_cmd = 0; - - spin_lock_irqsave(cmd->host->host_lock, flags); + cmd->scsi_done(cmd); - spin_unlock_irqrestore(cmd->host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); + return; } @@ -921,7 +920,7 @@ case 4: /* Phase 4 - Setup scatter/gather buffers */ if (cmd->use_sg) { /* if many buffers are available, start filling the first */ - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; + cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset; } else { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/scsi.h linux-2.5/drivers/scsi/scsi.h --- linux-2.5.20/drivers/scsi/scsi.h Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/scsi/scsi.h Sun May 26 19:08:10 2002 @@ -670,8 +670,8 @@ unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ unsigned sr_underflow; /* Return error if less than this amount is transferred */ - void * upper_private_data; /* reserved for owner (usually upper - level driver) of this request */ + void * upper_private_data; /* reserved for owner (usually upper + level driver) of this request */ }; /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/sd.c linux-2.5/drivers/scsi/sd.c --- linux-2.5.20/drivers/scsi/sd.c Mon Jun 3 02:44:43 2002 +++ linux-2.5/drivers/scsi/sd.c Sat May 25 19:52:05 2002 @@ -45,7 +45,6 @@ #include #include -#include #include #define MAJOR_NR SCSI_DISK0_MAJOR @@ -90,6 +89,7 @@ static rwlock_t sd_dsk_arr_lock = RW_LOCK_UNLOCKED; static int *sd_sizes; +static int *sd_blocksizes; static int *sd_max_sectors; static int check_scsidisk_media_change(kdev_t); @@ -1063,7 +1063,19 @@ */ sdkp->capacity = 0; } - { + if (sector_size > 1024) { + int m; + + /* + * We must fix the sd_blocksizes and sd_hardsizes + * to allow us to read the partition tables. + * The disk reading code does not allow for reading + * of partial sectors. + */ + for (m = dsk_nr << 4; m < ((dsk_nr + 1) << 4); m++) { + sd_blocksizes[m] = sector_size; + } + } { /* * The msdos fs needs to know the hardware sector size * So I have created this table. See ll_rw_blk.c @@ -1110,10 +1122,6 @@ * we're only interested in the header anyway, this should * be fine. * -- Matthew Dharm (mdharm-scsi@one-eyed-alien.net) - * - * As it turns out, some devices return an error for - * every MODE_SENSE request except one for page 0. - * So, we should also try that. --aeb */ memset((void *) &cmd[0], 0, 8); @@ -1134,9 +1142,8 @@ the_result = SRpnt->sr_result; if (the_result) { - printk("%s: test WP failed, assume Write Enabled\n", - nbuff); - /* alternatively, try page 0 */ + printk(KERN_NOTICE "%s: test WP failed, assume " + "Write Enabled\n", nbuff); } else { sdkp->write_prot = ((buffer[2] & 0x80) != 0); printk(KERN_NOTICE "%s: Write Protect is %s\n", nbuff, @@ -1222,17 +1229,19 @@ } } init_mem_lth(sd_sizes, maxparts); + init_mem_lth(sd_blocksizes, maxparts); init_mem_lth(sd, maxparts); init_mem_lth(sd_gendisks, N_USED_SD_MAJORS); init_mem_lth(sd_max_sectors, sd_template.dev_max << 4); - if (!sd_dsk_arr || !sd_sizes || !sd || !sd_gendisks) + if (!sd_dsk_arr || !sd_sizes || !sd_blocksizes || !sd || !sd_gendisks) goto cleanup_mem; zero_mem_lth(sd_sizes, maxparts); zero_mem_lth(sd, maxparts); for (k = 0; k < maxparts; k++) { + sd_blocksizes[k] = 1024; /* * Allow lowlevel device drivers to generate 512k large scsi * commands if they know what they're doing and they ask for it @@ -1279,6 +1288,8 @@ sd_gendisks = NULL; if (sd) vfree(sd); sd = NULL; + if (sd_blocksizes) vfree(sd_blocksizes); + sd_blocksizes = NULL; if (sd_sizes) vfree(sd_sizes); sd_sizes = NULL; if (sd_dsk_arr) { @@ -1559,6 +1570,7 @@ vfree(sd_dsk_arr); } if (sd_sizes) vfree(sd_sizes); + if (sd_blocksizes) vfree(sd_blocksizes); if (sd) vfree((char *) sd); for (k = 0; k < N_USED_SD_MAJORS; k++) { blk_dev[SD_MAJOR(k)].queue = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/sgiwd93.c linux-2.5/drivers/scsi/sgiwd93.c --- linux-2.5.20/drivers/scsi/sgiwd93.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/scsi/sgiwd93.c Fri May 10 01:27:40 2002 @@ -4,10 +4,13 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * 1999 Andrew R. Baker (andrewb@uab.edu) * - Support for 2nd SCSI controller on Indigo2 + * 2001 Florian Lohoff (flo@rfc822.org) + * - Delete HPC scatter gather (Read corruption on + * multiple disks) + * - Cleanup wback cache handling * * (In all truth, Jed Schimmel wrote all this code.) * - * $Id: sgiwd93.c,v 1.19 2000/02/04 07:40:47 ralf Exp $ */ #include #include @@ -36,32 +39,13 @@ struct hpc_chunk { struct hpc_dma_desc desc; - unsigned long padding; + u32 _padding; /* align to quadword boundary */ }; struct Scsi_Host *sgiwd93_host = NULL; struct Scsi_Host *sgiwd93_host1 = NULL; /* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */ -static inline void write_wd33c93_count(const wd33c93_regs regs, - unsigned long value) -{ - *regs.SASR = WD_TRANSFER_COUNT_MSB; - *regs.SCMD = ((value >> 16) & 0xff); - *regs.SCMD = ((value >> 8) & 0xff); - *regs.SCMD = ((value >> 0) & 0xff); -} - -static inline unsigned long read_wd33c93_count(const wd33c93_regs regs) -{ - unsigned long value; - - *regs.SASR = WD_TRANSFER_COUNT_MSB; - value = (*regs.SCMD << 16); - value |= (*regs.SCMD << 8); - value |= (*regs.SCMD << 0); - return value; -} /* XXX woof! */ static void sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs) @@ -82,7 +66,6 @@ unsigned long physaddr; unsigned long count; - dma_cache_wback_inv((unsigned long)addr,len); physaddr = PHYSADDR(addr); while (len) { /* @@ -101,7 +84,6 @@ static int dma_setup(Scsi_Cmnd *cmd, int datainp) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata; - const wd33c93_regs regs = hdata->regs; struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base; struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer; @@ -112,46 +94,17 @@ hdata->dma_dir = datainp; - if(cmd->SCp.buffers_residual) { - struct scatterlist *slp = cmd->SCp.buffer; - int i, totlen = 0; + /* + * wd33c93 shouldn't pass us bogus dma_setups, but + * it does:-( The other wd33c93 drivers deal with + * it the same way (which isn't that obvious). + * IMHO a better fix would be, not to do these + * dma setups in the first place + */ + if (cmd->SCp.ptr == NULL) + return 1; -#ifdef DEBUG_DMA - printk("SCLIST<"); -#endif - for(i = 0; i <= cmd->SCp.buffers_residual; i++) { -#ifdef DEBUG_DMA - printk("[%p,%d]", - page_address(slp[i].page) + slp[i].offset, - slp[i].length); -#endif - fill_hpc_entries (&hcp, - page_address(slp[i].page) + slp[i].offset, - slp[i].length); - totlen += slp[i].length; - } -#ifdef DEBUG_DMA - printk(">tlen<%d>", totlen); -#endif - hdata->dma_bounce_len = totlen; /* a trick... */ - write_wd33c93_count(regs, totlen); - } else { - /* Non-scattered dma. */ -#ifdef DEBUG_DMA - printk("ONEBUF<%p,%d>", cmd->SCp.ptr, cmd->SCp.this_residual); -#endif - /* - * wd33c93 shouldn't pass us bogus dma_setups, but - * it does:-( The other wd33c93 drivers deal with - * it the same way (which isn't that obvious). - * IMHO a better fix would be, not to do these - * dma setups in the first place - */ - if (cmd->SCp.ptr == NULL) - return 1; - fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); - write_wd33c93_count(regs, cmd->SCp.this_residual); - } + fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); /* To make sure, if we trip an HPC bug, that we transfer * every single byte, we tag on an extra zero length dma @@ -166,10 +119,14 @@ /* Start up the HPC. */ hregs->ndptr = PHYSADDR(hdata->dma_bounce_buffer); - if(datainp) + if(datainp) { + dma_cache_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual); hregs->ctrl = (HPC3_SCTRL_ACTIVE); - else + } else { + dma_cache_wback_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual); hregs->ctrl = (HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR); + } + return 0; } @@ -177,7 +134,6 @@ int status) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata; - const wd33c93_regs regs = hdata->regs; struct hpc3_scsiregs *hregs; if (!SCpnt) @@ -197,44 +153,6 @@ } hregs->ctrl = 0; - /* See how far we got and update scatterlist state if necessary. */ - if(SCpnt->SCp.buffers_residual) { - struct scatterlist *slp = SCpnt->SCp.buffer; - int totlen, wd93_residual, transferred, i; - - /* Yep, we were doing the scatterlist thang. */ - totlen = hdata->dma_bounce_len; - wd93_residual = read_wd33c93_count(regs); - transferred = totlen - wd93_residual; - -#ifdef DEBUG_DMA - printk("tlen<%d>resid<%d>transf<%d> ", - totlen, wd93_residual, transferred); -#endif - - /* Avoid long winded partial-transfer search for common case. */ - if(transferred != totlen) { - /* This is the nut case. */ -#ifdef DEBUG_DMA - printk("Jed was here..."); -#endif - for(i = 0; i <= SCpnt->SCp.buffers_residual; i++) { - if(slp[i].length >= transferred) - break; - transferred -= slp[i].length; - } - } else { - /* This is the common case. */ -#ifdef DEBUG_DMA - printk("did it all..."); -#endif - i = SCpnt->SCp.buffers_residual; - } - SCpnt->SCp.buffer = &slp[i]; - SCpnt->SCp.buffers_residual = SCpnt->SCp.buffers_residual - i; - SCpnt->SCp.ptr = (char *) page_address(slp[i].page) + slp[i].offset; - SCpnt->SCp.this_residual = slp[i].length; - } #ifdef DEBUG_DMA printk("\n"); #endif @@ -264,6 +182,9 @@ }; hcp--; hcp->desc.pnext = PHYSADDR(buf); + + /* Force flush to memory */ + dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); } int __init sgiwd93_detect(Scsi_Host_Template *SGIblows) @@ -273,8 +194,8 @@ struct hpc3_scsiregs *hregs1 = &hpc3c0->scsi_chan1; struct WD33C93_hostdata *hdata; struct WD33C93_hostdata *hdata1; - uchar *buf; wd33c93_regs regs; + uchar *buf; if(called) return 0; /* Should bitch on the console about this... */ @@ -294,10 +215,10 @@ return 0; } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG0 | 0x03 | KSEG1 */ - regs.SASR = (volatile unsigned char *)KSEG1ADDR (0x1fbc0003); - regs.SCMD = (volatile unsigned char *)KSEG1ADDR (0x1fbc0007); + regs.SASR = (unsigned char*) KSEG1ADDR (0x1fbc0003); + regs.SCMD = (unsigned char*) KSEG1ADDR (0x1fbc0007); wd33c93_init(sgiwd93_host, regs, dma_setup, dma_stop, WD33C93_FS_16_20); hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata; @@ -329,17 +250,16 @@ return 1; /* We registered host0 so return success*/ } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG1 | 0x03 | KSEG1 */ - regs.SASR = (volatile unsigned char *)KSEG1ADDR (0x1fbc8003); - regs.SCMD = (volatile unsigned char *)KSEG1ADDR (0x1fbc8007); + regs.SASR = (unsigned char*) KSEG1ADDR(0x1fbc8003); + regs.SCMD = (unsigned char*) KSEG1ADDR(0x1fbc8007); wd33c93_init(sgiwd93_host1, regs, dma_setup, dma_stop, - WD33C93_FS_16_20); + WD33C93_FS_16_20); hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata; hdata1->no_sync = 0; hdata1->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf)); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); if (request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1)) { printk(KERN_WARNING "sgiwd93: Could not allocate irq %d (for host1).\n", SGI_WD93_1_IRQ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/sun3_NCR5380.c linux-2.5/drivers/scsi/sun3_NCR5380.c --- linux-2.5.20/drivers/scsi/sun3_NCR5380.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/scsi/sun3_NCR5380.c Wed Mar 27 13:07:17 2002 @@ -647,10 +647,7 @@ static volatile int main_running = 0; static struct tq_struct NCR5380_tqueue = { -// NULL, /* next */ - sync: 0, /* sync */ - routine: (void (*)(void*))NCR5380_main, /* routine, must have (void *) arg... */ - data: NULL /* data */ + routine: (void (*)(void*))NCR5380_main /* must have (void *) arg... */ }; static __inline__ void queue_main(void) @@ -1219,9 +1216,9 @@ if((sun3scsi_dma_finish(hostdata->connected->request.cmd))) { printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO); - printk("please e-mail sammy@oh.verio.com with a description of how this\n"); + printk("please e-mail sammy@sammy.net with a description of how this\n"); printk("error was produced.\n"); - machine_halt(); + BUG(); } /* make sure we're not stuck in a data phase */ @@ -1232,9 +1229,9 @@ printk("scsi%d: bus stuck in data phase -- probably a single byte overrun!\n", HOSTNO); printk("not prepared for this error!\n"); - printk("please e-mail sammy@oh.verio.com with a description of how this\n"); + printk("please e-mail sammy@sammy.net with a description of how this\n"); printk("error was produced.\n"); - machine_halt(); + BUG(); } @@ -1922,7 +1919,7 @@ /* sanity check */ if(!sun3_dma_setup_done) { printk("scsi%d: transfer_dma without setup!\n", HOSTNO); - machine_halt(); + BUG(); } hostdata->dma_len = c; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/sun3_scsi.c linux-2.5/drivers/scsi/sun3_scsi.c --- linux-2.5.20/drivers/scsi/sun3_scsi.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/scsi/sun3_scsi.c Wed Mar 27 13:07:17 2002 @@ -80,8 +80,10 @@ #include "NCR5380.h" #include "constants.h" +/* #define OLDDMA */ + #define USE_WRAPPER -#define RESET_BOOT +/*#define RESET_BOOT */ #define DRIVER_SETUP #define NDEBUG 0 @@ -94,7 +96,7 @@ #undef DRIVER_SETUP #endif -#undef SUPPORT_TAGS +/* #define SUPPORT_TAGS */ #define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI ); @@ -126,7 +128,9 @@ static volatile unsigned char *sun3_scsi_regp; static volatile struct sun3_dma_regs *dregs; +#ifdef OLDDMA static unsigned char *dmabuf = NULL; /* dma memory buffer */ +#endif static struct sun3_udc_regs *udc_regs = NULL; static unsigned char *sun3_dma_orig_addr = NULL; static unsigned long sun3_dma_orig_count = 0; @@ -260,7 +264,7 @@ #endif #ifdef SUPPORT_TAGS if (setup_use_tagged_queuing < 0) - setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING; + setup_use_tagged_queuing = USE_TAGGED_QUEUING; #endif instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); @@ -310,6 +314,11 @@ dregs->fifo_count = 0; called = 1; + +#ifdef RESET_BOOT + sun3_scsi_reset_boot(instance); +#endif + return 1; } @@ -341,7 +350,7 @@ printk( "Sun3 SCSI: resetting the SCSI bus..." ); /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */ - sun3_disable_irq( IRQ_SUN3_SCSI ); +// sun3_disable_irq( IRQ_SUN3_SCSI ); /* get in phase */ NCR5380_write( TARGET_COMMAND_REG, @@ -361,7 +370,7 @@ barrier(); /* switch on SCSI IRQ again */ - sun3_enable_irq( IRQ_SUN3_SCSI ); +// sun3_enable_irq( IRQ_SUN3_SCSI ); printk( " done\n" ); } @@ -427,8 +436,12 @@ #else void *addr; + if(sun3_dma_orig_addr != NULL) + dvma_unmap(sun3_dma_orig_addr); + // addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf); addr = (void *)dvma_map((unsigned long) data, count); + sun3_dma_orig_addr = addr; sun3_dma_orig_count = count; #endif @@ -454,7 +467,6 @@ dregs->csr &= ~CSR_FIFO; dregs->csr |= CSR_FIFO; - if(dregs->fifo_count != count) { printk("scsi%d: fifo_mismatch %04x not %04x\n", default_instance->host_no, dregs->fifo_count, @@ -533,10 +545,10 @@ int ret = 0; sun3_dma_active = 0; - +#if 1 // check to empty the fifo on a read if(!write_flag) { - int tmo = 200000; /* 2 sec */ + int tmo = 20000; /* .2 sec */ while(1) { if(dregs->csr & CSR_FIFO_EMPTY) @@ -549,6 +561,7 @@ } } +#endif count = sun3scsi_dma_count(default_instance); #ifdef OLDDMA @@ -588,6 +601,7 @@ } dvma_unmap(sun3_dma_orig_addr); + sun3_dma_orig_addr = NULL; #endif sun3_udc_write(UDC_RESET, UDC_CSR); dregs->fifo_count = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/sym53c8xx.c linux-2.5/drivers/scsi/sym53c8xx.c --- linux-2.5.20/drivers/scsi/sym53c8xx.c Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/scsi/sym53c8xx.c Wed Mar 27 13:07:17 2002 @@ -14116,7 +14116,7 @@ if (len) return -EINVAL; else { - long flags; + unsigned long flags; NCR_LOCK_NCB(np, flags); ncr_usercmd (np); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/t128.c linux-2.5/drivers/scsi/t128.c --- linux-2.5.20/drivers/scsi/t128.c Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/scsi/t128.c Thu Dec 13 16:32:36 2001 @@ -47,17 +47,12 @@ * increase compared to polled I/O. * * PARITY - enable parity checking. Not supported. - * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You * only really want to use this if you're having a problem with * dropped characters during high speed communications, and even * then, you're going to be better off twiddling with transfersize. * - * USLEEP - enable support for devices that don't disconnect. Untested. - * * The card is detected and initialized in one of several ways : * 1. Autoprobe (default) - since the board is memory mapped, * a BIOS signature is scanned for to locate the registers. @@ -101,10 +96,6 @@ * 14 10-12 * 15 9-11 */ - -/* - * $Log: t128.c,v $ - */ #include #include @@ -123,276 +114,252 @@ #include static struct override { - unsigned long address; - int irq; -} overrides + unsigned long address; + int irq; +} overrides #ifdef T128_OVERRIDE - [] __initdata = T128_OVERRIDE; +[] __initdata = T128_OVERRIDE; #else - [4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, - {0 ,IRQ_AUTO}, {0, IRQ_AUTO}}; +[4] __initdata = { + { 0, IRQ_AUTO}, + { 0, IRQ_AUTO}, + { 0, IRQ_AUTO}, + { 0, IRQ_AUTO} +}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned int address; - int noauto; + unsigned int address; + int noauto; } bases[] __initdata = { - { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0} + {0xcc000, 0}, + {0xc8000, 0}, + {0xdc000, 0}, + {0xd8000, 0} }; #define NO_BASES (sizeof (bases) / sizeof (struct base)) static const struct signature { - const char *string; - int offset; + const char *string; + int offset; } signatures[] __initdata = { -{"TSROM: SCSI BIOS, Version 1.12", 0x36}, + {"TSROM: SCSI BIOS, Version 1.12", 0x36}, }; #define NO_SIGNATURES (sizeof (signatures) / sizeof (struct signature)) -/* - * Function : t128_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. +/** + * t128_setup + * @str: command line * + * LILO command line initialization of the overrides array, */ -void __init t128_setup(char *str, int *ints){ - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("t128_setup : usage t128=address,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].address = ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; +int __init t128_setup(char *str) +{ + static int commandline_current = 0; + int ints[10]; + int i; + + get_options(str, sizeof(ints) / sizeof(int), ints); + + if (ints[0] != 2) + printk(KERN_ERR "t128_setup : usage t128=address,irq\n"); + else if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].address = ints[1]; + overrides[commandline_current].irq = ints[2]; + for (i = 0; i < NO_BASES; ++i) + if (bases[i].address == ints[1]) { + bases[i].noauto = 1; + break; + } + ++commandline_current; } + return 1; } -/* - * Function : int t128_detect(Scsi_Host_Template * tpnt) +__setup("t128=", t128_setup); + +/** + * t128_detect - detect controllers + * @tpnt: SCSI template * - * Purpose : detects and initializes T128,T128F, or T228 controllers + * Detects and initializes T128,T128F, or T228 controllers * that were autoprobed, overridden on the LILO command line, * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * */ -int __init t128_detect(Scsi_Host_Template * tpnt){ - static int current_override = 0, current_base = 0; - struct Scsi_Host *instance; - unsigned long base; - int sig, count; - - tpnt->proc_name = "t128"; - tpnt->proc_info = &t128_proc_info; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - base = 0; - - if (overrides[current_override].address) - base = overrides[current_override].address; - else - for (; !base && (current_base < NO_BASES); ++current_base) { -#if (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : probing address %08x\n", bases[current_base].address); -#endif - for (sig = 0; sig < NO_SIGNATURES; ++sig) - if (!bases[current_base].noauto && - isa_check_signature(bases[current_base].address + - signatures[sig].offset, - signatures[sig].string, - strlen(signatures[sig].string))) { - base = bases[current_base].address; -#if (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : detected board.\n"); -#endif +int __init t128_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0, current_base = 0; + struct Scsi_Host *instance; + unsigned long base; + int sig, count; + + tpnt->proc_name = "t128"; + tpnt->proc_info = &t128_proc_info; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) + { + base = 0; + + if (overrides[current_override].address) + base = overrides[current_override].address; + else + for (; !base && (current_base < NO_BASES); ++current_base) { + for (sig = 0; sig < NO_SIGNATURES; ++sig) + if (!bases[current_base].noauto && + isa_check_signature(bases[current_base].address + signatures[sig].offset, + signatures[sig].string, + strlen(signatures[sig].string))) + { + base = bases[current_base].address; + break; + } + } + + if (!base) break; - } - } -#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : base = %08x\n", (unsigned int) base); -#endif + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) + break; - if (!base) - break; + instance->base = base; - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->base = base; - - NCR5380_init(instance, 0); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, T128_IRQS); - - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", instance)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } - - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } + NCR5380_init(instance, 0); -#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, T128_IRQS); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", NULL)) + { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + } + + printk(KERN_INFO "scsi%d : at 0x%08lx", instance->host_no,instance->base); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); - printk("scsi%d : at 0x%08lx", instance->host_no, instance->base); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; + ++current_override; + ++count; + } + return count; } -/* - * Function : int t128_biosparam(Disk * disk, kdev_t dev, int *ip) +/** + * t128_biosparam - disk geometry + * @disk: device + * @dev: device major/minor + * @ip: array to return results * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for + * Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * + * Most SCSI boards use this mapping, I could be incorrect. Some one + * using hard disks on a trantor should verify that this mapping + * corresponds to that used by the BIOS / ASPI driver by running the + * linux fdisk program and matching the H_C_S coordinates to those + * that DOS uses. */ -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. - */ - -int t128_biosparam(Disk * disk, kdev_t dev, int * ip) +int t128_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - return 0; + int size = disk->capacity; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + return 0; } -/* - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) +/** + * NCR5380_pread - pseudo DMA read + * @instance: controller + * @dst: buffer to write to + * @len: expect/max length * - * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. + * Fast 5380 pseudo-dma read function, transfers len bytes to + * dst from the controller. */ -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, - int len) { - unsigned long reg = instance->base + T_DATA_REG_OFFSET; - unsigned char *d = dst; - register int i = len; - - -#if 0 - for (; i; --i) { - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); -#else - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); - for (; i; --i) { -#endif - *d++ = isa_readb(reg); - } +static inline int NCR5380_pread(struct Scsi_Host *instance, + unsigned char *dst, int len) +{ + unsigned long reg = instance->base + T_DATA_REG_OFFSET; + unsigned char *d = dst; + int i = len; + + while (!(isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_RDY)) + barrier(); + for (; i; --i) { + *d++ = isa_readb(reg); + } - if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { - unsigned char tmp; - unsigned long foo; - foo = instance->base + T_CONTROL_REG_OFFSET; - tmp = isa_readb(foo); - isa_writeb(tmp | T_CR_CT, foo); - isa_writeb(tmp, foo); - printk("scsi%d : watchdog timer fired in NCR5380_pread()\n", - instance->host_no); - return -1; - } else - return 0; + if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { + unsigned char tmp; + unsigned long foo; + foo = instance->base + T_CONTROL_REG_OFFSET; + tmp = isa_readb(foo); + isa_writeb(tmp | T_CR_CT, foo); + isa_writeb(tmp, foo); + printk(KERN_ERR "scsi%d : watchdog timer fired in t128 NCR5380_pread.\n", instance->host_no); + return -1; + } else + return 0; } -/* - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) +/** + * NCR5380_pwrite - pseudo DMA write + * @instance: controller + * @dst: buffer to write to + * @len: expect/max length * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. + * Fast 5380 pseudo-dma write function, transfers len bytes from + * dst to the controller. */ -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, - int len) { - unsigned long reg = instance->base + T_DATA_REG_OFFSET; - unsigned char *s = src; - register int i = len; - -#if 0 - for (; i; --i) { - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); -#else - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); - for (; i; --i) { -#endif - isa_writeb(*s++, reg); - } - if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { - unsigned char tmp; - unsigned long foo; - foo = instance->base + T_CONTROL_REG_OFFSET; - tmp = isa_readb(foo); - isa_writeb(tmp | T_CR_CT, foo); - isa_writeb(tmp, foo); - printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n", - instance->host_no); - return -1; - } else - return 0; +static inline int NCR5380_pwrite(struct Scsi_Host *instance, + unsigned char *src, int len) +{ + unsigned long reg = instance->base + T_DATA_REG_OFFSET; + unsigned char *s = src; + int i = len; + + while (!(isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_RDY)) + barrier(); + for (; i; --i) { + isa_writeb(*s++, reg); + } + + if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { + unsigned char tmp; + unsigned long foo; + foo = instance->base + T_CONTROL_REG_OFFSET; + tmp = isa_readb(foo); + isa_writeb(tmp | T_CR_CT, foo); + isa_writeb(tmp, foo); + printk(KERN_ERR "scsi%d : watchdog timer fired in t128 NCR5380_pwrite()\n", instance->host_no); + return -1; + } else + return 0; } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/tmscsim.c linux-2.5/drivers/scsi/tmscsim.c --- linux-2.5.20/drivers/scsi/tmscsim.c Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/scsi/tmscsim.c Mon Apr 15 03:03:36 2002 @@ -1448,7 +1448,7 @@ PACB pACB = (PACB) disk->device->host->hostdata; int ret_code = -1; int size = disk->capacity; - unsigned char *buf; + unsigned char *buf; if ((buf = scsi_bios_ptable(devno))) { @@ -2522,15 +2522,15 @@ #define SEARCH(buffer, pos, p0, var, txt, max) \ if (dc390_search (&buffer, &pos, &p0, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \ -else if (!p1) goto ok2 +else if (!pos) goto ok2 #define SEARCH2(buffer, pos, p0, var, txt, max, scale) \ if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, "")) goto einv2; \ -else if (!p1) goto ok2 +else if (!pos) goto ok2 -#define SEARCH3(buffer, pos, &p0, var, txt, max, scale, ign) \ -if (dc390_search (&buffer, &pos, p0, &var, txt, max, scale, ign)) goto einv2; \ -else if (!p1) goto ok2 +#define SEARCH3(buffer, pos, p0, var, txt, max, scale, ign) \ +if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, ign)) goto einv2; \ +else if (!pos) goto ok2 #ifdef DC390_PARSEDEBUG diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/scsi/wd33c93.c linux-2.5/drivers/scsi/wd33c93.c --- linux-2.5.20/drivers/scsi/wd33c93.c Mon Jun 3 02:44:42 2002 +++ linux-2.5/drivers/scsi/wd33c93.c Fri May 10 02:05:26 2002 @@ -1409,11 +1409,31 @@ -static void reset_wd33c93(struct Scsi_Host *instance) +void reset_wd33c93(struct Scsi_Host *instance) { struct WD33C93_hostdata *hostdata = (struct WD33C93_hostdata *)instance->hostdata; const wd33c93_regs regs = hostdata->regs; uchar sr; + +#ifdef CONFIG_SGI_IP22 +{ +int busycount = 0; +extern void sgiwd93_reset(unsigned long); + /* wait 'til the chip gets some time for us */ + while ((READ_AUX_STAT() & ASR_BSY) && busycount++ < 100) + udelay (10); + /* + * there are scsi devices out there, which manage to lock up + * the wd33c93 in a busy condition. In this state it won't + * accept the reset command. The only way to solve this is to + * give the chip a hardware reset (if possible). The code below + * does this for the SGI Indy, where this is possible + */ + /* still busy ? */ + if (READ_AUX_STAT() & ASR_BSY) + sgiwd93_reset(instance->base); /* yeah, give it the hard one */ +} +#endif write_wd33c93(regs, WD_OWN_ID, OWNID_EAF | OWNID_RAF | instance->this_id | hostdata->clock_freq); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/sgi/char/Makefile linux-2.5/drivers/sgi/char/Makefile --- linux-2.5.20/drivers/sgi/char/Makefile Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/sgi/char/Makefile Fri May 31 02:44:03 2002 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -export-objs := newport.o shmiq.o sgicons.o usema.o +export-objs := newport.o rrm.o shmiq.o sgicons.o usema.o obj-y := newport.o shmiq.o sgicons.o usema.o streamable.o obj-$(CONFIG_SGI_SERIAL) += sgiserial.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/sgi/char/ds1286.c linux-2.5/drivers/sgi/char/ds1286.c --- linux-2.5.20/drivers/sgi/char/ds1286.c Mon Jun 3 02:44:46 2002 +++ linux-2.5/drivers/sgi/char/ds1286.c Sun Mar 3 17:54:36 2002 @@ -61,8 +61,9 @@ static unsigned int ds1286_poll(struct file *file, poll_table *wait); -void get_rtc_time (struct rtc_time *rtc_tm); -void get_rtc_alm_time (struct rtc_time *alm_tm); +void ds1286_get_alm_time (struct rtc_time *alm_tm); +void ds1286_get_time(struct rtc_time *rtc_tm); +int ds1286_set_time(struct rtc_time *rtc_tm); void set_rtc_irq_bit(unsigned char bit); void clear_rtc_irq_bit(unsigned char bit); @@ -173,7 +174,7 @@ * tm_min, and tm_sec values are filled in. */ - get_rtc_alm_time(&wtime); + ds1286_get_alm_time(&wtime); break; } case RTC_ALM_SET: /* Store a time into the alarm */ @@ -215,15 +216,12 @@ } case RTC_RD_TIME: /* Read the time/date from RTC */ { - get_rtc_time(&wtime); + ds1286_get_time(&wtime); break; } case RTC_SET_TIME: /* Set the RTC */ { struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned char save_control; - unsigned int yrs, flags; if (!capable(CAP_SYS_TIME)) return -EACCES; @@ -231,57 +229,8 @@ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) return -EFAULT; - - yrs = rtc_tm.tm_year + 1900; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; - - if (yrs < 1970) - return -EINVAL; - - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - - if ((mon > 12) || (day == 0)) - return -EINVAL; - - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - - if ((yrs -= 1940) > 255) /* They are unsigned */ - return -EINVAL; - - if (yrs >= 100) - yrs -= 100; - - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); - - spin_lock_irqsave(&ds1286_lock, flags); - save_control = CMOS_READ(RTC_CMD); - CMOS_WRITE((save_control|RTC_TE), RTC_CMD); - - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DATE); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); - CMOS_WRITE(0, RTC_HUNDREDTH_SECOND); - - CMOS_WRITE(save_control, RTC_CMD); - spin_unlock_irqrestore(&ds1286_lock, flags); - - return 0; + + return ds1286_set_time(&rtc_tm); } default: return -EINVAL; @@ -369,7 +318,7 @@ p = buf; - get_rtc_time(&tm); + ds1286_get_time(&tm); hundredth = CMOS_READ(RTC_HUNDREDTH_SECOND); BCD_TO_BIN(hundredth); @@ -384,7 +333,7 @@ * match any value for that particular field. Values that are * greater than a valid time, but less than 0xc0 shouldn't appear. */ - get_rtc_alm_time(&tm); + ds1286_get_alm_time(&tm); p += sprintf(p, "alarm\t\t: %s ", days[tm.tm_wday]); if (tm.tm_hour <= 24) p += sprintf(p, "%02d:", tm.tm_hour); @@ -441,12 +390,13 @@ return CMOS_READ(RTC_CMD) & RTC_TE; } -void get_rtc_time(struct rtc_time *rtc_tm) + +void ds1286_get_time(struct rtc_time *rtc_tm) { - unsigned long uip_watchdog = jiffies; unsigned char save_control; unsigned int flags; - + unsigned long uip_watchdog = jiffies; + /* * read RTC once any update in progress is done. The update * can take just over 2ms. We wait 10 to 20ms. There is no need to @@ -500,7 +450,66 @@ rtc_tm->tm_mon--; } -void get_rtc_alm_time(struct rtc_time *alm_tm) +int ds1286_set_time(struct rtc_time *rtc_tm) +{ + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control; + unsigned int yrs, flags; + + + yrs = rtc_tm->tm_year + 1900; + mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm->tm_mday; + hrs = rtc_tm->tm_hour; + min = rtc_tm->tm_min; + sec = rtc_tm->tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= 1940) > 255) /* They are unsigned */ + return -EINVAL; + + if (yrs >= 100) + yrs -= 100; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + + spin_lock_irqsave(&ds1286_lock, flags); + save_control = CMOS_READ(RTC_CMD); + CMOS_WRITE((save_control|RTC_TE), RTC_CMD); + + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DATE); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + CMOS_WRITE(0, RTC_HUNDREDTH_SECOND); + + CMOS_WRITE(save_control, RTC_CMD); + spin_unlock_irqrestore(&ds1286_lock, flags); + + return 0; +} + +void ds1286_get_alm_time(struct rtc_time *alm_tm) { unsigned char cmd; unsigned int flags; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/sgi/char/sgiserial.c linux-2.5/drivers/sgi/char/sgiserial.c --- linux-2.5.20/drivers/sgi/char/sgiserial.c Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/sgi/char/sgiserial.c Sat May 25 19:52:05 2002 @@ -98,6 +98,7 @@ DECLARE_TASK_QUEUE(tq_serial); struct tty_driver serial_driver, callout_driver; +struct console sgi_console_driver; struct console *sgisercon; static int serial_refcount; @@ -1883,7 +1884,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sgi_console_driver; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -1909,9 +1912,9 @@ callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); + panic("Couldn't register serial driver"); if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); + panic("Couldn't register callout driver"); save_flags(flags); cli(); @@ -2010,7 +2013,7 @@ if (request_irq(zilog_irq, rs_interrupt, (SA_INTERRUPT), "Zilog8530", zs_chain)) - panic("Unable to attach zs intr\n"); + panic("Unable to attach zs intr"); restore_flags(flags); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/tc/lk201.c linux-2.5/drivers/tc/lk201.c --- linux-2.5.20/drivers/tc/lk201.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/tc/lk201.c Sun Mar 3 17:54:36 2002 @@ -4,13 +4,22 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * + * Copyright (C) 2001 Maciej W. Rozycki */ + +#include + #include +#include #include #include #include #include #include +#include +#include + +#include #include #include #include @@ -27,6 +36,8 @@ */ unsigned char lk201_sysrq_xlate[128]; unsigned char *kbd_sysrq_xlate = lk201_sysrq_xlate; + +unsigned char kbd_sysrq_key = -1; #endif #define KEYB_LINE 3 @@ -71,6 +82,8 @@ LK_CMD_LEDS_OFF, LK_PARAM_LED_MASK(0xf) }; +static struct dec_serial* lk201kbd_info; + static int __init lk201_reset(struct dec_serial *info) { int i; @@ -83,9 +96,115 @@ return 0; } +#define DEFAULT_KEYB_REP_DELAY (250/5) /* [5ms] */ +#define DEFAULT_KEYB_REP_RATE 30 /* [cps] */ + +static struct kbd_repeat kbdrate = { + DEFAULT_KEYB_REP_DELAY, + DEFAULT_KEYB_REP_RATE +}; + +static void parse_kbd_rate(struct kbd_repeat *r) +{ + if (r->delay <= 0) + r->delay = kbdrate.delay; + if (r->rate <= 0) + r->rate = kbdrate.rate; + + if (r->delay < 5) + r->delay = 5; + if (r->delay > 630) + r->delay = 630; + if (r->rate < 12) + r->rate = 12; + if (r->rate > 127) + r->rate = 127; + if (r->rate == 125) + r->rate = 124; +} + +static int write_kbd_rate(struct kbd_repeat *rep) +{ + struct dec_serial* info = lk201kbd_info; + int delay, rate; + int i; + + delay = rep->delay / 5; + rate = rep->rate; + for (i = 0; i < 4; i++) { + if (info->hook->poll_tx_char(info, LK_CMD_RPT_RATE(i))) + return 1; + if (info->hook->poll_tx_char(info, LK_PARAM_DELAY(delay))) + return 1; + if (info->hook->poll_tx_char(info, LK_PARAM_RATE(rate))) + return 1; + } + return 0; +} + +static int lk201kbd_rate(struct kbd_repeat *rep) +{ + if (rep == NULL) + return -EINVAL; + + parse_kbd_rate(rep); + + if (write_kbd_rate(rep)) { + memcpy(rep, &kbdrate, sizeof(struct kbd_repeat)); + return -EIO; + } + + memcpy(&kbdrate, rep, sizeof(struct kbd_repeat)); + + return 0; +} + +static void lk201kd_mksound(unsigned int hz, unsigned int ticks) +{ + struct dec_serial* info = lk201kbd_info; + + if (!ticks) + return; + + /* + * Can't set frequency and we "approximate" + * duration by volume. ;-) + */ + ticks /= HZ / 32; + if (ticks > 7) + ticks = 7; + ticks = 7 - ticks; + + if (info->hook->poll_tx_char(info, LK_CMD_ENB_BELL)) + return; + if (info->hook->poll_tx_char(info, LK_PARAM_VOLUME(ticks))) + return; + if (info->hook->poll_tx_char(info, LK_CMD_BELL)) + return; +} + void kbd_leds(unsigned char leds) { - return; + struct dec_serial* info = lk201kbd_info; + unsigned char l = 0; + + if (!info) /* FIXME */ + return; + + /* FIXME -- Only Hold and Lock LEDs for now. --macro */ + if (leds & LED_SCR) + l |= LK_LED_HOLD; + if (leds & LED_CAP) + l |= LK_LED_LOCK; + + if (info->hook->poll_tx_char(info, LK_CMD_LEDS_ON)) + return; + if (info->hook->poll_tx_char(info, LK_PARAM_LED_MASK(l))) + return; + if (info->hook->poll_tx_char(info, LK_CMD_LEDS_OFF)) + return; + if (info->hook->poll_tx_char(info, LK_PARAM_LED_MASK(~l))) + return; } int kbd_setkeycode(unsigned int scancode, unsigned int keycode) @@ -118,7 +237,12 @@ if (!stat || stat == 4) { switch (ch) { - case LK_KEY_ACK: + case LK_STAT_RESUME_ERR: + case LK_STAT_ERROR: + case LK_STAT_INHIBIT_ACK: + case LK_STAT_TEST_ACK: + case LK_STAT_MODE_KEYDOWN: + case LK_STAT_MODE_ACK: break; case LK_KEY_LOCK: shift_state ^= LK_LOCK; @@ -157,6 +281,7 @@ } } else printk("Error reading LKx01 keyboard: 0x%02x\n", stat); + tasklet_schedule(&keyboard_tasklet); } static void __init lk201_info(struct dec_serial *info) @@ -200,6 +325,10 @@ */ info->hook->rx_char = lk201_kbd_rx_char; + lk201kbd_info = info; + kbd_rate = lk201kbd_rate; + kd_mksound = lk201kd_mksound; + return 0; } @@ -231,7 +360,3 @@ printk("LK201 Support for DS3100 not yet ready ...\n"); } } - - - - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/tc/lk201.h linux-2.5/drivers/tc/lk201.h --- linux-2.5.20/drivers/tc/lk201.h Mon Jun 3 02:44:49 2002 +++ linux-2.5/drivers/tc/lk201.h Sun Mar 3 17:54:36 2002 @@ -2,52 +2,121 @@ * Commands to the keyboard processor */ -#define LK_PARAM 0x80 /* start/end parameter list */ +#define LK_PARAM 0x80 /* start/end parameter list */ -#define LK_CMD_RESUME 0x8b -#define LK_CMD_INHIBIT 0xb9 -#define LK_CMD_LEDS_ON 0x13 /* 1 param: led bitmask */ -#define LK_CMD_LEDS_OFF 0x11 /* 1 param: led bitmask */ -#define LK_CMD_DIS_KEYCLK 0x99 -#define LK_CMD_ENB_KEYCLK 0x1b /* 1 param: volume */ -#define LK_CMD_DIS_CTLCLK 0xb9 -#define LK_CMD_ENB_CTLCLK 0xbb -#define LK_CMD_SOUND_CLK 0x9f -#define LK_CMD_DIS_BELL 0xa1 -#define LK_CMD_ENB_BELL 0x23 /* 1 param: volume */ -#define LK_CMD_BELL 0xa7 -#define LK_CMD_TMP_NORPT 0xc1 -#define LK_CMD_ENB_RPT 0xe3 -#define LK_CMD_DIS_RPT 0xe1 -#define LK_CMD_RPT_TO_DOWN 0xd9 -#define LK_CMD_REQ_ID 0xab -#define LK_CMD_POWER_UP 0xfd -#define LK_CMD_TEST_MODE 0xcb -#define LK_CMD_SET_DEFAULTS 0xd3 +#define LK_CMD_RESUME 0x8b /* resume transmission to the host */ +#define LK_CMD_INHIBIT 0x89 /* stop transmission to the host */ +#define LK_CMD_LEDS_ON 0x13 /* light LEDs */ + /* 1st param: led bitmask */ +#define LK_CMD_LEDS_OFF 0x11 /* turn off LEDs */ + /* 1st param: led bitmask */ +#define LK_CMD_DIS_KEYCLK 0x99 /* disable the keyclick */ +#define LK_CMD_ENB_KEYCLK 0x1b /* enable the keyclick */ + /* 1st param: volume */ +#define LK_CMD_DIS_CTLCLK 0xb9 /* disable the Ctrl keyclick */ +#define LK_CMD_ENB_CTLCLK 0xbb /* enable the Ctrl keyclick */ +#define LK_CMD_SOUND_CLK 0x9f /* emit a keyclick */ +#define LK_CMD_DIS_BELL 0xa1 /* disable the bell */ +#define LK_CMD_ENB_BELL 0x23 /* enable the bell */ + /* 1st param: volume */ +#define LK_CMD_BELL 0xa7 /* emit a bell */ +#define LK_CMD_TMP_NORPT 0xc1 /* disable typematic */ + /* for the currently pressed key */ +#define LK_CMD_ENB_RPT 0xe3 /* enable typematic */ + /* for RPT_DOWN groups */ +#define LK_CMD_DIS_RPT 0xe1 /* disable typematic */ + /* for RPT_DOWN groups */ +#define LK_CMD_RPT_TO_DOWN 0xd9 /* set RPT_DOWN groups to DOWN */ +#define LK_CMD_REQ_ID 0xab /* request the keyboard ID */ +#define LK_CMD_POWER_UP 0xfd /* init power-up sequence */ +#define LK_CMD_TEST_MODE 0xcb /* enter the factory test mode */ +#define LK_CMD_TEST_EXIT 0x80 /* exit the factory test mode */ +#define LK_CMD_SET_DEFAULTS 0xd3 /* set power-up defaults */ + +#define LK_CMD_MODE(m,div) (LK_PARAM|(((div)&0xf)<<3)|m) + /* select the repeat mode */ + /* for the selected key group */ +#define LK_CMD_MODE_AR(m,div) ((((div)&0xf)<<3)|m) + /* select the repeat mode */ + /* and the repeat register */ + /* for the selected key group */ + /* 1st param: register number */ +#define LK_CMD_RPT_RATE(r) (0x04|((((r)&0x3)<<1))) + /* set the delay and repeat rate */ + /* for the selected repeat register */ + /* 1st param: initial delay */ + /* 2nd param: repeat rate */ /* there are 4 leds, represent them in the low 4 bits of a byte */ -#define LK_PARAM_LED_MASK(ledbmap) (LK_PARAM|(ledbmap)) +#define LK_PARAM_LED_MASK(ledbmap) (LK_PARAM|((ledbmap)&0xf)) +#define LK_LED_WAIT 0x1 /* Wait LED */ +#define LK_LED_COMP 0x2 /* Compose LED */ +#define LK_LED_LOCK 0x4 /* Lock LED */ +#define LK_LED_HOLD 0x8 /* Hold Screen LED */ /* max volume is 0, lowest is 0x7 */ -#define LK_PARAM_VOLUME(v) (LK_PARAM|((v)&0x7)) +#define LK_PARAM_VOLUME(v) (LK_PARAM|((v)&0x7)) -/* mode set command(s) details */ -#define LK_MODE_DOWN 0x0 -#define LK_MODE_RPT_DOWN 0x2 -#define LK_MODE_DOWN_UP 0x6 -#define LK_CMD_MODE(m,div) (LK_PARAM|(div<<3)|m) +/* mode set command details, div is a key group number */ +#define LK_MODE_DOWN 0x0 /* make only */ +#define LK_MODE_RPT_DOWN 0x2 /* make and typematic */ +#define LK_MODE_DOWN_UP 0x6 /* make and release */ + +/* there are 4 repeat registers */ +#define LK_PARAM_AR(r) (LK_PARAM|((v)&0x3)) + +/* + * Mappings between key groups and keycodes are as follows: + * + * 1: 0xbf - 0xfb -- alphanumeric, + * 2: 0x92 - 0xa4 -- numeric keypad, + * 3: 0xbc -- Backspace, + * 4: 0xbd - 0xbe -- Tab, Return, + * 5: 0xb0 - 0xb1 -- Lock, Compose Character, + * 6: 0xae - 0xaf -- Ctrl, Shift, + * 7: 0xa7 - 0xa8 -- Left Arrow, Right Arrow, + * 8: 0xa9 - 0xab -- Up Arrow, Down Arrow, Right Shift, + * 9: 0x8a - 0x8f -- editor keypad, + * 10: 0x56 - 0x5a -- F1 - F5, + * 11: 0x64 - 0x68 -- F6 - F10, + * 12: 0x71 - 0x74 -- F11 - F14, + * 13: 0x7c - 0x7d -- Help, Do, + * 14: 0x80 - 0x83 -- F17 - F20. + * + * Others, i.e. 0x55, 0xac, 0xad, 0xb2, are undiscovered. + */ + +/* delay is 5 - 630 ms; 0x00 and 0x7f are reserved */ +#define LK_PARAM_DELAY(t) ((t)&0x7f) + +/* rate is 12 - 127 Hz; 0x00 - 0x0b and 0x7d (power-up!) are reserved */ +#define LK_PARAM_RATE(r) (LK_PARAM|((r)&0x7f)) #define LK_SHIFT 1<<0 #define LK_CTRL 1<<1 #define LK_LOCK 1<<2 #define LK_COMP 1<<3 -#define LK_KEY_SHIFT 174 -#define LK_KEY_CTRL 175 -#define LK_KEY_LOCK 176 -#define LK_KEY_COMP 177 -#define LK_KEY_RELEASE 179 -#define LK_KEY_REPEAT 180 -#define LK_KEY_ACK 186 +#define LK_KEY_SHIFT 0xae +#define LK_KEY_CTRL 0xaf +#define LK_KEY_LOCK 0xb0 +#define LK_KEY_COMP 0xb1 + +#define LK_KEY_RELEASE 0xb3 /* all keys released */ +#define LK_KEY_REPEAT 0xb4 /* repeat the last key */ + +/* status responses */ +#define LK_STAT_RESUME_ERR 0xb5 /* keystrokes lost while inhibited */ +#define LK_STAT_ERROR 0xb6 /* an invalid command received */ +#define LK_STAT_INHIBIT_ACK 0xb7 /* transmission inhibited */ +#define LK_STAT_TEST_ACK 0xb8 /* the factory test mode entered */ +#define LK_STAT_MODE_KEYDOWN 0xb9 /* a key is down on a change */ + /* to the DOWN_UP mode; */ + /* the keycode follows */ +#define LK_STAT_MODE_ACK 0xba /* the mode command succeeded */ + +#define LK_STAT_PWRUP_OK 0x00 /* the power-up self test OK */ +#define LK_STAT_PWRUP_KDOWN 0x3d /* a key was down during the test */ +#define LK_STAT_PWRUP_ERROR 0x3e /* keyboard self test failure */ -extern unsigned char scancodeRemap[256]; \ No newline at end of file +extern unsigned char scancodeRemap[256]; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/tc/zs.c linux-2.5/drivers/tc/zs.c --- linux-2.5.20/drivers/tc/zs.c Mon Jun 3 02:44:45 2002 +++ linux-2.5/drivers/tc/zs.c Sun Mar 3 23:50:42 2002 @@ -443,7 +443,7 @@ if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); break_pressed = 0; goto ignore_char; } @@ -1892,7 +1892,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -1924,9 +1926,9 @@ callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); + panic("Couldn't register serial driver"); if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); + panic("Couldn't register callout driver"); save_flags(flags); cli(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/telephony/Config.help linux-2.5/drivers/telephony/Config.help --- linux-2.5.20/drivers/telephony/Config.help Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/telephony/Config.help Sat Mar 23 22:55:28 2002 @@ -28,6 +28,6 @@ CONFIG_PHONE_IXJ_PCMCIA Say Y here to configure in PCMCIA service support for the Quicknet - cards manufactured by Quicknet Technologies, Inc. This changes the - card initialization code to work with the card manager daemon. + cards manufactured by Quicknet Technologies, Inc. This builds an + additional support module for the PCMCIA version of the card. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/telephony/Config.in linux-2.5/drivers/telephony/Config.in --- linux-2.5.20/drivers/telephony/Config.in Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/telephony/Config.in Sat Apr 13 17:42:56 2002 @@ -6,5 +6,5 @@ tristate 'Linux telephony support' CONFIG_PHONE dep_tristate 'QuickNet Internet LineJack/PhoneJack support' CONFIG_PHONE_IXJ $CONFIG_PHONE -dep_tristate 'QuickNet Internet LineJack/PhoneJack PCMCIA support' CONFIG_PHONE_IXJ_PCMCIA $CONFIG_PHONE_IXJ +dep_tristate 'QuickNet Internet LineJack/PhoneJack PCMCIA support' CONFIG_PHONE_IXJ_PCMCIA $CONFIG_PHONE_IXJ $CONFIG_PCMCIA endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/telephony/ixj.c linux-2.5/drivers/telephony/ixj.c --- linux-2.5.20/drivers/telephony/ixj.c Mon Jun 3 02:44:40 2002 +++ linux-2.5/drivers/telephony/ixj.c Sun Mar 3 17:54:36 2002 @@ -274,8 +274,8 @@ #include "ixj.h" -#define TYPE(dev) (MINOR(dev) >> 4) -#define NUM(dev) (MINOR(dev) & 0xf) +#define TYPE(dev) (minor(dev) >> 4) +#define NUM(dev) (minor(dev) & 0xf) static int ixjdebug; static int hertz = HZ; @@ -386,7 +386,7 @@ #ifdef PERFMON_STATS #define ixj_perfmon(x) ((x)++) #else -#define ixj_perfmon(x) do {} while(0); +#define ixj_perfmon(x) do { } while(0) #endif static int ixj_convert_loaded; @@ -6202,7 +6202,7 @@ IXJ_FILTER_RAW jfr; unsigned int raise, mant; - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); int board = NUM(inode->i_rdev); IXJ *j = get_ixj(NUM(inode->i_rdev)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/usb/class/audio.c linux-2.5/drivers/usb/class/audio.c --- linux-2.5.20/drivers/usb/class/audio.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/usb/class/audio.c Sat May 25 19:52:05 2002 @@ -2349,6 +2349,7 @@ if (vma->vm_pgoff != 0) goto out; + vma->vm_flags &= ~VM_IO; ret = dmabuf_mmap(vma, db, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot); out: unlock_kernel(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/usb/storage/datafab.c linux-2.5/drivers/usb/storage/datafab.c --- linux-2.5.20/drivers/usb/storage/datafab.c Mon Jun 3 02:44:53 2002 +++ linux-2.5/drivers/usb/storage/datafab.c Sat May 25 19:52:06 2002 @@ -671,7 +671,7 @@ srb->result = SUCCESS; } else { info->sense_key = UNIT_ATTENTION; - srb->result = CHECK_CONDITION << 1; + srb->result = CHECK_CONDITION; } return rc; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/usb/storage/jumpshot.c linux-2.5/drivers/usb/storage/jumpshot.c --- linux-2.5.20/drivers/usb/storage/jumpshot.c Mon Jun 3 02:44:39 2002 +++ linux-2.5/drivers/usb/storage/jumpshot.c Sat May 25 19:52:06 2002 @@ -616,7 +616,7 @@ srb->result = SUCCESS; } else { info->sense_key = UNIT_ATTENTION; - srb->result = CHECK_CONDITION << 1; + srb->result = CHECK_CONDITION; } return rc; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/usb/storage/unusual_devs.h linux-2.5/drivers/usb/storage/unusual_devs.h --- linux-2.5.20/drivers/usb/storage/unusual_devs.h Mon Jun 3 02:44:52 2002 +++ linux-2.5/drivers/usb/storage/unusual_devs.h Sun May 19 16:11:12 2002 @@ -106,9 +106,9 @@ * This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200, - "Panasonic", - "LS-120 Camera", - US_SC_UFI, US_PR_CBI, NULL, 0), + "Panasonic", + "LS-120 Camera", + US_SC_UFI, US_PR_CBI, NULL, 0), /* Reported by Peter Wächtler */ UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074, @@ -117,6 +117,21 @@ US_SC_SCSI, US_PR_BULK, NULL, US_FL_FIX_INQUIRY ), +/* Reported by Leif Sawyer */ +UNUSUAL_DEV( 0x04ce, 0x0002, 0x0240, 0x0240, + "H45 ScanLogic", + "SL11R-IDE 9951SQFP-1.2 K004", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY | US_FL_SL_IDE_BUG ), + +/* Reported by Rene Engelhard and + Dylan Egan */ +UNUSUAL_DEV( 0x04ce, 0x0002, 0x0260, 0x0260, + "ScanLogic", + "SL11R-IDE unknown HW rev", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_SL_IDE_BUG ), + /* Most of the following entries were developed with the help of * Shuttle/SCM directly. */ @@ -230,7 +245,7 @@ US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE), UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999, - "Sony", + "Sony", "Memorystick MSC-U01N", US_SC_UFI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP ), @@ -261,34 +276,34 @@ #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110, - "In-System", - "USB/IDE Bridge (ATA/ATAPI)", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), + "In-System", + "USB/IDE Bridge (ATA/ATAPI)", + US_SC_ISD200, US_PR_BULK, isd200_Initialization, + 0 ), UNUSUAL_DEV( 0x05ab, 0x0301, 0x0100, 0x0110, - "In-System", - "Portable USB Harddrive V2", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), + "In-System", + "Portable USB Harddrive V2", + US_SC_ISD200, US_PR_BULK, isd200_Initialization, + 0 ), UNUSUAL_DEV( 0x05ab, 0x0351, 0x0100, 0x0110, - "In-System", - "Portable USB Harddrive V2", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), + "In-System", + "Portable USB Harddrive V2", + US_SC_ISD200, US_PR_BULK, isd200_Initialization, + 0 ), UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110, - "In-System", - "USB Storage Adapter V2", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), + "In-System", + "USB Storage Adapter V2", + US_SC_ISD200, US_PR_BULK, isd200_Initialization, + 0 ), UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x0110, - "Sony", - "Portable USB Harddrive V2", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), + "Sony", + "Portable USB Harddrive V2", + US_SC_ISD200, US_PR_BULK, isd200_Initialization, + 0 ), #endif #ifdef CONFIG_USB_STORAGE_JUMPSHOT @@ -342,18 +357,18 @@ /* Submitted by kedar@centillium * Needed for START_STOP flag, but that is unconfirmed */ UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001, - "Minolta", - "Dimage S304", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), + "Minolta", + "Dimage S304", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_START_STOP ), /* Submitted by f.brugmans@hccnet.nl * Needed for START_STOP flag */ UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001, - "Minolta", - "Dimage S304", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), + "Minolta", + "Dimage S304", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_START_STOP ), UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara", @@ -378,10 +393,10 @@ US_FL_IGNORE_SER), UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, - "Sandisk", - "ImageMate SDDR-12", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN ), + "Sandisk", + "ImageMate SDDR-12", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN ), #ifdef CONFIG_USB_STORAGE_SDDR09 UNUSUAL_DEV( 0x0781, 0x0200, 0x0000, 0x9999, @@ -393,9 +408,9 @@ #ifdef CONFIG_USB_STORAGE_FREECOM UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999, - "Freecom", - "USB-IDE", - US_SC_QIC, US_PR_FREECOM, freecom_init, 0), + "Freecom", + "USB-IDE", + US_SC_QIC, US_PR_FREECOM, freecom_init, 0), #endif UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133, @@ -473,7 +488,7 @@ US_SC_SCSI, US_PR_DATAFAB, NULL, US_FL_MODE_XLATE ), #endif - + #ifdef CONFIG_USB_STORAGE_SDDR55 /* Contributed by Peter Waechtler */ UNUSUAL_DEV( 0x07c4, 0xa103, 0x0000, 0x9999, @@ -491,10 +506,10 @@ * of the SCSI layer ourselves. */ UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009, - "Casio", - "QV DigitalCamera", - US_SC_8070, US_PR_CB, NULL, - US_FL_FIX_INQUIRY ), + "Casio", + "QV DigitalCamera", + US_SC_8070, US_PR_CB, NULL, + US_FL_FIX_INQUIRY ), UNUSUAL_DEV( 0x097a, 0x0001, 0x0000, 0x0001, "Minds@Work", @@ -510,10 +525,10 @@ #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, - "ATI", - "USB Cable 205", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), + "ATI", + "USB Cable 205", + US_SC_ISD200, US_PR_BULK, isd200_Initialization, + 0 ), #endif /* EasyDisk support. Submitted by Stanislav Karchebny */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/usb/storage/usb.h linux-2.5/drivers/usb/storage/usb.h --- linux-2.5.20/drivers/usb/storage/usb.h Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/usb/storage/usb.h Sat Jun 1 00:34:37 2002 @@ -102,6 +102,7 @@ #define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */ #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ +#define US_FL_SL_IDE_BUG 0x00000100 /* ScanLogic usb-ide workaround */ /* device attached/detached states */ #define US_STATE_DETACHED 1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/video/Config.help linux-2.5/drivers/video/Config.help --- linux-2.5.20/drivers/video/Config.help Mon Jun 3 02:44:44 2002 +++ linux-2.5/drivers/video/Config.help Sat Jun 1 02:15:26 2002 @@ -68,6 +68,12 @@ Say Y to enable support for the Amiga Phase 5 CVisionPPC BVisionPPC framebuffer cards. Phase 5 is no longer with us, alas. +CONFIG_FB_PM3 + This is the frame buffer device driver for the 3DLabs Permedia3 + chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & + similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 + and maybe other boards. + CONFIG_FB_AMIGA This is the frame buffer device driver for the builtin graphics chipset found in Amigas. @@ -586,6 +592,12 @@ CONFIG_FB_IMSTT The IMS Twin Turbo is a PCI-based frame buffer card bundled with many Macintosh and compatible computers. + +CONFIG_FB_TX3912 + The TX3912 is a Toshiba RISC processor based on the MIPS 3900 core; + see . + + Say Y here to enable kernel support for the on-board framebuffer. CONFIG_FB_VIRTUAL This is a `virtual' frame buffer device. It operates on a chunk of diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/video/Config.in linux-2.5/drivers/video/Config.in --- linux-2.5.20/drivers/video/Config.in Mon Jun 3 02:44:50 2002 +++ linux-2.5/drivers/video/Config.in Mon Jun 3 15:26:24 2002 @@ -262,7 +262,7 @@ if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \ - "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_PM3" = "y" -o \ + "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_PM3" = "y" -o \ "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \ @@ -275,13 +275,13 @@ "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_SIS" = "y" -o \ "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \ - "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" ]; then + "$CONFIG_FB_MAXINE" = "y" ]; then define_tristate CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \ "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \ - "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_PM3" = "m" -o \ + "$CONFIG_FB_SIS" = "m" -o "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_TRIDENT" = "m" -o \ @@ -294,12 +294,12 @@ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \ "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \ "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ - "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then + "$CONFIG_FB_SA1100" = "m" ]; then define_tristate CONFIG_FBCON_CFB8 m fi fi if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ - "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \ + "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \ "$CONFIG_FB_TRIDENT" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ @@ -309,12 +309,11 @@ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PM3" = "y" -o \ - "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \ - "$CONFIG_FB_PVR2" = "y" ]; then + "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" ]; then define_tristate CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ - "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \ + "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \ "$CONFIG_FB_TRIDENT" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ @@ -324,8 +323,7 @@ "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ - "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ - "$CONFIG_FB_PVR2" = "m" ]; then + "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" ]; then define_tristate CONFIG_FBCON_CFB16 m fi fi @@ -374,7 +372,7 @@ "$CONFIG_FB_HP300" = "y" -o "$CONFIG_FB_Q40" = "y" -o \ "$CONFIG_FB_ANAKIN" = "y" -o "$CONFIG_FB_G364" = "y" -o \ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_CLPS711X" = "y" -o \ - "$CONFIG_FB_3DFX" = "y" ]; then + "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_APOLLO" = "y" ]; then define_tristate CONFIG_FBCON_ACCEL y else if [ "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_HIT" = "m" -o \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/video/Makefile linux-2.5/drivers/video/Makefile --- linux-2.5.20/drivers/video/Makefile Mon Jun 3 02:44:41 2002 +++ linux-2.5/drivers/video/Makefile Mon Jun 3 15:26:24 2002 @@ -43,18 +43,18 @@ obj-$(CONFIG_FB_AMIGA) += amifb.o obj-$(CONFIG_FB_PM2) += pm2fb.o obj-$(CONFIG_FB_PM3) += pm3fb.o -obj-$(CONFIG_FB_APOLLO) += dnfb.o +obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_ATARI) += atafb.o obj-$(CONFIG_FB_ATY128) += aty128fb.o obj-$(CONFIG_FB_RADEON) += radeonfb.o -obj-$(CONFIG_FB_NEOMAGIC) += neofb.o +obj-$(CONFIG_FB_NEOMAGIC) += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_IGA) += igafb.o obj-$(CONFIG_FB_CONTROL) += controlfb.o obj-$(CONFIG_FB_PLATINUM) += platinumfb.o obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o obj-$(CONFIG_FB_CT65550) += chipsfb.o -obj-$(CONFIG_FB_ANAKIN) += anakinfb.o +obj-$(CONFIG_FB_ANAKIN) += anakinfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CYBER) += cyberfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/video/acornfb.c linux-2.5/drivers/video/acornfb.c --- linux-2.5.20/drivers/video/acornfb.c Mon Jun 3 02:44:48 2002 +++ linux-2.5/drivers/video/acornfb.c Sat Jun 1 02:15:26 2002 @@ -1155,9 +1155,6 @@ off += start; vma->vm_pgoff = off >> PAGE_SHIFT; - /* This is an IO map - tell maydump to skip this VMA */ - vma->vm_flags |= VM_IO; - #ifdef CONFIG_CPU_32 pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE; #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.20/drivers/video/anakinfb.c linux-2.5/drivers/video/anakinfb.c --- linux-2.5.20/drivers/video/anakinfb.c Mon Jun 3 02:44:51 2002 +++ linux-2.5/drivers/video/anakinfb.c Mon Jun 3 15:26:24 2002 @@ -21,7 +21,6 @@ #include #include